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/netinet/if_ether.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 /*      $OpenBSD: if_ether.c,v 1.256 2023/01/31 13:41:54 mvs Exp $      */
    2 /*      $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $    */
    3 
    4 /*
    5  * Copyright (c) 1982, 1986, 1988, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)if_ether.c  8.1 (Berkeley) 6/10/93
   33  */
   34 
   35 /*
   36  * Ethernet address resolution protocol.
   37  * TODO:
   38  *      add "inuse/lock" bit (or ref. count) along with valid bit
   39  */
   40 
   41 #include "carp.h"
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/mbuf.h>
   46 #include <sys/socket.h>
   47 #include <sys/timeout.h>
   48 #include <sys/kernel.h>
   49 #include <sys/syslog.h>
   50 #include <sys/queue.h>
   51 #include <sys/pool.h>
   52 
   53 #include <net/if.h>
   54 #include <net/if_var.h>
   55 #include <net/if_dl.h>
   56 #include <net/route.h>
   57 #include <net/if_types.h>
   58 #include <net/netisr.h>
   59 
   60 #include <netinet/in.h>
   61 #include <netinet/in_var.h>
   62 #include <netinet/if_ether.h>
   63 #include <netinet/ip_var.h>
   64 #if NCARP > 0
   65 #include <netinet/ip_carp.h>
   66 #endif
   67 
   68 /*
   69  *  Locks used to protect struct members in this file:
   70  *      a       atomic operations
   71  *      I       immutable after creation
   72  *      K       kernel lock
   73  *      m       arp mutex, needed when net lock is shared
   74  *      N       net lock
   75  */
   76 
   77 struct llinfo_arp {
   78         LIST_ENTRY(llinfo_arp)   la_list;       /* [mN] global arp_list */
   79         struct rtentry          *la_rt;         /* [I] backpointer to rtentry */
   80         struct mbuf_queue        la_mq;         /* packet hold queue */
   81         time_t                   la_refreshed;  /* when was refresh sent */
   82         int                      la_asked;      /* number of queries sent */
   83 };
   84 #define LA_HOLD_QUEUE 10
   85 #define LA_HOLD_TOTAL 100
   86 
   87 /* timer values */
   88 int     arpt_prune = (5 * 60);  /* [I] walk list every 5 minutes */
   89 int     arpt_keep = (20 * 60);  /* [a] once resolved, cache for 20 minutes */
   90 int     arpt_down = 20; /* [a] once declared down, don't send for 20 secs */
   91 
   92 struct mbuf *arppullup(struct mbuf *m);
   93 void arpinvalidate(struct rtentry *);
   94 void arptfree(struct rtentry *);
   95 void arptimer(void *);
   96 struct rtentry *arplookup(struct in_addr *, int, int, unsigned int);
   97 void in_arpinput(struct ifnet *, struct mbuf *);
   98 void in_revarpinput(struct ifnet *, struct mbuf *);
   99 int arpcache(struct ifnet *, struct ether_arp *, struct rtentry *);
  100 void arpreply(struct ifnet *, struct mbuf *, struct in_addr *, uint8_t *,
  101     unsigned int);
  102 
  103 struct niqueue arpinq = NIQUEUE_INITIALIZER(50, NETISR_ARP);
  104 
  105 /* llinfo_arp live time, rt_llinfo and RTF_LLINFO are protected by arp_mtx */
  106 struct mutex arp_mtx = MUTEX_INITIALIZER(IPL_SOFTNET);
  107 
  108 LIST_HEAD(, llinfo_arp) arp_list; /* [mN] list of all llinfo_arp structures */
  109 struct  pool arp_pool;          /* [I] pool for llinfo_arp structures */
  110 int     arp_maxtries = 5;       /* [I] arp requests before set to rejected */
  111 int     la_hold_total;          /* [a] packets currently in the arp queue */
  112 
  113 #ifdef NFSCLIENT
  114 /* revarp state */
  115 struct in_addr revarp_myip, revarp_srvip;
  116 int revarp_finished;
  117 unsigned int revarp_ifidx;
  118 #endif /* NFSCLIENT */
  119 
  120 /*
  121  * Timeout routine.  Age arp_tab entries periodically.
  122  */
  123 /* ARGSUSED */
  124 void
  125 arptimer(void *arg)
  126 {
  127         struct timeout *to = arg;
  128         struct llinfo_arp *la, *nla;
  129         time_t uptime;
  130 
  131         NET_LOCK();
  132         uptime = getuptime();
  133         timeout_add_sec(to, arpt_prune);
  134         /* Net lock is exclusive, no arp mutex needed for arp_list here. */
  135         LIST_FOREACH_SAFE(la, &arp_list, la_list, nla) {
  136                 struct rtentry *rt = la->la_rt;
  137 
  138                 if (rt->rt_expire && rt->rt_expire < uptime)
  139                         arptfree(rt); /* timer has expired; clear */
  140         }
  141         NET_UNLOCK();
  142 }
  143 
  144 void
  145 arpinit(void)
  146 {
  147         static struct timeout arptimer_to;
  148 
  149         pool_init(&arp_pool, sizeof(struct llinfo_arp), 0,
  150             IPL_SOFTNET, 0, "arp", NULL);
  151 
  152         timeout_set_proc(&arptimer_to, arptimer, &arptimer_to);
  153         timeout_add_sec(&arptimer_to, arpt_prune);
  154 }
  155 
  156 void
  157 arp_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt)
  158 {
  159         struct sockaddr *gate = rt->rt_gateway;
  160         struct llinfo_arp *la;
  161         time_t uptime;
  162 
  163         NET_ASSERT_LOCKED();
  164 
  165         if (ISSET(rt->rt_flags,
  166             RTF_GATEWAY|RTF_BROADCAST|RTF_MULTICAST|RTF_MPLS))
  167                 return;
  168 
  169         uptime = getuptime();
  170         switch (req) {
  171         case RTM_ADD:
  172                 if (rt->rt_flags & RTF_CLONING) {
  173                         rt->rt_expire = 0;
  174                         break;
  175                 }
  176                 if ((rt->rt_flags & RTF_LOCAL) && rt->rt_llinfo == NULL)
  177                         rt->rt_expire = 0;
  178                 /*
  179                  * Announce a new entry if requested or warn the user
  180                  * if another station has this IP address.
  181                  */
  182                 if (rt->rt_flags & (RTF_ANNOUNCE|RTF_LOCAL))
  183                         arprequest(ifp,
  184                             &satosin(rt_key(rt))->sin_addr.s_addr,
  185                             &satosin(rt_key(rt))->sin_addr.s_addr,
  186                             (u_char *)LLADDR(satosdl(gate)));
  187                 /*FALLTHROUGH*/
  188         case RTM_RESOLVE:
  189                 if (gate->sa_family != AF_LINK ||
  190                     gate->sa_len < sizeof(struct sockaddr_dl)) {
  191                         log(LOG_DEBUG, "%s: bad gateway value: %s\n", __func__,
  192                             ifp->if_xname);
  193                         break;
  194                 }
  195                 satosdl(gate)->sdl_type = ifp->if_type;
  196                 satosdl(gate)->sdl_index = ifp->if_index;
  197                 /*
  198                  * Case 2:  This route may come from cloning, or a manual route
  199                  * add with a LL address.
  200                  */
  201                 la = pool_get(&arp_pool, PR_NOWAIT | PR_ZERO);
  202                 if (la == NULL) {
  203                         log(LOG_DEBUG, "%s: pool get failed\n", __func__);
  204                         break;
  205                 }
  206 
  207                 mtx_enter(&arp_mtx);
  208                 if (rt->rt_llinfo != NULL) {
  209                         /* we lost the race, another thread has entered it */
  210                         mtx_leave(&arp_mtx);
  211                         pool_put(&arp_pool, la);
  212                         break;
  213                 }
  214                 mq_init(&la->la_mq, LA_HOLD_QUEUE, IPL_SOFTNET);
  215                 rt->rt_llinfo = (caddr_t)la;
  216                 la->la_rt = rt;
  217                 rt->rt_flags |= RTF_LLINFO;
  218                 LIST_INSERT_HEAD(&arp_list, la, la_list);
  219                 if ((rt->rt_flags & RTF_LOCAL) == 0)
  220                         rt->rt_expire = uptime;
  221                 mtx_leave(&arp_mtx);
  222 
  223                 break;
  224 
  225         case RTM_DELETE:
  226                 mtx_enter(&arp_mtx);
  227                 la = (struct llinfo_arp *)rt->rt_llinfo;
  228                 if (la == NULL) {
  229                         /* we lost the race, another thread has removed it */
  230                         mtx_leave(&arp_mtx);
  231                         break;
  232                 }
  233                 LIST_REMOVE(la, la_list);
  234                 rt->rt_llinfo = NULL;
  235                 rt->rt_flags &= ~RTF_LLINFO;
  236                 atomic_sub_int(&la_hold_total, mq_purge(&la->la_mq));
  237                 mtx_leave(&arp_mtx);
  238 
  239                 pool_put(&arp_pool, la);
  240                 break;
  241 
  242         case RTM_INVALIDATE:
  243                 if (!ISSET(rt->rt_flags, RTF_LOCAL))
  244                         arpinvalidate(rt);
  245                 break;
  246         }
  247 }
  248 
  249 /*
  250  * Broadcast an ARP request. Caller specifies:
  251  *      - arp header source ip address
  252  *      - arp header target ip address
  253  *      - arp header source ethernet address
  254  */
  255 void
  256 arprequest(struct ifnet *ifp, u_int32_t *sip, u_int32_t *tip, u_int8_t *enaddr)
  257 {
  258         struct mbuf *m;
  259         struct ether_header *eh;
  260         struct ether_arp *ea;
  261         struct sockaddr sa;
  262 
  263         if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
  264                 return;
  265         m->m_len = sizeof(*ea);
  266         m->m_pkthdr.len = sizeof(*ea);
  267         m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
  268         m->m_pkthdr.pf.prio = ifp->if_llprio;
  269         m_align(m, sizeof(*ea));
  270         ea = mtod(m, struct ether_arp *);
  271         eh = (struct ether_header *)sa.sa_data;
  272         memset(ea, 0, sizeof(*ea));
  273         memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost));
  274         eh->ether_type = htons(ETHERTYPE_ARP);  /* if_output will not swap */
  275         ea->arp_hrd = htons(ARPHRD_ETHER);
  276         ea->arp_pro = htons(ETHERTYPE_IP);
  277         ea->arp_hln = sizeof(ea->arp_sha);      /* hardware address length */
  278         ea->arp_pln = sizeof(ea->arp_spa);      /* protocol address length */
  279         ea->arp_op = htons(ARPOP_REQUEST);
  280         memcpy(eh->ether_shost, enaddr, sizeof(eh->ether_shost));
  281         memcpy(ea->arp_sha, enaddr, sizeof(ea->arp_sha));
  282         memcpy(ea->arp_spa, sip, sizeof(ea->arp_spa));
  283         memcpy(ea->arp_tpa, tip, sizeof(ea->arp_tpa));
  284         sa.sa_family = pseudo_AF_HDRCMPLT;
  285         sa.sa_len = sizeof(sa);
  286         m->m_flags |= M_BCAST;
  287         ifp->if_output(ifp, m, &sa, NULL);
  288 }
  289 
  290 void
  291 arpreply(struct ifnet *ifp, struct mbuf *m, struct in_addr *sip, uint8_t *eaddr,
  292     unsigned int rdomain)
  293 {
  294         struct ether_header *eh;
  295         struct ether_arp *ea;
  296         struct sockaddr sa;
  297 
  298         m_resethdr(m);
  299         m->m_pkthdr.ph_rtableid = rdomain;
  300 
  301         ea = mtod(m, struct ether_arp *);
  302         ea->arp_op = htons(ARPOP_REPLY);
  303         ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */
  304 
  305         /* We're replying to a request. */
  306         memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha));
  307         memcpy(ea->arp_tpa, ea->arp_spa, sizeof(ea->arp_spa));
  308 
  309         memcpy(ea->arp_sha, eaddr, sizeof(ea->arp_sha));
  310         memcpy(ea->arp_spa, sip, sizeof(ea->arp_spa));
  311 
  312         eh = (struct ether_header *)sa.sa_data;
  313         memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost));
  314         memcpy(eh->ether_shost, eaddr, sizeof(eh->ether_shost));
  315         eh->ether_type = htons(ETHERTYPE_ARP);
  316         sa.sa_family = pseudo_AF_HDRCMPLT;
  317         sa.sa_len = sizeof(sa);
  318         ifp->if_output(ifp, m, &sa, NULL);
  319 }
  320 
  321 /*
  322  * Resolve an IP address into an ethernet address.  If success,
  323  * desten is filled in.  If there is no entry in arptab,
  324  * set one up and broadcast a request for the IP address.
  325  * Hold onto this mbuf and resend it once the address
  326  * is finally resolved.  A return value of 0 indicates
  327  * that desten has been filled in and the packet should be sent
  328  * normally; A return value of EAGAIN indicates that the packet
  329  * has been taken over here, either now or for later transmission.
  330  * Any other return value indicates an error.
  331  */
  332 int
  333 arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
  334     struct sockaddr *dst, u_char *desten)
  335 {
  336         struct arpcom *ac = (struct arpcom *)ifp;
  337         struct llinfo_arp *la;
  338         struct sockaddr_dl *sdl;
  339         struct rtentry *rt = NULL;
  340         char addr[INET_ADDRSTRLEN];
  341         time_t uptime;
  342 
  343         if (m->m_flags & M_BCAST) {     /* broadcast */
  344                 memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr));
  345                 return (0);
  346         }
  347         if (m->m_flags & M_MCAST) {     /* multicast */
  348                 ETHER_MAP_IP_MULTICAST(&satosin(dst)->sin_addr, desten);
  349                 return (0);
  350         }
  351 
  352         uptime = getuptime();
  353         rt = rt_getll(rt0);
  354 
  355         if (ISSET(rt->rt_flags, RTF_REJECT) &&
  356             (rt->rt_expire == 0 || rt->rt_expire > uptime)) {
  357                 m_freem(m);
  358                 return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
  359         }
  360 
  361         if (!ISSET(rt->rt_flags, RTF_LLINFO)) {
  362                 log(LOG_DEBUG, "%s: %s: route contains no arp information\n",
  363                     __func__, inet_ntop(AF_INET, &satosin(rt_key(rt))->sin_addr,
  364                     addr, sizeof(addr)));
  365                 goto bad;
  366         }
  367 
  368         sdl = satosdl(rt->rt_gateway);
  369         if (sdl->sdl_alen > 0 && sdl->sdl_alen != ETHER_ADDR_LEN) {
  370                 log(LOG_DEBUG, "%s: %s: incorrect arp information\n", __func__,
  371                     inet_ntop(AF_INET, &satosin(dst)->sin_addr,
  372                         addr, sizeof(addr)));
  373                 goto bad;
  374         }
  375 
  376 
  377         /*
  378          * Check the address family and length is valid, the address
  379          * is resolved; otherwise, try to resolve.
  380          */
  381         if ((rt->rt_expire == 0 || rt->rt_expire > uptime) &&
  382             sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
  383                 int refresh = 0;
  384 
  385                 memcpy(desten, LLADDR(sdl), sdl->sdl_alen);
  386 
  387                 /* refresh ARP entry when timeout gets close */
  388                 if (rt->rt_expire != 0 &&
  389                     rt->rt_expire - arpt_keep / 8 < uptime) {
  390 
  391                         mtx_enter(&arp_mtx);
  392                         if (ISSET(rt->rt_flags, RTF_LLINFO)) {
  393                                 la = (struct llinfo_arp *)rt->rt_llinfo;
  394                                 KASSERT(la != NULL);
  395 
  396                                 if (la->la_refreshed + 30 < uptime) {
  397                                         la->la_refreshed = uptime;
  398                                         refresh = 1;
  399                                 }
  400                         }
  401                         mtx_leave(&arp_mtx);
  402                 }
  403                 if (refresh) {
  404                         arprequest(ifp,
  405                             &satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr,
  406                             &satosin(dst)->sin_addr.s_addr,
  407                             ac->ac_enaddr);
  408                 }
  409                 return (0);
  410         }
  411 
  412         if (ifp->if_flags & (IFF_NOARP|IFF_STATICARP))
  413                 goto bad;
  414 
  415         KERNEL_LOCK();
  416         /*
  417          * Re-check since we grab the kernel lock after the first check.
  418          * rtrequest_delete() can be called with shared netlock.  From
  419          * there arp_rtrequest() is reached which touches RTF_LLINFO
  420          * and rt_llinfo.  As this is called with kernel lock we grab the
  421          * kernel lock here and are safe.  XXXSMP
  422          */
  423         if (!ISSET(rt->rt_flags, RTF_LLINFO)) {
  424                 KERNEL_UNLOCK();
  425                 goto bad;
  426         }
  427         la = (struct llinfo_arp *)rt->rt_llinfo;
  428         KASSERT(la != NULL);
  429 
  430         /*
  431          * There is an arptab entry, but no ethernet address
  432          * response yet. Insert mbuf in hold queue if below limit.
  433          * If above the limit free the queue without queuing the new packet.
  434          */
  435         if (atomic_inc_int_nv(&la_hold_total) <= LA_HOLD_TOTAL) {
  436                 if (mq_push(&la->la_mq, m) != 0)
  437                         atomic_dec_int(&la_hold_total);
  438         } else {
  439                 atomic_sub_int(&la_hold_total, mq_purge(&la->la_mq) + 1);
  440                 m_freem(m);
  441         }
  442 
  443         /*
  444          * Re-send the ARP request when appropriate.
  445          */
  446 #ifdef  DIAGNOSTIC
  447         if (rt->rt_expire == 0) {
  448                 /* This should never happen. (Should it? -gwr) */
  449                 printf("%s: unresolved and rt_expire == 0\n", __func__);
  450                 /* Set expiration time to now (expired). */
  451                 rt->rt_expire = uptime;
  452         }
  453 #endif
  454         if (rt->rt_expire) {
  455                 rt->rt_flags &= ~RTF_REJECT;
  456                 if (la->la_asked == 0 || rt->rt_expire != uptime) {
  457                         rt->rt_expire = uptime;
  458                         if (la->la_asked++ < arp_maxtries)
  459                                 arprequest(ifp,
  460                                     &satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr,
  461                                     &satosin(dst)->sin_addr.s_addr,
  462                                     ac->ac_enaddr);
  463                         else {
  464                                 rt->rt_flags |= RTF_REJECT;
  465                                 rt->rt_expire += arpt_down;
  466                                 la->la_asked = 0;
  467                                 la->la_refreshed = 0;
  468                                 atomic_sub_int(&la_hold_total,
  469                                     mq_purge(&la->la_mq));
  470                         }
  471                 }
  472         }
  473 
  474         KERNEL_UNLOCK();
  475         return (EAGAIN);
  476 
  477 bad:
  478         m_freem(m);
  479         return (EINVAL);
  480 }
  481 
  482 struct mbuf *
  483 arppullup(struct mbuf *m)
  484 {
  485         struct arphdr *ar;
  486         int len;
  487 
  488 #ifdef DIAGNOSTIC
  489         if ((m->m_flags & M_PKTHDR) == 0)
  490                 panic("arp without packet header");
  491 #endif
  492 
  493         len = sizeof(struct arphdr);
  494         if (m->m_len < len && (m = m_pullup(m, len)) == NULL)
  495                 return NULL;
  496 
  497         ar = mtod(m, struct arphdr *);
  498         if (ntohs(ar->ar_hrd) != ARPHRD_ETHER ||
  499             ntohs(ar->ar_pro) != ETHERTYPE_IP ||
  500             ar->ar_hln != ETHER_ADDR_LEN ||
  501             ar->ar_pln != sizeof(struct in_addr)) {
  502                 m_freem(m);
  503                 return NULL;
  504         }
  505 
  506         len += 2 * (ar->ar_hln + ar->ar_pln);
  507         if (m->m_len < len && (m = m_pullup(m, len)) == NULL)
  508                 return NULL;
  509 
  510         return m;
  511 }
  512 
  513 /*
  514  * Common length and type checks are done here,
  515  * then the protocol-specific routine is called.
  516  */
  517 void
  518 arpinput(struct ifnet *ifp, struct mbuf *m)
  519 {
  520         if ((m = arppullup(m)) == NULL)
  521                 return;
  522         niq_enqueue(&arpinq, m);
  523 }
  524 
  525 void
  526 arpintr(void)
  527 {
  528         struct mbuf_list ml;
  529         struct mbuf *m;
  530         struct ifnet *ifp;
  531 
  532         niq_delist(&arpinq, &ml);
  533 
  534         while ((m = ml_dequeue(&ml)) != NULL) {
  535                 ifp = if_get(m->m_pkthdr.ph_ifidx);
  536 
  537                 if (ifp != NULL)
  538                         in_arpinput(ifp, m);
  539                 else
  540                         m_freem(m);
  541 
  542                 if_put(ifp);
  543         }
  544 }
  545 
  546 /*
  547  * ARP for Internet protocols on Ethernet, RFC 826.
  548  * In addition, a sanity check is performed on the sender
  549  * protocol address, to catch impersonators.
  550  */
  551 void
  552 in_arpinput(struct ifnet *ifp, struct mbuf *m)
  553 {
  554         struct ether_arp *ea;
  555         struct rtentry *rt = NULL;
  556         struct sockaddr_in sin;
  557         struct in_addr isaddr, itaddr;
  558         char addr[INET_ADDRSTRLEN];
  559         int op, target = 0;
  560         unsigned int rdomain;
  561 
  562         rdomain = rtable_l2(m->m_pkthdr.ph_rtableid);
  563 
  564         ea = mtod(m, struct ether_arp *);
  565         op = ntohs(ea->arp_op);
  566         if ((op != ARPOP_REQUEST) && (op != ARPOP_REPLY))
  567                 goto out;
  568 
  569         memcpy(&itaddr, ea->arp_tpa, sizeof(itaddr));
  570         memcpy(&isaddr, ea->arp_spa, sizeof(isaddr));
  571         memset(&sin, 0, sizeof(sin));
  572         sin.sin_len = sizeof(sin);
  573         sin.sin_family = AF_INET;
  574 
  575         if (ETHER_IS_MULTICAST(ea->arp_sha) &&
  576             ETHER_IS_BROADCAST(ea->arp_sha)) {
  577                 inet_ntop(AF_INET, &isaddr, addr, sizeof(addr));
  578                 log(LOG_ERR, "arp: ether address is broadcast for IP address "
  579                     "%s!\n", addr);
  580                 goto out;
  581         }
  582 
  583         if (!memcmp(ea->arp_sha, LLADDR(ifp->if_sadl), sizeof(ea->arp_sha)))
  584                 goto out;       /* it's from me, ignore it. */
  585 
  586         /* Check target against our interface addresses. */
  587         sin.sin_addr = itaddr;
  588         rt = rtalloc(sintosa(&sin), 0, rdomain);
  589         if (rtisvalid(rt) && ISSET(rt->rt_flags, RTF_LOCAL) &&
  590             rt->rt_ifidx == ifp->if_index)
  591                 target = 1;
  592         rtfree(rt);
  593         rt = NULL;
  594 
  595 #if NCARP > 0
  596         if (target && op == ARPOP_REQUEST && ifp->if_type == IFT_CARP &&
  597             !carp_iamatch(ifp))
  598                 goto out;
  599 #endif
  600 
  601         /* Do we have an ARP cache for the sender? Create if we are target. */
  602         rt = arplookup(&isaddr, target, 0, rdomain);
  603 
  604         /* Check sender against our interface addresses. */
  605         if (rtisvalid(rt) && ISSET(rt->rt_flags, RTF_LOCAL) &&
  606             rt->rt_ifidx == ifp->if_index && isaddr.s_addr != INADDR_ANY) {
  607                 inet_ntop(AF_INET, &isaddr, addr, sizeof(addr));
  608                 log(LOG_ERR, "duplicate IP address %s sent from ethernet "
  609                     "address %s\n", addr, ether_sprintf(ea->arp_sha));
  610                 itaddr = isaddr;
  611         } else if (rt != NULL) {
  612                 int error;
  613 
  614                 KERNEL_LOCK();
  615                 error = arpcache(ifp, ea, rt);
  616                 KERNEL_UNLOCK();
  617                 if (error)
  618                         goto out;
  619         }
  620 
  621         if (op == ARPOP_REQUEST) {
  622                 uint8_t *eaddr;
  623 
  624                 if (target) {
  625                         /* We already have all info for the reply */
  626                         eaddr = LLADDR(ifp->if_sadl);
  627                 } else {
  628                         rtfree(rt);
  629                         rt = arplookup(&itaddr, 0, SIN_PROXY, rdomain);
  630                         /*
  631                          * Protect from possible duplicates, only owner
  632                          * should respond
  633                          */
  634                         if ((rt == NULL) || (rt->rt_ifidx != ifp->if_index))
  635                                 goto out;
  636                         eaddr = LLADDR(satosdl(rt->rt_gateway));
  637                 }
  638                 arpreply(ifp, m, &itaddr, eaddr, rdomain);
  639                 rtfree(rt);
  640                 return;
  641         }
  642 
  643 out:
  644         rtfree(rt);
  645         m_freem(m);
  646 }
  647 
  648 int
  649 arpcache(struct ifnet *ifp, struct ether_arp *ea, struct rtentry *rt)
  650 {
  651         struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
  652         struct sockaddr_dl *sdl = satosdl(rt->rt_gateway);
  653         struct in_addr *spa = (struct in_addr *)ea->arp_spa;
  654         char addr[INET_ADDRSTRLEN];
  655         struct ifnet *rifp;
  656         struct mbuf_list ml;
  657         struct mbuf *m;
  658         time_t uptime;
  659         unsigned int len;
  660         int changed = 0;
  661 
  662         KERNEL_ASSERT_LOCKED();
  663         KASSERT(sdl != NULL);
  664 
  665         /*
  666          * This can happen if the entry has been deleted by another CPU
  667          * after we found it.
  668          */
  669         if (la == NULL)
  670                 return (0);
  671 
  672         uptime = getuptime();
  673         if (sdl->sdl_alen > 0) {
  674                 if (memcmp(ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) {
  675                         if (ISSET(rt->rt_flags, RTF_PERMANENT_ARP|RTF_LOCAL)) {
  676                                 inet_ntop(AF_INET, spa, addr, sizeof(addr));
  677                                 log(LOG_WARNING, "arp: attempt to overwrite "
  678                                    "permanent entry for %s by %s on %s\n", addr,
  679                                    ether_sprintf(ea->arp_sha), ifp->if_xname);
  680                                 return (-1);
  681                         } else if (rt->rt_ifidx != ifp->if_index) {
  682 #if NCARP > 0
  683                                 if (ifp->if_type != IFT_CARP)
  684 #endif
  685                                 {
  686                                         rifp = if_get(rt->rt_ifidx);
  687                                         if (rifp == NULL)
  688                                                 return (-1);
  689                                         inet_ntop(AF_INET, spa, addr,
  690                                             sizeof(addr));
  691                                         log(LOG_WARNING, "arp: attempt to "
  692                                             "overwrite entry for %s on %s by "
  693                                             "%s on %s\n", addr, rifp->if_xname,
  694                                             ether_sprintf(ea->arp_sha),
  695                                             ifp->if_xname);
  696                                         if_put(rifp);
  697                                 }
  698                                 return (-1);
  699                         } else {
  700                                 inet_ntop(AF_INET, spa, addr, sizeof(addr));
  701                                 log(LOG_INFO, "arp info overwritten for %s by "
  702                                     "%s on %s\n", addr,
  703                                     ether_sprintf(ea->arp_sha), ifp->if_xname);
  704                                 rt->rt_expire = 1;/* no longer static */
  705                         }
  706                         changed = 1;
  707                 }
  708         } else if (!if_isconnected(ifp, rt->rt_ifidx)) {
  709                 rifp = if_get(rt->rt_ifidx);
  710                 if (rifp == NULL)
  711                         return (-1);
  712                 inet_ntop(AF_INET, spa, addr, sizeof(addr));
  713                 log(LOG_WARNING, "arp: attempt to add entry for %s on %s by %s"
  714                     " on %s\n", addr, rifp->if_xname,
  715                     ether_sprintf(ea->arp_sha), ifp->if_xname);
  716                 if_put(rifp);
  717                 return (-1);
  718         }
  719         sdl->sdl_alen = sizeof(ea->arp_sha);
  720         memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha));
  721         if (rt->rt_expire)
  722                 rt->rt_expire = uptime + arpt_keep;
  723         rt->rt_flags &= ~RTF_REJECT;
  724 
  725         /* Notify userland that an ARP resolution has been done. */
  726         if (la->la_asked || changed) {
  727                 rtm_send(rt, RTM_RESOLVE, 0, ifp->if_rdomain);
  728         }
  729 
  730         la->la_asked = 0;
  731         la->la_refreshed = 0;
  732         mq_delist(&la->la_mq, &ml);
  733         len = ml_len(&ml);
  734         while ((m = ml_dequeue(&ml)) != NULL)
  735                 ifp->if_output(ifp, m, rt_key(rt), rt);
  736         /* XXXSMP we discard if other CPU enqueues */
  737         if (mq_len(&la->la_mq) > 0) {
  738                 /* mbuf is back in queue. Discard. */
  739                 atomic_sub_int(&la_hold_total, len + mq_purge(&la->la_mq));
  740         } else
  741                 atomic_sub_int(&la_hold_total, len);
  742 
  743         return (0);
  744 }
  745 
  746 void
  747 arpinvalidate(struct rtentry *rt)
  748 {
  749         struct llinfo_arp *la;
  750         struct sockaddr_dl *sdl = satosdl(rt->rt_gateway);
  751 
  752         mtx_enter(&arp_mtx);
  753         la = (struct llinfo_arp *)rt->rt_llinfo;
  754         if (la == NULL) {
  755                 mtx_leave(&arp_mtx);
  756                 return;
  757         }
  758         atomic_sub_int(&la_hold_total, mq_purge(&la->la_mq));
  759         sdl->sdl_alen = 0;
  760         la->la_asked = 0;
  761         mtx_leave(&arp_mtx);
  762 }
  763 
  764 /*
  765  * Free an arp entry.
  766  */
  767 void
  768 arptfree(struct rtentry *rt)
  769 {
  770         struct ifnet *ifp;
  771 
  772         KASSERT(!ISSET(rt->rt_flags, RTF_LOCAL));
  773         arpinvalidate(rt);
  774 
  775         ifp = if_get(rt->rt_ifidx);
  776         KASSERT(ifp != NULL);
  777         if (!ISSET(rt->rt_flags, RTF_STATIC|RTF_CACHED))
  778                 rtdeletemsg(rt, ifp, ifp->if_rdomain);
  779         if_put(ifp);
  780 }
  781 
  782 /*
  783  * Lookup or enter a new address in arptab.
  784  */
  785 struct rtentry *
  786 arplookup(struct in_addr *inp, int create, int proxy, u_int tableid)
  787 {
  788         struct rtentry *rt;
  789         struct sockaddr_inarp sin;
  790         int flags;
  791 
  792         memset(&sin, 0, sizeof(sin));
  793         sin.sin_len = sizeof(sin);
  794         sin.sin_family = AF_INET;
  795         sin.sin_addr.s_addr = inp->s_addr;
  796         sin.sin_other = proxy ? SIN_PROXY : 0;
  797         flags = (create) ? RT_RESOLVE : 0;
  798 
  799         rt = rtalloc((struct sockaddr *)&sin, flags, tableid);
  800         if (!rtisvalid(rt) || ISSET(rt->rt_flags, RTF_GATEWAY) ||
  801             !ISSET(rt->rt_flags, RTF_LLINFO) ||
  802             rt->rt_gateway->sa_family != AF_LINK) {
  803                 rtfree(rt);
  804                 return (NULL);
  805         }
  806 
  807         if (proxy && !ISSET(rt->rt_flags, RTF_ANNOUNCE)) {
  808                 while ((rt = rtable_iterate(rt)) != NULL) {
  809                         if (ISSET(rt->rt_flags, RTF_ANNOUNCE)) {
  810                                 break;
  811                         }
  812                 }
  813         }
  814 
  815         return (rt);
  816 }
  817 
  818 /*
  819  * Check whether we do proxy ARP for this address and we point to ourselves.
  820  */
  821 int
  822 arpproxy(struct in_addr in, unsigned int rtableid)
  823 {
  824         struct sockaddr_dl *sdl;
  825         struct rtentry *rt;
  826         struct ifnet *ifp;
  827         int found = 0;
  828 
  829         rt = arplookup(&in, 0, SIN_PROXY, rtableid);
  830         if (!rtisvalid(rt)) {
  831                 rtfree(rt);
  832                 return (0);
  833         }
  834 
  835         /* Check that arp information are correct. */
  836         sdl = satosdl(rt->rt_gateway);
  837         if (sdl->sdl_alen != ETHER_ADDR_LEN) {
  838                 rtfree(rt);
  839                 return (0);
  840         }
  841 
  842         ifp = if_get(rt->rt_ifidx);
  843         if (ifp == NULL) {
  844                 rtfree(rt);
  845                 return (0);
  846         }
  847 
  848         if (!memcmp(LLADDR(sdl), LLADDR(ifp->if_sadl), sdl->sdl_alen))
  849                 found = 1;
  850 
  851         if_put(ifp);
  852         rtfree(rt);
  853         return (found);
  854 }
  855 
  856 /*
  857  * Called from Ethernet interrupt handlers
  858  * when ether packet type ETHERTYPE_REVARP
  859  * is received.  Common length and type checks are done here,
  860  * then the protocol-specific routine is called.
  861  */
  862 void
  863 revarpinput(struct ifnet *ifp, struct mbuf *m)
  864 {
  865         if ((m = arppullup(m)) == NULL)
  866                 return;
  867         in_revarpinput(ifp, m);
  868 }
  869 
  870 /*
  871  * RARP for Internet protocols on Ethernet.
  872  * Algorithm is that given in RFC 903.
  873  * We are only using for bootstrap purposes to get an ip address for one of
  874  * our interfaces.  Thus we support no user-interface.
  875  *
  876  * Since the contents of the RARP reply are specific to the interface that
  877  * sent the request, this code must ensure that they are properly associated.
  878  *
  879  * Note: also supports ARP via RARP packets, per the RFC.
  880  */
  881 void
  882 in_revarpinput(struct ifnet *ifp, struct mbuf *m)
  883 {
  884         struct ether_arp *ar;
  885         int op;
  886 
  887         ar = mtod(m, struct ether_arp *);
  888         op = ntohs(ar->arp_op);
  889         switch (op) {
  890         case ARPOP_REQUEST:
  891         case ARPOP_REPLY:       /* per RFC */
  892                 niq_enqueue(&arpinq, m);
  893                 return;
  894         case ARPOP_REVREPLY:
  895                 break;
  896         case ARPOP_REVREQUEST:  /* handled by rarpd(8) */
  897         default:
  898                 goto out;
  899         }
  900 #ifdef NFSCLIENT
  901         if (revarp_ifidx == 0)
  902                 goto out;
  903         if (revarp_ifidx != m->m_pkthdr.ph_ifidx) /* !same interface */
  904                 goto out;
  905         if (revarp_finished)
  906                 goto wake;
  907         if (memcmp(ar->arp_tha, LLADDR(ifp->if_sadl), sizeof(ar->arp_tha)))
  908                 goto out;
  909         memcpy(&revarp_srvip, ar->arp_spa, sizeof(revarp_srvip));
  910         memcpy(&revarp_myip, ar->arp_tpa, sizeof(revarp_myip));
  911         revarp_finished = 1;
  912 wake:   /* Do wakeup every time in case it was missed. */
  913         wakeup((caddr_t)&revarp_myip);
  914 #endif /* NFSCLIENT */
  915 
  916 out:
  917         m_freem(m);
  918 }
  919 
  920 /*
  921  * Send a RARP request for the ip address of the specified interface.
  922  * The request should be RFC 903-compliant.
  923  */
  924 void
  925 revarprequest(struct ifnet *ifp)
  926 {
  927         struct sockaddr sa;
  928         struct mbuf *m;
  929         struct ether_header *eh;
  930         struct ether_arp *ea;
  931         struct arpcom *ac = (struct arpcom *)ifp;
  932 
  933         if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
  934                 return;
  935         m->m_len = sizeof(*ea);
  936         m->m_pkthdr.len = sizeof(*ea);
  937         m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
  938         m->m_pkthdr.pf.prio = ifp->if_llprio;
  939         m_align(m, sizeof(*ea));
  940         ea = mtod(m, struct ether_arp *);
  941         eh = (struct ether_header *)sa.sa_data;
  942         memset(ea, 0, sizeof(*ea));
  943         memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost));
  944         eh->ether_type = htons(ETHERTYPE_REVARP);
  945         ea->arp_hrd = htons(ARPHRD_ETHER);
  946         ea->arp_pro = htons(ETHERTYPE_IP);
  947         ea->arp_hln = sizeof(ea->arp_sha);      /* hardware address length */
  948         ea->arp_pln = sizeof(ea->arp_spa);      /* protocol address length */
  949         ea->arp_op = htons(ARPOP_REVREQUEST);
  950         memcpy(eh->ether_shost, ac->ac_enaddr, sizeof(ea->arp_tha));
  951         memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha));
  952         memcpy(ea->arp_tha, ac->ac_enaddr, sizeof(ea->arp_tha));
  953         sa.sa_family = pseudo_AF_HDRCMPLT;
  954         sa.sa_len = sizeof(sa);
  955         m->m_flags |= M_BCAST;
  956         ifp->if_output(ifp, m, &sa, NULL);
  957 }
  958 
  959 #ifdef NFSCLIENT
  960 /*
  961  * RARP for the ip address of the specified interface, but also
  962  * save the ip address of the server that sent the answer.
  963  * Timeout if no response is received.
  964  */
  965 int
  966 revarpwhoarewe(struct ifnet *ifp, struct in_addr *serv_in,
  967     struct in_addr *clnt_in)
  968 {
  969         int result, count = 20;
  970 
  971         if (revarp_finished)
  972                 return EIO;
  973 
  974         revarp_ifidx = ifp->if_index;
  975         while (count--) {
  976                 revarprequest(ifp);
  977                 result = tsleep_nsec(&revarp_myip, PSOCK, "revarp",
  978                     MSEC_TO_NSEC(500));
  979                 if (result != EWOULDBLOCK)
  980                         break;
  981         }
  982         revarp_ifidx = 0;
  983         if (!revarp_finished)
  984                 return ENETUNREACH;
  985 
  986         memcpy(serv_in, &revarp_srvip, sizeof(*serv_in));
  987         memcpy(clnt_in, &revarp_myip, sizeof(*clnt_in));
  988         return 0;
  989 }
  990 
  991 /* For compatibility: only saves interface address. */
  992 int
  993 revarpwhoami(struct in_addr *in, struct ifnet *ifp)
  994 {
  995         struct in_addr server;
  996         return (revarpwhoarewe(ifp, &server, in));
  997 }
  998 #endif /* NFSCLIENT */

Cache object: ac22a66146f442d38164d6b66d01862c


[ 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.