123172Smckusick /* 229134Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323172Smckusick * All rights reserved. The Berkeley software License Agreement 423172Smckusick * specifies the terms and conditions for redistribution. 523172Smckusick * 6*30300Skarels * @(#)if_ether.c 7.2 (Berkeley) 12/16/86 723172Smckusick */ 811570Ssam 911570Ssam /* 1011570Ssam * Ethernet address resolution protocol. 11*30300Skarels * TODO: 12*30300Skarels * run at splnet (add ARP protocol intr.) 13*30300Skarels * link entries onto hash chains, keep free list 14*30300Skarels * add "inuse/lock" bit (or ref. count) along with valid bit 1511570Ssam */ 1611570Ssam 1717057Sbloom #include "param.h" 1817057Sbloom #include "systm.h" 1917057Sbloom #include "mbuf.h" 2017057Sbloom #include "socket.h" 2117057Sbloom #include "time.h" 2217057Sbloom #include "kernel.h" 2317057Sbloom #include "errno.h" 2417057Sbloom #include "ioctl.h" 2525890Skarels #include "syslog.h" 2611570Ssam 2711570Ssam #include "../net/if.h" 2817057Sbloom #include "in.h" 2917057Sbloom #include "in_systm.h" 3017057Sbloom #include "ip.h" 3117057Sbloom #include "if_ether.h" 3211570Ssam 33*30300Skarels #ifdef GATEWAY 34*30300Skarels #define ARPTAB_BSIZ 16 /* bucket size */ 35*30300Skarels #define ARPTAB_NB 37 /* number of buckets */ 36*30300Skarels #else 3724803Skarels #define ARPTAB_BSIZ 9 /* bucket size */ 3811570Ssam #define ARPTAB_NB 19 /* number of buckets */ 39*30300Skarels #endif 4011570Ssam #define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB) 4111570Ssam struct arptab arptab[ARPTAB_SIZE]; 4216221Skarels int arptab_size = ARPTAB_SIZE; /* for arp command */ 4311570Ssam 4425890Skarels /* 4525890Skarels * ARP trailer negotiation. Trailer protocol is not IP specific, 4625890Skarels * but ARP request/response use IP addresses. 4725890Skarels */ 4825890Skarels #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL 4925890Skarels 5011570Ssam #define ARPTAB_HASH(a) \ 5125890Skarels ((u_long)(a) % ARPTAB_NB) 5211570Ssam 5311570Ssam #define ARPTAB_LOOK(at,addr) { \ 5411570Ssam register n; \ 5511570Ssam at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \ 5611570Ssam for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \ 5711570Ssam if (at->at_iaddr.s_addr == addr) \ 5811570Ssam break; \ 5911570Ssam if (n >= ARPTAB_BSIZ) \ 6025890Skarels at = 0; \ 6125890Skarels } 6211570Ssam 6311570Ssam /* timer values */ 6411570Ssam #define ARPT_AGE (60*1) /* aging timer, 1 min. */ 6511570Ssam #define ARPT_KILLC 20 /* kill completed entry in 20 mins. */ 6611570Ssam #define ARPT_KILLI 3 /* kill incomplete entry in 3 minutes */ 6711570Ssam 6818640Skarels u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 6911570Ssam extern struct ifnet loif; 7011570Ssam 7114867Ssam /* 7211570Ssam * Timeout routine. Age arp_tab entries once a minute. 7311570Ssam */ 7411570Ssam arptimer() 7511570Ssam { 7611570Ssam register struct arptab *at; 7711570Ssam register i; 7811570Ssam 7925890Skarels timeout(arptimer, (caddr_t)0, ARPT_AGE * hz); 8025890Skarels at = &arptab[0]; 8125890Skarels for (i = 0; i < ARPTAB_SIZE; i++, at++) { 8225890Skarels if (at->at_flags == 0 || (at->at_flags & ATF_PERM)) 8325890Skarels continue; 8425890Skarels if (++at->at_timer < ((at->at_flags&ATF_COM) ? 8525890Skarels ARPT_KILLC : ARPT_KILLI)) 8625890Skarels continue; 8725890Skarels /* timer has expired, clear entry */ 8825890Skarels arptfree(at); 8911570Ssam } 9011570Ssam } 9111570Ssam 9211570Ssam /* 9311570Ssam * Broadcast an ARP packet, asking who has addr on interface ac. 9411570Ssam */ 9511570Ssam arpwhohas(ac, addr) 9611570Ssam register struct arpcom *ac; 9711570Ssam struct in_addr *addr; 9811570Ssam { 9911570Ssam register struct mbuf *m; 10011570Ssam register struct ether_header *eh; 10111570Ssam register struct ether_arp *ea; 10211570Ssam struct sockaddr sa; 10311570Ssam 10411570Ssam if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) 10526380Skarels return; 10615718Skarels m->m_len = sizeof *ea; 10711570Ssam m->m_off = MMAXOFF - m->m_len; 10811570Ssam ea = mtod(m, struct ether_arp *); 10911570Ssam eh = (struct ether_header *)sa.sa_data; 11012763Ssam bzero((caddr_t)ea, sizeof (*ea)); 11118640Skarels bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, 11218640Skarels sizeof(eh->ether_dhost)); 11318378Skarels eh->ether_type = ETHERTYPE_ARP; /* if_output will swap */ 11411570Ssam ea->arp_hrd = htons(ARPHRD_ETHER); 11518378Skarels ea->arp_pro = htons(ETHERTYPE_IP); 11618640Skarels ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */ 11718640Skarels ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */ 11811570Ssam ea->arp_op = htons(ARPOP_REQUEST); 11918640Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, 12018640Skarels sizeof(ea->arp_sha)); 12118640Skarels bcopy((caddr_t)&ac->ac_ipaddr, (caddr_t)ea->arp_spa, 12218640Skarels sizeof(ea->arp_spa)); 12318640Skarels bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa)); 12411570Ssam sa.sa_family = AF_UNSPEC; 12526380Skarels (*ac->ac_if.if_output)(&ac->ac_if, m, &sa); 12611570Ssam } 12711570Ssam 128*30300Skarels int useloopback = 1; /* use loopback interface for local traffic */ 129*30300Skarels 13011570Ssam /* 13111570Ssam * Resolve an IP address into an ethernet address. If success, 13225890Skarels * desten is filled in. If there is no entry in arptab, 13325890Skarels * set one up and broadcast a request for the IP address. 13425890Skarels * Hold onto this mbuf and resend it once the address 13525890Skarels * is finally resolved. A return value of 1 indicates 13625890Skarels * that desten has been filled in and the packet should be sent 13725890Skarels * normally; a 0 return indicates that the packet has been 13825890Skarels * taken over here, either now or for later transmission. 13911570Ssam * 14011570Ssam * We do some (conservative) locking here at splimp, since 14111570Ssam * arptab is also altered from input interrupt service (ecintr/ilintr 14218378Skarels * calls arpinput when ETHERTYPE_ARP packets come in). 14311570Ssam */ 14425890Skarels arpresolve(ac, m, destip, desten, usetrailers) 14511570Ssam register struct arpcom *ac; 14611570Ssam struct mbuf *m; 14711570Ssam register struct in_addr *destip; 14818640Skarels register u_char *desten; 14925890Skarels int *usetrailers; 15011570Ssam { 15111570Ssam register struct arptab *at; 15211570Ssam struct sockaddr_in sin; 153*30300Skarels u_long lna; 154*30300Skarels int s; 15511570Ssam 15625890Skarels *usetrailers = 0; 15718378Skarels if (in_broadcast(*destip)) { /* broadcast address */ 15818640Skarels bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten, 15918640Skarels sizeof(etherbroadcastaddr)); 16011570Ssam return (1); 16111570Ssam } 16218378Skarels lna = in_lnaof(*destip); 16326223Skarels /* if for us, use software loopback driver if up */ 16426223Skarels if (destip->s_addr == ac->ac_ipaddr.s_addr) { 165*30300Skarels /* 166*30300Skarels * This test used to be 167*30300Skarels * if (loif.if_flags & IFF_UP) 168*30300Skarels * It allowed local traffic to be forced 169*30300Skarels * through the hardware by configuring the loopback down. 170*30300Skarels * However, it causes problems during network configuration 171*30300Skarels * for boards that can't receive packets they send. 172*30300Skarels * It is now necessary to clear "useloopback" 173*30300Skarels * to force traffic out to the hardware. 174*30300Skarels */ 175*30300Skarels if (useloopback) { 17626223Skarels sin.sin_family = AF_INET; 17726223Skarels sin.sin_addr = *destip; 17826223Skarels (void) looutput(&loif, m, (struct sockaddr *)&sin); 17926223Skarels /* 18026223Skarels * The packet has already been sent and freed. 18126223Skarels */ 18226223Skarels return (0); 18326223Skarels } else { 18426223Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 18526223Skarels sizeof(ac->ac_enaddr)); 18626223Skarels return (1); 18726223Skarels } 18811570Ssam } 18911570Ssam s = splimp(); 19011570Ssam ARPTAB_LOOK(at, destip->s_addr); 19111570Ssam if (at == 0) { /* not found */ 192*30300Skarels if (ac->ac_if.if_flags & IFF_NOARP) { 19318640Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3); 19418640Skarels desten[3] = (lna >> 16) & 0x7f; 19518640Skarels desten[4] = (lna >> 8) & 0xff; 19618640Skarels desten[5] = lna & 0xff; 19716221Skarels splx(s); 19816221Skarels return (1); 19916221Skarels } else { 20016221Skarels at = arptnew(destip); 201*30300Skarels if (at == 0) 202*30300Skarels panic("arpresolve: no free entry"); 20316221Skarels at->at_hold = m; 20416221Skarels arpwhohas(ac, destip); 20516221Skarels splx(s); 20616221Skarels return (0); 20716221Skarels } 20811570Ssam } 20911570Ssam at->at_timer = 0; /* restart the timer */ 21011570Ssam if (at->at_flags & ATF_COM) { /* entry IS complete */ 21118640Skarels bcopy((caddr_t)at->at_enaddr, (caddr_t)desten, 21218640Skarels sizeof(at->at_enaddr)); 21325890Skarels if (at->at_flags & ATF_USETRAILERS) 21425890Skarels *usetrailers = 1; 21511570Ssam splx(s); 21611570Ssam return (1); 21711570Ssam } 21811570Ssam /* 21911570Ssam * There is an arptab entry, but no ethernet address 22011570Ssam * response yet. Replace the held mbuf with this 22111570Ssam * latest one. 22211570Ssam */ 22311570Ssam if (at->at_hold) 22411570Ssam m_freem(at->at_hold); 22511570Ssam at->at_hold = m; 22611570Ssam arpwhohas(ac, destip); /* ask again */ 22711570Ssam splx(s); 22811570Ssam return (0); 22911570Ssam } 23011570Ssam 23111570Ssam /* 23218378Skarels * Called from 10 Mb/s Ethernet interrupt handlers 23318378Skarels * when ether packet type ETHERTYPE_ARP 23425890Skarels * is received. Common length and type checks are done here, 23525890Skarels * then the protocol-specific routine is called. 23625890Skarels */ 23725890Skarels arpinput(ac, m) 23825890Skarels struct arpcom *ac; 23925890Skarels struct mbuf *m; 24025890Skarels { 24125890Skarels register struct arphdr *ar; 24225890Skarels 24325890Skarels if (ac->ac_if.if_flags & IFF_NOARP) 24425890Skarels goto out; 24525890Skarels IF_ADJ(m); 24625890Skarels if (m->m_len < sizeof(struct arphdr)) 24725890Skarels goto out; 24825890Skarels ar = mtod(m, struct arphdr *); 24925890Skarels if (ntohs(ar->ar_hrd) != ARPHRD_ETHER) 25025890Skarels goto out; 25125890Skarels if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) 25225890Skarels goto out; 25325890Skarels 25425890Skarels switch (ntohs(ar->ar_pro)) { 25525890Skarels 25625890Skarels case ETHERTYPE_IP: 25725890Skarels case ETHERTYPE_IPTRAILERS: 25825890Skarels in_arpinput(ac, m); 25925890Skarels return; 26025890Skarels 26125890Skarels default: 26225890Skarels break; 26325890Skarels } 26425890Skarels out: 26525890Skarels m_freem(m); 26625890Skarels } 26725890Skarels 26825890Skarels /* 26925890Skarels * ARP for Internet protocols on 10 Mb/s Ethernet. 27025890Skarels * Algorithm is that given in RFC 826. 27111570Ssam * In addition, a sanity check is performed on the sender 27211570Ssam * protocol address, to catch impersonators. 27325890Skarels * We also handle negotiations for use of trailer protocol: 27425890Skarels * ARP replies for protocol type ETHERTYPE_TRAIL are sent 27525890Skarels * along with IP replies if we want trailers sent to us, 27625890Skarels * and also send them in response to IP replies. 27725890Skarels * This allows either end to announce the desire to receive 27825890Skarels * trailer packets. 27925890Skarels * We reply to requests for ETHERTYPE_TRAIL protocol as well, 28025890Skarels * but don't normally send requests. 28111570Ssam */ 28225890Skarels in_arpinput(ac, m) 28311570Ssam register struct arpcom *ac; 28411570Ssam struct mbuf *m; 28511570Ssam { 28611570Ssam register struct ether_arp *ea; 28711570Ssam struct ether_header *eh; 28824803Skarels register struct arptab *at; /* same as "merge" flag */ 28925890Skarels struct mbuf *mcopy = 0; 29011570Ssam struct sockaddr_in sin; 29111570Ssam struct sockaddr sa; 29225890Skarels struct in_addr isaddr, itaddr, myaddr; 293*30300Skarels int proto, op, s; 29411570Ssam 29518378Skarels myaddr = ac->ac_ipaddr; 29611570Ssam ea = mtod(m, struct ether_arp *); 29725890Skarels proto = ntohs(ea->arp_pro); 29825890Skarels op = ntohs(ea->arp_op); 299*30300Skarels bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr)); 300*30300Skarels bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr)); 30118640Skarels if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr, 30218640Skarels sizeof (ea->arp_sha))) 30311570Ssam goto out; /* it's from me, ignore it. */ 30425890Skarels if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr, 30525890Skarels sizeof (ea->arp_sha))) { 30625890Skarels log(LOG_ERR, 30725890Skarels "arp: ether address is broadcast for IP address %x!\n", 30825890Skarels ntohl(isaddr.s_addr)); 30925890Skarels goto out; 31025890Skarels } 31111570Ssam if (isaddr.s_addr == myaddr.s_addr) { 31225890Skarels log(LOG_ERR, "%s: %s\n", 31325890Skarels "duplicate IP address!! sent from ethernet address", 31425890Skarels ether_sprintf(ea->arp_sha)); 31516221Skarels itaddr = myaddr; 31625890Skarels if (op == ARPOP_REQUEST) 31711570Ssam goto reply; 31811570Ssam goto out; 31911570Ssam } 320*30300Skarels s = splimp(); 32111570Ssam ARPTAB_LOOK(at, isaddr.s_addr); 32226147Skarels if (at) { 32318640Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, 32418640Skarels sizeof(ea->arp_sha)); 32511570Ssam at->at_flags |= ATF_COM; 32611570Ssam if (at->at_hold) { 32711570Ssam sin.sin_family = AF_INET; 32811570Ssam sin.sin_addr = isaddr; 32911570Ssam (*ac->ac_if.if_output)(&ac->ac_if, 33018759Skarels at->at_hold, (struct sockaddr *)&sin); 33118759Skarels at->at_hold = 0; 33211570Ssam } 33318759Skarels } 33418759Skarels if (at == 0 && itaddr.s_addr == myaddr.s_addr) { 33516221Skarels /* ensure we have a table entry */ 33611570Ssam at = arptnew(&isaddr); 33718640Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, 33818640Skarels sizeof(ea->arp_sha)); 33911570Ssam at->at_flags |= ATF_COM; 34011570Ssam } 341*30300Skarels splx(s); 34211570Ssam reply: 34325890Skarels switch (proto) { 34425890Skarels 34525890Skarels case ETHERTYPE_IPTRAILERS: 34625890Skarels /* partner says trailers are OK */ 34725890Skarels if (at) 34825890Skarels at->at_flags |= ATF_USETRAILERS; 34925890Skarels /* 35025890Skarels * Reply to request iff we want trailers. 35125890Skarels */ 35225890Skarels if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS) 35325890Skarels goto out; 35425890Skarels break; 35525890Skarels 35625890Skarels case ETHERTYPE_IP: 35725890Skarels /* 35825890Skarels * Reply if this is an IP request, or if we want to send 35925890Skarels * a trailer response. 36025890Skarels */ 36125890Skarels if (op != ARPOP_REQUEST && ac->ac_if.if_flags & IFF_NOTRAILERS) 36225890Skarels goto out; 36325890Skarels } 36425890Skarels if (itaddr.s_addr == myaddr.s_addr) { 36525890Skarels /* I am the target */ 36625890Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, 36725890Skarels sizeof(ea->arp_sha)); 36825890Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, 36925890Skarels sizeof(ea->arp_sha)); 37025890Skarels } else { 37125890Skarels ARPTAB_LOOK(at, itaddr.s_addr); 37225890Skarels if (at == NULL || (at->at_flags & ATF_PUBL) == 0) 37325890Skarels goto out; 37425890Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, 37525890Skarels sizeof(ea->arp_sha)); 37625890Skarels bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha, 37725890Skarels sizeof(ea->arp_sha)); 37825890Skarels } 37925890Skarels 38018640Skarels bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, 38118640Skarels sizeof(ea->arp_spa)); 38218640Skarels bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa, 38318640Skarels sizeof(ea->arp_spa)); 38425890Skarels ea->arp_op = htons(ARPOP_REPLY); 38525890Skarels /* 38625890Skarels * If incoming packet was an IP reply, 38725890Skarels * we are sending a reply for type IPTRAILERS. 38825890Skarels * If we are sending a reply for type IP 38925890Skarels * and we want to receive trailers, 39025890Skarels * send a trailer reply as well. 39125890Skarels */ 39225890Skarels if (op == ARPOP_REPLY) 39325890Skarels ea->arp_pro = htons(ETHERTYPE_IPTRAILERS); 39425890Skarels else if (proto == ETHERTYPE_IP && 39525890Skarels (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0) 39626453Skarels mcopy = m_copy(m, 0, (int)M_COPYALL); 39711570Ssam eh = (struct ether_header *)sa.sa_data; 39818640Skarels bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost, 39918640Skarels sizeof(eh->ether_dhost)); 40018378Skarels eh->ether_type = ETHERTYPE_ARP; 40111570Ssam sa.sa_family = AF_UNSPEC; 40211570Ssam (*ac->ac_if.if_output)(&ac->ac_if, m, &sa); 40325890Skarels if (mcopy) { 40425890Skarels ea = mtod(mcopy, struct ether_arp *); 40525890Skarels ea->arp_pro = htons(ETHERTYPE_IPTRAILERS); 40625890Skarels (*ac->ac_if.if_output)(&ac->ac_if, mcopy, &sa); 40725890Skarels } 40811570Ssam return; 40911570Ssam out: 41011570Ssam m_freem(m); 41111570Ssam return; 41211570Ssam } 41311570Ssam 41411570Ssam /* 41511570Ssam * Free an arptab entry. 41611570Ssam */ 41711570Ssam arptfree(at) 41811570Ssam register struct arptab *at; 41911570Ssam { 42011570Ssam int s = splimp(); 42111570Ssam 42211570Ssam if (at->at_hold) 42311570Ssam m_freem(at->at_hold); 42411570Ssam at->at_hold = 0; 42511570Ssam at->at_timer = at->at_flags = 0; 42611570Ssam at->at_iaddr.s_addr = 0; 42711570Ssam splx(s); 42811570Ssam } 42911570Ssam 43011570Ssam /* 43111570Ssam * Enter a new address in arptab, pushing out the oldest entry 43211570Ssam * from the bucket if there is no room. 43316221Skarels * This always succeeds since no bucket can be completely filled 43416221Skarels * with permanent entries (except from arpioctl when testing whether 43518640Skarels * another permanent entry will fit). 436*30300Skarels * MUST BE CALLED AT SPLIMP. 43711570Ssam */ 43811570Ssam struct arptab * 43911570Ssam arptnew(addr) 44011570Ssam struct in_addr *addr; 44111570Ssam { 44211570Ssam register n; 44324803Skarels int oldest = -1; 44416221Skarels register struct arptab *at, *ato = NULL; 44516221Skarels static int first = 1; 44611570Ssam 44716221Skarels if (first) { 44816221Skarels first = 0; 44916221Skarels timeout(arptimer, (caddr_t)0, hz); 45016221Skarels } 45116221Skarels at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ]; 45218640Skarels for (n = 0; n < ARPTAB_BSIZ; n++,at++) { 45311570Ssam if (at->at_flags == 0) 45411570Ssam goto out; /* found an empty entry */ 45516221Skarels if (at->at_flags & ATF_PERM) 45616221Skarels continue; 45711570Ssam if (at->at_timer > oldest) { 45811570Ssam oldest = at->at_timer; 45911570Ssam ato = at; 46011570Ssam } 46111570Ssam } 46216221Skarels if (ato == NULL) 46318640Skarels return (NULL); 46411570Ssam at = ato; 46511570Ssam arptfree(at); 46611570Ssam out: 46711570Ssam at->at_iaddr = *addr; 46811570Ssam at->at_flags = ATF_INUSE; 46911570Ssam return (at); 47011570Ssam } 47116221Skarels 47216221Skarels arpioctl(cmd, data) 47316221Skarels int cmd; 47416221Skarels caddr_t data; 47516221Skarels { 47616221Skarels register struct arpreq *ar = (struct arpreq *)data; 47716221Skarels register struct arptab *at; 47816221Skarels register struct sockaddr_in *sin; 47916221Skarels int s; 48016221Skarels 48116221Skarels if (ar->arp_pa.sa_family != AF_INET || 48216221Skarels ar->arp_ha.sa_family != AF_UNSPEC) 48316221Skarels return (EAFNOSUPPORT); 48416221Skarels sin = (struct sockaddr_in *)&ar->arp_pa; 48516221Skarels s = splimp(); 48616221Skarels ARPTAB_LOOK(at, sin->sin_addr.s_addr); 48716221Skarels if (at == NULL) { /* not found */ 48816221Skarels if (cmd != SIOCSARP) { 48916221Skarels splx(s); 49016221Skarels return (ENXIO); 49116221Skarels } 49218378Skarels if (ifa_ifwithnet(&ar->arp_pa) == NULL) { 49316221Skarels splx(s); 49416221Skarels return (ENETUNREACH); 49516221Skarels } 49616221Skarels } 49716221Skarels switch (cmd) { 49816221Skarels 49916221Skarels case SIOCSARP: /* set entry */ 50016221Skarels if (at == NULL) { 50116221Skarels at = arptnew(&sin->sin_addr); 50216221Skarels if (ar->arp_flags & ATF_PERM) { 50316221Skarels /* never make all entries in a bucket permanent */ 50416221Skarels register struct arptab *tat; 50516221Skarels 50616221Skarels /* try to re-allocate */ 50716221Skarels tat = arptnew(&sin->sin_addr); 50816221Skarels if (tat == NULL) { 50916221Skarels arptfree(at); 51016221Skarels splx(s); 51116221Skarels return (EADDRNOTAVAIL); 51216221Skarels } 51316221Skarels arptfree(tat); 51416221Skarels } 51516221Skarels } 51618640Skarels bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr, 51718640Skarels sizeof(at->at_enaddr)); 51816221Skarels at->at_flags = ATF_COM | ATF_INUSE | 51916221Skarels (ar->arp_flags & (ATF_PERM|ATF_PUBL)); 52016221Skarels at->at_timer = 0; 52116221Skarels break; 52216221Skarels 52316221Skarels case SIOCDARP: /* delete entry */ 52416221Skarels arptfree(at); 52516221Skarels break; 52616221Skarels 52716221Skarels case SIOCGARP: /* get entry */ 52818640Skarels bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data, 52918640Skarels sizeof(at->at_enaddr)); 53016221Skarels ar->arp_flags = at->at_flags; 53116221Skarels break; 53216221Skarels } 53316221Skarels splx(s); 53416221Skarels return (0); 53516221Skarels } 53625890Skarels 53725890Skarels /* 53825890Skarels * Convert Ethernet address to printable (loggable) representation. 53925890Skarels */ 54025890Skarels char * 54125890Skarels ether_sprintf(ap) 54225890Skarels register u_char *ap; 54325890Skarels { 54425890Skarels register i; 54525890Skarels static char etherbuf[18]; 54625890Skarels register char *cp = etherbuf; 54725890Skarels static char digits[] = "0123456789abcdef"; 54825890Skarels 54925890Skarels for (i = 0; i < 6; i++) { 55025890Skarels *cp++ = digits[*ap >> 4]; 55125890Skarels *cp++ = digits[*ap++ & 0xf]; 55225890Skarels *cp++ = ':'; 55325890Skarels } 55425890Skarels *--cp = 0; 55525890Skarels return (etherbuf); 55625890Skarels } 557