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