The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/lib/libsa/arp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: arp.c,v 1.24 2003/08/31 22:40:47 fvdl Exp $    */
    2 
    3 /*
    4  * Copyright (c) 1992 Regents of the University of California.
    5  * All rights reserved.
    6  *
    7  * This software was developed by the Computer Systems Engineering group
    8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
    9  * contributed to Berkeley.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the University of
   22  *      California, Lawrence Berkeley Laboratory and its contributors.
   23  * 4. Neither the name of the University nor the names of its contributors
   24  *    may be used to endorse or promote products derived from this software
   25  *    without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   37  * SUCH DAMAGE.
   38  *
   39  * @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp  (LBL)
   40  */
   41 
   42 #include <sys/types.h>
   43 #include <sys/socket.h>
   44 #include <net/if.h>
   45 #include <net/if_ether.h>
   46 #include <netinet/in.h>
   47 
   48 #include <netinet/in_systm.h>
   49 
   50 #ifdef _STANDALONE
   51 #include <lib/libkern/libkern.h>
   52 #else
   53 #include <string.h>
   54 #endif
   55 
   56 #include "stand.h"
   57 #include "net.h"
   58 
   59 /*
   60  * Ethernet Address Resolution Protocol.
   61  *
   62  * See RFC 826 for protocol description.  Structure below is adapted
   63  * to resolving internet addresses.  Field names used correspond to 
   64  * RFC 826.
   65  */
   66 struct  ether_arp {
   67         struct   arphdr ea_hdr;                 /* fixed-size header */
   68         u_int8_t arp_sha[ETHER_ADDR_LEN];       /* sender hardware address */
   69         u_int8_t arp_spa[4];                    /* sender protocol address */
   70         u_int8_t arp_tha[ETHER_ADDR_LEN];       /* target hardware address */
   71         u_int8_t arp_tpa[4];                    /* target protocol address */
   72 };
   73 #define arp_hrd ea_hdr.ar_hrd
   74 #define arp_pro ea_hdr.ar_pro
   75 #define arp_hln ea_hdr.ar_hln
   76 #define arp_pln ea_hdr.ar_pln
   77 #define arp_op  ea_hdr.ar_op
   78 
   79 /* Cache stuff */
   80 #define ARP_NUM 8                       /* need at most 3 arp entries */
   81 
   82 struct arp_list {
   83         struct in_addr  addr;
   84         u_char          ea[6];
   85 } arp_list[ARP_NUM] = {
   86         /* XXX - net order `INADDR_BROADCAST' must be a constant */
   87         { {0xffffffff}, BA }
   88 };
   89 int arp_num = 1;
   90 
   91 /* Local forwards */
   92 static  ssize_t arpsend __P((struct iodesc *, void *, size_t));
   93 static  ssize_t arprecv __P((struct iodesc *, void *, size_t, time_t));
   94 
   95 /* Broadcast an ARP packet, asking who has addr on interface d */
   96 u_char *
   97 arpwhohas(d, addr)
   98         struct iodesc *d;
   99         struct in_addr addr;
  100 {
  101         int i;
  102         struct ether_arp *ah;
  103         struct arp_list *al;
  104         struct {
  105                 struct ether_header eh;
  106                 struct {
  107                         struct ether_arp arp;
  108                         u_char pad[18];         /* 60 - sizeof(...) */
  109                 } data;
  110         } wbuf;
  111         struct {
  112                 struct ether_header eh;
  113                 struct {
  114                         struct ether_arp arp;
  115                         u_char pad[24];         /* extra space */
  116                 } data;
  117         } rbuf;
  118 
  119         /* Try for cached answer first */
  120         for (i = 0, al = arp_list; i < arp_num; ++i, ++al)
  121                 if (addr.s_addr == al->addr.s_addr)
  122                         return (al->ea);
  123 
  124         /* Don't overflow cache */
  125         if (arp_num > ARP_NUM - 1) {
  126                 arp_num = 1;    /* recycle */
  127                 printf("arpwhohas: overflowed arp_list!\n");
  128         }
  129 
  130 #ifdef ARP_DEBUG
  131         if (debug)
  132             printf("arpwhohas: send request for %s\n", inet_ntoa(addr));
  133 #endif
  134 
  135         bzero((char*)&wbuf.data, sizeof(wbuf.data));
  136         ah = &wbuf.data.arp;
  137         ah->arp_hrd = htons(ARPHRD_ETHER);
  138         ah->arp_pro = htons(ETHERTYPE_IP);
  139         ah->arp_hln = sizeof(ah->arp_sha); /* hardware address length */
  140         ah->arp_pln = sizeof(ah->arp_spa); /* protocol address length */
  141         ah->arp_op = htons(ARPOP_REQUEST);
  142         MACPY(d->myea, ah->arp_sha);
  143         bcopy(&d->myip, ah->arp_spa, sizeof(ah->arp_spa));
  144         /* Leave zeros in arp_tha */
  145         bcopy(&addr, ah->arp_tpa, sizeof(ah->arp_tpa));
  146 
  147         /* Store ip address in cache (incomplete entry). */
  148         al->addr = addr;
  149 
  150         i = sendrecv(d,
  151             arpsend, &wbuf.data, sizeof(wbuf.data),
  152             arprecv, &rbuf.data, sizeof(rbuf.data));
  153         if (i == -1) {
  154                 panic("arp: no response for %s",
  155                           inet_ntoa(addr));
  156         }
  157 
  158         /* Store ethernet address in cache */
  159         ah = &rbuf.data.arp;
  160 #ifdef ARP_DEBUG
  161         if (debug) {
  162                 printf("arp: response from %s\n",
  163                     ether_sprintf(rbuf.eh.ether_shost));
  164                 printf("arp: cacheing %s --> %s\n",
  165                     inet_ntoa(addr), ether_sprintf(ah->arp_sha));
  166         }
  167 #endif
  168         MACPY(ah->arp_sha, al->ea);
  169         ++arp_num;
  170 
  171         return (al->ea);
  172 }
  173 
  174 static ssize_t
  175 arpsend(d, pkt, len)
  176         struct iodesc *d;
  177         void *pkt;
  178         size_t len;
  179 {
  180 
  181 #ifdef ARP_DEBUG
  182         if (debug)
  183                 printf("arpsend: called\n");
  184 #endif
  185 
  186         return (sendether(d, pkt, len, bcea, ETHERTYPE_ARP));
  187 }
  188 
  189 /*
  190  * Returns 0 if this is the packet we're waiting for
  191  * else -1 (and errno == 0)
  192  */
  193 static ssize_t
  194 arprecv(d, pkt, len, tleft)
  195         struct iodesc *d;
  196         void *pkt;
  197         size_t len;
  198         time_t tleft;
  199 {
  200         ssize_t n;
  201         struct ether_arp *ah;
  202         u_int16_t etype;        /* host order */
  203 
  204 #ifdef ARP_DEBUG
  205         if (debug)
  206                 printf("arprecv: ");
  207 #endif
  208 
  209         n = readether(d, pkt, len, tleft, &etype);
  210         errno = 0;      /* XXX */
  211         if (n == -1 || (size_t)n < sizeof(struct ether_arp)) {
  212 #ifdef ARP_DEBUG
  213                 if (debug)
  214                         printf("bad len=%ld\n", (signed long) n);
  215 #endif
  216                 return (-1);
  217         }
  218 
  219         if (etype != ETHERTYPE_ARP) {
  220 #ifdef ARP_DEBUG
  221                 if (debug)
  222                         printf("not arp type=%d\n", etype);
  223 #endif
  224                 return (-1);
  225         }
  226 
  227         /* Ethernet address now checked in readether() */
  228 
  229         ah = (struct ether_arp *)pkt;
  230         if (ah->arp_hrd != htons(ARPHRD_ETHER) ||
  231             ah->arp_pro != htons(ETHERTYPE_IP) ||
  232             ah->arp_hln != sizeof(ah->arp_sha) ||
  233             ah->arp_pln != sizeof(ah->arp_spa) )
  234         {
  235 #ifdef ARP_DEBUG
  236                 if (debug)
  237                         printf("bad hrd/pro/hln/pln\n");
  238 #endif
  239                 return (-1);
  240         }
  241 
  242         if (ah->arp_op == htons(ARPOP_REQUEST)) {
  243 #ifdef ARP_DEBUG
  244                 if (debug)
  245                         printf("is request\n");
  246 #endif
  247                 arp_reply(d, ah);
  248                 return (-1);
  249         }
  250 
  251         if (ah->arp_op != htons(ARPOP_REPLY)) {
  252 #ifdef ARP_DEBUG
  253                 if (debug)
  254                         printf("not ARP reply\n");
  255 #endif
  256                 return (-1);
  257         }
  258 
  259         /* Is the reply from the source we want? */
  260         if (bcmp(&arp_list[arp_num].addr,
  261                          ah->arp_spa, sizeof(ah->arp_spa)))
  262         {
  263 #ifdef ARP_DEBUG
  264                 if (debug)
  265                         printf("unwanted address\n");
  266 #endif
  267                 return (-1);
  268         }
  269         /* We don't care who the reply was sent to. */
  270 
  271         /* We have our answer. */
  272 #ifdef ARP_DEBUG
  273         if (debug)
  274                 printf("got it\n");
  275 #endif
  276         return (n);
  277 }
  278 
  279 /*
  280  * Convert an ARP request into a reply and send it.
  281  * Notes:  Re-uses buffer.  Pad to length = 46.
  282  */
  283 void
  284 arp_reply(d, pkt)
  285         struct iodesc *d;
  286         void *pkt;              /* the request */
  287 {
  288         struct ether_arp *arp = pkt;
  289 
  290         if (arp->arp_hrd != htons(ARPHRD_ETHER) ||
  291             arp->arp_pro != htons(ETHERTYPE_IP) ||
  292             arp->arp_hln != sizeof(arp->arp_sha) ||
  293             arp->arp_pln != sizeof(arp->arp_spa) )
  294         {
  295 #ifdef ARP_DEBUG
  296                 if (debug)
  297                         printf("arp_reply: bad hrd/pro/hln/pln\n");
  298 #endif
  299                 return;
  300         }
  301 
  302         if (arp->arp_op != htons(ARPOP_REQUEST)) {
  303 #ifdef ARP_DEBUG
  304                 if (debug)
  305                         printf("arp_reply: not request!\n");
  306 #endif
  307                 return;
  308         }
  309 
  310         /* If we are not the target, ignore the request. */
  311         if (bcmp(arp->arp_tpa, &d->myip, sizeof(arp->arp_tpa)))
  312                 return;
  313 
  314 #ifdef ARP_DEBUG
  315         if (debug) {
  316                 printf("arp_reply: to %s\n", ether_sprintf(arp->arp_sha));
  317         }
  318 #endif
  319 
  320         arp->arp_op = htons(ARPOP_REPLY);
  321         /* source becomes target */
  322         bcopy(arp->arp_sha, arp->arp_tha, sizeof(arp->arp_tha));
  323         bcopy(arp->arp_spa, arp->arp_tpa, sizeof(arp->arp_tpa));
  324         /* here becomes source */
  325         bcopy(d->myea,  arp->arp_sha, sizeof(arp->arp_sha));
  326         bcopy(&d->myip, arp->arp_spa, sizeof(arp->arp_spa));
  327 
  328         /*
  329          * No need to get fancy here.  If the send fails, the
  330          * requestor will just ask again.
  331          */
  332         (void) sendether(d, pkt, sizeof(*arp) + 18,
  333                          arp->arp_tha, ETHERTYPE_ARP);
  334 }

Cache object: 03f06deb0789ed058f2d313123ccd659


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.