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 /*
    2  * Copyright (c) 1982, 1986, 1988, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by the University of
   16  *      California, Berkeley and its contributors.
   17  * 4. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  *      @(#)if_ether.c  8.1 (Berkeley) 6/10/93
   34  * $FreeBSD: src/sys/netinet/if_ether.c,v 1.34.2.4 1999/09/05 08:18:12 peter Exp $
   35  */
   36 
   37 /*
   38  * Ethernet address resolution protocol.
   39  * TODO:
   40  *      add "inuse/lock" bit (or ref. count) along with valid bit
   41  */
   42 
   43 #include <sys/param.h>
   44 #include <sys/kernel.h>
   45 #include <sys/sysctl.h>
   46 #include <sys/queue.h>
   47 #include <sys/systm.h>
   48 #include <sys/mbuf.h>
   49 #include <sys/malloc.h>
   50 #include <sys/socket.h>
   51 #include <sys/syslog.h>
   52 
   53 #include <net/if.h>
   54 #include <net/if_dl.h>
   55 #include <net/route.h>
   56 #include <net/netisr.h>
   57 
   58 #include <netinet/in.h>
   59 #include <netinet/in_var.h>
   60 #include <netinet/if_ether.h>
   61 
   62 #define SIN(s) ((struct sockaddr_in *)s)
   63 #define SDL(s) ((struct sockaddr_dl *)s)
   64 
   65 SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, "");
   66 
   67 /* timer values */
   68 static int arpt_prune = (5*60*1); /* walk list every 5 minutes */
   69 static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
   70 static int arpt_down = 20;      /* once declared down, don't send for 20 sec */
   71 
   72 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW,
   73            &arpt_prune, 0, "");
   74 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW, 
   75            &arpt_keep, 0, "");
   76 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW,
   77            &arpt_down, 0, "");
   78 
   79 #define rt_expire rt_rmx.rmx_expire
   80 
   81 struct llinfo_arp {
   82         LIST_ENTRY(llinfo_arp) la_le;
   83         struct  rtentry *la_rt;
   84         struct  mbuf *la_hold;          /* last packet until resolved/timeout */
   85         long    la_asked;               /* last time we QUERIED for this addr */
   86 #define la_timer la_rt->rt_rmx.rmx_expire /* deletion time in seconds */
   87 };
   88 
   89 static  LIST_HEAD(, llinfo_arp) llinfo_arp;
   90 
   91 struct  ifqueue arpintrq = {0, 0, 0, 50};
   92 static int      arp_inuse, arp_allocated;
   93 
   94 static int      arp_maxtries = 5;
   95 static int      useloopback = 1; /* use loopback interface for local traffic */
   96 static int      arp_proxyall = 0;
   97 
   98 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxtries, CTLFLAG_RW,
   99            &arp_maxtries, 0, "");
  100 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW,
  101            &useloopback, 0, "");
  102 SYSCTL_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW,
  103            &arp_proxyall, 0, "");
  104 
  105 static void     arp_rtrequest __P((int, struct rtentry *, struct sockaddr *));
  106 static void     arprequest __P((struct arpcom *, u_long *, u_long *, u_char *));
  107 static void     arpintr __P((void));
  108 static void     arptfree __P((struct llinfo_arp *));
  109 static void     arptimer __P((void *));
  110 static struct llinfo_arp
  111                 *arplookup __P((u_long, int, int));
  112 static void     in_arpinput __P((struct mbuf *));
  113 
  114 /*
  115  * Timeout routine.  Age arp_tab entries periodically.
  116  */
  117 /* ARGSUSED */
  118 static void
  119 arptimer(ignored_arg)
  120         void *ignored_arg;
  121 {
  122         int s = splnet();
  123         register struct llinfo_arp *la = llinfo_arp.lh_first;
  124         struct llinfo_arp *ola;
  125 
  126         timeout(arptimer, (caddr_t)0, arpt_prune * hz);
  127         while ((ola = la) != 0) {
  128                 register struct rtentry *rt = la->la_rt;
  129                 la = la->la_le.le_next;
  130                 if (rt->rt_expire && rt->rt_expire <= time.tv_sec)
  131                         arptfree(ola); /* timer has expired, clear */
  132         }
  133         splx(s);
  134 }
  135 
  136 /*
  137  * Parallel to llc_rtrequest.
  138  */
  139 static void
  140 arp_rtrequest(req, rt, sa)
  141         int req;
  142         register struct rtentry *rt;
  143         struct sockaddr *sa;
  144 {
  145         register struct sockaddr *gate = rt->rt_gateway;
  146         register struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
  147         static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
  148         static int arpinit_done;
  149 
  150         if (!arpinit_done) {
  151                 arpinit_done = 1;
  152                 LIST_INIT(&llinfo_arp);
  153                 timeout(arptimer, (caddr_t)0, hz);
  154         }
  155         if (rt->rt_flags & RTF_GATEWAY)
  156                 return;
  157         switch (req) {
  158 
  159         case RTM_ADD:
  160                 /*
  161                  * XXX: If this is a manually added route to interface
  162                  * such as older version of routed or gated might provide,
  163                  * restore cloning bit.
  164                  */
  165                 if ((rt->rt_flags & RTF_HOST) == 0 &&
  166                     SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
  167                         rt->rt_flags |= RTF_CLONING;
  168                 if (rt->rt_flags & RTF_CLONING) {
  169                         /*
  170                          * Case 1: This route should come from a route to iface.
  171                          */
  172                         rt_setgate(rt, rt_key(rt),
  173                                         (struct sockaddr *)&null_sdl);
  174                         gate = rt->rt_gateway;
  175                         SDL(gate)->sdl_type = rt->rt_ifp->if_type;
  176                         SDL(gate)->sdl_index = rt->rt_ifp->if_index;
  177                         rt->rt_expire = time.tv_sec;
  178                         break;
  179                 }
  180                 /* Announce a new entry if requested. */
  181                 if (rt->rt_flags & RTF_ANNOUNCE)
  182                         arprequest((struct arpcom *)rt->rt_ifp,
  183                             &SIN(rt_key(rt))->sin_addr.s_addr,
  184                             &SIN(rt_key(rt))->sin_addr.s_addr,
  185                             (u_char *)LLADDR(SDL(gate)));
  186                 /*FALLTHROUGH*/
  187         case RTM_RESOLVE:
  188                 if (gate->sa_family != AF_LINK ||
  189                     gate->sa_len < sizeof(null_sdl)) {
  190                         log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n");
  191                         break;
  192                 }
  193                 SDL(gate)->sdl_type = rt->rt_ifp->if_type;
  194                 SDL(gate)->sdl_index = rt->rt_ifp->if_index;
  195                 if (la != 0)
  196                         break; /* This happens on a route change */
  197                 /*
  198                  * Case 2:  This route may come from cloning, or a manual route
  199                  * add with a LL address.
  200                  */
  201                 R_Malloc(la, struct llinfo_arp *, sizeof(*la));
  202                 rt->rt_llinfo = (caddr_t)la;
  203                 if (la == 0) {
  204                         log(LOG_DEBUG, "arp_rtrequest: malloc failed\n");
  205                         break;
  206                 }
  207                 arp_inuse++, arp_allocated++;
  208                 Bzero(la, sizeof(*la));
  209                 la->la_rt = rt;
  210                 rt->rt_flags |= RTF_LLINFO;
  211                 LIST_INSERT_HEAD(&llinfo_arp, la, la_le);
  212 
  213                 /*
  214                  * This keeps the multicast addresses from showing up
  215                  * in `arp -a' listings as unresolved.  It's not actually
  216                  * functional.  Then the same for broadcast.
  217                  */
  218                 if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr))) {
  219                         ETHER_MAP_IP_MULTICAST(&SIN(rt_key(rt))->sin_addr,
  220                                                LLADDR(SDL(gate)));
  221                         SDL(gate)->sdl_alen = 6;
  222                         rt->rt_expire = 0;
  223                 }
  224                 if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) {
  225                         memcpy(LLADDR(SDL(gate)), etherbroadcastaddr, 6);
  226                         SDL(gate)->sdl_alen = 6;
  227                         rt->rt_expire = 0;
  228                 }
  229 
  230                 if (SIN(rt_key(rt))->sin_addr.s_addr ==
  231                     (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) {
  232                     /*
  233                      * This test used to be
  234                      *  if (loif.if_flags & IFF_UP)
  235                      * It allowed local traffic to be forced
  236                      * through the hardware by configuring the loopback down.
  237                      * However, it causes problems during network configuration
  238                      * for boards that can't receive packets they send.
  239                      * It is now necessary to clear "useloopback" and remove
  240                      * the route to force traffic out to the hardware.
  241                      */
  242                         rt->rt_expire = 0;
  243                         Bcopy(((struct arpcom *)rt->rt_ifp)->ac_enaddr,
  244                                 LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6);
  245                         if (useloopback)
  246                                 rt->rt_ifp = loif;
  247 
  248                 }
  249                 break;
  250 
  251         case RTM_DELETE:
  252                 if (la == 0)
  253                         break;
  254                 arp_inuse--;
  255                 LIST_REMOVE(la, la_le);
  256                 rt->rt_llinfo = 0;
  257                 rt->rt_flags &= ~RTF_LLINFO;
  258                 if (la->la_hold)
  259                         m_freem(la->la_hold);
  260                 Free((caddr_t)la);
  261         }
  262 }
  263 
  264 /*
  265  * Broadcast an ARP request. Caller specifies:
  266  *      - arp header source ip address
  267  *      - arp header target ip address
  268  *      - arp header source ethernet address
  269  */
  270 static void
  271 arprequest(ac, sip, tip, enaddr)
  272         register struct arpcom *ac;
  273         register u_long *sip, *tip;
  274         register u_char *enaddr;
  275 {
  276         register struct mbuf *m;
  277         register struct ether_header *eh;
  278         register struct ether_arp *ea;
  279         struct sockaddr sa;
  280 
  281         if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
  282                 return;
  283         m->m_len = sizeof(*ea);
  284         m->m_pkthdr.len = sizeof(*ea);
  285         MH_ALIGN(m, sizeof(*ea));
  286         ea = mtod(m, struct ether_arp *);
  287         eh = (struct ether_header *)sa.sa_data;
  288         bzero((caddr_t)ea, sizeof (*ea));
  289         (void)memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost));
  290         eh->ether_type = htons(ETHERTYPE_ARP);  /* if_output will not swap */
  291         ea->arp_hrd = htons(ARPHRD_ETHER);
  292         ea->arp_pro = htons(ETHERTYPE_IP);
  293         ea->arp_hln = sizeof(ea->arp_sha);      /* hardware address length */
  294         ea->arp_pln = sizeof(ea->arp_spa);      /* protocol address length */
  295         ea->arp_op = htons(ARPOP_REQUEST);
  296         (void)memcpy(ea->arp_sha, enaddr, sizeof(ea->arp_sha));
  297         (void)memcpy(ea->arp_spa, sip, sizeof(ea->arp_spa));
  298         (void)memcpy(ea->arp_tpa, tip, sizeof(ea->arp_tpa));
  299         sa.sa_family = AF_UNSPEC;
  300         sa.sa_len = sizeof(sa);
  301         (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
  302 }
  303 
  304 /*
  305  * Resolve an IP address into an ethernet address.  If success,
  306  * desten is filled in.  If there is no entry in arptab,
  307  * set one up and broadcast a request for the IP address.
  308  * Hold onto this mbuf and resend it once the address
  309  * is finally resolved.  A return value of 1 indicates
  310  * that desten has been filled in and the packet should be sent
  311  * normally; a 0 return indicates that the packet has been
  312  * taken over here, either now or for later transmission.
  313  */
  314 int
  315 arpresolve(ac, rt, m, dst, desten, rt0)
  316         register struct arpcom *ac;
  317         register struct rtentry *rt;
  318         struct mbuf *m;
  319         register struct sockaddr *dst;
  320         register u_char *desten;
  321         struct rtentry *rt0;
  322 {
  323         register struct llinfo_arp *la;
  324         struct sockaddr_dl *sdl;
  325 
  326         if (m->m_flags & M_BCAST) {     /* broadcast */
  327                 (void)memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr));
  328                 return (1);
  329         }
  330         if (m->m_flags & M_MCAST) {     /* multicast */
  331                 ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
  332                 return(1);
  333         }
  334         if (rt)
  335                 la = (struct llinfo_arp *)rt->rt_llinfo;
  336         else {
  337                 la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0);
  338                 if (la)
  339                         rt = la->la_rt;
  340         }
  341         if (la == 0 || rt == 0) {
  342                 log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s\n",
  343                         inet_ntoa(SIN(dst)->sin_addr));
  344                 m_freem(m);
  345                 return (0);
  346         }
  347         sdl = SDL(rt->rt_gateway);
  348         /*
  349          * Check the address family and length is valid, the address
  350          * is resolved; otherwise, try to resolve.
  351          */
  352         if ((rt->rt_expire == 0 || rt->rt_expire > time.tv_sec) &&
  353             sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
  354                 bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
  355                 return 1;
  356         }
  357         /*
  358          * There is an arptab entry, but no ethernet address
  359          * response yet.  Replace the held mbuf with this
  360          * latest one.
  361          */
  362         if (la->la_hold)
  363                 m_freem(la->la_hold);
  364         la->la_hold = m;
  365         if (rt->rt_expire) {
  366                 rt->rt_flags &= ~RTF_REJECT;
  367                 if (la->la_asked == 0 || rt->rt_expire != time.tv_sec) {
  368                         rt->rt_expire = time.tv_sec;
  369                         if (la->la_asked++ < arp_maxtries)
  370                             arprequest(ac,
  371                                 &(SIN(rt->rt_ifa->ifa_addr)->sin_addr.s_addr),
  372                                 &(SIN(dst)->sin_addr.s_addr),
  373                                 ac->ac_enaddr);
  374                         else {
  375                                 rt->rt_flags |= RTF_REJECT;
  376                                 rt->rt_expire += arpt_down;
  377                                 la->la_asked = 0;
  378                         }
  379 
  380                 }
  381         }
  382         return (0);
  383 }
  384 
  385 /*
  386  * Common length and type checks are done here,
  387  * then the protocol-specific routine is called.
  388  */
  389 static void
  390 arpintr(void)
  391 {
  392         register struct mbuf *m;
  393         register struct arphdr *ar;
  394         int s;
  395 
  396         while (arpintrq.ifq_head) {
  397                 s = splimp();
  398                 IF_DEQUEUE(&arpintrq, m);
  399                 splx(s);
  400                 if (m == 0 || (m->m_flags & M_PKTHDR) == 0)
  401                         panic("arpintr");
  402                 if (m->m_len >= sizeof(struct arphdr) &&
  403                     (ar = mtod(m, struct arphdr *)) &&
  404                     ntohs(ar->ar_hrd) == ARPHRD_ETHER &&
  405                     m->m_len >=
  406                       sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
  407 
  408                             switch (ntohs(ar->ar_pro)) {
  409 
  410                             case ETHERTYPE_IP:
  411                                     in_arpinput(m);
  412                                     continue;
  413                             }
  414                 m_freem(m);
  415         }
  416 }
  417 
  418 NETISR_SET(NETISR_ARP, arpintr);
  419 
  420 /*
  421  * ARP for Internet protocols on 10 Mb/s Ethernet.
  422  * Algorithm is that given in RFC 826.
  423  * In addition, a sanity check is performed on the sender
  424  * protocol address, to catch impersonators.
  425  * We no longer handle negotiations for use of trailer protocol:
  426  * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent
  427  * along with IP replies if we wanted trailers sent to us,
  428  * and also sent them in response to IP replies.
  429  * This allowed either end to announce the desire to receive
  430  * trailer packets.
  431  * We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
  432  * but formerly didn't normally send requests.
  433  */
  434 static void
  435 in_arpinput(m)
  436         struct mbuf *m;
  437 {
  438         register struct ether_arp *ea;
  439         register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif;
  440         struct ether_header *eh;
  441         register struct llinfo_arp *la = 0;
  442         register struct rtentry *rt;
  443         struct in_ifaddr *ia, *maybe_ia = 0;
  444         struct sockaddr_dl *sdl;
  445         struct sockaddr sa;
  446         struct in_addr isaddr, itaddr, myaddr;
  447         int op;
  448 
  449         ea = mtod(m, struct ether_arp *);
  450         op = ntohs(ea->arp_op);
  451         (void)memcpy(&isaddr, ea->arp_spa, sizeof (isaddr));
  452         (void)memcpy(&itaddr, ea->arp_tpa, sizeof (itaddr));
  453         for (ia = in_ifaddr; ia; ia = ia->ia_next)
  454 #ifdef BRIDGE
  455                 /*
  456                  * For a bridge, we want to check the address irrespective
  457                  * of the receive interface. (This will change slightly
  458                  * when we have clusters of interfaces).
  459                  */
  460                 {
  461 #else
  462                 if (ia->ia_ifp == &ac->ac_if) {
  463 #endif
  464                         maybe_ia = ia;
  465                         if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
  466                              (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
  467                                 break;
  468                 }
  469         if (maybe_ia == 0) {
  470                 m_freem(m);
  471                 return;
  472         }
  473         myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
  474         if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
  475             sizeof (ea->arp_sha))) {
  476                 m_freem(m);     /* it's from me, ignore it. */
  477                 return;
  478         }
  479         if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
  480             sizeof (ea->arp_sha))) {
  481                 log(LOG_ERR,
  482                     "arp: ether address is broadcast for IP address %s!\n",
  483                     inet_ntoa(isaddr));
  484                 m_freem(m);
  485                 return;
  486         }
  487         if (isaddr.s_addr == myaddr.s_addr) {
  488                 log(LOG_ERR,
  489                    "arp: %6D is using my IP address %s!\n",
  490                    ea->arp_sha, ":", inet_ntoa(isaddr));
  491                 itaddr = myaddr;
  492                 goto reply;
  493         }
  494         la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0);
  495         if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
  496                 if (sdl->sdl_alen &&
  497                     bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen))
  498                         log(LOG_INFO, "arp: %s moved from %6D to %6D\n",
  499                             inet_ntoa(isaddr), (u_char *)LLADDR(sdl), ":",
  500                             ea->arp_sha, ":");
  501                 (void)memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha));
  502                 sdl->sdl_alen = sizeof(ea->arp_sha);
  503                 if (rt->rt_expire)
  504                         rt->rt_expire = time.tv_sec + arpt_keep;
  505                 rt->rt_flags &= ~RTF_REJECT;
  506                 la->la_asked = 0;
  507                 if (la->la_hold) {
  508                         (*ac->ac_if.if_output)(&ac->ac_if, la->la_hold,
  509                                 rt_key(rt), rt);
  510                         la->la_hold = 0;
  511                 }
  512         }
  513 reply:
  514         if (op != ARPOP_REQUEST) {
  515                 m_freem(m);
  516                 return;
  517         }
  518         if (itaddr.s_addr == myaddr.s_addr) {
  519                 /* I am the target */
  520                 (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha));
  521                 (void)memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha));
  522         } else {
  523                 la = arplookup(itaddr.s_addr, 0, SIN_PROXY);
  524                 if (la == NULL) {
  525                         struct sockaddr_in sin;
  526 
  527                         if (!arp_proxyall) {
  528                                 m_freem(m);
  529                                 return;
  530                         }
  531 
  532                         bzero(&sin, sizeof sin);
  533                         sin.sin_family = AF_INET;
  534                         sin.sin_len = sizeof sin;
  535                         sin.sin_addr = itaddr;
  536 
  537                         rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
  538                         if (!rt) {
  539                                 m_freem(m);
  540                                 return;
  541                         }
  542                         /*
  543                          * Don't send proxies for nodes on the same interface
  544                          * as this one came out of, or we'll get into a fight
  545                          * over who claims what Ether address.
  546                          */
  547                         if (rt->rt_ifp == &ac->ac_if) {
  548                                 rtfree(rt);
  549                                 m_freem(m);
  550                                 return;
  551                         }
  552                         (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha));
  553                         (void)memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha));
  554                         rtfree(rt);
  555 #ifdef DEBUG_PROXY
  556                         printf("arp: proxying for %s\n",
  557                                inet_ntoa(itaddr));
  558 #endif
  559                 } else {
  560                         rt = la->la_rt;
  561                         (void)memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha));
  562                         sdl = SDL(rt->rt_gateway);
  563                         (void)memcpy(ea->arp_sha, LLADDR(sdl), sizeof(ea->arp_sha));
  564                 }
  565         }
  566 
  567         (void)memcpy(ea->arp_tpa, ea->arp_spa, sizeof(ea->arp_spa));
  568         (void)memcpy(ea->arp_spa, &itaddr, sizeof(ea->arp_spa));
  569         ea->arp_op = htons(ARPOP_REPLY);
  570         ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */
  571         eh = (struct ether_header *)sa.sa_data;
  572         (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost));
  573         eh->ether_type = htons(ETHERTYPE_ARP);
  574         sa.sa_family = AF_UNSPEC;
  575         sa.sa_len = sizeof(sa);
  576         (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
  577         return;
  578 }
  579 
  580 /*
  581  * Free an arp entry.
  582  */
  583 static void
  584 arptfree(la)
  585         register struct llinfo_arp *la;
  586 {
  587         register struct rtentry *rt = la->la_rt;
  588         register struct sockaddr_dl *sdl;
  589         if (rt == 0)
  590                 panic("arptfree");
  591         if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) &&
  592             sdl->sdl_family == AF_LINK) {
  593                 sdl->sdl_alen = 0;
  594                 la->la_asked = 0;
  595                 rt->rt_flags &= ~RTF_REJECT;
  596                 return;
  597         }
  598         rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
  599                         0, (struct rtentry **)0);
  600 }
  601 /*
  602  * Lookup or enter a new address in arptab.
  603  */
  604 static struct llinfo_arp *
  605 arplookup(addr, create, proxy)
  606         u_long addr;
  607         int create, proxy;
  608 {
  609         register struct rtentry *rt;
  610         static struct sockaddr_inarp sin = {sizeof(sin), AF_INET };
  611         const char *why = 0;
  612 
  613         sin.sin_addr.s_addr = addr;
  614         sin.sin_other = proxy ? SIN_PROXY : 0;
  615         rt = rtalloc1((struct sockaddr *)&sin, create, 0UL);
  616         if (rt == 0)
  617                 return (0);
  618         rt->rt_refcnt--;
  619 
  620         if (rt->rt_flags & RTF_GATEWAY)
  621                 why = "host is not on local network";
  622         else if ((rt->rt_flags & RTF_LLINFO) == 0)
  623                 why = "could not allocate llinfo";
  624         else if (rt->rt_gateway->sa_family != AF_LINK)
  625                 why = "gateway route is not ours";
  626 
  627         if (why && create) {
  628                 log(LOG_DEBUG, "arplookup %s failed: %s\n",
  629                     inet_ntoa(sin.sin_addr), why);
  630                 return 0;
  631         } else if (why) {
  632                 return 0;
  633         }
  634         return ((struct llinfo_arp *)rt->rt_llinfo);
  635 }
  636 
  637 void
  638 arp_ifinit(ac, ifa)
  639         struct arpcom *ac;
  640         struct ifaddr *ifa;
  641 {
  642         if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY)
  643                 arprequest(ac, &(IA_SIN(ifa)->sin_addr.s_addr),
  644                                &(IA_SIN(ifa)->sin_addr.s_addr), ac->ac_enaddr);
  645         ifa->ifa_rtrequest = arp_rtrequest;
  646         ifa->ifa_flags |= RTF_CLONING;
  647 }

Cache object: 589ca095654ec701c7f4b0c3180b4ab9


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