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