1 /* $NetBSD: natm.c,v 1.5 1996/11/09 03:26:26 chuck Exp $ */
2 /* $FreeBSD: src/sys/netnatm/natm.c,v 1.12 2000/02/13 03:32:03 peter Exp $ */
3 /* $DragonFly: src/sys/netproto/natm/natm.c,v 1.17 2004/06/06 19:16:13 dillon Exp $ */
7 * Copyright (c) 1996 Charles D. Cranor and Washington University.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Charles D. Cranor and
21 * Washington University.
22 * 4. The name of the author may not be used to endorse or promote products
23 * derived from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 * natm.c: native mode ATM access (both aal0 and aal5).
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
45 #include <sys/sockio.h>
46 #include <sys/protosw.h>
47 #include <sys/malloc.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
52 #include <sys/thread2.h>
53 #include <sys/msgport2.h>
56 #include <net/if_atm.h>
57 #include <net/netisr.h>
59 #include <netinet/in.h>
63 static u_long natm5_sendspace = 16*1024;
64 static u_long natm5_recvspace = 16*1024;
66 static u_long natm0_sendspace = 16*1024;
67 static u_long natm0_recvspace = 16*1024;
72 #ifdef FREEBSD_USRREQS
74 * FreeBSD new usrreqs supersedes pr_usrreq.
76 static int natm_usr_attach (struct socket *, int, struct pru_attach_info *);
77 static int natm_usr_detach (struct socket *);
78 static int natm_usr_connect (struct socket *, struct sockaddr *,
80 static int natm_usr_disconnect (struct socket *);
81 static int natm_usr_shutdown (struct socket *);
82 static int natm_usr_send (struct socket *, int, struct mbuf *,
83 struct sockaddr *, struct mbuf *,
85 static int natm_usr_peeraddr (struct socket *, struct sockaddr **);
86 static int natm_usr_control (struct socket *, u_long, caddr_t,
87 struct ifnet *, struct thread *);
88 static int natm_usr_abort (struct socket *);
89 static int natm_usr_bind (struct socket *, struct sockaddr *,
91 static int natm_usr_sockaddr (struct socket *, struct sockaddr **);
94 natm_usr_attach(struct socket *so, int proto, struct pru_attach_info *ai)
100 npcb = (struct natmpcb *) so->so_pcb;
107 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
108 if (proto == PROTO_NATMAAL5)
109 error = soreserve(so, natm5_sendspace, natm5_recvspace,
112 error = soreserve(so, natm0_sendspace, natm0_recvspace,
118 so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
119 npcb->npcb_socket = so;
126 natm_usr_detach(struct socket *so)
128 struct natmpcb *npcb;
130 int s = SPLSOFTNET();
132 npcb = (struct natmpcb *) so->so_pcb;
139 * we turn on 'drain' *before* we sofree.
141 npcb_free(npcb, NPCB_DESTROY); /* drain */
150 natm_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
152 struct natmpcb *npcb;
153 struct sockaddr_natm *snatm;
154 struct atm_pseudoioctl api;
157 int s2, s = SPLSOFTNET();
158 int proto = so->so_proto->pr_protocol;
160 npcb = (struct natmpcb *) so->so_pcb;
167 * validate nam and npcb
170 snatm = (struct sockaddr_natm *)nam;
171 if (snatm->snatm_len != sizeof(*snatm) ||
172 (npcb->npcb_flags & NPCB_FREE) == 0) {
176 if (snatm->snatm_family != AF_NATM) {
177 error = EAFNOSUPPORT;
181 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination
182 since ifunit() uses strcmp */
185 * convert interface string to ifp, validate.
188 ifp = ifunit(snatm->snatm_if);
189 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
193 if (ifp->if_output != atm_output) {
194 error = EAFNOSUPPORT;
199 * register us with the NATM PCB layer
202 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
211 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
212 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
213 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
216 if (ifp->if_ioctl == NULL ||
217 ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api,
218 td->td_proc->p_ucred) != 0) {
220 npcb_free(npcb, NPCB_REMOVE);
234 natm_usr_disconnect(struct socket *so)
236 struct natmpcb *npcb;
237 struct atm_pseudoioctl api;
240 int s2, s = SPLSOFTNET();
242 npcb = (struct natmpcb *) so->so_pcb;
248 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
249 printf("natm: disconnected check\n");
253 ifp = npcb->npcb_ifp;
259 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
260 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
261 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
264 if (ifp->if_ioctl != NULL)
265 ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api, (struct ucred *)NULL);
268 npcb_free(npcb, NPCB_REMOVE);
269 soisdisconnected(so);
277 natm_usr_shutdown(struct socket *so)
284 natm_usr_send(struct socket *so, int flags, struct mbuf *m,
285 struct sockaddr *nam, struct mbuf *control, struct thread *td)
287 struct natmpcb *npcb;
288 struct atm_pseudohdr *aph;
290 int s = SPLSOFTNET();
291 int proto = so->so_proto->pr_protocol;
293 npcb = (struct natmpcb *) so->so_pcb;
299 if (control && control->m_len) {
307 * send the data. we must put an atm_pseudohdr on first
310 M_PREPEND(m, sizeof(*aph), M_WAITOK);
315 aph = mtod(m, struct atm_pseudohdr *);
316 ATM_PH_VPI(aph) = npcb->npcb_vpi;
317 ATM_PH_SETVCI(aph, npcb->npcb_vci);
318 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
320 error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
328 natm_usr_peeraddr(struct socket *so, struct sockaddr **nam)
330 struct natmpcb *npcb;
331 struct sockaddr_natm *snatm, ssnatm;
333 int s = SPLSOFTNET();
335 npcb = (struct natmpcb *) so->so_pcb;
342 bzero(snatm, sizeof(*snatm));
343 snatm->snatm_len = sizeof(*snatm);
344 snatm->snatm_family = AF_NATM;
345 strlcpy(snatm->snatm_if, npcb->npcb_ifp->if_xname,
346 sizeof(snatm->snatm_if));
347 snatm->snatm_vci = npcb->npcb_vci;
348 snatm->snatm_vpi = npcb->npcb_vpi;
349 *nam = dup_sockaddr((struct sockaddr *)snatm);
357 natm_usr_control(struct socket *so, u_long cmd, caddr_t arg,
358 struct ifnet *ifp, struct thread *td)
360 struct natmpcb *npcb;
361 struct atm_rawioctl ario;
363 int s = SPLSOFTNET();
365 npcb = (struct natmpcb *) so->so_pcb;
372 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
373 * SIOCXRAWATM and pass it to the driver.
375 if (cmd == SIOCRAWATM) {
376 if (npcb->npcb_ifp == NULL) {
381 ario.rawvalue = *((int *)arg);
382 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp,
383 SIOCXRAWATM, (caddr_t) &ario,
384 td->td_proc->p_ucred);
387 npcb->npcb_flags |= NPCB_RAW;
389 npcb->npcb_flags &= ~(NPCB_RAW);
401 natm_usr_abort(struct socket *so)
403 return natm_usr_shutdown(so);
407 natm_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
413 natm_usr_sockaddr(struct socket *so, struct sockaddr **nam)
418 /* xxx - should be const */
419 struct pr_usrreqs natm_usrreqs = {
420 natm_usr_abort, pru_accept_notsupp, natm_usr_attach, natm_usr_bind,
421 natm_usr_connect, pru_connect2_notsupp, natm_usr_control,
422 natm_usr_detach, natm_usr_disconnect, pru_listen_notsupp,
423 natm_usr_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp,
424 natm_usr_send, pru_sense_null, natm_usr_shutdown,
425 natm_usr_sockaddr, sosend, soreceive, sopoll
428 #else /* !FREEBSD_USRREQS */
430 #if defined(__NetBSD__) || defined(__OpenBSD__)
431 int natm_usrreq(so, req, m, nam, control, p)
432 #elif defined(__DragonFly__)
433 int natm_usrreq(so, req, m, nam, control)
438 struct mbuf *m, *nam, *control;
439 #if defined(__NetBSD__) || defined(__OpenBSD__)
444 int error = 0, s, s2;
445 struct natmpcb *npcb;
446 struct sockaddr_natm *snatm;
447 struct atm_pseudoioctl api;
448 struct atm_pseudohdr *aph;
449 struct atm_rawioctl ario;
451 int proto = so->so_proto->pr_protocol;
455 npcb = (struct natmpcb *) so->so_pcb;
457 if (npcb == NULL && req != PRU_ATTACH) {
464 case PRU_ATTACH: /* attach protocol to up */
471 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
472 if (proto == PROTO_NATMAAL5)
473 error = soreserve(so, natm5_sendspace, natm5_recvspace);
475 error = soreserve(so, natm0_sendspace, natm0_recvspace);
480 so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
481 npcb->npcb_socket = so;
485 case PRU_DETACH: /* detach protocol from up */
488 * we turn on 'drain' *before* we sofree.
491 npcb_free(npcb, NPCB_DESTROY); /* drain */
497 case PRU_CONNECT: /* establish connection to peer */
500 * validate nam and npcb
503 if (nam->m_len != sizeof(*snatm)) {
507 snatm = mtod(nam, struct sockaddr_natm *);
508 if (snatm->snatm_len != sizeof(*snatm) ||
509 (npcb->npcb_flags & NPCB_FREE) == 0) {
513 if (snatm->snatm_family != AF_NATM) {
514 error = EAFNOSUPPORT;
518 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination
519 since ifunit() uses strcmp */
522 * convert interface string to ifp, validate.
525 ifp = ifunit(snatm->snatm_if);
526 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
530 if (ifp->if_output != atm_output) {
531 error = EAFNOSUPPORT;
537 * register us with the NATM PCB layer
540 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
549 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
550 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
551 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
554 if (ifp->if_ioctl == NULL ||
555 ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api,
556 (struct ucred *)NULL) != 0) {
558 npcb_free(npcb, NPCB_REMOVE);
568 case PRU_DISCONNECT: /* disconnect from peer */
570 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
571 printf("natm: disconnected check\n");
575 ifp = npcb->npcb_ifp;
581 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
582 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
583 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
586 if (ifp->if_ioctl != NULL)
587 ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api, (struct ucred *)NULL);
590 npcb_free(npcb, NPCB_REMOVE);
591 soisdisconnected(so);
595 case PRU_SHUTDOWN: /* won't send any more data */
599 case PRU_SEND: /* send this data */
600 if (control && control->m_len) {
608 * send the data. we must put an atm_pseudohdr on first
611 M_PREPEND(m, sizeof(*aph), M_WAITOK);
616 aph = mtod(m, struct atm_pseudohdr *);
617 ATM_PH_VPI(aph) = npcb->npcb_vpi;
618 ATM_PH_SETVCI(aph, npcb->npcb_vci);
619 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
621 error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
625 case PRU_SENSE: /* return status into m */
629 case PRU_PEERADDR: /* fetch peer's address */
630 snatm = mtod(nam, struct sockaddr_natm *);
631 bzero(snatm, sizeof(*snatm));
632 nam->m_len = snatm->snatm_len = sizeof(*snatm);
633 snatm->snatm_family = AF_NATM;
634 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
635 bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if));
636 #elif defined(__DragonFly__)
637 snprintf(snatm->snatm_if, sizeof(snatm->snatm_if),
638 "%s%d", npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit);
640 snatm->snatm_vci = npcb->npcb_vci;
641 snatm->snatm_vpi = npcb->npcb_vpi;
644 case PRU_CONTROL: /* control operations on protocol */
646 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
647 * SIOCXRAWATM and pass it to the driver.
649 if ((u_long)m == SIOCRAWATM) {
650 if (npcb->npcb_ifp == NULL) {
655 ario.rawvalue = *((int *)nam);
656 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, SIOCXRAWATM,
657 (caddr_t) &ario, (struct ucred *)NULL);
660 npcb->npcb_flags |= NPCB_RAW;
662 npcb->npcb_flags &= ~(NPCB_RAW);
671 case PRU_BIND: /* bind socket to address */
672 case PRU_LISTEN: /* listen for connection */
673 case PRU_ACCEPT: /* accept connection from peer */
674 case PRU_CONNECT2: /* connect two sockets */
675 case PRU_ABORT: /* abort (fast DISCONNECT, DETATCH) */
676 /* (only happens if LISTEN socket) */
677 case PRU_RCVD: /* have taken data; more room now */
678 case PRU_FASTTIMO: /* 200ms timeout */
679 case PRU_SLOWTIMO: /* 500ms timeout */
680 case PRU_RCVOOB: /* retrieve out of band data */
681 case PRU_SENDOOB: /* send out of band data */
682 case PRU_PROTORCV: /* receive from below */
683 case PRU_PROTOSEND: /* send to below */
684 case PRU_SOCKADDR: /* fetch socket's address */
686 printf("natm: PRU #%d unsupported\n", req);
691 default: panic("natm usrreq");
699 #endif /* !FREEBSD_USRREQS */
702 * natm0_sysctl: not used, but here in case we want to add something
706 int natm0_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
707 void *newp, size_t newlen)
709 /* All sysctl names at this level are terminal. */
712 return (ENOPROTOOPT);
716 * natm5_sysctl: not used, but here in case we want to add something
720 int natm5_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
721 void *newp, size_t newlen)
723 /* All sysctl names at this level are terminal. */
726 return (ENOPROTOOPT);
729 static int natmintr(struct netmsg *);
731 #if defined(__DragonFly__)
733 netisr_natm_setup(void *dummy __unused)
736 netisr_register(NETISR_NATM, cpu0_portfn, natmintr);
738 SYSINIT(natm_setup, SI_SUB_CPU, SI_ORDER_ANY, netisr_natm_setup, NULL);
744 LIST_INIT(&natm_pcbs);
746 netisr_register(NETISR_NATM, cpu0_portfn, natmintr);
750 * natmintr: splsoftnet interrupt
752 * note: we expect a socket pointer in rcvif rather than an interface
753 * pointer. we can get the interface pointer from the so's PCB if
757 natmintr(struct netmsg *msg)
759 struct mbuf *m = ((struct netmsg_packet *)msg)->nm_packet;
762 struct natmpcb *npcb;
765 if ((m->m_flags & M_PKTHDR) == 0)
766 panic("natmintr no HDR");
769 npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
770 so = npcb->npcb_socket;
772 s = splimp(); /* could have atm devs @ different levels */
776 if (npcb->npcb_flags & NPCB_DRAIN) {
778 if (npcb->npcb_inq == 0)
779 FREE(npcb, M_PCB); /* done! */
783 if (npcb->npcb_flags & NPCB_FREE) {
784 m_freem(m); /* drop */
788 #ifdef NEED_TO_RESTORE_IFP
789 m->m_pkthdr.rcvif = npcb->npcb_ifp;
792 m->m_pkthdr.rcvif = NULL; /* null it out to be safe */
796 if (sbspace(&so->so_rcv) > m->m_pkthdr.len ||
797 ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) {
800 natm_sookbytes += m->m_pkthdr.len;
802 sbappendrecord(&so->so_rcv, m);
807 natm_sodropbytes += m->m_pkthdr.len;
812 lwkt_replymsg(&msg->nm_lmsg, 0);