diff options
author | Andreas Henriksson <andreas@fatal.se> | 2016-01-06 18:42:14 +0100 |
---|---|---|
committer | Andreas Henriksson <andreas@fatal.se> | 2016-01-06 18:42:14 +0100 |
commit | 5941da738b84471b6eb89daf1427a80fa4934491 (patch) | |
tree | 1821561c26ff4ec9e575925118b81d78f1917fa7 | |
parent | 7517228145310a29b7cb7f4bddccb1b70df347eb (diff) |
Import Debian version 2.0
vlan (2.0) experimental; urgency=medium
* Non-maintainer upload.
* Make this a native package and replace the previous upstream source
with Andrew Shaduras vconfig compatibility script. (Closes: #501402)
* Update package description to better describe this package content.
* Rewrite debian/rules
* Bump Standards-Version to 3.9.6
* Update debian/network/ contents to not rely on vconfig.
- in preparation for potentian future dropping vconfig compat script.
* Update debian/copyright for the new package content.
* Make vconfig always print a deprecated notice to stderr when executed.
79 files changed, 76 insertions, 17169 deletions
diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index 85c60bf..0000000 --- a/CHANGELOG +++ /dev/null @@ -1,363 +0,0 @@ -This file should be prepended to each time a release is made. - -Date: Sept 30, 2003 -Version: 1.8 -Kernel Version: 2.4.21+ -Changes: Compile fixes for newer gcc, VLAN rework, inclusion of entire - Candela Technologies kernel networking patch (MAC-VLANs too). - -Date: March 11, 2003 -Version: 1.7 -Kernel Version: 2.4.14+ -Changes: Added Alex's MAC-Vlan code to the repository. See README for more. - - -Date: March 24, 2002 -Version: 1.6 -Kernel Version: 2.4.14+ -Changes: Removed 2.4 kernel patch from VLAN distribution..it's now in the - standard linux kernel. Other updates include vconfig changes - to fix some compile problems, and to enable cross-compiling to - ARM (this assumes you are using the Intrinsyc cross-compiler in - it's standard location). - - -Date: Oct 20, 2001 -Version: 1.5 -Kernel Version: 2.4.12-pre5 -Changes: - Mostly added other peoples fixes and patches (thanks folks!) - Finally fixed mc-list leakage (Ard van Breemen) - Flush mc-list at vlan-destory (Ard van Breemen) - Add vconfig man page to distribution (Ard van Breemen) - Fix problem with /proc and renaming VLAN devices (af AT devcon D.T net) - Add relatively large change by Nick Eggelston that makes VLAN - devices more transparent to tools like tcpdump and other raw - packet snoopers. This will only be enabled when the REORDER_HDR - flag is set. - - -Date: August 16, 2001 -Version: 1.4 -Kernel Version: 2.4.9-pre4 -Status: Should be stable, but a decent amount of rework went into - this one... -Changes: - Code should no longer require /proc interface in order to - get at the IOCTLs. The IOCTLs are now tied to sockets. - When using modules, it may auto-load now, too... - - Fixed format string error in proc fs display. - - Fixed crash bug relating to memory allocation with locks - held (we now use GF_ATOMIC). - - hard_start_xmit will now grow the packet header if there - is not enough headroom. This may fix an MPLS-over-VLAN problem, - though the real solution is to make MPLS allocate - more headroom anyway... - - vconfig was changed to use the new IOCTL API, and the old - vconfig WILL NOT WORK with this or any newer patches... - - -Date: August 5, 2001 -Version: 1.0.3 -Kernel Version: 2.4.7 -Status: Should be stable, but a decent amount of rework went into - this one... -Changes: - Re-worked code to comply with linux network code gurus' - wishes. This included several boundary case fixes, including - some that could crash your kernel. - - The default naming scheme is eth0.5 now, for VID == 5 on - eth0. Use vconfig to change the naming scheme if you want. - - There were *NO* changes to the 2.2 series patch, and there - probably won't be any more changes to it, ever! - - -Date: April 16, 2001 -Version: 1.0.1 -Kernel Version: 2.2.18/19, 2.4.3-pre3 -Status: Very similar to 1.0.0, should be relatively stable. -Changes: - Incorporated a fix for changing a MAC on a VLAN, it now - correctly sets PACKET_HOST. - Thanks to Martin Bokaemper for this one. - - The 2.4 series patch should now compile as a module, thanks - to a tweak from someone who's mail I have lost! Anyway, 3 - cheers to the un-named coder! - - There were *NO* changes to the 2.2 series patch, though I did - verify that it seems to work fine with the 2.2.19 kernel. - - - -Date: January 14, 2001 -Version: 1.0.0 -Kernel Version: 2.2.18, 2.4.0 -Status: Fairly similar to 0.0.15, should be relatively stable. -Changes: - - Really fixed (and tested) MAC change-ability. When you set the - MAC address on a VLAN, it will also attempt to set the underlying - device to PROMISCious mode (otherwise, the VLAN will not - receive any packets.) - - Hashed-device lookup is disabled by default because some people - had trouble with the 'lo' device. Please feel free to re-enable by - editing the line in net/core/dev. - (search for #define BEN_FAST_DEV_LOOKUP). - - vconfig should warn when creating VLAN 1, because that VLAN is - not compatible with many switches. - - -Date: December 31, 2000 -Version: 0.0.15 -Kernel Version: 2.2.18, 2.4.prerelease -Status: This one is pretty fresh..beware, especially the 2.4 patch. -Changes: - - Merged most of Matti Aarnio's patches. This means no significant patch - to eth.c now, and will help port VLANs to non-ethernet devices - (ie ppp, TokenRing??). - - Setting the MAC address should work now..I think it was broken before. - - Miscellaneous code re-organization to make patches to existing files smaller. - - -Date: October 26, 2000 -Version: 0.0.14 -Kernel Version: 2.2.17, 2.4.pre9 -Status: Seems stable. -Changes: - Removed vlan-space-per-machine, so vlan-space-per-NIC is mandatory now. - - DHCP might work now, as I've added support for encapsulating regular ethernet - frames if they are sent to the vlan driver. - - Fixed up the name/index hashing stuff to handle changing the name on a device. - - Took out default VID & default priority, as their usefullness was in question, - and the code was broken anyway. - - -Date: October 11, 2000 -Version: 0.0.13 -Kernel Version: 2.2.17, 2.4.pre9 -Status: BUSTED!! Don't use it. -Changes: - Added support for MULTICAST to the VLAN devices. Thanks to - Gleb & Co for most of that code. - - Added the ability to set the MAC address on the VLAN. For now, - you'll either need to set your Ethernet NIC into PROMISC mode, or - maybe figure out some multi-cast ethernet address to set on the - NIC. This has not been tested well at all. - - Added a hashed device-name lookup scheme. This greatly speeds - up ifconfig -a. I was able to run an ifconfig -a in 20 seconds on a - Celeron 500, with 4000 vlan devices configured!! - - Added vlan_test.pl to help me find dumb bugs. Feel free to make this - much more powerful, and send the code back to me! - - vconfig.c has been converted to C code now, instead of C++. - Thanks to MATHIEU. - - Significantly cleaned up the code w/out decreasing any useful - functionality, I believe. - - Removed the dhcp stuff from the VLAN distribution. - - -Date: August 27, 2000 -Version: 0.0.12 -Kernel Version: 2.2.16, 2.4.pre7 -Status: This one turned out pretty stable, no known bugs. -Changes: - - Added ability to re-order the VLAN packet so that it looks - like a real ethernet packet for the ingress pathway. This - should help DHCP and other programs that insist on reading - the raw buffer and then make assumptions about byte offsets. - I don't have a good way to test this fully, so consider it - experimental :) This behavior can be changed at run-time, - and is set on a per-VLAN basis. The default is NOT to reorder - the header, which has been the only behavior up untill this - point. The vconfig program can set/clear the flag, by using - a VLAN IOCTL. You can read the flag's value from the - /proc/net/vlan/vlan* files. - - You can also set a default priority on a NON-VLAN device. - This priority will only be used when the default_VID for the - device is set as well. This priority won't be mapped anywhere, - just copied straight into the skb->priority. It is a uint16. - - The 2.3 patch is now the 2.4 patch, and it has been tested - against 2.4.pre7. - - -Date: April 23, 2000 -Version: 0.0.11 -Kernel Version: 2.2.13 & 2.2.14, 2.3.99 -Status: As of August 27, this seems like a very stable patch. -Changes: - Added real support for PRIORITY. Through IOCTL calls (see the - vconfig program), you can set explicit ingress and egress mappings - to/from the VLAN QOS bits and the sk_buff->priority field. This - is not tested very well, as I don't know much about how people really - use the priority field... Took out the round-robin aggretation that - went in in rls 0.10, as it was mainly just a hack, and doing link - aggregation at a lower level and then putting VLAN on top of that - virtual device probably makes more sense. The vconfig program - changed to support the new features..here's it's new usage:<br> - - Usage: add [interface-name] [vlan_id] - rem [vlan-name] - set_dflt [interface-name] [vlan_id] - add_port [port-name] [vlan_id] - rem_port [port-name] [vlan_id] - set_egress_map [vlan-name] [skb_priority] [vlan_qos] - set_ingress_map [vlan-name] [skb_priority] [vlan_qos] - set_name_type [name-type] - set_bind_mode [bind-type] - - * The [interface-name] is the name of the ethernet card that hosts - the VLAN you are talking about. - * The port-name is the name of the physical interface that a VLAN - may be attached to. - * The vlan_id is the identifier (0-4095) of the VLAN you are operating on. - * skb_priority is the priority in the socket buffer (sk_buff). - * vlan_qos is the 3 bit priority in the VLAN header - * name-type: VLAN_PLUS_VID (vlan0005), VLAN_PLUS_VID_NO_PAD (vlan5), - DEV_PLUS_VID (eth0.0005), DEV_PLUS_VID_NO_PAD (eth0.5) - * bind-type: PER_DEVICE # Allows vlan 5 on eth0 and eth1 to be unique. - PER_KERNEL # Forces vlan 5 to be unique across all devices. - - The 2.3 patches have been ported foward to 2.3.99, thanks to - Patrick for the vlanproc.c updates! - - - -Date: February 26, 2000 -Version: 0.0.10 -Kernel Version: 2.2.13 & 2.2.14, 2.3.47 -Status: Added several new features in the critical path...beware! -Changes: - Added support for PRIORITY. The way it works is that the lower - 3 bits of the skb->priority are set into the PRIORITY field in - the VLAN header. No special handling is done with priority, - but it should be handled by other switches and such. This has - not been tested, but the default case (no priority in the skb) - seems to work at least. - - The big change is that you can now aggregate several ethernet - ports in a single VLAN. The packets will be transmitted in a - round robin fashion. In order for this to work, you have - to change the MAC addresses on all cards to the same thing, - and put the cards in promiscious mode (because most drivers don't - __really__ honor the request to set the MAC all the way to - the NIC. This works with two different speed NICs, but I think - it will only be really useful if they are the same speed. Here - is how I set them up in my test environment: - - ifdown eth1 - ifconfig eth1 hw ether 00:40:05:41:00:5e # This is the MAC of eth0 - ifup eth1 - - ifconfig eth1 promisc - - /usr/local/bin/vconfig add eth0 5 - /usr/local/bin/vconfig add_port eth1 5 - ifconfig vlan0005 192.168.2.1 - - On my other machine, I have this: - ifdown eth1 - ifconfig eth1 hw ether 00:48:54:66:68:68 # This is the MAC of eth0 - ifup eth1 - - ifconfig eth1 promisc - - /usr/local/bin/vconfig add eth0 5 - /usr/local/bin/vconfig add_port eth1 5 - ifconfig vlan0005 192.168.2.3 - - Note that there are now two patches, one for the 2.2 series, - and one for the 2.3 series. - - -Date: February 6, 2000 -Version: 0.0.9 -Kernel Version: 2.2.13 & 2.2.14 -Status: Mostly solid. May be issues with adding/removing, but it - works at least most of the time. -Changes: Changed the way vlan names are created: They now have the - VID in the name. You can revert to the old behavior by - changing an #define in the 802_18/vlan.h file. Changed - the destruction process for vlans. Not sure if this fixed the - kernel lock problem I found while adding/removing VLAN devices, - and also hacking with DHCP, but the problem seemed to go away. - Added patch to dhcp to allow it to work with VLANs. However, - I don't grok DHCP as well as might be desired, so use at your - own risk!! Added some debugging code (you have to compile - it in if you need it) - - -Date: December 22, 1999 -Version: 0.0.8 -Kernel Version: 2.2.13+ -Status: ARP seems to fail in certain cases (but not on my machines.) -Changes: Fixed compile warnings and a linking problem due to #ifdef's. - No major changes in functionality or performance. - -Date: December 5, 1999 -Version: 0.0.7 -Kernel Version: 2.2.13+ -Status: ARP seems to fail in certain cases (but not on my machines.) - Several (many?) ethernet drivers can't handle the extra 4 bytes - of VLAN, so the MTU on the network may have to be set to 1496, - or fix the ethernet drivers!! -Changes: Re-wrote the /proc code to never go above 4k buffers. This means - that each port now has it's own file entry. Fixed crash bug with - removing VLAN devices. Byte and pkt counters are now updated correctly, - and are found in the /proc/net/vlan/<device> file. - - -Date: October 20, 1999 -Version: 0.0.6 -Kernel Version: 2.2.10+ -Status: ping -f still kills one of my machines, but it takes longer...and I'm - not sure if its the fault of the VLAN code, or maybe some hardware problem. -Changes: Coded around an extraneous skb alloc/free so that there should be no - extra buffer copying as compared to an ethernet interface, unless the - vlan device spans more than one interface. Put #ifdef around all printk - debugging calls, at least for non-control code (ie no more printk in the - critical paths.) - - -Date: October 19, 1999 -Version: 0.0.6 -Kernel Version: 2.2.10 -Status: Ping & FTP work, ping -f kills it after some time...not sure why yet. -Changes: Got tcpdump working with VLAN pkts (use the -e option). Got basic VLAN - functionality working, though problems remain, including a KERNEL CRASH - that can be induced by ping -f on one of the vlan interfaces. My test - setup consists of two linux boxes, each running my modified kernel. - Since I have no third-party implementation to test against, it is likely - the code is not too right yet!! - Performance isn't all that great: Running a Cyrix 155 <-> a Cyrix 233, - connected through a 10bt hub, I get 910 Mbps on regular ethernet, - and only 650 Mbps on the VLAN device. This was using a 30 MB file. - - -Date: Long time ago. -Version: 0.0.3 -Kernel Version: 2.2.2 -Status: Definately broken, but lots of code in there!! -Changes: Initial partially functional release (not very functional.) diff --git a/CVS/Entries b/CVS/Entries deleted file mode 100644 index d86968c..0000000 --- a/CVS/Entries +++ /dev/null @@ -1,17 +0,0 @@ -/vlan_2.2.patch/1.7/Mon Jan 15 03:30:45 2001// -/vconfig.8/1.1/Sat Oct 20 22:57:02 2001// -/vconfig.spec/1.1/Thu Apr 18 00:11:42 2002// -/vlan_test.pl/1.5/Wed Aug 28 08:11:49 2002// -/vlan_test2.pl/1.1/Wed Nov 6 08:34:37 2002// -D/libpcap-0.4//// -D/tcpdump-3.4//// -/howto.html/1.2/Fri Jul 4 16:53:40 2003// -/vlan.html/1.26/Tue Apr 8 15:44:00 2003// -/vconfig.c/1.7/Thu Jul 31 22:43:08 2003// -/macvlan_config.c/1.4/Tue Aug 12 19:36:36 2003// -/CHANGELOG/1.19/Tue Sep 30 21:01:55 2003// -/MakeInclude/1.8/Mon Aug 25 17:08:18 2003// -/Makefile/1.7/Tue Sep 30 21:04:14 2003// -/README/1.7/Tue Sep 30 21:03:42 2003// -/candela_2.4.21.patch/1.4/Tue Sep 30 21:05:04 2003// -D/contrib//// diff --git a/CVS/Repository b/CVS/Repository deleted file mode 100644 index d56118f..0000000 --- a/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan diff --git a/CVS/Root b/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/MakeInclude b/MakeInclude deleted file mode 100644 index f518572..0000000 --- a/MakeInclude +++ /dev/null @@ -1,35 +0,0 @@ -# -*-Makefile-*- - - -# This is the version of the make utility you wish to use. -# On some systems (BSD?) you might want this to be gmake. -#MAKE=gmake -MAKE=make - - -VERSION=1.0.2 - -CUR_DATE=`date '+%y.%m.%d'` - -ifeq "${PLATFORM}" "" - PLATFORM=x86 -endif - -## You may need to change this linux/include part. -CCFLAGS = -g -D_GNU_SOURCE -Wall -I${HOME}/linux/include -LDLIBS = # -lm #-lnsl # -lsocket - -ARM_TC_BIN = ${HOME}/Intrinsyc/bin -ARM_TC_LIB = ${HOME}/Intrinsyc/lib - -ifeq "${PLATFORM}" "ARM" - #echo "Building for ARM platform." - STRIP=${ARM_TC_BIN}/arm-linux-strip - CC = ${ARM_TC_BIN}/arm-linux-gcc # this is generally the c compiler, unused AFAIK - CCC = ${ARM_TC_BIN}/arm-linux-g++ # this is generally the c++ compiler -else - #echo "Building for x86 platform." - STRIP=strip - CC = gcc # this is generally the c compiler, unused AFAIK - CCC = g++ # this is generally the c++ compiler -endif diff --git a/Makefile b/Makefile deleted file mode 100644 index 23bb374..0000000 --- a/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# makefile template - -include MakeInclude - -LDLIBS = - -VLAN_OBJS = vconfig.o - -ALL_OBJS = ${VLAN_OBJS} - -VCONFIG = vconfig #program to be created - - -all: ${VCONFIG} macvlan_config - - -#This is pretty silly.. -vconfig.h: Makefile - touch vconfig.h - - -$(VCONFIG): $(VLAN_OBJS) - $(CC) $(CCFLAGS) $(LDFLAGS) -o $(VCONFIG) $(VLAN_OBJS) $(LDLIBS) - $(STRIP) $(VCONFIG) - -macvlan_config: macvlan_config.c - $(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< - -$(ALL_OBJS): %.o: %.c %.h - @echo " " - @echo "Making $<" - $(CC) $(CCFLAGS) -c $< - -clean: - rm -f *.o - -purge: clean - rm -f *.flc ${VCONFIG} macvlan_config vconfig.h - rm -f *~ - - - - - @@ -1,12 +0,0 @@ -The MAC vlan stuff is primarily the work of, and is copy-righted (GPL) -by: - -# (C) Copyright 2001 -# Alex Zeffertt, Cambridge Broadband Ltd, ajz@cambridgebroadband.com - -However, I (Ben) reworked the MAC-VLAN code extensively, including re-writing -all of the locking code. So, any complaints & bugs should come to me. - - ---Ben Greear (greearb@candelatech.com) -http://www.candelatech.com/~greear diff --git a/candela_2.4.21.patch b/candela_2.4.21.patch deleted file mode 100644 index 8b2f320..0000000 --- a/candela_2.4.21.patch +++ /dev/null @@ -1,6911 +0,0 @@ ---- linux-2.4.21/include/linux/if.h 2003-06-13 07:51:38.000000000 -0700 -+++ linux-2.4.21.amds/include/linux/if.h 2003-07-30 16:27:15.000000000 -0700 -@@ -48,6 +48,12 @@ - - /* Private (from user) interface flags (netdevice->priv_flags). */ - #define IFF_802_1Q_VLAN 0x1 /* 802.1Q VLAN device. */ -+#define IFF_PKTGEN_RCV 0x2 /* Registered to receive & consume Pktgen skbs */ -+#define IFF_ACCEPT_LOCAL_ADDRS 0x4 /** Accept pkts even if they come from a local -+ * address. This lets use send pkts to ourselves -+ * over external interfaces (when used in conjunction -+ * with SO_BINDTODEVICE -+ */ - - - #define IF_GET_IFACE 0x0001 /* for querying only */ ---- linux-2.4.21/include/linux/netdevice.h 2003-06-13 07:51:38.000000000 -0700 -+++ linux-2.4.21.amds/include/linux/netdevice.h 2003-07-30 16:27:20.000000000 -0700 -@@ -296,7 +296,9 @@ - - unsigned short flags; /* interface flags (a la BSD) */ - unsigned short gflags; -- unsigned short priv_flags; /* Like 'flags' but invisible to userspace. */ -+ unsigned short priv_flags; /* Like 'flags' but invisible to userspace, -+ * see: if.h for flag definitions. -+ */ - unsigned short unused_alignment_fixer; /* Because we need priv_flags, - * and we want to be 32-bit aligned. - */ -@@ -422,12 +424,20 @@ - int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); - int (*accept_fastpath)(struct net_device *, struct dst_entry*); - -+#ifdef CONFIG_NET_SKB_RECYCLING -+ int (*skb_recycle) (struct sk_buff *skb); -+ void (*mem_reclaim) (struct net_device *dev); -+#endif - /* open/release and usage marking */ - struct module *owner; - - /* bridge stuff */ - struct net_bridge_port *br_port; - -+#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE) -+ struct macvlan_port *macvlan_priv; -+#endif -+ - #ifdef CONFIG_NET_FASTROUTE - #define NETDEV_FASTROUTE_HMASK 0xF - /* Semi-private data. Keep it at the end of device struct. */ -@@ -438,6 +448,7 @@ - /* this will get initialized at each interface type init routine */ - struct divert_blk *divert; - #endif /* CONFIG_NET_DIVERT */ -+ - }; - - ---- linux-2.4.21/net/core/dev.c 2003-06-13 07:51:39.000000000 -0700 -+++ linux-2.4.21.amds/net/core/dev.c 2003-07-30 16:20:41.000000000 -0700 -@@ -1,4 +1,4 @@ --/* -+/* -*-linux-c-*- - * NET3 Protocol independent device support routines. - * - * This program is free software; you can redistribute it and/or -@@ -82,6 +82,7 @@ - #include <linux/interrupt.h> - #include <linux/if_ether.h> - #include <linux/netdevice.h> -+#include <linux/ethtool.h> - #include <linux/etherdevice.h> - #include <linux/notifier.h> - #include <linux/skbuff.h> -@@ -109,6 +110,11 @@ - #endif - - -+#if defined(CONFIG_NET_PKTGEN) || defined(CONFIG_NET_PKTGEN_MODULE) -+#include "pktgen.h" -+#endif -+ -+ - /* This define, if set, will randomly drop a packet when congestion - * is more than moderate. It helps fairness in the multi-interface - * case when one of them is a hog, but it kills performance for the -@@ -1131,7 +1137,7 @@ - =======================================================================*/ - - int netdev_max_backlog = 300; --int weight_p = 64; /* old backlog weight */ -+int weight_p = 64; /* old backlog weight */ - /* These numbers are selected based on intuition and some - * experimentatiom, if you have more scientific way of doing this - * please go ahead and fix things. -@@ -1423,6 +1429,19 @@ - } - - -+#if defined(CONFIG_NET_PKTGEN) || defined(CONFIG_NET_PKTGEN_MODULE) -+#warning "Compiling dev.c for pktgen."; -+ -+int (*handle_pktgen_hook)(struct sk_buff *skb) = NULL; -+ -+static __inline__ int handle_pktgen_rcv(struct sk_buff* skb) { -+ if (handle_pktgen_hook) { -+ return handle_pktgen_hook(skb); -+ } -+ return -1; -+} -+#endif -+ - #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) - void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL; - #endif -@@ -1445,6 +1464,20 @@ - return ret; - } - -+#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE) -+/* Returns >= 0 if we consume the packet. Otherwise, let -+ * it fall through the rest of the packet processing. -+ */ -+int (*macvlan_handle_frame_hook)(struct sk_buff *skb) = NULL; -+#endif -+ -+/* Returns >= 0 if we consume the packet. Otherwise, let -+ * it fall through the rest of the packet processing. -+ */ -+static __inline__ int handle_macvlan(struct sk_buff *skb) -+{ -+ return macvlan_handle_frame_hook(skb); -+} - - #ifdef CONFIG_NET_DIVERT - static inline int handle_diverter(struct sk_buff *skb) -@@ -1493,11 +1526,23 @@ - } - } - -+#if defined(CONFIG_NET_PKTGEN) || defined(CONFIG_NET_PKTGEN_MODULE) -+ if ((skb->dev->priv_flags & IFF_PKTGEN_RCV) && -+ (handle_pktgen_rcv(skb) >= 0)) { -+ /* Pktgen may consume the packet, no need to send -+ * to further protocols. -+ */ -+ return 0; -+ } -+#endif -+ -+ - #ifdef CONFIG_NET_DIVERT - if (skb->dev->divert && skb->dev->divert->divert) - ret = handle_diverter(skb); - #endif /* CONFIG_NET_DIVERT */ -- -+ -+ - #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) - if (skb->dev->br_port != NULL && - br_handle_frame_hook != NULL) { -@@ -1505,6 +1550,22 @@ - } - #endif - -+#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE) -+ if (skb->dev->macvlan_priv != NULL && -+ macvlan_handle_frame_hook != NULL) { -+ if (handle_macvlan(skb) >= 0) { -+ /* consumed by mac-vlan...it would have been -+ * re-sent to this method with a different -+ * device... -+ */ -+ return 0; -+ } -+ else { -+ /* Let it fall through and be processed normally */ -+ } -+ } -+#endif -+ - for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) { - if (ptype->type == type && - (!ptype->dev || ptype->dev == skb->dev)) { -@@ -1618,20 +1679,45 @@ - local_irq_enable(); - - dev = list_entry(queue->poll_list.next, struct net_device, poll_list); -- -+#define ORIGINAL_NAPI_ALGORITHM -+#ifdef ORIGINAL_NAPI_ALGORITHM - if (dev->quota <= 0 || dev->poll(dev, &budget)) { - local_irq_disable(); - list_del(&dev->poll_list); - list_add_tail(&dev->poll_list, &queue->poll_list); - if (dev->quota < 0) -- dev->quota += dev->weight; -- else -- dev->quota = dev->weight; -+ dev->quota += dev->weight; -+ else -+ dev->quota = dev->weight; - } else { - dev_put(dev); - local_irq_disable(); - } -- } -+#else -+ /* This scheme should allow devices to build up 2x their weight in quota -+ * credit. Heavy users will only get their normal quota. This should -+ * help let bursty traffic get higher priority. --Ben -+ */ -+ if (dev->poll(dev, &budget)) { -+ /* More to do, put these guys back on the poll list */ -+ local_irq_disable(); -+ list_del(&dev->poll_list); -+ list_add_tail(&dev->poll_list, &queue->poll_list); -+ dev->quota = dev->weight; -+ } -+ else { -+ /* These guys are done, they come off of the poll list */ -+ if (dev->quota >= dev->weight) { -+ dev->quota = (dev->weight << 1); /* max quota of 2x weight */ -+ } -+ else { -+ dev->quota += dev->weight; -+ } -+ dev_put(dev); -+ local_irq_disable(); -+ } -+#endif -+ } - - local_irq_enable(); - br_read_unlock(BR_NETPROTO_LOCK); -@@ -2183,11 +2269,70 @@ - notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); - return 0; - -+ case SIOCSIFWEIGHT: -+ if (ifr->ifr_qlen < 0) -+ return -EINVAL; -+ dev->weight = ifr->ifr_qlen; -+ return 0; -+ -+ case SIOCGIFWEIGHT: -+ ifr->ifr_qlen = dev->weight; -+ return 0; -+ -+ case SIOCSACCEPTLOCALADDRS: -+ if (ifr->ifr_flags) { -+ dev->priv_flags |= IFF_ACCEPT_LOCAL_ADDRS; -+ } -+ else { -+ dev->priv_flags &= ~IFF_ACCEPT_LOCAL_ADDRS; -+ } -+ return 0; -+ -+ case SIOCGACCEPTLOCALADDRS: -+ if (dev->priv_flags & IFF_ACCEPT_LOCAL_ADDRS) { -+ ifr->ifr_flags = 1; -+ } -+ else { -+ ifr->ifr_flags = 0; -+ } -+ return 0; -+ - /* - * Unknown or private ioctl - */ - - default: -+ /* Handle some generic ethtool commands here */ -+ if (cmd == SIOCETHTOOL) { -+ u32 cmd = 0; -+ if (copy_from_user(&cmd, ifr->ifr_data, sizeof(cmd))) { -+ return -EFAULT; -+ } -+ -+ if (cmd == ETHTOOL_GNDSTATS) { -+ -+ struct ethtool_ndstats* nds = (struct ethtool_ndstats*)(ifr->ifr_data); -+ -+ /* Get net-device stats struct, will save it in the space -+ * pointed to by the ifr->flags number. Would like to use -+ * ethtool, but it seems to require specific driver support, -+ * when this is a general purpose netdevice request... -+ */ -+ struct net_device_stats *stats = dev->get_stats(dev); -+ if (stats) { -+ if (copy_to_user(nds->data, stats, sizeof(*stats))) { -+ return -EFAULT; -+ } -+ } -+ else { -+ return -EOPNOTSUPP; -+ } -+ return 0; -+ } -+ } -+ -+ -+ - if ((cmd >= SIOCDEVPRIVATE && - cmd <= SIOCDEVPRIVATE + 15) || - cmd == SIOCBONDENSLAVE || -@@ -2280,6 +2425,8 @@ - case SIOCGIFMAP: - case SIOCGIFINDEX: - case SIOCGIFTXQLEN: -+ case SIOCGIFWEIGHT: -+ case SIOCGACCEPTLOCALADDRS: - dev_load(ifr.ifr_name); - read_lock(&dev_base_lock); - ret = dev_ifsioc(&ifr, cmd); -@@ -2343,6 +2490,8 @@ - case SIOCBONDSLAVEINFOQUERY: - case SIOCBONDINFOQUERY: - case SIOCBONDCHANGEACTIVE: -+ case SIOCSIFWEIGHT: -+ case SIOCSACCEPTLOCALADDRS: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - dev_load(ifr.ifr_name); ---- linux-2.4.21/net/core/pktgen.c 2002-11-28 15:53:15.000000000 -0800 -+++ linux-2.4.21.amds/net/core/pktgen.c 2003-07-30 16:20:41.000000000 -0700 -@@ -1,9 +1,8 @@ - /* -*-linux-c-*- -- * $Id: candela_2.4.21.patch,v 1.4 2003/09/30 21:05:04 greear Exp $ -- * pktgen.c: Packet Generator for performance evaluation. - * - * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se> - * Uppsala University, Sweden -+ * 2002 Ben Greear <greearb@candelatech.com> - * - * A tool for loading the network with preconfigurated packets. - * The tool is implemented as a linux module. Parameters are output -@@ -21,30 +20,32 @@ - * Added multiskb option 020301 --DaveM - * Scaling of results. 020417--sigurdur@linpro.no - * Significant re-work of the module: -- * * Updated to support generation over multiple interfaces at once -- * by creating 32 /proc/net/pg* files. Each file can be manipulated -- * individually. -+ * * Convert to threaded model to more efficiently be able to transmit -+ * and receive on multiple interfaces at once. - * * Converted many counters to __u64 to allow longer runs. - * * Allow configuration of ranges, like min/max IP address, MACs, - * and UDP-ports, for both source and destination, and can - * set to use a random distribution or sequentially walk the range. -- * * Can now change some values after starting. -+ * * Can now change most values after starting. - * * Place 12-byte packet in UDP payload with magic number, -- * sequence number, and timestamp. Will write receiver next. -- * * The new changes seem to have a performance impact of around 1%, -- * as far as I can tell. -+ * sequence number, and timestamp. -+ * * Add receiver code that detects dropped pkts, re-ordered pkts, and -+ * latencies (with micro-second) precision. -+ * * Add IOCTL interface to easily get counters & configuration. - * --Ben Greear <greearb@candelatech.com> - * - * Renamed multiskb to clone_skb and cleaned up sending core for two distinct - * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0 - * as a "fastpath" with a configurable number of clones after alloc's. -- * - * clone_skb=0 means all packets are allocated this also means ranges time - * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100 - * clones. - * - * Also moved to /proc/net/pktgen/ -- * --ro -+ * --ro -+ * -+ * Sept 10: Fixed threading/locking. Lots of bone-headed and more clever -+ * mistakes. Also merged in DaveM's patch in the -pre6 patch. - * - * See Documentation/networking/pktgen.txt for how to use this. - */ -@@ -79,172 +80,533 @@ - #include <linux/proc_fs.h> - #include <linux/if_arp.h> - #include <net/checksum.h> -+#include <net/profile.h> - #include <asm/timex.h> - --#define cycles() ((u32)get_cycles()) -+#include <linux/smp_lock.h> /* for lock kernel */ -+#include <asm/div64.h> /* do_div */ -+ -+#include "pktgen.h" - - --#define VERSION "pktgen version 1.2" - static char version[] __initdata = -- "pktgen.c: v1.2: Packet Generator for packet performance testing.\n"; -+ "pktgen.c: v1.6: Packet Generator for packet performance testing.\n"; - - /* Used to help with determining the pkts on receive */ - - #define PKTGEN_MAGIC 0xbe9be955 - -+/* #define PG_DEBUG(a) a */ -+#define PG_DEBUG(a) /* a */ - --/* Keep information per interface */ --struct pktgen_info { -- /* Parameters */ -+/* cycles per micro-second */ -+static u32 pg_cycles_per_ns; -+static u32 pg_cycles_per_us; -+static u32 pg_cycles_per_ms; - -- /* If min != max, then we will either do a linear iteration, or -- * we will do a random selection from within the range. -- */ -- __u32 flags; -+/* Module parameters, defaults. */ -+static int pg_count_d = 0; /* run forever by default */ -+static int pg_ipg_d = 0; -+static int pg_multiskb_d = 0; -+static int pg_thread_count = 1; /* Initial threads to create */ -+static int debug = 0; - --#define F_IPSRC_RND (1<<0) /* IP-Src Random */ --#define F_IPDST_RND (1<<1) /* IP-Dst Random */ --#define F_UDPSRC_RND (1<<2) /* UDP-Src Random */ --#define F_UDPDST_RND (1<<3) /* UDP-Dst Random */ --#define F_MACSRC_RND (1<<4) /* MAC-Src Random */ --#define F_MACDST_RND (1<<5) /* MAC-Dst Random */ --#define F_SET_SRCMAC (1<<6) /* Specify-Src-Mac -- (default is to use Interface's MAC Addr) */ --#define F_SET_SRCIP (1<<7) /* Specify-Src-IP -- (default is to use Interface's IP Addr) */ -- -- -- int pkt_size; /* = ETH_ZLEN; */ -- int nfrags; -- __u32 ipg; /* Default Interpacket gap in nsec */ -- __u64 count; /* Default No packets to send */ -- __u64 sofar; /* How many pkts we've sent so far */ -- __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */ -- struct timeval started_at; -- struct timeval stopped_at; -- __u64 idle_acc; -- __u32 seq_num; -- -- int clone_skb; /* Use multiple SKBs during packet gen. If this number -- * is greater than 1, then that many coppies of the same -- * packet will be sent before a new packet is allocated. -- * For instance, if you want to send 1024 identical packets -- * before creating a new packet, set clone_skb to 1024. -- */ -- int busy; -- int do_run_run; /* if this changes to false, the test will stop */ -- -- char outdev[32]; -- char dst_min[32]; -- char dst_max[32]; -- char src_min[32]; -- char src_max[32]; - -- /* If we're doing ranges, random or incremental, then this -- * defines the min/max for those ranges. -- */ -- __u32 saddr_min; /* inclusive, source IP address */ -- __u32 saddr_max; /* exclusive, source IP address */ -- __u32 daddr_min; /* inclusive, dest IP address */ -- __u32 daddr_max; /* exclusive, dest IP address */ -- -- __u16 udp_src_min; /* inclusive, source UDP port */ -- __u16 udp_src_max; /* exclusive, source UDP port */ -- __u16 udp_dst_min; /* inclusive, dest UDP port */ -- __u16 udp_dst_max; /* exclusive, dest UDP port */ -- -- __u32 src_mac_count; /* How many MACs to iterate through */ -- __u32 dst_mac_count; /* How many MACs to iterate through */ -- -- unsigned char dst_mac[6]; -- unsigned char src_mac[6]; -- -- __u32 cur_dst_mac_offset; -- __u32 cur_src_mac_offset; -- __u32 cur_saddr; -- __u32 cur_daddr; -- __u16 cur_udp_dst; -- __u16 cur_udp_src; -- -- __u8 hh[14]; -- /* = { -- 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, -- -- We fill in SRC address later -- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -- 0x08, 0x00 -- }; -- */ -- __u16 pad; /* pad out the hh struct to an even 16 bytes */ -- char result[512]; - -- /* proc file names */ -- char fname[80]; -- char busy_fname[80]; -- -- struct proc_dir_entry *proc_ent; -- struct proc_dir_entry *busy_proc_ent; --}; -+/* List of all running threads */ -+static struct pktgen_thread_info* pktgen_threads = NULL; -+spinlock_t _pg_threadlist_lock = SPIN_LOCK_UNLOCKED; -+ -+/* Holds interfaces for all threads */ -+#define PG_INFO_HASH_MAX 32 -+static struct pktgen_interface_info* pg_info_hash[PG_INFO_HASH_MAX]; -+spinlock_t _pg_hash_lock = SPIN_LOCK_UNLOCKED; -+ -+#define PG_PROC_DIR "pktgen" -+static struct proc_dir_entry *pg_proc_dir = NULL; -+ -+char module_fname[128]; -+struct proc_dir_entry *module_proc_ent = NULL; - --struct pktgen_hdr { -- __u32 pgh_magic; -- __u32 seq_num; -- struct timeval timestamp; -+ -+static void init_pktgen_kthread(struct pktgen_thread_info *kthread, char *name); -+static int pg_rem_interface_info(struct pktgen_thread_info* pg_thread, -+ struct pktgen_interface_info* i); -+static int pg_add_interface_info(struct pktgen_thread_info* pg_thread, -+ const char* ifname); -+static void exit_pktgen_kthread(struct pktgen_thread_info *kthread); -+static void stop_pktgen_kthread(struct pktgen_thread_info *kthread); -+static struct pktgen_thread_info* pg_find_thread(const char* name); -+static int pg_add_thread_info(const char* name); -+static struct pktgen_interface_info* pg_find_interface(struct pktgen_thread_info* pg_thread, -+ const char* ifname); -+static int pktgen_device_event(struct notifier_block *, unsigned long, void *); -+ -+ -+struct notifier_block pktgen_notifier_block = { -+ notifier_call: pktgen_device_event, - }; - --static int cpu_speed; --static int debug; -+/* This code works around the fact that do_div cannot handle two 64-bit -+ numbers, and regular 64-bit division doesn't work on x86 kernels. -+ --Ben -+*/ - --/* Module parameters, defaults. */ --static int count_d = 100000; --static int ipg_d = 0; --static int clone_skb_d = 0; -+#define PG_DIV 0 -+#define PG_REM 1 -+ -+/* This was emailed to LMKL by: Chris Caputo <ccaputo@alt.net> -+ * Function copied/adapted/optimized from: -+ * -+ * nemesis.sourceforge.net/browse/lib/static/intmath/ix86/intmath.c.html -+ * -+ * Copyright 1994, University of Cambridge Computer Laboratory -+ * All Rights Reserved. -+ * -+ * TODO: When running on a 64-bit CPU platform, this should no longer be -+ * TODO: necessary. -+ */ -+inline static s64 divremdi3(s64 x, s64 y, int type) { -+ u64 a = (x < 0) ? -x : x; -+ u64 b = (y < 0) ? -y : y; -+ u64 res = 0, d = 1; -+ -+ if (b > 0) { -+ while (b < a) { -+ b <<= 1; -+ d <<= 1; -+ } -+ } -+ -+ do { -+ if ( a >= b ) { -+ a -= b; -+ res += d; -+ } -+ b >>= 1; -+ d >>= 1; -+ } -+ while (d); -+ -+ if (PG_DIV == type) { -+ return (((x ^ y) & (1ll<<63)) == 0) ? res : -(s64)res; -+ } -+ else { -+ return ((x & (1ll<<63)) == 0) ? a : -(s64)a; -+ } -+}/* divremdi3 */ -+ -+/* End of hacks to deal with 64-bit math on x86 */ - - --#define MAX_PKTGEN 8 --static struct pktgen_info pginfos[MAX_PKTGEN]; - -+inline static void pg_lock_thread_list(char* msg) { -+ if (debug > 1) { -+ printk("before pg_lock_thread_list, msg: %s\n", msg); -+ } -+ spin_lock(&_pg_threadlist_lock); -+ if (debug > 1) { -+ printk("after pg_lock_thread_list, msg: %s\n", msg); -+ } -+} -+ -+inline static void pg_unlock_thread_list(char* msg) { -+ if (debug > 1) { -+ printk("before pg_unlock_thread_list, msg: %s\n", msg); -+ } -+ spin_unlock(&_pg_threadlist_lock); -+ if (debug > 1) { -+ printk("after pg_unlock_thread_list, msg: %s\n", msg); -+ } -+} -+ -+inline static void pg_lock_hash(char* msg) { -+ if (debug > 1) { -+ printk("before pg_lock_hash, msg: %s\n", msg); -+ } -+ spin_lock(&_pg_hash_lock); -+ if (debug > 1) { -+ printk("before pg_lock_hash, msg: %s\n", msg); -+ } -+} -+ -+inline static void pg_unlock_hash(char* msg) { -+ if (debug > 1) { -+ printk("before pg_unlock_hash, msg: %s\n", msg); -+ } -+ spin_unlock(&_pg_hash_lock); -+ if (debug > 1) { -+ printk("after pg_unlock_hash, msg: %s\n", msg); -+ } -+} -+ -+inline static void pg_lock(struct pktgen_thread_info* pg_thread, char* msg) { -+ if (debug > 1) { -+ printk("before pg_lock thread, msg: %s\n", msg); -+ } -+ spin_lock(&(pg_thread->pg_threadlock)); -+ if (debug > 1) { -+ printk("after pg_lock thread, msg: %s\n", msg); -+ } -+} -+ -+inline static void pg_unlock(struct pktgen_thread_info* pg_thread, char* msg) { -+ if (debug > 1) { -+ printk("before pg_unlock thread, thread: %p msg: %s\n", -+ pg_thread, msg); -+ } -+ spin_unlock(&(pg_thread->pg_threadlock)); -+ if (debug > 1) { -+ printk("after pg_unlock thread, thread: %p msg: %s\n", -+ pg_thread, msg); -+ } -+} - - /** Convert to miliseconds */ --inline __u64 tv_to_ms(const struct timeval* tv) { -+static inline __u64 tv_to_ms(const struct timeval* tv) { - __u64 ms = tv->tv_usec / 1000; - ms += (__u64)tv->tv_sec * (__u64)1000; - return ms; - } - --inline __u64 getCurMs(void) { -+ -+/** Convert to micro-seconds */ -+static inline __u64 tv_to_us(const struct timeval* tv) { -+ __u64 us = tv->tv_usec; -+ us += (__u64)tv->tv_sec * (__u64)1000000; -+ return us; -+} -+ -+ -+static inline __u64 pg_div(__u64 n, __u32 base) { -+ __u64 tmp = n; -+ do_div(tmp, base); -+ /* printk("pg_div, n: %llu base: %d rv: %llu\n", -+ n, base, tmp); */ -+ return tmp; -+} -+ -+/* Fast, not horribly accurate, since the machine started. */ -+static inline __u64 getRelativeCurMs(void) { -+ return pg_div(get_cycles(), pg_cycles_per_ms); -+} -+ -+/* Since the epoc. More precise over long periods of time than -+ * getRelativeCurMs -+ */ -+static inline __u64 getCurMs(void) { - struct timeval tv; - do_gettimeofday(&tv); - return tv_to_ms(&tv); - } - --#define PG_PROC_DIR "pktgen" --static struct proc_dir_entry *proc_dir = 0; -+/* Since the epoc. More precise over long periods of time than -+ * getRelativeCurMs -+ */ -+static inline __u64 getCurUs(void) { -+ struct timeval tv; -+ do_gettimeofday(&tv); -+ return tv_to_us(&tv); -+} - --static struct net_device *setup_inject(struct pktgen_info* info) --{ -+/* Since the machine booted. */ -+static inline __u64 getRelativeCurUs(void) { -+ return pg_div(get_cycles(), pg_cycles_per_us); -+} -+ -+/* Since the machine booted. */ -+static inline __u64 getRelativeCurNs(void) { -+ return pg_div(get_cycles(), pg_cycles_per_ns); -+} -+ -+static inline __u64 tv_diff(const struct timeval* a, const struct timeval* b) { -+ return tv_to_us(a) - tv_to_us(b); -+} -+ -+ -+ -+int pktgen_proc_ioctl(struct inode* inode, struct file* file, unsigned int cmd, -+ unsigned long arg) { -+ int err = 0; -+ struct pktgen_ioctl_info args; -+ struct pktgen_thread_info* targ = NULL; -+ -+ /* -+ if (!capable(CAP_NET_ADMIN)){ -+ return -EPERM; -+ } -+ */ -+ -+ if (copy_from_user(&args, (void*)arg, sizeof(args))) { -+ return -EFAULT; -+ } -+ -+ /* Null terminate the names */ -+ args.thread_name[31] = 0; -+ args.interface_name[31] = 0; -+ -+ /* printk("pktgen: thread_name: %s interface_name: %s\n", -+ * args.thread_name, args.interface_name); -+ */ -+ -+ switch (cmd) { -+ case GET_PKTGEN_INTERFACE_INFO: { -+ targ = pg_find_thread(args.thread_name); -+ if (targ) { -+ struct pktgen_interface_info* info; -+ info = pg_find_interface(targ, args.interface_name); -+ if (info) { -+ memcpy(&(args.info), info, sizeof(args.info)); -+ if (copy_to_user((void*)(arg), &args, sizeof(args))) { -+ printk("ERROR: pktgen: copy_to_user failed.\n"); -+ err = -EFAULT; -+ } -+ else { -+ err = 0; -+ } -+ } -+ else { -+ /* printk("ERROR: pktgen: Could not find interface -:%s:-\n", -+ args.interface_name);*/ -+ err = -ENODEV; -+ } -+ } -+ else { -+ printk("ERROR: pktgen: Could not find thread -:%s:-.\n", -+ args.thread_name); -+ err = -ENODEV; -+ } -+ break; -+ } -+ default: -+ /* pass on to underlying device instead?? */ -+ printk(__FUNCTION__ ": Unknown pktgen IOCTL: %x \n", -+ cmd); -+ return -EINVAL; -+ } -+ -+ return err; -+}/* pktgen_proc_ioctl */ -+ -+static struct file_operations pktgen_fops = { -+ ioctl: pktgen_proc_ioctl, -+}; -+ -+static void remove_pg_info_from_hash(struct pktgen_interface_info* info) { -+ pg_lock_hash(__FUNCTION__); -+ { -+ int device_idx = info->odev ? info->odev->ifindex : 0; -+ int b = device_idx % PG_INFO_HASH_MAX; -+ struct pktgen_interface_info* p = pg_info_hash[b]; -+ struct pktgen_interface_info* prev = pg_info_hash[b]; -+ -+ PG_DEBUG(printk("remove_pg_info_from_hash, p: %p info: %p device_idx: %i\n", -+ p, info, device_idx)); -+ -+ if (p != NULL) { -+ -+ if (p == info) { -+ pg_info_hash[b] = p->next_hash; -+ p->next_hash = NULL; -+ } -+ else { -+ while (prev->next_hash) { -+ p = prev->next_hash; -+ if (p == info) { -+ prev->next_hash = p->next_hash; -+ p->next_hash = NULL; -+ break; -+ } -+ prev = p; -+ } -+ } -+ } -+ -+ if (info->odev) { -+ info->odev->priv_flags &= ~(IFF_PKTGEN_RCV); -+ } -+ } -+ pg_unlock_hash(__FUNCTION__); -+}/* remove_pg_info_from_hash */ -+ -+ -+static void add_pg_info_to_hash(struct pktgen_interface_info* info) { -+ /* First remove it, just in case it's already there. */ -+ remove_pg_info_from_hash(info); -+ -+ pg_lock_hash(__FUNCTION__); -+ { -+ int device_idx = info->odev ? info->odev->ifindex : 0; -+ int b = device_idx % PG_INFO_HASH_MAX; -+ -+ PG_DEBUG(printk("add_pg_info_from_hash, b: %i info: %p device_idx: %i\n", -+ b, info, device_idx)); -+ -+ info->next_hash = pg_info_hash[b]; -+ pg_info_hash[b] = info; -+ -+ -+ if (info->odev) { -+ info->odev->priv_flags |= (IFF_PKTGEN_RCV); -+ } -+ } -+ pg_unlock_hash(__FUNCTION__); -+}/* add_pg_info_to_hash */ -+ -+ -+/* Find the pktgen_interface_info for a device idx */ -+struct pktgen_interface_info* find_pg_info(int device_idx) { -+ struct pktgen_interface_info* p = NULL; -+ if (debug > 1) { -+ printk("in find_pg_info...\n"); -+ } -+ pg_lock_hash(__FUNCTION__); -+ { -+ int b = device_idx % PG_INFO_HASH_MAX; -+ p = pg_info_hash[b]; -+ while (p) { -+ if (p->odev && (p->odev->ifindex == device_idx)) { -+ break; -+ } -+ p = p->next_hash; -+ } -+ } -+ pg_unlock_hash(__FUNCTION__); -+ return p; -+} -+ -+ -+/* Remove an interface from our hash, dissassociate pktgen_interface_info -+ * from interface -+ */ -+static void check_remove_device(struct pktgen_interface_info* info) { -+ struct pktgen_interface_info* pi = NULL; -+ if (info->odev) { -+ pi = find_pg_info(info->odev->ifindex); -+ if (pi != info) { -+ printk("ERROR: pi != info, pi: %p info: %p\n", pi, info); -+ } -+ else { -+ /* Remove info from our hash */ -+ remove_pg_info_from_hash(info); -+ } -+ -+ rtnl_lock(); -+ info->odev->priv_flags &= ~(IFF_PKTGEN_RCV); -+ atomic_dec(&(info->odev->refcnt)); -+ info->odev = NULL; -+ rtnl_unlock(); -+ } -+}/* check_remove_device */ -+ -+ -+static int pg_remove_interface_from_all_threads(const char* dev_name) { -+ int cnt = 0; -+ pg_lock_thread_list(__FUNCTION__); -+ { -+ struct pktgen_thread_info* tmp = pktgen_threads; -+ struct pktgen_interface_info* info = NULL; -+ -+ while (tmp) { -+ info = pg_find_interface(tmp, dev_name); -+ if (info) { -+ printk("pktgen: Removing interface: %s from pktgen control.\n", -+ dev_name); -+ pg_rem_interface_info(tmp, info); -+ cnt++; -+ } -+ else { -+ printk("pktgen: Could not find interface: %s in rem_from_all.\n", -+ dev_name); -+ } -+ tmp = tmp->next; -+ } -+ } -+ pg_unlock_thread_list(__FUNCTION__); -+ return cnt; -+}/* pg_rem_interface_from_all_threads */ -+ -+ -+static int pktgen_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { -+ struct net_device *dev = (struct net_device *)(ptr); -+ -+ /* It is OK that we do not hold the group lock right now, -+ * as we run under the RTNL lock. -+ */ -+ -+ switch (event) { -+ case NETDEV_CHANGEADDR: -+ case NETDEV_GOING_DOWN: -+ case NETDEV_DOWN: -+ case NETDEV_UP: -+ /* Ignore for now */ -+ break; -+ -+ case NETDEV_UNREGISTER: -+ pg_remove_interface_from_all_threads(dev->name); -+ break; -+ }; -+ -+ return NOTIFY_DONE; -+} -+ -+ -+/* Associate pktgen_interface_info with a device. -+ */ -+static struct net_device* pg_setup_interface(struct pktgen_interface_info* info) { - struct net_device *odev; - -+ check_remove_device(info); -+ - rtnl_lock(); -- odev = __dev_get_by_name(info->outdev); -+ odev = __dev_get_by_name(info->ifname); - if (!odev) { -- sprintf(info->result, "No such netdevice: \"%s\"", info->outdev); -- goto out_unlock; -+ printk("No such netdevice: \"%s\"\n", info->ifname); - } -- -- if (odev->type != ARPHRD_ETHER) { -- sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev); -- goto out_unlock; -+ else if (odev->type != ARPHRD_ETHER) { -+ printk("Not an ethernet device: \"%s\"\n", info->ifname); - } -- -- if (!netif_running(odev)) { -- sprintf(info->result, "Device is down: \"%s\"", info->outdev); -- goto out_unlock; -+ else if (!netif_running(odev)) { -+ printk("Device is down: \"%s\"\n", info->ifname); - } -+ else if (odev->priv_flags & IFF_PKTGEN_RCV) { -+ printk("ERROR: Device: \"%s\" is already assigned to a pktgen interface.\n", -+ info->ifname); -+ } -+ else { -+ atomic_inc(&odev->refcnt); -+ info->odev = odev; -+ info->odev->priv_flags |= (IFF_PKTGEN_RCV); -+ } -+ -+ rtnl_unlock(); -+ -+ if (info->odev) { -+ add_pg_info_to_hash(info); -+ } -+ -+ return info->odev; -+} - -+/* Read info from the interface and set up internal pktgen_interface_info -+ * structure to have the right information to create/send packets -+ */ -+static void pg_setup_inject(struct pktgen_interface_info* info) -+{ -+ if (!info->odev) { -+ /* Try once more, just in case it works now. */ -+ pg_setup_interface(info); -+ } -+ -+ if (!info->odev) { -+ printk("ERROR: info->odev == NULL in setup_inject.\n"); -+ sprintf(info->result, "ERROR: info->odev == NULL in setup_inject.\n"); -+ return; -+ } -+ - /* Default to the interface's mac if not explicitly set. */ - if (!(info->flags & F_SET_SRCMAC)) { -- memcpy(&(info->hh[6]), odev->dev_addr, 6); -+ memcpy(&(info->hh[6]), info->odev->dev_addr, 6); - } - else { - memcpy(&(info->hh[6]), info->src_mac, 6); -@@ -252,12 +614,15 @@ - - /* Set up Dest MAC */ - memcpy(&(info->hh[0]), info->dst_mac, 6); -+ -+ /* Set up pkt size */ -+ info->cur_pkt_size = info->min_pkt_size; - - info->saddr_min = 0; - info->saddr_max = 0; - if (strlen(info->src_min) == 0) { -- if (odev->ip_ptr) { -- struct in_device *in_dev = odev->ip_ptr; -+ if (info->odev->ip_ptr) { -+ struct in_device *in_dev = info->odev->ip_ptr; - - if (in_dev->ifa_list) { - info->saddr_min = in_dev->ifa_list->ifa_address; -@@ -280,65 +645,131 @@ - info->cur_daddr = info->daddr_min; - info->cur_udp_dst = info->udp_dst_min; - info->cur_udp_src = info->udp_src_min; -- -- atomic_inc(&odev->refcnt); -- rtnl_unlock(); -- -- return odev; -- --out_unlock: -- rtnl_unlock(); -- return NULL; - } - --static void nanospin(int ipg, struct pktgen_info* info) -+/* ipg is in nano-seconds */ -+static void nanospin(__u32 ipg, struct pktgen_interface_info* info) - { -- u32 idle_start, idle; -- -- idle_start = cycles(); -+ u64 idle_start = get_cycles(); -+ u64 idle; - - for (;;) { - barrier(); -- idle = cycles() - idle_start; -- if (idle * 1000 >= ipg * cpu_speed) -+ idle = get_cycles() - idle_start; -+ if (idle * 1000 >= ipg * pg_cycles_per_us) - break; - } - info->idle_acc += idle; - } - -+ -+/* ipg is in micro-seconds (usecs) */ -+static void pg_udelay(__u32 delay_us, struct pktgen_interface_info* info, -+ struct pktgen_thread_info* pg_thread) -+{ -+ u64 start = getRelativeCurUs(); -+ u64 now; -+ if (delay_us > (1000000 / HZ)) { -+ /* fall asleep for a bit */ -+ __u32 us_per_tick = 1000000 / HZ; -+ __u32 ticks = delay_us / us_per_tick; -+ interruptible_sleep_on_timeout(&(pg_thread->queue), ticks); -+ } -+ -+ for (;;) { -+ now = getRelativeCurUs(); -+ if (start + delay_us <= (now - 10)) { -+ break; -+ } -+ -+ if (!info->do_run_run) { -+ return; -+ } -+ -+ if (current->need_resched) { -+ schedule(); -+ } -+ -+ now = getRelativeCurUs(); -+ if (start + delay_us <= (now - 10)) { -+ break; -+ } -+ -+ do_softirq(); -+ } -+ -+ info->idle_acc += (1000 * (now - start)); -+ -+ /* We can break out of the loop up to 10us early, so spend the rest of -+ * it spinning to increase accuracy. -+ */ -+ if (start + delay_us > now) { -+ nanospin((start + delay_us) - now, info); -+ } -+} -+ -+ -+ -+ -+/* Returns: cycles per micro-second */ - static int calc_mhz(void) - { - struct timeval start, stop; -- u32 start_s, elapsed; -- -+ u64 start_s; -+ u64 t1, t2; -+ u32 elapsed; -+ u32 clock_time = 0; -+ - do_gettimeofday(&start); -- start_s = cycles(); -+ start_s = get_cycles(); -+ /* Spin for 50,000,000 cycles */ - do { - barrier(); -- elapsed = cycles() - start_s; -+ elapsed = (u32)(get_cycles() - start_s); - if (elapsed == 0) - return 0; -- } while (elapsed < 1000 * 50000); -+ } while (elapsed < 50000000); - do_gettimeofday(&stop); -- return elapsed/(stop.tv_usec-start.tv_usec+1000000*(stop.tv_sec-start.tv_sec)); -+ -+ t1 = tv_to_us(&start); -+ t2 = tv_to_us(&stop); -+ -+ clock_time = (u32)(t2 - t1); -+ if (clock_time == 0) { -+ printk("pktgen: ERROR: clock_time was zero..things may not work right, t1: %u t2: %u ...\n", -+ (u32)(t1), (u32)(t2)); -+ return 0x7FFFFFFF; -+ } -+ return elapsed / clock_time; - } - -+/* Calibrate cycles per micro-second */ - static void cycles_calibrate(void) - { - int i; - - for (i = 0; i < 3; i++) { -- int res = calc_mhz(); -- if (res > cpu_speed) -- cpu_speed = res; -+ u32 res = calc_mhz(); -+ if (res > pg_cycles_per_us) -+ pg_cycles_per_us = res; - } -+ -+ /* Set these up too, only need to calculate these once. */ -+ pg_cycles_per_ns = pg_cycles_per_us / 1000; -+ if (pg_cycles_per_ns == 0) { -+ pg_cycles_per_ns = 1; -+ } -+ pg_cycles_per_ms = pg_cycles_per_us * 1000; -+ -+ printk("pktgen: cycles_calibrate, cycles_per_ns: %d per_us: %d per_ms: %d\n", -+ pg_cycles_per_ns, pg_cycles_per_us, pg_cycles_per_ms); - } - - - /* Increment/randomize headers according to flags and current values - * for IP src/dest, UDP src/dst port, MAC-Addr src/dst - */ --static void mod_cur_headers(struct pktgen_info* info) { -+static void mod_cur_headers(struct pktgen_interface_info* info) { - __u32 imn; - __u32 imx; - -@@ -428,7 +859,7 @@ - else { - t = ntohl(info->cur_saddr); - t++; -- if (t >= imx) { -+ if (t > imx) { - t = imn; - } - } -@@ -443,16 +874,31 @@ - else { - t = ntohl(info->cur_daddr); - t++; -- if (t >= imx) { -+ if (t > imx) { - t = imn; - } - } - info->cur_daddr = htonl(t); - } -+ -+ if (info->min_pkt_size < info->max_pkt_size) { -+ __u32 t; -+ if (info->flags & F_TXSIZE_RND) { -+ t = ((net_random() % (info->max_pkt_size - info->min_pkt_size)) -+ + info->min_pkt_size); -+ } -+ else { -+ t = info->cur_pkt_size + 1; -+ if (t > info->max_pkt_size) { -+ t = info->min_pkt_size; -+ } -+ } -+ info->cur_pkt_size = t; -+ } - }/* mod_cur_headers */ - - --static struct sk_buff *fill_packet(struct net_device *odev, struct pktgen_info* info) -+static struct sk_buff *fill_packet(struct net_device *odev, struct pktgen_interface_info* info) - { - struct sk_buff *skb = NULL; - __u8 *eth; -@@ -461,7 +907,7 @@ - struct iphdr *iph; - struct pktgen_hdr *pgh = NULL; - -- skb = alloc_skb(info->pkt_size + 64 + 16, GFP_ATOMIC); -+ skb = alloc_skb(info->cur_pkt_size + 64 + 16, GFP_ATOMIC); - if (!skb) { - sprintf(info->result, "No memory"); - return NULL; -@@ -481,7 +927,7 @@ - - memcpy(eth, info->hh, 14); - -- datalen = info->pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */ -+ datalen = info->cur_pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */ - if (datalen < sizeof(struct pktgen_hdr)) { - datalen = sizeof(struct pktgen_hdr); - } -@@ -493,7 +939,7 @@ - - iph->ihl = 5; - iph->version = 4; -- iph->ttl = 3; -+ iph->ttl = 32; - iph->tos = 0; - iph->protocol = IPPROTO_UDP; /* UDP */ - iph->saddr = info->cur_saddr; -@@ -514,7 +960,6 @@ - int frags = info->nfrags; - int i; - -- /* TODO: Verify this is OK...it sure is ugly. --Ben */ - pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8); - - if (frags > MAX_SKB_FRAGS) -@@ -562,234 +1007,855 @@ - - /* Stamp the time, and sequence number, convert them to network byte order */ - if (pgh) { -- pgh->pgh_magic = htonl(PKTGEN_MAGIC); -+ pgh->pgh_magic = __constant_htonl(PKTGEN_MAGIC); - do_gettimeofday(&(pgh->timestamp)); - pgh->timestamp.tv_usec = htonl(pgh->timestamp.tv_usec); - pgh->timestamp.tv_sec = htonl(pgh->timestamp.tv_sec); - pgh->seq_num = htonl(info->seq_num); - } -+ info->seq_num++; - - return skb; - } - - --static void inject(struct pktgen_info* info) --{ -- struct net_device *odev = NULL; -- struct sk_buff *skb = NULL; -- __u64 total = 0; -- __u64 idle = 0; -- __u64 lcount = 0; -- int nr_frags = 0; -- int last_ok = 1; /* Was last skb sent? -- * Or a failed transmit of some sort? This will keep -- * sequence numbers in order, for example. -- */ -- __u64 fp = 0; -- __u32 fp_tmp = 0; -- -- odev = setup_inject(info); -- if (!odev) -- return; -- -- info->do_run_run = 1; /* Cranke yeself! */ -- info->idle_acc = 0; -- info->sofar = 0; -- lcount = info->count; -- -- -- /* Build our initial pkt and place it as a re-try pkt. */ -- skb = fill_packet(odev, info); -- if (skb == NULL) goto out_reldev; -+static void record_latency(struct pktgen_interface_info* info, int latency) { -+ /* NOTE: Latency can be negative */ -+ int div = 100; -+ int diff; -+ int vl; -+ int i; - -- do_gettimeofday(&(info->started_at)); -+ info->pkts_rcvd_since_clear++; -+ -+ if (info->pkts_rcvd_since_clear < 100) { -+ div = info->pkts_rcvd; -+ if (info->pkts_rcvd_since_clear == 1) { -+ info->avg_latency = latency; -+ } -+ } - -- while(info->do_run_run) { -+ if ((div + 1) == 0) { -+ info->avg_latency = 0; -+ } -+ else { -+ info->avg_latency = ((info->avg_latency * div + latency) / (div + 1)); -+ } - -- /* Set a time-stamp, so build a new pkt each time */ -+ if (latency < info->min_latency) { -+ info->min_latency = latency; -+ } -+ if (latency > info->max_latency) { -+ info->max_latency = latency; -+ } - -- if (last_ok) { -- if (++fp_tmp >= info->clone_skb ) { -- kfree_skb(skb); -- skb = fill_packet(odev, info); -- if (skb == NULL) { -- break; -- } -- fp++; -- fp_tmp = 0; /* reset counter */ -- } -- atomic_inc(&skb->users); -+ /* Place the latency in the right 'bucket' */ -+ diff = (latency - info->min_latency); -+ for (i = 0; i<LAT_BUCKETS_MAX; i++) { -+ vl = (1<<i); -+ if (latency <= vl) { -+ info->latency_bkts[i]++; -+ break; - } -+ } -+}/* record latency */ - -- nr_frags = skb_shinfo(skb)->nr_frags; -- -- spin_lock_bh(&odev->xmit_lock); -- if (!netif_queue_stopped(odev)) { - -- if (odev->hard_start_xmit(skb, odev)) { -- if (net_ratelimit()) { -- printk(KERN_INFO "Hard xmit error\n"); -- } -- info->errors++; -- last_ok = 0; -- } -- else { -- last_ok = 1; -- info->sofar++; -- info->seq_num++; -+/* Returns < 0 if the skb is not a pktgen buffer. */ -+int pktgen_receive(struct sk_buff* skb) { -+ /* See if we have a pktgen packet */ -+ if ((skb->len >= (20 + 8 + sizeof(struct pktgen_hdr))) && -+ (skb->protocol == __constant_htons(ETH_P_IP))) { -+ -+ /* It's IP, and long enough, lets check the magic number. -+ * TODO: This is a hack not always guaranteed to catch the right -+ * packets. -+ */ -+ /*int i; -+ char* tmp; */ -+ struct pktgen_hdr* pgh; -+ /* printk("Length & protocol passed, skb->data: %p, raw: %p\n", -+ skb->data, skb->h.raw); */ -+ pgh = (struct pktgen_hdr*)(skb->data + 20 + 8); -+ /* -+ tmp = (char*)(skb->data); -+ for (i = 0; i<60; i++) { -+ printk("%02hx ", tmp[i]); -+ if (((i + 1) % 15) == 0) { -+ printk("\n"); - } -- } -- else { -- /* Re-try it next time */ -- last_ok = 0; - } -+ printk("\n"); -+ */ - -+ if (pgh->pgh_magic == __constant_ntohl(PKTGEN_MAGIC)) { -+ struct net_device* dev = skb->dev; -+ struct pktgen_interface_info* info = find_pg_info(dev->ifindex); -+ -+ /* Got one! */ -+ /* TODO: Check UDP checksum ?? */ -+ __u32 seq = ntohl(pgh->seq_num); - -- spin_unlock_bh(&odev->xmit_lock); -- -- if (info->ipg) { -- /* Try not to busy-spin if we have larger sleep times. -- * TODO: Investigate better ways to do this. -- */ -- if (info->ipg < 10000) { /* 10 usecs or less */ -- nanospin(info->ipg, info); -+ if (!info) { -+ return -1; - } -- else if (info->ipg < 10000000) { /* 10ms or less */ -- udelay(info->ipg / 1000); -+ -+ info->pkts_rcvd++; -+ info->bytes_rcvd += (skb->len + 4); /* +4 for the checksum */ -+ -+ /* Check for out-of-sequence packets */ -+ if (info->last_seq_rcvd == seq) { -+ info->dup_rcvd++; -+ info->dup_since_incr++; - } - else { -- mdelay(info->ipg / 1000000); -+ __s64 rx = tv_to_us(&(skb->stamp)); -+ __s64 tx; -+ struct timeval txtv; -+ txtv.tv_usec = ntohl(pgh->timestamp.tv_usec); -+ txtv.tv_sec = ntohl(pgh->timestamp.tv_sec); -+ tx = tv_to_us(&txtv); -+ record_latency(info, rx - tx); -+ -+ if ((info->last_seq_rcvd + 1) == seq) { -+ if ((info->peer_multiskb > 1) && -+ (info->peer_multiskb > (info->dup_since_incr + 1))) { -+ -+ info->seq_gap_rcvd += (info->peer_multiskb - -+ info->dup_since_incr - 1); -+ } -+ /* Great, in order...all is well */ -+ } -+ else if (info->last_seq_rcvd < seq) { -+ /* sequence gap, means we dropped a pkt most likely */ -+ if (info->peer_multiskb > 1) { -+ /* We dropped more than one sequence number's worth, -+ * and if we're using multiskb, then this is quite -+ * a few. This number still will not be exact, but -+ * it will be closer. -+ */ -+ info->seq_gap_rcvd += (((seq - info->last_seq_rcvd) * -+ info->peer_multiskb) - -+ info->dup_since_incr); -+ } -+ else { -+ info->seq_gap_rcvd += (seq - info->last_seq_rcvd - 1); -+ } -+ } -+ else { -+ info->ooo_rcvd++; /* out-of-order */ -+ } -+ -+ info->dup_since_incr = 0; - } -+ info->last_seq_rcvd = seq; -+ kfree_skb(skb); -+ if (debug > 1) { -+ printk("done with pktgen_receive, free'd pkt\n"); -+ } -+ return 0; - } -- -- if (signal_pending(current)) { -- break; -- } -+ } -+ return -1; /* Let another protocol handle it, it's not for us! */ -+}/* pktgen_receive */ - -- /* If lcount is zero, then run forever */ -- if ((lcount != 0) && (--lcount == 0)) { -- if (atomic_read(&skb->users) != 1) { -- u32 idle_start, idle; -- -- idle_start = cycles(); -- while (atomic_read(&skb->users) != 1) { -- if (signal_pending(current)) { -- break; -- } -- schedule(); -- } -- idle = cycles() - idle_start; -- info->idle_acc += idle; -- } -- break; -- } -+static void pg_reset_latency_counters(struct pktgen_interface_info* info) { -+ int i; -+ info->avg_latency = 0; -+ info->min_latency = 0x7fffffff; /* largest integer */ -+ info->max_latency = 0x80000000; /* smallest integer */ -+ info->pkts_rcvd_since_clear = 0; -+ for (i = 0; i<LAT_BUCKETS_MAX; i++) { -+ info->latency_bkts[i] = 0; -+ } -+} - -- if (netif_queue_stopped(odev) || current->need_resched) { -- u32 idle_start, idle; -+static void pg_clear_counters(struct pktgen_interface_info* info, int seq_too) { -+ info->idle_acc = 0; -+ info->sofar = 0; -+ info->tx_bytes = 0; -+ info->errors = 0; -+ info->ooo_rcvd = 0; -+ info->dup_rcvd = 0; -+ info->pkts_rcvd = 0; -+ info->bytes_rcvd = 0; -+ info->non_pg_pkts_rcvd = 0; -+ info->seq_gap_rcvd = 0; /* dropped */ - -- idle_start = cycles(); -- do { -- if (signal_pending(current)) { -- info->do_run_run = 0; -- break; -- } -- if (!netif_running(odev)) { -- info->do_run_run = 0; -- break; -+ /* This is a bit of a hack, but it gets the dup counters -+ * in line so we don't have false alarms on dropped pkts. -+ */ -+ if (seq_too) { -+ info->dup_since_incr = info->peer_multiskb - 1; -+ info->seq_num = 1; -+ info->last_seq_rcvd = 0; -+ } -+ -+ pg_reset_latency_counters(info); -+} -+ -+/* Adds an interface to the thread. The interface will be in -+ * the stopped queue untill started. -+ */ -+static int add_interface_to_thread(struct pktgen_thread_info* pg_thread, -+ struct pktgen_interface_info* info) { -+ int rv = 0; -+ /* grab lock & insert into the stopped list */ -+ pg_lock(pg_thread, __FUNCTION__); -+ -+ if (info->pg_thread) { -+ printk("pktgen: ERROR: Already assigned to a thread.\n"); -+ rv = -EBUSY; -+ goto out; -+ } -+ -+ info->next = pg_thread->stopped_if_infos; -+ pg_thread->stopped_if_infos = info; -+ info->pg_thread = pg_thread; -+ -+ out: -+ pg_unlock(pg_thread, __FUNCTION__); -+ return rv; -+} -+ -+/* Set up structure for sending pkts, clear counters, add to rcv hash, -+ * create initial packet, and move from the stopped to the running -+ * interface_info list -+ */ -+static int pg_start_interface(struct pktgen_thread_info* pg_thread, -+ struct pktgen_interface_info* info) { -+ PG_DEBUG(printk("Entering pg_start_interface..\n")); -+ pg_setup_inject(info); -+ -+ if (!info->odev) { -+ return -1; -+ } -+ -+ PG_DEBUG(printk("About to clean counters..\n")); -+ pg_clear_counters(info, 1); -+ -+ info->do_run_run = 1; /* Cranke yeself! */ -+ -+ info->skb = NULL; -+ -+ info->started_at = getCurUs(); -+ -+ pg_lock(pg_thread, __FUNCTION__); -+ { -+ /* Remove from the stopped list */ -+ struct pktgen_interface_info* p = pg_thread->stopped_if_infos; -+ if (p == info) { -+ pg_thread->stopped_if_infos = p->next; -+ p->next = NULL; -+ } -+ else { -+ while (p) { -+ if (p->next == info) { -+ p->next = p->next->next; -+ info->next = NULL; -+ break; - } -- if (current->need_resched) -- schedule(); -- else -- do_softirq(); -- } while (netif_queue_stopped(odev)); -- idle = cycles() - idle_start; -- info->idle_acc += idle; -- } -- }/* while we should be running */ -+ p = p->next; -+ } -+ } - -- do_gettimeofday(&(info->stopped_at)); -+ info->next_tx_ns = 0; /* Transmit immediately */ -+ -+ /* Move to the front of the running list */ -+ info->next = pg_thread->running_if_infos; -+ pg_thread->running_if_infos = info; -+ pg_thread->running_if_sz++; -+ } -+ pg_unlock(pg_thread, __FUNCTION__); -+ PG_DEBUG(printk("Leaving pg_start_interface..\n")); -+ return 0; -+}/* pg_start_interface */ - -- total = (info->stopped_at.tv_sec - info->started_at.tv_sec) * 1000000 + -- info->stopped_at.tv_usec - info->started_at.tv_usec; - -- idle = (__u32)(info->idle_acc)/(__u32)(cpu_speed); -+/* set stopped-at timer, remove from running list, do counters & statistics -+ * NOTE: We do not remove from the rcv hash. -+ */ -+static int pg_stop_interface(struct pktgen_thread_info* pg_thread, -+ struct pktgen_interface_info* info) { -+ __u64 total_us; -+ if (!info->do_run_run) { -+ printk("pktgen interface: %s is already stopped\n", info->ifname); -+ return -EINVAL; -+ } -+ -+ info->stopped_at = getCurMs(); -+ info->do_run_run = 0; -+ -+ /* The main worker loop will place it onto the stopped list if needed, -+ * next time this interface is asked to be re-inserted into the -+ * list. -+ */ -+ -+ total_us = info->stopped_at - info->started_at; - - { -+ __u64 idle = pg_div(info->idle_acc, pg_cycles_per_us); - char *p = info->result; -- __u64 pps = (__u32)(info->sofar * 1000) / ((__u32)(total) / 1000); -- __u64 bps = pps * 8 * (info->pkt_size + 4); /* take 32bit ethernet CRC into account */ -- p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags) %llupps %lluMb/sec (%llubps) errors: %llu", -- (unsigned long long) total, -- (unsigned long long) (total - idle), -- (unsigned long long) idle, -- (unsigned long long) info->sofar, -- skb->len + 4, /* Add 4 to account for the ethernet checksum */ -- nr_frags, -- (unsigned long long) pps, -- (unsigned long long) (bps / (u64) 1024 / (u64) 1024), -- (unsigned long long) bps, -- (unsigned long long) info->errors -+ __u64 pps = divremdi3(info->sofar * 1000, pg_div(total_us, 1000), PG_DIV); -+ __u64 bps = pps * 8 * (info->cur_pkt_size + 4); /* take 32bit ethernet CRC into account */ -+ -+ p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte) %llupps %lluMb/sec (%llubps) errors: %llu", -+ total_us, total_us - idle, idle, -+ info->sofar, -+ info->cur_pkt_size + 4, /* Add 4 to account for the ethernet checksum */ -+ pps, -+ bps >> 20, bps, info->errors - ); - } -+ return 0; -+}/* pg_stop_interface */ -+ -+ -+/* Re-inserts 'last' into the pg_thread's list. Calling code should -+ * make sure that 'last' is not already in the list. -+ */ -+static struct pktgen_interface_info* pg_resort_pginfos(struct pktgen_thread_info* pg_thread, -+ struct pktgen_interface_info* last, -+ int setup_cur_if) { -+ struct pktgen_interface_info* rv = NULL; -+ -+ pg_lock(pg_thread, __FUNCTION__); -+ { -+ struct pktgen_interface_info* p = pg_thread->running_if_infos; - --out_reldev: -- if (odev) { -- dev_put(odev); -- odev = NULL; -+ if (last) { -+ if (!last->do_run_run) { -+ /* If this guy was stopped while 'current', then -+ * we'll want to place him on the stopped list -+ * here. -+ */ -+ last->next = pg_thread->stopped_if_infos; -+ pg_thread->stopped_if_infos = last; -+ pg_thread->running_if_sz--; -+ } -+ else { -+ /* re-insert */ -+ if (!p) { -+ pg_thread->running_if_infos = last; -+ last->next = NULL; -+ } -+ else { -+ /* Another special case, check to see if we should go at the -+ * front of the queue. -+ */ -+ if (p->next_tx_ns > last->next_tx_ns) { -+ last->next = p; -+ pg_thread->running_if_infos = last; -+ } -+ else { -+ int inserted = 0; -+ while (p->next) { -+ if (p->next->next_tx_ns > last->next_tx_ns) { -+ /* Insert into the list */ -+ last->next = p->next; -+ p->next = last; -+ inserted = 1; -+ break; -+ } -+ p = p->next; -+ } -+ if (!inserted) { -+ /* place at the end */ -+ last->next = NULL; -+ p->next = last; -+ } -+ } -+ } -+ } -+ } -+ -+ /* List is re-sorted, so grab the first one to return */ -+ rv = pg_thread->running_if_infos; -+ if (rv) { -+ /* Pop him off of the list. We do this here because we already -+ * have the lock. Calling code just has to be aware of this -+ * feature. -+ */ -+ pg_thread->running_if_infos = rv->next; -+ } -+ } -+ -+ if (setup_cur_if) { -+ pg_thread->cur_if = rv; -+ } -+ -+ pg_unlock(pg_thread, __FUNCTION__); -+ return rv; -+}/* pg_resort_pginfos */ -+ -+ -+void pg_stop_all_ifs(struct pktgen_thread_info* pg_thread) { -+ struct pktgen_interface_info* next = NULL; -+ -+ pg_lock(pg_thread, __FUNCTION__); -+ if (pg_thread->cur_if) { -+ /* Move it onto the stopped list */ -+ pg_stop_interface(pg_thread, pg_thread->cur_if); -+ pg_thread->cur_if->next = pg_thread->stopped_if_infos; -+ pg_thread->stopped_if_infos = pg_thread->cur_if; -+ pg_thread->cur_if = NULL; -+ } -+ pg_unlock(pg_thread, __FUNCTION__); -+ -+ /* These have their own locking */ -+ next = pg_resort_pginfos(pg_thread, NULL, 0); -+ while (next) { -+ pg_stop_interface(pg_thread, next); -+ next = pg_resort_pginfos(pg_thread, NULL, 0); - } -+}/* pg_stop_all_ifs */ - -- /* TODO: Is this worth printing out (other than for debug?) */ -- printk("fp = %llu\n", (unsigned long long) fp); -- return; - -+void pg_rem_all_ifs(struct pktgen_thread_info* pg_thread) { -+ struct pktgen_interface_info* next = NULL; -+ -+ /* Remove all interfaces, clean up memory */ -+ while ((next = pg_thread->stopped_if_infos)) { -+ int rv = pg_rem_interface_info(pg_thread, next); -+ if (rv >= 0) { -+ kfree(next); -+ } -+ else { -+ printk("ERROR: failed to rem_interface: %i\n", rv); -+ } -+ } -+}/* pg_rem_all_ifs */ -+ -+ -+void pg_rem_from_thread_list(struct pktgen_thread_info* pg_thread) { -+ /* Remove from the thread list */ -+ pg_lock_thread_list(__FUNCTION__); -+ { -+ struct pktgen_thread_info* tmp = pktgen_threads; -+ if (tmp == pg_thread) { -+ pktgen_threads = tmp->next; -+ } -+ else { -+ while (tmp) { -+ if (tmp->next == pg_thread) { -+ tmp->next = pg_thread->next; -+ pg_thread->next = NULL; -+ break; -+ } -+ tmp = tmp->next; -+ } -+ } -+ } -+ pg_unlock_thread_list(__FUNCTION__); -+}/* pg_rem_from_thread_list */ -+ -+ -+/* Main loop of the thread. Send pkts. -+ */ -+void pg_thread_worker(struct pktgen_thread_info* pg_thread) { -+ struct net_device *odev = NULL; -+ __u64 idle_start = 0; -+ struct pktgen_interface_info* next = NULL; -+ u32 next_ipg = 0; -+ u64 now = 0; /* in nano-seconds */ -+ u32 tx_since_softirq = 0; -+ u32 queue_stopped = 0; -+ -+ /* setup the thread environment */ -+ init_pktgen_kthread(pg_thread, "kpktgend"); -+ -+ PG_DEBUG(printk("Starting up pktgen thread: %s\n", pg_thread->name)); -+ -+ /* an endless loop in which we are doing our work */ -+ while (1) { -+ -+ /* Re-sorts the list, inserting 'next' (which is really the last one -+ * we used). It pops the top one off of the queue and returns it. -+ * Calling code must make sure to re-insert the returned value -+ */ -+ next = pg_resort_pginfos(pg_thread, next, 1); -+ -+ if (next) { -+ -+ odev = next->odev; -+ -+ if (next->ipg) { -+ -+ now = getRelativeCurNs(); -+ if (now < next->next_tx_ns) { -+ next_ipg = (u32)(next->next_tx_ns - now); -+ -+ /* Try not to busy-spin if we have larger sleep times. -+ * TODO: Investigate better ways to do this. -+ */ -+ if (next_ipg < 10000) { /* 10 usecs or less */ -+ nanospin(next_ipg, next); -+ } -+ else if (next_ipg < 10000000) { /* 10ms or less */ -+ pg_udelay(next_ipg / 1000, next, pg_thread); -+ } -+ else { -+ /* fall asleep for 10ms or more. */ -+ pg_udelay(next_ipg / 1000, next, pg_thread); -+ } -+ } -+ -+ /* This is max IPG, this has special meaning of -+ * "never transmit" -+ */ -+ if (next->ipg == 0x7FFFFFFF) { -+ next->next_tx_ns = getRelativeCurNs() + next->ipg; -+ continue; -+ } -+ } -+ -+ if (netif_queue_stopped(odev) || current->need_resched) { -+ -+ idle_start = get_cycles(); -+ -+ if (!netif_running(odev)) { -+ pg_stop_interface(pg_thread, next); -+ continue; -+ } -+ if (current->need_resched) { -+ schedule(); -+ } -+ else { -+ do_softirq(); -+ tx_since_softirq = 0; -+ } -+ next->idle_acc += get_cycles() - idle_start; -+ -+ if (netif_queue_stopped(odev)) { -+ queue_stopped++; -+ continue; /* Try the next interface */ -+ } -+ } -+ -+ if (next->last_ok || !next->skb) { -+ if ((++next->fp_tmp >= next->multiskb ) || (!next->skb)) { -+ /* build a new pkt */ -+ if (next->skb) { -+ kfree_skb(next->skb); -+ } -+ next->skb = fill_packet(odev, next); -+ if (next->skb == NULL) { -+ printk("ERROR: Couldn't allocate skb in fill_packet.\n"); -+ schedule(); -+ next->fp_tmp--; /* back out increment, OOM */ -+ continue; -+ } -+ next->fp++; -+ next->fp_tmp = 0; /* reset counter */ -+ /* Not sure what good knowing nr_frags is... -+ next->nr_frags = skb_shinfo(skb)->nr_frags; -+ */ -+ } -+ atomic_inc(&(next->skb->users)); -+ } -+ -+ spin_lock_bh(&odev->xmit_lock); -+ if (!netif_queue_stopped(odev)) { -+ if (odev->hard_start_xmit(next->skb, odev)) { -+ if (net_ratelimit()) { -+ printk(KERN_INFO "Hard xmit error\n"); -+ } -+ next->errors++; -+ next->last_ok = 0; -+ queue_stopped++; -+ } -+ else { -+ queue_stopped = 0; -+ next->last_ok = 1; -+ next->sofar++; -+ next->tx_bytes += (next->cur_pkt_size + 4); /* count csum */ -+ } -+ -+ next->next_tx_ns = getRelativeCurNs() + next->ipg; -+ } -+ else { /* Re-try it next time */ -+ queue_stopped++; -+ next->last_ok = 0; -+ } -+ -+ spin_unlock_bh(&odev->xmit_lock); -+ -+ if (++tx_since_softirq > pg_thread->max_before_softirq) { -+ do_softirq(); -+ tx_since_softirq = 0; -+ } -+ -+ /* If next->count is zero, then run forever */ -+ if ((next->count != 0) && (next->sofar >= next->count)) { -+ if (atomic_read(&(next->skb->users)) != 1) { -+ idle_start = get_cycles(); -+ while (atomic_read(&(next->skb->users)) != 1) { -+ if (signal_pending(current)) { -+ break; -+ } -+ schedule(); -+ } -+ next->idle_acc += get_cycles() - idle_start; -+ } -+ pg_stop_interface(pg_thread, next); -+ }/* if we're done with a particular interface. */ -+ -+ }/* if could find the next interface to send on. */ -+ else { -+ /* fall asleep for a bit */ -+ interruptible_sleep_on_timeout(&(pg_thread->queue), HZ/10); -+ queue_stopped = 0; -+ } -+ -+ /* here we are back from sleep, either due to the timeout -+ (one second), or because we caught a signal. -+ */ -+ if (pg_thread->terminate || signal_pending(current)) { -+ /* we received a request to terminate ourself */ -+ break; -+ } -+ -+ if (queue_stopped > pg_thread->running_if_sz) { -+ /* All our devices are all fulled up, schedule and hope to run -+ * again soon. -+ */ -+ schedule(); -+ queue_stopped = 0; -+ } -+ }//while true -+ -+ /* here we go only in case of termination of the thread */ -+ -+ PG_DEBUG(printk("pgthread: %s stopping all Interfaces.\n", pg_thread->name)); -+ pg_stop_all_ifs(pg_thread); -+ -+ PG_DEBUG(printk("pgthread: %s removing all Interfaces.\n", pg_thread->name)); -+ pg_rem_all_ifs(pg_thread); -+ -+ pg_rem_from_thread_list(pg_thread); -+ -+ /* cleanup the thread, leave */ -+ PG_DEBUG(printk("pgthread: %s calling exit_pktgen_kthread.\n", pg_thread->name)); -+ exit_pktgen_kthread(pg_thread); -+} -+ -+/* private functions */ -+static void kthread_launcher(void *data) { -+ struct pktgen_thread_info *kthread = data; -+ kernel_thread((int (*)(void *))kthread->function, (void *)kthread, 0); - } - --/* proc/net/pktgen/pg */ -+/* create a new kernel thread. Called by the creator. */ -+void start_pktgen_kthread(struct pktgen_thread_info *kthread) { - --static int proc_busy_read(char *buf , char **start, off_t offset, -- int len, int *eof, void *data) --{ -- char *p; -- int idx = (int)(long)(data); -- struct pktgen_info* info = NULL; -+ /* initialize the semaphore: -+ we start with the semaphore locked. The new kernel -+ thread will setup its stuff and unlock it. This -+ control flow (the one that creates the thread) blocks -+ in the down operation below until the thread has reached -+ the up() operation. -+ */ -+ init_MUTEX_LOCKED(&kthread->startstop_sem); -+ -+ /* store the function to be executed in the data passed to -+ the launcher */ -+ kthread->function = pg_thread_worker; - -- if ((idx < 0) || (idx >= MAX_PKTGEN)) { -- printk("ERROR: idx: %i is out of range in proc_write\n", idx); -- return -EINVAL; -+ /* create the new thread my running a task through keventd */ -+ -+ /* initialize the task queue structure */ -+ kthread->tq.sync = 0; -+ INIT_LIST_HEAD(&kthread->tq.list); -+ kthread->tq.routine = kthread_launcher; -+ kthread->tq.data = kthread; -+ -+ /* and schedule it for execution */ -+ schedule_task(&kthread->tq); -+ -+ /* wait till it has reached the setup_thread routine */ -+ down(&kthread->startstop_sem); -+} -+ -+/* stop a kernel thread. Called by the removing instance */ -+static void stop_pktgen_kthread(struct pktgen_thread_info *kthread) { -+ PG_DEBUG(printk("pgthread: %s stop_pktgen_kthread.\n", kthread->name)); -+ -+ if (kthread->thread == NULL) { -+ printk("stop_kthread: killing non existing thread!\n"); -+ return; - } -- info = &(pginfos[idx]); -- -- p = buf; -- p += sprintf(p, "%d\n", info->busy); -- *eof = 1; -- -- return p-buf; -+ -+ /* Stop each interface */ -+ pg_lock(kthread, __FUNCTION__); -+ { -+ struct pktgen_interface_info* tmp = kthread->running_if_infos; -+ while (tmp) { -+ tmp->do_run_run = 0; -+ tmp->next_tx_ns = 0; -+ tmp = tmp->next; -+ } -+ if (kthread->cur_if) { -+ kthread->cur_if->do_run_run = 0; -+ kthread->cur_if->next_tx_ns = 0; -+ } -+ } -+ pg_unlock(kthread, __FUNCTION__); -+ -+ /* Wait for everything to fully stop */ -+ while (1) { -+ pg_lock(kthread, __FUNCTION__); -+ if (kthread->cur_if || kthread->running_if_infos) { -+ pg_unlock(kthread, __FUNCTION__); -+ if (current->need_resched) { -+ schedule(); -+ } -+ mdelay(1); -+ } -+ else { -+ pg_unlock(kthread, __FUNCTION__); -+ break; -+ } -+ } -+ -+ /* this function needs to be protected with the big -+ kernel lock (lock_kernel()). The lock must be -+ grabbed before changing the terminate -+ flag and released after the down() call. */ -+ lock_kernel(); -+ -+ /* initialize the semaphore. We lock it here, the -+ leave_thread call of the thread to be terminated -+ will unlock it. As soon as we see the semaphore -+ unlocked, we know that the thread has exited. -+ */ -+ init_MUTEX_LOCKED(&kthread->startstop_sem); -+ -+ /* We need to do a memory barrier here to be sure that -+ the flags are visible on all CPUs. -+ */ -+ mb(); -+ -+ /* set flag to request thread termination */ -+ kthread->terminate = 1; -+ -+ /* We need to do a memory barrier here to be sure that -+ the flags are visible on all CPUs. -+ */ -+ mb(); -+ kill_proc(kthread->thread->pid, SIGKILL, 1); -+ -+ /* block till thread terminated */ -+ down(&kthread->startstop_sem); -+ kthread->in_use = 0; -+ -+ /* release the big kernel lock */ -+ unlock_kernel(); -+ -+ /* now we are sure the thread is in zombie state. We -+ notify keventd to clean the process up. -+ */ -+ kill_proc(2, SIGCHLD, 1); -+ -+ PG_DEBUG(printk("pgthread: %s done with stop_pktgen_kthread.\n", kthread->name)); -+}/* stop_pktgen_kthread */ -+ -+ -+/* initialize new created thread. Called by the new thread. */ -+void init_pktgen_kthread(struct pktgen_thread_info *kthread, char *name) { -+ /* lock the kernel. A new kernel thread starts without -+ the big kernel lock, regardless of the lock state -+ of the creator (the lock level is *not* inheritated) -+ */ -+ lock_kernel(); -+ -+ /* fill in thread structure */ -+ kthread->thread = current; -+ -+ /* set signal mask to what we want to respond */ -+ siginitsetinv(¤t->blocked, sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)); -+ -+ /* initialise wait queue */ -+ init_waitqueue_head(&kthread->queue); -+ -+ /* initialise termination flag */ -+ kthread->terminate = 0; -+ -+ /* set name of this process (max 15 chars + 0 !) */ -+ sprintf(current->comm, name); -+ -+ /* let others run */ -+ unlock_kernel(); -+ -+ /* tell the creator that we are ready and let him continue */ -+ up(&kthread->startstop_sem); -+}/* init_pktgen_kthread */ -+ -+/* cleanup of thread. Called by the exiting thread. */ -+static void exit_pktgen_kthread(struct pktgen_thread_info *kthread) { -+ /* we are terminating */ -+ -+ /* lock the kernel, the exit will unlock it */ -+ lock_kernel(); -+ kthread->thread = NULL; -+ mb(); -+ -+ /* Clean up proc file system */ -+ if (strlen(kthread->fname)) { -+ remove_proc_entry(kthread->fname, NULL); -+ } -+ -+ /* notify the stop_kthread() routine that we are terminating. */ -+ up(&kthread->startstop_sem); -+ /* the kernel_thread that called clone() does a do_exit here. */ -+ -+ /* there is no race here between execution of the "killer" and real termination -+ of the thread (race window between up and do_exit), since both the -+ thread and the "killer" function are running with the kernel lock held. -+ The kernel lock will be freed after the thread exited, so the code -+ is really not executed anymore as soon as the unload functions gets -+ the kernel lock back. -+ The init process may not have made the cleanup of the process here, -+ but the cleanup can be done safely with the module unloaded. -+ */ -+}/* exit_pktgen_kthread */ -+ -+ -+/* proc/net/pg */ -+ -+static char* pg_display_latency(struct pktgen_interface_info* info, char* p, int reset_latency) { -+ int i; -+ p += sprintf(p, " avg_latency: %dus min_lat: %dus max_lat: %dus pkts_in_sample: %llu\n", -+ info->avg_latency, info->min_latency, info->max_latency, -+ info->pkts_rcvd_since_clear); -+ p += sprintf(p, " Buckets(us) [ "); -+ for (i = 0; i<LAT_BUCKETS_MAX; i++) { -+ p += sprintf(p, "%llu ", info->latency_bkts[i]); -+ } -+ p += sprintf(p, "]\n"); -+ -+ if (reset_latency) { -+ pg_reset_latency_counters(info); -+ } -+ return p; - } - --static int proc_read(char *buf , char **start, off_t offset, -- int len, int *eof, void *data) -+static int proc_pg_if_read(char *buf , char **start, off_t offset, -+ int len, int *eof, void *data) - { - char *p; - int i; -- int idx = (int)(long)(data); -- struct pktgen_info* info = NULL; -+ struct pktgen_interface_info* info = (struct pktgen_interface_info*)(data); - __u64 sa; - __u64 stopped; -- __u64 now = getCurMs(); -+ __u64 now = getCurUs(); -+ __u64 now_rel_ns = getRelativeCurNs(); - -- if ((idx < 0) || (idx >= MAX_PKTGEN)) { -- printk("ERROR: idx: %i is out of range in proc_write\n", idx); -- return -EINVAL; -- } -- info = &(pginfos[idx]); -- - p = buf; -- p += sprintf(p, "%s\n", VERSION); /* Help with parsing compatibility */ -- p += sprintf(p, "Params: count %llu pkt_size: %u frags: %d ipg: %u clone_skb: %d odev \"%s\"\n", -- (unsigned long long) info->count, -- info->pkt_size, info->nfrags, info->ipg, -- info->clone_skb, info->outdev); -- p += sprintf(p, " dst_min: %s dst_max: %s src_min: %s src_max: %s\n", -+ p += sprintf(p, "VERSION-1\n"); /* Help with parsing compatibility */ -+ p += sprintf(p, "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n frags: %d ipg: %u multiskb: %d ifname: %s\n", -+ info->count, info->min_pkt_size, info->max_pkt_size, -+ info->nfrags, info->ipg, info->multiskb, info->ifname); -+ p += sprintf(p, " dst_min: %s dst_max: %s\n src_min: %s src_max: %s\n", - info->dst_min, info->dst_max, info->src_min, info->src_max); - p += sprintf(p, " src_mac: "); - for (i = 0; i < 6; i++) { -@@ -802,14 +1868,17 @@ - p += sprintf(p, " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", - info->udp_src_min, info->udp_src_max, info->udp_dst_min, - info->udp_dst_max); -- p += sprintf(p, " src_mac_count: %d dst_mac_count: %d\n Flags: ", -- info->src_mac_count, info->dst_mac_count); -+ p += sprintf(p, " src_mac_count: %d dst_mac_count: %d peer_multiskb: %d\n Flags: ", -+ info->src_mac_count, info->dst_mac_count, info->peer_multiskb); - if (info->flags & F_IPSRC_RND) { - p += sprintf(p, "IPSRC_RND "); - } - if (info->flags & F_IPDST_RND) { - p += sprintf(p, "IPDST_RND "); - } -+ if (info->flags & F_TXSIZE_RND) { -+ p += sprintf(p, "TXSIZE_RND "); -+ } - if (info->flags & F_UDPSRC_RND) { - p += sprintf(p, "UDPSRC_RND "); - } -@@ -824,22 +1893,24 @@ - } - p += sprintf(p, "\n"); - -- sa = tv_to_ms(&(info->started_at)); -- stopped = tv_to_ms(&(info->stopped_at)); -+ sa = info->started_at; -+ stopped = info->stopped_at; - if (info->do_run_run) { - stopped = now; /* not really stopped, more like last-running-at */ - } -- p += sprintf(p, "Current:\n pkts-sofar: %llu errors: %llu\n started: %llums stopped: %llums now: %llums idle: %lluns\n", -- (unsigned long long) info->sofar, -- (unsigned long long) info->errors, -- (unsigned long long) sa, -- (unsigned long long) stopped, -- (unsigned long long) now, -- (unsigned long long) info->idle_acc); -+ p += sprintf(p, "Current:\n pkts-sofar: %llu errors: %llu\n started: %lluus elapsed: %lluus\n idle: %lluns next_tx: %llu(%lli)ns\n", -+ info->sofar, info->errors, sa, (stopped - sa), info->idle_acc, -+ info->next_tx_ns, (long long)(info->next_tx_ns) - (long long)(now_rel_ns)); - p += sprintf(p, " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", - info->seq_num, info->cur_dst_mac_offset, info->cur_src_mac_offset); - p += sprintf(p, " cur_saddr: 0x%x cur_daddr: 0x%x cur_udp_dst: %d cur_udp_src: %d\n", - info->cur_saddr, info->cur_daddr, info->cur_udp_dst, info->cur_udp_src); -+ p += sprintf(p, " pkts_rcvd: %llu bytes_rcvd: %llu last_seq_rcvd: %d ooo_rcvd: %llu\n", -+ info->pkts_rcvd, info->bytes_rcvd, info->last_seq_rcvd, info->ooo_rcvd); -+ p += sprintf(p, " dup_rcvd: %llu seq_gap_rcvd(dropped): %llu non_pg_rcvd: %llu\n", -+ info->dup_rcvd, info->seq_gap_rcvd, info->non_pg_pkts_rcvd); -+ -+ p = pg_display_latency(info, p, 0); - - if (info->result[0]) - p += sprintf(p, "Result: %s\n", info->result); -@@ -850,16 +1921,94 @@ - return p - buf; - } - -+ -+static int proc_pg_thread_read(char *buf , char **start, off_t offset, -+ int len, int *eof, void *data) -+{ -+ char *p; -+ struct pktgen_thread_info* pg_thread = (struct pktgen_thread_info*)(data); -+ struct pktgen_interface_info* info = NULL; -+ -+ if (!pg_thread) { -+ printk("ERROR: could not find pg_thread in proc_pg_thread_read\n"); -+ return -EINVAL; -+ } -+ -+ p = buf; -+ p += sprintf(p, "VERSION-1\n"); /* Help with parsing compatibility */ -+ p += sprintf(p, "Name: %s max_before_softirq: %d\n", -+ pg_thread->name, pg_thread->max_before_softirq); -+ -+ pg_lock(pg_thread, __FUNCTION__); -+ if (pg_thread->cur_if) { -+ p += sprintf(p, "Current: %s\n", pg_thread->cur_if->ifname); -+ } -+ else { -+ p += sprintf(p, "Current: NULL\n"); -+ } -+ pg_unlock(pg_thread, __FUNCTION__); -+ -+ p += sprintf(p, "Running: "); -+ -+ pg_lock(pg_thread, __FUNCTION__); -+ info = pg_thread->running_if_infos; -+ while (info) { -+ p += sprintf(p, "%s ", info->ifname); -+ info = info->next; -+ } -+ p += sprintf(p, "\nStopped: "); -+ info = pg_thread->stopped_if_infos; -+ while (info) { -+ p += sprintf(p, "%s ", info->ifname); -+ info = info->next; -+ } -+ -+ if (pg_thread->result[0]) -+ p += sprintf(p, "\nResult: %s\n", pg_thread->result); -+ else -+ p += sprintf(p, "\nResult: NA\n"); -+ *eof = 1; -+ -+ pg_unlock(pg_thread, __FUNCTION__); -+ -+ return p - buf; -+}/* proc_pg_thread_read */ -+ -+ -+static int proc_pg_ctrl_read(char *buf , char **start, off_t offset, -+ int len, int *eof, void *data) -+{ -+ char *p; -+ struct pktgen_thread_info* pg_thread = NULL; -+ -+ p = buf; -+ p += sprintf(p, "VERSION-1\n"); /* Help with parsing compatibility */ -+ p += sprintf(p, "Threads: "); -+ -+ pg_lock_thread_list(__FUNCTION__); -+ pg_thread = pktgen_threads; -+ while (pg_thread) { -+ p += sprintf(p, "%s ", pg_thread->name); -+ pg_thread = pg_thread->next; -+ } -+ p += sprintf(p, "\n"); -+ -+ *eof = 1; -+ -+ pg_unlock_thread_list(__FUNCTION__); -+ return p - buf; -+}/* proc_pg_ctrl_read */ -+ -+ - static int count_trail_chars(const char *user_buffer, unsigned int maxlen) - { - int i; - - for (i = 0; i < maxlen; i++) { -- char c; -- -- if (get_user(c, &user_buffer[i])) -- return -EFAULT; -- switch (c) { -+ char c; -+ if (get_user(c, &user_buffer[i])) -+ return -EFAULT; -+ switch (c) { - case '\"': - case '\n': - case '\r': -@@ -875,7 +2024,7 @@ - return i; - } - --static unsigned long num_arg(const char *user_buffer, unsigned long maxlen, -+static unsigned long num_arg(const char *user_buffer, unsigned long maxlen, - unsigned long *num) - { - int i = 0; -@@ -883,11 +2032,10 @@ - *num = 0; - - for(; i < maxlen; i++) { -- char c; -- -- if (get_user(c, &user_buffer[i])) -- return -EFAULT; -- if ((c >= '0') && (c <= '9')) { -+ char c; -+ if (get_user(c, &user_buffer[i])) -+ return -EFAULT; -+ if ((c >= '0') && (c <= '9')) { - *num *= 10; - *num += c -'0'; - } else -@@ -901,11 +2049,10 @@ - int i = 0; - - for(; i < maxlen; i++) { -- char c; -- -- if (get_user(c, &user_buffer[i])) -- return -EFAULT; -- switch (c) { -+ char c; -+ if (get_user(c, &user_buffer[i])) -+ return -EFAULT; -+ switch (c) { - case '\"': - case '\n': - case '\r': -@@ -913,189 +2060,220 @@ - case ' ': - goto done_str; - default: -- break; - }; - } - done_str: - return i; - } - --static int proc_write(struct file *file, const char *user_buffer, -- unsigned long count, void *data) -+static int proc_pg_if_write(struct file *file, const char *user_buffer, -+ unsigned long count, void *data) - { - int i = 0, max, len; - char name[16], valstr[32]; - unsigned long value = 0; -- int idx = (int)(long)(data); -- struct pktgen_info* info = NULL; -- char* result = NULL; -- int tmp; -+ struct pktgen_interface_info* info = (struct pktgen_interface_info*)(data); -+ char* pg_result = NULL; -+ int tmp = 0; - -- if ((idx < 0) || (idx >= MAX_PKTGEN)) { -- printk("ERROR: idx: %i is out of range in proc_write\n", idx); -- return -EINVAL; -- } -- info = &(pginfos[idx]); -- result = &(info->result[0]); -+ pg_result = &(info->result[0]); - - if (count < 1) { -- sprintf(result, "Wrong command format"); -+ sprintf(pg_result, "Wrong command format"); - return -EINVAL; - } - - max = count - i; - tmp = count_trail_chars(&user_buffer[i], max); -- if (tmp < 0) -- return tmp; -- i += tmp; -- -+ if (tmp < 0) { return tmp; } -+ i += tmp; -+ - /* Read variable name */ - - len = strn_len(&user_buffer[i], sizeof(name) - 1); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - memset(name, 0, sizeof(name)); - copy_from_user(name, &user_buffer[i], len); - i += len; - - max = count -i; - len = count_trail_chars(&user_buffer[i], max); -- if (len < 0) -- return len; -+ if (len < 0) { -+ return len; -+ } - i += len; - -- if (debug) -- printk("pg: %s,%lu\n", name, count); -+ if (debug) { -+ char tb[count + 1]; -+ copy_from_user(tb, user_buffer, count); -+ tb[count] = 0; -+ printk("pg: %s,%lu buffer -:%s:-\n", name, count, tb); -+ } - - if (!strcmp(name, "stop")) { - if (info->do_run_run) { -- strcpy(result, "Stopping"); -+ strcpy(pg_result, "Stopping"); -+ pg_stop_interface(info->pg_thread, info); - } - else { -- strcpy(result, "Already stopped...\n"); -+ strcpy(pg_result, "Already stopped...\n"); -+ } -+ return count; -+ } -+ -+ if (!strcmp(name, "min_pkt_size")) { -+ len = num_arg(&user_buffer[i], 10, &value); -+ if (len < 0) { return len; } -+ i += len; -+ if (value < 14+20+8) -+ value = 14+20+8; -+ if (value != info->min_pkt_size) { -+ info->min_pkt_size = value; -+ info->cur_pkt_size = value; - } -- info->do_run_run = 0; -+ sprintf(pg_result, "OK: min_pkt_size=%u", info->min_pkt_size); -+ return count; -+ } -+ -+ if (!strcmp(name, "debug")) { -+ len = num_arg(&user_buffer[i], 10, &value); -+ if (len < 0) { return len; } -+ i += len; -+ debug = value; -+ sprintf(pg_result, "OK: debug=%u", debug); - return count; - } - -- if (!strcmp(name, "pkt_size")) { -+ if (!strcmp(name, "max_pkt_size")) { - len = num_arg(&user_buffer[i], 10, &value); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - i += len; - if (value < 14+20+8) - value = 14+20+8; -- info->pkt_size = value; -- sprintf(result, "OK: pkt_size=%u", info->pkt_size); -+ if (value != info->max_pkt_size) { -+ info->max_pkt_size = value; -+ info->cur_pkt_size = value; -+ } -+ sprintf(pg_result, "OK: max_pkt_size=%u", info->max_pkt_size); - return count; - } -- if (!strcmp(name, "frags")) { -+ -+ if (!strcmp(name, "frags")) { - len = num_arg(&user_buffer[i], 10, &value); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - i += len; - info->nfrags = value; -- sprintf(result, "OK: frags=%u", info->nfrags); -+ sprintf(pg_result, "OK: frags=%u", info->nfrags); - return count; - } - if (!strcmp(name, "ipg")) { - len = num_arg(&user_buffer[i], 10, &value); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - i += len; - info->ipg = value; -- sprintf(result, "OK: ipg=%u", info->ipg); -+ if ((getRelativeCurNs() + info->ipg) > info->next_tx_ns) { -+ info->next_tx_ns = getRelativeCurNs() + info->ipg; -+ } -+ sprintf(pg_result, "OK: ipg=%u", info->ipg); - return count; - } - if (!strcmp(name, "udp_src_min")) { - len = num_arg(&user_buffer[i], 10, &value); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - i += len; -- info->udp_src_min = value; -- sprintf(result, "OK: udp_src_min=%u", info->udp_src_min); -+ if (value != info->udp_src_min) { -+ info->udp_src_min = value; -+ info->cur_udp_src = value; -+ } -+ sprintf(pg_result, "OK: udp_src_min=%u", info->udp_src_min); - return count; - } - if (!strcmp(name, "udp_dst_min")) { - len = num_arg(&user_buffer[i], 10, &value); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - i += len; -- info->udp_dst_min = value; -- sprintf(result, "OK: udp_dst_min=%u", info->udp_dst_min); -+ if (value != info->udp_dst_min) { -+ info->udp_dst_min = value; -+ info->cur_udp_dst = value; -+ } -+ sprintf(pg_result, "OK: udp_dst_min=%u", info->udp_dst_min); - return count; - } - if (!strcmp(name, "udp_src_max")) { - len = num_arg(&user_buffer[i], 10, &value); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - i += len; -- info->udp_src_max = value; -- sprintf(result, "OK: udp_src_max=%u", info->udp_src_max); -+ if (value != info->udp_src_max) { -+ info->udp_src_max = value; -+ info->cur_udp_src = value; -+ } -+ sprintf(pg_result, "OK: udp_src_max=%u", info->udp_src_max); - return count; - } - if (!strcmp(name, "udp_dst_max")) { - len = num_arg(&user_buffer[i], 10, &value); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - i += len; -- info->udp_dst_max = value; -- sprintf(result, "OK: udp_dst_max=%u", info->udp_dst_max); -+ if (value != info->udp_dst_max) { -+ info->udp_dst_max = value; -+ info->cur_udp_dst = value; -+ } -+ sprintf(pg_result, "OK: udp_dst_max=%u", info->udp_dst_max); - return count; - } -- if (!strcmp(name, "clone_skb")) { -+ if (!strcmp(name, "multiskb")) { - len = num_arg(&user_buffer[i], 10, &value); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - i += len; -- info->clone_skb = value; -+ info->multiskb = value; - -- sprintf(result, "OK: clone_skb=%d", info->clone_skb); -+ sprintf(pg_result, "OK: multiskb=%d", info->multiskb); -+ return count; -+ } -+ if (!strcmp(name, "peer_multiskb")) { -+ len = num_arg(&user_buffer[i], 10, &value); -+ if (len < 0) { return len; } -+ i += len; -+ info->peer_multiskb = value; -+ -+ sprintf(pg_result, "OK: peer_multiskb=%d", info->peer_multiskb); - return count; - } - if (!strcmp(name, "count")) { - len = num_arg(&user_buffer[i], 10, &value); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - i += len; - info->count = value; -- sprintf(result, "OK: count=%llu", (unsigned long long) info->count); -+ sprintf(pg_result, "OK: count=%llu", info->count); - return count; - } - if (!strcmp(name, "src_mac_count")) { - len = num_arg(&user_buffer[i], 10, &value); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - i += len; -- info->src_mac_count = value; -- sprintf(result, "OK: src_mac_count=%d", info->src_mac_count); -+ if (info->src_mac_count != value) { -+ info->src_mac_count = value; -+ info->cur_src_mac_offset = 0; -+ } -+ sprintf(pg_result, "OK: src_mac_count=%d", info->src_mac_count); - return count; - } - if (!strcmp(name, "dst_mac_count")) { - len = num_arg(&user_buffer[i], 10, &value); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - i += len; -- info->dst_mac_count = value; -- sprintf(result, "OK: dst_mac_count=%d", info->dst_mac_count); -- return count; -- } -- if (!strcmp(name, "odev")) { -- len = strn_len(&user_buffer[i], sizeof(info->outdev) - 1); -- if (len < 0) -- return len; -- memset(info->outdev, 0, sizeof(info->outdev)); -- copy_from_user(info->outdev, &user_buffer[i], len); -- i += len; -- sprintf(result, "OK: odev=%s", info->outdev); -+ if (info->dst_mac_count != value) { -+ info->dst_mac_count = value; -+ info->cur_dst_mac_offset = 0; -+ } -+ sprintf(pg_result, "OK: dst_mac_count=%d", info->dst_mac_count); - return count; - } - if (!strcmp(name, "flag")) { - char f[32]; - memset(f, 0, 32); - len = strn_len(&user_buffer[i], sizeof(f) - 1); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - copy_from_user(f, &user_buffer[i], len); - i += len; - if (strcmp(f, "IPSRC_RND") == 0) { -@@ -1104,6 +2282,12 @@ - else if (strcmp(f, "!IPSRC_RND") == 0) { - info->flags &= ~F_IPSRC_RND; - } -+ else if (strcmp(f, "TXSIZE_RND") == 0) { -+ info->flags |= F_TXSIZE_RND; -+ } -+ else if (strcmp(f, "!TXSIZE_RND") == 0) { -+ info->flags &= ~F_TXSIZE_RND; -+ } - else if (strcmp(f, "IPDST_RND") == 0) { - info->flags |= F_IPDST_RND; - } -@@ -1135,69 +2319,94 @@ - info->flags &= ~F_MACDST_RND; - } - else { -- sprintf(result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", -+ sprintf(pg_result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", - f, -- "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n"); -+ "IPSRC_RND, IPDST_RND, TXSIZE_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n"); - return count; - } -- sprintf(result, "OK: flags=0x%x", info->flags); -+ sprintf(pg_result, "OK: flags=0x%x", info->flags); - return count; - } - if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { -+ char buf[IP_NAME_SZ]; - len = strn_len(&user_buffer[i], sizeof(info->dst_min) - 1); -- if (len < 0) -- return len; -- memset(info->dst_min, 0, sizeof(info->dst_min)); -- copy_from_user(info->dst_min, &user_buffer[i], len); -- if(debug) -- printk("pg: dst_min set to: %s\n", info->dst_min); -- i += len; -- sprintf(result, "OK: dst_min=%s", info->dst_min); -+ if (len < 0) { return len; } -+ copy_from_user(buf, &user_buffer[i], len); -+ buf[len] = 0; -+ if (strcmp(buf, info->dst_min) != 0) { -+ memset(info->dst_min, 0, sizeof(info->dst_min)); -+ strncpy(info->dst_min, buf, len); -+ info->daddr_min = in_aton(info->dst_min); -+ info->cur_daddr = info->daddr_min; -+ } -+ if(debug) -+ printk("pg: dst_min set to: %s\n", info->dst_min); -+ i += len; -+ sprintf(pg_result, "OK: dst_min=%s", info->dst_min); - return count; - } - if (!strcmp(name, "dst_max")) { -+ char buf[IP_NAME_SZ]; - len = strn_len(&user_buffer[i], sizeof(info->dst_max) - 1); -- if (len < 0) -- return len; -- memset(info->dst_max, 0, sizeof(info->dst_max)); -- copy_from_user(info->dst_max, &user_buffer[i], len); -+ if (len < 0) { return len; } -+ copy_from_user(buf, &user_buffer[i], len); -+ buf[len] = 0; -+ if (strcmp(buf, info->dst_max) != 0) { -+ memset(info->dst_max, 0, sizeof(info->dst_max)); -+ strncpy(info->dst_max, buf, len); -+ info->daddr_max = in_aton(info->dst_max); -+ info->cur_daddr = info->daddr_max; -+ } - if(debug) - printk("pg: dst_max set to: %s\n", info->dst_max); - i += len; -- sprintf(result, "OK: dst_max=%s", info->dst_max); -+ sprintf(pg_result, "OK: dst_max=%s", info->dst_max); - return count; - } - if (!strcmp(name, "src_min")) { -+ char buf[IP_NAME_SZ]; - len = strn_len(&user_buffer[i], sizeof(info->src_min) - 1); -- if (len < 0) -- return len; -- memset(info->src_min, 0, sizeof(info->src_min)); -- copy_from_user(info->src_min, &user_buffer[i], len); -+ if (len < 0) { return len; } -+ copy_from_user(buf, &user_buffer[i], len); -+ buf[len] = 0; -+ if (strcmp(buf, info->src_min) != 0) { -+ memset(info->src_min, 0, sizeof(info->src_min)); -+ strncpy(info->src_min, buf, len); -+ info->saddr_min = in_aton(info->src_min); -+ info->cur_saddr = info->saddr_min; -+ } - if(debug) - printk("pg: src_min set to: %s\n", info->src_min); - i += len; -- sprintf(result, "OK: src_min=%s", info->src_min); -+ sprintf(pg_result, "OK: src_min=%s", info->src_min); - return count; - } - if (!strcmp(name, "src_max")) { -+ char buf[IP_NAME_SZ]; - len = strn_len(&user_buffer[i], sizeof(info->src_max) - 1); -- if (len < 0) -- return len; -- memset(info->src_max, 0, sizeof(info->src_max)); -- copy_from_user(info->src_max, &user_buffer[i], len); -+ if (len < 0) { return len; } -+ copy_from_user(buf, &user_buffer[i], len); -+ buf[len] = 0; -+ if (strcmp(buf, info->src_max) != 0) { -+ memset(info->src_max, 0, sizeof(info->src_max)); -+ strncpy(info->src_max, buf, len); -+ info->saddr_max = in_aton(info->src_max); -+ info->cur_saddr = info->saddr_max; -+ } - if(debug) - printk("pg: src_max set to: %s\n", info->src_max); - i += len; -- sprintf(result, "OK: src_max=%s", info->src_max); -+ sprintf(pg_result, "OK: src_max=%s", info->src_max); - return count; - } -- if (!strcmp(name, "dstmac")) { -+ if (!strcmp(name, "dst_mac")) { - char *v = valstr; -+ unsigned char old_dmac[6]; - unsigned char *m = info->dst_mac; -- -+ memcpy(old_dmac, info->dst_mac, 6); -+ - len = strn_len(&user_buffer[i], sizeof(valstr) - 1); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - memset(valstr, 0, sizeof(valstr)); - copy_from_user(valstr, &user_buffer[i], len); - i += len; -@@ -1219,17 +2428,24 @@ - m++; - *m = 0; - } -- } -- sprintf(result, "OK: dstmac"); -+ } -+ -+ if (memcmp(old_dmac, info->dst_mac, 6) != 0) { -+ /* Set up Dest MAC */ -+ memcpy(&(info->hh[0]), info->dst_mac, 6); -+ } -+ -+ sprintf(pg_result, "OK: dstmac"); - return count; - } -- if (!strcmp(name, "srcmac")) { -+ if (!strcmp(name, "src_mac")) { - char *v = valstr; -+ unsigned char old_smac[6]; - unsigned char *m = info->src_mac; - -+ memcpy(old_smac, info->src_mac, 6); - len = strn_len(&user_buffer[i], sizeof(valstr) - 1); -- if (len < 0) -- return len; -+ if (len < 0) { return len; } - memset(valstr, 0, sizeof(valstr)); - copy_from_user(valstr, &user_buffer[i], len); - i += len; -@@ -1252,28 +2468,186 @@ - *m = 0; - } - } -- sprintf(result, "OK: srcmac"); -+ -+ if (memcmp(old_smac, info->src_mac, 6) != 0) { -+ /* Default to the interface's mac if not explicitly set. */ -+ if ((!(info->flags & F_SET_SRCMAC)) && info->odev) { -+ memcpy(&(info->hh[6]), info->odev->dev_addr, 6); -+ } -+ else { -+ memcpy(&(info->hh[6]), info->src_mac, 6); -+ } -+ } -+ -+ sprintf(pg_result, "OK: srcmac"); - return count; - } - -+ if (!strcmp(name, "clear_counters")) { -+ pg_clear_counters(info, 0); -+ sprintf(pg_result, "OK: Clearing counters...\n"); -+ return count; -+ } -+ - if (!strcmp(name, "inject") || !strcmp(name, "start")) { -- MOD_INC_USE_COUNT; -- if (info->busy) { -+ if (info->do_run_run) { - strcpy(info->result, "Already running...\n"); - } - else { -- info->busy = 1; -- strcpy(info->result, "Starting"); -- inject(info); -- info->busy = 0; -+ int rv; -+ if ((rv = pg_start_interface(info->pg_thread, info)) >= 0) { -+ strcpy(info->result, "Starting"); -+ } -+ else { -+ sprintf(info->result, "Error starting: %i\n", rv); -+ } - } -- MOD_DEC_USE_COUNT; - return count; - } - - sprintf(info->result, "No such parameter \"%s\"", name); - return -EINVAL; --} -+}/* proc_pg_if_write */ -+ -+ -+static int proc_pg_ctrl_write(struct file *file, const char *user_buffer, -+ unsigned long count, void *data) -+{ -+ int i = 0, max, len; -+ char name[16]; -+ struct pktgen_thread_info* pg_thread = NULL; -+ -+ if (count < 1) { -+ printk("Wrong command format"); -+ return -EINVAL; -+ } -+ -+ max = count - i; -+ len = count_trail_chars(&user_buffer[i], max); -+ if (len < 0) { return len; } -+ i += len; -+ -+ /* Read variable name */ -+ -+ len = strn_len(&user_buffer[i], sizeof(name) - 1); -+ if (len < 0) { return len; } -+ memset(name, 0, sizeof(name)); -+ copy_from_user(name, &user_buffer[i], len); -+ i += len; -+ -+ max = count -i; -+ len = count_trail_chars(&user_buffer[i], max); -+ if (len < 0) { return len; } -+ i += len; -+ -+ if (debug) -+ printk("pg_thread: %s,%lu\n", name, count); -+ -+ if (!strcmp(name, "stop")) { -+ char f[32]; -+ memset(f, 0, 32); -+ len = strn_len(&user_buffer[i], sizeof(f) - 1); -+ if (len < 0) { return len; } -+ copy_from_user(f, &user_buffer[i], len); -+ i += len; -+ pg_thread = pg_find_thread(f); -+ if (pg_thread) { -+ printk("pktgen INFO: stopping thread: %s\n", pg_thread->name); -+ stop_pktgen_kthread(pg_thread); -+ } -+ return count; -+ } -+ -+ if (!strcmp(name, "start")) { -+ char f[32]; -+ memset(f, 0, 32); -+ len = strn_len(&user_buffer[i], sizeof(f) - 1); -+ if (len < 0) { return len; } -+ copy_from_user(f, &user_buffer[i], len); -+ i += len; -+ pg_add_thread_info(f); -+ return count; -+ } -+ -+ return -EINVAL; -+}/* proc_pg_ctrl_write */ -+ -+ -+static int proc_pg_thread_write(struct file *file, const char *user_buffer, -+ unsigned long count, void *data) -+{ -+ int i = 0, max, len; -+ char name[16]; -+ struct pktgen_thread_info* pg_thread = (struct pktgen_thread_info*)(data); -+ char* pg_result = &(pg_thread->result[0]); -+ unsigned long value = 0; -+ -+ if (count < 1) { -+ sprintf(pg_result, "Wrong command format"); -+ return -EINVAL; -+ } -+ -+ max = count - i; -+ len = count_trail_chars(&user_buffer[i], max); -+ if (len < 0) { return len; } -+ i += len; -+ -+ /* Read variable name */ -+ -+ len = strn_len(&user_buffer[i], sizeof(name) - 1); -+ if (len < 0) { return len; } -+ memset(name, 0, sizeof(name)); -+ copy_from_user(name, &user_buffer[i], len); -+ i += len; -+ -+ max = count -i; -+ len = count_trail_chars(&user_buffer[i], max); -+ if (len < 0) { return len; } -+ i += len; -+ -+ if (debug) { -+ printk("pg_thread: %s,%lu\n", name, count); -+ } -+ -+ if (!strcmp(name, "add_interface")) { -+ char f[32]; -+ memset(f, 0, 32); -+ len = strn_len(&user_buffer[i], sizeof(f) - 1); -+ if (len < 0) { return len; } -+ copy_from_user(f, &user_buffer[i], len); -+ i += len; -+ pg_add_interface_info(pg_thread, f); -+ return count; -+ } -+ -+ if (!strcmp(name, "rem_interface")) { -+ struct pktgen_interface_info* info = NULL; -+ char f[32]; -+ memset(f, 0, 32); -+ len = strn_len(&user_buffer[i], sizeof(f) - 1); -+ if (len < 0) { return len; } -+ copy_from_user(f, &user_buffer[i], len); -+ i += len; -+ info = pg_find_interface(pg_thread, f); -+ if (info) { -+ pg_rem_interface_info(pg_thread, info); -+ return count; -+ } -+ else { -+ printk("ERROR: That interface is not found.\n"); -+ return -ENODEV; -+ } -+ } -+ -+ if (!strcmp(name, "max_before_softirq")) { -+ len = num_arg(&user_buffer[i], 10, &value); -+ pg_thread->max_before_softirq = value; -+ return count; -+ } -+ -+ -+ return -EINVAL; -+}/* proc_pg_thread_write */ - - - int create_proc_dir(void) -@@ -1282,109 +2656,348 @@ - /* does proc_dir already exists */ - len = strlen(PG_PROC_DIR); - -- for (proc_dir = proc_net->subdir; proc_dir; -- proc_dir=proc_dir->next) { -- if ((proc_dir->namelen == len) && -- (! memcmp(proc_dir->name, PG_PROC_DIR, len))) -+ for (pg_proc_dir = proc_net->subdir; pg_proc_dir; pg_proc_dir=pg_proc_dir->next) { -+ if ((pg_proc_dir->namelen == len) && -+ (! memcmp(pg_proc_dir->name, PG_PROC_DIR, len))) { - break; -+ } -+ } -+ -+ if (!pg_proc_dir) { -+ pg_proc_dir = create_proc_entry(PG_PROC_DIR, S_IFDIR, proc_net); - } -- if (!proc_dir) -- proc_dir = create_proc_entry(PG_PROC_DIR, S_IFDIR, proc_net); -- if (!proc_dir) return -ENODEV; -- return 1; -+ -+ if (!pg_proc_dir) { -+ return -ENODEV; -+ } -+ -+ return 0; - } - - int remove_proc_dir(void) - { - remove_proc_entry(PG_PROC_DIR, proc_net); -- return 1; -+ return 0; - } - --static int __init init(void) --{ -+static struct pktgen_interface_info* pg_find_interface(struct pktgen_thread_info* pg_thread, -+ const char* ifname) { -+ struct pktgen_interface_info* rv = NULL; -+ pg_lock(pg_thread, __FUNCTION__); -+ -+ if (pg_thread->cur_if && (strcmp(pg_thread->cur_if->ifname, ifname) == 0)) { -+ rv = pg_thread->cur_if; -+ goto found; -+ } -+ -+ rv = pg_thread->running_if_infos; -+ while (rv) { -+ if (strcmp(rv->ifname, ifname) == 0) { -+ goto found; -+ } -+ rv = rv->next; -+ } -+ -+ rv = pg_thread->stopped_if_infos; -+ while (rv) { -+ if (strcmp(rv->ifname, ifname) == 0) { -+ goto found; -+ } -+ rv = rv->next; -+ } -+ found: -+ pg_unlock(pg_thread, __FUNCTION__); -+ return rv; -+}/* pg_find_interface */ -+ -+ -+static int pg_add_interface_info(struct pktgen_thread_info* pg_thread, const char* ifname) { -+ struct pktgen_interface_info* i = pg_find_interface(pg_thread, ifname); -+ if (!i) { -+ i = kmalloc(sizeof(struct pktgen_interface_info), GFP_KERNEL); -+ if (!i) { -+ return -ENOMEM; -+ } -+ memset(i, 0, sizeof(struct pktgen_interface_info)); -+ -+ i->min_pkt_size = ETH_ZLEN; -+ i->max_pkt_size = ETH_ZLEN; -+ i->nfrags = 0; -+ i->multiskb = pg_multiskb_d; -+ i->peer_multiskb = 0; -+ i->ipg = pg_ipg_d; -+ i->count = pg_count_d; -+ i->sofar = 0; -+ i->hh[12] = 0x08; /* fill in protocol. Rest is filled in later. */ -+ i->hh[13] = 0x00; -+ i->udp_src_min = 9; /* sink NULL */ -+ i->udp_src_max = 9; -+ i->udp_dst_min = 9; -+ i->udp_dst_max = 9; -+ i->rcv = pktgen_receive; -+ -+ strncpy(i->ifname, ifname, 31); -+ sprintf(i->fname, "net/%s/%s", PG_PROC_DIR, ifname); -+ -+ if (! pg_setup_interface(i)) { -+ printk("ERROR: pg_setup_interface failed.\n"); -+ kfree(i); -+ return -ENODEV; -+ } -+ -+ i->proc_ent = create_proc_entry(i->fname, 0600, 0); -+ if (!i->proc_ent) { -+ printk("pktgen: Error: cannot create %s procfs entry.\n", i->fname); -+ kfree(i); -+ return -EINVAL; -+ } -+ i->proc_ent->read_proc = proc_pg_if_read; -+ i->proc_ent->write_proc = proc_pg_if_write; -+ i->proc_ent->data = (void*)(i); -+ -+ return add_interface_to_thread(pg_thread, i); -+ } -+ else { -+ printk("ERROR: interface already exists.\n"); -+ return -EBUSY; -+ } -+}/* pg_add_interface_info */ -+ -+ -+/* return the first !in_use thread structure */ -+static struct pktgen_thread_info* pg_gc_thread_list_helper(void) { -+ struct pktgen_thread_info* rv = NULL; -+ -+ pg_lock_thread_list(__FUNCTION__); -+ -+ rv = pktgen_threads; -+ while (rv) { -+ if (!rv->in_use) { -+ break; -+ } -+ rv = rv->next; -+ } -+ pg_unlock_thread_list(__FUNCTION__); -+ return rv; -+}/* pg_find_thread */ -+ -+static void pg_gc_thread_list(void) { -+ struct pktgen_thread_info* t = NULL; -+ struct pktgen_thread_info* w = NULL; -+ -+ while ((t = pg_gc_thread_list_helper())) { -+ pg_lock_thread_list(__FUNCTION__); -+ if (pktgen_threads == t) { -+ pktgen_threads = t->next; -+ kfree(t); -+ } -+ else { -+ w = pktgen_threads; -+ while (w) { -+ if (w->next == t) { -+ w->next = t->next; -+ t->next = NULL; -+ kfree(t); -+ break; -+ } -+ w = w->next; -+ } -+ } -+ pg_unlock_thread_list(__FUNCTION__); -+ } -+}/* pg_gc_thread_list */ -+ -+ -+static struct pktgen_thread_info* pg_find_thread(const char* name) { -+ struct pktgen_thread_info* rv = NULL; -+ -+ pg_gc_thread_list(); -+ -+ pg_lock_thread_list(__FUNCTION__); -+ -+ rv = pktgen_threads; -+ while (rv) { -+ if (strcmp(rv->name, name) == 0) { -+ break; -+ } -+ rv = rv->next; -+ } -+ pg_unlock_thread_list(__FUNCTION__); -+ return rv; -+}/* pg_find_thread */ -+ -+ -+static int pg_add_thread_info(const char* name) { -+ struct pktgen_thread_info* pg_thread = NULL; -+ -+ if (strlen(name) > 31) { -+ printk("pktgen ERROR: Thread name cannot be more than 31 characters.\n"); -+ return -EINVAL; -+ } -+ -+ if (pg_find_thread(name)) { -+ printk("pktgen ERROR: Thread: %s already exists\n", name); -+ return -EINVAL; -+ } -+ -+ pg_thread = (struct pktgen_thread_info*)(kmalloc(sizeof(struct pktgen_thread_info), GFP_KERNEL)); -+ if (!pg_thread) { -+ printk("pktgen: ERROR: out of memory, can't create new thread.\n"); -+ return -ENOMEM; -+ } -+ -+ memset(pg_thread, 0, sizeof(struct pktgen_thread_info)); -+ strcpy(pg_thread->name, name); -+ spin_lock_init(&(pg_thread->pg_threadlock)); -+ pg_thread->in_use = 1; -+ pg_thread->max_before_softirq = 100; -+ -+ sprintf(pg_thread->fname, "net/%s/%s", PG_PROC_DIR, pg_thread->name); -+ pg_thread->proc_ent = create_proc_entry(pg_thread->fname, 0600, 0); -+ if (!pg_thread->proc_ent) { -+ printk("pktgen: Error: cannot create %s procfs entry.\n", pg_thread->fname); -+ kfree(pg_thread); -+ return -EINVAL; -+ } -+ pg_thread->proc_ent->read_proc = proc_pg_thread_read; -+ pg_thread->proc_ent->write_proc = proc_pg_thread_write; -+ pg_thread->proc_ent->data = (void*)(pg_thread); -+ -+ pg_thread->next = pktgen_threads; -+ pktgen_threads = pg_thread; -+ -+ /* Start the thread running */ -+ start_pktgen_kthread(pg_thread); -+ -+ return 0; -+}/* pg_add_thread_info */ -+ -+ -+/* interface_info must be stopped and on the pg_thread stopped list -+ */ -+static int pg_rem_interface_info(struct pktgen_thread_info* pg_thread, -+ struct pktgen_interface_info* info) { -+ if (info->do_run_run) { -+ printk("WARNING: trying to remove a running interface, stopping it now.\n"); -+ pg_stop_interface(pg_thread, info); -+ } -+ -+ /* Diss-associate from the interface */ -+ check_remove_device(info); -+ -+ /* Clean up proc file system */ -+ if (strlen(info->fname)) { -+ remove_proc_entry(info->fname, NULL); -+ } -+ -+ pg_lock(pg_thread, __FUNCTION__); -+ { -+ /* Remove from the stopped list */ -+ struct pktgen_interface_info* p = pg_thread->stopped_if_infos; -+ if (p == info) { -+ pg_thread->stopped_if_infos = p->next; -+ p->next = NULL; -+ } -+ else { -+ while (p) { -+ if (p->next == info) { -+ p->next = p->next->next; -+ info->next = NULL; -+ break; -+ } -+ p = p->next; -+ } -+ } -+ -+ info->pg_thread = NULL; -+ } -+ pg_unlock(pg_thread, __FUNCTION__); -+ -+ return 0; -+}/* pg_rem_interface_info */ -+ -+ -+static int __init pg_init(void) { - int i; - printk(version); -+ -+ /* Initialize our global variables */ -+ for (i = 0; i<PG_INFO_HASH_MAX; i++) { -+ pg_info_hash[i] = NULL; -+ } -+ module_fname[0] = 0; -+ -+ if (handle_pktgen_hook) { -+ printk("pktgen: ERROR: pktgen is already loaded it seems..\n"); -+ /* Already loaded */ -+ return -EEXIST; -+ } -+ - cycles_calibrate(); -- if (cpu_speed == 0) { -+ if (pg_cycles_per_us == 0) { - printk("pktgen: Error: your machine does not have working cycle counter.\n"); - return -EINVAL; - } - - create_proc_dir(); - -- for (i = 0; i<MAX_PKTGEN; i++) { -- memset(&(pginfos[i]), 0, sizeof(pginfos[i])); -- pginfos[i].pkt_size = ETH_ZLEN; -- pginfos[i].nfrags = 0; -- pginfos[i].clone_skb = clone_skb_d; -- pginfos[i].ipg = ipg_d; -- pginfos[i].count = count_d; -- pginfos[i].sofar = 0; -- pginfos[i].hh[12] = 0x08; /* fill in protocol. Rest is filled in later. */ -- pginfos[i].hh[13] = 0x00; -- pginfos[i].udp_src_min = 9; /* sink NULL */ -- pginfos[i].udp_src_max = 9; -- pginfos[i].udp_dst_min = 9; -- pginfos[i].udp_dst_max = 9; -- -- sprintf(pginfos[i].fname, "net/%s/pg%i", PG_PROC_DIR, i); -- pginfos[i].proc_ent = create_proc_entry(pginfos[i].fname, 0600, 0); -- if (!pginfos[i].proc_ent) { -- printk("pktgen: Error: cannot create net/%s/pg procfs entry.\n", PG_PROC_DIR); -- goto cleanup_mem; -- } -- pginfos[i].proc_ent->read_proc = proc_read; -- pginfos[i].proc_ent->write_proc = proc_write; -- pginfos[i].proc_ent->data = (void*)(long)(i); -- -- sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i", PG_PROC_DIR, i); -- pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, 0); -- if (!pginfos[i].busy_proc_ent) { -- printk("pktgen: Error: cannot create net/%s/pg_busy procfs entry.\n", PG_PROC_DIR); -- goto cleanup_mem; -- } -- pginfos[i].busy_proc_ent->read_proc = proc_busy_read; -- pginfos[i].busy_proc_ent->data = (void*)(long)(i); -+ sprintf(module_fname, "net/%s/pgctrl", PG_PROC_DIR); -+ module_proc_ent = create_proc_entry(module_fname, 0600, 0); -+ if (!module_proc_ent) { -+ printk("pktgen: Error: cannot create %s procfs entry.\n", module_fname); -+ return -EINVAL; - } -- return 0; -- --cleanup_mem: -- for (i = 0; i<MAX_PKTGEN; i++) { -- if (strlen(pginfos[i].fname)) { -- remove_proc_entry(pginfos[i].fname, NULL); -- } -- if (strlen(pginfos[i].busy_fname)) { -- remove_proc_entry(pginfos[i].busy_fname, NULL); -- } -+ module_proc_ent->read_proc = proc_pg_ctrl_read; -+ module_proc_ent->write_proc = proc_pg_ctrl_write; -+ module_proc_ent->proc_fops = &(pktgen_fops); /* IOCTL hook */ -+ module_proc_ent->data = NULL; -+ -+ /* Register us to receive netdevice events */ -+ register_netdevice_notifier(&pktgen_notifier_block); -+ -+ /* Register handler */ -+ handle_pktgen_hook = pktgen_receive; -+ -+ for (i = 0; i<pg_thread_count; i++) { -+ char buf[30]; -+ sprintf(buf, "kpktgend_%i", i); -+ pg_add_thread_info(buf); - } -- return -ENOMEM; --} -+ -+ -+ return 0; -+}/* pg_init */ - - --static void __exit cleanup(void) -+static void __exit pg_cleanup(void) - { -- int i; -- for (i = 0; i<MAX_PKTGEN; i++) { -- if (strlen(pginfos[i].fname)) { -- remove_proc_entry(pginfos[i].fname, NULL); -- } -- if (strlen(pginfos[i].busy_fname)) { -- remove_proc_entry(pginfos[i].busy_fname, NULL); -- } -+ /* Un-register handler */ -+ handle_pktgen_hook = NULL; -+ -+ /* Stop all interfaces & threads */ -+ while (pktgen_threads) { -+ stop_pktgen_kthread(pktgen_threads); - } -+ -+ /* Un-register us from receiving netdevice events */ -+ unregister_netdevice_notifier(&pktgen_notifier_block); -+ -+ /* Clean up proc file system */ -+ remove_proc_entry(module_fname, NULL); -+ - remove_proc_dir(); -+ - } - --module_init(init); --module_exit(cleanup); - --MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se"); -+module_init(pg_init); -+module_exit(pg_cleanup); -+ -+MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se, Ben Greear<greearb@candelatech.com>"); - MODULE_DESCRIPTION("Packet Generator tool"); - MODULE_LICENSE("GPL"); --MODULE_PARM(count_d, "i"); --MODULE_PARM(ipg_d, "i"); --MODULE_PARM(cpu_speed, "i"); --MODULE_PARM(clone_skb_d, "i"); -- -- -- -+MODULE_PARM(pg_count_d, "i"); -+MODULE_PARM(pg_ipg_d, "i"); -+MODULE_PARM(pg_thread_count, "i"); -+MODULE_PARM(pg_multiskb_d, "i"); -+MODULE_PARM(debug, "i"); ---- linux-2.4.21/net/core/pktgen.h 1969-12-31 16:00:00.000000000 -0800 -+++ linux-2.4.21.amds/net/core/pktgen.h 2003-07-30 16:20:41.000000000 -0700 -@@ -0,0 +1,241 @@ -+/* -*-linux-c-*- -+ * $Id: candela_2.4.21.patch,v 1.4 2003/09/30 21:05:04 greear Exp $ -+ * pktgen.c: Packet Generator for performance evaluation. -+ * -+ * See pktgen.c for details of changes, etc. -+*/ -+ -+ -+#ifndef PKTGEN_H_INCLUDE_KERNEL__ -+#define PKTGEN_H_INCLUDE_KERNEL__ -+ -+ -+/* The buckets are exponential in 'width' */ -+#define LAT_BUCKETS_MAX 32 -+ -+#define IP_NAME_SZ 32 -+ -+/* Keep information per interface */ -+struct pktgen_interface_info { -+ char ifname[32]; -+ -+ /* Parameters */ -+ -+ /* If min != max, then we will either do a linear iteration, or -+ * we will do a random selection from within the range. -+ */ -+ __u32 flags; -+ -+#define F_IPSRC_RND (1<<0) /* IP-Src Random */ -+#define F_IPDST_RND (1<<1) /* IP-Dst Random */ -+#define F_UDPSRC_RND (1<<2) /* UDP-Src Random */ -+#define F_UDPDST_RND (1<<3) /* UDP-Dst Random */ -+#define F_MACSRC_RND (1<<4) /* MAC-Src Random */ -+#define F_MACDST_RND (1<<5) /* MAC-Dst Random */ -+#define F_SET_SRCMAC (1<<6) /* Specify-Src-Mac -+ (default is to use Interface's MAC Addr) */ -+#define F_SET_SRCIP (1<<7) /* Specify-Src-IP -+ (default is to use Interface's IP Addr) */ -+#define F_TXSIZE_RND (1<<8) /* Transmit size is random */ -+ -+ int min_pkt_size; /* = ETH_ZLEN; */ -+ int max_pkt_size; /* = ETH_ZLEN; */ -+ int nfrags; -+ __u32 ipg; /* Default Interpacket gap in nsec */ -+ __u64 count; /* Default No packets to send */ -+ __u64 sofar; /* How many pkts we've sent so far */ -+ __u64 tx_bytes; /* How many bytes we've transmitted */ -+ __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */ -+ -+ /* runtime counters relating to multiskb */ -+ __u64 next_tx_ns; /* timestamp of when to tx next, in nano-seconds */ -+ -+ __u64 fp; -+ __u32 fp_tmp; -+ int last_ok; /* Was last skb sent? -+ * Or a failed transmit of some sort? This will keep -+ * sequence numbers in order, for example. -+ */ -+ /* Fields relating to receiving pkts */ -+ __u32 last_seq_rcvd; -+ __u64 ooo_rcvd; /* out-of-order packets received */ -+ __u64 pkts_rcvd; /* packets received */ -+ __u64 dup_rcvd; /* duplicate packets received */ -+ __u64 bytes_rcvd; /* total bytes received, as obtained from the skb */ -+ __u64 seq_gap_rcvd; /* how many gaps we received. This coorelates to -+ * dropped pkts, except perhaps in cases where we also -+ * have re-ordered pkts. In that case, you have to tie-break -+ * by looking at send v/s received pkt totals for the interfaces -+ * involved. -+ */ -+ __u64 non_pg_pkts_rcvd; /* Count how many non-pktgen skb's we are sent to check. */ -+ __u64 dup_since_incr; /* How many dumplicates since the last seq number increment, -+ * used to detect gaps when multiskb > 1 -+ */ -+ int avg_latency; /* in micro-seconds */ -+ int min_latency; -+ int max_latency; -+ __u64 latency_bkts[LAT_BUCKETS_MAX]; -+ __u64 pkts_rcvd_since_clear; /* with regard to clearing/resetting the latency logic */ -+ -+ __u64 started_at; /* micro-seconds */ -+ __u64 stopped_at; /* micro-seconds */ -+ __u64 idle_acc; -+ __u32 seq_num; -+ -+ int multiskb; /* Use multiple SKBs during packet gen. If this number -+ * is greater than 1, then that many coppies of the same -+ * packet will be sent before a new packet is allocated. -+ * For instance, if you want to send 1024 identical packets -+ * before creating a new packet, set multiskb to 1024. -+ */ -+ int peer_multiskb; /* Helps detect drops when multiskb > 1 on peer */ -+ int do_run_run; /* if this changes to false, the test will stop */ -+ -+ char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ -+ char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ -+ char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ -+ char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ -+ -+ /* If we're doing ranges, random or incremental, then this -+ * defines the min/max for those ranges. -+ */ -+ __u32 saddr_min; /* inclusive, source IP address */ -+ __u32 saddr_max; /* exclusive, source IP address */ -+ __u32 daddr_min; /* inclusive, dest IP address */ -+ __u32 daddr_max; /* exclusive, dest IP address */ -+ -+ __u16 udp_src_min; /* inclusive, source UDP port */ -+ __u16 udp_src_max; /* exclusive, source UDP port */ -+ __u16 udp_dst_min; /* inclusive, dest UDP port */ -+ __u16 udp_dst_max; /* exclusive, dest UDP port */ -+ -+ __u32 src_mac_count; /* How many MACs to iterate through */ -+ __u32 dst_mac_count; /* How many MACs to iterate through */ -+ -+ unsigned char dst_mac[6]; -+ unsigned char src_mac[6]; -+ -+ __u32 cur_dst_mac_offset; -+ __u32 cur_src_mac_offset; -+ __u32 cur_saddr; -+ __u32 cur_daddr; -+ __u16 cur_udp_dst; -+ __u16 cur_udp_src; -+ __u32 cur_pkt_size; -+ -+ __u8 hh[14]; -+ /* = { -+ 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, -+ -+ We fill in SRC address later -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x08, 0x00 -+ }; -+ */ -+ __u16 pad; /* pad out the hh struct to an even 16 bytes */ -+ char result[512]; -+ /* proc file names */ -+ char fname[80]; -+ -+ /* End of stuff that user-space should care about */ -+ -+ struct sk_buff* skb; /* skb we are to transmit next, mainly used for when we -+ * are transmitting the same one multiple times -+ */ -+ struct pktgen_thread_info* pg_thread; /* the owner */ -+ -+ struct pktgen_interface_info* next_hash; /* Used for chaining in the hash buckets */ -+ struct pktgen_interface_info* next; /* Used for chaining in the thread's run-queue */ -+ -+ -+ -+ struct net_device* odev; /* The out-going device. Note that the device should -+ * have it's pg_info pointer pointing back to this -+ * device. This will be set when the user specifies -+ * the out-going device name (not when the inject is -+ * started as it used to do.) -+ */ -+ -+ struct proc_dir_entry *proc_ent; -+ -+ int (*rcv) (struct sk_buff *skb); -+}; /* pktgen_interface_info */ -+ -+ -+struct pktgen_hdr { -+ __u32 pgh_magic; -+ __u32 seq_num; -+ struct timeval timestamp; -+}; -+ -+ -+/* Define some IOCTLs. Just picking random numbers, basically. */ -+#define GET_PKTGEN_INTERFACE_INFO 0x7450 -+ -+struct pktgen_ioctl_info { -+ char thread_name[32]; -+ char interface_name[32]; -+ struct pktgen_interface_info info; -+}; -+ -+ -+struct pktgen_thread_info { -+ struct pktgen_interface_info* running_if_infos; /* list of running interfaces, current will -+ * not be in this list. -+ */ -+ struct pktgen_interface_info* stopped_if_infos; /* list of stopped interfaces. */ -+ struct pktgen_interface_info* cur_if; /* Current (running) interface we are servicing in -+ * the main thread loop. -+ */ -+ -+ int running_if_sz; -+ struct pktgen_thread_info* next; -+ char name[32]; -+ char fname[128]; /* name of proc file */ -+ struct proc_dir_entry *proc_ent; -+ char result[512]; -+ u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */ -+ -+ spinlock_t pg_threadlock; -+ -+ /* Linux task structure of thread */ -+ struct task_struct *thread; -+ -+ /* Task queue need to launch thread */ -+ struct tq_struct tq; -+ -+ /* function to be started as thread */ -+ void (*function) (struct pktgen_thread_info *kthread); -+ -+ /* semaphore needed on start and creation of thread. */ -+ struct semaphore startstop_sem; -+ -+ /* public data */ -+ -+ /* queue thread is waiting on. Gets initialized by -+ init_kthread, can be used by thread itself. -+ */ -+ wait_queue_head_t queue; -+ -+ /* flag to tell thread whether to die or not. -+ When the thread receives a signal, it must check -+ the value of terminate and call exit_kthread and terminate -+ if set. -+ */ -+ int terminate; -+ -+ int in_use; /* if 0, then we can delete or re-use this struct */ -+ -+ /* additional data to pass to kernel thread */ -+ void *arg; -+};/* struct pktgen_thread_info */ -+ -+/* Defined in dev.c */ -+extern int (*handle_pktgen_hook)(struct sk_buff *skb); -+ -+/* Returns < 0 if the skb is not a pktgen buffer. */ -+int pktgen_receive(struct sk_buff* skb); -+ -+ -+#endif ---- linux-2.4.21/net/netsyms.c 2003-06-13 07:51:39.000000000 -0700 -+++ linux-2.4.21.amds/net/netsyms.c 2003-07-30 16:20:41.000000000 -0700 -@@ -30,6 +30,7 @@ - #include <net/pkt_sched.h> - #include <net/scm.h> - #include <linux/if_bridge.h> -+#include <linux/if_macvlan.h> - #include <linux/if_vlan.h> - #include <linux/random.h> - #ifdef CONFIG_NET_DIVERT -@@ -90,6 +91,14 @@ - extern int sysctl_max_syn_backlog; - #endif - -+#ifdef CONFIG_NET_PKTGEN_MODULE -+#warning "EXPORT_SYMBOL(handle_pktgen_hook);"; -+extern int (*handle_pktgen_hook)(struct sk_buff *skb); -+/* Would be OK to export as EXPORT_SYMBOL_GPL, but can't get that to work for -+ * some reason. --Ben */ -+EXPORT_SYMBOL(handle_pktgen_hook); -+#endif -+ - /* Skbuff symbols. */ - EXPORT_SYMBOL(skb_over_panic); - EXPORT_SYMBOL(skb_under_panic); -@@ -234,6 +243,13 @@ - #endif - #endif - -+#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE) -+EXPORT_SYMBOL(macvlan_handle_frame_hook); -+#ifdef CONFIG_INET -+EXPORT_SYMBOL(macvlan_ioctl_hook); -+#endif -+#endif -+ - #ifdef CONFIG_NET_DIVERT - EXPORT_SYMBOL(alloc_divert_blk); - EXPORT_SYMBOL(free_divert_blk); ---- linux-2.4.21/Documentation/networking/pktgen.txt 2003-06-13 07:51:29.000000000 -0700 -+++ linux-2.4.21.amds/Documentation/networking/pktgen.txt 2003-07-30 16:20:41.000000000 -0700 -@@ -1,76 +1,118 @@ - How to use the Linux packet generator module. - --1. Enable CONFIG_NET_PKTGEN to compile and build pktgen.o, install it -- in the place where insmod may find it. --2. Cut script "ipg" (see below). --3. Edit script to set preferred device and destination IP address. --3a. Create more scripts for different interfaces. Up to thirty-two -- pktgen processes can be configured and run at once by using the -- 32 /proc/net/pktgen/pg* files. --4. Run in shell: ". ipg" --5. After this two commands are defined: -- A. "pg" to start generator and to get results. -- B. "pgset" to change generator parameters. F.e. -- pgset "multiskb 1" use multiple SKBs for packet generation -- pgset "multiskb 0" use single SKB for all transmits -- pgset "pkt_size 9014" sets packet size to 9014 -- pgset "frags 5" packet will consist of 5 fragments -- pgset "count 200000" sets number of packets to send, set to zero -- for continious sends untill explicitly -- stopped. -- pgset "ipg 5000" sets artificial gap inserted between packets -- to 5000 nanoseconds -- pgset "dst 10.0.0.1" sets IP destination address -- (BEWARE! This generator is very aggressive!) -- pgset "dst_min 10.0.0.1" Same as dst -- pgset "dst_max 10.0.0.254" Set the maximum destination IP. -- pgset "src_min 10.0.0.1" Set the minimum (or only) source IP. -- pgset "src_max 10.0.0.254" Set the maximum source IP. -- pgset "dstmac 00:00:00:00:00:00" sets MAC destination address -- pgset "srcmac 00:00:00:00:00:00" sets MAC source address -- pgset "src_mac_count 1" Sets the number of MACs we'll range through. The -- 'minimum' MAC is what you set with srcmac. -- pgset "dst_mac_count 1" Sets the number of MACs we'll range through. The -- 'minimum' MAC is what you set with dstmac. -- pgset "flag [name]" Set a flag to determine behaviour. Current flags -- are: IPSRC_RND #IP Source is random (between min/max), -- IPDST_RND, UDPSRC_RND, -- UDPDST_RND, MACSRC_RND, MACDST_RND -- pgset "udp_src_min 9" set UDP source port min, If < udp_src_max, then -- cycle through the port range. -- pgset "udp_src_max 9" set UDP source port max. -- pgset "udp_dst_min 9" set UDP destination port min, If < udp_dst_max, then -- cycle through the port range. -- pgset "udp_dst_max 9" set UDP destination port max. -- pgset stop aborts injection -+1. Enable CONFIG_NET_PKTGEN to compile and build pktgen.o, install it -+ in the place where insmod may find it. -+2. Add an interface to the kpktgend_0 thread: -+ echo "add_interface eth1" > /proc/net/pktgen/kpktgend_0 -+2a. Add more interfaces as needed. -+3. Configure interfaces by setting values as defined below. The -+ general strategy is: echo "command" > /proc/net/pktgen/[device] -+ For example: echo "multiskb 100" > /proc/net/pktgen/eth1 -+ -+ "multiskb 100" Will send 100 identical pkts before creating -+ new packet with new timestamp, etc. -+ "multiskb 0" Will create new skb for all transmits. -+ "peer_multiskb 100" Helps us determine dropped & dup pkts, sender's multiskb. -+ "min_pkt_size 60" sets packet minimum size to 60 (64 counting CRC) -+ "max_pkt_size 1514" sets packet size to 1514 (1518 counting CRC) -+ "frags 5" packet will consist of 5 fragments -+ "count 200000" sets number of packets to send, set to zero -+ for continious sends untill explicitly -+ stopped. -+ "ipg 5000" sets artificial gap inserted between packets -+ to 5000 nanoseconds -+ "dst 10.0.0.1" sets IP destination address -+ (BEWARE! This generator is very aggressive!) -+ "dst_min 10.0.0.1" Same as dst -+ "dst_max 10.0.0.254" Set the maximum destination IP. -+ "src_min 10.0.0.1" Set the minimum (or only) source IP. -+ "src_max 10.0.0.254" Set the maximum source IP. -+ "dst_mac 00:00:00:00:00:00" sets MAC destination address -+ "src_mac 00:00:00:00:00:00" sets MAC source address -+ "src_mac_count 1" Sets the number of MACs we'll range through. The -+ 'minimum' MAC is what you set with srcmac. -+ "dst_mac_count 1" Sets the number of MACs we'll range through. The -+ 'minimum' MAC is what you set with dstmac. -+ "flag [name]" Set a flag to determine behaviour. Prepend '!' to the -+ flag to turn it off. Current flags are: -+ IPSRC_RND #IP Source is random (between min/max), -+ IPDST_RND, UDPSRC_RND, TXSIZE_RND -+ UDPDST_RND, MACSRC_RND, MACDST_RND -+ "udp_src_min 9" set UDP source port min, If < udp_src_max, then -+ cycle through the port range. -+ "udp_src_max 9" set UDP source port max. -+ "udp_dst_min 9" set UDP destination port min, If < udp_dst_max, then -+ cycle through the port range. -+ "udp_dst_max 9" set UDP destination port max. -+ "stop" Stops this interface from transmitting. It will still -+ receive packets and record their latency, etc. -+ "start" Starts the interface transmitting packets. -+ "clear_counters" Clear the packet and latency counters. -+ -+You can start and stop threads by echoing commands to the /proc/net/pktgen/pgctrl -+file. Supported commands are: -+ "stop kpktgend_0" Stop thread 0. -+ "start threadXX" Start (create) thread XX. You may wish to create one thread -+ per CPU. - -- Also, ^C aborts generator. - ------ cut here -+You can control manage the interfaces on a thread by echoing commands to -+the /proc/net/pktgen/[thread] file. Supported commands are: -+ "add_interface eth1" Add interface eth1 to the chosen thread. -+ "rem_interface eth1" Remove interface eth1 from the chosen thread. -+ "max_before_softirq" Maximum loops before we cause a call to do_softirq, -+ this is to help mitigate starvatation on the RX side. -+ -+ -+You can examine various counters and parameters by reading the appropriate -+proc file: -+ -+[root@localhost lanforge]# cat /proc/net/pktgen/kpktgend_0 -+VERSION-1 -+Name: kpktgend_0 -+Current: eth2 -+Running: eth6 -+Stopped: eth1 eth5 -+Result: NA -+ -+ -+[root@localhost lanforge]# cat /proc/net/pktgen/eth2 -+VERSION-1 -+Params: count 0 pkt_size: 300 frags: 0 ipg: 0 multiskb: 0 ifname "eth2" -+ dst_min: 172.2.1.1 dst_max: 172.2.1.6 src_min: 172.1.1.4 src_max: 172.1.1.8 -+ src_mac: 00:00:00:00:00:00 dst_mac: 00:00:00:00:00:00 -+ udp_src_min: 99 udp_src_max: 1005 udp_dst_min: 9 udp_dst_max: 9 -+ src_mac_count: 0 dst_mac_count: 0 -+ Flags: IPSRC_RND IPDST_RND UDPSRC_RND -+Current: -+ pkts-sofar: 158835950 errors: 0 -+ started: 1026024703542360us elapsed: 4756326418us -+ idle: 1723232054307ns next_tx: 27997154666566(-3202934)ns -+ seq_num: 158835951 cur_dst_mac_offset: 0 cur_src_mac_offset: 0 -+ cur_saddr: 0x60101ac cur_daddr: 0x30102ac cur_udp_dst: 9 cur_udp_src: 966 -+ pkts_rcvd: 476002 bytes_rcvd: 159929440 last_seq_rcvd: 476002 ooo_rcvd: 0 -+ dup_rcvd: 0 seq_gap_rcvd(dropped): 0 non_pg_rcvd: 0 -+ avg_latency: 41us min_latency: 40us max_latency: 347us pkts_in_sample: 476002 -+ Buckets(us) [ 0 0 0 0 0 0 311968 164008 23 3 0 0 0 0 0 0 0 0 0 0 ] -+Result: OK: ipg=0 -+ -+[root@localhost lanforge]# cat /proc/net/pktgen/eth6 -+VERSION-1 -+Params: count 0 pkt_size: 300 frags: 0 ipg: 11062341 multiskb: 0 ifname "eth6" -+ dst_min: 90 dst_max: 90 src_min: 90 src_max: 90 -+ src_mac: 00:00:00:00:00:00 dst_mac: 00:00:00:00:00:00 -+ udp_src_min: 9 udp_src_max: 9 udp_dst_min: 9 udp_dst_max: 9 -+ src_mac_count: 0 dst_mac_count: 0 -+ Flags: -+Current: -+ pkts-sofar: 479940 errors: 0 -+ started: 1026024703542707us elapsed: 4795667656us -+ idle: 109585100905ns next_tx: 28042807786397(-79364)ns -+ seq_num: 479941 cur_dst_mac_offset: 0 cur_src_mac_offset: 0 -+ cur_saddr: 0x0 cur_daddr: 0x0 cur_udp_dst: 9 cur_udp_src: 9 -+ pkts_rcvd: 160323509 bytes_rcvd: 50392479910 last_seq_rcvd: 160323509 ooo_rcvd: 0 -+ dup_rcvd: 0 seq_gap_rcvd(dropped): 0 non_pg_rcvd: 0 -+ avg_latency: 230us min_latency: 36us max_latency: 1837us pkts_in_sample: 160323509 -+ Buckets(us) [ 0 0 0 0 0 0 287725 2618755 54130607 98979415 80358 4226649 0 0 0 0 0 0 0 0 ] -+Result: OK: ipg=11062341 - --#! /bin/sh -- --modprobe pktgen -- --PGDEV=/proc/net/pktgen/pg0 -- --function pgset() { -- local result -- -- echo $1 > $PGDEV -- -- result=`cat $PGDEV | fgrep "Result: OK:"` -- if [ "$result" = "" ]; then -- cat $PGDEV | fgrep Result: -- fi --} -- --function pg() { -- echo inject > $PGDEV -- cat $PGDEV --} -- --pgset "odev eth0" --pgset "dst 0.0.0.0" -- ------ cut here ---- linux-2.4.21/include/linux/if_macvlan.h 1969-12-31 16:00:00.000000000 -0800 -+++ linux-2.4.21.amds/include/linux/if_macvlan.h 2003-07-30 16:28:27.000000000 -0700 -@@ -0,0 +1,57 @@ -+/* -*- linux-c -*- */ -+#ifndef _LINUX_IF_MACVLAN_H -+#define _LINUX_IF_MACVLAN_H -+ -+/* the ioctl commands */ -+ -+/* actions */ -+#define MACVLAN_ENABLE 1 -+#define MACVLAN_DISABLE 2 -+#define MACVLAN_ADD 3 -+#define MACVLAN_DEL 4 -+#define MACVLAN_BIND 5 -+#define MACVLAN_UNBIND 6 -+ -+/* informative */ -+#define MACVLAN_GET_NUM_PORTS 7 -+#define MACVLAN_GET_PORT_NAME 8 -+#define MACVLAN_GET_NUM_VLANS 9 -+#define MACVLAN_GET_VLAN_NAME 10 -+#define MACVLAN_GET_NUM_MACS 11 -+#define MACVLAN_GET_MAC_NAME 12 -+ -+#define MACVLAN_SET_PORT_FLAGS 13 -+#define MACVLAN_GET_PORT_FLAGS 14 -+ -+/* If this IOCTL succeedes, we are a MAC-VLAN interface, otherwise, we are not. */ -+#define MACVLAN_IS_MACVLAN 15 -+ -+ -+#ifdef __KERNEL__ -+#include <linux/if.h> -+#include <linux/netdevice.h> -+extern int (*macvlan_ioctl_hook)(unsigned long arg); -+ -+/* Returns >= 0 if it consumed the packet, otherwise let the pkt -+ * be processed by the netif_rx method, as if macvlan's didn't -+ * exist. -+ */ -+extern int (*macvlan_handle_frame_hook)(struct sk_buff *skb); -+#endif -+ -+struct macvlan_ioctl_reply { -+ int num; -+ char name[IFNAMSIZ]; -+}; -+ -+struct macvlan_ioctl { -+ int cmd; -+ int portidx; -+ char *ifname; -+ int ifidx; /* flags when setting port flags */ -+ unsigned char *macaddr; -+ int macaddridx; -+ struct macvlan_ioctl_reply *reply; -+}; -+ -+#endif ---- linux-2.4.21/include/linux/sockios.h 2003-06-13 07:51:39.000000000 -0700 -+++ linux-2.4.21.amds/include/linux/sockios.h 2003-07-30 16:20:41.000000000 -0700 -@@ -65,6 +65,8 @@ - #define SIOCDIFADDR 0x8936 /* delete PA address */ - #define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */ - #define SIOCGIFCOUNT 0x8938 /* get number of devices */ -+#define SIOCGIFWEIGHT 0x8939 /* get weight of device, in stones */ -+#define SIOCSIFWEIGHT 0x893a /* set weight of device, in stones */ - - #define SIOCGIFBR 0x8940 /* Bridging support */ - #define SIOCSIFBR 0x8941 /* Set bridging options */ -@@ -94,6 +96,10 @@ - #define SIOCGRARP 0x8961 /* get RARP table entry */ - #define SIOCSRARP 0x8962 /* set RARP table entry */ - -+/* MAC address based VLAN control calls */ -+#define SIOCGIFMACVLAN 0x8965 /* Mac address multiplex/demultiplex support */ -+#define SIOCSIFMACVLAN 0x8966 /* Set macvlan options */ -+ - /* Driver configuration calls */ - - #define SIOCGIFMAP 0x8970 /* Get device parameters */ -@@ -116,6 +122,15 @@ - #define SIOCBONDINFOQUERY 0x8994 /* rtn info about bond state */ - #define SIOCBONDCHANGEACTIVE 0x8995 /* update to a new active slave */ - -+ -+/* Ben's little hack land */ -+#define SIOCSACCEPTLOCALADDRS 0x89a0 /* Allow interfaces to accept pkts from -+ * local interfaces...use with SO_BINDTODEVICE -+ */ -+#define SIOCGACCEPTLOCALADDRS 0x89a1 /* Allow interfaces to accept pkts from -+ * local interfaces...use with SO_BINDTODEVICE -+ */ -+ - /* Device private ioctl calls */ - - /* ---- linux-2.4.21/net/Config.in 2002-08-02 17:39:46.000000000 -0700 -+++ linux-2.4.21.amds/net/Config.in 2003-07-30 16:20:41.000000000 -0700 -@@ -48,6 +48,7 @@ - bool ' Per-VC IP filter kludge' CONFIG_ATM_BR2684_IPFILTER - fi - fi -+ tristate 'MAC address based VLANs (EXPERIMENTAL)' CONFIG_MACVLAN - fi - tristate '802.1Q VLAN Support' CONFIG_VLAN_8021Q - ---- linux-2.4.21/net/Makefile 2002-08-02 17:39:46.000000000 -0700 -+++ linux-2.4.21.amds/net/Makefile 2003-07-30 16:20:41.000000000 -0700 -@@ -44,7 +44,8 @@ - subdir-$(CONFIG_ATM) += atm - subdir-$(CONFIG_DECNET) += decnet - subdir-$(CONFIG_ECONET) += econet --subdir-$(CONFIG_VLAN_8021Q) += 8021q -+subdir-$(CONFIG_VLAN_8021Q) += 8021q -+subdir-$(CONFIG_MACVLAN) += macvlan - - - obj-y := socket.o $(join $(subdir-y), $(patsubst %,/%.o,$(notdir $(subdir-y)))) ---- linux-2.4.21/net/ipv4/af_inet.c 2003-06-13 07:51:39.000000000 -0700 -+++ linux-2.4.21.amds/net/ipv4/af_inet.c 2003-07-30 16:20:41.000000000 -0700 -@@ -143,6 +143,10 @@ - int (*br_ioctl_hook)(unsigned long); - #endif - -+#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE) -+int (*macvlan_ioctl_hook)(unsigned long) = NULL; -+#endif -+ - #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) - int (*vlan_ioctl_hook)(unsigned long arg); - #endif -@@ -879,6 +883,18 @@ - #endif - return -ENOPKG; - -+ case SIOCGIFMACVLAN: -+ case SIOCSIFMACVLAN: -+#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE) -+#ifdef CONFIG_KMOD -+ if (macvlan_ioctl_hook == NULL) -+ request_module("macvlan"); -+#endif -+ if (macvlan_ioctl_hook != NULL) -+ return macvlan_ioctl_hook(arg); -+#endif -+ return -ENOPKG; -+ - case SIOCGIFVLAN: - case SIOCSIFVLAN: - #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ---- linux-2.4.21/net/macvlan/Makefile 1969-12-31 16:00:00.000000000 -0800 -+++ linux-2.4.21.amds/net/macvlan/Makefile 2003-07-30 16:20:41.000000000 -0700 -@@ -0,0 +1,11 @@ -+# -+# Note! Dependencies are done automagically by 'make dep', which also -+# removes any old dependencies. DON'T put your own dependencies here -+# unless it's something special (ie not a .c file). -+# -+# Note 2! The CFLAGS definition is now in the main makefile... -+ -+O_TARGET := mac-mux.o -+obj-$(CONFIG_MACVLAN) := macvlan.o -+ -+include $(TOPDIR)/Rules.make ---- linux-2.4.21/net/macvlan/macvlan.c 1969-12-31 16:00:00.000000000 -0800 -+++ linux-2.4.21.amds/net/macvlan/macvlan.c 2003-08-13 16:26:11.000000000 -0700 -@@ -0,0 +1,2051 @@ -+/* -*- linux-c -*- -+####################################################################### -+# -+# (C) Copyright 2001-2003 -+# Alex Zeffertt, Cambridge Broadband Ltd, ajz@cambridgebroadband.com -+# Re-worked by Ben Greear <greearb@candelatech.com> -+# -+# This program is free software; you can redistribute it and/or -+# modify it under the terms of the GNU General Public License as -+# published by the Free Software Foundation; either version 2 of -+# the License, or (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software -+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, -+# MA 02111-1307 USA -+####################################################################### -+# Notes: -+# -+# This file implements the macvlan.o MAC address based VLAN support -+# module. -+# -+# This provides an IOCTL interface which allows you to -+# It uses an IOCTL interface which allows you to -+# -+# 1. enable/disable MAC address based VLANS over an ether type net_device -+# 2. add/remove a MAC address based VLAN - which is an ether type net_device -+# layered over the original MACVLAN enabled ether type net_device. -+# 3. bind/unbind MAC addresses to/from particular MAC address based VLANs -+# 4. discover the state of MAC address based VLANs on the system. -+# 5. set/get port flags, including whether to bind to destination MAC -+# or source mac. -+# 6. Traffic to/from eth0 will not be affected. -+ -+# Example: (Assuming you are using source binding) -+# -+# If you enable MAC address based VLANS over eth0 -+# -+# You may then create further VLANs, e.g. eth0#1 eth0#2 .... -+# These will not receive any frames until you bind MAC addresses to them. -+# If you bind 11:22:33:44:55:66 to eth0#1, then any frames received by -+# eth0 with source MAC 11:22:33:44:55:66 will be routed up through eth0#1 -+# instead of eth0. -+# -+# Example: (Assuming you are using destination (local) binding) -+# -+# If you enable MAC address based VLANS over eth0 -+# -+# You may then create further VLANs, e.g. eth0#1 eth0#2 .... -+# These will not receive any frames until you bind MAC addresses to them. -+# If you bind 11:22:33:44:55:66 to eth0#1, then any broadcast/multicast -+# frames, or frames with a destination MAC 11:22:33:44:55:66 -+# will be routed up through eth0#1 instead of eth0 -+# -+# For broadcasts, the packet will be duplicated for every VLAN -+# with at least one MAC attached. Attaching more than one MAC -+# when destination binding makes no sense...don't do it! -+# -+# -+####################################################################### -+*/ -+#include <linux/config.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/sched.h> -+#include <linux/kernel.h> -+#include <linux/fs.h> -+#include <linux/errno.h> -+#include <linux/delay.h> -+#include <linux/slab.h> -+#include <linux/mm.h> -+#include <linux/ioport.h> -+#include <linux/interrupt.h> -+#include <linux/tqueue.h> -+#include <linux/poll.h> -+#include <linux/types.h> -+#include <linux/string.h> -+#include <linux/if_macvlan.h> -+#include <linux/if_arp.h> -+#include <linux/etherdevice.h> -+#include <net/arp.h> -+ -+#include <asm/io.h> -+#include <asm/irq.h> -+#include <asm/uaccess.h> -+#include <asm/semaphore.h> -+ -+#ifdef CONFIG_PROC_FS -+#include <linux/proc_fs.h> -+#define MVL_PROC_DIR "macvlan" -+#define MVL_PROC_CFG "config" -+#define PORT_CFG_FILE_NAME "config" -+static struct proc_dir_entry *mvl_proc_dir; -+static struct proc_dir_entry *mvl_proc_cfg; -+#endif -+ -+#include "macvlan.h" -+ -+ -+/*********************************************************/ -+/* defines */ -+/*********************************************************/ -+ -+#if 0 -+#define DEBUG(format,args...) printk(KERN_ERR format, ##args); -+#else -+#define DEBUG(format,args...) -+#endif -+ -+ -+#undef MVL_USE_RW_LOCKS -+#ifdef MVL_USE_RW_LOCKS -+/* Must hold this lock to make any changes to the macvlan structures. -+ */ -+static rwlock_t mvl_cfg_lock = RW_LOCK_UNLOCKED; -+ -+#define MVL_READ_LOCK /* printk("%i: read-lock port list\n", __LINE__); */ \ -+ BUG_ON(in_interrupt()); \ -+ read_lock(&mvl_cfg_lock); -+#define MVL_READ_UNLOCK /* printk("%i: read-unlock port list\n", __LINE__); */ \ -+ BUG_ON(in_interrupt()); \ -+ read_unlock(&mvl_cfg_lock); -+ -+#define MVL_WRITE_LOCK /* printk("%i: write-lock port list\n", __LINE__); */ \ -+ BUG_ON(in_interrupt()); \ -+ write_lock(&mvl_cfg_lock); -+#define MVL_WRITE_UNLOCK /* printk("%i: write-unlock port list\n", __LINE__); */ \ -+ BUG_ON(in_interrupt()); \ -+ write_unlock(&mvl_cfg_lock); -+ -+ -+#define MVL_IRQ_RLOCK(a) /* printk("%i: read-unlock port list\n", __LINE__); */ { \ -+ __u64 now = getCurUs(); \ -+ __u64 later; \ -+ read_lock_irqsave(&mvl_cfg_lock, a); \ -+ later = getCurUs(); \ -+ if ((later - now) > 100) { \ -+ printk("took: %lluus to acquire read lock, line: %i\n", \ -+ later - now, __LINE__); \ -+ }} -+ -+#define MVL_IRQ_RUNLOCK(a) /* printk("%i: read-unlock port list\n", __LINE__); */ \ -+ read_unlock_irqrestore(&mvl_cfg_lock, a); -+#else -+/* Must hold this lock to make any changes to the macvlan structures. -+ */ -+static spinlock_t mvl_cfg_lock = SPIN_LOCK_UNLOCKED; -+ -+#define MVL_READ_LOCK(a) MVL_WRITE_LOCK(a) -+#define MVL_READ_UNLOCK(a) MVL_WRITE_UNLOCK(a) -+ -+#define MVL_WRITE_LOCK(a) /* printk("%i: write-lock port list\n", __LINE__); */ \ -+ spin_lock_irqsave(&mvl_cfg_lock, a); -+#define MVL_WRITE_UNLOCK(a) /* printk("%i: write-unlock port list\n", __LINE__); */ \ -+ spin_unlock_irqrestore(&mvl_cfg_lock, a); \ -+ -+ -+#define MVL_IRQ_RLOCK(a) /* printk("%i: read-unlock port list\n", __LINE__); */ \ -+ spin_lock_irqsave(&mvl_cfg_lock, a); \ -+ -+#define MVL_IRQ_RUNLOCK(a) /* printk("%i: read-unlock port list\n", __LINE__); */ \ -+ spin_unlock_irqrestore(&mvl_cfg_lock, a); -+#endif -+ -+ -+/*********************************************************/ -+/* file scope variables */ -+/*********************************************************/ -+ -+static struct macvlan_port *port_list = NULL; -+ -+static atomic_t macvlan_nports; -+static atomic_t mvl_vlan_counter; -+ -+static int debug_lvl = 0; -+ -+ -+/*********************************************************/ -+/* forward declarations */ -+/*********************************************************/ -+static int macvlan_hash_rem(const char* vlan_ifname, -+ const unsigned char* mac); -+ -+/*********************************************************/ -+/* function definitions */ -+/*********************************************************/ -+ -+/** Convert to micro-seconds */ -+static inline __u64 tv_to_us(const struct timeval* tv) { -+ __u64 us = tv->tv_usec; -+ us += (__u64)tv->tv_sec * (__u64)1000000; -+ return us; -+} -+ -+ -+/* Since the epoc. More precise over long periods of time than -+ * getRelativeCurMs -+ */ -+static inline __u64 getCurUs(void) { -+ struct timeval tv; -+ do_gettimeofday(&tv); -+ return tv_to_us(&tv); -+} -+ -+ -+char toupper(char in) { -+ if ((in >= 'a') && (in <= 'z')) { -+ in -= ('a' - 'A'); -+ } -+ return in; -+} -+ -+#define iswhitespace(x)\ -+ ((x) == ' ' || (x) == '\n' || (x) == '\r' || (x) == '\r' ) -+ -+#define skip_whitespace(x) { while (iswhitespace(*x)) (x)++; } -+ -+static int copy_next_word(char *dst, char *src, int len) { -+ char *p; -+ for (p=src; p < src + len ; p++) { -+ if ( iswhitespace(*p)) -+ break; -+ *dst++ = *p; -+ } -+ return p - src; -+} -+ -+ -+static int toMacString(unsigned char* rslt_mac, const char* raw_mac) { -+ // Turn HEX into bytes. First, gather all the useful HEX -+ char tmp[12]; //More than 12 is useless, at least right now -+ char c; -+ int j = 0; //tmp's index. -+ int i; -+ char tmp_bt[3]; -+ for (i = 0; i<strlen(raw_mac); i++) { -+ c = toupper(raw_mac[i]); -+ if (((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'F'))) { -+ tmp[j] = c; -+ //VLOG_ERR(VLOG << " c: " << c << endl); -+ if (j == 11) { -+ break; //done -+ } -+ j++; -+ } -+ else { -+ if ((c == ':') || (c == ' ') || (c == '.')) { -+ // Ok, valid divider -+ } -+ else { -+ // Invalid header -+ return -EINVAL; -+ } -+ } -+ } -+ -+ if (j != 11) { -+ //msg->append("ERROR: Not enough HEX values in the input string.\n"); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i<6; i++) { -+ tmp_bt[0] = tmp[i*2]; -+ tmp_bt[1] = tmp[i*2 +1]; -+ tmp_bt[2] = 0; -+ //VLOG_ERR(VLOG << " tmp_bt -:" << tmp_bt << ":- i: " << i << endl); -+ rslt_mac[i] = (unsigned char)(simple_strtol(tmp_bt, NULL, 16) & 0xFF); -+ //VLOG_ERR(VLOG << " rslt_mac[" << i << "] -:" << rslt_mac[i] << ":-\n"); -+ } -+ return 0; -+}//toMacString -+ -+ -+struct macvlan_vlan* macvlan_find_vlan_in_port(struct macvlan_port* port, -+ const char* ifname) { -+ struct macvlan_vlan* vlan; -+ for (vlan = port->vlan_list; vlan; vlan = vlan->next) { -+ if (!strcmp(vlan->dev->name, ifname)) { -+ return vlan; -+ } -+ } -+ return NULL; -+} -+ -+ -+/* Find port by mac-vlan interface name (eth1#777) */ -+struct macvlan_port* macvlan_find_port_for_mvlan_ifname(const char* ifname) { -+ struct macvlan_port* port; -+ for (port = port_list; port; port = port->next) { -+ if (macvlan_find_vlan_in_port(port, ifname)) { -+ break; -+ } -+ } -+ return port; -+} -+ -+struct macvlan_port* macvlan_find_port_for_underlying_ifname(const char* ifname) { -+ struct macvlan_port* port; -+ //printk("finding port for underlying ifname: %s\n", ifname); -+ for (port = port_list; port; port = port->next) { -+ //printk("Testing port: %p name: %s\n", port, port->dev->name); -+ if (strcmp(port->dev->name, ifname) == 0) { -+ break; -+ } -+ } -+ //printk("done finding port: %p\n", port); -+ return port; -+} -+ -+/* -+ * Rebuild the Ethernet MAC header. This is called after an ARP -+ * (or in future other address resolution) has completed on this -+ * sk_buff. We now let ARP fill in the other fields. -+ * -+ * This routine CANNOT use cached dst->neigh! -+ * Really, it is used only when dst->neigh is wrong. -+ * -+ */ -+int macvlan_dev_rebuild_header(struct sk_buff *skb) { -+ struct net_device *dev = skb->dev; -+ struct ethhdr *veth = (struct ethhdr *)(skb->data); -+ -+ switch (veth->h_proto) { -+#ifdef CONFIG_INET -+ case __constant_htons(ETH_P_IP): -+ -+ return arp_find(veth->h_dest, skb); -+#endif -+ default: -+ DEBUG("%s: unable to resolve type %X addresses.\n", -+ dev->name, (int)veth->h_proto); -+ -+ memcpy(veth->h_source, dev->dev_addr, ETH_ALEN); -+ break; -+ }; -+ -+ return 0; -+} -+ -+ -+ -+static struct net_device_stats *macvlan_get_stats(struct net_device *dev) -+{ -+ struct macvlan_vlan *vlan = dev->priv; -+ -+ return &vlan->statistics; -+} -+ -+static int macvlan_xmit(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct macvlan_vlan *vlan = dev->priv; -+ DEBUG("%s: \n", __PRETTY_FUNCTION__); -+ vlan->statistics.tx_packets++; -+ vlan->statistics.tx_bytes += skb->len; -+ -+ skb->dev = vlan->lowerdev; -+ dev_queue_xmit(skb); -+ return 0; -+} -+ -+static int macvlan_open(struct net_device *dev) -+{ -+ MOD_INC_USE_COUNT; -+ netif_start_queue(dev); -+ return 0; -+} -+ -+static void macvlan_set_multicast_list(struct net_device *dev) -+{ -+ /* TODO ??? */ -+} -+ -+static int macvlan_stop(struct net_device *dev) -+{ -+ netif_stop_queue(dev); -+ MOD_DEC_USE_COUNT; -+ return 0; -+} -+ -+static int macvlan_accept_fastpath(struct net_device *dev, struct dst_entry *dst) -+{ -+ return -1; -+} -+ -+ -+/* -+ * Create the VLAN header for an arbitrary protocol layer -+ * -+ * saddr=NULL means use device source address -+ * daddr=NULL means leave destination address (eg unresolved arp) -+ * -+ * This is called when the SKB is moving down the stack towards the -+ * physical devices. -+ */ -+int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev, -+ unsigned short type, void *daddr, void *saddr, -+ unsigned len) -+{ -+ struct macvlan_vlan *vlan = dev->priv; -+ -+ DEBUG("%s: \n", __PRETTY_FUNCTION__); -+ -+ /* Before delegating work to the lower layer, enter our MAC-address */ -+ saddr = dev->dev_addr; -+ -+ dev = vlan->lowerdev; -+ -+ /* Now make the underlying real hard header */ -+ return dev->hard_header(skb, dev, type, daddr, saddr, len); -+} -+ -+ -+void macvlan_dev_destructor(struct net_device *dev) { -+ atomic_dec(&mvl_vlan_counter); -+ if (dev->priv) { -+ //printk("dst: %s", dev->name); -+ kfree(dev->priv); -+ dev->priv = NULL; -+ } -+ else { -+ //printk("dst2: %s", dev->name); -+ } -+} -+ -+ -+static int macvlan_vlan_create(const char* port_name, int newifidx) { -+ struct macvlan_vlan *vlan = NULL; -+ struct macvlan_port* port; -+ char newifname[IFNAMSIZ+1]; -+ struct net_device* td = NULL; -+ unsigned long flags; -+ int rv; -+ -+ MVL_WRITE_LOCK(flags); -+ -+ //printk("--*-- "); -+ /* find the port to which ifname belongs */ -+ port = macvlan_find_port_for_underlying_ifname(port_name); -+ if (!port) { -+ MVL_WRITE_UNLOCK(flags); -+ rv = -ENODEV; -+ goto unlockout; -+ } -+ -+ BUG_ON(!port->dev); -+ -+ //printk("1 "); -+ if (newifidx < 0) { -+ /* Find the next free index */ -+ int i; -+ for (i = 0; i<MAX_MACVLANS_PER_PORT; i++) { -+ snprintf(newifname, IFNAMSIZ, "%s#%d", port->dev->name, i); -+ newifname[IFNAMSIZ] = 0; -+ if ((td = dev_get_by_name(newifname)) == NULL) { -+ newifidx = i; -+ break; -+ } -+ dev_put(td); -+ } -+ -+ if (newifidx < 0) { -+ printk("macvlan: Could not find a free index, reached max: %i\n", i); -+ } -+ } -+ -+ //printk("2 "); -+ /* generate a name for the new vlan */ -+ snprintf(newifname, IFNAMSIZ, "%s#%d", port->dev->name, newifidx); -+ newifname[IFNAMSIZ] = 0; -+ -+ if ((td = dev_get_by_name(newifname)) != NULL) { -+ DEBUG("macvlan: vlan by that name already exists\n"); -+ dev_put(td); -+ rv = -EEXIST; -+ goto unlockout; -+ } -+ -+ //printk("3 "); -+ if ((vlan = kmalloc(sizeof(*vlan), GFP_KERNEL)) == NULL) { -+ DEBUG("macvlan: kmalloc failure\n"); -+ rv = -ENOMEM; -+ goto unlockout; -+ } -+ -+ memset(vlan, 0, sizeof(*vlan)); -+ -+ //printk("4 "); -+ if ((vlan->dev = kmalloc(sizeof(struct net_device), GFP_KERNEL)) == NULL) { -+ rv = -ENOMEM; -+ kfree(vlan); -+ goto unlockout; -+ } -+ memset(vlan->dev, 0, sizeof(struct net_device)); -+ -+ //printk("5 "); -+ strcpy(vlan->dev->name, newifname); -+ ether_setup(vlan->dev); -+ -+ dev_hold(vlan->dev); /* MVL code holds reference */ -+ -+ vlan->dev->priv = vlan; -+ vlan->port = port; -+ vlan->lowerdev = port->dev; -+ -+ //printk("6 "); -+ /* dev->do_ioctl = macvlan_do_ioctl; */ -+ vlan->dev->get_stats = macvlan_get_stats; -+ vlan->dev->hard_start_xmit = macvlan_xmit; -+ vlan->dev->hard_header = macvlan_hard_header; -+ vlan->dev->rebuild_header = macvlan_dev_rebuild_header; -+ vlan->dev->open = macvlan_open; -+ vlan->dev->set_multicast_list = macvlan_set_multicast_list; -+ vlan->dev->stop = macvlan_stop; -+ vlan->dev->accept_fastpath = macvlan_accept_fastpath; -+ vlan->dev->tx_queue_len = 0; -+ vlan->dev->set_mac_address = NULL; -+ vlan->dev->priv = vlan; -+ vlan->dev->destructor = macvlan_dev_destructor; -+ -+ /* This will change if you are using Destination (local) binding, -+ * when you add a MAC to it.. -+ */ -+ memcpy(vlan->dev->dev_addr, vlan->lowerdev->dev_addr, ETH_ALEN); -+ -+ DEBUG("macvlan: created vlan %p\n", vlan); -+ -+#ifdef MVL_CONFIG_PROC_FS -+ //printk("7 "); -+ if (vlan->port->proc_dir) { -+ vlan->proc_ent = create_proc_read_entry(vlan->dev->name, S_IRUGO, -+ vlan->port->proc_dir, -+ read_mvl, vlan); -+ if (!vlan->proc_ent) { -+ printk("ERROR: Could not create proc entry for device: %s\n", -+ vlan->dev->name); -+ } -+ else { -+ vlan->proc_ent->write_proc = write_mvl; -+ } -+ } -+#endif -+ -+ atomic_inc(&port->ndevs); -+ -+ /* link to list */ -+ //printk("8 "); -+ vlan->next = port->vlan_list; -+ port->vlan_list = vlan; -+ -+ //printk("End of mac_vlan create1, ref-cnt: %i\n", atomic_read(&dev->refcnt)); -+ -+ MVL_WRITE_UNLOCK(flags); -+ register_netdev(vlan->dev); -+ -+ //printk("End of mac_vlan create2, ref-cnt: %i\n", atomic_read(&dev->refcnt)); -+ -+ atomic_inc(&mvl_vlan_counter); -+ //printk("9\n"); -+ rv = 0; -+ goto out; -+ -+ unlockout: -+ MVL_WRITE_UNLOCK(flags); -+ out: -+ return rv; -+} /* macvlan_vlan_create */ -+ -+ -+/* Has locking internally */ -+int macvlan_vlan_cleanup(const char* ifname) { -+ int i; -+ struct macvlan_port* port; -+ struct macvlan_vlan* vlan; -+ struct macvlan_vlan* walker; -+ struct macvlan_vlan* prev; -+ unsigned long flags; -+ int rv; -+ -+ DEBUG(__FUNCTION__"(%p)\n",vlan); -+ //printk("mvl_cln: %s", ifname); -+ -+ MVL_WRITE_LOCK(flags); -+ /* NOTE: Cannot depend on device name, it can be changed. --Ben */ -+ port = macvlan_find_port_for_mvlan_ifname(ifname); -+ if (!port) { -+ rv = -ENODEV; -+ goto unlockout; -+ } -+ -+ //printk("1 "); -+ vlan = macvlan_find_vlan_in_port(port, ifname); -+ BUG_ON(!vlan); -+ -+ if (vlan->dev->flags & IFF_UP) { -+ rv = -EBUSY; -+ goto unlockout; -+ } -+ -+ //printk("2 "); -+ for (i = 0; i<MACVLAN_HASH_LEN; i++) { -+ struct macvlan_hash_entry* tmp = vlan->port->hash_table[i]; -+ struct macvlan_hash_entry* prev = NULL; -+ while (tmp) { -+ if (tmp->vlan == vlan) { -+ if (prev) { -+ prev->next = tmp->next; -+ kfree(tmp); -+ tmp = prev->next; -+ } -+ else { -+ vlan->port->hash_table[i] = tmp->next; -+ kfree(tmp); -+ tmp = vlan->port->hash_table[i]; -+ } -+ } -+ else { -+ prev = tmp; -+ tmp = tmp->next; -+ } -+ } -+ }/* for all hash buckets */ -+ //printk("3 "); -+ -+#ifdef MVL_CONFIG_PROC_FS -+ if (vlan->proc_ent) { -+ remove_proc_entry(vlan->dev->name, vlan->port->proc_dir); -+ vlan->proc_ent = NULL; -+ } -+#endif -+ -+ -+ /* -+ * remove the vlan in question from the list -+ */ -+ prev = NULL; -+ walker = port->vlan_list; -+ while (walker) { -+ if (walker == vlan) { -+ if (prev) { -+ prev->next = walker->next; -+ } -+ else { -+ port->vlan_list = walker->next; -+ } -+ break; -+ } -+ prev = walker; -+ walker = walker->next; -+ }/* while */ -+ BUG_ON(walker != vlan); -+ -+ atomic_dec(&port->ndevs); -+ -+ //printk("4 "); -+ //printk("End of mac_vlan cleanup1, ref-cnt: %i\n", atomic_read(&vlan->dev->refcnt)); -+ dev_put(vlan->dev); -+ -+ MVL_WRITE_UNLOCK(flags); -+ -+ //printk("End of mac_vlan cleanup2, ref-cnt: %i\n", atomic_read(&vlan->dev->refcnt)); -+ unregister_netdev(vlan->dev); -+ -+ /* VLAN will be deleted when the device is deleted */ -+ -+ //printk("5 "); -+ rv = 0; -+ goto out; -+ -+ unlockout: -+ MVL_WRITE_UNLOCK(flags); -+ -+ out: -+ return rv; -+ -+} /* mac_vlan cleanup */ -+ -+ -+ -+static int macvlan_port_set_flags(const char* ifname, int flags) { -+ struct macvlan_port *port; -+ -+ /* find the port to which ifname belongs */ -+ port = macvlan_find_port_for_underlying_ifname(ifname); -+ if (!port) { -+ return -ENODEV; -+ } -+ else { -+ port->flags = flags; -+ } -+ return 0; -+}/* macvlan_port_set_flags */ -+ -+static int macvlan_port_create(const char* ifname) { -+ struct macvlan_port *port; -+ struct net_device* dev; -+ -+ port = macvlan_find_port_for_underlying_ifname(ifname); -+ if (port != NULL) { -+ return -EEXIST; -+ } -+ -+ dev = dev_get_by_name(ifname); -+ if (dev == NULL) { -+ return -ENODEV; -+ } -+ -+ if ((dev->macvlan_priv != NULL) -+ || (dev->flags & IFF_LOOPBACK) -+ || (dev->type != ARPHRD_ETHER)) { -+ printk("macvlan: lower layer failed" -+ " dev->macvlan_priv=%p dev->flags=%08x dev->type=%08x\n", -+ dev->macvlan_priv, dev->flags, dev->type); -+ dev_put(dev); -+ return -EINVAL; -+ } -+ -+ if ((port = kmalloc(sizeof(*port), GFP_KERNEL)) == NULL) { -+ dev_put(dev); -+ return -ENOBUFS; -+ } -+ -+ memset(port, 0, sizeof(*port)); -+ port->dev = dev; -+ -+ /* TODO: Could use multicast filters in some NICs at least. */ -+ dev_set_promiscuity(dev, 1); -+ dev->macvlan_priv = port; -+ -+#ifdef MVL_CONFIG_PROC_FS -+ if (mvl_proc_dir) { -+ port->proc_dir = proc_mkdir(port->dev->name, mvl_proc_dir); -+ -+ if (port->proc_dir) { -+ port->proc_ent = create_proc_read_entry(PORT_CFG_FILE_NAME, S_IRUGO, -+ port->proc_dir, -+ read_mvl_port, port); -+ if (port->proc_ent) { -+ port->proc_ent->write_proc = write_mvl_port; -+ } -+ else { -+ printk("macvlan: ERROR: failed to create proc entry for port: %s\n", -+ port->dev->name); -+ } -+ } -+ } -+#endif -+ -+ atomic_inc(&macvlan_nports); -+ -+ /* Link into our list */ -+ port->next = port_list; -+ port_list = port; -+ -+ DEBUG("macvlan: created port=%p\n", port); -+ return 0; -+}/* macvlan_port_create */ -+ -+ -+/* Clears all memory, kfree's it if possible. -+ */ -+static int macvlan_port_cleanup(const char* ifname) { -+ struct macvlan_port *port; -+ struct macvlan_port *prev; -+ struct macvlan_port *walker; -+ int i; -+ -+ port = macvlan_find_port_for_underlying_ifname(ifname); -+ if (!port) { -+ return -ENODEV; -+ } -+ -+ if (port->vlan_list) { -+ return -EBUSY; -+ } -+ -+ /* hash table should be empty at this point */ -+ for (i = 0 ; i < MACVLAN_HASH_LEN; i++) { -+ BUG_ON(port->hash_table[i]); -+ } -+ -+ /* Remove from our port list */ -+ prev = NULL; -+ walker = port_list; -+ while (walker) { -+ if (walker == port) { -+ if (prev) { -+ prev->next = walker->next; -+ } -+ else { -+ port_list = walker->next; -+ } -+ break; -+ } -+ prev = walker; -+ walker = walker->next; -+ } -+ BUG_ON(walker != port); -+ -+ -+#ifdef MVL_CONFIG_PROC_FS -+ if (port->proc_dir) { -+ if (port->proc_ent) { -+ remove_proc_entry(PORT_CFG_FILE_NAME, port->proc_dir); -+ port->proc_ent = NULL; -+ } -+ -+ remove_proc_entry(port->dev->name, mvl_proc_dir); -+ port->proc_dir = NULL; -+ } -+#endif -+ -+ dev_set_promiscuity(port->dev, -1); -+ port->dev->macvlan_priv = NULL; -+ dev_put(port->dev); -+ -+ atomic_dec(&macvlan_nports); -+ -+ kfree(port); -+ -+ return 0; -+}/* macvlan_port_cleanup */ -+ -+ -+static inline struct macvlan_vlan *macvlan_hash_lookup(struct macvlan_port *port, -+ const unsigned char *src) { -+ /* -+ * The hashing function is to simply -+ * take the bottom source address byte -+ */ -+ struct macvlan_hash_entry *entry; -+ unsigned int bucket = VLAN_BUCKET(src); -+ for (entry = port->hash_table[bucket]; entry; entry = entry->next) { -+ if (memcmp(entry->mac, src, ETH_ALEN) == 0) { -+ /*DEBUG("macvlan: matched %02x:%02x:%02x:%02x:%02x:%02x to vlan %p\n", -+ src[0],src[1],src[2],src[3],src[4],src[5],entry->vlan); */ -+ return entry->vlan; -+ } -+ } -+ return NULL; -+} -+ -+ -+static int macvlan_hash_add(const char* ifname, -+ const unsigned char* macaddr) { -+ -+ struct macvlan_port *port; -+ struct macvlan_vlan *vlan; -+ unsigned int bucket = VLAN_BUCKET(macaddr); -+ struct macvlan_hash_entry* entry; -+ -+ -+ /* find the port in question */ -+ port = macvlan_find_port_for_mvlan_ifname(ifname); -+ if (!port) { -+ return -ENODEV; -+ } -+ -+ /* find the vlan layered over this port */ -+ vlan = macvlan_find_vlan_in_port(port, ifname); -+ BUG_ON(!vlan); -+ -+ /* check it's not already in the hash lookup table */ -+ if (macvlan_hash_lookup(port, macaddr)) { -+ DEBUG("macvlan: user tried to add mac addr twice!\n"); -+ return -EEXIST; -+ } -+ -+ if ((atomic_read(&vlan->nmacs) > 0) -+ && (port->flags & MVL_FILTER_ON_DEST)) { -+ printk("macvlan: Already have a MAC on this vlan: %s and we are filtering on DEST, so no more are allowed!\n", -+ ifname); -+ return -EINVAL; -+ } -+ -+ entry = kmalloc(sizeof(*entry), GFP_KERNEL); -+ if (!entry) { -+ return -ENOBUFS; -+ } -+ memset(entry, 0, sizeof(*entry)); -+ -+ memcpy(entry->mac, macaddr, sizeof(entry->mac)); -+ entry->vlan = vlan; -+ entry->next = port->hash_table[bucket]; -+ port->hash_table[bucket] = entry; -+ DEBUG("macvlan: added %02x:%02x:%02x:%02x:%02x:%02x to vlan %p\n", -+ entry->src[0],entry->src[1],entry->src[2], -+ entry->src[3],entry->src[4],entry->src[5], -+ vlan); -+ -+ atomic_inc(&vlan->nmacs); -+ -+ if (port->flags & MVL_FILTER_ON_DEST) { -+ /* Set the MAC on the vlan device so that it sends pkts correctly. */ -+ memcpy(vlan->dev->dev_addr, macaddr, ETH_ALEN); -+ } -+ -+ return 0; -+} /* macvlan_hash_add */ -+ -+/* cleans up the mac hash entry memory (kfree). */ -+static int macvlan_hash_rem(const char* vlan_ifname, -+ const unsigned char* mac) { -+ int bucket = VLAN_BUCKET(mac); -+ struct macvlan_port *port; -+ struct macvlan_hash_entry *entry; -+ struct macvlan_hash_entry* prev; -+ -+ /* find the port in question */ -+ port = macvlan_find_port_for_mvlan_ifname(vlan_ifname); -+ -+ if (!port) { -+ return -ENODEV; -+ } -+ -+ entry = port->hash_table[bucket]; -+ prev = NULL; -+ //printk("hash_rem, found port: %p bucket: %i entry: %p\n", -+ // port, bucket, entry); -+ while (entry) { -+ //printk("Testing entry: %p\n", entry); -+ if (memcmp(entry->mac, mac, ETH_ALEN) == 0) { -+ if (prev) { -+ prev->next = entry->next; -+ } -+ else { -+ port->hash_table[bucket] = entry->next; -+ } -+ atomic_dec(&entry->vlan->nmacs); -+ kfree(entry); -+ return 0; -+ } -+ prev = entry; -+ entry = entry->next; -+ } -+ -+ return -EINVAL; -+}/* macvlan_hash_rem */ -+ -+ -+static int macvlan_ioctl_deviceless_stub(unsigned long arg) { -+ int err = 0; -+ struct macvlan_ioctl req; -+ struct macvlan_ioctl_reply rep; -+ unsigned long flags; -+ -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; -+ -+ if (copy_from_user(&req, (void *)arg, sizeof(req))) -+ return -EFAULT; -+ -+ memset(&rep, 0, sizeof(rep)); -+ -+ switch (req.cmd) -+ { -+ case MACVLAN_ENABLE: -+ { -+ /* -+ * enable creation of mac based vlans -+ * layered over an ethernet device -+ */ -+ char ifname[IFNAMSIZ]; -+ -+ /* Get name of ethernet device */ -+ if(copy_from_user(ifname, (void *)req.ifname, sizeof(ifname))) { -+ err = -EFAULT; -+ break; -+ } -+ ifname[IFNAMSIZ-1] = '\0'; -+ -+ MVL_WRITE_LOCK(flags); -+ err = macvlan_port_create(ifname); -+ MVL_WRITE_UNLOCK(flags); -+ -+ break; -+ } -+ case MACVLAN_DISABLE: -+ { -+ /* -+ * disable creation of mac based vlans -+ * layered over an ethernet device -+ */ -+ char ifname[IFNAMSIZ]; -+ -+ /* Get name of ethernet device */ -+ if(copy_from_user(ifname, (void *)req.ifname, sizeof(ifname))) { -+ err = -EFAULT; -+ break; -+ } -+ ifname[IFNAMSIZ-1] = '\0'; -+ -+ MVL_WRITE_LOCK(flags); -+ err = macvlan_port_cleanup(ifname); -+ MVL_WRITE_UNLOCK(flags); -+ -+ break; -+ } -+ case MACVLAN_ADD: -+ { -+ /* -+ * create a new mac based vlan -+ */ -+ char ifname[IFNAMSIZ]; -+ int ifidx; -+ -+ /* Get name of port over which we are creating a vlan */ -+ if(copy_from_user(ifname, (void *)req.ifname, sizeof(ifname))) { -+ err = -EFAULT; -+ break; -+ } -+ ifname[IFNAMSIZ-1] = '\0'; -+ -+ /* Get index of new vlan we are creating */ -+ ifidx = req.ifidx; -+ -+ /* Has internal locking. */ -+ err = macvlan_vlan_create(ifname, ifidx); -+ -+ break; -+ } -+ case MACVLAN_SET_PORT_FLAGS: -+ { -+ /* -+ * Set a macvlan_port's flags -+ */ -+ char ifname[IFNAMSIZ]; -+ -+ /* Get name of port over which we are creating a vlan */ -+ if(copy_from_user(ifname, (void *)req.ifname, sizeof(ifname))) { -+ err = -EFAULT; -+ break; -+ } -+ ifname[IFNAMSIZ-1] = '\0'; -+ -+ MVL_WRITE_LOCK(flags); -+ err = macvlan_port_set_flags(ifname, req.ifidx); -+ MVL_WRITE_UNLOCK(flags); -+ -+ break; -+ } -+ case MACVLAN_GET_PORT_FLAGS: -+ { -+ /* -+ * Set a macvlan_port's flags -+ */ -+ struct macvlan_port *port; -+ char ifname[IFNAMSIZ]; -+ -+ /* Get name of port over which we are creating a vlan */ -+ if(copy_from_user(ifname, (void *)req.ifname, sizeof(ifname))) { -+ err = -EFAULT; -+ break; -+ } -+ ifname[IFNAMSIZ-1] = '\0'; -+ -+ MVL_READ_LOCK(flags); -+ /* find the port to which ifname belongs */ -+ port = macvlan_find_port_for_mvlan_ifname(ifname); -+ if (!port) { -+ err = -ENODEV; -+ } -+ else { -+ rep.num = port->flags; -+ } -+ MVL_READ_UNLOCK(flags); -+ -+ if (copy_to_user((void *)req.reply, &rep, sizeof(rep))) { -+ err = -EFAULT; -+ } -+ -+ break; -+ } -+ case MACVLAN_DEL: -+ { -+ /* -+ * destroy a mac based vlan -+ */ -+ char ifname[IFNAMSIZ]; -+ -+ /* Get name of vlan to remove */ -+ if (copy_from_user(ifname, (void *)req.ifname, sizeof(ifname))) { -+ err = -EFAULT; -+ break; -+ } -+ ifname[IFNAMSIZ-1] = '\0'; -+ -+ /* Has internal locking */ -+ err = macvlan_vlan_cleanup(ifname); -+ break; -+ } -+ -+ case MACVLAN_BIND: -+ { -+ /* -+ * Bind a MAC address to vlan -+ */ -+ char ifname[IFNAMSIZ]; -+ unsigned char macaddr[ETH_ALEN]; -+ -+ /* Get name of vlan */ -+ if (copy_from_user(ifname, (void *)req.ifname, sizeof(ifname))) { -+ err = -EFAULT; -+ break; -+ } -+ ifname[IFNAMSIZ-1] = '\0'; -+ -+ /* Get mac address to bind to vlan */ -+ if (copy_from_user(macaddr, (void *)req.macaddr, sizeof(macaddr))) { -+ err = -EFAULT; -+ break; -+ } -+ -+ MVL_WRITE_LOCK(flags); -+ err = macvlan_hash_add(ifname, macaddr); -+ MVL_WRITE_UNLOCK(flags); -+ break; -+ } -+ case MACVLAN_UNBIND: -+ { -+ /* -+ * Unbind a MAC address from a vlan -+ */ -+ char ifname[IFNAMSIZ]; -+ unsigned char macaddr[ETH_ALEN]; -+ -+ /* Get name of vlan */ -+ if (copy_from_user(ifname, (void *)req.ifname, sizeof(ifname))) { -+ err = -EFAULT; -+ break; -+ } -+ ifname[IFNAMSIZ-1] = '\0'; -+ -+ /* Get mac address to unbind */ -+ if (copy_from_user(macaddr, (void *)req.macaddr, sizeof(macaddr))) { -+ err = -EFAULT; -+ break; -+ } -+ -+ MVL_WRITE_LOCK(flags); -+ err = macvlan_hash_rem(ifname, macaddr); -+ MVL_WRITE_UNLOCK(flags); -+ break; -+ } -+ -+ case MACVLAN_IS_MACVLAN: -+ { -+ /* -+ * Give user-space a chance of determining if we are a MAC-VLAN nor not. -+ * (If the IOCTL fails, we are not, otherwise we are.) -+ */ -+ struct macvlan_port *port; -+ char ifname[IFNAMSIZ]; -+ -+ /* Get name of vlan */ -+ if(copy_from_user(ifname, (void *)req.ifname, sizeof(ifname))) { -+ err = -EFAULT; -+ break; -+ } -+ ifname[IFNAMSIZ-1] = '\0'; -+ -+ MVL_READ_LOCK(flags); -+ /* find the port in question */ -+ port = macvlan_find_port_for_mvlan_ifname(ifname); -+ MVL_READ_UNLOCK(flags); -+ -+ if (!port) { -+ /* printk("device: %s is NOT a MAC-VLAN\n", ifname); */ -+ err = -ENODEV; -+ } -+ else { -+ /* printk("device: %s IS a MAC-VLAN\n", ifname); */ -+ err = 0; -+ } -+ break; -+ } -+ case MACVLAN_GET_NUM_PORTS: -+ { -+ /* -+ * how many ethernet devices have mac based vlans enabled over them -+ */ -+ rep.num = atomic_read(&macvlan_nports); -+ if (copy_to_user((void *)req.reply, &rep, sizeof(rep))) { -+ err = -EFAULT; -+ break; -+ } -+ break; -+ } -+ case MACVLAN_GET_PORT_NAME: -+ { -+ /* -+ * name the nth device which has mac based vlans enabled over it -+ */ -+ struct macvlan_port *port; -+ int n = req.portidx; -+ -+ MVL_READ_LOCK(flags); -+ /* find the port in question */ -+ for (port = port_list; port && n; port = port->next, n--); -+ if (!port) { -+ err = -ENODEV; -+ } -+ else { -+ memcpy(rep.name, port->dev->name, IFNAMSIZ); -+ -+ if (copy_to_user((void *)req.reply, &rep, sizeof(rep))) { -+ err = -EFAULT; -+ } -+ } -+ MVL_READ_UNLOCK(flags); -+ break; -+ } -+ case MACVLAN_GET_NUM_VLANS: -+ { -+ /* -+ * how many vlans are layered over the nth mac-based -+ * vlan enabled device -+ */ -+ -+ struct macvlan_port *port; -+ int n = req.portidx; -+ -+ MVL_READ_LOCK(flags); -+ /* find the port in question */ -+ for (port = port_list; port && n; port = port->next, n--); -+ -+ if (!port) { -+ err = -ENODEV; -+ } -+ else { -+ rep.num = atomic_read(&port->ndevs); -+ if (copy_to_user((void *)req.reply, &rep, sizeof(rep))) { -+ err = -EFAULT; -+ } -+ } -+ MVL_READ_UNLOCK(flags); -+ -+ break; -+ } -+ case MACVLAN_GET_VLAN_NAME: -+ { -+ /* -+ * what's the name of the mth vlan layered over the nth -+ * mac-based-vlan enabled ethernet device -+ */ -+ struct macvlan_port *port; -+ struct macvlan_vlan *vlan; -+ int n = req.portidx; -+ int m = req.ifidx; -+ -+ -+ MVL_READ_LOCK(flags); -+ /* find the port in question */ -+ for (port = port_list; port && n; port = port->next, n--); -+ if (!port) { -+ err = -EINVAL; -+ } -+ else { -+ /* find the vlan in question */ -+ for (vlan = port->vlan_list; vlan && m; vlan = vlan->next, m--); -+ -+ if (!vlan) { -+ err = -ENODEV; -+ } -+ else { -+ memcpy(rep.name, vlan->dev->name, IFNAMSIZ); -+ } -+ if (copy_to_user((void *)req.reply, &rep, sizeof(rep))) { -+ err = -EFAULT; -+ } -+ } -+ MVL_READ_UNLOCK(flags); -+ break; -+ } -+ case MACVLAN_GET_NUM_MACS: -+ { -+ /* -+ * how many mac addresses are owned by the mth vlan -+ * layered over the nth mac-based-vlan enabled -+ * ethernet device -+ */ -+ struct macvlan_port *port; -+ struct macvlan_vlan *vlan; -+ int n = req.portidx; -+ int m = req.ifidx; -+ -+ -+ MVL_READ_LOCK(flags); -+ /* find the port in question */ -+ for (port = port_list; port && n; port = port->next, n--); -+ -+ if (!port) { -+ err = -EINVAL; -+ } -+ else { -+ /* find the vlan in question */ -+ for (vlan = port->vlan_list; vlan && m; vlan = vlan->next, m--); -+ -+ if (!vlan) { -+ err = -ENODEV; -+ } -+ else { -+ rep.num = atomic_read(&vlan->nmacs); -+ } -+ if (copy_to_user((void *)req.reply, &rep, sizeof(rep))) { -+ err = -EFAULT; -+ } -+ } -+ MVL_READ_UNLOCK(flags); -+ break; -+ } -+ case MACVLAN_GET_MAC_NAME: -+ { -+ /* -+ * what's the pth mac address owned by the mth vlan -+ * layered over the nth mac-based-vlan enabled -+ * ethernet device -+ */ -+ struct macvlan_port *port; -+ struct macvlan_vlan *vlan; -+ struct macvlan_hash_entry *entry; -+ int n = req.portidx; -+ int m = req.ifidx; -+ int p = req.macaddridx; -+ -+ MVL_READ_LOCK(flags); -+ /* find the port in question */ -+ for (port = port_list; port && n; port = port->next, n--); -+ -+ if (!port) { -+ err = -EINVAL; -+ } -+ else { -+ /* find the vlan in question */ -+ for (vlan = port->vlan_list; vlan && m; vlan = vlan->next, m--); -+ -+ if (!vlan) { -+ err = -ENODEV; -+ } -+ else { -+ /* find the mac addr in question */ -+ int i; -+ for (i = 0; i<MACVLAN_HASH_LEN; i++) { -+ entry = port->hash_table[i]; -+ while (entry) { -+ if (entry->vlan == vlan) { -+ if (--p == 0) { -+ memcpy(rep.name, entry->mac, sizeof(entry->mac)); -+ goto found_one; -+ } -+ } -+ entry = entry->next; -+ } /* while */ -+ }/* for */ -+ -+ /* Didn't find one */ -+ err = -ENODEV; -+ } -+ -+ found_one: -+ -+ if (copy_to_user((void *)req.reply, &rep, sizeof(rep))) { -+ err = -EFAULT; -+ } -+ } -+ MVL_READ_UNLOCK(flags); -+ break; -+ } -+ default: -+ err = -EOPNOTSUPP; -+ break; -+ } -+ -+ /* printk("Returning err: %i\n", err); */ -+ return err; -+}/* ioctl handler */ -+ -+ -+/* Return >= 0 if packet is consumed, otherwise return < 0. */ -+static inline int mvl_handle_frame_fos(struct macvlan_port* port, struct sk_buff* skb) { -+ struct macvlan_vlan *vlan; /* the higher layer i/f to which skbuff is mapped */ -+ int rv; -+ unsigned long flags; -+ -+ DEBUG("%s: got port: %p, not filtering on DEST\n", __PRETTY_FUNCTION__, port); -+ -+ MVL_IRQ_RLOCK(flags); -+ if (!(vlan = macvlan_hash_lookup(port, skb->mac.ethernet->h_source))) { -+ /* not for us, but don't delete it, others may consume it */ -+ rv = -ENODEV; -+ } -+ else { -+ if (!(vlan->dev->flags & IFF_UP)) { -+ rv = 1; /* was consumed */ -+ kfree_skb(skb); -+ } -+ else { -+ vlan->statistics.rx_packets++; -+ /* Count the lower-level's header to make our counters look more -+ * like an ethernet device. */ -+ vlan->statistics.rx_bytes += (skb->len + vlan->lowerdev->hard_header_len); -+ -+ skb->dev = vlan->dev; -+ dev_hold(skb->dev); -+ if (memcmp(vlan->dev->dev_addr, skb->mac.ethernet->h_dest, ETH_ALEN)) { -+ skb->pkt_type=PACKET_OTHERHOST; -+ } -+ else { -+ skb->pkt_type = PACKET_HOST; -+ } -+ MVL_IRQ_RUNLOCK(flags); -+ netif_rx(skb); -+ dev_put(skb->dev); -+ rv = 0; -+ goto out; -+ } -+ } -+ -+ MVL_IRQ_RLOCK(flags); -+ out: -+ return rv; -+} /* filter on source */ -+ -+ -+/* Return >= 0 if packet is consumed, otherwise return < 0. */ -+static inline int mvl_handle_frame_fod(struct macvlan_port* port, struct sk_buff* skb) { -+ struct macvlan_vlan *vlan; /* the higher layer i/f to which skbuff is mapped */ -+ int rv; -+ unsigned long flags; -+ -+ /* Filtering on destination.. */ -+ /* If it's a broadcast pkt, send it to all of them. Otherwise, -+ * send it to just one of them. -+ */ -+ if ((skb->pkt_type == PACKET_BROADCAST) || (skb->pkt_type == PACKET_MULTICAST)) { -+ /* never consume if we take this code branch, because it's bcast */ -+ DEBUG("%s: got port: %p, filtering on DEST, type is bcast or multicast\n", -+ __PRETTY_FUNCTION__, port); -+ //printk("fod: "); -+ MVL_IRQ_RLOCK(flags); -+ //printk("1 "); -+ for (vlan = port->vlan_list; vlan; vlan = vlan->next) { -+ //printk("."); -+ DEBUG("%s: got vlan: %s, nmacs: %i, up: %i\n", -+ __PRETTY_FUNCTION__, vlan->dev->name, -+ vlan->nmacs, (vlan->dev->flags & IFF_UP)); -+ if (atomic_read(&vlan->nmacs) && (vlan->dev->flags & IFF_UP)) { -+ struct sk_buff* nskb; -+ -+ atomic_inc(&skb->users); -+ nskb = skb_share_check(skb, GFP_ATOMIC); -+ if (!nskb) { -+ vlan->statistics.rx_fifo_errors++; -+ vlan->statistics.rx_errors++; -+ } -+ else { -+ vlan->statistics.rx_packets++; -+ /* Count the lower-level's header to make our counters -+ * look more like an ethernet device. */ -+ vlan->statistics.rx_bytes += -+ (nskb->len + vlan->lowerdev->hard_header_len); -+ vlan->statistics.multicast++; -+ -+ nskb->dev = vlan->dev; -+ netif_rx(nskb); -+ } -+ } -+ } -+ //printk("2 "); -+ rv = -1; /* did not consume this pkt, merely tasted it */ -+ MVL_IRQ_RUNLOCK(flags); -+ goto out; -+ } -+ else { -+ struct ethhdr *eth = skb->mac.ethernet; -+ char* d = eth->h_dest; -+ /* Not a broadcast, try to find our port based on DESTINATION */ -+ //printk("fodNB "); -+ MVL_IRQ_RLOCK(flags); -+ if (!(vlan = macvlan_hash_lookup(port, d))) { -+ /* not for us */ -+ DEBUG("%s: not a broadcast, and could not find vlan for dest: %2hx:%2hx:%2hx:%2hx:%2hx:%2hx\n", -+ __PRETTY_FUNCTION__, d[0], d[1], d[2], d[3], d[4], d[5]); -+ -+ rv = -ENODEV; -+ //printk("1 "); -+ } -+ else { -+ DEBUG("%s: not a broadcast, found vlan for dest: " -+ "%2hx:%2hx:%2hx:%2hx:%2hx:%2hx, up: %i\n", -+ __PRETTY_FUNCTION__, d[0], d[1], d[2], d[3], d[4], d[5], -+ (vlan->dev->flags & IFF_UP)); -+ -+ if (!(vlan->dev->flags & IFF_UP)) { -+ kfree_skb(skb); -+ rv = 0; /* consume */ -+ } -+ else { -+ vlan->statistics.rx_packets++; -+ /* Count the lower-level's header to make our counters -+ * look more like an ethernet device. */ -+ vlan->statistics.rx_bytes += -+ (skb->len + vlan->lowerdev->hard_header_len); -+ -+ skb->dev = vlan->dev; -+ if (!(eth->h_dest[0] & 1)) { -+ /* if it's not multicast, see if it's -+ * for us, or not. -+ */ -+ if (memcmp(vlan->dev->dev_addr, eth->h_dest, ETH_ALEN)) { -+ skb->pkt_type = PACKET_OTHERHOST; -+ } -+ else { -+ skb->pkt_type = PACKET_HOST; -+ } -+ } -+ dev_hold(skb->dev); -+ MVL_IRQ_RUNLOCK(flags); -+ //printk("2 "); -+ netif_rx(skb); -+ dev_put(skb->dev); -+ //printk("3 "); -+ rv = 0; -+ goto out; -+ } -+ } -+ }/* else, was not broadcast */ -+ -+ MVL_IRQ_RUNLOCK(flags); -+ //printk("4 "); -+ -+ out: -+ //printk("5 "); -+ return rv; -+}/* filter on dest */ -+ -+ -+/* global entry point when receiving a pkt from lower-level devices. Return -+ * >= 0 if we consume, otherwise packet will be sent to the rest of the stack -+ * as normal. -+ * -+ */ -+static int macvlan_handle_frame(struct sk_buff *skb) -+{ -+ struct macvlan_port *port; /* maps skbuffs arriving from a lower layer -+ * i/f to a higher layer i/f */ -+ int rv = 0; -+ -+ port = skb->dev->macvlan_priv; -+ if (port->flags & MVL_FILTER_ON_DEST) { -+ rv = mvl_handle_frame_fod(port, skb); -+ } -+ else { -+ rv = mvl_handle_frame_fos(port, skb); -+ } -+ -+ return rv; -+} -+ -+ -+#ifdef MVL_CONFIG_PROC_FS -+ -+static int read_mvl_glbl(char *page, char **start, off_t off, -+ int count, int *eof, void *data) { -+ int ret = -1; -+ char *p = page; -+ int mx_len = (4096 - (p - page)); -+ -+ if (! *eof ) { -+ struct macvlan_port* port; -+ int cnt; -+ unsigned long flags; -+ -+ /* Global counts here... */ -+ p += sprintf(p, "MAC-VLAN module:\n"); -+ -+ p += sprintf(p, " port count: %i vlan_counter: %i\n", -+ atomic_read(&macvlan_nports), -+ atomic_read(&mvl_vlan_counter)); -+ -+ MVL_READ_LOCK(flags); -+ port = port_list; -+ while (port) { -+ p += sprintf(p, " %s num_vlans: %i flags: %x\n", -+ port->dev->name, atomic_read(&port->ndevs), port->flags); -+ -+ /* catch overflow */ -+ cnt = p - page; -+ if (cnt > (mx_len - 60)) { -+ if (mx_len - cnt >= 20) { -+ p += sprintf(p, "OUT_OF_SPACE!\n"); -+ } -+ break; -+ } -+ -+ port = port->next; -+ } -+ -+ ret = p - page; -+ MVL_READ_UNLOCK(flags); -+ } -+ return ret; -+} /* read_mvl_glbl */ -+ -+static int write_mvl_glbl(struct file *file, const char *buffer, -+ unsigned long count, void *data) { -+ char *p; -+ const char *end; -+ int ret=count; -+ int len; -+ char dev_name[2][IFNAMSIZ]; -+ char* tmps = NULL; -+ unsigned long flags; -+ -+ MVL_WRITE_LOCK(flags); -+ -+ end = buffer+count; -+ -+ for (p= (char *) buffer; p< end ; ) { -+ if (iswhitespace(*p)) { -+ p++; -+ continue; -+ } -+ -+ memset(dev_name[0], 0 ,IFNAMSIZ); -+ memset(dev_name[1], 0 ,IFNAMSIZ); -+ -+ len = strlen("add_port "); -+ if (strncmp(p, "add_port ", len)==0) -+ { -+ p += len; -+ -+ if ( (p + IFNAMSIZ) <= end) -+ p += copy_next_word(dev_name[0], p, IFNAMSIZ); -+ else -+ p += copy_next_word(dev_name[0], p, end-p ); -+ -+ skip_whitespace(p); -+ -+ /* This can fail, but not sure how to return failure -+ * to user-space here. -+ */ -+ macvlan_port_create(dev_name[0]); -+ goto forend; -+ } -+ -+ len = strlen("remove_port "); -+ if (strncmp(p,"remove_port ",len)==0) { -+ p += len; -+ -+ if ( (p + IFNAMSIZ) <= end) -+ p += copy_next_word(dev_name[0], p, IFNAMSIZ); -+ else -+ p += copy_next_word(dev_name[0], p, end-p ); -+ -+ skip_whitespace(p); -+ -+ macvlan_port_cleanup(dev_name[0]); -+ goto forend; -+ } -+ -+ len = strlen("debug_lvl "); -+ if (strncmp(p,"debug_lvl ",len)==0) -+ { -+ p += len; -+ -+ if ( (p + IFNAMSIZ) <= end) -+ p += copy_next_word(dev_name[0], p, IFNAMSIZ); -+ else -+ p += copy_next_word(dev_name[0], p, end-p ); -+ -+ skip_whitespace(p); -+ -+ debug_lvl = simple_strtoul(dev_name[0], &tmps, 10); -+ goto forend; -+ } -+ -+ printk("ERROR: Unsupported command\n"); -+ -+ forend: -+ p++; -+ } -+ -+ MVL_WRITE_UNLOCK(flags); -+ -+ return ret; -+} /* write_mvl_glbl */ -+ -+/* Proc file read for mac-vlan. */ -+static int read_mvl(char *page, char **start, off_t off, -+ int count, int *eof, void *data) { -+ int ret = -1; -+ if (! *eof ) { -+ char *p = page; -+ struct macvlan_vlan* vlan = (struct macvlan_vlan*)(data); -+ struct macvlan_hash_entry* entry; -+ int i; -+ int count = 0; -+ int cnt; -+ int mx_len = 4096; -+ unsigned long flags; -+ -+ -+ MVL_READ_LOCK(flags); -+ -+ /* Global counts here... */ -+ p += sprintf(p, "MAC-VLAN %s:\n", vlan->dev->name); -+ -+ p += sprintf(p, " MAC count: %i lower_dev: %s macvlan-port: %s\n", -+ atomic_read(&vlan->nmacs), vlan->lowerdev->name, -+ vlan->port->dev->name); -+ -+ for (i = 0; i<MACVLAN_HASH_LEN; i++) { -+ entry = vlan->port->hash_table[i]; -+ while (entry) { -+ if (entry->vlan == vlan) { -+ /* catch overflow */ -+ cnt = p - page; -+ if (cnt > (mx_len - 40)) { -+ if (mx_len - cnt >= 20) { -+ p += sprintf(p, "OUT_OF_SPACE!\n"); -+ } -+ goto outofspace; -+ } -+ -+ p += sprintf(p, " [%i] %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n", -+ count, entry->mac[0], entry->mac[1], entry->mac[2], -+ entry->mac[3], entry->mac[4], entry->mac[5]); -+ count++; -+ -+ } -+ entry = entry->next; -+ }/* while */ -+ }/* for */ -+ -+ outofspace: -+ -+ ret = p - page; -+ -+ MVL_READ_UNLOCK(flags); -+ } -+ return ret; -+} /* read_mvl_glbl */ -+ -+ -+static int write_mvl(struct file *file, const char *buffer, -+ unsigned long count, void *data) { -+ char *p; -+ const char *end; -+ int ret=count; -+ int len; -+ char arg[MVL_MX_ARG_LEN+1]; -+ -+ struct macvlan_vlan* vlan = (struct macvlan_vlan*)(data); -+ char mac[ETH_ALEN]; -+ unsigned long flags; -+ -+ MVL_WRITE_LOCK(flags); -+ -+ end = buffer+count; -+ -+ for (p= (char *) buffer; p< end ; ) { -+ if (iswhitespace(*p)) { -+ p++; -+ continue; -+ } -+ -+ memset(arg, 0, MVL_MX_ARG_LEN+1); -+ -+ len = strlen("add_mac "); -+ if (strncmp(p, "add_mac ", len)==0) { -+ p += len; -+ -+ if ( (p + MVL_MX_ARG_LEN) <= end) -+ p += copy_next_word(arg, p, MVL_MX_ARG_LEN); -+ else -+ p += copy_next_word(arg, p, end-p); -+ -+ skip_whitespace(p); -+ -+ if (toMacString(mac, arg) < 0) { -+ printk("macvlan: MAC format is incorrect: %s\n", -+ arg); -+ } -+ else { -+ /* This can fail, but not sure how to return failure -+ * to user-space here. -+ */ -+ macvlan_hash_add(vlan->dev->name, mac); -+ } -+ goto forend; -+ } -+ -+ len = strlen("remove_mac "); -+ if (strncmp(p,"remove_mac ",len)==0) { -+ p += len; -+ -+ if ( (p + MVL_MX_ARG_LEN) <= end) -+ p += copy_next_word(arg, p, MVL_MX_ARG_LEN); -+ else -+ p += copy_next_word(arg, p, end-p); -+ -+ skip_whitespace(p); -+ -+ if (toMacString(mac, arg) < 0) { -+ printk("macvlan: MAC format is incorrect: %s\n", -+ arg); -+ } -+ else { -+ /* This can fail, but not sure how to return failure -+ * to user-space here. -+ */ -+ macvlan_hash_rem(vlan->dev->name, mac); -+ } -+ goto forend; -+ } -+ -+ printk("ERROR: Unsupported command\n"); -+ -+ forend: -+ p++; -+ } -+ -+ MVL_WRITE_UNLOCK(flags); -+ -+ return ret; -+} /* write_mvl */ -+ -+ -+static int read_mvl_port(char *page, char **start, off_t off, -+ int count, int *eof, void *data) { -+ int ret = -1; -+ char *p = page; -+ int mx_len = (4096 - (p - page)); -+ int i; -+ -+ if (! *eof ) { -+ struct macvlan_port* port = (struct macvlan_port*)(data); -+ int cnt; -+ struct macvlan_vlan* vlan; -+ struct macvlan_hash_entry* entry; -+ unsigned long flags; -+ -+ MVL_READ_LOCK(flags); -+ -+ /* Global counts here... */ -+ p += sprintf(p, "MAC-VLAN Port: %s\n", port->dev->name); -+ -+ p += sprintf(p, " vlan count: %i\n", atomic_read(&port->ndevs)); -+ -+ vlan = port->vlan_list; -+ while (vlan) { -+ p += sprintf(p, " %s\n", vlan->dev->name); -+ -+ /* catch overflow */ -+ cnt = p - page; -+ if (cnt > (mx_len - 40)) { -+ if (mx_len - cnt >= 20) { -+ p += sprintf(p, "OUT_OF_SPACE!\n"); -+ } -+ goto outofspace; -+ } -+ -+ vlan = vlan->next; -+ } -+ -+ /* MAC addr hash */ -+ -+ for (i = 0; i<MACVLAN_HASH_LEN; i++) { -+ if (port->hash_table[i]) { -+ p += sprintf(p, " [%i] ", i); -+ entry = port->hash_table[i]; -+ while (entry) { -+ /* catch overflow */ -+ cnt = p - page; -+ if (cnt > (mx_len - 40)) { -+ if (mx_len - cnt >= 20) { -+ p += sprintf(p, "OUT_OF_SPACE!\n"); -+ } -+ goto outofspace; -+ } -+ -+ p += sprintf(p, " %02hx:%02hx:%02hx:%02hx:%02hx:%02hx", -+ entry->mac[0], entry->mac[1], entry->mac[2], -+ entry->mac[3], entry->mac[4], entry->mac[5]); -+ -+ entry = entry->next; -+ } -+ p += sprintf(p, "\n"); -+ } -+ } -+ -+ outofspace: -+ ret = p - page; -+ MVL_READ_UNLOCK(flags); -+ } -+ return ret; -+} /* read_mvl_glbl */ -+ -+ -+static int write_mvl_port(struct file *file, const char *buffer, -+ unsigned long count, void *data) { -+ char *p; -+ const char *end; -+ int ret=count; -+ int len; -+ char dev_name[2][IFNAMSIZ]; -+ char* tmps = NULL; -+ struct macvlan_port* port = (struct macvlan_port*)(data); -+ unsigned long flags; -+ -+ end = buffer+count; -+ -+ for (p= (char *) buffer; p< end ; ) { -+ if (iswhitespace(*p)) { -+ p++; -+ continue; -+ } -+ -+ memset(dev_name[0], 0 ,IFNAMSIZ); -+ memset(dev_name[1], 0 ,IFNAMSIZ); -+ -+ len = strlen("add_vlan "); -+ if (strncmp(p, "add_vlan ", len)==0) { -+ p += len; -+ -+ if ( (p + IFNAMSIZ) <= end) -+ p += copy_next_word(dev_name[0], p, IFNAMSIZ); -+ else -+ p += copy_next_word(dev_name[0], p, end-p ); -+ -+ skip_whitespace(p); -+ -+ /* This can fail, but not sure how to return failure -+ * to user-space here. -+ */ -+ /* has internal locking */ -+ macvlan_vlan_create(port->dev->name, -+ simple_strtoul(dev_name[0], &tmps, 10)); -+ goto forend; -+ } -+ -+ len = strlen("set_flags "); -+ if (strncmp(p, "set_flags ", len)==0) { -+ p += len; -+ -+ if ( (p + IFNAMSIZ) <= end) -+ p += copy_next_word(dev_name[0], p, IFNAMSIZ); -+ else -+ p += copy_next_word(dev_name[0], p, end-p ); -+ -+ skip_whitespace(p); -+ -+ /* This can fail, but not sure how to return failure -+ * to user-space here. -+ */ -+ -+ MVL_WRITE_LOCK(flags); -+ macvlan_port_set_flags(port->dev->name, -+ simple_strtoul(dev_name[0], &tmps, 16)); -+ MVL_WRITE_UNLOCK(flags); -+ goto forend; -+ } -+ -+ len = strlen("remove_vlan "); -+ if (strncmp(p,"remove_vlan ",len)==0) { -+ p += len; -+ -+ if ( (p + IFNAMSIZ) <= end) -+ p += copy_next_word(dev_name[0], p, IFNAMSIZ); -+ else -+ p += copy_next_word(dev_name[0], p, end-p ); -+ -+ skip_whitespace(p); -+ -+ /* Has internal locking */ -+ macvlan_vlan_cleanup(dev_name[0]); -+ goto forend; -+ } -+ -+ printk("ERROR: Unsupported command\n"); -+ -+ forend: -+ p++; -+ } -+ -+ return ret; -+} /* write_mvl_port */ -+ -+ -+#endif -+ -+ -+static int __init macvlan_init(void) { -+ printk (KERN_INFO "MAC address based VLAN support Revision: 1.3\n"); -+ -+ port_list = NULL; -+ -+ macvlan_ioctl_hook = macvlan_ioctl_deviceless_stub; -+ macvlan_handle_frame_hook = macvlan_handle_frame; -+ -+#ifdef MVL_CONFIG_PROC_FS -+ -+ mvl_proc_dir = proc_mkdir(MVL_PROC_DIR, proc_net); -+ if (mvl_proc_dir) { -+ mvl_proc_cfg = create_proc_read_entry(MVL_PROC_CFG, S_IRUGO, mvl_proc_dir, -+ read_mvl_glbl, NULL); -+ if (mvl_proc_cfg) { -+ mvl_proc_cfg->write_proc = write_mvl_glbl; -+ } -+ } -+#endif -+ -+ -+ return 0; -+} -+ -+static void macvlan_cleanup(void) { -+ struct macvlan_port *port; -+ -+ macvlan_handle_frame_hook = NULL; -+ macvlan_ioctl_hook = NULL; -+ -+ /* destroy all existing ports */ -+ while ((port = port_list)) { -+ if (macvlan_port_cleanup(port->dev->name) < 0) { -+ BUG_ON(1); -+ } -+ } -+ -+#ifdef MVL_CONFIG_PROC_FS -+ if (mvl_proc_cfg) { -+ remove_proc_entry(MVL_PROC_CFG, mvl_proc_dir); -+ mvl_proc_cfg = NULL; -+ } -+ if (mvl_proc_dir) { -+ remove_proc_entry(MVL_PROC_DIR, proc_net); -+ mvl_proc_dir = NULL; -+ } -+#endif -+ -+}/* macvlan_cleanup */ -+ -+ -+module_init(macvlan_init); -+module_exit(macvlan_cleanup); -+MODULE_LICENSE("GPL"); ---- linux-2.4.21/net/macvlan/macvlan.h 1969-12-31 16:00:00.000000000 -0800 -+++ linux-2.4.21.amds/net/macvlan/macvlan.h 2003-08-13 16:26:08.000000000 -0700 -@@ -0,0 +1,104 @@ -+/* -*- linux-c -*- -+ -+# (C) Copyright 2001-2003 -+# Alex Zeffertt, Cambridge Broadband Ltd, ajz@cambridgebroadband.com -+# Re-worked by Ben Greear <greearb@candelatech.com> -+ -+*/ -+ -+#ifndef MACVLAN_KERNEL_H_FILE__ -+#define MACVLAN_KERNEL_H_FILE__ -+ -+ -+/* NOTE: If you change this below, you should probably change macvlan_hash_lookup as -+ * well. Especially if you make this bigger. -+ */ -+#define MACVLAN_HASH_LEN 256 -+ -+#define VLAN_BUCKET(a) a[5] % MACVLAN_HASH_LEN; -+ -+/* This can be made as large as desired, and mainly helps keep bad -+ * IOCTL arguments from taking down the box. -+ */ -+#define MAX_MACVLANS_PER_PORT 10000 -+ -+/* Proc file related */ -+#define MVL_MX_ARG_LEN 80 -+ -+#ifdef CONFIG_PROC_FS -+ -+/* To use or not to use the PROC-FS */ -+#define MVL_CONFIG_PROC_FS -+ -+#endif -+ -+ -+/*********************************************************/ -+/* types */ -+/*********************************************************/ -+/* a macvlan_vlan represents an upper layer interface */ -+struct macvlan_vlan { -+ struct net_device* dev; -+ struct net_device_stats statistics; -+ struct macvlan_vlan *next; -+ struct macvlan_port *port; -+ struct net_device *lowerdev; -+ atomic_t nmacs; /* the number of mac addresses bound to this vlan */ -+ -+#ifdef MVL_CONFIG_PROC_FS -+ struct proc_dir_entry* proc_ent; -+#endif -+ -+}; -+ -+struct macvlan_hash_entry { -+ unsigned char mac[ETH_ALEN]; /* the eth hdr source to match. Can -+ * match as destination too, see flags in -+ * macvlan_port. Cannot match on both. */ -+ struct macvlan_vlan *vlan; /* the vlan target */ -+ struct macvlan_hash_entry *next;/* next entry in list (same hash, any dev) */ -+}; -+ -+ -+/* -+ * a macvlan_port represents a mux/demux between a mac- -+ * based-vlan enabled ethernet device and vlans -+ * layered on top of it -+ */ -+struct macvlan_port { -+ /* MAC to vlan lookup */ -+ struct macvlan_hash_entry *hash_table[MACVLAN_HASH_LEN]; -+ struct net_device *dev; /* the mac-based-vlan enabled ethernet device */ -+ atomic_t ndevs; /* number of vlans layered over dev */ -+ struct macvlan_vlan *vlan_list; /* list of vlans layered over this port */ -+ struct macvlan_port *next; /* next port */ -+ -+#define MVL_FILTER_ON_DEST 0x1 /* 0x1 filter-on-destination (instead of source) */ -+ int flags; -+ -+#ifdef MVL_CONFIG_PROC_FS -+ struct proc_dir_entry* proc_dir; -+ struct proc_dir_entry* proc_ent; -+#endif -+ -+}; -+ -+ -+#ifdef MVL_CONFIG_PROC_FS -+static int read_mvl_glbl(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int write_mvl_glbl(struct file *file, const char *buffer, -+ unsigned long count, void *data); -+static int read_mvl(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int write_mvl(struct file *file, const char *buffer, -+ unsigned long count, void *data); -+static int read_mvl_port(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+static int write_mvl_port(struct file *file, const char *buffer, -+ unsigned long count, void *data); -+#endif -+ -+ -+#endif -+ ---- linux-2.4.21/net/packet/af_packet.c 2002-08-02 17:39:46.000000000 -0700 -+++ linux-2.4.21.amds/net/packet/af_packet.c 2003-07-30 16:20:41.000000000 -0700 -@@ -68,6 +68,7 @@ - #include <linux/module.h> - #include <linux/init.h> - #include <linux/if_bridge.h> -+#include <linux/if_macvlan.h> - - #ifdef CONFIG_NET_DIVERT - #include <linux/divert.h> -@@ -1504,6 +1505,20 @@ - #endif - return -ENOPKG; - -+ case SIOCGIFMACVLAN: -+ case SIOCSIFMACVLAN: -+#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE) -+#ifdef CONFIG_INET -+#ifdef CONFIG_KMOD -+ if (macvlan_ioctl_hook == NULL) -+ request_module("macvlan"); -+#endif -+ if (macvlan_ioctl_hook != NULL) -+ return macvlan_ioctl_hook(arg); -+#endif -+#endif -+ return -ENOPKG; -+ - case SIOCGIFDIVERT: - case SIOCSIFDIVERT: - #ifdef CONFIG_NET_DIVERT ---- linux-2.4.21/net/ipv4/arp.c 2002-11-28 15:53:15.000000000 -0800 -+++ linux-2.4.21.amds/net/ipv4/arp.c 2003-07-30 16:20:41.000000000 -0700 -@@ -1,4 +1,4 @@ --/* linux/net/inet/arp.c -+/* linux/net/inet/arp.c -*-linux-c-*- - * - * Version: $Id: candela_2.4.21.patch,v 1.4 2003/09/30 21:05:04 greear Exp $ - * -@@ -351,12 +351,22 @@ - int flag = 0; - /*unsigned long now; */ - -- if (ip_route_output(&rt, sip, tip, 0, 0) < 0) -+ if (ip_route_output(&rt, sip, tip, 0, 0) < 0) - return 1; -- if (rt->u.dst.dev != dev) { -- NET_INC_STATS_BH(ArpFilter); -- flag = 1; -- } -+ -+ if (rt->u.dst.dev != dev) { -+ if ((dev->priv_flags & IFF_ACCEPT_LOCAL_ADDRS) && -+ (rt->u.dst.dev == &loopback_dev)) { -+ /* OK, we'll let this special case slide, so that we can arp from one -+ * local interface to another. This seems to work, but could use some -+ * review. --Ben -+ */ -+ } -+ else { -+ NET_INC_STATS_BH(ArpFilter); -+ flag = 1; -+ } -+ } - ip_rt_put(rt); - return flag; - } ---- linux-2.4.21/net/ipv4/fib_frontend.c 2002-08-02 17:39:46.000000000 -0700 -+++ linux-2.4.21.amds/net/ipv4/fib_frontend.c 2003-07-30 16:20:41.000000000 -0700 -@@ -233,8 +233,17 @@ - - if (fib_lookup(&key, &res)) - goto last_resort; -- if (res.type != RTN_UNICAST) -- goto e_inval_res; -+ -+ if (res.type != RTN_UNICAST) { -+ if ((res.type == RTN_LOCAL) && -+ (dev->priv_flags & IFF_ACCEPT_LOCAL_ADDRS)) { -+ /* All is OK */ -+ } -+ else { -+ goto e_inval_res; -+ } -+ } -+ - *spec_dst = FIB_RES_PREFSRC(res); - fib_combine_itag(itag, &res); - #ifdef CONFIG_IP_ROUTE_MULTIPATH ---- linux-2.4.21/net/ipv4/tcp_ipv4.c 2003-06-13 07:51:39.000000000 -0700 -+++ linux-2.4.21.amds/net/ipv4/tcp_ipv4.c 2003-07-30 16:20:41.000000000 -0700 -@@ -1403,7 +1403,7 @@ - #define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */ - #endif - -- /* Never answer to SYNs send to broadcast or multicast */ -+ /* Never answer to SYNs sent to broadcast or multicast */ - if (((struct rtable *)skb->dst)->rt_flags & - (RTCF_BROADCAST|RTCF_MULTICAST)) - goto drop; ---- linux-2.4.21/net/8021q/vlan_dev.c 2003-06-13 07:51:39.000000000 -0700 -+++ linux-2.4.21.amds/net/8021q/vlan_dev.c 2003-08-05 20:38:25.000000000 -0700 -@@ -1,18 +1,18 @@ --/* -+/* -*- linux-c -*- - * INET 802.1Q VLAN - * Ethernet-type device handling. - * - * Authors: Ben Greear <greearb@candelatech.com> -- * Please send support related email to: vlan@scry.wanfear.com -- * VLAN Home Page: http://www.candelatech.com/~greear/vlan.html -+ * Please send support related email to: vlan@scry.wanfear.com -+ * VLAN Home Page: http://www.candelatech.com/~greear/vlan.html - * -- * Fixes: Mar 22 2001: Martin Bokaemper <mbokaemper@unispherenetworks.com> -- * - reset skb->pkt_type on incoming packets when MAC was changed -- * - see that changed MAC is saddr for outgoing packets -- * Oct 20, 2001: Ard van Breeman: -- * - Fix MC-list, finally. -- * - Flush MC-list on VLAN destroy. -- * -+ * Fixes: Mar 22 2001: Martin Bokaemper <mbokaemper@unispherenetworks.com> -+ * - reset skb->pkt_type on incoming packets when MAC was changed -+ * - see that changed MAC is saddr for outgoing packets -+ * Oct 20, 2001: Ard van Breeman: -+ * - Fix MC-list, finally. -+ * - Flush MC-list on VLAN destroy. -+ * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License -@@ -99,18 +99,18 @@ - * NOTE: Should be similar to ethernet/eth.c. - * - * SANITY NOTE: This method is called when a packet is moving up the stack -- * towards userland. To get here, it would have already passed -- * through the ethernet/eth.c eth_type_trans() method. -+ * towards userland. To get here, it would have already passed -+ * through the ethernet/eth.c eth_type_trans() method. - * SANITY NOTE 2: We are referencing to the VLAN_HDR frields, which MAY be -- * stored UNALIGNED in the memory. RISC systems don't like -- * such cases very much... -+ * stored UNALIGNED in the memory. RISC systems don't like -+ * such cases very much... - * SANITY NOTE 2a: According to Dave Miller & Alexey, it will always be aligned, -- * so there doesn't need to be any of the unaligned stuff. It has -- * been commented out now... --Ben -+ * so there doesn't need to be any of the unaligned stuff. It has -+ * been commented out now... --Ben - * - */ - int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, -- struct packet_type* ptype) -+ struct packet_type* ptype) - { - unsigned char *rawp = NULL; - struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb->data); -@@ -170,7 +170,7 @@ - spin_unlock_bh(&vlan_group_lock); - - #ifdef VLAN_DEBUG -- printk(VLAN_DBG "%s: dropping skb: %p because came in on wrong device, dev: %s real_dev: %s, skb_dev: %s\n", -+ printk(VLAN_DBG "%s: dropping skb: %p because came in on wrong device, dev: %s real_dev: %s, skb_dev: %s\n", - __FUNCTION__ skb, dev->name, - VLAN_DEV_INFO(skb->dev)->real_dev->name, - skb->dev->name); -@@ -324,8 +324,8 @@ - * physical devices. - */ - int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, -- unsigned short type, void *daddr, void *saddr, -- unsigned len) -+ unsigned short type, void *daddr, void *saddr, -+ unsigned len) - { - struct vlan_hdr *vhdr; - unsigned short veth_TCI = 0; -@@ -613,7 +613,7 @@ - dev_put(dev); - return 0; - } else { -- printk(KERN_ERR "%s: flag %i is not valid.\n", -+ printk(KERN_ERR "%s: flag %i is not valid.\n", - __FUNCTION__, (int)(flag)); - dev_put(dev); - return -EINVAL; -@@ -625,13 +625,66 @@ - dev_put(dev); - } - } else { -- printk(KERN_ERR "%s: Could not find device: %s\n", -+ printk(KERN_ERR "%s: Could not find device: %s\n", - __FUNCTION__, dev_name); - } - - return -EINVAL; - } - -+ -+int vlan_dev_get_realdev_name(const char *dev_name, char* result) -+{ -+ struct net_device *dev = dev_get_by_name(dev_name); -+ int rv = 0; -+ -+ if (dev) { -+ if (dev->priv_flags & IFF_802_1Q_VLAN) { -+ strncpy(result, VLAN_DEV_INFO(dev)->real_dev->name, 23); -+ dev_put(dev); -+ rv = 0; -+ } else { -+ printk(KERN_ERR -+ "%s: %s is not a vlan device, priv_flags: %hX.\n", -+ __FUNCTION__, dev->name, dev->priv_flags); -+ dev_put(dev); -+ rv = -EINVAL; -+ } -+ } else { -+ printk(KERN_ERR "%s: Could not find device: %s\n", -+ __FUNCTION__, dev_name); -+ rv = -ENODEV; -+ } -+ -+ return rv; -+} -+ -+int vlan_dev_get_vid(const char *dev_name, unsigned short* result) -+{ -+ struct net_device *dev = dev_get_by_name(dev_name); -+ int rv = 0; -+ -+ if (dev) { -+ if (dev->priv_flags & IFF_802_1Q_VLAN) { -+ *result = VLAN_DEV_INFO(dev)->vlan_id; -+ dev_put(dev); -+ rv = 0; -+ } else { -+ printk(KERN_ERR -+ "%s: %s is not a vlan device, priv_flags: %hX.\n", -+ __FUNCTION__, dev->name, dev->priv_flags); -+ dev_put(dev); -+ rv = -EINVAL; -+ } -+ } else { -+ printk(KERN_ERR "%s: Could not find device: %s\n", -+ __FUNCTION__, dev_name); -+ rv = -ENODEV; -+ } -+ -+ return rv; -+} -+ - int vlan_dev_set_mac_address(struct net_device *dev, void *addr_struct_p) - { - struct sockaddr *addr = (struct sockaddr *)(addr_struct_p); -@@ -671,7 +724,7 @@ - } - - static inline int vlan_dmi_equals(struct dev_mc_list *dmi1, -- struct dev_mc_list *dmi2) -+ struct dev_mc_list *dmi2) - { - return ((dmi1->dmi_addrlen == dmi2->dmi_addrlen) && - (memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0)); ---- linux-2.4.21/net/8021q/vlan.c 2003-06-13 07:51:39.000000000 -0700 -+++ linux-2.4.21.amds/net/8021q/vlan.c 2003-08-11 16:43:09.000000000 -0700 -@@ -1,13 +1,13 @@ --/* -+/* -*- linux-c -*- - * INET 802.1Q VLAN - * Ethernet-type device handling. - * - * Authors: Ben Greear <greearb@candelatech.com> -- * Please send support related email to: vlan@scry.wanfear.com -- * VLAN Home Page: http://www.candelatech.com/~greear/vlan.html -+ * Please send support related email to: vlan@scry.wanfear.com -+ * VLAN Home Page: http://www.candelatech.com/~greear/vlan.html - * - * Fixes: -- * Fix for packet capture - Nick Eggleston <nick@dccinc.com>; -+ * Fix for packet capture - Nick Eggleston <nick@dccinc.com>; - * Add HW acceleration hooks - David S. Miller <davem@redhat.com>; - * Correct all the locking - David S. Miller <davem@redhat.com>; - * Use hash table for VLAN groups - David S. Miller <davem@redhat.com> -@@ -173,7 +173,7 @@ - *pprev = grp->next; - } - --/* Find the protocol handler. Assumes VID < VLAN_VID_MASK. -+/* Find the protocol handler. Assumes VID < VLAN_VID_MASK. - * - * Must be invoked with vlan_group_lock held. - */ -@@ -183,7 +183,7 @@ - struct vlan_group *grp = __vlan_find_group(real_dev->ifindex); - - if (grp) -- return grp->vlan_devices[VID]; -+ return grp->vlan_devices[VID]; - - return NULL; - } -@@ -270,7 +270,7 @@ - } - } - -- return ret; -+ return ret; - } - - static int unregister_vlan_device(const char *vlan_IF_name) -@@ -655,17 +655,14 @@ - int vlan_ioctl_handler(unsigned long arg) - { - int err = 0; -+ unsigned short vid = 0; - struct vlan_ioctl_args args; - -- /* everything here needs root permissions, except aguably the -- * hack ioctls for sending packets. However, I know _I_ don't -- * want users running that on my network! --BLG -- */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (copy_from_user(&args, (void*)arg, -- sizeof(struct vlan_ioctl_args))) -+ sizeof(struct vlan_ioctl_args))) - return -EFAULT; - - /* Null terminate this sucker, just in case. */ -@@ -678,24 +675,32 @@ - - switch (args.cmd) { - case SET_VLAN_INGRESS_PRIORITY_CMD: -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; - err = vlan_dev_set_ingress_priority(args.device1, - args.u.skb_priority, - args.vlan_qos); - break; - - case SET_VLAN_EGRESS_PRIORITY_CMD: -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; - err = vlan_dev_set_egress_priority(args.device1, - args.u.skb_priority, - args.vlan_qos); - break; - - case SET_VLAN_FLAG_CMD: -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; - err = vlan_dev_set_vlan_flag(args.device1, - args.u.flag, - args.vlan_qos); - break; - - case SET_VLAN_NAME_TYPE_CMD: -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; - if ((args.u.name_type >= 0) && - (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) { - vlan_name_type = args.u.name_type; -@@ -705,17 +710,9 @@ - } - break; - -- /* TODO: Figure out how to pass info back... -- case GET_VLAN_INGRESS_PRIORITY_IOCTL: -- err = vlan_dev_get_ingress_priority(args); -- break; -- -- case GET_VLAN_EGRESS_PRIORITY_IOCTL: -- err = vlan_dev_get_egress_priority(args); -- break; -- */ -- - case ADD_VLAN_CMD: -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; - /* we have been given the name of the Ethernet Device we want to - * talk to: args.dev1 We also have the - * VLAN ID: args.u.VID -@@ -728,12 +725,53 @@ - break; - - case DEL_VLAN_CMD: -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; - /* Here, the args.dev1 is the actual VLAN we want - * to get rid of. - */ - err = unregister_vlan_device(args.device1); - break; - -+ case GET_VLAN_INGRESS_PRIORITY_CMD: -+ /* TODO: Implement -+ err = vlan_dev_get_ingress_priority(args); -+ if (copy_to_user((void*)arg, &args, -+ sizeof(struct vlan_ioctl_args))) { -+ err = -EFAULT; -+ } -+ */ -+ err = -EINVAL; -+ break; -+ -+ case GET_VLAN_EGRESS_PRIORITY_CMD: -+ /* TODO: Implement -+ err = vlan_dev_get_egress_priority(args.device1, &(args.args); -+ if (copy_to_user((void*)arg, &args, -+ sizeof(struct vlan_ioctl_args))) { -+ err = -EFAULT; -+ } -+ */ -+ err = -EINVAL; -+ break; -+ -+ case GET_VLAN_REALDEV_NAME_CMD: -+ err = vlan_dev_get_realdev_name(args.device1, args.u.device2); -+ if (copy_to_user((void*)arg, &args, -+ sizeof(struct vlan_ioctl_args))) { -+ err = -EFAULT; -+ } -+ break; -+ -+ case GET_VLAN_VID_CMD: -+ err = vlan_dev_get_vid(args.device1, &vid); -+ args.u.VID = vid; -+ if (copy_to_user((void*)arg, &args, -+ sizeof(struct vlan_ioctl_args))) { -+ err = -EFAULT; -+ } -+ break; -+ - default: - /* pass on to underlying device instead?? */ - printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n", ---- linux-2.4.21/net/8021q/vlan.h 2002-08-02 17:39:46.000000000 -0700 -+++ linux-2.4.21.amds/net/8021q/vlan.h 2003-08-13 16:29:30.000000000 -0700 -@@ -72,6 +72,8 @@ - int vlan_dev_set_ingress_priority(char* dev_name, __u32 skb_prio, short vlan_prio); - int vlan_dev_set_egress_priority(char* dev_name, __u32 skb_prio, short vlan_prio); - int vlan_dev_set_vlan_flag(char* dev_name, __u32 flag, short flag_val); -+int vlan_dev_get_realdev_name(const char* dev_name, char* result); -+int vlan_dev_get_vid(const char* dev_name, unsigned short* result); - void vlan_dev_set_multicast_list(struct net_device *vlan_dev); - - #endif /* !(__BEN_VLAN_802_1Q_INC__) */ ---- linux-2.4.21/include/linux/if_vlan.h 2002-11-28 15:53:15.000000000 -0800 -+++ linux-2.4.21.amds/include/linux/if_vlan.h 2003-08-13 16:27:39.000000000 -0700 -@@ -212,7 +212,9 @@ - GET_VLAN_INGRESS_PRIORITY_CMD, - GET_VLAN_EGRESS_PRIORITY_CMD, - SET_VLAN_NAME_TYPE_CMD, -- SET_VLAN_FLAG_CMD -+ SET_VLAN_FLAG_CMD, -+ GET_VLAN_REALDEV_NAME_CMD, /* If this works, you know it's a VLAN device, btw */ -+ GET_VLAN_VID_CMD /* Get the VID of this VLAN (specified by name) */ - }; - - enum vlan_name_types { ---- linux-2.4.21/include/linux/ethtool.h 2003-06-13 07:51:38.000000000 -0700 -+++ linux-2.4.21.amds/include/linux/ethtool.h 2003-07-30 16:20:41.000000000 -0700 -@@ -250,6 +250,12 @@ - u64 data[0]; - }; - -+/* for dumping net-device statistics */ -+struct ethtool_ndstats { -+ u32 cmd; /* ETHTOOL_GNDSTATS */ -+ u8 data[0]; /* sizeof(struct net_device_stats) */ -+}; -+ - /* CMDs currently supported */ - #define ETHTOOL_GSET 0x00000001 /* Get settings. */ - #define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */ -@@ -281,6 +287,7 @@ - #define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */ - #define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */ - #define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */ -+#define ETHTOOL_GNDSTATS 0x0000001e /* get standard net-device statistics */ - - /* compatibility with older code */ - #define SPARC_ETH_GSET ETHTOOL_GSET ---- linux-2.4.21/Documentation/CodingStyle 2001-09-09 16:40:43.000000000 -0700 -+++ linux-2.4.21.amds/Documentation/CodingStyle 2003-08-05 20:51:17.000000000 -0700 -@@ -184,6 +184,8 @@ - (interactive) - (c-mode) - (c-set-style "K&R") -+ (setq tab-width 8) -+ (setq indent-tabs-mode t) - (setq c-basic-offset 8)) - - This will define the M-x linux-c-mode command. When hacking on a ---- linux-2.4.21/include/linux/proc_fs.h 2002-08-02 17:39:45.000000000 -0700 -+++ linux-2.4.21.amds/include/linux/proc_fs.h 2003-08-13 16:47:29.000000000 -0700 -@@ -25,7 +25,8 @@ - /* Finally, the dynamically allocatable proc entries are reserved: */ - - #define PROC_DYNAMIC_FIRST 4096 --#define PROC_NDYNAMIC 4096 -+#define PROC_NDYNAMIC 8192 /* was 4096 previously, but was running out of -+ * slots when creating lots of VLANs --Ben */ - - #define PROC_SUPER_MAGIC 0x9fa0 - diff --git a/contrib/CVS/Entries b/contrib/CVS/Entries deleted file mode 100644 index 2e0a86d..0000000 --- a/contrib/CVS/Entries +++ /dev/null @@ -1,5 +0,0 @@ -/vlan_2.2-full.patch/1.1/Mon Jun 18 22:31:13 2001// -/vlan_2.2-module.patch/1.1/Mon Jun 18 22:31:13 2001// -/README/1.2/Tue Sep 30 23:21:29 2003// -/network/1.1/Tue Sep 30 23:19:45 2003// -D diff --git a/contrib/CVS/Repository b/contrib/CVS/Repository deleted file mode 100644 index 54d399b..0000000 --- a/contrib/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/contrib diff --git a/contrib/CVS/Root b/contrib/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/contrib/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/contrib/README b/contrib/README deleted file mode 100644 index 5af786d..0000000 --- a/contrib/README +++ /dev/null @@ -1,20 +0,0 @@ -Here lies contributions from the community at large that for one -reason or another (laziness on my part, and lack of testing, are -valid reasons!), are not in the main distribution. - -If any of these seem particularly stable or useful, let me -know and I will consider adding them to the main patch. - -Descriptions: -network - "Thanks for the great vconfig patch/tool. I submit to you a minor - change to the RedHat 7.3 /etc/rc.d/init.d/network script that - recognizes VLAN interfaces /etc/sysconfig/network-scripts/ifcfg-ethx.y , - and makes appropriate calls to vconfig prior to bringing the - interface up. This makes startup more straightforward, - and may be of use to your website visitors. - -Derek" - - - - Thanks, Ben Greear (greearb@candelatech.com) diff --git a/contrib/network b/contrib/network deleted file mode 100644 index 48e4240..0000000 --- a/contrib/network +++ /dev/null @@ -1,288 +0,0 @@ -#! /bin/bash -# -# network Bring up/down networking -# -# chkconfig: 2345 10 90 -# description: Activates/Deactivates all network interfaces configured to \ -# start at boot time. -# probe: true -### BEGIN INIT INFO -# Provides: $network -### END INIT INFO - -# Source function library. - -. /etc/init.d/functions - -if [ ! -f /etc/sysconfig/network ]; then - exit 0 -fi - -. /etc/sysconfig/network - -if [ -f /etc/sysconfig/pcmcia ]; then - . /etc/sysconfig/pcmcia -fi - - -# Check that networking is up. -[ "${NETWORKING}" = "no" ] && exit 0 - -# if the ip configuration utility isn't around we can't function. -[ -x /sbin/ip ] || exit 1 - -# Even if IPX is configured, without the utilities we can't do much -[ ! -x /sbin/ipx_internal_net -o ! -x /sbin/ipx_configure ] && IPX= - -# If IPv6 is explicitly configured, make sure it's available. -if [ "$NETWORKING_IPV6" = "yes" ]; then - alias=`modprobe -c | awk '/^alias net-pf-10 / { print $3 }'` - if [ "$alias" != "ipv6" -a ! -f /proc/net/if_inet6 ]; then - echo "alias net-pf-10 ipv6" >> /etc/modules.conf - fi -fi - -CWD=`pwd` -cd /etc/sysconfig/network-scripts - -. network-functions - -# find all the interfaces besides loopback. -# ignore aliases, alternative configurations, and editor backup files -interfaces=`ls ifcfg* | LANG=C egrep -v '(ifcfg-lo|:|\.|rpmsave|rpmorig|rpmnew)' | \ - LANG=C egrep -v '(~|\.bak)$' | \ - LANG=C egrep 'ifcfg-[A-Za-z0-9_-]+$' | \ - sed 's/^ifcfg-//g'` - -vlan_interfaces=`ls ifcfg-eth?.?* | \ - LANG=C egrep -v '(~|\.bak)$' | \ - LANG=C egrep 'ifcfg-[A-Za-z0-9_-\.]+$' | \ - sed 's/^ifcfg-//g'` - -# See how we were called. -case "$1" in - start) - # IPv6 hook (pre IPv4 start) - if [ "$NETWORKING_IPV6" = "yes" ]; then - if [ -x /etc/sysconfig/network-scripts/init.ipv6-global ]; then - /etc/sysconfig/network-scripts/init.ipv6-global start pre - fi - fi - - action $"Setting network parameters: " sysctl -e -p /etc/sysctl.conf - - # bring up loopback interface - action $"Bringing up loopback interface: " ./ifup ifcfg-lo - - case "$IPX" in - yes|true) - /sbin/ipx_configure --auto_primary=$IPXAUTOPRIMARY \ - --auto_interface=$IPXAUTOFRAME - if [ "$IPXINTERNALNETNUM" != "0" ]; then - /sbin/ipx_internal_net add $IPXINTERNALNETNUM $IPXINTERNALNODENUM - fi - ;; - esac - - oldhotplug=`sysctl kernel.hotplug 2>/dev/null | \ - awk '{ print $3 }' 2>/dev/null` - sysctl -w kernel.hotplug="/bin/true" > /dev/null 2>&1 - - cipeinterfaces="" - - # bring up all other interfaces configured to come up at boot time - for i in $interfaces; do - eval $(fgrep "DEVICE=" ifcfg-$i) - if [ -z "$DEVICE" ] ; then DEVICE="$i"; fi - - if [ "${DEVICE##cipcb}" != "$DEVICE" ] ; then - cipeinterfaces="$cipeinterfaces $DEVICE" - continue - fi - if LANG=C egrep -L "^ONBOOT=\"?[Nn][Oo]\"?" ifcfg-$i > /dev/null ; then - # this loads the module, to preserve ordering - is_available $i - continue - fi - # If we're in confirmation mode, get user confirmation - [ -n "$CONFIRM" ] && - { - confirm $i - case $? in - 0) - : - ;; - 2) - CONFIRM= - ;; - *) - continue - ;; - esac - } - - action $"Bringing up interface $i: " ./ifup $i boot - done - - # bring up vlan interfaces configured to come up at boot time - for i in $vlan_interfaces; do - eval $(fgrep "DEVICE=" ifcfg-$i) - if [ -z "$DEVICE" ] ; then DEVICE="$i"; fi - - if LANG=C egrep -L "^ONBOOT=\"?[Nn][Oo]\"?" ifcfg-$i > /dev/null ; then - # this loads the module, to preserve ordering - is_available $i - continue - fi - # If we're in confirmation mode, get user confirmation - [ -n "$CONFIRM" ] && - { - confirm $i - case $? in - 0) - : - ;; - 2) - CONFIRM= - ;; - *) - continue - ;; - esac - } - /usr/local/bin/vconfig add `echo $i | tr '.' ' '` - action $"Bringing up interface $i: " ./ifup $i boot - done - - # Bring up CIPE VPN interfaces - for i in $cipeinterfaces ; do - if ! LANG=C egrep -L "^ONBOOT=\"?[Nn][Oo]\"?" ifcfg-$i >/dev/null 2>&1 ; then - # If we're in confirmation mode, get user confirmation - [ -n "$CONFIRM" ] && - { - confirm $i - case $? in - 0) - : - ;; - 2) - CONFIRM= - ;; - *) - continue - ;; - esac - } - action $"Bringing up interface $i: " ./ifup $i boot - fi - done - - sysctl -w kernel.hotplug=$oldhotplug > /dev/null 2>&1 - - # Add non interface-specific static-routes. - if [ -f /etc/sysconfig/static-routes ]; then - grep "^any" /etc/sysconfig/static-routes | while read ignore args ; do - /sbin/route add -$args - done - fi - - # IPv6 hook (post IPv4 start) - if [ "$NETWORKING_IPV6" = "yes" ]; then - if [ -x /etc/sysconfig/network-scripts/init.ipv6-global ]; then - /etc/sysconfig/network-scripts/init.ipv6-global start post - fi - fi - # Run this again to catch any interface-specific actions - sysctl -e -p /etc/sysctl.conf >/dev/null 2>&1 - - touch /var/lock/subsys/network - ;; - stop) - # If this is a final shutdown/halt, check for network FS, - # and unmount them even if the user didn't turn on netfs - - if [ "$RUNLEVEL" = "6" -o "$RUNLEVEL" = "0" -o "$RUNLEVEL" = "1" ]; then - NFSMTAB=`grep -v '^#' /proc/mounts | awk '{ if ($3 ~ /^nfs$/ ) print $2}'` - SMBMTAB=`grep -v '^#' /proc/mounts | awk '{ if ($3 ~ /^smbfs$/ ) print $2}'` - NCPMTAB=`grep -v '^#' /proc/mounts | awk '{ if ($3 ~ /^ncpfs$/ ) print $2}'` - if [ -n "$NFSMTAB" -o -n "$SMBMTAB" -o -n "$NCPMTAB" ] ; then - /etc/init.d/netfs stop - fi - fi - - # IPv6 hook (pre IPv4 stop) - if [ "$NETWORKING_IPV6" = "yes" ]; then - if [ -x /etc/sysconfig/network-scripts/init.ipv6-global ]; then - /etc/sysconfig/network-scripts/init.ipv6-global stop pre - fi - fi - - # shut down all interfaces (other than loopback) - for i in $interfaces ; do - eval $(fgrep "DEVICE=" ifcfg-$i) - if [ -z "$DEVICE" ] ; then DEVICE="$i"; fi - - if ! check_device_down $i; then - action $"Shutting down interface $i: " ./ifdown $i boot - fi - done - # VLAN - for i in $vlan_interfaces ; do - eval $(fgrep "DEVICE=" ifcfg-$i) - if [ -z "$DEVICE" ] ; then DEVICE="$i"; fi - - if [ -f /proc/net/vlan/$i ]; then - action $"Removing vlan interface interface $i: " /usr/local/bin/vconfig rem $i - fi - done - - case "$IPX" in - yes|true) - if [ "$IPXINTERNALNETNUM" != "0" ]; then - /sbin/ipx_internal_net del - fi - ;; - esac - - action $"Shutting down loopback interface: " ./ifdown ifcfg-lo - - if [ -d /proc/sys/net/ipv4 ]; then - if [ -f /proc/sys/net/ipv4/ip_forward ]; then - if [ `cat /proc/sys/net/ipv4/ip_forward` != 0 ]; then - action $"Disabling IPv4 packet forwarding: " sysctl -w net.ipv4.ip_forward=0 - fi - fi - if [ -f /proc/sys/net/ipv4/ip_always_defrag ]; then - if [ `cat /proc/sys/net/ipv4/ip_always_defrag` != 0 ]; then - action $"Disabling IPv4 automatic defragmentation: " sysctl -w net.ipv4.ip_always_defrag=0 - fi - fi - fi - - # IPv6 hook (post IPv4 stop) - if [ "$NETWORKING_IPV6" = "yes" ]; then - if [ -x /etc/sysconfig/network-scripts/init.ipv6-global ]; then - /etc/sysconfig/network-scripts/init.ipv6-global stop post - fi - fi - - rm -f /var/lock/subsys/network - ;; - status) - echo $"Configured devices:" - echo lo $interfaces - - echo $"Currently active devices:" - echo `/sbin/ip -o link show | awk -F ": " '{ print $2 }'` - ;; - restart|reload) - cd $CWD - $0 stop - $0 start - ;; - *) - echo $"Usage: $0 {start|stop|restart|reload|status}" - exit 1 -esac - -exit 0 diff --git a/contrib/vlan_2.2-full.patch b/contrib/vlan_2.2-full.patch deleted file mode 100644 index 4ae3012..0000000 --- a/contrib/vlan_2.2-full.patch +++ /dev/null @@ -1,2906 +0,0 @@ -diff -Nurb linux/include/linux/if_ether.h linux.p/include/linux/if_ether.h ---- linux/include/linux/if_ether.h Sun Mar 25 18:31:03 2001 -+++ linux.p/include/linux/if_ether.h Mon Jun 4 16:10:17 2001 -@@ -32,6 +32,33 @@ - #define ETH_DATA_LEN 1500 /* Max. octets in payload */ - #define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ - -+ -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) -+ -+#define VLAN_ETH_ALEN 6 /* Octets in one ethernet addr */ -+#define VLAN_ETH_HLEN 18 /* Total octets in header. */ -+#define VLAN_ETH_ZLEN 64 /* Min. octets in frame sans FCS */ -+ -+/* These could be bumped up by 4, but I'm not sure if all the underlying -+ * drivers would like it. -+ * UPDATE: Bumping it by 4, as per Klika's suggestion below. --BLG -+ * -+ * According to 802.3ac, the packet can be 4 bytes longer. --Klika Jan -+ */ -+#define VLAN_ETH_DATA_LEN 1500 /* Max. octets in payload */ -+#define VLAN_ETH_FRAME_LEN 1518 /* Max. octets in frame sans FCS */ -+ -+struct vlan_ethhdr -+{ -+ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ -+ unsigned char h_source[ETH_ALEN]; /* source ether addr */ -+ unsigned short h_vlan_proto; /* Should always be 0x8100 */ -+ unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID */ -+ unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */ -+}; -+ -+#endif /* CONFIG_VLAN_802_1Q ... */ -+ - /* - * These are the defined Ethernet Protocol ID's. - */ -@@ -54,6 +81,7 @@ - #define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ - #define ETH_P_ATALK 0x809B /* Appletalk DDP */ - #define ETH_P_AARP 0x80F3 /* Appletalk AARP */ -+#define ETH_P_802_1Q 0x8100 /* 802.1Q VLAN Extended Header */ - #define ETH_P_IPX 0x8137 /* IPX over DIX */ - #define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ - #define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */ -diff -Nurb linux/include/linux/if_vlan.h linux.p/include/linux/if_vlan.h ---- linux/include/linux/if_vlan.h Thu Jan 1 01:00:00 1970 -+++ linux.p/include/linux/if_vlan.h Mon Jun 4 16:18:26 2001 -@@ -0,0 +1,238 @@ -+/* -*- linux-c -*- -+ * VLAN An implementation of 802.1Q VLAN tagging. -+ * -+ * Version: 0.0.1 03/06/99 -+ * -+ * Authors: Ben Greear <greearb@candelatech.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ * -+ */ -+ -+#ifndef _LINUX_IF_VLAN_H_ -+#define _LINUX_IF_VLAN_H_ -+ -+#ifdef __KERNEL__ -+ -+ -+/* externally defined structs */ -+struct vlan_group; -+struct device; -+struct sk_buff; -+struct packet_type; -+struct vlan_collection; -+ -+ -+#include <linux/proc_fs.h> /* for proc_dir_entry */ -+ -+ -+ -+/* Find a VLAN device by the MAC address of it's Ethernet device, and -+ * it's VLAN ID. The default configuration is to have VLAN's scope -+ * to be box-wide, so the MAC will be ignored. The mac will only be -+ * looked at if we are configured to have a seperate set of VLANs per -+ * each MAC addressable interface. Note that this latter option does -+ * NOT follow the spec for VLANs, but may be useful for doing very -+ * large quantities of VLAN MUX/DEMUX onto FrameRelay or ATM PVCs. -+ */ -+struct device *find_802_1Q_vlan_dev(struct device* real_dev, -+ unsigned short VID); /* vlan.c */ -+ -+ -+int register_netdevice(struct device *dev); /* found in dev.c */ -+int unregister_netdevice(struct device *dev); /* found in dev.c */ -+int dev_new_index(void); /* dev.c */ -+ -+/* found in vlan_dev.c */ -+struct net_device_stats* vlan_dev_get_stats(struct device* dev); -+int vlan_dev_rebuild_header(struct sk_buff *skb); -+int vlan_dev_type_trans(struct sk_buff *skb, struct device *dev, -+ struct packet_type* ptype); -+int vlan_dev_hard_header(struct sk_buff *skb, struct device *dev, -+ unsigned short type, void *daddr, void *saddr, -+ unsigned len); -+int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct device *dev); -+int vlan_dev_change_mtu(struct device *dev, int new_mtu); -+int vlan_dev_set_mac_address(struct device *dev, void* addr); -+int vlan_dev_open(struct device* dev); -+int vlan_dev_stop(struct device* dev); -+int vlan_dev_init(struct device* dev); -+void vlan_dev_destruct(struct device* dev); -+int vlan_dev_set_vlan_flag(char* dev_name, __u32 flag, short flag_val); -+/* I'm ignorant of these right now. --BLG -+int vlan_dev_header_cache(struct neighbour *neigh, struct hh_cache *hh); -+void vlan_dev_header_cache_update(struct hh_cache *hh, struct device *dev, -+ unsigned char * haddr); -+*/ -+void vlan_dev_copy_and_sum(struct sk_buff *dest, unsigned char *src, -+ int length, int base); -+int vlan_dev_set_ingress_priority(char* dev_name, __u32 skb_prio, short vlan_prio); -+int vlan_dev_set_egress_priority(char* dev_name, __u32 skb_prio, short vlan_prio); -+ -+/* VLAN multicast stuff */ -+/* Delete all of the MC list entries from this vlan device. Also deals -+ * with the underlying device... -+ */ -+void vlan_flush_mc_list(struct device* dev); -+/* copy the mc_list into the vlan_info structure. */ -+void vlan_copy_mc_list(struct dev_mc_list* mc_list, struct vlan_dev_info* vlan_info); -+/** dmi is a single entry into a dev_mc_list, a single node. mc_list is -+ * an entire list, and we'll iterate through it. -+ */ -+int vlan_should_add_mc(struct dev_mc_list *dmi, struct dev_mc_list *mc_list); -+/** Taken from Gleb + Lennert's VLAN code, and modified... */ -+void vlan_dev_set_multicast_list(struct device *vlan_dev); -+ -+ -+int vlan_collection_add_vlan(struct vlan_collection* vc, unsigned short vlan_id, -+ unsigned short flags); -+int vlan_collection_remove_vlan(struct vlan_collection* vc, -+ struct device* vlan_dev); -+int vlan_collection_remove_vlan_id(struct vlan_collection* vc, unsigned short vlan_id); -+ -+ -+ -+/* found in vlan.c */ -+/* Our listing of VLAN group(s) */ -+extern struct vlan_group* p802_1Q_vlan_list; -+ -+ -+#define VLAN_NAME "vlan" -+ -+/* if this changes, algorithm will have to be reworked because this -+ * depends on completely exhausting the VLAN identifier space. Thus -+ * it gives constant time lookup, but it many cases it wastes memory. -+ */ -+#define VLAN_GROUP_ARRAY_LEN 4096 -+ -+struct vlan_group { -+ int real_dev_ifindex; /* The index of the ethernet(like?) device the vlan is attached to. */ -+ struct device* vlan_devices[VLAN_GROUP_ARRAY_LEN]; -+ -+ struct vlan_group* next; /* the next in the list */ -+}; -+ -+ -+/* __Flags__ relating to the vlan ports */ -+#define VLAN_FLAG_ALLOW_802_3 1 -+#define VLAN_FLAG_ALLOW_802_1Q 2 -+#define VLAN_FLAG_IS_IN_USE 4 -+ -+ -+struct vlan_priority_tci_mapping { -+ unsigned long priority; -+ unsigned short vlan_qos; /* This should be shifted when first set, so we only do it -+ * at provisioning time. -+ * ((skb->priority << 13) & 0xE000) -+ */ -+ struct vlan_priority_tci_mapping* next; -+}; -+ -+/* Holds information that makes sense if this device is a VLAN device. */ -+struct vlan_dev_info { -+ /** This will be the mapping that correlates skb->priority to -+ * 3 bits of VLAN QOS tags... -+ */ -+ unsigned long ingress_priority_map[8]; -+ struct vlan_priority_tci_mapping* egress_priority_map[16]; /* hash table */ -+ -+ unsigned short vlan_id; /* The VLAN Identifier for this interface. */ -+ unsigned short flags; /* (1 << 0) re_order_header This option will cause the -+ * VLAN code to move around the ethernet header on -+ * ingress to make the skb look **exactly** like it -+ * came in from an ethernet port. This destroys some of -+ * the VLAN information in the skb, but it fixes programs -+ * like DHCP that use packet-filtering and don't understand -+ * 802.1Q -+ */ -+ struct dev_mc_list* old_mc_list; /* old multi-cast list for the VLAN interface.. -+ * we save this so we can tell what changes were -+ * made, in order to feed the right changes down -+ * to the real hardware... -+ */ -+ int old_allmulti; /* similar to above. */ -+ int old_promiscuity; /* similar to above. */ -+ struct device* real_dev; /* the underlying device/interface */ -+ struct proc_dir_entry dent; /* Holds the proc data */ -+ unsigned long cnt_inc_headroom_on_tx; /* How many times did we have to grow the skb on TX. */ -+ unsigned long cnt_encap_on_xmit; /* How many times did we have to encapsulate the skb on TX. */ -+}; -+ -+static inline unsigned short vlan_dev_get_egress_qos_mask(struct device* dev, struct sk_buff* skb) { -+ struct vlan_priority_tci_mapping* mp = dev->vlan_dev->egress_priority_map[(skb->priority & 0xF)]; -+ while (mp) { -+ if (mp->priority == skb->priority) { -+ return mp->vlan_qos; /* This should already be shifted to mask correctly with -+ * the VLAN's TCI -+ */ -+ } -+ mp = mp->next; -+ } -+ return 0; -+} -+ -+static inline int vlan_dmi_equals(struct dev_mc_list *dmi1, -+ struct dev_mc_list *dmi2) { -+ return ((dmi1->dmi_addrlen == dmi2->dmi_addrlen) && -+ (memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0)); -+} -+ -+static inline void vlan_destroy_mc_list(struct dev_mc_list *mc_list) { -+ struct dev_mc_list *dmi = mc_list, *next; -+ -+ while(dmi) { -+ next = dmi->next; -+ kfree(dmi); -+ dmi = next; -+ } -+} -+ -+#endif /* __KERNEL__ */ -+ -+/** These are the IOCTLs relating to the /proc/net/vlan/ * files. -+ * Not all may be supported at this time, and some may be primarily -+ * used for testing and obtaining non-standard access to kernel -+ * devices. -+ */ -+ -+#define VLAN_IOCTL 0x52 /* TODO: Can I just make these up??? */ -+ -+enum vlan_ioctls { -+ ADD_VLAN_IOCTL = (VLAN_IOCTL << 8), -+ DEL_VLAN_IOCTL, -+ SET_INGRESS_PRIORITY_IOCTL, -+ SET_EGRESS_PRIORITY_IOCTL, -+ GET_INGRESS_PRIORITY_IOCTL, -+ GET_EGRESS_PRIORITY_IOCTL, -+ SET_NAME_TYPE_IOCTL, -+ SET_VLAN_FLAG_IOCTL -+}; /* vlan_ioctl enum */ -+ -+enum vlan_name_types { -+ VLAN_NAME_TYPE_PLUS_VID, /* Name will look like: vlan0005 */ -+ VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like: eth1.0005 */ -+ VLAN_NAME_TYPE_PLUS_VID_NO_PAD, /* Name will look like: vlan5 */ -+ VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, /* Name will look like: eth0.5 */ -+ VLAN_NAME_TYPE_HIGHEST -+}; -+ -+struct vlan_ioctl_args { -+ char dev1[24]; -+ -+ union { -+ char dev2[24]; -+ int VID; -+ unsigned long skb_priority; -+ unsigned long name_type; -+ unsigned long bind_type; -+ unsigned long flag; /* Matches vlan_dev_info flags */ -+ } u; -+ -+ short vlan_qos; /* Can also be flag-value, 1 to set, 0 to clear. */ -+}; -+ -+ -+#endif -diff -Nurb linux/include/linux/netdevice.h linux.p/include/linux/netdevice.h ---- linux/include/linux/netdevice.h Sun Mar 25 18:31:03 2001 -+++ linux.p/include/linux/netdevice.h Mon Jun 4 16:10:48 2001 -@@ -39,6 +39,10 @@ - #endif - #endif - -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) -+struct vlan_dev_info; -+#endif /* CONFIG_VLAN_802_1Q ... */ -+ - struct divert_blk; - - /* -@@ -53,7 +57,11 @@ - */ - - #if !defined(CONFIG_AX25) && !defined(CONFIG_AX25_MODULE) && !defined(CONFIG_TR) -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) -+#define LL_MAX_HEADER 36 -+#else - #define LL_MAX_HEADER 32 -+#endif /* CONFIG_VLAN_802_1Q ... */ - #else - #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - #define LL_MAX_HEADER 96 -@@ -155,11 +163,18 @@ - { - struct hh_cache *hh_next; /* Next entry */ - atomic_t hh_refcnt; /* number of users */ -- unsigned short hh_type; /* protocol identifier, f.e ETH_P_IP */ -+ unsigned short hh_type; /* protocol identifier, f.e ETH_P_IP -+ * NOTE: For VLANs, this will be the -+ * encapsulated type. --BLG -+ */ - int (*hh_output)(struct sk_buff *skb); - rwlock_t hh_lock; - /* cached hardware header; allow for machine alignment needs. */ -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) /* we need 4 extra bytes for VLAN headers */ -+ unsigned long hh_data[20/sizeof(unsigned long)]; -+#else - unsigned long hh_data[16/sizeof(unsigned long)]; -+#endif /* CONFIG_VLAN_802_1Q ... */ - }; - - -@@ -319,6 +334,11 @@ - /* Semi-private data. Keep it at the end of device struct. */ - struct dst_entry *fastpath[NETDEV_FASTROUTE_HMASK+1]; - #endif -+ -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) -+ /* Holds information that makes sense if this device is a VLAN device. */ -+ struct vlan_dev_info* vlan_dev; -+#endif /* CONFIG_VLAN_802_1Q ... */ - - #ifdef CONFIG_NET_DIVERT - /* this will get initialized at each interface type init routine */ -diff -Nurb linux/net/802_1Q/Makefile linux.p/net/802_1Q/Makefile ---- linux/net/802_1Q/Makefile Thu Jan 1 01:00:00 1970 -+++ linux.p/net/802_1Q/Makefile Mon Jun 4 16:08:04 2001 -@@ -0,0 +1,21 @@ -+# -+# Makefile for the Linux 802.1q protocol layer -+# -+# Note! Dependencies are done automagically by 'make dep', which also -+# removes any old dependencies. DON'T put your own dependencies here -+# unless it's something special (ie not a .c file). -+# -+# Note 2! The CFLAGS definition is now in the main makefile... -+ -+O_TARGET := 802_1Q.o -+O_OBJS := vlan.o vlanproc.o vlan_dev.o -+ -+ifeq ($(CONFIG_VLAN_802_1Q),m) -+M_OBJS := $(O_TARGET) -+endif -+ -+ifeq ($(CONFIG_SYSCTL),y) -+O_OBJS += sysctl_net_vlan.o -+endif -+ -+include $(TOPDIR)/Rules.make -diff -Nurb linux/net/802_1Q/sysctl_net_vlan.c linux.p/net/802_1Q/sysctl_net_vlan.c ---- linux/net/802_1Q/sysctl_net_vlan.c Thu Jan 1 01:00:00 1970 -+++ linux.p/net/802_1Q/sysctl_net_vlan.c Mon Jun 4 16:08:04 2001 -@@ -0,0 +1,18 @@ -+/* -+ * sysctl_net_vlan.c: sysctl interface to net Ethernet VLAN subsystem. -+ * -+ * Begun Dec 20, 1998, Ben Greear -+ * -+ * TODO: What, if anything, should this do?? -+ */ -+ -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) -+ -+#include <linux/mm.h> -+#include <linux/sysctl.h> -+ -+ctl_table ether_vlan_table[] = { -+ {0} -+}; -+ -+#endif /* CONFIG_VLAN_802_1Q ... */ -diff -Nurb linux/net/802_1Q/vlan.c linux.p/net/802_1Q/vlan.c ---- linux/net/802_1Q/vlan.c Thu Jan 1 01:00:00 1970 -+++ linux.p/net/802_1Q/vlan.c Mon Jun 4 17:46:31 2001 -@@ -0,0 +1,445 @@ -+/* -*- linux-c -*- -+ * INET An implementation of the TCP/IP protocol suite for the LINUX -+ * operating system. INET is implemented using the BSD Socket -+ * interface as the means of communication with the user level. -+ * -+ * Ethernet-type device handling. -+ * -+ * Version: @(#)vlan.c started 12/21/98 -+ * -+ * Authors: Ben Greear <greearb@candelatech.com>, <greearb@agcs.com> -+ * -+ * Fixes: -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include <asm/uaccess.h> /* for copy_from_user */ -+#include <linux/module.h> -+#include <linux/netdevice.h> -+#include <linux/skbuff.h> -+#include <net/datalink.h> -+#include <linux/mm.h> -+#include <linux/in.h> -+#include <linux/init.h> -+#include <net/p8022.h> -+#include <net/arp.h> -+ -+#include <linux/if_vlan.h> -+#include "vlan.h" -+#include "vlanproc.h" -+ -+extern int register_netdevice(struct device *dev); /* found in dev.c */ -+extern int unregister_netdevice(struct device *dev); /* found in dev.c */ -+extern int dev_new_index(void); /* dev.c */ -+ -+extern int eth_header_parse(struct sk_buff *skb, unsigned char *haddr); /* eth.c */ -+ -+extern struct Qdisc noqueue_qdisc; -+ -+/* Global VLAN variables */ -+ -+/* Our listing of VLAN group(s) */ -+struct vlan_group *p802_1Q_vlan_list = NULL; -+ -+static char vlan_fullname[] = "802.1Q VLAN Support"; -+static unsigned int vlan_version = 1; -+static unsigned int vlan_release = 0; -+static char vlan_copyright[] = "(c) 2000 Ben Greear (GPL)"; -+ -+/** These may be changed at run-time through IOCTLs */ -+unsigned short vlan_name_type = 0; /* determines interface naming scheme */ -+unsigned long vlan_bad_proto_recvd = 0; /* Counter for how many NON-VLAN protos we've received on a VLAN. */ -+ -+ -+static struct packet_type vlan_packet_type = -+{ -+ 0, /* MUTTER ntohs(ETH_P_802_1Q),*/ -+ NULL, -+ vlan_dev_type_trans, /* VLAN receive method */ -+ NULL, -+ NULL, -+}; -+ -+/* End of global variables definitions. */ -+ -+#ifdef MODULE -+ -+/* -+ * Kernel Loadable Module Entry Points -+ * -+ * Module 'insert' entry point. -+ * o print announcement -+ * o initialize static data -+ * o create /proc/net/vlan directory and static entries -+ * -+ * Return: 0 Ok -+ * < 0 error. -+ * Context: process -+ */ -+int init_module (void) { -+ vlan_proto_init(NULL); -+ return 0; -+} -+ -+/* -+ * Module 'remove' entry point. -+ * o delete /proc/net/router directory and static entries. -+ */ -+void cleanup_module (void) { -+ dev_remove_pack(&vlan_packet_type); -+ vlan_proc_cleanup(); -+} -+ -+#else -+ -+ -+/** Non-module init entry point. */ -+__initfunc(void vlan_system_init(void)) { -+ /* protocol initialization */ -+ vlan_proto_init(NULL); -+} -+#endif -+ -+/* -+ * Function vlan_proto_init (pro) -+ * -+ * Initialize VLAN protocol layer, -+ * -+ */ -+void vlan_proto_init(struct net_proto *pro) { -+ -+ int err; -+ printk(VLAN_INF "%s v%u.%u %s\n", -+ vlan_fullname, vlan_version, vlan_release, vlan_copyright); -+ -+ /* proc file system initialization */ -+ err = vlan_proc_init(); -+ if (err < 0) { -+ printk(KERN_ERR __FUNCTION__ -+ "%s: can't create entry in proc filesystem!\n", VLAN_NAME); -+ } -+ -+ /* network byte order!! */ -+ vlan_packet_type.type = htons(ETH_P_802_1Q); -+ dev_add_pack(&vlan_packet_type); -+ printk(VLAN_INF "%s Initialization complete.\n", VLAN_NAME); -+} -+ -+ -+ -+/** Will search linearly for now, based on device index. Could -+ * hash, or directly link, this some day. --Ben -+ */ -+struct vlan_group* vlan_find_group(int real_dev_ifindex) { -+ struct vlan_group* grp = NULL; -+ -+ for (grp = p802_1Q_vlan_list; -+ ((grp != NULL) && (grp->real_dev_ifindex != real_dev_ifindex)); -+ grp = grp->next) { -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": grp_idx: %i real_dev_idx: %i\n", -+ grp->real_dev_ifindex, real_dev_ifindex); -+#endif -+ ; -+ } /* for */ -+ -+ return grp; -+} -+ -+/* Find the protocol handler. Assumes VID < 0xFFF. -+ */ -+struct device *find_802_1Q_vlan_dev(struct device* real_dev, unsigned short VID) { -+ -+ struct vlan_group* grp = vlan_find_group(real_dev->ifindex); -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": idx: %i grp: %p\n", real_dev->ifindex, grp); -+#endif -+ -+ /* When here, we have found the correct group, if it exists. */ -+ -+ if (grp) { /* then we found one */ -+ return grp->vlan_devices[VID]; /* return the vlan device */ -+ }//if -+ -+ return NULL; -+}/* find_802_1Q_vlan_dev */ -+ -+ -+ -+int unregister_802_1Q_vlan_dev(int real_dev_ifindex, unsigned short vlan_id) { -+ struct vlan_group* grp; -+ struct device* dev = NULL; -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": VID: %i\n", vlan_id); -+#endif -+ -+ /* sanity check */ -+ if ((vlan_id >= 0xFFF) || (vlan_id <= 0)) { -+ return -EINVAL; -+ } -+ -+ grp = vlan_find_group(real_dev_ifindex); -+ /* When here, we have found the correct group, if it exists. */ -+ -+ if (grp) { -+ dev = grp->vlan_devices[vlan_id]; -+ if (dev) { -+ -+ /* Remove proc entry */ -+ vlan_proc_rem_dev(dev); -+ -+ /* take it out of our own structures */ -+ grp->vlan_devices[vlan_id] = NULL; -+ -+ /* Take it out of the global list of devices. -+ * NOTE: This deletes dev, don't access it again!! -+ */ -+ unregister_netdevice(dev); -+ MOD_DEC_USE_COUNT; -+ -+ }/* if */ -+ }/* if */ -+ return 0; -+}/* unregister vlan device */ -+ -+ -+ -+int unregister_802_1Q_vlan_device(const char* vlan_IF_name) { -+ struct device* dev = NULL; -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": unregister VLAN by name, name -:%s:-\n", -+ vlan_IF_name); -+#endif -+ -+ dev = dev_get(vlan_IF_name); -+ -+ if (dev && dev->vlan_dev) { -+ return unregister_802_1Q_vlan_dev(dev->vlan_dev->real_dev->ifindex, -+ (unsigned short)(dev->vlan_dev->vlan_id)); -+ } -+ else { -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": WARNING: Could not find dev\n"); -+#endif -+ return -EINVAL; -+ } -+}/* unregister vlan device */ -+ -+ -+/* -+ TODO: This for modules or something?? --BLG -+ -+ EXPORT_SYMBOL(register_802_1Q_vlan_device); -+ EXPORT_SYMBOL(unregister_802_1Q_vlan_device); -+ -+*/ -+ -+/* Attach a VLAN device to a mac address (ie Ethernet Card). -+ * Returns the device that was created, or NULL if there was -+ * an error of some kind. -+ */ -+struct device *register_802_1Q_vlan_device(const char* eth_IF_name, -+ unsigned short VLAN_ID) { -+ struct vlan_group* grp; -+ struct device *new_dev; -+ struct device *real_dev; /* the ethernet device */ -+ int malloc_size = 0; -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": if_name -:%s:- vid: %i\n", -+ eth_IF_name, VLAN_ID); -+#endif -+ -+ /* find the device relating to eth_IF_name. -+ * TODO: Make sure it's an ethernet device. */ -+ real_dev = dev_get(eth_IF_name); -+ -+ if (real_dev != NULL) { -+ /* printk(KERN_ALERT "Found real_dev"); */ -+ -+ if ((VLAN_ID > 0) && (VLAN_ID < 0xFFF)) { -+ -+ /* printk(KERN_ALERT "VID is in range"); */ -+ -+ if (find_802_1Q_vlan_dev(real_dev, VLAN_ID)) { -+ /* was already registered. */ -+ printk(VLAN_DBG __FUNCTION__ ": ALREADY had VLAN registered\n"); -+ return NULL; -+ } -+ -+ malloc_size = (sizeof(struct device)); -+ -+ new_dev = (struct device*) kmalloc(malloc_size, GFP_KERNEL); -+ VLAN_MEM_DBG("device malloc, addr: %p size: %i\n", new_dev, malloc_size); -+ -+ if (new_dev != NULL) { -+ /* printk(KERN_ALERT "Got a new device.."); */ -+ -+ memset(new_dev, 0, malloc_size); /* zero everything out */ -+ -+ /* set us up to not use a Qdisc, as the underlying Hardware device -+ * can do all the queueing we could want. -+ */ -+ new_dev->qdisc_sleeping = &noqueue_qdisc; -+ -+ /* Gotta set up the fields for the device. */ -+ new_dev->name = (char*)(kmalloc(IFNAMSIZ + 1, GFP_KERNEL)); -+ VLAN_MEM_DBG("new_dev->name malloc, addr: %p size: %i\n", new_dev->name, IFNAMSIZ + 1); -+ -+ if (new_dev->name) { -+ memset(new_dev->name, 0, IFNAMSIZ + 1); /* zero everything out */ -+ } -+ else { -+ kfree(new_dev); -+ VLAN_FMEM_DBG("new_dev free, addr: %p\n", new_dev); -+ return NULL; -+ } -+ -+ if (vlan_name_type == VLAN_NAME_TYPE_RAW_PLUS_VID) { -+ /* name will look like: eth1.0005 */ -+ sprintf(new_dev->name, "%s.%.4i", real_dev->name, VLAN_ID); -+ } -+ else if (vlan_name_type == VLAN_NAME_TYPE_PLUS_VID_NO_PAD) { -+ /* Put our vlan.VID in the name. Name will look like: vlan5 */ -+ sprintf(new_dev->name, "vlan%i", VLAN_ID); -+ } -+ else if (vlan_name_type == VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD) { -+ /* Put our vlan.VID in the name. Name will look like: eth0.5 */ -+ sprintf(new_dev->name, "%s.%i", real_dev->name, VLAN_ID); -+ } -+ else { /* (vlan_name_type == VLAN_NAME_TYPE_PLUS_VID) { */ -+ /* Put our vlan.VID in the name. Name will look like: vlan0005 */ -+ /* default case */ -+ sprintf(new_dev->name, "vlan%.4i", VLAN_ID); -+ } -+ -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name); -+#endif -+ /* set up method calls */ -+ new_dev->init = vlan_dev_init; -+ new_dev->destructor = vlan_dev_destruct; -+ -+ /* new_dev->ifindex = 0; it will be set when added to -+ * the global list. -+ * iflink is set as well. */ -+ -+ new_dev->get_stats = vlan_dev_get_stats; -+ -+ /* IFF_BROADCAST|IFF_MULTICAST; ??? */ -+ new_dev->flags = real_dev->flags; -+ new_dev->flags &= ~IFF_UP; -+ -+ /* need 4 bytes for extra VLAN header info, hope -+ * underlying device can handle it. */ -+ new_dev->mtu = real_dev->mtu; -+ -+ new_dev->type = real_dev->type; /* TODO: is this true? */ -+ -+ /* Regular ethernet + 4 bytes (18 total). */ -+ new_dev->hard_header_len = VLAN_ETH_HLEN; -+ -+ new_dev->priv = kmalloc(sizeof(struct net_device_stats), -+ GFP_KERNEL); -+ VLAN_MEM_DBG("new_dev->priv malloc, addr: %p size: %i\n", new_dev->priv, -+ sizeof(struct net_device_stats)); -+ -+ if (new_dev->priv) { -+ memset(new_dev->priv, 0, sizeof(struct net_device_stats)); -+ }//if -+ -+ memcpy(new_dev->broadcast, real_dev->broadcast, real_dev->addr_len); -+ memcpy(new_dev->dev_addr, real_dev->dev_addr, real_dev->addr_len); -+ new_dev->addr_len = real_dev->addr_len; -+ -+ new_dev->open = vlan_dev_open; -+ new_dev->stop = vlan_dev_stop; -+ new_dev->hard_header = vlan_dev_hard_header; -+ /*new_dev->hard_header_cache = vlan_header_cache;*/ -+ /*new_dev->header_cache_update = vlan_header_cache_update;*/ -+ new_dev->hard_start_xmit = vlan_dev_hard_start_xmit; -+ new_dev->rebuild_header = vlan_dev_rebuild_header; -+ new_dev->hard_header_parse = eth_header_parse; /* trivial. */ -+ new_dev->set_mac_address = vlan_dev_set_mac_address; -+ new_dev->set_multicast_list = vlan_dev_set_multicast_list; -+ -+ new_dev->vlan_dev = (struct vlan_dev_info*) kmalloc(sizeof(struct vlan_dev_info), -+ GFP_KERNEL); -+ VLAN_MEM_DBG("new_dev->vlan_dev malloc, addr: %p size: %i\n", new_dev->vlan_dev, -+ sizeof(struct vlan_dev_info)); -+ if (new_dev->vlan_dev == NULL) { -+ kfree(new_dev->priv); -+ VLAN_FMEM_DBG("new_dev->priv free, addr: %p\n", new_dev->priv); -+ kfree(new_dev->name); -+ VLAN_FMEM_DBG("new_dev->name free, addr: %p\n", new_dev->name); -+ kfree(new_dev); -+ VLAN_FMEM_DBG("new_dev free, addr: %p\n", new_dev); -+ return NULL; -+ } -+ else { -+ /* Initialize it. */ -+ memset(new_dev->vlan_dev, 0, sizeof(struct vlan_dev_info)); -+ -+ new_dev->vlan_dev->vlan_id = VLAN_ID; /* 1 through 0xFFF */ -+ /* TODO: have to be careful deleting real devices now. */ -+ new_dev->vlan_dev->real_dev = real_dev; -+ -+ memset(&(new_dev->vlan_dev->dent), 0, sizeof(struct proc_dir_entry)); -+ } -+ -+ /* So, got the sucker initialized, now lets place it into our local -+ * structure. -+ */ -+ -+ grp = vlan_find_group(real_dev->ifindex); -+ -+ /* When here, we have found the correct group, if it exists. */ -+ -+ if (!grp) { /* need to add a new group */ -+ /* printk(VLAN_DBG "VLAN REGISTER: " -+ "Need to add new vlan group.\n");*/ -+ -+ grp = kmalloc(sizeof(struct vlan_group), GFP_KERNEL); -+ VLAN_MEM_DBG("grp malloc, addr: %p size: %i\n", grp, sizeof(struct vlan_group)); -+ -+ if (grp) { -+ printk(KERN_ALERT "VLAN REGISTER: Allocated new group, idx: %i\n", -+ real_dev->ifindex); -+ memset(grp, 0, sizeof(struct vlan_group)); -+ grp->real_dev_ifindex = real_dev->ifindex; -+ grp->next = p802_1Q_vlan_list; -+ p802_1Q_vlan_list = grp; -+ } -+ else { -+ kfree(new_dev->name); -+ VLAN_FMEM_DBG("new_dev->name free, addr: %p\n", new_dev->name); -+ kfree(new_dev->priv); -+ VLAN_FMEM_DBG("new_dev->priv free, addr: %p\n", new_dev->priv); -+ kfree(new_dev); -+ VLAN_FMEM_DBG("new_dev free, addr: %p\n", new_dev); -+ return NULL; -+ } -+ }/* if */ -+ -+ grp->vlan_devices[VLAN_ID] = new_dev; -+ -+ /* Now, add it to the global list of devices. */ -+ /* printk(KERN_ALERT "Registering new device."); */ -+ register_netdevice(new_dev); -+ vlan_proc_add_dev(new_dev); /* create it's proc entry */ -+ MOD_INC_USE_COUNT; /* Add was a success!! */ -+ return new_dev; -+ } -+ }//if -+ }//if -+ -+ return NULL; -+}/* register (create) VLAN device */ -diff -Nurb linux/net/802_1Q/vlan.h linux.p/net/802_1Q/vlan.h ---- linux/net/802_1Q/vlan.h Thu Jan 1 01:00:00 1970 -+++ linux.p/net/802_1Q/vlan.h Mon Jun 4 16:18:27 2001 -@@ -0,0 +1,44 @@ -+#ifndef __BEN_VLAN_802_1Q_INC__ -+#define __BEN_VLAN_802_1Q_INC__ -+ -+#include <linux/if_vlan.h> -+ -+/* If this is undefined, the name will look like: vlan0005 */ -+/* #define USE_RAW_IN_NAME Use this one if you like it: eth.0005 */ -+ -+/* Uncomment this if you want debug traces to be shown. */ -+/* #define VLAN_DEBUG */ -+ -+#define VLAN_ERR KERN_ERR -+#define VLAN_INF KERN_ALERT -+#define VLAN_DBG KERN_DEBUG /* change these... to debug, having a hard time -+ * changing the log level at run-time..for some reason. -+ */ -+ -+/* -+ -+These I use for memory debugging. I feared a leak at one time, but -+I never found it..and the problem seems to have dissappeared. Still, -+I'll bet they might prove useful again... --Ben -+ -+#define VLAN_MEM_DBG(x, y, z) printk(VLAN_DBG __FUNCTION__ ": " x, y, z); -+#define VLAN_FMEM_DBG(x, y) printk(VLAN_DBG __FUNCTION__ ": " x, y); -+*/ -+ -+/* This way they don't do anything! */ -+#define VLAN_MEM_DBG(x, y, z) -+#define VLAN_FMEM_DBG(x, y) -+ -+ -+extern unsigned short vlan_name_type; -+extern unsigned long vlan_bad_proto_recvd; /* Counter for how many NON-VLAN protos we've received on a VLAN. */ -+ -+/* Add some headers for the public VLAN methods. */ -+int unregister_802_1Q_vlan_device(const char* vlan_IF_name); -+struct device *register_802_1Q_vlan_device(const char* eth_IF_name, -+ unsigned short VID); -+ -+void vlan_system_init(void); -+void vlan_proto_init(struct net_proto *pro); -+ -+#endif -diff -Nurb linux/net/802_1Q/vlan_dev.c linux.p/net/802_1Q/vlan_dev.c ---- linux/net/802_1Q/vlan_dev.c Thu Jan 1 01:00:00 1970 -+++ linux.p/net/802_1Q/vlan_dev.c Mon Jun 4 16:08:04 2001 -@@ -0,0 +1,765 @@ -+/* -*- linux-c -*- -+ * INET An implementation of the TCP/IP protocol suite for the LINUX -+ * operating system. INET is implemented using the BSD Socket -+ * interface as the means of communication with the user level. -+ * -+ * Ethernet-type device handling. -+ * -+ * Version: @(#)vlan_dev.c Started 3/29/99 -+ * -+ * Authors: Ben Greear <greearb@candelatech.com>, <greearb@agcs.com> -+ * -+ * Fixes: -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include <asm/uaccess.h> /* for copy_from_user */ -+#include <linux/netdevice.h> -+#include <linux/skbuff.h> -+#include <net/datalink.h> -+#include <linux/mm.h> -+#include <linux/in.h> -+#include <linux/init.h> -+#include <net/p8022.h> -+#include <net/arp.h> -+#include "vlan.h" -+#include "vlanproc.h" -+#include <linux/if_vlan.h> -+#include <net/ip.h> -+#include <asm/checksum.h> -+ -+ -+struct net_device_stats* vlan_dev_get_stats(struct device* dev) { -+ return (struct net_device_stats*)(dev->priv); -+} -+ -+ -+/* -+ * Rebuild the Ethernet MAC header. This is called after an ARP -+ * (or in future other address resolution) has completed on this -+ * sk_buff. We now let ARP fill in the other fields. -+ * -+ * This routine CANNOT use cached dst->neigh! -+ * Really, it is used only when dst->neigh is wrong. -+ * -+ * TODO: This needs a checkup, I'm ignorant here. --BLG -+ */ -+int vlan_dev_rebuild_header(struct sk_buff *skb) { -+ -+ struct device *dev = skb->dev; -+ struct vlan_ethhdr *veth = (struct vlan_ethhdr*)(skb->data); -+ -+ switch (veth->h_vlan_encapsulated_proto) -+ { -+#ifdef CONFIG_INET -+ case __constant_htons(ETH_P_IP): -+ -+ /* TODO: Confirm this will work with VLAN headers... */ -+ return arp_find(veth->h_dest, skb); -+#endif -+ default: -+ printk(VLAN_DBG -+ "%s: unable to resolve type %X addresses.\n", -+ dev->name, (int)veth->h_vlan_encapsulated_proto); -+ -+ memcpy(veth->h_source, dev->dev_addr, ETH_ALEN); -+ break; -+ }/* switch */ -+ -+ return 0; -+}/* vlan_dev_rebuild_header */ -+ -+ -+ -+/* -+ * Determine the packet's protocol ID. The rule here is that we -+ * assume 802.3 if the type field is short enough to be a length. -+ * This is normal practice and works for any 'now in use' protocol. -+ * -+ * Also, at this point we assume that we ARE dealing exclusively with -+ * VLAN packets, or packets that should be made into VLAN packets based -+ * on a default VLAN ID. -+ * -+ * NOTE: Should be similar to ethernet/eth.c. -+ * -+ * SANITY NOTE: This method is called when a packet is moving up the stack -+ * towards userland. To get here, it would have already passed -+ * through the ethernet/eth.c eth_type_trans() method. -+ */ -+int vlan_dev_type_trans(struct sk_buff *skb, struct device *dev, -+ struct packet_type* ptype) { -+ unsigned char* rawp = NULL; -+ struct vlan_ethhdr *veth = (struct vlan_ethhdr*)(skb->mac.ethernet); -+ unsigned short vid = 0; -+ struct net_device_stats* stats; -+ -+ /* Do we have a VLAN packet? If not, then throw it away, after printing an error. -+ * -+ */ -+ if (veth->h_vlan_proto != __constant_htons(ETH_P_802_1Q)) { -+ printk(VLAN_INF __FUNCTION__ ": VLAN device received NON-VLAN protocol: %hx\n", htons(veth->h_vlan_proto)); -+ vlan_bad_proto_recvd++; -+ kfree_skb(skb); -+ return -EINVAL; -+ } -+ else { -+ vid = ((unsigned short)(ntohs(veth->h_vlan_TCI)) & 0xFFF); -+ } -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": skb: %p vlan_id: %hx dev: %s, encap_proto: %hx\n", -+ skb, vid, dev->name, veth->h_vlan_encapsulated_proto); -+#endif -+ -+ /* Ok, we will find the correct VLAN device, strip the header, -+ and then go on as usual. -+ */ -+ -+ /* we have 12 bits of vlan ID. */ -+ /* If it's NULL, we will tag the skb to be junked below */ -+ skb->dev = find_802_1Q_vlan_dev(dev, vid); -+ -+ if (!skb->dev) { -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": ERROR: No device for VID: %i on dev: %s [%i]\n", -+ (unsigned int)(vid), dev->name, dev->ifindex); -+#endif -+ kfree_skb(skb); -+ return -1; -+ } -+ -+ stats = (struct net_device_stats*)(skb->dev->priv); -+ -+ /* -+ * Deal with ingress priority mapping. -+ */ -+ skb->priority = skb->dev->vlan_dev->ingress_priority_map[(ntohs(veth->h_vlan_TCI) >> 13) & 0x7]; -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": priority: %lu for TCI: %hu (hbo) on vlan_dev: %s\n", -+ (unsigned long)(skb->priority), ntohs(veth->h_vlan_TCI), skb->dev->name); -+#endif -+ -+ /* Bump the rx counters for the VLAN device. */ -+ stats->rx_packets++; -+ stats->rx_bytes += skb->len; -+ -+ /* NOTE: The underlying device SHOULD NOT PULL THE MAC BYTES OFF. -+ (it doesn't seem to.) -+ */ -+ skb_pull(skb, VLAN_ETH_HLEN); /* take off the VLAN header */ -+ -+ -+ /* VLAN and regular Ethernet headers have the addresses in the same place. -+ * TODO: Add code to deal with VLAN control packets?? --BLG -+ * Is there such a thing?? -+ */ -+ if (*(veth->h_dest) & 1) { -+ stats->multicast++; -+ if (memcmp(veth->h_dest, dev->broadcast, ETH_ALEN) == 0) -+ skb->pkt_type = PACKET_BROADCAST; -+ else -+ skb->pkt_type = PACKET_MULTICAST; -+ } -+ -+ /* -+ * This ALLMULTI check should be redundant by 1.4 -+ * so don't forget to remove it. -+ * -+ * Seems, you forgot to remove it. All silly devices -+ * seems to set IFF_PROMISC. -+ */ -+ -+ else if (dev->flags & (IFF_PROMISC/*|IFF_ALLMULTI*/)) { -+ if (memcmp(veth->h_dest, dev->dev_addr, ETH_ALEN) != 0) -+ skb->pkt_type = PACKET_OTHERHOST; -+ } -+ -+ /* Was a VLAN packet, grab the encapsulated protocol, which the layer -+ * three protocols care about. -+ */ -+ if (ntohs(veth->h_vlan_encapsulated_proto) >= 1536) { -+ -+ skb->protocol = veth->h_vlan_encapsulated_proto; -+ /* place it back on the queue to be handled by true layer 3 protocols. -+ */ -+ -+ /* See if we are configured to re-write the VLAN header to make it look like -+ * ethernet... -+ */ -+ if (skb->dev->vlan_dev->flags & 1) { -+ /* Lifted from Gleb's VLAN code... */ -+ memmove(skb->data - (VLAN_ETH_HLEN - 4), skb->data - VLAN_ETH_HLEN, 12); -+ skb->mac.raw += 4; -+ } -+ netif_rx(skb); -+ return 0; -+ } -+ -+ rawp = skb->data; -+ -+ /* -+ * This is a magic hack to spot IPX packets. Older Novell breaks -+ * the protocol design and runs IPX over 802.3 without an 802.2 LLC -+ * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This -+ * won't work for fault tolerant netware but does for the rest. -+ */ -+ if (*(unsigned short *)rawp == 0xFFFF) { -+ skb->protocol = __constant_htons(ETH_P_802_3); -+ /* place it back on the queue to be handled by true layer 3 protocols. -+ */ -+ -+ /* See if we are configured to re-write the VLAN header to make it look like -+ * ethernet... -+ */ -+ if (skb->dev->vlan_dev->flags & 1) { -+ /* Lifted from Gleb's VLAN code... */ -+ memmove(skb->data - (VLAN_ETH_HLEN - 4), skb->data - VLAN_ETH_HLEN, 12); -+ skb->mac.raw += 4; -+ } -+ netif_rx(skb); -+ return 0; -+ } -+ -+ /* -+ * Real 802.2 LLC -+ */ -+ skb->protocol = __constant_htons(ETH_P_802_2); -+ /* place it back on the queue to be handled by upper layer protocols. -+ */ -+ -+ /* See if we are configured to re-write the VLAN header to make it look like -+ * ethernet... -+ */ -+ if (skb->dev->vlan_dev->flags & 1) { -+ /* Lifted from Gleb's VLAN code... */ -+ memmove(skb->data - (VLAN_ETH_HLEN - 4), skb->data - VLAN_ETH_HLEN, 12); -+ skb->mac.raw += 4; -+ } -+ netif_rx(skb); -+ return 0; -+} -+ -+ -+/* -+ * Create the Ethernet VLAN MAC header for an arbitrary protocol layer -+ * -+ * saddr=NULL means use device source address -+ * daddr=NULL means leave destination address (eg unresolved arp) -+ * -+ * This is called when the SKB is moving down the stack towards the -+ * physical devices. -+ */ -+int vlan_dev_hard_header(struct sk_buff *skb, struct device *dev, -+ unsigned short type, void *daddr, void *saddr, -+ unsigned len) { -+ struct vlan_ethhdr *veth; -+ unsigned short veth_TCI = 0; -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": skb: %p type: %hx len: %x vlan_id: %hx, daddr: %p\n", -+ skb, type, len, dev->vlan_dev->vlan_id, daddr); -+#endif -+ -+ veth = (struct vlan_ethhdr*)skb_push(skb, VLAN_ETH_HLEN); -+ -+ /* build the four bytes that make this a VLAN header. */ -+ -+ /* first, the ethernet type */ -+ veth->h_vlan_proto = __constant_htons(ETH_P_802_1Q); -+ -+ /* Now, construct the second two bytes. This field looks something -+ * like: -+ * usr_priority: 3 bits (high bits) -+ * CFI 1 bit -+ * VLAN ID 12 bits (low bits) -+ * -+ */ -+ veth_TCI = dev->vlan_dev->vlan_id; -+ veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb); -+ -+ veth->h_vlan_TCI = htons(veth_TCI); -+ -+ /* Rest should be the same as a normal header. */ -+ /* -+ * Set the protocol type. For a packet of type ETH_P_802_3 we put the length -+ * in here instead. It is up to the 802.2 layer to carry protocol information. -+ * -+ */ -+ -+ if (type != ETH_P_802_3) -+ veth->h_vlan_encapsulated_proto = htons(type); -+ else -+ veth->h_vlan_encapsulated_proto = htons(len); -+ -+ /* -+ * Set the source hardware address. -+ */ -+ -+ if (saddr) -+ memcpy(veth->h_source, saddr, ETH_ALEN); -+ else -+ memcpy(veth->h_source, dev->dev_addr, ETH_ALEN); -+ -+ /* -+ * Anyway, the loopback-device should never use this function... -+ * This is especially true with VLAN's. --BLG -+ */ -+ -+ if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { -+ memset(veth->h_dest, 0, ETH_ALEN); -+ return (VLAN_ETH_HLEN); /* was: dev->hard_header_len */ -+ } -+ -+ if (daddr) { -+ memcpy(veth->h_dest, daddr, ETH_ALEN); -+ return (VLAN_ETH_HLEN); /* was: dev->hard_header_len */ -+ } -+ -+ return -(VLAN_ETH_HLEN); /* was: dev->hard_header_len */ -+ -+} /* vlan_hard_header, put on the VLAN hardware header */ -+ -+ -+int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct device *dev) { -+ struct net_device_stats* stats = (struct net_device_stats*)(dev->priv); -+ struct vlan_ethhdr *veth = (struct vlan_ethhdr*)(skb->data); -+ -+ /* Handle non-VLAN frames if they are sent to us, for example by DHCP. */ -+ if (veth->h_vlan_proto != __constant_htons(ETH_P_802_1Q)) { -+ /* This is not a VLAN frame...but we can fix that! */ -+ unsigned short veth_TCI = 0; -+ dev->vlan_dev->cnt_encap_on_xmit++; -+ -+ if (skb_headroom(skb) < 4) { -+ struct sk_buff* sk_tmp = skb; -+ skb = skb_realloc_headroom(sk_tmp, 4); -+ kfree_skb(sk_tmp); -+ if (skb == NULL) { -+ stats->tx_dropped++; -+ kfree_skb(sk_tmp); -+ return -ENOMEM; -+ } -+ dev->vlan_dev->cnt_inc_headroom_on_tx++; -+ } -+ else { -+ if( !(skb = skb_unshare(skb, GFP_ATOMIC)) ) { -+ printk(KERN_ERR "vlan: failed to unshare skbuff\n"); -+ stats->tx_dropped++; -+ return -ENOMEM; -+ } -+ } -+ veth = (struct vlan_ethhdr*)skb_push(skb, 4); -+ -+ /* Move the mac addresses to the beginning of the new header. */ -+ memmove(skb->data, skb->data + 4, 12); -+ -+ /* first, the ethernet type */ -+ veth->h_vlan_proto = __constant_htons(ETH_P_802_1Q); -+ -+ /* Now, construct the second two bytes. This field looks something -+ * like: -+ * usr_priority: 3 bits (high bits) -+ * CFI 1 bit -+ * VLAN ID 12 bits (low bits) -+ * -+ */ -+ veth_TCI = dev->vlan_dev->vlan_id; -+ veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb); -+ -+ veth->h_vlan_TCI = htons(veth_TCI); -+ }/* If we needed to encapsulate the frame */ -+ -+ skb->dev = dev->vlan_dev->real_dev; -+ -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": about to send skb: %p to dev: %s\n", skb, skb->dev->name); -+#endif -+ -+ dev_queue_xmit(skb); -+ stats->tx_packets++; /* for statics only */ -+ stats->tx_bytes += skb->len; -+ return 0; -+}/* vlan_dev_hard_start_xmit */ -+ -+ -+int vlan_dev_change_mtu(struct device *dev, int new_mtu) { -+ /* TODO: gotta make sure the underlying layer can handle it, -+ * maybe an IFF_VLAN_CAPABLE flag for devices? -+ */ -+ -+ dev->mtu = new_mtu; -+ return new_mtu; -+} -+ -+int vlan_dev_open(struct device* dev) { -+ dev->flags |= IFF_UP; -+ return 0; -+} -+ -+int vlan_dev_stop(struct device* dev) { -+ dev->flags &= ~IFF_UP; -+ return 0; -+} -+ -+int vlan_dev_init(struct device* dev) { -+ /* TODO: figure this out, maybe do nothing?? */ -+ return 0; -+} -+ -+void vlan_dev_destruct(struct device* dev) { -+ kfree(dev->name); -+ VLAN_FMEM_DBG("dev->name free, addr: %p\n", dev->name); -+ dev->name = NULL; /* better safe than hosed */ -+ -+ kfree(dev->priv); -+ VLAN_FMEM_DBG("dev->priv free, addr: %p\n", dev->priv); -+ dev->priv = NULL; -+ -+ kfree(dev->vlan_dev); -+ VLAN_FMEM_DBG("dev->vlan_dev free, addr: %p\n", dev->vlan_dev); -+ dev->vlan_dev = NULL; -+ -+ kfree(dev); -+ VLAN_FMEM_DBG("device free, addr: %p\n", dev); -+ dev = NULL; -+ -+ return; -+} -+ -+ -+/* TODO: Not to sure if the VLAN stuff works here. Need to understand -+ * this better. --BLG -+ */ -+/* -+int vlan_dev_header_cache(struct neighbour *neigh, struct hh_cache *hh) { -+ unsigned short type = hh->hh_type; -+ struct vlan_ethhdr *veth = (struct vlan_ethhdr*)(((u8*)hh->hh_data) + 2); -+ struct device *dev = neigh->dev; -+ -+ if (type == __constant_htons(ETH_P_802_3)) { -+ return -1; -+ } -+ -+ veth->h_vlan_proto = __constant_htons(ETH_P_802_1Q); -+ memcpy(veth->h_source, dev->dev_addr, ETH_ALEN); -+ memcpy(veth->h_dest, neigh->ha, ETH_ALEN); -+ -+ * VLAN specific attributes. * -+ veth->h_vlan_TCI = htons(dev->VLAN_id); * TODO: Add priority control (high 3 bits.) * -+ veth->h_vlan_encapsulated_proto = type; * should already be in network order * -+ -+ return 0; -+} -+*/ -+ -+/* -+ * Called by Address Resolution module to notify changes in address. -+ */ -+/* -+void vlan_dev_header_cache_update(struct hh_cache *hh, struct device *dev, -+ unsigned char * haddr) { -+ memcpy(((u8*)hh->hh_data) + 2, haddr, VLAN_ETH_HLEN); -+} -+*/ -+ -+#ifndef CONFIG_IP_ROUTER -+ -+/* -+ * Copy from an ethernet device memory space to an sk_buff while -+ * checksumming if IP -+ * -+ * TODO: Find out who calls this: This was lifted from eth.c, and -+ * was called eth_copy_and_sum. --BLG -+ */ -+ -+void vlan_dev_copy_and_sum(struct sk_buff *dest, unsigned char *src, -+ int length, int base) { -+ struct vlan_ethhdr* veth; -+ struct iphdr *iph; -+ int ip_length; -+ -+ veth = (struct vlan_ethhdr*)(src); -+ -+ /* This grabs the VLAN part of the header too. */ -+ if (veth->h_vlan_encapsulated_proto != __constant_htons(ETH_P_IP)) { -+ memcpy(dest->data, src, length); -+ return; -+ } -+ -+ /* -+ * We have to watch for padded packets. The csum doesn't include the -+ * padding, and there is no point in copying the padding anyway. -+ * We have to use the smaller of length and ip_length because it -+ * can happen that ip_length > length. -+ */ -+ -+ /* ethernet is always >= 34 */ -+ memcpy(dest->data, src, sizeof(struct iphdr) + VLAN_ETH_HLEN); -+ -+ length -= sizeof(struct iphdr) + VLAN_ETH_HLEN; -+ iph = (struct iphdr*)(src + VLAN_ETH_HLEN); -+ ip_length = ntohs(iph->tot_len) - sizeof(struct iphdr); -+ -+ /* Also watch out for bogons - min IP size is 8 (rfc-1042) */ -+ if ((ip_length <= length) && (ip_length > 7)) -+ length=ip_length; -+ -+ dest->csum = csum_partial_copy(src + sizeof(struct iphdr) + VLAN_ETH_HLEN, -+ dest->data + sizeof(struct iphdr) + VLAN_ETH_HLEN, -+ length, base); -+ dest->ip_summed=1; -+ -+} /* vlan_copy_and_sum */ -+ -+#endif //! CONFIG_IP_ROUTER -+ -+ -+int vlan_dev_set_ingress_priority(char* dev_name, __u32 skb_prio, short vlan_prio) { -+ struct device* dev = dev_get(dev_name); -+ -+ if (dev) { -+ if (dev->vlan_dev) { /* can't put a dflt ID on a vlan device */ -+ /* see if a priority mapping exists.. */ -+ dev->vlan_dev->ingress_priority_map[vlan_prio & 0x7] = skb_prio; -+ return 0; -+ } -+ } -+ return -EINVAL; -+} -+ -+int vlan_dev_set_egress_priority(char* dev_name, __u32 skb_prio, short vlan_prio) { -+ struct device* dev = dev_get(dev_name); -+ struct vlan_priority_tci_mapping* mp = NULL; -+ struct vlan_priority_tci_mapping* np; -+ -+ if (dev) { -+ if (dev->vlan_dev) { /* can't put a dflt ID on a vlan device */ -+ /* see if a priority mapping exists.. */ -+ mp = dev->vlan_dev->egress_priority_map[skb_prio & 0xF]; -+ while (mp) { -+ if (mp->priority == skb_prio) { -+ mp->vlan_qos = ((vlan_prio << 13) & 0xE000); -+ return 0; -+ } -+ } -+ /* create a new mapping then. */ -+ mp = dev->vlan_dev->egress_priority_map[skb_prio & 0xF]; -+ np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL); -+ if (np) { -+ np->next = mp; -+ np->priority = skb_prio; -+ np->vlan_qos = ((vlan_prio << 13) & 0xE000); -+ dev->vlan_dev->egress_priority_map[skb_prio & 0xF] = np; -+ return 0; -+ } -+ else { -+ return -ENOBUFS; -+ } -+ } -+ } -+ return -EINVAL; -+} -+ -+/* Flags are defined in the vlan_dev_info class in include/linux/if_vlan.h file. */ -+int vlan_dev_set_vlan_flag(char* dev_name, __u32 flag, short flag_val) { -+ struct device* dev = dev_get(dev_name); -+ -+ if (dev) { -+ if (dev->vlan_dev) { -+ /* verify flag is supported */ -+ if (flag == 1) { -+ if (flag_val) { -+ dev->vlan_dev->flags |= 1; -+ } -+ else { -+ dev->vlan_dev->flags &= ~1; -+ } -+ return 0; -+ } -+ else { -+ return -EINVAL; -+ } -+ }/* if it's a vlan device */ -+ }/* if we found the device */ -+ return -EINVAL; -+} -+ -+ -+int vlan_dev_set_mac_address(struct device *dev, void* addr_struct_p) { -+ int i; -+ struct sockaddr *addr = (struct sockaddr*)(addr_struct_p); -+ -+ if (dev->start) { -+ return -EBUSY; -+ } -+ -+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); -+ -+ printk("%s: Setting MAC address to ", dev->name); -+ for (i = 0; i < 6; i++) { -+ printk(" %2.2x", dev->dev_addr[i]); -+ } -+ printk(".\n"); -+ -+ if (memcmp(dev->vlan_dev->real_dev->dev_addr, dev->dev_addr, dev->addr_len) != 0) { -+ if (dev->vlan_dev->real_dev->flags & IFF_PROMISC) { -+ /* Already promiscious...leave it alone. */ -+ printk("VLAN (%s): Good, underlying device (%s) is already promiscious.\n", -+ dev->name, dev->vlan_dev->real_dev->name); -+ } -+ else { -+ int flgs = dev->vlan_dev->real_dev->flags; -+ printk("VLAN (%s): Setting underlying device (%s) to promiscious mode.\n", -+ dev->name, dev->vlan_dev->real_dev->name); -+ flgs |= IFF_PROMISC; -+ dev_change_flags(dev->vlan_dev->real_dev, flgs); -+ /* This should work, but doesn't: -+ dev_set_promiscuity(dev->vlan_dev->real_dev, 1); -+ */ -+ } -+ } -+ else { -+ printk("VLAN (%s): Underlying device (%s) has same MAC, not checking promiscious mode.\n", -+ dev->name, dev->vlan_dev->real_dev->name); -+ } -+ return 0; -+} -+ -+ -+/** Taken from Gleb + Lennert's VLAN code, and modified... */ -+void vlan_dev_set_multicast_list(struct device *vlan_dev) { -+ struct dev_mc_list *dmi; -+ struct device *real_dev; -+ int inc; -+ -+ if (vlan_dev && vlan_dev->vlan_dev) { -+ /* Then it's a real vlan device, as far as we can tell.. */ -+ real_dev = vlan_dev->vlan_dev->real_dev; -+ -+ /* compare the current promiscuity to the last promisc we had.. */ -+ inc = vlan_dev->promiscuity - vlan_dev->vlan_dev->old_promiscuity; -+ -+ if (inc) { -+ printk(KERN_INFO "vlan: dev_set_promiscuity(master, %d)\n", inc); -+ dev_set_promiscuity(real_dev, inc); /* found in dev.c */ -+ vlan_dev->vlan_dev->old_promiscuity = vlan_dev->promiscuity; -+ } -+ -+ inc = vlan_dev->allmulti - vlan_dev->vlan_dev->old_allmulti; -+ -+ if (inc) { -+ printk(KERN_INFO "vlan: dev_set_allmulti(master, %d)\n", inc); -+ dev_set_allmulti(real_dev, inc); /* dev.c */ -+ vlan_dev->vlan_dev->old_allmulti = vlan_dev->allmulti; -+ } -+ -+ /* looking for addresses to add to master's list */ -+ for (dmi = vlan_dev->mc_list; dmi!=NULL; dmi=dmi->next) { -+ if (vlan_should_add_mc(dmi, vlan_dev->vlan_dev->old_mc_list)) { -+ dev_mc_add(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); -+ printk(KERN_INFO "vlan: add %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address to master interface\n", -+ dmi->dmi_addr[0], -+ dmi->dmi_addr[1], -+ dmi->dmi_addr[2], -+ dmi->dmi_addr[3], -+ dmi->dmi_addr[4], -+ dmi->dmi_addr[5]); -+ } -+ } -+ -+ /* looking for addresses to delete from master's list */ -+ for (dmi = vlan_dev->mc_list; dmi!=NULL; dmi=dmi->next) { -+ if (vlan_should_add_mc(dmi, vlan_dev->mc_list)) { -+ /* if we think we should add it to the new list, then we should really -+ * delete it from the real list on the underlying device. -+ */ -+ dev_mc_delete(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); -+ printk(KERN_INFO "vlan: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n", -+ dmi->dmi_addr[0], -+ dmi->dmi_addr[1], -+ dmi->dmi_addr[2], -+ dmi->dmi_addr[3], -+ dmi->dmi_addr[4], -+ dmi->dmi_addr[5]); -+ } -+ } -+ -+ /* save multicast list */ -+ vlan_copy_mc_list(vlan_dev->mc_list, vlan_dev->vlan_dev); -+ }/* if we were sent a valid device */ -+}/* vlan_dev_set_multicast */ -+ -+ -+/** dmi is a single entry into a dev_mc_list, a single node. mc_list is -+ * an entire list, and we'll iterate through it. -+ */ -+int vlan_should_add_mc(struct dev_mc_list *dmi, struct dev_mc_list *mc_list) { -+ struct dev_mc_list *idmi; /* iterator */ -+ -+ for (idmi=mc_list; idmi!=NULL;) { -+ if (vlan_dmi_equals(dmi, idmi)) { -+ if (dmi->dmi_users > idmi->dmi_users) -+ return 1; -+ else -+ return 0; -+ } -+ else { -+ idmi = idmi->next; -+ } -+ } -+ -+ return 1; -+} -+ -+ -+void vlan_copy_mc_list(struct dev_mc_list *mc_list, struct vlan_dev_info *vlan_info) { -+ struct dev_mc_list *dmi, *new_dmi; -+ -+ vlan_destroy_mc_list(vlan_info->old_mc_list); -+ vlan_info->old_mc_list = NULL; -+ -+ for (dmi=mc_list; dmi!=NULL; dmi=dmi->next) { -+ new_dmi = kmalloc(sizeof(*new_dmi), GFP_KERNEL); -+ if (new_dmi == NULL) { -+ printk(KERN_ERR "vlan: cannot allocate memory. Multicast may not work properly from now.\n"); -+ return; -+ } -+ -+ new_dmi->next = vlan_info->old_mc_list; -+ vlan_info->old_mc_list = new_dmi; -+ -+ new_dmi->dmi_addrlen = dmi->dmi_addrlen; -+ memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); -+ new_dmi->dmi_users = dmi->dmi_users; -+ new_dmi->dmi_gusers = dmi->dmi_gusers; -+ } -+} -+ -+void vlan_flush_mc_list(struct device *dev) { -+ struct dev_mc_list *dmi = dev->mc_list; -+ -+ while (dmi) { -+ dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); -+ printk(KERN_INFO "vlan: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n", -+ dmi->dmi_addr[0], -+ dmi->dmi_addr[1], -+ dmi->dmi_addr[2], -+ dmi->dmi_addr[3], -+ dmi->dmi_addr[4], -+ dmi->dmi_addr[5]); -+ dmi = dev->mc_list; -+ } -+ -+ vlan_destroy_mc_list(dev->mc_list); -+ if (dev->vlan_dev) { -+ vlan_destroy_mc_list(dev->vlan_dev->old_mc_list); -+ dev->vlan_dev->old_mc_list = NULL; -+ } -+ dev->mc_list = NULL; -+}/* vlan_flush_mc_list */ -diff -Nurb linux/net/802_1Q/vlanproc.c linux.p/net/802_1Q/vlanproc.c ---- linux/net/802_1Q/vlanproc.c Thu Jan 1 01:00:00 1970 -+++ linux.p/net/802_1Q/vlanproc.c Mon Jun 4 16:08:04 2001 -@@ -0,0 +1,654 @@ -+/* * -*- linux-c -*- */ -+/***************************************************************************** -+ * vlanproc.c VLAN Module. /proc filesystem interface. -+ * -+ * Author: Ben Greear, <greearb@candelatech.com> coppied from wanproc.c -+ * by: Gene Kozin <genek@compuserve.com> -+ * -+ * Copyright: (c) 1998-2000 Ben Greear -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ * ============================================================================ -+ * Jan 20, 1998 Ben Greear Initial Version -+ *****************************************************************************/ -+ -+#include <linux/config.h> -+#include <linux/stddef.h> /* offsetof(), etc. */ -+#include <linux/errno.h> /* return codes */ -+#include <linux/kernel.h> -+#include <linux/malloc.h> /* kmalloc(), kfree() */ -+#include <linux/mm.h> /* verify_area(), etc. */ -+#include <linux/string.h> /* inline mem*, str* functions */ -+#include <linux/init.h> /* __initfunc et al. */ -+#include <asm/segment.h> /* kernel <-> user copy */ -+#include <asm/byteorder.h> /* htons(), etc. */ -+#include <asm/uaccess.h> /* copy_to_user */ -+#include <asm/io.h> -+#include <linux/proc_fs.h> -+#include <linux/fs.h> -+#include <linux/netdevice.h> -+#include <linux/if_vlan.h> -+#include "vlanproc.h" -+#include "vlan.h" -+ -+/****** Defines and Macros **************************************************/ -+ -+#ifndef min -+#define min(a,b) (((a)<(b))?(a):(b)) -+#endif -+#ifndef max -+#define max(a,b) (((a)>(b))?(a):(b)) -+#endif -+ -+ -+/****** Function Prototypes *************************************************/ -+ -+#ifdef CONFIG_PROC_FS -+ -+/* Proc filesystem interface */ -+static int vlan_proc_perms(struct inode *, int); -+static ssize_t vlan_proc_read(struct file* file, char* buf, size_t count, -+ loff_t *ppos); -+ -+/* Methods for preparing data for reading proc entries */ -+ -+static int vlan_config_get_info(char* buf, char** start, off_t offs, int len, -+ int dummy); -+static int vlandev_get_info(char* buf, char** start, off_t offs, int len, -+ int dummy); -+ -+ -+/* Miscellaneous */ -+ -+/* -+ * Global Data -+ */ -+ -+/* -+ * Names of the proc directory entries -+ */ -+ -+static char name_root[] = "vlan"; -+static char name_conf[] = "config"; -+static char term_msg[] = "***KERNEL: Out of buffer space!***\n"; -+ -+ -+/* -+ * VLAN device IOCTL. -+ * o execute requested action or pass command to the device driver -+ */ -+ -+int vlan_ioctl(struct inode* inode, struct file* file, -+ unsigned int cmd, unsigned long arg) { -+ int err = 0; -+ /* -+ struct proc_dir_entry* dent; -+ struct device* dev; -+ */ -+ struct vlan_ioctl_args args; -+ -+ printk(VLAN_DBG __FUNCTION__ ": cmd: %x\n", cmd); -+ -+ /* everything here needs root permissions, except aguably the -+ * hack ioctls for sending packets. However, I know _I_ don't -+ * want users running that on my network! --BLG -+ */ -+ if (!capable(CAP_NET_ADMIN)){ -+ return -EPERM; -+ } -+ -+ if ((cmd >> 8) != VLAN_IOCTL) { -+ printk(VLAN_DBG __FUNCTION__ ": Not a VLAN IOCTL: %x \n", cmd); -+ return -EINVAL; -+ } -+ -+ if (copy_from_user(&args, (void*)arg, sizeof(struct vlan_ioctl_args))) -+ return -EFAULT; -+ -+ /* Null terminate this sucker, just in case. */ -+ args.dev1[23] = 0; -+ args.u.dev2[23] = 0; -+ -+ /* -+ dent = inode->u.generic_ip; -+ if ((dent == NULL) || (dent->data == NULL)) -+ return -EINVAL; -+ -+ dev = dent->data; -+ */ -+ -+ switch (cmd) -+ { -+ case SET_INGRESS_PRIORITY_IOCTL: -+ err = vlan_dev_set_ingress_priority(args.dev1, args.u.skb_priority, args.vlan_qos); -+ break; -+ -+ case SET_EGRESS_PRIORITY_IOCTL: -+ err = vlan_dev_set_egress_priority(args.dev1, args.u.skb_priority, args.vlan_qos); -+ break; -+ -+ case SET_VLAN_FLAG_IOCTL: -+ err = vlan_dev_set_vlan_flag(args.dev1, args.u.flag, args.vlan_qos); -+ break; -+ -+ case SET_NAME_TYPE_IOCTL: -+ if ((args.u.name_type >= 0) && (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) { -+ vlan_name_type = args.u.name_type; -+ err = 0; -+ } -+ else { -+ err = -EINVAL; -+ } -+ break; -+ -+ /* TODO: Figure out how to pass info back... -+ case GET_INGRESS_PRIORITY_IOCTL: -+ err = vlan_dev_get_ingress_priority(args); -+ break; -+ -+ case GET_EGRESS_PRIORITY_IOCTL: -+ err = vlan_dev_get_egress_priority(args); -+ break; -+ */ -+ -+ case ADD_VLAN_IOCTL: -+ /* we have been given the name of the Ethernet Device we want to -+ * talk to: args.dev1 We also have the -+ * VLAN ID: args.u.VID -+ */ -+ if (register_802_1Q_vlan_device(args.dev1, args.u.VID)) { -+ err = 0; -+ } -+ else { -+ err = -EINVAL; -+ } -+ break; -+ -+ case DEL_VLAN_IOCTL: -+ /* Here, the args.dev1 is the actual VLAN we want to get rid of. */ -+ -+ err = unregister_802_1Q_vlan_device(args.dev1); -+ break; -+ -+ default: -+ /* pass on to underlying device instead?? */ -+ printk(VLAN_DBG __FUNCTION__ ": Unknown VLAN IOCTL: %x \n", cmd); -+ return -EINVAL; -+ }/* switch */ -+ return err; -+} -+ -+/* -+ * Structures for interfacing with the /proc filesystem. -+ * VLAN creates its own directory /proc/net/vlan with the folowing -+ * entries: -+ * config device status/configuration -+ * <device> entry for each device -+ */ -+ -+/* -+ * Generic /proc/net/vlan/<file> file and inode operations -+ */ -+ -+static struct file_operations vlan_fops = { -+ NULL, /* lseek */ -+ vlan_proc_read, /* read */ -+ NULL, /* write */ -+ NULL, /* readdir */ -+ NULL, /* select */ -+ vlan_ioctl, /* ioctl */ -+ NULL, /* mmap */ -+ NULL, /* no special open code */ -+ NULL, /* flush */ -+ NULL, /* no special release code */ -+ NULL /* can't fsync */ -+}; -+ -+static struct inode_operations vlan_inode = { -+ &vlan_fops, -+ NULL, /* create */ -+ NULL, /* lookup */ -+ NULL, /* link */ -+ NULL, /* unlink */ -+ NULL, /* symlink */ -+ NULL, /* mkdir */ -+ NULL, /* rmdir */ -+ NULL, /* mknod */ -+ NULL, /* rename */ -+ NULL, /* follow link */ -+ NULL, /* readlink */ -+ NULL, /* readpage */ -+ NULL, /* writepage */ -+ NULL, /* bmap */ -+ NULL, /* truncate */ -+ vlan_proc_perms -+}; -+ -+/* -+ * /proc/net/vlan/<device> file and inode operations -+ */ -+ -+static struct file_operations vlandev_fops = { -+ NULL, /* lseek */ -+ vlan_proc_read, /* read */ -+ NULL, /* write */ -+ NULL, /* readdir */ -+ NULL, /* select */ -+ vlan_ioctl, /* ioctl */ -+ NULL, /* mmap */ -+ NULL, /* no special open code */ -+ NULL, /* flush */ -+ NULL, /* no special release code */ -+ NULL /* can't fsync */ -+}; -+ -+static struct inode_operations vlandev_inode = { -+ &vlandev_fops, -+ NULL, /* create */ -+ NULL, /* lookup */ -+ NULL, /* link */ -+ NULL, /* unlink */ -+ NULL, /* symlink */ -+ NULL, /* mkdir */ -+ NULL, /* rmdir */ -+ NULL, /* mknod */ -+ NULL, /* rename */ -+ NULL, /* readlink */ -+ NULL, /* follow_link */ -+ NULL, /* readpage */ -+ NULL, /* writepage */ -+ NULL, /* bmap */ -+ NULL, /* truncate */ -+ vlan_proc_perms -+}; -+ -+ -+/* -+ * Proc filesystem derectory entries. -+ */ -+ -+/* -+ * /proc/net/vlan -+ */ -+ -+static struct proc_dir_entry proc_vlan = { -+ 0, /* .low_ino */ -+ sizeof(name_root) - 1, /* .namelen */ -+ name_root, /* .name */ -+ 0555 | S_IFDIR, /* .mode */ -+ 2, /* .nlink */ -+ 0, /* .uid */ -+ 0, /* .gid */ -+ 0, /* .size */ -+ &proc_dir_inode_operations, /* .ops */ -+ NULL, /* .get_info */ -+ NULL, /* .fill_node */ -+ NULL, /* .next */ -+ NULL, /* .parent */ -+ NULL, /* .subdir */ -+ NULL, /* .data */ -+}; -+ -+/* -+ * /proc/net/vlan/config -+ */ -+ -+static struct proc_dir_entry proc_vlan_conf = { -+ 0, /* .low_ino */ -+ sizeof(name_conf) - 1, /* .namelen */ -+ name_conf, /* .name */ -+ 0444 | S_IFREG, /* .mode */ -+ 1, /* .nlink */ -+ 0, /* .uid */ -+ 0, /* .gid */ -+ 0, /* .size */ -+ &vlan_inode, /* .ops */ -+ &vlan_config_get_info, /* .get_info */ -+ NULL, /* .fill_node */ -+ NULL, /* .next */ -+ NULL, /* .parent */ -+ NULL, /* .subdir */ -+ NULL, /* .data */ -+}; -+ -+ -+/* Strings */ -+static char conf_hdr[] = "VLAN Dev name | VLAN ID\n"; -+ -+ -+/* -+ * Interface functions -+ */ -+ -+/* -+ * Initialize vlan proc interface. -+ */ -+ -+__initfunc(int vlan_proc_init (void)) { -+ int err = proc_register(proc_net, &proc_vlan); -+ -+ if (!err) { -+ proc_register(&proc_vlan, &proc_vlan_conf); -+ } -+ return err; -+} -+ -+/* -+ * Clean up router proc interface. -+ */ -+ -+void vlan_proc_cleanup (void) { -+ proc_unregister(&proc_vlan, proc_vlan_conf.low_ino); -+ proc_unregister(proc_net, proc_vlan.low_ino); -+} -+ -+ -+/* -+ * Add directory entry for VLAN device. -+ */ -+ -+int vlan_proc_add_dev (struct device* vlandev) { -+ if (!vlandev->vlan_dev) { -+ printk(KERN_ERR "ERROR: vlan_proc_add, device -:%s:- is NOT a VLAN\n", -+ vlandev->name); -+ return -EINVAL; -+ } -+ -+ memset(&(vlandev->vlan_dev->dent), 0, sizeof(vlandev->vlan_dev->dent)); -+ vlandev->vlan_dev->dent.namelen = strlen(vlandev->name); -+ vlandev->vlan_dev->dent.name = vlandev->name; -+ vlandev->vlan_dev->dent.mode = 0444 | S_IFREG; -+ vlandev->vlan_dev->dent.nlink = 1; -+ vlandev->vlan_dev->dent.ops = &vlandev_inode; -+ vlandev->vlan_dev->dent.get_info = &vlandev_get_info; -+ vlandev->vlan_dev->dent.data = vlandev; -+ -+#ifdef VLAN_DEBUG -+ printk(KERN_ERR "vlan_proc_add, device -:%s:- being added.\n", -+ vlandev->name); -+#endif -+ -+ return proc_register(&proc_vlan, &vlandev->vlan_dev->dent); -+} -+ -+ -+ -+/* -+ * Delete directory entry for VLAN device. -+ */ -+int vlan_proc_rem_dev(struct device* vlandev) { -+ if (!vlandev || !vlandev->vlan_dev) { -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": invalid argument: %p\n", vlandev); -+#endif -+ return -EINVAL; -+ } -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": calling proc_unregister for dev: %p\n", -+ vlandev); -+#endif -+ return proc_unregister(&proc_vlan, vlandev->vlan_dev->dent.low_ino); -+} -+ -+ -+/****** Proc filesystem entry points ****************************************/ -+ -+/* -+ * Verify access rights. -+ */ -+ -+static int vlan_proc_perms (struct inode* inode, int op) { -+ return 0; -+} -+ -+/* -+ * Read VLAN proc directory entry. -+ * This is universal routine for reading all entries in /proc/net/vlan -+ * directory. Each directory entry contains a pointer to the 'method' for -+ * preparing data for that entry. -+ * o verify arguments -+ * o allocate kernel buffer -+ * o call get_info() to prepare data -+ * o copy data to user space -+ * o release kernel buffer -+ * -+ * Return: number of bytes copied to user space (0, if no data) -+ * <0 error -+ */ -+static ssize_t vlan_proc_read(struct file* file, char* buf, size_t count, -+ loff_t *ppos) { -+ struct inode *inode = file->f_dentry->d_inode; -+ struct proc_dir_entry* dent; -+ char* page; -+ int pos, offs, len; -+ -+ if (count <= 0) -+ return 0; -+ -+ dent = inode->u.generic_ip; -+ if ((dent == NULL) || (dent->get_info == NULL)) -+ return 0; -+ -+ page = kmalloc(VLAN_PROC_BUFSZ, GFP_KERNEL); -+ VLAN_MEM_DBG("page malloc, addr: %p size: %i\n", page, VLAN_PROC_BUFSZ); -+ -+ if (page == NULL) -+ return -ENOBUFS; -+ -+ pos = dent->get_info(page, dent->data, 0, 0, 0); -+ offs = file->f_pos; -+ if (offs < pos) { -+ len = min(pos - offs, count); -+ if (copy_to_user(buf, (page + offs), len)) { -+ return -EFAULT; -+ } -+ file->f_pos += len; -+ } -+ else { -+ len = 0; -+ } -+ -+ kfree(page); -+ VLAN_FMEM_DBG("page free, addr: %p\n", page); -+ return len; -+}/* vlan_proc_read */ -+ -+ -+static int vlan_proc_get_vlan_info(char* buf, unsigned int cnt) { -+ struct device* vlandev = NULL; -+ struct vlan_group* grp = NULL; -+ int i = 0; -+ char* nm_type = NULL; -+ -+ printk(VLAN_DBG __FUNCTION__ ": cnt == %i\n", cnt); -+ -+ if (vlan_name_type == VLAN_NAME_TYPE_RAW_PLUS_VID) { -+ nm_type = "VLAN_NAME_TYPE_RAW_PLUS_VID"; -+ } -+ else if (vlan_name_type == VLAN_NAME_TYPE_PLUS_VID_NO_PAD) { -+ nm_type = "VLAN_NAME_TYPE_PLUS_VID_NO_PAD"; -+ } -+ else if (vlan_name_type == VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD) { -+ nm_type = "VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD"; -+ } -+ else if (vlan_name_type == VLAN_NAME_TYPE_PLUS_VID) { -+ nm_type = "VLAN_NAME_TYPE_PLUS_VID"; -+ } -+ else { -+ nm_type = "UNKNOWN"; -+ } -+ -+ cnt += sprintf(buf + cnt, "Name-Type: %s bad_proto_recvd: %lu\n", -+ nm_type, vlan_bad_proto_recvd); -+ -+ for (grp = p802_1Q_vlan_list; grp != NULL; grp = grp->next) { -+ /* loop through all devices for this device */ -+ printk(VLAN_DBG __FUNCTION__ ": found a group, addr: %p\n", grp); -+ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { -+ /* printk(VLAN_DBG __FUNCTION__ ": checking index[%i]\n", i); */ -+ if ((vlandev = grp->vlan_devices[i])) { -+ printk(VLAN_DBG __FUNCTION__ ": found a vlan_dev, addr: %p\n", vlandev); -+ if ((cnt + 100) > VLAN_PROC_BUFSZ) { -+ if ((cnt + strlen(term_msg)) >= VLAN_PROC_BUFSZ) { -+ /* should never get here */ -+ return cnt; -+ } -+ else { -+ cnt += sprintf(buf + cnt, "%s", term_msg); -+ return cnt; -+ } -+ }/* if running out of buffer space */ -+ else { -+ if (!vlandev->vlan_dev) { -+ printk(KERN_ERR __FUNCTION__ ": ERROR: vlandev->vlan_dev is NULL\n"); -+ } -+ else { -+ printk(VLAN_DBG __FUNCTION__ ": got a good vlandev, addr: %p\n", vlandev->vlan_dev); -+ cnt += sprintf(buf + cnt, "%-15s| %d | %s\n", -+ vlandev->name, vlandev->vlan_dev->vlan_id, vlandev->vlan_dev->real_dev->name); -+ }/* else */ -+ }/* else */ -+ }/* if we have a vlan of this number */ -+ }/* for all VLAN's */ -+ }/* for each vlan group, default is only one.*/ -+ -+ return cnt; -+}/* vlan_proc_get_vlan_info */ -+ -+/* -+ * Prepare data for reading 'Config' entry. -+ * Return length of data. -+ */ -+ -+static int vlan_config_get_info(char* buf, char** start, off_t offs, int len, -+ int dummy) { -+ strcpy(buf, conf_hdr); -+ return vlan_proc_get_vlan_info(buf, (unsigned int)(strlen(conf_hdr))); -+} -+ -+ -+/* -+ * Prepare data for reading <device> entry. -+ * Return length of data. -+ * -+ * On entry, the 'start' argument will contain a pointer to VLAN device -+ * data space. -+ */ -+ -+static int vlandev_get_info(char* buf, char** start, off_t offs, int len, -+ int dummy) { -+ struct device* vlandev = (void*)start; -+ struct net_device_stats* stats; -+ int cnt = 0; -+ struct vlan_priority_tci_mapping* mp; -+ int i; -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": vlandev: %p\n", vlandev); -+#endif -+ -+ if ((vlandev == NULL) || (!vlandev->vlan_dev)) { -+ return 0; -+ } -+ -+ cnt += sprintf(buf + cnt, "%s VID: %d REORDER_HDR: %i\n", -+ vlandev->name, vlandev->vlan_dev->vlan_id, (int)(vlandev->vlan_dev->flags & 1)); -+ stats = (struct net_device_stats*)(vlandev->priv); -+ -+ cnt += sprintf(buf + cnt, "%30s: %12lu\n", -+ "total frames received", stats->rx_packets); -+ -+ cnt += sprintf(buf + cnt, "%30s: %12lu\n", -+ "total bytes received", stats->rx_bytes); -+ -+ cnt += sprintf(buf + cnt, "%30s: %12lu\n", -+ "Broadcast/Multicast Rcvd", stats->multicast); -+ -+ cnt += sprintf(buf + cnt, "\n%30s: %12lu\n", -+ "total frames transmitted", stats->tx_packets); -+ -+ cnt += sprintf(buf + cnt, "%30s: %12lu\n", -+ "total bytes transmitted", stats->tx_bytes); -+ -+ cnt += sprintf(buf + cnt, "%30s: %12lu\n", -+ "total headroom inc", vlandev->vlan_dev->cnt_inc_headroom_on_tx); -+ -+ cnt += sprintf(buf + cnt, "%30s: %12lu\n", -+ "total encap on xmit", vlandev->vlan_dev->cnt_encap_on_xmit); -+ -+ cnt += sprintf(buf + cnt, "Device: %s", vlandev->vlan_dev->real_dev->name); -+ -+ /* now show all PRIORITY mappings relating to this VLAN */ -+ cnt += sprintf(buf + cnt, "\nINGRESS priority mappings: 0:%lu 1:%lu 2:%lu 3:%lu 4:%lu 5:%lu 6:%lu 7:%lu\n", -+ vlandev->vlan_dev->ingress_priority_map[0], -+ vlandev->vlan_dev->ingress_priority_map[1], -+ vlandev->vlan_dev->ingress_priority_map[2], -+ vlandev->vlan_dev->ingress_priority_map[3], -+ vlandev->vlan_dev->ingress_priority_map[4], -+ vlandev->vlan_dev->ingress_priority_map[5], -+ vlandev->vlan_dev->ingress_priority_map[6], -+ vlandev->vlan_dev->ingress_priority_map[7]); -+ -+ cnt += sprintf(buf + cnt, "EGRESSS priority Mappings: "); -+ -+ for (i = 0; i<16; i++) { -+ mp = vlandev->vlan_dev->egress_priority_map[i]; -+ while (mp) { -+ cnt += sprintf(buf + cnt, "%lu:%hu ", mp->priority, ((mp->vlan_qos >> 13) & 0x7)); -+ -+ if ((cnt + 100) > VLAN_PROC_BUFSZ) { -+ if ((cnt + strlen(term_msg)) >= VLAN_PROC_BUFSZ) { -+ /* should never get here */ -+ return cnt; -+ } -+ else { -+ cnt += sprintf(buf + cnt, "%s", term_msg); -+ return cnt; -+ } -+ }/* if running out of buffer space */ -+ mp = mp->next; -+ } -+ }/* for */ -+ -+ cnt += sprintf(buf + cnt, "\n"); -+ -+ return cnt; -+} -+ -+ -+/* -+ * End -+ */ -+ -+#else -+ -+/* -+ * No /proc - output stubs -+ */ -+ -+__initfunc(int vlan_proc_init(void)) -+{ -+ return 0; -+} -+ -+void vlan_proc_cleanup(void) -+{ -+ return; -+} -+ -+ -+int vlan_proc_add_dev(struct device *vlandev) -+{ -+ return 0; -+} -+ -+int vlan_proc_rem_dev(struct device *vlandev) -+{ -+ return 0; -+} -+ -+#endif -diff -Nurb linux/net/802_1Q/vlanproc.h linux.p/net/802_1Q/vlanproc.h ---- linux/net/802_1Q/vlanproc.h Thu Jan 1 01:00:00 1970 -+++ linux.p/net/802_1Q/vlanproc.h Mon Jun 4 16:08:04 2001 -@@ -0,0 +1,27 @@ -+ -+#ifndef __BEN_VLAN_PROC_INC__ -+#define __BEN_VLAN_PROC_INC__ -+ -+ -+int vlan_proc_init(void); -+ -+int vlan_proc_rem_dev(struct device* vlandev); -+int vlan_proc_add_dev (struct device* vlandev); -+void vlan_proc_cleanup (void); -+ -+ -+#define VLAN_PROC_BUFSZ (4096) /* buffer size for printing proc info */ -+ -+/****** Data Types **********************************************************/ -+ -+/* -+typedef struct vlan_stat_entry { -+ struct vlan_stat_entry * next; -+ char *description; * description string * -+ void *data; * -> data * -+ unsigned data_type; * data type * -+} vlan_stat_entry_t; -+*/ -+ -+ -+#endif -diff -Nurb linux/net/Config.in linux.p/net/Config.in ---- linux/net/Config.in Mon Jun 4 17:48:17 2001 -+++ linux.p/net/Config.in Mon Jun 4 16:08:04 2001 -@@ -51,6 +51,9 @@ - # if [ "$CONFIG_LLC" = "y" ]; then - # bool 'Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI - # fi -+ -+ tristate '802.1Q VLAN Support (EXPERIMENTAL)' CONFIG_VLAN_802_1Q -+ - tristate 'Acorn Econet/AUN protocols (EXPERIMENTAL)' CONFIG_ECONET - if [ "$CONFIG_ECONET" != "n" ]; then - bool ' AUN over UDP' CONFIG_ECONET_AUNUDP -diff -Nurb linux/net/Makefile linux.p/net/Makefile ---- linux/net/Makefile Mon Jun 4 17:48:17 2001 -+++ linux.p/net/Makefile Mon Jun 4 16:08:04 2001 -@@ -10,7 +10,7 @@ - MOD_SUB_DIRS := ipv4 - ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \ - netrom rose lapb x25 wanrouter netlink sched packet sunrpc \ -- econet irda #decnet -+ econet irda 802_1Q #decnet - SUB_DIRS := core ethernet sched - MOD_LIST_NAME := NET_MISC_MODULES - -@@ -59,6 +59,14 @@ - - ifeq ($(CONFIG_BRIDGE),y) - SUB_DIRS += bridge -+endif -+ -+ifeq ($(CONFIG_VLAN_802_1Q),y) -+SUB_DIRS += 802_1Q -+else -+ ifeq ($(CONFIG_VLAN_802_1Q),m) -+ MOD_SUB_DIRS += 802_1Q -+ endif - endif - - ifeq ($(CONFIG_IPX),y) -diff -Nurb linux/net/core/dev.c linux.p/net/core/dev.c ---- linux/net/core/dev.c Sun Mar 25 18:37:41 2001 -+++ linux.p/net/core/dev.c Mon Jun 4 16:08:04 2001 -@@ -94,6 +94,9 @@ - #ifdef CONFIG_NET_RADIO - #include <linux/wireless.h> - #endif /* CONFIG_NET_RADIO */ -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) -+#include "../802_1Q/vlan.h" -+#endif /* CONFIG_VLAN_802_1Q ... */ - #ifdef CONFIG_PLIP - extern int plip_init(void); - #endif -@@ -125,6 +128,13 @@ - * Why 16. Because with 16 the only overlap we get on a hash of the - * low nibble of the protocol value is RARP/SNAP/X.25. - * -+ * NOTE: That is no longer true with the addition of VLAN tags. Not -+ * sure which should go first, but I bet it won't make much -+ * difference if we are running VLANs. The good news is that -+ * this protocol won't be in the list unless compiled in, so -+ * the average user (w/out VLANs) will not be adversly affected. -+ * --BLG -+ * - * 0800 IP - * 0001 802.3 - * 0002 AX.25 -@@ -133,6 +143,7 @@ - * 0005 SNAP - * 0805 X.25 - * 0806 ARP -+ * 8100 802.1Q VLAN - * 8137 IPX - * 0009 Localtalk - * 86DD IPv6 -@@ -170,6 +181,257 @@ - static void dev_clear_backlog(struct device *dev); - - -+/* Taking this out, because lo has problems for some people. Feel -+ * free to turn it back on and give me (greearb@candelatech.com) bug -+ * reports if you can re-produce the problem. --Ben -+ * -+ * #define BENS_FAST_DEV_LOOKUP -+ * -+ */ -+ -+#ifdef BENS_FAST_DEV_LOOKUP -+/* Fast Device Lookup code. Should give much better than -+ * linear speed when looking for devices by idx or name. -+ * --Ben (greearb@candelatech.com) -+ */ -+#define FDL_HASH_LEN 256 -+ -+/* #define FDL_DEBUG */ -+ -+struct dev_hash_node { -+ struct device* dev; -+ struct dev_hash_node* next; -+}; -+ -+struct dev_hash_node* fdl_name_base[FDL_HASH_LEN];/* hashed by name */ -+struct dev_hash_node* fdl_idx_base[FDL_HASH_LEN]; /* hashed by index */ -+int fdl_initialized_yet = 0; -+ -+/* TODO: Make these inline methods */ -+/* Nice cheesy little hash method to be used on device-names (eth0, ppp0, etc) */ -+int fdl_calc_name_idx(const char* dev_name) { -+ int tmp = 0; -+ int i; -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "fdl_calc_name_idx, name: %s\n", dev_name); -+#endif -+ for (i = 0; dev_name[i]; i++) { -+ tmp += (int)(dev_name[i]); -+ } -+ if (i > 3) { -+ tmp += (dev_name[i-2] * 10); /* might add a little spread to the hash */ -+ tmp += (dev_name[i-3] * 100); /* might add a little spread to the hash */ -+ } -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "fdl_calc_name_idx, rslt: %i\n", (int)(tmp % FDL_HASH_LEN)); -+#endif -+ return (tmp % FDL_HASH_LEN); -+} -+ -+int fdl_calc_index_idx(const int ifindex) { -+ return (ifindex % FDL_HASH_LEN); -+} -+ -+ -+/* Better have a lock on the dev_base before calling this... */ -+int __fdl_ensure_init(void) { -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_ensure_init, enter\n"); -+#endif -+ if (! fdl_initialized_yet) { -+ /* only do this once.. */ -+ int i; -+ int idx = 0; /* into the hash table */ -+ struct device* dev = dev_base; -+ struct dev_hash_node* dhn; -+ -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_ensure_init, doing real work..."); -+#endif -+ -+ fdl_initialized_yet = 1; /* it has been attempted at least... */ -+ -+ for (i = 0; i<FDL_HASH_LEN; i++) { -+ fdl_name_base[i] = NULL; -+ fdl_idx_base[i] = NULL; -+ } -+ -+ /* add any current devices to the hash tables at this time. Note that -+ * this method must be called with locks on the dev_base acquired. -+ */ -+ while (dev) { -+ -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_ensure_init, dev: %p dev: %s, idx: %i\n", dev, dev->name, idx); -+#endif -+ /* first, take care of the hash-by-name */ -+ idx = fdl_calc_name_idx(dev->name); -+ dhn = kmalloc(sizeof(struct dev_hash_node), GFP_ATOMIC); -+ if (dhn) { -+ dhn->dev = dev; -+ dhn->next = fdl_name_base[idx]; -+ fdl_name_base[idx] = dhn; -+ } -+ else { -+ /* Nasty..couldn't get memory... */ -+ return -ENOMEM; -+ } -+ -+ /* now, do the hash-by-idx */ -+ idx = fdl_calc_index_idx(dev->ifindex); -+ dhn = kmalloc(sizeof(struct dev_hash_node), GFP_ATOMIC); -+ if (dhn) { -+ dhn->dev = dev; -+ dhn->next = fdl_idx_base[idx]; -+ fdl_idx_base[idx] = dhn; -+ } -+ else { -+ /* Nasty..couldn't get memory... */ -+ return -ENOMEM; -+ } -+ -+ dev = dev->next; -+ } -+ fdl_initialized_yet = 2; /* initialization actually worked */ -+ } -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_ensure_init, end, fdl_initialized_yet: %i\n", fdl_initialized_yet); -+#endif -+ if (fdl_initialized_yet == 2) { -+ return 0; -+ } -+ else { -+ return -1; -+ } -+}/* fdl_ensure_init */ -+ -+ -+/* called from register_netdevice, assumes dev is locked, and that no one -+ * will be calling __find_dev_by_name before this exits.. etc. -+ */ -+int __fdl_register_netdevice(struct device* dev) { -+ if (__fdl_ensure_init() == 0) { -+ /* first, take care of the hash-by-name */ -+ int idx = fdl_calc_name_idx(dev->name); -+ struct dev_hash_node* dhn = kmalloc(sizeof(struct dev_hash_node), GFP_ATOMIC); -+ -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_register_netdevice, dev: %p dev: %s, idx: %i", dev, dev->name, idx); -+#endif -+ -+ if (dhn) { -+ dhn->dev = dev; -+ dhn->next = fdl_name_base[idx]; -+ fdl_name_base[idx] = dhn; -+ } -+ else { -+ /* Nasty..couldn't get memory... */ -+ /* Don't try to use these hash tables any more... */ -+ fdl_initialized_yet = 1; /* tried, but failed */ -+ return -ENOMEM; -+ } -+ -+ /* now, do the hash-by-idx */ -+ idx = fdl_calc_index_idx(dev->ifindex); -+ dhn = kmalloc(sizeof(struct dev_hash_node), GFP_ATOMIC); -+ -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_register_netdevice, ifindex: %i, idx: %i", dev->ifindex, idx); -+#endif -+ -+ if (dhn) { -+ dhn->dev = dev; -+ dhn->next = fdl_idx_base[idx]; -+ fdl_idx_base[idx] = dhn; -+ } -+ else { -+ /* Nasty..couldn't get memory... */ -+ /* Don't try to use these hash tables any more... */ -+ fdl_initialized_yet = 1; /* tried, but failed */ -+ return -ENOMEM; -+ } -+ } -+ return 0; -+} /* fdl_register_netdevice */ -+ -+ -+/* called from register_netdevice, assumes dev is locked, and that no one -+ * will be calling __find_dev_by_name, etc. Returns 0 if found & removed one, -+ * returns -1 otherwise. -+ */ -+int __fdl_unregister_netdevice(struct device* dev) { -+ int retval = -1; -+ if (fdl_initialized_yet == 2) { /* If we've been initialized correctly... */ -+ /* first, take care of the hash-by-name */ -+ int idx = fdl_calc_name_idx(dev->name); -+ struct dev_hash_node* prev = fdl_name_base[idx]; -+ struct dev_hash_node* cur = NULL; -+ -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_unregister_netdevice, dev: %p dev: %s, idx: %i", dev, dev->name, idx); -+#endif -+ -+ if (prev) { -+ if (strcmp(dev->name, prev->dev->name) == 0) { -+ /* it's the first one... */ -+ fdl_name_base[idx] = prev->next; -+ kfree(prev); -+ retval = 0; -+ } -+ else { -+ cur = prev->next; -+ while (cur) { -+ if (strcmp(dev->name, cur->dev->name) == 0) { -+ prev->next = cur->next; -+ kfree(cur); -+ retval = 0; -+ break; -+ } -+ else { -+ prev = cur; -+ cur = cur->next; -+ } -+ } -+ } -+ } -+ -+ /* Now, the hash-by-index */ -+ idx = fdl_calc_index_idx(dev->ifindex); -+ prev = fdl_idx_base[idx]; -+ cur = NULL; -+ if (prev) { -+ if (dev->ifindex == prev->dev->ifindex) { -+ /* it's the first one... */ -+ fdl_idx_base[idx] = prev->next; -+ kfree(prev); -+ retval = 0; -+ } -+ else { -+ cur = prev->next; -+ while (cur) { -+ if (dev->ifindex == cur->dev->ifindex) { -+ prev->next = cur->next; -+ kfree(cur); -+ retval = 0; -+ break; -+ } -+ else { -+ prev = cur; -+ cur = cur->next; -+ } -+ } -+ } -+ } -+ }/* if we ensured init OK */ -+ return retval; -+} /* fdl_unregister_netdevice */ -+ -+ -+ -+#endif /* BENS_FAST_DEV_LOOKUP */ -+ -+ -+ - /****************************************************************************************** - - Protocol management and registration routines -@@ -267,6 +529,26 @@ - { - struct device *dev; - -+#ifdef BENS_FAST_DEV_LOOKUP -+ int idx = fdl_calc_name_idx(name); -+ struct dev_hash_node* dhn; -+ if (fdl_initialized_yet == 2) { -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__dev_get_by_name, name: %s idx: %i\n", name, idx); -+#endif -+ dhn = fdl_name_base[idx]; -+ while (dhn) { -+ if (strcmp(dhn->dev->name, name) == 0) { -+ /* printk(KERN_ERR "__dev_get_by_name, found it: %p\n", dhn->dev); */ -+ return dhn->dev; -+ } -+ dhn = dhn->next; -+ } -+ /* printk(KERN_ERR "__dev_get_by_name, didn't find it for name: %s\n", name); */ -+ return NULL; -+ } -+#endif /* BENS_FAST_DEV_LOOKUP */ -+ - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (strcmp(dev->name, name) == 0) -@@ -279,6 +561,20 @@ - { - struct device *dev; - -+#ifdef BENS_FAST_DEV_LOOKUP -+ int idx = fdl_calc_index_idx(ifindex); -+ struct dev_hash_node* dhn; -+ if (fdl_initialized_yet == 2) { /* have we gone through initialization before... */ -+ dhn = fdl_idx_base[idx]; -+ while (dhn) { -+ if (dhn->dev->ifindex == ifindex) -+ return dhn->dev; -+ dhn = dhn->next; -+ } -+ return NULL; -+ } -+#endif /* BENS_FAST_DEV_LOOKUP */ -+ - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (dev->ifindex == ifindex) -@@ -310,14 +606,17 @@ - int i; - /* - * If you need over 100 please also fix the algorithm... -+ * -+ * Increased it to deal with VLAN interfaces. It is unlikely -+ * that this many will ever be added, but it can't hurt! -BLG - */ -- for(i=0;i<100;i++) -+ for(i=0;i<8192;i++) - { - sprintf(dev->name,name,i); - if(dev_get(dev->name)==NULL) - return i; - } -- return -ENFILE; /* Over 100 of the things .. bail out! */ -+ return -ENFILE; /* Over 8192 of the things .. bail out! */ - } - - struct device *dev_alloc(const char *name, int *err) -@@ -1603,8 +1902,15 @@ - return -EBUSY; - if (dev_get(ifr->ifr_newname)) - return -EEXIST; -+#ifdef BENS_FAST_DEV_LOOKUP -+ /* Doesn't seem to need any additional locking in kernel 2.2 series... --Ben */ -+ __fdl_unregister_netdevice(dev); /* take it out of the name hash table */ -+#endif /* BENS_FAST_DEV_LOOKUP */ - memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ); - dev->name[IFNAMSIZ-1] = 0; -+#ifdef BENS_FAST_DEV_LOOKUP -+ __fdl_register_netdevice(dev); /* put it back in the name hash table, with the new name */ -+#endif /* BENS_FAST_DEV_LOOKUP */ - notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); - return 0; - -@@ -1809,6 +2115,15 @@ - return -EEXIST; - } - dev->next = NULL; -+ -+#ifdef BENS_FAST_DEV_LOOKUP -+ /* Must do this before dp is set to dev, or it could be added twice, -+ * once on initialization based on dev_base, and once again after -+ * that... -+ */ -+ __fdl_register_netdevice(dev); -+#endif /* BENS_FAST_DEV_LOOKUP */ -+ - *dp = dev; - #ifdef CONFIG_NET_DIVERT - ret=alloc_divert_blk(dev); -@@ -1834,6 +2149,13 @@ - dev->ifindex = dev_new_index(); - if (dev->iflink == -1) - dev->iflink = dev->ifindex; -+ -+#ifdef BENS_FAST_DEV_LOOKUP -+ /* Must do this before dp is set to dev, or it could be added twice, once -+ * on initialization based on dev_base, and once again after that... -+ */ -+ __fdl_register_netdevice(dev); -+#endif /* BENS_FAST_DEV_LOOKUP */ - *dp = dev; - - /* Notify protocols, that a new device appeared. */ -@@ -1885,6 +2207,9 @@ - for (dp = &dev_base; (d=*dp) != NULL; dp=&d->next) { - if (d == dev) { - *dp = d->next; -+#ifdef BENS_FAST_DEV_LOOKUP -+ __fdl_unregister_netdevice(dev); -+#endif /* BENS_FAST_DEV_LOOKUP */ - synchronize_bh(); - d->next = NULL; - -diff -Nurb linux/net/ethernet/eth.c linux.p/net/ethernet/eth.c ---- linux/net/ethernet/eth.c Sun Mar 25 18:31:12 2001 -+++ linux.p/net/ethernet/eth.c Mon Jun 4 16:08:04 2001 -@@ -174,6 +174,9 @@ - * Determine the packet's protocol ID. The rule here is that we - * assume 802.3 if the type field is short enough to be a length. - * This is normal practice and works for any 'now in use' protocol. -+ * -+ * NOTE: It is likely that you will want to change vlan_type_trans in -+ * 802_1Q/vlan.c if you change anything here. - */ - - unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev) -@@ -182,7 +185,19 @@ - unsigned char *rawp; - - skb->mac.raw=skb->data; -+ -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) -+ /* Moving this below to be more selective. Reason is that for VLAN -+ * devices, we do not want to pull the header, we'll let the VLAN -+ * device do that instead. This makes default vlans (based on incoming -+ * port), much more sane! --BLG -+ */ -+ -+ /* skb_pull(skb,dev->hard_header_len); */ -+#else - skb_pull(skb,dev->hard_header_len); -+#endif /* CONFIG_VLAN_802_1Q ... */ -+ - eth= skb->mac.ethernet; - - if(*eth->h_dest&1) -@@ -207,6 +222,20 @@ - skb->pkt_type=PACKET_OTHERHOST; - } - -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) -+ if (ntohs(eth->h_proto) == ETH_P_802_1Q) { -+ /* then we have to convert this into a VLAN looking packet. -+ * We'll wait to do that in the VLAN protocol handler. -+ * -+ * NOTE: We DO NOT PULL ANYTHING FROM THE SKB HERE!!! -+ */ -+ return __constant_htons(ETH_P_802_1Q); -+ } -+ else { -+ skb_pull(skb, dev->hard_header_len); -+ } -+#endif /* CONFIG_VLAN_802_1Q ... */ -+ - if (ntohs(eth->h_proto) >= 1536) - return eth->h_proto; - -diff -Nurb linux/net/netsyms.c linux.p/net/netsyms.c ---- linux/net/netsyms.c Mon Jun 4 17:48:17 2001 -+++ linux.p/net/netsyms.c Mon Jun 4 17:39:36 2001 -@@ -403,6 +403,12 @@ - EXPORT_SYMBOL(rtnl_lock); - EXPORT_SYMBOL(rtnl_unlock); - -+#if defined(CONFIG_VLAN_802_1Q_MODULE) -+extern struct Qdisc noqueue_qdisc; -+EXPORT_SYMBOL(noqueue_qdisc); -+EXPORT_SYMBOL(dev_change_flags); -+EXPORT_SYMBOL(eth_header_parse); -+#endif - - /* Used by at least ipip.c. */ - EXPORT_SYMBOL(ipv4_config); -@@ -533,7 +539,6 @@ - #include<linux/if_ltalk.h> - EXPORT_SYMBOL(ltalk_setup); - #endif -- - - /* Packet scheduler modules want these. */ - EXPORT_SYMBOL(qdisc_destroy); -diff -Nurb linux/net/protocols.c linux.p/net/protocols.c ---- linux/net/protocols.c Sun Mar 25 18:31:11 2001 -+++ linux.p/net/protocols.c Mon Jun 4 16:08:04 2001 -@@ -34,6 +34,10 @@ - extern void packet_proto_init(struct net_proto *pro); - #endif - -+#ifdef CONFIG_VLAN_802_1Q -+extern void vlan_proto_init(struct net_proto* pro); -+#endif -+ - #if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE) - #define NEED_802 - #include <net/ipxcall.h> -@@ -169,5 +173,9 @@ - { "IrDA", irda_proto_init }, /* IrDA protocols */ - #endif - -+#ifdef CONFIG_VLAN_802_1Q -+ { "VLAN", vlan_proto_init }, /* 802.1Q VLAN Support. --BLG */ -+#endif -+ - { NULL, NULL } /* End marker */ - }; diff --git a/contrib/vlan_2.2-module.patch b/contrib/vlan_2.2-module.patch deleted file mode 100644 index f4c4bd0..0000000 --- a/contrib/vlan_2.2-module.patch +++ /dev/null @@ -1,495 +0,0 @@ -diff -Nurb linux/include/linux/if_ether.h linux.p/include/linux/if_ether.h ---- linux/include/linux/if_ether.h Mon Jun 4 17:51:51 2001 -+++ linux.p/include/linux/if_ether.h Mon Jun 4 16:10:17 2001 -@@ -33,8 +33,7 @@ - #define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ - - --#ifdef CONFIG_VLAN_802_1Q -- -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) - - #define VLAN_ETH_ALEN 6 /* Octets in one ethernet addr */ - #define VLAN_ETH_HLEN 18 /* Total octets in header. */ -@@ -58,9 +57,7 @@ - unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */ - }; - -- --#endif -- -+#endif /* CONFIG_VLAN_802_1Q ... */ - - /* - * These are the defined Ethernet Protocol ID's. -diff -Nurb linux/include/linux/netdevice.h linux.p/include/linux/netdevice.h ---- linux/include/linux/netdevice.h Mon Jun 4 17:51:51 2001 -+++ linux.p/include/linux/netdevice.h Mon Jun 4 16:10:48 2001 -@@ -37,14 +37,11 @@ - #ifdef CONFIG_NET_PROFILE - #include <net/profile.h> - #endif -- --#if (defined(CONFIG_VLAN_802_1Q)) --struct vlan_dev_info; --#endif -- - #endif - -- -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) -+struct vlan_dev_info; -+#endif /* CONFIG_VLAN_802_1Q ... */ - - struct divert_blk; - -@@ -60,11 +57,11 @@ - */ - - #if !defined(CONFIG_AX25) && !defined(CONFIG_AX25_MODULE) && !defined(CONFIG_TR) --#if defined(CONFIG_VLAN_802_1Q) -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) - #define LL_MAX_HEADER 36 - #else - #define LL_MAX_HEADER 32 --#endif -+#endif /* CONFIG_VLAN_802_1Q ... */ - #else - #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - #define LL_MAX_HEADER 96 -@@ -168,17 +165,16 @@ - atomic_t hh_refcnt; /* number of users */ - unsigned short hh_type; /* protocol identifier, f.e ETH_P_IP - * NOTE: For VLANs, this will be the -- * encapuslated type. --BLG -+ * encapsulated type. --BLG - */ - int (*hh_output)(struct sk_buff *skb); - rwlock_t hh_lock; -- - /* cached hardware header; allow for machine alignment needs. */ --#ifdef CONFIG_VLAN_802_1Q /* we need 4 extra bytes for VLAN headers */ -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) /* we need 4 extra bytes for VLAN headers */ - unsigned long hh_data[20/sizeof(unsigned long)]; - #else - unsigned long hh_data[16/sizeof(unsigned long)]; --#endif -+#endif /* CONFIG_VLAN_802_1Q ... */ - }; - - -@@ -336,14 +332,13 @@ - int tx_semaphore; - #define NETDEV_FASTROUTE_HMASK 0xF - /* Semi-private data. Keep it at the end of device struct. */ -- - struct dst_entry *fastpath[NETDEV_FASTROUTE_HMASK+1]; - #endif - --#ifdef CONFIG_VLAN_802_1Q -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) - /* Holds information that makes sense if this device is a VLAN device. */ - struct vlan_dev_info* vlan_dev; --#endif -+#endif /* CONFIG_VLAN_802_1Q ... */ - - #ifdef CONFIG_NET_DIVERT - /* this will get initialized at each interface type init routine */ -diff -Nurb linux/net/802_1Q/Makefile linux.p/net/802_1Q/Makefile ---- linux/net/802_1Q/Makefile Mon Jun 4 17:51:51 2001 -+++ linux.p/net/802_1Q/Makefile Mon Jun 4 16:08:04 2001 -@@ -1,5 +1,5 @@ - # --# Makefile for the Linux Ethernet layer. -+# Makefile for the Linux 802.1q protocol layer - # - # Note! Dependencies are done automagically by 'make dep', which also - # removes any old dependencies. DON'T put your own dependencies here -@@ -8,19 +8,14 @@ - # Note 2! The CFLAGS definition is now in the main makefile... - - O_TARGET := 802_1Q.o -+O_OBJS := vlan.o vlanproc.o vlan_dev.o - --OBJS := vlan.o vlanproc.o vlan_dev.o -- --ifeq ($(CONFIG_SYSCTL),y) --OBJS += sysctl_net_vlan.o -+ifeq ($(CONFIG_VLAN_802_1Q),m) -+M_OBJS := $(O_TARGET) - endif - -- --ifdef CONFIG_NET --O_OBJS := $(OBJS) $(OBJ2) -+ifeq ($(CONFIG_SYSCTL),y) -+O_OBJS += sysctl_net_vlan.o - endif - - include $(TOPDIR)/Rules.make -- --tar: -- tar -cvf /dev/f1 . -diff -Nurb linux/net/802_1Q/sysctl_net_vlan.c linux.p/net/802_1Q/sysctl_net_vlan.c ---- linux/net/802_1Q/sysctl_net_vlan.c Mon Jun 4 17:51:51 2001 -+++ linux.p/net/802_1Q/sysctl_net_vlan.c Mon Jun 4 16:08:04 2001 -@@ -6,7 +6,7 @@ - * TODO: What, if anything, should this do?? - */ - --#ifdef CONFIG_VLAN_802_1Q -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) - - #include <linux/mm.h> - #include <linux/sysctl.h> -@@ -15,4 +15,4 @@ - {0} - }; - --#endif -+#endif /* CONFIG_VLAN_802_1Q ... */ -diff -Nurb linux/net/802_1Q/vlan.c linux.p/net/802_1Q/vlan.c ---- linux/net/802_1Q/vlan.c Mon Jun 4 17:51:51 2001 -+++ linux.p/net/802_1Q/vlan.c Mon Jun 4 17:46:31 2001 -@@ -81,8 +81,6 @@ - * Context: process - */ - int init_module (void) { -- printk(VLAN_INF __FUNCTION__); -- - vlan_proto_init(NULL); - return 0; - } -@@ -92,7 +90,8 @@ - * o delete /proc/net/router directory and static entries. - */ - void cleanup_module (void) { -- vlan_proto_cleanup(); // TODO: Define this so modules work. -+ dev_remove_pack(&vlan_packet_type); -+ vlan_proc_cleanup(); - } - - #else -@@ -100,11 +99,8 @@ - - /** Non-module init entry point. */ - __initfunc(void vlan_system_init(void)) { -- printk(VLAN_INF __FUNCTION__); -- - /* protocol initialization */ - vlan_proto_init(NULL); -- - } - #endif - -@@ -205,6 +201,7 @@ - * NOTE: This deletes dev, don't access it again!! - */ - unregister_netdevice(dev); -+ MOD_DEC_USE_COUNT; - - }/* if */ - }/* if */ -@@ -438,6 +435,7 @@ - /* printk(KERN_ALERT "Registering new device."); */ - register_netdevice(new_dev); - vlan_proc_add_dev(new_dev); /* create it's proc entry */ -+ MOD_INC_USE_COUNT; /* Add was a success!! */ - return new_dev; - } - }//if -diff -Nurb linux/net/802_1Q/vlan_dev.c linux.p/net/802_1Q/vlan_dev.c ---- linux/net/802_1Q/vlan_dev.c Mon Jun 4 17:51:51 2001 -+++ linux.p/net/802_1Q/vlan_dev.c Mon Jun 4 16:08:04 2001 -@@ -18,7 +18,6 @@ - */ - - #include <asm/uaccess.h> /* for copy_from_user */ --#include <linux/module.h> - #include <linux/netdevice.h> - #include <linux/skbuff.h> - #include <net/datalink.h> -diff -Nurb linux/net/802_1Q/vlanproc.c linux.p/net/802_1Q/vlanproc.c ---- linux/net/802_1Q/vlanproc.c Mon Jun 4 17:51:51 2001 -+++ linux.p/net/802_1Q/vlanproc.c Mon Jun 4 16:08:04 2001 -@@ -1,19 +1,19 @@ - /* * -*- linux-c -*- */ - /***************************************************************************** - * vlanproc.c VLAN Module. /proc filesystem interface. --* --* Author: Ben Greear, <greearb@candelatech.com> coppied from wanproc.c --* by: Gene Kozin <genek@compuserve.com> --* --* Copyright: (c) 1998-2000 Ben Greear --* --* This program is free software; you can redistribute it and/or --* modify it under the terms of the GNU General Public License --* as published by the Free Software Foundation; either version --* 2 of the License, or (at your option) any later version. --* ============================================================================ --* Jan 20, 1998 Ben Greear Initial Version --*****************************************************************************/ -+ * -+ * Author: Ben Greear, <greearb@candelatech.com> coppied from wanproc.c -+ * by: Gene Kozin <genek@compuserve.com> -+ * -+ * Copyright: (c) 1998-2000 Ben Greear -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ * ============================================================================ -+ * Jan 20, 1998 Ben Greear Initial Version -+ *****************************************************************************/ - - #include <linux/config.h> - #include <linux/stddef.h> /* offsetof(), etc. */ -diff -Nurb linux/net/Config.in linux.p/net/Config.in ---- linux/net/Config.in Mon Jun 4 17:51:51 2001 -+++ linux.p/net/Config.in Mon Jun 4 16:08:04 2001 -@@ -48,12 +48,12 @@ - fi - bool 'Frame Diverter (EXPERIMENTAL)' CONFIG_NET_DIVERT - bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC -- -- bool '802.1Q VLAN Support (EXPERIMENTAL)' CONFIG_VLAN_802_1Q -- - # if [ "$CONFIG_LLC" = "y" ]; then - # bool 'Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI - # fi -+ -+ tristate '802.1Q VLAN Support (EXPERIMENTAL)' CONFIG_VLAN_802_1Q -+ - tristate 'Acorn Econet/AUN protocols (EXPERIMENTAL)' CONFIG_ECONET - if [ "$CONFIG_ECONET" != "n" ]; then - bool ' AUN over UDP' CONFIG_ECONET_AUNUDP -diff -Nurb linux/net/Makefile linux.p/net/Makefile ---- linux/net/Makefile Mon Jun 4 17:51:51 2001 -+++ linux.p/net/Makefile Mon Jun 4 16:08:04 2001 -@@ -63,6 +63,10 @@ - - ifeq ($(CONFIG_VLAN_802_1Q),y) - SUB_DIRS += 802_1Q -+else -+ ifeq ($(CONFIG_VLAN_802_1Q),m) -+ MOD_SUB_DIRS += 802_1Q -+ endif - endif - - ifeq ($(CONFIG_IPX),y) -diff -Nurb linux/net/core/dev.c linux.p/net/core/dev.c ---- linux/net/core/dev.c Mon Jun 4 17:51:51 2001 -+++ linux.p/net/core/dev.c Mon Jun 4 16:08:04 2001 -@@ -1,4 +1,4 @@ --/* -*- linux-c -*- -+/* - * NET3 Protocol independent device support routines. - * - * This program is free software; you can redistribute it and/or -@@ -94,11 +94,9 @@ - #ifdef CONFIG_NET_RADIO - #include <linux/wireless.h> - #endif /* CONFIG_NET_RADIO */ -- --#ifdef CONFIG_VLAN_802_1Q -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) - #include "../802_1Q/vlan.h" --#endif -- -+#endif /* CONFIG_VLAN_802_1Q ... */ - #ifdef CONFIG_PLIP - extern int plip_init(void); - #endif -@@ -138,7 +136,6 @@ - * --BLG - * - * 0800 IP -- * 8100 802.1Q VLAN - * 0001 802.3 - * 0002 AX.25 - * 0004 802.2 -@@ -146,6 +143,7 @@ - * 0005 SNAP - * 0805 X.25 - * 0806 ARP -+ * 8100 802.1Q VLAN - * 8137 IPX - * 0009 Localtalk - * 86DD IPv6 -@@ -186,10 +184,11 @@ - /* Taking this out, because lo has problems for some people. Feel - * free to turn it back on and give me (greearb@candelatech.com) bug - * reports if you can re-produce the problem. --Ben -+ * -+ * #define BENS_FAST_DEV_LOOKUP -+ * -+ */ - -- #define BENS_FAST_DEV_LOOKUP -- --*/ - #ifdef BENS_FAST_DEV_LOOKUP - /* Fast Device Lookup code. Should give much better than - * linear speed when looking for devices by idx or name. -@@ -548,7 +547,8 @@ - /* printk(KERN_ERR "__dev_get_by_name, didn't find it for name: %s\n", name); */ - return NULL; - } --#endif -+#endif /* BENS_FAST_DEV_LOOKUP */ -+ - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (strcmp(dev->name, name) == 0) -@@ -560,6 +560,7 @@ - struct device * dev_get_by_index(int ifindex) - { - struct device *dev; -+ - #ifdef BENS_FAST_DEV_LOOKUP - int idx = fdl_calc_index_idx(ifindex); - struct dev_hash_node* dhn; -@@ -572,7 +573,8 @@ - } - return NULL; - } --#endif -+#endif /* BENS_FAST_DEV_LOOKUP */ -+ - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (dev->ifindex == ifindex) -@@ -1127,7 +1129,7 @@ - if(skb==NULL) - return; - -- offset = skb->data - skb->mac.raw; -+ offset=skb->data-skb->mac.raw; - skb_push(skb,offset); /* Put header back on for bridge */ - - if(br_receive_frame(skb)) -@@ -1253,7 +1255,7 @@ - } - - /* -- * Fetch the packet protocol ID. (In Network Byte Order --BLG) -+ * Fetch the packet protocol ID. - */ - - type = skb->protocol; -@@ -1903,12 +1905,12 @@ - #ifdef BENS_FAST_DEV_LOOKUP - /* Doesn't seem to need any additional locking in kernel 2.2 series... --Ben */ - __fdl_unregister_netdevice(dev); /* take it out of the name hash table */ --#endif -+#endif /* BENS_FAST_DEV_LOOKUP */ - memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ); - dev->name[IFNAMSIZ-1] = 0; - #ifdef BENS_FAST_DEV_LOOKUP - __fdl_register_netdevice(dev); /* put it back in the name hash table, with the new name */ --#endif -+#endif /* BENS_FAST_DEV_LOOKUP */ - notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); - return 0; - -@@ -2113,12 +2115,15 @@ - return -EEXIST; - } - dev->next = NULL; -+ - #ifdef BENS_FAST_DEV_LOOKUP -- /* Must do this before dp is set to dev, or it could be added twice, once -- * on initialization based on dev_base, and once again after that... -+ /* Must do this before dp is set to dev, or it could be added twice, -+ * once on initialization based on dev_base, and once again after -+ * that... - */ - __fdl_register_netdevice(dev); --#endif -+#endif /* BENS_FAST_DEV_LOOKUP */ -+ - *dp = dev; - #ifdef CONFIG_NET_DIVERT - ret=alloc_divert_blk(dev); -@@ -2150,7 +2155,7 @@ - * on initialization based on dev_base, and once again after that... - */ - __fdl_register_netdevice(dev); --#endif -+#endif /* BENS_FAST_DEV_LOOKUP */ - *dp = dev; - - /* Notify protocols, that a new device appeared. */ -@@ -2204,7 +2209,7 @@ - *dp = d->next; - #ifdef BENS_FAST_DEV_LOOKUP - __fdl_unregister_netdevice(dev); --#endif -+#endif /* BENS_FAST_DEV_LOOKUP */ - synchronize_bh(); - d->next = NULL; - -diff -Nurb linux/net/ethernet/eth.c linux.p/net/ethernet/eth.c ---- linux/net/ethernet/eth.c Mon Jun 4 17:51:51 2001 -+++ linux.p/net/ethernet/eth.c Mon Jun 4 16:08:04 2001 -@@ -186,7 +186,7 @@ - - skb->mac.raw=skb->data; - --#ifdef CONFIG_VLAN_802_1Q -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) - /* Moving this below to be more selective. Reason is that for VLAN - * devices, we do not want to pull the header, we'll let the VLAN - * device do that instead. This makes default vlans (based on incoming -@@ -196,7 +196,7 @@ - /* skb_pull(skb,dev->hard_header_len); */ - #else - skb_pull(skb,dev->hard_header_len); --#endif -+#endif /* CONFIG_VLAN_802_1Q ... */ - - eth= skb->mac.ethernet; - -@@ -222,7 +222,7 @@ - skb->pkt_type=PACKET_OTHERHOST; - } - --#ifdef CONFIG_VLAN_802_1Q -+#if (defined(CONFIG_VLAN_802_1Q) || defined(CONFIG_VLAN_802_1Q_MODULE)) - if (ntohs(eth->h_proto) == ETH_P_802_1Q) { - /* then we have to convert this into a VLAN looking packet. - * We'll wait to do that in the VLAN protocol handler. -@@ -234,7 +234,7 @@ - else { - skb_pull(skb, dev->hard_header_len); - } --#endif -+#endif /* CONFIG_VLAN_802_1Q ... */ - - if (ntohs(eth->h_proto) >= 1536) - return eth->h_proto; -diff -Nurb linux/net/netsyms.c linux.p/net/netsyms.c ---- linux/net/netsyms.c Mon Jun 4 17:48:17 2001 -+++ linux.p/net/netsyms.c Mon Jun 4 17:39:36 2001 -@@ -403,6 +403,12 @@ - EXPORT_SYMBOL(rtnl_lock); - EXPORT_SYMBOL(rtnl_unlock); - -+#if defined(CONFIG_VLAN_802_1Q_MODULE) -+extern struct Qdisc noqueue_qdisc; -+EXPORT_SYMBOL(noqueue_qdisc); -+EXPORT_SYMBOL(dev_change_flags); -+EXPORT_SYMBOL(eth_header_parse); -+#endif - - /* Used by at least ipip.c. */ - EXPORT_SYMBOL(ipv4_config); -@@ -533,7 +539,6 @@ - #include<linux/if_ltalk.h> - EXPORT_SYMBOL(ltalk_setup); - #endif -- - - /* Packet scheduler modules want these. */ - EXPORT_SYMBOL(qdisc_destroy); diff --git a/debian/changelog b/debian/changelog index f7437f0..2971634 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,18 @@ +vlan (2.0) experimental; urgency=medium + + * Non-maintainer upload. + * Make this a native package and replace the previous upstream source + with Andrew Shaduras vconfig compatibility script. (Closes: #501402) + * Update package description to better describe this package content. + * Rewrite debian/rules + * Bump Standards-Version to 3.9.6 + * Update debian/network/ contents to not rely on vconfig. + - in preparation for potentian future dropping vconfig compat script. + * Update debian/copyright for the new package content. + * Make vconfig always print a deprecated notice to stderr when executed. + + -- Andreas Henriksson <andreas@fatal.se> Wed, 06 Jan 2016 18:42:14 +0100 + vlan (1.9-3.2) unstable; urgency=medium * Non-maintainer upload. diff --git a/debian/compat b/debian/compat index 7ed6ff8..ec63514 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -5 +9 diff --git a/debian/control b/debian/control index 4fd484c..a2f8273 100644 --- a/debian/control +++ b/debian/control @@ -3,8 +3,8 @@ Section: misc Priority: extra Maintainer: Ard van Breemen <ard@kwaak.net> Uploaders: Loic Minier <lool@dooz.org> -Build-Depends: debhelper (>= 5) -Standards-Version: 3.7.2 +Build-Depends: debhelper (>= 9) +Standards-Version: 3.9.6 XS-Vcs-Git: git://git.debian.org/git/collab-maint/vlan.git XS-Vcs-Browser: http://git.debian.org/?p=collab-maint/vlan.git @@ -12,13 +12,20 @@ Package: vlan Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, iproute2 Section: misc -Description: user mode programs to enable VLANs on your ethernet devices - This package contains the user mode programs you need to add and remove - VLAN devices from your ethernet devices. +Description: ifupdown integration for vlan configuration + This package contains integration scripts for configuring vlan + interfaces via ifupdown (/etc/network/interfaces). + For further details see vlan-interfaces(5) man page in this package. . - A typical application for a VLAN enabled box is a single wire firewall, - router or load balancer. + Please note that these integration scripts only supports a limited + set of interface naming schemes, which means you might be better + off with writing your own ifupdown hooks using ip(route2) + directly in /etc/network/interfaces rather than using this package. . - You need a VLAN Linux kernel for this. Linux kernel versions >= 2.4.14 - have VLAN support. - + It currently also ships a wrapper script for backwards compatibility + called vconfig, that replaces the old deprecated vconfig program + with translations to ip(route2) commands. + This compatibility shim might be dropped in future releases, please + use ip(route2) commands directly. + . + Your kernel needs vlan support for this to work, see "modinfo 8021q". diff --git a/debian/copyright b/debian/copyright index 48846f2..79409c7 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,68 +1,20 @@ -This package was downloaded from http://www.candelatech.com/~greear/vlan.html +The current native package replaces obsoleted vlan utilities (vconfig, etc) +previously available from http://www.candelatech.com/~greear/vlan.html -Files: candela_2.4.21.patch -Copyright: © 1994 University of Cambridge Computer Laboratory -Copyright: © 2001-2003 Alex Zeffertt, Cambridge Broadband Ltd <ajz@cambridgebroadband.com> -Copyright: © 2002 Ben Greear <greearb@candelatech.com> +Files: vconfig +Copyright: 2013 Andrew Shadura License: GPL-2+ - This program is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free Software - Foundation; either version 2 of the License, or (at your option) any later - version. - -Files: contrib/vlan_2.2-full.patch, contrib/vlan_2.2-module.patch -Copyright: © 1998-2000 Ben Greear <greearb@candelatech.com> -Copyright: © Gene Kozin <genek@compuserve.com> -License: GPL-2+ - This program is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free Software - Foundation; either version 2 of the License, or (at your option) any later - version. +Note: originally from https://bitbucket.org/andrew_shadura/fake-vconfig/raw/2e8c89b663965814a6734439b52710c0ebcea7a6/vconfig Files: debian/* Copyright: © 2001-2005 Ard van Breemen <ard@kwaak.net> Copyright: © 2005-2007 Loic Minier <lool@dooz.org> +Copyright: 2016 Andreas Henriksson <andreas@fatal.se> License: GPL-compatible -Files: howto.html -Copyright: © Kristjan Kotkas <kristjan@data.ee> -Copyright: © Ben Greear <greearb@candelatech.com> - -Files: macvlan_config.c -Copyright: © 2001 Alex Zeffertt, Cambridge Broadband Ltd <ajz@cambridgebroadband.com> -License: GPL-2+ - This program is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free Software - Foundation; either version 2 of the License, or (at your option) any later - version. - Files: vconfig.8 Copyright: © Ard van Breemen <ard@kwaak.net> -Files: vconfig.c, vconfig.h -Copyright: © 2001 Ben Greear <greearb@candelatech.com> -License: GPL-2+ - This program is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free Software - Foundation; either version 2 of the License, or (at your option) any later - version. - -Files: vconfig.spec -Copyright: © 2001-2002 Dale Bewley <dale@bewley.net> - -Files: vlan_2.2.patch -Copyright: © 1998-2000, 2002 Ben Greear <greearb@candelatech.com> -Copyright: © Gene Kozin <genek@compuserve.com> -License: GPL-2+ - This program is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free Software - Foundation; either version 2 of the License, or (at your option) any later - version. - -Files: howto.html -Copyright: © 1999-2001, 2003 Ben Greear <greearb@candelatech.com> - -Files: * License: GPL-compatible When not otherwise specified, files are under a GPL compatible license. Many files lack licensing and copyright information, and this should be fixed with diff --git a/debian/docs b/debian/docs deleted file mode 100644 index 6f68529..0000000 --- a/debian/docs +++ /dev/null @@ -1,2 +0,0 @@ -howto.html -vlan.html diff --git a/debian/network/if-post-down.d/vlan b/debian/network/if-post-down.d/vlan index 73e3dd9..d2cb50a 100644 --- a/debian/network/if-post-down.d/vlan +++ b/debian/network/if-post-down.d/vlan @@ -27,8 +27,8 @@ case "$IFACE" in ;; esac -if [ ! -x /sbin/vconfig ]; then +if [ ! -x "$(which ip)" ]; then exit 0 fi -vconfig rem $IFACE +ip link del $IFACE || exit 4 diff --git a/debian/network/if-pre-up.d/vlan b/debian/network/if-pre-up.d/vlan index 1580fc2..39ecda4 100644 --- a/debian/network/if-pre-up.d/vlan +++ b/debian/network/if-pre-up.d/vlan @@ -2,45 +2,32 @@ # Most of this stuff is to enable vlans +STATEDIR=/run/network/vlan + case "$IFACE" in # Ignore any alias (#272891) which uses <interface>:<alabel> *:*) exit 0 ;; vlan0*) - vconfig set_name_type VLAN_PLUS_VID + #vconfig set_name_type VLAN_PLUS_VID + mkdir -p "$STATEDIR" && echo "VLAN_PLUS_VID" > "$STATEDIR/name-type" VLANID=`echo $IFACE|sed "s/vlan0*//"` ;; vlan*) - vconfig set_name_type VLAN_PLUS_VID_NO_PAD + #vconfig set_name_type VLAN_PLUS_VID_NO_PAD + mkdir -p "$STATEDIR" && echo "VLAN_PLUS_VID_NO_PAD" > "$STATEDIR/name-type" VLANID=`echo $IFACE|sed "s/vlan0*//"` ;; eth*.0*|bond*.0*|wlan*.0*) # Silently ignore interfaces which ifupdown handles on its own # If IF_BRIDGE_PORTS is set, probably we're called by bridge-utils [ -z "$IF_VLAN_RAW_DEVICE" -a -z "$IF_BRIDGE_PORTS" ] && exit 0 - vconfig set_name_type DEV_PLUS_VID - VLANID=`echo $IFACE|sed "s/eth[0-9][0-9]*\.0*//g;s/bond[0-9][0-9]*\.0*//;s/wlan[0-9][0-9]*\.0*//"` - IF_VLAN_RAW_DEVICE=`echo $IFACE|sed "s/\(eth[0-9][0-9]*\)\..*/\1/;s/\(bond[0-9][0-9]*\)\..*/\1/;s/\(wlan[0-9][0-9]*\)\..*/\1/"` - ;; - eth*.*|bond*.*|wlan*.*) - # Silently ignore interfaces which ifupdown handles on its own - # If IF_BRIDGE_PORTS is set, probably we're called by bridge-utils - [ -z "$IF_VLAN_RAW_DEVICE" -a -z "$IF_BRIDGE_PORTS" ] && exit 0 - vconfig set_name_type DEV_PLUS_VID_NO_PAD - VLANID=`echo $IFACE|sed "s/eth[0-9][0-9]*\.0*//g;s/bond[0-9][0-9]*\.0*//g;s/wlan[0-9][0-9]*\.0*//g"` - IF_VLAN_RAW_DEVICE=`echo $IFACE|sed "s/\(eth[0-9][0-9]*\)\..*/\1/;s/\(bond[0-9][0-9]*\)\..*/\1/;s/\(wlan[0-9][0-9]*\)\..*/\1/"` - ;; - *.0*) - # Silently ignore interfaces which we do not (know how to) support - [ -z "$IF_VLAN_RAW_DEVICE" ] && exit 0 - vconfig set_name_type DEV_PLUS_VID - VLANID=`echo $IFACE|sed "s/[^.]*\.0*//g"` - ;; - *.*) - # Silently ignore interfaces which we do not (know how to) support + #vconfig set_name_type DEV_PLUS_VID + mkdir -p "$STATEDIR" && echo "DEV_PLUS_VID" > "$STATEDIR/name-type" [ -z "$IF_VLAN_RAW_DEVICE" ] && exit 0 - vconfig set_name_type DEV_PLUS_VID_NO_PAD + #vconfig set_name_type DEV_PLUS_VID_NO_PAD + mkdir -p "$STATEDIR" && echo "DEV_PLUS_VID_NO_PAD" > "$STATEDIR/name-type" VLANID=`echo $IFACE|sed "s/[^.]*\.0*//g"` ;; @@ -50,7 +37,7 @@ case "$IFACE" in esac if [ -n "$IF_VLAN_RAW_DEVICE" ]; then - if [ ! -x /sbin/vconfig ]; then + if [ ! -x $(which ip) ]; then exit 0 fi if ! ip link show dev "$IF_VLAN_RAW_DEVICE" > /dev/null; then @@ -59,7 +46,25 @@ if [ -n "$IF_VLAN_RAW_DEVICE" ]; then fi if [ ! -e "/sys/class/net/$IFACE" ]; then ip link set up dev $IF_VLAN_RAW_DEVICE - vconfig add $IF_VLAN_RAW_DEVICE $VLANID + #vconfig add $IF_VLAN_RAW_DEVICE $VLANID + NAME_TYPE=DEV_PLUS_VID_NO_PAD + [ -r "$STATEDIR/name-type" ] && NAME_TYPE=$(cat "$STATEDIR/name-type") + case "$NAME_TYPE" in + VLAN_PLUS_VID) + NAME="$(printf vlan%.4d "$VLANID")" + ;; + VLAN_PLUS_VID_NO_PAD) + NAME="vlan$VLAN_ID" + ;; + DEV_PLUS_VID) + NAME="$(printf %s.%.4d "$IF_VLAN_RAW_DEVICE" "$VLANID")" + ;; + DEV_PLUS_VID_NO_PAD) + NAME="$IF_VLAN_RAW_DEVICE.$VLANID" + ;; + esac + ip link add link "$IF_VLAN_RAW_DEVICE" name "$NAME" \ + type vlan id "$VLANID" fi fi diff --git a/debian/rules b/debian/rules index 735776c..7f46fc6 100755 --- a/debian/rules +++ b/debian/rules @@ -1,38 +1,7 @@ #!/usr/bin/make -f +%: + dh $@ -CCFLAGS += -Wall -g -O$(if $(findstring noopt,$(DEB_BUILD_OPTIONS)),0,2) - -binary-arch: - dh_testdir - dh_testroot - dh_installdocs -s - dh_installman -s - dh_installchangelogs -s CHANGELOG - dh_install -s +override_dh_fixperms: + dh_fixperms chmod -R 755 debian/vlan/etc/network - dh_strip -s - dh_fixperms -s - dh_compress -s - dh_shlibdeps -s - dh_gencontrol -s - dh_installdeb -s - dh_md5sums -s - dh_builddeb -s - -build: - # upstream ships a macvlan_config binary - #mv -f macvlan_config macvlan_config.orig - # STRIP is to avoid the upstream stripping - $(MAKE) CCFLAGS="$(CCFLAGS)" STRIP=true - -clean: - # restore macvlan_config binary shipped by upstream - #-mv -f macvlan_config.orig macvlan_config - dh_clean - rm -f vconfig.h vconfig.o vconfig - -binary-indep: - -binary: binary-arch binary-indep - -.PHONY: binary binary-arch binary-indep clean diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..89ae9db --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/debian/vlan.install b/debian/vlan.install index c29eacf..75f45e2 100644 --- a/debian/vlan.install +++ b/debian/vlan.install @@ -1,3 +1,2 @@ debian/network etc vconfig sbin -#macvlan_config sbin diff --git a/howto.html b/howto.html deleted file mode 100644 index a23c180..0000000 --- a/howto.html +++ /dev/null @@ -1,1219 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> - <head> - <title>LINUX VLAN + Cisco HOWTO</title> - </head> - - <body bgcolor=#ffffff text=#000000> - <center><h1>LINUX VLAN + Cisco HOWTO</h1></center> -<P> -<center>0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0</center> -<pre> - - The Linux VLAN HOWTO - - VLAN Mailing list: <a href="mailto:vlan@candelatech.com">vlan@candelatech.com</a> - Kristjan Kotkas <a href="mailto:kristjan@data.ee">kristjan@data.ee</a> - Ben Greear <a href="mailto:greearb@candelatech.com">greearb@candelatech.com</a> - -</pre> -<P> - -<b>NOTE: If you can get ping to work, but telnet/http/ssh/etc hangs, then you most -likely have a driver that is broken with regard to 802.1Q vlans. There are various -patches for different drivers below. As a last ditch effort, you can set the MTU -on your VLAN interface to 1496 as opposed to 1500. If you are unaware of the -consequences of such a thing, please consider getting supported hardware and/or -ask the writer of your driver for a patch. --Ben -</b> -<P> -<h2>Contents</h2> -<ol> - <li><a href="#targ1">Who, why and where</a></li> - <li><a href="#targ2">Actual info on how to make it work.</a></li> - <li><a href="#targ3">Specific work-arounds/patches for certain configurations.</a> - <ul> - <li><a href="#tulip">Tulip driver patch.</a></li> - <li><a href="#eepro">eepro100 driver patch.</a></li> - <li><a href="#syskonnect">SysKonnect sk98lin driver patch.</a></li> - <li><a href="#3c59x">3c59X driver patch.</a></li> - <li><a href="#natsemi">natsemi driver patch.</a></li> - <li><a href="#3c905b">3c509b driver patch.</a></li> - <li><a href="#pcmcia">pcmcia drivers.</a></li> - </ul> - <li><a href="#targ4">Scripts and Recipes.</a></li> -</ol> -<P> - -<ol> - <li><a name="targ1">META</a> - <ol> - <li> - This is the first HOWTO for the "802.1Q VLAN implementation for Linux"<P> - - Homepage: <a href="http://scry.wanfear.com/~greear/vlan.html">http://scry.wanfear.com/~greear/vlan.html</a> - Mailing List: VLAN@Scry.WANfear.com - </li> - <P> - <li>Copyright<P> - - This document is part of the Linux HOWTO project. The copyright notice - is the following: Unless otherwise stated, Linux HOWTO documents are - copyrighted by their respective authors. Linux HOWTO documents may be - reproduced and distributed in whole or in part, in any medium physical - or electronic, as long as this copyright notice is retained on all - copies. Commercial redistribution is allowed and encouraged; however, - the author would like to be notified of any such distributions. All - translations, derivative works, or aggregate works incorporating any - Linux HOWTO documents must be covered under this copyright notice. - That is, you may not produce a derivative work from a HOWTO and impose - additional restrictions on its distribution. Exceptions to these rules - may be granted under certain conditions; please contact the Linux - HOWTO coordinator at the address given below. In short, we wish to - promote dissemination of this information through as many channels as - possible. However, we do wish to retain copyright on the HOWTO - documents, and would like to be notified of any plans to redistribute - the HOWTOs. If you have questions, please contact Tim Bynum, the Linux - HOWTO coordinator, at linux-howto@sunsite.unc.edu via email. - </li> - <P> - <li>Disclaimer<P> - - As usual: the author IS NOT responsible for any damage. For the correct - wording, see the relevant part of the GNU GPL 0.1.1 - </li> - <P> - <li>Credits<P> - - Thanks to Ben Greear <a href="http://www.candelatech.com/~greear">http://www.candelatech.com/~greear</a> - for the VLAN project and also to all the people who have contributed to the project. - </li> - <P> - <li>General<P> - - What is VLAN is not described in this document. Info on the VLAN protocol - can be found at - <a href="http://standards.ieee.org/getieee802/download/802.1Q-1998.pdf">http://standards.ieee.org/getieee802/download/802.1Q-1998.pdf</a>. - </li> - </ol> - </li> - <P> - <li><a name="targ2"><b>Software/Hardware (Cisco-specific setup, with some general info as well.)</b></a><P> - <ol> - <li>VLAN installation & Configuration on the Linux Side.<P> -<PRE> - -NOTE: This is fairly old. I'm leaving it in for historical reasons, but -be aware that VLAN is included in the later 2.4 kernels, so most folks do -NOT have to patch their kernel. --Ben - - -* Linux kernel 2.2.14 -* Vlan 0.0.10 Patched into it -* Cisco Catalyst 2900XL -* 3Com 3C509B NIC using patched driver 3c59x - - -Currently VLAN is not part of the kernel distribution so you need to patch -it into a supported Linux kernel and re-compile. - -You need the kernel source. If you don't have it already, you can get from -ftp.kernel.org or from one of its mirrors. If this scares you, read the -KERNEL-HOWTO. - -It is assumed that you have the linux kernel source extracted, and found at: -$HOME/linux If your setup is different, then some of these commands may -need to be slightly different. - -Download the VLAN package from the vlan homepage and extract it's contents. -tar -xvzf vlan*.tar.gz - -Go to the vlan directory, build the vlan tools by just typing: -make - -After this you get a programm named <vconfig>. This program manages all VLAN -specific configurations. - -Now patch the kernel. -Go to the linux directory -cd linux -(if you installed the kernel source from some rpm based distribution it is -something like /usr/src/linux) -patch the kernel by typing: - -patch -p 1 < $HOME/vlan/vlan.patch (patch is in the vlan directory) - -Time to compile your kernel. Use the make menuconfig command in your -linux directory to select your kernel options. The option related to -802.1Q VLANs is found under the Networking options. - -Additional help for kernel compilation can be found in KERNEL-HOWTO - -Assuming your kernel compiled cleanly, you are now ready to use it. -Install your kernel in the normal manner (fix up your /etc/lilo.conf file -appropriately and run lilo as root.) -Reboot your computer and choose your new kernel. - -As your computer comes back to life, there will be little sign that you are -now 802.1Q capable. -You should see something like this: - - 802.1Q VLAN Support v0.10 Ben Greear <greearb@candelatech.com> - vlan Initialization complete. - - -Your system is now vlan ready, lets configure some vlans: -I'm assuming that your VLAN capable network card is eth0. - -First, set the eth0 state to down: - -ifconfig eth0 down -</pre> - -<b>Ben's Note: Regarding the next section, you can run plain ethernet -and VLAN over the same NIC, but you may not want to..</b><pre> -Whatever your previous netconf was, you should move everything to vlans. -This means, that you don't set ip address to the real interface, but set it to -vlan interface. To set your eth0 with no ip: - -ifconfig eth0 0.0.0.0 up - -!note! -YOU MUST SET THE ETH0 TO UP, or it wont work. (ifconfig eth0 up) - -Add some vlans; goto your vlan directory where you previously compiled -vconfig and type: - -vconfig add eth0 2 - -! Little note about VLAN 1. In Cisco systems it is the default VLAN -so you MUST start using vlans from 2. - -This will create device vlan0002 to your system. Linux will think, that it -is just another network device, so you can configure it like any other. Also -you should see the interface by typing - -ifconfig -a - -Lets make some conf on the vlan then: -ifconfig -i vlan0002 10.0.231.1 broadcast 10.0.231.0 netmask 255.255.255.0 up - -This ends the configuration at the linux side. -</pre> -</li> -<P> -<li> Specific Extreme Networks Configuration<P><pre> - From: Craig Metz: cmetz@inner.net - -Extreme configuration example: - - create vlan v42 - config vlan v42 tag 42 - config vlan v42 add port 10 tagged - - ... will create a vlan named v42, whose 802.1Q tag is 42, and connect port -10 (tag 42) to that vlan. -</pre> -</li> -<P> -<li> Cisco-specific configuration<P> -<pre> -Cisco Conf -configure the port you want to use as the trunk: - -telnet switch or use the console port - -ena -(will prompt for password, so have it ready) - -conf t -interface FastEthernet0/24 (it doesnt have to be 0/24) - duplex full - speed 100 - switchport trunk encapsulation dot1q - switchport trunk allowed vlan 2 - switchport mode trunk - - -This conf will do the following: - -Set the port to full duplex mode; force the port to 100Mb mode; set the port -vlan encapsulation to support 802.1Q; tell the -switch that the port is allowed to run vlans through (even if you set just -VLAN 2, cisco will automatically add VLAN 1 and VLAN 1002-1005) to the port -and set the port to trunk mode aswell. Trunk mode tells the switch that -a number of VLANS can go through it. - -Last line is usually the mother of all screw-ups. If you forget that, you -won't get your VLAN working. Simple as that. - -Now configure some other port to be used as the destination for the vlan: - -conf t -interface FastEthernet0/1 - duplex half - speed 10 - switchport access vlan 2 -end - -Here we tell the switch to force the port 1 to half duplex 10Mb mode (normal -10 Mb NIC) and only traffic from interface VLAN 2 can go through this port. -also you can use a number of ports with VLAN 2, like a HUB ;) - -You should now connect some other device to port 1. - -Let it have an ip of eg. 10.0.231.2 mask 255.255.255.0 - -Ping linux from it - -ping 10.0.231.1 - -If it replies scream: "YESS!!" This means, that VLAN is working. - -Hard truth: It's not over, till its over. -if this works, then you are out of the woods, if not, well I hear that -tcpdump is a good tool ;-) and tcpdump that came with the vlan package even -better tool. (if you want to dump, use the one that came with vlan package) -</PRE> -<b> NOTE: <a href="http://ethereal.zing.org">Ethereal</a> also supports VLANs, -and is much more beautiful than tcpdump, if you have GUI capabilities.</b> -<pre> - -If you can ping the linux and from linux the host, you should try the -following at linux side: - -ping -s 1476 10.0.231.2 - -If there is no reply, there is something foggy with the NIC. and you -should start debugging. If ping -s 100 10.0.231.2 works, then it is most likely -an MTU problem with your NIC/Driver. -</PRE> -</li> -</ol> -</li> -<P> -<li><a name="targ3"><h3>Specific patches and work-arounds for various configurations.</h3></a><P> - <ol> - -<a name="tulip"> - <li><B>My Tulip-based card has MTU problems.</B><P> -<pre> - - Here is a patch sent in by Ben McKeegan: -Dear VLAN list members, - -Courtesy of my new employer, I've finally got around to updating my tulip -vlan patch for use with linux 2.4.x. I've also taken the opportunity to -do a rewrite and fix various (non-critical) flaws in my previous patch -(which was against 2.2.x). The patch allows the driver to receive vlan -frames with maximum MTU. - -Hopefully this rewrite will help satisfy some of the concerns of the 2.4 -kernel driver maintainers and thus aid inclusion of the patch in the -main driver. - -The old patch would erroneously allow incoming frames sized between 1519 -and 1536 bytes excluding the CRC. The new patch should correctly limit -this to 1518, the maximum size for VLANs. The old patch also needlessly -increased various constants. - -I believe there was some suggestion that the old patch disabled all length -error checking and opened the system to DoS attacks from massively -oversized packets. This is was never really the case, although the above -mentioned bug did exist. The patch only disabled checking of the 'Frame -Too Long' flag which indicates the frame exceeds 1518 bytes (including the -CRC). The NIC does not take any special action when this flag is set and -it does not stop the buffers getting filled up - the protection against -DoS comes from the receive timer which has a separate error flag that gets -set when length exceeds 2048 bytes. The 'Frame Too Long' flag is -basically just a summary of the length bits that are passed as part of the -same descriptor as the flag. The patch just explicitly checks the length -instead of relying on the flag. - -The unpatched driver uses 'magic number' constants to check the receive -status code. Having worked out what these meant from the documentation, -in the old patch I replaced them with a similar magic number. The new -patch replaces them with a series of verbose enumerations. Any worthwhile -compiler should optimize these down to a single constant, but these make -the code much easier to read. (In fact, its a lot easier to tell what the -patched driver does than what the unpatched driver does. - -I have tested the new patch on our own systems (using chipset 21143 rev -65), and it works ok, but I would appreciate feedback from other people. -With a lot of testing and a bit of luck and persuasion this patch might -make it into the kernel. - -Ben, I would be grateful if you could update the section of your how-to -containing my old patch, and add a note about the problems with the old -patch alongside it. (Perhaps someone else may wish to backport the new -patch to 2.2) - - -Regards, - -Ben McKeegan. - - -diff -ur linux-2.4.19/drivers/net/tulip/interrupt.c linux-2.4.19-tulip-vlan/drivers/net/tulip/interrupt.c ---- linux-2.4.19/drivers/net/tulip/interrupt.c Fri Nov 9 21:45:35 2001 -+++ linux-2.4.19-tulip-vlan/drivers/net/tulip/interrupt.c Mon Sep 16 13:17:40 2002 -@@ -122,14 +122,36 @@ - /* If we own the next entry, it is a new packet. Send it up. */ - while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { - s32 status = le32_to_cpu(tp->rx_ring[entry].status); -+ short pkt_len; - - if (tulip_debug > 5) - printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", - dev->name, entry, status); - if (--rx_work_limit < 0) -- break; -- if ((status & 0x38008300) != 0x0300) { -- if ((status & 0x38000300) != 0x0300) { -+ break; -+ -+ /* -+ Omit the four octet CRC from the length. -+ (May not be considered valid until we have -+ checked status for RxLengthOver2047 bits) -+ */ -+ pkt_len = ((status >> 16) & 0x7ff) - 4; -+ -+ /* -+ Maximum pkt_len is 1518 (1514 + vlan header) -+ Anything higher than this is always invalid -+ regardless of RxLengthOver2047 bits -+ */ -+ -+ if ((status & (RxLengthOver2047 | -+ RxDescCRCError | -+ RxDescCollisionSeen | -+ RxDescRunt | -+ RxDescDescErr | -+ RxWholePkt)) != RxWholePkt -+ || pkt_len > 1518 ) { -+ if ((status & (RxLengthOver2047 | -+ RxWholePkt)) != RxWholePkt) { - /* Ingore earlier buffers. */ - if ((status & 0xffff) != 0x7fff) { - if (tulip_debug > 1) -@@ -138,31 +160,21 @@ - dev->name, status); - tp->stats.rx_length_errors++; - } -- } else if (status & RxDescFatalErr) { -+ } else { - /* There was a fatal error. */ - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", - dev->name, status); - tp->stats.rx_errors++; /* end of a packet.*/ -- if (status & 0x0890) tp->stats.rx_length_errors++; -+ if (pkt_len > 1518 || -+ status & RxDescRunt) tp->stats.rx_length_errors++; - if (status & 0x0004) tp->stats.rx_frame_errors++; - if (status & 0x0002) tp->stats.rx_crc_errors++; - if (status & 0x0001) tp->stats.rx_fifo_errors++; - } - } else { -- /* Omit the four octet CRC from the length. */ -- short pkt_len = ((status >> 16) & 0x7ff) - 4; - struct sk_buff *skb; - --#ifndef final_version -- if (pkt_len > 1518) { -- printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", -- dev->name, pkt_len, pkt_len); -- pkt_len = 1518; -- tp->stats.rx_length_errors++; -- } --#endif -- - #ifdef CONFIG_NET_HW_FLOWCONTROL - drop = atomic_read(&netdev_dropping); - if (drop) -diff -ur linux-2.4.19/drivers/net/tulip/tulip.h linux-2.4.19-tulip-vlan/drivers/net/tulip/tulip.h ---- linux-2.4.19/drivers/net/tulip/tulip.h Fri Nov 9 21:45:35 2001 -+++ linux-2.4.19-tulip-vlan/drivers/net/tulip/tulip.h Mon Sep 16 11:55:33 2002 -@@ -186,11 +186,44 @@ - - enum desc_status_bits { - DescOwned = 0x80000000, -- RxDescFatalErr = 0x8000, -+ -+ /* -+ Error summary flag is logical or of 'CRC Error', -+ 'Collision Seen', 'Frame Too Long', 'Runt' and -+ 'Descriptor Error' flags generated within tulip chip. -+ */ -+ RxDescErrorSummary = 0x8000, -+ -+ RxDescCRCError = 0x0002, -+ RxDescCollisionSeen = 0x0040, -+ -+ /* -+ 'Frame Too Long' flag is set if packet length including CRC -+ exceeds 1518. However, a full sized VLAN tagged frame is -+ 1522 bytes including CRC. -+ -+ The tulip chip does not block oversized frames, and if this -+ flag is set on a receive descriptor it does not indicate -+ the frame has been truncated. The receive descriptor also -+ includes the actual length. Therefore we can safety ignore -+ this flag and check the length ourselves. -+ */ -+ RxDescFrameTooLong = 0x0080, -+ RxDescRunt = 0x0800, -+ RxDescDescErr = 0x4000, - RxWholePkt = 0x0300, -+ -+ /* -+ Top three bits of 14 bit frame length (status bits 27-29) -+ should never be set as that would make frame over 2047 bytes. -+ The Receive Watchdog flag (bit 4) may indicate the length is -+ over 2048 and the length field is invalid. -+ */ -+ RxLengthOver2047 = 0x38000010 - }; - - -+ - enum t21041_csr13_bits { - csr13_eng = (0xEF0<<4), /* for eng. purposes only, hardcode at EF0h */ - csr13_aui = (1<<3), /* clear to force 10bT, set to force AUI/BNC */ - -</pre> -</li> - -<a name="eepro"> - <li><B>My eepro100 has MTU problems.</B><P> - -NOTE: Intel's e100 driver works out-of-the-box. --Ben -<P> - - Here is a patch sent in by gleb@nbase.co.il<br> - -<pre> - filename="linux-2.2.14-eepro100-vlan.patch" - ---- linux/drivers/net/eepro100.c Tue Oct 26 20:53:40 1999 -+++ linux1/drivers/net/eepro100.c Sun May 14 07:47:34 2000 -@@ -377,12 +377,12 @@ - const char i82557_config_cmd[22] = { - 22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */ - 0, 0x2E, 0, 0x60, 0, -- 0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */ -+ 0xf2, 0x48, 0, 0x40, 0xfa, 0x80, /* 0x40=Force full-duplex */ - 0x3f, 0x05, }; - const char i82558_config_cmd[22] = { - 22, 0x08, 0, 1, 0, 0x80, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */ - 0, 0x2E, 0, 0x60, 0x08, 0x88, -- 0x68, 0, 0x40, 0xf2, 0xBD, /* 0xBD->0xFD=Force full-duplex */ -+ 0x68, 0, 0x40, 0xfa, 0xBD, /* 0xBD->0xFD=Force full-duplex */ - 0x31, 0x05, }; - - /* PHY media interface chips. */ -</pre> -</li> -<P> -<a name="syskonnect"> -<li><B>My SysKonnect sk98lin doesn't work</b> (submitted by: Patrick Schaaf <bof@bof.de>)<P> - -Here's a piece needed to get SysKonnect sk98lin -driven cards to play nice; they recognize and drop incoming VLAN tagged -frames in the driver, the patch below removes that check. Tested a bit -with a Cisco Catalyst 6509 on the other side, and a fibre link, works -like a charm. The card and driver already supports MTUs up to over 9000, -so no problem on that side. -<P> -<PRE> -diff -urN linux/drivers/net/sk98lin/skge.c blues/drivers/net/sk98lin/skge.c ---- linux/drivers/net/sk98lin/skge.c Mon Jun 19 20:42:38 2000 -+++ blues/drivers/net/sk98lin/skge.c Mon Aug 7 09:43:18 2000 -@@ -1948,7 +1948,7 @@ - - if ((Control & RX_CTRL_STAT_VALID) == RX_CTRL_STAT_VALID && - (FrameStat & -- (XMR_FS_ANY_ERR | XMR_FS_1L_VLAN | XMR_FS_2L_VLAN)) -+ (XMR_FS_ANY_ERR /*| XMR_FS_1L_VLAN*/ | XMR_FS_2L_VLAN)) - == 0) { - SK_DBG_MSG(NULL, SK_DBGMOD_DRV, - SK_DBGCAT_DRV_RX_PROGRESS,("V")); - -</pre> -</li> -<P> -<a name="3c59x"> -<li><b>My 3C59X has MTU problems.</b><P> - -Various contributors, most recently: Richard Fuchs - -<pre> - ---- 3c59x.c-ori 2003-07-02 15:26:26.000000000 +0200 -+++ 3c59x.c 2003-07-02 15:40:26.000000000 +0200 -@@ -308,6 +308,9 @@ - code size of a per-interface flag is not worthwhile. */ - static char mii_preamble_required; - -+/* The Ethernet Type used for 802.1q tagged frames */ -+#define VLAN_ETHER_TYPE 0x8100 -+ - #define PFX DRV_NAME ": " - - -@@ -655,7 +658,7 @@ - Wn2_ResetOptions=12, - }; - enum Window3 { /* Window 3: MAC/config bits. */ -- Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, -+ Wn3_Config=0, Wn3_MaxPktSize=4, Wn3_MAC_Ctrl=6, Wn3_Options=8, - }; - - #define BFEXT(value, offset, bitcount) \ -@@ -683,7 +686,8 @@ - Media_LnkBeat = 0x0800, - }; - enum Window7 { /* Window 7: Bus Master control. */ -- Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12, -+ Wn7_MasterAddr = 0, Wn7_VlanEtherType=4, Wn7_MasterLen = 6, -+ Wn7_MasterStatus = 12, - }; - /* Boomerang bus master control registers. */ - enum MasterCtrl { -@@ -780,7 +784,8 @@ - pm_state_valid:1, /* power_state[] has sane contents */ - open:1, - medialock:1, -- must_free_region:1; /* Flag: if zero, Cardbus owns the I/O region */ -+ must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */ -+ large_frames:1; /* accept large frames */ - int drv_flags; - u16 status_enable; - u16 intr_enable; -@@ -848,6 +853,9 @@ - static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); - static void vortex_tx_timeout(struct net_device *dev); - static void acpi_set_WOL(struct net_device *dev); -+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -+static void set_8021q_mode(struct net_device *dev, int enable); -+#endif - - /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ - /* Option count limit only -- unlimited interfaces are supported. */ -@@ -1031,6 +1039,7 @@ - dev->base_addr = ioaddr; - dev->irq = irq; - dev->mtu = mtu; -+ vp->large_frames = mtu > 1500; - vp->drv_flags = vci->drv_flags; - vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0; - vp->io_size = vci->io_size; -@@ -1450,7 +1459,7 @@ - - /* Set the full-duplex bit. */ - outw( ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | -- (dev->mtu > 1500 ? 0x40 : 0) | -+ (vp->large_frames ? 0x40 : 0) | - ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), - ioaddr + Wn3_MAC_Ctrl); - -@@ -1534,6 +1543,10 @@ - } - /* Set receiver mode: presumably accept b-case and phys addr only. */ - set_rx_mode(dev); -+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -+ /* enable 802.1q tagged frames */ -+ set_8021q_mode(dev, 1); -+#endif - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - - // issue_and_wait(dev, SetTxStart|0x07ff); -@@ -1674,7 +1687,7 @@ - /* Set the full-duplex bit. */ - EL3WINDOW(3); - outw( (vp->full_duplex ? 0x20 : 0) | -- (dev->mtu > 1500 ? 0x40 : 0) | -+ (vp->large_frames ? 0x40 : 0) | - ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), - ioaddr + Wn3_MAC_Ctrl); - if (vortex_debug > 1) -@@ -1897,6 +1910,10 @@ - issue_and_wait(dev, RxReset|0x07); - /* Set the Rx filter to the current state. */ - set_rx_mode(dev); -+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -+ /* enable 802.1q VLAN tagged frames */ -+ set_8021q_mode(dev, 1); -+#endif - outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ - outw(AckIntr | HostError, ioaddr + EL3_CMD); - } -@@ -2494,6 +2511,11 @@ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - -+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -+ /* Disable receiving 802.1q tagged frames */ -+ set_8021q_mode(dev, 0); -+#endif -+ - if (dev->if_port == XCVR_10base2) - /* Turn off thinnet power. Green! */ - outw(StopCoax, ioaddr + EL3_CMD); -@@ -2758,6 +2780,50 @@ - outw(new_mode, ioaddr + EL3_CMD); - } - -+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -+/* Setup the card so that it can receive frames with an 802.1q VLAN tag. -+ Note that this must be done after each RxReset due to some backwards -+ compatibility logic in the Cyclone and Tornado ASICs */ -+static void set_8021q_mode(struct net_device *dev, int enable) -+{ -+ struct vortex_private *vp = (struct vortex_private *)dev->priv; -+ long ioaddr = dev->base_addr; -+ int old_window = inw(ioaddr + EL3_CMD); -+ int mac_ctrl; -+ -+ if (vp->drv_flags&IS_CYCLONE || vp->drv_flags&IS_TORNADO) { -+ /* cyclone and tornado chipsets can recognize 802.1q -+ * tagged frames and treat them correctly */ -+ -+ int max_pkt_size = dev->mtu+14; /* MTU+Ethernet header */ -+ if (enable) -+ max_pkt_size += 4; /* 802.1Q VLAN tag */ -+ -+ EL3WINDOW(3); -+ outw(max_pkt_size, ioaddr+Wn3_MaxPktSize); -+ -+ /* set VlanEtherType to let the hardware checksumming -+ treat tagged frames correctly */ -+ EL3WINDOW(7); -+ outw(VLAN_ETHER_TYPE, ioaddr+Wn7_VlanEtherType); -+ } else { -+ /* on older cards we have to enable large frames */ -+ -+ vp->large_frames = dev->mtu > 1500 || enable; -+ -+ EL3WINDOW(3); -+ mac_ctrl = inw(ioaddr+Wn3_MAC_Ctrl); -+ if (vp->large_frames) -+ mac_ctrl |= 0x40; -+ else -+ mac_ctrl &= ~0x40; -+ outw(mac_ctrl, ioaddr+Wn3_MAC_Ctrl); -+ } -+ -+ EL3WINDOW(old_window); -+} -+#endif -+ - /* MII transceiver control section. - Read and write the MII registers using software-generated serial - MDIO protocol. See the MII specifications or DP83840A data sheet - -</pre> -</li> -<P> - -<a name="natsemi"> -<li><b>My natsemi has MTU problems.</b><P> -By Peter Stuge: -<pre> - ---- natsemi.c.orig 2002-12-30 21:38:04.000000000 +0100 -+++ natsemi.c 2002-12-30 22:25:19.000000000 +0100 -@@ -233,7 +233,7 @@ - #define NATSEMI_REGS_SIZE (NATSEMI_NREGS * sizeof(u32)) - #define NATSEMI_EEPROM_SIZE 24 /* 12 16-bit values */ - --#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ -+#define PKT_BUF_SZ 2064 /* Size of each temporary Rx buffer. */ - - /* These identify the driver base version and may not be removed. */ - static char version[] __devinitdata = -@@ -1290,7 +1290,7 @@ - /* DRTH 0x10: start copying to memory if 128 bytes are in the fifo - * MXDMA 0: up to 256 byte bursts - */ -- np->rx_config = RxMxdma_256 | 0x20; -+ np->rx_config = RxAcceptLong | RxMxdma_256 | 0x20; - writel(np->rx_config, ioaddr + RxConfig); - - /* Disable PME: -</pre> -</li> -<P> - -<a name="3c905b"> -<li><b>My 3C905B has MTU problems.</b><P> -As found -<a href="http://www.bewley.net/linux/vlan/patches/vlan-3c59x.patch">here</a> -at one point in time.<br> -Furnished by: Luis Miguel Cruz Miranda luismi@b2bi.es<br> -(I don't know the original author --Ben). - -<PRE> ---- linux.orig/drivers/net/3c59x.c Sun Sep 30 21:26:06 2001 -+++ linux/drivers/net/3c59x.c Wed Oct 24 21:52:10 2001 -@@ -308,6 +308,9 @@ - code size of a per-interface flag is not worthwhile. */ - static char mii_preamble_required; - -+/* The Ethernet Type used for 802.1q tagged frames */ -+#define VLAN_ETHER_TYPE 0x8100 -+ - #define PFX DRV_NAME ": " - - -@@ -651,7 +654,7 @@ - Wn2_ResetOptions=12, - }; - enum Window3 { /* Window 3: MAC/config bits. */ -- Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, -+ Wn3_Config=0, Wn3_MaxPktSize=4, Wn3_MAC_Ctrl=6, Wn3_Options=8, - }; - - #define BFEXT(value, offset, bitcount) \ -@@ -679,7 +682,8 @@ - Media_LnkBeat = 0x0800, - }; - enum Window7 { /* Window 7: Bus Master control. */ -- Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12, -+ Wn7_MasterAddr = 0, Wn7_VlanEtherType=4, Wn7_MasterLen = 6, -+ Wn7_MasterStatus = 12, - }; - /* Boomerang bus master control registers. */ - enum MasterCtrl { -@@ -776,7 +780,8 @@ - pm_state_valid:1, /* power_state[] has sane contents */ - open:1, - medialock:1, -- must_free_region:1; /* Flag: if zero, Cardbus owns the I/O region */ -+ must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */ -+ large_frames:1; /* accept large frames */ - int drv_flags; - u16 status_enable; - u16 intr_enable; -@@ -844,6 +849,9 @@ - static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); - static void vortex_tx_timeout(struct net_device *dev); - static void acpi_set_WOL(struct net_device *dev); -+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -+static void set_8021q_mode(struct net_device *dev, int enable); -+#endif - - /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ - /* Option count limit only -- unlimited interfaces are supported. */ -@@ -1030,6 +1038,7 @@ - dev->base_addr = ioaddr; - dev->irq = irq; - dev->mtu = mtu; -+ vp->large_frames = mtu > 1500; - vp->drv_flags = vci->drv_flags; - vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0; - vp->io_size = vci->io_size; -@@ -1461,7 +1470,7 @@ - - /* Set the full-duplex bit. */ - outw( ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | -- (dev->mtu > 1500 ? 0x40 : 0) | -+ (vp->large_frames ? 0x40 : 0) | - ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), - ioaddr + Wn3_MAC_Ctrl); - -@@ -1545,6 +1554,10 @@ - } - /* Set receiver mode: presumably accept b-case and phys addr only. */ - set_rx_mode(dev); -+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -+ /* enable 802.1q tagged frames */ -+ set_8021q_mode(dev, 1); -+#endif - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - - // issue_and_wait(dev, SetTxStart|0x07ff); -@@ -1680,7 +1693,7 @@ - /* Set the full-duplex bit. */ - EL3WINDOW(3); - outw( (vp->full_duplex ? 0x20 : 0) | -- (dev->mtu > 1500 ? 0x40 : 0) | -+ (vp->large_frames ? 0x40 : 0) | - ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), - ioaddr + Wn3_MAC_Ctrl); - if (vortex_debug > 1) -@@ -1900,6 +1913,10 @@ - issue_and_wait(dev, RxReset|0x07); - /* Set the Rx filter to the current state. */ - set_rx_mode(dev); -+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -+ /* enable 802.1q VLAN tagged frames */ -+ set_8021q_mode(dev, 1); -+#endif - outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ - outw(AckIntr | HostError, ioaddr + EL3_CMD); - } -@@ -2497,6 +2514,11 @@ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - -+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -+ /* Disable receiving 802.1q tagged frames */ -+ set_8021q_mode(dev, 0); -+#endif -+ - if (dev->if_port == XCVR_10base2) - /* Turn off thinnet power. Green! */ - outw(StopCoax, ioaddr + EL3_CMD); -@@ -2760,6 +2782,50 @@ - - outw(new_mode, ioaddr + EL3_CMD); - } -+ -+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -+/* Setup the card so that it can receive frames with an 802.1q VLAN tag. -+ Note that this must be done after each RxReset due to some backwards -+ compatibility logic in the Cyclone and Tornado ASICs */ -+static void set_8021q_mode(struct net_device *dev, int enable) -+{ -+ struct vortex_private *vp = (struct vortex_private *)dev->priv; -+ long ioaddr = dev->base_addr; -+ int old_window = inw(ioaddr + EL3_CMD); -+ int mac_ctrl; -+ -+ if (vp->drv_flags&IS_CYCLONE || vp->drv_flags&IS_TORNADO) { -+ /* cyclone and tornado chipsets can recognize 802.1q -+ * tagged frames and treat them correctly */ -+ -+ int max_pkt_size = dev->mtu+14; /* MTU+Ethernet header */ -+ if (enable) -+ max_pkt_size += 4; /* 802.1Q VLAN tag */ -+ -+ EL3WINDOW(3); -+ outw(max_pkt_size, ioaddr+Wn3_MaxPktSize); -+ -+ /* set VlanEtherType to let the hardware checksumming -+ treat tagged frames correctly */ -+ EL3WINDOW(7); -+ outw(VLAN_ETHER_TYPE, ioaddr+Wn7_VlanEtherType); -+ } else { -+ /* on older cards we have to enable large frames */ -+ -+ vp->large_frames = dev->mtu > 1500 || enable; -+ -+ EL3WINDOW(3); -+ mac_ctrl = inw(ioaddr+Wn3_MAC_Ctrl); -+ if (vp->large_frames) -+ mac_ctrl |= 0x40; -+ else -+ mac_ctrl &= ~0x40; -+ outw(mac_ctrl, ioaddr+Wn3_MAC_Ctrl); -+ } -+ -+ EL3WINDOW(old_window); -+} -+#endif - - /* MII transceiver control section. - Read and write the MII registers using software-generated serial -</pre> -</li> -<P> - -<a name="pcmcia"> -<li><b>How to make my PCMCIA ethernet card work with VLANs?</b><P> -Per Peter Stuge:<P> - -The problem was that the VLAN code in kernel header files weren't included -properly when compiling the PCMCIA stuff. Exactly why? I'm not sure, might -be because the PCMCIA stuff isn't the actual kernel and that means it's -missing defines that trigger the VLAN #ifdefs. -<P> -Commenting the #ifdefs in linux/netdevice.h and adding code to clear out -the struct vlan_dev_info* vlan_dev after having created the new network -device in the PCMCIA client for the networking card did the trick if I -remember correctly. (The reason it doesn't work out-of-the-box is that the -kernel VLAN code has garbage data for the VLAN fields in struct device since -the device creator (PCMCIA client driver) doesn't know about them.) -<P> -Ben Adds:<P> -To clear out the garbage, the PCMCIA driver needs to mset the net_device structure -to zero (it should do this anyway..) If anyone has a patch, please send it to me -and the owners of the PCMCIA code... -</pre> -</li> - -</ol> -</li> -<P> -<li><a name="targ4"><h3>Scripts and Recipes.</h3></a><P> - <ol> - <li><B>Mandrake (RedHat-style) startup script for VLANs.</B><P> - Contributed by: "MaxiM Basunov" <maxim@idknet.com> -<PRE> -#!/bin/sh -# -# network Bring up/down networking -# -# chkconfig: 2345 10 90 -# description: Activates/Deactivates all network interfaces configured to \ -# start at boot time. -# probe: true - -# Source function library. -. /etc/init.d/functions - -if [ ! -f /etc/sysconfig/network ]; then - exit 0 -fi - -. /etc/sysconfig/network - -if [ -f /etc/sysconfig/pcmcia ]; then - . /etc/sysconfig/pcmcia -fi - - -# Check that networking is up. -[ ${NETWORKING} = "no" ] && exit 0 - -[ -x /sbin/ifconfig ] || exit 0 - -# Even if IPX is configured, without the utilities we can't do much -[ ! -x /sbin/ipx_internal_net -o ! -x /sbin/ipx_configure ] && IPX= - -CWD=`pwd` -cd /etc/sysconfig/network-scripts - -# find all the interfaces besides loopback. -# ignore aliases, alternative configurations, and editor backup files -interfaces=`ls ifcfg* | egrep -v '(ifcfg-lo|:)' | \ - egrep -v 'ifcfg-ippp[0-9]+$' | \ -> egrep 'ifcfg-[a-z0-9\.]+$' | \ -< egrep 'ifcfg-[a-z0-9]+$' | \ - sed 's/^ifcfg-//g'` - -# See how we were called. -case "$1" in - start) - - action "Setting network parameters: " sysctl -p /etc/sysctl.conf - - action "Bringing up interface lo: " ./ifup ifcfg-lo - - case "$IPX" in - yes|true) - /sbin/ipx_configure --auto_primary=$IPXAUTOPRIMARY \ - --auto_interface=$IPXAUTOFRAME - if [ "$IPXINTERNALNETNUM" != "0" ]; then - /sbin/ipx_internal_net add $IPXINTERNALNETNUM $IPXINTERNALNODENUM - fi - ;; - esac - # depreciated but we still use it. - if [ -f /proc/sys/net/ipv4/ip_forward ] && [ "$FORWARD_IPV4" = "yes" ] || - "$FORWARD_IPV4" = "true" ]; - then - action "Enabling IPv4 packet forwarding" sysctl -w net.ipv4.ip_forward=1 - fi - -> action "Setting VLAN parameters: " vconfig set_name_type DEV_PLUS_VID - - for i in $interfaces; do - if egrep -L "^ONBOOT=\"?[Nn][Oo]\"?" ifcfg-$i >/dev/null 2>&1; then - # Probe module to preserve interface ordering - /sbin/ifconfig $i >/dev/null 2>&1 - else -> vlan=`echo $i | egrep -v '(lo|:)' | \ -> egrep -v 'ippp[0-9]+$' | \ -> egrep '[a-z0-9]+\.[0-9][0-9][0-9][0-9]$' | \ -> sed "s/^[a-z0-9]*\.//g;s/^0*//g"` -> ifvlan=`echo $i | egrep -v '(lo|:)' | \ -> egrep -v 'ippp[0-9]+$' | \ -> egrep '[a-z0-9]+\.[0-9][0-9][0-9][0-9]$' | \ -> sed "s/\.[a-z0-9]*$//g"` - -> if [ -n "${vlan}" ]; then -> action "Enable ${vlan} on {$ifvlan}: " vconfig add ${ifvlan} ${vlan} -> fi - action "Bringing up interface $i: " ./ifup $i boot - fi - done - - # Add non interface-specific static-routes. - if [ -f /etc/sysconfig/static-routes ]; then - grep "^any" /etc/sysconfig/static-routes | while read ignore type dest -netmask mask bogus args; do - if [ "${bogus}" = "gw" ]; then - /sbin/route add -$type $dest $netmask $mask $args - else - /sbin/route add -$type $dest $netmask $mask $bogus $args - fi - done - fi - - touch /var/lock/subsys/network - ;; - stop) - # If this is a final shutdown/halt, check for network FS, - # and unmount them even if the user didn't turn on netfs - - if [ "$RUNLEVEL" = "6" -o "$RUNLEVEL" = "0" -o "$RUNLEVEL" = "1" ]; then - NFSMTAB=`grep -v '^#' /proc/mounts | awk '{ if ($3 ~ /^nfs$/ ) print $2}'` - SMBMTAB=`grep -v '^#' /proc/mounts | awk '{ if ($3 ~ /^smbfs$/ ) print -$2}'` - NCPMTAB=`grep -v '^#' /proc/mounts | awk '{ if ($3 ~ /^ncpfs$/ ) print -$2}'` - if [ -n "$NFSMTAB" -o -n "$SMBMTAB" -o -n "$NCPMTAB" ] ; then - /etc/init.d/netfs stop - fi - fi - - for i in $interfaces ; do - if ifconfig $i 2>/dev/null | grep -q "UP" >/dev/null 2>&1 ; then - action "Shutting down interface $i: " ./ifdown $i boot - fi - done - case "$IPX" in - yes|true) - if [ "$IPXINTERNALNETNUM" != "0" ]; then - /sbin/ipx_internal_net del - fi - ;; - esac - ./ifdown ifcfg-lo - if [ -d /proc/sys/net/ipv4 ]; then - if [ -f /proc/sys/net/ipv4/ip_forward ]; then - if [ `cat /proc/sys/net/ipv4/ip_forward` != 0 ]; then - action "Disabling IPv4 packet forwarding: " sysctl -w -net.ipv4.ip_forward=0 - fi - fi - if [ -f /proc/sys/net/ipv4/ip_always_defrag ]; then - if [ `cat /proc/sys/net/ipv4/ip_always_defrag` != 0 ]; then - action "Disabling IPv4 automatic defragmentation: " sysctl -w -net.ipv4.ip_always_defrag=0 - fi - fi - fi - if [ -f /proc/sys/net/ipv4/tcp_syncookies ];then - if [ `cat /proc/sys/net/ipv4/tcp_syncookies` != 0 ]; then - sysctl -w net.ipv4.tcp_syncookies=0 - fi - fi - - rm -f /var/lock/subsys/network - ;; - status) - echo "Configured devices:" - echo lo $interfaces - - if [ -x /bin/linuxconf ] ; then - eval `/bin/linuxconf --hint netdev` - echo "Devices that are down:" - echo $DEV_UP - echo "Devices with modified configuration:" - echo $DEV_RECONF - else - echo "Currently active devices:" - echo `/sbin/ifconfig | grep ^[a-z] | awk '{print $1}'` - fi - ;; - restart) - cd $CWD - $0 stop - $0 start - ;; - reload) - if [ -x /bin/linuxconf ] ; then - eval `/bin/linuxconf --hint netdev` - for device in $DEV_UP ; do - action "Bringing up device $device: " ./ifup $device - done - for device in $DEV_DOWN ; do - action "Shutting down device $device: " ./ifdown $device - done - for device in $DEV_RECONF ; do - action "Shutting down device $device: " ./ifdown $device - action "Bringing up device $device: " ./ifup $device - done - for device in $DEV_RECONF_ALIASES ; do - action "Briging up alias $device: " -/etc/sysconfig/network-scripts/ifup-aliases $device - done - for device in $DEV_RECONF_ROUTES ; do - action "Bringing up route $device: " -/etc/sysconfig/network-scripts/ifup-routes $device - done - case $IPX in yes|true) - case $IPXINTERNALNET in - reconf) - action "Deleting internal IPX network: " /sbin/ipx_internal_net del - action "Adding internal IPX network $IPXINTERNALNETNUM -$IPXINTERNALNODENUM: " /sbin/ipx_internal_net add $IPXINTERNALNETNUM \ - $IPXINTERNALNODENUM - ;; - add) - action "Adding internal IPX network $IPXINTERNALNETNUM -$IPXINTERNALNODENUM: "/sbin/ipx_internal_net add $IPXINTERNALNETNUM \ - $IPXINTERNALNODENUM - ;; - del) - action "Deleting internal IPX network: " /sbin/ipx_internal_net del - ;; - esac - ;; - esac - else - cd $CWD - $0 restart - fi - ;; - probe) - if [ -x /bin/linuxconf ] ; then - eval `/bin/linuxconf --hint netdev` - [ -n "$DEV_UP$DEV_DOWN$DEV_RECONF$DEV_RECONF_ALIASES" -o \ - -n "$DEV_RECONF_ROUTES$IPXINTERNALNET" ] && \ - echo reload - exit 0 - else - # if linuxconf isn't around to figure stuff out for us, - # we punt. Probably better than completely reloading - # networking if user isn't sure which to do. If user - # is sure, they would run restart or reload, not probe. - exit 0 - fi - ;; - *) - echo "Usage: network {start|stop|restart|reload|status|probe}" - exit 1 -esac - -exit 0 -</pre> -</li> - -</ol> -<P> -<HR> -<pre> -Terv, - ------------------------------ -Kristjan Kotkas -KPNQwest Estonia -kristjan.kotkas@kpnqwest.ee -t + 372 62 66299 m + 372 51 60697 f + 372 62 66292 - -</pre> - - - <hr> - <address><a href="mailto:greear@cyberhighway.net">Ben Greear</a></address> -<!-- Created: Mon May 29 12:17:35 MST 2000 --> -<!-- hhmts start --> -Last modified: Fri Jul 4 09:53:40 PDT 2003 -<!-- hhmts end --> - </body> -</html> diff --git a/libpcap-0.4/CVS/Entries b/libpcap-0.4/CVS/Entries deleted file mode 100644 index 54e26d9..0000000 --- a/libpcap-0.4/CVS/Entries +++ /dev/null @@ -1,5 +0,0 @@ -D/SUNOS4//// -D/bpf//// -D/lbl//// -D/linux-include//// -D/net//// diff --git a/libpcap-0.4/CVS/Repository b/libpcap-0.4/CVS/Repository deleted file mode 100644 index 0e0ddbb..0000000 --- a/libpcap-0.4/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/libpcap-0.4 diff --git a/libpcap-0.4/CVS/Root b/libpcap-0.4/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/libpcap-0.4/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/libpcap-0.4/SUNOS4/CVS/Entries b/libpcap-0.4/SUNOS4/CVS/Entries deleted file mode 100644 index 1784810..0000000 --- a/libpcap-0.4/SUNOS4/CVS/Entries +++ /dev/null @@ -1 +0,0 @@ -D diff --git a/libpcap-0.4/SUNOS4/CVS/Repository b/libpcap-0.4/SUNOS4/CVS/Repository deleted file mode 100644 index 3e7444c..0000000 --- a/libpcap-0.4/SUNOS4/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/libpcap-0.4/SUNOS4 diff --git a/libpcap-0.4/SUNOS4/CVS/Root b/libpcap-0.4/SUNOS4/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/libpcap-0.4/SUNOS4/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/libpcap-0.4/bpf/CVS/Entries b/libpcap-0.4/bpf/CVS/Entries deleted file mode 100644 index 27ad449..0000000 --- a/libpcap-0.4/bpf/CVS/Entries +++ /dev/null @@ -1 +0,0 @@ -D/net//// diff --git a/libpcap-0.4/bpf/CVS/Repository b/libpcap-0.4/bpf/CVS/Repository deleted file mode 100644 index e2ce17c..0000000 --- a/libpcap-0.4/bpf/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/libpcap-0.4/bpf diff --git a/libpcap-0.4/bpf/CVS/Root b/libpcap-0.4/bpf/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/libpcap-0.4/bpf/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/libpcap-0.4/bpf/net/CVS/Entries b/libpcap-0.4/bpf/net/CVS/Entries deleted file mode 100644 index 1784810..0000000 --- a/libpcap-0.4/bpf/net/CVS/Entries +++ /dev/null @@ -1 +0,0 @@ -D diff --git a/libpcap-0.4/bpf/net/CVS/Repository b/libpcap-0.4/bpf/net/CVS/Repository deleted file mode 100644 index c8ca0dc..0000000 --- a/libpcap-0.4/bpf/net/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/libpcap-0.4/bpf/net diff --git a/libpcap-0.4/bpf/net/CVS/Root b/libpcap-0.4/bpf/net/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/libpcap-0.4/bpf/net/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/libpcap-0.4/lbl/CVS/Entries b/libpcap-0.4/lbl/CVS/Entries deleted file mode 100644 index 1784810..0000000 --- a/libpcap-0.4/lbl/CVS/Entries +++ /dev/null @@ -1 +0,0 @@ -D diff --git a/libpcap-0.4/lbl/CVS/Repository b/libpcap-0.4/lbl/CVS/Repository deleted file mode 100644 index b351c7f..0000000 --- a/libpcap-0.4/lbl/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/libpcap-0.4/lbl diff --git a/libpcap-0.4/lbl/CVS/Root b/libpcap-0.4/lbl/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/libpcap-0.4/lbl/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/libpcap-0.4/linux-include/CVS/Entries b/libpcap-0.4/linux-include/CVS/Entries deleted file mode 100644 index 7e34cc5..0000000 --- a/libpcap-0.4/linux-include/CVS/Entries +++ /dev/null @@ -1 +0,0 @@ -D/netinet//// diff --git a/libpcap-0.4/linux-include/CVS/Repository b/libpcap-0.4/linux-include/CVS/Repository deleted file mode 100644 index 6f3b3e1..0000000 --- a/libpcap-0.4/linux-include/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/libpcap-0.4/linux-include diff --git a/libpcap-0.4/linux-include/CVS/Root b/libpcap-0.4/linux-include/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/libpcap-0.4/linux-include/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/libpcap-0.4/linux-include/netinet/CVS/Entries b/libpcap-0.4/linux-include/netinet/CVS/Entries deleted file mode 100644 index 1784810..0000000 --- a/libpcap-0.4/linux-include/netinet/CVS/Entries +++ /dev/null @@ -1 +0,0 @@ -D diff --git a/libpcap-0.4/linux-include/netinet/CVS/Repository b/libpcap-0.4/linux-include/netinet/CVS/Repository deleted file mode 100644 index 2604b84..0000000 --- a/libpcap-0.4/linux-include/netinet/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/libpcap-0.4/linux-include/netinet diff --git a/libpcap-0.4/linux-include/netinet/CVS/Root b/libpcap-0.4/linux-include/netinet/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/libpcap-0.4/linux-include/netinet/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/libpcap-0.4/net/CVS/Entries b/libpcap-0.4/net/CVS/Entries deleted file mode 100644 index 1784810..0000000 --- a/libpcap-0.4/net/CVS/Entries +++ /dev/null @@ -1 +0,0 @@ -D diff --git a/libpcap-0.4/net/CVS/Repository b/libpcap-0.4/net/CVS/Repository deleted file mode 100644 index bff9ac2..0000000 --- a/libpcap-0.4/net/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/libpcap-0.4/net diff --git a/libpcap-0.4/net/CVS/Root b/libpcap-0.4/net/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/libpcap-0.4/net/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/macvlan_config b/macvlan_config Binary files differdeleted file mode 100755 index 372ede0..0000000 --- a/macvlan_config +++ /dev/null diff --git a/macvlan_config.c b/macvlan_config.c deleted file mode 100644 index 5bc6723..0000000 --- a/macvlan_config.c +++ /dev/null @@ -1,635 +0,0 @@ -/* -####################################################################### -# -# (C) Copyright 2001 -# Alex Zeffertt, Cambridge Broadband Ltd, ajz@cambridgebroadband.com -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, -# MA 02111-1307 USA -####################################################################### -# Notes: -# -# This configuration utility communicates with macvlan.o, the MAC address -# based VLAN support module. -# -# It uses an IOCTL interface which allows you to -# -# 1. enable/disable MAC address based VLANS over an ether type net_device -# 2. add/remove a MAC address based VLAN - which is an ether type net_device -# layered over the original MACVLAN enabled ether type net_device. -# 3. bind/unbind MAC addresses to/from particular MAC address based VLANs -# 4. discover the state of MAC address based VLANs on the system. -# 5. set/get port flags, including whether to bind to destination MAC -# or source mac. -# 6. Traffic to/from eth0 will not be affected. - - -# -# Example: (Assuming you are using source binding) -# -# If you enable MAC address based VLANS over eth0 -# -# You may then create further VLANs, e.g. eth0#1 eth0#2 .... -# These will not receive any frames until you bind MAC addresses to them. -# If you bind 11:22:33:44:55:66 to eth0#1, then any frames received by -# eth0 with source MAC 11:22:33:44:55:66 will be routed up through eth0#1 -# instead of eth0. -# -# Example: (Assuming you are using destination (local) binding) -# -# If you enable MAC address based VLANS over eth0 -# -# You may then create further VLANs, e.g. eth0#1 eth0#2 .... -# These will not receive any frames until you bind MAC addresses to them. -# If you bind 11:22:33:44:55:66 to eth0#1, then any broadcast/multicast -# frames, or frames with a destination MAC 11:22:33:44:55:66 -# will be routed up through eth0#1 instead of eth0 -# -# For broadcasts, the packet will be duplicated for every VLAN -# with at least one MAC attached. Attaching more than one MAC -# when destination binding makes no sense...don't do it! -# -# -# -####################################################################### -*/ -#include <stdio.h> -#include <stdlib.h> -#include <sys/ioctl.h> -#include <net/if.h> -#include <linux/if_macvlan.h> -#include <linux/sockios.h> -#include <string.h> -#include <errno.h> - - -int do_help(int argc, char *argv[]); -int do_enable(int argc, char *argv[]); -int do_disable(int argc, char *argv[]); -int do_add(int argc, char *argv[]); -int do_del(int argc, char *argv[]); -int do_bind(int argc, char *argv[]); -int do_unbind(int argc, char *argv[]); -int do_info(int argc, char *argv[]); -int do_setflags(int argc, char *argv[]); -int do_unload(int argc, char* argv[]); - -struct command { - char *name; - char *short_help; - int (*fn)(int argc, char *argv[]); - char *long_help; -} command_list[] = { - {"help", "help on other commands", do_help, "help <command>"}, - {"enable", "enables mac based vlans over an ethernet device", do_enable, - "enable <ifname>\n" - " - enables mac based vlans over \"ifname\"\n" - " - also creates a default vlan over \"ifname\" called \"ifname#0\"" - }, - {"disable", "disables mac based vlans over an ethernet device", do_disable, "disable <ifname>"}, - {"add", "creates new mac based vlan", do_add, - "add <ifname> <index>\n" - " - creates a new mac based vlan called \"ifname#index\" layered over \"ifname\"\n" - " - mac based vlans over \"ifname\" must first be enabled with \"enable\"\n" - " - \"ifname#index\" is not mapped to any MAC address until \"bind\" is called" - }, - {"del", "destroys a mac based vlan", do_del, - "del <ifname>\n" - " - deletes a mac base vlan called \"ifname\"" - }, - {"bind", "binds macaddr to vlan", do_bind, - "bind <ifname> <macaddr>\n" - " - binds macaddr to vlan called \"ifname\"" - }, - {"unbind", "unbinds macaddr from vlan", do_unbind, - "unbind <ifname> <macaddr>\n" - " - unbinds macaddr from vlan called \"ifname\"" - }, - {"unload", "Unconfigure all of the macvlan devices", - do_unload, "Unconfigure all of the macvlan devices so module can be unloaded"}, - {"setflags", "Set port flags on a port", - do_setflags, - "setflags <ifname> <new_flags>\n" - "0x01 Bind to Destination instead of source MAC" - }, - {"info", "print state of mac based vlans", do_info, "info"}, -}; -#define NCOMMANDS (sizeof(command_list)/sizeof(struct command)) - - -int parseInt(const char* s) { - return strtol(s, NULL, 0); //should parse HEX, Octal, and Decimal. If not decimal, must start with 0x -} - - -int do_help(int argc, char *argv[]) -{ - unsigned int cmd; - if (argc < 2) - return -1; - - for (cmd = 0; cmd < NCOMMANDS; cmd++) { - if (!strcmp(command_list[cmd].name,argv[1])) - break; - } - if (cmd == NCOMMANDS) - return -1; - puts(command_list[cmd].long_help); - return 0; -} - -int do_enable(int argc, char *argv[]) -{ - struct macvlan_ioctl req; - int s; - - if (argc < 2) { - printf("usage: %s <ifname>\n", argv[0]); - return 1; - } - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket"); - return 1; - } - - req.cmd = MACVLAN_ENABLE; - req.ifname = argv[1]; /* - * name of ethernet device over which we - * are enabling mac based vlans - */ - - if (ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - if (errno != EEXIST) { - perror("ioctl (SIOCGIFMACVLAN, MACVLAN_ENABLE)"); - printf("errno: %i\n", errno); - return 1; - } - else { - return 0; - } - } - return 0; -} - - -int do_setflags(int argc, char *argv[]) -{ - struct macvlan_ioctl req; - int s; - - if (argc < 3) { - printf("usage: %s <ifname> <flags>\n", argv[0]); - return 1; - } - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket"); - return 1; - } - - req.cmd = MACVLAN_SET_PORT_FLAGS; - req.ifname = argv[1]; /* - * name of ethernet device over which we - * are enabling mac based vlans - */ - req.ifidx = parseInt(argv[2]); - - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (SIOCGIFMACVLAN, SET_PORT_FLAGS)"); - return 1; - } - return 0; -} - -int _do_disable(char* port, int s) { - struct macvlan_ioctl req; - - req.cmd = MACVLAN_DISABLE; - req.ifname = port; /* - * name of ethernet device over which we - * are disabling mac based vlans - */ - - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("disable-port"); - return -1; - } - else { - printf("Disabled port: %s\n", port); - } - return 0; -} - -int do_disable(int argc, char *argv[]) -{ - int s; - - if (argc < 2) { - printf("usage: %s <ifname>\n", argv[0]); - return 1; - } - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket"); - return 1; - } - - return _do_disable(argv[1], s); -} - -int do_add(int argc, char *argv[]) -{ - int s; - struct macvlan_ioctl req; - - if (argc < 3) { - printf("usage: %s <ifname> <index>\n", argv[0]); - return 1; - } - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket"); - return 1; - } - - req.cmd = MACVLAN_ADD; - req.ifname = argv[1]; /* name of lower layer i/f over which we are adding an upper layer i/f */ - req.ifidx = parseInt(argv[2]); - - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (SIOCGIFMACVLAN, MACVLAN_ADD)"); - return 1; - } - return 0; -} - -int _do_del(char* ifname, int s) { - struct macvlan_ioctl req; - - req.cmd = MACVLAN_DEL; - req.ifname = ifname; /* name mac based vlan to destroy */ - - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - printf("failed to delete interface: %s\n", ifname); - perror("ioctl (SIOCGIFMACVLAN, MACVLAN_DEL)"); - return -1; - } - else { - printf("Deleted interface: %s\n", ifname); - } - - return 0; -} - -int do_del(int argc, char *argv[]) -{ - int s; - - if (argc < 2) { - printf("usage: %s <ifname>\n", argv[0]); - return 1; - } - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket"); - return 1; - } - - return _do_del(argv[1], s); -} - - - -int get_num_ports(int s) { - struct macvlan_ioctl req; - struct macvlan_ioctl_reply rep; - - req.cmd = MACVLAN_GET_NUM_PORTS; - req.reply = &rep; - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (SIOCGIFMACVLAN, GET_NUM_PORTS)"); - return -1; - } - - printf("Found: %i ports\n", rep.num); - - return rep.num; -} - -int get_num_vlans(int portidx, int s) { - struct macvlan_ioctl req; - struct macvlan_ioctl_reply rep; - - /* Get the number of mac-based-vlans layered - * over this ethernet device - */ - req.cmd = MACVLAN_GET_NUM_VLANS; - req.portidx = portidx; - req.reply = &rep; - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (GET_NUM_VLANS)"); - return -1; - } - printf("Found: %i vlans for port: %i\n", rep.num, portidx); - return rep.num; -} - - -int htoi(char *s) -{ - char ch; - int i = 0; - while ((ch = *s++)) { - i <<= 4; - i += (ch>='0'&&ch<='9')?(ch-'0'):((ch>='a'&&ch<='f')?(ch-'a'+10):((ch>='A'&&ch<='F')?(ch-'A'+10):0)); - } - return i; -} - -int do_bind(int argc, char *argv[]) -{ - int s; - struct macvlan_ioctl req; - char *ptr; - unsigned char macaddr[6]; - - if (argc < 3) { - printf("usage: %s <ifname> <macaddr>\n", argv[0]); - return 1; - } - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket"); - return 1; - } - - req.cmd = MACVLAN_BIND; - req.ifname = argv[1]; /* name of vlan to which we are binding a MAC address */ - - /* assemble the macaddr */ - ptr = argv[2]; - if (strlen(ptr) != 17) { - printf("bad macaddr format: need aa:bb:cc:dd:ee:ff\n"); - return 1; - } - for (ptr = argv[2]+2; ptr < argv[2]+16; ptr+=3) - *ptr = 0; - ptr = argv[2]; - macaddr[0] = (unsigned char)htoi(ptr); - macaddr[1] = (unsigned char)htoi(ptr+3); - macaddr[2] = (unsigned char)htoi(ptr+6); - macaddr[3] = (unsigned char)htoi(ptr+9); - macaddr[4] = (unsigned char)htoi(ptr+12); - macaddr[5] = (unsigned char)htoi(ptr+15); - req.macaddr = macaddr; - - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (MACVLAN_BIND)"); - return 1; - } - return 0; -} - -int do_unbind(int argc, char *argv[]) -{ - int s; - struct macvlan_ioctl req; - char *ptr; - unsigned char macaddr[6]; - - if (argc < 3) { - printf("usage: %s <ifname> <macaddr>\n", argv[0]); - return 1; - } - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket"); - return 1; - } - - req.cmd = MACVLAN_UNBIND; - req.ifname = argv[1]; /* name of vlan from which we are deleting a MAC address */ - - /* assemble the macaddr */ - ptr = argv[2]; - if (strlen(ptr) != 17) { - printf("bad macaddr format: need aa:bb:cc:dd:ee:ff\n"); - return 1; - } - for (ptr = argv[2]+2; ptr < argv[2]+16; ptr+=3) - *ptr = 0; - ptr = argv[2]; - macaddr[0] = (unsigned char)htoi(ptr); - macaddr[1] = (unsigned char)htoi(ptr+3); - macaddr[2] = (unsigned char)htoi(ptr+6); - macaddr[3] = (unsigned char)htoi(ptr+9); - macaddr[4] = (unsigned char)htoi(ptr+12); - macaddr[5] = (unsigned char)htoi(ptr+15); - req.macaddr = macaddr; - - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (MACVLAN_UNBIND)"); - return 1; - } - return 0; -} - -int do_info(int argc, char *argv[]) -{ - int s; - struct macvlan_ioctl req; - struct macvlan_ioctl_reply rep; - int nports; - int portidx; - int nifs; - int ifidx; - int nmacs; - int macidx; - unsigned char *p; - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket"); - return 1; - } - /* get the number of ethernet devices which have mac based vlans - * enabled over them - */ - req.cmd = MACVLAN_GET_NUM_PORTS; - req.reply = &rep; - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (GET_NUM_PORTS)"); - return 1; - } - nports = rep.num; - for (portidx = 0; portidx < nports; portidx++) { - char tmpifname[64]; - /* Get the name of this mac-based-vlan enabled - * ethernet device - */ - req.cmd = MACVLAN_GET_PORT_NAME; - req.portidx = portidx; - req.reply = &rep; - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (GET_PORT_NAME)"); - return 1; - } - printf("-%s\n", rep.name); - - /* get the port flags */ - req.cmd = MACVLAN_GET_PORT_FLAGS; - req.portidx = portidx; - strcpy(tmpifname, rep.name); - req.ifname = tmpifname; - req.reply = &rep; - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (GET_PORT_FLAGS)"); - return 1; - } - printf("-%s flag: 0x%x\n", tmpifname, rep.num); - - /* Get the number of mac-based-vlans layered - * over this ethernet device - */ - req.cmd = MACVLAN_GET_NUM_VLANS; - req.portidx = portidx; - req.reply = &rep; - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (GET_NUM_VLANS)"); - return 1; - } - nifs = rep.num; - for (ifidx = 0; ifidx < nifs; ifidx++) { - /* Get the name of this vlan */ - req.cmd = MACVLAN_GET_VLAN_NAME; - req.portidx = portidx; - req.ifidx = ifidx; - req.reply = &rep; - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (GET_VLAN_NAME)"); - return 1; - } - /* get the number of mac addresses owned by this vlan */ - printf(" |-%s\n", rep.name); - req.cmd = MACVLAN_GET_NUM_MACS; - req.portidx = portidx; - req.ifidx = ifidx; - req.reply = &rep; - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (GET_NUM_MACS)"); - return 1; - } - nmacs = rep.num; - for (macidx = 0; macidx < nmacs; macidx++) { - /* get the value of this mac address */ - req.cmd = MACVLAN_GET_MAC_NAME; - req.portidx = portidx; - req.ifidx = ifidx; - req.macaddridx = macidx; - req.reply = &rep; - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (GET_MAC_NAME)"); - return 1; - } - p = (unsigned char *) rep.name; - printf(" | |-%02x:%02x:%02x:%02x:%02x:%02x\n", - p[0],p[1],p[2],p[3],p[4],p[5]); - } - } - } - return 0; -} - - -int do_unload(int argc, char *argv[]) -{ - int s; - struct macvlan_ioctl req; - struct macvlan_ioctl_reply rep; - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket"); - return 1; - } - - while (get_num_ports(s) > 0) { - char port[64]; - /* Get the name of this mac-based-vlan enabled - * ethernet device - */ - req.cmd = MACVLAN_GET_PORT_NAME; - req.portidx = 0; - req.reply = &rep; - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (GET_PORT_NAME)"); - return 1; - } - strcpy(port, rep.name); - - while (get_num_vlans(0, s) > 0) { - char cmd[128]; - /* Get the name of this vlan */ - req.cmd = MACVLAN_GET_VLAN_NAME; - req.portidx = 0; - req.ifidx = 0; - req.reply = &rep; - if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) { - perror("ioctl (GET_VLAN_NAME)"); - return 1; - } - - /* Configure down the vlan */ - /* This would be faster using IOCTLs, of course! */ - printf("Configuring down interface: %s with ifconfig...", rep.name); - sprintf(cmd, "ifconfig %s down", rep.name); - system(cmd); - - /* Now, can remove it */ - _do_del(rep.name, s); - } - - /* Now, remove the port */ - _do_disable(port, s); - - } - return 0; -} - -int main(int argc, char *argv[]) -{ - unsigned int cmd; - int err; - - if (argc < 2) - goto usage; - - for (cmd = 0; cmd < NCOMMANDS; cmd++) { - if (!strcmp(command_list[cmd].name,argv[1])) - break; - } - if (cmd == NCOMMANDS) - goto usage; - - if ((err = command_list[cmd].fn(argc-1,argv+1))) - goto usage; - return 0; - - usage: - printf("\n%s subcommands:\n\n", argv[0]); - for (cmd = 0; cmd < NCOMMANDS; cmd++) { - printf("%s %s:\t%s\n",argv[0],command_list[cmd].name,command_list[cmd].short_help); - } - return err; -} diff --git a/tcpdump-3.4/CVS/Entries b/tcpdump-3.4/CVS/Entries deleted file mode 100644 index baec772..0000000 --- a/tcpdump-3.4/CVS/Entries +++ /dev/null @@ -1,2 +0,0 @@ -D/lbl//// -D/linux-include//// diff --git a/tcpdump-3.4/CVS/Repository b/tcpdump-3.4/CVS/Repository deleted file mode 100644 index 7759328..0000000 --- a/tcpdump-3.4/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/tcpdump-3.4 diff --git a/tcpdump-3.4/CVS/Root b/tcpdump-3.4/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/tcpdump-3.4/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/tcpdump-3.4/lbl/CVS/Entries b/tcpdump-3.4/lbl/CVS/Entries deleted file mode 100644 index 1784810..0000000 --- a/tcpdump-3.4/lbl/CVS/Entries +++ /dev/null @@ -1 +0,0 @@ -D diff --git a/tcpdump-3.4/lbl/CVS/Repository b/tcpdump-3.4/lbl/CVS/Repository deleted file mode 100644 index f9d5b2f..0000000 --- a/tcpdump-3.4/lbl/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/tcpdump-3.4/lbl diff --git a/tcpdump-3.4/lbl/CVS/Root b/tcpdump-3.4/lbl/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/tcpdump-3.4/lbl/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/tcpdump-3.4/linux-include/CVS/Entries b/tcpdump-3.4/linux-include/CVS/Entries deleted file mode 100644 index d74c534..0000000 --- a/tcpdump-3.4/linux-include/CVS/Entries +++ /dev/null @@ -1,3 +0,0 @@ -D/net//// -D/netinet//// -D/sys//// diff --git a/tcpdump-3.4/linux-include/CVS/Repository b/tcpdump-3.4/linux-include/CVS/Repository deleted file mode 100644 index 63abf70..0000000 --- a/tcpdump-3.4/linux-include/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/tcpdump-3.4/linux-include diff --git a/tcpdump-3.4/linux-include/CVS/Root b/tcpdump-3.4/linux-include/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/tcpdump-3.4/linux-include/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/tcpdump-3.4/linux-include/net/CVS/Entries b/tcpdump-3.4/linux-include/net/CVS/Entries deleted file mode 100644 index 1784810..0000000 --- a/tcpdump-3.4/linux-include/net/CVS/Entries +++ /dev/null @@ -1 +0,0 @@ -D diff --git a/tcpdump-3.4/linux-include/net/CVS/Repository b/tcpdump-3.4/linux-include/net/CVS/Repository deleted file mode 100644 index 72afc29..0000000 --- a/tcpdump-3.4/linux-include/net/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/tcpdump-3.4/linux-include/net diff --git a/tcpdump-3.4/linux-include/net/CVS/Root b/tcpdump-3.4/linux-include/net/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/tcpdump-3.4/linux-include/net/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/tcpdump-3.4/linux-include/netinet/CVS/Entries b/tcpdump-3.4/linux-include/netinet/CVS/Entries deleted file mode 100644 index 1784810..0000000 --- a/tcpdump-3.4/linux-include/netinet/CVS/Entries +++ /dev/null @@ -1 +0,0 @@ -D diff --git a/tcpdump-3.4/linux-include/netinet/CVS/Repository b/tcpdump-3.4/linux-include/netinet/CVS/Repository deleted file mode 100644 index 3ae1a1b..0000000 --- a/tcpdump-3.4/linux-include/netinet/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/tcpdump-3.4/linux-include/netinet diff --git a/tcpdump-3.4/linux-include/netinet/CVS/Root b/tcpdump-3.4/linux-include/netinet/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/tcpdump-3.4/linux-include/netinet/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/tcpdump-3.4/linux-include/sys/CVS/Entries b/tcpdump-3.4/linux-include/sys/CVS/Entries deleted file mode 100644 index 1784810..0000000 --- a/tcpdump-3.4/linux-include/sys/CVS/Entries +++ /dev/null @@ -1 +0,0 @@ -D diff --git a/tcpdump-3.4/linux-include/sys/CVS/Repository b/tcpdump-3.4/linux-include/sys/CVS/Repository deleted file mode 100644 index 6a6e5d2..0000000 --- a/tcpdump-3.4/linux-include/sys/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -vlan/tcpdump-3.4/linux-include/sys diff --git a/tcpdump-3.4/linux-include/sys/CVS/Root b/tcpdump-3.4/linux-include/sys/CVS/Root deleted file mode 100644 index 469c859..0000000 --- a/tcpdump-3.4/linux-include/sys/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:greear@ns1.wanfear.com:/home/cvs/vlan Binary files differdiff --git a/vconfig.c b/vconfig.c deleted file mode 100644 index c89cfa0..0000000 --- a/vconfig.c +++ /dev/null @@ -1,273 +0,0 @@ -// -//Copyright (C) 2001 Ben Greear -// -//This program is free software; you can redistribute it and/or -//modify it under the terms of the GNU Library General Public License -//as published by the Free Software Foundation; either version 2 -//of the License, or (at your option) any later version. -// -//This program is distributed in the hope that it will be useful, -//but WITHOUT ANY WARRANTY; without even the implied warranty of -//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -//GNU General Public License for more details. -// -//You should have received a copy of the GNU Library General Public License -//along with this program; if not, write to the Free Software -//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -// To contact the Author, Ben Greear: greearb@candelatech.com -// - - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <strings.h> -#include <sys/ioctl.h> -#include <linux/if_vlan.h> -#include <linux/sockios.h> -#include <string.h> -#include <sys/socket.h> -#include <sys/types.h> - - -#define MAX_HOSTNAME 256 - - -static char* usage = - "\n" -"Usage: add [interface-name] [vlan_id]\n" -" rem [vlan-name]\n" -" set_flag [interface-name] [flag-num] [0 | 1]\n" -" set_egress_map [vlan-name] [skb_priority] [vlan_qos]\n" -" set_ingress_map [vlan-name] [skb_priority] [vlan_qos]\n" -" set_name_type [name-type]\n" -"\n" -"* The [interface-name] is the name of the ethernet card that hosts\n" -" the VLAN you are talking about.\n" -"* The vlan_id is the identifier (0-4095) of the VLAN you are operating on.\n" -"* skb_priority is the priority in the socket buffer (sk_buff).\n" -"* vlan_qos is the 3 bit priority in the VLAN header\n" -"* name-type: VLAN_PLUS_VID (vlan0005), VLAN_PLUS_VID_NO_PAD (vlan5),\n" -" DEV_PLUS_VID (eth0.0005), DEV_PLUS_VID_NO_PAD (eth0.5)\n" -// Debian: this option appears nowhere else in the source, see Debian #398807 -#if 0 -"* bind-type: PER_DEVICE # Allows vlan 5 on eth0 and eth1 to be unique.\n" -" PER_KERNEL # Forces vlan 5 to be unique across all devices.\n" -#endif -"* FLAGS: 1 REORDER_HDR When this is set, the VLAN device will move the\n" -" ethernet header around to make it look exactly like a real\n" -" ethernet device. This may help programs such as DHCPd which\n" -" read the raw ethernet packet and make assumptions about the\n" -" location of bytes. If you don't need it, don't turn it on, because\n" -" there will be at least a small performance degradation. Default\n" -" is OFF.\n"; - -void show_usage() { - fprintf(stdout,usage); -} - -int hex_to_bytes(char* bytes, int bytes_length, char* hex_str) { - int hlen; - int i; - - int j = 0; - char hex[3]; - char* stop; /* not used for any real purpose */ - - hlen = strlen(hex_str); - - hex[2] = 0; - - for (i = 0; i<hlen; i++) { - - hex[0] = hex_str[i]; - i++; - if (i >= hlen) { - return j; /* done */ - } - - hex[1] = hex_str[i]; - bytes[j++] = (char)strtoul(hex, &stop, 16); - } - return j; -} - - -int main(int argc, char** argv) { - int fd; - struct vlan_ioctl_args if_request; - - char* cmd = NULL; - char* if_name = NULL; - unsigned int vid = 0; - unsigned int skb_priority; - unsigned short vlan_qos; - unsigned int nm_type = VLAN_NAME_TYPE_PLUS_VID; - - char* conf_file_name = "/proc/net/vlan/config"; - - memset(&if_request, 0, sizeof(struct vlan_ioctl_args)); - - if ((argc < 3) || (argc > 5)) { - fprintf(stdout,"Expecting argc to be 3-5, inclusive. Was: %d\n",argc); - - show_usage(); - exit(1); - } - else { - cmd = argv[1]; - - if (strcasecmp(cmd, "set_name_type") == 0) { - if (strcasecmp(argv[2], "VLAN_PLUS_VID") == 0) { - nm_type = VLAN_NAME_TYPE_PLUS_VID; - } - else if (strcasecmp(argv[2], "VLAN_PLUS_VID_NO_PAD") == 0) { - nm_type = VLAN_NAME_TYPE_PLUS_VID_NO_PAD; - } - else if (strcasecmp(argv[2], "DEV_PLUS_VID") == 0) { - nm_type = VLAN_NAME_TYPE_RAW_PLUS_VID; - } - else if (strcasecmp(argv[2], "DEV_PLUS_VID_NO_PAD") == 0) { - nm_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD; - } - else { - // MATHIEU - //cerr << "Invalid name type.\n"; - fprintf(stderr,"Invalid name type.\n"); - - show_usage(); - exit(1); - } - if_request.u.name_type = nm_type; - } - else { - if_name = argv[2]; - if (strlen(if_name) > 15) { - // MATHIEU - //cerr << "ERROR: if_name must be 15 characters or less." << endl; - fprintf(stderr,"ERROR: if_name must be 15 characters or less.\n"); - exit(1); - } - strcpy(if_request.device1, if_name); - } - - if (argc == 4) { - vid = atoi(argv[3]); - if_request.u.VID = vid; - } - - if (argc == 5) { - skb_priority = atoi(argv[3]); - vlan_qos = atoi(argv[4]); - if_request.u.skb_priority = skb_priority; - if_request.vlan_qos = vlan_qos; - } - } - - // Open up the /proc/vlan/config - if ((fd = open(conf_file_name, O_RDONLY)) < 0) { - // MATHIEU - //cerr << "ERROR: Could not open /proc/vlan/config.\n"; - fprintf(stderr,"WARNING: Could not open /proc/net/vlan/config. Maybe you need to load the 8021q module, or maybe you are not using PROCFS??\n"); - - } - else { - close(fd); - } - - /* We use sockets now, instead of the file descriptor */ - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "FATAL: Couldn't open a socket..go figure!\n"); - exit(2); - } - - /* add */ - if (strcasecmp(cmd, "add") == 0) { - if_request.cmd = ADD_VLAN_CMD; - if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { - fprintf(stderr,"ERROR: trying to add VLAN #%u to IF -:%s:- error: %s\n", - vid, if_name, strerror(errno)); - exit(3); - } - else { - fprintf(stdout,"Added VLAN with VID == %u to IF -:%s:-\n", - vid, if_name); - if (vid == 1) { - fprintf(stdout, "WARNING: VLAN 1 does not work with many switches,\nconsider another number if you have problems.\n"); - } - } - }//if - else if (strcasecmp(cmd, "rem") == 0) { - if_request.cmd = DEL_VLAN_CMD; - if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { - fprintf(stderr,"ERROR: trying to remove VLAN -:%s:- error: %s\n", - if_name, strerror(errno)); - exit(4); - } - else { - fprintf(stdout,"Removed VLAN -:%s:-\n", if_name); - } - }//if - else if (strcasecmp(cmd, "set_egress_map") == 0) { - if_request.cmd = SET_VLAN_EGRESS_PRIORITY_CMD; - if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { - fprintf(stderr,"ERROR: trying to set egress map on device -:%s:- error: %s\n", - if_name, strerror(errno)); - exit(5); - } - else { - fprintf(stdout,"Set egress mapping on device -:%s:- " - "Should be visible in /proc/net/vlan/%s\n", - if_name, if_name); - } - } - else if (strcasecmp(cmd, "set_ingress_map") == 0) { - if_request.cmd = SET_VLAN_INGRESS_PRIORITY_CMD; - if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { - fprintf(stderr,"ERROR: trying to set ingress map on device -:%s:- error: %s\n", - if_name, strerror(errno)); - exit(6); - } - else { - fprintf(stdout,"Set ingress mapping on device -:%s:- " - "Should be visible in /proc/net/vlan/%s\n", - if_name, if_name); - } - } - else if (strcasecmp(cmd, "set_flag") == 0) { - if_request.cmd = SET_VLAN_FLAG_CMD; - if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { - fprintf(stderr,"ERROR: trying to set flag on device -:%s:- error: %s\n", - if_name, strerror(errno)); - exit(7); - } - else { - fprintf(stdout,"Set flag on device -:%s:- " - "Should be visible in /proc/net/vlan/%s\n", - if_name, if_name); - } - } - else if (strcasecmp(cmd, "set_name_type") == 0) { - if_request.cmd = SET_VLAN_NAME_TYPE_CMD; - if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { - fprintf(stderr,"ERROR: trying to set name type for VLAN subsystem, error: %s\n", - strerror(errno)); - exit(8); - } - else { - fprintf(stdout,"Set name-type for VLAN subsystem." - " Should be visible in /proc/net/vlan/config\n"); - } - } - else { - fprintf(stderr, "Unknown command -:%s:-\n", cmd); - - show_usage(); - exit(5); - } - - return 0; -}/* main */ diff --git a/vconfig.h b/vconfig.h deleted file mode 100644 index e69de29..0000000 --- a/vconfig.h +++ /dev/null diff --git a/vconfig.o b/vconfig.o Binary files differdeleted file mode 100644 index 8e8da0e..0000000 --- a/vconfig.o +++ /dev/null diff --git a/vconfig.spec b/vconfig.spec deleted file mode 100644 index c05c7b5..0000000 --- a/vconfig.spec +++ /dev/null @@ -1,61 +0,0 @@ -Summary: Linux 802.1q VLAN configuration utility -Name: vconfig -Version: 1.6 -Release: 4 -License: distributable -Group: Applications/System -Source: http://scry.wanfear.com/~greear/vlan/vlan.%{version}.tar.gz -Source1: ifup-vlan -Source2: ifdown-vlan -Source3: vlan.sysconfig -Source4: README.ifup -Source5: ifcfg-vlan2-example -URL: http://scry.wanfear.com/~greear/vlan.html -BuildRoot: %{_tmppath}/%{name}-%{version}-root -Packager: Dale Bewley <dale@bewley.net> -BuildRequires: kernel-source >= 2.4.14 -Requires: kernel >= 2.4.14 - -%description -802.1q VLAN support is now in the linux kernel as of 2.4.14. -This package provides the vlan configuration utility, vconfig, -and ifup and ifdown scripts for configuring interfaces. - -%prep -%setup -q -n vlan -cp %SOURCE4 . -cp %SOURCE5 . - -%build -make - -%clean -rm -rf $RPM_BUILD_ROOT - -%install -rm -rf $RPM_BUILD_ROOT -mkdir -p $RPM_BUILD_ROOT/%{_sbindir} -mkdir -p $RPM_BUILD_ROOT/etc/sysconfig/network-scripts -mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man8 -install -o 0 -g 0 -m 755 vconfig $RPM_BUILD_ROOT/%{_sbindir}/vconfig -install -o 0 -g 0 -m 755 vconfig.8 $RPM_BUILD_ROOT/%{_mandir}/man8 -install -o 0 -g 0 -m 755 %SOURCE1 $RPM_BUILD_ROOT/etc/sysconfig/network-scripts/ifup-vlan -install -o 0 -g 0 -m 755 %SOURCE2 $RPM_BUILD_ROOT/etc/sysconfig/network-scripts/ifdown-vlan -install -o 0 -g 0 -m 644 %SOURCE3 $RPM_BUILD_ROOT/etc/sysconfig/vlan - -%files -%defattr(-,root,root) -%doc CHANGELOG contrib README README.ifup vlan.html vlan_test.pl ifcfg-vlan2-example -%{_sbindir}/vconfig -%{_mandir}/man8/vconfig.8.gz -/etc/sysconfig/vlan -/etc/sysconfig/network-scripts/ifup-vlan -/etc/sysconfig/network-scripts/ifdown-vlan - -%changelog -* Fri Apr 05 2002 Dale Bewley <dale@bewley.net> -- update to 1.6 -- add ifup scripts - -* Tue Dec 11 2001 Dale Bewley <dale@bewley.net> -- initial specfile diff --git a/vlan.html b/vlan.html deleted file mode 100644 index 0588b61..0000000 --- a/vlan.html +++ /dev/null @@ -1,436 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> - <head> - <title>802.1Q VLAN implementation for Linux</title> - </head> - - <body bgcolor=#ffffff text=#000000> - <h1><center>802.1Q VLAN implementation for Linux</center></h1> - -<center><i> -Updated Sept 30, 2003<br> -Release: 1.8</br> -</i></center> -<P> - -MTU problems exist for many ethernet drivers. Other than that, things seem fairly stable! -<P> - -<center> -<B>PLUG: Check out my company that makes traffic generation and WAN simulation - test equipment based on the Linux operating system:<br> - <a target=_top href="http://www.candelatech.com"><img src="http://www.candelatech.com/images/candela_swirl_small.png" - alt="Candela Technologies" - border=0></a> -<br> -Let us help you test your DSL, Cable Access, Satellite and other network systems!</b> -</center> -<font size = -1> -<BR> -TIP jar on <a href="http://www.candelatech.com/~greear" target="_top"> my home page.</a><P> -</font> - -Join the <a HREF="http://ns1.wanfear.com/mailman/listinfo/vlan">vlan mailing list</a>, - After that, to post, send mail to -<A HREF="mailto:vlan@ns1.wanfear.com">vlan@ns1.wanfear.com</a>. -<P> -Submit a bug/issue/enhancement with the: <a href="http://grok.yi.org:8080/~greear/bugzilla/enter_bug.cgi?product=VLAN%20for%20Linux">VLAN Bugzilla</a></li> -<P> - -I hear that the 2.2/2.4 kernel patches have worked -with these (and other, I'm sure) systems: <P> -<ul> - <li> Cisco: {Catalyst: 6509}, - 3Com: {Corebuilder, Netbuilder II, SuperStack II switch 630}, - Alpine: {3804(SMMi,F32Ti)} - Extreme Ntwks {Summit 48, 48i, 5i} - Foundry: {ServerIronXL, FastIron}</li> - <li> Alteon ACENic Gigabit, 3Com 3c509, realtek RTL8029(AS), RTL8139, DEC DC21140 (tulip), - DFE-570TX quad-21143, Intel PRO/1000 with Intel's driver - </li> -</ul> -<P> - -<u><b>Performance:</b></u> -The difference in running traffic over VLANs v/s regular ethernet is very slight. If -someone has done some sort of benchmark, I'll be happy to place it here! - -<b><center>VLAN related Resources.</center></b> -<ul> -<li> <a href="#setup"> VLAN Installation & Configuration info.</a></li> -<li> <a href="#cvs_setup"> CVS Access.</a></li> -<li> <a href="vlan/howto.html"> VLAN HOWTO/FAQ (Some CISCO & 3COM specific info too.)</a></li> -<li> <a href="http://www.planetconnect.com/vlan/"> Another VLAN Recipe (Some info specific to Intel EEPRO Nics too.)</a></il> -<li> <a href="http://www.geocities.co.jp/AnimeComic-White/6586/vlan.html"> VLAN Research page in Japanese</a></li> -<li> <a href="http://www.geocities.co.jp/AnimeComic-White/6586/vlan-e.html"> VLAN page translated to English</a></li> -<li> <a target=_top href="http://standards.ieee.org/getieee802/download/802.1Q-1998.pdf"> - IEEE 802.1Q Standard</a></li> -</ul> -<P> - -<center><b>Features</b></center> -<ul> - <li>Implements 802.1Q VLAN spec.</li> - <li>Implements support for a non-standard (as far as I know) - MAC-based VLAN functionality.</li> - <li>Can support up to 4094 VLANs per ethernet interface.</li> - <li>Scales well in critical paths: O(n), where n is the number of PHYSICAL ethernet interfaces, - and that is only on ingress. O(1) in every other critical path, as far as I know.</li> - <li>Supports MULTICAST</li> - <li>Can change MAC address of VLAN.</li> - <li>Multiple naming conventions supported, and adjustable at runtime.</li> - <li>Optional header-reordering, to make the VLAN interface look <b>JUST LIKE</b> - an Ethernet interface. This fixes some problems with DHCPd and anything else - that uses a SOCK_PACKET socket. Default setting is off, which works for - every other protocol I know about, and is slightly faster. - </li> -</ul> -<P> - - -<hr> -Download vconfig binaries (source is more flexible, but this will work for most people). -<ul> - <li> <a href="vconfig">vconfig binary for x86</a></li> - <li> <a href="vconfig.arm">vconfig binary for StrongArm</a></li> -</ul> -<P> - -<hr> -<center><b>Change Log</b></center> -<ul> -<P> - -<li> <b><a href="vlan/vlan.1.8.tar.gz">Release 1.8 (gz)</a> For Kernel: 2.4.21+ Sept 30, 2003:</b><br> - <P> - <ul> - <li>Updated MAC-VLAN code and completed testing. Based on Alex Zeffertt's - work but much has been re-written and he cannot be held responsible! - Please send all bug reports to the VLAN mailing list. The Candela Technologies unified - patch is the thing to apply now, and it contains various other not-necessarily-VLAN - related bits and pieces. - </li> - </ul> -</li> - -<P> -<li> <b><a href="vlan/vlan.1.7m.tar.gz">Release 1.7m (gz)</a> For Kernel: 2.4.14+ Feb 27, 2003:</b><br> - <P> - <ul> - <li>Added Alex Zeffertt's MAC-based VLAN code. Not fully functional - yet (mostly because I broke his original work...gonna fix it up - soon. Grab & use his raw patch* files in the meantime. - </li> - </ul> -</li> -<P> - -<li> <b><a href="vlan/vlan.1.7.tar.gz">Release 1.7 (gz)</a> For Kernel: 2.4.14+ Feb 27, 2003:</b><br> - <P> - <ul> - <li>Clarified the license for vconfig (GPL). Other small tweaks. </li> - </ul> -</li> - -<P> -<li> <b><a href="vlan/vlan.1.6.tar.gz">Release 1.6 (gz)</a> For Kernel: 2.4.14+ March 24, 2002:</b><br> - <P> - <ul> - <li>Removed 2.4 kernel patch: It's in the standard kernel now.</li> - <li>Updated vconfig to fix some compile issues, and enable cross-compilation - to the StrongARM platform (changes should help other cross-compile - attempts too.)</li> - </ul> -</li> -<P> - -<li> <b><a href="vlan/vlan.1.5.tar.gz">Release 1.5 (gz)</a> For Kernel: 2.4.12-pre5 October 22, 2001:</b><br> - <P> - <ul> - <li>Mostly added other peoples fixes and patches (thanks folks!)</li> - <li>Finally fixed mc-list leakage (Ard van Breemen)</li> - <li>Flush mc-list at vlan-destory (Ard van Breemen)</li> - <li>Add vconfig man page to distribution (Ard van Breemen)</li> - <li>Fix problem with /proc and renaming VLAN devices (af AT devcon D.T net)</li> - <li>Add relatively large change by Nick Eggelston that makes VLAN - devices more transparent to tools like tcpdump and other raw - packet snoopers. This will only be enabled when the REORDER_HDR - flag is set.</li> - </ul> -</li> -<P> - -<li> <b><a href="vlan/vlan.1.4.tar.gz">Release 1.4 (gz)</a> For Kernel: 2.4.8 August 16, 2001:</b><br> - <P> - <ul> - <li> Code should no longer require /proc interface in order to get at the IOCTLs. - The IOCTLs are now tied to sockets. When using modules, it may auto-load now, too...</li> - <li> Fixed format string error in proc fs display.</li> - <li> Fixed crash bug relating to memory allocation with locks held (we now use GF_ATOMIC)</li> - <li> hard_start_xmit will now grow the packet header if there is not enough headroom. This - may fix an MPLS-over-VLAN problem, though the real solution is to make MPLS allocate - more headroom anyway...</li> - <li> vconfig was changed to use the new IOCTL API, and the old vconfig WILL NOT WORK - with this or any newer patches...</li> - </ul> -</li> - -<P> -<li> <b><a href="vlan/vlan.1.0.3.tar.gz">Release 1.0.3 (gz)</a> For Kernel: 2.4.7 August 5, 2001:</b><br> - <P> - <ul> - <li> Re-worked code to be more stable and more in-line with what the kernel maintainers - want to see before the VLAN patch is included into the kernel.</li> - <li> One of those requests was to change the default naming scheme to eth0.5, for a VLAN - of VID 5 on eth0. You can over-ride this naming behaviour with the vconfig tool.</li> - <li> There were *NO* changes to the 2.2 series patch, and I don't expect to ever make - any more changes there...</li> - </ul> - -</li> -<P> - -<li> <b><a href="vlan/vlan.1.0.1.tar.gz">Release 1.0.1 (gz)</a> For Kernel: 2.2.18/19, 2.4.3-pre3 April 16, 2001:</b><br> - <P> - <ul> - <li> Incorporated a fix for changing a MAC on a VLAN, it now correctly sets PACKET_HOST. - Thanks to Martin Bokaemper for this one.</li> - <li> The 2.4 series patch should now compile as a module, thanks to a tweak from someone - who's mail I have lost! Anyway, 3 cheers to the un-named coder!</li> - <li> There were *NO* changes to the 2.2 series patch, though I did verify that it seems to - work fine with the 2.2.19 kernel.</li> - </ul> - -</li> - -<P> -<li> <b><a href="vlan/vlan.1.0.0.tar.gz">Release 1.0.0 (gz)</a> For Kernel: 2.2.18, 2.4.0 Jan 14, 2001:</b><br> - <P> - <ul> - <li> Really fixed (and tested) MAC change-ability. When you set the MAC address on - a VLAN, it will also attempt to set the underlying device to PROMISCious mode - (otherwise, the VLAN will not receive any packets.)</li> - <li> Hashed-device lookup is disabled by default because some people had trouble with - the 'lo' device. Please feel free to re-enable by editing the line in net/core/dev.c - (search for #define BEN_FAST_DEV_LOOKUP).</li> - <li> vconfig should warn when creating VLAN 1, because that VLAN is not compatible with many - switches.</li> - </ul> - -</li> - -<P> -<li> <b><a href="vlan/vlan.0.0.15.tar.gz">Release 0.0.15 (gz)</a> For Kernel: 2.2.18, 2.4.prerelease Dec 31, 2000:</b><br> - <P> - <ul> - <li>Merged most of Matti Aarnio's patches. This means no significant patch to - eth.c now, and will help port VLANs to non-ethernet devices (ie ppp, TokenRing??).</li> - <li> Setting the MAC address should work now..I think it was broken before.</li> - <li> Miscellaneous code re-organization to make patches to existing files smaller.</li> - </ul> - -</li> - -<P> -<li> <b><a href="vlan/vlan.0.0.14.tar.gz">Release 0.0.14 (gz)</a> For Kernel: 2.2.17, 2.4.pre9 Oct 26, 2000:</b><br> - <P> - This code seems pretty stable. - <ul> - <li>Removed vlan-space-per-machine, so vlan-space-per-NIC is mandatory now.</li> - <li>DHCP might work now, as I've added support for encapsulating regular ethernet - frames if they are sent to the vlan driver.</li> - <li>Fixed up the name/index hashing stuff to handle changing the name on a device.</li> - <li>Took out default VID & default priority, as their usefullness was in question, - and the code was broken anyway.</li> - </ul> - -</li> - -<P> -<li> <b><a href="vlan/vlan.0.0.13.tar.gz">Release 0.0.13 (gz)</a> For Kernel: 2.2.17, 2.4.pre9 Oct 11, 2000:</b><br> - <center><b>KNOWN TO BE BUSTED, here for posterity's sake.</b></center> - <P> - <ul> - <li>Added support for MULTICAST to the VLAN devices. Thanks to - <a href="http://vlan.sourceforge.net" target=_top>Gleb & Co</a> for most of - that code.</li> - <li>Added the ability to set the MAC address on the VLAN. For now, you'll either need - to set your Ethernet NIC into PROMISC mode, or maybe figure out some multi-cast - ethernet address to set on the NIC. This has not been tested well at all.</li> - <li>Added a hashed device-name lookup scheme. This greatly speeds up ifconfig -a. - I was able to run an ifconfig -a in 20 seconds on a Celeron 500, with 4000 - vlan devices configured!!</li> - <li>Added vlan_test.pl to help me find dumb bugs. Feel free to make this much - more powerful, and send the code back to me!</li> - <li>vconfig.c has been converted to C code now, instead of C++. Thanks to MATHIEU.</li> - <li>Significantly cleaned up the code w/out decreasing any useful functionality, - I believe.</li> - <li>Removed the DHCP stuff from the VLAN distribution.</li> - </ul> - -</li> -<P> - -<li> <b><a href="vlan/vlan.0.0.12.tar.gz">Release 0.0.12 (gz)</a> For Kernel: 2.2.16, 2.4.pre7 August 27, 2000:</b><br> - Added ability to re-order the VLAN packet so that it looks like a real ethernet - packet for the ingress pathway. This should help DHCP and other programs that insist - on reading the raw buffer and then make assumptions about byte offsets. I don't have - a good way to test this fully, so consider it experimental :) This behavior can be - changed at run-time, and is set on a per-VLAN basis. The default is NOT to reorder the - header, which has been the only behavior up untill this point. The <tt>vconfig</tt> - program can set/clear the flag, by using a VLAN IOCTL. You can read the flag's value - from the /proc/net/vlan/vlan* files. -<P> - You can also set a default priority on a NON-VLAN device. This priority will only - be used when the default_VID for the device is set as well. This priority won't - be mapped anywhere, just copied straight into the skb->priority. It is a uint16. -<P> - The 2.3 patch is now the 2.4 patch, and it has been tested against 2.4.pre7. -</li> -<P> - -<li> <b><a href="vlan/vlan.0.0.11.tar.gz">Release 0.0.11 (gz)</a> For Kernel: 2.2.13/14, 2.3.99 April 23, 2000:</b><br> - Added real support for PRIORITY. Through IOCTL calls (see the vconfig program), you can set - explicit ingress and egress mappings to/from the VLAN QOS bits and the sk_buff->priority - field. This is not tested very well, as I don't know much about how people really use the - priority field... Took out the round-robin aggretation that went in in rls 0.10, as it was - mainly just a hack, and doing link aggregation at a lower level and then putting VLAN on - top of that virtual device probably makes more sense. The vconfig program changed to support - the new features..here's it's new usage:<br> -<pre> -Usage: add [interface-name] [vlan_id] - rem [vlan-name] - set_dflt [interface-name] [vlan_id] - add_port [port-name] [vlan_id] - rem_port [port-name] [vlan_id] - set_egress_map [vlan-name] [skb_priority] [vlan_qos] - set_ingress_map [vlan-name] [skb_priority] [vlan_qos] - set_name_type [name-type] - set_bind_mode [bind-type] - -* The [interface-name] is the name of the ethernet card that hosts - the VLAN you are talking about. -* The port-name is the name of the physical interface that a VLAN - may be attached to. -* The vlan_id is the identifier (0-4095) of the VLAN you are operating on. -* skb_priority is the priority in the socket buffer (sk_buff). -* vlan_qos is the 3 bit priority in the VLAN header -* name-type: VLAN_PLUS_VID (vlan0005), VLAN_PLUS_VID_NO_PAD (vlan5), - DEV_PLUS_VID (eth0.0005), DEV_PLUS_VID_NO_PAD (eth0.5) -* bind-type: PER_DEVICE # Allows vlan 5 on eth0 and eth1 to be unique. - PER_KERNEL # Forces vlan 5 to be unique across all devices. -</pre> -<P> - The 2.3 patches have been ported foward to 2.3.99, thanks to Patrick for the vlanproc.c - updates! -</li> -<P> - -</ul><hr> -<P> - -<center><h3> -<a name="setup">VLAN Setup and Configuration</a></h3></center> - -To get started, you will want to download the latest vlan.X.X.tar.gz -file (to your $HOME directory.) Unpack it with your favorite commands, for -example: <tt> tar -xvzf vlan.1.6.tar.gz </tt> -<a name="cvs_setup">Alternatively, you can get it from the CVS Repository using something like this:</a><br> -<ol> - <li> Install and configure - <a href="http://www.loria.fr/~molli/cvs-index.html">cvs</a> - on your machine.</li> - <li> Specify the vlan repository:<br> - <b>export CVSROOT=:pserver:anonymous@ns1.wanfear.com:/home/cvs/vlan</b> - </li> - <li> Log in to the repository:<br> - <b>cvs login (PASSWORD: anonymous)</b> - </li> - <li> Check out the source:<br> - <b> mkdir vlan; cd vlan; cvs -z3 checkout vlan</b> - </li> -</ol> -<P> - -Now, you should have a vlan directory in your home directory. You only have -to patch the kernel if you are using Linux 2.4.14 or earlier. Now, -read the README or other docs to figure out what kernel it patches against. -A list of mirrors are kept at <a href=http://www.kernel.org>www.kernel.org</a>. -Unzip and un-tar this in your home directory as well, which should -create a linux directory in your $HOME directory. Example:<tt> -tar -xvzf linux-2.2.14.tar.gz</tt><P> - -Now add the VLAN kernel changes to the kernel if your kernel requires it. I finally figured -out how to do patches that diff can handle (I think I did it right at least!). You -will find the patch in the vlan directory. It will be called: vlan.patch, -or something equally straight-foward. Apply the patch to your kernel:<p> - -<tt>cd $HOME/linux<br> -patch -p 1 < $HOME/vlan/[vlan.patch]</br> -</tt> -<P> - -Your new, patched, kernel should be in your INCLUDE path before trying to -compile the vconfig program. One way to get things working is to link $HOME/linux -to the 'linux' directory that you just un-zipped and patched. A command might -be something like: -<tt>cd $HOME; ln -s /home/greear/kernel/2.4/linux.dev linux</tt> -<P> - -Build the vconfig program in the $HOME/vlan directory:<br> -<tt>cd $HOME/vlan<br> -make<br> -</tt> -<P> - -Now, time to compile your new kernel! Use the <tt>make xconfig</tt> -command in your $HOME/linux directory to select your kernel options. The -option related to 802.1Q VLANs is found under the <b>Networking options</b>. -If the option is not highlighted, make sure you select "Experimental Drivers" -in one of the first xconfig menus. -<P> - -Assuming your kernel compiled cleanly (yell if it didn't and you think my -code broke it!!), you are now ready to try it out!! Install your kernel -in the normal manner (fix up your <tt>/etc/lilo.conf</tt> file appropriately and -run <tt>lilo</tt> as root.) Reboot your computer and choose your new kernel. -<P> -As your computer comes back to life, there will be little sign that you are -now 802.1Q capable, other than a line spit out during the boot process. -There should be a config programs in your $HOME/vlan -directory: <tt>vconfig</tt>. <b>vconfig</b> is used -to create and destroy VLAN devices. So, lets create a VLAN device on your -first ethernet NIC. vconfig<return> will list a short spiel on how to -use it. The vconfig command I usually use is: -<P> - -<tt>vconfig add eth0 5</tt> -<P> - -This attempts to create a VLAN device with VLAN-ID of 5 on the eth0 device. -If you want to delete a VLAN, use something like: -<P> -<tt>vconfig rem eth0.5</tt> -<P> - -You will also need to give it an ip, eg: <tt>ifconfig -i eth0.5 192.168.2.1</tt><br> -and configure it UP: <tt>ifconfig -i eth0.5 up</tt> -<P> - -<b>NOTE:</b> You can get lots of VLAN related configuration information from -the <b>/proc/net/vlan/*</b> files by using 'cat' or 'more' to look at them. -<P> - -Please get in contact with me if you have suggestions, patches, or other -comments. -<P> - - <hr> - <address><a href="mailto:greearb@candelatech.com">greearb@candelatech.com</a> - <a target=_top href="index.html">Ben Greear's Home Page</a></address> -<!-- Created: Sat Jan 30 18:27:28 MST 1999 --> -<!-- hhmts start --> -Last modified: Tue Sep 30 14:16:14 PDT 2003 -<!-- hhmts end --> - </body> -</html> diff --git a/vlan_2.2.patch b/vlan_2.2.patch deleted file mode 100644 index e038825..0000000 --- a/vlan_2.2.patch +++ /dev/null @@ -1,2927 +0,0 @@ -diff -u -r -N -X /home/greear/exclude.list linux/include/linux/if_ether.h linux.dev/include/linux/if_ether.h ---- linux/include/linux/if_ether.h Sun Dec 10 17:49:44 2000 -+++ linux.dev/include/linux/if_ether.h Thu Jan 4 20:41:19 2001 -@@ -32,6 +32,36 @@ - #define ETH_DATA_LEN 1500 /* Max. octets in payload */ - #define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ - -+ -+#ifdef CONFIG_VLAN_802_1Q -+ -+ -+#define VLAN_ETH_ALEN 6 /* Octets in one ethernet addr */ -+#define VLAN_ETH_HLEN 18 /* Total octets in header. */ -+#define VLAN_ETH_ZLEN 64 /* Min. octets in frame sans FCS */ -+ -+/* These could be bumped up by 4, but I'm not sure if all the underlying -+ * drivers would like it. -+ * UPDATE: Bumping it by 4, as per Klika's suggestion below. --BLG -+ * -+ * According to 802.3ac, the packet can be 4 bytes longer. --Klika Jan -+ */ -+#define VLAN_ETH_DATA_LEN 1500 /* Max. octets in payload */ -+#define VLAN_ETH_FRAME_LEN 1518 /* Max. octets in frame sans FCS */ -+ -+struct vlan_ethhdr -+{ -+ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ -+ unsigned char h_source[ETH_ALEN]; /* source ether addr */ -+ unsigned short h_vlan_proto; /* Should always be 0x8100 */ -+ unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID */ -+ unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */ -+}; -+ -+ -+#endif -+ -+ - /* - * These are the defined Ethernet Protocol ID's. - */ -@@ -54,6 +84,7 @@ - #define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ - #define ETH_P_ATALK 0x809B /* Appletalk DDP */ - #define ETH_P_AARP 0x80F3 /* Appletalk AARP */ -+#define ETH_P_802_1Q 0x8100 /* 802.1Q VLAN Extended Header */ - #define ETH_P_IPX 0x8137 /* IPX over DIX */ - #define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ - #define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */ -diff -u -r -N -X /home/greear/exclude.list linux/include/linux/if_vlan.h linux.dev/include/linux/if_vlan.h ---- linux/include/linux/if_vlan.h Wed Dec 31 17:00:00 1969 -+++ linux.dev/include/linux/if_vlan.h Sun Jan 14 14:30:56 2001 -@@ -0,0 +1,238 @@ -+/* -*- linux-c -*- -+ * VLAN An implementation of 802.1Q VLAN tagging. -+ * -+ * Version: 0.0.1 03/06/99 -+ * -+ * Authors: Ben Greear <greearb@candelatech.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ * -+ */ -+ -+#ifndef _LINUX_IF_VLAN_H_ -+#define _LINUX_IF_VLAN_H_ -+ -+#ifdef __KERNEL__ -+ -+ -+/* externally defined structs */ -+struct vlan_group; -+struct device; -+struct sk_buff; -+struct packet_type; -+struct vlan_collection; -+ -+ -+#include <linux/proc_fs.h> /* for proc_dir_entry */ -+ -+ -+ -+/* Find a VLAN device by the MAC address of it's Ethernet device, and -+ * it's VLAN ID. The default configuration is to have VLAN's scope -+ * to be box-wide, so the MAC will be ignored. The mac will only be -+ * looked at if we are configured to have a seperate set of VLANs per -+ * each MAC addressable interface. Note that this latter option does -+ * NOT follow the spec for VLANs, but may be useful for doing very -+ * large quantities of VLAN MUX/DEMUX onto FrameRelay or ATM PVCs. -+ */ -+struct device *find_802_1Q_vlan_dev(struct device* real_dev, -+ unsigned short VID); /* vlan.c */ -+ -+ -+int register_netdevice(struct device *dev); /* found in dev.c */ -+int unregister_netdevice(struct device *dev); /* found in dev.c */ -+int dev_new_index(void); /* dev.c */ -+ -+/* found in vlan_dev.c */ -+struct net_device_stats* vlan_dev_get_stats(struct device* dev); -+int vlan_dev_rebuild_header(struct sk_buff *skb); -+int vlan_dev_type_trans(struct sk_buff *skb, struct device *dev, -+ struct packet_type* ptype); -+int vlan_dev_hard_header(struct sk_buff *skb, struct device *dev, -+ unsigned short type, void *daddr, void *saddr, -+ unsigned len); -+int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct device *dev); -+int vlan_dev_change_mtu(struct device *dev, int new_mtu); -+int vlan_dev_set_mac_address(struct device *dev, void* addr); -+int vlan_dev_open(struct device* dev); -+int vlan_dev_stop(struct device* dev); -+int vlan_dev_init(struct device* dev); -+void vlan_dev_destruct(struct device* dev); -+int vlan_dev_set_vlan_flag(char* dev_name, __u32 flag, short flag_val); -+/* I'm ignorant of these right now. --BLG -+int vlan_dev_header_cache(struct neighbour *neigh, struct hh_cache *hh); -+void vlan_dev_header_cache_update(struct hh_cache *hh, struct device *dev, -+ unsigned char * haddr); -+*/ -+void vlan_dev_copy_and_sum(struct sk_buff *dest, unsigned char *src, -+ int length, int base); -+int vlan_dev_set_ingress_priority(char* dev_name, __u32 skb_prio, short vlan_prio); -+int vlan_dev_set_egress_priority(char* dev_name, __u32 skb_prio, short vlan_prio); -+ -+/* VLAN multicast stuff */ -+/* Delete all of the MC list entries from this vlan device. Also deals -+ * with the underlying device... -+ */ -+void vlan_flush_mc_list(struct device* dev); -+/* copy the mc_list into the vlan_info structure. */ -+void vlan_copy_mc_list(struct dev_mc_list* mc_list, struct vlan_dev_info* vlan_info); -+/** dmi is a single entry into a dev_mc_list, a single node. mc_list is -+ * an entire list, and we'll iterate through it. -+ */ -+int vlan_should_add_mc(struct dev_mc_list *dmi, struct dev_mc_list *mc_list); -+/** Taken from Gleb + Lennert's VLAN code, and modified... */ -+void vlan_dev_set_multicast_list(struct device *vlan_dev); -+ -+ -+int vlan_collection_add_vlan(struct vlan_collection* vc, unsigned short vlan_id, -+ unsigned short flags); -+int vlan_collection_remove_vlan(struct vlan_collection* vc, -+ struct device* vlan_dev); -+int vlan_collection_remove_vlan_id(struct vlan_collection* vc, unsigned short vlan_id); -+ -+ -+ -+/* found in vlan.c */ -+/* Our listing of VLAN group(s) */ -+extern struct vlan_group* p802_1Q_vlan_list; -+ -+ -+#define VLAN_NAME "vlan" -+ -+/* if this changes, algorithm will have to be reworked because this -+ * depends on completely exhausting the VLAN identifier space. Thus -+ * it gives constant time lookup, but it many cases it wastes memory. -+ */ -+#define VLAN_GROUP_ARRAY_LEN 4096 -+ -+struct vlan_group { -+ int real_dev_ifindex; /* The index of the ethernet(like?) device the vlan is attached to. */ -+ struct device* vlan_devices[VLAN_GROUP_ARRAY_LEN]; -+ -+ struct vlan_group* next; /* the next in the list */ -+}; -+ -+ -+/* __Flags__ relating to the vlan ports */ -+#define VLAN_FLAG_ALLOW_802_3 1 -+#define VLAN_FLAG_ALLOW_802_1Q 2 -+#define VLAN_FLAG_IS_IN_USE 4 -+ -+ -+struct vlan_priority_tci_mapping { -+ unsigned long priority; -+ unsigned short vlan_qos; /* This should be shifted when first set, so we only do it -+ * at provisioning time. -+ * ((skb->priority << 13) & 0xE000) -+ */ -+ struct vlan_priority_tci_mapping* next; -+}; -+ -+/* Holds information that makes sense if this device is a VLAN device. */ -+struct vlan_dev_info { -+ /** This will be the mapping that correlates skb->priority to -+ * 3 bits of VLAN QOS tags... -+ */ -+ unsigned long ingress_priority_map[8]; -+ struct vlan_priority_tci_mapping* egress_priority_map[16]; /* hash table */ -+ -+ unsigned short vlan_id; /* The VLAN Identifier for this interface. */ -+ unsigned short flags; /* (1 << 0) re_order_header This option will cause the -+ * VLAN code to move around the ethernet header on -+ * ingress to make the skb look **exactly** like it -+ * came in from an ethernet port. This destroys some of -+ * the VLAN information in the skb, but it fixes programs -+ * like DHCP that use packet-filtering and don't understand -+ * 802.1Q -+ */ -+ struct dev_mc_list* old_mc_list; /* old multi-cast list for the VLAN interface.. -+ * we save this so we can tell what changes were -+ * made, in order to feed the right changes down -+ * to the real hardware... -+ */ -+ int old_allmulti; /* similar to above. */ -+ int old_promiscuity; /* similar to above. */ -+ struct device* real_dev; /* the underlying device/interface */ -+ struct proc_dir_entry dent; /* Holds the proc data */ -+ unsigned long cnt_inc_headroom_on_tx; /* How many times did we have to grow the skb on TX. */ -+ unsigned long cnt_encap_on_xmit; /* How many times did we have to encapsulate the skb on TX. */ -+}; -+ -+static inline unsigned short vlan_dev_get_egress_qos_mask(struct device* dev, struct sk_buff* skb) { -+ struct vlan_priority_tci_mapping* mp = dev->vlan_dev->egress_priority_map[(skb->priority & 0xF)]; -+ while (mp) { -+ if (mp->priority == skb->priority) { -+ return mp->vlan_qos; /* This should already be shifted to mask correctly with -+ * the VLAN's TCI -+ */ -+ } -+ mp = mp->next; -+ } -+ return 0; -+} -+ -+static inline int vlan_dmi_equals(struct dev_mc_list *dmi1, -+ struct dev_mc_list *dmi2) { -+ return ((dmi1->dmi_addrlen == dmi2->dmi_addrlen) && -+ (memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0)); -+} -+ -+static inline void vlan_destroy_mc_list(struct dev_mc_list *mc_list) { -+ struct dev_mc_list *dmi = mc_list, *next; -+ -+ while(dmi) { -+ next = dmi->next; -+ kfree(dmi); -+ dmi = next; -+ } -+} -+ -+#endif /* __KERNEL__ */ -+ -+/** These are the IOCTLs relating to the /proc/net/vlan/ * files. -+ * Not all may be supported at this time, and some may be primarily -+ * used for testing and obtaining non-standard access to kernel -+ * devices. -+ */ -+ -+#define VLAN_IOCTL 0x52 /* TODO: Can I just make these up??? */ -+ -+enum vlan_ioctls { -+ ADD_VLAN_IOCTL = (VLAN_IOCTL << 8), -+ DEL_VLAN_IOCTL, -+ SET_INGRESS_PRIORITY_IOCTL, -+ SET_EGRESS_PRIORITY_IOCTL, -+ GET_INGRESS_PRIORITY_IOCTL, -+ GET_EGRESS_PRIORITY_IOCTL, -+ SET_NAME_TYPE_IOCTL, -+ SET_VLAN_FLAG_IOCTL -+}; /* vlan_ioctl enum */ -+ -+enum vlan_name_types { -+ VLAN_NAME_TYPE_PLUS_VID, /* Name will look like: vlan0005 */ -+ VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like: eth1.0005 */ -+ VLAN_NAME_TYPE_PLUS_VID_NO_PAD, /* Name will look like: vlan5 */ -+ VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, /* Name will look like: eth0.5 */ -+ VLAN_NAME_TYPE_HIGHEST -+}; -+ -+struct vlan_ioctl_args { -+ char dev1[24]; -+ -+ union { -+ char dev2[24]; -+ int VID; -+ unsigned long skb_priority; -+ unsigned long name_type; -+ unsigned long bind_type; -+ unsigned long flag; /* Matches vlan_dev_info flags */ -+ } u; -+ -+ short vlan_qos; /* Can also be flag-value, 1 to set, 0 to clear. */ -+}; -+ -+ -+#endif -diff -u -r -N -X /home/greear/exclude.list linux/include/linux/netdevice.h linux.dev/include/linux/netdevice.h ---- linux/include/linux/netdevice.h Sun Dec 31 14:36:46 2000 -+++ linux.dev/include/linux/netdevice.h Sun Jan 14 14:23:12 2001 -@@ -37,8 +37,15 @@ - #ifdef CONFIG_NET_PROFILE - #include <net/profile.h> - #endif -+ -+#if (defined(CONFIG_VLAN_802_1Q)) -+struct vlan_dev_info; -+#endif -+ - #endif - -+ -+ - struct divert_blk; - - /* -@@ -53,7 +60,11 @@ - */ - - #if !defined(CONFIG_AX25) && !defined(CONFIG_AX25_MODULE) && !defined(CONFIG_TR) -+#if defined(CONFIG_VLAN_802_1Q) -+#define LL_MAX_HEADER 36 -+#else - #define LL_MAX_HEADER 32 -+#endif - #else - #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) - #define LL_MAX_HEADER 96 -@@ -155,11 +166,19 @@ - { - struct hh_cache *hh_next; /* Next entry */ - atomic_t hh_refcnt; /* number of users */ -- unsigned short hh_type; /* protocol identifier, f.e ETH_P_IP */ -+ unsigned short hh_type; /* protocol identifier, f.e ETH_P_IP -+ * NOTE: For VLANs, this will be the -+ * encapuslated type. --BLG -+ */ - int (*hh_output)(struct sk_buff *skb); - rwlock_t hh_lock; -+ - /* cached hardware header; allow for machine alignment needs. */ -- unsigned long hh_data[16/sizeof(unsigned long)]; -+#ifdef CONFIG_VLAN_802_1Q /* we need 4 extra bytes for VLAN headers */ -+ unsigned long hh_data[20/sizeof(unsigned long)]; -+#else -+ unsigned long hh_data[16/sizeof(unsigned long)]; -+#endif - }; - - -@@ -317,7 +336,13 @@ - int tx_semaphore; - #define NETDEV_FASTROUTE_HMASK 0xF - /* Semi-private data. Keep it at the end of device struct. */ -+ - struct dst_entry *fastpath[NETDEV_FASTROUTE_HMASK+1]; -+#endif -+ -+#ifdef CONFIG_VLAN_802_1Q -+ /* Holds information that makes sense if this device is a VLAN device. */ -+ struct vlan_dev_info* vlan_dev; - #endif - - #ifdef CONFIG_NET_DIVERT -diff -u -r -N -X /home/greear/exclude.list linux/net/802_1Q/Makefile linux.dev/net/802_1Q/Makefile ---- linux/net/802_1Q/Makefile Wed Dec 31 17:00:00 1969 -+++ linux.dev/net/802_1Q/Makefile Fri Dec 29 19:51:33 2000 -@@ -0,0 +1,26 @@ -+# -+# Makefile for the Linux Ethernet layer. -+# -+# Note! Dependencies are done automagically by 'make dep', which also -+# removes any old dependencies. DON'T put your own dependencies here -+# unless it's something special (ie not a .c file). -+# -+# Note 2! The CFLAGS definition is now in the main makefile... -+ -+O_TARGET := 802_1Q.o -+ -+OBJS := vlan.o vlanproc.o vlan_dev.o -+ -+ifeq ($(CONFIG_SYSCTL),y) -+OBJS += sysctl_net_vlan.o -+endif -+ -+ -+ifdef CONFIG_NET -+O_OBJS := $(OBJS) $(OBJ2) -+endif -+ -+include $(TOPDIR)/Rules.make -+ -+tar: -+ tar -cvf /dev/f1 . -diff -u -r -N -X /home/greear/exclude.list linux/net/802_1Q/sysctl_net_vlan.c linux.dev/net/802_1Q/sysctl_net_vlan.c ---- linux/net/802_1Q/sysctl_net_vlan.c Wed Dec 31 17:00:00 1969 -+++ linux.dev/net/802_1Q/sysctl_net_vlan.c Fri Dec 29 19:51:33 2000 -@@ -0,0 +1,18 @@ -+/* -+ * sysctl_net_vlan.c: sysctl interface to net Ethernet VLAN subsystem. -+ * -+ * Begun Dec 20, 1998, Ben Greear -+ * -+ * TODO: What, if anything, should this do?? -+ */ -+ -+#ifdef CONFIG_VLAN_802_1Q -+ -+#include <linux/mm.h> -+#include <linux/sysctl.h> -+ -+ctl_table ether_vlan_table[] = { -+ {0} -+}; -+ -+#endif -diff -u -r -N -X /home/greear/exclude.list linux/net/802_1Q/vlan.c linux.dev/net/802_1Q/vlan.c ---- linux/net/802_1Q/vlan.c Wed Dec 31 17:00:00 1969 -+++ linux.dev/net/802_1Q/vlan.c Sun Jan 14 14:55:46 2001 -@@ -0,0 +1,447 @@ -+/* -*- linux-c -*- -+ * INET An implementation of the TCP/IP protocol suite for the LINUX -+ * operating system. INET is implemented using the BSD Socket -+ * interface as the means of communication with the user level. -+ * -+ * Ethernet-type device handling. -+ * -+ * Version: @(#)vlan.c started 12/21/98 -+ * -+ * Authors: Ben Greear <greearb@candelatech.com>, <greearb@agcs.com> -+ * -+ * Fixes: -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include <asm/uaccess.h> /* for copy_from_user */ -+#include <linux/module.h> -+#include <linux/netdevice.h> -+#include <linux/skbuff.h> -+#include <net/datalink.h> -+#include <linux/mm.h> -+#include <linux/in.h> -+#include <linux/init.h> -+#include <net/p8022.h> -+#include <net/arp.h> -+ -+#include <linux/if_vlan.h> -+#include "vlan.h" -+#include "vlanproc.h" -+ -+extern int register_netdevice(struct device *dev); /* found in dev.c */ -+extern int unregister_netdevice(struct device *dev); /* found in dev.c */ -+extern int dev_new_index(void); /* dev.c */ -+ -+extern int eth_header_parse(struct sk_buff *skb, unsigned char *haddr); /* eth.c */ -+ -+extern struct Qdisc noqueue_qdisc; -+ -+/* Global VLAN variables */ -+ -+/* Our listing of VLAN group(s) */ -+struct vlan_group *p802_1Q_vlan_list = NULL; -+ -+static char vlan_fullname[] = "802.1Q VLAN Support"; -+static unsigned int vlan_version = 1; -+static unsigned int vlan_release = 0; -+static char vlan_copyright[] = "(c) 2000 Ben Greear (GPL)"; -+ -+/** These may be changed at run-time through IOCTLs */ -+unsigned short vlan_name_type = 0; /* determines interface naming scheme */ -+unsigned long vlan_bad_proto_recvd = 0; /* Counter for how many NON-VLAN protos we've received on a VLAN. */ -+ -+ -+static struct packet_type vlan_packet_type = -+{ -+ 0, /* MUTTER ntohs(ETH_P_802_1Q),*/ -+ NULL, -+ vlan_dev_type_trans, /* VLAN receive method */ -+ NULL, -+ NULL, -+}; -+ -+/* End of global variables definitions. */ -+ -+#ifdef MODULE -+ -+/* -+ * Kernel Loadable Module Entry Points -+ * -+ * Module 'insert' entry point. -+ * o print announcement -+ * o initialize static data -+ * o create /proc/net/vlan directory and static entries -+ * -+ * Return: 0 Ok -+ * < 0 error. -+ * Context: process -+ */ -+int init_module (void) { -+ printk(VLAN_INF __FUNCTION__); -+ -+ vlan_proto_init(NULL); -+ return 0; -+} -+ -+/* -+ * Module 'remove' entry point. -+ * o delete /proc/net/router directory and static entries. -+ */ -+void cleanup_module (void) { -+ vlan_proto_cleanup(); // TODO: Define this so modules work. -+} -+ -+#else -+ -+ -+/** Non-module init entry point. */ -+__initfunc(void vlan_system_init(void)) { -+ printk(VLAN_INF __FUNCTION__); -+ -+ /* protocol initialization */ -+ vlan_proto_init(NULL); -+ -+} -+#endif -+ -+/* -+ * Function vlan_proto_init (pro) -+ * -+ * Initialize VLAN protocol layer, -+ * -+ */ -+void vlan_proto_init(struct net_proto *pro) { -+ -+ int err; -+ printk(VLAN_INF "%s v%u.%u %s\n", -+ vlan_fullname, vlan_version, vlan_release, vlan_copyright); -+ -+ /* proc file system initialization */ -+ err = vlan_proc_init(); -+ if (err < 0) { -+ printk(KERN_ERR __FUNCTION__ -+ "%s: can't create entry in proc filesystem!\n", VLAN_NAME); -+ } -+ -+ /* network byte order!! */ -+ vlan_packet_type.type = htons(ETH_P_802_1Q); -+ dev_add_pack(&vlan_packet_type); -+ printk(VLAN_INF "%s Initialization complete.\n", VLAN_NAME); -+} -+ -+ -+ -+/** Will search linearly for now, based on device index. Could -+ * hash, or directly link, this some day. --Ben -+ */ -+struct vlan_group* vlan_find_group(int real_dev_ifindex) { -+ struct vlan_group* grp = NULL; -+ -+ for (grp = p802_1Q_vlan_list; -+ ((grp != NULL) && (grp->real_dev_ifindex != real_dev_ifindex)); -+ grp = grp->next) { -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": grp_idx: %i real_dev_idx: %i\n", -+ grp->real_dev_ifindex, real_dev_ifindex); -+#endif -+ ; -+ } /* for */ -+ -+ return grp; -+} -+ -+/* Find the protocol handler. Assumes VID < 0xFFF. -+ */ -+struct device *find_802_1Q_vlan_dev(struct device* real_dev, unsigned short VID) { -+ -+ struct vlan_group* grp = vlan_find_group(real_dev->ifindex); -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": idx: %i grp: %p\n", real_dev->ifindex, grp); -+#endif -+ -+ /* When here, we have found the correct group, if it exists. */ -+ -+ if (grp) { /* then we found one */ -+ return grp->vlan_devices[VID]; /* return the vlan device */ -+ }//if -+ -+ return NULL; -+}/* find_802_1Q_vlan_dev */ -+ -+ -+ -+int unregister_802_1Q_vlan_dev(int real_dev_ifindex, unsigned short vlan_id) { -+ struct vlan_group* grp; -+ struct device* dev = NULL; -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": VID: %i\n", vlan_id); -+#endif -+ -+ /* sanity check */ -+ if ((vlan_id >= 0xFFF) || (vlan_id <= 0)) { -+ return -EINVAL; -+ } -+ -+ grp = vlan_find_group(real_dev_ifindex); -+ /* When here, we have found the correct group, if it exists. */ -+ -+ if (grp) { -+ dev = grp->vlan_devices[vlan_id]; -+ if (dev) { -+ -+ /* Remove proc entry */ -+ vlan_proc_rem_dev(dev); -+ -+ /* take it out of our own structures */ -+ grp->vlan_devices[vlan_id] = NULL; -+ -+ /* Take it out of the global list of devices. -+ * NOTE: This deletes dev, don't access it again!! -+ */ -+ unregister_netdevice(dev); -+ -+ }/* if */ -+ }/* if */ -+ return 0; -+}/* unregister vlan device */ -+ -+ -+ -+int unregister_802_1Q_vlan_device(const char* vlan_IF_name) { -+ struct device* dev = NULL; -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": unregister VLAN by name, name -:%s:-\n", -+ vlan_IF_name); -+#endif -+ -+ dev = dev_get(vlan_IF_name); -+ -+ if (dev && dev->vlan_dev) { -+ return unregister_802_1Q_vlan_dev(dev->vlan_dev->real_dev->ifindex, -+ (unsigned short)(dev->vlan_dev->vlan_id)); -+ } -+ else { -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": WARNING: Could not find dev\n"); -+#endif -+ return -EINVAL; -+ } -+}/* unregister vlan device */ -+ -+ -+/* -+ TODO: This for modules or something?? --BLG -+ -+ EXPORT_SYMBOL(register_802_1Q_vlan_device); -+ EXPORT_SYMBOL(unregister_802_1Q_vlan_device); -+ -+*/ -+ -+/* Attach a VLAN device to a mac address (ie Ethernet Card). -+ * Returns the device that was created, or NULL if there was -+ * an error of some kind. -+ */ -+struct device *register_802_1Q_vlan_device(const char* eth_IF_name, -+ unsigned short VLAN_ID) { -+ struct vlan_group* grp; -+ struct device *new_dev; -+ struct device *real_dev; /* the ethernet device */ -+ int malloc_size = 0; -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": if_name -:%s:- vid: %i\n", -+ eth_IF_name, VLAN_ID); -+#endif -+ -+ /* find the device relating to eth_IF_name. -+ * TODO: Make sure it's an ethernet device. */ -+ real_dev = dev_get(eth_IF_name); -+ -+ if (real_dev != NULL) { -+ /* printk(KERN_ALERT "Found real_dev"); */ -+ -+ if ((VLAN_ID > 0) && (VLAN_ID < 0xFFF)) { -+ -+ /* printk(KERN_ALERT "VID is in range"); */ -+ -+ if (find_802_1Q_vlan_dev(real_dev, VLAN_ID)) { -+ /* was already registered. */ -+ printk(VLAN_DBG __FUNCTION__ ": ALREADY had VLAN registered\n"); -+ return NULL; -+ } -+ -+ malloc_size = (sizeof(struct device)); -+ -+ new_dev = (struct device*) kmalloc(malloc_size, GFP_KERNEL); -+ VLAN_MEM_DBG("device malloc, addr: %p size: %i\n", new_dev, malloc_size); -+ -+ if (new_dev != NULL) { -+ /* printk(KERN_ALERT "Got a new device.."); */ -+ -+ memset(new_dev, 0, malloc_size); /* zero everything out */ -+ -+ /* set us up to not use a Qdisc, as the underlying Hardware device -+ * can do all the queueing we could want. -+ */ -+ new_dev->qdisc_sleeping = &noqueue_qdisc; -+ -+ /* Gotta set up the fields for the device. */ -+ new_dev->name = (char*)(kmalloc(IFNAMSIZ + 1, GFP_KERNEL)); -+ VLAN_MEM_DBG("new_dev->name malloc, addr: %p size: %i\n", new_dev->name, IFNAMSIZ + 1); -+ -+ if (new_dev->name) { -+ memset(new_dev->name, 0, IFNAMSIZ + 1); /* zero everything out */ -+ } -+ else { -+ kfree(new_dev); -+ VLAN_FMEM_DBG("new_dev free, addr: %p\n", new_dev); -+ return NULL; -+ } -+ -+ if (vlan_name_type == VLAN_NAME_TYPE_RAW_PLUS_VID) { -+ /* name will look like: eth1.0005 */ -+ sprintf(new_dev->name, "%s.%.4i", real_dev->name, VLAN_ID); -+ } -+ else if (vlan_name_type == VLAN_NAME_TYPE_PLUS_VID_NO_PAD) { -+ /* Put our vlan.VID in the name. Name will look like: vlan5 */ -+ sprintf(new_dev->name, "vlan%i", VLAN_ID); -+ } -+ else if (vlan_name_type == VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD) { -+ /* Put our vlan.VID in the name. Name will look like: eth0.5 */ -+ sprintf(new_dev->name, "%s.%i", real_dev->name, VLAN_ID); -+ } -+ else { /* (vlan_name_type == VLAN_NAME_TYPE_PLUS_VID) { */ -+ /* Put our vlan.VID in the name. Name will look like: vlan0005 */ -+ /* default case */ -+ sprintf(new_dev->name, "vlan%.4i", VLAN_ID); -+ } -+ -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name); -+#endif -+ /* set up method calls */ -+ new_dev->init = vlan_dev_init; -+ new_dev->destructor = vlan_dev_destruct; -+ -+ /* new_dev->ifindex = 0; it will be set when added to -+ * the global list. -+ * iflink is set as well. */ -+ -+ new_dev->get_stats = vlan_dev_get_stats; -+ -+ /* IFF_BROADCAST|IFF_MULTICAST; ??? */ -+ new_dev->flags = real_dev->flags; -+ new_dev->flags &= ~IFF_UP; -+ -+ /* need 4 bytes for extra VLAN header info, hope -+ * underlying device can handle it. */ -+ new_dev->mtu = real_dev->mtu; -+ -+ new_dev->type = real_dev->type; /* TODO: is this true? */ -+ -+ /* Regular ethernet + 4 bytes (18 total). */ -+ new_dev->hard_header_len = VLAN_ETH_HLEN; -+ -+ new_dev->priv = kmalloc(sizeof(struct net_device_stats), -+ GFP_KERNEL); -+ VLAN_MEM_DBG("new_dev->priv malloc, addr: %p size: %i\n", new_dev->priv, -+ sizeof(struct net_device_stats)); -+ -+ if (new_dev->priv) { -+ memset(new_dev->priv, 0, sizeof(struct net_device_stats)); -+ }//if -+ -+ memcpy(new_dev->broadcast, real_dev->broadcast, real_dev->addr_len); -+ memcpy(new_dev->dev_addr, real_dev->dev_addr, real_dev->addr_len); -+ new_dev->addr_len = real_dev->addr_len; -+ -+ new_dev->open = vlan_dev_open; -+ new_dev->stop = vlan_dev_stop; -+ new_dev->hard_header = vlan_dev_hard_header; -+ /*new_dev->hard_header_cache = vlan_header_cache;*/ -+ /*new_dev->header_cache_update = vlan_header_cache_update;*/ -+ new_dev->hard_start_xmit = vlan_dev_hard_start_xmit; -+ new_dev->rebuild_header = vlan_dev_rebuild_header; -+ new_dev->hard_header_parse = eth_header_parse; /* trivial. */ -+ new_dev->set_mac_address = vlan_dev_set_mac_address; -+ new_dev->set_multicast_list = vlan_dev_set_multicast_list; -+ -+ new_dev->vlan_dev = (struct vlan_dev_info*) kmalloc(sizeof(struct vlan_dev_info), -+ GFP_KERNEL); -+ VLAN_MEM_DBG("new_dev->vlan_dev malloc, addr: %p size: %i\n", new_dev->vlan_dev, -+ sizeof(struct vlan_dev_info)); -+ if (new_dev->vlan_dev == NULL) { -+ kfree(new_dev->priv); -+ VLAN_FMEM_DBG("new_dev->priv free, addr: %p\n", new_dev->priv); -+ kfree(new_dev->name); -+ VLAN_FMEM_DBG("new_dev->name free, addr: %p\n", new_dev->name); -+ kfree(new_dev); -+ VLAN_FMEM_DBG("new_dev free, addr: %p\n", new_dev); -+ return NULL; -+ } -+ else { -+ /* Initialize it. */ -+ memset(new_dev->vlan_dev, 0, sizeof(struct vlan_dev_info)); -+ -+ new_dev->vlan_dev->vlan_id = VLAN_ID; /* 1 through 0xFFF */ -+ /* TODO: have to be careful deleting real devices now. */ -+ new_dev->vlan_dev->real_dev = real_dev; -+ -+ memset(&(new_dev->vlan_dev->dent), 0, sizeof(struct proc_dir_entry)); -+ } -+ -+ /* So, got the sucker initialized, now lets place it into our local -+ * structure. -+ */ -+ -+ grp = vlan_find_group(real_dev->ifindex); -+ -+ /* When here, we have found the correct group, if it exists. */ -+ -+ if (!grp) { /* need to add a new group */ -+ /* printk(VLAN_DBG "VLAN REGISTER: " -+ "Need to add new vlan group.\n");*/ -+ -+ grp = kmalloc(sizeof(struct vlan_group), GFP_KERNEL); -+ VLAN_MEM_DBG("grp malloc, addr: %p size: %i\n", grp, sizeof(struct vlan_group)); -+ -+ if (grp) { -+ printk(KERN_ALERT "VLAN REGISTER: Allocated new group, idx: %i\n", -+ real_dev->ifindex); -+ memset(grp, 0, sizeof(struct vlan_group)); -+ grp->real_dev_ifindex = real_dev->ifindex; -+ grp->next = p802_1Q_vlan_list; -+ p802_1Q_vlan_list = grp; -+ } -+ else { -+ kfree(new_dev->name); -+ VLAN_FMEM_DBG("new_dev->name free, addr: %p\n", new_dev->name); -+ kfree(new_dev->priv); -+ VLAN_FMEM_DBG("new_dev->priv free, addr: %p\n", new_dev->priv); -+ kfree(new_dev); -+ VLAN_FMEM_DBG("new_dev free, addr: %p\n", new_dev); -+ return NULL; -+ } -+ }/* if */ -+ -+ grp->vlan_devices[VLAN_ID] = new_dev; -+ -+ /* Now, add it to the global list of devices. */ -+ /* printk(KERN_ALERT "Registering new device."); */ -+ register_netdevice(new_dev); -+ vlan_proc_add_dev(new_dev); /* create it's proc entry */ -+ return new_dev; -+ } -+ }//if -+ }//if -+ -+ return NULL; -+}/* register (create) VLAN device */ -diff -u -r -N -X /home/greear/exclude.list linux/net/802_1Q/vlan.h linux.dev/net/802_1Q/vlan.h ---- linux/net/802_1Q/vlan.h Wed Dec 31 17:00:00 1969 -+++ linux.dev/net/802_1Q/vlan.h Sun Jan 14 14:30:56 2001 -@@ -0,0 +1,44 @@ -+#ifndef __BEN_VLAN_802_1Q_INC__ -+#define __BEN_VLAN_802_1Q_INC__ -+ -+#include <linux/if_vlan.h> -+ -+/* If this is undefined, the name will look like: vlan0005 */ -+/* #define USE_RAW_IN_NAME Use this one if you like it: eth.0005 */ -+ -+/* Uncomment this if you want debug traces to be shown. */ -+/* #define VLAN_DEBUG */ -+ -+#define VLAN_ERR KERN_ERR -+#define VLAN_INF KERN_ALERT -+#define VLAN_DBG KERN_DEBUG /* change these... to debug, having a hard time -+ * changing the log level at run-time..for some reason. -+ */ -+ -+/* -+ -+These I use for memory debugging. I feared a leak at one time, but -+I never found it..and the problem seems to have dissappeared. Still, -+I'll bet they might prove useful again... --Ben -+ -+#define VLAN_MEM_DBG(x, y, z) printk(VLAN_DBG __FUNCTION__ ": " x, y, z); -+#define VLAN_FMEM_DBG(x, y) printk(VLAN_DBG __FUNCTION__ ": " x, y); -+*/ -+ -+/* This way they don't do anything! */ -+#define VLAN_MEM_DBG(x, y, z) -+#define VLAN_FMEM_DBG(x, y) -+ -+ -+extern unsigned short vlan_name_type; -+extern unsigned long vlan_bad_proto_recvd; /* Counter for how many NON-VLAN protos we've received on a VLAN. */ -+ -+/* Add some headers for the public VLAN methods. */ -+int unregister_802_1Q_vlan_device(const char* vlan_IF_name); -+struct device *register_802_1Q_vlan_device(const char* eth_IF_name, -+ unsigned short VID); -+ -+void vlan_system_init(void); -+void vlan_proto_init(struct net_proto *pro); -+ -+#endif -diff -u -r -N -X /home/greear/exclude.list linux/net/802_1Q/vlan_dev.c linux.dev/net/802_1Q/vlan_dev.c ---- linux/net/802_1Q/vlan_dev.c Wed Dec 31 17:00:00 1969 -+++ linux.dev/net/802_1Q/vlan_dev.c Sun Jan 14 19:21:08 2001 -@@ -0,0 +1,766 @@ -+/* -*- linux-c -*- -+ * INET An implementation of the TCP/IP protocol suite for the LINUX -+ * operating system. INET is implemented using the BSD Socket -+ * interface as the means of communication with the user level. -+ * -+ * Ethernet-type device handling. -+ * -+ * Version: @(#)vlan_dev.c Started 3/29/99 -+ * -+ * Authors: Ben Greear <greearb@candelatech.com>, <greearb@agcs.com> -+ * -+ * Fixes: -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include <asm/uaccess.h> /* for copy_from_user */ -+#include <linux/module.h> -+#include <linux/netdevice.h> -+#include <linux/skbuff.h> -+#include <net/datalink.h> -+#include <linux/mm.h> -+#include <linux/in.h> -+#include <linux/init.h> -+#include <net/p8022.h> -+#include <net/arp.h> -+#include "vlan.h" -+#include "vlanproc.h" -+#include <linux/if_vlan.h> -+#include <net/ip.h> -+#include <asm/checksum.h> -+ -+ -+struct net_device_stats* vlan_dev_get_stats(struct device* dev) { -+ return (struct net_device_stats*)(dev->priv); -+} -+ -+ -+/* -+ * Rebuild the Ethernet MAC header. This is called after an ARP -+ * (or in future other address resolution) has completed on this -+ * sk_buff. We now let ARP fill in the other fields. -+ * -+ * This routine CANNOT use cached dst->neigh! -+ * Really, it is used only when dst->neigh is wrong. -+ * -+ * TODO: This needs a checkup, I'm ignorant here. --BLG -+ */ -+int vlan_dev_rebuild_header(struct sk_buff *skb) { -+ -+ struct device *dev = skb->dev; -+ struct vlan_ethhdr *veth = (struct vlan_ethhdr*)(skb->data); -+ -+ switch (veth->h_vlan_encapsulated_proto) -+ { -+#ifdef CONFIG_INET -+ case __constant_htons(ETH_P_IP): -+ -+ /* TODO: Confirm this will work with VLAN headers... */ -+ return arp_find(veth->h_dest, skb); -+#endif -+ default: -+ printk(VLAN_DBG -+ "%s: unable to resolve type %X addresses.\n", -+ dev->name, (int)veth->h_vlan_encapsulated_proto); -+ -+ memcpy(veth->h_source, dev->dev_addr, ETH_ALEN); -+ break; -+ }/* switch */ -+ -+ return 0; -+}/* vlan_dev_rebuild_header */ -+ -+ -+ -+/* -+ * Determine the packet's protocol ID. The rule here is that we -+ * assume 802.3 if the type field is short enough to be a length. -+ * This is normal practice and works for any 'now in use' protocol. -+ * -+ * Also, at this point we assume that we ARE dealing exclusively with -+ * VLAN packets, or packets that should be made into VLAN packets based -+ * on a default VLAN ID. -+ * -+ * NOTE: Should be similar to ethernet/eth.c. -+ * -+ * SANITY NOTE: This method is called when a packet is moving up the stack -+ * towards userland. To get here, it would have already passed -+ * through the ethernet/eth.c eth_type_trans() method. -+ */ -+int vlan_dev_type_trans(struct sk_buff *skb, struct device *dev, -+ struct packet_type* ptype) { -+ unsigned char* rawp = NULL; -+ struct vlan_ethhdr *veth = (struct vlan_ethhdr*)(skb->mac.ethernet); -+ unsigned short vid = 0; -+ struct net_device_stats* stats; -+ -+ /* Do we have a VLAN packet? If not, then throw it away, after printing an error. -+ * -+ */ -+ if (veth->h_vlan_proto != __constant_htons(ETH_P_802_1Q)) { -+ printk(VLAN_INF __FUNCTION__ ": VLAN device received NON-VLAN protocol: %hx\n", htons(veth->h_vlan_proto)); -+ vlan_bad_proto_recvd++; -+ kfree_skb(skb); -+ return -EINVAL; -+ } -+ else { -+ vid = ((unsigned short)(ntohs(veth->h_vlan_TCI)) & 0xFFF); -+ } -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": skb: %p vlan_id: %hx dev: %s, encap_proto: %hx\n", -+ skb, vid, dev->name, veth->h_vlan_encapsulated_proto); -+#endif -+ -+ /* Ok, we will find the correct VLAN device, strip the header, -+ and then go on as usual. -+ */ -+ -+ /* we have 12 bits of vlan ID. */ -+ /* If it's NULL, we will tag the skb to be junked below */ -+ skb->dev = find_802_1Q_vlan_dev(dev, vid); -+ -+ if (!skb->dev) { -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": ERROR: No device for VID: %i on dev: %s [%i]\n", -+ (unsigned int)(vid), dev->name, dev->ifindex); -+#endif -+ kfree_skb(skb); -+ return -1; -+ } -+ -+ stats = (struct net_device_stats*)(skb->dev->priv); -+ -+ /* -+ * Deal with ingress priority mapping. -+ */ -+ skb->priority = skb->dev->vlan_dev->ingress_priority_map[(ntohs(veth->h_vlan_TCI) >> 13) & 0x7]; -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": priority: %lu for TCI: %hu (hbo) on vlan_dev: %s\n", -+ (unsigned long)(skb->priority), ntohs(veth->h_vlan_TCI), skb->dev->name); -+#endif -+ -+ /* Bump the rx counters for the VLAN device. */ -+ stats->rx_packets++; -+ stats->rx_bytes += skb->len; -+ -+ /* NOTE: The underlying device SHOULD NOT PULL THE MAC BYTES OFF. -+ (it doesn't seem to.) -+ */ -+ skb_pull(skb, VLAN_ETH_HLEN); /* take off the VLAN header */ -+ -+ -+ /* VLAN and regular Ethernet headers have the addresses in the same place. -+ * TODO: Add code to deal with VLAN control packets?? --BLG -+ * Is there such a thing?? -+ */ -+ if (*(veth->h_dest) & 1) { -+ stats->multicast++; -+ if (memcmp(veth->h_dest, dev->broadcast, ETH_ALEN) == 0) -+ skb->pkt_type = PACKET_BROADCAST; -+ else -+ skb->pkt_type = PACKET_MULTICAST; -+ } -+ -+ /* -+ * This ALLMULTI check should be redundant by 1.4 -+ * so don't forget to remove it. -+ * -+ * Seems, you forgot to remove it. All silly devices -+ * seems to set IFF_PROMISC. -+ */ -+ -+ else if (dev->flags & (IFF_PROMISC/*|IFF_ALLMULTI*/)) { -+ if (memcmp(veth->h_dest, dev->dev_addr, ETH_ALEN) != 0) -+ skb->pkt_type = PACKET_OTHERHOST; -+ } -+ -+ /* Was a VLAN packet, grab the encapsulated protocol, which the layer -+ * three protocols care about. -+ */ -+ if (ntohs(veth->h_vlan_encapsulated_proto) >= 1536) { -+ -+ skb->protocol = veth->h_vlan_encapsulated_proto; -+ /* place it back on the queue to be handled by true layer 3 protocols. -+ */ -+ -+ /* See if we are configured to re-write the VLAN header to make it look like -+ * ethernet... -+ */ -+ if (skb->dev->vlan_dev->flags & 1) { -+ /* Lifted from Gleb's VLAN code... */ -+ memmove(skb->data - (VLAN_ETH_HLEN - 4), skb->data - VLAN_ETH_HLEN, 12); -+ skb->mac.raw += 4; -+ } -+ netif_rx(skb); -+ return 0; -+ } -+ -+ rawp = skb->data; -+ -+ /* -+ * This is a magic hack to spot IPX packets. Older Novell breaks -+ * the protocol design and runs IPX over 802.3 without an 802.2 LLC -+ * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This -+ * won't work for fault tolerant netware but does for the rest. -+ */ -+ if (*(unsigned short *)rawp == 0xFFFF) { -+ skb->protocol = __constant_htons(ETH_P_802_3); -+ /* place it back on the queue to be handled by true layer 3 protocols. -+ */ -+ -+ /* See if we are configured to re-write the VLAN header to make it look like -+ * ethernet... -+ */ -+ if (skb->dev->vlan_dev->flags & 1) { -+ /* Lifted from Gleb's VLAN code... */ -+ memmove(skb->data - (VLAN_ETH_HLEN - 4), skb->data - VLAN_ETH_HLEN, 12); -+ skb->mac.raw += 4; -+ } -+ netif_rx(skb); -+ return 0; -+ } -+ -+ /* -+ * Real 802.2 LLC -+ */ -+ skb->protocol = __constant_htons(ETH_P_802_2); -+ /* place it back on the queue to be handled by upper layer protocols. -+ */ -+ -+ /* See if we are configured to re-write the VLAN header to make it look like -+ * ethernet... -+ */ -+ if (skb->dev->vlan_dev->flags & 1) { -+ /* Lifted from Gleb's VLAN code... */ -+ memmove(skb->data - (VLAN_ETH_HLEN - 4), skb->data - VLAN_ETH_HLEN, 12); -+ skb->mac.raw += 4; -+ } -+ netif_rx(skb); -+ return 0; -+} -+ -+ -+/* -+ * Create the Ethernet VLAN MAC header for an arbitrary protocol layer -+ * -+ * saddr=NULL means use device source address -+ * daddr=NULL means leave destination address (eg unresolved arp) -+ * -+ * This is called when the SKB is moving down the stack towards the -+ * physical devices. -+ */ -+int vlan_dev_hard_header(struct sk_buff *skb, struct device *dev, -+ unsigned short type, void *daddr, void *saddr, -+ unsigned len) { -+ struct vlan_ethhdr *veth; -+ unsigned short veth_TCI = 0; -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": skb: %p type: %hx len: %x vlan_id: %hx, daddr: %p\n", -+ skb, type, len, dev->vlan_dev->vlan_id, daddr); -+#endif -+ -+ veth = (struct vlan_ethhdr*)skb_push(skb, VLAN_ETH_HLEN); -+ -+ /* build the four bytes that make this a VLAN header. */ -+ -+ /* first, the ethernet type */ -+ veth->h_vlan_proto = __constant_htons(ETH_P_802_1Q); -+ -+ /* Now, construct the second two bytes. This field looks something -+ * like: -+ * usr_priority: 3 bits (high bits) -+ * CFI 1 bit -+ * VLAN ID 12 bits (low bits) -+ * -+ */ -+ veth_TCI = dev->vlan_dev->vlan_id; -+ veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb); -+ -+ veth->h_vlan_TCI = htons(veth_TCI); -+ -+ /* Rest should be the same as a normal header. */ -+ /* -+ * Set the protocol type. For a packet of type ETH_P_802_3 we put the length -+ * in here instead. It is up to the 802.2 layer to carry protocol information. -+ * -+ */ -+ -+ if (type != ETH_P_802_3) -+ veth->h_vlan_encapsulated_proto = htons(type); -+ else -+ veth->h_vlan_encapsulated_proto = htons(len); -+ -+ /* -+ * Set the source hardware address. -+ */ -+ -+ if (saddr) -+ memcpy(veth->h_source, saddr, ETH_ALEN); -+ else -+ memcpy(veth->h_source, dev->dev_addr, ETH_ALEN); -+ -+ /* -+ * Anyway, the loopback-device should never use this function... -+ * This is especially true with VLAN's. --BLG -+ */ -+ -+ if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { -+ memset(veth->h_dest, 0, ETH_ALEN); -+ return (VLAN_ETH_HLEN); /* was: dev->hard_header_len */ -+ } -+ -+ if (daddr) { -+ memcpy(veth->h_dest, daddr, ETH_ALEN); -+ return (VLAN_ETH_HLEN); /* was: dev->hard_header_len */ -+ } -+ -+ return -(VLAN_ETH_HLEN); /* was: dev->hard_header_len */ -+ -+} /* vlan_hard_header, put on the VLAN hardware header */ -+ -+ -+int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct device *dev) { -+ struct net_device_stats* stats = (struct net_device_stats*)(dev->priv); -+ struct vlan_ethhdr *veth = (struct vlan_ethhdr*)(skb->data); -+ -+ /* Handle non-VLAN frames if they are sent to us, for example by DHCP. */ -+ if (veth->h_vlan_proto != __constant_htons(ETH_P_802_1Q)) { -+ /* This is not a VLAN frame...but we can fix that! */ -+ unsigned short veth_TCI = 0; -+ dev->vlan_dev->cnt_encap_on_xmit++; -+ -+ if (skb_headroom(skb) < 4) { -+ struct sk_buff* sk_tmp = skb; -+ skb = skb_realloc_headroom(sk_tmp, 4); -+ kfree_skb(sk_tmp); -+ if (skb == NULL) { -+ stats->tx_dropped++; -+ kfree_skb(sk_tmp); -+ return -ENOMEM; -+ } -+ dev->vlan_dev->cnt_inc_headroom_on_tx++; -+ } -+ else { -+ if( !(skb = skb_unshare(skb, GFP_ATOMIC)) ) { -+ printk(KERN_ERR "vlan: failed to unshare skbuff\n"); -+ stats->tx_dropped++; -+ return -ENOMEM; -+ } -+ } -+ veth = (struct vlan_ethhdr*)skb_push(skb, 4); -+ -+ /* Move the mac addresses to the beginning of the new header. */ -+ memmove(skb->data, skb->data + 4, 12); -+ -+ /* first, the ethernet type */ -+ veth->h_vlan_proto = __constant_htons(ETH_P_802_1Q); -+ -+ /* Now, construct the second two bytes. This field looks something -+ * like: -+ * usr_priority: 3 bits (high bits) -+ * CFI 1 bit -+ * VLAN ID 12 bits (low bits) -+ * -+ */ -+ veth_TCI = dev->vlan_dev->vlan_id; -+ veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb); -+ -+ veth->h_vlan_TCI = htons(veth_TCI); -+ }/* If we needed to encapsulate the frame */ -+ -+ skb->dev = dev->vlan_dev->real_dev; -+ -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": about to send skb: %p to dev: %s\n", skb, skb->dev->name); -+#endif -+ -+ dev_queue_xmit(skb); -+ stats->tx_packets++; /* for statics only */ -+ stats->tx_bytes += skb->len; -+ return 0; -+}/* vlan_dev_hard_start_xmit */ -+ -+ -+int vlan_dev_change_mtu(struct device *dev, int new_mtu) { -+ /* TODO: gotta make sure the underlying layer can handle it, -+ * maybe an IFF_VLAN_CAPABLE flag for devices? -+ */ -+ -+ dev->mtu = new_mtu; -+ return new_mtu; -+} -+ -+int vlan_dev_open(struct device* dev) { -+ dev->flags |= IFF_UP; -+ return 0; -+} -+ -+int vlan_dev_stop(struct device* dev) { -+ dev->flags &= ~IFF_UP; -+ return 0; -+} -+ -+int vlan_dev_init(struct device* dev) { -+ /* TODO: figure this out, maybe do nothing?? */ -+ return 0; -+} -+ -+void vlan_dev_destruct(struct device* dev) { -+ kfree(dev->name); -+ VLAN_FMEM_DBG("dev->name free, addr: %p\n", dev->name); -+ dev->name = NULL; /* better safe than hosed */ -+ -+ kfree(dev->priv); -+ VLAN_FMEM_DBG("dev->priv free, addr: %p\n", dev->priv); -+ dev->priv = NULL; -+ -+ kfree(dev->vlan_dev); -+ VLAN_FMEM_DBG("dev->vlan_dev free, addr: %p\n", dev->vlan_dev); -+ dev->vlan_dev = NULL; -+ -+ kfree(dev); -+ VLAN_FMEM_DBG("device free, addr: %p\n", dev); -+ dev = NULL; -+ -+ return; -+} -+ -+ -+/* TODO: Not to sure if the VLAN stuff works here. Need to understand -+ * this better. --BLG -+ */ -+/* -+int vlan_dev_header_cache(struct neighbour *neigh, struct hh_cache *hh) { -+ unsigned short type = hh->hh_type; -+ struct vlan_ethhdr *veth = (struct vlan_ethhdr*)(((u8*)hh->hh_data) + 2); -+ struct device *dev = neigh->dev; -+ -+ if (type == __constant_htons(ETH_P_802_3)) { -+ return -1; -+ } -+ -+ veth->h_vlan_proto = __constant_htons(ETH_P_802_1Q); -+ memcpy(veth->h_source, dev->dev_addr, ETH_ALEN); -+ memcpy(veth->h_dest, neigh->ha, ETH_ALEN); -+ -+ * VLAN specific attributes. * -+ veth->h_vlan_TCI = htons(dev->VLAN_id); * TODO: Add priority control (high 3 bits.) * -+ veth->h_vlan_encapsulated_proto = type; * should already be in network order * -+ -+ return 0; -+} -+*/ -+ -+/* -+ * Called by Address Resolution module to notify changes in address. -+ */ -+/* -+void vlan_dev_header_cache_update(struct hh_cache *hh, struct device *dev, -+ unsigned char * haddr) { -+ memcpy(((u8*)hh->hh_data) + 2, haddr, VLAN_ETH_HLEN); -+} -+*/ -+ -+#ifndef CONFIG_IP_ROUTER -+ -+/* -+ * Copy from an ethernet device memory space to an sk_buff while -+ * checksumming if IP -+ * -+ * TODO: Find out who calls this: This was lifted from eth.c, and -+ * was called eth_copy_and_sum. --BLG -+ */ -+ -+void vlan_dev_copy_and_sum(struct sk_buff *dest, unsigned char *src, -+ int length, int base) { -+ struct vlan_ethhdr* veth; -+ struct iphdr *iph; -+ int ip_length; -+ -+ veth = (struct vlan_ethhdr*)(src); -+ -+ /* This grabs the VLAN part of the header too. */ -+ if (veth->h_vlan_encapsulated_proto != __constant_htons(ETH_P_IP)) { -+ memcpy(dest->data, src, length); -+ return; -+ } -+ -+ /* -+ * We have to watch for padded packets. The csum doesn't include the -+ * padding, and there is no point in copying the padding anyway. -+ * We have to use the smaller of length and ip_length because it -+ * can happen that ip_length > length. -+ */ -+ -+ /* ethernet is always >= 34 */ -+ memcpy(dest->data, src, sizeof(struct iphdr) + VLAN_ETH_HLEN); -+ -+ length -= sizeof(struct iphdr) + VLAN_ETH_HLEN; -+ iph = (struct iphdr*)(src + VLAN_ETH_HLEN); -+ ip_length = ntohs(iph->tot_len) - sizeof(struct iphdr); -+ -+ /* Also watch out for bogons - min IP size is 8 (rfc-1042) */ -+ if ((ip_length <= length) && (ip_length > 7)) -+ length=ip_length; -+ -+ dest->csum = csum_partial_copy(src + sizeof(struct iphdr) + VLAN_ETH_HLEN, -+ dest->data + sizeof(struct iphdr) + VLAN_ETH_HLEN, -+ length, base); -+ dest->ip_summed=1; -+ -+} /* vlan_copy_and_sum */ -+ -+#endif //! CONFIG_IP_ROUTER -+ -+ -+int vlan_dev_set_ingress_priority(char* dev_name, __u32 skb_prio, short vlan_prio) { -+ struct device* dev = dev_get(dev_name); -+ -+ if (dev) { -+ if (dev->vlan_dev) { /* can't put a dflt ID on a vlan device */ -+ /* see if a priority mapping exists.. */ -+ dev->vlan_dev->ingress_priority_map[vlan_prio & 0x7] = skb_prio; -+ return 0; -+ } -+ } -+ return -EINVAL; -+} -+ -+int vlan_dev_set_egress_priority(char* dev_name, __u32 skb_prio, short vlan_prio) { -+ struct device* dev = dev_get(dev_name); -+ struct vlan_priority_tci_mapping* mp = NULL; -+ struct vlan_priority_tci_mapping* np; -+ -+ if (dev) { -+ if (dev->vlan_dev) { /* can't put a dflt ID on a vlan device */ -+ /* see if a priority mapping exists.. */ -+ mp = dev->vlan_dev->egress_priority_map[skb_prio & 0xF]; -+ while (mp) { -+ if (mp->priority == skb_prio) { -+ mp->vlan_qos = ((vlan_prio << 13) & 0xE000); -+ return 0; -+ } -+ } -+ /* create a new mapping then. */ -+ mp = dev->vlan_dev->egress_priority_map[skb_prio & 0xF]; -+ np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL); -+ if (np) { -+ np->next = mp; -+ np->priority = skb_prio; -+ np->vlan_qos = ((vlan_prio << 13) & 0xE000); -+ dev->vlan_dev->egress_priority_map[skb_prio & 0xF] = np; -+ return 0; -+ } -+ else { -+ return -ENOBUFS; -+ } -+ } -+ } -+ return -EINVAL; -+} -+ -+/* Flags are defined in the vlan_dev_info class in include/linux/if_vlan.h file. */ -+int vlan_dev_set_vlan_flag(char* dev_name, __u32 flag, short flag_val) { -+ struct device* dev = dev_get(dev_name); -+ -+ if (dev) { -+ if (dev->vlan_dev) { -+ /* verify flag is supported */ -+ if (flag == 1) { -+ if (flag_val) { -+ dev->vlan_dev->flags |= 1; -+ } -+ else { -+ dev->vlan_dev->flags &= ~1; -+ } -+ return 0; -+ } -+ else { -+ return -EINVAL; -+ } -+ }/* if it's a vlan device */ -+ }/* if we found the device */ -+ return -EINVAL; -+} -+ -+ -+int vlan_dev_set_mac_address(struct device *dev, void* addr_struct_p) { -+ int i; -+ struct sockaddr *addr = (struct sockaddr*)(addr_struct_p); -+ -+ if (dev->start) { -+ return -EBUSY; -+ } -+ -+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); -+ -+ printk("%s: Setting MAC address to ", dev->name); -+ for (i = 0; i < 6; i++) { -+ printk(" %2.2x", dev->dev_addr[i]); -+ } -+ printk(".\n"); -+ -+ if (memcmp(dev->vlan_dev->real_dev->dev_addr, dev->dev_addr, dev->addr_len) != 0) { -+ if (dev->vlan_dev->real_dev->flags & IFF_PROMISC) { -+ /* Already promiscious...leave it alone. */ -+ printk("VLAN (%s): Good, underlying device (%s) is already promiscious.\n", -+ dev->name, dev->vlan_dev->real_dev->name); -+ } -+ else { -+ int flgs = dev->vlan_dev->real_dev->flags; -+ printk("VLAN (%s): Setting underlying device (%s) to promiscious mode.\n", -+ dev->name, dev->vlan_dev->real_dev->name); -+ flgs |= IFF_PROMISC; -+ dev_change_flags(dev->vlan_dev->real_dev, flgs); -+ /* This should work, but doesn't: -+ dev_set_promiscuity(dev->vlan_dev->real_dev, 1); -+ */ -+ } -+ } -+ else { -+ printk("VLAN (%s): Underlying device (%s) has same MAC, not checking promiscious mode.\n", -+ dev->name, dev->vlan_dev->real_dev->name); -+ } -+ return 0; -+} -+ -+ -+/** Taken from Gleb + Lennert's VLAN code, and modified... */ -+void vlan_dev_set_multicast_list(struct device *vlan_dev) { -+ struct dev_mc_list *dmi; -+ struct device *real_dev; -+ int inc; -+ -+ if (vlan_dev && vlan_dev->vlan_dev) { -+ /* Then it's a real vlan device, as far as we can tell.. */ -+ real_dev = vlan_dev->vlan_dev->real_dev; -+ -+ /* compare the current promiscuity to the last promisc we had.. */ -+ inc = vlan_dev->promiscuity - vlan_dev->vlan_dev->old_promiscuity; -+ -+ if (inc) { -+ printk(KERN_INFO "vlan: dev_set_promiscuity(master, %d)\n", inc); -+ dev_set_promiscuity(real_dev, inc); /* found in dev.c */ -+ vlan_dev->vlan_dev->old_promiscuity = vlan_dev->promiscuity; -+ } -+ -+ inc = vlan_dev->allmulti - vlan_dev->vlan_dev->old_allmulti; -+ -+ if (inc) { -+ printk(KERN_INFO "vlan: dev_set_allmulti(master, %d)\n", inc); -+ dev_set_allmulti(real_dev, inc); /* dev.c */ -+ vlan_dev->vlan_dev->old_allmulti = vlan_dev->allmulti; -+ } -+ -+ /* looking for addresses to add to master's list */ -+ for (dmi = vlan_dev->mc_list; dmi!=NULL; dmi=dmi->next) { -+ if (vlan_should_add_mc(dmi, vlan_dev->vlan_dev->old_mc_list)) { -+ dev_mc_add(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); -+ printk(KERN_INFO "vlan: add %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address to master interface\n", -+ dmi->dmi_addr[0], -+ dmi->dmi_addr[1], -+ dmi->dmi_addr[2], -+ dmi->dmi_addr[3], -+ dmi->dmi_addr[4], -+ dmi->dmi_addr[5]); -+ } -+ } -+ -+ /* looking for addresses to delete from master's list */ -+ for (dmi = vlan_dev->mc_list; dmi!=NULL; dmi=dmi->next) { -+ if (vlan_should_add_mc(dmi, vlan_dev->mc_list)) { -+ /* if we think we should add it to the new list, then we should really -+ * delete it from the real list on the underlying device. -+ */ -+ dev_mc_delete(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); -+ printk(KERN_INFO "vlan: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n", -+ dmi->dmi_addr[0], -+ dmi->dmi_addr[1], -+ dmi->dmi_addr[2], -+ dmi->dmi_addr[3], -+ dmi->dmi_addr[4], -+ dmi->dmi_addr[5]); -+ } -+ } -+ -+ /* save multicast list */ -+ vlan_copy_mc_list(vlan_dev->mc_list, vlan_dev->vlan_dev); -+ }/* if we were sent a valid device */ -+}/* vlan_dev_set_multicast */ -+ -+ -+/** dmi is a single entry into a dev_mc_list, a single node. mc_list is -+ * an entire list, and we'll iterate through it. -+ */ -+int vlan_should_add_mc(struct dev_mc_list *dmi, struct dev_mc_list *mc_list) { -+ struct dev_mc_list *idmi; /* iterator */ -+ -+ for (idmi=mc_list; idmi!=NULL;) { -+ if (vlan_dmi_equals(dmi, idmi)) { -+ if (dmi->dmi_users > idmi->dmi_users) -+ return 1; -+ else -+ return 0; -+ } -+ else { -+ idmi = idmi->next; -+ } -+ } -+ -+ return 1; -+} -+ -+ -+void vlan_copy_mc_list(struct dev_mc_list *mc_list, struct vlan_dev_info *vlan_info) { -+ struct dev_mc_list *dmi, *new_dmi; -+ -+ vlan_destroy_mc_list(vlan_info->old_mc_list); -+ vlan_info->old_mc_list = NULL; -+ -+ for (dmi=mc_list; dmi!=NULL; dmi=dmi->next) { -+ new_dmi = kmalloc(sizeof(*new_dmi), GFP_KERNEL); -+ if (new_dmi == NULL) { -+ printk(KERN_ERR "vlan: cannot allocate memory. Multicast may not work properly from now.\n"); -+ return; -+ } -+ -+ new_dmi->next = vlan_info->old_mc_list; -+ vlan_info->old_mc_list = new_dmi; -+ -+ new_dmi->dmi_addrlen = dmi->dmi_addrlen; -+ memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); -+ new_dmi->dmi_users = dmi->dmi_users; -+ new_dmi->dmi_gusers = dmi->dmi_gusers; -+ } -+} -+ -+void vlan_flush_mc_list(struct device *dev) { -+ struct dev_mc_list *dmi = dev->mc_list; -+ -+ while (dmi) { -+ dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); -+ printk(KERN_INFO "vlan: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n", -+ dmi->dmi_addr[0], -+ dmi->dmi_addr[1], -+ dmi->dmi_addr[2], -+ dmi->dmi_addr[3], -+ dmi->dmi_addr[4], -+ dmi->dmi_addr[5]); -+ dmi = dev->mc_list; -+ } -+ -+ vlan_destroy_mc_list(dev->mc_list); -+ if (dev->vlan_dev) { -+ vlan_destroy_mc_list(dev->vlan_dev->old_mc_list); -+ dev->vlan_dev->old_mc_list = NULL; -+ } -+ dev->mc_list = NULL; -+}/* vlan_flush_mc_list */ -diff -u -r -N -X /home/greear/exclude.list linux/net/802_1Q/vlanproc.c linux.dev/net/802_1Q/vlanproc.c ---- linux/net/802_1Q/vlanproc.c Wed Dec 31 17:00:00 1969 -+++ linux.dev/net/802_1Q/vlanproc.c Fri Dec 29 19:51:33 2000 -@@ -0,0 +1,654 @@ -+/* * -*- linux-c -*- */ -+/***************************************************************************** -+ * vlanproc.c VLAN Module. /proc filesystem interface. -+* -+* Author: Ben Greear, <greearb@candelatech.com> coppied from wanproc.c -+* by: Gene Kozin <genek@compuserve.com> -+* -+* Copyright: (c) 1998-2000 Ben Greear -+* -+* This program is free software; you can redistribute it and/or -+* modify it under the terms of the GNU General Public License -+* as published by the Free Software Foundation; either version -+* 2 of the License, or (at your option) any later version. -+* ============================================================================ -+* Jan 20, 1998 Ben Greear Initial Version -+*****************************************************************************/ -+ -+#include <linux/config.h> -+#include <linux/stddef.h> /* offsetof(), etc. */ -+#include <linux/errno.h> /* return codes */ -+#include <linux/kernel.h> -+#include <linux/malloc.h> /* kmalloc(), kfree() */ -+#include <linux/mm.h> /* verify_area(), etc. */ -+#include <linux/string.h> /* inline mem*, str* functions */ -+#include <linux/init.h> /* __initfunc et al. */ -+#include <asm/segment.h> /* kernel <-> user copy */ -+#include <asm/byteorder.h> /* htons(), etc. */ -+#include <asm/uaccess.h> /* copy_to_user */ -+#include <asm/io.h> -+#include <linux/proc_fs.h> -+#include <linux/fs.h> -+#include <linux/netdevice.h> -+#include <linux/if_vlan.h> -+#include "vlanproc.h" -+#include "vlan.h" -+ -+/****** Defines and Macros **************************************************/ -+ -+#ifndef min -+#define min(a,b) (((a)<(b))?(a):(b)) -+#endif -+#ifndef max -+#define max(a,b) (((a)>(b))?(a):(b)) -+#endif -+ -+ -+/****** Function Prototypes *************************************************/ -+ -+#ifdef CONFIG_PROC_FS -+ -+/* Proc filesystem interface */ -+static int vlan_proc_perms(struct inode *, int); -+static ssize_t vlan_proc_read(struct file* file, char* buf, size_t count, -+ loff_t *ppos); -+ -+/* Methods for preparing data for reading proc entries */ -+ -+static int vlan_config_get_info(char* buf, char** start, off_t offs, int len, -+ int dummy); -+static int vlandev_get_info(char* buf, char** start, off_t offs, int len, -+ int dummy); -+ -+ -+/* Miscellaneous */ -+ -+/* -+ * Global Data -+ */ -+ -+/* -+ * Names of the proc directory entries -+ */ -+ -+static char name_root[] = "vlan"; -+static char name_conf[] = "config"; -+static char term_msg[] = "***KERNEL: Out of buffer space!***\n"; -+ -+ -+/* -+ * VLAN device IOCTL. -+ * o execute requested action or pass command to the device driver -+ */ -+ -+int vlan_ioctl(struct inode* inode, struct file* file, -+ unsigned int cmd, unsigned long arg) { -+ int err = 0; -+ /* -+ struct proc_dir_entry* dent; -+ struct device* dev; -+ */ -+ struct vlan_ioctl_args args; -+ -+ printk(VLAN_DBG __FUNCTION__ ": cmd: %x\n", cmd); -+ -+ /* everything here needs root permissions, except aguably the -+ * hack ioctls for sending packets. However, I know _I_ don't -+ * want users running that on my network! --BLG -+ */ -+ if (!capable(CAP_NET_ADMIN)){ -+ return -EPERM; -+ } -+ -+ if ((cmd >> 8) != VLAN_IOCTL) { -+ printk(VLAN_DBG __FUNCTION__ ": Not a VLAN IOCTL: %x \n", cmd); -+ return -EINVAL; -+ } -+ -+ if (copy_from_user(&args, (void*)arg, sizeof(struct vlan_ioctl_args))) -+ return -EFAULT; -+ -+ /* Null terminate this sucker, just in case. */ -+ args.dev1[23] = 0; -+ args.u.dev2[23] = 0; -+ -+ /* -+ dent = inode->u.generic_ip; -+ if ((dent == NULL) || (dent->data == NULL)) -+ return -EINVAL; -+ -+ dev = dent->data; -+ */ -+ -+ switch (cmd) -+ { -+ case SET_INGRESS_PRIORITY_IOCTL: -+ err = vlan_dev_set_ingress_priority(args.dev1, args.u.skb_priority, args.vlan_qos); -+ break; -+ -+ case SET_EGRESS_PRIORITY_IOCTL: -+ err = vlan_dev_set_egress_priority(args.dev1, args.u.skb_priority, args.vlan_qos); -+ break; -+ -+ case SET_VLAN_FLAG_IOCTL: -+ err = vlan_dev_set_vlan_flag(args.dev1, args.u.flag, args.vlan_qos); -+ break; -+ -+ case SET_NAME_TYPE_IOCTL: -+ if ((args.u.name_type >= 0) && (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) { -+ vlan_name_type = args.u.name_type; -+ err = 0; -+ } -+ else { -+ err = -EINVAL; -+ } -+ break; -+ -+ /* TODO: Figure out how to pass info back... -+ case GET_INGRESS_PRIORITY_IOCTL: -+ err = vlan_dev_get_ingress_priority(args); -+ break; -+ -+ case GET_EGRESS_PRIORITY_IOCTL: -+ err = vlan_dev_get_egress_priority(args); -+ break; -+ */ -+ -+ case ADD_VLAN_IOCTL: -+ /* we have been given the name of the Ethernet Device we want to -+ * talk to: args.dev1 We also have the -+ * VLAN ID: args.u.VID -+ */ -+ if (register_802_1Q_vlan_device(args.dev1, args.u.VID)) { -+ err = 0; -+ } -+ else { -+ err = -EINVAL; -+ } -+ break; -+ -+ case DEL_VLAN_IOCTL: -+ /* Here, the args.dev1 is the actual VLAN we want to get rid of. */ -+ -+ err = unregister_802_1Q_vlan_device(args.dev1); -+ break; -+ -+ default: -+ /* pass on to underlying device instead?? */ -+ printk(VLAN_DBG __FUNCTION__ ": Unknown VLAN IOCTL: %x \n", cmd); -+ return -EINVAL; -+ }/* switch */ -+ return err; -+} -+ -+/* -+ * Structures for interfacing with the /proc filesystem. -+ * VLAN creates its own directory /proc/net/vlan with the folowing -+ * entries: -+ * config device status/configuration -+ * <device> entry for each device -+ */ -+ -+/* -+ * Generic /proc/net/vlan/<file> file and inode operations -+ */ -+ -+static struct file_operations vlan_fops = { -+ NULL, /* lseek */ -+ vlan_proc_read, /* read */ -+ NULL, /* write */ -+ NULL, /* readdir */ -+ NULL, /* select */ -+ vlan_ioctl, /* ioctl */ -+ NULL, /* mmap */ -+ NULL, /* no special open code */ -+ NULL, /* flush */ -+ NULL, /* no special release code */ -+ NULL /* can't fsync */ -+}; -+ -+static struct inode_operations vlan_inode = { -+ &vlan_fops, -+ NULL, /* create */ -+ NULL, /* lookup */ -+ NULL, /* link */ -+ NULL, /* unlink */ -+ NULL, /* symlink */ -+ NULL, /* mkdir */ -+ NULL, /* rmdir */ -+ NULL, /* mknod */ -+ NULL, /* rename */ -+ NULL, /* follow link */ -+ NULL, /* readlink */ -+ NULL, /* readpage */ -+ NULL, /* writepage */ -+ NULL, /* bmap */ -+ NULL, /* truncate */ -+ vlan_proc_perms -+}; -+ -+/* -+ * /proc/net/vlan/<device> file and inode operations -+ */ -+ -+static struct file_operations vlandev_fops = { -+ NULL, /* lseek */ -+ vlan_proc_read, /* read */ -+ NULL, /* write */ -+ NULL, /* readdir */ -+ NULL, /* select */ -+ vlan_ioctl, /* ioctl */ -+ NULL, /* mmap */ -+ NULL, /* no special open code */ -+ NULL, /* flush */ -+ NULL, /* no special release code */ -+ NULL /* can't fsync */ -+}; -+ -+static struct inode_operations vlandev_inode = { -+ &vlandev_fops, -+ NULL, /* create */ -+ NULL, /* lookup */ -+ NULL, /* link */ -+ NULL, /* unlink */ -+ NULL, /* symlink */ -+ NULL, /* mkdir */ -+ NULL, /* rmdir */ -+ NULL, /* mknod */ -+ NULL, /* rename */ -+ NULL, /* readlink */ -+ NULL, /* follow_link */ -+ NULL, /* readpage */ -+ NULL, /* writepage */ -+ NULL, /* bmap */ -+ NULL, /* truncate */ -+ vlan_proc_perms -+}; -+ -+ -+/* -+ * Proc filesystem derectory entries. -+ */ -+ -+/* -+ * /proc/net/vlan -+ */ -+ -+static struct proc_dir_entry proc_vlan = { -+ 0, /* .low_ino */ -+ sizeof(name_root) - 1, /* .namelen */ -+ name_root, /* .name */ -+ 0555 | S_IFDIR, /* .mode */ -+ 2, /* .nlink */ -+ 0, /* .uid */ -+ 0, /* .gid */ -+ 0, /* .size */ -+ &proc_dir_inode_operations, /* .ops */ -+ NULL, /* .get_info */ -+ NULL, /* .fill_node */ -+ NULL, /* .next */ -+ NULL, /* .parent */ -+ NULL, /* .subdir */ -+ NULL, /* .data */ -+}; -+ -+/* -+ * /proc/net/vlan/config -+ */ -+ -+static struct proc_dir_entry proc_vlan_conf = { -+ 0, /* .low_ino */ -+ sizeof(name_conf) - 1, /* .namelen */ -+ name_conf, /* .name */ -+ 0444 | S_IFREG, /* .mode */ -+ 1, /* .nlink */ -+ 0, /* .uid */ -+ 0, /* .gid */ -+ 0, /* .size */ -+ &vlan_inode, /* .ops */ -+ &vlan_config_get_info, /* .get_info */ -+ NULL, /* .fill_node */ -+ NULL, /* .next */ -+ NULL, /* .parent */ -+ NULL, /* .subdir */ -+ NULL, /* .data */ -+}; -+ -+ -+/* Strings */ -+static char conf_hdr[] = "VLAN Dev name | VLAN ID\n"; -+ -+ -+/* -+ * Interface functions -+ */ -+ -+/* -+ * Initialize vlan proc interface. -+ */ -+ -+__initfunc(int vlan_proc_init (void)) { -+ int err = proc_register(proc_net, &proc_vlan); -+ -+ if (!err) { -+ proc_register(&proc_vlan, &proc_vlan_conf); -+ } -+ return err; -+} -+ -+/* -+ * Clean up router proc interface. -+ */ -+ -+void vlan_proc_cleanup (void) { -+ proc_unregister(&proc_vlan, proc_vlan_conf.low_ino); -+ proc_unregister(proc_net, proc_vlan.low_ino); -+} -+ -+ -+/* -+ * Add directory entry for VLAN device. -+ */ -+ -+int vlan_proc_add_dev (struct device* vlandev) { -+ if (!vlandev->vlan_dev) { -+ printk(KERN_ERR "ERROR: vlan_proc_add, device -:%s:- is NOT a VLAN\n", -+ vlandev->name); -+ return -EINVAL; -+ } -+ -+ memset(&(vlandev->vlan_dev->dent), 0, sizeof(vlandev->vlan_dev->dent)); -+ vlandev->vlan_dev->dent.namelen = strlen(vlandev->name); -+ vlandev->vlan_dev->dent.name = vlandev->name; -+ vlandev->vlan_dev->dent.mode = 0444 | S_IFREG; -+ vlandev->vlan_dev->dent.nlink = 1; -+ vlandev->vlan_dev->dent.ops = &vlandev_inode; -+ vlandev->vlan_dev->dent.get_info = &vlandev_get_info; -+ vlandev->vlan_dev->dent.data = vlandev; -+ -+#ifdef VLAN_DEBUG -+ printk(KERN_ERR "vlan_proc_add, device -:%s:- being added.\n", -+ vlandev->name); -+#endif -+ -+ return proc_register(&proc_vlan, &vlandev->vlan_dev->dent); -+} -+ -+ -+ -+/* -+ * Delete directory entry for VLAN device. -+ */ -+int vlan_proc_rem_dev(struct device* vlandev) { -+ if (!vlandev || !vlandev->vlan_dev) { -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": invalid argument: %p\n", vlandev); -+#endif -+ return -EINVAL; -+ } -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": calling proc_unregister for dev: %p\n", -+ vlandev); -+#endif -+ return proc_unregister(&proc_vlan, vlandev->vlan_dev->dent.low_ino); -+} -+ -+ -+/****** Proc filesystem entry points ****************************************/ -+ -+/* -+ * Verify access rights. -+ */ -+ -+static int vlan_proc_perms (struct inode* inode, int op) { -+ return 0; -+} -+ -+/* -+ * Read VLAN proc directory entry. -+ * This is universal routine for reading all entries in /proc/net/vlan -+ * directory. Each directory entry contains a pointer to the 'method' for -+ * preparing data for that entry. -+ * o verify arguments -+ * o allocate kernel buffer -+ * o call get_info() to prepare data -+ * o copy data to user space -+ * o release kernel buffer -+ * -+ * Return: number of bytes copied to user space (0, if no data) -+ * <0 error -+ */ -+static ssize_t vlan_proc_read(struct file* file, char* buf, size_t count, -+ loff_t *ppos) { -+ struct inode *inode = file->f_dentry->d_inode; -+ struct proc_dir_entry* dent; -+ char* page; -+ int pos, offs, len; -+ -+ if (count <= 0) -+ return 0; -+ -+ dent = inode->u.generic_ip; -+ if ((dent == NULL) || (dent->get_info == NULL)) -+ return 0; -+ -+ page = kmalloc(VLAN_PROC_BUFSZ, GFP_KERNEL); -+ VLAN_MEM_DBG("page malloc, addr: %p size: %i\n", page, VLAN_PROC_BUFSZ); -+ -+ if (page == NULL) -+ return -ENOBUFS; -+ -+ pos = dent->get_info(page, dent->data, 0, 0, 0); -+ offs = file->f_pos; -+ if (offs < pos) { -+ len = min(pos - offs, count); -+ if (copy_to_user(buf, (page + offs), len)) { -+ return -EFAULT; -+ } -+ file->f_pos += len; -+ } -+ else { -+ len = 0; -+ } -+ -+ kfree(page); -+ VLAN_FMEM_DBG("page free, addr: %p\n", page); -+ return len; -+}/* vlan_proc_read */ -+ -+ -+static int vlan_proc_get_vlan_info(char* buf, unsigned int cnt) { -+ struct device* vlandev = NULL; -+ struct vlan_group* grp = NULL; -+ int i = 0; -+ char* nm_type = NULL; -+ -+ printk(VLAN_DBG __FUNCTION__ ": cnt == %i\n", cnt); -+ -+ if (vlan_name_type == VLAN_NAME_TYPE_RAW_PLUS_VID) { -+ nm_type = "VLAN_NAME_TYPE_RAW_PLUS_VID"; -+ } -+ else if (vlan_name_type == VLAN_NAME_TYPE_PLUS_VID_NO_PAD) { -+ nm_type = "VLAN_NAME_TYPE_PLUS_VID_NO_PAD"; -+ } -+ else if (vlan_name_type == VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD) { -+ nm_type = "VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD"; -+ } -+ else if (vlan_name_type == VLAN_NAME_TYPE_PLUS_VID) { -+ nm_type = "VLAN_NAME_TYPE_PLUS_VID"; -+ } -+ else { -+ nm_type = "UNKNOWN"; -+ } -+ -+ cnt += sprintf(buf + cnt, "Name-Type: %s bad_proto_recvd: %lu\n", -+ nm_type, vlan_bad_proto_recvd); -+ -+ for (grp = p802_1Q_vlan_list; grp != NULL; grp = grp->next) { -+ /* loop through all devices for this device */ -+ printk(VLAN_DBG __FUNCTION__ ": found a group, addr: %p\n", grp); -+ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { -+ /* printk(VLAN_DBG __FUNCTION__ ": checking index[%i]\n", i); */ -+ if ((vlandev = grp->vlan_devices[i])) { -+ printk(VLAN_DBG __FUNCTION__ ": found a vlan_dev, addr: %p\n", vlandev); -+ if ((cnt + 100) > VLAN_PROC_BUFSZ) { -+ if ((cnt + strlen(term_msg)) >= VLAN_PROC_BUFSZ) { -+ /* should never get here */ -+ return cnt; -+ } -+ else { -+ cnt += sprintf(buf + cnt, "%s", term_msg); -+ return cnt; -+ } -+ }/* if running out of buffer space */ -+ else { -+ if (!vlandev->vlan_dev) { -+ printk(KERN_ERR __FUNCTION__ ": ERROR: vlandev->vlan_dev is NULL\n"); -+ } -+ else { -+ printk(VLAN_DBG __FUNCTION__ ": got a good vlandev, addr: %p\n", vlandev->vlan_dev); -+ cnt += sprintf(buf + cnt, "%-15s| %d | %s\n", -+ vlandev->name, vlandev->vlan_dev->vlan_id, vlandev->vlan_dev->real_dev->name); -+ }/* else */ -+ }/* else */ -+ }/* if we have a vlan of this number */ -+ }/* for all VLAN's */ -+ }/* for each vlan group, default is only one.*/ -+ -+ return cnt; -+}/* vlan_proc_get_vlan_info */ -+ -+/* -+ * Prepare data for reading 'Config' entry. -+ * Return length of data. -+ */ -+ -+static int vlan_config_get_info(char* buf, char** start, off_t offs, int len, -+ int dummy) { -+ strcpy(buf, conf_hdr); -+ return vlan_proc_get_vlan_info(buf, (unsigned int)(strlen(conf_hdr))); -+} -+ -+ -+/* -+ * Prepare data for reading <device> entry. -+ * Return length of data. -+ * -+ * On entry, the 'start' argument will contain a pointer to VLAN device -+ * data space. -+ */ -+ -+static int vlandev_get_info(char* buf, char** start, off_t offs, int len, -+ int dummy) { -+ struct device* vlandev = (void*)start; -+ struct net_device_stats* stats; -+ int cnt = 0; -+ struct vlan_priority_tci_mapping* mp; -+ int i; -+ -+#ifdef VLAN_DEBUG -+ printk(VLAN_DBG __FUNCTION__ ": vlandev: %p\n", vlandev); -+#endif -+ -+ if ((vlandev == NULL) || (!vlandev->vlan_dev)) { -+ return 0; -+ } -+ -+ cnt += sprintf(buf + cnt, "%s VID: %d REORDER_HDR: %i\n", -+ vlandev->name, vlandev->vlan_dev->vlan_id, (int)(vlandev->vlan_dev->flags & 1)); -+ stats = (struct net_device_stats*)(vlandev->priv); -+ -+ cnt += sprintf(buf + cnt, "%30s: %12lu\n", -+ "total frames received", stats->rx_packets); -+ -+ cnt += sprintf(buf + cnt, "%30s: %12lu\n", -+ "total bytes received", stats->rx_bytes); -+ -+ cnt += sprintf(buf + cnt, "%30s: %12lu\n", -+ "Broadcast/Multicast Rcvd", stats->multicast); -+ -+ cnt += sprintf(buf + cnt, "\n%30s: %12lu\n", -+ "total frames transmitted", stats->tx_packets); -+ -+ cnt += sprintf(buf + cnt, "%30s: %12lu\n", -+ "total bytes transmitted", stats->tx_bytes); -+ -+ cnt += sprintf(buf + cnt, "%30s: %12lu\n", -+ "total headroom inc", vlandev->vlan_dev->cnt_inc_headroom_on_tx); -+ -+ cnt += sprintf(buf + cnt, "%30s: %12lu\n", -+ "total encap on xmit", vlandev->vlan_dev->cnt_encap_on_xmit); -+ -+ cnt += sprintf(buf + cnt, "Device: %s", vlandev->vlan_dev->real_dev->name); -+ -+ /* now show all PRIORITY mappings relating to this VLAN */ -+ cnt += sprintf(buf + cnt, "\nINGRESS priority mappings: 0:%lu 1:%lu 2:%lu 3:%lu 4:%lu 5:%lu 6:%lu 7:%lu\n", -+ vlandev->vlan_dev->ingress_priority_map[0], -+ vlandev->vlan_dev->ingress_priority_map[1], -+ vlandev->vlan_dev->ingress_priority_map[2], -+ vlandev->vlan_dev->ingress_priority_map[3], -+ vlandev->vlan_dev->ingress_priority_map[4], -+ vlandev->vlan_dev->ingress_priority_map[5], -+ vlandev->vlan_dev->ingress_priority_map[6], -+ vlandev->vlan_dev->ingress_priority_map[7]); -+ -+ cnt += sprintf(buf + cnt, "EGRESSS priority Mappings: "); -+ -+ for (i = 0; i<16; i++) { -+ mp = vlandev->vlan_dev->egress_priority_map[i]; -+ while (mp) { -+ cnt += sprintf(buf + cnt, "%lu:%hu ", mp->priority, ((mp->vlan_qos >> 13) & 0x7)); -+ -+ if ((cnt + 100) > VLAN_PROC_BUFSZ) { -+ if ((cnt + strlen(term_msg)) >= VLAN_PROC_BUFSZ) { -+ /* should never get here */ -+ return cnt; -+ } -+ else { -+ cnt += sprintf(buf + cnt, "%s", term_msg); -+ return cnt; -+ } -+ }/* if running out of buffer space */ -+ mp = mp->next; -+ } -+ }/* for */ -+ -+ cnt += sprintf(buf + cnt, "\n"); -+ -+ return cnt; -+} -+ -+ -+/* -+ * End -+ */ -+ -+#else -+ -+/* -+ * No /proc - output stubs -+ */ -+ -+__initfunc(int vlan_proc_init(void)) -+{ -+ return 0; -+} -+ -+void vlan_proc_cleanup(void) -+{ -+ return; -+} -+ -+ -+int vlan_proc_add_dev(struct device *vlandev) -+{ -+ return 0; -+} -+ -+int vlan_proc_rem_dev(struct device *vlandev) -+{ -+ return 0; -+} -+ -+#endif -diff -u -r -N -X /home/greear/exclude.list linux/net/802_1Q/vlanproc.h linux.dev/net/802_1Q/vlanproc.h ---- linux/net/802_1Q/vlanproc.h Wed Dec 31 17:00:00 1969 -+++ linux.dev/net/802_1Q/vlanproc.h Fri Dec 29 19:51:33 2000 -@@ -0,0 +1,27 @@ -+ -+#ifndef __BEN_VLAN_PROC_INC__ -+#define __BEN_VLAN_PROC_INC__ -+ -+ -+int vlan_proc_init(void); -+ -+int vlan_proc_rem_dev(struct device* vlandev); -+int vlan_proc_add_dev (struct device* vlandev); -+void vlan_proc_cleanup (void); -+ -+ -+#define VLAN_PROC_BUFSZ (4096) /* buffer size for printing proc info */ -+ -+/****** Data Types **********************************************************/ -+ -+/* -+typedef struct vlan_stat_entry { -+ struct vlan_stat_entry * next; -+ char *description; * description string * -+ void *data; * -> data * -+ unsigned data_type; * data type * -+} vlan_stat_entry_t; -+*/ -+ -+ -+#endif -diff -u -r -N -X /home/greear/exclude.list linux/net/Config.in linux.dev/net/Config.in ---- linux/net/Config.in Sun Dec 10 17:49:44 2000 -+++ linux.dev/net/Config.in Fri Dec 29 19:51:33 2000 -@@ -44,6 +44,9 @@ - fi - bool 'Frame Diverter (EXPERIMENTAL)' CONFIG_NET_DIVERT - bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC -+ -+ bool '802.1Q VLAN Support (EXPERIMENTAL)' CONFIG_VLAN_802_1Q -+ - # if [ "$CONFIG_LLC" = "y" ]; then - # bool 'Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI - # fi -diff -u -r -N -X /home/greear/exclude.list linux/net/Makefile linux.dev/net/Makefile ---- linux/net/Makefile Mon Mar 22 12:18:17 1999 -+++ linux.dev/net/Makefile Fri Dec 29 19:51:33 2000 -@@ -10,7 +10,7 @@ - MOD_SUB_DIRS := ipv4 - ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \ - netrom rose lapb x25 wanrouter netlink sched packet sunrpc \ -- econet irda #decnet -+ econet irda 802_1Q #decnet - SUB_DIRS := core ethernet sched - MOD_LIST_NAME := NET_MISC_MODULES - -@@ -59,6 +59,10 @@ - - ifeq ($(CONFIG_BRIDGE),y) - SUB_DIRS += bridge -+endif -+ -+ifeq ($(CONFIG_VLAN_802_1Q),y) -+SUB_DIRS += 802_1Q - endif - - ifeq ($(CONFIG_IPX),y) -diff -u -r -N -X /home/greear/exclude.list linux/net/core/dev.c linux.dev/net/core/dev.c ---- linux/net/core/dev.c Sun Dec 10 17:49:44 2000 -+++ linux.dev/net/core/dev.c Sun Jan 14 14:16:43 2001 -@@ -1,4 +1,4 @@ --/* -+/* -*- linux-c -*- - * NET3 Protocol independent device support routines. - * - * This program is free software; you can redistribute it and/or -@@ -94,6 +94,11 @@ - #ifdef CONFIG_NET_RADIO - #include <linux/wireless.h> - #endif /* CONFIG_NET_RADIO */ -+ -+#ifdef CONFIG_VLAN_802_1Q -+#include "../802_1Q/vlan.h" -+#endif -+ - #ifdef CONFIG_PLIP - extern int plip_init(void); - #endif -@@ -123,9 +128,17 @@ - * and the routines to invoke. - * - * Why 16. Because with 16 the only overlap we get on a hash of the -- * low nibble of the protocol value is RARP/SNAP/X.25. -+ * low nibble of the protocol value is RARP/SNAP/X.25. -+ * -+ * NOTE: That is no longer true with the addition of VLAN tags. Not -+ * sure which should go first, but I bet it won't make much -+ * difference if we are running VLANs. The good news is that -+ * this protocol won't be in the list unless compiled in, so -+ * the average user (w/out VLANs) will not be adversly affected. -+ * --BLG - * - * 0800 IP -+ * 8100 802.1Q VLAN - * 0001 802.3 - * 0002 AX.25 - * 0004 802.2 -@@ -170,6 +183,256 @@ - static void dev_clear_backlog(struct device *dev); - - -+/* Taking this out, because lo has problems for some people. Feel -+ * free to turn it back on and give me (greearb@candelatech.com) bug -+ * reports if you can re-produce the problem. --Ben -+ -+ #define BENS_FAST_DEV_LOOKUP -+ -+*/ -+#ifdef BENS_FAST_DEV_LOOKUP -+/* Fast Device Lookup code. Should give much better than -+ * linear speed when looking for devices by idx or name. -+ * --Ben (greearb@candelatech.com) -+ */ -+#define FDL_HASH_LEN 256 -+ -+/* #define FDL_DEBUG */ -+ -+struct dev_hash_node { -+ struct device* dev; -+ struct dev_hash_node* next; -+}; -+ -+struct dev_hash_node* fdl_name_base[FDL_HASH_LEN];/* hashed by name */ -+struct dev_hash_node* fdl_idx_base[FDL_HASH_LEN]; /* hashed by index */ -+int fdl_initialized_yet = 0; -+ -+/* TODO: Make these inline methods */ -+/* Nice cheesy little hash method to be used on device-names (eth0, ppp0, etc) */ -+int fdl_calc_name_idx(const char* dev_name) { -+ int tmp = 0; -+ int i; -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "fdl_calc_name_idx, name: %s\n", dev_name); -+#endif -+ for (i = 0; dev_name[i]; i++) { -+ tmp += (int)(dev_name[i]); -+ } -+ if (i > 3) { -+ tmp += (dev_name[i-2] * 10); /* might add a little spread to the hash */ -+ tmp += (dev_name[i-3] * 100); /* might add a little spread to the hash */ -+ } -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "fdl_calc_name_idx, rslt: %i\n", (int)(tmp % FDL_HASH_LEN)); -+#endif -+ return (tmp % FDL_HASH_LEN); -+} -+ -+int fdl_calc_index_idx(const int ifindex) { -+ return (ifindex % FDL_HASH_LEN); -+} -+ -+ -+/* Better have a lock on the dev_base before calling this... */ -+int __fdl_ensure_init(void) { -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_ensure_init, enter\n"); -+#endif -+ if (! fdl_initialized_yet) { -+ /* only do this once.. */ -+ int i; -+ int idx = 0; /* into the hash table */ -+ struct device* dev = dev_base; -+ struct dev_hash_node* dhn; -+ -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_ensure_init, doing real work..."); -+#endif -+ -+ fdl_initialized_yet = 1; /* it has been attempted at least... */ -+ -+ for (i = 0; i<FDL_HASH_LEN; i++) { -+ fdl_name_base[i] = NULL; -+ fdl_idx_base[i] = NULL; -+ } -+ -+ /* add any current devices to the hash tables at this time. Note that -+ * this method must be called with locks on the dev_base acquired. -+ */ -+ while (dev) { -+ -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_ensure_init, dev: %p dev: %s, idx: %i\n", dev, dev->name, idx); -+#endif -+ /* first, take care of the hash-by-name */ -+ idx = fdl_calc_name_idx(dev->name); -+ dhn = kmalloc(sizeof(struct dev_hash_node), GFP_ATOMIC); -+ if (dhn) { -+ dhn->dev = dev; -+ dhn->next = fdl_name_base[idx]; -+ fdl_name_base[idx] = dhn; -+ } -+ else { -+ /* Nasty..couldn't get memory... */ -+ return -ENOMEM; -+ } -+ -+ /* now, do the hash-by-idx */ -+ idx = fdl_calc_index_idx(dev->ifindex); -+ dhn = kmalloc(sizeof(struct dev_hash_node), GFP_ATOMIC); -+ if (dhn) { -+ dhn->dev = dev; -+ dhn->next = fdl_idx_base[idx]; -+ fdl_idx_base[idx] = dhn; -+ } -+ else { -+ /* Nasty..couldn't get memory... */ -+ return -ENOMEM; -+ } -+ -+ dev = dev->next; -+ } -+ fdl_initialized_yet = 2; /* initialization actually worked */ -+ } -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_ensure_init, end, fdl_initialized_yet: %i\n", fdl_initialized_yet); -+#endif -+ if (fdl_initialized_yet == 2) { -+ return 0; -+ } -+ else { -+ return -1; -+ } -+}/* fdl_ensure_init */ -+ -+ -+/* called from register_netdevice, assumes dev is locked, and that no one -+ * will be calling __find_dev_by_name before this exits.. etc. -+ */ -+int __fdl_register_netdevice(struct device* dev) { -+ if (__fdl_ensure_init() == 0) { -+ /* first, take care of the hash-by-name */ -+ int idx = fdl_calc_name_idx(dev->name); -+ struct dev_hash_node* dhn = kmalloc(sizeof(struct dev_hash_node), GFP_ATOMIC); -+ -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_register_netdevice, dev: %p dev: %s, idx: %i", dev, dev->name, idx); -+#endif -+ -+ if (dhn) { -+ dhn->dev = dev; -+ dhn->next = fdl_name_base[idx]; -+ fdl_name_base[idx] = dhn; -+ } -+ else { -+ /* Nasty..couldn't get memory... */ -+ /* Don't try to use these hash tables any more... */ -+ fdl_initialized_yet = 1; /* tried, but failed */ -+ return -ENOMEM; -+ } -+ -+ /* now, do the hash-by-idx */ -+ idx = fdl_calc_index_idx(dev->ifindex); -+ dhn = kmalloc(sizeof(struct dev_hash_node), GFP_ATOMIC); -+ -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_register_netdevice, ifindex: %i, idx: %i", dev->ifindex, idx); -+#endif -+ -+ if (dhn) { -+ dhn->dev = dev; -+ dhn->next = fdl_idx_base[idx]; -+ fdl_idx_base[idx] = dhn; -+ } -+ else { -+ /* Nasty..couldn't get memory... */ -+ /* Don't try to use these hash tables any more... */ -+ fdl_initialized_yet = 1; /* tried, but failed */ -+ return -ENOMEM; -+ } -+ } -+ return 0; -+} /* fdl_register_netdevice */ -+ -+ -+/* called from register_netdevice, assumes dev is locked, and that no one -+ * will be calling __find_dev_by_name, etc. Returns 0 if found & removed one, -+ * returns -1 otherwise. -+ */ -+int __fdl_unregister_netdevice(struct device* dev) { -+ int retval = -1; -+ if (fdl_initialized_yet == 2) { /* If we've been initialized correctly... */ -+ /* first, take care of the hash-by-name */ -+ int idx = fdl_calc_name_idx(dev->name); -+ struct dev_hash_node* prev = fdl_name_base[idx]; -+ struct dev_hash_node* cur = NULL; -+ -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__fdl_unregister_netdevice, dev: %p dev: %s, idx: %i", dev, dev->name, idx); -+#endif -+ -+ if (prev) { -+ if (strcmp(dev->name, prev->dev->name) == 0) { -+ /* it's the first one... */ -+ fdl_name_base[idx] = prev->next; -+ kfree(prev); -+ retval = 0; -+ } -+ else { -+ cur = prev->next; -+ while (cur) { -+ if (strcmp(dev->name, cur->dev->name) == 0) { -+ prev->next = cur->next; -+ kfree(cur); -+ retval = 0; -+ break; -+ } -+ else { -+ prev = cur; -+ cur = cur->next; -+ } -+ } -+ } -+ } -+ -+ /* Now, the hash-by-index */ -+ idx = fdl_calc_index_idx(dev->ifindex); -+ prev = fdl_idx_base[idx]; -+ cur = NULL; -+ if (prev) { -+ if (dev->ifindex == prev->dev->ifindex) { -+ /* it's the first one... */ -+ fdl_idx_base[idx] = prev->next; -+ kfree(prev); -+ retval = 0; -+ } -+ else { -+ cur = prev->next; -+ while (cur) { -+ if (dev->ifindex == cur->dev->ifindex) { -+ prev->next = cur->next; -+ kfree(cur); -+ retval = 0; -+ break; -+ } -+ else { -+ prev = cur; -+ cur = cur->next; -+ } -+ } -+ } -+ } -+ }/* if we ensured init OK */ -+ return retval; -+} /* fdl_unregister_netdevice */ -+ -+ -+ -+#endif /* BENS_FAST_DEV_LOOKUP */ -+ -+ -+ - /****************************************************************************************** - - Protocol management and registration routines -@@ -267,6 +530,25 @@ - { - struct device *dev; - -+#ifdef BENS_FAST_DEV_LOOKUP -+ int idx = fdl_calc_name_idx(name); -+ struct dev_hash_node* dhn; -+ if (fdl_initialized_yet == 2) { -+#ifdef FDL_DEBUG -+ printk(KERN_ERR "__dev_get_by_name, name: %s idx: %i\n", name, idx); -+#endif -+ dhn = fdl_name_base[idx]; -+ while (dhn) { -+ if (strcmp(dhn->dev->name, name) == 0) { -+ /* printk(KERN_ERR "__dev_get_by_name, found it: %p\n", dhn->dev); */ -+ return dhn->dev; -+ } -+ dhn = dhn->next; -+ } -+ /* printk(KERN_ERR "__dev_get_by_name, didn't find it for name: %s\n", name); */ -+ return NULL; -+ } -+#endif - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (strcmp(dev->name, name) == 0) -@@ -278,7 +560,19 @@ - struct device * dev_get_by_index(int ifindex) - { - struct device *dev; -- -+#ifdef BENS_FAST_DEV_LOOKUP -+ int idx = fdl_calc_index_idx(ifindex); -+ struct dev_hash_node* dhn; -+ if (fdl_initialized_yet == 2) { /* have we gone through initialization before... */ -+ dhn = fdl_idx_base[idx]; -+ while (dhn) { -+ if (dhn->dev->ifindex == ifindex) -+ return dhn->dev; -+ dhn = dhn->next; -+ } -+ return NULL; -+ } -+#endif - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (dev->ifindex == ifindex) -@@ -310,14 +604,17 @@ - int i; - /* - * If you need over 100 please also fix the algorithm... -- */ -- for(i=0;i<100;i++) -+ * -+ * Increased it to deal with VLAN interfaces. It is unlikely -+ * that this many will ever be added, but it can't hurt! -BLG -+ */ -+ for(i=0;i<8192;i++) - { - sprintf(dev->name,name,i); - if(dev_get(dev->name)==NULL) - return i; - } -- return -ENFILE; /* Over 100 of the things .. bail out! */ -+ return -ENFILE; /* Over 8192 of the things .. bail out! */ - } - - struct device *dev_alloc(const char *name, int *err) -@@ -830,7 +1127,7 @@ - if(skb==NULL) - return; - -- offset=skb->data-skb->mac.raw; -+ offset = skb->data - skb->mac.raw; - skb_push(skb,offset); /* Put header back on for bridge */ - - if(br_receive_frame(skb)) -@@ -956,7 +1253,7 @@ - } - - /* -- * Fetch the packet protocol ID. -+ * Fetch the packet protocol ID. (In Network Byte Order --BLG) - */ - - type = skb->protocol; -@@ -1603,8 +1900,15 @@ - return -EBUSY; - if (dev_get(ifr->ifr_newname)) - return -EEXIST; -+#ifdef BENS_FAST_DEV_LOOKUP -+ /* Doesn't seem to need any additional locking in kernel 2.2 series... --Ben */ -+ __fdl_unregister_netdevice(dev); /* take it out of the name hash table */ -+#endif - memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ); - dev->name[IFNAMSIZ-1] = 0; -+#ifdef BENS_FAST_DEV_LOOKUP -+ __fdl_register_netdevice(dev); /* put it back in the name hash table, with the new name */ -+#endif - notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); - return 0; - -@@ -1809,6 +2113,12 @@ - return -EEXIST; - } - dev->next = NULL; -+#ifdef BENS_FAST_DEV_LOOKUP -+ /* Must do this before dp is set to dev, or it could be added twice, once -+ * on initialization based on dev_base, and once again after that... -+ */ -+ __fdl_register_netdevice(dev); -+#endif - *dp = dev; - #ifdef CONFIG_NET_DIVERT - ret=alloc_divert_blk(dev); -@@ -1834,6 +2144,13 @@ - dev->ifindex = dev_new_index(); - if (dev->iflink == -1) - dev->iflink = dev->ifindex; -+ -+#ifdef BENS_FAST_DEV_LOOKUP -+ /* Must do this before dp is set to dev, or it could be added twice, once -+ * on initialization based on dev_base, and once again after that... -+ */ -+ __fdl_register_netdevice(dev); -+#endif - *dp = dev; - - /* Notify protocols, that a new device appeared. */ -@@ -1885,6 +2202,9 @@ - for (dp = &dev_base; (d=*dp) != NULL; dp=&d->next) { - if (d == dev) { - *dp = d->next; -+#ifdef BENS_FAST_DEV_LOOKUP -+ __fdl_unregister_netdevice(dev); -+#endif - synchronize_bh(); - d->next = NULL; - -diff -u -r -N -X /home/greear/exclude.list linux/net/ethernet/eth.c linux.dev/net/ethernet/eth.c ---- linux/net/ethernet/eth.c Tue Jan 4 11:12:26 2000 -+++ linux.dev/net/ethernet/eth.c Fri Dec 29 19:51:33 2000 -@@ -174,17 +174,32 @@ - * Determine the packet's protocol ID. The rule here is that we - * assume 802.3 if the type field is short enough to be a length. - * This is normal practice and works for any 'now in use' protocol. -+ * -+ * NOTE: It is likely that you will want to change vlan_type_trans in -+ * 802_1Q/vlan.c if you change anything here. - */ - - unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev) - { - struct ethhdr *eth; - unsigned char *rawp; -- -- skb->mac.raw=skb->data; -- skb_pull(skb,dev->hard_header_len); -- eth= skb->mac.ethernet; -- -+ -+ skb->mac.raw=skb->data; -+ -+#ifdef CONFIG_VLAN_802_1Q -+ /* Moving this below to be more selective. Reason is that for VLAN -+ * devices, we do not want to pull the header, we'll let the VLAN -+ * device do that instead. This makes default vlans (based on incoming -+ * port), much more sane! --BLG -+ */ -+ -+ /* skb_pull(skb,dev->hard_header_len); */ -+#else -+ skb_pull(skb,dev->hard_header_len); -+#endif -+ -+ eth= skb->mac.ethernet; -+ - if(*eth->h_dest&1) - { - if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) -@@ -206,7 +221,21 @@ - if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN)) - skb->pkt_type=PACKET_OTHERHOST; - } -- -+ -+#ifdef CONFIG_VLAN_802_1Q -+ if (ntohs(eth->h_proto) == ETH_P_802_1Q) { -+ /* then we have to convert this into a VLAN looking packet. -+ * We'll wait to do that in the VLAN protocol handler. -+ * -+ * NOTE: We DO NOT PULL ANYTHING FROM THE SKB HERE!!! -+ */ -+ return __constant_htons(ETH_P_802_1Q); -+ } -+ else { -+ skb_pull(skb, dev->hard_header_len); -+ } -+#endif -+ - if (ntohs(eth->h_proto) >= 1536) - return eth->h_proto; - -diff -u -r -N -X /home/greear/exclude.list linux/net/protocols.c linux.dev/net/protocols.c ---- linux/net/protocols.c Thu Dec 17 10:03:57 1998 -+++ linux.dev/net/protocols.c Fri Dec 29 19:51:33 2000 -@@ -34,6 +34,10 @@ - extern void packet_proto_init(struct net_proto *pro); - #endif - -+#ifdef CONFIG_VLAN_802_1Q -+extern void vlan_proto_init(struct net_proto* pro); -+#endif -+ - #if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE) - #define NEED_802 - #include <net/ipxcall.h> -@@ -169,5 +173,9 @@ - { "IrDA", irda_proto_init }, /* IrDA protocols */ - #endif - -+#ifdef CONFIG_VLAN_802_1Q -+ { "VLAN", vlan_proto_init }, /* 802.1Q VLAN Support. --BLG */ -+#endif -+ - { NULL, NULL } /* End marker */ - }; diff --git a/vlan_test.pl b/vlan_test.pl deleted file mode 100644 index f723089..0000000 --- a/vlan_test.pl +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/perl - -# For now, this just tests the addition and removal of 1000 VLAN interfaces on eth0 - -# Arguments: -# graph Generate a graph. -# clean Remove interfaces. - -use strict; - -$| = 1; - -if ($ARGV[0] eq "graph") { - my $dev_cnt = 0; - my $user = 0; - my $system = 0; - my $real = 0; - my $prog = ""; - - open(IPNH, ">/tmp/ip_rpt_no_hash.txt") || die("Can't open /tmp/ip_rpt_no_hash.txt\n"); - open(IFCFGNH, ">/tmp/ifconfig_rpt_no_hash.txt") || die("Can't open /tmp/ifconfig_rpt_no_hash.txt\n"); - open(IP, ">/tmp/ip_rpt.txt") || die("Can't open /tmp/ip_rpt.txt\n"); - open(IFCFG, ">/tmp/ifconfig_rpt.txt") || die("Can't open /tmp/ifconfig_rpt.txt\n"); - - my $hash = $ARGV[1]; - my $no_hash = $ARGV[2]; - - open(IF, "$no_hash"); - while (<IF>) { - my $ln = $_; - chomp($ln); - - #print "LINE: -:$ln:-\n"; - - if ($ln =~ /Doing ip addr show for (\S+)/) { - $dev_cnt = $1; - $prog = "ip"; - } - elsif ($ln =~ /Doing ifconfig -a for (\S+)/) { - $dev_cnt = $1; - $prog = "ifconfig"; - } - elsif ($ln =~ /^real (\S+)/) { - $real = $1; - } - elsif ($ln =~ /^user (\S+)/) { - $user = $1; - } - elsif ($ln =~ /^sys (\S+)/) { - $system = $1; - #print "prog: $prog $dev_cnt\t$user\t$system\t$real\n"; - if ($prog eq "ip") { - print IPNH "$dev_cnt\t$user\t$system\t$real\n"; - } - else { - print IFCFGNH "$dev_cnt\t$user\t$system\t$real\n"; - } - } - else { - #print "INFO: Didn't match anything -:$ln:-\n"; - } - } - - close(IPNH); - close(IFCFGNH); - close(IF); - - open(IF, "$hash"); - while (<IF>) { - my $ln = $_; - chomp($ln); - - #print "LINE: -:$ln:-\n"; - - if ($ln =~ /Doing ip addr show for (\S+)/) { - $dev_cnt = $1; - $prog = "ip"; - } - elsif ($ln =~ /Doing ifconfig -a for (\S+)/) { - $dev_cnt = $1; - $prog = "ifconfig"; - } - elsif ($ln =~ /^real (\S+)/) { - $real = $1; - } - elsif ($ln =~ /^user (\S+)/) { - $user = $1; - } - elsif ($ln =~ /^sys (\S+)/) { - $system = $1; - #print "prog: $prog $dev_cnt\t$user\t$system\t$real\n"; - if ($prog eq "ip") { - print IP "$dev_cnt\t$user\t$system\t$real\n"; - } - else { - print IFCFG "$dev_cnt\t$user\t$system\t$real\n"; - } - } - else { - #print "INFO: Didn't match anything -:$ln:-\n"; - } - } - - close(IP); - close(IFCFG); - - my $plot_cmd = "set title \"ip addr show V/S ifconfig -a\" -set terminal png color -set output \"ip_addr_show.png\" -set size 1,2 -set xlabel \"Interface Count\" -set ylabel \"Seconds\" -set grid -plot \'/tmp/ip_rpt.txt\' using 1:3 title \"ip_system\" with lines, \\ - \'/tmp/ip_rpt.txt\' using 1:2 title \"ip_user\" with lines, \\ - \'/tmp/ifconfig_rpt.txt\' using 1:3 title \"ifconfig_system\" with lines, \\ - \'/tmp/ifconfig_rpt.txt\' using 1:2 title \"ifconfig_user\" with lines, \\ - \'/tmp/ip_rpt_no_hash.txt\' using 1:3 title \"ip_system_no_hash\" with lines, \\ - \'/tmp/ip_rpt_no_hash.txt\' using 1:2 title \"ip_user_no_hash\" with lines, \\ - \'/tmp/ifconfig_rpt_no_hash.txt\' using 1:3 title \"ifconfig_system_no_hash\" with lines, \\ - \'/tmp/ifconfig_rpt_no_hash.txt\' using 1:2 title \"ifconfig_user_no_hash\" with lines"; - print "Plotting with cmd -:$plot_cmd:-\n"; - - open(GP, "| gnuplot") or die ("Can't open gnuplot pipe(2).\n"); - print GP "$plot_cmd"; - close(GP); - - exit(0); -} - -my $num_if = 4000; - -`/usr/local/bin/vconfig set_name_type VLAN_PLUS_VID_NO_PAD`; - -my $d = 5; -my $c = 5; - -if ($ARGV[0] ne "clean") { - - my $i; - print "Adding VLAN interfaces 1 through $num_if\n"; - - print "Turnning off /sbin/hotplug"; - `echo > /proc/sys/kernel/hotplug`; - - my $p = time(); - for ($i = 1; $i<=$num_if; $i++) { - `/usr/local/bin/vconfig add eth0 $i`; - #`ip address flush dev vlan$i`; - `ip address add 192.168.$c.$c/24 dev vlan$i`; - `ip link set dev vlan$i up`; - - if (($i <= 4000) && (($i % 250) == 0)) { - print "Doing ifconfig -a for $i devices.\n"; - `time -p ifconfig -a > /tmp/vlan_test_ifconfig_a_$i.txt`; - print "Doing ip addr show for $i devices.\n"; - `time -p ip addr show > /tmp/vlan_test_ip_addr_$i.txt`; - } - - $d++; - if ($d > 250) { - $d = 5; - $c++; - } - } - my $n = time(); - my $diff = $n - $p; - - print "Done adding $num_if VLAN interfaces in $diff seconds.\n"; - - sleep 2; -} - -print "Removing VLAN interfaces 1 through $num_if\n"; -$d = 5; -$c = 5; -my $p = time(); -my $i; -for ($i = 1; $i<=$num_if; $i++) { - `/usr/local/bin/vconfig rem vlan$i`; - - $d++; - if ($d > 250) { - $d = 5; - $c++; - } -} -my $n = time(); -my $diff = $n - $p; -print "Done deleting $num_if VLAN interfaces in $diff seconds.\n"; - -sleep 2; - - -if ($ARGV[0] ne "clean") { - - my $tmp = $num_if / 4; - print "\nGoing to add and remove 2 interfaces $tmp times.\n"; - $p = time(); - - - for ($i = 1; $i<=$tmp; $i++) { - `/usr/local/bin/vconfig add eth0 1`; - `ifconfig vlan1 192.168.200.200`; - `ifconfig vlan1 up`; - `ifconfig vlan1 down`; - - `/usr/local/bin/vconfig add eth0 2`; - `ifconfig vlan2 192.168.202.202`; - `ifconfig vlan2 up`; - `ifconfig vlan2 down`; - - `/usr/local/bin/vconfig rem vlan2`; - `/usr/local/bin/vconfig rem vlan1`; - } - $n = time(); - $diff = $n - $p; - print "Done adding/removing 2 VLAN interfaces $tmp times in $diff seconds.\n"; -} - -print "Re-installing /sbin/hotplug"; -`echo /sbin/hotplug > /proc/sys/kernel/hotplug`; - diff --git a/vlan_test2.pl b/vlan_test2.pl deleted file mode 100644 index 4b73a81..0000000 --- a/vlan_test2.pl +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/perl - -# Arguments: -# clean Remove interfaces. - -use strict; - -$| = 1; - -my $num_if = 4000; - -`modprobe 8021q`; -print "Memory after loading 8021q module: "; -print `free`; -print "\n"; - -`/usr/local/bin/vconfig set_name_type VLAN_PLUS_VID_NO_PAD`; - -my $d = 5; -my $c = 5; - -if ($ARGV[0] ne "clean") { - - my $i; - print "Adding VLAN interfaces 1 through $num_if\n"; - - print "Turnning off /sbin/hotplug...\n"; - `echo > /proc/sys/kernel/hotplug`; - - my $p = time(); - for ($i = 1; $i<=$num_if; $i++) { - `/usr/local/bin/vconfig add eth0 $i`; - #`ip address flush dev vlan$i`; - `ip address add 192.168.$c.$c/24 dev vlan$i`; - `ip link set dev vlan$i up`; - - $d++; - if ($d > 250) { - print "."; - $d = 5; - $c++; - } - } - - print "\nMemory after creating $i vlan devices: "; - print `free`; - print "\n"; - - print "Doing ifconfig -a for $i devices.\n"; - `time -p ifconfig -a > /tmp/vlan_test_ifconfig_a_$i.txt`; - print "Doing ip addr show for $i devices.\n"; - `time -p ip addr show > /tmp/vlan_test_ip_addr_$i.txt`; - - my $n = time(); - my $diff = $n - $p; - - print "Done adding $num_if VLAN interfaces in $diff seconds.\n"; - - sleep 2; -} - -print "Removing VLAN interfaces 1 through $num_if\n"; -$d = 5; -$c = 5; -my $p = time(); -my $i; -for ($i = 1; $i<=$num_if; $i++) { - `/usr/local/bin/vconfig rem vlan$i`; -} -my $n = time(); -my $diff = $n - $p; -print "Done deleting $num_if VLAN interfaces in $diff seconds.\n"; - -print "Memory after deleting $i vlan devices: "; -print `free`; -print "\n"; - -sleep 2; - - -if ($ARGV[0] ne "clean") { - - my $tmp = $num_if * 4; - print "\nGoing to add and remove 2 interfaces $tmp times.\n"; - $p = time(); - - - for ($i = 1; $i<=$tmp; $i++) { - `/usr/local/bin/vconfig add eth0 1`; - `ifconfig vlan1 192.168.200.200`; - `ifconfig vlan1 up`; - `ifconfig vlan1 down`; - - `/usr/local/bin/vconfig add eth0 2`; - `ifconfig vlan2 192.168.202.202`; - `ifconfig vlan2 up`; - `ifconfig vlan2 down`; - - `/usr/local/bin/vconfig rem vlan2`; - `/usr/local/bin/vconfig rem vlan1`; - - if (($i % 125) == 0) { - print "."; - } - } - $n = time(); - $diff = $n - $p; - print "\nDone adding/removing 2 VLAN interfaces $tmp times in $diff seconds.\n"; -} - -print "Re-installing /sbin/hotplug...\n"; -`echo /sbin/hotplug > /proc/sys/kernel/hotplug`; - -print "Memory at end of the run: "; -print `free`; -print "\n"; |