123172Smckusick /* 235794Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 332787Sbostic * All rights reserved. 423172Smckusick * 532787Sbostic * Redistribution and use in source and binary forms are permitted 634854Sbostic * provided that the above copyright notice and this paragraph are 734854Sbostic * duplicated in all such forms and that any documentation, 834854Sbostic * advertising materials, and other materials related to such 934854Sbostic * distribution and use acknowledge that the software was developed 1034854Sbostic * by the University of California, Berkeley. The name of the 1134854Sbostic * University may not be used to endorse or promote products derived 1234854Sbostic * from this software without specific prior written permission. 1334854Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434854Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534854Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1632787Sbostic * 17*36819Skarels * @(#)if_ether.c 7.9 (Berkeley) 02/17/89 1823172Smckusick */ 1911570Ssam 2011570Ssam /* 2111570Ssam * Ethernet address resolution protocol. 2232346Skarels * TODO: 2332346Skarels * run at splnet (add ARP protocol intr.) 2432346Skarels * link entries onto hash chains, keep free list 2532346Skarels * add "inuse/lock" bit (or ref. count) along with valid bit 2611570Ssam */ 2711570Ssam 2817057Sbloom #include "param.h" 2917057Sbloom #include "systm.h" 3035794Skarels #include "malloc.h" 3117057Sbloom #include "mbuf.h" 3217057Sbloom #include "socket.h" 3317057Sbloom #include "time.h" 3417057Sbloom #include "kernel.h" 3517057Sbloom #include "errno.h" 3617057Sbloom #include "ioctl.h" 3725890Skarels #include "syslog.h" 3811570Ssam 3911570Ssam #include "../net/if.h" 4017057Sbloom #include "in.h" 4117057Sbloom #include "in_systm.h" 4217057Sbloom #include "ip.h" 4317057Sbloom #include "if_ether.h" 4411570Ssam 4532346Skarels #ifdef GATEWAY 4632346Skarels #define ARPTAB_BSIZ 16 /* bucket size */ 4732346Skarels #define ARPTAB_NB 37 /* number of buckets */ 4832346Skarels #else 4924803Skarels #define ARPTAB_BSIZ 9 /* bucket size */ 5011570Ssam #define ARPTAB_NB 19 /* number of buckets */ 5132346Skarels #endif 5211570Ssam #define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB) 5311570Ssam struct arptab arptab[ARPTAB_SIZE]; 5416221Skarels int arptab_size = ARPTAB_SIZE; /* for arp command */ 5511570Ssam 5625890Skarels /* 5725890Skarels * ARP trailer negotiation. Trailer protocol is not IP specific, 5825890Skarels * but ARP request/response use IP addresses. 5925890Skarels */ 6025890Skarels #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL 6125890Skarels 6211570Ssam #define ARPTAB_HASH(a) \ 6325890Skarels ((u_long)(a) % ARPTAB_NB) 6411570Ssam 6511570Ssam #define ARPTAB_LOOK(at,addr) { \ 6611570Ssam register n; \ 6711570Ssam at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \ 6811570Ssam for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \ 6911570Ssam if (at->at_iaddr.s_addr == addr) \ 7011570Ssam break; \ 7111570Ssam if (n >= ARPTAB_BSIZ) \ 7225890Skarels at = 0; \ 7325890Skarels } 7411570Ssam 7511570Ssam /* timer values */ 7611570Ssam #define ARPT_AGE (60*1) /* aging timer, 1 min. */ 7711570Ssam #define ARPT_KILLC 20 /* kill completed entry in 20 mins. */ 7811570Ssam #define ARPT_KILLI 3 /* kill incomplete entry in 3 minutes */ 7911570Ssam 8011570Ssam extern struct ifnet loif; 8111570Ssam 8214867Ssam /* 8311570Ssam * Timeout routine. Age arp_tab entries once a minute. 8411570Ssam */ 8511570Ssam arptimer() 8611570Ssam { 8711570Ssam register struct arptab *at; 8811570Ssam register i; 8911570Ssam 9025890Skarels timeout(arptimer, (caddr_t)0, ARPT_AGE * hz); 9125890Skarels at = &arptab[0]; 9225890Skarels for (i = 0; i < ARPTAB_SIZE; i++, at++) { 9325890Skarels if (at->at_flags == 0 || (at->at_flags & ATF_PERM)) 9425890Skarels continue; 9525890Skarels if (++at->at_timer < ((at->at_flags&ATF_COM) ? 9625890Skarels ARPT_KILLC : ARPT_KILLI)) 9725890Skarels continue; 9825890Skarels /* timer has expired, clear entry */ 9925890Skarels arptfree(at); 10011570Ssam } 10111570Ssam } 10211570Ssam 10311570Ssam /* 10411570Ssam * Broadcast an ARP packet, asking who has addr on interface ac. 10511570Ssam */ 10611570Ssam arpwhohas(ac, addr) 10711570Ssam register struct arpcom *ac; 10811570Ssam struct in_addr *addr; 10911570Ssam { 11011570Ssam register struct mbuf *m; 11111570Ssam register struct ether_header *eh; 11211570Ssam register struct ether_arp *ea; 11311570Ssam struct sockaddr sa; 11411570Ssam 11535794Skarels if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) 11626380Skarels return; 11735794Skarels m->m_len = sizeof(*ea); 11835794Skarels m->m_pkthdr.len = sizeof(*ea); 11935794Skarels MH_ALIGN(m, sizeof(*ea)); 12011570Ssam ea = mtod(m, struct ether_arp *); 12111570Ssam eh = (struct ether_header *)sa.sa_data; 12212763Ssam bzero((caddr_t)ea, sizeof (*ea)); 12318640Skarels bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, 12418640Skarels sizeof(eh->ether_dhost)); 12518378Skarels eh->ether_type = ETHERTYPE_ARP; /* if_output will swap */ 12611570Ssam ea->arp_hrd = htons(ARPHRD_ETHER); 12718378Skarels ea->arp_pro = htons(ETHERTYPE_IP); 12818640Skarels ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */ 12918640Skarels ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */ 13011570Ssam ea->arp_op = htons(ARPOP_REQUEST); 13118640Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, 13218640Skarels sizeof(ea->arp_sha)); 13318640Skarels bcopy((caddr_t)&ac->ac_ipaddr, (caddr_t)ea->arp_spa, 13418640Skarels sizeof(ea->arp_spa)); 13518640Skarels bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa)); 13611570Ssam sa.sa_family = AF_UNSPEC; 137*36819Skarels sa.sa_len = sizeof(sa); 13826380Skarels (*ac->ac_if.if_output)(&ac->ac_if, m, &sa); 13911570Ssam } 14011570Ssam 14130300Skarels int useloopback = 1; /* use loopback interface for local traffic */ 14230300Skarels 14311570Ssam /* 14411570Ssam * Resolve an IP address into an ethernet address. If success, 14525890Skarels * desten is filled in. If there is no entry in arptab, 14625890Skarels * set one up and broadcast a request for the IP address. 14725890Skarels * Hold onto this mbuf and resend it once the address 14825890Skarels * is finally resolved. A return value of 1 indicates 14925890Skarels * that desten has been filled in and the packet should be sent 15025890Skarels * normally; a 0 return indicates that the packet has been 15125890Skarels * taken over here, either now or for later transmission. 15211570Ssam * 15311570Ssam * We do some (conservative) locking here at splimp, since 15411570Ssam * arptab is also altered from input interrupt service (ecintr/ilintr 15518378Skarels * calls arpinput when ETHERTYPE_ARP packets come in). 15611570Ssam */ 15725890Skarels arpresolve(ac, m, destip, desten, usetrailers) 15811570Ssam register struct arpcom *ac; 15911570Ssam struct mbuf *m; 16011570Ssam register struct in_addr *destip; 16118640Skarels register u_char *desten; 16225890Skarels int *usetrailers; 16311570Ssam { 16411570Ssam register struct arptab *at; 16511570Ssam struct sockaddr_in sin; 16632346Skarels u_long lna; 16732346Skarels int s; 16811570Ssam 16925890Skarels *usetrailers = 0; 17035794Skarels if (m->m_flags & M_BCAST) { /* broadcast */ 17118640Skarels bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten, 17218640Skarels sizeof(etherbroadcastaddr)); 17311570Ssam return (1); 17411570Ssam } 17518378Skarels lna = in_lnaof(*destip); 17626223Skarels /* if for us, use software loopback driver if up */ 17726223Skarels if (destip->s_addr == ac->ac_ipaddr.s_addr) { 17832346Skarels /* 17932346Skarels * This test used to be 18032346Skarels * if (loif.if_flags & IFF_UP) 18132346Skarels * It allowed local traffic to be forced 18232346Skarels * through the hardware by configuring the loopback down. 18332346Skarels * However, it causes problems during network configuration 18432346Skarels * for boards that can't receive packets they send. 18532346Skarels * It is now necessary to clear "useloopback" 18632346Skarels * to force traffic out to the hardware. 18732346Skarels */ 18830300Skarels if (useloopback) { 18926223Skarels sin.sin_family = AF_INET; 19026223Skarels sin.sin_addr = *destip; 19126223Skarels (void) looutput(&loif, m, (struct sockaddr *)&sin); 19226223Skarels /* 19326223Skarels * The packet has already been sent and freed. 19426223Skarels */ 19526223Skarels return (0); 19626223Skarels } else { 19726223Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 19826223Skarels sizeof(ac->ac_enaddr)); 19926223Skarels return (1); 20026223Skarels } 20111570Ssam } 20211570Ssam s = splimp(); 20311570Ssam ARPTAB_LOOK(at, destip->s_addr); 20411570Ssam if (at == 0) { /* not found */ 20532346Skarels if (ac->ac_if.if_flags & IFF_NOARP) { 20618640Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3); 20718640Skarels desten[3] = (lna >> 16) & 0x7f; 20818640Skarels desten[4] = (lna >> 8) & 0xff; 20918640Skarels desten[5] = lna & 0xff; 21016221Skarels splx(s); 21116221Skarels return (1); 21216221Skarels } else { 21316221Skarels at = arptnew(destip); 21432346Skarels if (at == 0) 21532346Skarels panic("arpresolve: no free entry"); 21616221Skarels at->at_hold = m; 21716221Skarels arpwhohas(ac, destip); 21816221Skarels splx(s); 21916221Skarels return (0); 22016221Skarels } 22111570Ssam } 22211570Ssam at->at_timer = 0; /* restart the timer */ 22311570Ssam if (at->at_flags & ATF_COM) { /* entry IS complete */ 22418640Skarels bcopy((caddr_t)at->at_enaddr, (caddr_t)desten, 22518640Skarels sizeof(at->at_enaddr)); 22625890Skarels if (at->at_flags & ATF_USETRAILERS) 22725890Skarels *usetrailers = 1; 22811570Ssam splx(s); 22911570Ssam return (1); 23011570Ssam } 23111570Ssam /* 23211570Ssam * There is an arptab entry, but no ethernet address 23311570Ssam * response yet. Replace the held mbuf with this 23411570Ssam * latest one. 23511570Ssam */ 23611570Ssam if (at->at_hold) 23711570Ssam m_freem(at->at_hold); 23811570Ssam at->at_hold = m; 23911570Ssam arpwhohas(ac, destip); /* ask again */ 24011570Ssam splx(s); 24111570Ssam return (0); 24211570Ssam } 24311570Ssam 24411570Ssam /* 24518378Skarels * Called from 10 Mb/s Ethernet interrupt handlers 24618378Skarels * when ether packet type ETHERTYPE_ARP 24725890Skarels * is received. Common length and type checks are done here, 24825890Skarels * then the protocol-specific routine is called. 24925890Skarels */ 25025890Skarels arpinput(ac, m) 25125890Skarels struct arpcom *ac; 25225890Skarels struct mbuf *m; 25325890Skarels { 25425890Skarels register struct arphdr *ar; 25525890Skarels 25625890Skarels if (ac->ac_if.if_flags & IFF_NOARP) 25725890Skarels goto out; 25825890Skarels if (m->m_len < sizeof(struct arphdr)) 25925890Skarels goto out; 26025890Skarels ar = mtod(m, struct arphdr *); 26125890Skarels if (ntohs(ar->ar_hrd) != ARPHRD_ETHER) 26225890Skarels goto out; 26325890Skarels if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln) 26425890Skarels goto out; 26525890Skarels 26625890Skarels switch (ntohs(ar->ar_pro)) { 26725890Skarels 26825890Skarels case ETHERTYPE_IP: 26925890Skarels case ETHERTYPE_IPTRAILERS: 27025890Skarels in_arpinput(ac, m); 27125890Skarels return; 27225890Skarels 27325890Skarels default: 27425890Skarels break; 27525890Skarels } 27625890Skarels out: 27725890Skarels m_freem(m); 27825890Skarels } 27925890Skarels 28025890Skarels /* 28125890Skarels * ARP for Internet protocols on 10 Mb/s Ethernet. 28225890Skarels * Algorithm is that given in RFC 826. 28311570Ssam * In addition, a sanity check is performed on the sender 28411570Ssam * protocol address, to catch impersonators. 28525890Skarels * We also handle negotiations for use of trailer protocol: 28625890Skarels * ARP replies for protocol type ETHERTYPE_TRAIL are sent 28725890Skarels * along with IP replies if we want trailers sent to us, 28825890Skarels * and also send them in response to IP replies. 28925890Skarels * This allows either end to announce the desire to receive 29025890Skarels * trailer packets. 29125890Skarels * We reply to requests for ETHERTYPE_TRAIL protocol as well, 29225890Skarels * but don't normally send requests. 29311570Ssam */ 29425890Skarels in_arpinput(ac, m) 29511570Ssam register struct arpcom *ac; 29611570Ssam struct mbuf *m; 29711570Ssam { 29811570Ssam register struct ether_arp *ea; 29911570Ssam struct ether_header *eh; 30024803Skarels register struct arptab *at; /* same as "merge" flag */ 30125890Skarels struct mbuf *mcopy = 0; 30211570Ssam struct sockaddr_in sin; 30311570Ssam struct sockaddr sa; 30425890Skarels struct in_addr isaddr, itaddr, myaddr; 30532346Skarels int proto, op, s, completed = 0; 30611570Ssam 30718378Skarels myaddr = ac->ac_ipaddr; 30811570Ssam ea = mtod(m, struct ether_arp *); 30925890Skarels proto = ntohs(ea->arp_pro); 31025890Skarels op = ntohs(ea->arp_op); 31132346Skarels bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr)); 31232346Skarels bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr)); 31318640Skarels if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr, 31435794Skarels sizeof (ea->arp_sha))) 31511570Ssam goto out; /* it's from me, ignore it. */ 31625890Skarels if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr, 31725890Skarels sizeof (ea->arp_sha))) { 31825890Skarels log(LOG_ERR, 31925890Skarels "arp: ether address is broadcast for IP address %x!\n", 32025890Skarels ntohl(isaddr.s_addr)); 32125890Skarels goto out; 32225890Skarels } 32311570Ssam if (isaddr.s_addr == myaddr.s_addr) { 324*36819Skarels log(LOG_ERR, 325*36819Skarels "duplicate IP address %x!! sent from ethernet address: %s\n", 326*36819Skarels ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha)); 32716221Skarels itaddr = myaddr; 32825890Skarels if (op == ARPOP_REQUEST) 32911570Ssam goto reply; 33011570Ssam goto out; 33111570Ssam } 33230300Skarels s = splimp(); 33311570Ssam ARPTAB_LOOK(at, isaddr.s_addr); 33426147Skarels if (at) { 33518640Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, 33618640Skarels sizeof(ea->arp_sha)); 33732346Skarels if ((at->at_flags & ATF_COM) == 0) 33832346Skarels completed = 1; 33911570Ssam at->at_flags |= ATF_COM; 34011570Ssam if (at->at_hold) { 34111570Ssam sin.sin_family = AF_INET; 34211570Ssam sin.sin_addr = isaddr; 34311570Ssam (*ac->ac_if.if_output)(&ac->ac_if, 34418759Skarels at->at_hold, (struct sockaddr *)&sin); 34518759Skarels at->at_hold = 0; 34611570Ssam } 34718759Skarels } 34818759Skarels if (at == 0 && itaddr.s_addr == myaddr.s_addr) { 34916221Skarels /* ensure we have a table entry */ 35032346Skarels if (at = arptnew(&isaddr)) { 35132346Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, 35232346Skarels sizeof(ea->arp_sha)); 35332346Skarels completed = 1; 35432346Skarels at->at_flags |= ATF_COM; 35532346Skarels } 35611570Ssam } 35730300Skarels splx(s); 35811570Ssam reply: 35925890Skarels switch (proto) { 36025890Skarels 36125890Skarels case ETHERTYPE_IPTRAILERS: 36225890Skarels /* partner says trailers are OK */ 36325890Skarels if (at) 36425890Skarels at->at_flags |= ATF_USETRAILERS; 36525890Skarels /* 36625890Skarels * Reply to request iff we want trailers. 36725890Skarels */ 36825890Skarels if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS) 36925890Skarels goto out; 37025890Skarels break; 37125890Skarels 37225890Skarels case ETHERTYPE_IP: 37325890Skarels /* 37432346Skarels * Reply if this is an IP request, 37532346Skarels * or if we want to send a trailer response. 37632346Skarels * Send the latter only to the IP response 37732346Skarels * that completes the current ARP entry. 37825890Skarels */ 37932346Skarels if (op != ARPOP_REQUEST && 38032346Skarels (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS)) 38125890Skarels goto out; 38225890Skarels } 38325890Skarels if (itaddr.s_addr == myaddr.s_addr) { 38425890Skarels /* I am the target */ 38525890Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, 38625890Skarels sizeof(ea->arp_sha)); 38725890Skarels bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha, 38825890Skarels sizeof(ea->arp_sha)); 38925890Skarels } else { 39025890Skarels ARPTAB_LOOK(at, itaddr.s_addr); 39125890Skarels if (at == NULL || (at->at_flags & ATF_PUBL) == 0) 39225890Skarels goto out; 39325890Skarels bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha, 39425890Skarels sizeof(ea->arp_sha)); 39525890Skarels bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha, 39625890Skarels sizeof(ea->arp_sha)); 39725890Skarels } 39825890Skarels 39918640Skarels bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, 40018640Skarels sizeof(ea->arp_spa)); 40118640Skarels bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa, 40218640Skarels sizeof(ea->arp_spa)); 40325890Skarels ea->arp_op = htons(ARPOP_REPLY); 40425890Skarels /* 40525890Skarels * If incoming packet was an IP reply, 40625890Skarels * we are sending a reply for type IPTRAILERS. 40725890Skarels * If we are sending a reply for type IP 40825890Skarels * and we want to receive trailers, 40925890Skarels * send a trailer reply as well. 41025890Skarels */ 41125890Skarels if (op == ARPOP_REPLY) 41225890Skarels ea->arp_pro = htons(ETHERTYPE_IPTRAILERS); 41325890Skarels else if (proto == ETHERTYPE_IP && 41425890Skarels (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0) 41526453Skarels mcopy = m_copy(m, 0, (int)M_COPYALL); 41611570Ssam eh = (struct ether_header *)sa.sa_data; 41718640Skarels bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost, 41818640Skarels sizeof(eh->ether_dhost)); 41918378Skarels eh->ether_type = ETHERTYPE_ARP; 42011570Ssam sa.sa_family = AF_UNSPEC; 421*36819Skarels sa.sa_len = sizeof(sa); 42211570Ssam (*ac->ac_if.if_output)(&ac->ac_if, m, &sa); 42325890Skarels if (mcopy) { 42425890Skarels ea = mtod(mcopy, struct ether_arp *); 42525890Skarels ea->arp_pro = htons(ETHERTYPE_IPTRAILERS); 42625890Skarels (*ac->ac_if.if_output)(&ac->ac_if, mcopy, &sa); 42725890Skarels } 42811570Ssam return; 42911570Ssam out: 43011570Ssam m_freem(m); 43111570Ssam return; 43211570Ssam } 43311570Ssam 43411570Ssam /* 43511570Ssam * Free an arptab entry. 43611570Ssam */ 43711570Ssam arptfree(at) 43811570Ssam register struct arptab *at; 43911570Ssam { 44011570Ssam int s = splimp(); 44111570Ssam 44211570Ssam if (at->at_hold) 44311570Ssam m_freem(at->at_hold); 44411570Ssam at->at_hold = 0; 44511570Ssam at->at_timer = at->at_flags = 0; 44611570Ssam at->at_iaddr.s_addr = 0; 44711570Ssam splx(s); 44811570Ssam } 44911570Ssam 45011570Ssam /* 45111570Ssam * Enter a new address in arptab, pushing out the oldest entry 45211570Ssam * from the bucket if there is no room. 45316221Skarels * This always succeeds since no bucket can be completely filled 45416221Skarels * with permanent entries (except from arpioctl when testing whether 45518640Skarels * another permanent entry will fit). 45632346Skarels * MUST BE CALLED AT SPLIMP. 45711570Ssam */ 45811570Ssam struct arptab * 45911570Ssam arptnew(addr) 46011570Ssam struct in_addr *addr; 46111570Ssam { 46211570Ssam register n; 46324803Skarels int oldest = -1; 46416221Skarels register struct arptab *at, *ato = NULL; 46516221Skarels static int first = 1; 46611570Ssam 46716221Skarels if (first) { 46816221Skarels first = 0; 46916221Skarels timeout(arptimer, (caddr_t)0, hz); 47016221Skarels } 47116221Skarels at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ]; 47218640Skarels for (n = 0; n < ARPTAB_BSIZ; n++,at++) { 47311570Ssam if (at->at_flags == 0) 47411570Ssam goto out; /* found an empty entry */ 47516221Skarels if (at->at_flags & ATF_PERM) 47616221Skarels continue; 47732346Skarels if ((int) at->at_timer > oldest) { 47811570Ssam oldest = at->at_timer; 47911570Ssam ato = at; 48011570Ssam } 48111570Ssam } 48216221Skarels if (ato == NULL) 48318640Skarels return (NULL); 48411570Ssam at = ato; 48511570Ssam arptfree(at); 48611570Ssam out: 48711570Ssam at->at_iaddr = *addr; 48811570Ssam at->at_flags = ATF_INUSE; 48911570Ssam return (at); 49011570Ssam } 49116221Skarels 49216221Skarels arpioctl(cmd, data) 49316221Skarels int cmd; 49416221Skarels caddr_t data; 49516221Skarels { 49616221Skarels register struct arpreq *ar = (struct arpreq *)data; 49716221Skarels register struct arptab *at; 49816221Skarels register struct sockaddr_in *sin; 49916221Skarels int s; 50016221Skarels 501*36819Skarels sin = (struct sockaddr_in *)&ar->arp_ha; 502*36819Skarels #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN 503*36819Skarels if (sin->sin_family == 0 && sin->sin_len < 16) 504*36819Skarels sin->sin_family = sin->sin_len; 505*36819Skarels #endif 506*36819Skarels sin->sin_len = sizeof(ar->arp_ha); 507*36819Skarels sin = (struct sockaddr_in *)&ar->arp_pa; 508*36819Skarels #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN 509*36819Skarels if (sin->sin_family == 0 && sin->sin_len < 16) 510*36819Skarels sin->sin_family = sin->sin_len; 511*36819Skarels #endif 512*36819Skarels sin->sin_len = sizeof(ar->arp_pa); 51316221Skarels if (ar->arp_pa.sa_family != AF_INET || 51416221Skarels ar->arp_ha.sa_family != AF_UNSPEC) 51516221Skarels return (EAFNOSUPPORT); 51616221Skarels s = splimp(); 51716221Skarels ARPTAB_LOOK(at, sin->sin_addr.s_addr); 51816221Skarels if (at == NULL) { /* not found */ 51916221Skarels if (cmd != SIOCSARP) { 52016221Skarels splx(s); 52116221Skarels return (ENXIO); 52216221Skarels } 52318378Skarels if (ifa_ifwithnet(&ar->arp_pa) == NULL) { 52416221Skarels splx(s); 52516221Skarels return (ENETUNREACH); 52616221Skarels } 52716221Skarels } 52816221Skarels switch (cmd) { 52916221Skarels 53016221Skarels case SIOCSARP: /* set entry */ 53116221Skarels if (at == NULL) { 53216221Skarels at = arptnew(&sin->sin_addr); 53332346Skarels if (at == NULL) { 53432346Skarels splx(s); 53532346Skarels return (EADDRNOTAVAIL); 53632346Skarels } 53716221Skarels if (ar->arp_flags & ATF_PERM) { 53816221Skarels /* never make all entries in a bucket permanent */ 53916221Skarels register struct arptab *tat; 54016221Skarels 54116221Skarels /* try to re-allocate */ 54216221Skarels tat = arptnew(&sin->sin_addr); 54316221Skarels if (tat == NULL) { 54416221Skarels arptfree(at); 54516221Skarels splx(s); 54616221Skarels return (EADDRNOTAVAIL); 54716221Skarels } 54816221Skarels arptfree(tat); 54916221Skarels } 55016221Skarels } 55118640Skarels bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr, 55218640Skarels sizeof(at->at_enaddr)); 55316221Skarels at->at_flags = ATF_COM | ATF_INUSE | 55432566Sbostic (ar->arp_flags & (ATF_PERM|ATF_PUBL|ATF_USETRAILERS)); 55516221Skarels at->at_timer = 0; 55616221Skarels break; 55716221Skarels 55816221Skarels case SIOCDARP: /* delete entry */ 55916221Skarels arptfree(at); 56016221Skarels break; 56116221Skarels 56216221Skarels case SIOCGARP: /* get entry */ 563*36819Skarels case OSIOCGARP: 56418640Skarels bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data, 56518640Skarels sizeof(at->at_enaddr)); 566*36819Skarels #ifdef COMPAT_43 567*36819Skarels if (cmd == OSIOCGARP) 568*36819Skarels *(u_short *)&ar->arp_ha = ar->arp_ha.sa_family; 569*36819Skarels #endif 57016221Skarels ar->arp_flags = at->at_flags; 57116221Skarels break; 57216221Skarels } 57316221Skarels splx(s); 57416221Skarels return (0); 57516221Skarels } 576