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_pcb.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-2009 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_pcb.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/malloc.h>
   71 #include <sys/priv.h>
   72 #include <sys/socket.h>
   73 #include <sys/socketvar.h>
   74 
   75 #include <net/if.h>
   76 #include <net/route.h>
   77 
   78 #include <netipx/ipx.h>
   79 #include <netipx/ipx_if.h>
   80 #include <netipx/ipx_pcb.h>
   81 #include <netipx/ipx_var.h>
   82 
   83 static struct   ipx_addr zeroipx_addr;
   84 static u_short  ipxpcb_lport_cache;
   85 
   86 int
   87 ipx_pcballoc(struct socket *so, struct ipxpcbhead *head, struct thread *td)
   88 {
   89         struct ipxpcb *ipxp;
   90 
   91         KASSERT(so->so_pcb == NULL, ("ipx_pcballoc: so_pcb != NULL"));
   92         IPX_LIST_LOCK_ASSERT();
   93 
   94         ipxp = malloc(sizeof *ipxp, M_PCB, M_NOWAIT | M_ZERO);
   95         if (ipxp == NULL)
   96                 return (ENOBUFS);
   97         IPX_LOCK_INIT(ipxp);
   98         ipxp->ipxp_socket = so;
   99         if (ipxcksum)
  100                 ipxp->ipxp_flags |= IPXP_CHECKSUM;
  101         LIST_INSERT_HEAD(head, ipxp, ipxp_list);
  102         so->so_pcb = (caddr_t)ipxp;
  103         return (0);
  104 }
  105 
  106 int
  107 ipx_pcbbind(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
  108 {
  109         struct sockaddr_ipx *sipx;
  110         u_short lport = 0;
  111 
  112         IPX_LIST_LOCK_ASSERT();
  113         IPX_LOCK_ASSERT(ipxp);
  114 
  115         if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr))
  116                 return (EINVAL);
  117         if (nam == NULL)
  118                 goto noname;
  119         sipx = (struct sockaddr_ipx *)nam;
  120         if (!ipx_nullhost(sipx->sipx_addr)) {
  121                 int tport = sipx->sipx_port;
  122 
  123                 sipx->sipx_port = 0;            /* yech... */
  124                 if (ifa_ifwithaddr_check((struct sockaddr *)sipx) == 0)
  125                         return (EADDRNOTAVAIL);
  126                 sipx->sipx_port = tport;
  127         }
  128         lport = sipx->sipx_port;
  129         if (lport) {
  130                 u_short aport = ntohs(lport);
  131 
  132                 if (aport < IPXPORT_RESERVED && td != NULL &&
  133                     priv_check(td, PRIV_NETIPX_RESERVEDPORT))
  134                         return (EACCES);
  135                 if (ipx_pcblookup(&zeroipx_addr, lport, 0))
  136                         return (EADDRINUSE);
  137         }
  138         ipxp->ipxp_laddr = sipx->sipx_addr;
  139 noname:
  140         if (lport == 0)
  141                 do {
  142                         ipxpcb_lport_cache++;
  143                         if ((ipxpcb_lport_cache < IPXPORT_RESERVED) ||
  144                             (ipxpcb_lport_cache >= IPXPORT_WELLKNOWN))
  145                                 ipxpcb_lport_cache = IPXPORT_RESERVED;
  146                         lport = htons(ipxpcb_lport_cache);
  147                 } while (ipx_pcblookup(&zeroipx_addr, lport, 0));
  148         ipxp->ipxp_lport = lport;
  149         return (0);
  150 }
  151 
  152 /*
  153  * Connect from a socket to a specified address.
  154  * Both address and port must be specified in argument sipx.
  155  * If don't have a local address for this socket yet,
  156  * then pick one.
  157  */
  158 int
  159 ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
  160 {
  161         struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam;
  162         struct ipx_addr *dst;
  163         struct route *ro;
  164         struct ifnet *ifp;
  165 
  166         IPX_LIST_LOCK_ASSERT();
  167         IPX_LOCK_ASSERT(ipxp);
  168 
  169         if (sipx->sipx_family != AF_IPX)
  170                 return (EAFNOSUPPORT);
  171         if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr))
  172                 return (EADDRNOTAVAIL);
  173         /*
  174          * If we haven't bound which network number to use as ours,
  175          * we will use the number of the outgoing interface.
  176          * This depends on having done a routing lookup, which
  177          * we will probably have to do anyway, so we might
  178          * as well do it now.  On the other hand if we are
  179          * sending to multiple destinations we may have already
  180          * done the lookup, so see if we can use the route
  181          * from before.  In any case, we only
  182          * chose a port number once, even if sending to multiple
  183          * destinations.
  184          */
  185         ro = &ipxp->ipxp_route;
  186         dst = &satoipx_addr(ro->ro_dst);
  187         if (ipxp->ipxp_socket->so_options & SO_DONTROUTE)
  188                 goto flush;
  189         if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr))
  190                 goto flush;
  191         if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) {
  192                 if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) {
  193                         /* can patch route to avoid rtalloc */
  194                         *dst = sipx->sipx_addr;
  195                 } else {
  196         flush:
  197                         if (ro->ro_rt != NULL)
  198                                 RTFREE(ro->ro_rt);
  199                         ro->ro_rt = NULL;
  200                 }
  201         }/* else cached route is ok; do nothing */
  202         ipxp->ipxp_lastdst = sipx->sipx_addr;
  203         if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
  204             (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) {
  205                     /* No route yet, so try to acquire one */
  206                     ro->ro_dst.sa_family = AF_IPX;
  207                     ro->ro_dst.sa_len = sizeof(ro->ro_dst);
  208                     *dst = sipx->sipx_addr;
  209                     dst->x_port = 0;
  210                     rtalloc_ign(ro, 0);
  211         }
  212         if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) {
  213                 struct ipx_ifaddr *ia = NULL;
  214 
  215                 /*
  216                  * If route is known or can be allocated now,
  217                  * our src addr is taken from the i/f, else punt.
  218                  */
  219 
  220                 /*
  221                  * If we found a route, use the address
  222                  * corresponding to the outgoing interface
  223                  */
  224                 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) {
  225                         IPX_IFADDR_RLOCK();
  226                         TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) {
  227                                 if (ia->ia_ifp == ifp) {
  228                                         ifa_ref(&ia->ia_ifa);
  229                                         break;
  230                                 }
  231                         }
  232                         IPX_IFADDR_RUNLOCK();
  233                 }
  234                 if (ia == NULL) {
  235                         u_short fport = sipx->sipx_addr.x_port;
  236                         sipx->sipx_addr.x_port = 0;
  237                         ia = (struct ipx_ifaddr *)
  238                                 ifa_ifwithdstaddr((struct sockaddr *)sipx);
  239                         sipx->sipx_addr.x_port = fport;
  240                         if (ia == NULL) {
  241                                 IPX_IFADDR_RLOCK();
  242                                 ia = ipx_iaonnetof(&sipx->sipx_addr);
  243                                 if (ia != NULL)
  244                                         ifa_ref(&ia->ia_ifa);
  245                                 IPX_IFADDR_RUNLOCK();
  246                         }
  247                         if (ia == NULL) {
  248                                 IPX_IFADDR_RLOCK();
  249                                 ia = TAILQ_FIRST(&ipx_ifaddrhead);
  250                                 if (ia != NULL)
  251                                         ifa_ref(&ia->ia_ifa);
  252                                 IPX_IFADDR_RUNLOCK();
  253                         }
  254                         if (ia == NULL)
  255                                 return (EADDRNOTAVAIL);
  256                 }
  257                 ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net;
  258                 ifa_free(&ia->ia_ifa);
  259         }
  260         if (ipx_nullhost(ipxp->ipxp_laddr)) {
  261                 struct ipx_ifaddr *ia = NULL;
  262                 /*
  263                  * If route is known or can be allocated now,
  264                  * our src addr is taken from the i/f, else punt.
  265                  */
  266 
  267                 /*
  268                  * If we found a route, use the address
  269                  * corresponding to the outgoing interface
  270                  */
  271                 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) {
  272                         IPX_IFADDR_RLOCK();
  273                         TAILQ_FOREACH(ia, &ipx_ifaddrhead, ia_link) {
  274                                 if (ia->ia_ifp == ifp) {
  275                                         ifa_ref(&ia->ia_ifa);
  276                                         break;
  277                                 }
  278                         }
  279                         IPX_IFADDR_RUNLOCK();
  280                 }
  281                 if (ia == NULL) {
  282                         u_short fport = sipx->sipx_addr.x_port;
  283                         sipx->sipx_addr.x_port = 0;
  284                         ia = (struct ipx_ifaddr *)
  285                                 ifa_ifwithdstaddr((struct sockaddr *)sipx);
  286                         sipx->sipx_addr.x_port = fport;
  287                         if (ia == NULL) {
  288                                 IPX_IFADDR_RLOCK();
  289                                 ia = ipx_iaonnetof(&sipx->sipx_addr);
  290                                 if (ia != NULL)
  291                                         ifa_ref(&ia->ia_ifa);
  292                                 IPX_IFADDR_RUNLOCK();
  293                         }
  294                         if (ia == NULL) {
  295                                 IPX_IFADDR_RLOCK();
  296                                 ia = TAILQ_FIRST(&ipx_ifaddrhead);
  297                                 if (ia != NULL)
  298                                         ifa_ref(&ia->ia_ifa);
  299                                 IPX_IFADDR_RUNLOCK();
  300                         }
  301                         if (ia == NULL)
  302                                 return (EADDRNOTAVAIL);
  303                 }
  304                 ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host;
  305                 ifa_free(&ia->ia_ifa);
  306         }
  307         if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0))
  308                 return (EADDRINUSE);
  309         if (ipxp->ipxp_lport == 0)
  310                 ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td);
  311 
  312         /* XXX just leave it zero if we can't find a route */
  313 
  314         ipxp->ipxp_faddr = sipx->sipx_addr;
  315         /* Includes ipxp->ipxp_fport = sipx->sipx_port; */
  316         return (0);
  317 }
  318 
  319 void
  320 ipx_pcbdisconnect(struct ipxpcb *ipxp)
  321 {
  322 
  323         IPX_LIST_LOCK_ASSERT();
  324         IPX_LOCK_ASSERT(ipxp);
  325 
  326         ipxp->ipxp_faddr = zeroipx_addr;
  327 }
  328 
  329 void
  330 ipx_pcbdetach(struct ipxpcb *ipxp)
  331 {
  332         struct socket *so = ipxp->ipxp_socket;
  333 
  334         IPX_LIST_LOCK_ASSERT();
  335         IPX_LOCK_ASSERT(ipxp);
  336 
  337         so->so_pcb = NULL;
  338         ipxp->ipxp_socket = NULL;
  339 }
  340 
  341 void
  342 ipx_pcbfree(struct ipxpcb *ipxp)
  343 {
  344 
  345         KASSERT(ipxp->ipxp_socket == NULL,
  346             ("ipx_pcbfree: ipxp_socket != NULL"));
  347         IPX_LIST_LOCK_ASSERT();
  348         IPX_LOCK_ASSERT(ipxp);
  349 
  350         if (ipxp->ipxp_route.ro_rt != NULL)
  351                 RTFREE(ipxp->ipxp_route.ro_rt);
  352         LIST_REMOVE(ipxp, ipxp_list);
  353         IPX_LOCK_DESTROY(ipxp);
  354         free(ipxp, M_PCB);
  355 }
  356 
  357 void
  358 ipx_getsockaddr(struct ipxpcb *ipxp, struct sockaddr **nam)
  359 {
  360         struct sockaddr_ipx *sipx, ssipx;
  361 
  362         sipx = &ssipx;
  363         bzero((caddr_t)sipx, sizeof(*sipx));
  364         sipx->sipx_len = sizeof(*sipx);
  365         sipx->sipx_family = AF_IPX;
  366         IPX_LOCK(ipxp);
  367         sipx->sipx_addr = ipxp->ipxp_laddr;
  368         IPX_UNLOCK(ipxp);
  369         *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK);
  370 }
  371 
  372 void
  373 ipx_getpeeraddr(struct ipxpcb *ipxp, struct sockaddr **nam)
  374 {
  375         struct sockaddr_ipx *sipx, ssipx;
  376 
  377         sipx = &ssipx;
  378         bzero(sipx, sizeof(*sipx));
  379         sipx->sipx_len = sizeof(*sipx);
  380         sipx->sipx_family = AF_IPX;
  381         IPX_LOCK(ipxp);
  382         sipx->sipx_addr = ipxp->ipxp_faddr;
  383         IPX_UNLOCK(ipxp);
  384         *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK);
  385 }
  386 
  387 struct ipxpcb *
  388 ipx_pcblookup(struct ipx_addr *faddr, u_short lport, int wildp)
  389 {
  390         struct ipxpcb *ipxp, *match = NULL;
  391         int matchwild = 3, wildcard;
  392         u_short fport;
  393 
  394         IPX_LIST_LOCK_ASSERT();
  395 
  396         fport = faddr->x_port;
  397         LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) {
  398                 if (ipxp->ipxp_lport != lport)
  399                         continue;
  400                 wildcard = 0;
  401                 if (ipx_nullhost(ipxp->ipxp_faddr)) {
  402                         if (!ipx_nullhost(*faddr))
  403                                 wildcard++;
  404                 } else {
  405                         if (ipx_nullhost(*faddr))
  406                                 wildcard++;
  407                         else {
  408                                 if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr))
  409                                         continue;
  410                                 if (ipxp->ipxp_fport != fport) {
  411                                         if (ipxp->ipxp_fport != 0)
  412                                                 continue;
  413                                         else
  414                                                 wildcard++;
  415                                 }
  416                         }
  417                 }
  418                 if (wildcard && wildp == 0)
  419                         continue;
  420                 if (wildcard < matchwild) {
  421                         match = ipxp;
  422                         matchwild = wildcard;
  423                         if (wildcard == 0)
  424                                 break;
  425                 }
  426         }
  427         return (match);
  428 }

Cache object: ce7177354924d0906e91ee81059a6fef


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