vde_autolink: Add missing null entry in getopt_long array.
[vde.git] / ipn / ipn_netdev.c
blob8ce62c7577813e736e649ce8ae24affb51baab55
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
48 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)
49 #define IPN_PRE2639
50 #endif
52 static const struct ethtool_ops ipn_ethtool_ops;
54 struct ipntap {
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);
63 return 0;
66 /* TAP Net device close. */
67 static int ipntap_net_close(struct net_device *dev)
69 netif_stop_queue(dev);
70 return 0;
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)
86 goto drop;
87 newmsg=ipn_msgpool_alloc(ipn_node->ipn,1,skb->len);
88 if (!newmsg)
89 goto drop;
90 newmsg->len=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;
96 kfree_skb(skb);
97 return 0;
99 drop:
100 ipntap->stats.tx_dropped++;
101 kfree_skb(skb);
102 return 0;
105 #ifdef IPN_PRE2637
106 /* receive from a GRAB via interface hook */
107 struct sk_buff *ipn_handle_hook(struct ipn_node *ipn_node, struct sk_buff *skb)
108 #else
109 #ifdef IPN_PRE2639
110 static struct sk_buff *ipn_handle_frame(struct sk_buff *skb)
111 #else
112 static rx_handler_result_t ipn_handle_frame(struct sk_buff **pskb)
113 #endif
114 #endif
116 #ifndef IPN_PRE2639
117 struct sk_buff *skb = *pskb;
118 #endif
119 char *data=(skb->data)-(skb->mac_len);
120 int len=skb->len+skb->mac_len;
121 #ifndef IPN_PRE2637
122 struct ipn_node *ipn_node=ipn_netdev2node(skb->dev);
123 #endif
125 if (ipn_node &&
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);
130 if (newmsg) {
131 newmsg->len=len;
132 memcpy(newmsg->data,data,len);
133 ipn_proto_injectmsg(ipn_node,newmsg);
134 ipn_msgpool_put(newmsg,ipn_node->ipn);
138 #ifdef IPN_PRE2639
139 return (skb);
140 #else
141 return RX_HANDLER_PASS;
142 #endif
145 #ifndef IPN_PRE2629
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
152 #endif
154 static void ipntap_setup(struct net_device *dev)
156 #ifdef IPN_PRE2629
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;
161 #endif
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;
168 *err=0;
169 if (!name || *name==0)
170 name="ipn%d";
171 switch (type) {
172 case IPN_NODEFLAG_TAP:
173 dev=alloc_netdev(sizeof(struct ipntap), name, ipntap_setup);
174 if (!dev)
175 *err= -ENOMEM;
176 #ifndef IPN_PRE2629
177 dev_net_set(dev, net);
178 dev->netdev_ops = &ipntap_netdev_ops;
179 #endif
180 ether_setup(dev);
181 if (strchr(dev->name, '%')) {
182 *err = dev_alloc_name(dev, dev->name);
183 if (*err < 0) {
184 free_netdev(dev);
185 return NULL;
188 random_ether_addr(dev->dev_addr);
189 break;
190 case IPN_NODEFLAG_GRAB:
191 #ifdef IPN_PRE2637
192 #ifdef IPN_STEALING
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");
196 return NULL;
198 #endif
199 #endif
200 #ifdef IPN_PRE2624
201 dev=dev_get_by_name(name);
202 #else
203 dev=dev_get_by_name(net,name);
204 #endif
205 if (dev) {
206 if (dev->flags & IFF_LOOPBACK)
207 *err= -EINVAL;
208 #ifdef IPN_PRE2637
209 else if (rcu_dereference(dev->ipn_port) != NULL)
210 *err= -EBUSY;
211 #else
212 else if (rcu_dereference(dev->rx_handler) != NULL)
213 *err= -EBUSY;
214 #endif
215 if (*err)
216 dev=NULL;
218 break;
220 return dev;
223 int ipn_netdev_activate(struct ipn_node *ipn_node)
225 int rv=-EINVAL;
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;
231 rtnl_lock();
232 if ((rv=register_netdevice(ipn_node->netdev)) == 0) {
233 #ifdef IPN_PRE2637
234 rcu_assign_pointer(ipn_node->netdev->ipn_port,
235 #ifdef IPN_STEALING
236 (void *)
237 #endif
238 ipn_node);
239 #else
240 netdev_rx_handler_register(ipn_node->netdev,
241 ipn_handle_frame,
242 ipn_node);
243 #endif
245 rtnl_unlock();
246 if (rv) {/* error! */
247 ipn_node->flags &= ~IPN_NODEFLAG_DEVMASK;
248 free_netdev(ipn_node->netdev);
251 break;
252 case IPN_NODEFLAG_GRAB:
253 rtnl_lock();
254 #ifdef IPN_PRE2637
255 rcu_assign_pointer(ipn_node->netdev->ipn_port,
256 #ifdef IPN_STEALING
257 (void *)
258 #endif
259 ipn_node);
260 #else
261 netdev_rx_handler_register(ipn_node->netdev,
262 ipn_handle_frame,
263 ipn_node);
264 #endif
265 dev_set_promiscuity(ipn_node->netdev,1);
266 rtnl_unlock();
267 rv=0;
268 break;
270 return rv;
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;
278 rtnl_lock();
279 #ifdef IPN_PRE2637
280 rcu_assign_pointer(ipn_node->netdev->ipn_port, NULL);
281 #else
282 netdev_rx_handler_unregister(ipn_node->netdev);
283 #endif
284 unregister_netdevice(ipn_node->netdev);
285 rtnl_unlock();
286 free_netdev(ipn_node->netdev);
287 break;
288 case IPN_NODEFLAG_GRAB:
289 ipn_node->flags &= ~IPN_NODEFLAG_DEVMASK;
290 rtnl_lock();
291 #ifdef IPN_PRE2637
292 rcu_assign_pointer(ipn_node->netdev->ipn_port, NULL);
293 #else
294 netdev_rx_handler_unregister(ipn_node->netdev);
295 #endif
296 dev_set_promiscuity(ipn_node->netdev,-1);
297 rtnl_unlock();
298 break;
302 void ipn_netdev_sendmsg(struct ipn_node *to,struct msgpool_item *msg)
304 struct sk_buff *skb;
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++;
311 return;
313 skb=alloc_skb(msg->len+NET_IP_ALIGN,GFP_KERNEL);
314 if (!skb) {
315 printk("ipn_netdev_sendmsg: dropping packet, cannot alloc skb\n");
316 ipntap->stats.rx_dropped++;
317 return;
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);
323 netif_rx_ni(skb);
324 ipntap->stats.rx_packets++;
325 ipntap->stats.rx_bytes += msg->len;
326 break;
327 case IPN_NODEFLAG_GRAB:
328 skb->dev = dev;
329 dev_queue_xmit(skb);
330 break;
334 /* ethtool interface */
336 static int ipn_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
338 cmd->supported = 0;
339 cmd->advertising = 0;
340 cmd->speed = SPEED_10;
341 cmd->duplex = DUPLEX_FULL;
342 cmd->port = PORT_TP;
343 cmd->phy_address = 0;
344 cmd->transceiver = XCVR_INTERNAL;
345 cmd->autoneg = AUTONEG_DISABLE;
346 cmd->maxtxpkt = 0;
347 cmd->maxrxpkt = 0;
348 return 0;
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)
371 #ifdef IPN_PRE2637
372 #ifdef IPN_STEALING
373 if (ipn_handle_frame_hook != NULL)
374 printk (KERN_WARNING "IPN interface GRAB disabled (stealing mode) if bridge is loaded\n");
375 else
376 #endif
377 ipn_handle_frame_hook=
378 #ifdef IPN_STEALING
379 (void *)
380 #endif
381 ipn_handle_hook;
382 #endif
384 return 0;
387 void ipn_netdev_fini(void)
389 #ifdef IPN_PRE2637
390 #ifdef IPN_STEALING
391 /* only if bridge is not working */
392 if (ipn_handle_frame_hook == (void *) ipn_handle_hook)
393 #endif
394 ipn_handle_frame_hook=NULL;
395 #endif