123172Smckusick /* 235794Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 332787Sbostic * All rights reserved. 423172Smckusick * 5*44471Sbostic * %sccs.include.redist.c% 632787Sbostic * 7*44471Sbostic * @(#)if_ether.c 7.12 (Berkeley) 06/28/90 823172Smckusick */ 911570Ssam 1011570Ssam /* 1111570Ssam * Ethernet address resolution protocol. 1232346Skarels * TODO: 1332346Skarels * run at splnet (add ARP protocol intr.) 1432346Skarels * link entries onto hash chains, keep free list 1532346Skarels * add "inuse/lock" bit (or ref. count) along with valid bit 1611570Ssam */ 1711570Ssam 1817057Sbloom #include "param.h" 1917057Sbloom #include "systm.h" 2035794Skarels #include "malloc.h" 2117057Sbloom #include "mbuf.h" 2217057Sbloom #include "socket.h" 2317057Sbloom #include "time.h" 2417057Sbloom #include "kernel.h" 2517057Sbloom #include "errno.h" 2617057Sbloom #include "ioctl.h" 2725890Skarels #include "syslog.h" 2811570Ssam 2911570Ssam #include "../net/if.h" 3017057Sbloom #include "in.h" 3117057Sbloom #include "in_systm.h" 3237471Ssklower #include "in_var.h" 3317057Sbloom #include "ip.h" 3417057Sbloom #include "if_ether.h" 3511570Ssam 3632346Skarels #ifdef GATEWAY 3732346Skarels #define ARPTAB_BSIZ 16 /* bucket size */ 3832346Skarels #define ARPTAB_NB 37 /* number of buckets */ 3932346Skarels #else 4024803Skarels #define ARPTAB_BSIZ 9 /* bucket size */ 4111570Ssam #define ARPTAB_NB 19 /* number of buckets */ 4232346Skarels #endif 4311570Ssam #define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB) 4411570Ssam struct arptab arptab[ARPTAB_SIZE]; 4516221Skarels int arptab_size = ARPTAB_SIZE; /* for arp command */ 4611570Ssam 4725890Skarels /* 4825890Skarels * ARP trailer negotiation. Trailer protocol is not IP specific, 4925890Skarels * but ARP request/response use IP addresses. 5025890Skarels */ 5125890Skarels #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL 5225890Skarels 5311570Ssam #define ARPTAB_HASH(a) \ 5425890Skarels ((u_long)(a) % ARPTAB_NB) 5511570Ssam 5611570Ssam #define ARPTAB_LOOK(at,addr) { \ 5711570Ssam register n; \ 5811570Ssam at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \ 5911570Ssam for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \ 6011570Ssam if (at->at_iaddr.s_addr == addr) \ 6111570Ssam break; \ 6211570Ssam if (n >= ARPTAB_BSIZ) \ 6325890Skarels at = 0; \ 6425890Skarels } 6511570Ssam 6611570Ssam /* timer values */ 6711570Ssam #define ARPT_AGE (60*1) /* aging timer, 1 min. */ 6811570Ssam #define ARPT_KILLC 20 /* kill completed entry in 20 mins. */ 6911570Ssam #define ARPT_KILLI 3 /* kill incomplete entry in 3 minutes */ 7011570Ssam 7111570Ssam extern struct ifnet loif; 7211570Ssam 7314867Ssam /* 7411570Ssam * Timeout routine. Age arp_tab entries once a minute. 7511570Ssam */ 7611570Ssam arptimer() 7711570Ssam { 7811570Ssam register struct arptab *at; 7911570Ssam register i; 8011570Ssam 8125890Skarels timeout(arptimer, (caddr_t)0, ARPT_AGE * hz); 8225890Skarels at = &arptab[0]; 8325890Skarels for (i = 0; i < ARPTAB_SIZE; i++, at++) { 8425890Skarels if (at->at_flags == 0 || (at->at_flags & ATF_PERM)) 8525890Skarels continue; 8625890Skarels if (++at->at_timer < ((at->at_flags&ATF_COM) ? 8725890Skarels ARPT_KILLC : ARPT_KILLI)) 8825890Skarels continue; 8925890Skarels /* timer has expired, clear entry */ 9025890Skarels arptfree(at); 9111570Ssam } 9211570Ssam } 9311570Ssam 9411570Ssam /* 9511570Ssam * Broadcast an ARP packet, asking who has addr on interface ac. 9611570Ssam */ 9711570Ssam arpwhohas(ac, addr) 9811570Ssam register struct arpcom *ac; 9911570Ssam struct in_addr *addr; 10011570Ssam { 10111570Ssam register struct mbuf *m; 10211570Ssam register struct ether_header *eh; 10311570Ssam register struct ether_arp *ea; 10411570Ssam struct sockaddr sa; 10511570Ssam 10635794Skarels if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) 10726380Skarels return; 10835794Skarels m->m_len = sizeof(*ea); 10935794Skarels m->m_pkthdr.len = sizeof(*ea); 11035794Skarels MH_ALIGN(m, sizeof(*ea)); 11111570Ssam ea = mtod(m, struct ether_arp *); 11211570Ssam eh = (struct ether_header *)sa.sa_data; 11312763Ssam bzero((caddr_t)ea, sizeof (*ea)); 11418640Skarels bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, 11518640Skarels sizeof(eh->ether_dhost)); 11618378Skarels eh->ether_type = ETHERTYPE_ARP; /* if_output will swap */ 11711570Ssam ea->arp_hrd = htons(ARPHRD_ETHER); 11818378Skarels ea->arp_pro = htons(ETHERTYPE_IP); 11918640Skarels ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */ 12018640Skarels ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */ 12111570Ssam ea->arp_op = htons(ARPOP_REQUEST); 12218640Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, 12318640Skarels sizeof(ea->arp_sha)); 12418640Skarels bcopy((caddr_t)&ac->ac_ipaddr, (caddr_t)ea->arp_spa, 12518640Skarels sizeof(ea->arp_spa)); 12618640Skarels bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa)); 12711570Ssam sa.sa_family = AF_UNSPEC; 12836819Skarels sa.sa_len = sizeof(sa); 12940796Ssklower (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0); 13011570Ssam } 13111570Ssam 13230300Skarels int useloopback = 1; /* use loopback interface for local traffic */ 13330300Skarels 13411570Ssam /* 13511570Ssam * Resolve an IP address into an ethernet address. If success, 13625890Skarels * desten is filled in. If there is no entry in arptab, 13725890Skarels * set one up and broadcast a request for the IP address. 13825890Skarels * Hold onto this mbuf and resend it once the address 13925890Skarels * is finally resolved. A return value of 1 indicates 14025890Skarels * that desten has been filled in and the packet should be sent 14125890Skarels * normally; a 0 return indicates that the packet has been 14225890Skarels * taken over here, either now or for later transmission. 14311570Ssam * 14411570Ssam * We do some (conservative) locking here at splimp, since 14511570Ssam * arptab is also altered from input interrupt service (ecintr/ilintr 14618378Skarels * calls arpinput when ETHERTYPE_ARP packets come in). 14711570Ssam */ 14825890Skarels arpresolve(ac, m, destip, desten, usetrailers) 14911570Ssam register struct arpcom *ac; 15011570Ssam struct mbuf *m; 15111570Ssam register struct in_addr *destip; 15218640Skarels register u_char *desten; 15325890Skarels int *usetrailers; 15411570Ssam { 15511570Ssam register struct arptab *at; 15611570Ssam struct sockaddr_in sin; 15737471Ssklower register struct in_ifaddr *ia; 15832346Skarels u_long lna; 15932346Skarels int s; 16011570Ssam 16125890Skarels *usetrailers = 0; 16235794Skarels if (m->m_flags & M_BCAST) { /* broadcast */ 16318640Skarels bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten, 16418640Skarels sizeof(etherbroadcastaddr)); 16511570Ssam return (1); 16611570Ssam } 16718378Skarels lna = in_lnaof(*destip); 16826223Skarels /* if for us, use software loopback driver if up */ 16937471Ssklower for (ia = in_ifaddr; ia; ia = ia->ia_next) 17037471Ssklower if ((ia->ia_ifp == &ac->ac_if) && 17137471Ssklower (destip->s_addr == ia->ia_addr.sin_addr.s_addr)) { 17232346Skarels /* 17332346Skarels * This test used to be 17432346Skarels * if (loif.if_flags & IFF_UP) 17532346Skarels * It allowed local traffic to be forced 17632346Skarels * through the hardware by configuring the loopback down. 17732346Skarels * However, it causes problems during network configuration 17832346Skarels * for boards that can't receive packets they send. 17932346Skarels * It is now necessary to clear "useloopback" 18032346Skarels * to force traffic out to the hardware. 18132346Skarels */ 18230300Skarels if (useloopback) { 18326223Skarels sin.sin_family = AF_INET; 18426223Skarels sin.sin_addr = *destip; 18526223Skarels (void) looutput(&loif, m, (struct sockaddr *)&sin); 18626223Skarels /* 18726223Skarels * The packet has already been sent and freed. 18826223Skarels */ 18926223Skarels return (0); 19026223Skarels } else { 19126223Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 19226223Skarels sizeof(ac->ac_enaddr)); 19326223Skarels return (1); 19426223Skarels } 19511570Ssam } 19611570Ssam s = splimp(); 19711570Ssam ARPTAB_LOOK(at, destip->s_addr); 19811570Ssam if (at == 0) { /* not found */ 19932346Skarels if (ac->ac_if.if_flags & IFF_NOARP) { 20018640Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3); 20118640Skarels desten[3] = (lna >> 16) & 0x7f; 20218640Skarels desten[4] = (lna >> 8) & 0xff; 20318640Skarels desten[5] = lna & 0xff; 20416221Skarels splx(s); 20516221Skarels return (1); 20616221Skarels } else { 20716221Skarels at = arptnew(destip); 20832346Skarels if (at == 0) 20932346Skarels panic("arpresolve: no free entry"); 21016221Skarels at->at_hold = m; 21116221Skarels arpwhohas(ac, destip); 21216221Skarels splx(s); 21316221Skarels return (0); 21416221Skarels } 21511570Ssam } 21611570Ssam at->at_timer = 0; /* restart the timer */ 21711570Ssam if (at->at_flags & ATF_COM) { /* entry IS complete */ 21818640Skarels bcopy((caddr_t)at->at_enaddr, (caddr_t)desten, 21918640Skarels sizeof(at->at_enaddr)); 22025890Skarels if (at->at_flags & ATF_USETRAILERS) 22125890Skarels *usetrailers = 1; 22211570Ssam splx(s); 22311570Ssam return (1); 22411570Ssam } 22511570Ssam /* 22611570Ssam * There is an arptab entry, but no ethernet address 22711570Ssam * response yet. Replace the held mbuf with this 22811570Ssam * latest one. 22911570Ssam */ 23011570Ssam if (at->at_hold) 23111570Ssam m_freem(at->at_hold); 23211570Ssam at->at_hold = m; 23311570Ssam arpwhohas(ac, destip); /* ask again */ 23411570Ssam splx(s); 23511570Ssam return (0); 23611570Ssam } 23711570Ssam 23811570Ssam /* 23918378Skarels * Called from 10 Mb/s Ethernet interrupt handlers 24018378Skarels * when ether packet type ETHERTYPE_ARP 24125890Skarels * is received. Common length and type checks are done here, 24225890Skarels * then the protocol-specific routine is called. 24325890Skarels */ 24425890Skarels arpinput(ac, m) 24525890Skarels struct arpcom *ac; 24625890Skarels struct mbuf *m; 24725890Skarels { 24825890Skarels register struct arphdr *ar; 24925890Skarels 25025890Skarels if (ac->ac_if.if_flags & IFF_NOARP) 25125890Skarels goto out; 25225890Skarels if (m->m_len < sizeof(struct arphdr)) 25325890Skarels goto out; 25425890Skarels ar = mtod(m, struct arphdr *); 25525890Skarels if (ntohs(ar->ar_hrd) != ARPHRD_ETHER) 25625890Skarels goto out; 25725890Skarels if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) 25825890Skarels goto out; 25925890Skarels 26025890Skarels switch (ntohs(ar->ar_pro)) { 26125890Skarels 26225890Skarels case ETHERTYPE_IP: 26325890Skarels case ETHERTYPE_IPTRAILERS: 26425890Skarels in_arpinput(ac, m); 26525890Skarels return; 26625890Skarels 26725890Skarels default: 26825890Skarels break; 26925890Skarels } 27025890Skarels out: 27125890Skarels m_freem(m); 27225890Skarels } 27325890Skarels 27425890Skarels /* 27525890Skarels * ARP for Internet protocols on 10 Mb/s Ethernet. 27625890Skarels * Algorithm is that given in RFC 826. 27711570Ssam * In addition, a sanity check is performed on the sender 27811570Ssam * protocol address, to catch impersonators. 27925890Skarels * We also handle negotiations for use of trailer protocol: 28025890Skarels * ARP replies for protocol type ETHERTYPE_TRAIL are sent 28125890Skarels * along with IP replies if we want trailers sent to us, 28225890Skarels * and also send them in response to IP replies. 28325890Skarels * This allows either end to announce the desire to receive 28425890Skarels * trailer packets. 28525890Skarels * We reply to requests for ETHERTYPE_TRAIL protocol as well, 28625890Skarels * but don't normally send requests. 28711570Ssam */ 28825890Skarels in_arpinput(ac, m) 28911570Ssam register struct arpcom *ac; 29011570Ssam struct mbuf *m; 29111570Ssam { 29211570Ssam register struct ether_arp *ea; 29311570Ssam struct ether_header *eh; 29424803Skarels register struct arptab *at; /* same as "merge" flag */ 29537471Ssklower register struct in_ifaddr *ia; 29637471Ssklower struct in_ifaddr *maybe_ia = 0; 29725890Skarels struct mbuf *mcopy = 0; 29811570Ssam struct sockaddr_in sin; 29911570Ssam struct sockaddr sa; 30025890Skarels struct in_addr isaddr, itaddr, myaddr; 30132346Skarels int proto, op, s, completed = 0; 30211570Ssam 30311570Ssam ea = mtod(m, struct ether_arp *); 30425890Skarels proto = ntohs(ea->arp_pro); 30525890Skarels op = ntohs(ea->arp_op); 30632346Skarels bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr)); 30732346Skarels bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr)); 30837471Ssklower for (ia = in_ifaddr; ia; ia = ia->ia_next) 30937471Ssklower if (ia->ia_ifp == &ac->ac_if) { 31037471Ssklower maybe_ia = ia; 31137471Ssklower if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) || 31237471Ssklower (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) 31337471Ssklower break; 31437471Ssklower } 31537471Ssklower if (maybe_ia == 0) 31637471Ssklower goto out; 31737471Ssklower myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr; 31818640Skarels if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr, 31935794Skarels sizeof (ea->arp_sha))) 32011570Ssam goto out; /* it's from me, ignore it. */ 32125890Skarels if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr, 32225890Skarels sizeof (ea->arp_sha))) { 32325890Skarels log(LOG_ERR, 32425890Skarels "arp: ether address is broadcast for IP address %x!\n", 32525890Skarels ntohl(isaddr.s_addr)); 32625890Skarels goto out; 32725890Skarels } 32811570Ssam if (isaddr.s_addr == myaddr.s_addr) { 32936819Skarels log(LOG_ERR, 33036819Skarels "duplicate IP address %x!! sent from ethernet address: %s\n", 33136819Skarels ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha)); 33216221Skarels itaddr = myaddr; 33325890Skarels if (op == ARPOP_REQUEST) 33411570Ssam goto reply; 33511570Ssam goto out; 33611570Ssam } 33730300Skarels s = splimp(); 33811570Ssam ARPTAB_LOOK(at, isaddr.s_addr); 33926147Skarels if (at) { 34018640Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, 34118640Skarels sizeof(ea->arp_sha)); 34232346Skarels if ((at->at_flags & ATF_COM) == 0) 34332346Skarels completed = 1; 34411570Ssam at->at_flags |= ATF_COM; 34511570Ssam if (at->at_hold) { 34611570Ssam sin.sin_family = AF_INET; 34711570Ssam sin.sin_addr = isaddr; 34840796Ssklower (*ac->ac_if.if_output)(&ac->ac_if, at->at_hold, 34940796Ssklower (struct sockaddr *)&sin, (struct rtentry *)0); 35018759Skarels at->at_hold = 0; 35111570Ssam } 35218759Skarels } 35318759Skarels if (at == 0 && itaddr.s_addr == myaddr.s_addr) { 35416221Skarels /* ensure we have a table entry */ 35532346Skarels if (at = arptnew(&isaddr)) { 35632346Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, 35732346Skarels sizeof(ea->arp_sha)); 35832346Skarels completed = 1; 35932346Skarels at->at_flags |= ATF_COM; 36032346Skarels } 36111570Ssam } 36230300Skarels splx(s); 36311570Ssam reply: 36425890Skarels switch (proto) { 36525890Skarels 36625890Skarels case ETHERTYPE_IPTRAILERS: 36725890Skarels /* partner says trailers are OK */ 36825890Skarels if (at) 36925890Skarels at->at_flags |= ATF_USETRAILERS; 37025890Skarels /* 37125890Skarels * Reply to request iff we want trailers. 37225890Skarels */ 37325890Skarels if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS) 37425890Skarels goto out; 37525890Skarels break; 37625890Skarels 37725890Skarels case ETHERTYPE_IP: 37825890Skarels /* 37932346Skarels * Reply if this is an IP request, 38032346Skarels * or if we want to send a trailer response. 38132346Skarels * Send the latter only to the IP response 38232346Skarels * that completes the current ARP entry. 38325890Skarels */ 38432346Skarels if (op != ARPOP_REQUEST && 38532346Skarels (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS)) 38625890Skarels goto out; 38725890Skarels } 38825890Skarels if (itaddr.s_addr == myaddr.s_addr) { 38925890Skarels /* I am the target */ 39025890Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, 39125890Skarels sizeof(ea->arp_sha)); 39225890Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, 39325890Skarels sizeof(ea->arp_sha)); 39425890Skarels } else { 39525890Skarels ARPTAB_LOOK(at, itaddr.s_addr); 39625890Skarels if (at == NULL || (at->at_flags & ATF_PUBL) == 0) 39725890Skarels goto out; 39825890Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, 39925890Skarels sizeof(ea->arp_sha)); 40025890Skarels bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha, 40125890Skarels sizeof(ea->arp_sha)); 40225890Skarels } 40325890Skarels 40418640Skarels bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, 40518640Skarels sizeof(ea->arp_spa)); 40618640Skarels bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa, 40718640Skarels sizeof(ea->arp_spa)); 40825890Skarels ea->arp_op = htons(ARPOP_REPLY); 40925890Skarels /* 41025890Skarels * If incoming packet was an IP reply, 41125890Skarels * we are sending a reply for type IPTRAILERS. 41225890Skarels * If we are sending a reply for type IP 41325890Skarels * and we want to receive trailers, 41425890Skarels * send a trailer reply as well. 41525890Skarels */ 41625890Skarels if (op == ARPOP_REPLY) 41725890Skarels ea->arp_pro = htons(ETHERTYPE_IPTRAILERS); 41825890Skarels else if (proto == ETHERTYPE_IP && 41925890Skarels (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0) 42026453Skarels mcopy = m_copy(m, 0, (int)M_COPYALL); 42111570Ssam eh = (struct ether_header *)sa.sa_data; 42218640Skarels bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost, 42318640Skarels sizeof(eh->ether_dhost)); 42418378Skarels eh->ether_type = ETHERTYPE_ARP; 42511570Ssam sa.sa_family = AF_UNSPEC; 42636819Skarels sa.sa_len = sizeof(sa); 42740796Ssklower (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0); 42825890Skarels if (mcopy) { 42925890Skarels ea = mtod(mcopy, struct ether_arp *); 43025890Skarels ea->arp_pro = htons(ETHERTYPE_IPTRAILERS); 43140796Ssklower (*ac->ac_if.if_output)(&ac->ac_if, 43240796Ssklower mcopy, &sa, (struct rtentry *)0); 43325890Skarels } 43411570Ssam return; 43511570Ssam out: 43611570Ssam m_freem(m); 43711570Ssam return; 43811570Ssam } 43911570Ssam 44011570Ssam /* 44111570Ssam * Free an arptab entry. 44211570Ssam */ 44311570Ssam arptfree(at) 44411570Ssam register struct arptab *at; 44511570Ssam { 44611570Ssam int s = splimp(); 44711570Ssam 44811570Ssam if (at->at_hold) 44911570Ssam m_freem(at->at_hold); 45011570Ssam at->at_hold = 0; 45111570Ssam at->at_timer = at->at_flags = 0; 45211570Ssam at->at_iaddr.s_addr = 0; 45311570Ssam splx(s); 45411570Ssam } 45511570Ssam 45611570Ssam /* 45711570Ssam * Enter a new address in arptab, pushing out the oldest entry 45811570Ssam * from the bucket if there is no room. 45916221Skarels * This always succeeds since no bucket can be completely filled 46016221Skarels * with permanent entries (except from arpioctl when testing whether 46118640Skarels * another permanent entry will fit). 46232346Skarels * MUST BE CALLED AT SPLIMP. 46311570Ssam */ 46411570Ssam struct arptab * 46511570Ssam arptnew(addr) 46611570Ssam struct in_addr *addr; 46711570Ssam { 46811570Ssam register n; 46924803Skarels int oldest = -1; 47016221Skarels register struct arptab *at, *ato = NULL; 47116221Skarels static int first = 1; 47211570Ssam 47316221Skarels if (first) { 47416221Skarels first = 0; 47516221Skarels timeout(arptimer, (caddr_t)0, hz); 47616221Skarels } 47716221Skarels at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ]; 47818640Skarels for (n = 0; n < ARPTAB_BSIZ; n++,at++) { 47911570Ssam if (at->at_flags == 0) 48011570Ssam goto out; /* found an empty entry */ 48116221Skarels if (at->at_flags & ATF_PERM) 48216221Skarels continue; 48332346Skarels if ((int) at->at_timer > oldest) { 48411570Ssam oldest = at->at_timer; 48511570Ssam ato = at; 48611570Ssam } 48711570Ssam } 48816221Skarels if (ato == NULL) 48918640Skarels return (NULL); 49011570Ssam at = ato; 49111570Ssam arptfree(at); 49211570Ssam out: 49311570Ssam at->at_iaddr = *addr; 49411570Ssam at->at_flags = ATF_INUSE; 49511570Ssam return (at); 49611570Ssam } 49716221Skarels 49816221Skarels arpioctl(cmd, data) 49916221Skarels int cmd; 50016221Skarels caddr_t data; 50116221Skarels { 50216221Skarels register struct arpreq *ar = (struct arpreq *)data; 50316221Skarels register struct arptab *at; 50416221Skarels register struct sockaddr_in *sin; 50516221Skarels int s; 50616221Skarels 50736819Skarels sin = (struct sockaddr_in *)&ar->arp_ha; 50836819Skarels #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN 50936819Skarels if (sin->sin_family == 0 && sin->sin_len < 16) 51036819Skarels sin->sin_family = sin->sin_len; 51136819Skarels #endif 51236819Skarels sin->sin_len = sizeof(ar->arp_ha); 51336819Skarels sin = (struct sockaddr_in *)&ar->arp_pa; 51436819Skarels #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN 51536819Skarels if (sin->sin_family == 0 && sin->sin_len < 16) 51636819Skarels sin->sin_family = sin->sin_len; 51736819Skarels #endif 51836819Skarels sin->sin_len = sizeof(ar->arp_pa); 51916221Skarels if (ar->arp_pa.sa_family != AF_INET || 52016221Skarels ar->arp_ha.sa_family != AF_UNSPEC) 52116221Skarels return (EAFNOSUPPORT); 52216221Skarels s = splimp(); 52316221Skarels ARPTAB_LOOK(at, sin->sin_addr.s_addr); 52416221Skarels if (at == NULL) { /* not found */ 52516221Skarels if (cmd != SIOCSARP) { 52616221Skarels splx(s); 52716221Skarels return (ENXIO); 52816221Skarels } 52918378Skarels if (ifa_ifwithnet(&ar->arp_pa) == NULL) { 53016221Skarels splx(s); 53116221Skarels return (ENETUNREACH); 53216221Skarels } 53316221Skarels } 53416221Skarels switch (cmd) { 53516221Skarels 53616221Skarels case SIOCSARP: /* set entry */ 53716221Skarels if (at == NULL) { 53816221Skarels at = arptnew(&sin->sin_addr); 53932346Skarels if (at == NULL) { 54032346Skarels splx(s); 54132346Skarels return (EADDRNOTAVAIL); 54232346Skarels } 54316221Skarels if (ar->arp_flags & ATF_PERM) { 54416221Skarels /* never make all entries in a bucket permanent */ 54516221Skarels register struct arptab *tat; 54616221Skarels 54716221Skarels /* try to re-allocate */ 54816221Skarels tat = arptnew(&sin->sin_addr); 54916221Skarels if (tat == NULL) { 55016221Skarels arptfree(at); 55116221Skarels splx(s); 55216221Skarels return (EADDRNOTAVAIL); 55316221Skarels } 55416221Skarels arptfree(tat); 55516221Skarels } 55616221Skarels } 55718640Skarels bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr, 55818640Skarels sizeof(at->at_enaddr)); 55916221Skarels at->at_flags = ATF_COM | ATF_INUSE | 56032566Sbostic (ar->arp_flags & (ATF_PERM|ATF_PUBL|ATF_USETRAILERS)); 56116221Skarels at->at_timer = 0; 56216221Skarels break; 56316221Skarels 56416221Skarels case SIOCDARP: /* delete entry */ 56516221Skarels arptfree(at); 56616221Skarels break; 56716221Skarels 56816221Skarels case SIOCGARP: /* get entry */ 56936819Skarels case OSIOCGARP: 57018640Skarels bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data, 57118640Skarels sizeof(at->at_enaddr)); 57236819Skarels #ifdef COMPAT_43 57336819Skarels if (cmd == OSIOCGARP) 57436819Skarels *(u_short *)&ar->arp_ha = ar->arp_ha.sa_family; 57536819Skarels #endif 57616221Skarels ar->arp_flags = at->at_flags; 57716221Skarels break; 57816221Skarels } 57916221Skarels splx(s); 58016221Skarels return (0); 58116221Skarels } 582