Wirefilter: new markov mode (see man page)
[vde.git] / ipn / ipn_netdev.c
blob098bb890f86aaa26669f43590165a93dfad08bcb
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 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"
39 static const struct ethtool_ops ipn_ethtool_ops;
41 struct ipntap {
42 struct ipn_node *ipn_node;
43 struct net_device_stats stats;
46 /* TAP Net device open. */
47 static int ipntap_net_open(struct net_device *dev)
49 netif_start_queue(dev);
50 return 0;
53 /* TAP Net device close. */
54 static int ipntap_net_close(struct net_device *dev)
56 netif_stop_queue(dev);
57 return 0;
60 static struct net_device_stats *ipntap_net_stats(struct net_device *dev)
62 struct ipntap *ipntap = netdev_priv(dev);
63 return &ipntap->stats;
66 /* receive from a TAP */
67 static int ipn_net_xmit(struct sk_buff *skb, struct net_device *dev)
69 struct ipntap *ipntap = netdev_priv(dev);
70 struct ipn_node *ipn_node=ipntap->ipn_node;
71 struct msgpool_item *newmsg;
72 if (!ipn_node || !ipn_node->ipn || skb->len > ipn_node->ipn->mtu)
73 goto drop;
74 newmsg=ipn_msgpool_alloc(ipn_node->ipn,1);
75 if (!newmsg)
76 goto drop;
77 newmsg->len=skb->len;
78 memcpy(newmsg->data,skb->data,skb->len);
79 ipn_proto_injectmsg(ipntap->ipn_node,newmsg);
80 ipn_msgpool_put(newmsg,ipn_node->ipn);
81 ipntap->stats.tx_packets++;
82 ipntap->stats.tx_bytes += skb->len;
83 kfree_skb(skb);
84 return 0;
86 drop:
87 ipntap->stats.tx_dropped++;
88 kfree_skb(skb);
89 return 0;
92 /* receive from a GRAB via interface hook */
93 struct sk_buff *ipn_handle_hook(struct ipn_node *ipn_node, struct sk_buff *skb)
95 char *data=(skb->data)-(skb->mac_len);
96 int len=skb->len+skb->mac_len;
98 if (ipn_node &&
99 ((ipn_node->flags & IPN_NODEFLAG_DEVMASK) == IPN_NODEFLAG_GRAB) &&
100 ipn_node->ipn && len<=ipn_node->ipn->mtu) {
101 struct msgpool_item *newmsg;
102 newmsg=ipn_msgpool_alloc(ipn_node->ipn,1);
103 if (newmsg) {
104 newmsg->len=len;
105 memcpy(newmsg->data,data,len);
106 ipn_proto_injectmsg(ipn_node,newmsg);
107 ipn_msgpool_put(newmsg,ipn_node->ipn);
111 return (skb);
114 static void ipntap_setup(struct net_device *dev)
116 dev->open = ipntap_net_open;
117 dev->hard_start_xmit = ipn_net_xmit;
118 dev->stop = ipntap_net_close;
119 dev->get_stats = ipntap_net_stats;
120 dev->ethtool_ops = &ipn_ethtool_ops;
124 struct net_device *ipn_netdev_alloc(struct net *net,int type, char *name, int *err)
126 struct net_device *dev=NULL;
127 *err=0;
128 if (!name || *name==0)
129 name="ipn%d";
130 switch (type) {
131 case IPN_NODEFLAG_TAP:
132 dev=alloc_netdev(sizeof(struct ipntap), name, ipntap_setup);
133 if (!dev)
134 *err= -ENOMEM;
135 ether_setup(dev);
136 /* this commented code is similar to tuntap MAC assignment.
137 * why tuntap does not use the random_ether_addr?
138 *(u16 *)dev->dev_addr = htons(0x00FF);
139 get_random_bytes(dev->dev_addr + sizeof(u16), 4);*/
140 random_ether_addr((u8 *)&dev->dev_addr);
141 break;
142 case IPN_NODEFLAG_GRAB:
143 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
144 dev=dev_get_by_name(name);
145 #else
146 dev=dev_get_by_name(net,name);
147 #endif
148 if (dev) {
149 if (dev->flags & IFF_LOOPBACK)
150 *err= -EINVAL;
151 else if (rcu_dereference(dev->ipn_port) != NULL)
152 *err= -EBUSY;
153 if (*err)
154 dev=NULL;
156 break;
158 return dev;
161 int ipn_netdev_activate(struct ipn_node *ipn_node)
163 int rv=-EINVAL;
164 switch (ipn_node->flags & IPN_NODEFLAG_DEVMASK) {
165 case IPN_NODEFLAG_TAP:
167 struct ipntap *ipntap=netdev_priv(ipn_node->dev);
168 ipntap->ipn_node=ipn_node;
169 rtnl_lock();
170 if ((rv=register_netdevice(ipn_node->dev)) == 0)
171 rcu_assign_pointer(ipn_node->dev->ipn_port,
172 #ifdef IPN_STEALING
173 (void *)
174 #endif
175 ipn_node);
176 rtnl_unlock();
177 if (rv) {/* error! */
178 ipn_node->flags &= ~IPN_NODEFLAG_DEVMASK;
179 free_netdev(ipn_node->dev);
182 break;
183 case IPN_NODEFLAG_GRAB:
184 rtnl_lock();
185 rcu_assign_pointer(ipn_node->dev->ipn_port,
186 #ifdef IPN_STEALING
187 (void *)
188 #endif
189 ipn_node);
190 dev_set_promiscuity(ipn_node->dev,1);
191 rtnl_unlock();
192 rv=0;
193 break;
195 return rv;
198 void ipn_netdev_close(struct ipn_node *ipn_node)
200 switch (ipn_node->flags & IPN_NODEFLAG_DEVMASK) {
201 case IPN_NODEFLAG_TAP:
202 ipn_node->flags &= ~IPN_NODEFLAG_DEVMASK;
203 rtnl_lock();
204 rcu_assign_pointer(ipn_node->dev->ipn_port, NULL);
205 unregister_netdevice(ipn_node->dev);
206 rtnl_unlock();
207 free_netdev(ipn_node->dev);
208 break;
209 case IPN_NODEFLAG_GRAB:
210 ipn_node->flags &= ~IPN_NODEFLAG_DEVMASK;
211 rtnl_lock();
212 rcu_assign_pointer(ipn_node->dev->ipn_port, NULL);
213 dev_set_promiscuity(ipn_node->dev,-1);
214 rtnl_unlock();
215 break;
219 void ipn_netdev_sendmsg(struct ipn_node *to,struct msgpool_item *msg)
221 struct sk_buff *skb;
222 struct net_device *dev=to->dev;
223 struct ipntap *ipntap=netdev_priv(dev);
225 if (msg->len > dev->mtu)
226 return;
227 skb=alloc_skb(msg->len+NET_IP_ALIGN,GFP_KERNEL);
228 if (!skb) {
229 ipntap->stats.rx_dropped++;
230 return;
232 memcpy(skb_put(skb,msg->len),msg->data,msg->len);
233 switch (to->flags & IPN_NODEFLAG_DEVMASK) {
234 case IPN_NODEFLAG_TAP:
235 skb->protocol = eth_type_trans(skb, dev);
236 netif_rx(skb);
237 ipntap->stats.rx_packets++;
238 ipntap->stats.rx_bytes += msg->len;
239 break;
240 case IPN_NODEFLAG_GRAB:
241 skb->dev = dev;
242 dev_queue_xmit(skb);
243 break;
247 /* ethtool interface */
249 static int ipn_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
251 cmd->supported = 0;
252 cmd->advertising = 0;
253 cmd->speed = SPEED_10;
254 cmd->duplex = DUPLEX_FULL;
255 cmd->port = PORT_TP;
256 cmd->phy_address = 0;
257 cmd->transceiver = XCVR_INTERNAL;
258 cmd->autoneg = AUTONEG_DISABLE;
259 cmd->maxtxpkt = 0;
260 cmd->maxrxpkt = 0;
261 return 0;
264 static void ipn_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
266 strcpy(info->driver, DRV_NAME);
267 strcpy(info->version, DRV_VERSION);
268 strcpy(info->fw_version, "N/A");
271 static const struct ethtool_ops ipn_ethtool_ops = {
272 .get_settings = ipn_get_settings,
273 .get_drvinfo = ipn_get_drvinfo,
274 /* not implemented (yet?)
275 .get_msglevel = ipn_get_msglevel,
276 .set_msglevel = ipn_set_msglevel,
277 .get_link = ipn_get_link,
278 .get_rx_csum = ipn_get_rx_csum,
279 .set_rx_csum = ipn_set_rx_csum */
282 int ipn_netdev_init(void)
284 ipn_handle_frame_hook=
285 #ifdef IPN_STEALING
286 (void *)
287 #endif
288 ipn_handle_hook;
290 return 0;
293 void ipn_netdev_fini(void)
295 ipn_handle_frame_hook=NULL;