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) 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_usrreq.c
   35  *
   36  * $FreeBSD: src/sys/netipx/ipx_usrreq.c,v 1.7.2.3 1999/09/05 08:19:04 peter Exp $
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/kernel.h>
   42 #include <sys/mbuf.h>
   43 #include <sys/protosw.h>
   44 #include <sys/socket.h>
   45 #include <sys/socketvar.h>
   46 #include <sys/sysctl.h>
   47 
   48 #include <net/if.h>
   49 #include <net/route.h>
   50 
   51 #include <netinet/in.h>
   52 
   53 #include <netipx/ipx.h>
   54 #include <netipx/ipx_pcb.h>
   55 #include <netipx/ipx_if.h>
   56 #include <netipx/ipx_var.h>
   57 #include <netipx/ipx_ip.h>
   58 
   59 /*
   60  * IPX protocol implementation.
   61  */
   62 
   63 int ipxsendspace = IPXSNDQ;
   64 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
   65             &ipxsendspace, 0, "");
   66 int ipxrecvspace = IPXRCVQ;
   67 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
   68             &ipxrecvspace, 0, "");
   69 
   70 static  int ipx_usr_abort(struct socket *so);
   71 static  int ipx_attach(struct socket *so, int proto);
   72 static  int ipx_bind(struct socket *so, struct mbuf *nam);
   73 static  int ipx_connect(struct socket *so, struct mbuf *nam);
   74 static  int ipx_detach(struct socket *so);
   75 static  int ipx_disconnect(struct socket *so);
   76 static  int ipx_send(struct socket *so, int flags, struct mbuf *m,
   77                      struct mbuf *addr, struct mbuf *control);
   78 static  int ipx_shutdown(struct socket *so);
   79 static  int ripx_attach(struct socket *so, int proto);
   80 static  int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
   81 
   82 struct  pr_usrreqs ipx_usrreqs = {
   83         ipx_usr_abort, pru_accept_notsupp, ipx_attach, ipx_bind,
   84         ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach,
   85         ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp,
   86         pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown,
   87         ipx_sockaddr
   88 };
   89 
   90 struct  pr_usrreqs ripx_usrreqs = {
   91         ipx_usr_abort, pru_accept_notsupp, ripx_attach, ipx_bind,
   92         ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach,
   93         ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp,
   94         pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown,
   95         ipx_sockaddr
   96 };
   97 
   98 /*
   99  *  This may also be called for raw listeners.
  100  */
  101 void
  102 ipx_input(m, ipxp)
  103         struct mbuf *m;
  104         register struct ipxpcb *ipxp;
  105 {
  106         register struct ipx *ipx = mtod(m, struct ipx *);
  107         struct ifnet *ifp = m->m_pkthdr.rcvif;
  108         struct sockaddr_ipx ipx_ipx;
  109 
  110         if (ipxp == NULL)
  111                 panic("No ipxpcb");
  112         /*
  113          * Construct sockaddr format source address.
  114          * Stuff source address and datagram in user buffer.
  115          */
  116         ipx_ipx.sipx_len = sizeof(ipx_ipx);
  117         ipx_ipx.sipx_family = AF_IPX;
  118         ipx_ipx.sipx_addr = ipx->ipx_sna;
  119         ipx_ipx.sipx_zero[0] = '\0';
  120         ipx_ipx.sipx_zero[1] = '\0';
  121         if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
  122                 register struct ifaddr *ifa;
  123 
  124                 for (ifa = ifp->if_addrlist; ifa != NULL; ifa = ifa->ifa_next) {
  125                         if (ifa->ifa_addr->sa_family == AF_IPX) {
  126                                 ipx_ipx.sipx_addr.x_net =
  127                                         IA_SIPX(ifa)->sipx_addr.x_net;
  128                                 break;
  129                         }
  130                 }
  131         }
  132         ipxp->ipxp_rpt = ipx->ipx_pt;
  133         if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) {
  134                 m->m_len -= sizeof(struct ipx);
  135                 m->m_pkthdr.len -= sizeof(struct ipx);
  136                 m->m_data += sizeof(struct ipx);
  137         }
  138         if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx,
  139             m, (struct mbuf *)NULL) == 0)
  140                 goto bad;
  141         sorwakeup(ipxp->ipxp_socket);
  142         return;
  143 bad:
  144         m_freem(m);
  145 }
  146 
  147 void
  148 ipx_abort(ipxp)
  149         struct ipxpcb *ipxp;
  150 {
  151         struct socket *so = ipxp->ipxp_socket;
  152 
  153         ipx_pcbdisconnect(ipxp);
  154         soisdisconnected(so);
  155 }
  156 
  157 /*
  158  * Drop connection, reporting
  159  * the specified error.
  160  */
  161 void
  162 ipx_drop(ipxp, errno)
  163         register struct ipxpcb *ipxp;
  164         int errno;
  165 {
  166         struct socket *so = ipxp->ipxp_socket;
  167 
  168         /*
  169          * someday, in the IPX world
  170          * we will generate error protocol packets
  171          * announcing that the socket has gone away.
  172          *
  173          * XXX Probably never. IPX does not have error packets.
  174          */
  175         /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
  176                 tp->t_state = TCPS_CLOSED;
  177                 tcp_output(tp);
  178         }*/
  179         so->so_error = errno;
  180         ipx_pcbdisconnect(ipxp);
  181         soisdisconnected(so);
  182 }
  183 
  184 static int
  185 ipx_output(ipxp, m0)
  186         struct ipxpcb *ipxp;
  187         struct mbuf *m0;
  188 {
  189         register struct mbuf *m;
  190         register struct ipx *ipx;
  191         register struct socket *so;
  192         register int len = 0;
  193         register struct route *ro;
  194         struct mbuf *mprev = NULL;
  195 
  196         /*
  197          * Calculate data length.
  198          */
  199         for (m = m0; m != NULL; m = m->m_next) {
  200                 mprev = m;
  201                 len += m->m_len;
  202         }
  203         /*
  204          * Make sure packet is actually of even length.
  205          */
  206         
  207         if (len & 1) {
  208                 m = mprev;
  209                 if ((m->m_flags & M_EXT) == 0 &&
  210                         (m->m_len + m->m_data < &m->m_dat[MLEN])) {
  211                         m->m_len++;
  212                 } else {
  213                         struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
  214 
  215                         if (m1 == NULL) {
  216                                 m_freem(m0);
  217                                 return (ENOBUFS);
  218                         }
  219                         m1->m_len = 1;
  220                         * mtod(m1, char *) = 0;
  221                         m->m_next = m1;
  222                 }
  223                 m0->m_pkthdr.len++;
  224         }
  225 
  226         /*
  227          * Fill in mbuf with extended IPX header
  228          * and addresses and length put into network format.
  229          */
  230         m = m0;
  231         if (ipxp->ipxp_flags & IPXP_RAWOUT) {
  232                 ipx = mtod(m, struct ipx *);
  233         } else {
  234                 M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT);
  235                 if (m == NULL)
  236                         return (ENOBUFS);
  237                 ipx = mtod(m, struct ipx *);
  238                 ipx->ipx_tc = 0;
  239                 ipx->ipx_pt = ipxp->ipxp_dpt;
  240                 ipx->ipx_sna = ipxp->ipxp_laddr;
  241                 ipx->ipx_dna = ipxp->ipxp_faddr;
  242                 len += sizeof(struct ipx);
  243         }
  244 
  245         ipx->ipx_len = htons((u_short)len);
  246 
  247         if (ipxcksum) {
  248                 ipx->ipx_sum = 0;
  249                 len = ((len - 1) | 1) + 1;
  250                 ipx->ipx_sum = ipx_cksum(m, len);
  251         } else
  252                 ipx->ipx_sum = 0xffff;
  253 
  254         /*
  255          * Output datagram.
  256          */
  257         so = ipxp->ipxp_socket;
  258         if (so->so_options & SO_DONTROUTE)
  259                 return (ipx_outputfl(m, (struct route *)NULL,
  260                     (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
  261         /*
  262          * Use cached route for previous datagram if
  263          * possible.  If the previous net was the same
  264          * and the interface was a broadcast medium, or
  265          * if the previous destination was identical,
  266          * then we are ok.
  267          *
  268          * NB: We don't handle broadcasts because that
  269          *     would require 3 subroutine calls.
  270          */
  271         ro = &ipxp->ipxp_route;
  272 #ifdef ancient_history
  273         /*
  274          * I think that this will all be handled in ipx_pcbconnect!
  275          */
  276         if (ro->ro_rt != NULL) {
  277                 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
  278                         /*
  279                          * This assumes we have no GH type routes
  280                          */
  281                         if (ro->ro_rt->rt_flags & RTF_HOST) {
  282                                 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
  283                                         goto re_route;
  284 
  285                         }
  286                         if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
  287                                 register struct ipx_addr *dst =
  288                                                 &satoipx_addr(ro->ro_dst);
  289                                 dst->x_host = ipx->ipx_dna.x_host;
  290                         }
  291                         /* 
  292                          * Otherwise, we go through the same gateway
  293                          * and dst is already set up.
  294                          */
  295                 } else {
  296                 re_route:
  297                         RTFREE(ro->ro_rt);
  298                         ro->ro_rt = NULL;
  299                 }
  300         }
  301         ipxp->ipxp_lastdst = ipx->ipx_dna;
  302 #endif /* ancient_history */
  303         return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
  304 }
  305 
  306 int
  307 ipx_ctloutput(req, so, level, name, value)
  308         int req, level;
  309         struct socket *so;
  310         int name;
  311         struct mbuf **value;
  312 {
  313         register struct mbuf *m;
  314         struct ipxpcb *ipxp = sotoipxpcb(so);
  315         int mask, error = 0;
  316 
  317         if (ipxp == NULL)
  318                 return (EINVAL);
  319 
  320         switch (req) {
  321 
  322         case PRCO_GETOPT:
  323                 if (value == NULL)
  324                         return (EINVAL);
  325                 m = m_get(M_DONTWAIT, MT_DATA);
  326                 if (m == NULL)
  327                         return (ENOBUFS);
  328                 switch (name) {
  329 
  330                 case SO_ALL_PACKETS:
  331                         mask = IPXP_ALL_PACKETS;
  332                         goto get_flags;
  333 
  334                 case SO_HEADERS_ON_INPUT:
  335                         mask = IPXP_RAWIN;
  336                         goto get_flags;
  337                         
  338                 case SO_HEADERS_ON_OUTPUT:
  339                         mask = IPXP_RAWOUT;
  340                 get_flags:
  341                         m->m_len = sizeof(short);
  342                         *mtod(m, short *) = ipxp->ipxp_flags & mask;
  343                         break;
  344 
  345                 case SO_DEFAULT_HEADERS:
  346                         m->m_len = sizeof(struct ipx);
  347                         {
  348                                 register struct ipx *ipx = mtod(m, struct ipx *);
  349                                 ipx->ipx_len = 0;
  350                                 ipx->ipx_sum = 0;
  351                                 ipx->ipx_tc = 0;
  352                                 ipx->ipx_pt = ipxp->ipxp_dpt;
  353                                 ipx->ipx_dna = ipxp->ipxp_faddr;
  354                                 ipx->ipx_sna = ipxp->ipxp_laddr;
  355                         }
  356                         break;
  357 
  358                 case SO_SEQNO:
  359                         m->m_len = sizeof(long);
  360                         *mtod(m, long *) = ipx_pexseq++;
  361                         break;
  362 
  363                 default:
  364                         error = EINVAL;
  365                 }
  366                 *value = m;
  367                 break;
  368 
  369         case PRCO_SETOPT:
  370                 switch (name) {
  371                         int *ok;
  372 
  373                 case SO_ALL_PACKETS:
  374                         mask = IPXP_ALL_PACKETS;
  375                         goto set_head;
  376 
  377                 case SO_HEADERS_ON_INPUT:
  378                         mask = IPXP_RAWIN;
  379                         goto set_head;
  380 
  381                 case SO_HEADERS_ON_OUTPUT:
  382                         mask = IPXP_RAWOUT;
  383                 set_head:
  384                         if (value && *value) {
  385                                 ok = mtod(*value, int *);
  386                                 if (*ok)
  387                                         ipxp->ipxp_flags |= mask;
  388                                 else
  389                                         ipxp->ipxp_flags &= ~mask;
  390                         } else error = EINVAL;
  391                         break;
  392 
  393                 case SO_DEFAULT_HEADERS:
  394                         {
  395                                 register struct ipx *ipx
  396                                     = mtod(*value, struct ipx *);
  397                                 ipxp->ipxp_dpt = ipx->ipx_pt;
  398                         }
  399                         break;
  400 #ifdef IPXIP
  401                 case SO_IPXIP_ROUTE:
  402                         error = ipxip_route(so, *value);
  403                         break;
  404 #endif /* IPXIP */
  405 #ifdef IPXTUNNEL
  406                 case SO_IPXTUNNEL_ROUTE
  407                         error = ipxtun_route(so, *value);
  408                         break;
  409 #endif
  410                 default:
  411                         error = EINVAL;
  412                 }
  413                 if (value && *value)
  414                         m_freem(*value);
  415                 break;
  416         }
  417         return (error);
  418 }
  419 
  420 static int
  421 ipx_usr_abort(so)
  422         struct socket *so;
  423 {
  424         int s;
  425         struct ipxpcb *ipxp = sotoipxpcb(so);
  426 
  427         s = splnet();
  428         ipx_pcbdetach(ipxp);
  429         splx(s);
  430         sofree(so);
  431         soisdisconnected(so);
  432         return (0);
  433 }
  434 
  435 static int
  436 ipx_attach(so, proto)
  437         struct socket *so;
  438         int proto;
  439 {
  440         int error;
  441         int s;
  442         struct ipxpcb *ipxp = sotoipxpcb(so);
  443 
  444         if (ipxp != NULL)
  445                 return (EINVAL);
  446         s = splnet();
  447         error = ipx_pcballoc(so, &ipxpcb);
  448         splx(s);
  449         if (error == 0)
  450                 error = soreserve(so, ipxsendspace, ipxrecvspace);
  451         return (error);
  452 }
  453 
  454 static int
  455 ipx_bind(so, nam)
  456         struct socket *so;
  457         struct mbuf *nam;
  458 {
  459         struct ipxpcb *ipxp = sotoipxpcb(so);
  460 
  461         return (ipx_pcbbind(ipxp, nam));
  462 }
  463 
  464 static int
  465 ipx_connect(so, nam)
  466         struct socket *so;
  467         struct mbuf *nam;
  468 {
  469         int error;
  470         int s;
  471         struct ipxpcb *ipxp = sotoipxpcb(so);
  472 
  473         if (!ipx_nullhost(ipxp->ipxp_faddr))
  474                 return (EISCONN);
  475         s = splnet();
  476         error = ipx_pcbconnect(ipxp, nam);
  477         splx(s);
  478         if (error == 0)
  479                 soisconnected(so);
  480         return (error);
  481 }
  482 
  483 static int
  484 ipx_detach(so)
  485         struct socket *so;
  486 {
  487         int s;
  488         struct ipxpcb *ipxp = sotoipxpcb(so);
  489 
  490         if (ipxp == NULL)
  491                 return (ENOTCONN);
  492         s = splnet();
  493         ipx_pcbdetach(ipxp);
  494         splx(s);
  495         return (0);
  496 }
  497 
  498 static int
  499 ipx_disconnect(so)
  500         struct socket *so;
  501 {
  502         int s;
  503         struct ipxpcb *ipxp = sotoipxpcb(so);
  504 
  505         if (ipx_nullhost(ipxp->ipxp_faddr))
  506                 return (ENOTCONN);
  507         s = splnet();
  508         ipx_pcbdisconnect(ipxp);
  509         splx(s);
  510         soisdisconnected(so);
  511         return (0);
  512 }
  513 
  514 int
  515 ipx_peeraddr(so, nam)
  516         struct socket *so;
  517         struct mbuf *nam;
  518 {
  519         struct ipxpcb *ipxp = sotoipxpcb(so);
  520 
  521         ipx_setpeeraddr(ipxp, nam);
  522         return (0);
  523 }
  524 
  525 static int
  526 ipx_send(so, flags, m, nam, control)
  527         struct socket *so;
  528         int flags;
  529         struct mbuf *m;
  530         struct mbuf *nam;
  531         struct mbuf *control;
  532 {
  533         int error;
  534         struct ipxpcb *ipxp = sotoipxpcb(so);
  535         struct ipx_addr laddr;
  536         int s = 0;
  537 
  538         if (nam != NULL) {
  539                 laddr = ipxp->ipxp_laddr;
  540                 if (!ipx_nullhost(ipxp->ipxp_faddr)) {
  541                         error = EISCONN;
  542                         goto send_release;
  543                 }
  544                 /*
  545                  * Must block input while temporarily connected.
  546                  */
  547                 s = splnet();
  548                 error = ipx_pcbconnect(ipxp, nam);
  549                 if (error) {
  550                         splx(s);
  551                         goto send_release;
  552                 }
  553         } else {
  554                 if (ipx_nullhost(ipxp->ipxp_faddr)) {
  555                         error = ENOTCONN;
  556                         goto send_release;
  557                 }
  558         }
  559         error = ipx_output(ipxp, m);
  560         m = NULL;
  561         if (nam != NULL) {
  562                 ipx_pcbdisconnect(ipxp);
  563                 splx(s);
  564                 ipxp->ipxp_laddr.x_host = laddr.x_host;
  565                 ipxp->ipxp_laddr.x_port = laddr.x_port;
  566         }
  567 
  568 send_release:
  569         if (m != NULL)
  570                 m_freem(m);
  571         return (error);
  572 }
  573 
  574 static int
  575 ipx_shutdown(so)
  576         struct socket *so;
  577 {
  578         socantsendmore(so);
  579         return (0);
  580 }
  581 
  582 int
  583 ipx_sockaddr(so, nam)
  584         struct socket *so;
  585         struct mbuf *nam;
  586 {
  587         struct ipxpcb *ipxp = sotoipxpcb(so);
  588 
  589         ipx_setsockaddr(ipxp, nam);
  590         return (0);
  591 }
  592 
  593 static int
  594 ripx_attach(so, proto)
  595         struct socket *so;
  596         int proto;
  597 {
  598         int error = 0;
  599         int s;
  600         struct ipxpcb *ipxp = sotoipxpcb(so);
  601 
  602         if (!(so->so_state & SS_PRIV) || (ipxp != NULL))
  603                 return (EINVAL);
  604         s = splnet();
  605         error = ipx_pcballoc(so, &ipxrawpcb);
  606         splx(s);
  607         if (error)
  608                 return (error);
  609         error = soreserve(so, ipxsendspace, ipxrecvspace);
  610         if (error)
  611                 return (error);
  612         ipxp = sotoipxpcb(so);
  613         ipxp->ipxp_faddr.x_host = ipx_broadhost;
  614         ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
  615         return (error);
  616 }

Cache object: 4d6d1eef26eeb9a396ffcc8026d388e9


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