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 * Ethernet-type device handling.
7 *
8 * Version: @(#)eth.c 1.0.7 05/25/93
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 *
16 * Fixes:
17 * Mr Linux : Arp problems
18 * Alan Cox : Generic queue tidyup (very tiny here)
19 * Alan Cox : eth_header ntohs should be htons
20 * Alan Cox : eth_rebuild_header missing an htons and
21 * minor other things.
22 * Tegge : Arp bug fixes.
23 * Florian : Removed many unnecessary functions, code cleanup
24 * and changes for new arp and skbuff.
25 * Alan Cox : Redid header building to reflect new format.
26 * Alan Cox : ARP only when compiled with CONFIG_INET
27 * Greg Page : 802.2 and SNAP stuff.
28 * Alan Cox : MAC layer pointers/new format.
29 * Paul Gortmaker : eth_copy_and_sum shouldn't csum padding.
30 * Alan Cox : Protect against forwarding explosions with
31 * older network drivers and IFF_ALLMULTI
32 *
33 * This program is free software; you can redistribute it and/or
34 * modify it under the terms of the GNU General Public License
35 * as published by the Free Software Foundation; either version
36 * 2 of the License, or (at your option) any later version.
37 */
38 #include <asm/segment.h>
39 #include <asm/system.h>
40 #include <linux/types.h>
41 #include <linux/kernel.h>
42 #include <linux/sched.h>
43 #include <linux/string.h>
44 #include <linux/mm.h>
45 #include <linux/socket.h>
46 #include <linux/in.h>
47 #include <linux/inet.h>
48 #include <linux/netdevice.h>
49 #include <linux/etherdevice.h>
50 #include <linux/skbuff.h>
51 #include <linux/errno.h>
52 #include <linux/config.h>
53 #include <net/arp.h>
54 #include <net/sock.h>
55 #include <asm/checksum.h>
56
57 void eth_setup(char *str, int *ints)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
58 {
59 struct device *d = dev_base;
60
61 if (!str || !*str)
62 return;
63 while (d)
64 {
65 if (!strcmp(str,d->name))
66 {
67 if (ints[0] > 0)
68 d->irq=ints[1];
69 if (ints[0] > 1)
70 d->base_addr=ints[2];
71 if (ints[0] > 2)
72 d->mem_start=ints[3];
73 if (ints[0] > 3)
74 d->mem_end=ints[4];
75 break;
76 }
77 d=d->next;
78 }
79 }
80
81
82 /*
83 * Create the Ethernet MAC header for an arbitrary protocol layer
84 *
85 * saddr=NULL means use device source address
86 * daddr=NULL means leave destination address (eg unresolved arp)
87 */
88
89 int eth_header(struct sk_buff *skb, struct device *dev, unsigned short type,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
90 void *daddr, void *saddr, unsigned len)
91 {
92 struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN);
93
94 /*
95 * Set the protocol type. For a packet of type ETH_P_802_3 we put the length
96 * in here instead. It is up to the 802.2 layer to carry protocol information.
97 */
98
99 if(type!=ETH_P_802_3)
100 eth->h_proto = htons(type);
101 else
102 eth->h_proto = htons(len);
103
104 /*
105 * Set the source hardware address.
106 */
107
108 if(saddr)
109 memcpy(eth->h_source,saddr,dev->addr_len);
110 else
111 memcpy(eth->h_source,dev->dev_addr,dev->addr_len);
112
113 /*
114 * Anyway, the loopback-device should never use this function...
115 */
116
117 if (dev->flags & IFF_LOOPBACK)
118 {
119 memset(eth->h_dest, 0, dev->addr_len);
120 return(dev->hard_header_len);
121 }
122
123 if(daddr)
124 {
125 memcpy(eth->h_dest,daddr,dev->addr_len);
126 return dev->hard_header_len;
127 }
128
129 return -dev->hard_header_len;
130 }
131
132
133 /*
134 * Rebuild the Ethernet MAC header. This is called after an ARP
135 * (or in future other address resolution) has completed on this
136 * sk_buff. We now let ARP fill in the other fields.
137 */
138
139 int eth_rebuild_header(void *buff, struct device *dev, unsigned long dst,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
140 struct sk_buff *skb)
141 {
142 struct ethhdr *eth = (struct ethhdr *)buff;
143
144 /*
145 * Only ARP/IP is currently supported
146 */
147
148 if(eth->h_proto != htons(ETH_P_IP))
149 {
150 printk("eth_rebuild_header: Don't know how to resolve type %d addresses?\n",(int)eth->h_proto);
151 memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
152 return 0;
153 }
154
155 /*
156 * Try and get ARP to resolve the header.
157 */
158 #ifdef CONFIG_INET
159 return arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0;
160 #else
161 return 0;
162 #endif
163 }
164
165
166 /*
167 * Determine the packet's protocol ID. The rule here is that we
168 * assume 802.3 if the type field is short enough to be a length.
169 * This is normal practice and works for any 'now in use' protocol.
170 */
171
172 unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
173 {
174 struct ethhdr *eth;
175 unsigned char *rawp;
176
177 skb->mac.raw=skb->data;
178 skb_pull(skb,dev->hard_header_len);
179 eth= skb->mac.ethernet;
180
181 if(*eth->h_dest&1)
182 {
183 if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
184 skb->pkt_type=PACKET_BROADCAST;
185 else
186 skb->pkt_type=PACKET_MULTICAST;
187 }
188
189 /*
190 * This ALLMULTI check should be redundant by 1.4
191 * so don't forget to remove it.
192 */
193
194 else if(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
195 {
196 if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
197 skb->pkt_type=PACKET_OTHERHOST;
198 }
199
200 if (ntohs(eth->h_proto) >= 1536)
201 return eth->h_proto;
202
203 rawp = skb->data;
204
205 /*
206 * This is a magic hack to spot IPX packets. Older Novell breaks
207 * the protocol design and runs IPX over 802.3 without an 802.2 LLC
208 * layer. We look for FFFF which isnt a used 802.2 SSAP/DSAP. This
209 * won't work for fault tolerant netware but does for the rest.
210 */
211 if (*(unsigned short *)rawp == 0xFFFF)
212 return htons(ETH_P_802_3);
213
214 /*
215 * Real 802.2 LLC
216 */
217 return htons(ETH_P_802_2);
218 }
219
220 /*
221 * Upper level calls this function to bind hardware header cache entry.
222 * If the call is successful, then corresponding Address Resolution Protocol
223 * (maybe, not ARP) takes responsibility for updating cache content.
224 */
225
226 void eth_header_cache_bind(struct hh_cache ** hhp, struct device *dev,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
227 unsigned short htype, __u32 daddr)
228 {
229 struct hh_cache *hh;
230
231 if (htype != ETH_P_IP)
232 {
233 printk("eth_header_cache_bind: %04x cache is not implemented\n", htype);
234 return;
235 }
236 if (arp_bind_cache(hhp, dev, htype, daddr))
237 return;
238 if ((hh=*hhp) != NULL)
239 {
240 memcpy(hh->hh_data+6, dev->dev_addr, ETH_ALEN);
241 hh->hh_data[12] = htype>>8;
242 hh->hh_data[13] = htype&0xFF;
243 }
244 }
245
246 /*
247 * Called by Address Resolution module to notify changes in address.
248 */
249
250 void eth_header_cache_update(struct hh_cache *hh, struct device *dev, unsigned char * haddr)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
251 {
252 if (hh->hh_type != ETH_P_IP)
253 {
254 printk("eth_header_cache_update: %04x cache is not implemented\n", hh->hh_type);
255 return;
256 }
257 memcpy(hh->hh_data, haddr, ETH_ALEN);
258 hh->hh_uptodate = 1;
259 }
260
261 /*
262 * Copy from an ethernet device memory space to an sk_buff while checksumming if IP
263 */
264
265 void eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int length, int base)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
266 {
267 struct ethhdr *eth;
268 struct iphdr *iph;
269 int ip_length;
270
271 IS_SKB(dest);
272 eth=(struct ethhdr *)dest->data;
273 if(eth->h_proto!=htons(ETH_P_IP))
274 {
275 memcpy(dest->data,src,length);
276 return;
277 }
278 /*
279 * We have to watch for padded packets. The csum doesn't include the
280 * padding, and there is no point in copying the padding anyway.
281 * We have to use the smaller of length and ip_length because it
282 * can happen that ip_length > length.
283 */
284 memcpy(dest->data,src,sizeof(struct iphdr)+ETH_HLEN); /* ethernet is always >= 34 */
285 length -= sizeof(struct iphdr) + ETH_HLEN;
286 iph=(struct iphdr*)(src+ETH_HLEN);
287 ip_length = ntohs(iph->tot_len) - sizeof(struct iphdr);
288
289 /* Also watch out for bogons - min IP size is 8 (rfc-1042) */
290 if ((ip_length <= length) && (ip_length > 7))
291 length=ip_length;
292
293 dest->csum=csum_partial_copy(src+sizeof(struct iphdr)+ETH_HLEN,dest->data+sizeof(struct iphdr)+ETH_HLEN,length,base);
294 dest->ip_summed=1;
295 }