Add missing headers in vde_router Makefile.am.
[vde.git] / kernel-patch-ipn / patch-linux-2.6.28.2-ipn
blob1c3837975981abc3320267852559ba87b927f3c5
1 diff -Naur linux-2.6.28.2/Documentation/networking/ipn.txt linux-2.6.28.2-ipn/Documentation/networking/ipn.txt
2 --- linux-2.6.28.2/Documentation/networking/ipn.txt     1970-01-01 01:00:00.000000000 +0100
3 +++ linux-2.6.28.2-ipn/Documentation/networking/ipn.txt 2009-02-01 13:29:48.000000000 +0100
4 @@ -0,0 +1,315 @@
5 +Inter Process Networking (IPN)
7 +IPN is an Inter Process Communication service. It uses the same programming
8 +interface and protocols used for networking. Processes using IPN are connected
9 +to a "network" (many to many communication). The messages or packets sent by a
10 +process on an IPN network can be delivered to many other processes connected to
11 +the same IPN network, potentially to all the other processes. Different
12 +protocols can be defined on the IPN service. The basic one is the broadcast
13 +(level 1) protocol: all the packets get received by all the processes but the
14 +sender. It is also possible to define more sophisticated protocols. For example
15 +it is possible to have IPN sockets dipatching packets using the Ethernet
16 +protocol (like a Virtual Distributed Ethernet - VDE switch), or Internet
17 +Protocol (like a layer 3 switch). These are just examples, several other
18 +policies can be defined.  
20 +Description:
21 +------------
23 +The Berkeley socket Application Programming Interface (API) was designed for
24 +client server applications and for point-to-point communications. There is not
25 +a support for broadcasting/multicasting domains.
27 +IPN updates the interface by introducing a new protocol family (PF_IPN or
28 +AF_IPN). PF_IPN is similar to PF_UNIX but for IPN the Socket API calls have a
29 +different (extended) behavior.
31 +   #include <sys/socket.h>
32 +   #include <sys/un.h>
33 +   #include <sys/ipn.h>
35 +   sockfd = socket(AF_IPN, int socket_type, int protocol);
37 +creates a communication socket. The only socket_type defined is SOCK_RAW, other
38 +socket_types can be used for future extensions. A socket cannot be used to send
39 +or receive data until it gets connected (using the "connect" call). The
40 +protocol argument defines the policy used by the socket. Protocol IPN_BROADCAST
41 +(1) is the basic policy: a packet is sent to all the receipients but the sender
42 +itself. The policy IPN_ANY (0) can be used to connect or bind a pre-existing
43 +IPN network regardless of the policy used. (2 will be IPN_VDESWITCH and 3
44 +IPN_VDESWITCHL3).
46 +The address format is the same of PF_UNIX (a.k.a PF_LOCAL), see unix(7) manual.
48 +   int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
50 +This call creates an IPN network if it does not exist, or join an existing
51 +network (just for management) if it already exists. The policy of the network
52 +must be consistent with the protocol argument of the "socket" call. A new
53 +network has the policy defined for the socket. "bind" or "connect" operations
54 +on existing networks fail if the policy of the socket is neither IPN_ANY nor
55 +the same of the network. (A network should not be created by a IPN_ANY socket).
56 +An IPN network appears in the file system as a unix socket. The execution
57 +permission (x) on this file is required for "bind' to succeed (otherwise -EPERM
58 +is returned). Similarly the read/write permissions (rw) permits the "connect"
59 +operation for reading (receiving) or writing (sending) packets respectively.
60 +When a socket is bound (but not connected) to a IPN network the process does
61 +not receive or send any data but it can call "ioctl" or "setsockopt" to
62 +configure the network.
64 +  int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
66 +This call connects a socket to an existing IPN network. The socket can be
67 +already bound (through the "bind" call) or unbound. Unbound connected sockets
68 +receive and send data but they cannot configure the network. The read or write
69 +permission on the socket (rw) is required to "connect" the channel and
70 +read/write respectively. When "connect" succeeds and provided the socket has
71 +appropriate permissions, the process can sends packets and receives all the
72 +packets sent by other processes and delivered to it by the network policy. The
73 +socket can receive data at any time (like a network interface) so the process
74 +must be able to handle incoming data (using select/poll or multithreading).
75 +Obviously higher lever protocols can also prevent the reception of unexpected
76 +messages by design. It is the case of networks used with with exactly one
77 +sender, all the other processes can simply receive the data and the sender will
78 +never receive any packet. It is also possible to have sockets with different
79 +roles assigning reading permission to some and writing permissions to others.
80 +If data overrun occurs there can be data loss or the sender can be blocked
81 +depending on the policy of the socket (LOSSY or LOSSLESS, see over). Bind must
82 +be called before connect. The correct sequences are: socket+bind: just for
83 +management, socket+bind+connect: management and communication. socket+connect:
84 +communication without management).
86 +The calls "accept" and "listen" are not defined for AF_IPN, as there is not any
87 +server. All the communication takes place among peers.
89 +Data can be sent and received using read, write, send, recv, sendto, recvfrom, sendmsg, recvmsg.
91 +Socket options and flags.
92 +-------------------------
94 +These options can be set by getsockopt and setsockopt.
96 +There are two different kinds of options: network options and node options. The
97 +formers define the structure of the network and must be set prior to bind. It
98 +is not currently possible to change this flag of an existing network. When a
99 +socket is bound and/or connected to an existing network getsockopt gives the
100 +current value of the options. Node options define parameters of the node. These
101 +must be set prior to connect.  
103 +Network Options
105 +IPN_SO_FLAGS: This tag permits to set/get the network flags.
107 +IPN_FLAG_LOSSLESS: this flag defines the behavior in case of network
108 +overloading or data overrun, i.e. when some process are too slow in consuming
109 +the packets for the network buffers. When the network is LOSSY (the flag is
110 +cleared) packets get dropped in case of buffer overflow. A LOSSLESS (flag set)
111 +IPN network blocks the sender if the buffer is full. LOSSY is the default
112 +behavior. 
114 +IPN_SO_NUMNODES: max number of connected sockets (default value 32)
116 +IPN_SO_MTU: maximum transfer unit: maximum size of packets (default value 1514,
117 +Ethernet frame, including VLAN).
119 +IPN_SO_MSGPOOLSIZE: size of the buffer (#of pending packets, default value 8).
120 +This option has two different meanings depending on the LOSSY/LOSSLESS behavior
121 +of the network. For LOSSY networks, this is the maximum number of pending
122 +packets of each node. For LOSSLESS network this is the global number of the
123 +pending packets in the network. When the same packet is sent to many
124 +destinations it is counted just once.
126 +IPN_SO_MODE: this option specifies the permission to use when the socket gets
127 +created on the file system. It is modified by the process' umask in the usual
128 +way. The created socket permission are (mode & ~umask).  
130 +Node Options
132 +IPN_SO_PORT: (default value IPN_PORTNO_ANY) This option specify the port number
133 +where the socket must be connected. When IPN_PORTNO_ANY the port number is
134 +decided by the service. There can be network services where different ports
135 +have different definitions (e.g. different VLANs for ports of virtual Ethernet
136 +switches).
138 +IPN_SO_DESCR: This is the description of the node. It is a string, having
139 +maxlength IPN_DESCRLEN. It is just used by debugging tools.  
141 +TAP and GRAB nodes for IPN networks
143 +It is possible to connect IPN sockets to virtual and real network interfaces
144 +using specific ioctl and provided the user has the permission to configure the
145 +network (e.g. the CAP_NET_ADMIN Posix capability). A virtual interface
146 +connected to an IPN network is similar to a tap interface (provided by the
147 +tuntap module). A tap interface appears as an ethernet interface to the hosting
148 +operating system, all the packets sent and received through the tap interface
149 +get received and sent by the application which created the tap interface. IPN
150 +virtual network interface appears in the same way but the packets are received
151 +and sent through the IPN network and delivered consistently with the policy
152 +(BROADCAST acts as a basic HUB for the connected processes). It is also
153 +possible to *grab* a real interface. In this case the closest example is the
154 +Linux kernel ethernet bridge. When a real interface is connected to a IPN all
155 +the packets received from the real network are injected also into the IPN and
156 +all the packets sent by the IPN through the real network 'port' get sent on the
157 +real network.
159 +ioctl is used for creation or control of TAP or GRAB interfaces.
161 +    int ioctl(int d, int request, .../* arg */);
163 +A list of the request values currently supported follows.
165 +IPN_CONN_NETDEV: (struct ifreq *arg). This call creates a TAP interface or
166 +implements a GRAB on an existing interface and connects it to a bound IPN
167 +socket. The field ifr_flags can be IPN_NODEFLAG_TAP for a TAP interface,
168 +IPN_NODEFLAG_GRAB to grab an existing interface. The field ifr_name is the
169 +desired name for the new TAP interface or is the name of the interface to grab
170 +(e.g. eth0). For TAP interfaces, ifr_name can be an empty string. The interface
171 +in this latter case is named ipn followed by a number (e.g. ipn0, ipn1, ...).
172 +This ioctl must be used on a bound but unconnected socket. When the call
173 +succeeds, the socket gets the connected status, but the packets are sent and
174 +received through the interface. Persistence apply only to interface nodes (TAP
175 +or GRAB). 
177 +IPN_SETPERSIST (int arg). If (arg != 0) it gives the interface the persistent
178 +status: the network interface survives and stay connected to the IPN network
179 +when the socket is closed. When (arg == 0) the standard behavior is resumed:
180 +the interface is deleted or the grabbing is terminated when the socket is
181 +closed. 
183 +IPN_JOIN_NETDEV: (struct ifreq *arg). This call reconnects a socket to an
184 +existing persistent node. The interface can be defined either by name
185 +(ifr_name) or by index (ifr_index). If there is already a socket controlling
186 +the interface this call fails (EADDRNOTAVAIL). 
188 +There are also some ioctl that can be used by a sysadm to give/clear
189 +persistence on existing IPN interfaces. These calls apply to unbound sockets.
191 +IPN_SETPERSIST_NETDEV: (struct ifreq *arg). This call sets the persistence
192 +status of an IPN interface. The interface can be defined either by name
193 +(ifr_name) or by index (ifr_index). 
195 +IPN_CLRPERSIST_NETDEV: (struct ifreq *arg). This call clears the persistence
196 +status of an IPN interface. The interface is specified as in the opposite call
197 +above. The interface is deleted (TAP) or the grabbing is terminated when the
198 +socket is closed, or immediately if the interface is not controlled by a
199 +socket. If the IPN network had the interface as its sole node, the IPN network
200 +is terminated, too. 
202 +When unloading the ipn kernel module, all the persistent flags of interfaces
203 +are cleared.  
205 +Related Work.
206 +-------------
208 +IPN is able to give a unifying solution to several problems and creates new
209 +opportunities for applications. 
211 +Several existing tools can be implemented using IPN sockets:
213 +    * VDE. Level 2 service implements a VDE switch in the kernel, providing a
214 +    considerable speedup.  
215 +    * Tap (tuntap) networking for virtual machines
216 +    * Kernel ethernet bridge
217 +    * All the applications which need multicasting of data streams, like tee 
219 +A continuous stream of data (like audio/video/midi etc) can be sent on an IPN
220 +network and several application can receive the broadcast just by joining the
221 +channel.
223 +It is possible to write programs that forward packets between different IPN
224 +networks running on the same or on different systems extending the IPN in the
225 +same way as cables extend ethernet networks connecting switches or hubs
226 +together. (VDE cables are examples of such a kind of programs).
228 +IPN interface to protocol modules
229 +---------------------------------
231 +struct ipn_protocol {
232 +  int refcnt;
233 +  int (*ipn_p_newport)(struct ipn_node *newport);
234 +  int (*ipn_p_handlemsg)(struct ipn_node *from,struct msgpool_item *msgitem, int depth);
235 +  void (*ipn_p_delport)(struct ipn_node *oldport);
236 +  void (*ipn_p_postnewport)(struct ipn_node *newport);
237 +  void (*ipn_p_predelport)(struct ipn_node *oldport);
238 +  int (*ipn_p_newnet)(struct ipn_network *newnet);
239 +  void (*ipn_p_delnet)(struct ipn_network *oldnet);
240 +  int (*ipn_p_setsockopt)(struct ipn_node *port,int optname,
241 +      char __user *optval, int optlen);
242 +  int (*ipn_p_getsockopt)(struct ipn_node *port,int optname,
243 +      char __user *optval, int *optlen);
244 +  int (*ipn_p_ioctl)(struct ipn_node *port,unsigned int request,
245 +      unsigned long arg);
248 +int ipn_proto_register(int protocol,struct ipn_protocol *ipn_service);
249 +int ipn_proto_deregister(int protocol);
251 +void ipn_proto_sendmsg(struct ipn_node *to, struct msgpool_item *msg, int depth);
254 +A protocol (sub) module must define its own ipn_protocol structure (maybe a
255 +global static variable).
257 +ipn_proto_register must be called in the module init to register the protocol
258 +to the IPN core module. ipn_proto_deregister must be called in the destructor
259 +of the module. It fails if there are already running networks based on this
260 +protocol.
262 +Only two fields must be initialized in any case: ipn_p_newport and
263 +ipn_p_handlemsg.
265 +ipn_p_newport is the new network node notification. The return value is the
266 +port number of the new node. This call can be used to allocate and set private
267 +data used by the protocol (the field proto_private of the struct ipn_node has
268 +been defined for this purpose).
270 +ipn_p_handlemsg is the notification of a message that must be dispatched. This
271 +function should call ipn_proto_sendmsg for each recipient. It is possible for
272 +the protocol to change the message (provided the global length of the packet
273 +does not exceed the MTU of the network). Depth is for loop control. Two IPN can
274 +be interconnected by kernel cables (not implemented yet). Cycles of cables
275 +would generate infinite loops of packets. After a pre-defined number of hops
276 +the packet gets dropped (it is like EMLINK for symbolic links). Depth value
277 +must be copied to all ipn_proto_sendmsg calls. Usually the handlemsg function
278 +has the following structure:
280 +static int ipn_xxxxx_handlemsg(struct ipn_node *from, struct msgpool_item *msgitem, int depth)
282 + /* compute the set of receipients */
283 + for (/*each receipient "to"*/)
284 +   ipn_proto_sendmsg(to,msgitem,depth);
287 +It is also possible to send different packets to different recipients.
289 +struct msgpool_item *newitem=ipn_msgpool_alloc(from->ipn);
290 +/* create a new contents for the packet by filling in newitem->len and newitem->data */
291 +ipn_proto_sendmsg(recipient1,newitem,depth);
292 +ipn_proto_sendmsg(recipient2,newitem,depth);
293 +....
294 +ipn_msgpool_put(newitem);
296 +(please remember to call ipn_msgpool_put after the sendmsg of packets allocated
297 +by the protocol submodule).
299 +ipn_p_delport is used to deallocate port related data structures.
301 +ipn_p_postnewport and ipn_p_predelport are used to notify new nodes or deleted
302 +nodes. newport and delport get called before activating the port and after
303 +disactivating it respectively, therefore it is not possible to use the new port
304 +or deleted port to signal the change on the net itself. ipn_p_postnewport and
305 +ipn_p_predelport get called just after the activation and just before the
306 +deactivation thus the protocols can already send packets on the network.
308 +ipn_p_newnet and ipn_p_delnet notify the creation/deletion of a IPN network
309 +using the given protocol.
311 +ipn_p_setsockopt and ipn_p_getsockopt can be used to provide specific socket
312 +options.
314 +ipn_p_ioctl protocols can implement also specific ioctl services. 
316 +More info and examples here: wiki.virtualsquare.org
317 +Note: waiting for the official assignment of a specific Address Family
318 +IPN is currently using AF_NETBEUI (unimplemented at the moment).
319 +AF_NETBEUI is 13, but we are not superstitious!
320 diff -Naur linux-2.6.28.2/MAINTAINERS linux-2.6.28.2-ipn/MAINTAINERS
321 --- linux-2.6.28.2/MAINTAINERS  2009-01-25 01:42:07.000000000 +0100
322 +++ linux-2.6.28.2-ipn/MAINTAINERS      2009-02-01 13:29:48.000000000 +0100
323 @@ -2378,6 +2378,15 @@
324  S:     Maintained
325  T:     git://git.kernel.org/pub/scm/linux/kernel/git/jikos/ipwireless_cs.git
327 +IPN INTER PROCESS NETWORKING
328 +P:     Renzo Davoli
329 +M:     renzo@cs.unibo.it
330 +P:     Ludovico Gardenghi
331 +M:     garden@cs.unibo.it
332 +L:     netdev@vger.kernel.org
333 +W:     http://wiki.virtualsquare.org
334 +S:     Maintained
336  IPX NETWORK LAYER
337  P:     Arnaldo Carvalho de Melo
338  M:     acme@ghostprotocols.net
339 diff -Naur linux-2.6.28.2/include/linux/netdevice.h linux-2.6.28.2-ipn/include/linux/netdevice.h
340 --- linux-2.6.28.2/include/linux/netdevice.h    2009-01-25 01:42:07.000000000 +0100
341 +++ linux-2.6.28.2-ipn/include/linux/netdevice.h        2009-02-01 13:30:05.000000000 +0100
342 @@ -747,6 +747,9 @@
343         struct net_bridge_port  *br_port;
344         /* macvlan */
345         struct macvlan_port     *macvlan_port;
346 +       /* ipn */
347 +       struct ipn_node   *ipn_port;
349         /* GARP */
350         struct garp_port        *garp_port;
352 diff -Naur linux-2.6.28.2/include/linux/socket.h linux-2.6.28.2-ipn/include/linux/socket.h
353 --- linux-2.6.28.2/include/linux/socket.h       2009-01-25 01:42:07.000000000 +0100
354 +++ linux-2.6.28.2-ipn/include/linux/socket.h   2009-02-01 13:30:05.000000000 +0100
355 @@ -231,6 +231,10 @@
356  #define PF_PHONET      AF_PHONET
357  #define PF_MAX         AF_MAX
359 +/* IPN stealing mode, waiting for an officially assigned AF */
360 +#define AF_IPN    AF_NETBEUI
361 +#define PF_IPN    AF_IPN
363  /* Maximum queue length specifiable by listen.  */
364  #define SOMAXCONN      128
366 diff -Naur linux-2.6.28.2/include/net/af_ipn.h linux-2.6.28.2-ipn/include/net/af_ipn.h
367 --- linux-2.6.28.2/include/net/af_ipn.h 1970-01-01 01:00:00.000000000 +0100
368 +++ linux-2.6.28.2-ipn/include/net/af_ipn.h     2009-02-01 13:30:05.000000000 +0100
369 @@ -0,0 +1,236 @@
370 +#ifndef __LINUX_NET_AFIPN_H
371 +#define __LINUX_NET_AFIPN_H
373 +#define IPN_ANY 0
374 +#define IPN_BROADCAST 1
375 +#define IPN_HUB 1
376 +#define IPN_VDESWITCH 2
377 +#define IPN_VDESWITCH_L3 3
379 +#define IPN_SO_PREBIND 0x80
380 +#define IPN_SO_PORT 0
381 +#define IPN_SO_DESCR 1
382 +#define IPN_SO_CHANGE_NUMNODES 2
383 +#define IPN_SO_HANDLE_OOB 3
384 +#define IPN_SO_WANT_OOB_NUMNODES 4
385 +#define IPN_SO_MTU (IPN_SO_PREBIND | 0)
386 +#define IPN_SO_NUMNODES (IPN_SO_PREBIND | 1)
387 +#define IPN_SO_MSGPOOLSIZE (IPN_SO_PREBIND | 2)
388 +#define IPN_SO_FLAGS (IPN_SO_PREBIND | 3)
389 +#define IPN_SO_MODE (IPN_SO_PREBIND | 4)
391 +#define IPN_PORTNO_ANY -1
393 +#define IPN_DESCRLEN 128
395 +#define IPN_FLAG_LOSSLESS 1
396 +#define IPN_FLAG_EXCL 2
397 +#define IPN_FLAG_TERMINATED 0x1000
399 +/* Ioctl defines */
400 +#define IPN_CHECK               _IOW('I', 199, int) 
401 +#define IPN_SETPERSIST_NETDEV          _IOW('I', 200, int) 
402 +#define IPN_CLRPERSIST_NETDEV          _IOW('I', 201, int) 
403 +#define IPN_CONN_NETDEV          _IOW('I', 202, int) 
404 +#define IPN_JOIN_NETDEV          _IOW('I', 203, int) 
405 +#define IPN_SETPERSIST           _IOW('I', 204, int) 
407 +#define IPN_OOB_NUMNODE_TAG 0
409 +/* OOB message for change of numnodes
410 + * Common fields for oob IPN signaling:
411 + * @level=level of the service who generated the oob
412 + * @tag=tag of the message
413 + * Specific fields:
414 + * @numreaders=number of readers
415 + * @numwriters=number of writers
416 + * */
417 +struct numnode_oob {
418 +       int level;
419 +       int tag;
420 +       int numreaders;
421 +       int numwriters;
424 +#ifdef __KERNEL__
425 +#include <linux/socket.h>
426 +#include <linux/mutex.h>
427 +#include <linux/un.h>
428 +#include <net/sock.h>
429 +#include <linux/netdevice.h>
431 +#define IPN_HASH_SIZE  256
433 +/* The AF_IPN socket */
434 +struct msgpool_item;
435 +struct ipn_network;
436 +struct pre_bind_parms;
438 +/* 
439 + * ipn_node
440 + *
441 + * @nodelist=pointers for connectqueue or unconnectqueue (see network)
442 + * @protocol=kind of service 0->standard broadcast
443 + * @flags= see IPN_NODEFLAG_xxx
444 + * @shutdown= SEND_SHUTDOWN/RCV_SHUTDOWN and OOBRCV_SHUTDOWN
445 + * @descr=description of this port
446 + * @portno=when connected: port of the netowrk (<0 means unconnected)
447 + * @msglock=mutex on the msg queue
448 + * @totmsgcount=total # of pending msgs
449 + * @oobmsgcount=# of pending oob msgs
450 + * @msgqueue=queue of messages
451 + * @oobmsgqueue=queue of messages
452 + * @read_wait=waitqueue for reading
453 + * @net=current network
454 + * @dev=device (TAP or GRAB)
455 + * @ipn=network we are connected to
456 + * @pbp=temporary storage for parms that must be set prior to bind
457 + * @proto_private=handle for protocol private data
458 + */
459 +struct ipn_node {
460 +       struct list_head nodelist;
461 +       int protocol;
462 +       volatile unsigned char flags;
463 +       unsigned char shutdown;
464 +       char descr[IPN_DESCRLEN];
465 +       int portno;
466 +       spinlock_t msglock;
467 +       unsigned short totmsgcount;
468 +       unsigned short oobmsgcount;
469 +       struct list_head msgqueue;
470 +       struct list_head oobmsgqueue;
471 +       wait_queue_head_t read_wait;
472 +       struct net *net;
473 +       struct net_device *dev;
474 +       struct ipn_network *ipn;
475 +       struct pre_bind_parms *pbp;
476 +       void *proto_private;
479 +#define IPN_NODEFLAG_BOUND 0x1     /* bind succeeded */
480 +#define IPN_NODEFLAG_INUSE 0x2     /* is currently "used" (0 for persistent, unbound interfaces) */
481 +#define IPN_NODEFLAG_PERSIST 0x4   /* if persist does not disappear on close (net interfaces) */
482 +#define IPN_NODEFLAG_TAP   0x10    /* This is a tap interface */
483 +#define IPN_NODEFLAG_GRAB  0x20    /* This is a grab of a real interface */
484 +#define IPN_NODEFLAG_DEVMASK 0x30  /* True if this is a device */
485 +#define IPN_NODEFLAG_OOB_NUMNODES 0x40  /* Node wants OOB for NNODES */
488 + * ipn_sock
489 + * 
490 + * unfortunately we must use a struct sock (most of the fields are useless) as
491 + * this is the standard "agnostic" structure for socket implementation.
492 + * This proofs that it is not "agnostic" enough!
493 + */
495 +struct ipn_sock {
496 +       struct sock sk;
497 +       struct ipn_node *node;
500 +/* 
501 + * ipn_network network descriptor
502 + *
503 + * @hnode=hash to find this entry (looking for i-node)
504 + * @unconnectqueue=queue of unconnected (bound) nodes
505 + * @connectqueue=queue of connected nodes (faster for broadcasting)
506 + * @refcnt=reference count (bound or connected sockets)
507 + * @dentry/@mnt=to keep the file system descriptor into memory
508 + * @ipnn_lock=lock for protocol functions
509 + * @protocol=kind of service
510 + * @flags=flags (IPN_FLAG_LOSSLESS)
511 + * @maxports=number of ports available in this network
512 + * @msgpool_nelem=number of pending messages
513 + * @msgpool_size=max number of pending messages *per net* when IPN_FLAG_LOSSLESS
514 + * @msgpool_size=max number of pending messages *per port*when LOSSY
515 + * @mtu=MTU
516 + * @send_wait=wait queue waiting for a message in the msgpool (IPN_FLAG_LOSSLESS)
517 + * @msgpool_cache=slab for msgpool (unused yet)
518 + * @proto_private=handle for protocol private data
519 + * @connports=array of connected sockets
520 + */
521 +struct ipn_network {
522 +       struct hlist_node hnode;
523 +       struct list_head unconnectqueue;
524 +       struct list_head connectqueue;
525 +       int refcnt;
526 +       struct dentry   *dentry;
527 +       struct vfsmount   *mnt;
528 +       struct semaphore ipnn_mutex;
529 +       int sunaddr_len;
530 +       struct sockaddr_un sunaddr;
531 +       unsigned int protocol;
532 +       unsigned int flags;
533 +       int numreaders;
534 +       int numwriters;
535 +       atomic_t msgpool_nelem;
536 +       unsigned short maxports;
537 +       unsigned short msgpool_size;
538 +       unsigned short mtu;
539 +       wait_queue_head_t send_wait;
540 +                                                                                                                                                         struct kmem_cache *msgpool_cache;
541 +                                                                                                                                                                 void *proto_private;
542 +                                                                                                                                                                         struct ipn_node **connport;
545 +/* struct msgpool_item 
546 + * the local copy of the message for dispatching
547 + * @count refcount
548 + * @len packet len
549 + * @data payload
550 + */
551 +struct msgpool_item {
552 +       atomic_t count;
553 +       int len;
554 +       unsigned char data[0];
557 +struct msgpool_item *ipn_msgpool_alloc(struct ipn_network *ipnn,int leaky);
558 +void ipn_msgpool_put(struct msgpool_item *old, struct ipn_network *ipnn);
560 +/* 
561 + * protocol service:
562 + *
563 + * @refcnt: number of networks using this protocol
564 + * @newport=upcall for reporting a new port. returns the portno, -1=error  
565 + * @handlemsg=dispatch a message.
566 + *            should call ipn_proto_sendmsg for each desctination
567 + *            can allocate other msgitems using ipn_msgpool_alloc to send
568 + *            different messages to different destinations;
569 + * @delport=(may be null) reports the terminatio of a port
570 + * @postnewport,@predelport: similar to newport/delport but during these calls
571 + *            the node is (still) connected. Useful when protocols need
572 + *            welcome and goodbye messages.
573 + * @ipn_p_setsockopt
574 + * @ipn_p_getsockopt
575 + * @ipn_p_ioctl=(may be null) upcall to manage specific options or ctls.
576 + */
577 +struct ipn_protocol {
578 +       int refcnt;
579 +       int (*ipn_p_newport)(struct ipn_node *newport);
580 +       int (*ipn_p_handlemsg)(struct ipn_node *from,struct msgpool_item *msgitem);
581 +       void (*ipn_p_delport)(struct ipn_node *oldport);
582 +       void (*ipn_p_postnewport)(struct ipn_node *newport);
583 +       void (*ipn_p_predelport)(struct ipn_node *oldport);
584 +       int (*ipn_p_newnet)(struct ipn_network *newnet);
585 +       int (*ipn_p_resizenet)(struct ipn_network *net,int oldsize,int newsize);
586 +       void (*ipn_p_delnet)(struct ipn_network *oldnet);
587 +       int (*ipn_p_setsockopt)(struct ipn_node *port,int optname,
588 +                       char __user *optval, int optlen);
589 +       int (*ipn_p_getsockopt)(struct ipn_node *port,int optname,
590 +                       char __user *optval, int *optlen);
591 +       int (*ipn_p_ioctl)(struct ipn_node *port,unsigned int request,
592 +                       unsigned long arg);
595 +int ipn_proto_register(int protocol,struct ipn_protocol *ipn_service);
596 +int ipn_proto_deregister(int protocol);
598 +int ipn_proto_injectmsg(struct ipn_node *from, struct msgpool_item *msg);
599 +void ipn_proto_sendmsg(struct ipn_node *to, struct msgpool_item *msg);
600 +void ipn_proto_oobsendmsg(struct ipn_node *to, struct msgpool_item *msg);
602 +extern struct sk_buff *(*ipn_handle_frame_hook)(struct ipn_node *p,
603 +                                               struct sk_buff *skb);
604 +#endif
605 +#endif
606 diff -Naur linux-2.6.28.2/net/Kconfig linux-2.6.28.2-ipn/net/Kconfig
607 --- linux-2.6.28.2/net/Kconfig  2009-01-25 01:42:07.000000000 +0100
608 +++ linux-2.6.28.2-ipn/net/Kconfig      2009-02-01 13:30:06.000000000 +0100
609 @@ -34,6 +34,7 @@
611  source "net/packet/Kconfig"
612  source "net/unix/Kconfig"
613 +source "net/ipn/Kconfig"
614  source "net/xfrm/Kconfig"
615  source "net/iucv/Kconfig"
617 diff -Naur linux-2.6.28.2/net/Makefile linux-2.6.28.2-ipn/net/Makefile
618 --- linux-2.6.28.2/net/Makefile 2009-01-25 01:42:07.000000000 +0100
619 +++ linux-2.6.28.2-ipn/net/Makefile     2009-02-01 13:30:06.000000000 +0100
620 @@ -19,6 +19,7 @@
621  obj-$(CONFIG_INET)             += ipv4/
622  obj-$(CONFIG_XFRM)             += xfrm/
623  obj-$(CONFIG_UNIX)             += unix/
624 +obj-$(CONFIG_IPN)              += ipn/
625  ifneq ($(CONFIG_IPV6),)
626  obj-y                          += ipv6/
627  endif
628 diff -Naur linux-2.6.28.2/net/core/dev.c linux-2.6.28.2-ipn/net/core/dev.c
629 --- linux-2.6.28.2/net/core/dev.c       2009-01-25 01:42:07.000000000 +0100
630 +++ linux-2.6.28.2-ipn/net/core/dev.c   2009-02-01 13:30:07.000000000 +0100
631 @@ -2087,7 +2087,7 @@
632                                              int *ret,
633                                              struct net_device *orig_dev)
635 -       if (skb->dev->macvlan_port == NULL)
636 +       if (!skb || skb->dev->macvlan_port == NULL)
637                 return skb;
639         if (*pt_prev) {
640 @@ -2100,6 +2100,32 @@
641  #define handle_macvlan(skb, pt_prev, ret, orig_dev)    (skb)
642  #endif
644 +#if defined(CONFIG_IPN) || defined(CONFIG_IPN_MODULE)
645 +struct sk_buff *(*ipn_handle_frame_hook)(struct ipn_node *port,
646 +                                       struct sk_buff *skb) __read_mostly;
647 +EXPORT_SYMBOL_GPL(ipn_handle_frame_hook);
649 +static inline struct sk_buff *handle_ipn(struct sk_buff *skb,
650 +                                            struct packet_type **pt_prev,
651 +                                            int *ret,
652 +                                            struct net_device *orig_dev)
654 +        struct ipn_node *port;
656 +        if (!skb || skb->pkt_type == PACKET_LOOPBACK ||
657 +                        (port = rcu_dereference(skb->dev->ipn_port)) == NULL)
658 +                return skb;
660 +       if (*pt_prev) {
661 +               *ret = deliver_skb(skb, *pt_prev, orig_dev);
662 +               *pt_prev = NULL;
663 +       }
664 +       return ipn_handle_frame_hook(port, skb);
666 +#else
667 +#define handle_ipn(skb, pt_prev, ret, orig_dev)        (skb)
668 +#endif
670  #ifdef CONFIG_NET_CLS_ACT
671  /* TODO: Maybe we should just force sch_ingress to be compiled in
672   * when CONFIG_NET_CLS_ACT is? otherwise some useless instructions
673 @@ -2278,9 +2304,8 @@
674  #endif
676         skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
677 -       if (!skb)
678 -               goto out;
679         skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
680 +       skb = handle_ipn(skb, &pt_prev, &ret, orig_dev);
681         if (!skb)
682                 goto out;
684 diff -Naur linux-2.6.28.2/net/ipn/Kconfig linux-2.6.28.2-ipn/net/ipn/Kconfig
685 --- linux-2.6.28.2/net/ipn/Kconfig      1970-01-01 01:00:00.000000000 +0100
686 +++ linux-2.6.28.2-ipn/net/ipn/Kconfig  2009-02-01 13:30:09.000000000 +0100
687 @@ -0,0 +1,21 @@
689 +# Unix Domain Sockets
692 +config IPN
693 +       tristate "IPN domain sockets (EXPERIMENTAL)"
694 +       depends on EXPERIMENTAL
695 +       ---help---
696 +         If you say Y here, you will include support for IPN domain sockets.
697 +         Inter Process Networking socket are similar to Unix sockets but
698 +         they support peer-to-peer, one-to-many and many-to-many communication
699 +         among processes. 
700 +         Sub-Modules can be loaded to provide dispatching protocols.
701 +         This service include the IPN_BROADCST policy: all the messages get
702 +         sent to all the receipients (but the sender itself).
704 +         To compile this driver as a module, choose M here: the module will be
705 +         called ipn.  
707 +         If unsure, say 'N'.
709 diff -Naur linux-2.6.28.2/net/ipn/Makefile linux-2.6.28.2-ipn/net/ipn/Makefile
710 --- linux-2.6.28.2/net/ipn/Makefile     1970-01-01 01:00:00.000000000 +0100
711 +++ linux-2.6.28.2-ipn/net/ipn/Makefile 2009-02-01 13:30:09.000000000 +0100
712 @@ -0,0 +1,8 @@
714 +## Makefile for the IPN (Inter Process Networking) domain socket layer.
717 +obj-$(CONFIG_IPN)      += ipn.o
719 +ipn-y                  := af_ipn.o ipn_netdev.o ipn_msgbuf.o
721 diff -Naur linux-2.6.28.2/net/ipn/af_ipn.c linux-2.6.28.2-ipn/net/ipn/af_ipn.c
722 --- linux-2.6.28.2/net/ipn/af_ipn.c     1970-01-01 01:00:00.000000000 +0100
723 +++ linux-2.6.28.2-ipn/net/ipn/af_ipn.c 2009-02-01 13:30:09.000000000 +0100
724 @@ -0,0 +1,1586 @@
726 + * Main inter process networking (virtual distributed ethernet) module
727 + *  (part of the View-OS project: wiki.virtualsquare.org) 
728 + *
729 + * Copyright (C) 2007   Renzo Davoli (renzo@cs.unibo.it)
730 + *
731 + *  This program is free software; you can redistribute it and/or modify
732 + *  it under the terms of the GNU General Public License as published by
733 + *  the Free Software Foundation; either version 2 of the License, or
734 + *  (at your option) any later version.
735 + *
736 + *  Due to this file being licensed under the GPL there is controversy over
737 + *  whether this permits you to write a module that #includes this file
738 + *  without placing your module under the GPL.  Please consult a lawyer for
739 + *  advice before doing this.
740 + *
741 + * WARNING: THIS CODE IS ALREADY EXPERIMENTAL
742 + *
743 + */
745 +#include <linux/init.h>
746 +#include <linux/module.h>
747 +#include <linux/socket.h>
748 +#include <linux/poll.h>
749 +#include <linux/un.h>
750 +#include <linux/list.h>
751 +#include <linux/mount.h>
752 +#include <linux/version.h>
753 +#include <linux/namei.h>
754 +#include <net/sock.h>
755 +#include <net/af_ipn.h>
756 +#include "ipn_netdev.h"
757 +#include "ipn_msgbuf.h"
759 +MODULE_LICENSE("GPL");
760 +MODULE_AUTHOR("VIEW-OS TEAM");
761 +MODULE_DESCRIPTION("IPN Kernel Module");
763 +#define IPN_MAX_PROTO 4
765 +/*extension of RCV_SHUTDOWN defined in include/net/sock.h
766 + * when the bit is set recv fails */
767 +/* NO_OOB: do not send OOB */
768 +#define RCV_SHUTDOWN_NO_OOB    4
769 +/* EXTENDED MASK including OOB */
770 +#define SHUTDOWN_XMASK (SHUTDOWN_MASK | RCV_SHUTDOWN_NO_OOB)
771 +/* if XRCV_SHUTDOWN is all set recv fails */
772 +#define XRCV_SHUTDOWN  (RCV_SHUTDOWN | RCV_SHUTDOWN_NO_OOB)
774 +/* Network table and hash */
775 +struct hlist_head ipn_network_table[IPN_HASH_SIZE + 1];
776 +/* not needed. Now protected by ipn_glob_mutex 
777 + * comment *IPNTL*
778 + * DEFINE_SPINLOCK(ipn_table_lock);
779 + */
780 +static struct kmem_cache *ipn_network_cache;
781 +static struct kmem_cache *ipn_node_cache;
782 +static struct kmem_cache *ipn_msgitem_cache;
783 +static DECLARE_MUTEX(ipn_glob_mutex);
785 +/* Protocol 1: HUB/Broadcast default protocol. Function Prototypes */
786 +static int ipn_bcast_newport(struct ipn_node *newport);
787 +static int ipn_bcast_handlemsg(struct ipn_node *from, 
788 +               struct msgpool_item *msgitem);
790 +/* default protocol IPN_BROADCAST (0) */
791 +static struct ipn_protocol ipn_bcast = {
792 +       .refcnt=0,
793 +       .ipn_p_newport=ipn_bcast_newport, 
794 +       .ipn_p_handlemsg=ipn_bcast_handlemsg};
795 +/* Protocol table */
796 +static struct ipn_protocol *ipn_protocol_table[IPN_MAX_PROTO]={&ipn_bcast};
798 +/* Socket call function prototypes */
799 +static int ipn_release(struct socket *);
800 +static int ipn_bind(struct socket *, struct sockaddr *, int);
801 +static int ipn_connect(struct socket *, struct sockaddr *,
802 +               int addr_len, int flags);
803 +static int ipn_getname(struct socket *, struct sockaddr *, int *, int);
804 +static unsigned int ipn_poll(struct file *, struct socket *, poll_table *);
805 +static int ipn_ioctl(struct socket *, unsigned int, unsigned long);
806 +static int ipn_shutdown(struct socket *, int);
807 +static int ipn_sendmsg(struct kiocb *, struct socket *,
808 +               struct msghdr *, size_t);
809 +static int ipn_recvmsg(struct kiocb *, struct socket *,
810 +               struct msghdr *, size_t, int);
811 +static int ipn_setsockopt(struct socket *sock, int level, int optname,
812 +               char __user *optval, int optlen);
813 +static int ipn_getsockopt(struct socket *sock, int level, int optname,
814 +               char __user *optval, int __user *optlen);
816 +/* Network table Management 
817 + * inode->ipn_network hash table 
818 + * LOCKING: MUTEX ipn_glob_mutex must be LOCKED*/
819 +static inline void ipn_insert_network(struct hlist_head *list, struct ipn_network *ipnn)
821 +       /* *IPNTL* spin_lock(&ipn_table_lock); */
822 +       hlist_add_head(&ipnn->hnode, list);
823 +       /* *IPNTL* spin_unlock(&ipn_table_lock); */
826 +static inline void ipn_remove_network(struct ipn_network *ipnn)
828 +       /* *IPNTL* spin_lock(&ipn_table_lock); */
829 +       hlist_del(&ipnn->hnode);
830 +       /* *IPNTL* spin_unlock(&ipn_table_lock); */
833 +static struct ipn_network *ipn_find_network_byinode(struct inode *i)
835 +       struct ipn_network *ipnn;
836 +       struct hlist_node *node;
838 +       /* *IPNTL* spin_lock(&ipn_table_lock);*/
839 +       hlist_for_each_entry(ipnn, node,
840 +                       &ipn_network_table[i->i_ino & (IPN_HASH_SIZE - 1)], hnode) {
841 +               struct dentry *dentry = ipnn->dentry;
843 +               if(ipnn->refcnt > 0 && dentry && dentry->d_inode == i)
844 +                       goto found;
845 +       }
846 +       ipnn = NULL;
847 +found:
848 +       /* *IPNTL* spin_unlock(&ipn_table_lock); */
849 +       return ipnn;
852 +/* msgpool management 
853 + * msgpool_item are ipn_network dependent (each net has its own MTU)
854 + * for each message sent there is one msgpool_item and many struct msgitem
855 + * one for each receipient. 
856 + * msgitem are connected to the node's msgqueue or oobmsgqueue.
857 + * when a message is delivered to a process the msgitem is deleted and
858 + * the count of the msgpool_item is decreased.
859 + * msgpool_item elements gets deleted automatically when count is 0*/
861 +struct msgitem {
862 +       struct list_head list;
863 +       struct msgpool_item *msg;
866 +/* alloc a fresh msgpool item. count is set to 1.
867 + * the typical use is
868 + *  ipn_msgpool_alloc
869 + *  for each receipient
870 + *    enqueue messages to the process (using msgitem), ipn_msgpool_hold 
871 + *  ipn_msgpool_put
872 + * The message can be delivered concurrently. init count to 1 guarantees
873 + * that it survives at least until is has been enqueued to all
874 + * receivers */
875 +static struct msgpool_item *_ipn_msgpool_alloc(struct ipn_network *ipnn)
877 +       struct msgpool_item *new;
878 +       if ((new=kmem_cache_alloc(ipnn->msgpool_cache,GFP_KERNEL)) != NULL) {
879 +               atomic_set(&new->count,1);
880 +               atomic_inc(&ipnn->msgpool_nelem);
881 +       }
882 +       return new;
885 +struct msgpool_item *ipn_msgpool_alloc(struct ipn_network *ipnn,int leaky)
887 +         if (leaky && (ipnn->flags & IPN_FLAG_LOSSLESS) &&
888 +                               atomic_read(&ipnn->msgpool_nelem) < ipnn->msgpool_size)
889 +                       return NULL;
890 +               else 
891 +                       return _ipn_msgpool_alloc(ipnn);
894 +/* If the service il LOSSLESS, this msgpool call waits for an
895 + * available msgpool item */
896 +static struct msgpool_item *ipn_msgpool_alloc_locking(struct ipn_network *ipnn)
898 +       if (ipnn->flags & IPN_FLAG_LOSSLESS) {
899 +               while (atomic_read(&ipnn->msgpool_nelem) >= ipnn->msgpool_size) {
900 +                       if (wait_event_interruptible_exclusive(ipnn->send_wait,
901 +                                               atomic_read(&ipnn->msgpool_nelem) < ipnn->msgpool_size))
902 +                               return NULL;
903 +               }
904 +       }
905 +       return _ipn_msgpool_alloc(ipnn);
908 +static inline void ipn_msgpool_hold(struct msgpool_item *msg)
910 +       atomic_inc(&msg->count);
913 +/* decrease count and delete msgpool_item if count == 0 */
914 +void ipn_msgpool_put(struct msgpool_item *old,
915 +               struct ipn_network *ipnn)
917 +       if (atomic_dec_and_test(&old->count)) {
918 +               kmem_cache_free(ipnn->msgpool_cache,old);
919 +               atomic_dec(&ipnn->msgpool_nelem);
920 +               if (ipnn->flags & IPN_FLAG_LOSSLESS) /* this could be done anyway */
921 +                       wake_up_interruptible(&ipnn->send_wait);
922 +       }
925 +/* socket calls */
926 +static const struct proto_ops ipn_ops = {
927 +       .family = PF_IPN,
928 +       .owner =  THIS_MODULE,
929 +       .release =  ipn_release,
930 +       .bind =   ipn_bind,
931 +       .connect =  ipn_connect,
932 +       .socketpair = sock_no_socketpair,
933 +       .accept = sock_no_accept,
934 +       .getname =  ipn_getname,
935 +       .poll =   ipn_poll,
936 +       .ioctl =  ipn_ioctl,
937 +       .listen = sock_no_listen,
938 +       .shutdown = ipn_shutdown,
939 +       .setsockopt = ipn_setsockopt,
940 +       .getsockopt = ipn_getsockopt,
941 +       .sendmsg =  ipn_sendmsg,
942 +       .recvmsg =  ipn_recvmsg,
943 +       .mmap =   sock_no_mmap,
944 +       .sendpage = sock_no_sendpage,
947 +static struct proto ipn_proto = {
948 +       .name   = "IPN",
949 +       .owner    = THIS_MODULE,
950 +       .obj_size = sizeof(struct ipn_sock),
953 +/* create a socket
954 + * ipn_node is a separate structure, pointed by ipn_sock -> node
955 + * when a node is "persistent", ipn_node survives while ipn_sock gets released*/
956 +static int ipn_create(struct net *net,struct socket *sock, int protocol)
958 +       struct ipn_sock *ipn_sk;
959 +       struct ipn_node *ipn_node;
960 +       
961 +       if (net != &init_net)
962 +               return -EAFNOSUPPORT;
964 +       if (sock->type != SOCK_RAW)
965 +               return -EPROTOTYPE;
966 +       if (protocol > 0)
967 +               protocol=protocol-1;
968 +       else
969 +               protocol=IPN_BROADCAST-1;
970 +       if (protocol < 0 || protocol >= IPN_MAX_PROTO ||
971 +                       ipn_protocol_table[protocol] == NULL)
972 +               return -EPROTONOSUPPORT;
973 +       ipn_sk = (struct ipn_sock *) sk_alloc(net, PF_IPN, GFP_KERNEL, &ipn_proto);
975 +       if (!ipn_sk) 
976 +               return -ENOMEM;
977 +       ipn_sk->node=ipn_node=kmem_cache_alloc(ipn_node_cache,GFP_KERNEL);
978 +       if (!ipn_node) {
979 +               sock_put((struct sock *) ipn_sk);
980 +               return -ENOMEM;
981 +       }
982 +       sock_init_data(sock,(struct sock *) ipn_sk);
983 +       sock->state = SS_UNCONNECTED;
984 +       sock->ops = &ipn_ops;
985 +       sock->sk=(struct sock *)ipn_sk;
986 +       INIT_LIST_HEAD(&ipn_node->nodelist);
987 +       ipn_node->protocol=protocol;
988 +       ipn_node->flags=IPN_NODEFLAG_INUSE;
989 +       ipn_node->shutdown=RCV_SHUTDOWN_NO_OOB;
990 +       ipn_node->descr[0]=0;
991 +       ipn_node->portno=IPN_PORTNO_ANY;
992 +       ipn_node->net=net;
993 +       ipn_node->dev=NULL;
994 +       ipn_node->proto_private=NULL;
995 +       ipn_node->totmsgcount=0;
996 +       ipn_node->oobmsgcount=0;
997 +       spin_lock_init(&ipn_node->msglock);
998 +       INIT_LIST_HEAD(&ipn_node->msgqueue);
999 +       INIT_LIST_HEAD(&ipn_node->oobmsgqueue);
1000 +       ipn_node->ipn=NULL;
1001 +       init_waitqueue_head(&ipn_node->read_wait);
1002 +       ipn_node->pbp=NULL;
1003 +       return 0;
1006 +/* update # of readers and # of writers counters for an ipn network.
1007 + * This function sends oob messages to nodes requesting the service */
1008 +/* LOCKING ipnn_mutex is locked */
1009 +static void ipn_net_update_counters(struct ipn_network *ipnn,
1010 +               int chg_readers, int chg_writers) {
1011 +       ipnn->numreaders += chg_readers;
1012 +       ipnn->numwriters += chg_writers;
1013 +       if (ipnn->mtu >= sizeof(struct numnode_oob))
1014 +       {
1015 +               struct msgpool_item *ipn_msg=_ipn_msgpool_alloc(ipnn);
1016 +               if (ipn_msg) {
1017 +                       struct numnode_oob *oob_msg=(struct numnode_oob *)(ipn_msg->data);
1018 +                       struct ipn_node *ipn_node;
1019 +                       ipn_msg->len=sizeof(struct numnode_oob);
1020 +                       oob_msg->level=IPN_ANY;
1021 +                       oob_msg->tag=IPN_OOB_NUMNODE_TAG;
1022 +                       oob_msg->numreaders=ipnn->numreaders;
1023 +                       oob_msg->numwriters=ipnn->numwriters;
1024 +                       list_for_each_entry(ipn_node, &ipnn->connectqueue, nodelist) {
1025 +                               if (ipn_node->flags & IPN_NODEFLAG_OOB_NUMNODES)
1026 +                                       ipn_proto_oobsendmsg(ipn_node,ipn_msg);
1027 +                       }
1028 +                       ipn_msgpool_put(ipn_msg,ipnn);
1029 +               }
1030 +       }
1033 +/* flush pending messages (for close and shutdown RCV) */
1034 +/* LOCKING: ipnn_mutex is locked */
1035 +static void ipn_flush_recvqueue(struct ipn_node *ipn_node)
1037 +       struct ipn_network *ipnn=ipn_node->ipn;
1038 +       spin_lock(&ipn_node->msglock);
1039 +       while (!list_empty(&ipn_node->msgqueue)) {
1040 +               struct msgitem *msgitem=
1041 +                       list_first_entry(&ipn_node->msgqueue, struct msgitem, list);
1042 +               list_del(&msgitem->list);
1043 +               ipn_node->totmsgcount--;
1044 +               ipn_msgpool_put(msgitem->msg,ipnn);
1045 +               kmem_cache_free(ipn_msgitem_cache,msgitem);
1046 +       }
1047 +       spin_unlock(&ipn_node->msglock);
1050 +/* flush pending oob messages (for socket close) */
1051 +/* LOCKING: ipnn_mutex is locked */
1052 +static void ipn_flush_oobrecvqueue(struct ipn_node *ipn_node)
1054 +       struct ipn_network *ipnn=ipn_node->ipn;
1055 +       spin_lock(&ipn_node->msglock);
1056 +       while (!list_empty(&ipn_node->oobmsgqueue)) {
1057 +               struct msgitem *msgitem=
1058 +                       list_first_entry(&ipn_node->oobmsgqueue, struct msgitem, list);
1059 +               list_del(&msgitem->list);
1060 +               ipn_node->totmsgcount--;
1061 +               ipn_node->oobmsgcount--;
1062 +               ipn_msgpool_put(msgitem->msg,ipnn);
1063 +               kmem_cache_free(ipn_msgitem_cache,msgitem);
1064 +       }
1065 +       spin_unlock(&ipn_node->msglock);
1068 +/* Terminate node. The node is "logically" terminated. */
1069 +/* LOCKING: ipn_glob_lock must be locked here */
1070 +static int ipn_terminate_node(struct ipn_node *ipn_node)
1072 +       struct ipn_network *ipnn=ipn_node->ipn;
1073 +       if (ipnn) {
1074 +               if (down_interruptible(&ipnn->ipnn_mutex)) 
1075 +                       return -ERESTARTSYS;
1076 +               if (ipn_node->portno >= 0) {
1077 +                       ipn_protocol_table[ipnn->protocol]->ipn_p_predelport(ipn_node);
1078 +                       ipnn->connport[ipn_node->portno]=NULL;
1079 +               }
1080 +               list_del(&ipn_node->nodelist);
1081 +               ipn_flush_recvqueue(ipn_node);
1082 +               ipn_flush_oobrecvqueue(ipn_node);
1083 +               if (ipn_node->portno >= 0) 
1084 +                       ipn_protocol_table[ipnn->protocol]->ipn_p_delport(ipn_node);
1085 +               ipn_node->ipn=NULL;
1086 +               ipn_net_update_counters(ipnn,
1087 +                               (ipn_node->shutdown & RCV_SHUTDOWN)?0:-1,
1088 +                               (ipn_node->shutdown & SEND_SHUTDOWN)?0:-1);
1089 +               ipn_node->shutdown = SHUTDOWN_XMASK;
1090 +               up(&ipnn->ipnn_mutex);
1091 +               if (ipn_node->dev)
1092 +                       ipn_netdev_close(ipn_node);
1093 +               /* No more network elements */
1094 +               ipnn->refcnt--;
1095 +               if (ipnn->refcnt == 0)
1096 +               {
1097 +                       ipn_protocol_table[ipnn->protocol]->ipn_p_delnet(ipnn);
1098 +                       ipn_remove_network(ipnn);
1099 +                       ipn_protocol_table[ipnn->protocol]->refcnt--;
1100 +                       if (ipnn->dentry) {
1101 +                               dput(ipnn->dentry);
1102 +                               mntput(ipnn->mnt);
1103 +                       }
1104 +                       if (ipnn->msgpool_cache)
1105 +                               ipn_msgbuf_put(ipnn->msgpool_cache);
1106 +                       if (ipnn->connport)
1107 +                               kfree(ipnn->connport);
1108 +                       kmem_cache_free(ipn_network_cache, ipnn);
1109 +                       module_put(THIS_MODULE);
1110 +               }
1111 +       }
1112 +       if (ipn_node->pbp) {
1113 +               kfree(ipn_node->pbp);
1114 +               ipn_node->pbp=NULL;
1115 +       } 
1116 +       return 0;
1119 +/* release of a socket */
1120 +static int ipn_release (struct socket *sock)
1122 +       struct ipn_sock *ipn_sk=(struct ipn_sock *)sock->sk;
1123 +       struct ipn_node *ipn_node=ipn_sk->node;
1124 +       int rv;
1125 +       if (down_interruptible(&ipn_glob_mutex))
1126 +               return -ERESTARTSYS;
1127 +       if (ipn_node->flags & IPN_NODEFLAG_PERSIST) {
1128 +               ipn_node->flags &= ~IPN_NODEFLAG_INUSE;
1129 +               rv=0;
1130 +               up(&ipn_glob_mutex);
1131 +       } else {
1132 +               rv=ipn_terminate_node(ipn_node);
1133 +               up(&ipn_glob_mutex);
1134 +               if (rv==0) {
1135 +                       ipn_netdevsync();
1136 +                       kmem_cache_free(ipn_node_cache,ipn_node);
1137 +               }
1138 +       }
1139 +       if (rv==0) 
1140 +               sock_put((struct sock *) ipn_sk);
1141 +       return rv;
1144 +/* _set persist, change the persistence of a node,
1145 + * when persistence gets cleared and the node is no longer used
1146 + * the node is terminated and freed.
1147 + * ipn_glob_mutex must be locked */
1148 +static int _ipn_setpersist(struct ipn_node *ipn_node, int persist)
1150 +       int rv=0;
1151 +       if (persist)
1152 +               ipn_node->flags |= IPN_NODEFLAG_PERSIST;
1153 +       else {
1154 +               ipn_node->flags &= ~IPN_NODEFLAG_PERSIST;
1155 +               if (!(ipn_node->flags & IPN_NODEFLAG_INUSE)) {
1156 +                       rv=ipn_terminate_node(ipn_node);
1157 +                       if (rv==0)
1158 +                               kmem_cache_free(ipn_node_cache,ipn_node);
1159 +               }
1160 +       }
1161 +       return rv;
1164 +/* ipn_setpersist 
1165 + * lock ipn_glob_mutex and call __ipn_setpersist above */
1166 +static int ipn_setpersist(struct ipn_node *ipn_node, int persist)
1168 +       int rv=0;
1169 +       if (ipn_node->dev == NULL)
1170 +               return -ENODEV;
1171 +       if (down_interruptible(&ipn_glob_mutex))
1172 +               return -ERESTARTSYS;
1173 +       rv=_ipn_setpersist(ipn_node,persist);
1174 +       up(&ipn_glob_mutex);
1175 +       return rv;
1178 +/* several network parameters can be set by setsockopt prior to bind */
1179 +/* struct pre_bind_parms is a temporary stucture connected to ipn_node->pbp
1180 + * to keep the parameter values. */
1181 +struct pre_bind_parms {
1182 +       unsigned short maxports;
1183 +       unsigned short flags;
1184 +       unsigned short msgpoolsize;
1185 +       unsigned short mtu;
1186 +       unsigned short mode;
1189 +/* STD_PARMS:  BITS_PER_LONG nodes, no flags, BITS_PER_BYTE pending msgs, 
1190 + * Ethernet + VLAN MTU*/
1191 +#define STD_BIND_PARMS {BITS_PER_LONG, 0, BITS_PER_BYTE, 1514, 0x777};
1193 +static int ipn_mkname(struct sockaddr_un * sunaddr, int len)
1195 +       if (len <= sizeof(short) || len > sizeof(*sunaddr))
1196 +               return -EINVAL;
1197 +       if (!sunaddr || sunaddr->sun_family != AF_IPN)
1198 +               return -EINVAL;
1199 +       /*
1200 +        * This may look like an off by one error but it is a bit more
1201 +        * subtle. 108 is the longest valid AF_IPN path for a binding.
1202 +        * sun_path[108] doesnt as such exist.  However in kernel space
1203 +        * we are guaranteed that it is a valid memory location in our
1204 +        * kernel address buffer.
1205 +        */
1206 +       ((char *)sunaddr)[len]=0;
1207 +       len = strlen(sunaddr->sun_path)+1+sizeof(short);
1208 +       return len;
1211 +/* IPN BIND */
1212 +static int ipn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
1214 +       struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
1215 +       struct ipn_node *ipn_node=((struct ipn_sock *)sock->sk)->node;
1216 +       struct nameidata nd;
1217 +       struct ipn_network *ipnn;
1218 +       struct dentry * dentry = NULL;
1219 +       int err;
1220 +       struct pre_bind_parms parms=STD_BIND_PARMS;
1222 +       //printk("IPN bind\n");
1224 +       if (down_interruptible(&ipn_glob_mutex))
1225 +               return -ERESTARTSYS;
1226 +       if (sock->state != SS_UNCONNECTED || 
1227 +                       ipn_node->ipn != NULL) {
1228 +               err= -EISCONN;
1229 +               goto out;
1230 +       }
1232 +       if (ipn_node->protocol >= 0 && 
1233 +                       (ipn_node->protocol >= IPN_MAX_PROTO ||
1234 +                        ipn_protocol_table[ipn_node->protocol] == NULL)) {
1235 +               err= -EPROTONOSUPPORT;
1236 +               goto out;
1237 +       }
1239 +       addr_len = ipn_mkname(sunaddr, addr_len);
1240 +       if (addr_len < 0) {
1241 +               err=addr_len;
1242 +               goto out;
1243 +       }
1245 +       /* check if there is already an ipn-network socket with that name */
1246 +       err = path_lookup(sunaddr->sun_path, LOOKUP_FOLLOW, &nd);
1247 +       if (err) { /* it does not exist, NEW IPN socket! */
1248 +               unsigned int mode;
1249 +               /* Is it everything okay with the parent? */
1250 +               err = path_lookup(sunaddr->sun_path, LOOKUP_PARENT, &nd);
1251 +               if (err)
1252 +                       goto out_mknod_parent;
1253 +               /* Do I have the permission to create a file? */
1254 +               dentry = lookup_create(&nd, 0);
1255 +               err = PTR_ERR(dentry);
1256 +               if (IS_ERR(dentry))
1257 +                       goto out_mknod_unlock;
1258 +               /*
1259 +                * All right, let's create it.
1260 +                */
1261 +               if (ipn_node->pbp) 
1262 +                       mode = ipn_node->pbp->mode;
1263 +               else
1264 +                       mode = SOCK_INODE(sock)->i_mode;
1265 +               mode = S_IFSOCK | (mode & ~current->fs->umask);
1266 +               err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0);
1267 +               if (err)
1268 +                       goto out_mknod_dput;
1269 +               mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
1270 +               dput(nd.path.dentry);
1271 +               nd.path.dentry = dentry;
1272 +               /* create a new ipn_network item */
1273 +               if (ipn_node->pbp) 
1274 +                       parms=*ipn_node->pbp;
1275 +               ipnn=kmem_cache_zalloc(ipn_network_cache,GFP_KERNEL); 
1276 +               if (!ipnn) {
1277 +                       err=-ENOMEM;
1278 +                       goto out_mknod_dput_ipnn;
1279 +               }
1280 +               ipnn->connport=kzalloc(parms.maxports * sizeof(struct ipn_node *),GFP_KERNEL);
1281 +               if (!ipnn->connport) {
1282 +                       err=-ENOMEM;
1283 +                       goto out_mknod_dput_ipnn2;
1284 +               }
1286 +               /* module refcnt is incremented for each network, thus
1287 +                * rmmod is forbidden if there are persistent node */
1288 +               if (!try_module_get(THIS_MODULE)) {
1289 +                       err = -EINVAL;
1290 +                       goto out_mknod_dput_ipnn2;
1291 +               }
1292 +               memcpy(&ipnn->sunaddr,sunaddr,addr_len);
1293 +               ipnn->mtu=parms.mtu;
1294 +               ipnn->msgpool_cache=ipn_msgbuf_get(ipnn->mtu);
1295 +               if (!ipnn->msgpool_cache) {
1296 +                       err=-ENOMEM;
1297 +                       goto out_mknod_dput_putmodule;
1298 +               }
1299 +               INIT_LIST_HEAD(&ipnn->unconnectqueue);
1300 +               INIT_LIST_HEAD(&ipnn->connectqueue);
1301 +               ipnn->refcnt=1;
1302 +               ipnn->dentry=nd.path.dentry;
1303 +               ipnn->mnt=nd.path.mnt;
1304 +               init_MUTEX(&ipnn->ipnn_mutex);
1305 +               ipnn->sunaddr_len=addr_len;
1306 +               ipnn->protocol=ipn_node->protocol;
1307 +               if (ipnn->protocol < 0) ipnn->protocol = 0;
1308 +               ipn_protocol_table[ipnn->protocol]->refcnt++;
1309 +               ipnn->flags=parms.flags;
1310 +               ipnn->numreaders=0;
1311 +               ipnn->numwriters=0;
1312 +               ipnn->maxports=parms.maxports;
1313 +               atomic_set(&ipnn->msgpool_nelem,0);
1314 +               ipnn->msgpool_size=parms.msgpoolsize;
1315 +               ipnn->proto_private=NULL;
1316 +               init_waitqueue_head(&ipnn->send_wait);
1317 +               err=ipn_protocol_table[ipnn->protocol]->ipn_p_newnet(ipnn);
1318 +               if (err)
1319 +                       goto out_mknod_dput_putmodule;
1320 +               ipn_insert_network(&ipn_network_table[nd.path.dentry->d_inode->i_ino & (IPN_HASH_SIZE-1)],ipnn);
1321 +       } else {
1322 +               /* join an existing network */
1323 +               if (parms.flags & IPN_FLAG_EXCL) {
1324 +                       err=-EEXIST;
1325 +                       goto put_fail;
1326 +               }
1327 +               err = vfs_permission(&nd, MAY_EXEC);
1328 +               if (err)
1329 +                       goto put_fail;
1330 +               err = -ECONNREFUSED;
1331 +               if (!S_ISSOCK(nd.path.dentry->d_inode->i_mode))
1332 +                       goto put_fail;
1333 +               ipnn=ipn_find_network_byinode(nd.path.dentry->d_inode);
1334 +               if (!ipnn || (ipnn->flags & IPN_FLAG_TERMINATED) ||
1335 +                               (ipnn->flags & IPN_FLAG_EXCL))
1336 +                       goto put_fail;
1337 +               list_add_tail(&ipn_node->nodelist,&ipnn->unconnectqueue);
1338 +               ipnn->refcnt++;
1339 +       }
1340 +       if (ipn_node->pbp) {
1341 +               kfree(ipn_node->pbp);
1342 +               ipn_node->pbp=NULL;
1343 +       } 
1344 +       ipn_node->ipn=ipnn;
1345 +       ipn_node->flags |= IPN_NODEFLAG_BOUND;
1346 +       up(&ipn_glob_mutex);
1347 +       return 0;
1349 +put_fail:
1350 +       path_put(&nd.path);
1351 +out:
1352 +       up(&ipn_glob_mutex);
1353 +       return err;
1355 +out_mknod_dput_putmodule:
1356 +       module_put(THIS_MODULE);
1357 +out_mknod_dput_ipnn2:
1358 +       kfree(ipnn->connport);
1359 +out_mknod_dput_ipnn:
1360 +       kmem_cache_free(ipn_network_cache,ipnn);
1361 +out_mknod_dput:
1362 +       dput(dentry);
1363 +out_mknod_unlock:
1364 +       mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
1365 +       path_put(&nd.path);
1366 +out_mknod_parent:
1367 +       if (err==-EEXIST)
1368 +               err=-EADDRINUSE;
1369 +       up(&ipn_glob_mutex);
1370 +       return err;
1373 +/* IPN CONNECT */
1374 +static int ipn_connect(struct socket *sock, struct sockaddr *addr,
1375 +               int addr_len, int flags){
1376 +       struct sockaddr_un *sunaddr=(struct sockaddr_un*)addr;
1377 +       struct ipn_node *ipn_node=((struct ipn_sock *)sock->sk)->node;
1378 +       struct nameidata nd;
1379 +       struct ipn_network *ipnn,*previousipnn;
1380 +       int err=0;
1381 +       int portno;
1383 +       /* the socket cannot be connected twice */
1384 +       if (sock->state != SS_UNCONNECTED) 
1385 +               return EISCONN;
1387 +       if (down_interruptible(&ipn_glob_mutex))
1388 +               return -ERESTARTSYS;
1390 +       if ((previousipnn=ipn_node->ipn) == NULL) { /* unbound */
1391 +               unsigned char mustshutdown=0;
1392 +               err = ipn_mkname(sunaddr, addr_len);
1393 +               if (err < 0)
1394 +                       goto out;
1395 +               addr_len=err;
1396 +               err = path_lookup(sunaddr->sun_path, LOOKUP_FOLLOW, &nd);
1397 +               if (err)
1398 +                       goto out;
1399 +               err = vfs_permission(&nd, MAY_READ);
1400 +               if (err) {
1401 +                       if (err == -EACCES || err == -EROFS)
1402 +                               mustshutdown|=RCV_SHUTDOWN;
1403 +                       else
1404 +                               goto put_fail;
1405 +               }
1406 +               err = vfs_permission(&nd, MAY_WRITE);
1407 +               if (err) {
1408 +                       if (err == -EACCES)
1409 +                               mustshutdown|=SEND_SHUTDOWN;
1410 +                       else
1411 +                               goto put_fail;
1412 +               }
1413 +               mustshutdown |= ipn_node->shutdown;
1414 +               /* if the combination of shutdown and permissions leaves
1415 +                * no abilities, connect returns EACCES */
1416 +               if (mustshutdown == SHUTDOWN_XMASK) {
1417 +                       err=-EACCES;
1418 +                       goto put_fail;
1419 +               } else {
1420 +                       err=0;
1421 +                       ipn_node->shutdown=mustshutdown;
1422 +               }
1423 +               if (!S_ISSOCK(nd.path.dentry->d_inode->i_mode)) {
1424 +                       err = -ECONNREFUSED;
1425 +                       goto put_fail;
1426 +               }
1427 +               ipnn=ipn_find_network_byinode(nd.path.dentry->d_inode);
1428 +               if (!ipnn || (ipnn->flags & IPN_FLAG_TERMINATED)) {
1429 +                       err = -ECONNREFUSED;
1430 +                       goto put_fail;
1431 +               }
1432 +               if (ipn_node->protocol == IPN_ANY)
1433 +                       ipn_node->protocol=ipnn->protocol;
1434 +               else if (ipnn->protocol != ipn_node->protocol) {
1435 +                       err = -EPROTO;
1436 +                       goto put_fail;
1437 +               }
1438 +               path_put(&nd.path);
1439 +               ipn_node->ipn=ipnn;
1440 +       } else
1441 +               ipnn=ipn_node->ipn;
1443 +       if (down_interruptible(&ipnn->ipnn_mutex)) {
1444 +               err=-ERESTARTSYS;
1445 +               goto out;
1446 +       }
1447 +       portno = ipn_protocol_table[ipnn->protocol]->ipn_p_newport(ipn_node);
1448 +       if (portno >= 0 && portno<ipnn->maxports) {
1449 +               sock->state = SS_CONNECTED;
1450 +               ipn_node->portno=portno;
1451 +               ipnn->connport[portno]=ipn_node;
1452 +               if (!(ipn_node->flags & IPN_NODEFLAG_BOUND)) {
1453 +                       ipnn->refcnt++;
1454 +                       list_del(&ipn_node->nodelist);
1455 +               }
1456 +               list_add_tail(&ipn_node->nodelist,&ipnn->connectqueue);
1457 +               ipn_net_update_counters(ipnn,
1458 +                               (ipn_node->shutdown & RCV_SHUTDOWN)?0:1,
1459 +                               (ipn_node->shutdown & SEND_SHUTDOWN)?0:1);
1460 +       } else {
1461 +               ipn_node->ipn=previousipnn; /* undo changes on ipn_node->ipn */
1462 +               err=-EADDRNOTAVAIL;
1463 +       }
1464 +       up(&ipnn->ipnn_mutex);
1465 +       up(&ipn_glob_mutex);
1466 +       return err;
1468 +put_fail:
1469 +       path_put(&nd.path);
1470 +out:
1471 +       up(&ipn_glob_mutex);
1472 +       return err;
1475 +static int ipn_getname(struct socket *sock, struct sockaddr *uaddr, 
1476 +               int *uaddr_len, int peer) {
1477 +       struct ipn_node *ipn_node=((struct ipn_sock *)sock->sk)->node;
1478 +       struct ipn_network *ipnn=ipn_node->ipn;
1479 +       struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
1480 +       int err=0;
1482 +       if (down_interruptible(&ipn_glob_mutex))
1483 +               return -ERESTARTSYS;
1484 +       if (ipnn) {
1485 +               *uaddr_len = ipnn->sunaddr_len;
1486 +               memcpy(sunaddr,&ipnn->sunaddr,*uaddr_len);
1487 +       } else
1488 +               err = -ENOTCONN;
1489 +       up(&ipn_glob_mutex);
1490 +       return err;
1493 +/* IPN POLL */
1494 +static unsigned int ipn_poll(struct file *file, struct socket *sock, 
1495 +               poll_table *wait) {
1496 +       struct ipn_node *ipn_node=((struct ipn_sock *)sock->sk)->node;
1497 +       struct ipn_network *ipnn=ipn_node->ipn;
1498 +       unsigned int mask=0;
1500 +       if (ipnn) {
1501 +               poll_wait(file,&ipn_node->read_wait,wait);
1502 +               if (ipnn->flags & IPN_FLAG_LOSSLESS)
1503 +                       poll_wait(file,&ipnn->send_wait,wait);
1504 +               /* POLLIN if recv succeeds, 
1505 +                * POLL{PRI,RDNORM} if there are {oob,non-oob} messages */
1506 +               if (ipn_node->totmsgcount > 0) mask |= POLLIN;
1507 +               if (!(list_empty(&ipn_node->msgqueue))) mask |= POLLRDNORM;
1508 +               if (!(list_empty(&ipn_node->oobmsgqueue))) mask |= POLLPRI;
1509 +               if ((!(ipnn->flags & IPN_FLAG_LOSSLESS)) |
1510 +                               (atomic_read(&ipnn->msgpool_nelem) < ipnn->msgpool_size))
1511 +                       mask |= POLLOUT | POLLWRNORM;
1512 +       } 
1513 +       return mask;
1516 +/* connect netdev (from ioctl). connect a bound socket to a 
1517 + * network device TAP or GRAB */
1518 +static int ipn_connect_netdev(struct socket *sock,struct ifreq *ifr)
1520 +       int err=0;
1521 +       struct ipn_node *ipn_node=((struct ipn_sock *)sock->sk)->node;
1522 +       struct ipn_network *ipnn=ipn_node->ipn;
1523 +       if (!capable(CAP_NET_ADMIN))
1524 +               return -EPERM;
1525 +       if (sock->state != SS_UNCONNECTED) 
1526 +               return -EISCONN;
1527 +       if (!ipnn)
1528 +               return -ENOTCONN;  /* Maybe we need a different error for "NOT BOUND" */
1529 +       if (down_interruptible(&ipn_glob_mutex))
1530 +               return -ERESTARTSYS;
1531 +       if (down_interruptible(&ipnn->ipnn_mutex)) {
1532 +               up(&ipn_glob_mutex);
1533 +               return -ERESTARTSYS;
1534 +       }
1535 +       ipn_node->dev=ipn_netdev_alloc(ipn_node->net,ifr->ifr_flags,ifr->ifr_name,&err);
1536 +       if (ipn_node->dev) {
1537 +               int portno;
1538 +               portno = ipn_protocol_table[ipnn->protocol]->ipn_p_newport(ipn_node);
1539 +               if (portno >= 0 && portno<ipnn->maxports) {
1540 +                       sock->state = SS_CONNECTED;
1541 +                       ipn_node->portno=portno;
1542 +                       ipn_node->flags |= ifr->ifr_flags & IPN_NODEFLAG_DEVMASK;
1543 +                       ipnn->connport[portno]=ipn_node;
1544 +                       err=ipn_netdev_activate(ipn_node);
1545 +                       if (err) {
1546 +                               sock->state = SS_UNCONNECTED;
1547 +                               ipn_protocol_table[ipnn->protocol]->ipn_p_delport(ipn_node);
1548 +                               ipn_node->dev=NULL;
1549 +                               ipn_node->portno= -1;
1550 +                               ipn_node->flags &= ~IPN_NODEFLAG_DEVMASK;
1551 +                               ipnn->connport[portno]=NULL;
1552 +                       } else  {
1553 +                               ipn_protocol_table[ipnn->protocol]->ipn_p_postnewport(ipn_node);
1554 +                               list_del(&ipn_node->nodelist);
1555 +                               list_add_tail(&ipn_node->nodelist,&ipnn->connectqueue);
1556 +                       }
1557 +               } else {
1558 +                       ipn_netdev_close(ipn_node); 
1559 +                       err=-EADDRNOTAVAIL;
1560 +                       ipn_node->dev=NULL;
1561 +               }
1562 +       } else 
1563 +               err=-EINVAL;
1564 +       up(&ipnn->ipnn_mutex);
1565 +       up(&ipn_glob_mutex);
1566 +       return err;
1569 +/* join a netdev, a socket gets connected to a persistent node
1570 + * not connected to another socket */
1571 +static int ipn_join_netdev(struct socket *sock,struct ifreq *ifr)
1573 +       int err=0;
1574 +       struct net_device *dev;
1575 +       struct ipn_node *ipn_node=((struct ipn_sock *)sock->sk)->node;
1576 +       struct ipn_node *ipn_joined;
1577 +       struct ipn_network *ipnn=ipn_node->ipn;
1578 +       if (sock->state != SS_UNCONNECTED)
1579 +               return -EISCONN;
1580 +       if (down_interruptible(&ipn_glob_mutex))
1581 +               return -ERESTARTSYS;
1582 +       if (down_interruptible(&ipnn->ipnn_mutex)) {
1583 +               up(&ipn_glob_mutex);
1584 +               return -ERESTARTSYS;
1585 +       }
1586 +       dev=__dev_get_by_name(ipn_node->net,ifr->ifr_name);
1587 +       if (!dev) 
1588 +               dev=__dev_get_by_index(ipn_node->net,ifr->ifr_ifindex);
1589 +       if (dev && (ipn_joined=ipn_netdev2node(dev)) != NULL) { /* the interface does exist */
1590 +               int i;
1591 +               for (i=0;i<ipnn->maxports && ipn_joined != ipnn->connport[i] ;i++)
1592 +                       ;
1593 +               if (i < ipnn->maxports) { /* found */
1594 +                       /* ipn_joined is substituted to ipn_node */
1595 +                       ((struct ipn_sock *)sock->sk)->node=ipn_joined;
1596 +                       ipn_joined->flags |= IPN_NODEFLAG_INUSE;
1597 +                       ipnn->refcnt--;
1598 +                       kmem_cache_free(ipn_node_cache,ipn_node);
1599 +               } else
1600 +                       err=-EPERM;
1601 +       } else
1602 +               err=-EADDRNOTAVAIL;
1603 +       up(&ipnn->ipnn_mutex);
1604 +       up(&ipn_glob_mutex);
1605 +       return err;
1608 +/* set persistence of a node looking for it by interface name
1609 + * (it is for sysadm, to close network interfaces)*/
1610 +static int ipn_setpersist_netdev(struct ifreq *ifr, int value)
1612 +       struct net_device *dev;
1613 +       struct ipn_node *ipn_node;
1614 +       int err=0;
1615 +       if (!capable(CAP_NET_ADMIN))
1616 +               return -EPERM;
1617 +       if (down_interruptible(&ipn_glob_mutex))
1618 +               return -ERESTARTSYS;
1619 +       dev=__dev_get_by_name(&init_net,ifr->ifr_name);
1620 +       if (!dev)
1621 +               dev=__dev_get_by_index(&init_net,ifr->ifr_ifindex);
1622 +       if (dev && (ipn_node=ipn_netdev2node(dev)) != NULL) 
1623 +               _ipn_setpersist(ipn_node,value);
1624 +       else
1625 +               err=-EADDRNOTAVAIL;
1626 +       up(&ipn_glob_mutex);
1627 +       return err;
1630 +/* IPN IOCTL */
1631 +static int ipn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) {
1632 +       struct ipn_node *ipn_node=((struct ipn_sock *)sock->sk)->node;
1633 +       struct ipn_network *ipnn=ipn_node->ipn;
1634 +       void __user* argp = (void __user*)arg;
1635 +       struct ifreq ifr;
1637 +       if (ipn_node->shutdown == SHUTDOWN_XMASK)
1638 +               return -ECONNRESET;
1640 +       /* get arguments */
1641 +       switch (cmd) {
1642 +               case IPN_CHECK:
1643 +                       return IPN_CHECK;
1644 +               case IPN_SETPERSIST_NETDEV:
1645 +               case IPN_CLRPERSIST_NETDEV:
1646 +               case IPN_CONN_NETDEV:
1647 +               case IPN_JOIN_NETDEV:
1648 +               case SIOCSIFHWADDR:
1649 +                       if (copy_from_user(&ifr, argp, sizeof ifr))
1650 +                               return -EFAULT;
1651 +                       ifr.ifr_name[IFNAMSIZ-1] = '\0';
1652 +       }
1654 +       /* actions for unconnected and unbound sockets */
1655 +       switch (cmd) {
1656 +               case IPN_SETPERSIST_NETDEV:
1657 +                       return ipn_setpersist_netdev(&ifr,1);
1658 +               case IPN_CLRPERSIST_NETDEV:
1659 +                       return ipn_setpersist_netdev(&ifr,0);
1660 +               case SIOCSIFHWADDR:
1661 +                       if (capable(CAP_NET_ADMIN))
1662 +                               return -EPERM;
1663 +                       if (ipn_node->dev && (ipn_node->flags &IPN_NODEFLAG_TAP))
1664 +                               return dev_set_mac_address(ipn_node->dev, &ifr.ifr_hwaddr);
1665 +                       else
1666 +                               return -EADDRNOTAVAIL;
1667 +       }
1668 +       if (ipnn == NULL || (ipnn->flags & IPN_FLAG_TERMINATED))
1669 +               return -ENOTCONN;
1670 +       /* actions for connected or bound sockets */
1671 +       switch (cmd) {
1672 +               case IPN_CONN_NETDEV:
1673 +                       return ipn_connect_netdev(sock,&ifr);
1674 +               case IPN_JOIN_NETDEV:
1675 +                       return ipn_join_netdev(sock,&ifr);
1676 +               case IPN_SETPERSIST:
1677 +                       return ipn_setpersist(ipn_node,arg);
1678 +               default:
1679 +                       if (ipnn) {
1680 +                               int rv;
1681 +                               if (down_interruptible(&ipnn->ipnn_mutex))
1682 +                                       return -ERESTARTSYS;
1683 +                               rv=ipn_protocol_table[ipn_node->protocol]->ipn_p_ioctl(ipn_node,cmd,arg);
1684 +                               up(&ipnn->ipnn_mutex);
1685 +                               return rv;
1686 +                       } else
1687 +                               return -EOPNOTSUPP;
1688 +       }
1691 +/* shutdown: close socket for input or for output.
1692 + * shutdown can be called prior to connect and it is not reversible */
1693 +static int ipn_shutdown(struct socket *sock, int mode) {
1694 +       struct ipn_node *ipn_node=((struct ipn_sock *)sock->sk)->node;
1695 +       struct ipn_network *ipnn=ipn_node->ipn;
1696 +       int oldshutdown=ipn_node->shutdown;
1697 +       mode = (mode+1)&(RCV_SHUTDOWN|SEND_SHUTDOWN);
1699 +       ipn_node->shutdown |= mode;
1701 +       if(ipnn) {
1702 +               if (down_interruptible(&ipnn->ipnn_mutex)) {
1703 +                       ipn_node->shutdown = oldshutdown;
1704 +                       return -ERESTARTSYS;
1705 +               }
1706 +               oldshutdown=ipn_node->shutdown-oldshutdown;
1707 +               if (sock->state == SS_CONNECTED && oldshutdown) {
1708 +                       ipn_net_update_counters(ipnn,
1709 +                                       (ipn_node->shutdown & RCV_SHUTDOWN)?0:-1,
1710 +                                       (ipn_node->shutdown & SEND_SHUTDOWN)?0:-1);
1711 +               }
1713 +               /* if recv channel has been shut down, flush the recv queue */
1714 +               if ((ipn_node->shutdown & RCV_SHUTDOWN))
1715 +                       ipn_flush_recvqueue(ipn_node);
1716 +               up(&ipnn->ipnn_mutex);
1717 +       }
1718 +       return 0;
1721 +/* injectmsg: a new message is entering the ipn network.
1722 + * injectmsg gets called by send and by the grab/tap node */
1723 +int ipn_proto_injectmsg(struct ipn_node *from, struct msgpool_item *msg)
1725 +       struct ipn_network *ipnn=from->ipn;
1726 +       int err=0;
1727 +       if (down_interruptible(&ipnn->ipnn_mutex))
1728 +               err=-ERESTARTSYS;
1729 +       else {
1730 +               ipn_protocol_table[ipnn->protocol]->ipn_p_handlemsg(from, msg);
1731 +               up(&ipnn->ipnn_mutex);
1732 +       }
1733 +       return err;
1736 +/* SEND MSG */
1737 +static int ipn_sendmsg(struct kiocb *kiocb, struct socket *sock,
1738 +               struct msghdr *msg, size_t len) {
1739 +       struct ipn_node *ipn_node=((struct ipn_sock *)sock->sk)->node;
1740 +       struct ipn_network *ipnn=ipn_node->ipn;
1741 +       struct msgpool_item *newmsg;
1742 +       int err=0;
1744 +       if (unlikely(sock->state != SS_CONNECTED)) 
1745 +                       return -ENOTCONN;
1746 +       if (unlikely(ipn_node->shutdown & SEND_SHUTDOWN)) {
1747 +               if (ipn_node->shutdown == SHUTDOWN_XMASK)
1748 +                       return -ECONNRESET;
1749 +               else
1750 +                       return -EPIPE;
1751 +       }
1752 +       if (len > ipnn->mtu)
1753 +               return -EOVERFLOW;
1754 +       newmsg=ipn_msgpool_alloc_locking(ipnn);
1755 +       if (!newmsg)
1756 +               return -ENOMEM;
1757 +       newmsg->len=len;
1758 +       err=memcpy_fromiovec(newmsg->data, msg->msg_iov, len);
1759 +       if (!err) 
1760 +               ipn_proto_injectmsg(ipn_node, newmsg);
1761 +       ipn_msgpool_put(newmsg,ipnn);
1762 +       return err;
1765 +/* enqueue an oob message. "to" is the destination */
1766 +void ipn_proto_oobsendmsg(struct ipn_node *to, struct msgpool_item *msg)
1768 +       if (to) {
1769 +               if (!to->dev) { /* no oob to netdev */
1770 +                       struct msgitem *msgitem;
1771 +                       struct ipn_network *ipnn=to->ipn;
1772 +                       spin_lock(&to->msglock);
1773 +                       if ((to->shutdown & RCV_SHUTDOWN_NO_OOB) == 0 && 
1774 +                                       (ipnn->flags & IPN_FLAG_LOSSLESS ||
1775 +                                        to->oobmsgcount < ipnn->msgpool_size)) {
1776 +                               if ((msgitem=kmem_cache_alloc(ipn_msgitem_cache,GFP_KERNEL))!=NULL) {
1777 +                                       msgitem->msg=msg;
1778 +                                       to->totmsgcount++;
1779 +                                       to->oobmsgcount++;
1780 +                                       list_add_tail(&msgitem->list, &to->oobmsgqueue);
1781 +                                       ipn_msgpool_hold(msg);
1782 +                               }
1783 +                       }
1784 +                       spin_unlock(&to->msglock);
1785 +                       wake_up_interruptible(&to->read_wait);
1786 +               }
1787 +       }
1790 +/* ipn_proto_sendmsg is called by protocol implementation to enqueue a 
1791 + * for a destination (to).*/
1792 +void ipn_proto_sendmsg(struct ipn_node *to, struct msgpool_item *msg)
1794 +       if (to) {
1795 +               if (to->dev) {
1796 +                       ipn_netdev_sendmsg(to,msg);
1797 +               } else {
1798 +                       /* socket send */
1799 +                       struct msgitem *msgitem;
1800 +                       struct ipn_network *ipnn=to->ipn;
1801 +                       spin_lock(&to->msglock);
1802 +                       if (likely((to->shutdown & RCV_SHUTDOWN)==0)) {
1803 +                               /*if (unlikely((ipnn->flags & IPN_FLAG_LOSSLESS) == 0 ||
1804 +                                                                   to->totmsgcount >= ipnn->msgpool_size))
1805 +                                       yield();*/
1806 +                               if (likely(ipnn->flags & IPN_FLAG_LOSSLESS ||
1807 +                                               to->totmsgcount < ipnn->msgpool_size)) { 
1808 +                                       if ((msgitem=kmem_cache_alloc(ipn_msgitem_cache,GFP_KERNEL))!=NULL) {
1809 +                                               msgitem->msg=msg;
1810 +                                               to->totmsgcount++;
1811 +                                               list_add_tail(&msgitem->list, &to->msgqueue);
1812 +                                               ipn_msgpool_hold(msg);
1813 +                                       }
1814 +                               }
1815 +                       }
1816 +                       spin_unlock(&to->msglock);
1817 +                       wake_up_interruptible(&to->read_wait);
1818 +               }
1819 +       }
1822 +/* IPN RECV */
1823 +static int ipn_recvmsg(struct kiocb *kiocb, struct socket *sock,
1824 +               struct msghdr *msg, size_t len, int flags) {
1825 +       struct ipn_node *ipn_node=((struct ipn_sock *)sock->sk)->node;
1826 +       struct ipn_network *ipnn=ipn_node->ipn;
1827 +       struct msgitem *msgitem;
1828 +       struct msgpool_item *currmsg;
1830 +       if (unlikely(sock->state != SS_CONNECTED)) 
1831 +                       return -ENOTCONN;
1833 +       if (unlikely((ipn_node->shutdown & XRCV_SHUTDOWN) == XRCV_SHUTDOWN)) {
1834 +               if (ipn_node->shutdown == SHUTDOWN_XMASK) /*EOF, nothing can be read*/
1835 +                       return 0;
1836 +               else
1837 +                       return -EPIPE; /*trying to read on a write only node */
1838 +       }
1840 +       /* wait for a message */
1841 +       spin_lock(&ipn_node->msglock);
1842 +       while (ipn_node->totmsgcount == 0) {
1843 +               spin_unlock(&ipn_node->msglock);
1844 +               if (wait_event_interruptible(ipn_node->read_wait,
1845 +                                       !(ipn_node->totmsgcount == 0)))
1846 +                       return -ERESTARTSYS;
1847 +               spin_lock(&ipn_node->msglock);
1848 +       }
1849 +       /* oob gets delivered first. oob are rare */
1850 +       if (likely(list_empty(&ipn_node->oobmsgqueue)))
1851 +               msgitem=list_first_entry(&ipn_node->msgqueue, struct msgitem, list);
1852 +       else {
1853 +               msgitem=list_first_entry(&ipn_node->oobmsgqueue, struct msgitem, list);
1854 +               msg->msg_flags |= MSG_OOB;
1855 +               ipn_node->oobmsgcount--;
1856 +       }
1857 +       list_del(&msgitem->list);
1858 +       ipn_node->totmsgcount--;
1859 +       spin_unlock(&ipn_node->msglock);
1860 +       currmsg=msgitem->msg;
1861 +       if (currmsg->len < len)
1862 +               len=currmsg->len;
1863 +       memcpy_toiovec(msg->msg_iov, currmsg->data, len);
1864 +       ipn_msgpool_put(currmsg,ipnn);
1865 +       kmem_cache_free(ipn_msgitem_cache,msgitem);
1867 +       return len;
1870 +/* resize a network: change the # of communication ports (connport) */
1871 +static int ipn_netresize(struct ipn_network *ipnn,int newsize)
1873 +       int oldsize,min;
1874 +       struct ipn_node **newconnport;
1875 +       struct ipn_node **oldconnport;
1876 +       int err;
1877 +       if (down_interruptible(&ipnn->ipnn_mutex))
1878 +                       return -ERESTARTSYS;
1879 +       oldsize=ipnn->maxports;
1880 +       if (newsize == oldsize) {
1881 +               up(&ipnn->ipnn_mutex);
1882 +               return 0;
1883 +       }
1884 +       min=oldsize;
1885 +       /* shrink a network. all the ports we are going to eliminate
1886 +        * must be unused! */
1887 +       if (newsize < oldsize) {
1888 +               int i;
1889 +               for (i=newsize; i<oldsize; i++)
1890 +                       if (ipnn->connport[i]) {
1891 +                               up(&ipnn->ipnn_mutex);
1892 +                               return -EADDRINUSE;
1893 +                       }
1894 +               min=newsize;
1895 +       }
1896 +       oldconnport=ipnn->connport;
1897 +       /* allocate the new connport array and copy the old one */
1898 +       newconnport=kzalloc(newsize * sizeof(struct ipn_node *),GFP_KERNEL);
1899 +       if (!newconnport) {
1900 +               up(&ipnn->ipnn_mutex);
1901 +               return -ENOMEM;
1902 +       }
1903 +       memcpy(newconnport,oldconnport,min * sizeof(struct ipn_node *));
1904 +       ipnn->connport=newconnport;
1905 +       ipnn->maxports=newsize;
1906 +       /* notify the protocol that the netowrk has been resized */
1907 +       err=ipn_protocol_table[ipnn->protocol]->ipn_p_resizenet(ipnn,oldsize,newsize);
1908 +       if (err) {
1909 +               /* roll back if the resize operation failed for the protocol */
1910 +               ipnn->connport=oldconnport;
1911 +               ipnn->maxports=oldsize;
1912 +               kfree(newconnport);
1913 +       } else 
1914 +               /* successful mission, network resized */
1915 +               kfree(oldconnport);
1916 +       up(&ipnn->ipnn_mutex);
1917 +       return err;
1920 +/* IPN SETSOCKOPT */
1921 +static int ipn_setsockopt(struct socket *sock, int level, int optname,
1922 +               char __user *optval, int optlen) {
1923 +       struct ipn_node *ipn_node=((struct ipn_sock *)sock->sk)->node;
1924 +       struct ipn_network *ipnn=ipn_node->ipn;
1926 +       if (ipn_node->shutdown == SHUTDOWN_XMASK)
1927 +               return -ECONNRESET;
1928 +       if (level != 0 && level != ipn_node->protocol+1)
1929 +               return -EPROTONOSUPPORT;
1930 +       if (level > 0) {
1931 +               /* protocol specific sockopt */
1932 +               if (ipnn) {
1933 +                       int rv;
1934 +                       if (down_interruptible(&ipnn->ipnn_mutex))
1935 +                               return -ERESTARTSYS;
1936 +                       rv=ipn_protocol_table[ipn_node->protocol]->ipn_p_setsockopt(ipn_node,optname,optval,optlen);
1937 +                       up(&ipnn->ipnn_mutex);
1938 +                       return rv;
1939 +               } else
1940 +                       return -EOPNOTSUPP;
1941 +       } else {
1942 +               if (optname == IPN_SO_DESCR) {
1943 +                       if (optlen > IPN_DESCRLEN)
1944 +                               return -EINVAL;
1945 +                       else {
1946 +                               memset(ipn_node->descr,0,IPN_DESCRLEN);
1947 +                               if (copy_from_user(ipn_node->descr,optval,optlen))
1948 +                                       ipn_node->descr[0]=0;
1949 +                               else
1950 +                                       ipn_node->descr[optlen-1]=0;
1951 +                               return 0;
1952 +                       }
1953 +               } else {
1954 +                       if (optlen < sizeof(int))
1955 +                               return -EINVAL;
1956 +                       else if ((optname & IPN_SO_PREBIND) && (ipnn != NULL))
1957 +                               return -EISCONN;
1958 +                       else {
1959 +                               int val;
1960 +                               get_user(val, (int __user *) optval);
1961 +                               if ((optname & IPN_SO_PREBIND) && !ipn_node->pbp) {
1962 +                                       struct pre_bind_parms std=STD_BIND_PARMS;
1963 +                                       ipn_node->pbp=kzalloc(sizeof(struct pre_bind_parms),GFP_KERNEL);
1964 +                                       if (!ipn_node->pbp)
1965 +                                               return -ENOMEM;
1966 +                                       *(ipn_node->pbp)=std;
1967 +                               }
1968 +                               switch (optname) {
1969 +                                       case IPN_SO_PORT:
1970 +                                               if (sock->state == SS_UNCONNECTED)
1971 +                                                       ipn_node->portno=val;
1972 +                                               else
1973 +                                                       return -EISCONN;
1974 +                                               break;
1975 +                                       case IPN_SO_CHANGE_NUMNODES:
1976 +                                               if ((ipn_node->flags & IPN_NODEFLAG_BOUND)!=0) {
1977 +                                                       if (val <= 0)
1978 +                                                               return -EINVAL;
1979 +                                                       else
1980 +                                                               return ipn_netresize(ipnn,val);
1981 +                                               } else
1982 +                                                       val=-ENOTCONN;
1983 +                                               break;
1984 +                                       case IPN_SO_WANT_OOB_NUMNODES:
1985 +                                               if (val)
1986 +                                                       ipn_node->flags |= IPN_NODEFLAG_OOB_NUMNODES;
1987 +                                               else
1988 +                                                       ipn_node->flags &= ~IPN_NODEFLAG_OOB_NUMNODES;
1989 +                                               break;
1990 +                                       case IPN_SO_HANDLE_OOB:
1991 +                                               if (val)
1992 +                                                       ipn_node->shutdown &= ~RCV_SHUTDOWN_NO_OOB;
1993 +                                               else
1994 +                                                       ipn_node->shutdown |= RCV_SHUTDOWN_NO_OOB;
1995 +                                               break;
1996 +                                       case IPN_SO_MTU:
1997 +                                               if (val <= 0)
1998 +                                                       return -EINVAL;
1999 +                                               else
2000 +                                                       ipn_node->pbp->mtu=val;
2001 +                                               break;
2002 +                                       case IPN_SO_NUMNODES:
2003 +                                               if (val <= 0)
2004 +                                                       return -EINVAL;
2005 +                                               else
2006 +                                                       ipn_node->pbp->maxports=val;
2007 +                                               break;
2008 +                                       case IPN_SO_MSGPOOLSIZE:
2009 +                                               if (val <= 0)
2010 +                                                       return -EINVAL;
2011 +                                               else
2012 +                                                       ipn_node->pbp->msgpoolsize=val;
2013 +                                               break;
2014 +                                       case IPN_SO_FLAGS:
2015 +                                               ipn_node->pbp->flags=val;
2016 +                                               break;
2017 +                                       case IPN_SO_MODE:
2018 +                                               ipn_node->pbp->mode=val;
2019 +                                               break;
2020 +                               }
2021 +                               return 0;
2022 +                       }
2023 +               }
2024 +       }
2027 +/* IPN GETSOCKOPT */
2028 +static int ipn_getsockopt(struct socket *sock, int level, int optname,
2029 +               char __user *optval, int __user *optlen) {
2030 +       struct ipn_node *ipn_node=((struct ipn_sock *)sock->sk)->node;
2031 +       struct ipn_network *ipnn=ipn_node->ipn;
2032 +       int len;
2034 +       if (ipn_node->shutdown == SHUTDOWN_XMASK)
2035 +               return -ECONNRESET;
2036 +       if (level != 0 && level != ipn_node->protocol+1)
2037 +               return -EPROTONOSUPPORT;
2038 +       if (level > 0) {
2039 +               if (ipnn) {
2040 +                       int rv;
2041 +                       /* protocol specific sockopt */
2042 +                       if (down_interruptible(&ipnn->ipnn_mutex))
2043 +                               return -ERESTARTSYS;
2044 +                       rv=ipn_protocol_table[ipn_node->protocol]->ipn_p_getsockopt(ipn_node,optname,optval,optlen);
2045 +                       up(&ipnn->ipnn_mutex);
2046 +                       return rv;
2047 +               } else
2048 +                       return -EOPNOTSUPP;
2049 +       } else {
2050 +               if (get_user(len, optlen))
2051 +                       return -EFAULT;
2052 +               if (optname == IPN_SO_DESCR) {
2053 +                       if (len < IPN_DESCRLEN)
2054 +                               return -EINVAL;
2055 +                       else {
2056 +                               if (len > IPN_DESCRLEN)
2057 +                                       len=IPN_DESCRLEN;
2058 +                               if(put_user(len, optlen))
2059 +                                       return -EFAULT;
2060 +                               if(copy_to_user(optval,ipn_node->descr,len))
2061 +                                       return -EFAULT;
2062 +                               return 0;
2063 +                       }
2064 +               } else {
2065 +                       int val=-2;
2066 +                       switch (optname) {
2067 +                               case IPN_SO_PORT:
2068 +                                       val=ipn_node->portno;
2069 +                                       break;
2070 +                               case IPN_SO_MTU:
2071 +                                       if (ipnn)
2072 +                                               val=ipnn->mtu;
2073 +                                       else if (ipn_node->pbp)
2074 +                                               val=ipn_node->pbp->mtu;
2075 +                                       break;
2076 +                               case IPN_SO_NUMNODES:
2077 +                                       if (ipnn)
2078 +                                               val=ipnn->maxports;
2079 +                                       else if (ipn_node->pbp)
2080 +                                               val=ipn_node->pbp->maxports;
2081 +                                       break;
2082 +                               case IPN_SO_MSGPOOLSIZE:
2083 +                                       if (ipnn)
2084 +                                               val=ipnn->msgpool_size;
2085 +                                       else if (ipn_node->pbp)
2086 +                                               val=ipn_node->pbp->msgpoolsize;
2087 +                                       break;
2088 +                               case IPN_SO_FLAGS:
2089 +                                       if (ipnn)
2090 +                                               val=ipnn->flags;
2091 +                                       else if (ipn_node->pbp)
2092 +                                               val=ipn_node->pbp->flags;
2093 +                                       break;
2094 +                               case IPN_SO_MODE:
2095 +                                       if (ipnn)
2096 +                                               val=-1;
2097 +                                       else if (ipn_node->pbp)
2098 +                                               val=ipn_node->pbp->mode;
2099 +                                       break;
2100 +                       }
2101 +                       if (val < -1)
2102 +                               return -EINVAL;
2103 +                       else {
2104 +                               if (len < sizeof(int))
2105 +                                       return -EOVERFLOW;
2106 +                               else {
2107 +                                       len = sizeof(int);
2108 +                                       if(put_user(len, optlen))
2109 +                                               return -EFAULT;
2110 +                                       if(copy_to_user(optval,&val,len))
2111 +                                               return -EFAULT;
2112 +                                       return 0;
2113 +                               }
2114 +                       }
2115 +               }
2116 +       }
2119 +/* BROADCAST/HUB implementation */
2121 +static int ipn_bcast_newport(struct ipn_node *newport) {
2122 +       struct ipn_network *ipnn=newport->ipn;
2123 +       int i;
2124 +       for (i=0;i<ipnn->maxports;i++) {
2125 +               if (ipnn->connport[i] == NULL) 
2126 +                       return i;
2127 +       }
2128 +       return -1;
2131 +static int ipn_bcast_handlemsg(struct ipn_node *from, 
2132 +               struct msgpool_item *msgitem){
2133 +       struct ipn_network *ipnn=from->ipn;
2135 +       struct ipn_node *ipn_node;
2136 +       list_for_each_entry(ipn_node, &ipnn->connectqueue, nodelist) {
2137 +               if (ipn_node != from)
2138 +                       ipn_proto_sendmsg(ipn_node,msgitem);
2139 +       }
2140 +       return 0;
2143 +static void ipn_null_delport(struct ipn_node *oldport) {}
2144 +static void ipn_null_postnewport(struct ipn_node *newport) {}
2145 +static  void ipn_null_predelport(struct ipn_node *oldport) {}
2146 +static int ipn_null_newnet(struct ipn_network *newnet) {return 0;}
2147 +static int ipn_null_resizenet(struct ipn_network *net,int oldsize,int newsize) {
2148 +       return 0;}
2149 +static void ipn_null_delnet(struct ipn_network *oldnet) {}
2150 +static int ipn_null_setsockopt(struct ipn_node *port,int optname,
2151 +               char __user *optval, int optlen) {return -EOPNOTSUPP;}
2152 +static int ipn_null_getsockopt(struct ipn_node *port,int optname,
2153 +               char __user *optval, int *optlen) {return -EOPNOTSUPP;}
2154 +static int ipn_null_ioctl(struct ipn_node *port,unsigned int request,
2155 +               unsigned long arg) {return -EOPNOTSUPP;}
2157 +/* Protocol Registration/deregisteration */
2159 +void ipn_init_protocol(struct ipn_protocol *p)
2161 +       if (p->ipn_p_delport == NULL) p->ipn_p_delport=ipn_null_delport;
2162 +       if (p->ipn_p_postnewport == NULL) p->ipn_p_postnewport=ipn_null_postnewport;
2163 +       if (p->ipn_p_predelport == NULL) p->ipn_p_predelport=ipn_null_predelport;
2164 +       if (p->ipn_p_newnet == NULL) p->ipn_p_newnet=ipn_null_newnet;
2165 +       if (p->ipn_p_resizenet == NULL) p->ipn_p_resizenet=ipn_null_resizenet;
2166 +       if (p->ipn_p_delnet == NULL) p->ipn_p_delnet=ipn_null_delnet;
2167 +       if (p->ipn_p_setsockopt == NULL) p->ipn_p_setsockopt=ipn_null_setsockopt;
2168 +       if (p->ipn_p_getsockopt == NULL) p->ipn_p_getsockopt=ipn_null_getsockopt;
2169 +       if (p->ipn_p_ioctl == NULL) p->ipn_p_ioctl=ipn_null_ioctl;
2172 +int ipn_proto_register(int protocol,struct ipn_protocol *ipn_service)
2174 +       int rv=0;
2175 +       if (ipn_service->ipn_p_newport == NULL ||
2176 +                       ipn_service->ipn_p_handlemsg == NULL)
2177 +               return -EINVAL;
2178 +       ipn_init_protocol(ipn_service);
2179 +       if (down_interruptible(&ipn_glob_mutex)) 
2180 +               return -ERESTARTSYS;
2181 +       if (protocol > 1 && protocol <= IPN_MAX_PROTO) {
2182 +               protocol--;
2183 +               if (ipn_protocol_table[protocol])
2184 +                       rv= -EEXIST;
2185 +               else {
2186 +                       ipn_service->refcnt=0;
2187 +                       ipn_protocol_table[protocol]=ipn_service;
2188 +                       printk(KERN_INFO "IPN: Registered protocol %d\n",protocol+1);
2189 +               }
2190 +       } else
2191 +               rv= -EINVAL;
2192 +       up(&ipn_glob_mutex);
2193 +       return rv;
2196 +int ipn_proto_deregister(int protocol) 
2198 +       int rv=0;
2199 +       if (down_interruptible(&ipn_glob_mutex)) 
2200 +               return -ERESTARTSYS;
2201 +       if (protocol > 1 && protocol <= IPN_MAX_PROTO) {
2202 +               protocol--;
2203 +               if (ipn_protocol_table[protocol]) {
2204 +                       if (ipn_protocol_table[protocol]->refcnt == 0) {
2205 +                               ipn_protocol_table[protocol]=NULL;
2206 +                               printk(KERN_INFO "IPN: Unregistered protocol %d\n",protocol+1);
2207 +                       } else
2208 +                               rv=-EADDRINUSE;
2209 +               } else 
2210 +                       rv= -ENOENT;
2211 +       } else
2212 +               rv= -EINVAL;
2213 +       up(&ipn_glob_mutex);
2214 +       return rv;
2217 +/* MAIN SECTION */
2218 +/* Module constructor/destructor */
2219 +static struct net_proto_family ipn_family_ops = {
2220 +       .family = PF_IPN,
2221 +       .create = ipn_create,
2222 +       .owner  = THIS_MODULE,
2225 +/* IPN constructor */
2226 +static int ipn_init(void)
2228 +       int rc;
2230 +       ipn_init_protocol(&ipn_bcast);
2231 +       ipn_network_cache=kmem_cache_create("ipn_network",sizeof(struct ipn_network),0,0,NULL);
2232 +       if (!ipn_network_cache) {
2233 +               printk(KERN_CRIT "%s: Cannot create ipn_network SLAB cache!\n",
2234 +                               __FUNCTION__);
2235 +               rc=-ENOMEM;
2236 +               goto out;
2237 +       }
2239 +       ipn_node_cache=kmem_cache_create("ipn_node",sizeof(struct ipn_node),0,0,NULL);
2240 +       if (!ipn_node_cache) {
2241 +               printk(KERN_CRIT "%s: Cannot create ipn_node SLAB cache!\n",
2242 +                               __FUNCTION__);
2243 +               rc=-ENOMEM;
2244 +               goto out_net;
2245 +       }
2247 +       ipn_msgitem_cache=kmem_cache_create("ipn_msgitem",sizeof(struct msgitem),0,0,NULL);
2248 +       if (!ipn_msgitem_cache) {
2249 +               printk(KERN_CRIT "%s: Cannot create ipn_msgitem SLAB cache!\n",
2250 +                               __FUNCTION__);
2251 +               rc=-ENOMEM;
2252 +               goto out_net_node;
2253 +       }
2255 +       rc=ipn_msgbuf_init();
2256 +       if (rc != 0) {
2257 +               printk(KERN_CRIT "%s: Cannot create ipn_msgbuf SLAB cache\n",
2258 +                               __FUNCTION__);
2259 +               goto out_net_node_msg;
2260 +       }
2262 +       rc=proto_register(&ipn_proto,1);
2263 +       if (rc != 0) {
2264 +               printk(KERN_CRIT "%s: Cannot register the protocol!\n",
2265 +                               __FUNCTION__);
2266 +               goto out_net_node_msg_msgbuf;
2267 +       }
2269 +       sock_register(&ipn_family_ops);
2270 +       ipn_netdev_init();
2271 +       printk(KERN_INFO "IPN: Virtual Square Project, University of Bologna 2007\n");
2272 +       return 0;
2274 +out_net_node_msg_msgbuf:
2275 +       ipn_msgbuf_fini();
2276 +out_net_node_msg:
2277 +       kmem_cache_destroy(ipn_msgitem_cache);
2278 +out_net_node:
2279 +       kmem_cache_destroy(ipn_node_cache);
2280 +out_net:
2281 +       kmem_cache_destroy(ipn_network_cache);
2282 +out:
2283 +       return rc;
2286 +/* IPN destructor */
2287 +static void ipn_exit(void)
2289 +       ipn_netdev_fini();
2290 +       if (ipn_msgitem_cache)
2291 +               kmem_cache_destroy(ipn_msgitem_cache);
2292 +       if (ipn_node_cache)
2293 +               kmem_cache_destroy(ipn_node_cache);
2294 +       if (ipn_network_cache)
2295 +               kmem_cache_destroy(ipn_network_cache);
2296 +       ipn_msgbuf_fini();
2297 +       sock_unregister(PF_IPN);
2298 +       proto_unregister(&ipn_proto);
2299 +       printk(KERN_INFO "IPN removed\n");
2302 +module_init(ipn_init);
2303 +module_exit(ipn_exit);
2305 +EXPORT_SYMBOL_GPL(ipn_proto_register);
2306 +EXPORT_SYMBOL_GPL(ipn_proto_deregister);
2307 +EXPORT_SYMBOL_GPL(ipn_proto_sendmsg);
2308 +EXPORT_SYMBOL_GPL(ipn_proto_oobsendmsg);
2309 +EXPORT_SYMBOL_GPL(ipn_msgpool_alloc);
2310 +EXPORT_SYMBOL_GPL(ipn_msgpool_put);
2311 diff -Naur linux-2.6.28.2/net/ipn/ipn_msgbuf.c linux-2.6.28.2-ipn/net/ipn/ipn_msgbuf.c
2312 --- linux-2.6.28.2/net/ipn/ipn_msgbuf.c 1970-01-01 01:00:00.000000000 +0100
2313 +++ linux-2.6.28.2-ipn/net/ipn/ipn_msgbuf.c     2009-02-01 13:30:09.000000000 +0100
2314 @@ -0,0 +1,108 @@
2316 + * Inter process networking (virtual distributed ethernet) module
2317 + * management of ipn_msgbuf (one slab for each MTU)
2318 + *  (part of the View-OS project: wiki.virtualsquare.org) 
2319 + *
2320 + * N.B. all these functions need global locking! (ipn_glob_lock)
2321 + *
2322 + * Copyright (C) 2007   Renzo Davoli (renzo@cs.unibo.it)
2323 + *
2324 + *  This program is free software; you can redistribute it and/or modify
2325 + *  it under the terms of the GNU General Public License as published by
2326 + *  the Free Software Foundation; either version 2 of the License, or
2327 + *  (at your option) any later version.
2328 + *
2329 + *  Due to this file being licensed under the GPL there is controversy over
2330 + *  whether this permits you to write a module that #includes this file
2331 + *  without placing your module under the GPL.  Please consult a lawyer for
2332 + *  advice before doing this.
2333 + *
2334 + * WARNING: THIS CODE IS ALREADY EXPERIMENTAL
2335 + *
2336 + */
2338 +#include <linux/init.h>
2339 +#include <linux/module.h>
2341 +#include <net/af_ipn.h>
2342 +#include "ipn_netdev.h"
2344 +struct ipn_msgbuf {
2345 +       struct list_head list;
2346 +       int mtu;
2347 +       int refcnt;
2348 +       char cachename[12];
2349 +       struct kmem_cache *cache;
2352 +static LIST_HEAD(ipn_msgbufh);
2353 +static struct kmem_cache *ipn_msgbuf_cache;
2355 +/* get a kmem_cache pointer for a given mtu.
2356 + * it is a cache for struct msgpool_item elements (the latter field of
2357 + * the struct, i.e. the payload, has variable length depending on the mtu)
2358 + * if it exists already a cache with the given mtu, ipn_msgbuf_get creates
2359 + * one more reference for that cache, otherwise a new one is created.
2360 + */
2361 +struct kmem_cache *ipn_msgbuf_get(int mtu)
2363 +       struct ipn_msgbuf *ipn_msgbuf;
2364 +       list_for_each_entry(ipn_msgbuf, &ipn_msgbufh, list) {
2365 +               if (mtu == ipn_msgbuf->mtu) {
2366 +                       ipn_msgbuf->refcnt++;
2367 +                       return ipn_msgbuf->cache;
2368 +               }
2369 +       }
2370 +       ipn_msgbuf=kmem_cache_alloc(ipn_msgbuf_cache,GFP_KERNEL);
2371 +       if (ipn_msgbuf == NULL)
2372 +               return NULL;
2373 +       else {
2374 +               ipn_msgbuf->mtu=mtu;
2375 +               ipn_msgbuf->refcnt=1;
2376 +               snprintf(ipn_msgbuf->cachename,12,"ipn%d",mtu);
2377 +               ipn_msgbuf->cache=kmem_cache_create(ipn_msgbuf->cachename,sizeof(struct msgpool_item)+mtu,0,0,NULL);
2378 +               list_add_tail(&ipn_msgbuf->list,&ipn_msgbufh);
2379 +               return ipn_msgbuf->cache;
2380 +       }
2383 +/* release a reference of a msgbuf cache (a network with a given mtu
2384 + * is terminating).
2385 + * the last reference for a given mtu releases the slub*/
2386 +void ipn_msgbuf_put(struct kmem_cache *cache)
2388 +       struct ipn_msgbuf *ipn_msgbuf;
2389 +       list_for_each_entry(ipn_msgbuf, &ipn_msgbufh, list) {
2390 +               if (ipn_msgbuf->cache == cache) {
2391 +                       ipn_msgbuf->refcnt--;
2392 +                       if (ipn_msgbuf->refcnt == 0) {
2393 +                               kmem_cache_destroy(ipn_msgbuf->cache);
2394 +                               list_del(&ipn_msgbuf->list);
2395 +                               kmem_cache_free(ipn_msgbuf_cache,ipn_msgbuf);
2396 +                               return;
2397 +                       }
2398 +               }
2399 +       }
2402 +int ipn_msgbuf_init(void)
2404 +       ipn_msgbuf_cache=kmem_cache_create("ipn_msgbuf",sizeof(struct ipn_msgbuf),0,0,NULL);
2405 +       if (!ipn_msgbuf_cache)
2406 +               return -ENOMEM;
2407 +       else
2408 +               return 0;
2411 +void ipn_msgbuf_fini(void)
2413 +       if (ipn_msgbuf_cache) {
2414 +               while (!list_empty(&ipn_msgbufh)) {
2415 +                       struct ipn_msgbuf *ipn_msgbuf=list_first_entry(&ipn_msgbufh, struct ipn_msgbuf, list);
2416 +                       list_del(&ipn_msgbuf->list);
2417 +                       kmem_cache_destroy(ipn_msgbuf->cache);
2418 +                       kmem_cache_free(ipn_msgbuf_cache,ipn_msgbuf);
2419 +               }
2420 +               kmem_cache_destroy(ipn_msgbuf_cache);
2421 +       }
2423 diff -Naur linux-2.6.28.2/net/ipn/ipn_msgbuf.h linux-2.6.28.2-ipn/net/ipn/ipn_msgbuf.h
2424 --- linux-2.6.28.2/net/ipn/ipn_msgbuf.h 1970-01-01 01:00:00.000000000 +0100
2425 +++ linux-2.6.28.2-ipn/net/ipn/ipn_msgbuf.h     2009-02-01 13:30:09.000000000 +0100
2426 @@ -0,0 +1,30 @@
2428 + * Inter process networking (virtual distributed ethernet) module
2429 + * management of msgbuf (one slab for each MTU)
2430 + *  (part of the View-OS project: wiki.virtualsquare.org) 
2431 + *
2432 + * Copyright (C) 2007   Renzo Davoli (renzo@cs.unibo.it)
2433 + *
2434 + *  This program is free software; you can redistribute it and/or modify
2435 + *  it under the terms of the GNU General Public License as published by
2436 + *  the Free Software Foundation; either version 2 of the License, or
2437 + *  (at your option) any later version.
2438 + *
2439 + *  Due to this file being licensed under the GPL there is controversy over
2440 + *  whether this permits you to write a module that #includes this file
2441 + *  without placing your module under the GPL.  Please consult a lawyer for
2442 + *  advice before doing this.
2443 + *
2444 + * WARNING: THIS CODE IS ALREADY EXPERIMENTAL
2445 + *
2446 + */
2448 +#ifndef _IPN_MSGBUF_H
2449 +#define _IPN_MSGBUF_H
2451 +struct kmem_cache *ipn_msgbuf_get(int mtu);
2452 +void ipn_msgbuf_put(struct kmem_cache *cache);
2453 +int ipn_msgbuf_init(void);
2454 +void ipn_msgbuf_fini(void);
2456 +#endif
2457 diff -Naur linux-2.6.28.2/net/ipn/ipn_netdev.c linux-2.6.28.2-ipn/net/ipn/ipn_netdev.c
2458 --- linux-2.6.28.2/net/ipn/ipn_netdev.c 1970-01-01 01:00:00.000000000 +0100
2459 +++ linux-2.6.28.2-ipn/net/ipn/ipn_netdev.c     2009-02-01 13:30:09.000000000 +0100
2460 @@ -0,0 +1,286 @@
2462 + * Inter process networking (virtual distributed ethernet) module
2463 + * Net devices: tap and grab
2464 + *  (part of the View-OS project: wiki.virtualsquare.org) 
2465 + *
2466 + * Copyright (C) 2007   Renzo Davoli (renzo@cs.unibo.it)
2467 + *
2468 + *  This program is free software; you can redistribute it and/or modify
2469 + *  it under the terms of the GNU General Public License as published by
2470 + *  the Free Software Foundation; either version 2 of the License, or
2471 + *  (at your option) any later version.
2472 + *
2473 + *  Due to this file being licensed under the GPL there is controversy over
2474 + *  whether this permits you to write a module that #includes this file
2475 + *  without placing your module under the GPL.  Please consult a lawyer for
2476 + *  advice before doing this.
2477 + *
2478 + * WARNING: THIS CODE IS ALREADY EXPERIMENTAL
2479 + *
2480 + */
2482 +#include <linux/init.h>
2483 +#include <linux/module.h>
2484 +#include <linux/socket.h>
2485 +#include <linux/poll.h>
2486 +#include <linux/un.h>
2487 +#include <linux/list.h>
2488 +#include <linux/mount.h>
2489 +#include <linux/etherdevice.h>
2490 +#include <linux/ethtool.h>
2491 +#include <linux/version.h>
2492 +#include <net/sock.h>
2493 +#include <net/af_ipn.h>
2494 +#include "ipn_netdev.h"
2496 +#define DRV_NAME  "ipn"
2497 +#define DRV_VERSION "0.3"
2499 +static const struct ethtool_ops ipn_ethtool_ops;
2501 +struct ipntap {
2502 +       struct ipn_node *ipn_node;
2503 +       struct net_device_stats stats;
2506 +/* TAP Net device open. */
2507 +static int ipntap_net_open(struct net_device *dev)
2509 +         netif_start_queue(dev);
2510 +                 return 0;
2513 +/* TAP Net device close. */
2514 +static int ipntap_net_close(struct net_device *dev)
2516 +         netif_stop_queue(dev);
2517 +                 return 0;
2520 +static struct net_device_stats *ipntap_net_stats(struct net_device *dev)
2522 +       struct ipntap *ipntap = netdev_priv(dev);
2523 +       return &ipntap->stats;
2526 +/* receive from a TAP */
2527 +static int ipn_net_xmit(struct sk_buff *skb, struct net_device *dev)
2529 +       struct ipntap *ipntap = netdev_priv(dev);
2530 +       struct ipn_node *ipn_node=ipntap->ipn_node;
2531 +       struct msgpool_item *newmsg;
2532 +       if (!ipn_node || !ipn_node->ipn || skb->len > ipn_node->ipn->mtu)
2533 +               goto drop;
2534 +       newmsg=ipn_msgpool_alloc(ipn_node->ipn,1);
2535 +       if (!newmsg)
2536 +               goto drop;
2537 +       newmsg->len=skb->len;
2538 +       memcpy(newmsg->data,skb->data,skb->len);
2539 +       ipn_proto_injectmsg(ipntap->ipn_node,newmsg);
2540 +       ipn_msgpool_put(newmsg,ipn_node->ipn);
2541 +       ipntap->stats.tx_packets++;
2542 +       ipntap->stats.tx_bytes += skb->len;
2543 +       kfree_skb(skb);
2544 +       return 0;
2546 +drop:
2547 +       ipntap->stats.tx_dropped++;
2548 +       kfree_skb(skb);
2549 +       return 0;
2552 +/* receive from a GRAB via interface hook */
2553 +struct sk_buff *ipn_handle_hook(struct ipn_node *ipn_node, struct sk_buff *skb)
2555 +       char *data=(skb->data)-(skb->mac_len);
2556 +       int len=skb->len+skb->mac_len;
2558 +       if (ipn_node && 
2559 +                       ((ipn_node->flags & IPN_NODEFLAG_DEVMASK) == IPN_NODEFLAG_GRAB) &&
2560 +                       ipn_node->ipn && len<=ipn_node->ipn->mtu) {
2561 +               struct msgpool_item *newmsg;
2562 +               newmsg=ipn_msgpool_alloc(ipn_node->ipn,1);
2563 +               if (newmsg) {
2564 +                       newmsg->len=len;
2565 +                       memcpy(newmsg->data,data,len);
2566 +                       ipn_proto_injectmsg(ipn_node,newmsg);
2567 +                       ipn_msgpool_put(newmsg,ipn_node->ipn);
2568 +               }
2569 +       }
2571 +       return (skb);
2574 +static void ipntap_setup(struct net_device *dev)
2576 +       dev->open = ipntap_net_open;
2577 +       dev->hard_start_xmit = ipn_net_xmit;
2578 +       dev->stop = ipntap_net_close;
2579 +       dev->get_stats = ipntap_net_stats;
2580 +       dev->ethtool_ops = &ipn_ethtool_ops;
2584 +struct net_device *ipn_netdev_alloc(struct net *net,int type, char *name, int *err)
2586 +       struct net_device *dev=NULL;
2587 +       *err=0;
2588 +       if (!name || *name==0) 
2589 +               name="ipn%d";
2590 +       switch (type) {
2591 +               case IPN_NODEFLAG_TAP:
2592 +                       dev=alloc_netdev(sizeof(struct ipntap), name, ipntap_setup);
2593 +                       if (!dev)
2594 +                               *err= -ENOMEM;
2595 +                       ether_setup(dev);
2596 +                       /* this commented code is similar to tuntap MAC assignment.
2597 +                        * why tuntap does not use the random_ether_addr? 
2598 +                       *(u16 *)dev->dev_addr = htons(0x00FF);
2599 +                       get_random_bytes(dev->dev_addr + sizeof(u16), 4);*/
2600 +                       random_ether_addr((u8 *)&dev->dev_addr);
2601 +                       break;
2602 +               case IPN_NODEFLAG_GRAB:
2603 +                       dev=dev_get_by_name(net,name);
2604 +                       if (dev) {
2605 +                               if (dev->flags & IFF_LOOPBACK)
2606 +                                       *err= -EINVAL;
2607 +                               else if (rcu_dereference(dev->ipn_port) != NULL)
2608 +                                       *err= -EBUSY;
2609 +                               if (*err)
2610 +                                       dev=NULL;
2611 +                       }
2612 +                       break;
2613 +       }
2614 +       return dev;
2617 +int ipn_netdev_activate(struct ipn_node *ipn_node)
2619 +       int rv=-EINVAL;
2620 +       switch (ipn_node->flags & IPN_NODEFLAG_DEVMASK) {
2621 +               case IPN_NODEFLAG_TAP:
2622 +                       {
2623 +                               struct ipntap *ipntap=netdev_priv(ipn_node->dev);
2624 +                               ipntap->ipn_node=ipn_node;
2625 +                               rtnl_lock(); 
2626 +                               if ((rv=register_netdevice(ipn_node->dev)) == 0)
2627 +                                       rcu_assign_pointer(ipn_node->dev->ipn_port, 
2628 +                                                       ipn_node);
2629 +                               rtnl_unlock();
2630 +                               if (rv) {/* error! */
2631 +                                       ipn_node->flags &= ~IPN_NODEFLAG_DEVMASK;
2632 +                                       free_netdev(ipn_node->dev);
2633 +                               }
2634 +                       }
2635 +                       break;
2636 +               case IPN_NODEFLAG_GRAB:
2637 +                       rtnl_lock(); 
2638 +                       rcu_assign_pointer(ipn_node->dev->ipn_port, 
2639 +                                       ipn_node);
2640 +                       dev_set_promiscuity(ipn_node->dev,1);
2641 +                       rtnl_unlock();
2642 +                       rv=0;
2643 +                       break;
2644 +       }
2645 +       return rv;
2648 +void ipn_netdev_close(struct ipn_node *ipn_node)
2650 +       switch (ipn_node->flags & IPN_NODEFLAG_DEVMASK) {
2651 +               case IPN_NODEFLAG_TAP:
2652 +                       ipn_node->flags &= ~IPN_NODEFLAG_DEVMASK;
2653 +                       rtnl_lock(); 
2654 +                       rcu_assign_pointer(ipn_node->dev->ipn_port, NULL);
2655 +                       unregister_netdevice(ipn_node->dev);
2656 +                       rtnl_unlock();
2657 +                       free_netdev(ipn_node->dev);
2658 +                       break;
2659 +               case IPN_NODEFLAG_GRAB:
2660 +                       ipn_node->flags &= ~IPN_NODEFLAG_DEVMASK;
2661 +                       rtnl_lock(); 
2662 +                       rcu_assign_pointer(ipn_node->dev->ipn_port, NULL);
2663 +                       dev_set_promiscuity(ipn_node->dev,-1);
2664 +                       rtnl_unlock();
2665 +                       break;
2666 +       }
2669 +void ipn_netdev_sendmsg(struct ipn_node *to,struct msgpool_item *msg)
2671 +       struct sk_buff *skb;
2672 +       struct net_device *dev=to->dev;
2673 +       struct ipntap *ipntap=netdev_priv(dev);
2674 +       
2675 +       if (msg->len > dev->mtu)
2676 +               return;
2677 +       skb=alloc_skb(msg->len+NET_IP_ALIGN,GFP_KERNEL);
2678 +       if (!skb) {
2679 +               ipntap->stats.rx_dropped++;
2680 +               return;
2681 +       }
2682 +       memcpy(skb_put(skb,msg->len),msg->data,msg->len);
2683 +       switch (to->flags & IPN_NODEFLAG_DEVMASK) {
2684 +               case IPN_NODEFLAG_TAP:
2685 +                       skb->protocol = eth_type_trans(skb, dev);
2686 +                       netif_rx(skb);
2687 +                       ipntap->stats.rx_packets++;
2688 +                       ipntap->stats.rx_bytes += msg->len;
2689 +                       break;
2690 +               case IPN_NODEFLAG_GRAB:
2691 +                       skb->dev = dev;
2692 +                       dev_queue_xmit(skb);
2693 +                       break;
2694 +       }
2697 +/* ethtool interface */
2699 +static int ipn_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
2701 +       cmd->supported    = 0;
2702 +       cmd->advertising  = 0;
2703 +       cmd->speed    = SPEED_10;
2704 +       cmd->duplex   = DUPLEX_FULL;
2705 +       cmd->port   = PORT_TP;
2706 +       cmd->phy_address  = 0;
2707 +       cmd->transceiver  = XCVR_INTERNAL;
2708 +       cmd->autoneg    = AUTONEG_DISABLE;
2709 +       cmd->maxtxpkt   = 0;
2710 +       cmd->maxrxpkt   = 0;
2711 +       return 0;
2714 +static void ipn_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
2716 +       strcpy(info->driver, DRV_NAME);
2717 +       strcpy(info->version, DRV_VERSION);
2718 +       strcpy(info->fw_version, "N/A");
2721 +static const struct ethtool_ops ipn_ethtool_ops = {
2722 +       .get_settings = ipn_get_settings,
2723 +       .get_drvinfo  = ipn_get_drvinfo,
2724 +       /* not implemented (yet?)
2725 +       .get_msglevel = ipn_get_msglevel,
2726 +       .set_msglevel = ipn_set_msglevel,
2727 +       .get_link = ipn_get_link,
2728 +       .get_rx_csum  = ipn_get_rx_csum,
2729 +       .set_rx_csum  = ipn_set_rx_csum */
2732 +int ipn_netdev_init(void)
2734 +       ipn_handle_frame_hook=
2735 +#ifdef IPN_STEALING
2736 +               (void *)
2737 +#endif
2738 +               ipn_handle_hook;
2740 +       return 0;
2743 +void ipn_netdev_fini(void)
2745 +       ipn_handle_frame_hook=NULL;
2747 diff -Naur linux-2.6.28.2/net/ipn/ipn_netdev.h linux-2.6.28.2-ipn/net/ipn/ipn_netdev.h
2748 --- linux-2.6.28.2/net/ipn/ipn_netdev.h 1970-01-01 01:00:00.000000000 +0100
2749 +++ linux-2.6.28.2-ipn/net/ipn/ipn_netdev.h     2009-02-01 13:30:09.000000000 +0100
2750 @@ -0,0 +1,56 @@
2751 +#ifndef _IPN_NETDEV_H
2752 +#define _IPN_NETDEV_H
2754 + * Inter process networking (virtual distributed ethernet) module
2755 + * Net devices: tap and grab
2756 + *  (part of the View-OS project: wiki.virtualsquare.org) 
2757 + *
2758 + * Copyright (C) 2007   Renzo Davoli (renzo@cs.unibo.it)
2759 + *
2760 + *  This program is free software; you can redistribute it and/or modify
2761 + *  it under the terms of the GNU General Public License as published by
2762 + *  the Free Software Foundation; either version 2 of the License, or
2763 + *  (at your option) any later version.
2764 + *
2765 + *  Due to this file being licensed under the GPL there is controversy over
2766 + *  whether this permits you to write a module that #includes this file
2767 + *  without placing your module under the GPL.  Please consult a lawyer for
2768 + *  advice before doing this.
2769 + *
2770 + * WARNING: THIS CODE IS ALREADY EXPERIMENTAL
2771 + *
2772 + */
2774 +#include <linux/init.h>
2775 +#include <linux/module.h>
2776 +#include <linux/socket.h>
2777 +#include <linux/poll.h>
2778 +#include <linux/un.h>
2779 +#include <linux/list.h>
2780 +#include <linux/mount.h>
2781 +#include <linux/etherdevice.h>
2782 +#include <linux/if_bridge.h>
2783 +#include <net/sock.h>
2784 +#include <net/af_ipn.h>
2786 +#ifdef IPN_STEALING
2787 +#define ipn_port br_port
2788 +#endif
2790 +struct net_device *ipn_netdev_alloc(struct net *net,int type, char *name, int *err);
2791 +int ipn_netdev_activate(struct ipn_node *ipn_node);
2792 +void ipn_netdev_close(struct ipn_node *ipn_node);
2793 +void ipn_netdev_sendmsg(struct ipn_node *to,struct msgpool_item *msg);
2794 +int ipn_netdev_init(void);
2795 +void ipn_netdev_fini(void);
2797 +static inline struct ipn_node *ipn_netdev2node(struct net_device *dev)
2799 +       return (struct ipn_node *)rcu_dereference(dev->ipn_port);
2802 +static inline void ipn_netdevsync(void)
2804 +       synchronize_rcu();
2806 +#endif