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