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/netipx/ipx_input.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) 1984, 1985, 1986, 1987, 1993
    3  *      The Regents of the University of California.
    4  * Copyright (c) 2004-2005 Robert N. M. Watson
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 4. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  * Copyright (c) 1995, Mike Mitchell
   32  * All rights reserved.
   33  *
   34  * Redistribution and use in source and binary forms, with or without
   35  * modification, are permitted provided that the following conditions
   36  * are met:
   37  * 1. Redistributions of source code must retain the above copyright
   38  *    notice, this list of conditions and the following disclaimer.
   39  * 2. Redistributions in binary form must reproduce the above copyright
   40  *    notice, this list of conditions and the following disclaimer in the
   41  *    documentation and/or other materials provided with the distribution.
   42  * 3. All advertising materials mentioning features or use of this software
   43  *    must display the following acknowledgement:
   44  *      This product includes software developed by the University of
   45  *      California, Berkeley and its contributors.
   46  * 4. Neither the name of the University nor the names of its contributors
   47  *    may be used to endorse or promote products derived from this software
   48  *    without specific prior written permission.
   49  *
   50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   60  * SUCH DAMAGE.
   61  *
   62  *      @(#)ipx_input.c
   63  */
   64 
   65 #include <sys/cdefs.h>
   66 __FBSDID("$FreeBSD$");
   67 
   68 #include <sys/param.h>
   69 #include <sys/systm.h>
   70 #include <sys/mbuf.h>
   71 #include <sys/protosw.h>
   72 #include <sys/socket.h>
   73 #include <sys/kernel.h>
   74 #include <sys/random.h>
   75 #include <sys/sysctl.h>
   76 
   77 #include <net/if.h>
   78 #include <net/route.h>
   79 #include <net/netisr.h>
   80 
   81 #include <netipx/ipx.h>
   82 #include <netipx/spx.h>
   83 #include <netipx/ipx_if.h>
   84 #include <netipx/ipx_pcb.h>
   85 #include <netipx/ipx_var.h>
   86 
   87 int     ipxcksum = 0;
   88 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, checksum, CTLFLAG_RW,
   89            &ipxcksum, 0, "");
   90 
   91 static int      ipxprintfs = 0;         /* printing forwarding information */
   92 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxprintfs, CTLFLAG_RW,
   93            &ipxprintfs, 0, "");
   94 
   95 static int      ipxforwarding = 0;
   96 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxforwarding, CTLFLAG_RW,
   97             &ipxforwarding, 0, "");
   98 
   99 static int      ipxnetbios = 0;
  100 SYSCTL_INT(_net_ipx, OID_AUTO, ipxnetbios, CTLFLAG_RW,
  101            &ipxnetbios, 0, "");
  102 
  103 const union     ipx_net ipx_zeronet;
  104 const union     ipx_host ipx_zerohost;
  105 
  106 const union     ipx_net ipx_broadnet = { .s_net[0] = 0xffff,
  107                                             .s_net[1] = 0xffff };
  108 const union     ipx_host ipx_broadhost = { .s_host[0] = 0xffff,
  109                                             .s_host[1] = 0xffff,
  110                                             .s_host[2] = 0xffff };
  111 
  112 struct  ipxstat ipxstat;
  113 struct  sockaddr_ipx ipx_netmask, ipx_hostmask;
  114 
  115 /*
  116  * IPX protocol control block (pcb) lists.
  117  */
  118 struct mtx              ipxpcb_list_mtx;
  119 struct ipxpcbhead       ipxpcb_list;
  120 struct ipxpcbhead       ipxrawpcb_list;
  121 
  122 static int ipxqmaxlen = IFQ_MAXLEN;
  123 static  struct ifqueue ipxintrq;
  124 
  125 long    ipx_pexseq;             /* Locked with ipxpcb_list_mtx. */
  126 
  127 static  int ipx_do_route(struct ipx_addr *src, struct route *ro);
  128 static  void ipx_undo_route(struct route *ro);
  129 static  void ipx_forward(struct mbuf *m);
  130 static  void ipxintr(struct mbuf *m);
  131 
  132 /*
  133  * IPX initialization.
  134  */
  135 
  136 void
  137 ipx_init(void)
  138 {
  139 
  140         read_random(&ipx_pexseq, sizeof ipx_pexseq);
  141 
  142         LIST_INIT(&ipxpcb_list);
  143         LIST_INIT(&ipxrawpcb_list);
  144 
  145         IPX_LIST_LOCK_INIT();
  146 
  147         ipx_netmask.sipx_len = 6;
  148         ipx_netmask.sipx_addr.x_net = ipx_broadnet;
  149 
  150         ipx_hostmask.sipx_len = 12;
  151         ipx_hostmask.sipx_addr.x_net = ipx_broadnet;
  152         ipx_hostmask.sipx_addr.x_host = ipx_broadhost;
  153 
  154         ipxintrq.ifq_maxlen = ipxqmaxlen;
  155         mtx_init(&ipxintrq.ifq_mtx, "ipx_inq", NULL, MTX_DEF);
  156         netisr_register(NETISR_IPX, ipxintr, &ipxintrq, NETISR_MPSAFE);
  157 }
  158 
  159 /*
  160  * IPX input routine.  Pass to next level.
  161  */
  162 static void
  163 ipxintr(struct mbuf *m)
  164 {
  165         struct ipx *ipx;
  166         struct ipxpcb *ipxp;
  167         struct ipx_ifaddr *ia;
  168         int len;
  169 
  170         /*
  171          * If no IPX addresses have been set yet but the interfaces
  172          * are receiving, can't do anything with incoming packets yet.
  173          */
  174         if (ipx_ifaddr == NULL) {
  175                 m_freem(m);
  176                 return;
  177         }
  178 
  179         ipxstat.ipxs_total++;
  180 
  181         if ((m->m_flags & M_EXT || m->m_len < sizeof(struct ipx)) &&
  182             (m = m_pullup(m, sizeof(struct ipx))) == NULL) {
  183                 ipxstat.ipxs_toosmall++;
  184                 return;
  185         }
  186 
  187         /*
  188          * Give any raw listeners a crack at the packet
  189          */
  190         IPX_LIST_LOCK();
  191         LIST_FOREACH(ipxp, &ipxrawpcb_list, ipxp_list) {
  192                 struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL);
  193                 if (m1 != NULL) {
  194                         IPX_LOCK(ipxp);
  195                         ipx_input(m1, ipxp);
  196                         IPX_UNLOCK(ipxp);
  197                 }
  198         }
  199         IPX_LIST_UNLOCK();
  200 
  201         ipx = mtod(m, struct ipx *);
  202         len = ntohs(ipx->ipx_len);
  203         /*
  204          * Check that the amount of data in the buffers
  205          * is as at least much as the IPX header would have us expect.
  206          * Trim mbufs if longer than we expect.
  207          * Drop packet if shorter than we expect.
  208          */
  209         if (m->m_pkthdr.len < len) {
  210                 ipxstat.ipxs_tooshort++;
  211                 m_freem(m);
  212                 return;
  213         }
  214         if (m->m_pkthdr.len > len) {
  215                 if (m->m_len == m->m_pkthdr.len) {
  216                         m->m_len = len;
  217                         m->m_pkthdr.len = len;
  218                 } else
  219                         m_adj(m, len - m->m_pkthdr.len);
  220         }
  221         if (ipxcksum && ipx->ipx_sum != 0xffff) {
  222                 if (ipx->ipx_sum != ipx_cksum(m, len)) {
  223                         ipxstat.ipxs_badsum++;
  224                         m_freem(m);
  225                         return;
  226                 }
  227         }
  228 
  229         /*
  230          * Propagated (Netbios) packets (type 20) has to be handled
  231          * different. :-(
  232          */
  233         if (ipx->ipx_pt == IPXPROTO_NETBIOS) {
  234                 if (ipxnetbios) {
  235                         ipx_output_type20(m);
  236                         return;
  237                 } else {
  238                         m_freem(m);
  239                         return;
  240                 }
  241         }
  242 
  243         /*
  244          * Is this a directed broadcast?
  245          */
  246         if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.x_host)) {
  247                 if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) &&
  248                     (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_broadnet)) &&
  249                     (!ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet)) &&
  250                     (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)) ) {
  251                         /*
  252                          * If it is a broadcast to the net where it was
  253                          * received from, treat it as ours.
  254                          */
  255                         for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
  256                                 if((ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) &&
  257                                    ipx_neteq(ia->ia_addr.sipx_addr,
  258                                              ipx->ipx_dna))
  259                                         goto ours;
  260 
  261                         /*
  262                          * Look to see if I need to eat this packet.
  263                          * Algorithm is to forward all young packets
  264                          * and prematurely age any packets which will
  265                          * by physically broadcasted.
  266                          * Any very old packets eaten without forwarding
  267                          * would die anyway.
  268                          *
  269                          * Suggestion of Bill Nesheim, Cornell U.
  270                          */
  271                         if (ipx->ipx_tc < IPX_MAXHOPS) {
  272                                 ipx_forward(m);
  273                                 return;
  274                         }
  275                 }
  276         /*
  277          * Is this our packet? If not, forward.
  278          */
  279         } else {
  280                 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
  281                         if (ipx_hosteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) &&
  282                             (ipx_neteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) ||
  283                              ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)))
  284                                 break;
  285 
  286                 if (ia == NULL) {
  287                         ipx_forward(m);
  288                         return;
  289                 }
  290         }
  291 ours:
  292         /*
  293          * Locate pcb for datagram.
  294          */
  295         IPX_LIST_LOCK();
  296         ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.x_port, IPX_WILDCARD);
  297         /*
  298          * Switch out to protocol's input routine.
  299          */
  300         if (ipxp != NULL) {
  301                 ipxstat.ipxs_delivered++;
  302                 if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS) == 0)
  303                         switch (ipx->ipx_pt) {
  304                         case IPXPROTO_SPX:
  305                                 IPX_LOCK(ipxp);
  306                                 /* Will release both locks. */
  307                                 spx_input(m, ipxp);
  308                                 return;
  309                         }
  310                 IPX_LOCK(ipxp);
  311                 ipx_input(m, ipxp);
  312                 IPX_UNLOCK(ipxp);
  313         } else
  314                 m_freem(m);
  315         IPX_LIST_UNLOCK();
  316 }
  317 
  318 void
  319 ipx_ctlinput(cmd, arg_as_sa, dummy)
  320         int cmd;
  321         struct sockaddr *arg_as_sa;     /* XXX should be swapped with dummy */
  322         void *dummy;
  323 {
  324 
  325         /* Currently, nothing. */
  326 }
  327 
  328 /*
  329  * Forward a packet. If some error occurs drop the packet. IPX don't
  330  * have a way to return errors to the sender.
  331  */
  332 
  333 static struct route ipx_droute;
  334 static struct route ipx_sroute;
  335 
  336 static void
  337 ipx_forward(struct mbuf *m)
  338 {
  339         struct ipx *ipx = mtod(m, struct ipx *);
  340         int error;
  341         int agedelta = 1;
  342         int flags = IPX_FORWARDING;
  343         int ok_there = 0;
  344         int ok_back = 0;
  345 
  346         if (ipxforwarding == 0) {
  347                 /* can't tell difference between net and host */
  348                 ipxstat.ipxs_cantforward++;
  349                 m_freem(m);
  350                 goto cleanup;
  351         }
  352         ipx->ipx_tc++;
  353         if (ipx->ipx_tc > IPX_MAXHOPS) {
  354                 ipxstat.ipxs_cantforward++;
  355                 m_freem(m);
  356                 goto cleanup;
  357         }
  358 
  359         if ((ok_there = ipx_do_route(&ipx->ipx_dna,&ipx_droute)) == 0) {
  360                 ipxstat.ipxs_noroute++;
  361                 m_freem(m);
  362                 goto cleanup;
  363         }
  364         /*
  365          * Here we think about  forwarding  broadcast packets,
  366          * so we try to insure that it doesn't go back out
  367          * on the interface it came in on.  Also, if we
  368          * are going to physically broadcast this, let us
  369          * age the packet so we can eat it safely the second time around.
  370          */
  371         if (ipx->ipx_dna.x_host.c_host[0] & 0x1) {
  372                 struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna);
  373                 struct ifnet *ifp;
  374                 if (ia != NULL) {
  375                         /* I'm gonna hafta eat this packet */
  376                         agedelta += IPX_MAXHOPS - ipx->ipx_tc;
  377                         ipx->ipx_tc = IPX_MAXHOPS;
  378                 }
  379                 if ((ok_back = ipx_do_route(&ipx->ipx_sna,&ipx_sroute)) == 0) {
  380                         /* error = ENETUNREACH; He'll never get it! */
  381                         ipxstat.ipxs_noroute++;
  382                         m_freem(m);
  383                         goto cleanup;
  384                 }
  385                 if (ipx_droute.ro_rt &&
  386                     (ifp = ipx_droute.ro_rt->rt_ifp) &&
  387                     ipx_sroute.ro_rt &&
  388                     (ifp != ipx_sroute.ro_rt->rt_ifp)) {
  389                         flags |= IPX_ALLOWBROADCAST;
  390                 } else {
  391                         ipxstat.ipxs_noroute++;
  392                         m_freem(m);
  393                         goto cleanup;
  394                 }
  395         }
  396         /*
  397          * We don't need to recompute checksum because ipx_tc field
  398          * is ignored by checksum calculation routine, however
  399          * it may be desirable to reset checksum if ipxcksum == 0
  400          */
  401 #if 0
  402         if (!ipxcksum)
  403                 ipx->ipx_sum = 0xffff;
  404 #endif
  405 
  406         error = ipx_outputfl(m, &ipx_droute, flags);
  407         if (error == 0) {
  408                 ipxstat.ipxs_forward++;
  409 
  410                 if (ipxprintfs) {
  411                         printf("forward: ");
  412                         ipx_printhost(&ipx->ipx_sna);
  413                         printf(" to ");
  414                         ipx_printhost(&ipx->ipx_dna);
  415                         printf(" hops %d\n", ipx->ipx_tc);
  416                 }
  417         } 
  418 cleanup:
  419         if (ok_there)
  420                 ipx_undo_route(&ipx_droute);
  421         if (ok_back)
  422                 ipx_undo_route(&ipx_sroute);
  423 }
  424 
  425 static int
  426 ipx_do_route(struct ipx_addr *src, struct route *ro)
  427 {
  428         struct sockaddr_ipx *dst;
  429 
  430         bzero((caddr_t)ro, sizeof(*ro));
  431         dst = (struct sockaddr_ipx *)&ro->ro_dst;
  432 
  433         dst->sipx_len = sizeof(*dst);
  434         dst->sipx_family = AF_IPX;
  435         dst->sipx_addr = *src;
  436         dst->sipx_addr.x_port = 0;
  437         rtalloc_ign(ro, 0);
  438         if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) {
  439                 return (0);
  440         }
  441         ro->ro_rt->rt_use++;
  442         return (1);
  443 }
  444 
  445 static void
  446 ipx_undo_route(struct route *ro)
  447 {
  448 
  449         if (ro->ro_rt != NULL) {
  450                 RTFREE(ro->ro_rt);
  451         }
  452 }
  453 
  454 /*
  455  * XXXRW: This code should be run in its own netisr dispatch to avoid a call
  456  * back into the socket code from the IPX output path.
  457  */
  458 void
  459 ipx_watch_output(struct mbuf *m, struct ifnet *ifp)
  460 {
  461         struct ipxpcb *ipxp;
  462         struct ifaddr *ifa;
  463         struct ipx_ifaddr *ia;
  464 
  465         /*
  466          * Give any raw listeners a crack at the packet
  467          */
  468         IPX_LIST_LOCK();
  469         LIST_FOREACH(ipxp, &ipxrawpcb_list, ipxp_list) {
  470                 struct mbuf *m0 = m_copy(m, 0, (int)M_COPYALL);
  471                 if (m0 != NULL) {
  472                         struct ipx *ipx;
  473 
  474                         M_PREPEND(m0, sizeof(*ipx), M_DONTWAIT);
  475                         if (m0 == NULL)
  476                                 continue;
  477                         ipx = mtod(m0, struct ipx *);
  478                         ipx->ipx_sna.x_net = ipx_zeronet;
  479                         for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
  480                                 if (ifp == ia->ia_ifp)
  481                                         break;
  482                         if (ia == NULL)
  483                                 ipx->ipx_sna.x_host = ipx_zerohost;
  484                         else
  485                                 ipx->ipx_sna.x_host =
  486                                     ia->ia_addr.sipx_addr.x_host;
  487 
  488                         if (ifp != NULL && (ifp->if_flags & IFF_POINTOPOINT))
  489                             TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
  490                                 if (ifa->ifa_addr->sa_family == AF_IPX) {
  491                                     ipx->ipx_sna = IA_SIPX(ifa)->sipx_addr;
  492                                     break;
  493                                 }
  494                             }
  495                         ipx->ipx_len = ntohl(m0->m_pkthdr.len);
  496                         IPX_LOCK(ipxp);
  497                         ipx_input(m0, ipxp);
  498                         IPX_UNLOCK(ipxp);
  499                 }
  500         }
  501         IPX_LIST_UNLOCK();
  502 }

Cache object: 93a52c2567151e62f5ce5b7852274f57


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