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 voideth_setup(char *str, int *ints)
/* */ 58 { 59 structdevice *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 inteth_header(structsk_buff *skb, structdevice *dev, unsignedshorttype,
/* */ 90 void *daddr, void *saddr, unsignedlen)
91 { 92 structethhdr *eth = (structethhdr *)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 returndev->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 inteth_rebuild_header(void *buff, structdevice *dev, unsignedlongdst,
/* */ 140 structsk_buff *skb)
141 { 142 structethhdr *eth = (structethhdr *)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 #ifdefCONFIG_INET 159 returnarp_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 unsignedshorteth_type_trans(structsk_buff *skb, structdevice *dev)
/* */ 173 { 174 structethhdr *eth;
175 unsignedchar *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 elseif(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 returneth->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 (*(unsignedshort *)rawp == 0xFFFF)
212 returnhtons(ETH_P_802_3);
213
214 /* 215 * Real 802.2 LLC 216 */ 217 returnhtons(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 voideth_header_cache_bind(structhh_cache ** hhp, structdevice *dev,
/* */ 227 unsignedshorthtype, __u32daddr)
228 { 229 structhh_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 voideth_header_cache_update(structhh_cache *hh, structdevice *dev, unsignedchar * haddr)
/* */ 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 voideth_copy_and_sum(structsk_buff *dest, unsignedchar *src, intlength, intbase)
/* */ 266 { 267 structethhdr *eth;
268 structiphdr *iph;
269 intip_length;
270
271 IS_SKB(dest);
272 eth=(structethhdr *)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(structiphdr)+ETH_HLEN); /* ethernet is always >= 34 */ 285 length -= sizeof(structiphdr) + ETH_HLEN;
286 iph=(structiphdr*)(src+ETH_HLEN);
287 ip_length = ntohs(iph->tot_len) - sizeof(structiphdr);
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(structiphdr)+ETH_HLEN,dest->data+sizeof(structiphdr)+ETH_HLEN,length,base);
294 dest->ip_summed=1;
295 }