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