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