From d43c6a7b7909a0a16902c1a522ba9e4431073cda Mon Sep 17 00:00:00 2001 From: Sehong Na Date: Sat, 31 May 2014 13:02:36 +0900 Subject: [PATCH] Initialize Tizen 2.3 --- CHANGELOG | 363 ++ CVS/Entries | 17 + CVS/Repository | 1 + CVS/Root | 1 + LICENSE | 339 ++ MakeInclude | 35 + Makefile | 44 + NOTICE | 3 + README | 12 + candela_2.4.21.patch | 6911 ++++++++++++++++++++++ contrib/CVS/Entries | 5 + contrib/CVS/Repository | 1 + contrib/CVS/Root | 1 + contrib/README | 20 + contrib/network | 288 + contrib/vlan_2.2-full.patch | 2906 +++++++++ contrib/vlan_2.2-module.patch | 495 ++ howto.html | 1219 ++++ libpcap-0.4/CVS/Entries | 5 + libpcap-0.4/CVS/Repository | 1 + libpcap-0.4/CVS/Root | 1 + libpcap-0.4/SUNOS4/CVS/Entries | 1 + libpcap-0.4/SUNOS4/CVS/Repository | 1 + libpcap-0.4/SUNOS4/CVS/Root | 1 + libpcap-0.4/bpf/CVS/Entries | 1 + libpcap-0.4/bpf/CVS/Repository | 1 + libpcap-0.4/bpf/CVS/Root | 1 + libpcap-0.4/bpf/net/CVS/Entries | 1 + libpcap-0.4/bpf/net/CVS/Repository | 1 + libpcap-0.4/bpf/net/CVS/Root | 1 + libpcap-0.4/lbl/CVS/Entries | 1 + libpcap-0.4/lbl/CVS/Repository | 1 + libpcap-0.4/lbl/CVS/Root | 1 + libpcap-0.4/linux-include/CVS/Entries | 1 + libpcap-0.4/linux-include/CVS/Repository | 1 + libpcap-0.4/linux-include/CVS/Root | 1 + libpcap-0.4/linux-include/netinet/CVS/Entries | 1 + libpcap-0.4/linux-include/netinet/CVS/Repository | 1 + libpcap-0.4/linux-include/netinet/CVS/Root | 1 + libpcap-0.4/net/CVS/Entries | 1 + libpcap-0.4/net/CVS/Repository | 1 + libpcap-0.4/net/CVS/Root | 1 + macvlan_config | Bin 0 -> 35763 bytes macvlan_config.c | 635 ++ packaging/vconfig.manifest | 5 + packaging/vconfig.spec | 43 + tcpdump-3.4/CVS/Entries | 2 + tcpdump-3.4/CVS/Repository | 1 + tcpdump-3.4/CVS/Root | 1 + tcpdump-3.4/lbl/CVS/Entries | 1 + tcpdump-3.4/lbl/CVS/Repository | 1 + tcpdump-3.4/lbl/CVS/Root | 1 + tcpdump-3.4/linux-include/CVS/Entries | 3 + tcpdump-3.4/linux-include/CVS/Repository | 1 + tcpdump-3.4/linux-include/CVS/Root | 1 + tcpdump-3.4/linux-include/net/CVS/Entries | 1 + tcpdump-3.4/linux-include/net/CVS/Repository | 1 + tcpdump-3.4/linux-include/net/CVS/Root | 1 + tcpdump-3.4/linux-include/netinet/CVS/Entries | 1 + tcpdump-3.4/linux-include/netinet/CVS/Repository | 1 + tcpdump-3.4/linux-include/netinet/CVS/Root | 1 + tcpdump-3.4/linux-include/sys/CVS/Entries | 1 + tcpdump-3.4/linux-include/sys/CVS/Repository | 1 + tcpdump-3.4/linux-include/sys/CVS/Root | 1 + vconfig | Bin 0 -> 8224 bytes vconfig.8 | 68 + vconfig.c | 270 + vconfig.h | 0 vconfig.o | Bin 0 -> 27944 bytes vconfig.spec | 61 + vlan.html | 436 ++ vlan_2.2.patch | 2927 +++++++++ vlan_test.pl | 223 + vlan_test2.pl | 116 + 74 files changed, 17494 insertions(+) create mode 100644 CHANGELOG create mode 100644 CVS/Entries create mode 100644 CVS/Repository create mode 100644 CVS/Root create mode 100644 LICENSE create mode 100644 MakeInclude create mode 100644 Makefile create mode 100644 NOTICE create mode 100644 README create mode 100644 candela_2.4.21.patch create mode 100644 contrib/CVS/Entries create mode 100644 contrib/CVS/Repository create mode 100644 contrib/CVS/Root create mode 100644 contrib/README create mode 100644 contrib/network create mode 100644 contrib/vlan_2.2-full.patch create mode 100644 contrib/vlan_2.2-module.patch create mode 100644 howto.html create mode 100644 libpcap-0.4/CVS/Entries create mode 100644 libpcap-0.4/CVS/Repository create mode 100644 libpcap-0.4/CVS/Root create mode 100644 libpcap-0.4/SUNOS4/CVS/Entries create mode 100644 libpcap-0.4/SUNOS4/CVS/Repository create mode 100644 libpcap-0.4/SUNOS4/CVS/Root create mode 100644 libpcap-0.4/bpf/CVS/Entries create mode 100644 libpcap-0.4/bpf/CVS/Repository create mode 100644 libpcap-0.4/bpf/CVS/Root create mode 100644 libpcap-0.4/bpf/net/CVS/Entries create mode 100644 libpcap-0.4/bpf/net/CVS/Repository create mode 100644 libpcap-0.4/bpf/net/CVS/Root create mode 100644 libpcap-0.4/lbl/CVS/Entries create mode 100644 libpcap-0.4/lbl/CVS/Repository create mode 100644 libpcap-0.4/lbl/CVS/Root create mode 100644 libpcap-0.4/linux-include/CVS/Entries create mode 100644 libpcap-0.4/linux-include/CVS/Repository create mode 100644 libpcap-0.4/linux-include/CVS/Root create mode 100644 libpcap-0.4/linux-include/netinet/CVS/Entries create mode 100644 libpcap-0.4/linux-include/netinet/CVS/Repository create mode 100644 libpcap-0.4/linux-include/netinet/CVS/Root create mode 100644 libpcap-0.4/net/CVS/Entries create mode 100644 libpcap-0.4/net/CVS/Repository create mode 100644 libpcap-0.4/net/CVS/Root create mode 100755 macvlan_config create mode 100644 macvlan_config.c create mode 100644 packaging/vconfig.manifest create mode 100644 packaging/vconfig.spec create mode 100644 tcpdump-3.4/CVS/Entries create mode 100644 tcpdump-3.4/CVS/Repository create mode 100644 tcpdump-3.4/CVS/Root create mode 100644 tcpdump-3.4/lbl/CVS/Entries create mode 100644 tcpdump-3.4/lbl/CVS/Repository create mode 100644 tcpdump-3.4/lbl/CVS/Root create mode 100644 tcpdump-3.4/linux-include/CVS/Entries create mode 100644 tcpdump-3.4/linux-include/CVS/Repository create mode 100644 tcpdump-3.4/linux-include/CVS/Root create mode 100644 tcpdump-3.4/linux-include/net/CVS/Entries create mode 100644 tcpdump-3.4/linux-include/net/CVS/Repository create mode 100644 tcpdump-3.4/linux-include/net/CVS/Root create mode 100644 tcpdump-3.4/linux-include/netinet/CVS/Entries create mode 100644 tcpdump-3.4/linux-include/netinet/CVS/Repository create mode 100644 tcpdump-3.4/linux-include/netinet/CVS/Root create mode 100644 tcpdump-3.4/linux-include/sys/CVS/Entries create mode 100644 tcpdump-3.4/linux-include/sys/CVS/Repository create mode 100644 tcpdump-3.4/linux-include/sys/CVS/Root create mode 100755 vconfig create mode 100644 vconfig.8 create mode 100644 vconfig.c create mode 100644 vconfig.h create mode 100644 vconfig.o create mode 100644 vconfig.spec create mode 100644 vlan.html create mode 100644 vlan_2.2.patch create mode 100644 vlan_test.pl create mode 100644 vlan_test2.pl diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..85c60bf --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,363 @@ +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:
+ + 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/ 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 new file mode 100644 index 0000000..d86968c --- /dev/null +++ b/CVS/Entries @@ -0,0 +1,17 @@ +/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 new file mode 100644 index 0000000..d56118f --- /dev/null +++ b/CVS/Repository @@ -0,0 +1 @@ +vlan diff --git a/CVS/Root b/CVS/Root new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/CVS/Root @@ -0,0 +1 @@ +:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/MakeInclude b/MakeInclude new file mode 100644 index 0000000..f518572 --- /dev/null +++ b/MakeInclude @@ -0,0 +1,35 @@ +# -*-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 new file mode 100644 index 0000000..23bb374 --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +# 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 *~ + + + + + diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..33394ef --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, This software is licensed under GNU GENERAL PUBLIC LICENSE Version 2. +Please, see the LICENSE file for GNU GENERAL PUBLIC LICENSE terms and conditions. diff --git a/README b/README new file mode 100644 index 0000000..0f9ce3a --- /dev/null +++ b/README @@ -0,0 +1,12 @@ +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 new file mode 100644 index 0000000..8b2f320 --- /dev/null +++ b/candela_2.4.21.patch @@ -0,0 +1,6911 @@ +--- 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 + #include + #include ++#include + #include + #include + #include +@@ -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 + * Uppsala University, Sweden ++ * 2002 Ben Greear + * + * 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 + * + * 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 + #include + #include ++#include + #include + +-#define cycles() ((u32)get_cycles()) ++#include /* for lock kernel */ ++#include /* 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 ++ * 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; ilatency_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; ilatency_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; ilatency_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; iread_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; iread_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"); + 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 + #include + #include ++#include + #include + #include + #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 ++#include ++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 ++# ++# 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_PROC_FS ++#include ++#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= '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; idev->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; iport->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; ihash_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; iport->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; ihash_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 ++ ++*/ ++ ++#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 + #include + #include ++#include + + #ifdef CONFIG_NET_DIVERT + #include +@@ -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 +- * 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 +- * - 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 ++ * - 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 +- * 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 ; ++ * Fix for packet capture - Nick Eggleston ; + * Add HW acceleration hooks - David S. Miller ; + * Correct all the locking - David S. Miller ; + * Use hash table for VLAN groups - David S. Miller +@@ -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 new file mode 100644 index 0000000..2e0a86d --- /dev/null +++ b/contrib/CVS/Entries @@ -0,0 +1,5 @@ +/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 new file mode 100644 index 0000000..54d399b --- /dev/null +++ b/contrib/CVS/Repository @@ -0,0 +1 @@ +vlan/contrib diff --git a/contrib/CVS/Root b/contrib/CVS/Root new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/contrib/CVS/Root @@ -0,0 +1 @@ +:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/contrib/README b/contrib/README new file mode 100644 index 0000000..5af786d --- /dev/null +++ b/contrib/README @@ -0,0 +1,20 @@ +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 new file mode 100644 index 0000000..48e4240 --- /dev/null +++ b/contrib/network @@ -0,0 +1,288 @@ +#! /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 new file mode 100644 index 0000000..4ae3012 --- /dev/null +++ b/contrib/vlan_2.2-full.patch @@ -0,0 +1,2906 @@ +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 ++ * ++ * 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 /* 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 ++#include ++ ++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 , ++ * ++ * 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 /* for copy_from_user */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#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 ++ ++/* 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 , ++ * ++ * 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 /* for copy_from_user */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "vlan.h" ++#include "vlanproc.h" ++#include ++#include ++#include ++ ++ ++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, coppied from wanproc.c ++ * by: Gene Kozin ++ * ++ * 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 ++#include /* offsetof(), etc. */ ++#include /* return codes */ ++#include ++#include /* kmalloc(), kfree() */ ++#include /* verify_area(), etc. */ ++#include /* inline mem*, str* functions */ ++#include /* __initfunc et al. */ ++#include /* kernel <-> user copy */ ++#include /* htons(), etc. */ ++#include /* copy_to_user */ ++#include ++#include ++#include ++#include ++#include ++#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 ++ * entry for each device ++ */ ++ ++/* ++ * Generic /proc/net/vlan/ 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/ 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 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 + #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; iname, 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 + 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 +@@ -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 new file mode 100644 index 0000000..f4c4bd0 --- /dev/null +++ b/contrib/vlan_2.2-module.patch @@ -0,0 +1,495 @@ +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 + #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 + #include +@@ -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 /* for copy_from_user */ +-#include + #include + #include + #include +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, coppied from wanproc.c +-* by: Gene Kozin +-* +-* 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, coppied from wanproc.c ++ * by: Gene Kozin ++ * ++ * 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 + #include /* 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 + #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 + EXPORT_SYMBOL(ltalk_setup); + #endif +- + + /* Packet scheduler modules want these. */ + EXPORT_SYMBOL(qdisc_destroy); diff --git a/howto.html b/howto.html new file mode 100644 index 0000000..a23c180 --- /dev/null +++ b/howto.html @@ -0,0 +1,1219 @@ + + + + LINUX VLAN + Cisco HOWTO + + + +

