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

Cache object: 53ac7c05fbb12fa7493985584874ebbf


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