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) 1995, Mike Mitchell
    3  * Copyright (c) 1984, 1985, 1986, 1987, 1993
    4  *      The Regents of the University of California.  All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. All advertising materials mentioning features or use of this software
   15  *    must display the following acknowledgement:
   16  *      This product includes software developed by the University of
   17  *      California, Berkeley and its contributors.
   18  * 4. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  *      @(#)ipx_pcb.c
   35  *
   36  * $FreeBSD: releng/5.1/sys/netipx/ipx_pcb.c 97658 2002-05-31 11:52:35Z tanimura $
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/malloc.h>
   42 #include <sys/socket.h>
   43 #include <sys/socketvar.h>
   44 
   45 #include <net/if.h>
   46 #include <net/route.h>
   47 
   48 #include <netipx/ipx.h>
   49 #include <netipx/ipx_if.h>
   50 #include <netipx/ipx_pcb.h>
   51 #include <netipx/ipx_var.h>
   52 
   53 static struct   ipx_addr zeroipx_addr;
   54 
   55 int
   56 ipx_pcballoc(so, head, td)
   57         struct socket *so;
   58         struct ipxpcb *head;
   59         struct thread *td;
   60 {
   61         register struct ipxpcb *ipxp;
   62 
   63         MALLOC(ipxp, struct ipxpcb *, sizeof *ipxp, M_PCB, M_NOWAIT | M_ZERO);
   64         if (ipxp == NULL)
   65                 return (ENOBUFS);
   66         ipxp->ipxp_socket = so;
   67         if (ipxcksum)
   68                 ipxp->ipxp_flags |= IPXP_CHECKSUM;
   69         insque(ipxp, head);
   70         so->so_pcb = (caddr_t)ipxp;
   71         return (0);
   72 }
   73         
   74 int
   75 ipx_pcbbind(ipxp, nam, td)
   76         register struct ipxpcb *ipxp;
   77         struct sockaddr *nam;
   78         struct thread *td;
   79 {
   80         register struct sockaddr_ipx *sipx;
   81         u_short lport = 0;
   82 
   83         if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr))
   84                 return (EINVAL);
   85         if (nam == NULL)
   86                 goto noname;
   87         sipx = (struct sockaddr_ipx *)nam;
   88         if (!ipx_nullhost(sipx->sipx_addr)) {
   89                 int tport = sipx->sipx_port;
   90 
   91                 sipx->sipx_port = 0;            /* yech... */
   92                 if (ifa_ifwithaddr((struct sockaddr *)sipx) == 0)
   93                         return (EADDRNOTAVAIL);
   94                 sipx->sipx_port = tport;
   95         }
   96         lport = sipx->sipx_port;
   97         if (lport) {
   98                 u_short aport = ntohs(lport);
   99                 int error;
  100 
  101                 if (aport < IPXPORT_RESERVED &&
  102                     td != NULL && (error = suser(td)) != 0)
  103                         return (error);
  104                 if (ipx_pcblookup(&zeroipx_addr, lport, 0))
  105                         return (EADDRINUSE);
  106         }
  107         ipxp->ipxp_laddr = sipx->sipx_addr;
  108 noname:
  109         if (lport == 0)
  110                 do {
  111                         ipxpcb.ipxp_lport++;
  112                         if ((ipxpcb.ipxp_lport < IPXPORT_RESERVED) ||
  113                             (ipxpcb.ipxp_lport >= IPXPORT_WELLKNOWN))
  114                                 ipxpcb.ipxp_lport = IPXPORT_RESERVED;
  115                         lport = htons(ipxpcb.ipxp_lport);
  116                 } while (ipx_pcblookup(&zeroipx_addr, lport, 0));
  117         ipxp->ipxp_lport = lport;
  118         return (0);
  119 }
  120 
  121 /*
  122  * Connect from a socket to a specified address.
  123  * Both address and port must be specified in argument sipx.
  124  * If don't have a local address for this socket yet,
  125  * then pick one.
  126  */
  127 int
  128 ipx_pcbconnect(ipxp, nam, td)
  129         struct ipxpcb *ipxp;
  130         struct sockaddr *nam;
  131         struct thread *td;
  132 {
  133         struct ipx_ifaddr *ia;
  134         register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam;
  135         register struct ipx_addr *dst;
  136         register struct route *ro;
  137         struct ifnet *ifp;
  138 
  139         ia = NULL;
  140 
  141         if (sipx->sipx_family != AF_IPX)
  142                 return (EAFNOSUPPORT);
  143         if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr))
  144                 return (EADDRNOTAVAIL);
  145         /*
  146          * If we haven't bound which network number to use as ours,
  147          * we will use the number of the outgoing interface.
  148          * This depends on having done a routing lookup, which
  149          * we will probably have to do anyway, so we might
  150          * as well do it now.  On the other hand if we are
  151          * sending to multiple destinations we may have already
  152          * done the lookup, so see if we can use the route
  153          * from before.  In any case, we only
  154          * chose a port number once, even if sending to multiple
  155          * destinations.
  156          */
  157         ro = &ipxp->ipxp_route;
  158         dst = &satoipx_addr(ro->ro_dst);
  159         if (ipxp->ipxp_socket->so_options & SO_DONTROUTE)
  160                 goto flush;
  161         if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr))
  162                 goto flush;
  163         if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) {
  164                 if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) {
  165                         /* can patch route to avoid rtalloc */
  166                         *dst = sipx->sipx_addr;
  167                 } else {
  168         flush:
  169                         if (ro->ro_rt != NULL)
  170                                 RTFREE(ro->ro_rt);
  171                         ro->ro_rt = NULL;
  172                 }
  173         }/* else cached route is ok; do nothing */
  174         ipxp->ipxp_lastdst = sipx->sipx_addr;
  175         if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
  176             (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) {
  177                     /* No route yet, so try to acquire one */
  178                     ro->ro_dst.sa_family = AF_IPX;
  179                     ro->ro_dst.sa_len = sizeof(ro->ro_dst);
  180                     *dst = sipx->sipx_addr;
  181                     dst->x_port = 0;
  182                     rtalloc(ro);
  183         }
  184         if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) {
  185                 /* 
  186                  * If route is known or can be allocated now,
  187                  * our src addr is taken from the i/f, else punt.
  188                  */
  189 
  190                 /*
  191                  * If we found a route, use the address
  192                  * corresponding to the outgoing interface
  193                  */
  194                 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL)
  195                         for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
  196                                 if (ia->ia_ifp == ifp)
  197                                         break;
  198                 if (ia == NULL) {
  199                         u_short fport = sipx->sipx_addr.x_port;
  200                         sipx->sipx_addr.x_port = 0;
  201                         ia = (struct ipx_ifaddr *)
  202                                 ifa_ifwithdstaddr((struct sockaddr *)sipx);
  203                         sipx->sipx_addr.x_port = fport;
  204                         if (ia == NULL)
  205                                 ia = ipx_iaonnetof(&sipx->sipx_addr);
  206                         if (ia == NULL)
  207                                 ia = ipx_ifaddr;
  208                         if (ia == NULL)
  209                                 return (EADDRNOTAVAIL);
  210                 }
  211                 ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net;
  212         }
  213         if (ipx_nullhost(ipxp->ipxp_laddr)) {
  214                 /* 
  215                  * If route is known or can be allocated now,
  216                  * our src addr is taken from the i/f, else punt.
  217                  */
  218 
  219                 /*
  220                  * If we found a route, use the address
  221                  * corresponding to the outgoing interface
  222                  */
  223                 if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL)
  224                         for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
  225                                 if (ia->ia_ifp == ifp)
  226                                         break;
  227                 if (ia == NULL) {
  228                         u_short fport = sipx->sipx_addr.x_port;
  229                         sipx->sipx_addr.x_port = 0;
  230                         ia = (struct ipx_ifaddr *)
  231                                 ifa_ifwithdstaddr((struct sockaddr *)sipx);
  232                         sipx->sipx_addr.x_port = fport;
  233                         if (ia == NULL)
  234                                 ia = ipx_iaonnetof(&sipx->sipx_addr);
  235                         if (ia == NULL)
  236                                 ia = ipx_ifaddr;
  237                         if (ia == NULL)
  238                                 return (EADDRNOTAVAIL);
  239                 }
  240                 ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host;
  241         }
  242         if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0))
  243                 return (EADDRINUSE);
  244         if (ipxp->ipxp_lport == 0)
  245                 ipx_pcbbind(ipxp, (struct sockaddr *)NULL, td);
  246 
  247         /* XXX just leave it zero if we can't find a route */
  248 
  249         ipxp->ipxp_faddr = sipx->sipx_addr;
  250         /* Includes ipxp->ipxp_fport = sipx->sipx_port; */
  251         return (0);
  252 }
  253 
  254 void
  255 ipx_pcbdisconnect(ipxp)
  256         struct ipxpcb *ipxp;
  257 {
  258 
  259         ipxp->ipxp_faddr = zeroipx_addr;
  260         if (ipxp->ipxp_socket->so_state & SS_NOFDREF)
  261                 ipx_pcbdetach(ipxp);
  262 }
  263 
  264 void
  265 ipx_pcbdetach(ipxp)
  266         struct ipxpcb *ipxp;
  267 {
  268         struct socket *so = ipxp->ipxp_socket;
  269 
  270         so->so_pcb = 0;
  271         sotryfree(so);
  272         if (ipxp->ipxp_route.ro_rt != NULL)
  273                 rtfree(ipxp->ipxp_route.ro_rt);
  274         remque(ipxp);
  275         FREE(ipxp, M_PCB);
  276 }
  277 
  278 void
  279 ipx_setsockaddr(ipxp, nam)
  280         register struct ipxpcb *ipxp;
  281         struct sockaddr **nam;
  282 {
  283         struct sockaddr_ipx *sipx, ssipx;
  284         
  285         sipx = &ssipx;
  286         bzero((caddr_t)sipx, sizeof(*sipx));
  287         sipx->sipx_len = sizeof(*sipx);
  288         sipx->sipx_family = AF_IPX;
  289         sipx->sipx_addr = ipxp->ipxp_laddr;
  290         *nam = dup_sockaddr((struct sockaddr *)sipx, 0);
  291 }
  292 
  293 void
  294 ipx_setpeeraddr(ipxp, nam)
  295         register struct ipxpcb *ipxp;
  296         struct sockaddr **nam;
  297 {
  298         struct sockaddr_ipx *sipx, ssipx;
  299         
  300         sipx = &ssipx;
  301         bzero((caddr_t)sipx, sizeof(*sipx));
  302         sipx->sipx_len = sizeof(*sipx);
  303         sipx->sipx_family = AF_IPX;
  304         sipx->sipx_addr = ipxp->ipxp_faddr;
  305         *nam = dup_sockaddr((struct sockaddr *)sipx, 0);
  306 }
  307 
  308 /*
  309  * Pass some notification to all connections of a protocol
  310  * associated with address dst.  Call the
  311  * protocol specific routine to handle each connection.
  312  * Also pass an extra paramter via the ipxpcb. (which may in fact
  313  * be a parameter list!)
  314  */
  315 void
  316 ipx_pcbnotify(dst, errno, notify, param)
  317         register struct ipx_addr *dst;
  318         int errno;
  319         void (*notify)(struct ipxpcb *);
  320         long param;
  321 {
  322         register struct ipxpcb *ipxp, *oinp;
  323         int s = splimp();
  324 
  325         for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb);) {
  326                 if (!ipx_hosteq(*dst,ipxp->ipxp_faddr)) {
  327         next:
  328                         ipxp = ipxp->ipxp_next;
  329                         continue;
  330                 }
  331                 if (ipxp->ipxp_socket == 0)
  332                         goto next;
  333                 if (errno) 
  334                         ipxp->ipxp_socket->so_error = errno;
  335                 oinp = ipxp;
  336                 ipxp = ipxp->ipxp_next;
  337                 oinp->ipxp_notify_param = param;
  338                 (*notify)(oinp);
  339         }
  340         splx(s);
  341 }
  342 
  343 #ifdef notdef
  344 /*
  345  * After a routing change, flush old routing
  346  * and allocate a (hopefully) better one.
  347  */
  348 ipx_rtchange(ipxp)
  349         struct ipxpcb *ipxp;
  350 {
  351         if (ipxp->ipxp_route.ro_rt != NULL) {
  352                 rtfree(ipxp->ipxp_route.ro_rt);
  353                 ipxp->ipxp_route.ro_rt = NULL;
  354                 /*
  355                  * A new route can be allocated the next time
  356                  * output is attempted.
  357                  */
  358         }
  359         /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */
  360 }
  361 #endif
  362 
  363 struct ipxpcb *
  364 ipx_pcblookup(faddr, lport, wildp)
  365         struct ipx_addr *faddr;
  366         u_short lport;
  367         int wildp;
  368 {
  369         register struct ipxpcb *ipxp, *match = 0;
  370         int matchwild = 3, wildcard;
  371         u_short fport;
  372 
  373         fport = faddr->x_port;
  374         for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb); ipxp = ipxp->ipxp_next) {
  375                 if (ipxp->ipxp_lport != lport)
  376                         continue;
  377                 wildcard = 0;
  378                 if (ipx_nullhost(ipxp->ipxp_faddr)) {
  379                         if (!ipx_nullhost(*faddr))
  380                                 wildcard++;
  381                 } else {
  382                         if (ipx_nullhost(*faddr))
  383                                 wildcard++;
  384                         else {
  385                                 if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr))
  386                                         continue;
  387                                 if (ipxp->ipxp_fport != fport) {
  388                                         if (ipxp->ipxp_fport != 0)
  389                                                 continue;
  390                                         else
  391                                                 wildcard++;
  392                                 }
  393                         }
  394                 }
  395                 if (wildcard && wildp == 0)
  396                         continue;
  397                 if (wildcard < matchwild) {
  398                         match = ipxp;
  399                         matchwild = wildcard;
  400                         if (wildcard == 0)
  401                                 break;
  402                 }
  403         }
  404         return (match);
  405 }

Cache object: 21b170ee4450c931993889f01b68e986


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