natm.c revision 118547
125605Skjc/* $NetBSD: natm.c,v 1.5 1996/11/09 03:26:26 chuck Exp $ */ 225605Skjc/* 325605Skjc * 425605Skjc * Copyright (c) 1996 Charles D. Cranor and Washington University. 525605Skjc * All rights reserved. 625605Skjc * 725605Skjc * Redistribution and use in source and binary forms, with or without 825605Skjc * modification, are permitted provided that the following conditions 925605Skjc * are met: 1025605Skjc * 1. Redistributions of source code must retain the above copyright 1125605Skjc * notice, this list of conditions and the following disclaimer. 1225605Skjc * 2. Redistributions in binary form must reproduce the above copyright 1325605Skjc * notice, this list of conditions and the following disclaimer in the 1425605Skjc * documentation and/or other materials provided with the distribution. 1525605Skjc * 3. All advertising materials mentioning features or use of this software 1625605Skjc * must display the following acknowledgement: 1725605Skjc * This product includes software developed by Charles D. Cranor and 1825605Skjc * Washington University. 1925605Skjc * 4. The name of the author may not be used to endorse or promote products 2025605Skjc * derived from this software without specific prior written permission. 2125605Skjc * 2225605Skjc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2325605Skjc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2425605Skjc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2525605Skjc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2625605Skjc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2725605Skjc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2825605Skjc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2925605Skjc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3025605Skjc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3125605Skjc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3225605Skjc */ 3325605Skjc 3425605Skjc/* 3525605Skjc * natm.c: native mode ATM access (both aal0 and aal5). 3625605Skjc */ 3725605Skjc 38116189Sobrien#include <sys/cdefs.h> 39116189Sobrien__FBSDID("$FreeBSD: head/sys/netnatm/natm.c 118547 2003-08-06 14:34:38Z harti $"); 40116189Sobrien 4125605Skjc#include <sys/param.h> 4295759Stanimura#include <sys/conf.h> 4325605Skjc#include <sys/kernel.h> 4495759Stanimura#include <sys/lock.h> 4529024Sbde#include <sys/malloc.h> 4625605Skjc#include <sys/mbuf.h> 4795759Stanimura#include <sys/protosw.h> 4895759Stanimura#include <sys/signalvar.h> 4925605Skjc#include <sys/socket.h> 5025605Skjc#include <sys/socketvar.h> 5195759Stanimura#include <sys/sockio.h> 5295759Stanimura#include <sys/sx.h> 5395759Stanimura#include <sys/systm.h> 54118541Sharti#include <sys/sysctl.h> 5525605Skjc 5625605Skjc#include <net/if.h> 5725605Skjc#include <net/if_atm.h> 5825605Skjc#include <net/netisr.h> 5925605Skjc 6025605Skjc#include <netinet/in.h> 6125605Skjc 6225605Skjc#include <netnatm/natm.h> 6325605Skjc 6433181Seivindstatic u_long natm5_sendspace = 16*1024; 6533181Seivindstatic u_long natm5_recvspace = 16*1024; 6625605Skjc 6733181Seivindstatic u_long natm0_sendspace = 16*1024; 6833181Seivindstatic u_long natm0_recvspace = 16*1024; 6925605Skjc 7025605Skjc/* 7125605Skjc * user requests 7225605Skjc */ 7325605Skjc#ifdef FREEBSD_USRREQS 7425605Skjc/* 7525605Skjc * FreeBSD new usrreqs supersedes pr_usrreq. 7625605Skjc */ 7792745Salfredstatic int natm_usr_attach(struct socket *, int, d_thread_t *); 7892745Salfredstatic int natm_usr_detach(struct socket *); 7992745Salfredstatic int natm_usr_connect(struct socket *, struct sockaddr *, d_thread_t *); 8092745Salfredstatic int natm_usr_disconnect(struct socket *); 8192745Salfredstatic int natm_usr_shutdown(struct socket *); 8292745Salfredstatic int natm_usr_send(struct socket *, int, struct mbuf *, 83118541Sharti struct sockaddr *, struct mbuf *, d_thread_t *); 8492745Salfredstatic int natm_usr_peeraddr(struct socket *, struct sockaddr **); 8592745Salfredstatic int natm_usr_control(struct socket *, u_long, caddr_t, 86118541Sharti struct ifnet *, d_thread_t *); 8792745Salfredstatic int natm_usr_abort(struct socket *); 8892745Salfredstatic int natm_usr_bind(struct socket *, struct sockaddr *, d_thread_t *); 8992745Salfredstatic int natm_usr_sockaddr(struct socket *, struct sockaddr **); 9025605Skjc 9125605Skjcstatic int 9291458Speternatm_usr_attach(struct socket *so, int proto, d_thread_t *p) 9325605Skjc{ 9425605Skjc struct natmpcb *npcb; 9525605Skjc int error = 0; 9625605Skjc int s = SPLSOFTNET(); 9725605Skjc 98118541Sharti npcb = (struct natmpcb *)so->so_pcb; 9925605Skjc 10025605Skjc if (npcb) { 10125605Skjc error = EISCONN; 10225605Skjc goto out; 10325605Skjc } 10425605Skjc 10525605Skjc if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 10625605Skjc if (proto == PROTO_NATMAAL5) 10725605Skjc error = soreserve(so, natm5_sendspace, natm5_recvspace); 10825605Skjc else 10925605Skjc error = soreserve(so, natm0_sendspace, natm0_recvspace); 11025605Skjc if (error) 11125605Skjc goto out; 11225605Skjc } 11325605Skjc 114111119Simp so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK)); 11525605Skjc npcb->npcb_socket = so; 11625605Skjc out: 11725605Skjc splx(s); 11825605Skjc return (error); 11925605Skjc} 12025605Skjc 12125605Skjcstatic int 12225605Skjcnatm_usr_detach(struct socket *so) 12325605Skjc{ 12425605Skjc struct natmpcb *npcb; 12525605Skjc int error = 0; 12625605Skjc int s = SPLSOFTNET(); 12725605Skjc 128118541Sharti npcb = (struct natmpcb *)so->so_pcb; 12925605Skjc if (npcb == NULL) { 13025605Skjc error = EINVAL; 13125605Skjc goto out; 13225605Skjc } 13325605Skjc 13425605Skjc /* 13525605Skjc * we turn on 'drain' *before* we sofree. 13625605Skjc */ 13725605Skjc npcb_free(npcb, NPCB_DESTROY); /* drain */ 13825605Skjc so->so_pcb = NULL; 13986487Sdillon sotryfree(so); 14025605Skjc out: 14125605Skjc splx(s); 14225605Skjc return (error); 14325605Skjc} 14425605Skjc 14525605Skjcstatic int 14691458Speternatm_usr_connect(struct socket *so, struct sockaddr *nam, d_thread_t *p) 14725605Skjc{ 14825605Skjc struct natmpcb *npcb; 14925605Skjc struct sockaddr_natm *snatm; 150118543Sharti struct atmio_openvcc op; 15125605Skjc struct ifnet *ifp; 15225605Skjc int error = 0; 15325605Skjc int s2, s = SPLSOFTNET(); 15425605Skjc int proto = so->so_proto->pr_protocol; 15525605Skjc 156118541Sharti npcb = (struct natmpcb *)so->so_pcb; 15725605Skjc if (npcb == NULL) { 15825605Skjc error = EINVAL; 15925605Skjc goto out; 16025605Skjc } 16125605Skjc 16225605Skjc /* 16325605Skjc * validate nam and npcb 16425605Skjc */ 16528270Swollman snatm = (struct sockaddr_natm *)nam; 16625605Skjc if (snatm->snatm_len != sizeof(*snatm) || 16725605Skjc (npcb->npcb_flags & NPCB_FREE) == 0) { 16825605Skjc error = EINVAL; 16925605Skjc goto out; 17025605Skjc } 17125605Skjc if (snatm->snatm_family != AF_NATM) { 17225605Skjc error = EAFNOSUPPORT; 17325605Skjc goto out; 17425605Skjc } 17525605Skjc 176118541Sharti snatm->snatm_if[IFNAMSIZ - 1] = '\0'; /* XXX ensure null termination 177118541Sharti since ifunit() uses strcmp */ 17825605Skjc 17925605Skjc /* 18025605Skjc * convert interface string to ifp, validate. 18125605Skjc */ 18225605Skjc ifp = ifunit(snatm->snatm_if); 18325605Skjc if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) { 18425605Skjc error = ENXIO; 18525605Skjc goto out; 18625605Skjc } 18725605Skjc if (ifp->if_output != atm_output) { 18825605Skjc error = EAFNOSUPPORT; 18925605Skjc goto out; 19025605Skjc } 19125605Skjc 19225605Skjc /* 19325605Skjc * register us with the NATM PCB layer 19425605Skjc */ 19525605Skjc if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) { 19625605Skjc error = EADDRINUSE; 19725605Skjc goto out; 19825605Skjc } 19925605Skjc 20025605Skjc /* 201118543Sharti * open the channel 20225605Skjc */ 203118543Sharti bzero(&op, sizeof(op)); 204118543Sharti op.rxhand = npcb; 205118543Sharti op.param.flags = ATMIO_FLAG_PVC; 206118543Sharti op.param.vpi = npcb->npcb_vpi; 207118543Sharti op.param.vci = npcb->npcb_vci; 208118543Sharti op.param.rmtu = op.param.tmtu = ifp->if_mtu; 209118543Sharti op.param.aal = (proto == PROTO_NATMAAL5) ? ATMIO_AAL_5 : ATMIO_AAL_0; 210118543Sharti op.param.traffic = ATMIO_TRAFFIC_UBR; 211118543Sharti 21225605Skjc s2 = splimp(); 21325605Skjc if (ifp->if_ioctl == NULL || 214118543Sharti ifp->if_ioctl(ifp, SIOCATMOPENVCC, (caddr_t)&op) != 0) { 21525605Skjc splx(s2); 21625605Skjc npcb_free(npcb, NPCB_REMOVE); 21725605Skjc error = EIO; 21825605Skjc goto out; 21925605Skjc } 22025605Skjc splx(s2); 22125605Skjc 22225605Skjc soisconnected(so); 22325605Skjc 22425605Skjc out: 22525605Skjc splx(s); 22625605Skjc return (error); 22725605Skjc} 22825605Skjc 22925605Skjcstatic int 23025605Skjcnatm_usr_disconnect(struct socket *so) 23125605Skjc{ 23225605Skjc struct natmpcb *npcb; 233118543Sharti struct atmio_closevcc cl; 23425605Skjc struct ifnet *ifp; 23525605Skjc int error = 0; 23625605Skjc int s2, s = SPLSOFTNET(); 23725605Skjc 238118541Sharti npcb = (struct natmpcb *)so->so_pcb; 23925605Skjc if (npcb == NULL) { 24025605Skjc error = EINVAL; 24125605Skjc goto out; 24225605Skjc } 24325605Skjc 24425605Skjc if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) { 24525605Skjc printf("natm: disconnected check\n"); 24625605Skjc error = EIO; 24725605Skjc goto out; 24825605Skjc } 24925605Skjc ifp = npcb->npcb_ifp; 25025605Skjc 25125605Skjc /* 25225605Skjc * disable rx 25325605Skjc */ 254118543Sharti cl.vpi = npcb->npcb_vpi; 255118543Sharti cl.vci = npcb->npcb_vci; 25625605Skjc s2 = splimp(); 25725605Skjc if (ifp->if_ioctl != NULL) 258118543Sharti ifp->if_ioctl(ifp, SIOCATMCLOSEVCC, (caddr_t)&cl); 25925605Skjc splx(s2); 26025605Skjc 26125605Skjc npcb_free(npcb, NPCB_REMOVE); 26225605Skjc soisdisconnected(so); 26325605Skjc 26425605Skjc out: 26525605Skjc splx(s); 26625605Skjc return (error); 26725605Skjc} 26825605Skjc 26925605Skjcstatic int 27025605Skjcnatm_usr_shutdown(struct socket *so) 27125605Skjc{ 27225605Skjc socantsendmore(so); 273118541Sharti return (0); 27425605Skjc} 27525605Skjc 27625605Skjcstatic int 27728270Swollmannatm_usr_send(struct socket *so, int flags, struct mbuf *m, 278118541Sharti struct sockaddr *nam, struct mbuf *control, d_thread_t *p) 27925605Skjc{ 28025605Skjc struct natmpcb *npcb; 28125605Skjc struct atm_pseudohdr *aph; 28225605Skjc int error = 0; 28325605Skjc int s = SPLSOFTNET(); 28425605Skjc int proto = so->so_proto->pr_protocol; 28525605Skjc 286118541Sharti npcb = (struct natmpcb *)so->so_pcb; 28725605Skjc if (npcb == NULL) { 28825605Skjc error = EINVAL; 28925605Skjc goto out; 29025605Skjc } 29125605Skjc 29225605Skjc if (control && control->m_len) { 29325605Skjc m_freem(control); 29425605Skjc m_freem(m); 29525605Skjc error = EINVAL; 29625605Skjc goto out; 29725605Skjc } 29825605Skjc 29925605Skjc /* 30025605Skjc * send the data. we must put an atm_pseudohdr on first 30125605Skjc */ 302111119Simp M_PREPEND(m, sizeof(*aph), M_TRYWAIT); 30325605Skjc if (m == NULL) { 30425605Skjc error = ENOBUFS; 30525605Skjc goto out; 30625605Skjc } 30725605Skjc aph = mtod(m, struct atm_pseudohdr *); 30825605Skjc ATM_PH_VPI(aph) = npcb->npcb_vpi; 30925605Skjc ATM_PH_SETVCI(aph, npcb->npcb_vci); 31025605Skjc ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0; 31125605Skjc 31225605Skjc error = atm_output(npcb->npcb_ifp, m, NULL, NULL); 31325605Skjc 31425605Skjc out: 31525605Skjc splx(s); 31625605Skjc return (error); 31725605Skjc} 31825605Skjc 31925605Skjcstatic int 32028270Swollmannatm_usr_peeraddr(struct socket *so, struct sockaddr **nam) 32125605Skjc{ 32225605Skjc struct natmpcb *npcb; 32328270Swollman struct sockaddr_natm *snatm, ssnatm; 32425605Skjc int error = 0; 32525605Skjc int s = SPLSOFTNET(); 32625605Skjc 327118541Sharti npcb = (struct natmpcb *)so->so_pcb; 32825605Skjc if (npcb == NULL) { 32925605Skjc error = EINVAL; 33025605Skjc goto out; 33125605Skjc } 33225605Skjc 33328270Swollman snatm = &ssnatm; 33425605Skjc bzero(snatm, sizeof(*snatm)); 33528270Swollman snatm->snatm_len = sizeof(*snatm); 33625605Skjc snatm->snatm_family = AF_NATM; 33741514Sarchie snprintf(snatm->snatm_if, sizeof(snatm->snatm_if), 33841514Sarchie "%s%d", npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit); 33925605Skjc snatm->snatm_vci = npcb->npcb_vci; 34025605Skjc snatm->snatm_vpi = npcb->npcb_vpi; 34128270Swollman *nam = dup_sockaddr((struct sockaddr *)snatm, 0); 34225605Skjc 34325605Skjc out: 34425605Skjc splx(s); 34525605Skjc return (error); 34625605Skjc} 34725605Skjc 34825605Skjcstatic int 34936735Sdfrnatm_usr_control(struct socket *so, u_long cmd, caddr_t arg, 350118541Sharti struct ifnet *ifp, d_thread_t *p) 35125605Skjc{ 35225605Skjc struct natmpcb *npcb; 35325605Skjc int error = 0; 35425605Skjc int s = SPLSOFTNET(); 35525605Skjc 356118541Sharti npcb = (struct natmpcb *)so->so_pcb; 35725605Skjc if (npcb == NULL) { 35825605Skjc error = EINVAL; 35925605Skjc goto out; 36025605Skjc } 36125605Skjc 362118547Sharti splx(s); 363118547Sharti if (ifp == NULL || ifp->if_ioctl == NULL) { 364118547Sharti error = EOPNOTSUPP; 365118547Sharti goto out; 36625605Skjc } 367118547Sharti return ((*ifp->if_ioctl)(ifp, cmd, arg)); 36825605Skjc 36925605Skjc out: 37025605Skjc splx(s); 37125605Skjc return (error); 37225605Skjc} 37325605Skjc 37425605Skjcstatic int 37525605Skjcnatm_usr_abort(struct socket *so) 37625605Skjc{ 377118541Sharti return (natm_usr_shutdown(so)); 37825605Skjc} 37925605Skjc 38025605Skjcstatic int 38191458Speternatm_usr_bind(struct socket *so, struct sockaddr *nam, d_thread_t *p) 38225605Skjc{ 383118541Sharti return (EOPNOTSUPP); 38425605Skjc} 38525605Skjc 38625605Skjcstatic int 38728270Swollmannatm_usr_sockaddr(struct socket *so, struct sockaddr **nam) 38825605Skjc{ 389118541Sharti return (EOPNOTSUPP); 39025605Skjc} 39125605Skjc 39225605Skjc/* xxx - should be const */ 39325605Skjcstruct pr_usrreqs natm_usrreqs = { 39425605Skjc natm_usr_abort, pru_accept_notsupp, natm_usr_attach, natm_usr_bind, 39525605Skjc natm_usr_connect, pru_connect2_notsupp, natm_usr_control, 39625605Skjc natm_usr_detach, natm_usr_disconnect, pru_listen_notsupp, 39725605Skjc natm_usr_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp, 39825605Skjc natm_usr_send, pru_sense_null, natm_usr_shutdown, 39929366Speter natm_usr_sockaddr, sosend, soreceive, sopoll 40025605Skjc}; 40125605Skjc 40225605Skjc#else /* !FREEBSD_USRREQS */ 40325605Skjc 40425605Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 40525605Skjcint natm_usrreq(so, req, m, nam, control, p) 40625605Skjc#elif defined(__FreeBSD__) 40725605Skjcint natm_usrreq(so, req, m, nam, control) 40825605Skjc#endif 40925605Skjc 41025605Skjcstruct socket *so; 41125605Skjcint req; 41225605Skjcstruct mbuf *m, *nam, *control; 41325605Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 41425605Skjcstruct proc *p; 41525605Skjc#endif 41625605Skjc 41725605Skjc{ 41825605Skjc int error = 0, s, s2; 41925605Skjc struct natmpcb *npcb; 42025605Skjc struct sockaddr_natm *snatm; 42125605Skjc struct atm_pseudoioctl api; 42225605Skjc struct atm_pseudohdr *aph; 42325605Skjc struct atm_rawioctl ario; 42425605Skjc struct ifnet *ifp; 42525605Skjc int proto = so->so_proto->pr_protocol; 42625605Skjc 42725605Skjc s = SPLSOFTNET(); 42825605Skjc 42925605Skjc npcb = (struct natmpcb *) so->so_pcb; 43025605Skjc 43125605Skjc if (npcb == NULL && req != PRU_ATTACH) { 43225605Skjc error = EINVAL; 43325605Skjc goto done; 43425605Skjc } 43525605Skjc 43625605Skjc 43725605Skjc switch (req) { 43825605Skjc case PRU_ATTACH: /* attach protocol to up */ 43925605Skjc 44025605Skjc if (npcb) { 44125605Skjc error = EISCONN; 44225605Skjc break; 44325605Skjc } 44425605Skjc 44525605Skjc if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 44625605Skjc if (proto == PROTO_NATMAAL5) 44725605Skjc error = soreserve(so, natm5_sendspace, natm5_recvspace); 44825605Skjc else 44925605Skjc error = soreserve(so, natm0_sendspace, natm0_recvspace); 45025605Skjc if (error) 45125605Skjc break; 45225605Skjc } 45325605Skjc 454111119Simp so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK)); 45525605Skjc npcb->npcb_socket = so; 45625605Skjc 45725605Skjc break; 45825605Skjc 45925605Skjc case PRU_DETACH: /* detach protocol from up */ 46025605Skjc 46125605Skjc /* 46225605Skjc * we turn on 'drain' *before* we sofree. 46325605Skjc */ 46425605Skjc 46525605Skjc npcb_free(npcb, NPCB_DESTROY); /* drain */ 46625605Skjc so->so_pcb = NULL; 46786487Sdillon sotryfree(so); 46825605Skjc 46925605Skjc break; 47025605Skjc 47125605Skjc case PRU_CONNECT: /* establish connection to peer */ 47225605Skjc 47325605Skjc /* 47425605Skjc * validate nam and npcb 47525605Skjc */ 47625605Skjc 47725605Skjc if (nam->m_len != sizeof(*snatm)) { 47825605Skjc error = EINVAL; 47925605Skjc break; 48025605Skjc } 48125605Skjc snatm = mtod(nam, struct sockaddr_natm *); 48225605Skjc if (snatm->snatm_len != sizeof(*snatm) || 48325605Skjc (npcb->npcb_flags & NPCB_FREE) == 0) { 48425605Skjc error = EINVAL; 48525605Skjc break; 48625605Skjc } 48725605Skjc if (snatm->snatm_family != AF_NATM) { 48825605Skjc error = EAFNOSUPPORT; 48925605Skjc break; 49025605Skjc } 49125605Skjc 49225605Skjc snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination 49325605Skjc since ifunit() uses strcmp */ 49425605Skjc 49525605Skjc /* 49625605Skjc * convert interface string to ifp, validate. 49725605Skjc */ 49825605Skjc 49925605Skjc ifp = ifunit(snatm->snatm_if); 50025605Skjc if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) { 50125605Skjc error = ENXIO; 50225605Skjc break; 50325605Skjc } 50425605Skjc if (ifp->if_output != atm_output) { 50525605Skjc error = EAFNOSUPPORT; 50625605Skjc break; 50725605Skjc } 50825605Skjc 50925605Skjc 51025605Skjc /* 51125605Skjc * register us with the NATM PCB layer 51225605Skjc */ 51325605Skjc 51425605Skjc if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) { 51525605Skjc error = EADDRINUSE; 51625605Skjc break; 51725605Skjc } 51825605Skjc 51925605Skjc /* 52025605Skjc * enable rx 52125605Skjc */ 52225605Skjc 52325605Skjc ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0; 52425605Skjc ATM_PH_VPI(&api.aph) = npcb->npcb_vpi; 52525605Skjc ATM_PH_SETVCI(&api.aph, npcb->npcb_vci); 52625605Skjc api.rxhand = npcb; 52725605Skjc s2 = splimp(); 52825605Skjc if (ifp->if_ioctl == NULL || 52925605Skjc ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) { 53025605Skjc splx(s2); 53125605Skjc npcb_free(npcb, NPCB_REMOVE); 53225605Skjc error = EIO; 53325605Skjc break; 53425605Skjc } 53525605Skjc splx(s2); 53625605Skjc 53725605Skjc soisconnected(so); 53825605Skjc 53925605Skjc break; 54025605Skjc 54125605Skjc case PRU_DISCONNECT: /* disconnect from peer */ 54225605Skjc 54325605Skjc if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) { 54425605Skjc printf("natm: disconnected check\n"); 54525605Skjc error = EIO; 54625605Skjc break; 54725605Skjc } 54825605Skjc ifp = npcb->npcb_ifp; 54925605Skjc 55025605Skjc /* 55125605Skjc * disable rx 55225605Skjc */ 55325605Skjc 55425605Skjc ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5; 55525605Skjc ATM_PH_VPI(&api.aph) = npcb->npcb_vpi; 55625605Skjc ATM_PH_SETVCI(&api.aph, npcb->npcb_vci); 55725605Skjc api.rxhand = npcb; 55825605Skjc s2 = splimp(); 55925605Skjc if (ifp->if_ioctl != NULL) 56025605Skjc ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api); 56125605Skjc splx(s2); 56225605Skjc 56325605Skjc npcb_free(npcb, NPCB_REMOVE); 56425605Skjc soisdisconnected(so); 56525605Skjc 56625605Skjc break; 56725605Skjc 56825605Skjc case PRU_SHUTDOWN: /* won't send any more data */ 56925605Skjc socantsendmore(so); 57025605Skjc break; 57125605Skjc 57225605Skjc case PRU_SEND: /* send this data */ 57325605Skjc if (control && control->m_len) { 57425605Skjc m_freem(control); 57525605Skjc m_freem(m); 57625605Skjc error = EINVAL; 57725605Skjc break; 57825605Skjc } 57925605Skjc 58025605Skjc /* 58125605Skjc * send the data. we must put an atm_pseudohdr on first 58225605Skjc */ 58325605Skjc 584111119Simp M_PREPEND(m, sizeof(*aph), M_TRYWAIT); 58525605Skjc if (m == NULL) { 58625605Skjc error = ENOBUFS; 58725605Skjc break; 58825605Skjc } 58925605Skjc aph = mtod(m, struct atm_pseudohdr *); 59025605Skjc ATM_PH_VPI(aph) = npcb->npcb_vpi; 59125605Skjc ATM_PH_SETVCI(aph, npcb->npcb_vci); 59225605Skjc ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0; 59325605Skjc 59425605Skjc error = atm_output(npcb->npcb_ifp, m, NULL, NULL); 59525605Skjc 59625605Skjc break; 59725605Skjc 59825605Skjc case PRU_SENSE: /* return status into m */ 59925605Skjc /* return zero? */ 60025605Skjc break; 60125605Skjc 60225605Skjc case PRU_PEERADDR: /* fetch peer's address */ 60325605Skjc snatm = mtod(nam, struct sockaddr_natm *); 60425605Skjc bzero(snatm, sizeof(*snatm)); 60525605Skjc nam->m_len = snatm->snatm_len = sizeof(*snatm); 60625605Skjc snatm->snatm_family = AF_NATM; 60725605Skjc#if defined(__NetBSD__) || defined(__OpenBSD__) 60825605Skjc bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if)); 60925605Skjc#elif defined(__FreeBSD__) 61041514Sarchie snprintf(snatm->snatm_if, sizeof(snatm->snatm_if), 61141514Sarchie "%s%d", npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit); 61225605Skjc#endif 61325605Skjc snatm->snatm_vci = npcb->npcb_vci; 61425605Skjc snatm->snatm_vpi = npcb->npcb_vpi; 61525605Skjc break; 61625605Skjc 61725605Skjc case PRU_CONTROL: /* control operations on protocol */ 61825605Skjc /* 61925605Skjc * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to 62025605Skjc * SIOCXRAWATM and pass it to the driver. 62125605Skjc */ 62225605Skjc if ((u_long)m == SIOCRAWATM) { 62325605Skjc if (npcb->npcb_ifp == NULL) { 62425605Skjc error = ENOTCONN; 62525605Skjc break; 62625605Skjc } 62725605Skjc ario.npcb = npcb; 62825605Skjc ario.rawvalue = *((int *)nam); 62925605Skjc error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, 63025605Skjc SIOCXRAWATM, (caddr_t) &ario); 63125605Skjc if (!error) { 63225605Skjc if (ario.rawvalue) 63325605Skjc npcb->npcb_flags |= NPCB_RAW; 63425605Skjc else 63525605Skjc npcb->npcb_flags &= ~(NPCB_RAW); 63625605Skjc } 63725605Skjc 63825605Skjc break; 63925605Skjc } 64025605Skjc 64125605Skjc error = EOPNOTSUPP; 64225605Skjc break; 64325605Skjc 64425605Skjc case PRU_BIND: /* bind socket to address */ 64525605Skjc case PRU_LISTEN: /* listen for connection */ 64625605Skjc case PRU_ACCEPT: /* accept connection from peer */ 64725605Skjc case PRU_CONNECT2: /* connect two sockets */ 64825605Skjc case PRU_ABORT: /* abort (fast DISCONNECT, DETATCH) */ 64925605Skjc /* (only happens if LISTEN socket) */ 65025605Skjc case PRU_RCVD: /* have taken data; more room now */ 65125605Skjc case PRU_FASTTIMO: /* 200ms timeout */ 65225605Skjc case PRU_SLOWTIMO: /* 500ms timeout */ 65325605Skjc case PRU_RCVOOB: /* retrieve out of band data */ 65425605Skjc case PRU_SENDOOB: /* send out of band data */ 65525605Skjc case PRU_PROTORCV: /* receive from below */ 65625605Skjc case PRU_PROTOSEND: /* send to below */ 65725605Skjc case PRU_SOCKADDR: /* fetch socket's address */ 65825605Skjc#ifdef DIAGNOSTIC 65925605Skjc printf("natm: PRU #%d unsupported\n", req); 66025605Skjc#endif 66125605Skjc error = EOPNOTSUPP; 66225605Skjc break; 66325605Skjc 66425605Skjc default: panic("natm usrreq"); 66525605Skjc } 66625605Skjc 66725605Skjcdone: 66825605Skjc splx(s); 66925605Skjc return(error); 67025605Skjc} 67125605Skjc 67225605Skjc#endif /* !FREEBSD_USRREQS */ 67325605Skjc 67425605Skjc/* 67525605Skjc * natmintr: splsoftnet interrupt 67625605Skjc * 67725605Skjc * note: we expect a socket pointer in rcvif rather than an interface 67825605Skjc * pointer. we can get the interface pointer from the so's PCB if 67925605Skjc * we really need it. 68025605Skjc */ 68125605Skjcvoid 682111888Sjlemonnatmintr(struct mbuf *m) 68325605Skjc{ 684118541Sharti int s; 685118541Sharti struct socket *so; 686118541Sharti struct natmpcb *npcb; 68725605Skjc 68825605Skjc#ifdef DIAGNOSTIC 689118541Sharti M_ASSERTPKTHDR(m); 69025605Skjc#endif 69125605Skjc 692118541Sharti npcb = (struct natmpcb *)m->m_pkthdr.rcvif; /* XXX: overloaded */ 693118541Sharti so = npcb->npcb_socket; 69425605Skjc 695118541Sharti s = splimp(); /* could have atm devs @ different levels */ 696118541Sharti npcb->npcb_inq--; 697118541Sharti splx(s); 69825605Skjc 699118541Sharti if (npcb->npcb_flags & NPCB_DRAIN) { 700118541Sharti m_freem(m); 701118541Sharti if (npcb->npcb_inq == 0) 702118541Sharti FREE(npcb, M_PCB); /* done! */ 703118541Sharti return; 704118541Sharti } 70525605Skjc 706118541Sharti if (npcb->npcb_flags & NPCB_FREE) { 707118541Sharti m_freem(m); /* drop */ 708118541Sharti return; 709118541Sharti } 71025605Skjc 71125605Skjc#ifdef NEED_TO_RESTORE_IFP 712118541Sharti m->m_pkthdr.rcvif = npcb->npcb_ifp; 71325605Skjc#else 71425605Skjc#ifdef DIAGNOSTIC 715118541Sharti m->m_pkthdr.rcvif = NULL; /* null it out to be safe */ 71625605Skjc#endif 71725605Skjc#endif 71825605Skjc 719118547Sharti if (sbspace(&so->so_rcv) > m->m_pkthdr.len) { 72025605Skjc#ifdef NATM_STAT 721118541Sharti natm_sookcnt++; 722118541Sharti natm_sookbytes += m->m_pkthdr.len; 72325605Skjc#endif 724118541Sharti sbappendrecord(&so->so_rcv, m); 725118541Sharti sorwakeup(so); 726118541Sharti } else { 72725605Skjc#ifdef NATM_STAT 728118541Sharti natm_sodropcnt++; 729118541Sharti natm_sodropbytes += m->m_pkthdr.len; 73025605Skjc#endif 731118541Sharti m_freem(m); 732118541Sharti } 73325605Skjc} 73425605Skjc 73525605Skjc/* 73625605Skjc * natm0_sysctl: not used, but here in case we want to add something 73725605Skjc * later... 73825605Skjc */ 739118541Shartiint 740118541Shartinatm0_sysctl(SYSCTL_HANDLER_ARGS) 74125605Skjc{ 742118541Sharti /* All sysctl names at this level are terminal. */ 743118541Sharti return (ENOENT); 74425605Skjc} 74525605Skjc 74625605Skjc/* 74725605Skjc * natm5_sysctl: not used, but here in case we want to add something 74825605Skjc * later... 74925605Skjc */ 750118541Shartiint 751118541Shartinatm5_sysctl(SYSCTL_HANDLER_ARGS) 75225605Skjc{ 753118541Sharti /* All sysctl names at this level are terminal. */ 754118541Sharti return (ENOENT); 75525605Skjc} 756