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_usrreq.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-2006 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_usrreq.c
   63  */
   64 
   65 #include <sys/cdefs.h>
   66 __FBSDID("$FreeBSD: releng/10.0/sys/netipx/ipx_usrreq.c 243882 2012-12-05 08:04:20Z glebius $");
   67 
   68 #include "opt_ipx.h"
   69 
   70 #include <sys/param.h>
   71 #include <sys/kernel.h>
   72 #include <sys/lock.h>
   73 #include <sys/mbuf.h>
   74 #include <sys/priv.h>
   75 #include <sys/protosw.h>
   76 #include <sys/signalvar.h>
   77 #include <sys/socket.h>
   78 #include <sys/socketvar.h>
   79 #include <sys/sx.h>
   80 #include <sys/sysctl.h>
   81 #include <sys/systm.h>
   82 
   83 #include <net/if.h>
   84 #include <net/route.h>
   85 
   86 #include <netinet/in.h>
   87 
   88 #include <netipx/ipx.h>
   89 #include <netipx/ipx_if.h>
   90 #include <netipx/ipx_pcb.h>
   91 #include <netipx/ipx_var.h>
   92 
   93 #include <security/mac/mac_framework.h>
   94 
   95 /*
   96  * IPX protocol implementation.
   97  */
   98 
   99 static int ipxsendspace = IPXSNDQ;
  100 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
  101             &ipxsendspace, 0, "Send buffer space");
  102 static int ipxrecvspace = IPXRCVQ;
  103 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
  104             &ipxrecvspace, 0, "Receive buffer space");
  105 
  106 static  void ipx_usr_abort(struct socket *so);
  107 static  int ipx_attach(struct socket *so, int proto, struct thread *td);
  108 static  int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
  109 static  int ipx_connect(struct socket *so, struct sockaddr *nam,
  110                         struct thread *td);
  111 static  void ipx_detach(struct socket *so);
  112 static  int ipx_disconnect(struct socket *so);
  113 static  int ipx_send(struct socket *so, int flags, struct mbuf *m,
  114                      struct sockaddr *addr, struct mbuf *control,
  115                      struct thread *td);
  116 static  int ipx_shutdown(struct socket *so);
  117 static  int ripx_attach(struct socket *so, int proto, struct thread *td);
  118 static  int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
  119 static  void ipx_usr_close(struct socket *so);
  120 
  121 struct  pr_usrreqs ipx_usrreqs = {
  122         .pru_abort =            ipx_usr_abort,
  123         .pru_attach =           ipx_attach,
  124         .pru_bind =             ipx_bind,
  125         .pru_connect =          ipx_connect,
  126         .pru_control =          ipx_control,
  127         .pru_detach =           ipx_detach,
  128         .pru_disconnect =       ipx_disconnect,
  129         .pru_peeraddr =         ipx_peeraddr,
  130         .pru_send =             ipx_send,
  131         .pru_shutdown =         ipx_shutdown,
  132         .pru_sockaddr =         ipx_sockaddr,
  133         .pru_close =            ipx_usr_close,
  134 };
  135 
  136 struct  pr_usrreqs ripx_usrreqs = {
  137         .pru_abort =            ipx_usr_abort,
  138         .pru_attach =           ripx_attach,
  139         .pru_bind =             ipx_bind,
  140         .pru_connect =          ipx_connect,
  141         .pru_control =          ipx_control,
  142         .pru_detach =           ipx_detach,
  143         .pru_disconnect =       ipx_disconnect,
  144         .pru_peeraddr =         ipx_peeraddr,
  145         .pru_send =             ipx_send,
  146         .pru_shutdown =         ipx_shutdown,
  147         .pru_sockaddr =         ipx_sockaddr,
  148         .pru_close =            ipx_usr_close,
  149 };
  150 
  151 /*
  152  *  This may also be called for raw listeners.
  153  */
  154 void
  155 ipx_input(struct mbuf *m, struct ipxpcb *ipxp)
  156 {
  157         struct ipx *ipx = mtod(m, struct ipx *);
  158         struct ifnet *ifp = m->m_pkthdr.rcvif;
  159         struct sockaddr_ipx ipx_ipx;
  160 
  161         KASSERT(ipxp != NULL, ("ipx_input: NULL ipxpcb"));
  162         IPX_LOCK_ASSERT(ipxp);
  163         /*
  164          * Construct sockaddr format source address.
  165          * Stuff source address and datagram in user buffer.
  166          */
  167         ipx_ipx.sipx_len = sizeof(ipx_ipx);
  168         ipx_ipx.sipx_family = AF_IPX;
  169         ipx_ipx.sipx_addr = ipx->ipx_sna;
  170         ipx_ipx.sipx_zero[0] = '\0';
  171         ipx_ipx.sipx_zero[1] = '\0';
  172         if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
  173                 struct ifaddr *ifa;
  174 
  175                 for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL;
  176                      ifa = TAILQ_NEXT(ifa, ifa_link)) {
  177                         if (ifa->ifa_addr->sa_family == AF_IPX) {
  178                                 ipx_ipx.sipx_addr.x_net =
  179                                         IA_SIPX(ifa)->sipx_addr.x_net;
  180                                 break;
  181                         }
  182                 }
  183         }
  184         ipxp->ipxp_rpt = ipx->ipx_pt;
  185         if ((ipxp->ipxp_flags & IPXP_RAWIN) == 0) {
  186                 m->m_len -= sizeof(struct ipx);
  187                 m->m_pkthdr.len -= sizeof(struct ipx);
  188                 m->m_data += sizeof(struct ipx);
  189         }
  190 #ifdef MAC
  191         if (mac_socket_check_deliver(ipxp->ipxp_socket, m) != 0) {
  192                 m_freem(m);
  193                 return;
  194         }
  195 #endif
  196         if (sbappendaddr(&ipxp->ipxp_socket->so_rcv,
  197             (struct sockaddr *)&ipx_ipx, m, NULL) == 0)
  198                 m_freem(m);
  199         else
  200                 sorwakeup(ipxp->ipxp_socket);
  201 }
  202 
  203 /*
  204  * Drop connection, reporting
  205  * the specified error.
  206  */
  207 void
  208 ipx_drop(struct ipxpcb *ipxp, int errno)
  209 {
  210         struct socket *so = ipxp->ipxp_socket;
  211 
  212         IPX_LIST_LOCK_ASSERT();
  213         IPX_LOCK_ASSERT(ipxp);
  214 
  215         /*
  216          * someday, in the IPX world
  217          * we will generate error protocol packets
  218          * announcing that the socket has gone away.
  219          *
  220          * XXX Probably never. IPX does not have error packets.
  221          */
  222         /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
  223                 tp->t_state = TCPS_CLOSED;
  224                 tcp_output(tp);
  225         }*/
  226         so->so_error = errno;
  227         ipx_pcbdisconnect(ipxp);
  228         soisdisconnected(so);
  229 }
  230 
  231 static int
  232 ipx_output(struct ipxpcb *ipxp, struct mbuf *m0)
  233 {
  234         struct ipx *ipx;
  235         struct socket *so;
  236         int len = 0;
  237         struct route *ro;
  238         struct mbuf *m;
  239         struct mbuf *mprev = NULL;
  240 
  241         IPX_LOCK_ASSERT(ipxp);
  242 
  243         /*
  244          * Calculate data length.
  245          */
  246         for (m = m0; m != NULL; m = m->m_next) {
  247                 mprev = m;
  248                 len += m->m_len;
  249         }
  250         /*
  251          * Make sure packet is actually of even length.
  252          */
  253 
  254         if (len & 1) {
  255                 m = mprev;
  256                 if ((m->m_flags & M_EXT) == 0 &&
  257                         (m->m_len + m->m_data < &m->m_dat[MLEN])) {
  258                         mtod(m, char*)[m->m_len++] = 0;
  259                 } else {
  260                         struct mbuf *m1 = m_get(M_NOWAIT, MT_DATA);
  261 
  262                         if (m1 == NULL) {
  263                                 m_freem(m0);
  264                                 return (ENOBUFS);
  265                         }
  266                         m1->m_len = 1;
  267                         * mtod(m1, char *) = 0;
  268                         m->m_next = m1;
  269                 }
  270                 m0->m_pkthdr.len++;
  271         }
  272 
  273         /*
  274          * Fill in mbuf with extended IPX header
  275          * and addresses and length put into network format.
  276          */
  277         m = m0;
  278         if (ipxp->ipxp_flags & IPXP_RAWOUT) {
  279                 ipx = mtod(m, struct ipx *);
  280         } else {
  281                 M_PREPEND(m, sizeof(struct ipx), M_NOWAIT);
  282                 if (m == NULL)
  283                         return (ENOBUFS);
  284                 ipx = mtod(m, struct ipx *);
  285                 ipx->ipx_tc = 0;
  286                 ipx->ipx_pt = ipxp->ipxp_dpt;
  287                 ipx->ipx_sna = ipxp->ipxp_laddr;
  288                 ipx->ipx_dna = ipxp->ipxp_faddr;
  289                 len += sizeof(struct ipx);
  290         }
  291 
  292         ipx->ipx_len = htons((u_short)len);
  293 
  294         if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
  295                 ipx->ipx_sum = ipx_cksum(m, len);
  296         } else
  297                 ipx->ipx_sum = 0xffff;
  298 
  299         /*
  300          * Output datagram.
  301          */
  302         so = ipxp->ipxp_socket;
  303         if (so->so_options & SO_DONTROUTE)
  304                 return (ipx_outputfl(m, (struct route *)NULL,
  305                     (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
  306         /*
  307          * Use cached route for previous datagram if
  308          * possible.  If the previous net was the same
  309          * and the interface was a broadcast medium, or
  310          * if the previous destination was identical,
  311          * then we are ok.
  312          *
  313          * NB: We don't handle broadcasts because that
  314          *     would require 3 subroutine calls.
  315          */
  316         ro = &ipxp->ipxp_route;
  317 #ifdef ancient_history
  318         /*
  319          * I think that this will all be handled in ipx_pcbconnect!
  320          */
  321         if (ro->ro_rt != NULL) {
  322                 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
  323                         /*
  324                          * This assumes we have no GH type routes
  325                          */
  326                         if (ro->ro_rt->rt_flags & RTF_HOST) {
  327                                 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
  328                                         goto re_route;
  329 
  330                         }
  331                         if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
  332                                 struct ipx_addr *dst =
  333                                                 &satoipx_addr(ro->ro_dst);
  334                                 dst->x_host = ipx->ipx_dna.x_host;
  335                         }
  336                         /*
  337                          * Otherwise, we go through the same gateway
  338                          * and dst is already set up.
  339                          */
  340                 } else {
  341                 re_route:
  342                         RTFREE(ro->ro_rt);
  343                         ro->ro_rt = NULL;
  344                 }
  345         }
  346         ipxp->ipxp_lastdst = ipx->ipx_dna;
  347 #endif /* ancient_history */
  348         return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
  349 }
  350 
  351 int
  352 ipx_ctloutput(struct socket *so, struct sockopt *sopt)
  353 {
  354         struct ipxpcb *ipxp = sotoipxpcb(so);
  355         int mask, error, optval;
  356         short soptval;
  357         struct ipx ioptval;
  358         long seq;
  359 
  360         KASSERT(ipxp != NULL, ("ipx_ctloutput: ipxp == NULL"));
  361         error = 0;
  362 
  363         switch (sopt->sopt_dir) {
  364         case SOPT_GET:
  365                 switch (sopt->sopt_name) {
  366                 case SO_ALL_PACKETS:
  367                         mask = IPXP_ALL_PACKETS;
  368                         goto get_flags;
  369 
  370                 case SO_HEADERS_ON_INPUT:
  371                         mask = IPXP_RAWIN;
  372                         goto get_flags;
  373 
  374                 case SO_IPX_CHECKSUM:
  375                         mask = IPXP_CHECKSUM;
  376                         goto get_flags;
  377 
  378                 case SO_HEADERS_ON_OUTPUT:
  379                         mask = IPXP_RAWOUT;
  380                 get_flags:
  381                         /* Unlocked read. */
  382                         soptval = ipxp->ipxp_flags & mask;
  383                         error = sooptcopyout(sopt, &soptval, sizeof soptval);
  384                         break;
  385 
  386                 case SO_DEFAULT_HEADERS:
  387                         ioptval.ipx_len = 0;
  388                         ioptval.ipx_sum = 0;
  389                         ioptval.ipx_tc = 0;
  390                         IPX_LOCK(ipxp);
  391                         ioptval.ipx_pt = ipxp->ipxp_dpt;
  392                         ioptval.ipx_dna = ipxp->ipxp_faddr;
  393                         ioptval.ipx_sna = ipxp->ipxp_laddr;
  394                         IPX_UNLOCK(ipxp);
  395                         error = sooptcopyout(sopt, &soptval, sizeof soptval);
  396                         break;
  397 
  398                 case SO_SEQNO:
  399                         IPX_LIST_LOCK();
  400                         seq = ipx_pexseq;
  401                         ipx_pexseq++;
  402                         IPX_LIST_UNLOCK();
  403                         error = sooptcopyout(sopt, &seq, sizeof seq);
  404                         break;
  405 
  406                 default:
  407                         error = EINVAL;
  408                 }
  409                 break;
  410 
  411         case SOPT_SET:
  412                 switch (sopt->sopt_name) {
  413                 case SO_ALL_PACKETS:
  414                         mask = IPXP_ALL_PACKETS;
  415                         goto set_head;
  416 
  417                 case SO_HEADERS_ON_INPUT:
  418                         mask = IPXP_RAWIN;
  419                         goto set_head;
  420 
  421                 case SO_IPX_CHECKSUM:
  422                         mask = IPXP_CHECKSUM;
  423                         goto set_head;
  424 
  425                 case SO_HEADERS_ON_OUTPUT:
  426                         mask = IPXP_RAWOUT;
  427                 set_head:
  428                         error = sooptcopyin(sopt, &optval, sizeof optval,
  429                                             sizeof optval);
  430                         if (error)
  431                                 break;
  432                         IPX_LOCK(ipxp);
  433                         if (optval)
  434                                 ipxp->ipxp_flags |= mask;
  435                         else
  436                                 ipxp->ipxp_flags &= ~mask;
  437                         IPX_UNLOCK(ipxp);
  438                         break;
  439 
  440                 case SO_DEFAULT_HEADERS:
  441                         error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
  442                                             sizeof ioptval);
  443                         if (error)
  444                                 break;
  445                         /* Unlocked write. */
  446                         ipxp->ipxp_dpt = ioptval.ipx_pt;
  447                         break;
  448                 default:
  449                         error = EINVAL;
  450                 }
  451                 break;
  452         }
  453         return (error);
  454 }
  455 
  456 static void
  457 ipx_usr_abort(struct socket *so)
  458 {
  459 
  460         /* XXXRW: Possibly ipx_disconnect() here? */
  461         soisdisconnected(so);
  462 }
  463 
  464 static int
  465 ipx_attach(struct socket *so, int proto, struct thread *td)
  466 {
  467 #ifdef INVARIANTS
  468         struct ipxpcb *ipxp = sotoipxpcb(so);
  469 #endif
  470         int error;
  471 
  472         KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL"));
  473         error = soreserve(so, ipxsendspace, ipxrecvspace);
  474         if (error != 0)
  475                 return (error);
  476         IPX_LIST_LOCK();
  477         error = ipx_pcballoc(so, &ipxpcb_list, td);
  478         IPX_LIST_UNLOCK();
  479         return (error);
  480 }
  481 
  482 static int
  483 ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
  484 {
  485         struct ipxpcb *ipxp = sotoipxpcb(so);
  486         int error;
  487 
  488         KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL"));
  489         IPX_LIST_LOCK();
  490         IPX_LOCK(ipxp);
  491         error = ipx_pcbbind(ipxp, nam, td);
  492         IPX_UNLOCK(ipxp);
  493         IPX_LIST_UNLOCK();
  494         return (error);
  495 }
  496 
  497 static void
  498 ipx_usr_close(struct socket *so)
  499 {
  500 
  501         /* XXXRW: Possibly ipx_disconnect() here? */
  502         soisdisconnected(so);
  503 }
  504 
  505 static int
  506 ipx_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
  507 {
  508         struct ipxpcb *ipxp = sotoipxpcb(so);
  509         int error;
  510 
  511         KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL"));
  512         IPX_LIST_LOCK();
  513         IPX_LOCK(ipxp);
  514         if (!ipx_nullhost(ipxp->ipxp_faddr)) {
  515                 error = EISCONN;
  516                 goto out;
  517         }
  518         error = ipx_pcbconnect(ipxp, nam, td);
  519         if (error == 0)
  520                 soisconnected(so);
  521 out:
  522         IPX_UNLOCK(ipxp);
  523         IPX_LIST_UNLOCK();
  524         return (error);
  525 }
  526 
  527 static void
  528 ipx_detach(struct socket *so)
  529 {
  530         struct ipxpcb *ipxp = sotoipxpcb(so);
  531 
  532         /* XXXRW: Should assert detached. */
  533         KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL"));
  534         IPX_LIST_LOCK();
  535         IPX_LOCK(ipxp);
  536         ipx_pcbdetach(ipxp);
  537         ipx_pcbfree(ipxp);
  538         IPX_LIST_UNLOCK();
  539 }
  540 
  541 static int
  542 ipx_disconnect(struct socket *so)
  543 {
  544         struct ipxpcb *ipxp = sotoipxpcb(so);
  545         int error;
  546 
  547         KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL"));
  548         IPX_LIST_LOCK();
  549         IPX_LOCK(ipxp);
  550         error = 0;
  551         if (ipx_nullhost(ipxp->ipxp_faddr)) {
  552                 error = ENOTCONN;
  553                 goto out;
  554         }
  555         ipx_pcbdisconnect(ipxp);
  556         soisdisconnected(so);
  557 out:
  558         IPX_UNLOCK(ipxp);
  559         IPX_LIST_UNLOCK();
  560         return (0);
  561 }
  562 
  563 int
  564 ipx_peeraddr(struct socket *so, struct sockaddr **nam)
  565 {
  566         struct ipxpcb *ipxp = sotoipxpcb(so);
  567 
  568         KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL"));
  569         ipx_getpeeraddr(ipxp, nam);
  570         return (0);
  571 }
  572 
  573 static int
  574 ipx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
  575     struct mbuf *control, struct thread *td)
  576 {
  577         int error;
  578         struct ipxpcb *ipxp = sotoipxpcb(so);
  579         struct ipx_addr laddr;
  580 
  581         KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL"));
  582         /*
  583          * Attempt to only acquire the necessary locks: if the socket is
  584          * already connected, we don't need to hold the IPX list lock to be
  585          * used by ipx_pcbconnect() and ipx_pcbdisconnect(), just the IPX
  586          * pcb lock.
  587          */
  588 #ifdef MAC
  589         mac_socket_create_mbuf(so, m);
  590 #endif
  591         if (nam != NULL) {
  592                 IPX_LIST_LOCK();
  593                 IPX_LOCK(ipxp);
  594                 laddr = ipxp->ipxp_laddr;
  595                 if (!ipx_nullhost(ipxp->ipxp_faddr)) {
  596                         IPX_UNLOCK(ipxp);
  597                         IPX_LIST_UNLOCK();
  598                         error = EISCONN;
  599                         goto send_release;
  600                 }
  601                 /*
  602                  * Must block input while temporarily connected.
  603                  */
  604                 error = ipx_pcbconnect(ipxp, nam, td);
  605                 if (error) {
  606                         IPX_UNLOCK(ipxp);
  607                         IPX_LIST_UNLOCK();
  608                         goto send_release;
  609                 }
  610         } else {
  611                 IPX_LOCK(ipxp);
  612                 if (ipx_nullhost(ipxp->ipxp_faddr)) {
  613                         IPX_UNLOCK(ipxp);
  614                         error = ENOTCONN;
  615                         goto send_release;
  616                 }
  617         }
  618         error = ipx_output(ipxp, m);
  619         m = NULL;
  620         if (nam != NULL) {
  621                 ipx_pcbdisconnect(ipxp);
  622                 ipxp->ipxp_laddr = laddr;
  623                 IPX_UNLOCK(ipxp);
  624                 IPX_LIST_UNLOCK();
  625         } else
  626                 IPX_UNLOCK(ipxp);
  627 
  628 send_release:
  629         if (m != NULL)
  630                 m_freem(m);
  631         return (error);
  632 }
  633 
  634 static int
  635 ipx_shutdown(so)
  636         struct socket *so;
  637 {
  638 
  639         KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL"));
  640         socantsendmore(so);
  641         return (0);
  642 }
  643 
  644 int
  645 ipx_sockaddr(struct socket *so, struct sockaddr **nam)
  646 {
  647         struct ipxpcb *ipxp = sotoipxpcb(so);
  648 
  649         KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL"));
  650         ipx_getsockaddr(ipxp, nam);
  651         return (0);
  652 }
  653 
  654 static int
  655 ripx_attach(struct socket *so, int proto, struct thread *td)
  656 {
  657         int error = 0;
  658         struct ipxpcb *ipxp = sotoipxpcb(so);
  659 
  660         KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL"));
  661 
  662         if (td != NULL) {
  663                 error = priv_check(td, PRIV_NETIPX_RAW);
  664                 if (error)
  665                         return (error);
  666         }
  667 
  668         /*
  669          * We hold the IPX list lock for the duration as address parameters
  670          * of the IPX pcb are changed.  Since no one else holds a reference
  671          * to the ipxpcb yet, we don't need the ipxpcb lock here.
  672          */
  673         IPX_LIST_LOCK();
  674         error = ipx_pcballoc(so, &ipxrawpcb_list, td);
  675         if (error)
  676                 goto out;
  677         ipxp = sotoipxpcb(so);
  678         error = soreserve(so, ipxsendspace, ipxrecvspace);
  679         if (error)
  680                 goto out;
  681         ipxp->ipxp_faddr.x_host = ipx_broadhost;
  682         ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
  683 out:
  684         IPX_LIST_UNLOCK();
  685         return (error);
  686 }

Cache object: 8f83e31d85fbd08f34e8b0727b3b87e5


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