root/netnatm/natm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. natm_usrreq
  2. natmintr
  3. natm0_sysctl
  4. natm5_sysctl

    1 /*      $OpenBSD: natm.c,v 1.7 2006/03/04 22:40:16 brad Exp $   */
    2 
    3 /*
    4  *
    5  * Copyright (c) 1996 Charles D. Cranor and Washington University.
    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 Charles D. Cranor and
   19  *      Washington University.
   20  * 4. The name of the author may not be used to endorse or promote products
   21  *    derived from this software without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 
   35 /*
   36  * natm.c: native mode ATM access (both aal0 and aal5).
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/kernel.h>
   42 #include <sys/domain.h>
   43 #include <sys/ioctl.h>
   44 #include <sys/proc.h>
   45 #include <sys/protosw.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/socket.h>
   48 #include <sys/socketvar.h>
   49 
   50 #include <net/if.h>
   51 #include <net/if_atm.h>
   52 #include <net/netisr.h>
   53 #include <net/radix.h>
   54 #include <net/route.h>
   55 
   56 #include <netinet/in.h>
   57 
   58 #include <netnatm/natm.h>
   59 
   60 u_long natm5_sendspace = 16*1024;
   61 u_long natm5_recvspace = 16*1024;
   62 
   63 u_long natm0_sendspace = 16*1024;
   64 u_long natm0_recvspace = 16*1024;
   65 
   66 /*
   67  * user requests
   68  */
   69 
   70 #if defined(__NetBSD__)
   71 int natm_usrreq(so, req, m, nam, control)
   72 #elif defined(__OpenBSD__) || defined(__FreeBSD__)
   73 int natm_usrreq(so, req, m, nam, control)
   74 #endif
   75 struct socket *so;
   76 int req;
   77 struct mbuf *m, *nam, *control;
   78 #if defined(__NetBSD__)
   79 struct proc *p;
   80 #endif
   81 {
   82   int error = 0, s, s2;
   83   struct natmpcb *npcb;
   84   struct sockaddr_natm *snatm;
   85   struct atm_pseudoioctl api;
   86   struct atm_pseudohdr *aph;
   87   struct atm_rawioctl ario;
   88   struct ifnet *ifp;
   89   int proto = so->so_proto->pr_protocol;
   90 
   91   s = SPLSOFTNET();
   92 
   93   npcb = (struct natmpcb *) so->so_pcb;
   94 
   95   if (npcb == NULL && req != PRU_ATTACH) {
   96     error = EINVAL;
   97     goto done;
   98   }
   99     
  100 
  101   switch (req) {
  102     case PRU_ATTACH:                    /* attach protocol to up */
  103 
  104       if (npcb) {
  105         error = EISCONN;
  106         break;
  107       }
  108 
  109       if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
  110         if (proto == PROTO_NATMAAL5) 
  111           error = soreserve(so, natm5_sendspace, natm5_recvspace);
  112         else
  113           error = soreserve(so, natm0_sendspace, natm0_recvspace);
  114         if (error)
  115           break;
  116       }
  117 
  118       so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
  119       npcb->npcb_socket = so;
  120 
  121       break;
  122 
  123     case PRU_DETACH:                    /* detach protocol from up */
  124 
  125       /*
  126        * we turn on 'drain' *before* we sofree.
  127        */
  128 
  129       npcb_free(npcb, NPCB_DESTROY);    /* drain */
  130       so->so_pcb = NULL;
  131       sofree(so);
  132 
  133       break;
  134 
  135     case PRU_CONNECT:                   /* establish connection to peer */
  136 
  137       /*
  138        * validate nam and npcb
  139        */
  140 
  141       if (nam->m_len != sizeof(*snatm)) {
  142         error = EINVAL;
  143         break;
  144       }
  145       snatm = mtod(nam, struct sockaddr_natm *);
  146       if (snatm->snatm_len != sizeof(*snatm) ||
  147                 (npcb->npcb_flags & NPCB_FREE) == 0) {
  148         error = EINVAL;
  149         break;
  150       }
  151       if (snatm->snatm_family != AF_NATM) {
  152         error = EAFNOSUPPORT;
  153         break;
  154       }
  155 
  156       snatm->snatm_if[IFNAMSIZ-1] = '\0';  /* XXX ensure null termination
  157                                                 since ifunit() uses strcmp */
  158 
  159       /*
  160        * convert interface string to ifp, validate.
  161        */
  162 
  163       ifp = ifunit(snatm->snatm_if);
  164       if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
  165         error = ENXIO;
  166         break;
  167       }
  168       if (ifp->if_output != atm_output) {
  169         error = EAFNOSUPPORT;
  170         break;
  171       }
  172 
  173 
  174       /*
  175        * register us with the NATM PCB layer
  176        */
  177 
  178       if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
  179         error = EADDRINUSE;
  180         break;
  181       }
  182 
  183       /*
  184        * enable rx
  185        */
  186 
  187       ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
  188       ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
  189       ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
  190       api.rxhand = npcb;
  191       s2 = splnet();
  192       if (ifp->if_ioctl == NULL || 
  193           ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) {
  194         splx(s2);
  195         npcb_free(npcb, NPCB_REMOVE);
  196         error = EIO;
  197         break;
  198       }
  199       splx(s2);
  200 
  201       soisconnected(so);
  202 
  203       break;
  204 
  205     case PRU_DISCONNECT:                /* disconnect from peer */
  206 
  207       if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
  208         printf("natm: disconnected check\n");
  209         error = EIO;
  210         break;
  211       }
  212       ifp = npcb->npcb_ifp;
  213 
  214       /*
  215        * disable rx
  216        */
  217 
  218       ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
  219       ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
  220       ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
  221       api.rxhand = npcb;
  222       s2 = splnet();
  223       if (ifp->if_ioctl != NULL)
  224           ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api);
  225       splx(s);
  226 
  227       npcb_free(npcb, NPCB_REMOVE);
  228       soisdisconnected(so);
  229 
  230       break;
  231 
  232     case PRU_SHUTDOWN:                  /* won't send any more data */
  233       socantsendmore(so);
  234       break;
  235 
  236     case PRU_SEND:                      /* send this data */
  237       if (control && control->m_len) {
  238         m_freem(control);
  239         m_freem(m);
  240         error = EINVAL;
  241         break;
  242       }
  243 
  244       /*
  245        * send the data.   we must put an atm_pseudohdr on first
  246        */
  247 
  248       M_PREPEND(m, sizeof(*aph), M_WAITOK);
  249       aph = mtod(m, struct atm_pseudohdr *);
  250       ATM_PH_VPI(aph) = npcb->npcb_vpi;
  251       ATM_PH_SETVCI(aph, npcb->npcb_vci);
  252       ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
  253 
  254       error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
  255 
  256       break;
  257 
  258     case PRU_SENSE:                     /* return status into m */
  259       /* return zero? */
  260       break;
  261 
  262     case PRU_PEERADDR:                  /* fetch peer's address */
  263       snatm = mtod(nam, struct sockaddr_natm *);
  264       bzero(snatm, sizeof(*snatm));
  265       nam->m_len = snatm->snatm_len = sizeof(*snatm);
  266       snatm->snatm_family = AF_NATM;
  267 #if defined(__NetBSD__) || defined(__OpenBSD__)
  268       bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if));
  269 #elif defined(__FreeBSD__)
  270       sprintf(snatm->snatm_if, "%s%d", npcb->npcb_ifp->if_name,
  271         npcb->npcb_ifp->if_unit);
  272 #endif
  273       snatm->snatm_vci = npcb->npcb_vci;
  274       snatm->snatm_vpi = npcb->npcb_vpi;
  275       break;
  276 
  277     case PRU_CONTROL:                   /* control operations on protocol */
  278       /*
  279        * raw atm ioctl.   comes in as a SIOCRAWATM.   we convert it to
  280        * SIOCXRAWATM and pass it to the driver.
  281        */
  282       if ((u_long)m == SIOCRAWATM) {
  283         if (npcb->npcb_ifp == NULL) {
  284           error = ENOTCONN;
  285           break;
  286         }
  287         ario.npcb = npcb;
  288         ario.rawvalue = *((int *)nam);
  289         error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, 
  290                                 SIOCXRAWATM, (caddr_t) &ario);
  291         if (!error) {
  292           if (ario.rawvalue) 
  293             npcb->npcb_flags |= NPCB_RAW;
  294           else
  295             npcb->npcb_flags &= ~(NPCB_RAW);
  296         }
  297 
  298         break;
  299       }
  300 
  301       error = EOPNOTSUPP;
  302       break;
  303 
  304     case PRU_BIND:                      /* bind socket to address */
  305     case PRU_LISTEN:                    /* listen for connection */
  306     case PRU_ACCEPT:                    /* accept connection from peer */
  307     case PRU_CONNECT2:                  /* connect two sockets */
  308     case PRU_ABORT:                     /* abort (fast DISCONNECT, DETATCH) */
  309                                         /* (only happens if LISTEN socket) */
  310     case PRU_RCVD:                      /* have taken data; more room now */
  311     case PRU_FASTTIMO:                  /* 200ms timeout */
  312     case PRU_SLOWTIMO:                  /* 500ms timeout */
  313     case PRU_RCVOOB:                    /* retrieve out of band data */
  314     case PRU_SENDOOB:                   /* send out of band data */
  315     case PRU_PROTORCV:                  /* receive from below */
  316     case PRU_PROTOSEND:                 /* send to below */
  317     case PRU_SOCKADDR:                  /* fetch socket's address */
  318 #ifdef DIAGNOSTIC
  319       printf("natm: PRU #%d unsupported\n", req);
  320 #endif
  321       error = EOPNOTSUPP;
  322       break;
  323    
  324     default: panic("natm usrreq");
  325   }
  326 
  327 done:
  328   splx(s);
  329   return(error);
  330 }
  331 
  332 /*
  333  * natmintr: splsoftnet interrupt
  334  *
  335  * note: we expect a socket pointer in rcvif rather than an interface
  336  * pointer.    we can get the interface pointer from the so's PCB if
  337  * we really need it.
  338  */
  339 
  340 void
  341 natmintr()
  342 
  343 {
  344   int s;
  345   struct mbuf *m;
  346   struct socket *so;
  347   struct natmpcb *npcb;
  348 
  349 next:
  350   s = splnet();
  351   IF_DEQUEUE(&natmintrq, m);
  352   splx(s);
  353   if (m == NULL)
  354     return;
  355 
  356 #ifdef DIAGNOSTIC
  357   if ((m->m_flags & M_PKTHDR) == 0)
  358     panic("natmintr no HDR");
  359 #endif
  360 
  361   npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
  362   so = npcb->npcb_socket;
  363 
  364   s = splnet();                 /* could have atm devs @ different levels */
  365   npcb->npcb_inq--;
  366   splx(s);
  367 
  368   if (npcb->npcb_flags & NPCB_DRAIN) {
  369     m_freem(m);
  370     if (npcb->npcb_inq == 0)
  371       FREE(npcb, M_PCB);                        /* done! */
  372     goto next;
  373   }
  374 
  375   if (npcb->npcb_flags & NPCB_FREE) {
  376     m_freem(m);                                 /* drop */
  377     goto next;
  378   }
  379 
  380 #ifdef NEED_TO_RESTORE_IFP
  381   m->m_pkthdr.rcvif = npcb->npcb_ifp;
  382 #else
  383 #ifdef DIAGNOSTIC
  384 m->m_pkthdr.rcvif = NULL;       /* null it out to be safe */
  385 #endif
  386 #endif
  387 
  388   if (sbspace(&so->so_rcv) > m->m_pkthdr.len ||
  389      ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) {
  390 #ifdef NATM_STAT
  391     natm_sookcnt++;
  392     natm_sookbytes += m->m_pkthdr.len;
  393 #endif
  394     sbappendrecord(&so->so_rcv, m);
  395     sorwakeup(so);
  396   } else {
  397 #ifdef NATM_STAT
  398     natm_sodropcnt++;
  399     natm_sodropbytes += m->m_pkthdr.len;
  400 #endif
  401     m_freem(m);
  402   }
  403 
  404   goto next;
  405 }
  406 
  407 #if defined(__FreeBSD__)
  408 NETISR_SET(NETISR_NATM, natmintr);
  409 #endif
  410 
  411 
  412 /* 
  413  * natm0_sysctl: not used, but here in case we want to add something
  414  * later...
  415  */
  416 
  417 int natm0_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
  418 
  419 int *name;
  420 u_int namelen;
  421 void *oldp;
  422 size_t *oldlenp;
  423 void *newp;
  424 size_t newlen;
  425 
  426 {
  427   /* All sysctl names at this level are terminal. */
  428   if (namelen != 1)
  429     return (ENOTDIR);
  430   return (ENOPROTOOPT);
  431 }
  432 
  433 /* 
  434  * natm5_sysctl: not used, but here in case we want to add something
  435  * later...
  436  */
  437 
  438 int natm5_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
  439 
  440 int *name;
  441 u_int namelen;
  442 void *oldp;
  443 size_t *oldlenp;
  444 void *newp;
  445 size_t newlen;
  446 
  447 {
  448   /* All sysctl names at this level are terminal. */
  449   if (namelen != 1)
  450     return (ENOTDIR);
  451   return (ENOPROTOOPT);
  452 }

/* [<][>][^][v][top][bottom][index][help] */