home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netinet / if_ether.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-08  |  16.7 KB  |  608 lines

  1. /*
  2.  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  *    @(#)if_ether.c    7.13 (Berkeley) 10/31/90
  34.  */
  35.  
  36. /*
  37.  * Ethernet address resolution protocol.
  38.  * TODO:
  39.  *    run at splnet (add ARP protocol intr.)
  40.  *    link entries onto hash chains, keep free list
  41.  *    add "inuse/lock" bit (or ref. count) along with valid bit
  42.  */
  43.  
  44. #include "param.h"
  45. #include "systm.h"
  46. #include "malloc.h"
  47. #include "mbuf.h"
  48. #include "socket.h"
  49. #include "time.h"
  50. #include "kernel.h"
  51. #include "errno.h"
  52. #include "ioctl.h"
  53. #include "syslog.h"
  54.  
  55. #include "../net/if.h"
  56. #include "in.h"
  57. #include "in_systm.h"
  58. #include "in_var.h"
  59. #include "ip.h"
  60. #include "if_ether.h"
  61.  
  62. #ifdef GATEWAY
  63. #define    ARPTAB_BSIZ    16        /* bucket size */
  64. #define    ARPTAB_NB    37        /* number of buckets */
  65. #else
  66. #define    ARPTAB_BSIZ    9        /* bucket size */
  67. #define    ARPTAB_NB    19        /* number of buckets */
  68. #endif
  69. #define    ARPTAB_SIZE    (ARPTAB_BSIZ * ARPTAB_NB)
  70. struct    arptab arptab[ARPTAB_SIZE];
  71. int    arptab_size = ARPTAB_SIZE;    /* for arp command */
  72.  
  73. /*
  74.  * ARP trailer negotiation.  Trailer protocol is not IP specific,
  75.  * but ARP request/response use IP addresses.
  76.  */
  77. #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
  78.  
  79. #define    ARPTAB_HASH(a) \
  80.     ((u_long)(a) % ARPTAB_NB)
  81.  
  82. #define    ARPTAB_LOOK(at,addr) { \
  83.     register n; \
  84.     at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
  85.     for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
  86.         if (at->at_iaddr.s_addr == addr) \
  87.             break; \
  88.     if (n >= ARPTAB_BSIZ) \
  89.         at = 0; \
  90. }
  91.  
  92. /* timer values */
  93. #define    ARPT_AGE    (60*1)    /* aging timer, 1 min. */
  94. #define    ARPT_KILLC    20    /* kill completed entry in 20 mins. */
  95. #define    ARPT_KILLI    3    /* kill incomplete entry in 3 minutes */
  96.  
  97. extern struct ifnet loif;
  98.  
  99. /*
  100.  * Timeout routine.  Age arp_tab entries once a minute.
  101.  */
  102. arptimer()
  103. {
  104.     register struct arptab *at;
  105.     register i;
  106.  
  107.     timeout(arptimer, (caddr_t)0, ARPT_AGE * hz);
  108.     at = &arptab[0];
  109.     for (i = 0; i < ARPTAB_SIZE; i++, at++) {
  110.         if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
  111.             continue;
  112.         if (++at->at_timer < ((at->at_flags&ATF_COM) ?
  113.             ARPT_KILLC : ARPT_KILLI))
  114.             continue;
  115.         /* timer has expired, clear entry */
  116.         arptfree(at);
  117.     }
  118. }
  119.  
  120. /*
  121.  * Broadcast an ARP packet, asking who has addr on interface ac.
  122.  */
  123. arpwhohas(ac, addr)
  124.     register struct arpcom *ac;
  125.     struct in_addr *addr;
  126. {
  127.     register struct mbuf *m;
  128.     register struct ether_header *eh;
  129.     register struct ether_arp *ea;
  130.     struct sockaddr sa;
  131.  
  132.     if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
  133.         return;
  134.     m->m_len = sizeof(*ea);
  135.     m->m_pkthdr.len = sizeof(*ea);
  136.     MH_ALIGN(m, sizeof(*ea));
  137.     ea = mtod(m, struct ether_arp *);
  138.     eh = (struct ether_header *)sa.sa_data;
  139.     bzero((caddr_t)ea, sizeof (*ea));
  140.     bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
  141.         sizeof(eh->ether_dhost));
  142.     eh->ether_type = ETHERTYPE_ARP;        /* if_output will swap */
  143.     ea->arp_hrd = htons(ARPHRD_ETHER);
  144.     ea->arp_pro = htons(ETHERTYPE_IP);
  145.     ea->arp_hln = sizeof(ea->arp_sha);    /* hardware address length */
  146.     ea->arp_pln = sizeof(ea->arp_spa);    /* protocol address length */
  147.     ea->arp_op = htons(ARPOP_REQUEST);
  148.     bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
  149.        sizeof(ea->arp_sha));
  150.     bcopy((caddr_t)&ac->ac_ipaddr, (caddr_t)ea->arp_spa,
  151.        sizeof(ea->arp_spa));
  152.     bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
  153.     sa.sa_family = AF_UNSPEC;
  154.     sa.sa_len = sizeof(sa);
  155.     (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
  156. }
  157.  
  158. int    useloopback = 1;    /* use loopback interface for local traffic */
  159.  
  160. /*
  161.  * Resolve an IP address into an ethernet address.  If success, 
  162.  * desten is filled in.  If there is no entry in arptab,
  163.  * set one up and broadcast a request for the IP address.
  164.  * Hold onto this mbuf and resend it once the address
  165.  * is finally resolved.  A return value of 1 indicates
  166.  * that desten has been filled in and the packet should be sent
  167.  * normally; a 0 return indicates that the packet has been
  168.  * taken over here, either now or for later transmission.
  169.  *
  170.  * We do some (conservative) locking here at splimp, since
  171.  * arptab is also altered from input interrupt service (ecintr/ilintr
  172.  * calls arpinput when ETHERTYPE_ARP packets come in).
  173.  */
  174. arpresolve(ac, m, destip, desten, usetrailers)
  175.     register struct arpcom *ac;
  176.     struct mbuf *m;
  177.     register struct in_addr *destip;
  178.     register u_char *desten;
  179.     int *usetrailers;
  180. {
  181.     register struct arptab *at;
  182.     struct sockaddr_in sin;
  183.     register struct in_ifaddr *ia;
  184.     u_long lna;
  185.     int s;
  186.  
  187.     *usetrailers = 0;
  188.     if (m->m_flags & M_BCAST) {    /* broadcast */
  189.         bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
  190.             sizeof(etherbroadcastaddr));
  191.         return (1);
  192.     }
  193.     lna = in_lnaof(*destip);
  194.     /* if for us, use software loopback driver if up */
  195.     for (ia = in_ifaddr; ia; ia = ia->ia_next)
  196.         if ((ia->ia_ifp == &ac->ac_if) &&
  197.         (destip->s_addr == ia->ia_addr.sin_addr.s_addr)) {
  198.         /*
  199.          * This test used to be
  200.          *    if (loif.if_flags & IFF_UP)
  201.          * It allowed local traffic to be forced
  202.          * through the hardware by configuring the loopback down.
  203.          * However, it causes problems during network configuration
  204.          * for boards that can't receive packets they send.
  205.          * It is now necessary to clear "useloopback"
  206.          * to force traffic out to the hardware.
  207.          */
  208.         if (useloopback) {
  209.             sin.sin_family = AF_INET;
  210.             sin.sin_addr = *destip;
  211.             (void) looutput(&loif, m, (struct sockaddr *)&sin, 0);
  212.             /*
  213.              * The packet has already been sent and freed.
  214.              */
  215.             return (0);
  216.         } else {
  217.             bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten,
  218.                 sizeof(ac->ac_enaddr));
  219.             return (1);
  220.         }
  221.     }
  222.     s = splimp();
  223.     ARPTAB_LOOK(at, destip->s_addr);
  224.     if (at == 0) {            /* not found */
  225.         if (ac->ac_if.if_flags & IFF_NOARP) {
  226.             bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
  227.             desten[3] = (lna >> 16) & 0x7f;
  228.             desten[4] = (lna >> 8) & 0xff;
  229.             desten[5] = lna & 0xff;
  230.             splx(s);
  231.             return (1);
  232.         } else {
  233.             at = arptnew(destip);
  234.             if (at == 0)
  235.                 panic("arpresolve: no free entry");
  236.             at->at_hold = m;
  237.             arpwhohas(ac, destip);
  238.             splx(s);
  239.             return (0);
  240.         }
  241.     }
  242.     at->at_timer = 0;        /* restart the timer */
  243.     if (at->at_flags & ATF_COM) {    /* entry IS complete */
  244.         bcopy((caddr_t)at->at_enaddr, (caddr_t)desten,
  245.             sizeof(at->at_enaddr));
  246.         if (at->at_flags & ATF_USETRAILERS)
  247.             *usetrailers = 1;
  248.         splx(s);
  249.         return (1);
  250.     }
  251.     /*
  252.      * There is an arptab entry, but no ethernet address
  253.      * response yet.  Replace the held mbuf with this
  254.      * latest one.
  255.      */
  256.     if (at->at_hold)
  257.         m_freem(at->at_hold);
  258.     at->at_hold = m;
  259.     arpwhohas(ac, destip);        /* ask again */
  260.     splx(s);
  261.     return (0);
  262. }
  263.  
  264. /*
  265.  * Called from 10 Mb/s Ethernet interrupt handlers
  266.  * when ether packet type ETHERTYPE_ARP
  267.  * is received.  Common length and type checks are done here,
  268.  * then the protocol-specific routine is called.
  269.  */
  270. arpinput(ac, m)
  271.     struct arpcom *ac;
  272.     struct mbuf *m;
  273. {
  274.     register struct arphdr *ar;
  275.  
  276.     if (ac->ac_if.if_flags & IFF_NOARP)
  277.         goto out;
  278.     if (m->m_len < sizeof(struct arphdr))
  279.         goto out;
  280.     ar = mtod(m, struct arphdr *);
  281.     if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
  282.         goto out;
  283.     if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
  284.         goto out;
  285.  
  286.     switch (ntohs(ar->ar_pro)) {
  287.  
  288.     case ETHERTYPE_IP:
  289.     case ETHERTYPE_IPTRAILERS:
  290.         in_arpinput(ac, m);
  291.         return;
  292.  
  293.     default:
  294.         break;
  295.     }
  296. out:
  297.     m_freem(m);
  298. }
  299.  
  300. /*
  301.  * ARP for Internet protocols on 10 Mb/s Ethernet.
  302.  * Algorithm is that given in RFC 826.
  303.  * In addition, a sanity check is performed on the sender
  304.  * protocol address, to catch impersonators.
  305.  * We also handle negotiations for use of trailer protocol:
  306.  * ARP replies for protocol type ETHERTYPE_TRAIL are sent
  307.  * along with IP replies if we want trailers sent to us,
  308.  * and also send them in response to IP replies.
  309.  * This allows either end to announce the desire to receive
  310.  * trailer packets.
  311.  * We reply to requests for ETHERTYPE_TRAIL protocol as well,
  312.  * but don't normally send requests.
  313.  */
  314. in_arpinput(ac, m)
  315.     register struct arpcom *ac;
  316.     struct mbuf *m;
  317. {
  318.     register struct ether_arp *ea;
  319.     struct ether_header *eh;
  320.     register struct arptab *at;  /* same as "merge" flag */
  321.     register struct in_ifaddr *ia;
  322.     struct in_ifaddr *maybe_ia = 0;
  323.     struct mbuf *mcopy = 0;
  324.     struct sockaddr_in sin;
  325.     struct sockaddr sa;
  326.     struct in_addr isaddr, itaddr, myaddr;
  327.     int proto, op, s, completed = 0;
  328.  
  329.     ea = mtod(m, struct ether_arp *);
  330.     proto = ntohs(ea->arp_pro);
  331.     op = ntohs(ea->arp_op);
  332.     bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
  333.     bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
  334.     for (ia = in_ifaddr; ia; ia = ia->ia_next)
  335.         if (ia->ia_ifp == &ac->ac_if) {
  336.             maybe_ia = ia;
  337.             if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
  338.                  (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
  339.                 break;
  340.         }
  341.     if (maybe_ia == 0)
  342.         goto out;
  343.     myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
  344.     if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
  345.         sizeof (ea->arp_sha)))
  346.         goto out;    /* it's from me, ignore it. */
  347.     if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
  348.         sizeof (ea->arp_sha))) {
  349.         log(LOG_ERR,
  350.             "arp: ether address is broadcast for IP address %x!\n",
  351.             ntohl(isaddr.s_addr));
  352.         goto out;
  353.     }
  354.     if (isaddr.s_addr == myaddr.s_addr) {
  355.         log(LOG_ERR,
  356.            "duplicate IP address %x!! sent from ethernet address: %s\n",
  357.            ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha));
  358.         itaddr = myaddr;
  359.         if (op == ARPOP_REQUEST)
  360.             goto reply;
  361.         goto out;
  362.     }
  363.     s = splimp();
  364.     ARPTAB_LOOK(at, isaddr.s_addr);
  365.     if (at) {
  366.         bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
  367.             sizeof(ea->arp_sha));
  368.         if ((at->at_flags & ATF_COM) == 0)
  369.             completed = 1;
  370.         at->at_flags |= ATF_COM;
  371.         if (at->at_hold) {
  372.             sin.sin_family = AF_INET;
  373.             sin.sin_addr = isaddr;
  374.             (*ac->ac_if.if_output)(&ac->ac_if, at->at_hold,
  375.                 (struct sockaddr *)&sin, (struct rtentry *)0);
  376.             at->at_hold = 0;
  377.         }
  378.     }
  379.     if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
  380.         /* ensure we have a table entry */
  381.         if (at = arptnew(&isaddr)) {
  382.             bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
  383.                 sizeof(ea->arp_sha));
  384.             completed = 1;
  385.             at->at_flags |= ATF_COM;
  386.         }
  387.     }
  388.     splx(s);
  389. reply:
  390.     switch (proto) {
  391.  
  392.     case ETHERTYPE_IPTRAILERS:
  393.         /* partner says trailers are OK */
  394.         if (at)
  395.             at->at_flags |= ATF_USETRAILERS;
  396.         /*
  397.          * Reply to request iff we want trailers.
  398.          */
  399.         if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS)
  400.             goto out;
  401.         break;
  402.  
  403.     case ETHERTYPE_IP:
  404.         /*
  405.          * Reply if this is an IP request,
  406.          * or if we want to send a trailer response.
  407.          * Send the latter only to the IP response
  408.          * that completes the current ARP entry.
  409.          */
  410.         if (op != ARPOP_REQUEST &&
  411.             (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS))
  412.             goto out;
  413.     }
  414.     if (itaddr.s_addr == myaddr.s_addr) {
  415.         /* I am the target */
  416.         bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
  417.             sizeof(ea->arp_sha));
  418.         bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
  419.             sizeof(ea->arp_sha));
  420.     } else {
  421.         ARPTAB_LOOK(at, itaddr.s_addr);
  422.         if (at == NULL || (at->at_flags & ATF_PUBL) == 0)
  423.             goto out;
  424.         bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
  425.             sizeof(ea->arp_sha));
  426.         bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha,
  427.             sizeof(ea->arp_sha));
  428.     }
  429.  
  430.     bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
  431.         sizeof(ea->arp_spa));
  432.     bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa,
  433.         sizeof(ea->arp_spa));
  434.     ea->arp_op = htons(ARPOP_REPLY); 
  435.     /*
  436.      * If incoming packet was an IP reply,
  437.      * we are sending a reply for type IPTRAILERS.
  438.      * If we are sending a reply for type IP
  439.      * and we want to receive trailers,
  440.      * send a trailer reply as well.
  441.      */
  442.     if (op == ARPOP_REPLY)
  443.         ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
  444.     else if (proto == ETHERTYPE_IP &&
  445.         (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0)
  446.         mcopy = m_copy(m, 0, (int)M_COPYALL);
  447.     eh = (struct ether_header *)sa.sa_data;
  448.     bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
  449.         sizeof(eh->ether_dhost));
  450.     eh->ether_type = ETHERTYPE_ARP;
  451.     sa.sa_family = AF_UNSPEC;
  452.     sa.sa_len = sizeof(sa);
  453.     (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
  454.     if (mcopy) {
  455.         ea = mtod(mcopy, struct ether_arp *);
  456.         ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
  457.         (*ac->ac_if.if_output)(&ac->ac_if,
  458.                     mcopy, &sa, (struct rtentry *)0);
  459.     }
  460.     return;
  461. out:
  462.     m_freem(m);
  463.     return;
  464. }
  465.  
  466. /*
  467.  * Free an arptab entry.
  468.  */
  469. arptfree(at)
  470.     register struct arptab *at;
  471. {
  472.     int s = splimp();
  473.  
  474.     if (at->at_hold)
  475.         m_freem(at->at_hold);
  476.     at->at_hold = 0;
  477.     at->at_timer = at->at_flags = 0;
  478.     at->at_iaddr.s_addr = 0;
  479.     splx(s);
  480. }
  481.  
  482. /*
  483.  * Enter a new address in arptab, pushing out the oldest entry 
  484.  * from the bucket if there is no room.
  485.  * This always succeeds since no bucket can be completely filled
  486.  * with permanent entries (except from arpioctl when testing whether
  487.  * another permanent entry will fit).
  488.  * MUST BE CALLED AT SPLIMP.
  489.  */
  490. struct arptab *
  491. arptnew(addr)
  492.     struct in_addr *addr;
  493. {
  494.     register n;
  495.     int oldest = -1;
  496.     register struct arptab *at, *ato = NULL;
  497.     static int first = 1;
  498.  
  499.     if (first) {
  500.         first = 0;
  501.         timeout(arptimer, (caddr_t)0, hz);
  502.     }
  503.     at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
  504.     for (n = 0; n < ARPTAB_BSIZ; n++,at++) {
  505.         if (at->at_flags == 0)
  506.             goto out;     /* found an empty entry */
  507.         if (at->at_flags & ATF_PERM)
  508.             continue;
  509.         if ((int) at->at_timer > oldest) {
  510.             oldest = at->at_timer;
  511.             ato = at;
  512.         }
  513.     }
  514.     if (ato == NULL)
  515.         return (NULL);
  516.     at = ato;
  517.     arptfree(at);
  518. out:
  519.     at->at_iaddr = *addr;
  520.     at->at_flags = ATF_INUSE;
  521.     return (at);
  522. }
  523.  
  524. arpioctl(cmd, data)
  525.     int cmd;
  526.     caddr_t data;
  527. {
  528.     register struct arpreq *ar = (struct arpreq *)data;
  529.     register struct arptab *at;
  530.     register struct sockaddr_in *sin;
  531.     int s;
  532.  
  533.     sin = (struct sockaddr_in *)&ar->arp_ha;
  534. #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN
  535.     if (sin->sin_family == 0 && sin->sin_len < 16)
  536.         sin->sin_family = sin->sin_len;
  537. #endif
  538.     sin->sin_len = sizeof(ar->arp_ha);
  539.     sin = (struct sockaddr_in *)&ar->arp_pa;
  540. #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN
  541.     if (sin->sin_family == 0 && sin->sin_len < 16)
  542.         sin->sin_family = sin->sin_len;
  543. #endif
  544.     sin->sin_len = sizeof(ar->arp_pa);
  545.     if (ar->arp_pa.sa_family != AF_INET ||
  546.         ar->arp_ha.sa_family != AF_UNSPEC)
  547.         return (EAFNOSUPPORT);
  548.     s = splimp();
  549.     ARPTAB_LOOK(at, sin->sin_addr.s_addr);
  550.     if (at == NULL) {        /* not found */
  551.         if (cmd != SIOCSARP) {
  552.             splx(s);
  553.             return (ENXIO);
  554.         }
  555.         if (ifa_ifwithnet(&ar->arp_pa) == NULL) {
  556.             splx(s);
  557.             return (ENETUNREACH);
  558.         }
  559.     }
  560.     switch (cmd) {
  561.  
  562.     case SIOCSARP:        /* set entry */
  563.         if (at == NULL) {
  564.             at = arptnew(&sin->sin_addr);
  565.             if (at == NULL) {
  566.                 splx(s);
  567.                 return (EADDRNOTAVAIL);
  568.             }
  569.             if (ar->arp_flags & ATF_PERM) {
  570.             /* never make all entries in a bucket permanent */
  571.                 register struct arptab *tat;
  572.                 
  573.                 /* try to re-allocate */
  574.                 tat = arptnew(&sin->sin_addr);
  575.                 if (tat == NULL) {
  576.                     arptfree(at);
  577.                     splx(s);
  578.                     return (EADDRNOTAVAIL);
  579.                 }
  580.                 arptfree(tat);
  581.             }
  582.         }
  583.         bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr,
  584.             sizeof(at->at_enaddr));
  585.         at->at_flags = ATF_COM | ATF_INUSE |
  586.             (ar->arp_flags & (ATF_PERM|ATF_PUBL|ATF_USETRAILERS));
  587.         at->at_timer = 0;
  588.         break;
  589.  
  590.     case SIOCDARP:        /* delete entry */
  591.         arptfree(at);
  592.         break;
  593.  
  594.     case SIOCGARP:        /* get entry */
  595.     case OSIOCGARP:
  596.         bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data,
  597.             sizeof(at->at_enaddr));
  598. #ifdef COMPAT_43
  599.         if (cmd == OSIOCGARP)
  600.             *(u_short *)&ar->arp_ha = ar->arp_ha.sa_family;
  601. #endif
  602.         ar->arp_flags = at->at_flags;
  603.         break;
  604.     }
  605.     splx(s);
  606.     return (0);
  607. }
  608.