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*32346Skarels * @(#)if_ether.c 7.4 (Berkeley) 10/06/87 723172Smckusick */ 811570Ssam 911570Ssam /* 1011570Ssam * Ethernet address resolution protocol. 11*32346Skarels * TODO: 12*32346Skarels * run at splnet (add ARP protocol intr.) 13*32346Skarels * link entries onto hash chains, keep free list 14*32346Skarels * 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*32346Skarels #ifdef GATEWAY 34*32346Skarels #define ARPTAB_BSIZ 16 /* bucket size */ 35*32346Skarels #define ARPTAB_NB 37 /* number of buckets */ 36*32346Skarels #else 3724803Skarels #define ARPTAB_BSIZ 9 /* bucket size */ 3811570Ssam #define ARPTAB_NB 19 /* number of buckets */ 39*32346Skarels #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 12830300Skarels int useloopback = 1; /* use loopback interface for local traffic */ 12930300Skarels 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*32346Skarels u_long lna; 154*32346Skarels 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*32346Skarels /* 166*32346Skarels * This test used to be 167*32346Skarels * if (loif.if_flags & IFF_UP) 168*32346Skarels * It allowed local traffic to be forced 169*32346Skarels * through the hardware by configuring the loopback down. 170*32346Skarels * However, it causes problems during network configuration 171*32346Skarels * for boards that can't receive packets they send. 172*32346Skarels * It is now necessary to clear "useloopback" 173*32346Skarels * to force traffic out to the hardware. 174*32346Skarels */ 17530300Skarels 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*32346Skarels 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*32346Skarels if (at == 0) 202*32346Skarels 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*32346Skarels int proto, op, s, completed = 0; 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*32346Skarels bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr)); 300*32346Skarels 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 } 32030300Skarels 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)); 325*32346Skarels if ((at->at_flags & ATF_COM) == 0) 326*32346Skarels completed = 1; 32711570Ssam at->at_flags |= ATF_COM; 32811570Ssam if (at->at_hold) { 32911570Ssam sin.sin_family = AF_INET; 33011570Ssam sin.sin_addr = isaddr; 33111570Ssam (*ac->ac_if.if_output)(&ac->ac_if, 33218759Skarels at->at_hold, (struct sockaddr *)&sin); 33318759Skarels at->at_hold = 0; 33411570Ssam } 33518759Skarels } 33618759Skarels if (at == 0 && itaddr.s_addr == myaddr.s_addr) { 33716221Skarels /* ensure we have a table entry */ 338*32346Skarels if (at = arptnew(&isaddr)) { 339*32346Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, 340*32346Skarels sizeof(ea->arp_sha)); 341*32346Skarels completed = 1; 342*32346Skarels at->at_flags |= ATF_COM; 343*32346Skarels } 34411570Ssam } 34530300Skarels splx(s); 34611570Ssam reply: 34725890Skarels switch (proto) { 34825890Skarels 34925890Skarels case ETHERTYPE_IPTRAILERS: 35025890Skarels /* partner says trailers are OK */ 35125890Skarels if (at) 35225890Skarels at->at_flags |= ATF_USETRAILERS; 35325890Skarels /* 35425890Skarels * Reply to request iff we want trailers. 35525890Skarels */ 35625890Skarels if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS) 35725890Skarels goto out; 35825890Skarels break; 35925890Skarels 36025890Skarels case ETHERTYPE_IP: 36125890Skarels /* 362*32346Skarels * Reply if this is an IP request, 363*32346Skarels * or if we want to send a trailer response. 364*32346Skarels * Send the latter only to the IP response 365*32346Skarels * that completes the current ARP entry. 36625890Skarels */ 367*32346Skarels if (op != ARPOP_REQUEST && 368*32346Skarels (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS)) 36925890Skarels goto out; 37025890Skarels } 37125890Skarels if (itaddr.s_addr == myaddr.s_addr) { 37225890Skarels /* I am the target */ 37325890Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, 37425890Skarels sizeof(ea->arp_sha)); 37525890Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, 37625890Skarels sizeof(ea->arp_sha)); 37725890Skarels } else { 37825890Skarels ARPTAB_LOOK(at, itaddr.s_addr); 37925890Skarels if (at == NULL || (at->at_flags & ATF_PUBL) == 0) 38025890Skarels goto out; 38125890Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, 38225890Skarels sizeof(ea->arp_sha)); 38325890Skarels bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha, 38425890Skarels sizeof(ea->arp_sha)); 38525890Skarels } 38625890Skarels 38718640Skarels bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, 38818640Skarels sizeof(ea->arp_spa)); 38918640Skarels bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa, 39018640Skarels sizeof(ea->arp_spa)); 39125890Skarels ea->arp_op = htons(ARPOP_REPLY); 39225890Skarels /* 39325890Skarels * If incoming packet was an IP reply, 39425890Skarels * we are sending a reply for type IPTRAILERS. 39525890Skarels * If we are sending a reply for type IP 39625890Skarels * and we want to receive trailers, 39725890Skarels * send a trailer reply as well. 39825890Skarels */ 39925890Skarels if (op == ARPOP_REPLY) 40025890Skarels ea->arp_pro = htons(ETHERTYPE_IPTRAILERS); 40125890Skarels else if (proto == ETHERTYPE_IP && 40225890Skarels (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0) 40326453Skarels mcopy = m_copy(m, 0, (int)M_COPYALL); 40411570Ssam eh = (struct ether_header *)sa.sa_data; 40518640Skarels bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost, 40618640Skarels sizeof(eh->ether_dhost)); 40718378Skarels eh->ether_type = ETHERTYPE_ARP; 40811570Ssam sa.sa_family = AF_UNSPEC; 40911570Ssam (*ac->ac_if.if_output)(&ac->ac_if, m, &sa); 41025890Skarels if (mcopy) { 41125890Skarels ea = mtod(mcopy, struct ether_arp *); 41225890Skarels ea->arp_pro = htons(ETHERTYPE_IPTRAILERS); 41325890Skarels (*ac->ac_if.if_output)(&ac->ac_if, mcopy, &sa); 41425890Skarels } 41511570Ssam return; 41611570Ssam out: 41711570Ssam m_freem(m); 41811570Ssam return; 41911570Ssam } 42011570Ssam 42111570Ssam /* 42211570Ssam * Free an arptab entry. 42311570Ssam */ 42411570Ssam arptfree(at) 42511570Ssam register struct arptab *at; 42611570Ssam { 42711570Ssam int s = splimp(); 42811570Ssam 42911570Ssam if (at->at_hold) 43011570Ssam m_freem(at->at_hold); 43111570Ssam at->at_hold = 0; 43211570Ssam at->at_timer = at->at_flags = 0; 43311570Ssam at->at_iaddr.s_addr = 0; 43411570Ssam splx(s); 43511570Ssam } 43611570Ssam 43711570Ssam /* 43811570Ssam * Enter a new address in arptab, pushing out the oldest entry 43911570Ssam * from the bucket if there is no room. 44016221Skarels * This always succeeds since no bucket can be completely filled 44116221Skarels * with permanent entries (except from arpioctl when testing whether 44218640Skarels * another permanent entry will fit). 443*32346Skarels * MUST BE CALLED AT SPLIMP. 44411570Ssam */ 44511570Ssam struct arptab * 44611570Ssam arptnew(addr) 44711570Ssam struct in_addr *addr; 44811570Ssam { 44911570Ssam register n; 45024803Skarels int oldest = -1; 45116221Skarels register struct arptab *at, *ato = NULL; 45216221Skarels static int first = 1; 45311570Ssam 45416221Skarels if (first) { 45516221Skarels first = 0; 45616221Skarels timeout(arptimer, (caddr_t)0, hz); 45716221Skarels } 45816221Skarels at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ]; 45918640Skarels for (n = 0; n < ARPTAB_BSIZ; n++,at++) { 46011570Ssam if (at->at_flags == 0) 46111570Ssam goto out; /* found an empty entry */ 46216221Skarels if (at->at_flags & ATF_PERM) 46316221Skarels continue; 464*32346Skarels if ((int) at->at_timer > oldest) { 46511570Ssam oldest = at->at_timer; 46611570Ssam ato = at; 46711570Ssam } 46811570Ssam } 46916221Skarels if (ato == NULL) 47018640Skarels return (NULL); 47111570Ssam at = ato; 47211570Ssam arptfree(at); 47311570Ssam out: 47411570Ssam at->at_iaddr = *addr; 47511570Ssam at->at_flags = ATF_INUSE; 47611570Ssam return (at); 47711570Ssam } 47816221Skarels 47916221Skarels arpioctl(cmd, data) 48016221Skarels int cmd; 48116221Skarels caddr_t data; 48216221Skarels { 48316221Skarels register struct arpreq *ar = (struct arpreq *)data; 48416221Skarels register struct arptab *at; 48516221Skarels register struct sockaddr_in *sin; 48616221Skarels int s; 48716221Skarels 48816221Skarels if (ar->arp_pa.sa_family != AF_INET || 48916221Skarels ar->arp_ha.sa_family != AF_UNSPEC) 49016221Skarels return (EAFNOSUPPORT); 49116221Skarels sin = (struct sockaddr_in *)&ar->arp_pa; 49216221Skarels s = splimp(); 49316221Skarels ARPTAB_LOOK(at, sin->sin_addr.s_addr); 49416221Skarels if (at == NULL) { /* not found */ 49516221Skarels if (cmd != SIOCSARP) { 49616221Skarels splx(s); 49716221Skarels return (ENXIO); 49816221Skarels } 49918378Skarels if (ifa_ifwithnet(&ar->arp_pa) == NULL) { 50016221Skarels splx(s); 50116221Skarels return (ENETUNREACH); 50216221Skarels } 50316221Skarels } 50416221Skarels switch (cmd) { 50516221Skarels 50616221Skarels case SIOCSARP: /* set entry */ 50716221Skarels if (at == NULL) { 50816221Skarels at = arptnew(&sin->sin_addr); 509*32346Skarels if (at == NULL) { 510*32346Skarels splx(s); 511*32346Skarels return (EADDRNOTAVAIL); 512*32346Skarels } 51316221Skarels if (ar->arp_flags & ATF_PERM) { 51416221Skarels /* never make all entries in a bucket permanent */ 51516221Skarels register struct arptab *tat; 51616221Skarels 51716221Skarels /* try to re-allocate */ 51816221Skarels tat = arptnew(&sin->sin_addr); 51916221Skarels if (tat == NULL) { 52016221Skarels arptfree(at); 52116221Skarels splx(s); 52216221Skarels return (EADDRNOTAVAIL); 52316221Skarels } 52416221Skarels arptfree(tat); 52516221Skarels } 52616221Skarels } 52718640Skarels bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr, 52818640Skarels sizeof(at->at_enaddr)); 52916221Skarels at->at_flags = ATF_COM | ATF_INUSE | 53016221Skarels (ar->arp_flags & (ATF_PERM|ATF_PUBL)); 53116221Skarels at->at_timer = 0; 53216221Skarels break; 53316221Skarels 53416221Skarels case SIOCDARP: /* delete entry */ 53516221Skarels arptfree(at); 53616221Skarels break; 53716221Skarels 53816221Skarels case SIOCGARP: /* get entry */ 53918640Skarels bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data, 54018640Skarels sizeof(at->at_enaddr)); 54116221Skarels ar->arp_flags = at->at_flags; 54216221Skarels break; 54316221Skarels } 54416221Skarels splx(s); 54516221Skarels return (0); 54616221Skarels } 54725890Skarels 54825890Skarels /* 54925890Skarels * Convert Ethernet address to printable (loggable) representation. 55025890Skarels */ 55125890Skarels char * 55225890Skarels ether_sprintf(ap) 55325890Skarels register u_char *ap; 55425890Skarels { 55525890Skarels register i; 55625890Skarels static char etherbuf[18]; 55725890Skarels register char *cp = etherbuf; 55825890Skarels static char digits[] = "0123456789abcdef"; 55925890Skarels 56025890Skarels for (i = 0; i < 6; i++) { 56125890Skarels *cp++ = digits[*ap >> 4]; 56225890Skarels *cp++ = digits[*ap++ & 0xf]; 56325890Skarels *cp++ = ':'; 56425890Skarels } 56525890Skarels *--cp = 0; 56625890Skarels return (etherbuf); 56725890Skarels } 568