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

Cache object: cc5cbe3e96f13705e63a7052a7f7b31b


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