LCOV - code coverage report
Current view: top level - netinet - if_ether.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 450 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_ether.c,v 1.236 2018/06/11 08:48:54 mpi 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             : #if NCARP > 0
      64             : #include <netinet/ip_carp.h>
      65             : #endif
      66             : 
      67             : struct llinfo_arp {
      68             :         LIST_ENTRY(llinfo_arp)   la_list;
      69             :         struct rtentry          *la_rt;         /* backpointer to rtentry */
      70             :         long                     la_asked;      /* last time we QUERIED */
      71             :         struct mbuf_list         la_ml;         /* packet hold queue */
      72             : };
      73             : #define LA_HOLD_QUEUE 10
      74             : #define LA_HOLD_TOTAL 100
      75             : 
      76             : /* timer values */
      77             : int     arpt_prune = (5 * 60);  /* walk list every 5 minutes */
      78             : int     arpt_keep = (20 * 60);  /* once resolved, cache for 20 minutes */
      79             : int     arpt_down = 20;         /* once declared down, don't send for 20 secs */
      80             : 
      81             : struct mbuf *arppullup(struct mbuf *m);
      82             : void arpinvalidate(struct rtentry *);
      83             : void arptfree(struct rtentry *);
      84             : void arptimer(void *);
      85             : struct rtentry *arplookup(struct in_addr *, int, int, unsigned int);
      86             : void in_arpinput(struct ifnet *, struct mbuf *);
      87             : void in_revarpinput(struct ifnet *, struct mbuf *);
      88             : int arpcache(struct ifnet *, struct ether_arp *, struct rtentry *);
      89             : void arpreply(struct ifnet *, struct mbuf *, struct in_addr *, uint8_t *,
      90             :     unsigned int);
      91             : 
      92             : struct niqueue arpinq = NIQUEUE_INITIALIZER(50, NETISR_ARP);
      93             : 
      94             : LIST_HEAD(, llinfo_arp) arp_list;
      95             : struct  pool arp_pool;          /* pool for llinfo_arp structures */
      96             : int     arp_maxtries = 5;
      97             : int     arpinit_done;
      98             : int     la_hold_total;
      99             : 
     100             : #ifdef NFSCLIENT
     101             : /* revarp state */
     102             : struct in_addr revarp_myip, revarp_srvip;
     103             : int revarp_finished;
     104             : unsigned int revarp_ifidx;
     105             : #endif /* NFSCLIENT */
     106             : 
     107             : /*
     108             :  * Timeout routine.  Age arp_tab entries periodically.
     109             :  */
     110             : /* ARGSUSED */
     111             : void
     112           0 : arptimer(void *arg)
     113             : {
     114           0 :         struct timeout *to = (struct timeout *)arg;
     115             :         struct llinfo_arp *la, *nla;
     116             : 
     117           0 :         NET_LOCK();
     118           0 :         timeout_add_sec(to, arpt_prune);
     119           0 :         LIST_FOREACH_SAFE(la, &arp_list, la_list, nla) {
     120           0 :                 struct rtentry *rt = la->la_rt;
     121             : 
     122           0 :                 if (rt->rt_expire && rt->rt_expire <= time_uptime)
     123           0 :                         arptfree(rt); /* timer has expired; clear */
     124             :         }
     125           0 :         NET_UNLOCK();
     126           0 : }
     127             : 
     128             : void
     129           0 : arp_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt)
     130             : {
     131           0 :         struct sockaddr *gate = rt->rt_gateway;
     132           0 :         struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
     133             :         struct ifaddr *ifa;
     134             : 
     135           0 :         if (!arpinit_done) {
     136             :                 static struct timeout arptimer_to;
     137             : 
     138           0 :                 arpinit_done = 1;
     139           0 :                 pool_init(&arp_pool, sizeof(struct llinfo_arp), 0,
     140             :                     IPL_SOFTNET, 0, "arp", NULL);
     141             : 
     142           0 :                 timeout_set_proc(&arptimer_to, arptimer, &arptimer_to);
     143           0 :                 timeout_add_sec(&arptimer_to, 1);
     144           0 :         }
     145             : 
     146           0 :         if (ISSET(rt->rt_flags, RTF_GATEWAY|RTF_BROADCAST|RTF_MULTICAST))
     147           0 :                 return;
     148             : 
     149           0 :         switch (req) {
     150             : 
     151             :         case RTM_ADD:
     152           0 :                 if (rt->rt_flags & RTF_CLONING ||
     153           0 :                     ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && !la)) {
     154             :                         /*
     155             :                          * Give this route an expiration time, even though
     156             :                          * it's a "permanent" route, so that routes cloned
     157             :                          * from it do not need their expiration time set.
     158             :                          */
     159           0 :                         rt->rt_expire = time_uptime;
     160           0 :                         if ((rt->rt_flags & RTF_CLONING) != 0)
     161             :                                 break;
     162             :                 }
     163             :                 /*
     164             :                  * Announce a new entry if requested or warn the user
     165             :                  * if another station has this IP address.
     166             :                  */
     167           0 :                 if (rt->rt_flags & (RTF_ANNOUNCE|RTF_LOCAL))
     168           0 :                         arprequest(ifp,
     169           0 :                             &satosin(rt_key(rt))->sin_addr.s_addr,
     170           0 :                             &satosin(rt_key(rt))->sin_addr.s_addr,
     171           0 :                             (u_char *)LLADDR(satosdl(gate)));
     172             :                 /*FALLTHROUGH*/
     173             :         case RTM_RESOLVE:
     174           0 :                 if (gate->sa_family != AF_LINK ||
     175           0 :                     gate->sa_len < sizeof(struct sockaddr_dl)) {
     176           0 :                         log(LOG_DEBUG, "%s: bad gateway value: %s\n", __func__,
     177           0 :                             ifp->if_xname);
     178           0 :                         break;
     179             :                 }
     180           0 :                 satosdl(gate)->sdl_type = ifp->if_type;
     181           0 :                 satosdl(gate)->sdl_index = ifp->if_index;
     182           0 :                 if (la != 0)
     183             :                         break; /* This happens on a route change */
     184             :                 /*
     185             :                  * Case 2:  This route may come from cloning, or a manual route
     186             :                  * add with a LL address.
     187             :                  */
     188           0 :                 la = pool_get(&arp_pool, PR_NOWAIT | PR_ZERO);
     189           0 :                 rt->rt_llinfo = (caddr_t)la;
     190           0 :                 if (la == NULL) {
     191           0 :                         log(LOG_DEBUG, "%s: pool get failed\n", __func__);
     192           0 :                         break;
     193             :                 }
     194             : 
     195           0 :                 ml_init(&la->la_ml);
     196           0 :                 la->la_rt = rt;
     197           0 :                 rt->rt_flags |= RTF_LLINFO;
     198           0 :                 LIST_INSERT_HEAD(&arp_list, la, la_list);
     199             : 
     200           0 :                 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
     201           0 :                         if ((ifa->ifa_addr->sa_family == AF_INET) &&
     202           0 :                             ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
     203           0 :                             satosin(rt_key(rt))->sin_addr.s_addr)
     204             :                                 break;
     205             :                 }
     206           0 :                 if (ifa) {
     207           0 :                         KASSERT(ifa == rt->rt_ifa);
     208           0 :                         rt->rt_expire = 0;
     209           0 :                 }
     210             :                 break;
     211             : 
     212             :         case RTM_DELETE:
     213           0 :                 if (la == NULL)
     214             :                         break;
     215           0 :                 LIST_REMOVE(la, la_list);
     216           0 :                 rt->rt_llinfo = NULL;
     217           0 :                 rt->rt_flags &= ~RTF_LLINFO;
     218           0 :                 la_hold_total -= ml_purge(&la->la_ml);
     219           0 :                 pool_put(&arp_pool, la);
     220           0 :                 break;
     221             : 
     222             :         case RTM_INVALIDATE:
     223           0 :                 if (!ISSET(rt->rt_flags, RTF_LOCAL))
     224           0 :                         arpinvalidate(rt);
     225             :                 break;
     226             :         }
     227           0 : }
     228             : 
     229             : /*
     230             :  * Broadcast an ARP request. Caller specifies:
     231             :  *      - arp header source ip address
     232             :  *      - arp header target ip address
     233             :  *      - arp header source ethernet address
     234             :  */
     235             : void
     236           0 : arprequest(struct ifnet *ifp, u_int32_t *sip, u_int32_t *tip, u_int8_t *enaddr)
     237             : {
     238             :         struct mbuf *m;
     239             :         struct ether_header *eh;
     240             :         struct ether_arp *ea;
     241           0 :         struct sockaddr sa;
     242             : 
     243           0 :         if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
     244           0 :                 return;
     245           0 :         m->m_len = sizeof(*ea);
     246           0 :         m->m_pkthdr.len = sizeof(*ea);
     247           0 :         m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
     248           0 :         m->m_pkthdr.pf.prio = ifp->if_llprio;
     249           0 :         MH_ALIGN(m, sizeof(*ea));
     250           0 :         ea = mtod(m, struct ether_arp *);
     251           0 :         eh = (struct ether_header *)sa.sa_data;
     252           0 :         memset(ea, 0, sizeof(*ea));
     253           0 :         memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost));
     254           0 :         eh->ether_type = htons(ETHERTYPE_ARP);       /* if_output will not swap */
     255           0 :         ea->arp_hrd = htons(ARPHRD_ETHER);
     256           0 :         ea->arp_pro = htons(ETHERTYPE_IP);
     257           0 :         ea->arp_hln = sizeof(ea->arp_sha);        /* hardware address length */
     258           0 :         ea->arp_pln = sizeof(ea->arp_spa);        /* protocol address length */
     259           0 :         ea->arp_op = htons(ARPOP_REQUEST);
     260           0 :         memcpy(eh->ether_shost, enaddr, sizeof(eh->ether_shost));
     261           0 :         memcpy(ea->arp_sha, enaddr, sizeof(ea->arp_sha));
     262           0 :         memcpy(ea->arp_spa, sip, sizeof(ea->arp_spa));
     263           0 :         memcpy(ea->arp_tpa, tip, sizeof(ea->arp_tpa));
     264           0 :         sa.sa_family = pseudo_AF_HDRCMPLT;
     265           0 :         sa.sa_len = sizeof(sa);
     266           0 :         m->m_flags |= M_BCAST;
     267           0 :         ifp->if_output(ifp, m, &sa, NULL);
     268           0 : }
     269             : 
     270             : void
     271           0 : arpreply(struct ifnet *ifp, struct mbuf *m, struct in_addr *sip, uint8_t *eaddr,
     272             :     unsigned int rdomain)
     273             : {
     274             :         struct ether_header *eh;
     275             :         struct ether_arp *ea;
     276           0 :         struct sockaddr sa;
     277             : 
     278           0 :         m_resethdr(m);
     279           0 :         m->m_pkthdr.ph_rtableid = rdomain;
     280             : 
     281           0 :         ea = mtod(m, struct ether_arp *);
     282           0 :         ea->arp_op = htons(ARPOP_REPLY);
     283           0 :         ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */
     284             : 
     285             :         /* We're replying to a request. */
     286           0 :         memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha));
     287           0 :         memcpy(ea->arp_tpa, ea->arp_spa, sizeof(ea->arp_spa));
     288             : 
     289           0 :         memcpy(ea->arp_sha, eaddr, sizeof(ea->arp_sha));
     290           0 :         memcpy(ea->arp_spa, sip, sizeof(ea->arp_spa));
     291             : 
     292           0 :         eh = (struct ether_header *)sa.sa_data;
     293           0 :         memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost));
     294           0 :         memcpy(eh->ether_shost, eaddr, sizeof(eh->ether_shost));
     295           0 :         eh->ether_type = htons(ETHERTYPE_ARP);
     296           0 :         sa.sa_family = pseudo_AF_HDRCMPLT;
     297           0 :         sa.sa_len = sizeof(sa);
     298           0 :         ifp->if_output(ifp, m, &sa, NULL);
     299           0 : }
     300             : 
     301             : /*
     302             :  * Resolve an IP address into an ethernet address.  If success,
     303             :  * desten is filled in.  If there is no entry in arptab,
     304             :  * set one up and broadcast a request for the IP address.
     305             :  * Hold onto this mbuf and resend it once the address
     306             :  * is finally resolved.  A return value of 0 indicates
     307             :  * that desten has been filled in and the packet should be sent
     308             :  * normally; A return value of EAGAIN indicates that the packet
     309             :  * has been taken over here, either now or for later transmission.
     310             :  * Any other return value indicates an error.
     311             :  */
     312             : int
     313           0 : arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
     314             :     struct sockaddr *dst, u_char *desten)
     315             : {
     316           0 :         struct arpcom *ac = (struct arpcom *)ifp;
     317             :         struct llinfo_arp *la = NULL;
     318             :         struct sockaddr_dl *sdl;
     319             :         struct rtentry *rt = NULL;
     320           0 :         char addr[INET_ADDRSTRLEN];
     321             : 
     322           0 :         if (m->m_flags & M_BCAST) {      /* broadcast */
     323           0 :                 memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr));
     324           0 :                 return (0);
     325             :         }
     326           0 :         if (m->m_flags & M_MCAST) {      /* multicast */
     327           0 :                 ETHER_MAP_IP_MULTICAST(&satosin(dst)->sin_addr, desten);
     328           0 :                 return (0);
     329             :         }
     330             : 
     331           0 :         rt = rt_getll(rt0);
     332             : 
     333           0 :         if (ISSET(rt->rt_flags, RTF_REJECT) &&
     334           0 :             (rt->rt_expire == 0 || time_uptime < rt->rt_expire)) {
     335           0 :                 m_freem(m);
     336           0 :                 return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
     337             :         }
     338             : 
     339           0 :         if (!ISSET(rt->rt_flags, RTF_LLINFO)) {
     340           0 :                 log(LOG_DEBUG, "%s: %s: route contains no arp information\n",
     341           0 :                     __func__, inet_ntop(AF_INET, &satosin(rt_key(rt))->sin_addr,
     342           0 :                     addr, sizeof(addr)));
     343           0 :                 m_freem(m);
     344           0 :                 return (EINVAL);
     345             :         }
     346             : 
     347           0 :         sdl = satosdl(rt->rt_gateway);
     348           0 :         if (sdl->sdl_alen > 0 && sdl->sdl_alen != ETHER_ADDR_LEN) {
     349           0 :                 log(LOG_DEBUG, "%s: %s: incorrect arp information\n", __func__,
     350           0 :                     inet_ntop(AF_INET, &satosin(dst)->sin_addr,
     351           0 :                         addr, sizeof(addr)));
     352           0 :                 goto bad;
     353             :         }
     354             : 
     355             :         /*
     356             :          * Check the address family and length is valid, the address
     357             :          * is resolved; otherwise, try to resolve.
     358             :          */
     359           0 :         if ((rt->rt_expire == 0 || rt->rt_expire > time_uptime) &&
     360           0 :             sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
     361           0 :                 memcpy(desten, LLADDR(sdl), sdl->sdl_alen);
     362           0 :                 return (0);
     363             :         }
     364             : 
     365           0 :         if (ifp->if_flags & (IFF_NOARP|IFF_STATICARP))
     366             :                 goto bad;
     367             : 
     368             :         /*
     369             :          * There is an arptab entry, but no ethernet address
     370             :          * response yet. Insert mbuf in hold queue if below limit
     371             :          * if above the limit free the queue without queuing the new packet.
     372             :          */
     373           0 :         la = (struct llinfo_arp *)rt->rt_llinfo;
     374           0 :         KASSERT(la != NULL);
     375           0 :         if (la_hold_total < LA_HOLD_TOTAL && la_hold_total < nmbclust / 64) {
     376             :                 struct mbuf *mh;
     377             : 
     378           0 :                 if (ml_len(&la->la_ml) >= LA_HOLD_QUEUE) {
     379           0 :                         mh = ml_dequeue(&la->la_ml);
     380           0 :                         la_hold_total--;
     381           0 :                         m_freem(mh);
     382           0 :                 }
     383           0 :                 ml_enqueue(&la->la_ml, m);
     384           0 :                 la_hold_total++;
     385           0 :         } else {
     386           0 :                 la_hold_total -= ml_purge(&la->la_ml);
     387           0 :                 m_freem(m);
     388             :         }
     389             : 
     390             :         /*
     391             :          * Re-send the ARP request when appropriate.
     392             :          */
     393             : #ifdef  DIAGNOSTIC
     394           0 :         if (rt->rt_expire == 0) {
     395             :                 /* This should never happen. (Should it? -gwr) */
     396           0 :                 printf("%s: unresolved and rt_expire == 0\n", __func__);
     397             :                 /* Set expiration time to now (expired). */
     398           0 :                 rt->rt_expire = time_uptime;
     399           0 :         }
     400             : #endif
     401           0 :         if (rt->rt_expire) {
     402           0 :                 rt->rt_flags &= ~RTF_REJECT;
     403           0 :                 if (la->la_asked == 0 || rt->rt_expire != time_uptime) {
     404           0 :                         rt->rt_expire = time_uptime;
     405           0 :                         if (la->la_asked++ < arp_maxtries)
     406           0 :                                 arprequest(ifp,
     407           0 :                                     &satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr,
     408           0 :                                     &satosin(dst)->sin_addr.s_addr,
     409           0 :                                     ac->ac_enaddr);
     410             :                         else {
     411           0 :                                 rt->rt_flags |= RTF_REJECT;
     412           0 :                                 rt->rt_expire += arpt_down;
     413           0 :                                 la->la_asked = 0;
     414           0 :                                 la_hold_total -= ml_purge(&la->la_ml);
     415             :                         }
     416             :                 }
     417             :         }
     418             : 
     419           0 :         return (EAGAIN);
     420             : 
     421             : bad:
     422           0 :         m_freem(m);
     423           0 :         return (EINVAL);
     424           0 : }
     425             : 
     426             : struct mbuf *
     427           0 : arppullup(struct mbuf *m)
     428             : {
     429             :         struct arphdr *ar;
     430             :         int len;
     431             : 
     432             : #ifdef DIAGNOSTIC
     433           0 :         if ((m->m_flags & M_PKTHDR) == 0)
     434           0 :                 panic("arp without packet header");
     435             : #endif
     436             : 
     437             :         len = sizeof(struct arphdr);
     438           0 :         if (m->m_len < len && (m = m_pullup(m, len)) == NULL)
     439           0 :                 return NULL;
     440             : 
     441           0 :         ar = mtod(m, struct arphdr *);
     442           0 :         if (ntohs(ar->ar_hrd) != ARPHRD_ETHER ||
     443           0 :             ntohs(ar->ar_pro) != ETHERTYPE_IP ||
     444           0 :             ar->ar_hln != ETHER_ADDR_LEN ||
     445           0 :             ar->ar_pln != sizeof(struct in_addr)) {
     446           0 :                 m_freem(m);
     447           0 :                 return NULL;
     448             :         }
     449             : 
     450           0 :         len += 2 * (ar->ar_hln + ar->ar_pln);
     451           0 :         if (m->m_len < len && (m = m_pullup(m, len)) == NULL)
     452           0 :                 return NULL;
     453             : 
     454           0 :         return m;
     455           0 : }
     456             : 
     457             : /*
     458             :  * Common length and type checks are done here,
     459             :  * then the protocol-specific routine is called.
     460             :  */
     461             : void
     462           0 : arpinput(struct ifnet *ifp, struct mbuf *m)
     463             : {
     464           0 :         if ((m = arppullup(m)) == NULL)
     465             :                 return;
     466           0 :         niq_enqueue(&arpinq, m);
     467           0 : }
     468             : 
     469             : void
     470           0 : arpintr(void)
     471             : {
     472           0 :         struct mbuf_list ml;
     473             :         struct mbuf *m;
     474             :         struct ifnet *ifp;
     475             : 
     476           0 :         niq_delist(&arpinq, &ml);
     477             : 
     478           0 :         while ((m = ml_dequeue(&ml)) != NULL) {
     479           0 :                 ifp = if_get(m->m_pkthdr.ph_ifidx);
     480             : 
     481           0 :                 if (ifp != NULL)
     482           0 :                         in_arpinput(ifp, m);
     483             :                 else
     484           0 :                         m_freem(m);
     485             : 
     486           0 :                 if_put(ifp);
     487             :         }
     488           0 : }
     489             : 
     490             : /*
     491             :  * ARP for Internet protocols on Ethernet, RFC 826.
     492             :  * In addition, a sanity check is performed on the sender
     493             :  * protocol address, to catch impersonators.
     494             :  */
     495             : void
     496           0 : in_arpinput(struct ifnet *ifp, struct mbuf *m)
     497             : {
     498             :         struct ether_arp *ea;
     499             :         struct rtentry *rt = NULL;
     500           0 :         struct sockaddr_in sin;
     501           0 :         struct in_addr isaddr, itaddr;
     502           0 :         char addr[INET_ADDRSTRLEN];
     503             :         int op, target = 0;
     504             :         unsigned int rdomain;
     505             : 
     506           0 :         rdomain = rtable_l2(m->m_pkthdr.ph_rtableid);
     507             : 
     508           0 :         ea = mtod(m, struct ether_arp *);
     509           0 :         op = ntohs(ea->arp_op);
     510           0 :         if ((op != ARPOP_REQUEST) && (op != ARPOP_REPLY))
     511             :                 goto out;
     512             : 
     513           0 :         memcpy(&itaddr, ea->arp_tpa, sizeof(itaddr));
     514           0 :         memcpy(&isaddr, ea->arp_spa, sizeof(isaddr));
     515           0 :         memset(&sin, 0, sizeof(sin));
     516           0 :         sin.sin_len = sizeof(sin);
     517           0 :         sin.sin_family = AF_INET;
     518             : 
     519           0 :         if (ETHER_IS_MULTICAST(&ea->arp_sha[0]) &&
     520           0 :             !memcmp(ea->arp_sha, etherbroadcastaddr, sizeof(ea->arp_sha))) {
     521           0 :                 inet_ntop(AF_INET, &isaddr, addr, sizeof(addr));
     522           0 :                 log(LOG_ERR, "arp: ether address is broadcast for IP address "
     523             :                     "%s!\n", addr);
     524           0 :                 goto out;
     525             :         }
     526             : 
     527           0 :         if (!memcmp(ea->arp_sha, LLADDR(ifp->if_sadl), sizeof(ea->arp_sha)))
     528             :                 goto out;       /* it's from me, ignore it. */
     529             : 
     530             :         /* Check target against our interface addresses. */
     531           0 :         sin.sin_addr = itaddr;
     532           0 :         rt = rtalloc(sintosa(&sin), 0, rdomain);
     533           0 :         if (rtisvalid(rt) && ISSET(rt->rt_flags, RTF_LOCAL) &&
     534           0 :             rt->rt_ifidx == ifp->if_index)
     535           0 :                 target = 1;
     536           0 :         rtfree(rt);
     537             :         rt = NULL;
     538             : 
     539             : #if NCARP > 0
     540           0 :         if (target && op == ARPOP_REQUEST && ifp->if_type == IFT_CARP &&
     541           0 :             !carp_iamatch(ifp))
     542             :                 goto out;
     543             : #endif
     544             : 
     545             :         /* Do we have an ARP cache for the sender? Create if we are target. */
     546           0 :         rt = arplookup(&isaddr, target, 0, rdomain);
     547             : 
     548             :         /* Check sender against our interface addresses. */
     549           0 :         if (rtisvalid(rt) && ISSET(rt->rt_flags, RTF_LOCAL) &&
     550           0 :             rt->rt_ifidx == ifp->if_index && isaddr.s_addr != INADDR_ANY) {
     551           0 :                 inet_ntop(AF_INET, &isaddr, addr, sizeof(addr));
     552           0 :                 log(LOG_ERR, "duplicate IP address %s sent from ethernet "
     553           0 :                     "address %s\n", addr, ether_sprintf(ea->arp_sha));
     554           0 :                 itaddr = isaddr;
     555           0 :         } else if (rt != NULL) {
     556             :                 int error;
     557             : 
     558           0 :                 KERNEL_LOCK();
     559           0 :                 error = arpcache(ifp, ea, rt);
     560           0 :                 KERNEL_UNLOCK();
     561           0 :                 if (error)
     562           0 :                         goto out;
     563           0 :         }
     564             : 
     565           0 :         if (op == ARPOP_REQUEST) {
     566             :                 uint8_t *eaddr;
     567             : 
     568           0 :                 if (target) {
     569             :                         /* We already have all info for the reply */
     570           0 :                         eaddr = LLADDR(ifp->if_sadl);
     571           0 :                 } else {
     572           0 :                         rtfree(rt);
     573           0 :                         rt = arplookup(&itaddr, 0, SIN_PROXY, rdomain);
     574             :                         /*
     575             :                          * Protect from possible duplicates, only owner
     576             :                          * should respond
     577             :                          */
     578           0 :                         if ((rt == NULL) || (rt->rt_ifidx != ifp->if_index))
     579           0 :                                 goto out;
     580           0 :                         eaddr = LLADDR(satosdl(rt->rt_gateway));
     581             :                 }
     582           0 :                 arpreply(ifp, m, &itaddr, eaddr, rdomain);
     583           0 :                 rtfree(rt);
     584           0 :                 return;
     585             :         }
     586             : 
     587             : out:
     588           0 :         rtfree(rt);
     589           0 :         m_freem(m);
     590           0 : }
     591             : 
     592             : int
     593           0 : arpcache(struct ifnet *ifp, struct ether_arp *ea, struct rtentry *rt)
     594             : {
     595           0 :         struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
     596           0 :         struct sockaddr_dl *sdl = satosdl(rt->rt_gateway);
     597           0 :         struct in_addr *spa = (struct in_addr *)ea->arp_spa;
     598           0 :         char addr[INET_ADDRSTRLEN];
     599             :         struct ifnet *rifp;
     600             :         unsigned int len;
     601             :         int changed = 0;
     602             : 
     603           0 :         KERNEL_ASSERT_LOCKED();
     604           0 :         KASSERT(sdl != NULL);
     605             : 
     606             :         /*
     607             :          * This can happen if the entry has been deleted by another CPU
     608             :          * after we found it.
     609             :          */
     610           0 :         if (la == NULL)
     611           0 :                 return (0);
     612             : 
     613           0 :         if (sdl->sdl_alen > 0) {
     614           0 :                 if (memcmp(ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) {
     615           0 :                         if (ISSET(rt->rt_flags, RTF_PERMANENT_ARP|RTF_LOCAL)) {
     616           0 :                                 inet_ntop(AF_INET, spa, addr, sizeof(addr));
     617           0 :                                 log(LOG_WARNING, "arp: attempt to overwrite "
     618             :                                    "permanent entry for %s by %s on %s\n", addr,
     619           0 :                                    ether_sprintf(ea->arp_sha), ifp->if_xname);
     620           0 :                                 return (-1);
     621           0 :                         } else if (rt->rt_ifidx != ifp->if_index) {
     622             : #if NCARP > 0
     623           0 :                                 if (ifp->if_type != IFT_CARP)
     624             : #endif
     625             :                                 {
     626           0 :                                         rifp = if_get(rt->rt_ifidx);
     627           0 :                                         if (rifp == NULL)
     628           0 :                                                 return (-1);
     629           0 :                                         inet_ntop(AF_INET, spa, addr,
     630             :                                             sizeof(addr));
     631           0 :                                         log(LOG_WARNING, "arp: attempt to "
     632             :                                             "overwrite entry for %s on %s by "
     633           0 :                                             "%s on %s\n", addr, rifp->if_xname,
     634           0 :                                             ether_sprintf(ea->arp_sha),
     635           0 :                                             ifp->if_xname);
     636           0 :                                         if_put(rifp);
     637           0 :                                 }
     638           0 :                                 return (-1);
     639             :                         } else {
     640           0 :                                 inet_ntop(AF_INET, spa, addr, sizeof(addr));
     641           0 :                                 log(LOG_INFO, "arp info overwritten for %s by "
     642             :                                     "%s on %s\n", addr,
     643           0 :                                     ether_sprintf(ea->arp_sha), ifp->if_xname);
     644           0 :                                 rt->rt_expire = 1;/* no longer static */
     645             :                         }
     646             :                         changed = 1;
     647           0 :                 }
     648           0 :         } else if (!if_isconnected(ifp, rt->rt_ifidx)) {
     649           0 :                 rifp = if_get(rt->rt_ifidx);
     650           0 :                 if (rifp == NULL)
     651           0 :                         return (-1);
     652           0 :                 inet_ntop(AF_INET, spa, addr, sizeof(addr));
     653           0 :                 log(LOG_WARNING, "arp: attempt to add entry for %s on %s by %s"
     654           0 :                     " on %s\n", addr, rifp->if_xname,
     655           0 :                     ether_sprintf(ea->arp_sha), ifp->if_xname);
     656           0 :                 if_put(rifp);
     657           0 :                 return (-1);
     658             :         }
     659           0 :         sdl->sdl_alen = sizeof(ea->arp_sha);
     660           0 :         memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha));
     661           0 :         if (rt->rt_expire)
     662           0 :                 rt->rt_expire = time_uptime + arpt_keep;
     663           0 :         rt->rt_flags &= ~RTF_REJECT;
     664             : 
     665             :         /* Notify userland that an ARP resolution has been done. */
     666           0 :         if (la->la_asked || changed) {
     667           0 :                 rtm_send(rt, RTM_RESOLVE, 0, ifp->if_rdomain);
     668           0 :         }
     669             : 
     670           0 :         la->la_asked = 0;
     671           0 :         while ((len = ml_len(&la->la_ml)) != 0) {
     672             :                 struct mbuf *mh;
     673             : 
     674           0 :                 mh = ml_dequeue(&la->la_ml);
     675           0 :                 la_hold_total--;
     676             : 
     677           0 :                 ifp->if_output(ifp, mh, rt_key(rt), rt);
     678             : 
     679           0 :                 if (ml_len(&la->la_ml) == len) {
     680             :                         /* mbuf is back in queue. Discard. */
     681           0 :                         while ((mh = ml_dequeue(&la->la_ml)) != NULL) {
     682           0 :                                 la_hold_total--;
     683           0 :                                 m_freem(mh);
     684             :                         }
     685           0 :                         break;
     686             :                 }
     687           0 :         }
     688             : 
     689           0 :         return (0);
     690           0 : }
     691             : 
     692             : void
     693           0 : arpinvalidate(struct rtentry *rt)
     694             : {
     695           0 :         struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
     696           0 :         struct sockaddr_dl *sdl = satosdl(rt->rt_gateway);
     697             : 
     698           0 :         la_hold_total -= ml_purge(&la->la_ml);
     699           0 :         sdl->sdl_alen = 0;
     700           0 :         la->la_asked = 0;
     701           0 : }
     702             : 
     703             : /*
     704             :  * Free an arp entry.
     705             :  */
     706             : void
     707           0 : arptfree(struct rtentry *rt)
     708             : {
     709             :         struct ifnet *ifp;
     710             : 
     711           0 :         KASSERT(!ISSET(rt->rt_flags, RTF_LOCAL));
     712           0 :         arpinvalidate(rt);
     713             : 
     714           0 :         ifp = if_get(rt->rt_ifidx);
     715           0 :         KASSERT(ifp != NULL);
     716           0 :         if (!ISSET(rt->rt_flags, RTF_STATIC|RTF_CACHED))
     717           0 :                 rtdeletemsg(rt, ifp, ifp->if_rdomain);
     718           0 :         if_put(ifp);
     719           0 : }
     720             : 
     721             : /*
     722             :  * Lookup or enter a new address in arptab.
     723             :  */
     724             : struct rtentry *
     725           0 : arplookup(struct in_addr *inp, int create, int proxy, u_int tableid)
     726             : {
     727             :         struct rtentry *rt;
     728           0 :         struct sockaddr_inarp sin;
     729             :         int flags;
     730             : 
     731           0 :         memset(&sin, 0, sizeof(sin));
     732           0 :         sin.sin_len = sizeof(sin);
     733           0 :         sin.sin_family = AF_INET;
     734           0 :         sin.sin_addr.s_addr = inp->s_addr;
     735           0 :         sin.sin_other = proxy ? SIN_PROXY : 0;
     736           0 :         flags = (create) ? RT_RESOLVE : 0;
     737             : 
     738           0 :         rt = rtalloc((struct sockaddr *)&sin, flags, tableid);
     739           0 :         if (!rtisvalid(rt) || ISSET(rt->rt_flags, RTF_GATEWAY) ||
     740           0 :             !ISSET(rt->rt_flags, RTF_LLINFO) ||
     741           0 :             rt->rt_gateway->sa_family != AF_LINK) {
     742           0 :                 rtfree(rt);
     743           0 :                 return (NULL);
     744             :         }
     745             : 
     746           0 :         if (proxy && !ISSET(rt->rt_flags, RTF_ANNOUNCE)) {
     747           0 :                 while ((rt = rtable_iterate(rt)) != NULL) {
     748           0 :                         if (ISSET(rt->rt_flags, RTF_ANNOUNCE)) {
     749             :                                 break;
     750             :                         }
     751             :                 }
     752             :         }
     753             : 
     754           0 :         return (rt);
     755           0 : }
     756             : 
     757             : /*
     758             :  * Check whether we do proxy ARP for this address and we point to ourselves.
     759             :  */
     760             : int
     761           0 : arpproxy(struct in_addr in, unsigned int rtableid)
     762             : {
     763             :         struct sockaddr_dl *sdl;
     764             :         struct rtentry *rt;
     765             :         struct ifnet *ifp;
     766             :         int found = 0;
     767             : 
     768           0 :         rt = arplookup(&in, 0, SIN_PROXY, rtableid);
     769           0 :         if (!rtisvalid(rt)) {
     770           0 :                 rtfree(rt);
     771           0 :                 return (0);
     772             :         }
     773             : 
     774             :         /* Check that arp information are correct. */
     775           0 :         sdl = satosdl(rt->rt_gateway);
     776           0 :         if (sdl->sdl_alen != ETHER_ADDR_LEN) {
     777           0 :                 rtfree(rt);
     778           0 :                 return (0);
     779             :         }
     780             : 
     781           0 :         ifp = if_get(rt->rt_ifidx);
     782           0 :         if (ifp == NULL) {
     783           0 :                 rtfree(rt);
     784           0 :                 return (0);
     785             :         }
     786             : 
     787           0 :         if (!memcmp(LLADDR(sdl), LLADDR(ifp->if_sadl), sdl->sdl_alen))
     788           0 :                 found = 1;
     789             : 
     790           0 :         if_put(ifp);
     791           0 :         rtfree(rt);
     792           0 :         return (found);
     793           0 : }
     794             : 
     795             : /*
     796             :  * Called from Ethernet interrupt handlers
     797             :  * when ether packet type ETHERTYPE_REVARP
     798             :  * is received.  Common length and type checks are done here,
     799             :  * then the protocol-specific routine is called.
     800             :  */
     801             : void
     802           0 : revarpinput(struct ifnet *ifp, struct mbuf *m)
     803             : {
     804           0 :         if ((m = arppullup(m)) == NULL)
     805             :                 return;
     806           0 :         in_revarpinput(ifp, m);
     807           0 : }
     808             : 
     809             : /*
     810             :  * RARP for Internet protocols on Ethernet.
     811             :  * Algorithm is that given in RFC 903.
     812             :  * We are only using for bootstrap purposes to get an ip address for one of
     813             :  * our interfaces.  Thus we support no user-interface.
     814             :  *
     815             :  * Since the contents of the RARP reply are specific to the interface that
     816             :  * sent the request, this code must ensure that they are properly associated.
     817             :  *
     818             :  * Note: also supports ARP via RARP packets, per the RFC.
     819             :  */
     820             : void
     821           0 : in_revarpinput(struct ifnet *ifp, struct mbuf *m)
     822             : {
     823             :         struct ether_arp *ar;
     824             :         int op;
     825             : 
     826           0 :         ar = mtod(m, struct ether_arp *);
     827           0 :         op = ntohs(ar->arp_op);
     828           0 :         switch (op) {
     829             :         case ARPOP_REQUEST:
     830             :         case ARPOP_REPLY:       /* per RFC */
     831           0 :                 niq_enqueue(&arpinq, m);
     832           0 :                 return;
     833             :         case ARPOP_REVREPLY:
     834             :                 break;
     835             :         case ARPOP_REVREQUEST:  /* handled by rarpd(8) */
     836             :         default:
     837             :                 goto out;
     838             :         }
     839             : #ifdef NFSCLIENT
     840           0 :         if (revarp_ifidx == 0)
     841             :                 goto out;
     842           0 :         if (revarp_ifidx != m->m_pkthdr.ph_ifidx) /* !same interface */
     843             :                 goto out;
     844           0 :         if (revarp_finished)
     845             :                 goto wake;
     846           0 :         if (memcmp(ar->arp_tha, LLADDR(ifp->if_sadl), sizeof(ar->arp_tha)))
     847             :                 goto out;
     848           0 :         memcpy(&revarp_srvip, ar->arp_spa, sizeof(revarp_srvip));
     849           0 :         memcpy(&revarp_myip, ar->arp_tpa, sizeof(revarp_myip));
     850           0 :         revarp_finished = 1;
     851             : wake:   /* Do wakeup every time in case it was missed. */
     852           0 :         wakeup((caddr_t)&revarp_myip);
     853             : #endif /* NFSCLIENT */
     854             : 
     855             : out:
     856           0 :         m_freem(m);
     857           0 : }
     858             : 
     859             : /*
     860             :  * Send a RARP request for the ip address of the specified interface.
     861             :  * The request should be RFC 903-compliant.
     862             :  */
     863             : void
     864           0 : revarprequest(struct ifnet *ifp)
     865             : {
     866           0 :         struct sockaddr sa;
     867             :         struct mbuf *m;
     868             :         struct ether_header *eh;
     869             :         struct ether_arp *ea;
     870           0 :         struct arpcom *ac = (struct arpcom *)ifp;
     871             : 
     872           0 :         if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
     873           0 :                 return;
     874           0 :         m->m_len = sizeof(*ea);
     875           0 :         m->m_pkthdr.len = sizeof(*ea);
     876           0 :         m->m_pkthdr.pf.prio = ifp->if_llprio;
     877           0 :         MH_ALIGN(m, sizeof(*ea));
     878           0 :         ea = mtod(m, struct ether_arp *);
     879           0 :         eh = (struct ether_header *)sa.sa_data;
     880           0 :         memset(ea, 0, sizeof(*ea));
     881           0 :         memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost));
     882           0 :         eh->ether_type = htons(ETHERTYPE_REVARP);
     883           0 :         ea->arp_hrd = htons(ARPHRD_ETHER);
     884           0 :         ea->arp_pro = htons(ETHERTYPE_IP);
     885           0 :         ea->arp_hln = sizeof(ea->arp_sha);        /* hardware address length */
     886           0 :         ea->arp_pln = sizeof(ea->arp_spa);        /* protocol address length */
     887           0 :         ea->arp_op = htons(ARPOP_REVREQUEST);
     888           0 :         memcpy(eh->ether_shost, ac->ac_enaddr, sizeof(ea->arp_tha));
     889           0 :         memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha));
     890           0 :         memcpy(ea->arp_tha, ac->ac_enaddr, sizeof(ea->arp_tha));
     891           0 :         sa.sa_family = pseudo_AF_HDRCMPLT;
     892           0 :         sa.sa_len = sizeof(sa);
     893           0 :         m->m_flags |= M_BCAST;
     894           0 :         ifp->if_output(ifp, m, &sa, NULL);
     895           0 : }
     896             : 
     897             : #ifdef NFSCLIENT
     898             : /*
     899             :  * RARP for the ip address of the specified interface, but also
     900             :  * save the ip address of the server that sent the answer.
     901             :  * Timeout if no response is received.
     902             :  */
     903             : int
     904           0 : revarpwhoarewe(struct ifnet *ifp, struct in_addr *serv_in,
     905             :     struct in_addr *clnt_in)
     906             : {
     907             :         int result, count = 20;
     908             : 
     909           0 :         if (revarp_finished)
     910           0 :                 return EIO;
     911             : 
     912           0 :         revarp_ifidx = ifp->if_index;
     913           0 :         while (count--) {
     914           0 :                 revarprequest(ifp);
     915           0 :                 result = tsleep((caddr_t)&revarp_myip, PSOCK, "revarp", hz/2);
     916           0 :                 if (result != EWOULDBLOCK)
     917             :                         break;
     918             :         }
     919           0 :         revarp_ifidx = 0;
     920           0 :         if (!revarp_finished)
     921           0 :                 return ENETUNREACH;
     922             : 
     923           0 :         memcpy(serv_in, &revarp_srvip, sizeof(*serv_in));
     924           0 :         memcpy(clnt_in, &revarp_myip, sizeof(*clnt_in));
     925           0 :         return 0;
     926           0 : }
     927             : 
     928             : /* For compatibility: only saves interface address. */
     929             : int
     930           0 : revarpwhoami(struct in_addr *in, struct ifnet *ifp)
     931             : {
     932           0 :         struct in_addr server;
     933           0 :         return (revarpwhoarewe(ifp, &server, in));
     934           0 : }
     935             : #endif /* NFSCLIENT */

Generated by: LCOV version 1.13