aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorAdrian Bunk <bunk@stusta.de>2006-11-13 19:02:22 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-03 00:22:23 -0500
commit90833aa4f496d69ca374af6acef7d1614c8693ff (patch)
treedbac818cc40ab12d493c45778febf6b7a768f757 /net/core
parentd7f7365f5776723da6df73540d855069c2daaa5c (diff)
[NET]: The scheduled removal of the frame diverter.
This patch contains the scheduled removal of the frame diverter. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/Makefile1
-rw-r--r--net/core/dev.c20
-rw-r--r--net/core/dv.c546
-rw-r--r--net/core/sysctl_net_core.c14
4 files changed, 4 insertions, 577 deletions
diff --git a/net/core/Makefile b/net/core/Makefile
index 119568077dab..73272d506e93 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -12,7 +12,6 @@ obj-y += dev.o ethtool.o dev_mcast.o dst.o netevent.o \
12 12
13obj-$(CONFIG_XFRM) += flow.o 13obj-$(CONFIG_XFRM) += flow.o
14obj-$(CONFIG_SYSFS) += net-sysfs.o 14obj-$(CONFIG_SYSFS) += net-sysfs.o
15obj-$(CONFIG_NET_DIVERT) += dv.o
16obj-$(CONFIG_NET_PKTGEN) += pktgen.o 15obj-$(CONFIG_NET_PKTGEN) += pktgen.o
17obj-$(CONFIG_WIRELESS_EXT) += wireless.o 16obj-$(CONFIG_WIRELESS_EXT) += wireless.o
18obj-$(CONFIG_NETPOLL) += netpoll.o 17obj-$(CONFIG_NETPOLL) += netpoll.o
diff --git a/net/core/dev.c b/net/core/dev.c
index 411c2428d268..5bf13b132dd7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -98,7 +98,6 @@
98#include <linux/seq_file.h> 98#include <linux/seq_file.h>
99#include <linux/stat.h> 99#include <linux/stat.h>
100#include <linux/if_bridge.h> 100#include <linux/if_bridge.h>
101#include <linux/divert.h>
102#include <net/dst.h> 101#include <net/dst.h>
103#include <net/pkt_sched.h> 102#include <net/pkt_sched.h>
104#include <net/checksum.h> 103#include <net/checksum.h>
@@ -1827,8 +1826,6 @@ int netif_receive_skb(struct sk_buff *skb)
1827ncls: 1826ncls:
1828#endif 1827#endif
1829 1828
1830 handle_diverter(skb);
1831
1832 if (handle_bridge(&skb, &pt_prev, &ret, orig_dev)) 1829 if (handle_bridge(&skb, &pt_prev, &ret, orig_dev))
1833 goto out; 1830 goto out;
1834 1831
@@ -2898,10 +2895,6 @@ int register_netdevice(struct net_device *dev)
2898 spin_lock_init(&dev->ingress_lock); 2895 spin_lock_init(&dev->ingress_lock);
2899#endif 2896#endif
2900 2897
2901 ret = alloc_divert_blk(dev);
2902 if (ret)
2903 goto out;
2904
2905 dev->iflink = -1; 2898 dev->iflink = -1;
2906 2899
2907 /* Init, if this function is available */ 2900 /* Init, if this function is available */
@@ -2910,13 +2903,13 @@ int register_netdevice(struct net_device *dev)
2910 if (ret) { 2903 if (ret) {
2911 if (ret > 0) 2904 if (ret > 0)
2912 ret = -EIO; 2905 ret = -EIO;
2913 goto out_err; 2906 goto out;
2914 } 2907 }
2915 } 2908 }
2916 2909
2917 if (!dev_valid_name(dev->name)) { 2910 if (!dev_valid_name(dev->name)) {
2918 ret = -EINVAL; 2911 ret = -EINVAL;
2919 goto out_err; 2912 goto out;
2920 } 2913 }
2921 2914
2922 dev->ifindex = dev_new_index(); 2915 dev->ifindex = dev_new_index();
@@ -2930,7 +2923,7 @@ int register_netdevice(struct net_device *dev)
2930 = hlist_entry(p, struct net_device, name_hlist); 2923 = hlist_entry(p, struct net_device, name_hlist);
2931 if (!strncmp(d->name, dev->name, IFNAMSIZ)) { 2924 if (!strncmp(d->name, dev->name, IFNAMSIZ)) {
2932 ret = -EEXIST; 2925 ret = -EEXIST;
2933 goto out_err; 2926 goto out;
2934 } 2927 }
2935 } 2928 }
2936 2929
@@ -2974,7 +2967,7 @@ int register_netdevice(struct net_device *dev)
2974 2967
2975 ret = netdev_register_sysfs(dev); 2968 ret = netdev_register_sysfs(dev);
2976 if (ret) 2969 if (ret)
2977 goto out_err; 2970 goto out;
2978 dev->reg_state = NETREG_REGISTERED; 2971 dev->reg_state = NETREG_REGISTERED;
2979 2972
2980 /* 2973 /*
@@ -3001,9 +2994,6 @@ int register_netdevice(struct net_device *dev)
3001 2994
3002out: 2995out:
3003 return ret; 2996 return ret;
3004out_err:
3005 free_divert_blk(dev);
3006 goto out;
3007} 2997}
3008 2998
3009/** 2999/**
@@ -3320,8 +3310,6 @@ int unregister_netdevice(struct net_device *dev)
3320 /* Notifier chain MUST detach us from master device. */ 3310 /* Notifier chain MUST detach us from master device. */
3321 BUG_TRAP(!dev->master); 3311 BUG_TRAP(!dev->master);
3322 3312
3323 free_divert_blk(dev);
3324
3325 /* Finish processing unregister after unlock */ 3313 /* Finish processing unregister after unlock */
3326 net_set_todo(dev); 3314 net_set_todo(dev);
3327 3315
diff --git a/net/core/dv.c b/net/core/dv.c
deleted file mode 100644
index 29ee77f15932..000000000000
--- a/net/core/dv.c
+++ /dev/null
@@ -1,546 +0,0 @@
1/*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * Generic frame diversion
7 *
8 * Authors:
9 * Benoit LOCHER: initial integration within the kernel with support for ethernet
10 * Dave Miller: improvement on the code (correctness, performance and source files)
11 *
12 */
13#include <linux/module.h>
14#include <linux/types.h>
15#include <linux/kernel.h>
16#include <linux/sched.h>
17#include <linux/string.h>
18#include <linux/mm.h>
19#include <linux/socket.h>
20#include <linux/in.h>
21#include <linux/inet.h>
22#include <linux/ip.h>
23#include <linux/udp.h>
24#include <linux/netdevice.h>
25#include <linux/etherdevice.h>
26#include <linux/skbuff.h>
27#include <linux/capability.h>
28#include <linux/errno.h>
29#include <linux/init.h>
30#include <net/dst.h>
31#include <net/arp.h>
32#include <net/sock.h>
33#include <net/ipv6.h>
34#include <net/ip.h>
35#include <asm/uaccess.h>
36#include <asm/system.h>
37#include <asm/checksum.h>
38#include <linux/divert.h>
39#include <linux/sockios.h>
40
41const char sysctl_divert_version[32]="0.46"; /* Current version */
42
43static int __init dv_init(void)
44{
45 return 0;
46}
47module_init(dv_init);
48
49/*
50 * Allocate a divert_blk for a device. This must be an ethernet nic.
51 */
52int alloc_divert_blk(struct net_device *dev)
53{
54 int alloc_size = (sizeof(struct divert_blk) + 3) & ~3;
55
56 dev->divert = NULL;
57 if (dev->type == ARPHRD_ETHER) {
58 dev->divert = kzalloc(alloc_size, GFP_KERNEL);
59 if (dev->divert == NULL) {
60 printk(KERN_INFO "divert: unable to allocate divert_blk for %s\n",
61 dev->name);
62 return -ENOMEM;
63 }
64 dev_hold(dev);
65 }
66
67 return 0;
68}
69
70/*
71 * Free a divert_blk allocated by the above function, if it was
72 * allocated on that device.
73 */
74void free_divert_blk(struct net_device *dev)
75{
76 if (dev->divert) {
77 kfree(dev->divert);
78 dev->divert=NULL;
79 dev_put(dev);
80 }
81}
82
83/*
84 * Adds a tcp/udp (source or dest) port to an array
85 */
86static int add_port(u16 ports[], u16 port)
87{
88 int i;
89
90 if (port == 0)
91 return -EINVAL;
92
93 /* Storing directly in network format for performance,
94 * thanks Dave :)
95 */
96 port = htons(port);
97
98 for (i = 0; i < MAX_DIVERT_PORTS; i++) {
99 if (ports[i] == port)
100 return -EALREADY;
101 }
102
103 for (i = 0; i < MAX_DIVERT_PORTS; i++) {
104 if (ports[i] == 0) {
105 ports[i] = port;
106 return 0;
107 }
108 }
109
110 return -ENOBUFS;
111}
112
113/*
114 * Removes a port from an array tcp/udp (source or dest)
115 */
116static int remove_port(u16 ports[], u16 port)
117{
118 int i;
119
120 if (port == 0)
121 return -EINVAL;
122
123 /* Storing directly in network format for performance,
124 * thanks Dave !
125 */
126 port = htons(port);
127
128 for (i = 0; i < MAX_DIVERT_PORTS; i++) {
129 if (ports[i] == port) {
130 ports[i] = 0;
131 return 0;
132 }
133 }
134
135 return -EINVAL;
136}
137
138/* Some basic sanity checks on the arguments passed to divert_ioctl() */
139static int check_args(struct divert_cf *div_cf, struct net_device **dev)
140{
141 char devname[32];
142 int ret;
143
144 if (dev == NULL)
145 return -EFAULT;
146
147 /* GETVERSION: all other args are unused */
148 if (div_cf->cmd == DIVCMD_GETVERSION)
149 return 0;
150
151 /* Network device index should reasonably be between 0 and 1000 :) */
152 if (div_cf->dev_index < 0 || div_cf->dev_index > 1000)
153 return -EINVAL;
154
155 /* Let's try to find the ifname */
156 sprintf(devname, "eth%d", div_cf->dev_index);
157 *dev = dev_get_by_name(devname);
158
159 /* dev should NOT be null */
160 if (*dev == NULL)
161 return -EINVAL;
162
163 ret = 0;
164
165 /* user issuing the ioctl must be a super one :) */
166 if (!capable(CAP_SYS_ADMIN)) {
167 ret = -EPERM;
168 goto out;
169 }
170
171 /* Device must have a divert_blk member NOT null */
172 if ((*dev)->divert == NULL)
173 ret = -EINVAL;
174out:
175 dev_put(*dev);
176 return ret;
177}
178
179/*
180 * control function of the diverter
181 */
182#if 0
183#define DVDBG(a) \
184 printk(KERN_DEBUG "divert_ioctl() line %d %s\n", __LINE__, (a))
185#else
186#define DVDBG(a)
187#endif
188
189int divert_ioctl(unsigned int cmd, struct divert_cf __user *arg)
190{
191 struct divert_cf div_cf;
192 struct divert_blk *div_blk;
193 struct net_device *dev;
194 int ret;
195
196 switch (cmd) {
197 case SIOCGIFDIVERT:
198 DVDBG("SIOCGIFDIVERT, copy_from_user");
199 if (copy_from_user(&div_cf, arg, sizeof(struct divert_cf)))
200 return -EFAULT;
201 DVDBG("before check_args");
202 ret = check_args(&div_cf, &dev);
203 if (ret)
204 return ret;
205 DVDBG("after checkargs");
206 div_blk = dev->divert;
207
208 DVDBG("befre switch()");
209 switch (div_cf.cmd) {
210 case DIVCMD_GETSTATUS:
211 /* Now, just give the user the raw divert block
212 * for him to play with :)
213 */
214 if (copy_to_user(div_cf.arg1.ptr, dev->divert,
215 sizeof(struct divert_blk)))
216 return -EFAULT;
217 break;
218
219 case DIVCMD_GETVERSION:
220 DVDBG("GETVERSION: checking ptr");
221 if (div_cf.arg1.ptr == NULL)
222 return -EINVAL;
223 DVDBG("GETVERSION: copying data to userland");
224 if (copy_to_user(div_cf.arg1.ptr,
225 sysctl_divert_version, 32))
226 return -EFAULT;
227 DVDBG("GETVERSION: data copied");
228 break;
229
230 default:
231 return -EINVAL;
232 }
233
234 break;
235
236 case SIOCSIFDIVERT:
237 if (copy_from_user(&div_cf, arg, sizeof(struct divert_cf)))
238 return -EFAULT;
239
240 ret = check_args(&div_cf, &dev);
241 if (ret)
242 return ret;
243
244 div_blk = dev->divert;
245
246 switch(div_cf.cmd) {
247 case DIVCMD_RESET:
248 div_blk->divert = 0;
249 div_blk->protos = DIVERT_PROTO_NONE;
250 memset(div_blk->tcp_dst, 0,
251 MAX_DIVERT_PORTS * sizeof(u16));
252 memset(div_blk->tcp_src, 0,
253 MAX_DIVERT_PORTS * sizeof(u16));
254 memset(div_blk->udp_dst, 0,
255 MAX_DIVERT_PORTS * sizeof(u16));
256 memset(div_blk->udp_src, 0,
257 MAX_DIVERT_PORTS * sizeof(u16));
258 return 0;
259
260 case DIVCMD_DIVERT:
261 switch(div_cf.arg1.int32) {
262 case DIVARG1_ENABLE:
263 if (div_blk->divert)
264 return -EALREADY;
265 div_blk->divert = 1;
266 break;
267
268 case DIVARG1_DISABLE:
269 if (!div_blk->divert)
270 return -EALREADY;
271 div_blk->divert = 0;
272 break;
273
274 default:
275 return -EINVAL;
276 }
277
278 break;
279
280 case DIVCMD_IP:
281 switch(div_cf.arg1.int32) {
282 case DIVARG1_ENABLE:
283 if (div_blk->protos & DIVERT_PROTO_IP)
284 return -EALREADY;
285 div_blk->protos |= DIVERT_PROTO_IP;
286 break;
287
288 case DIVARG1_DISABLE:
289 if (!(div_blk->protos & DIVERT_PROTO_IP))
290 return -EALREADY;
291 div_blk->protos &= ~DIVERT_PROTO_IP;
292 break;
293
294 default:
295 return -EINVAL;
296 }
297
298 break;
299
300 case DIVCMD_TCP:
301 switch(div_cf.arg1.int32) {
302 case DIVARG1_ENABLE:
303 if (div_blk->protos & DIVERT_PROTO_TCP)
304 return -EALREADY;
305 div_blk->protos |= DIVERT_PROTO_TCP;
306 break;
307
308 case DIVARG1_DISABLE:
309 if (!(div_blk->protos & DIVERT_PROTO_TCP))
310 return -EALREADY;
311 div_blk->protos &= ~DIVERT_PROTO_TCP;
312 break;
313
314 default:
315 return -EINVAL;
316 }
317
318 break;
319
320 case DIVCMD_TCPDST:
321 switch(div_cf.arg1.int32) {
322 case DIVARG1_ADD:
323 return add_port(div_blk->tcp_dst,
324 div_cf.arg2.uint16);
325
326 case DIVARG1_REMOVE:
327 return remove_port(div_blk->tcp_dst,
328 div_cf.arg2.uint16);
329
330 default:
331 return -EINVAL;
332 }
333
334 break;
335
336 case DIVCMD_TCPSRC:
337 switch(div_cf.arg1.int32) {
338 case DIVARG1_ADD:
339 return add_port(div_blk->tcp_src,
340 div_cf.arg2.uint16);
341
342 case DIVARG1_REMOVE:
343 return remove_port(div_blk->tcp_src,
344 div_cf.arg2.uint16);
345
346 default:
347 return -EINVAL;
348 }
349
350 break;
351
352 case DIVCMD_UDP:
353 switch(div_cf.arg1.int32) {
354 case DIVARG1_ENABLE:
355 if (div_blk->protos & DIVERT_PROTO_UDP)
356 return -EALREADY;
357 div_blk->protos |= DIVERT_PROTO_UDP;
358 break;
359
360 case DIVARG1_DISABLE:
361 if (!(div_blk->protos & DIVERT_PROTO_UDP))
362 return -EALREADY;
363 div_blk->protos &= ~DIVERT_PROTO_UDP;
364 break;
365
366 default:
367 return -EINVAL;
368 }
369
370 break;
371
372 case DIVCMD_UDPDST:
373 switch(div_cf.arg1.int32) {
374 case DIVARG1_ADD:
375 return add_port(div_blk->udp_dst,
376 div_cf.arg2.uint16);
377
378 case DIVARG1_REMOVE:
379 return remove_port(div_blk->udp_dst,
380 div_cf.arg2.uint16);
381
382 default:
383 return -EINVAL;
384 }
385
386 break;
387
388 case DIVCMD_UDPSRC:
389 switch(div_cf.arg1.int32) {
390 case DIVARG1_ADD:
391 return add_port(div_blk->udp_src,
392 div_cf.arg2.uint16);
393
394 case DIVARG1_REMOVE:
395 return remove_port(div_blk->udp_src,
396 div_cf.arg2.uint16);
397
398 default:
399 return -EINVAL;
400 }
401
402 break;
403
404 case DIVCMD_ICMP:
405 switch(div_cf.arg1.int32) {
406 case DIVARG1_ENABLE:
407 if (div_blk->protos & DIVERT_PROTO_ICMP)
408 return -EALREADY;
409 div_blk->protos |= DIVERT_PROTO_ICMP;
410 break;
411
412 case DIVARG1_DISABLE:
413 if (!(div_blk->protos & DIVERT_PROTO_ICMP))
414 return -EALREADY;
415 div_blk->protos &= ~DIVERT_PROTO_ICMP;
416 break;
417
418 default:
419 return -EINVAL;
420 }
421
422 break;
423
424 default:
425 return -EINVAL;
426 }
427
428 break;
429
430 default:
431 return -EINVAL;
432 }
433
434 return 0;
435}
436
437
438/*
439 * Check if packet should have its dest mac address set to the box itself
440 * for diversion
441 */
442
443#define ETH_DIVERT_FRAME(skb) \
444 memcpy(eth_hdr(skb), skb->dev->dev_addr, ETH_ALEN); \
445 skb->pkt_type=PACKET_HOST
446
447void divert_frame(struct sk_buff *skb)
448{
449 struct ethhdr *eth = eth_hdr(skb);
450 struct iphdr *iph;
451 struct tcphdr *tcph;
452 struct udphdr *udph;
453 struct divert_blk *divert = skb->dev->divert;
454 int i, src, dst;
455 unsigned char *skb_data_end = skb->data + skb->len;
456
457 /* Packet is already aimed at us, return */
458 if (!compare_ether_addr(eth->h_dest, skb->dev->dev_addr))
459 return;
460
461 /* proto is not IP, do nothing */
462 if (eth->h_proto != htons(ETH_P_IP))
463 return;
464
465 /* Divert all IP frames ? */
466 if (divert->protos & DIVERT_PROTO_IP) {
467 ETH_DIVERT_FRAME(skb);
468 return;
469 }
470
471 /* Check for possible (maliciously) malformed IP frame (thanks Dave) */
472 iph = (struct iphdr *) skb->data;
473 if (((iph->ihl<<2)+(unsigned char*)(iph)) >= skb_data_end) {
474 printk(KERN_INFO "divert: malformed IP packet !\n");
475 return;
476 }
477
478 switch (iph->protocol) {
479 /* Divert all ICMP frames ? */
480 case IPPROTO_ICMP:
481 if (divert->protos & DIVERT_PROTO_ICMP) {
482 ETH_DIVERT_FRAME(skb);
483 return;
484 }
485 break;
486
487 /* Divert all TCP frames ? */
488 case IPPROTO_TCP:
489 if (divert->protos & DIVERT_PROTO_TCP) {
490 ETH_DIVERT_FRAME(skb);
491 return;
492 }
493
494 /* Check for possible (maliciously) malformed IP
495 * frame (thanx Dave)
496 */
497 tcph = (struct tcphdr *)
498 (((unsigned char *)iph) + (iph->ihl<<2));
499 if (((unsigned char *)(tcph+1)) >= skb_data_end) {
500 printk(KERN_INFO "divert: malformed TCP packet !\n");
501 return;
502 }
503
504 /* Divert some tcp dst/src ports only ?*/
505 for (i = 0; i < MAX_DIVERT_PORTS; i++) {
506 dst = divert->tcp_dst[i];
507 src = divert->tcp_src[i];
508 if ((dst && dst == tcph->dest) ||
509 (src && src == tcph->source)) {
510 ETH_DIVERT_FRAME(skb);
511 return;
512 }
513 }
514 break;
515
516 /* Divert all UDP frames ? */
517 case IPPROTO_UDP:
518 if (divert->protos & DIVERT_PROTO_UDP) {
519 ETH_DIVERT_FRAME(skb);
520 return;
521 }
522
523 /* Check for possible (maliciously) malformed IP
524 * packet (thanks Dave)
525 */
526 udph = (struct udphdr *)
527 (((unsigned char *)iph) + (iph->ihl<<2));
528 if (((unsigned char *)(udph+1)) >= skb_data_end) {
529 printk(KERN_INFO
530 "divert: malformed UDP packet !\n");
531 return;
532 }
533
534 /* Divert some udp dst/src ports only ? */
535 for (i = 0; i < MAX_DIVERT_PORTS; i++) {
536 dst = divert->udp_dst[i];
537 src = divert->udp_src[i];
538 if ((dst && dst == udph->dest) ||
539 (src && src == udph->source)) {
540 ETH_DIVERT_FRAME(skb);
541 return;
542 }
543 }
544 break;
545 }
546}
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 02534131d88e..1e75b1585460 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -21,10 +21,6 @@ extern __u32 sysctl_rmem_max;
21 21
22extern int sysctl_core_destroy_delay; 22extern int sysctl_core_destroy_delay;
23 23
24#ifdef CONFIG_NET_DIVERT
25extern char sysctl_divert_version[];
26#endif /* CONFIG_NET_DIVERT */
27
28#ifdef CONFIG_XFRM 24#ifdef CONFIG_XFRM
29extern u32 sysctl_xfrm_aevent_etime; 25extern u32 sysctl_xfrm_aevent_etime;
30extern u32 sysctl_xfrm_aevent_rseqth; 26extern u32 sysctl_xfrm_aevent_rseqth;
@@ -105,16 +101,6 @@ ctl_table core_table[] = {
105 .mode = 0644, 101 .mode = 0644,
106 .proc_handler = &proc_dointvec 102 .proc_handler = &proc_dointvec
107 }, 103 },
108#ifdef CONFIG_NET_DIVERT
109 {
110 .ctl_name = NET_CORE_DIVERT_VERSION,
111 .procname = "divert_version",
112 .data = (void *)sysctl_divert_version,
113 .maxlen = 32,
114 .mode = 0444,
115 .proc_handler = &proc_dostring
116 },
117#endif /* CONFIG_NET_DIVERT */
118#ifdef CONFIG_XFRM 104#ifdef CONFIG_XFRM
119 { 105 {
120 .ctl_name = NET_CORE_AEVENT_ETIME, 106 .ctl_name = NET_CORE_AEVENT_ETIME,