2 * Inter process networking (virtual distributed ethernet) module
3 * Net devices: tap and grab
4 * (part of the View-OS project: wiki.virtualsquare.org)
6 * Copyright (C) 2007,2009 Renzo Davoli (renzo@cs.unibo.it)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * Due to this file being licensed under the GPL there is controversy over
14 * whether this permits you to write a module that #includes this file
15 * without placing your module under the GPL. Please consult a lawyer for
16 * advice before doing this.
18 * WARNING: THIS CODE IS ALREADY EXPERIMENTAL
22 #include <linux/init.h>
23 #include <linux/module.h>
24 #include <linux/socket.h>
25 #include <linux/poll.h>
27 #include <linux/list.h>
28 #include <linux/mount.h>
29 #include <linux/etherdevice.h>
30 #include <linux/ethtool.h>
31 #include <linux/version.h>
34 #include "ipn_netdev.h"
36 #define DRV_NAME "ipn"
37 #define DRV_VERSION "0.3.1"
39 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
42 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
45 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
48 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)
52 static const struct ethtool_ops ipn_ethtool_ops
;
55 struct ipn_node
*ipn_node
;
56 struct net_device_stats stats
;
59 /* TAP Net device open. */
60 static int ipntap_net_open(struct net_device
*dev
)
62 netif_start_queue(dev
);
66 /* TAP Net device close. */
67 static int ipntap_net_close(struct net_device
*dev
)
69 netif_stop_queue(dev
);
73 static struct net_device_stats
*ipntap_net_stats(struct net_device
*dev
)
75 struct ipntap
*ipntap
= netdev_priv(dev
);
76 return &ipntap
->stats
;
79 /* receive from a TAP */
80 static int ipn_net_xmit(struct sk_buff
*skb
, struct net_device
*dev
)
82 struct ipntap
*ipntap
= netdev_priv(dev
);
83 struct ipn_node
*ipn_node
=ipntap
->ipn_node
;
84 struct msgpool_item
*newmsg
;
85 if (!ipn_node
|| !ipn_node
->ipn
|| skb
->len
> ipn_node
->ipn
->mtu
)
87 newmsg
=ipn_msgpool_alloc(ipn_node
->ipn
,1,skb
->len
);
91 memcpy(newmsg
->data
,skb
->data
,skb
->len
);
92 ipn_proto_injectmsg(ipntap
->ipn_node
,newmsg
);
93 ipn_msgpool_put(newmsg
,ipn_node
->ipn
);
94 ipntap
->stats
.tx_packets
++;
95 ipntap
->stats
.tx_bytes
+= skb
->len
;
100 ipntap
->stats
.tx_dropped
++;
106 /* receive from a GRAB via interface hook */
107 struct sk_buff
*ipn_handle_hook(struct ipn_node
*ipn_node
, struct sk_buff
*skb
)
110 static struct sk_buff
*ipn_handle_frame(struct sk_buff
*skb
)
112 static rx_handler_result_t
ipn_handle_frame(struct sk_buff
**pskb
)
117 struct sk_buff
*skb
= *pskb
;
119 char *data
=(skb
->data
)-(skb
->mac_len
);
120 int len
=skb
->len
+skb
->mac_len
;
122 struct ipn_node
*ipn_node
=ipn_netdev2node(skb
->dev
);
126 ((ipn_node
->flags
& IPN_NODEFLAG_DEVMASK
) == IPN_NODEFLAG_GRAB
) &&
127 ipn_node
->ipn
&& len
<=ipn_node
->ipn
->mtu
) {
128 struct msgpool_item
*newmsg
;
129 newmsg
=ipn_msgpool_alloc(ipn_node
->ipn
,1,len
);
132 memcpy(newmsg
->data
,data
,len
);
133 ipn_proto_injectmsg(ipn_node
,newmsg
);
134 ipn_msgpool_put(newmsg
,ipn_node
->ipn
);
141 return RX_HANDLER_PASS
;
146 static struct net_device_ops ipntap_netdev_ops
= {
147 .ndo_open
= ipntap_net_open
,
148 .ndo_start_xmit
= ipn_net_xmit
,
149 .ndo_stop
= ipntap_net_close
,
150 .ndo_get_stats
= ipntap_net_stats
154 static void ipntap_setup(struct net_device
*dev
)
157 dev
->open
= ipntap_net_open
;
158 dev
->hard_start_xmit
= ipn_net_xmit
;
159 dev
->stop
= ipntap_net_close
;
160 dev
->get_stats
= ipntap_net_stats
;
162 dev
->ethtool_ops
= &ipn_ethtool_ops
;
165 struct net_device
*ipn_netdev_alloc(struct net
*net
,int type
, char *name
, int *err
)
167 struct net_device
*dev
=NULL
;
169 if (!name
|| *name
==0)
172 case IPN_NODEFLAG_TAP
:
173 dev
=alloc_netdev(sizeof(struct ipntap
), name
, ipntap_setup
);
177 dev_net_set(dev
, net
);
178 dev
->netdev_ops
= &ipntap_netdev_ops
;
181 if (strchr(dev
->name
, '%')) {
182 *err
= dev_alloc_name(dev
, dev
->name
);
188 random_ether_addr(dev
->dev_addr
);
190 case IPN_NODEFLAG_GRAB
:
193 /* only if bridge is not working */
194 if (ipn_handle_frame_hook
!= (void *) ipn_handle_hook
) {
195 printk (KERN_WARNING
"IPN interface GRAB disabled (stealing mode) if bridge is loaded\n");
201 dev
=dev_get_by_name(name
);
203 dev
=dev_get_by_name(net
,name
);
206 if (dev
->flags
& IFF_LOOPBACK
)
209 else if (rcu_dereference(dev
->ipn_port
) != NULL
)
212 else if (rcu_dereference(dev
->rx_handler
) != NULL
)
223 int ipn_netdev_activate(struct ipn_node
*ipn_node
)
226 switch (ipn_node
->flags
& IPN_NODEFLAG_DEVMASK
) {
227 case IPN_NODEFLAG_TAP
:
229 struct ipntap
*ipntap
=netdev_priv(ipn_node
->netdev
);
230 ipntap
->ipn_node
=ipn_node
;
232 if ((rv
=register_netdevice(ipn_node
->netdev
)) == 0) {
234 rcu_assign_pointer(ipn_node
->netdev
->ipn_port
,
240 netdev_rx_handler_register(ipn_node
->netdev
,
246 if (rv
) {/* error! */
247 ipn_node
->flags
&= ~IPN_NODEFLAG_DEVMASK
;
248 free_netdev(ipn_node
->netdev
);
252 case IPN_NODEFLAG_GRAB
:
255 rcu_assign_pointer(ipn_node
->netdev
->ipn_port
,
261 netdev_rx_handler_register(ipn_node
->netdev
,
265 dev_set_promiscuity(ipn_node
->netdev
,1);
273 void ipn_netdev_close(struct ipn_node
*ipn_node
)
275 switch (ipn_node
->flags
& IPN_NODEFLAG_DEVMASK
) {
276 case IPN_NODEFLAG_TAP
:
277 ipn_node
->flags
&= ~IPN_NODEFLAG_DEVMASK
;
280 rcu_assign_pointer(ipn_node
->netdev
->ipn_port
, NULL
);
282 netdev_rx_handler_unregister(ipn_node
->netdev
);
284 unregister_netdevice(ipn_node
->netdev
);
286 free_netdev(ipn_node
->netdev
);
288 case IPN_NODEFLAG_GRAB
:
289 ipn_node
->flags
&= ~IPN_NODEFLAG_DEVMASK
;
292 rcu_assign_pointer(ipn_node
->netdev
->ipn_port
, NULL
);
294 netdev_rx_handler_unregister(ipn_node
->netdev
);
296 dev_set_promiscuity(ipn_node
->netdev
,-1);
302 void ipn_netdev_sendmsg(struct ipn_node
*to
,struct msgpool_item
*msg
)
305 struct net_device
*dev
=to
->netdev
;
306 struct ipntap
*ipntap
=netdev_priv(dev
);
308 if (msg
->len
> dev
->mtu
+ dev
->hard_header_len
) {
309 printk("ipn_netdev_sendmsg: dropping packet, msg->len > MTU+HDR\n");
310 ipntap
->stats
.rx_dropped
++;
313 skb
=alloc_skb(msg
->len
+NET_IP_ALIGN
,GFP_KERNEL
);
315 printk("ipn_netdev_sendmsg: dropping packet, cannot alloc skb\n");
316 ipntap
->stats
.rx_dropped
++;
319 memcpy(skb_put(skb
,msg
->len
),msg
->data
,msg
->len
);
320 switch (to
->flags
& IPN_NODEFLAG_DEVMASK
) {
321 case IPN_NODEFLAG_TAP
:
322 skb
->protocol
= eth_type_trans(skb
, dev
);
324 ipntap
->stats
.rx_packets
++;
325 ipntap
->stats
.rx_bytes
+= msg
->len
;
327 case IPN_NODEFLAG_GRAB
:
334 /* ethtool interface */
336 static int ipn_get_settings(struct net_device
*dev
, struct ethtool_cmd
*cmd
)
339 cmd
->advertising
= 0;
340 cmd
->speed
= SPEED_10
;
341 cmd
->duplex
= DUPLEX_FULL
;
343 cmd
->phy_address
= 0;
344 cmd
->transceiver
= XCVR_INTERNAL
;
345 cmd
->autoneg
= AUTONEG_DISABLE
;
351 static void ipn_get_drvinfo(struct net_device
*dev
, struct ethtool_drvinfo
*info
)
353 strcpy(info
->driver
, DRV_NAME
);
354 strcpy(info
->version
, DRV_VERSION
);
355 strcpy(info
->fw_version
, "N/A");
358 static const struct ethtool_ops ipn_ethtool_ops
= {
359 .get_settings
= ipn_get_settings
,
360 .get_drvinfo
= ipn_get_drvinfo
,
361 /* not implemented (yet?)
362 .get_msglevel = ipn_get_msglevel,
363 .set_msglevel = ipn_set_msglevel,
364 .get_link = ipn_get_link,
365 .get_rx_csum = ipn_get_rx_csum,
366 .set_rx_csum = ipn_set_rx_csum */
369 int ipn_netdev_init(void)
373 if (ipn_handle_frame_hook
!= NULL
)
374 printk (KERN_WARNING
"IPN interface GRAB disabled (stealing mode) if bridge is loaded\n");
377 ipn_handle_frame_hook
=
387 void ipn_netdev_fini(void)
391 /* only if bridge is not working */
392 if (ipn_handle_frame_hook
== (void *) ipn_handle_hook
)
394 ipn_handle_frame_hook
=NULL
;