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.31 2008/09/24 14:26:39 sephe 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>
54 #include <sys/mplock2.h>
57 #include <net/if_atm.h>
58 #include <net/netisr.h>
60 #include <netinet/in.h>
64 static u_long natm5_sendspace = 16*1024;
65 static u_long natm5_recvspace = 16*1024;
67 static u_long natm0_sendspace = 16*1024;
68 static u_long natm0_recvspace = 16*1024;
73 #ifdef FREEBSD_USRREQS
76 * FreeBSD new usrreqs supersedes pr_usrreq.
80 natm_usr_attach(netmsg_t msg)
82 struct socket *so = msg->base.nm_so;
83 struct pru_attach_info *ai = msg->attach.nm_ai;
84 int proto = msg->attach.nm_proto;
89 npcb = (struct natmpcb *) so->so_pcb;
96 if (so->so_snd.ssb_hiwat == 0 || so->so_rcv.ssb_hiwat == 0) {
97 if (proto == PROTO_NATMAAL5)
98 error = soreserve(so, natm5_sendspace, natm5_recvspace,
101 error = soreserve(so, natm0_sendspace, natm0_recvspace,
107 so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
108 npcb->npcb_socket = so;
111 lwkt_replymsg(&msg->lmsg, error);
115 natm_usr_detach(netmsg_t msg)
117 struct socket *so = msg->base.nm_so;
118 struct natmpcb *npcb;
122 npcb = (struct natmpcb *) so->so_pcb;
129 * we turn on 'drain' *before* we sofree.
132 npcb_free(npcb, NPCB_DESTROY); /* drain */
133 sofree(so); /* remove pcb ref */
136 lwkt_replymsg(&msg->lmsg, error);
140 natm_usr_connect(netmsg_t msg)
142 struct socket *so = msg->base.nm_so;
143 struct sockaddr *nam = msg->connect.nm_nam;
144 struct thread *td = msg->connect.nm_td;
145 struct natmpcb *npcb;
146 struct sockaddr_natm *snatm;
147 struct atm_pseudoioctl api;
153 proto = so->so_proto->pr_protocol;
154 npcb = (struct natmpcb *) so->so_pcb;
161 * validate nam and npcb
164 snatm = (struct sockaddr_natm *)nam;
165 if (snatm->snatm_len != sizeof(*snatm) ||
166 (npcb->npcb_flags & NPCB_FREE) == 0) {
170 if (snatm->snatm_family != AF_NATM) {
171 error = EAFNOSUPPORT;
175 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination
176 since ifunit() uses strcmp */
179 * convert interface string to ifp, validate.
182 ifp = ifunit(snatm->snatm_if);
183 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
187 if (ifp->if_output != atm_output) {
188 error = EAFNOSUPPORT;
193 * register us with the NATM PCB layer
196 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
205 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
206 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
207 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
209 ifnet_serialize_all(ifp);
210 if (ifp->if_ioctl == NULL ||
211 ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api,
212 td->td_proc->p_ucred) != 0) {
213 ifnet_deserialize_all(ifp);
214 npcb_free(npcb, NPCB_REMOVE);
218 ifnet_deserialize_all(ifp);
224 lwkt_replymsg(&msg->lmsg, error);
228 natm_usr_disconnect(netmsg_t msg)
230 struct socket *so = msg->base.nm_so;
231 struct natmpcb *npcb;
232 struct atm_pseudoioctl api;
237 npcb = (struct natmpcb *) so->so_pcb;
243 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
244 kprintf("natm: disconnected check\n");
248 ifp = npcb->npcb_ifp;
254 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
255 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
256 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
258 if (ifp->if_ioctl != NULL) {
259 ifnet_serialize_all(ifp);
260 ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api, NULL);
261 ifnet_deserialize_all(ifp);
264 npcb_free(npcb, NPCB_REMOVE);
265 soisdisconnected(so);
269 lwkt_replymsg(&msg->lmsg, error);
273 natm_usr_shutdown(netmsg_t msg)
275 struct socket *so = msg->base.nm_so;
279 lwkt_replymsg(&msg->lmsg, 0);
283 natm_usr_send(netmsg_t msg)
285 struct socket *so = msg->base.nm_so;
286 struct mbuf *m = msg->send.nm_m;
287 struct mbuf *control = msg->send.nm_control;
288 struct natmpcb *npcb;
289 struct atm_pseudohdr *aph;
291 int proto = so->so_proto->pr_protocol;
295 npcb = (struct natmpcb *) so->so_pcb;
301 if (control && control->m_len) {
309 * send the data. we must put an atm_pseudohdr on first
312 M_PREPEND(m, sizeof(*aph), M_WAITOK);
317 aph = mtod(m, struct atm_pseudohdr *);
318 ATM_PH_VPI(aph) = npcb->npcb_vpi;
319 ATM_PH_SETVCI(aph, npcb->npcb_vci);
320 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
322 error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
326 lwkt_replymsg(&msg->lmsg, error);
331 natm_usr_peeraddr(netmsg_t msg)
333 struct socket *so = msg->base.nm_so;
334 struct sockaddr **nam = msg->peeraddr.nm_nam;
335 struct natmpcb *npcb;
336 struct sockaddr_natm *snatm, ssnatm;
340 npcb = (struct natmpcb *) so->so_pcb;
347 bzero(snatm, sizeof(*snatm));
348 snatm->snatm_len = sizeof(*snatm);
349 snatm->snatm_family = AF_NATM;
350 strlcpy(snatm->snatm_if, npcb->npcb_ifp->if_xname,
351 sizeof(snatm->snatm_if));
352 snatm->snatm_vci = npcb->npcb_vci;
353 snatm->snatm_vpi = npcb->npcb_vpi;
354 *nam = dup_sockaddr((struct sockaddr *)snatm);
358 lwkt_replymsg(&msg->lmsg, error);
362 natm_usr_control(netmsg_t msg)
364 struct socket *so = msg->base.nm_so;
365 u_long cmd = msg->control.nm_cmd;
366 caddr_t arg = msg->control.nm_data;
367 struct thread *td = msg->control.nm_td;
368 struct natmpcb *npcb;
369 struct atm_rawioctl ario;
372 npcb = (struct natmpcb *) so->so_pcb;
379 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
380 * SIOCXRAWATM and pass it to the driver.
382 if (cmd == SIOCRAWATM) {
383 if (npcb->npcb_ifp == NULL) {
388 ario.rawvalue = *((int *)arg);
389 ifnet_serialize_all(npcb->npcb_ifp);
390 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp,
391 SIOCXRAWATM, (caddr_t) &ario,
392 td->td_proc->p_ucred);
393 ifnet_deserialize_all(npcb->npcb_ifp);
396 npcb->npcb_flags |= NPCB_RAW;
398 npcb->npcb_flags &= ~(NPCB_RAW);
404 lwkt_replymsg(&msg->lmsg, error);
408 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
409 * will sofree() it when we return.
412 natm_usr_abort(netmsg_t msg)
414 natm_usr_shutdown(msg);
415 /* msg now invalid */
418 /* xxx - should be const */
419 struct pr_usrreqs natm_usrreqs = {
420 .pru_abort = natm_usr_abort,
421 .pru_accept = pr_generic_notsupp,
422 .pru_attach = natm_usr_attach,
423 .pru_bind = pr_generic_notsupp,
424 .pru_connect = natm_usr_connect,
425 .pru_connect2 = pr_generic_notsupp,
426 .pru_control = natm_usr_control,
427 .pru_detach = natm_usr_detach,
428 .pru_disconnect = natm_usr_disconnect,
429 .pru_listen = pr_generic_notsupp,
430 .pru_peeraddr = natm_usr_peeraddr,
431 .pru_rcvd = pr_generic_notsupp,
432 .pru_rcvoob = pr_generic_notsupp,
433 .pru_send = natm_usr_send,
434 .pru_sense = pru_sense_null,
435 .pru_shutdown = natm_usr_shutdown,
436 .pru_sockaddr = pr_generic_notsupp,
437 .pru_sosend = sosend,
438 .pru_soreceive = soreceive
441 #else /* !FREEBSD_USRREQS */
443 #if defined(__NetBSD__) || defined(__OpenBSD__)
445 natm_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
446 struct mbuf *control, struct proc *p)
447 #elif defined(__DragonFly__)
449 natm_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
450 struct mbuf *control)
454 struct natmpcb *npcb;
455 struct sockaddr_natm *snatm;
456 struct atm_pseudoioctl api;
457 struct atm_pseudohdr *aph;
458 struct atm_rawioctl ario;
460 int proto = so->so_proto->pr_protocol;
464 npcb = (struct natmpcb *) so->so_pcb;
466 if (npcb == NULL && req != PRU_ATTACH) {
473 case PRU_ATTACH: /* attach protocol to up */
480 if (so->so_snd.ssb_hiwat == 0 || so->so_rcv.ssb_hiwat == 0) {
481 if (proto == PROTO_NATMAAL5)
482 error = soreserve(so, natm5_sendspace, natm5_recvspace);
484 error = soreserve(so, natm0_sendspace, natm0_recvspace);
489 so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
490 npcb->npcb_socket = so;
494 case PRU_DETACH: /* detach protocol from up */
497 * we turn on 'drain' *before* we sofree.
501 npcb_free(npcb, NPCB_DESTROY); /* drain */
502 sofree(so); /* remove pcb ref */
506 case PRU_CONNECT: /* establish connection to peer */
509 * validate nam and npcb
512 if (nam->m_len != sizeof(*snatm)) {
516 snatm = mtod(nam, struct sockaddr_natm *);
517 if (snatm->snatm_len != sizeof(*snatm) ||
518 (npcb->npcb_flags & NPCB_FREE) == 0) {
522 if (snatm->snatm_family != AF_NATM) {
523 error = EAFNOSUPPORT;
527 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination
528 since ifunit() uses strcmp */
531 * convert interface string to ifp, validate.
534 ifp = ifunit(snatm->snatm_if);
535 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
539 if (ifp->if_output != atm_output) {
540 error = EAFNOSUPPORT;
546 * register us with the NATM PCB layer
549 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
558 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
559 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
560 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
562 ifnet_serialize_all(ifp);
563 if (ifp->if_ioctl == NULL ||
564 ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api, NULL) != 0) {
565 ifnet_deserialize_all(ifp);
566 npcb_free(npcb, NPCB_REMOVE);
570 ifnet_deserialize_all(ifp);
576 case PRU_DISCONNECT: /* disconnect from peer */
578 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
579 kprintf("natm: disconnected check\n");
583 ifp = npcb->npcb_ifp;
589 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
590 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
591 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
593 ifnet_serialize_all(ifp);
594 if (ifp->if_ioctl != NULL)
595 ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api, NULL);
596 ifnet_deserialize_all(ifp);
598 npcb_free(npcb, NPCB_REMOVE);
599 soisdisconnected(so);
603 case PRU_SHUTDOWN: /* won't send any more data */
607 case PRU_SEND: /* send this data */
608 if (control && control->m_len) {
616 * send the data. we must put an atm_pseudohdr on first
619 M_PREPEND(m, sizeof(*aph), M_WAITOK);
624 aph = mtod(m, struct atm_pseudohdr *);
625 ATM_PH_VPI(aph) = npcb->npcb_vpi;
626 ATM_PH_SETVCI(aph, npcb->npcb_vci);
627 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
629 error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
633 case PRU_SENSE: /* return status into m */
637 case PRU_PEERADDR: /* fetch peer's address */
638 snatm = mtod(nam, struct sockaddr_natm *);
639 bzero(snatm, sizeof(*snatm));
640 nam->m_len = snatm->snatm_len = sizeof(*snatm);
641 snatm->snatm_family = AF_NATM;
642 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
643 bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if));
644 #elif defined(__DragonFly__)
645 ksnprintf(snatm->snatm_if, sizeof(snatm->snatm_if),
646 "%s%d", npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit);
648 snatm->snatm_vci = npcb->npcb_vci;
649 snatm->snatm_vpi = npcb->npcb_vpi;
652 case PRU_CONTROL: /* control operations on protocol */
654 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
655 * SIOCXRAWATM and pass it to the driver.
657 if ((u_long)m == SIOCRAWATM) {
658 if (npcb->npcb_ifp == NULL) {
663 ario.rawvalue = *((int *)nam);
664 ifnet_serialize_all(npcb->npcb_ifp);
665 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, SIOCXRAWATM,
666 (caddr_t) &ario, NULL);
667 ifnet_deserialize_all(npcb->npcb_ifp);
670 npcb->npcb_flags |= NPCB_RAW;
672 npcb->npcb_flags &= ~(NPCB_RAW);
681 case PRU_BIND: /* bind socket to address */
682 case PRU_LISTEN: /* listen for connection */
683 case PRU_ACCEPT: /* accept connection from peer */
684 case PRU_CONNECT2: /* connect two sockets */
685 case PRU_ABORT: /* abort (fast DISCONNECT, DETATCH) */
686 /* (only happens if LISTEN socket) */
687 case PRU_RCVD: /* have taken data; more room now */
688 case PRU_FASTTIMO: /* 200ms timeout */
689 case PRU_SLOWTIMO: /* 500ms timeout */
690 case PRU_RCVOOB: /* retrieve out of band data */
691 case PRU_SENDOOB: /* send out of band data */
692 case PRU_PROTORCV: /* receive from below */
693 case PRU_PROTOSEND: /* send to below */
694 case PRU_SOCKADDR: /* fetch socket's address */
696 kprintf("natm: PRU #%d unsupported\n", req);
701 default: panic("natm usrreq");
709 #endif /* !FREEBSD_USRREQS */
712 * natm0_sysctl: not used, but here in case we want to add something
717 natm0_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
718 void *newp, size_t newlen)
720 /* All sysctl names at this level are terminal. */
723 return (ENOPROTOOPT);
727 * natm5_sysctl: not used, but here in case we want to add something
732 natm5_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
733 void *newp, size_t newlen)
735 /* All sysctl names at this level are terminal. */
738 return (ENOPROTOOPT);
741 static void natmintr(netmsg_t);
743 #if defined(__DragonFly__)
745 netisr_natm_setup(void *dummy __unused)
747 netisr_register(NETISR_NATM, natmintr, NULL);
749 SYSINIT(natm_setup, SI_BOOT2_KLD, SI_ORDER_ANY, netisr_natm_setup, NULL);
755 LIST_INIT(&natm_pcbs);
757 netisr_register(NETISR_NATM, natmintr, NULL);
761 * natmintr: software interrupt
763 * note: we expect a socket pointer in rcvif rather than an interface
764 * pointer. we can get the interface pointer from the so's PCB if
768 natmintr(netmsg_t msg)
770 struct mbuf *m = msg->packet.nm_packet;
772 struct natmpcb *npcb;
775 if ((m->m_flags & M_PKTHDR) == 0)
776 panic("natmintr no HDR");
781 npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
782 so = npcb->npcb_socket;
788 if (npcb->npcb_flags & NPCB_DRAIN) {
790 if (npcb->npcb_inq == 0)
791 FREE(npcb, M_PCB); /* done! */
795 if (npcb->npcb_flags & NPCB_FREE) {
796 m_freem(m); /* drop */
800 #ifdef NEED_TO_RESTORE_IFP
801 m->m_pkthdr.rcvif = npcb->npcb_ifp;
804 m->m_pkthdr.rcvif = NULL; /* null it out to be safe */
808 if (ssb_space(&so->so_rcv) > m->m_pkthdr.len ||
809 ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.ssb_cc < NPCB_RAWCC) ) {
812 natm_sookbytes += m->m_pkthdr.len;
814 sbappendrecord(&so->so_rcv.sb, m);
819 natm_sodropbytes += m->m_pkthdr.len;
825 /* msg was embedded in the mbuf, do not reply! */