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,14);
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,14);
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 * Header caching for ethernet. Try to find and cache a header to avoid arp overhead. 222 */ 223
224 voideth_header_cache(structdevice *dev, structsock *sk, unsignedlongsaddr, unsignedlongdaddr)
/* */ 225 { 226 intv=arp_find_cache(sk->ip_hcache_data, daddr, dev);
227 if(v!=1)
228 sk->ip_hcache_state=0; /* Try when arp resolves */ 229 else 230 { 231 memcpy(sk->ip_hcache_data+6, dev->dev_addr, ETH_ALEN);
232 sk->ip_hcache_data[12]=ETH_P_IP>>8;
233 sk->ip_hcache_data[13]=ETH_P_IP&0xFF;
234 sk->ip_hcache_state=1;
235 sk->ip_hcache_stamp=arp_cache_stamp;
236 sk->ip_hcache_ver=&arp_cache_stamp;
237 } 238 } 239
240 /* 241 * Copy from an ethernet device memory space to an sk_buff while checksumming if IP 242 * The magic "34" is Rx_addr+Tx_addr+type_field+sizeof(struct iphdr) == 6+6+2+20. 243 */ 244
245 voideth_copy_and_sum(structsk_buff *dest, unsignedchar *src, intlength, intbase)
/* */ 246 { 247 structethhdr *eth;
248 structiphdr *iph;
249 intip_length;
250
251 IS_SKB(dest);
252 eth=(structethhdr *)dest->data;
253 if(eth->h_proto!=htons(ETH_P_IP))
254 { 255 memcpy(dest->data,src,length);
256 return;
257 } 258 /* 259 * We have to watch for padded packets. The csum doesn't include the 260 * padding, and there is no point in copying the padding anyway. 261 * We have to use the smaller of length and ip_length because it 262 * can happen that ip_length > length. 263 */ 264 memcpy(dest->data,src,34); /* ethernet is always >= 34 */ 265 length -= 34;
266 iph=(structiphdr*)(src+14); /* 14 = Rx_addr+Tx_addr+type_field */ 267 ip_length = ntohs(iph->tot_len) - sizeof(structiphdr);
268 if (ip_length <= length)
269 length=ip_length;
270
271 dest->csum=csum_partial_copy(src+34,dest->data+34,length,base);
272 dest->ip_summed=1;
273 }