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

Cache object: af7f24e5126df89c6f5543da8e0b30e0


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