if_arp.c revision 1.3 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.3 1993/06/27 06:02:37 andrew 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 lna = in_lnaof(*destip);
197 /* if for us, use software loopback driver if up */
198 for (ia = in_ifaddr; ia; ia = ia->ia_next)
199 if ((ia->ia_ifp == &ac->ac_if) &&
200 (destip->s_addr == ia->ia_addr.sin_addr.s_addr)) {
201 /*
202 * This test used to be
203 * if (loif.if_flags & IFF_UP)
204 * It allowed local traffic to be forced
205 * through the hardware by configuring the loopback down.
206 * However, it causes problems during network configuration
207 * for boards that can't receive packets they send.
208 * It is now necessary to clear "useloopback"
209 * to force traffic out to the hardware.
210 */
211 if (useloopback) {
212 sin.sin_family = AF_INET;
213 sin.sin_addr = *destip;
214 (void) looutput(&loif, m, (struct sockaddr *)&sin, 0);
215 /*
216 * The packet has already been sent and freed.
217 */
218 return (0);
219 } else {
220 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten,
221 sizeof(ac->ac_enaddr));
222 return (1);
223 }
224 }
225 s = splimp();
226 ARPTAB_LOOK(at, destip->s_addr);
227 if (at == 0) { /* not found */
228 if (ac->ac_if.if_flags & IFF_NOARP) {
229 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
230 desten[3] = (lna >> 16) & 0x7f;
231 desten[4] = (lna >> 8) & 0xff;
232 desten[5] = lna & 0xff;
233 splx(s);
234 return (1);
235 } else {
236 at = arptnew(destip);
237 if (at == 0)
238 panic("arpresolve: no free entry");
239 at->at_hold = m;
240 arpwhohas(ac, destip);
241 splx(s);
242 return (0);
243 }
244 }
245 at->at_timer = 0; /* restart the timer */
246 if (at->at_flags & ATF_COM) { /* entry IS complete */
247 bcopy((caddr_t)at->at_enaddr, (caddr_t)desten,
248 sizeof(at->at_enaddr));
249 if (at->at_flags & ATF_USETRAILERS)
250 *usetrailers = 1;
251 splx(s);
252 return (1);
253 }
254 /*
255 * There is an arptab entry, but no ethernet address
256 * response yet. Replace the held mbuf with this
257 * latest one.
258 */
259 if (at->at_hold)
260 m_freem(at->at_hold);
261 at->at_hold = m;
262 arpwhohas(ac, destip); /* ask again */
263 splx(s);
264 return (0);
265 }
266
267 /*
268 * Called from 10 Mb/s Ethernet interrupt handlers
269 * when ether packet type ETHERTYPE_ARP
270 * is received. Common length and type checks are done here,
271 * then the protocol-specific routine is called.
272 */
273 arpinput(ac, m)
274 struct arpcom *ac;
275 struct mbuf *m;
276 {
277 register struct arphdr *ar;
278
279 if (ac->ac_if.if_flags & IFF_NOARP)
280 goto out;
281 if (m->m_len < sizeof(struct arphdr))
282 goto out;
283 ar = mtod(m, struct arphdr *);
284 if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
285 goto out;
286 if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
287 goto out;
288
289 switch (ntohs(ar->ar_pro)) {
290
291 case ETHERTYPE_IP:
292 case ETHERTYPE_IPTRAILERS:
293 in_arpinput(ac, m);
294 return;
295
296 default:
297 break;
298 }
299 out:
300 m_freem(m);
301 }
302
303 /*
304 * ARP for Internet protocols on 10 Mb/s Ethernet.
305 * Algorithm is that given in RFC 826.
306 * In addition, a sanity check is performed on the sender
307 * protocol address, to catch impersonators.
308 * We also handle negotiations for use of trailer protocol:
309 * ARP replies for protocol type ETHERTYPE_TRAIL are sent
310 * along with IP replies if we want trailers sent to us,
311 * and also send them in response to IP replies.
312 * This allows either end to announce the desire to receive
313 * trailer packets.
314 * We reply to requests for ETHERTYPE_TRAIL protocol as well,
315 * but don't normally send requests.
316 */
317 in_arpinput(ac, m)
318 register struct arpcom *ac;
319 struct mbuf *m;
320 {
321 register struct ether_arp *ea;
322 struct ether_header *eh;
323 register struct arptab *at; /* same as "merge" flag */
324 register struct in_ifaddr *ia;
325 struct in_ifaddr *maybe_ia = 0;
326 struct mbuf *mcopy = 0;
327 struct sockaddr_in sin;
328 struct sockaddr sa;
329 struct in_addr isaddr, itaddr, myaddr;
330 int proto, op, s, completed = 0;
331
332 ea = mtod(m, struct ether_arp *);
333 proto = ntohs(ea->arp_pro);
334 op = ntohs(ea->arp_op);
335 bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
336 bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
337 for (ia = in_ifaddr; ia; ia = ia->ia_next)
338 if (ia->ia_ifp == &ac->ac_if) {
339 maybe_ia = ia;
340 if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
341 (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
342 break;
343 }
344 if (maybe_ia == 0)
345 goto out;
346 myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
347 if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
348 sizeof (ea->arp_sha)))
349 goto out; /* it's from me, ignore it. */
350 if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
351 sizeof (ea->arp_sha))) {
352 log(LOG_ERR,
353 "arp: ether address is broadcast for IP address %x!\n",
354 ntohl(isaddr.s_addr));
355 goto out;
356 }
357 if (isaddr.s_addr == myaddr.s_addr) {
358 log(LOG_ERR,
359 "duplicate IP address %x!! sent from ethernet address: %s\n",
360 ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha));
361 itaddr = myaddr;
362 if (op == ARPOP_REQUEST)
363 goto reply;
364 goto out;
365 }
366 s = splimp();
367 ARPTAB_LOOK(at, isaddr.s_addr);
368 if (at) {
369 bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
370 sizeof(ea->arp_sha));
371 if ((at->at_flags & ATF_COM) == 0)
372 completed = 1;
373 at->at_flags |= ATF_COM;
374 if (at->at_hold) {
375 sin.sin_family = AF_INET;
376 sin.sin_addr = isaddr;
377 (*ac->ac_if.if_output)(&ac->ac_if, at->at_hold,
378 (struct sockaddr *)&sin, (struct rtentry *)0);
379 at->at_hold = 0;
380 }
381 }
382 if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
383 /* ensure we have a table entry */
384 if (at = arptnew(&isaddr)) {
385 bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
386 sizeof(ea->arp_sha));
387 completed = 1;
388 at->at_flags |= ATF_COM;
389 }
390 }
391 splx(s);
392 reply:
393 switch (proto) {
394
395 case ETHERTYPE_IPTRAILERS:
396 /* partner says trailers are OK */
397 if (at)
398 at->at_flags |= ATF_USETRAILERS;
399 /*
400 * Reply to request iff we want trailers.
401 */
402 if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS)
403 goto out;
404 break;
405
406 case ETHERTYPE_IP:
407 /*
408 * Reply if this is an IP request,
409 * or if we want to send a trailer response.
410 * Send the latter only to the IP response
411 * that completes the current ARP entry.
412 */
413 if (op != ARPOP_REQUEST &&
414 (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS))
415 goto out;
416 }
417 if (itaddr.s_addr == myaddr.s_addr) {
418 /* I am the target */
419 bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
420 sizeof(ea->arp_sha));
421 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
422 sizeof(ea->arp_sha));
423 } else {
424 ARPTAB_LOOK(at, itaddr.s_addr);
425 if (at == NULL || (at->at_flags & ATF_PUBL) == 0)
426 goto out;
427 bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
428 sizeof(ea->arp_sha));
429 bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha,
430 sizeof(ea->arp_sha));
431 }
432
433 bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
434 sizeof(ea->arp_spa));
435 bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa,
436 sizeof(ea->arp_spa));
437 ea->arp_op = htons(ARPOP_REPLY);
438 /*
439 * If incoming packet was an IP reply,
440 * we are sending a reply for type IPTRAILERS.
441 * If we are sending a reply for type IP
442 * and we want to receive trailers,
443 * send a trailer reply as well.
444 */
445 if (op == ARPOP_REPLY)
446 ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
447 else if (proto == ETHERTYPE_IP &&
448 (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0)
449 mcopy = m_copy(m, 0, (int)M_COPYALL);
450 eh = (struct ether_header *)sa.sa_data;
451 bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
452 sizeof(eh->ether_dhost));
453 eh->ether_type = ETHERTYPE_ARP;
454 sa.sa_family = AF_UNSPEC;
455 sa.sa_len = sizeof(sa);
456 (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
457 if (mcopy) {
458 ea = mtod(mcopy, struct ether_arp *);
459 ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
460 (*ac->ac_if.if_output)(&ac->ac_if,
461 mcopy, &sa, (struct rtentry *)0);
462 }
463 return;
464 out:
465 m_freem(m);
466 return;
467 }
468
469 /*
470 * Free an arptab entry.
471 */
472 arptfree(at)
473 register struct arptab *at;
474 {
475 int s = splimp();
476
477 if (at->at_hold)
478 m_freem(at->at_hold);
479 at->at_hold = 0;
480 at->at_timer = at->at_flags = 0;
481 at->at_iaddr.s_addr = 0;
482 splx(s);
483 }
484
485 /*
486 * Enter a new address in arptab, pushing out the oldest entry
487 * from the bucket if there is no room.
488 * This always succeeds since no bucket can be completely filled
489 * with permanent entries (except from arpioctl when testing whether
490 * another permanent entry will fit).
491 * MUST BE CALLED AT SPLIMP.
492 */
493 struct arptab *
494 arptnew(addr)
495 struct in_addr *addr;
496 {
497 register n;
498 int oldest = -1;
499 register struct arptab *at, *ato = NULL;
500 static int first = 1;
501
502 if (first) {
503 first = 0;
504 timeout(arptimer, (caddr_t)0, hz);
505 }
506 at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
507 for (n = 0; n < ARPTAB_BSIZ; n++,at++) {
508 if (at->at_flags == 0)
509 goto out; /* found an empty entry */
510 if (at->at_flags & ATF_PERM)
511 continue;
512 if ((int) at->at_timer > oldest) {
513 oldest = at->at_timer;
514 ato = at;
515 }
516 }
517 if (ato == NULL)
518 return (NULL);
519 at = ato;
520 arptfree(at);
521 out:
522 at->at_iaddr = *addr;
523 at->at_flags = ATF_INUSE;
524 return (at);
525 }
526
527 arpioctl(cmd, data)
528 int cmd;
529 caddr_t data;
530 {
531 register struct arpreq *ar = (struct arpreq *)data;
532 register struct arptab *at;
533 register struct sockaddr_in *sin;
534 int s;
535
536 sin = (struct sockaddr_in *)&ar->arp_ha;
537 #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN
538 if (sin->sin_family == 0 && sin->sin_len < 16)
539 sin->sin_family = sin->sin_len;
540 #endif
541 sin->sin_len = sizeof(ar->arp_ha);
542 sin = (struct sockaddr_in *)&ar->arp_pa;
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_pa);
548 if (ar->arp_pa.sa_family != AF_INET ||
549 ar->arp_ha.sa_family != AF_UNSPEC)
550 return (EAFNOSUPPORT);
551 s = splimp();
552 ARPTAB_LOOK(at, sin->sin_addr.s_addr);
553 if (at == NULL) { /* not found */
554 if (cmd != SIOCSARP) {
555 splx(s);
556 return (ENXIO);
557 }
558 if (ifa_ifwithnet(&ar->arp_pa) == NULL) {
559 splx(s);
560 return (ENETUNREACH);
561 }
562 }
563 switch (cmd) {
564
565 case SIOCSARP: /* set entry */
566 if (at == NULL) {
567 at = arptnew(&sin->sin_addr);
568 if (at == NULL) {
569 splx(s);
570 return (EADDRNOTAVAIL);
571 }
572 if (ar->arp_flags & ATF_PERM) {
573 /* never make all entries in a bucket permanent */
574 register struct arptab *tat;
575
576 /* try to re-allocate */
577 tat = arptnew(&sin->sin_addr);
578 if (tat == NULL) {
579 arptfree(at);
580 splx(s);
581 return (EADDRNOTAVAIL);
582 }
583 arptfree(tat);
584 }
585 }
586 bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr,
587 sizeof(at->at_enaddr));
588 at->at_flags = ATF_COM | ATF_INUSE |
589 (ar->arp_flags & (ATF_PERM|ATF_PUBL|ATF_USETRAILERS));
590 at->at_timer = 0;
591 break;
592
593 case SIOCDARP: /* delete entry */
594 arptfree(at);
595 break;
596
597 case SIOCGARP: /* get entry */
598 case OSIOCGARP:
599 bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data,
600 sizeof(at->at_enaddr));
601 #ifdef COMPAT_43
602 if (cmd == OSIOCGARP)
603 *(u_short *)&ar->arp_ha = ar->arp_ha.sa_family;
604 #endif
605 ar->arp_flags = at->at_flags;
606 break;
607 }
608 splx(s);
609 return (0);
610 }
611