diff options
Diffstat (limited to 'net/802')
-rw-r--r-- | net/802/Makefile | 15 | ||||
-rw-r--r-- | net/802/fc.c | 130 | ||||
-rw-r--r-- | net/802/fddi.c | 210 | ||||
-rw-r--r-- | net/802/hippi.c | 234 | ||||
-rw-r--r-- | net/802/p8022.c | 65 | ||||
-rw-r--r-- | net/802/p8023.c | 61 | ||||
-rw-r--r-- | net/802/psnap.c | 159 | ||||
-rw-r--r-- | net/802/sysctl_net_802.c | 33 | ||||
-rw-r--r-- | net/802/tr.c | 645 |
9 files changed, 1552 insertions, 0 deletions
diff --git a/net/802/Makefile b/net/802/Makefile new file mode 100644 index 000000000000..01861929591a --- /dev/null +++ b/net/802/Makefile | |||
@@ -0,0 +1,15 @@ | |||
1 | # | ||
2 | # Makefile for the Linux 802.x protocol layers. | ||
3 | # | ||
4 | |||
5 | obj-y := p8023.o | ||
6 | |||
7 | # Check the p8022 selections against net/core/Makefile. | ||
8 | obj-$(CONFIG_SYSCTL) += sysctl_net_802.o | ||
9 | obj-$(CONFIG_LLC) += p8022.o psnap.o | ||
10 | obj-$(CONFIG_TR) += p8022.o psnap.o tr.o sysctl_net_802.o | ||
11 | obj-$(CONFIG_NET_FC) += fc.o | ||
12 | obj-$(CONFIG_FDDI) += fddi.o | ||
13 | obj-$(CONFIG_HIPPI) += hippi.o | ||
14 | obj-$(CONFIG_IPX) += p8022.o psnap.o | ||
15 | obj-$(CONFIG_ATALK) += p8022.o psnap.o | ||
diff --git a/net/802/fc.c b/net/802/fc.c new file mode 100644 index 000000000000..640d34e026c2 --- /dev/null +++ b/net/802/fc.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * NET3: Fibre Channel device handling subroutines | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * Vineet Abraham <vma@iol.unh.edu> | ||
10 | * v 1.0 03/22/99 | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <asm/uaccess.h> | ||
15 | #include <asm/system.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/socket.h> | ||
22 | #include <linux/in.h> | ||
23 | #include <linux/inet.h> | ||
24 | #include <linux/netdevice.h> | ||
25 | #include <linux/fcdevice.h> | ||
26 | #include <linux/skbuff.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/timer.h> | ||
29 | #include <linux/net.h> | ||
30 | #include <linux/proc_fs.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <net/arp.h> | ||
33 | |||
34 | /* | ||
35 | * Put the headers on a Fibre Channel packet. | ||
36 | */ | ||
37 | |||
38 | static int fc_header(struct sk_buff *skb, struct net_device *dev, | ||
39 | unsigned short type, | ||
40 | void *daddr, void *saddr, unsigned len) | ||
41 | { | ||
42 | struct fch_hdr *fch; | ||
43 | int hdr_len; | ||
44 | |||
45 | /* | ||
46 | * Add the 802.2 SNAP header if IP as the IPv4 code calls | ||
47 | * dev->hard_header directly. | ||
48 | */ | ||
49 | if (type == ETH_P_IP || type == ETH_P_ARP) | ||
50 | { | ||
51 | struct fcllc *fcllc; | ||
52 | |||
53 | hdr_len = sizeof(struct fch_hdr) + sizeof(struct fcllc); | ||
54 | fch = (struct fch_hdr *)skb_push(skb, hdr_len); | ||
55 | fcllc = (struct fcllc *)(fch+1); | ||
56 | fcllc->dsap = fcllc->ssap = EXTENDED_SAP; | ||
57 | fcllc->llc = UI_CMD; | ||
58 | fcllc->protid[0] = fcllc->protid[1] = fcllc->protid[2] = 0x00; | ||
59 | fcllc->ethertype = htons(type); | ||
60 | } | ||
61 | else | ||
62 | { | ||
63 | hdr_len = sizeof(struct fch_hdr); | ||
64 | fch = (struct fch_hdr *)skb_push(skb, hdr_len); | ||
65 | } | ||
66 | |||
67 | if(saddr) | ||
68 | memcpy(fch->saddr,saddr,dev->addr_len); | ||
69 | else | ||
70 | memcpy(fch->saddr,dev->dev_addr,dev->addr_len); | ||
71 | |||
72 | if(daddr) | ||
73 | { | ||
74 | memcpy(fch->daddr,daddr,dev->addr_len); | ||
75 | return(hdr_len); | ||
76 | } | ||
77 | return -hdr_len; | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * A neighbour discovery of some species (eg arp) has completed. We | ||
82 | * can now send the packet. | ||
83 | */ | ||
84 | |||
85 | static int fc_rebuild_header(struct sk_buff *skb) | ||
86 | { | ||
87 | struct fch_hdr *fch=(struct fch_hdr *)skb->data; | ||
88 | struct fcllc *fcllc=(struct fcllc *)(skb->data+sizeof(struct fch_hdr)); | ||
89 | if(fcllc->ethertype != htons(ETH_P_IP)) { | ||
90 | printk("fc_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(fcllc->ethertype)); | ||
91 | return 0; | ||
92 | } | ||
93 | #ifdef CONFIG_INET | ||
94 | return arp_find(fch->daddr, skb); | ||
95 | #else | ||
96 | return 0; | ||
97 | #endif | ||
98 | } | ||
99 | |||
100 | static void fc_setup(struct net_device *dev) | ||
101 | { | ||
102 | dev->hard_header = fc_header; | ||
103 | dev->rebuild_header = fc_rebuild_header; | ||
104 | |||
105 | dev->type = ARPHRD_IEEE802; | ||
106 | dev->hard_header_len = FC_HLEN; | ||
107 | dev->mtu = 2024; | ||
108 | dev->addr_len = FC_ALEN; | ||
109 | dev->tx_queue_len = 100; /* Long queues on fc */ | ||
110 | dev->flags = IFF_BROADCAST; | ||
111 | |||
112 | memset(dev->broadcast, 0xFF, FC_ALEN); | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * alloc_fcdev - Register fibre channel device | ||
117 | * @sizeof_priv: Size of additional driver-private structure to be allocated | ||
118 | * for this fibre channel device | ||
119 | * | ||
120 | * Fill in the fields of the device structure with fibre channel-generic values. | ||
121 | * | ||
122 | * Constructs a new net device, complete with a private data area of | ||
123 | * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for | ||
124 | * this private data area. | ||
125 | */ | ||
126 | struct net_device *alloc_fcdev(int sizeof_priv) | ||
127 | { | ||
128 | return alloc_netdev(sizeof_priv, "fc%d", fc_setup); | ||
129 | } | ||
130 | EXPORT_SYMBOL(alloc_fcdev); | ||
diff --git a/net/802/fddi.c b/net/802/fddi.c new file mode 100644 index 000000000000..f9a31a9f70f1 --- /dev/null +++ b/net/802/fddi.c | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * INET An implementation of the TCP/IP protocol suite for the LINUX | ||
3 | * operating system. INET is implemented using the BSD Socket | ||
4 | * interface as the means of communication with the user level. | ||
5 | * | ||
6 | * FDDI-type device handling. | ||
7 | * | ||
8 | * Version: @(#)fddi.c 1.0.0 08/12/96 | ||
9 | * | ||
10 | * Authors: Lawrence V. Stefani, <stefani@lkg.dec.com> | ||
11 | * | ||
12 | * fddi.c is based on previous eth.c and tr.c work by | ||
13 | * Ross Biro, <bir7@leland.Stanford.Edu> | ||
14 | * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> | ||
15 | * Mark Evans, <evansmp@uhura.aston.ac.uk> | ||
16 | * Florian La Roche, <rzsfl@rz.uni-sb.de> | ||
17 | * Alan Cox, <gw4pts@gw4pts.ampr.org> | ||
18 | * | ||
19 | * This program is free software; you can redistribute it and/or | ||
20 | * modify it under the terms of the GNU General Public License | ||
21 | * as published by the Free Software Foundation; either version | ||
22 | * 2 of the License, or (at your option) any later version. | ||
23 | * | ||
24 | * Changes | ||
25 | * Alan Cox : New arp/rebuild header | ||
26 | * Maciej W. Rozycki : IPv6 support | ||
27 | */ | ||
28 | |||
29 | #include <linux/config.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <asm/system.h> | ||
32 | #include <linux/types.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/string.h> | ||
36 | #include <linux/mm.h> | ||
37 | #include <linux/socket.h> | ||
38 | #include <linux/in.h> | ||
39 | #include <linux/inet.h> | ||
40 | #include <linux/netdevice.h> | ||
41 | #include <linux/fddidevice.h> | ||
42 | #include <linux/if_ether.h> | ||
43 | #include <linux/skbuff.h> | ||
44 | #include <linux/errno.h> | ||
45 | #include <net/arp.h> | ||
46 | #include <net/sock.h> | ||
47 | |||
48 | /* | ||
49 | * Create the FDDI MAC header for an arbitrary protocol layer | ||
50 | * | ||
51 | * saddr=NULL means use device source address | ||
52 | * daddr=NULL means leave destination address (eg unresolved arp) | ||
53 | */ | ||
54 | |||
55 | static int fddi_header(struct sk_buff *skb, struct net_device *dev, | ||
56 | unsigned short type, | ||
57 | void *daddr, void *saddr, unsigned len) | ||
58 | { | ||
59 | int hl = FDDI_K_SNAP_HLEN; | ||
60 | struct fddihdr *fddi; | ||
61 | |||
62 | if(type != ETH_P_IP && type != ETH_P_IPV6 && type != ETH_P_ARP) | ||
63 | hl=FDDI_K_8022_HLEN-3; | ||
64 | fddi = (struct fddihdr *)skb_push(skb, hl); | ||
65 | fddi->fc = FDDI_FC_K_ASYNC_LLC_DEF; | ||
66 | if(type == ETH_P_IP || type == ETH_P_IPV6 || type == ETH_P_ARP) | ||
67 | { | ||
68 | fddi->hdr.llc_snap.dsap = FDDI_EXTENDED_SAP; | ||
69 | fddi->hdr.llc_snap.ssap = FDDI_EXTENDED_SAP; | ||
70 | fddi->hdr.llc_snap.ctrl = FDDI_UI_CMD; | ||
71 | fddi->hdr.llc_snap.oui[0] = 0x00; | ||
72 | fddi->hdr.llc_snap.oui[1] = 0x00; | ||
73 | fddi->hdr.llc_snap.oui[2] = 0x00; | ||
74 | fddi->hdr.llc_snap.ethertype = htons(type); | ||
75 | } | ||
76 | |||
77 | /* Set the source and destination hardware addresses */ | ||
78 | |||
79 | if (saddr != NULL) | ||
80 | memcpy(fddi->saddr, saddr, dev->addr_len); | ||
81 | else | ||
82 | memcpy(fddi->saddr, dev->dev_addr, dev->addr_len); | ||
83 | |||
84 | if (daddr != NULL) | ||
85 | { | ||
86 | memcpy(fddi->daddr, daddr, dev->addr_len); | ||
87 | return(hl); | ||
88 | } | ||
89 | |||
90 | return(-hl); | ||
91 | } | ||
92 | |||
93 | |||
94 | /* | ||
95 | * Rebuild the FDDI MAC header. This is called after an ARP | ||
96 | * (or in future other address resolution) has completed on | ||
97 | * this sk_buff. We now let ARP fill in the other fields. | ||
98 | */ | ||
99 | |||
100 | static int fddi_rebuild_header(struct sk_buff *skb) | ||
101 | { | ||
102 | struct fddihdr *fddi = (struct fddihdr *)skb->data; | ||
103 | |||
104 | #ifdef CONFIG_INET | ||
105 | if (fddi->hdr.llc_snap.ethertype == __constant_htons(ETH_P_IP)) | ||
106 | /* Try to get ARP to resolve the header and fill destination address */ | ||
107 | return arp_find(fddi->daddr, skb); | ||
108 | else | ||
109 | #endif | ||
110 | { | ||
111 | printk("%s: Don't know how to resolve type %02X addresses.\n", | ||
112 | skb->dev->name, htons(fddi->hdr.llc_snap.ethertype)); | ||
113 | return(0); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | |||
118 | /* | ||
119 | * Determine the packet's protocol ID and fill in skb fields. | ||
120 | * This routine is called before an incoming packet is passed | ||
121 | * up. It's used to fill in specific skb fields and to set | ||
122 | * the proper pointer to the start of packet data (skb->data). | ||
123 | */ | ||
124 | |||
125 | unsigned short fddi_type_trans(struct sk_buff *skb, struct net_device *dev) | ||
126 | { | ||
127 | struct fddihdr *fddi = (struct fddihdr *)skb->data; | ||
128 | unsigned short type; | ||
129 | |||
130 | /* | ||
131 | * Set mac.raw field to point to FC byte, set data field to point | ||
132 | * to start of packet data. Assume 802.2 SNAP frames for now. | ||
133 | */ | ||
134 | |||
135 | skb->mac.raw = skb->data; /* point to frame control (FC) */ | ||
136 | |||
137 | if(fddi->hdr.llc_8022_1.dsap==0xe0) | ||
138 | { | ||
139 | skb_pull(skb, FDDI_K_8022_HLEN-3); | ||
140 | type = __constant_htons(ETH_P_802_2); | ||
141 | } | ||
142 | else | ||
143 | { | ||
144 | skb_pull(skb, FDDI_K_SNAP_HLEN); /* adjust for 21 byte header */ | ||
145 | type=fddi->hdr.llc_snap.ethertype; | ||
146 | } | ||
147 | |||
148 | /* Set packet type based on destination address and flag settings */ | ||
149 | |||
150 | if (*fddi->daddr & 0x01) | ||
151 | { | ||
152 | if (memcmp(fddi->daddr, dev->broadcast, FDDI_K_ALEN) == 0) | ||
153 | skb->pkt_type = PACKET_BROADCAST; | ||
154 | else | ||
155 | skb->pkt_type = PACKET_MULTICAST; | ||
156 | } | ||
157 | |||
158 | else if (dev->flags & IFF_PROMISC) | ||
159 | { | ||
160 | if (memcmp(fddi->daddr, dev->dev_addr, FDDI_K_ALEN)) | ||
161 | skb->pkt_type = PACKET_OTHERHOST; | ||
162 | } | ||
163 | |||
164 | /* Assume 802.2 SNAP frames, for now */ | ||
165 | |||
166 | return(type); | ||
167 | } | ||
168 | |||
169 | EXPORT_SYMBOL(fddi_type_trans); | ||
170 | |||
171 | static int fddi_change_mtu(struct net_device *dev, int new_mtu) | ||
172 | { | ||
173 | if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN)) | ||
174 | return(-EINVAL); | ||
175 | dev->mtu = new_mtu; | ||
176 | return(0); | ||
177 | } | ||
178 | |||
179 | static void fddi_setup(struct net_device *dev) | ||
180 | { | ||
181 | dev->change_mtu = fddi_change_mtu; | ||
182 | dev->hard_header = fddi_header; | ||
183 | dev->rebuild_header = fddi_rebuild_header; | ||
184 | |||
185 | dev->type = ARPHRD_FDDI; | ||
186 | dev->hard_header_len = FDDI_K_SNAP_HLEN+3; /* Assume 802.2 SNAP hdr len + 3 pad bytes */ | ||
187 | dev->mtu = FDDI_K_SNAP_DLEN; /* Assume max payload of 802.2 SNAP frame */ | ||
188 | dev->addr_len = FDDI_K_ALEN; | ||
189 | dev->tx_queue_len = 100; /* Long queues on FDDI */ | ||
190 | dev->flags = IFF_BROADCAST | IFF_MULTICAST; | ||
191 | |||
192 | memset(dev->broadcast, 0xFF, FDDI_K_ALEN); | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * alloc_fddidev - Register FDDI device | ||
197 | * @sizeof_priv: Size of additional driver-private structure to be allocated | ||
198 | * for this FDDI device | ||
199 | * | ||
200 | * Fill in the fields of the device structure with FDDI-generic values. | ||
201 | * | ||
202 | * Constructs a new net device, complete with a private data area of | ||
203 | * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for | ||
204 | * this private data area. | ||
205 | */ | ||
206 | struct net_device *alloc_fddidev(int sizeof_priv) | ||
207 | { | ||
208 | return alloc_netdev(sizeof_priv, "fddi%d", fddi_setup); | ||
209 | } | ||
210 | EXPORT_SYMBOL(alloc_fddidev); | ||
diff --git a/net/802/hippi.c b/net/802/hippi.c new file mode 100644 index 000000000000..4eb135c0afbb --- /dev/null +++ b/net/802/hippi.c | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * INET An implementation of the TCP/IP protocol suite for the LINUX | ||
3 | * operating system. INET is implemented using the BSD Socket | ||
4 | * interface as the means of communication with the user level. | ||
5 | * | ||
6 | * HIPPI-type device handling. | ||
7 | * | ||
8 | * Version: @(#)hippi.c 1.0.0 05/29/97 | ||
9 | * | ||
10 | * Authors: Ross Biro, <bir7@leland.Stanford.Edu> | ||
11 | * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> | ||
12 | * Mark Evans, <evansmp@uhura.aston.ac.uk> | ||
13 | * Florian La Roche, <rzsfl@rz.uni-sb.de> | ||
14 | * Alan Cox, <gw4pts@gw4pts.ampr.org> | ||
15 | * Jes Sorensen, <Jes.Sorensen@cern.ch> | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or | ||
18 | * modify it under the terms of the GNU General Public License | ||
19 | * as published by the Free Software Foundation; either version | ||
20 | * 2 of the License, or (at your option) any later version. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/types.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/socket.h> | ||
30 | #include <linux/in.h> | ||
31 | #include <linux/inet.h> | ||
32 | #include <linux/netdevice.h> | ||
33 | #include <linux/hippidevice.h> | ||
34 | #include <linux/skbuff.h> | ||
35 | #include <linux/errno.h> | ||
36 | #include <net/arp.h> | ||
37 | #include <net/sock.h> | ||
38 | #include <asm/uaccess.h> | ||
39 | #include <asm/checksum.h> | ||
40 | #include <asm/system.h> | ||
41 | |||
42 | /* | ||
43 | * Create the HIPPI MAC header for an arbitrary protocol layer | ||
44 | * | ||
45 | * saddr=NULL means use device source address | ||
46 | * daddr=NULL means leave destination address (eg unresolved arp) | ||
47 | */ | ||
48 | |||
49 | static int hippi_header(struct sk_buff *skb, struct net_device *dev, | ||
50 | unsigned short type, void *daddr, void *saddr, | ||
51 | unsigned len) | ||
52 | { | ||
53 | struct hippi_hdr *hip = (struct hippi_hdr *)skb_push(skb, HIPPI_HLEN); | ||
54 | |||
55 | if (!len){ | ||
56 | len = skb->len - HIPPI_HLEN; | ||
57 | printk("hippi_header(): length not supplied\n"); | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * Due to the stupidity of the little endian byte-order we | ||
62 | * have to set the fp field this way. | ||
63 | */ | ||
64 | hip->fp.fixed = __constant_htonl(0x04800018); | ||
65 | hip->fp.d2_size = htonl(len + 8); | ||
66 | hip->le.fc = 0; | ||
67 | hip->le.double_wide = 0; /* only HIPPI 800 for the time being */ | ||
68 | hip->le.message_type = 0; /* Data PDU */ | ||
69 | |||
70 | hip->le.dest_addr_type = 2; /* 12 bit SC address */ | ||
71 | hip->le.src_addr_type = 2; /* 12 bit SC address */ | ||
72 | |||
73 | memcpy(hip->le.src_switch_addr, dev->dev_addr + 3, 3); | ||
74 | memset(&hip->le.reserved, 0, 16); | ||
75 | |||
76 | hip->snap.dsap = HIPPI_EXTENDED_SAP; | ||
77 | hip->snap.ssap = HIPPI_EXTENDED_SAP; | ||
78 | hip->snap.ctrl = HIPPI_UI_CMD; | ||
79 | hip->snap.oui[0] = 0x00; | ||
80 | hip->snap.oui[1] = 0x00; | ||
81 | hip->snap.oui[2] = 0x00; | ||
82 | hip->snap.ethertype = htons(type); | ||
83 | |||
84 | if (daddr) | ||
85 | { | ||
86 | memcpy(hip->le.dest_switch_addr, daddr + 3, 3); | ||
87 | memcpy(&skb->private.ifield, daddr + 2, 4); | ||
88 | return HIPPI_HLEN; | ||
89 | } | ||
90 | return -((int)HIPPI_HLEN); | ||
91 | } | ||
92 | |||
93 | |||
94 | /* | ||
95 | * Rebuild the HIPPI MAC header. This is called after an ARP has | ||
96 | * completed on this sk_buff. We now let ARP fill in the other fields. | ||
97 | */ | ||
98 | |||
99 | static int hippi_rebuild_header(struct sk_buff *skb) | ||
100 | { | ||
101 | struct hippi_hdr *hip = (struct hippi_hdr *)skb->data; | ||
102 | |||
103 | /* | ||
104 | * Only IP is currently supported | ||
105 | */ | ||
106 | |||
107 | if(hip->snap.ethertype != __constant_htons(ETH_P_IP)) | ||
108 | { | ||
109 | printk(KERN_DEBUG "%s: unable to resolve type %X addresses.\n",skb->dev->name,ntohs(hip->snap.ethertype)); | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * We don't support dynamic ARP on HIPPI, but we use the ARP | ||
115 | * static ARP tables to hold the I-FIELDs. | ||
116 | */ | ||
117 | return arp_find(hip->le.daddr, skb); | ||
118 | } | ||
119 | |||
120 | |||
121 | /* | ||
122 | * Determine the packet's protocol ID. | ||
123 | */ | ||
124 | |||
125 | unsigned short hippi_type_trans(struct sk_buff *skb, struct net_device *dev) | ||
126 | { | ||
127 | struct hippi_hdr *hip; | ||
128 | |||
129 | hip = (struct hippi_hdr *) skb->data; | ||
130 | |||
131 | /* | ||
132 | * This is actually wrong ... question is if we really should | ||
133 | * set the raw address here. | ||
134 | */ | ||
135 | skb->mac.raw = skb->data; | ||
136 | skb_pull(skb, HIPPI_HLEN); | ||
137 | |||
138 | /* | ||
139 | * No fancy promisc stuff here now. | ||
140 | */ | ||
141 | |||
142 | return hip->snap.ethertype; | ||
143 | } | ||
144 | |||
145 | EXPORT_SYMBOL(hippi_type_trans); | ||
146 | |||
147 | static int hippi_change_mtu(struct net_device *dev, int new_mtu) | ||
148 | { | ||
149 | /* | ||
150 | * HIPPI's got these nice large MTUs. | ||
151 | */ | ||
152 | if ((new_mtu < 68) || (new_mtu > 65280)) | ||
153 | return -EINVAL; | ||
154 | dev->mtu = new_mtu; | ||
155 | return(0); | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * For HIPPI we will actually use the lower 4 bytes of the hardware | ||
160 | * address as the I-FIELD rather than the actual hardware address. | ||
161 | */ | ||
162 | static int hippi_mac_addr(struct net_device *dev, void *p) | ||
163 | { | ||
164 | struct sockaddr *addr = p; | ||
165 | if (netif_running(dev)) | ||
166 | return -EBUSY; | ||
167 | memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) | ||
172 | { | ||
173 | /* Never send broadcast/multicast ARP messages */ | ||
174 | p->mcast_probes = 0; | ||
175 | |||
176 | /* In IPv6 unicast probes are valid even on NBMA, | ||
177 | * because they are encapsulated in normal IPv6 protocol. | ||
178 | * Should be a generic flag. | ||
179 | */ | ||
180 | if (p->tbl->family != AF_INET6) | ||
181 | p->ucast_probes = 0; | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static void hippi_setup(struct net_device *dev) | ||
186 | { | ||
187 | dev->set_multicast_list = NULL; | ||
188 | dev->change_mtu = hippi_change_mtu; | ||
189 | dev->hard_header = hippi_header; | ||
190 | dev->rebuild_header = hippi_rebuild_header; | ||
191 | dev->set_mac_address = hippi_mac_addr; | ||
192 | dev->hard_header_parse = NULL; | ||
193 | dev->hard_header_cache = NULL; | ||
194 | dev->header_cache_update = NULL; | ||
195 | dev->neigh_setup = hippi_neigh_setup_dev; | ||
196 | |||
197 | /* | ||
198 | * We don't support HIPPI `ARP' for the time being, and probably | ||
199 | * never will unless someone else implements it. However we | ||
200 | * still need a fake ARPHRD to make ifconfig and friends play ball. | ||
201 | */ | ||
202 | dev->type = ARPHRD_HIPPI; | ||
203 | dev->hard_header_len = HIPPI_HLEN; | ||
204 | dev->mtu = 65280; | ||
205 | dev->addr_len = HIPPI_ALEN; | ||
206 | dev->tx_queue_len = 25 /* 5 */; | ||
207 | memset(dev->broadcast, 0xFF, HIPPI_ALEN); | ||
208 | |||
209 | |||
210 | /* | ||
211 | * HIPPI doesn't support broadcast+multicast and we only use | ||
212 | * static ARP tables. ARP is disabled by hippi_neigh_setup_dev. | ||
213 | */ | ||
214 | dev->flags = 0; | ||
215 | } | ||
216 | |||
217 | /** | ||
218 | * alloc_hippi_dev - Register HIPPI device | ||
219 | * @sizeof_priv: Size of additional driver-private structure to be allocated | ||
220 | * for this HIPPI device | ||
221 | * | ||
222 | * Fill in the fields of the device structure with HIPPI-generic values. | ||
223 | * | ||
224 | * Constructs a new net device, complete with a private data area of | ||
225 | * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for | ||
226 | * this private data area. | ||
227 | */ | ||
228 | |||
229 | struct net_device *alloc_hippi_dev(int sizeof_priv) | ||
230 | { | ||
231 | return alloc_netdev(sizeof_priv, "hip%d", hippi_setup); | ||
232 | } | ||
233 | |||
234 | EXPORT_SYMBOL(alloc_hippi_dev); | ||
diff --git a/net/802/p8022.c b/net/802/p8022.c new file mode 100644 index 000000000000..5ae63416df6d --- /dev/null +++ b/net/802/p8022.c | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * NET3: Support for 802.2 demultiplexing off Ethernet (Token ring | ||
3 | * is kept separate see p8022tr.c) | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * Demultiplex 802.2 encoded protocols. We match the entry by the | ||
10 | * SSAP/DSAP pair and then deliver to the registered datalink that | ||
11 | * matches. The control byte is ignored and handling of such items | ||
12 | * is up to the routine passed the frame. | ||
13 | * | ||
14 | * Unlike the 802.3 datalink we have a list of 802.2 entries as | ||
15 | * there are multiple protocols to demux. The list is currently | ||
16 | * short (3 or 4 entries at most). The current demux assumes this. | ||
17 | */ | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <linux/skbuff.h> | ||
21 | #include <net/datalink.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/in.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <net/llc.h> | ||
26 | #include <net/p8022.h> | ||
27 | |||
28 | static int p8022_request(struct datalink_proto *dl, struct sk_buff *skb, | ||
29 | unsigned char *dest) | ||
30 | { | ||
31 | llc_build_and_send_ui_pkt(dl->sap, skb, dest, dl->sap->laddr.lsap); | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | struct datalink_proto *register_8022_client(unsigned char type, | ||
36 | int (*func)(struct sk_buff *skb, | ||
37 | struct net_device *dev, | ||
38 | struct packet_type *pt)) | ||
39 | { | ||
40 | struct datalink_proto *proto; | ||
41 | |||
42 | proto = kmalloc(sizeof(*proto), GFP_ATOMIC); | ||
43 | if (proto) { | ||
44 | proto->type[0] = type; | ||
45 | proto->header_length = 3; | ||
46 | proto->request = p8022_request; | ||
47 | proto->sap = llc_sap_open(type, func); | ||
48 | if (!proto->sap) { | ||
49 | kfree(proto); | ||
50 | proto = NULL; | ||
51 | } | ||
52 | } | ||
53 | return proto; | ||
54 | } | ||
55 | |||
56 | void unregister_8022_client(struct datalink_proto *proto) | ||
57 | { | ||
58 | llc_sap_close(proto->sap); | ||
59 | kfree(proto); | ||
60 | } | ||
61 | |||
62 | EXPORT_SYMBOL(register_8022_client); | ||
63 | EXPORT_SYMBOL(unregister_8022_client); | ||
64 | |||
65 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/802/p8023.c b/net/802/p8023.c new file mode 100644 index 000000000000..a0b61b40225f --- /dev/null +++ b/net/802/p8023.c | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * NET3: 802.3 data link hooks used for IPX 802.3 | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * 802.3 isn't really a protocol data link layer. Some old IPX stuff | ||
10 | * uses it however. Note that there is only one 802.3 protocol layer | ||
11 | * in the system. We don't currently support different protocols | ||
12 | * running raw 802.3 on different devices. Thankfully nobody else | ||
13 | * has done anything like the old IPX. | ||
14 | */ | ||
15 | |||
16 | #include <linux/in.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <linux/skbuff.h> | ||
21 | |||
22 | #include <net/datalink.h> | ||
23 | |||
24 | /* | ||
25 | * Place an 802.3 header on a packet. The driver will do the mac | ||
26 | * addresses, we just need to give it the buffer length. | ||
27 | */ | ||
28 | static int p8023_request(struct datalink_proto *dl, | ||
29 | struct sk_buff *skb, unsigned char *dest_node) | ||
30 | { | ||
31 | struct net_device *dev = skb->dev; | ||
32 | |||
33 | dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len); | ||
34 | return dev_queue_xmit(skb); | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * Create an 802.3 client. Note there can be only one 802.3 client | ||
39 | */ | ||
40 | struct datalink_proto *make_8023_client(void) | ||
41 | { | ||
42 | struct datalink_proto *proto = kmalloc(sizeof(*proto), GFP_ATOMIC); | ||
43 | |||
44 | if (proto) { | ||
45 | proto->header_length = 0; | ||
46 | proto->request = p8023_request; | ||
47 | } | ||
48 | return proto; | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * Destroy the 802.3 client. | ||
53 | */ | ||
54 | void destroy_8023_client(struct datalink_proto *dl) | ||
55 | { | ||
56 | if (dl) | ||
57 | kfree(dl); | ||
58 | } | ||
59 | |||
60 | EXPORT_SYMBOL(destroy_8023_client); | ||
61 | EXPORT_SYMBOL(make_8023_client); | ||
diff --git a/net/802/psnap.c b/net/802/psnap.c new file mode 100644 index 000000000000..1053821ddf93 --- /dev/null +++ b/net/802/psnap.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * SNAP data link layer. Derived from 802.2 | ||
3 | * | ||
4 | * Alan Cox <Alan.Cox@linux.org>, | ||
5 | * from the 802.2 layer by Greg Page. | ||
6 | * Merged in additions from Greg Page's psnap.c. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/netdevice.h> | ||
16 | #include <linux/skbuff.h> | ||
17 | #include <net/datalink.h> | ||
18 | #include <net/llc.h> | ||
19 | #include <net/psnap.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/in.h> | ||
22 | #include <linux/init.h> | ||
23 | |||
24 | static LIST_HEAD(snap_list); | ||
25 | static DEFINE_SPINLOCK(snap_lock); | ||
26 | static struct llc_sap *snap_sap; | ||
27 | |||
28 | /* | ||
29 | * Find a snap client by matching the 5 bytes. | ||
30 | */ | ||
31 | static struct datalink_proto *find_snap_client(unsigned char *desc) | ||
32 | { | ||
33 | struct list_head *entry; | ||
34 | struct datalink_proto *proto = NULL, *p; | ||
35 | |||
36 | list_for_each_rcu(entry, &snap_list) { | ||
37 | p = list_entry(entry, struct datalink_proto, node); | ||
38 | if (!memcmp(p->type, desc, 5)) { | ||
39 | proto = p; | ||
40 | break; | ||
41 | } | ||
42 | } | ||
43 | return proto; | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * A SNAP packet has arrived | ||
48 | */ | ||
49 | static int snap_rcv(struct sk_buff *skb, struct net_device *dev, | ||
50 | struct packet_type *pt) | ||
51 | { | ||
52 | int rc = 1; | ||
53 | struct datalink_proto *proto; | ||
54 | static struct packet_type snap_packet_type = { | ||
55 | .type = __constant_htons(ETH_P_SNAP), | ||
56 | }; | ||
57 | |||
58 | rcu_read_lock(); | ||
59 | proto = find_snap_client(skb->h.raw); | ||
60 | if (proto) { | ||
61 | /* Pass the frame on. */ | ||
62 | skb->h.raw += 5; | ||
63 | skb_pull(skb, 5); | ||
64 | rc = proto->rcvfunc(skb, dev, &snap_packet_type); | ||
65 | } else { | ||
66 | skb->sk = NULL; | ||
67 | kfree_skb(skb); | ||
68 | rc = 1; | ||
69 | } | ||
70 | |||
71 | rcu_read_unlock(); | ||
72 | return rc; | ||
73 | } | ||
74 | |||
75 | /* | ||
76 | * Put a SNAP header on a frame and pass to 802.2 | ||
77 | */ | ||
78 | static int snap_request(struct datalink_proto *dl, | ||
79 | struct sk_buff *skb, u8 *dest) | ||
80 | { | ||
81 | memcpy(skb_push(skb, 5), dl->type, 5); | ||
82 | llc_build_and_send_ui_pkt(snap_sap, skb, dest, snap_sap->laddr.lsap); | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * Set up the SNAP layer | ||
88 | */ | ||
89 | EXPORT_SYMBOL(register_snap_client); | ||
90 | EXPORT_SYMBOL(unregister_snap_client); | ||
91 | |||
92 | static char snap_err_msg[] __initdata = | ||
93 | KERN_CRIT "SNAP - unable to register with 802.2\n"; | ||
94 | |||
95 | static int __init snap_init(void) | ||
96 | { | ||
97 | snap_sap = llc_sap_open(0xAA, snap_rcv); | ||
98 | |||
99 | if (!snap_sap) | ||
100 | printk(snap_err_msg); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | module_init(snap_init); | ||
106 | |||
107 | static void __exit snap_exit(void) | ||
108 | { | ||
109 | llc_sap_close(snap_sap); | ||
110 | } | ||
111 | |||
112 | module_exit(snap_exit); | ||
113 | |||
114 | |||
115 | /* | ||
116 | * Register SNAP clients. We don't yet use this for IP. | ||
117 | */ | ||
118 | struct datalink_proto *register_snap_client(unsigned char *desc, | ||
119 | int (*rcvfunc)(struct sk_buff *, | ||
120 | struct net_device *, | ||
121 | struct packet_type *)) | ||
122 | { | ||
123 | struct datalink_proto *proto = NULL; | ||
124 | |||
125 | spin_lock_bh(&snap_lock); | ||
126 | |||
127 | if (find_snap_client(desc)) | ||
128 | goto out; | ||
129 | |||
130 | proto = kmalloc(sizeof(*proto), GFP_ATOMIC); | ||
131 | if (proto) { | ||
132 | memcpy(proto->type, desc,5); | ||
133 | proto->rcvfunc = rcvfunc; | ||
134 | proto->header_length = 5 + 3; /* snap + 802.2 */ | ||
135 | proto->request = snap_request; | ||
136 | list_add_rcu(&proto->node, &snap_list); | ||
137 | } | ||
138 | out: | ||
139 | spin_unlock_bh(&snap_lock); | ||
140 | |||
141 | synchronize_net(); | ||
142 | return proto; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Unregister SNAP clients. Protocols no longer want to play with us ... | ||
147 | */ | ||
148 | void unregister_snap_client(struct datalink_proto *proto) | ||
149 | { | ||
150 | spin_lock_bh(&snap_lock); | ||
151 | list_del_rcu(&proto->node); | ||
152 | spin_unlock_bh(&snap_lock); | ||
153 | |||
154 | synchronize_net(); | ||
155 | |||
156 | kfree(proto); | ||
157 | } | ||
158 | |||
159 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/802/sysctl_net_802.c b/net/802/sysctl_net_802.c new file mode 100644 index 000000000000..36079630c49f --- /dev/null +++ b/net/802/sysctl_net_802.c | |||
@@ -0,0 +1,33 @@ | |||
1 | /* -*- linux-c -*- | ||
2 | * sysctl_net_802.c: sysctl interface to net 802 subsystem. | ||
3 | * | ||
4 | * Begun April 1, 1996, Mike Shaver. | ||
5 | * Added /proc/sys/net/802 directory entry (empty =) ). [MS] | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/mm.h> | ||
14 | #include <linux/sysctl.h> | ||
15 | #include <linux/config.h> | ||
16 | |||
17 | #ifdef CONFIG_TR | ||
18 | extern int sysctl_tr_rif_timeout; | ||
19 | #endif | ||
20 | |||
21 | struct ctl_table tr_table[] = { | ||
22 | #ifdef CONFIG_TR | ||
23 | { | ||
24 | .ctl_name = NET_TR_RIF_TIMEOUT, | ||
25 | .procname = "rif_timeout", | ||
26 | .data = &sysctl_tr_rif_timeout, | ||
27 | .maxlen = sizeof(int), | ||
28 | .mode = 0644, | ||
29 | .proc_handler = &proc_dointvec | ||
30 | }, | ||
31 | #endif /* CONFIG_TR */ | ||
32 | { 0 }, | ||
33 | }; | ||
diff --git a/net/802/tr.c b/net/802/tr.c new file mode 100644 index 000000000000..85293ccf7efc --- /dev/null +++ b/net/802/tr.c | |||
@@ -0,0 +1,645 @@ | |||
1 | /* | ||
2 | * NET3: Token ring device handling subroutines | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * Fixes: 3 Feb 97 Paul Norton <pnorton@cts.com> Minor routing fixes. | ||
10 | * Added rif table to /proc/net/tr_rif and rif timeout to | ||
11 | * /proc/sys/net/token-ring/rif_timeout. | ||
12 | * 22 Jun 98 Paul Norton <p.norton@computer.org> Rearranged | ||
13 | * tr_header and tr_type_trans to handle passing IPX SNAP and | ||
14 | * 802.2 through the correct layers. Eliminated tr_reformat. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <asm/uaccess.h> | ||
19 | #include <asm/system.h> | ||
20 | #include <linux/config.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/jiffies.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/socket.h> | ||
28 | #include <linux/in.h> | ||
29 | #include <linux/inet.h> | ||
30 | #include <linux/netdevice.h> | ||
31 | #include <linux/trdevice.h> | ||
32 | #include <linux/skbuff.h> | ||
33 | #include <linux/errno.h> | ||
34 | #include <linux/timer.h> | ||
35 | #include <linux/net.h> | ||
36 | #include <linux/proc_fs.h> | ||
37 | #include <linux/seq_file.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <net/arp.h> | ||
40 | |||
41 | static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev); | ||
42 | static void rif_check_expire(unsigned long dummy); | ||
43 | |||
44 | #define TR_SR_DEBUG 0 | ||
45 | |||
46 | /* | ||
47 | * Each RIF entry we learn is kept this way | ||
48 | */ | ||
49 | |||
50 | struct rif_cache_s { | ||
51 | unsigned char addr[TR_ALEN]; | ||
52 | int iface; | ||
53 | __u16 rcf; | ||
54 | __u16 rseg[8]; | ||
55 | struct rif_cache_s *next; | ||
56 | unsigned long last_used; | ||
57 | unsigned char local_ring; | ||
58 | }; | ||
59 | |||
60 | #define RIF_TABLE_SIZE 32 | ||
61 | |||
62 | /* | ||
63 | * We hash the RIF cache 32 ways. We do after all have to look it | ||
64 | * up a lot. | ||
65 | */ | ||
66 | |||
67 | static struct rif_cache_s *rif_table[RIF_TABLE_SIZE]; | ||
68 | |||
69 | static DEFINE_SPINLOCK(rif_lock); | ||
70 | |||
71 | |||
72 | /* | ||
73 | * Garbage disposal timer. | ||
74 | */ | ||
75 | |||
76 | static struct timer_list rif_timer; | ||
77 | |||
78 | int sysctl_tr_rif_timeout = 60*10*HZ; | ||
79 | |||
80 | static inline unsigned long rif_hash(const unsigned char *addr) | ||
81 | { | ||
82 | unsigned long x; | ||
83 | |||
84 | x = addr[0]; | ||
85 | x = (x << 2) ^ addr[1]; | ||
86 | x = (x << 2) ^ addr[2]; | ||
87 | x = (x << 2) ^ addr[3]; | ||
88 | x = (x << 2) ^ addr[4]; | ||
89 | x = (x << 2) ^ addr[5]; | ||
90 | |||
91 | x ^= x >> 8; | ||
92 | |||
93 | return x & (RIF_TABLE_SIZE - 1); | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Put the headers on a token ring packet. Token ring source routing | ||
98 | * makes this a little more exciting than on ethernet. | ||
99 | */ | ||
100 | |||
101 | static int tr_header(struct sk_buff *skb, struct net_device *dev, | ||
102 | unsigned short type, | ||
103 | void *daddr, void *saddr, unsigned len) | ||
104 | { | ||
105 | struct trh_hdr *trh; | ||
106 | int hdr_len; | ||
107 | |||
108 | /* | ||
109 | * Add the 802.2 SNAP header if IP as the IPv4/IPv6 code calls | ||
110 | * dev->hard_header directly. | ||
111 | */ | ||
112 | if (type == ETH_P_IP || type == ETH_P_IPV6 || type == ETH_P_ARP) | ||
113 | { | ||
114 | struct trllc *trllc; | ||
115 | |||
116 | hdr_len = sizeof(struct trh_hdr) + sizeof(struct trllc); | ||
117 | trh = (struct trh_hdr *)skb_push(skb, hdr_len); | ||
118 | trllc = (struct trllc *)(trh+1); | ||
119 | trllc->dsap = trllc->ssap = EXTENDED_SAP; | ||
120 | trllc->llc = UI_CMD; | ||
121 | trllc->protid[0] = trllc->protid[1] = trllc->protid[2] = 0x00; | ||
122 | trllc->ethertype = htons(type); | ||
123 | } | ||
124 | else | ||
125 | { | ||
126 | hdr_len = sizeof(struct trh_hdr); | ||
127 | trh = (struct trh_hdr *)skb_push(skb, hdr_len); | ||
128 | } | ||
129 | |||
130 | trh->ac=AC; | ||
131 | trh->fc=LLC_FRAME; | ||
132 | |||
133 | if(saddr) | ||
134 | memcpy(trh->saddr,saddr,dev->addr_len); | ||
135 | else | ||
136 | memcpy(trh->saddr,dev->dev_addr,dev->addr_len); | ||
137 | |||
138 | /* | ||
139 | * Build the destination and then source route the frame | ||
140 | */ | ||
141 | |||
142 | if(daddr) | ||
143 | { | ||
144 | memcpy(trh->daddr,daddr,dev->addr_len); | ||
145 | tr_source_route(skb,trh,dev); | ||
146 | return(hdr_len); | ||
147 | } | ||
148 | |||
149 | return -hdr_len; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * A neighbour discovery of some species (eg arp) has completed. We | ||
154 | * can now send the packet. | ||
155 | */ | ||
156 | |||
157 | static int tr_rebuild_header(struct sk_buff *skb) | ||
158 | { | ||
159 | struct trh_hdr *trh=(struct trh_hdr *)skb->data; | ||
160 | struct trllc *trllc=(struct trllc *)(skb->data+sizeof(struct trh_hdr)); | ||
161 | struct net_device *dev = skb->dev; | ||
162 | |||
163 | /* | ||
164 | * FIXME: We don't yet support IPv6 over token rings | ||
165 | */ | ||
166 | |||
167 | if(trllc->ethertype != htons(ETH_P_IP)) { | ||
168 | printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(trllc->ethertype)); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | #ifdef CONFIG_INET | ||
173 | if(arp_find(trh->daddr, skb)) { | ||
174 | return 1; | ||
175 | } | ||
176 | else | ||
177 | #endif | ||
178 | { | ||
179 | tr_source_route(skb,trh,dev); | ||
180 | return 0; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * Some of this is a bit hackish. We intercept RIF information | ||
186 | * used for source routing. We also grab IP directly and don't feed | ||
187 | * it via SNAP. | ||
188 | */ | ||
189 | |||
190 | unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev) | ||
191 | { | ||
192 | |||
193 | struct trh_hdr *trh=(struct trh_hdr *)skb->data; | ||
194 | struct trllc *trllc; | ||
195 | unsigned riflen=0; | ||
196 | |||
197 | skb->mac.raw = skb->data; | ||
198 | |||
199 | if(trh->saddr[0] & TR_RII) | ||
200 | riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; | ||
201 | |||
202 | trllc = (struct trllc *)(skb->data+sizeof(struct trh_hdr)-TR_MAXRIFLEN+riflen); | ||
203 | |||
204 | skb_pull(skb,sizeof(struct trh_hdr)-TR_MAXRIFLEN+riflen); | ||
205 | |||
206 | if(*trh->daddr & 0x80) | ||
207 | { | ||
208 | if(!memcmp(trh->daddr,dev->broadcast,TR_ALEN)) | ||
209 | skb->pkt_type=PACKET_BROADCAST; | ||
210 | else | ||
211 | skb->pkt_type=PACKET_MULTICAST; | ||
212 | } | ||
213 | else if ( (trh->daddr[0] & 0x01) && (trh->daddr[1] & 0x00) && (trh->daddr[2] & 0x5E)) | ||
214 | { | ||
215 | skb->pkt_type=PACKET_MULTICAST; | ||
216 | } | ||
217 | else if(dev->flags & IFF_PROMISC) | ||
218 | { | ||
219 | if(memcmp(trh->daddr, dev->dev_addr, TR_ALEN)) | ||
220 | skb->pkt_type=PACKET_OTHERHOST; | ||
221 | } | ||
222 | |||
223 | if ((skb->pkt_type != PACKET_BROADCAST) && | ||
224 | (skb->pkt_type != PACKET_MULTICAST)) | ||
225 | tr_add_rif_info(trh,dev) ; | ||
226 | |||
227 | /* | ||
228 | * Strip the SNAP header from ARP packets since we don't | ||
229 | * pass them through to the 802.2/SNAP layers. | ||
230 | */ | ||
231 | |||
232 | if (trllc->dsap == EXTENDED_SAP && | ||
233 | (trllc->ethertype == ntohs(ETH_P_IP) || | ||
234 | trllc->ethertype == ntohs(ETH_P_IPV6) || | ||
235 | trllc->ethertype == ntohs(ETH_P_ARP))) | ||
236 | { | ||
237 | skb_pull(skb, sizeof(struct trllc)); | ||
238 | return trllc->ethertype; | ||
239 | } | ||
240 | |||
241 | return ntohs(ETH_P_802_2); | ||
242 | } | ||
243 | |||
244 | /* | ||
245 | * We try to do source routing... | ||
246 | */ | ||
247 | |||
248 | void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,struct net_device *dev) | ||
249 | { | ||
250 | int slack; | ||
251 | unsigned int hash; | ||
252 | struct rif_cache_s *entry; | ||
253 | unsigned char *olddata; | ||
254 | static const unsigned char mcast_func_addr[] | ||
255 | = {0xC0,0x00,0x00,0x04,0x00,0x00}; | ||
256 | |||
257 | spin_lock_bh(&rif_lock); | ||
258 | |||
259 | /* | ||
260 | * Broadcasts are single route as stated in RFC 1042 | ||
261 | */ | ||
262 | if( (!memcmp(&(trh->daddr[0]),&(dev->broadcast[0]),TR_ALEN)) || | ||
263 | (!memcmp(&(trh->daddr[0]),&(mcast_func_addr[0]), TR_ALEN)) ) | ||
264 | { | ||
265 | trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK) | ||
266 | | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST); | ||
267 | trh->saddr[0]|=TR_RII; | ||
268 | } | ||
269 | else | ||
270 | { | ||
271 | hash = rif_hash(trh->daddr); | ||
272 | /* | ||
273 | * Walk the hash table and look for an entry | ||
274 | */ | ||
275 | for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->daddr[0]),TR_ALEN);entry=entry->next); | ||
276 | |||
277 | /* | ||
278 | * If we found an entry we can route the frame. | ||
279 | */ | ||
280 | if(entry) | ||
281 | { | ||
282 | #if TR_SR_DEBUG | ||
283 | printk("source routing for %02X:%02X:%02X:%02X:%02X:%02X\n",trh->daddr[0], | ||
284 | trh->daddr[1],trh->daddr[2],trh->daddr[3],trh->daddr[4],trh->daddr[5]); | ||
285 | #endif | ||
286 | if(!entry->local_ring && (ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8) | ||
287 | { | ||
288 | trh->rcf=entry->rcf; | ||
289 | memcpy(&trh->rseg[0],&entry->rseg[0],8*sizeof(unsigned short)); | ||
290 | trh->rcf^=htons(TR_RCF_DIR_BIT); | ||
291 | trh->rcf&=htons(0x1fff); /* Issam Chehab <ichehab@madge1.demon.co.uk> */ | ||
292 | |||
293 | trh->saddr[0]|=TR_RII; | ||
294 | #if TR_SR_DEBUG | ||
295 | printk("entry found with rcf %04x\n", entry->rcf); | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | printk("entry found but without rcf length, local=%02x\n", entry->local_ring); | ||
300 | #endif | ||
301 | } | ||
302 | entry->last_used=jiffies; | ||
303 | } | ||
304 | else | ||
305 | { | ||
306 | /* | ||
307 | * Without the information we simply have to shout | ||
308 | * on the wire. The replies should rapidly clean this | ||
309 | * situation up. | ||
310 | */ | ||
311 | trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK) | ||
312 | | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST); | ||
313 | trh->saddr[0]|=TR_RII; | ||
314 | #if TR_SR_DEBUG | ||
315 | printk("no entry in rif table found - broadcasting frame\n"); | ||
316 | #endif | ||
317 | } | ||
318 | } | ||
319 | |||
320 | /* Compress the RIF here so we don't have to do it in the driver(s) */ | ||
321 | if (!(trh->saddr[0] & 0x80)) | ||
322 | slack = 18; | ||
323 | else | ||
324 | slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8); | ||
325 | olddata = skb->data; | ||
326 | spin_unlock_bh(&rif_lock); | ||
327 | |||
328 | skb_pull(skb, slack); | ||
329 | memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack); | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * We have learned some new RIF information for our source | ||
334 | * routing. | ||
335 | */ | ||
336 | |||
337 | static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev) | ||
338 | { | ||
339 | unsigned int hash, rii_p = 0; | ||
340 | struct rif_cache_s *entry; | ||
341 | |||
342 | |||
343 | spin_lock_bh(&rif_lock); | ||
344 | |||
345 | /* | ||
346 | * Firstly see if the entry exists | ||
347 | */ | ||
348 | |||
349 | if(trh->saddr[0] & TR_RII) | ||
350 | { | ||
351 | trh->saddr[0]&=0x7f; | ||
352 | if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) | ||
353 | { | ||
354 | rii_p = 1; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | hash = rif_hash(trh->saddr); | ||
359 | for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);entry=entry->next); | ||
360 | |||
361 | if(entry==NULL) | ||
362 | { | ||
363 | #if TR_SR_DEBUG | ||
364 | printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", | ||
365 | trh->saddr[0],trh->saddr[1],trh->saddr[2], | ||
366 | trh->saddr[3],trh->saddr[4],trh->saddr[5], | ||
367 | ntohs(trh->rcf)); | ||
368 | #endif | ||
369 | /* | ||
370 | * Allocate our new entry. A failure to allocate loses | ||
371 | * use the information. This is harmless. | ||
372 | * | ||
373 | * FIXME: We ought to keep some kind of cache size | ||
374 | * limiting and adjust the timers to suit. | ||
375 | */ | ||
376 | entry=kmalloc(sizeof(struct rif_cache_s),GFP_ATOMIC); | ||
377 | |||
378 | if(!entry) | ||
379 | { | ||
380 | printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n"); | ||
381 | spin_unlock_bh(&rif_lock); | ||
382 | return; | ||
383 | } | ||
384 | |||
385 | memcpy(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN); | ||
386 | entry->iface = dev->ifindex; | ||
387 | entry->next=rif_table[hash]; | ||
388 | entry->last_used=jiffies; | ||
389 | rif_table[hash]=entry; | ||
390 | |||
391 | if (rii_p) | ||
392 | { | ||
393 | entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK); | ||
394 | memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short)); | ||
395 | entry->local_ring = 0; | ||
396 | trh->saddr[0]|=TR_RII; /* put the routing indicator back for tcpdump */ | ||
397 | } | ||
398 | else | ||
399 | { | ||
400 | entry->local_ring = 1; | ||
401 | } | ||
402 | } | ||
403 | else /* Y. Tahara added */ | ||
404 | { | ||
405 | /* | ||
406 | * Update existing entries | ||
407 | */ | ||
408 | if (!entry->local_ring) | ||
409 | if (entry->rcf != (trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK)) && | ||
410 | !(trh->rcf & htons(TR_RCF_BROADCAST_MASK))) | ||
411 | { | ||
412 | #if TR_SR_DEBUG | ||
413 | printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", | ||
414 | trh->saddr[0],trh->saddr[1],trh->saddr[2], | ||
415 | trh->saddr[3],trh->saddr[4],trh->saddr[5], | ||
416 | ntohs(trh->rcf)); | ||
417 | #endif | ||
418 | entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK); | ||
419 | memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short)); | ||
420 | } | ||
421 | entry->last_used=jiffies; | ||
422 | } | ||
423 | spin_unlock_bh(&rif_lock); | ||
424 | } | ||
425 | |||
426 | /* | ||
427 | * Scan the cache with a timer and see what we need to throw out. | ||
428 | */ | ||
429 | |||
430 | static void rif_check_expire(unsigned long dummy) | ||
431 | { | ||
432 | int i; | ||
433 | unsigned long next_interval = jiffies + sysctl_tr_rif_timeout/2; | ||
434 | |||
435 | spin_lock_bh(&rif_lock); | ||
436 | |||
437 | for(i =0; i < RIF_TABLE_SIZE; i++) { | ||
438 | struct rif_cache_s *entry, **pentry; | ||
439 | |||
440 | pentry = rif_table+i; | ||
441 | while((entry=*pentry) != NULL) { | ||
442 | unsigned long expires | ||
443 | = entry->last_used + sysctl_tr_rif_timeout; | ||
444 | |||
445 | if (time_before_eq(expires, jiffies)) { | ||
446 | *pentry = entry->next; | ||
447 | kfree(entry); | ||
448 | } else { | ||
449 | pentry = &entry->next; | ||
450 | |||
451 | if (time_before(expires, next_interval)) | ||
452 | next_interval = expires; | ||
453 | } | ||
454 | } | ||
455 | } | ||
456 | |||
457 | spin_unlock_bh(&rif_lock); | ||
458 | |||
459 | mod_timer(&rif_timer, next_interval); | ||
460 | |||
461 | } | ||
462 | |||
463 | /* | ||
464 | * Generate the /proc/net information for the token ring RIF | ||
465 | * routing. | ||
466 | */ | ||
467 | |||
468 | #ifdef CONFIG_PROC_FS | ||
469 | |||
470 | static struct rif_cache_s *rif_get_idx(loff_t pos) | ||
471 | { | ||
472 | int i; | ||
473 | struct rif_cache_s *entry; | ||
474 | loff_t off = 0; | ||
475 | |||
476 | for(i = 0; i < RIF_TABLE_SIZE; i++) | ||
477 | for(entry = rif_table[i]; entry; entry = entry->next) { | ||
478 | if (off == pos) | ||
479 | return entry; | ||
480 | ++off; | ||
481 | } | ||
482 | |||
483 | return NULL; | ||
484 | } | ||
485 | |||
486 | static void *rif_seq_start(struct seq_file *seq, loff_t *pos) | ||
487 | { | ||
488 | spin_lock_bh(&rif_lock); | ||
489 | |||
490 | return *pos ? rif_get_idx(*pos - 1) : SEQ_START_TOKEN; | ||
491 | } | ||
492 | |||
493 | static void *rif_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
494 | { | ||
495 | int i; | ||
496 | struct rif_cache_s *ent = v; | ||
497 | |||
498 | ++*pos; | ||
499 | |||
500 | if (v == SEQ_START_TOKEN) { | ||
501 | i = -1; | ||
502 | goto scan; | ||
503 | } | ||
504 | |||
505 | if (ent->next) | ||
506 | return ent->next; | ||
507 | |||
508 | i = rif_hash(ent->addr); | ||
509 | scan: | ||
510 | while (++i < RIF_TABLE_SIZE) { | ||
511 | if ((ent = rif_table[i]) != NULL) | ||
512 | return ent; | ||
513 | } | ||
514 | return NULL; | ||
515 | } | ||
516 | |||
517 | static void rif_seq_stop(struct seq_file *seq, void *v) | ||
518 | { | ||
519 | spin_unlock_bh(&rif_lock); | ||
520 | } | ||
521 | |||
522 | static int rif_seq_show(struct seq_file *seq, void *v) | ||
523 | { | ||
524 | int j, rcf_len, segment, brdgnmb; | ||
525 | struct rif_cache_s *entry = v; | ||
526 | |||
527 | if (v == SEQ_START_TOKEN) | ||
528 | seq_puts(seq, | ||
529 | "if TR address TTL rcf routing segments\n"); | ||
530 | else { | ||
531 | struct net_device *dev = dev_get_by_index(entry->iface); | ||
532 | long ttl = (long) (entry->last_used + sysctl_tr_rif_timeout) | ||
533 | - (long) jiffies; | ||
534 | |||
535 | seq_printf(seq, "%s %02X:%02X:%02X:%02X:%02X:%02X %7li ", | ||
536 | dev?dev->name:"?", | ||
537 | entry->addr[0],entry->addr[1],entry->addr[2], | ||
538 | entry->addr[3],entry->addr[4],entry->addr[5], | ||
539 | ttl/HZ); | ||
540 | |||
541 | if (entry->local_ring) | ||
542 | seq_puts(seq, "local\n"); | ||
543 | else { | ||
544 | |||
545 | seq_printf(seq, "%04X", ntohs(entry->rcf)); | ||
546 | rcf_len = ((ntohs(entry->rcf) & TR_RCF_LEN_MASK)>>8)-2; | ||
547 | if (rcf_len) | ||
548 | rcf_len >>= 1; | ||
549 | for(j = 1; j < rcf_len; j++) { | ||
550 | if(j==1) { | ||
551 | segment=ntohs(entry->rseg[j-1])>>4; | ||
552 | seq_printf(seq," %03X",segment); | ||
553 | }; | ||
554 | segment=ntohs(entry->rseg[j])>>4; | ||
555 | brdgnmb=ntohs(entry->rseg[j-1])&0x00f; | ||
556 | seq_printf(seq,"-%01X-%03X",brdgnmb,segment); | ||
557 | } | ||
558 | seq_putc(seq, '\n'); | ||
559 | } | ||
560 | } | ||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | |||
565 | static struct seq_operations rif_seq_ops = { | ||
566 | .start = rif_seq_start, | ||
567 | .next = rif_seq_next, | ||
568 | .stop = rif_seq_stop, | ||
569 | .show = rif_seq_show, | ||
570 | }; | ||
571 | |||
572 | static int rif_seq_open(struct inode *inode, struct file *file) | ||
573 | { | ||
574 | return seq_open(file, &rif_seq_ops); | ||
575 | } | ||
576 | |||
577 | static struct file_operations rif_seq_fops = { | ||
578 | .owner = THIS_MODULE, | ||
579 | .open = rif_seq_open, | ||
580 | .read = seq_read, | ||
581 | .llseek = seq_lseek, | ||
582 | .release = seq_release, | ||
583 | }; | ||
584 | |||
585 | #endif | ||
586 | |||
587 | static void tr_setup(struct net_device *dev) | ||
588 | { | ||
589 | /* | ||
590 | * Configure and register | ||
591 | */ | ||
592 | |||
593 | dev->hard_header = tr_header; | ||
594 | dev->rebuild_header = tr_rebuild_header; | ||
595 | |||
596 | dev->type = ARPHRD_IEEE802_TR; | ||
597 | dev->hard_header_len = TR_HLEN; | ||
598 | dev->mtu = 2000; | ||
599 | dev->addr_len = TR_ALEN; | ||
600 | dev->tx_queue_len = 100; /* Long queues on tr */ | ||
601 | |||
602 | memset(dev->broadcast,0xFF, TR_ALEN); | ||
603 | |||
604 | /* New-style flags. */ | ||
605 | dev->flags = IFF_BROADCAST | IFF_MULTICAST ; | ||
606 | } | ||
607 | |||
608 | /** | ||
609 | * alloc_trdev - Register token ring device | ||
610 | * @sizeof_priv: Size of additional driver-private structure to be allocated | ||
611 | * for this token ring device | ||
612 | * | ||
613 | * Fill in the fields of the device structure with token ring-generic values. | ||
614 | * | ||
615 | * Constructs a new net device, complete with a private data area of | ||
616 | * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for | ||
617 | * this private data area. | ||
618 | */ | ||
619 | struct net_device *alloc_trdev(int sizeof_priv) | ||
620 | { | ||
621 | return alloc_netdev(sizeof_priv, "tr%d", tr_setup); | ||
622 | } | ||
623 | |||
624 | /* | ||
625 | * Called during bootup. We don't actually have to initialise | ||
626 | * too much for this. | ||
627 | */ | ||
628 | |||
629 | static int __init rif_init(void) | ||
630 | { | ||
631 | init_timer(&rif_timer); | ||
632 | rif_timer.expires = sysctl_tr_rif_timeout; | ||
633 | rif_timer.data = 0L; | ||
634 | rif_timer.function = rif_check_expire; | ||
635 | add_timer(&rif_timer); | ||
636 | |||
637 | proc_net_fops_create("tr_rif", S_IRUGO, &rif_seq_fops); | ||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | module_init(rif_init); | ||
642 | |||
643 | EXPORT_SYMBOL(tr_source_route); | ||
644 | EXPORT_SYMBOL(tr_type_trans); | ||
645 | EXPORT_SYMBOL(alloc_trdev); | ||