1 /* if_ether.c 4.3 83/06/13 */ 2 3 /* 4 * Ethernet address resolution protocol. 5 */ 6 7 #include "../h/param.h" 8 #include "../h/systm.h" 9 #include "../h/mbuf.h" 10 #include "../h/socket.h" 11 #include "../h/time.h" 12 #include "../h/kernel.h" 13 #include "../h/errno.h" 14 15 #include "../net/if.h" 16 #include "../netinet/in.h" 17 #include "../netinet/if_ether.h" 18 19 20 /* 21 * Internet to ethernet address resolution table. 22 */ 23 struct arptab { 24 struct in_addr at_iaddr; /* internet address */ 25 u_char at_enaddr[6]; /* ethernet address */ 26 struct mbuf *at_hold; /* last packet until resolved/timeout */ 27 u_char at_timer; /* minutes since last reference */ 28 u_char at_flags; /* flags */ 29 }; 30 /* at_flags field values */ 31 #define ATF_INUSE 1 /* entry in use */ 32 #define ATF_COM 2 /* completed entry (enaddr valid) */ 33 34 #define ARPTAB_BSIZ 5 /* bucket size */ 35 #define ARPTAB_NB 19 /* number of buckets */ 36 #define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB) 37 struct arptab arptab[ARPTAB_SIZE]; 38 39 #define ARPTAB_HASH(a) \ 40 ((short)((((a) >> 16) ^ (a)) & 0x7fff) % ARPTAB_NB) 41 42 #define ARPTAB_LOOK(at,addr) { \ 43 register n; \ 44 at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \ 45 for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \ 46 if (at->at_iaddr.s_addr == addr) \ 47 break; \ 48 if (n >= ARPTAB_BSIZ) \ 49 at = 0; } 50 51 struct arpcom *arpcom; /* chain of active ether interfaces */ 52 int arpt_age; /* aging timer */ 53 54 /* timer values */ 55 #define ARPT_AGE (60*1) /* aging timer, 1 min. */ 56 #define ARPT_KILLC 20 /* kill completed entry in 20 mins. */ 57 #define ARPT_KILLI 3 /* kill incomplete entry in 3 minutes */ 58 59 u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 60 extern struct ifnet loif; 61 62 #define OLDMAP 1 /* if LNA > 1023 use old 3COM mapping */ 63 64 /* 65 * Attach an ethernet interface to the list "arpcom" where 66 * arptimer() can find it. If first time 67 * initialization, start arptimer(). 68 */ 69 arpattach(ac) 70 register struct arpcom *ac; 71 { 72 register struct arpcom *acp; 73 74 for (acp = arpcom; acp != (struct arpcom *)0; acp = acp->ac_ac) 75 if (acp == ac) /* if already on list */ 76 return; 77 ac->ac_ac = arpcom; 78 arpcom = ac; 79 if (arpcom->ac_ac == 0) /* very first time */ 80 arptimer(); 81 } 82 83 /* 84 * Timeout routine. Age arp_tab entries once a minute. 85 */ 86 arptimer() 87 { 88 register struct arptab *at; 89 register i; 90 91 timeout(arptimer, (caddr_t)0, hz); 92 #ifdef notdef 93 if (++arpt_sanity > ARPT_SANITY) { 94 register struct arpcom *ac; 95 96 /* 97 * Randomize sanity timer based on my host address. 98 * Ask who has my own address; if someone else replies, 99 * then they are impersonating me. 100 */ 101 arpt_sanity = arpcom->ac_enaddr[5] & 0x3f; 102 for (ac = arpcom; ac != (struct arpcom *)-1; ac = ac->ac_ac) 103 arpwhohas(ac, &((struct sockaddr_in *) 104 &ac->ac_if.if_addr)->sin_addr); 105 } 106 #endif 107 if (++arpt_age > ARPT_AGE) { 108 arpt_age = 0; 109 at = &arptab[0]; 110 for (i = 0; i < ARPTAB_SIZE; i++, at++) { 111 if (at->at_flags == 0) 112 continue; 113 if (++at->at_timer < ((at->at_flags&ATF_COM) ? 114 ARPT_KILLC : ARPT_KILLI)) 115 continue; 116 /* timer has expired, clear entry */ 117 arptfree(at); 118 } 119 } 120 } 121 122 /* 123 * Broadcast an ARP packet, asking who has addr on interface ac. 124 */ 125 arpwhohas(ac, addr) 126 register struct arpcom *ac; 127 struct in_addr *addr; 128 { 129 register struct mbuf *m; 130 register struct ether_header *eh; 131 register struct ether_arp *ea; 132 struct sockaddr sa; 133 134 if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) 135 return; 136 m->m_len = sizeof *ea + sizeof *eh; 137 m->m_off = MMAXOFF - m->m_len; 138 ea = mtod(m, struct ether_arp *); 139 eh = (struct ether_header *)sa.sa_data; 140 bzero((caddr_t)ea, sizeof (*ea)); 141 bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, 142 sizeof (etherbroadcastaddr)); 143 eh->ether_type = ETHERPUP_ARPTYPE; /* if_output will swap */ 144 ea->arp_hrd = htons(ARPHRD_ETHER); 145 ea->arp_pro = htons(ETHERPUP_IPTYPE); 146 ea->arp_hln = sizeof ea->arp_sha; /* hardware address length */ 147 ea->arp_pln = sizeof ea->arp_spa; /* protocol address length */ 148 ea->arp_op = htons(ARPOP_REQUEST); 149 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, 150 sizeof (ea->arp_sha)); 151 bcopy((caddr_t)&((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr, 152 (caddr_t)ea->arp_spa, sizeof (ea->arp_spa)); 153 bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof (ea->arp_tpa)); 154 sa.sa_family = AF_UNSPEC; 155 (void) (*ac->ac_if.if_output)(&ac->ac_if, m, &sa); 156 } 157 158 /* 159 * Resolve an IP address into an ethernet address. If success, 160 * desten is filled in and 1 is returned. If there is no entry 161 * in arptab, set one up and broadcast a request 162 * for the IP address; return 0. Hold onto this mbuf and 163 * resend it once the address is finally resolved. 164 * 165 * We do some (conservative) locking here at splimp, since 166 * arptab is also altered from input interrupt service (ecintr/ilintr 167 * calls arpinput when ETHERPUP_ARPTYPE packets come in). 168 */ 169 arpresolve(ac, m, destip, desten) 170 register struct arpcom *ac; 171 struct mbuf *m; 172 register struct in_addr *destip; 173 register u_char *desten; 174 { 175 register struct arptab *at; 176 struct sockaddr_in sin; 177 int s, lna; 178 179 lna = in_lnaof(*destip); 180 if (lna == INADDR_ANY) { /* broadcast address */ 181 bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten, 182 sizeof (etherbroadcastaddr)); 183 return (1); 184 } 185 if (destip->s_addr == ((struct sockaddr_in *)&ac->ac_if.if_addr)-> 186 sin_addr.s_addr) { /* if for us, use lo driver */ 187 sin.sin_family = AF_INET; 188 sin.sin_addr = *destip; 189 return (looutput(&loif, m, (struct sockaddr *)&sin)); 190 } 191 #ifdef OLDMAP 192 if (lna >= 1024) { 193 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3); 194 desten[3] = (lna >> 16) & 0x7f; 195 desten[4] = (lna >> 8) & 0xff; 196 desten[5] = lna & 0xff; 197 return (1); 198 } 199 #endif OLDMAP 200 s = splimp(); 201 ARPTAB_LOOK(at, destip->s_addr); 202 if (at == 0) { /* not found */ 203 at = arptnew(destip); 204 at->at_hold = m; 205 arpwhohas(ac, destip); 206 splx(s); 207 return (0); 208 } 209 at->at_timer = 0; /* restart the timer */ 210 if (at->at_flags & ATF_COM) { /* entry IS complete */ 211 bcopy((caddr_t)at->at_enaddr, (caddr_t)desten, 6); 212 splx(s); 213 return (1); 214 } 215 /* 216 * There is an arptab entry, but no ethernet address 217 * response yet. Replace the held mbuf with this 218 * latest one. 219 */ 220 if (at->at_hold) 221 m_freem(at->at_hold); 222 at->at_hold = m; 223 arpwhohas(ac, destip); /* ask again */ 224 splx(s); 225 return (0); 226 } 227 228 /* 229 * Find my own IP address. It will either be waiting for us in 230 * monitor RAM, or can be obtained via broadcast to the file/boot 231 * server (not necessarily using the ARP packet format). 232 * 233 * Unimplemented at present, return 0 and assume that the host 234 * will set his own IP address via the SIOCSIFADDR ioctl. 235 */ 236 /*ARGSUSED*/ 237 struct in_addr 238 arpmyaddr(ac) 239 register struct arpcom *ac; 240 { 241 static struct in_addr addr; 242 243 #ifdef lint 244 ac = ac; 245 #endif 246 addr.s_addr = 0; 247 return (addr); 248 } 249 250 /* 251 * Called from ecintr/ilintr when ether packet type ETHERPUP_ARP 252 * is received. Algorithm is exactly that given in RFC 826. 253 * In addition, a sanity check is performed on the sender 254 * protocol address, to catch impersonators. 255 */ 256 arpinput(ac, m) 257 register struct arpcom *ac; 258 struct mbuf *m; 259 { 260 register struct ether_arp *ea; 261 struct ether_header *eh; 262 register struct arptab *at = 0; /* same as "merge" flag */ 263 struct sockaddr_in sin; 264 struct sockaddr sa; 265 struct mbuf *mhold; 266 struct in_addr isaddr,itaddr,myaddr; 267 268 if (m->m_len < sizeof *ea) 269 goto out; 270 myaddr = ((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr; 271 ea = mtod(m, struct ether_arp *); 272 if (ntohs(ea->arp_pro) != ETHERPUP_IPTYPE) 273 goto out; 274 isaddr.s_addr = ((struct in_addr *)ea->arp_spa)->s_addr; 275 itaddr.s_addr = ((struct in_addr *)ea->arp_tpa)->s_addr; 276 if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr, 277 sizeof (ac->ac_enaddr))) 278 goto out; /* it's from me, ignore it. */ 279 if (isaddr.s_addr == myaddr.s_addr) { 280 printf("duplicate IP address!! sent from ethernet address: "); 281 printf("%x %x %x %x %x %x\n", ea->arp_sha[0], ea->arp_sha[1], 282 ea->arp_sha[2], ea->arp_sha[3], 283 ea->arp_sha[4], ea->arp_sha[5]); 284 if (ntohs(ea->arp_op) == ARPOP_REQUEST) 285 goto reply; 286 goto out; 287 } 288 ARPTAB_LOOK(at, isaddr.s_addr); 289 if (at) { 290 bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, 291 sizeof (ea->arp_sha)); 292 at->at_flags |= ATF_COM; 293 if (at->at_hold) { 294 mhold = at->at_hold; 295 at->at_hold = 0; 296 sin.sin_family = AF_INET; 297 sin.sin_addr = isaddr; 298 (*ac->ac_if.if_output)(&ac->ac_if, 299 mhold, (struct sockaddr *)&sin); 300 } 301 } 302 if (itaddr.s_addr != myaddr.s_addr) 303 goto out; /* if I am not the target */ 304 if (at == 0) { /* ensure we have a table entry */ 305 at = arptnew(&isaddr); 306 bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, 307 sizeof (ea->arp_sha)); 308 at->at_flags |= ATF_COM; 309 } 310 if (ntohs(ea->arp_op) != ARPOP_REQUEST) 311 goto out; 312 reply: 313 bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, 314 sizeof (ea->arp_sha)); 315 bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, 316 sizeof (ea->arp_spa)); 317 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, 318 sizeof (ea->arp_sha)); 319 bcopy((caddr_t)&myaddr, (caddr_t)ea->arp_spa, 320 sizeof (ea->arp_spa)); 321 ea->arp_op = htons(ARPOP_REPLY); 322 eh = (struct ether_header *)sa.sa_data; 323 bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost, 324 sizeof (eh->ether_dhost)); 325 eh->ether_type = ETHERPUP_ARPTYPE; 326 sa.sa_family = AF_UNSPEC; 327 (*ac->ac_if.if_output)(&ac->ac_if, m, &sa); 328 return; 329 out: 330 m_freem(m); 331 return; 332 } 333 334 /* 335 * Free an arptab entry. 336 */ 337 arptfree(at) 338 register struct arptab *at; 339 { 340 int s = splimp(); 341 342 if (at->at_hold) 343 m_freem(at->at_hold); 344 at->at_hold = 0; 345 at->at_timer = at->at_flags = 0; 346 at->at_iaddr.s_addr = 0; 347 splx(s); 348 } 349 350 /* 351 * Enter a new address in arptab, pushing out the oldest entry 352 * from the bucket if there is no room. 353 */ 354 struct arptab * 355 arptnew(addr) 356 struct in_addr *addr; 357 { 358 register n; 359 int oldest = 0; 360 register struct arptab *at, *ato; 361 362 ato = at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ]; 363 for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) { 364 if (at->at_flags == 0) 365 goto out; /* found an empty entry */ 366 if (at->at_timer > oldest) { 367 oldest = at->at_timer; 368 ato = at; 369 } 370 } 371 at = ato; 372 arptfree(at); 373 out: 374 at->at_iaddr = *addr; 375 at->at_flags = ATF_INUSE; 376 return (at); 377 } 378