if_arp.c revision 1.4 1 /*
2 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * from: @(#)if_ether.c 7.13 (Berkeley) 10/31/90
34 * $Id: if_arp.c,v 1.4 1993/12/12 20:43:06 hpeyerl Exp $
35 */
36
37 /*
38 * Ethernet address resolution protocol.
39 * TODO:
40 * run at splnet (add ARP protocol intr.)
41 * link entries onto hash chains, keep free list
42 * add "inuse/lock" bit (or ref. count) along with valid bit
43 */
44
45 #include "param.h"
46 #include "systm.h"
47 #include "malloc.h"
48 #include "mbuf.h"
49 #include "socket.h"
50 #include "time.h"
51 #include "kernel.h"
52 #include "errno.h"
53 #include "ioctl.h"
54 #include "syslog.h"
55
56 #include "../net/if.h"
57 #include "in.h"
58 #include "in_systm.h"
59 #include "in_var.h"
60 #include "ip.h"
61 #include "if_ether.h"
62
63 #ifdef GATEWAY
64 #define ARPTAB_BSIZ 16 /* bucket size */
65 #define ARPTAB_NB 37 /* number of buckets */
66 #else
67 #define ARPTAB_BSIZ 9 /* bucket size */
68 #define ARPTAB_NB 19 /* number of buckets */
69 #endif
70 #define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB)
71 struct arptab arptab[ARPTAB_SIZE];
72 int arptab_size = ARPTAB_SIZE; /* for arp command */
73
74 /*
75 * ARP trailer negotiation. Trailer protocol is not IP specific,
76 * but ARP request/response use IP addresses.
77 */
78 #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
79
80 #define ARPTAB_HASH(a) \
81 ((u_long)(a) % ARPTAB_NB)
82
83 #define ARPTAB_LOOK(at,addr) { \
84 register n; \
85 at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
86 for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
87 if (at->at_iaddr.s_addr == addr) \
88 break; \
89 if (n >= ARPTAB_BSIZ) \
90 at = 0; \
91 }
92
93 /* timer values */
94 #define ARPT_AGE (60*1) /* aging timer, 1 min. */
95 #define ARPT_KILLC 20 /* kill completed entry in 20 mins. */
96 #define ARPT_KILLI 3 /* kill incomplete entry in 3 minutes */
97
98 extern struct ifnet loif;
99
100 /*
101 * Timeout routine. Age arp_tab entries once a minute.
102 */
103 /* ARGSUSED */
104 void
105 arptimer(caddr_t arg)
106 {
107 register struct arptab *at;
108 register i;
109
110 timeout(arptimer, (caddr_t)0, ARPT_AGE * hz);
111 at = &arptab[0];
112 for (i = 0; i < ARPTAB_SIZE; i++, at++) {
113 if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
114 continue;
115 if (++at->at_timer < ((at->at_flags&ATF_COM) ?
116 ARPT_KILLC : ARPT_KILLI))
117 continue;
118 /* timer has expired, clear entry */
119 arptfree(at);
120 }
121 }
122
123 /*
124 * Broadcast an ARP packet, asking who has addr on interface ac.
125 */
126 arpwhohas(ac, addr)
127 register struct arpcom *ac;
128 struct in_addr *addr;
129 {
130 register struct mbuf *m;
131 register struct ether_header *eh;
132 register struct ether_arp *ea;
133 struct sockaddr sa;
134
135 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
136 return;
137 m->m_len = sizeof(*ea);
138 m->m_pkthdr.len = sizeof(*ea);
139 MH_ALIGN(m, sizeof(*ea));
140 ea = mtod(m, struct ether_arp *);
141 eh = (struct ether_header *)sa.sa_data;
142 bzero((caddr_t)ea, sizeof (*ea));
143 bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
144 sizeof(eh->ether_dhost));
145 eh->ether_type = ETHERTYPE_ARP; /* if_output will swap */
146 ea->arp_hrd = htons(ARPHRD_ETHER);
147 ea->arp_pro = htons(ETHERTYPE_IP);
148 ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */
149 ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */
150 ea->arp_op = htons(ARPOP_REQUEST);
151 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
152 sizeof(ea->arp_sha));
153 bcopy((caddr_t)&ac->ac_ipaddr, (caddr_t)ea->arp_spa,
154 sizeof(ea->arp_spa));
155 bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
156 sa.sa_family = AF_UNSPEC;
157 sa.sa_len = sizeof(sa);
158 (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
159 }
160
161 int useloopback = 1; /* use loopback interface for local traffic */
162
163 /*
164 * Resolve an IP address into an ethernet address. If success,
165 * desten is filled in. If there is no entry in arptab,
166 * set one up and broadcast a request for the IP address.
167 * Hold onto this mbuf and resend it once the address
168 * is finally resolved. A return value of 1 indicates
169 * that desten has been filled in and the packet should be sent
170 * normally; a 0 return indicates that the packet has been
171 * taken over here, either now or for later transmission.
172 *
173 * We do some (conservative) locking here at splimp, since
174 * arptab is also altered from input interrupt service (ecintr/ilintr
175 * calls arpinput when ETHERTYPE_ARP packets come in).
176 */
177 arpresolve(ac, m, destip, desten, usetrailers)
178 register struct arpcom *ac;
179 struct mbuf *m;
180 register struct in_addr *destip;
181 register u_char *desten;
182 int *usetrailers;
183 {
184 register struct arptab *at;
185 struct sockaddr_in sin;
186 register struct in_ifaddr *ia;
187 u_long lna;
188 int s;
189
190 *usetrailers = 0;
191 if (m->m_flags & M_BCAST) { /* broadcast */
192 bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
193 sizeof(etherbroadcastaddr));
194 return (1);
195 }
196 #ifdef MULTICAST
197 if (m->m_flags & M_MCAST) { /* multicast */
198 ETHER_MAP_IP_MULTICAST(destip, desten);
199 return(1);
200 }
201 #endif
202 lna = in_lnaof(*destip);
203 /* if for us, use software loopback driver if up */
204 for (ia = in_ifaddr; ia; ia = ia->ia_next)
205 if ((ia->ia_ifp == &ac->ac_if) &&
206 (destip->s_addr == ia->ia_addr.sin_addr.s_addr)) {
207 /*
208 * This test used to be
209 * if (loif.if_flags & IFF_UP)
210 * It allowed local traffic to be forced
211 * through the hardware by configuring the loopback down.
212 * However, it causes problems during network configuration
213 * for boards that can't receive packets they send.
214 * It is now necessary to clear "useloopback"
215 * to force traffic out to the hardware.
216 */
217 if (useloopback) {
218 sin.sin_family = AF_INET;
219 sin.sin_addr = *destip;
220 (void) looutput(&loif, m, (struct sockaddr *)&sin, 0);
221 /*
222 * The packet has already been sent and freed.
223 */
224 return (0);
225 } else {
226 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten,
227 sizeof(ac->ac_enaddr));
228 return (1);
229 }
230 }
231 s = splimp();
232 ARPTAB_LOOK(at, destip->s_addr);
233 if (at == 0) { /* not found */
234 if (ac->ac_if.if_flags & IFF_NOARP) {
235 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
236 desten[3] = (lna >> 16) & 0x7f;
237 desten[4] = (lna >> 8) & 0xff;
238 desten[5] = lna & 0xff;
239 splx(s);
240 return (1);
241 } else {
242 at = arptnew(destip);
243 if (at == 0)
244 panic("arpresolve: no free entry");
245 at->at_hold = m;
246 arpwhohas(ac, destip);
247 splx(s);
248 return (0);
249 }
250 }
251 at->at_timer = 0; /* restart the timer */
252 if (at->at_flags & ATF_COM) { /* entry IS complete */
253 bcopy((caddr_t)at->at_enaddr, (caddr_t)desten,
254 sizeof(at->at_enaddr));
255 if (at->at_flags & ATF_USETRAILERS)
256 *usetrailers = 1;
257 splx(s);
258 return (1);
259 }
260 /*
261 * There is an arptab entry, but no ethernet address
262 * response yet. Replace the held mbuf with this
263 * latest one.
264 */
265 if (at->at_hold)
266 m_freem(at->at_hold);
267 at->at_hold = m;
268 arpwhohas(ac, destip); /* ask again */
269 splx(s);
270 return (0);
271 }
272
273 /*
274 * Called from 10 Mb/s Ethernet interrupt handlers
275 * when ether packet type ETHERTYPE_ARP
276 * is received. Common length and type checks are done here,
277 * then the protocol-specific routine is called.
278 */
279 arpinput(ac, m)
280 struct arpcom *ac;
281 struct mbuf *m;
282 {
283 register struct arphdr *ar;
284
285 if (ac->ac_if.if_flags & IFF_NOARP)
286 goto out;
287 if (m->m_len < sizeof(struct arphdr))
288 goto out;
289 ar = mtod(m, struct arphdr *);
290 if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
291 goto out;
292 if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
293 goto out;
294
295 switch (ntohs(ar->ar_pro)) {
296
297 case ETHERTYPE_IP:
298 case ETHERTYPE_IPTRAILERS:
299 in_arpinput(ac, m);
300 return;
301
302 default:
303 break;
304 }
305 out:
306 m_freem(m);
307 }
308
309 /*
310 * ARP for Internet protocols on 10 Mb/s Ethernet.
311 * Algorithm is that given in RFC 826.
312 * In addition, a sanity check is performed on the sender
313 * protocol address, to catch impersonators.
314 * We also handle negotiations for use of trailer protocol:
315 * ARP replies for protocol type ETHERTYPE_TRAIL are sent
316 * along with IP replies if we want trailers sent to us,
317 * and also send them in response to IP replies.
318 * This allows either end to announce the desire to receive
319 * trailer packets.
320 * We reply to requests for ETHERTYPE_TRAIL protocol as well,
321 * but don't normally send requests.
322 */
323 in_arpinput(ac, m)
324 register struct arpcom *ac;
325 struct mbuf *m;
326 {
327 register struct ether_arp *ea;
328 struct ether_header *eh;
329 register struct arptab *at; /* same as "merge" flag */
330 register struct in_ifaddr *ia;
331 struct in_ifaddr *maybe_ia = 0;
332 struct mbuf *mcopy = 0;
333 struct sockaddr_in sin;
334 struct sockaddr sa;
335 struct in_addr isaddr, itaddr, myaddr;
336 int proto, op, s, completed = 0;
337
338 ea = mtod(m, struct ether_arp *);
339 proto = ntohs(ea->arp_pro);
340 op = ntohs(ea->arp_op);
341 bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
342 bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
343 for (ia = in_ifaddr; ia; ia = ia->ia_next)
344 if (ia->ia_ifp == &ac->ac_if) {
345 maybe_ia = ia;
346 if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
347 (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
348 break;
349 }
350 if (maybe_ia == 0)
351 goto out;
352 myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
353 if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
354 sizeof (ea->arp_sha)))
355 goto out; /* it's from me, ignore it. */
356 if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
357 sizeof (ea->arp_sha))) {
358 log(LOG_ERR,
359 "arp: ether address is broadcast for IP address %x!\n",
360 ntohl(isaddr.s_addr));
361 goto out;
362 }
363 if (isaddr.s_addr == myaddr.s_addr) {
364 log(LOG_ERR,
365 "duplicate IP address %x!! sent from ethernet address: %s\n",
366 ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha));
367 itaddr = myaddr;
368 if (op == ARPOP_REQUEST)
369 goto reply;
370 goto out;
371 }
372 s = splimp();
373 ARPTAB_LOOK(at, isaddr.s_addr);
374 if (at) {
375 bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
376 sizeof(ea->arp_sha));
377 if ((at->at_flags & ATF_COM) == 0)
378 completed = 1;
379 at->at_flags |= ATF_COM;
380 if (at->at_hold) {
381 sin.sin_family = AF_INET;
382 sin.sin_addr = isaddr;
383 (*ac->ac_if.if_output)(&ac->ac_if, at->at_hold,
384 (struct sockaddr *)&sin, (struct rtentry *)0);
385 at->at_hold = 0;
386 }
387 }
388 if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
389 /* ensure we have a table entry */
390 if (at = arptnew(&isaddr)) {
391 bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
392 sizeof(ea->arp_sha));
393 completed = 1;
394 at->at_flags |= ATF_COM;
395 }
396 }
397 splx(s);
398 reply:
399 switch (proto) {
400
401 case ETHERTYPE_IPTRAILERS:
402 /* partner says trailers are OK */
403 if (at)
404 at->at_flags |= ATF_USETRAILERS;
405 /*
406 * Reply to request iff we want trailers.
407 */
408 if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS)
409 goto out;
410 break;
411
412 case ETHERTYPE_IP:
413 /*
414 * Reply if this is an IP request,
415 * or if we want to send a trailer response.
416 * Send the latter only to the IP response
417 * that completes the current ARP entry.
418 */
419 if (op != ARPOP_REQUEST &&
420 (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS))
421 goto out;
422 }
423 if (itaddr.s_addr == myaddr.s_addr) {
424 /* I am the target */
425 bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
426 sizeof(ea->arp_sha));
427 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
428 sizeof(ea->arp_sha));
429 } else {
430 ARPTAB_LOOK(at, itaddr.s_addr);
431 if (at == NULL || (at->at_flags & ATF_PUBL) == 0)
432 goto out;
433 bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
434 sizeof(ea->arp_sha));
435 bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha,
436 sizeof(ea->arp_sha));
437 }
438
439 bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
440 sizeof(ea->arp_spa));
441 bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa,
442 sizeof(ea->arp_spa));
443 ea->arp_op = htons(ARPOP_REPLY);
444 /*
445 * If incoming packet was an IP reply,
446 * we are sending a reply for type IPTRAILERS.
447 * If we are sending a reply for type IP
448 * and we want to receive trailers,
449 * send a trailer reply as well.
450 */
451 if (op == ARPOP_REPLY)
452 ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
453 else if (proto == ETHERTYPE_IP &&
454 (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0)
455 mcopy = m_copy(m, 0, (int)M_COPYALL);
456 eh = (struct ether_header *)sa.sa_data;
457 bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
458 sizeof(eh->ether_dhost));
459 eh->ether_type = ETHERTYPE_ARP;
460 sa.sa_family = AF_UNSPEC;
461 sa.sa_len = sizeof(sa);
462 (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
463 if (mcopy) {
464 ea = mtod(mcopy, struct ether_arp *);
465 ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
466 (*ac->ac_if.if_output)(&ac->ac_if,
467 mcopy, &sa, (struct rtentry *)0);
468 }
469 return;
470 out:
471 m_freem(m);
472 return;
473 }
474
475 /*
476 * Free an arptab entry.
477 */
478 arptfree(at)
479 register struct arptab *at;
480 {
481 int s = splimp();
482
483 if (at->at_hold)
484 m_freem(at->at_hold);
485 at->at_hold = 0;
486 at->at_timer = at->at_flags = 0;
487 at->at_iaddr.s_addr = 0;
488 splx(s);
489 }
490
491 /*
492 * Enter a new address in arptab, pushing out the oldest entry
493 * from the bucket if there is no room.
494 * This always succeeds since no bucket can be completely filled
495 * with permanent entries (except from arpioctl when testing whether
496 * another permanent entry will fit).
497 * MUST BE CALLED AT SPLIMP.
498 */
499 struct arptab *
500 arptnew(addr)
501 struct in_addr *addr;
502 {
503 register n;
504 int oldest = -1;
505 register struct arptab *at, *ato = NULL;
506 static int first = 1;
507
508 if (first) {
509 first = 0;
510 timeout(arptimer, (caddr_t)0, hz);
511 }
512 at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
513 for (n = 0; n < ARPTAB_BSIZ; n++,at++) {
514 if (at->at_flags == 0)
515 goto out; /* found an empty entry */
516 if (at->at_flags & ATF_PERM)
517 continue;
518 if ((int) at->at_timer > oldest) {
519 oldest = at->at_timer;
520 ato = at;
521 }
522 }
523 if (ato == NULL)
524 return (NULL);
525 at = ato;
526 arptfree(at);
527 out:
528 at->at_iaddr = *addr;
529 at->at_flags = ATF_INUSE;
530 return (at);
531 }
532
533 arpioctl(cmd, data)
534 int cmd;
535 caddr_t data;
536 {
537 register struct arpreq *ar = (struct arpreq *)data;
538 register struct arptab *at;
539 register struct sockaddr_in *sin;
540 int s;
541
542 sin = (struct sockaddr_in *)&ar->arp_ha;
543 #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN
544 if (sin->sin_family == 0 && sin->sin_len < 16)
545 sin->sin_family = sin->sin_len;
546 #endif
547 sin->sin_len = sizeof(ar->arp_ha);
548 sin = (struct sockaddr_in *)&ar->arp_pa;
549 #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN
550 if (sin->sin_family == 0 && sin->sin_len < 16)
551 sin->sin_family = sin->sin_len;
552 #endif
553 sin->sin_len = sizeof(ar->arp_pa);
554 if (ar->arp_pa.sa_family != AF_INET ||
555 ar->arp_ha.sa_family != AF_UNSPEC)
556 return (EAFNOSUPPORT);
557 s = splimp();
558 ARPTAB_LOOK(at, sin->sin_addr.s_addr);
559 if (at == NULL) { /* not found */
560 if (cmd != SIOCSARP) {
561 splx(s);
562 return (ENXIO);
563 }
564 if (ifa_ifwithnet(&ar->arp_pa) == NULL) {
565 splx(s);
566 return (ENETUNREACH);
567 }
568 }
569 switch (cmd) {
570
571 case SIOCSARP: /* set entry */
572 if (at == NULL) {
573 at = arptnew(&sin->sin_addr);
574 if (at == NULL) {
575 splx(s);
576 return (EADDRNOTAVAIL);
577 }
578 if (ar->arp_flags & ATF_PERM) {
579 /* never make all entries in a bucket permanent */
580 register struct arptab *tat;
581
582 /* try to re-allocate */
583 tat = arptnew(&sin->sin_addr);
584 if (tat == NULL) {
585 arptfree(at);
586 splx(s);
587 return (EADDRNOTAVAIL);
588 }
589 arptfree(tat);
590 }
591 }
592 bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr,
593 sizeof(at->at_enaddr));
594 at->at_flags = ATF_COM | ATF_INUSE |
595 (ar->arp_flags & (ATF_PERM|ATF_PUBL|ATF_USETRAILERS));
596 at->at_timer = 0;
597 break;
598
599 case SIOCDARP: /* delete entry */
600 arptfree(at);
601 break;
602
603 case SIOCGARP: /* get entry */
604 case OSIOCGARP:
605 bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data,
606 sizeof(at->at_enaddr));
607 #ifdef COMPAT_43
608 if (cmd == OSIOCGARP)
609 *(u_short *)&ar->arp_ha = ar->arp_ha.sa_family;
610 #endif
611 ar->arp_flags = at->at_flags;
612 break;
613 }
614 splx(s);
615 return (0);
616 }
617