LINUX VLAN + Cisco HOWTO

+

+

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
+
+
+  The Linux VLAN HOWTO
+ 
+  VLAN Mailing list: vlan@candelatech.com
+  Kristjan Kotkas kristjan@data.ee
+  Ben Greear greearb@candelatech.com
+
+
+

+ +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 + +

+

Contents

+
    +
  1. Who, why and where
  2. +
  3. Actual info on how to make it work.
  4. +
  5. Specific work-arounds/patches for certain configurations. + +
  6. Scripts and Recipes.
  7. +
+

+ +

    +
  1. META +
      +
    1. + This is the first HOWTO for the "802.1Q VLAN implementation for Linux"

      + + Homepage: http://scry.wanfear.com/~greear/vlan.html + Mailing List: VLAN@Scry.WANfear.com +

    2. +

      +

    3. Copyright

      + + 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. +

    4. +

      +

    5. Disclaimer

      + + 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 +

    6. +

      +

    7. Credits

      + + Thanks to Ben Greear http://www.candelatech.com/~greear + for the VLAN project and also to all the people who have contributed to the project. +

    8. +

      +

    9. General

      + + What is VLAN is not described in this document. Info on the VLAN protocol + can be found at + http://standards.ieee.org/getieee802/download/802.1Q-1998.pdf. +

    10. +
    +
  2. +

    +

  3. Software/Hardware (Cisco-specific setup, with some general info as well.)

    +

      +
    1. VLAN installation & Configuration on the Linux Side.

      +

      +
      +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
      +
      + +Ben's Note:   Regarding the next section, you can run plain ethernet +and VLAN over the same NIC, but you may not want to..
      +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.
      +
      +
    2. +

      +

    3. Specific Extreme Networks Configuration

      +  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.
      +
      +
    4. +

      +

    5. Cisco-specific configuration

      +

      +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)
      +
      + NOTE: Ethereal also supports VLANs, +and is much more beautiful than tcpdump, if you have GUI capabilities. +
      +
      +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.
      +
      +
    6. +
    +
  4. +

    +

  5. Specific patches and work-arounds for various configurations.

    +

      + + +
    1. My Tulip-based card has MTU problems.

      +

      +
      +   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 */
      +
      +
      +
    2. + +
      +
    3. My eepro100 has MTU problems.

      + +NOTE: Intel's e100 driver works out-of-the-box. --Ben +

      + + Here is a patch sent in by gleb@nbase.co.il
      + +

      +     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. */
      +
      +
    4. +

      + +

    5. My SysKonnect sk98lin doesn't work (submitted by: Patrick Schaaf <bof@bof.de>)

      + +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. +

      +

      +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"));
      +
      +
      +
    6. +

      + +

    7. My 3C59X has MTU problems.

      + +Various contributors, most recently: Richard Fuchs + +

      +
      +--- 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
      +
      +
      +
    8. +

      + + +

    9. My natsemi has MTU problems.

      +By Peter Stuge: +

      +
      +--- 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:
      +
      +
    10. +

      + + +

    11. My 3C905B has MTU problems.

      +As found +here +at one point in time.
      +Furnished by: Luis Miguel Cruz Miranda luismi@b2bi.es
      +(I don't know the original author --Ben). + +

      +--- 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
      +
      +
    12. +

      + + +

    13. How to make my PCMCIA ethernet card work with VLANs?

      +Per Peter Stuge:

      + +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. +

      +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.) +

      +Ben Adds:

      +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... + +

    14. + +
    +
  6. +

    +

  7. Scripts and Recipes.

    +

      +
    1. Mandrake (RedHat-style) startup script for VLANs.

      + Contributed by: "MaxiM Basunov" <maxim@idknet.com> +

      +#!/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
      +
      +
    2. + +
    +

    +


    +
    +Terv, 
    +
    +-----------------------------
    +Kristjan Kotkas 
    +KPNQwest Estonia
    +kristjan.kotkas@kpnqwest.ee
    +t + 372 62 66299 m + 372 51 60697 f + 372 62 66292
    +
    +
    + + +
    +
    Ben Greear
    + + +Last modified: Fri Jul 4 09:53:40 PDT 2003 + + + diff --git a/libpcap-0.4/CVS/Entries b/libpcap-0.4/CVS/Entries new file mode 100644 index 0000000..54e26d9 --- /dev/null +++ b/libpcap-0.4/CVS/Entries @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000..0e0ddbb --- /dev/null +++ b/libpcap-0.4/CVS/Repository @@ -0,0 +1 @@ +vlan/libpcap-0.4 diff --git a/libpcap-0.4/CVS/Root b/libpcap-0.4/CVS/Root new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/libpcap-0.4/CVS/Root @@ -0,0 +1 @@ +:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/libpcap-0.4/SUNOS4/CVS/Entries b/libpcap-0.4/SUNOS4/CVS/Entries new file mode 100644 index 0000000..1784810 --- /dev/null +++ b/libpcap-0.4/SUNOS4/CVS/Entries @@ -0,0 +1 @@ +D diff --git a/libpcap-0.4/SUNOS4/CVS/Repository b/libpcap-0.4/SUNOS4/CVS/Repository new file mode 100644 index 0000000..3e7444c --- /dev/null +++ b/libpcap-0.4/SUNOS4/CVS/Repository @@ -0,0 +1 @@ +vlan/libpcap-0.4/SUNOS4 diff --git a/libpcap-0.4/SUNOS4/CVS/Root b/libpcap-0.4/SUNOS4/CVS/Root new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/libpcap-0.4/SUNOS4/CVS/Root @@ -0,0 +1 @@ +:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/libpcap-0.4/bpf/CVS/Entries b/libpcap-0.4/bpf/CVS/Entries new file mode 100644 index 0000000..27ad449 --- /dev/null +++ b/libpcap-0.4/bpf/CVS/Entries @@ -0,0 +1 @@ +D/net//// diff --git a/libpcap-0.4/bpf/CVS/Repository b/libpcap-0.4/bpf/CVS/Repository new file mode 100644 index 0000000..e2ce17c --- /dev/null +++ b/libpcap-0.4/bpf/CVS/Repository @@ -0,0 +1 @@ +vlan/libpcap-0.4/bpf diff --git a/libpcap-0.4/bpf/CVS/Root b/libpcap-0.4/bpf/CVS/Root new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/libpcap-0.4/bpf/CVS/Root @@ -0,0 +1 @@ +: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 new file mode 100644 index 0000000..1784810 --- /dev/null +++ b/libpcap-0.4/bpf/net/CVS/Entries @@ -0,0 +1 @@ +D diff --git a/libpcap-0.4/bpf/net/CVS/Repository b/libpcap-0.4/bpf/net/CVS/Repository new file mode 100644 index 0000000..c8ca0dc --- /dev/null +++ b/libpcap-0.4/bpf/net/CVS/Repository @@ -0,0 +1 @@ +vlan/libpcap-0.4/bpf/net diff --git a/libpcap-0.4/bpf/net/CVS/Root b/libpcap-0.4/bpf/net/CVS/Root new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/libpcap-0.4/bpf/net/CVS/Root @@ -0,0 +1 @@ +:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/libpcap-0.4/lbl/CVS/Entries b/libpcap-0.4/lbl/CVS/Entries new file mode 100644 index 0000000..1784810 --- /dev/null +++ b/libpcap-0.4/lbl/CVS/Entries @@ -0,0 +1 @@ +D diff --git a/libpcap-0.4/lbl/CVS/Repository b/libpcap-0.4/lbl/CVS/Repository new file mode 100644 index 0000000..b351c7f --- /dev/null +++ b/libpcap-0.4/lbl/CVS/Repository @@ -0,0 +1 @@ +vlan/libpcap-0.4/lbl diff --git a/libpcap-0.4/lbl/CVS/Root b/libpcap-0.4/lbl/CVS/Root new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/libpcap-0.4/lbl/CVS/Root @@ -0,0 +1 @@ +: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 new file mode 100644 index 0000000..7e34cc5 --- /dev/null +++ b/libpcap-0.4/linux-include/CVS/Entries @@ -0,0 +1 @@ +D/netinet//// diff --git a/libpcap-0.4/linux-include/CVS/Repository b/libpcap-0.4/linux-include/CVS/Repository new file mode 100644 index 0000000..6f3b3e1 --- /dev/null +++ b/libpcap-0.4/linux-include/CVS/Repository @@ -0,0 +1 @@ +vlan/libpcap-0.4/linux-include diff --git a/libpcap-0.4/linux-include/CVS/Root b/libpcap-0.4/linux-include/CVS/Root new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/libpcap-0.4/linux-include/CVS/Root @@ -0,0 +1 @@ +: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 new file mode 100644 index 0000000..1784810 --- /dev/null +++ b/libpcap-0.4/linux-include/netinet/CVS/Entries @@ -0,0 +1 @@ +D diff --git a/libpcap-0.4/linux-include/netinet/CVS/Repository b/libpcap-0.4/linux-include/netinet/CVS/Repository new file mode 100644 index 0000000..2604b84 --- /dev/null +++ b/libpcap-0.4/linux-include/netinet/CVS/Repository @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/libpcap-0.4/linux-include/netinet/CVS/Root @@ -0,0 +1 @@ +:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/libpcap-0.4/net/CVS/Entries b/libpcap-0.4/net/CVS/Entries new file mode 100644 index 0000000..1784810 --- /dev/null +++ b/libpcap-0.4/net/CVS/Entries @@ -0,0 +1 @@ +D diff --git a/libpcap-0.4/net/CVS/Repository b/libpcap-0.4/net/CVS/Repository new file mode 100644 index 0000000..bff9ac2 --- /dev/null +++ b/libpcap-0.4/net/CVS/Repository @@ -0,0 +1 @@ +vlan/libpcap-0.4/net diff --git a/libpcap-0.4/net/CVS/Root b/libpcap-0.4/net/CVS/Root new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/libpcap-0.4/net/CVS/Root @@ -0,0 +1 @@ +:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/macvlan_config b/macvlan_config new file mode 100755 index 0000000000000000000000000000000000000000..372ede0fc9b65f423667ffe62069f08064d2ef06 GIT binary patch literal 35763 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 +#include +#include +#include +#include +#include +#include +#include + + +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 "}, + {"enable", "enables mac based vlans over an ethernet device", do_enable, + "enable \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 "}, + {"add", "creates new mac based vlan", do_add, + "add \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 \n" + " - deletes a mac base vlan called \"ifname\"" + }, + {"bind", "binds macaddr to vlan", do_bind, + "bind \n" + " - binds macaddr to vlan called \"ifname\"" + }, + {"unbind", "unbinds macaddr from vlan", do_unbind, + "unbind \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 \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 \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 \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 \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 \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 \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 \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 \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/packaging/vconfig.manifest b/packaging/vconfig.manifest new file mode 100644 index 0000000..75b0fa5 --- /dev/null +++ b/packaging/vconfig.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/vconfig.spec b/packaging/vconfig.spec new file mode 100644 index 0000000..4d0a8cb --- /dev/null +++ b/packaging/vconfig.spec @@ -0,0 +1,43 @@ +Summary: Linux 802.1q VLAN configuration utility +Name: vconfig +Version: 1.9 +Release: 14 +License: GPLv +Group: System Environment/Base +Source: http://www.candelatech.com/~greear/vlan/vlan.%{version}.tar.gz +Source1001: %{name}.manifest +URL: http://www.candelatech.com/~greear/vlan.html +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +%define _sbin /sbin + +%description +The vconfig program configures and adjusts 802.1q VLAN parameters. + +%prep +%setup -q -n vlan.%{version} + +%build +cp %{SOURCE1001} . +make clean +rm -f vconfig +make CCFLAGS="%{optflags}" STRIP=/bin/true vconfig + +%install +rm -rf ${RPM_BUILD_ROOT} +%{__install} -D -m755 vconfig ${RPM_BUILD_ROOT}%{_sbin}/vconfig +%{__install} -D -m644 vconfig.8 ${RPM_BUILD_ROOT}%{_mandir}/man8/vconfig.8 +rm -rf contrib/CVS +#license +mkdir -p %{buildroot}/usr/share/license +cp LICENSE %{buildroot}/usr/share/license/%{name} + +%clean +rm -rf ${RPM_BUILD_ROOT} + +%files +%defattr(-, root, root, 0755) +%manifest %{name}.manifest +%doc CHANGELOG contrib README vlan.html vlan_test.pl +%{_sbin}/vconfig +%{_mandir}/man8/vconfig.8* +/usr/share/license/%{name} diff --git a/tcpdump-3.4/CVS/Entries b/tcpdump-3.4/CVS/Entries new file mode 100644 index 0000000..baec772 --- /dev/null +++ b/tcpdump-3.4/CVS/Entries @@ -0,0 +1,2 @@ +D/lbl//// +D/linux-include//// diff --git a/tcpdump-3.4/CVS/Repository b/tcpdump-3.4/CVS/Repository new file mode 100644 index 0000000..7759328 --- /dev/null +++ b/tcpdump-3.4/CVS/Repository @@ -0,0 +1 @@ +vlan/tcpdump-3.4 diff --git a/tcpdump-3.4/CVS/Root b/tcpdump-3.4/CVS/Root new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/tcpdump-3.4/CVS/Root @@ -0,0 +1 @@ +:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/tcpdump-3.4/lbl/CVS/Entries b/tcpdump-3.4/lbl/CVS/Entries new file mode 100644 index 0000000..1784810 --- /dev/null +++ b/tcpdump-3.4/lbl/CVS/Entries @@ -0,0 +1 @@ +D diff --git a/tcpdump-3.4/lbl/CVS/Repository b/tcpdump-3.4/lbl/CVS/Repository new file mode 100644 index 0000000..f9d5b2f --- /dev/null +++ b/tcpdump-3.4/lbl/CVS/Repository @@ -0,0 +1 @@ +vlan/tcpdump-3.4/lbl diff --git a/tcpdump-3.4/lbl/CVS/Root b/tcpdump-3.4/lbl/CVS/Root new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/tcpdump-3.4/lbl/CVS/Root @@ -0,0 +1 @@ +: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 new file mode 100644 index 0000000..d74c534 --- /dev/null +++ b/tcpdump-3.4/linux-include/CVS/Entries @@ -0,0 +1,3 @@ +D/net//// +D/netinet//// +D/sys//// diff --git a/tcpdump-3.4/linux-include/CVS/Repository b/tcpdump-3.4/linux-include/CVS/Repository new file mode 100644 index 0000000..63abf70 --- /dev/null +++ b/tcpdump-3.4/linux-include/CVS/Repository @@ -0,0 +1 @@ +vlan/tcpdump-3.4/linux-include diff --git a/tcpdump-3.4/linux-include/CVS/Root b/tcpdump-3.4/linux-include/CVS/Root new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/tcpdump-3.4/linux-include/CVS/Root @@ -0,0 +1 @@ +: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 new file mode 100644 index 0000000..1784810 --- /dev/null +++ b/tcpdump-3.4/linux-include/net/CVS/Entries @@ -0,0 +1 @@ +D diff --git a/tcpdump-3.4/linux-include/net/CVS/Repository b/tcpdump-3.4/linux-include/net/CVS/Repository new file mode 100644 index 0000000..72afc29 --- /dev/null +++ b/tcpdump-3.4/linux-include/net/CVS/Repository @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/tcpdump-3.4/linux-include/net/CVS/Root @@ -0,0 +1 @@ +: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 new file mode 100644 index 0000000..1784810 --- /dev/null +++ b/tcpdump-3.4/linux-include/netinet/CVS/Entries @@ -0,0 +1 @@ +D diff --git a/tcpdump-3.4/linux-include/netinet/CVS/Repository b/tcpdump-3.4/linux-include/netinet/CVS/Repository new file mode 100644 index 0000000..3ae1a1b --- /dev/null +++ b/tcpdump-3.4/linux-include/netinet/CVS/Repository @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/tcpdump-3.4/linux-include/netinet/CVS/Root @@ -0,0 +1 @@ +: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 new file mode 100644 index 0000000..1784810 --- /dev/null +++ b/tcpdump-3.4/linux-include/sys/CVS/Entries @@ -0,0 +1 @@ +D diff --git a/tcpdump-3.4/linux-include/sys/CVS/Repository b/tcpdump-3.4/linux-include/sys/CVS/Repository new file mode 100644 index 0000000..6a6e5d2 --- /dev/null +++ b/tcpdump-3.4/linux-include/sys/CVS/Repository @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000..469c859 --- /dev/null +++ b/tcpdump-3.4/linux-include/sys/CVS/Root @@ -0,0 +1 @@ +:pserver:greear@ns1.wanfear.com:/home/cvs/vlan diff --git a/vconfig b/vconfig new file mode 100755 index 0000000000000000000000000000000000000000..8cfcbcd3f344333c6b5a759d530949ae7c8c162d GIT binary patch literal 8224 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 literal 0 HcmV?d00001 diff --git a/vconfig.8 b/vconfig.8 new file mode 100644 index 0000000..e9685c2 --- /dev/null +++ b/vconfig.8 @@ -0,0 +1,68 @@ +.TH VCONFIG 8 +.\" NAME should be all caps, SECTION should be 1-8, maybe w/ subsection +.\" other parms are allowed: see man(7), man(1) +.SH NAME +vconfig \- VLAN (802.1q) configuration program. +.SH SYNOPSIS +.B vconfig +.I [lots of long options] +.SH "DESCRIPTION" +The +.B vconfig +program allows you to create and remove vlan\-devices on a vlan enabled +kernel. Vlan\-devices are virtual ethernet devices which represents the +virtual lans on the physical lan. +.SH OPTIONS +.TP +.B add [interface\-name] [vlan\-id] +Creates a vlan-device on [interface\-name]. The resulting vlan\-device +will be called according to the nameing convention set. +.TP +.B rem [vlan\-device] +Removes the named vlan\-device. +.TP +.B set_flag [vlan\-device] 0 | 1 +When 1, ethernet header reorders are turned on. Dumping the device +will appear as a common ethernet device without vlans. When 0(default) +however, ethernet headers are not reordered, which results in vlan tagged +packets when dumping the device. Usually the default gives no problems, +but some packet filtering programs might have problems with it. +.TP + +.B set_egress_map [vlan\-device] [skb\-priority] [vlan\-qos] +This flags that outbound packets with a particular skb\-priority should +be tagged with the particular vlan priority vlan\-qos. The default vlan +priority is 0. +.TP + +.B set_ingress_map [vlan\-device] [skb\-priority] [vlan\-qos] +This flags that inbound packets with the particular vlan priority +vlan\-qos should be queued with a particular skb\-priority. The default +skb\-priority is 0. +.TP + +.B set_name_type VLAN_PLUS_VID | VLAN_PLUS_VID_NO_PAD | DEV_PLUS_VID | DEV_PLUS_VID_NO_PAD +Sets the way vlan\-device names are created. Use vconfig without arguments +to see the different formats. +.TP + +.SH NOTES +VLAN will use Broadcom's NICE interface when the network device supports +it. This is necessary, since usually the hardware of these devices already +removes the vlan tag from the ethernet packet. The set_flag option on +vlan\-devices created on such a physical network device will be ignored. +Dumping the network\-device will show only untagged(non-vlan) traffic, +and dumping the vlan\-devices will only show traffic intended for that +vlan, without the tags. +.br +.SH FILES +.I /proc/net/vlan/config +.br +.I /proc/net/vlan/[vlan\-device] + +.SH SEE ALSO +ip(8), ifconfig(8) +.SH AUTHORS +This manual page was written by Ard van Breemen +.br +The vlan patch is written by Ben Greear diff --git a/vconfig.c b/vconfig.c new file mode 100644 index 0000000..5057cfd --- /dev/null +++ b/vconfig.c @@ -0,0 +1,270 @@ +// +//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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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" +"* 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" +"* 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) { + 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 new file mode 100644 index 0000000..e69de29 diff --git a/vconfig.o b/vconfig.o new file mode 100644 index 0000000000000000000000000000000000000000..8e8da0edeed74c3db9cd15c71f65982bdb5d04be GIT binary patch literal 27944 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 OtZCWK@MDH%JNtk3lzjUD literal 0 HcmV?d00001 diff --git a/vconfig.spec b/vconfig.spec new file mode 100644 index 0000000..c05c7b5 --- /dev/null +++ b/vconfig.spec @@ -0,0 +1,61 @@ +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 +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 +- update to 1.6 +- add ifup scripts + +* Tue Dec 11 2001 Dale Bewley +- initial specfile diff --git a/vlan.html b/vlan.html new file mode 100644 index 0000000..0588b61 --- /dev/null +++ b/vlan.html @@ -0,0 +1,436 @@ + + + + 802.1Q VLAN implementation for Linux + + + +

    802.1Q VLAN implementation for Linux

    + +
    +Updated Sept 30, 2003
    +Release: 1.8
    +
    +

    + +MTU problems exist for many ethernet drivers. Other than that, things seem fairly stable! +

    + +

    +PLUG:   Check out my company that makes traffic generation and WAN simulation + test equipment based on the Linux operating system:
    +
    Candela Technologies +
    +Let us help you test your DSL, Cable Access, Satellite and other network systems!
    +
    + +
    +TIP jar on my home page.

    + + +Join the vlan mailing list, + After that, to post, send mail to +vlan@ns1.wanfear.com. +

    +Submit a bug/issue/enhancement with the: VLAN Bugzilla

  8. +

    + +I hear that the 2.2/2.4 kernel patches have worked +with these (and other, I'm sure) systems:

    +

      +
    • Cisco: {Catalyst: 6509}, + 3Com: {Corebuilder, Netbuilder II, SuperStack II switch 630}, + Alpine: {3804(SMMi,F32Ti)} + Extreme Ntwks {Summit 48, 48i, 5i} + Foundry: {ServerIronXL, FastIron}
    • +
    • Alteon ACENic Gigabit, 3Com 3c509, realtek RTL8029(AS), RTL8139, DEC DC21140 (tulip), + DFE-570TX quad-21143, Intel PRO/1000 with Intel's driver +
    • +
    +

    + +Performance: +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! + +

    VLAN related Resources.
    + +

    + +

    Features
    +
      +
    • Implements 802.1Q VLAN spec.
    • +
    • Implements support for a non-standard (as far as I know) + MAC-based VLAN functionality.
    • +
    • Can support up to 4094 VLANs per ethernet interface.
    • +
    • 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.
    • +
    • Supports MULTICAST
    • +
    • Can change MAC address of VLAN.
    • +
    • Multiple naming conventions supported, and adjustable at runtime.
    • +
    • Optional header-reordering, to make the VLAN interface look JUST LIKE + 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. +
    • +
    +

    + + +


    +Download vconfig binaries (source is more flexible, but this will work for most people). + +

    + +


    +
    Change Log
    +
      +

      + +

    • Release 1.8 (gz)   For Kernel: 2.4.21+   Sept 30, 2003:
      +

      +

        +
      • 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. +
      • +
      +
    • + +

      +

    • Release 1.7m (gz)   For Kernel: 2.4.14+   Feb 27, 2003:
      +

      +

        +
      • 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. +
      • +
      +
    • +

      + +

    • Release 1.7 (gz)   For Kernel: 2.4.14+   Feb 27, 2003:
      +

      +

        +
      • Clarified the license for vconfig (GPL). Other small tweaks.
      • +
      +
    • + +

      +

    • Release 1.6 (gz)   For Kernel: 2.4.14+   March 24, 2002:
      +

      +

        +
      • Removed 2.4 kernel patch: It's in the standard kernel now.
      • +
      • Updated vconfig to fix some compile issues, and enable cross-compilation + to the StrongARM platform (changes should help other cross-compile + attempts too.)
      • +
      +
    • +

      + +

    • Release 1.5 (gz)   For Kernel: 2.4.12-pre5   October 22, 2001:
      +

      +

        +
      • 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.
      • +
      +
    • +

      + +

    • Release 1.4 (gz)   For Kernel: 2.4.8   August 16, 2001:
      +

      +

        +
      • 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...
      • +
      +
    • + +

      +

    • Release 1.0.3 (gz)   For Kernel: 2.4.7   August 5, 2001:
      +

      +

        +
      • 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.
      • +
      • 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.
      • +
      • There were *NO* changes to the 2.2 series patch, and I don't expect to ever make + any more changes there...
      • +
      + +
    • +

      + +

    • Release 1.0.1 (gz)   For Kernel: 2.2.18/19, 2.4.3-pre3   April 16, 2001:
      +

      +

        +
      • 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.
      • +
      + +
    • + +

      +

    • Release 1.0.0 (gz)   For Kernel: 2.2.18, 2.4.0   Jan 14, 2001:
      +

      +

        +
      • 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.c + (search for #define BEN_FAST_DEV_LOOKUP).
      • +
      • vconfig should warn when creating VLAN 1, because that VLAN is not compatible with many + switches.
      • +
      + +
    • + +

      +

    • Release 0.0.15 (gz)   For Kernel: 2.2.18, 2.4.prerelease   Dec 31, 2000:
      +

      +

        +
      • 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.
      • +
      + +
    • + +

      +

    • Release 0.0.14 (gz)   For Kernel: 2.2.17, 2.4.pre9   Oct 26, 2000:
      +

      + This code seems pretty stable. +

        +
      • 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.
      • +
      + +
    • + +

      +

    • Release 0.0.13 (gz)   For Kernel: 2.2.17, 2.4.pre9   Oct 11, 2000:
      +
      KNOWN TO BE BUSTED, here for posterity's sake.
      +

      +

        +
      • 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.
      • +
      + +
    • +

      + +

    • Release 0.0.12 (gz)   For Kernel: 2.2.16, 2.4.pre7   August 27, 2000:
      + 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. +

    • +

      + +

    • Release 0.0.11 (gz)   For Kernel: 2.2.13/14, 2.3.99   April 23, 2000:
      + 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:
      +
      +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! +

    • +

      + +


    +

    + +

    +VLAN Setup and Configuration

    + +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: tar -xvzf vlan.1.6.tar.gz +Alternatively, you can get it from the CVS Repository using something like this:
    +
      +
    1. Install and configure + cvs + on your machine.
    2. +
    3. Specify the vlan repository:
      + export CVSROOT=:pserver:anonymous@ns1.wanfear.com:/home/cvs/vlan +
    4. +
    5. Log in to the repository:
      + cvs login     (PASSWORD: anonymous) +
    6. +
    7. Check out the source:
      + mkdir vlan; cd vlan; cvs -z3 checkout vlan +
    8. +
    +

    + +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 www.kernel.org. +Unzip and un-tar this in your home directory as well, which should +create a linux directory in your $HOME directory. Example: +tar -xvzf linux-2.2.14.tar.gz

    + +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:

    + +cd $HOME/linux
    +patch -p 1 < $HOME/vlan/[vlan.patch]
    +
    +

    + +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: +cd $HOME; ln -s /home/greear/kernel/2.4/linux.dev linux +

    + +Build the vconfig program in the $HOME/vlan directory:
    +cd $HOME/vlan
    +make
    +
    +

    + +Now, time to compile your new kernel! Use the make xconfig +command in your $HOME/linux directory to select your kernel options. The +option related to 802.1Q VLANs is found under the Networking options. +If the option is not highlighted, make sure you select "Experimental Drivers" +in one of the first xconfig menus. +

    + +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 /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, other than a line spit out during the boot process. +There should be a config programs in your $HOME/vlan +directory: vconfig. vconfig 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: +

    + +vconfig add eth0 5 +

    + +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: +

    +vconfig rem eth0.5 +

    + +You will also need to give it an ip, eg: ifconfig -i eth0.5 192.168.2.1
    +and configure it UP: ifconfig -i eth0.5 up +

    + +NOTE: You can get lots of VLAN related configuration information from +the /proc/net/vlan/* files by using 'cat' or 'more' to look at them. +

    + +Please get in contact with me if you have suggestions, patches, or other +comments. +

    + +


    +
    greearb@candelatech.com   + Ben Greear's Home Page
    + + +Last modified: Tue Sep 30 14:16:14 PDT 2003 + + + diff --git a/vlan_2.2.patch b/vlan_2.2.patch new file mode 100644 index 0000000..e038825 --- /dev/null +++ b/vlan_2.2.patch @@ -0,0 +1,2927 @@ +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 ++ * ++ * 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 /* 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 + #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 ++#include ++ ++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 , ++ * ++ * 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 /* for copy_from_user */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#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 ++ ++/* 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 , ++ * ++ * 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 /* for copy_from_user */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "vlan.h" ++#include "vlanproc.h" ++#include ++#include ++#include ++ ++ ++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, coppied from wanproc.c ++* by: Gene Kozin ++* ++* 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 ++#include /* offsetof(), etc. */ ++#include /* return codes */ ++#include ++#include /* kmalloc(), kfree() */ ++#include /* verify_area(), etc. */ ++#include /* inline mem*, str* functions */ ++#include /* __initfunc et al. */ ++#include /* kernel <-> user copy */ ++#include /* htons(), etc. */ ++#include /* copy_to_user */ ++#include ++#include ++#include ++#include ++#include ++#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 ++ * entry for each device ++ */ ++ ++/* ++ * Generic /proc/net/vlan/ 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/ 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 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 + #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; iname, 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 +@@ -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 new file mode 100644 index 0000000..f723089 --- /dev/null +++ b/vlan_test.pl @@ -0,0 +1,223 @@ +#!/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 () { + 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 () { + 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 new file mode 100644 index 0000000..4b73a81 --- /dev/null +++ b/vlan_test2.pl @@ -0,0 +1,116 @@ +#!/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"; -- 2.7.4