revert between 56095 -> 55830 in arch
[AROS.git] / workbench / network / stacks / AROSTCP / bsdsocket / net / sana2arp.c
blob7dbca776a69943030377f35d67f3c94161775a6d
1 /*
2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
4 * All rights reserved.
5 * Copyright (C) 2005 - 2007 The AROS Dev Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 * MA 02111-1307, USA.
24 * Address Resolution Protocol.
25 * TODO:
26 * add "inuse/lock" bit (or ref. count) along with valid bit
29 #include <conf.h>
31 #include <libraries/miami.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/malloc.h>
35 #include <sys/mbuf.h>
36 #include <sys/socket.h>
37 #include <sys/time.h>
38 #include <sys/kernel.h>
39 #include <sys/errno.h>
40 #include <sys/ioctl.h>
41 #include <sys/syslog.h>
42 #include <sys/synch.h>
44 #include <net/if.h>
45 #include <net/if_types.h>
46 #include <net/if_protos.h>
47 #include <net/pfil.h>
48 #include <netinet/in.h>
49 #include <netinet/in_systm.h>
50 #include <netinet/in_var.h>
51 #include <netinet/ip.h>
53 #include <net/if_sana.h>
54 #include <net/sana2arp.h>
56 #include <net/if_loop_protos.h>
59 * Internet to hardware address resolution table entry
61 struct arptab {
62 struct arptab *at_succ; /* doubly linked list */
63 struct arptab *at_pred;
64 struct in_addr at_iaddr; /* internet address */
65 u_char at_hwaddr[MAXADDRSANA]; /* hardware address */
66 u_char at_timer; /* minutes since last reference */
67 u_char at_flags; /* flags */
68 struct mbuf *at_hold; /* last packet until resolved/timeout */
72 * Global constant for ARP entry allocation
74 unsigned long arpentries = ARPENTRIES;
77 * General per interface hash table
79 struct arptable {
80 struct SignalSemaphore atb_lock;
81 struct arptab *atb_free;
82 struct MinList atb_entries[ARPTAB_HSIZE];
85 #define ARPTAB_LOCK(atb) (ObtainSemaphore(&atb->atb_lock))
86 #define ARPTAB_UNLOCK(atb) (ReleaseSemaphore(&atb->atb_lock))
87 #define ARPTAB_HASH(a) ((u_long)(a) % ARPTAB_HSIZE)
89 extern struct ifnet loif;
91 int useloopback = 0; /* use loopback interface for local traffic */
93 static void arpwhohas(register struct sana_softc *ssc, struct in_addr * addr);
94 static void in_arpinput(register struct sana_softc *ssc, struct mbuf *m);
95 static char *sana_sprintf(register u_char *ap, int len);
98 * Initialization routine. Allocate ARP entries.
99 * MUST BE CALLED AT SPLIMP.
101 void
102 alloc_arptable(struct sana_softc* ssc, int to_allocate)
104 struct arptab *at;
105 struct arptable *atab;
106 int i;
108 if (ssc->ss_arp.table)
109 return /* (void)ssc->ss_arp.table */;
111 #if 0
112 if (to_allocate < arpentries)
113 #endif
114 to_allocate = arpentries;
116 atab = bsd_malloc(sizeof(*atab), M_ARPENT, M_WAITOK);
117 at = bsd_malloc(sizeof(*at) * to_allocate, M_ARPENT, M_WAITOK);
119 if (atab && at) {
120 InitSemaphore(&atab->atb_lock);
121 for (i = 0; i < ARPTAB_HSIZE; i++)
122 NewList((struct List *)(atab->atb_entries + i));
124 aligned_bzero(at, sizeof(*at) * to_allocate);
126 at[0].at_succ = NULL;
127 for (i = 1; i < to_allocate; i++) {
128 at[i].at_succ = &at[i - 1];
130 atab->atb_free = &at[to_allocate - 1];
131 } else {
132 if (atab) bsd_free(atab, M_ARPENT);
133 if (at) bsd_free(at, M_ARPENT);
134 __log(LOG_ERR, "Could not allocate ARP table for %s\n", ssc->ss_name);
137 ssc->ss_arp.table = atab;
141 * Notification function for arp entries
143 LONG
144 arpentries_notify(void *dummy, LONG value)
146 return (ULONG)value > ARPENTRIES_MIN;
150 * Free an arptab entry. ARP TABLE MUST BE LOCKED
152 static void
153 arptfree(register struct arptable *atb, register struct arptab *at)
155 if (at->at_hold)
156 m_freem(at->at_hold);
158 Remove((struct Node *)at);
160 if (at->at_flags & ATF_PERM) {
161 bsd_free(at, M_ARPENT);
162 } else {
163 at->at_hold = NULL;
164 at->at_timer = at->at_flags = 0;
165 at->at_iaddr.s_addr = 0;
166 at->at_succ = atb->atb_free;
167 atb->atb_free = at;
172 * Enter a new address in arptab. ARP TABLE MUST BE LOCKED
174 static struct arptab *
175 arptnew(u_long addr, struct arptable *atb, int permanent)
177 struct arptab *at = NULL;
179 if (permanent) {
180 at = bsd_malloc(sizeof(*at), M_ARPENT, M_WAITOK);
181 bzero((caddr_t)at, sizeof(*at));
182 } else {
183 at = atb->atb_free;
184 if (at) {
185 atb->atb_free = at->at_succ;
186 } else {
188 * The oldest entry is pushed out from the
189 * interface table if there is no free entry.
190 * This should always succeed since all
191 * entries can not be permanent
193 struct arptab *oldest = NULL;
194 int i;
196 for (i = 0; i < ARPTAB_HSIZE; i++) {
197 for (at = (struct arptab *)atb->atb_entries[i].mlh_Head;
198 at->at_succ;
199 at = at->at_succ) {
200 if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
201 continue;
202 if (!oldest || oldest->at_timer < at->at_timer)
203 oldest = at;
206 if (oldest) {
207 Remove((struct Node *)oldest);
208 at = oldest;
209 } else {
210 at = NULL;
214 if (at) {
215 at->at_iaddr.s_addr = addr;
216 at->at_flags = ATF_INUSE;
217 AddHead((struct List *)(&atb->atb_entries[ARPTAB_HASH(addr)]),
218 (struct Node *)at);
220 return (at);
224 * Locate an IP address in the ARP table
225 * Assume looker have locked the table
227 static struct arptab*
228 arptab_look(struct arptable *table, u_long addr)
230 register struct arptab *at = (struct arptab *)
231 table->atb_entries[ARPTAB_HASH(addr)].mlh_Head;
233 for(;at->at_succ; at = at->at_succ)
234 if (at->at_iaddr.s_addr == addr)
235 return at;
237 return NULL;
241 * Timeout routine. Age arp_tab entries once a minute.
243 void
244 arptimer()
246 struct sana_softc *ssc;
247 register struct arptable *atab;
248 register struct arptab *at;
249 register int i;
251 for (ssc = ssq; ssc; ssc = ssc->ss_next) {
252 if (!(atab = ssc->ss_arp.table))
253 continue;
254 /* Lock the table */
255 ARPTAB_LOCK(atab);
257 for (i = 0; i < ARPTAB_HSIZE; i++) {
258 for (at = (struct arptab *)atab->atb_entries[i].mlh_Head;
259 at->at_succ;
260 at = at->at_succ) {
261 if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
262 continue;
263 if (++at->at_timer < ((at->at_flags & ATF_COM) ?
264 ARPT_KILLC : ARPT_KILLI))
265 continue;
266 /* timer has expired, clear entry */
267 arptfree(atab, at);
270 ARPTAB_UNLOCK(atab);
275 * Broadcast an ARP packet, asking who has addr on interface ssc.
277 static void
278 arpwhohas(register struct sana_softc *ssc, struct in_addr *addr)
280 register struct mbuf *m;
281 register struct s2_arppkt *s2a;
282 struct sockaddr_sana2 ss2;
284 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
285 return;
286 m->m_len = sizeof(*s2a);
287 m->m_pkthdr.len = sizeof(*s2a);
288 MH_ALIGN(m, sizeof(*s2a));
289 s2a = mtod(m, struct s2_arppkt *);
290 aligned_bzero_const((caddr_t)s2a, sizeof (*s2a));
291 m->m_flags |= M_BCAST;
293 /* fill in header depending of the interface */
294 s2a->arp_hrd = htons(ssc->ss_arp.hrd);
295 s2a->arp_pro = htons(ssc->ss_ip.type);
296 s2a->arp_pln = sizeof(struct in_addr); /* protocol address length */
297 s2a->arp_hln = ssc->ss_if.if_addrlen; /* hardware address length */
298 s2a->arp_op = htons(ARPOP_REQUEST);
300 /* Copy source hardware address */
301 bcopy((caddr_t)ssc->ss_hwaddr,
302 (caddr_t)&s2a->arpdata,
303 s2a->arp_hln);
304 /* Copy source protocol address */
305 bcopy((caddr_t)&ssc->ss_ipaddr,
306 (caddr_t)&s2a->arpdata + s2a->arp_hln,
307 s2a->arp_pln);
308 /* Zero target hardware address */
309 bzero((caddr_t)&s2a->arpdata + s2a->arp_hln + s2a->arp_pln,
310 s2a->arp_hln);
311 /* Copy target protocol address */
312 bcopy((caddr_t)addr,
313 (caddr_t)&s2a->arpdata + 2 * s2a->arp_hln + s2a->arp_pln,
314 s2a->arp_pln);
316 /* Send an ARP packet */
317 ss2.ss2_len = sizeof(ss2);
318 ss2.ss2_family = AF_UNSPEC;
319 ss2.ss2_type = ssc->ss_arp.type;
320 (*ssc->ss_if.if_output)(&ssc->ss_if, m, (struct sockaddr *)&ss2,
321 (struct rtentry *)0);
325 * Resolve an IP address into an SANA-II address. If success,
326 * desten is filled in. If there is no entry in arptab,
327 * set one up and broadcast a request for the IP address.
328 * Hold onto this mbuf and resend it once the address
329 * is finally resolved. A return value of 1 indicates
330 * that desten has been filled in and the packet should be sent
331 * normally; a 0 return indicates that the packet has been
332 * taken over here, either now or for later transmission.
334 * We do some (conservative) locking here at splimp, since
335 * arptab is also altered from sana poll routine
338 arpresolve(register struct sana_softc *ssc,
339 struct mbuf *m,
340 register struct in_addr *destip,
341 register u_char *desten,
342 int *error)
344 register struct arptab *at;
345 register struct arptable *atb;
346 struct sockaddr_in sin;
347 register struct in_ifaddr *ia;
349 if (m->m_flags & M_BCAST) { /* broadcast */
350 return 1;
353 /* if for us, use software loopback driver if up */
354 for (ia = in_ifaddr; ia; ia = ia->ia_next)
355 if ((ia->ia_ifp == &ssc->ss_if) &&
356 (destip->s_addr == ia->ia_addr.sin_addr.s_addr)) {
358 * This test used to be
359 * if (loif.if_flags & IFF_UP)
360 * It allowed local traffic to be forced
361 * through the hardware by configuring the loopback down.
362 * However, it causes problems during network configuration
363 * for boards that can't receive packets they send.
364 * It is now necessary to clear "useloopback"
365 * to force traffic out to the hardware.
367 if (useloopback) {
368 sin.sin_family = AF_INET;
369 sin.sin_addr = *destip;
370 (void) looutput(&loif, m, (struct sockaddr *)&sin, 0);
372 * The packet has already been sent and freed.
374 return (0);
375 } else {
376 bcopy((caddr_t)ssc->ss_hwaddr, (caddr_t)desten, ssc->ss_if.if_addrlen);
377 return (1);
381 if (ssc->ss_if.if_flags & IFF_NOARP) {
382 /* No arp */
383 __log(LOG_ERR,
384 "arpresolve: can't resolve address for if %s/%ld\n",
385 ssc->ss_if.if_name, ssc->ss_if.if_unit);
386 *error = ENETUNREACH;
387 m_freem(m);
388 return (0);
391 /* Try to locate ARP table */
392 if (!(atb = ssc->ss_arp.table)) {
393 alloc_arptable(ssc, 0);
394 if (!(atb = ssc->ss_arp.table)) {
395 __log(LOG_ERR, "arpresolve: memory exhausted");
396 *error = ENOBUFS;
397 m_free(m);
398 return 0;
402 ARPTAB_LOCK(atb);
403 at = arptab_look(atb, destip->s_addr);
404 if (at == 0) { /* not found */
405 at = arptnew(destip->s_addr, atb, FALSE);
406 if (at) {
407 at->at_hold = m;
408 arpwhohas(ssc, destip);
409 } else {
410 __log(LOG_ERR, "arpresolve: no free entry");
411 *error = ENETUNREACH;
412 m_free(m);
414 ARPTAB_UNLOCK(atb);
415 return 0;
418 at->at_timer = 0; /* restart the timer */
419 if (at->at_flags & ATF_COM) { /* entry IS complete */
420 bcopy((caddr_t)at->at_hwaddr, (caddr_t)desten, ssc->ss_if.if_addrlen);
421 ARPTAB_UNLOCK(atb);
422 return 1;
425 * There is an arptab entry, but no address response yet.
426 * Replace the held mbuf with this latest one.
428 if (at->at_hold)
429 m_freem(at->at_hold);
430 at->at_hold = m;
431 arpwhohas(ssc, destip); /* ask again */
432 ARPTAB_UNLOCK(atb);
433 return 0;
437 * Called from the sana poll routine
438 * when ARP type packet is received.
439 * Common length and type checks are done here,
440 * then the protocol-specific routine is called.
441 * In addition, a sanity check is performed on the sender
442 * protocol address, to catch impersonators.
444 void
445 arpinput(struct sana_softc *ssc,
446 struct mbuf *m,
447 caddr_t srcaddr)
449 register struct arphdr *ar;
450 int proto;
452 if (ssc->ss_if.if_flags & IFF_NOARP)
453 goto out;
454 if (m->m_len < sizeof(struct arphdr))
455 goto out;
456 ar = mtod(m, struct arphdr *);
457 if (ntohs(ar->ar_hrd) != ssc->ss_arp.hrd)
458 goto out;
459 if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
460 goto out;
461 if (ar->ar_hln != ssc->ss_if.if_addrlen)
462 goto out;
464 #ifdef paranoid_arp_mode
465 /* Sanity check */
466 if (bcmp(srcaddr, (UBYTE*)ar + sizeof(*ar), ar->ar_hln)) {
467 __log(LOG_ERR, "An ARP packet sent as %s",
468 sana_sprintf(srcaddr, ar->ar_hln));
469 __log(LOG_ERR, " from address: %s!!\n",
470 sana_sprintf((UBYTE*)ar + sizeof(*ar), ar->ar_hln));
471 goto out;
473 #endif
474 pfil_run_hooks(m, &ssc->ss_if, MIAMIPFBPT_ARP);
475 proto = ntohs(ar->ar_pro);
477 if (proto == ssc->ss_ip.type) {
478 in_arpinput(ssc, m);
479 return;
482 out:
483 m_freem(m);
487 * ARP for Internet protocols on SANA-II interfaces.
488 * Algorithm is that given in RFC 826.
490 static void
491 in_arpinput(register struct sana_softc *ssc,
492 struct mbuf *m)
494 register struct s2_arppkt *s2a;
495 struct sockaddr_in sin;
496 struct in_addr isaddr, itaddr, myaddr;
497 int op;
498 #if 0 /* unused */
499 int completed = 0;
500 #endif
501 caddr_t sha, spa, tha, tpa;
502 size_t len = ssc->ss_if.if_addrlen;
504 s2a = mtod(m, struct s2_arppkt *);
505 op = ntohs(s2a->arp_op);
507 if (s2a->arp_pln != sizeof(struct in_addr))
508 goto out;
510 sha = (caddr_t)&(s2a->arpdata); /* other members must be calculated */
511 bcopy(spa = sha + len, (caddr_t)&isaddr, sizeof (isaddr));
512 tha = spa + sizeof(struct in_addr);
513 bcopy(tpa = tha + len, (caddr_t)&itaddr, sizeof (itaddr));
517 register struct in_ifaddr *ia;
518 struct in_ifaddr *maybe_ia = 0;
520 /* Check for our own ARP packets */
521 for (ia = in_ifaddr; ia; ia = ia->ia_next)
522 if (ia->ia_ifp == &ssc->ss_if) {
523 maybe_ia = ia;
524 if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
525 (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
526 break;
528 if (maybe_ia == 0)
529 goto out;
530 myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
531 if (!bcmp(sha, (caddr_t)ssc->ss_hwaddr, len))
532 goto out; /* it's from me, ignore it. */
534 #ifndef AMITCP
535 if (!bcmp(sha, (caddr_t)etherbroadcastaddr, ac->ac_if.if_addrlen)) {
536 __log(LOG_ERR,
537 "arp: ether address is broadcast for IP address %lx!\n",
538 ntohl(isaddr.s_addr));
539 goto out;
541 #endif
543 /* Check for duplicate IP addresses */
544 if (isaddr.s_addr == myaddr.s_addr) {
545 __log(LOG_ERR,
546 "duplicate IP address %lx!! sent from hardware address: %s\n",
547 ntohl(isaddr.s_addr),
548 sana_sprintf(sha, len));
549 itaddr = myaddr;
550 if (op == ARPOP_REQUEST)
551 goto reply;
552 goto out;
556 struct arptable *atb;
557 register struct arptab *at = NULL; /* same as "merge" flag */
559 /* Try to locate ARP table */
560 if (!(atb = ssc->ss_arp.table)) {
561 goto reply;
564 ARPTAB_LOCK(atb);
565 at = arptab_look(atb, isaddr.s_addr);
567 if (at) {
568 bcopy(sha, (caddr_t)at->at_hwaddr, len);
569 #if o /* unused */
570 if ((at->at_flags & ATF_COM) == 0)
571 completed = 1;
572 #endif
573 at->at_flags |= ATF_COM;
574 if (at->at_hold) {
575 sin.sin_family = AF_INET;
576 sin.sin_addr = isaddr;
577 (*ssc->ss_if.if_output)(&ssc->ss_if, at->at_hold,
578 (struct sockaddr *)&sin, (struct rtentry *)0);
579 at->at_hold = 0;
582 if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
583 /* ensure we have a table entry */
584 if (at = arptnew(isaddr.s_addr, atb, FALSE)) {
585 bcopy(sha, (caddr_t)at->at_hwaddr, len);
586 #if 0 /* unused */
587 completed = 1;
588 #endif
589 at->at_flags |= ATF_COM;
592 ARPTAB_UNLOCK(atb);
595 reply:
597 * Reply if this is an IP request
599 if (op != ARPOP_REQUEST)
600 goto out;
602 if (itaddr.s_addr == myaddr.s_addr) {
603 /* I am the target */
604 bcopy(sha, tha, len);
605 bcopy((caddr_t)ssc->ss_hwaddr, sha, len);
606 } else {
607 /* Answer if we have a public entry */
608 register struct arptab *at;
610 /* Try to locate ARP table */
611 if (!ssc->ss_arp.table)
612 goto out;
614 ARPTAB_LOCK(ssc->ss_arp.table);
615 at = arptab_look(ssc->ss_arp.table, itaddr.s_addr);
616 if (at && (at->at_flags & ATF_PUBL)) {
617 bcopy(sha, tha, len);
618 bcopy(at->at_hwaddr, sha, len);
619 } else {
620 at = NULL;
622 ARPTAB_UNLOCK(ssc->ss_arp.table);
623 if (!at)
624 goto out;
627 struct sockaddr_sana2 ss2;
628 bcopy(spa, tpa, sizeof(struct in_addr));
629 bcopy((caddr_t)&itaddr, spa, sizeof(struct in_addr));
630 s2a->arp_op = htons(ARPOP_REPLY);
632 ss2.ss2_len = sizeof(ss2);
633 ss2.ss2_family = AF_UNSPEC;
634 ss2.ss2_type = ssc->ss_arp.type;
635 bcopy(tha, ss2.ss2_host, len);
637 m->m_flags &= ~(M_BCAST|M_MCAST);
639 pfil_run_hooks(m, &ssc->ss_if, MIAMIPFBPT_ARP);
640 (*ssc->ss_if.if_output)(&ssc->ss_if, m, (struct sockaddr *)&ss2,
641 (struct rtentry *)0);
642 return;
644 out:
645 m_freem(m);
646 return;
650 arpioctl(cmd, data)
651 int cmd;
652 caddr_t data;
654 register struct arpreq *ar = (struct arpreq *)data;
655 register struct arptab *at;
656 register struct sockaddr_in *sin;
657 struct arptable *atb;
658 struct ifaddr *ifa;
659 struct sana_softc *ssc;
660 spl_t s;
662 sin = (struct sockaddr_in *)&ar->arp_pa;
663 sin->sin_len = sizeof(ar->arp_pa);
665 if (ar->arp_pa.sa_family != AF_INET ||
666 ar->arp_ha.sa_family != AF_UNSPEC)
667 return (EAFNOSUPPORT);
669 s = splimp();
670 if ((ifa = ifa_ifwithnet(&ar->arp_pa)) == NULL) {
671 splx(s);
672 return (ENETUNREACH);
675 ssc = (struct sana_softc *)ifa->ifa_ifp;
676 splx(s);
678 /*if (ssc->ss_if.if_type != IFT_SANA || !(atb = ssc->ss_arp.table)) {*/
679 if (ssc->ss_if.if_output != sana_output || !(atb = ssc->ss_arp.table)) {
680 return (EAFNOSUPPORT);
683 ARPTAB_LOCK(atb);
685 if (cmd != SIOCGARPT) {
686 at = arptab_look(atb, sin->sin_addr.s_addr);
687 if (at == NULL && cmd != SIOCSARP) {
688 ARPTAB_UNLOCK(atb);
689 return (ENXIO);
693 switch (cmd) {
695 case SIOCSARP: /* set entry */
696 if (ar->arp_ha.sa_len > sizeof(at->at_hwaddr) + 2 ||
697 ar->arp_ha.sa_len != ssc->ss_if.if_addrlen + 2) {
698 ARPTAB_UNLOCK(atb);
699 return (EINVAL);
702 * Free if new entry should be allocated in a different way
704 if (at != NULL && (at->at_flags ^ ar->arp_flags) & ATF_PERM) {
705 arptfree(atb, at);
706 at = NULL;
708 if (at == NULL) {
709 at = arptnew(sin->sin_addr.s_addr, atb, ar->arp_flags & ATF_PERM);
710 if (at == NULL) {
711 ARPTAB_UNLOCK(atb);
712 return (EADDRNOTAVAIL);
716 bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_hwaddr,
717 ar->arp_ha.sa_len - 2);
718 at->at_flags = ATF_COM | ATF_INUSE |
719 (ar->arp_flags & (ATF_PERM|ATF_PUBL));
720 at->at_timer = 0;
721 break;
723 case SIOCDARP: /* delete entry */
724 arptfree(atb, at);
725 break;
727 case SIOCGARP: /* get entry */
728 bcopy((caddr_t)at->at_hwaddr, (caddr_t)ar->arp_ha.sa_data,
729 ar->arp_ha.sa_len = ssc->ss_if.if_addrlen + 2);
730 ar->arp_flags = at->at_flags;
731 break;
733 case SIOCGARPT: /* get table */
735 int i, n; long siz;
736 register struct arptabreq *atr = (struct arptabreq *)data;
737 ar = atr->atr_table;
738 siz = ar ? atr->atr_size : 0;
740 for (n = i = 0; i < ARPTAB_HSIZE; i++) {
741 for (at = (struct arptab *)atb->atb_entries[i].mlh_Head;
742 at->at_succ;
743 at = at->at_succ) {
744 n++;
745 if (siz > 0) {
746 struct sockaddr_in *sin = (struct sockaddr_in *)&ar->arp_pa;
747 sin->sin_len = sizeof(*sin);
748 sin->sin_family = AF_INET;
749 sin->sin_addr = at->at_iaddr;
750 bcopy((caddr_t)at->at_hwaddr, (caddr_t)ar->arp_ha.sa_data,
751 ar->arp_ha.sa_len = ssc->ss_if.if_addrlen + 2);
752 ar->arp_flags = at->at_flags;
753 siz--;
754 ar++;
758 atr->atr_size -= siz;
759 atr->atr_inuse = n;
763 ARPTAB_UNLOCK(atb);
764 return 0;
767 static const char *digits = "0123456789ABCDEF";
769 * Print Hardware Address
771 static char *sana_sprintf(register u_char *ap, int len)
773 register int i;
774 static char addrbuf[17*3];
775 register unsigned char *cp = addrbuf;
777 for (i = 0; i < len; ) {
778 *cp++ = digits[*ap >> 4];
779 *cp++ = digits[*ap++ & 0xf];
780 i++;
781 if (i < len)
782 *cp++ = ':';
784 *cp = 0;
785 return (addrbuf);