Home | History | Annotate | Line # | Download | only in netnatm
natm.c revision 1.49
      1 /*	$NetBSD: natm.c,v 1.48 2015/04/26 21:40:49 rtr Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1996 Charles D. Cranor and Washington University.
      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  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 /*
     29  * natm.c: native mode ATM access (both aal0 and aal5).
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: natm.c,v 1.48 2015/04/26 21:40:49 rtr Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/kmem.h>
     37 #include <sys/systm.h>
     38 #include <sys/kernel.h>
     39 #include <sys/domain.h>
     40 #include <sys/ioctl.h>
     41 #include <sys/protosw.h>
     42 #include <sys/mbuf.h>
     43 #include <sys/socket.h>
     44 #include <sys/socketvar.h>
     45 
     46 #include <net/if.h>
     47 #include <net/if_atm.h>
     48 #include <net/netisr.h>
     49 #include <net/route.h>
     50 
     51 #include <netinet/in.h>
     52 
     53 #include <netnatm/natm.h>
     54 
     55 u_long natm5_sendspace = 16*1024;
     56 u_long natm5_recvspace = 16*1024;
     57 
     58 u_long natm0_sendspace = 16*1024;
     59 u_long natm0_recvspace = 16*1024;
     60 
     61 static int
     62 natm_attach(struct socket *so, int proto)
     63 {
     64 	int error = 0;
     65 	struct natmpcb *npcb;
     66 
     67 	KASSERT(so->so_pcb == NULL);
     68 	sosetlock(so);
     69 
     70 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
     71 		if (proto == PROTO_NATMAAL5)
     72 			error = soreserve(so, natm5_sendspace, natm5_recvspace);
     73 		else
     74 			error = soreserve(so, natm0_sendspace, natm0_recvspace);
     75 		if (error)
     76 			return error;
     77 	}
     78 	npcb = npcb_alloc(true);
     79 	npcb->npcb_socket = so;
     80 	so->so_pcb = npcb;
     81 	return error;
     82 }
     83 
     84 static void
     85 natm_detach(struct socket *so)
     86 {
     87 	struct natmpcb *npcb = (struct natmpcb *)so->so_pcb;
     88 
     89 	/*
     90 	 * we turn on 'drain' *before* we sofree.
     91 	 */
     92 
     93 	npcb_free(npcb, NPCB_DESTROY);	/* drain */
     94 	so->so_pcb = NULL;
     95 	/* sofree drops the lock */
     96 	sofree(so);
     97 	mutex_enter(softnet_lock);
     98 }
     99 
    100 static int
    101 natm_accept(struct socket *so, struct sockaddr *nam)
    102 {
    103 	KASSERT(solocked(so));
    104 
    105 	return EOPNOTSUPP;
    106 }
    107 
    108 static int
    109 natm_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
    110 {
    111 	KASSERT(solocked(so));
    112 
    113 	return EOPNOTSUPP;
    114 }
    115 
    116 static int
    117 natm_listen(struct socket *so, struct lwp *l)
    118 {
    119 	KASSERT(solocked(so));
    120 
    121 	return EOPNOTSUPP;
    122 }
    123 
    124 static int
    125 natm_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
    126 {
    127 	int error = 0, s2;
    128 	struct natmpcb *npcb;
    129 	struct sockaddr_natm *snatm = (struct sockaddr_natm *)nam;
    130 	struct atm_pseudoioctl api;
    131 	struct atm_pseudohdr *aph;
    132 	struct ifnet *ifp;
    133 	int proto = so->so_proto->pr_protocol;
    134 
    135 	KASSERT(solocked(so));
    136 
    137 	/*
    138 	 * validate nam and npcb
    139 	 */
    140 
    141 	if (snatm->snatm_len != sizeof(*snatm) ||
    142 	    (npcb->npcb_flags & NPCB_FREE) == 0)
    143 		return EINVAL;
    144 	if (snatm->snatm_family != AF_NATM)
    145 		return EAFNOSUPPORT;
    146 
    147 	snatm->snatm_if[IFNAMSIZ-1] = '\0';  /* XXX ensure null termination
    148 						since ifunit() uses strcmp */
    149 
    150 	/*
    151 	 * convert interface string to ifp, validate.
    152 	 */
    153 
    154 	ifp = ifunit(snatm->snatm_if);
    155 	if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
    156 		return ENXIO;
    157 	}
    158 	if (ifp->if_output != atm_output) {
    159 		return EAFNOSUPPORT;
    160 	}
    161 
    162 	/*
    163 	 * register us with the NATM PCB layer
    164 	 */
    165 
    166 	if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb)
    167 		return EADDRINUSE;
    168 
    169 	/*
    170 	 * enable rx
    171 	 */
    172 
    173 	ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
    174 	ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
    175 	ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
    176 	api.rxhand = npcb;
    177 	s2 = splnet();
    178 	if (ifp->if_ioctl(ifp, SIOCATMENA, &api) != 0) {
    179 		splx(s2);
    180 		npcb_free(npcb, NPCB_REMOVE);
    181 		return EIO;
    182 	}
    183 	splx(s2);
    184 
    185 	soisconnected(so);
    186 	return error;
    187 }
    188 
    189 static int
    190 natm_connect2(struct socket *so, struct socket *so2)
    191 {
    192 	KASSERT(solocked(so));
    193 
    194 	return EOPNOTSUPP;
    195 }
    196 
    197 static int
    198 natm_disconnect(struct socket *so)
    199 {
    200 	struct natmpcb *npcb = (struct natmpcb *)so->so_pcb;
    201 
    202 	KASSERT(solocked(so));
    203 	KASSERT(npcb != NULL);
    204 
    205 	if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
    206 		printf("natm: disconnected check\n");
    207 		return EIO;
    208 	}
    209 	ifp = npcb->npcb_ifp;
    210 
    211 	/*
    212 	 * disable rx
    213 	 */
    214 	ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
    215 	ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
    216 	ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
    217 	api.rxhand = npcb;
    218 
    219 	s2 = splnet();
    220 	ifp->if_ioctl(ifp, SIOCATMDIS, &api);
    221 	splx(s);
    222 
    223 	npcb_free(npcb, NPCB_REMOVE);
    224 	soisdisconnected(so);
    225 	return 0;
    226 }
    227 
    228 static int
    229 natm_shutdown(struct socket *so)
    230 {
    231 	int s;
    232 
    233 	KASSERT(solocked(so));
    234 
    235 	s = splsoftnet();
    236 	socantsendmore(so);
    237 	splx(s);
    238 
    239 	return 0;
    240 }
    241 
    242 static int
    243 natm_abort(struct socket *so)
    244 {
    245 	KASSERT(solocked(so));
    246 
    247 	return EOPNOTSUPP;
    248 }
    249 
    250 static int
    251 natm_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
    252 {
    253   int error = 0, s;
    254   struct natmpcb *npcb;
    255   struct atm_rawioctl ario;
    256 
    257   s = SPLSOFTNET();
    258 
    259   npcb = (struct natmpcb *) so->so_pcb;
    260 
    261   /*
    262    * raw atm ioctl.   comes in as a SIOCRAWATM.   we convert it to
    263    * SIOCXRAWATM and pass it to the driver.
    264    */
    265   if (cmd == SIOCRAWATM) {
    266     if (npcb->npcb_ifp == NULL) {
    267       error = ENOTCONN;
    268       goto done;
    269     }
    270     ario.npcb = npcb;
    271     ario.rawvalue = *((int *)nam);
    272     error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, SIOCXRAWATM, &ario);
    273     if (!error) {
    274       if (ario.rawvalue)
    275 	npcb->npcb_flags |= NPCB_RAW;
    276       else
    277 	npcb->npcb_flags &= ~(NPCB_RAW);
    278     }
    279 
    280     goto done;
    281   }
    282 
    283   error = EOPNOTSUPP;
    284 
    285 done:
    286   splx(s);
    287   return(error);
    288 }
    289 
    290 static int
    291 natm_stat(struct socket *so, struct stat *ub)
    292 {
    293   KASSERT(solocked(so));
    294 
    295   return 0;
    296 }
    297 
    298 static int
    299 natm_peeraddr(struct socket *so, struct sockaddr *nam)
    300 {
    301   struct natmpcb *npcb = (struct natmpcb *) so->so_pcb;
    302   struct sockaddr_natm *snatm = (struct sockaddr_natm *)nam;
    303 
    304   KASSERT(solocked(so));
    305   KASSERT(pcb != NULL);
    306   KASSERT(nam != NULL);
    307 
    308   memset(snatm, 0, sizeof(*snatm));
    309   snatm->snatm_len = sizeof(*snatm);
    310   snatm->snatm_family = AF_NATM;
    311   memcpy(snatm->snatm_if, npcb->npcb_ifp->if_xname, sizeof(snatm->snatm_if));
    312   snatm->snatm_vci = npcb->npcb_vci;
    313   snatm->snatm_vpi = npcb->npcb_vpi;
    314   return 0;
    315 }
    316 
    317 static int
    318 natm_sockaddr(struct socket *so, struct sockaddr *nam)
    319 {
    320 	KASSERT(solocked(so));
    321 
    322 	return EOPNOTSUPP;
    323 }
    324 
    325 static int
    326 natm_rcvd(struct socket *so, int flags, struct lwp *l)
    327 {
    328 	KASSERT(solocked(so));
    329 
    330 	return EOPNOTSUPP;
    331 }
    332 
    333 static int
    334 natm_recvoob(struct socket *so, struct mbuf *m, int flags)
    335 {
    336 	KASSERT(solocked(so));
    337 
    338 	return EOPNOTSUPP;
    339 }
    340 
    341 static int
    342 natm_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
    343     struct mbuf *control)
    344 {
    345 	struct natmpcb *npcb = (struct natmpcb *) so->so_pcb;
    346 	struct atm_pseudohdr *aph;
    347 
    348 	KASSERT(solocked(so));
    349 	KASSERT(pcb != NULL);
    350 	KASSERT(m != NULL);
    351 
    352 	if (control && control->m_len) {
    353 		m_freem(control);
    354 		m_freem(m);
    355 		return EINVAL;
    356 	}
    357 
    358 	/*
    359 	 * send the data.   we must put an atm_pseudohdr on first
    360 	 */
    361 	s = SPLSOFTNET();
    362 	M_PREPEND(m, sizeof(*aph), M_WAITOK);
    363 	if (m == NULL) {
    364 		error = ENOBUFS;
    365 		break;
    366 	}
    367 	aph = mtod(m, struct atm_pseudohdr *);
    368 	ATM_PH_VPI(aph) = npcb->npcb_vpi;
    369 	ATM_PH_SETVCI(aph, npcb->npcb_vci);
    370 	ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
    371 	error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
    372 	splx(s);
    373 
    374 	return error;
    375 }
    376 
    377 static int
    378 natm_send(struct socket *so, struct mbuf *m, struct mbuf *nam,
    379     struct mbuf *control, struct lwp *l)
    380 {
    381 	struct natmpcb *npcb = (struct natmpcb *) so->so_pcb;
    382 	struct atm_pseudohdr *aph;
    383 
    384 	KASSERT(solocked(so));
    385 	KASSERT(pcb != NULL);
    386 	KASSERT(m != NULL);
    387 
    388 	if (control && control->m_len) {
    389 		m_freem(control);
    390 		m_freem(m);
    391 		return EINVAL;
    392 	}
    393 
    394 	/*
    395 	 * send the data.   we must put an atm_pseudohdr on first
    396 	 */
    397 	s = SPLSOFTNET();
    398 	M_PREPEND(m, sizeof(*aph), M_WAITOK);
    399 	if (m == NULL) {
    400 		error = ENOBUFS;
    401 		break;
    402 	}
    403 	aph = mtod(m, struct atm_pseudohdr *);
    404 	ATM_PH_VPI(aph) = npcb->npcb_vpi;
    405 	ATM_PH_SETVCI(aph, npcb->npcb_vci);
    406 	ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
    407 	error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
    408 	splx(s);
    409 
    410 	return error;
    411 }
    412 
    413 static int
    414 natm_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
    415 {
    416 	KASSERT(solocked(so));
    417 
    418 	return EOPNOTSUPP;
    419 }
    420 
    421 static int
    422 natm_purgeif(struct socket *so, struct ifnet *ifp)
    423 {
    424 
    425 	return EOPNOTSUPP;
    426 }
    427 
    428 /*
    429  * natmintr: splsoftnet interrupt
    430  *
    431  * note: we expect a socket pointer in rcvif rather than an interface
    432  * pointer.    we can get the interface pointer from the so's PCB if
    433  * we really need it.
    434  */
    435 
    436 void
    437 natmintr(void)
    438 
    439 {
    440   int s;
    441   struct mbuf *m;
    442   struct socket *so;
    443   struct natmpcb *npcb;
    444 
    445   mutex_enter(softnet_lock);
    446 next:
    447   s = splnet();
    448   IF_DEQUEUE(&natmintrq, m);
    449   splx(s);
    450   if (m == NULL) {
    451     mutex_exit(softnet_lock);
    452     return;
    453   }
    454 
    455 #ifdef DIAGNOSTIC
    456   if ((m->m_flags & M_PKTHDR) == 0)
    457     panic("natmintr no HDR");
    458 #endif
    459 
    460   npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
    461   so = npcb->npcb_socket;
    462 
    463   s = splnet();			/* could have atm devs @ different levels */
    464   npcb->npcb_inq--;
    465   splx(s);
    466 
    467   if (npcb->npcb_flags & NPCB_DRAIN) {
    468     m_freem(m);
    469     if (npcb->npcb_inq == 0)
    470       kmem_intr_free(npcb, sizeof(*npcb));
    471     goto next;
    472   }
    473 
    474   if (npcb->npcb_flags & NPCB_FREE) {
    475     m_freem(m);					/* drop */
    476     goto next;
    477   }
    478 
    479 #ifdef NEED_TO_RESTORE_IFP
    480   m->m_pkthdr.rcvif = npcb->npcb_ifp;
    481 #else
    482 #ifdef DIAGNOSTIC
    483 m->m_pkthdr.rcvif = NULL;	/* null it out to be safe */
    484 #endif
    485 #endif
    486 
    487   if (sbspace(&so->so_rcv) > m->m_pkthdr.len ||
    488      ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) {
    489 #ifdef NATM_STAT
    490     natm_sookcnt++;
    491     natm_sookbytes += m->m_pkthdr.len;
    492 #endif
    493     sbappendrecord(&so->so_rcv, m);
    494     sorwakeup(so);
    495   } else {
    496 #ifdef NATM_STAT
    497     natm_sodropcnt++;
    498     natm_sodropbytes += m->m_pkthdr.len;
    499 #endif
    500     m_freem(m);
    501   }
    502 
    503   goto next;
    504 }
    505 
    506 PR_WRAP_USRREQS(natm)
    507 #define	natm_attach	natm_attach_wrapper
    508 #define	natm_detach	natm_detach_wrapper
    509 #define	natm_accept	natm_accept_wrapper
    510 #define	natm_bind	natm_bind_wrapper
    511 #define	natm_listen	natm_listen_wrapper
    512 #define	natm_connect	natm_connect_wrapper
    513 #define	natm_connect2	natm_connect2_wrapper
    514 #define	natm_disconnect	natm_disconnect_wrapper
    515 #define	natm_shutdown	natm_shutdown_wrapper
    516 #define	natm_abort	natm_abort_wrapper
    517 #define	natm_ioctl	natm_ioctl_wrapper
    518 #define	natm_stat	natm_stat_wrapper
    519 #define	natm_peeraddr	natm_peeraddr_wrapper
    520 #define	natm_sockaddr	natm_sockaddr_wrapper
    521 #define	natm_rcvd	natm_rcvd_wrapper
    522 #define	natm_recvoob	natm_recvoob_wrapper
    523 #define	natm_send	natm_send_wrapper
    524 #define	natm_sendoob	natm_sendoob_wrapper
    525 #define	natm_purgeif	natm_purgeif_wrapper
    526 
    527 const struct pr_usrreqs natm_usrreqs = {
    528 	.pr_attach	= natm_attach,
    529 	.pr_detach	= natm_detach,
    530 	.pr_accept	= natm_accept,
    531 	.pr_bind	= natm_bind,
    532 	.pr_listen	= natm_listen,
    533 	.pr_connect	= natm_connect,
    534 	.pr_connect2	= natm_connect2,
    535 	.pr_disconnect	= natm_disconnect,
    536 	.pr_shutdown	= natm_shutdown,
    537 	.pr_abort	= natm_abort,
    538 	.pr_ioctl	= natm_ioctl,
    539 	.pr_stat	= natm_stat,
    540 	.pr_peeraddr	= natm_peeraddr,
    541 	.pr_sockaddr	= natm_sockaddr,
    542 	.pr_rcvd	= natm_rcvd,
    543 	.pr_recvoob	= natm_recvoob,
    544 	.pr_send	= natm_send,
    545 	.pr_sendoob	= natm_sendoob,
    546 	.pr_purgeif	= natm_purgeif,
    547 };
    548