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

Cache object: 85bf369f6d7f01524d71ac7e8cf21358


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