port to 2.6.37: mutex changed into semaphore and netdev_rx_handler management
[vde.git] / ipn / ipn_netdev.c
blob03e331bc39d38bba0bc1fb41ee1ea21ca29ad293
1 /*
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>
26 #include <linux/un.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>
32 #include <net/sock.h>
33 #include "af_ipn.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)
40 #define IPN_PRE2624
41 #endif
42 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
43 #define IPN_PRE2629
44 #endif
45 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
46 #define IPN_PRE2637
47 #endif
49 static const struct ethtool_ops ipn_ethtool_ops;
51 struct ipntap {
52 struct ipn_node *ipn_node;
53 struct net_device_stats stats;
56 /* TAP Net device open. */
57 static int ipntap_net_open(struct net_device *dev)
59 netif_start_queue(dev);
60 return 0;
63 /* TAP Net device close. */
64 static int ipntap_net_close(struct net_device *dev)
66 netif_stop_queue(dev);
67 return 0;
70 static struct net_device_stats *ipntap_net_stats(struct net_device *dev)
72 struct ipntap *ipntap = netdev_priv(dev);
73 return &ipntap->stats;
76 /* receive from a TAP */
77 static int ipn_net_xmit(struct sk_buff *skb, struct net_device *dev)
79 struct ipntap *ipntap = netdev_priv(dev);
80 struct ipn_node *ipn_node=ipntap->ipn_node;
81 struct msgpool_item *newmsg;
82 if (!ipn_node || !ipn_node->ipn || skb->len > ipn_node->ipn->mtu)
83 goto drop;
84 newmsg=ipn_msgpool_alloc(ipn_node->ipn,1,skb->len);
85 if (!newmsg)
86 goto drop;
87 newmsg->len=skb->len;
88 memcpy(newmsg->data,skb->data,skb->len);
89 ipn_proto_injectmsg(ipntap->ipn_node,newmsg);
90 ipn_msgpool_put(newmsg,ipn_node->ipn);
91 ipntap->stats.tx_packets++;
92 ipntap->stats.tx_bytes += skb->len;
93 kfree_skb(skb);
94 return 0;
96 drop:
97 ipntap->stats.tx_dropped++;
98 kfree_skb(skb);
99 return 0;
102 #ifdef IPN_PRE2637
103 /* receive from a GRAB via interface hook */
104 struct sk_buff *ipn_handle_hook(struct ipn_node *ipn_node, struct sk_buff *skb)
105 #else
106 static struct sk_buff *ipn_handle_frame(struct sk_buff *skb)
107 #endif
109 char *data=(skb->data)-(skb->mac_len);
110 int len=skb->len+skb->mac_len;
111 #ifndef IPN_PRE2637
112 struct ipn_node *ipn_node=ipn_netdev2node(skb->dev);
113 #endif
115 if (ipn_node &&
116 ((ipn_node->flags & IPN_NODEFLAG_DEVMASK) == IPN_NODEFLAG_GRAB) &&
117 ipn_node->ipn && len<=ipn_node->ipn->mtu) {
118 struct msgpool_item *newmsg;
119 newmsg=ipn_msgpool_alloc(ipn_node->ipn,1,len);
120 if (newmsg) {
121 newmsg->len=len;
122 memcpy(newmsg->data,data,len);
123 ipn_proto_injectmsg(ipn_node,newmsg);
124 ipn_msgpool_put(newmsg,ipn_node->ipn);
128 return (skb);
131 #ifndef IPN_PRE2629
132 static struct net_device_ops ipntap_netdev_ops = {
133 .ndo_open = ipntap_net_open,
134 .ndo_start_xmit = ipn_net_xmit,
135 .ndo_stop = ipntap_net_close,
136 .ndo_get_stats = ipntap_net_stats
138 #endif
140 static void ipntap_setup(struct net_device *dev)
142 #ifdef IPN_PRE2629
143 dev->open = ipntap_net_open;
144 dev->hard_start_xmit = ipn_net_xmit;
145 dev->stop = ipntap_net_close;
146 dev->get_stats = ipntap_net_stats;
147 #endif
148 dev->ethtool_ops = &ipn_ethtool_ops;
151 struct net_device *ipn_netdev_alloc(struct net *net,int type, char *name, int *err)
153 struct net_device *dev=NULL;
154 *err=0;
155 if (!name || *name==0)
156 name="ipn%d";
157 switch (type) {
158 case IPN_NODEFLAG_TAP:
159 dev=alloc_netdev(sizeof(struct ipntap), name, ipntap_setup);
160 if (!dev)
161 *err= -ENOMEM;
162 #ifndef IPN_PRE2629
163 dev_net_set(dev, net);
164 dev->netdev_ops = &ipntap_netdev_ops;
165 #endif
166 ether_setup(dev);
167 if (strchr(dev->name, '%')) {
168 *err = dev_alloc_name(dev, dev->name);
169 if (*err < 0) {
170 free_netdev(dev);
171 return NULL;
174 random_ether_addr(dev->dev_addr);
175 break;
176 case IPN_NODEFLAG_GRAB:
177 #ifdef IPN_PRE2637
178 #ifdef IPN_STEALING
179 /* only if bridge is not working */
180 if (ipn_handle_frame_hook != (void *) ipn_handle_hook) {
181 printk (KERN_WARNING "IPN interface GRAB disabled (stealing mode) if bridge is loaded\n");
182 return NULL;
184 #endif
185 #endif
186 #ifdef IPN_PRE2624
187 dev=dev_get_by_name(name);
188 #else
189 dev=dev_get_by_name(net,name);
190 #endif
191 if (dev) {
192 if (dev->flags & IFF_LOOPBACK)
193 *err= -EINVAL;
194 #ifdef IPN_PRE2637
195 else if (rcu_dereference(dev->ipn_port) != NULL)
196 *err= -EBUSY;
197 #else
198 else if (rcu_dereference(dev->rx_handler) != NULL)
199 *err= -EBUSY;
200 #endif
201 if (*err)
202 dev=NULL;
204 break;
206 return dev;
209 int ipn_netdev_activate(struct ipn_node *ipn_node)
211 int rv=-EINVAL;
212 switch (ipn_node->flags & IPN_NODEFLAG_DEVMASK) {
213 case IPN_NODEFLAG_TAP:
215 struct ipntap *ipntap=netdev_priv(ipn_node->netdev);
216 ipntap->ipn_node=ipn_node;
217 rtnl_lock();
218 if ((rv=register_netdevice(ipn_node->netdev)) == 0) {
219 #ifdef IPN_PRE2637
220 rcu_assign_pointer(ipn_node->netdev->ipn_port,
221 #ifdef IPN_STEALING
222 (void *)
223 #endif
224 ipn_node);
225 #else
226 netdev_rx_handler_register(ipn_node->netdev,
227 ipn_handle_frame,
228 ipn_node);
229 #endif
231 rtnl_unlock();
232 if (rv) {/* error! */
233 ipn_node->flags &= ~IPN_NODEFLAG_DEVMASK;
234 free_netdev(ipn_node->netdev);
237 break;
238 case IPN_NODEFLAG_GRAB:
239 rtnl_lock();
240 #ifdef IPN_PRE2637
241 rcu_assign_pointer(ipn_node->netdev->ipn_port,
242 #ifdef IPN_STEALING
243 (void *)
244 #endif
245 ipn_node);
246 #else
247 netdev_rx_handler_register(ipn_node->netdev,
248 ipn_handle_frame,
249 ipn_node);
250 #endif
251 dev_set_promiscuity(ipn_node->netdev,1);
252 rtnl_unlock();
253 rv=0;
254 break;
256 return rv;
259 void ipn_netdev_close(struct ipn_node *ipn_node)
261 switch (ipn_node->flags & IPN_NODEFLAG_DEVMASK) {
262 case IPN_NODEFLAG_TAP:
263 ipn_node->flags &= ~IPN_NODEFLAG_DEVMASK;
264 rtnl_lock();
265 #ifdef IPN_PRE2637
266 rcu_assign_pointer(ipn_node->netdev->ipn_port, NULL);
267 #else
268 netdev_rx_handler_unregister(ipn_node->netdev);
269 #endif
270 unregister_netdevice(ipn_node->netdev);
271 rtnl_unlock();
272 free_netdev(ipn_node->netdev);
273 break;
274 case IPN_NODEFLAG_GRAB:
275 ipn_node->flags &= ~IPN_NODEFLAG_DEVMASK;
276 rtnl_lock();
277 #ifdef IPN_PRE2637
278 rcu_assign_pointer(ipn_node->netdev->ipn_port, NULL);
279 #else
280 netdev_rx_handler_unregister(ipn_node->netdev);
281 #endif
282 dev_set_promiscuity(ipn_node->netdev,-1);
283 rtnl_unlock();
284 break;
288 void ipn_netdev_sendmsg(struct ipn_node *to,struct msgpool_item *msg)
290 struct sk_buff *skb;
291 struct net_device *dev=to->netdev;
292 struct ipntap *ipntap=netdev_priv(dev);
294 if (msg->len > dev->mtu + dev->hard_header_len) {
295 printk("ipn_netdev_sendmsg: dropping packet, msg->len > MTU+HDR\n");
296 ipntap->stats.rx_dropped++;
297 return;
299 skb=alloc_skb(msg->len+NET_IP_ALIGN,GFP_KERNEL);
300 if (!skb) {
301 printk("ipn_netdev_sendmsg: dropping packet, cannot alloc skb\n");
302 ipntap->stats.rx_dropped++;
303 return;
305 memcpy(skb_put(skb,msg->len),msg->data,msg->len);
306 switch (to->flags & IPN_NODEFLAG_DEVMASK) {
307 case IPN_NODEFLAG_TAP:
308 skb->protocol = eth_type_trans(skb, dev);
309 netif_rx_ni(skb);
310 ipntap->stats.rx_packets++;
311 ipntap->stats.rx_bytes += msg->len;
312 break;
313 case IPN_NODEFLAG_GRAB:
314 skb->dev = dev;
315 dev_queue_xmit(skb);
316 break;
320 /* ethtool interface */
322 static int ipn_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
324 cmd->supported = 0;
325 cmd->advertising = 0;
326 cmd->speed = SPEED_10;
327 cmd->duplex = DUPLEX_FULL;
328 cmd->port = PORT_TP;
329 cmd->phy_address = 0;
330 cmd->transceiver = XCVR_INTERNAL;
331 cmd->autoneg = AUTONEG_DISABLE;
332 cmd->maxtxpkt = 0;
333 cmd->maxrxpkt = 0;
334 return 0;
337 static void ipn_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
339 strcpy(info->driver, DRV_NAME);
340 strcpy(info->version, DRV_VERSION);
341 strcpy(info->fw_version, "N/A");
344 static const struct ethtool_ops ipn_ethtool_ops = {
345 .get_settings = ipn_get_settings,
346 .get_drvinfo = ipn_get_drvinfo,
347 /* not implemented (yet?)
348 .get_msglevel = ipn_get_msglevel,
349 .set_msglevel = ipn_set_msglevel,
350 .get_link = ipn_get_link,
351 .get_rx_csum = ipn_get_rx_csum,
352 .set_rx_csum = ipn_set_rx_csum */
355 int ipn_netdev_init(void)
357 #ifdef IPN_PRE2637
358 #ifdef IPN_STEALING
359 if (ipn_handle_frame_hook != NULL)
360 printk (KERN_WARNING "IPN interface GRAB disabled (stealing mode) if bridge is loaded\n");
361 else
362 #endif
363 ipn_handle_frame_hook=
364 #ifdef IPN_STEALING
365 (void *)
366 #endif
367 ipn_handle_hook;
368 #endif
370 return 0;
373 void ipn_netdev_fini(void)
375 #ifdef IPN_PRE2637
376 #ifdef IPN_STEALING
377 /* only if bridge is not working */
378 if (ipn_handle_frame_hook == (void *) ipn_handle_hook)
379 #endif
380 ipn_handle_frame_hook=NULL;
381 #endif