HAMMER 60I/Many: Mirroring
[dragonfly.git] / sys / netproto / natm / natm.c
blobe25dcff654dce465041439a6b104ba6aeae13767
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.29 2008/05/14 11:59:24 sephe Exp $ */
5 /*
7 * Copyright (c) 1996 Charles D. Cranor and Washington University.
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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>
44 #include <sys/proc.h>
45 #include <sys/sockio.h>
46 #include <sys/protosw.h>
47 #include <sys/malloc.h>
48 #include <sys/mbuf.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
52 #include <sys/thread2.h>
53 #include <sys/msgport2.h>
55 #include <net/if.h>
56 #include <net/if_atm.h>
57 #include <net/netisr.h>
59 #include <netinet/in.h>
61 #include "natm.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;
70 * user requests
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 *,
79 struct thread *);
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 *,
84 struct thread *);
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 *,
90 struct thread *);
91 static int natm_usr_sockaddr (struct socket *, struct sockaddr **);
93 static int
94 natm_usr_attach(struct socket *so, int proto, struct pru_attach_info *ai)
96 struct natmpcb *npcb;
97 int error = 0;
99 crit_enter();
100 npcb = (struct natmpcb *) so->so_pcb;
102 if (npcb) {
103 error = EISCONN;
104 goto out;
107 if (so->so_snd.ssb_hiwat == 0 || so->so_rcv.ssb_hiwat == 0) {
108 if (proto == PROTO_NATMAAL5)
109 error = soreserve(so, natm5_sendspace, natm5_recvspace,
110 ai->sb_rlimit);
111 else
112 error = soreserve(so, natm0_sendspace, natm0_recvspace,
113 ai->sb_rlimit);
114 if (error)
115 goto out;
118 so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
119 npcb->npcb_socket = so;
120 out:
121 crit_exit();
122 return (error);
125 static int
126 natm_usr_detach(struct socket *so)
128 struct natmpcb *npcb;
129 int error = 0;
131 crit_enter();
132 npcb = (struct natmpcb *) so->so_pcb;
133 if (npcb == NULL) {
134 error = EINVAL;
135 goto out;
139 * we turn on 'drain' *before* we sofree.
141 npcb_free(npcb, NPCB_DESTROY); /* drain */
142 so->so_pcb = NULL;
143 sofree(so);
144 out:
145 crit_exit();
146 return (error);
149 static int
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;
155 struct ifnet *ifp;
156 int error = 0;
157 int proto;
159 crit_enter();
160 proto = so->so_proto->pr_protocol;
161 npcb = (struct natmpcb *) so->so_pcb;
162 if (npcb == NULL) {
163 error = EINVAL;
164 goto out;
168 * validate nam and npcb
171 snatm = (struct sockaddr_natm *)nam;
172 if (snatm->snatm_len != sizeof(*snatm) ||
173 (npcb->npcb_flags & NPCB_FREE) == 0) {
174 error = EINVAL;
175 goto out;
177 if (snatm->snatm_family != AF_NATM) {
178 error = EAFNOSUPPORT;
179 goto out;
182 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination
183 since ifunit() uses strcmp */
186 * convert interface string to ifp, validate.
189 ifp = ifunit(snatm->snatm_if);
190 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
191 error = ENXIO;
192 goto out;
194 if (ifp->if_output != atm_output) {
195 error = EAFNOSUPPORT;
196 goto out;
200 * register us with the NATM PCB layer
203 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
204 error = EADDRINUSE;
205 goto out;
209 * enable rx
212 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
213 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
214 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
215 api.rxhand = npcb;
216 lwkt_serialize_enter(ifp->if_serializer);
217 if (ifp->if_ioctl == NULL ||
218 ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api,
219 td->td_proc->p_ucred) != 0) {
220 lwkt_serialize_exit(ifp->if_serializer);
221 npcb_free(npcb, NPCB_REMOVE);
222 error = EIO;
223 goto out;
225 lwkt_serialize_exit(ifp->if_serializer);
227 soisconnected(so);
229 out:
230 crit_exit();
231 return (error);
234 static int
235 natm_usr_disconnect(struct socket *so)
237 struct natmpcb *npcb;
238 struct atm_pseudoioctl api;
239 struct ifnet *ifp;
240 int error = 0;
242 crit_enter();
243 npcb = (struct natmpcb *) so->so_pcb;
244 if (npcb == NULL) {
245 error = EINVAL;
246 goto out;
249 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
250 kprintf("natm: disconnected check\n");
251 error = EIO;
252 goto out;
254 ifp = npcb->npcb_ifp;
257 * disable rx
260 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
261 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
262 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
263 api.rxhand = npcb;
264 if (ifp->if_ioctl != NULL) {
265 lwkt_serialize_enter(ifp->if_serializer);
266 ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api, (struct ucred *)NULL);
267 lwkt_serialize_exit(ifp->if_serializer);
270 npcb_free(npcb, NPCB_REMOVE);
271 soisdisconnected(so);
273 out:
274 crit_exit();
275 return (error);
278 static int
279 natm_usr_shutdown(struct socket *so)
281 socantsendmore(so);
282 return 0;
285 static int
286 natm_usr_send(struct socket *so, int flags, struct mbuf *m,
287 struct sockaddr *nam, struct mbuf *control, struct thread *td)
289 struct natmpcb *npcb;
290 struct atm_pseudohdr *aph;
291 int error = 0;
292 int proto = so->so_proto->pr_protocol;
294 crit_enter();
296 npcb = (struct natmpcb *) so->so_pcb;
297 if (npcb == NULL) {
298 error = EINVAL;
299 goto out;
302 if (control && control->m_len) {
303 m_freem(control);
304 m_freem(m);
305 error = EINVAL;
306 goto out;
310 * send the data. we must put an atm_pseudohdr on first
313 M_PREPEND(m, sizeof(*aph), M_WAITOK);
314 if (m == NULL) {
315 error = ENOBUFS;
316 goto out;
318 aph = mtod(m, struct atm_pseudohdr *);
319 ATM_PH_VPI(aph) = npcb->npcb_vpi;
320 ATM_PH_SETVCI(aph, npcb->npcb_vci);
321 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
323 error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
325 out:
326 crit_exit();
327 return (error);
330 static int
331 natm_usr_peeraddr(struct socket *so, struct sockaddr **nam)
333 struct natmpcb *npcb;
334 struct sockaddr_natm *snatm, ssnatm;
335 int error = 0;
337 crit_enter();
338 npcb = (struct natmpcb *) so->so_pcb;
339 if (npcb == NULL) {
340 error = EINVAL;
341 goto out;
344 snatm = &ssnatm;
345 bzero(snatm, sizeof(*snatm));
346 snatm->snatm_len = sizeof(*snatm);
347 snatm->snatm_family = AF_NATM;
348 strlcpy(snatm->snatm_if, npcb->npcb_ifp->if_xname,
349 sizeof(snatm->snatm_if));
350 snatm->snatm_vci = npcb->npcb_vci;
351 snatm->snatm_vpi = npcb->npcb_vpi;
352 *nam = dup_sockaddr((struct sockaddr *)snatm);
354 out:
355 crit_exit();
356 return (error);
359 static int
360 natm_usr_control(struct socket *so, u_long cmd, caddr_t arg,
361 struct ifnet *ifp, struct thread *td)
363 struct natmpcb *npcb;
364 struct atm_rawioctl ario;
365 int error = 0;
367 npcb = (struct natmpcb *) so->so_pcb;
368 if (npcb == NULL) {
369 error = EINVAL;
370 goto out;
374 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
375 * SIOCXRAWATM and pass it to the driver.
377 if (cmd == SIOCRAWATM) {
378 if (npcb->npcb_ifp == NULL) {
379 error = ENOTCONN;
380 goto out;
382 ario.npcb = npcb;
383 ario.rawvalue = *((int *)arg);
384 lwkt_serialize_enter(ifp->if_serializer);
385 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp,
386 SIOCXRAWATM, (caddr_t) &ario,
387 td->td_proc->p_ucred);
388 lwkt_serialize_exit(ifp->if_serializer);
389 if (!error) {
390 if (ario.rawvalue)
391 npcb->npcb_flags |= NPCB_RAW;
392 else
393 npcb->npcb_flags &= ~(NPCB_RAW);
396 else
397 error = EOPNOTSUPP;
398 out:
399 return (error);
402 static int
403 natm_usr_abort(struct socket *so)
405 return natm_usr_shutdown(so);
408 static int
409 natm_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
411 return EOPNOTSUPP;
414 static int
415 natm_usr_sockaddr(struct socket *so, struct sockaddr **nam)
417 return EOPNOTSUPP;
420 /* xxx - should be const */
421 struct pr_usrreqs natm_usrreqs = {
422 .pru_abort = natm_usr_abort,
423 .pru_accept = pru_accept_notsupp,
424 .pru_attach = natm_usr_attach,
425 .pru_bind = natm_usr_bind,
426 .pru_connect = natm_usr_connect,
427 .pru_connect2 = pru_connect2_notsupp,
428 .pru_control = natm_usr_control,
429 .pru_detach = natm_usr_detach,
430 .pru_disconnect = natm_usr_disconnect,
431 .pru_listen = pru_listen_notsupp,
432 .pru_peeraddr = natm_usr_peeraddr,
433 .pru_rcvd = pru_rcvd_notsupp,
434 .pru_rcvoob = pru_rcvoob_notsupp,
435 .pru_send = natm_usr_send,
436 .pru_sense = pru_sense_null,
437 .pru_shutdown = natm_usr_shutdown,
438 .pru_sockaddr = natm_usr_sockaddr,
439 .pru_sosend = sosend,
440 .pru_soreceive = soreceive,
441 .pru_sopoll = sopoll
444 #else /* !FREEBSD_USRREQS */
446 #if defined(__NetBSD__) || defined(__OpenBSD__)
448 natm_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
449 struct mbuf *control, struct proc *p)
450 #elif defined(__DragonFly__)
452 natm_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
453 struct mbuf *control)
454 #endif
456 int error = 0;
457 struct natmpcb *npcb;
458 struct sockaddr_natm *snatm;
459 struct atm_pseudoioctl api;
460 struct atm_pseudohdr *aph;
461 struct atm_rawioctl ario;
462 struct ifnet *ifp;
463 int proto = so->so_proto->pr_protocol;
465 crit_enter();
467 npcb = (struct natmpcb *) so->so_pcb;
469 if (npcb == NULL && req != PRU_ATTACH) {
470 error = EINVAL;
471 goto done;
475 switch (req) {
476 case PRU_ATTACH: /* attach protocol to up */
478 if (npcb) {
479 error = EISCONN;
480 break;
483 if (so->so_snd.ssb_hiwat == 0 || so->so_rcv.ssb_hiwat == 0) {
484 if (proto == PROTO_NATMAAL5)
485 error = soreserve(so, natm5_sendspace, natm5_recvspace);
486 else
487 error = soreserve(so, natm0_sendspace, natm0_recvspace);
488 if (error)
489 break;
492 so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
493 npcb->npcb_socket = so;
495 break;
497 case PRU_DETACH: /* detach protocol from up */
500 * we turn on 'drain' *before* we sofree.
503 npcb_free(npcb, NPCB_DESTROY); /* drain */
504 so->so_pcb = NULL;
505 sofree(so);
507 break;
509 case PRU_CONNECT: /* establish connection to peer */
512 * validate nam and npcb
515 if (nam->m_len != sizeof(*snatm)) {
516 error = EINVAL;
517 break;
519 snatm = mtod(nam, struct sockaddr_natm *);
520 if (snatm->snatm_len != sizeof(*snatm) ||
521 (npcb->npcb_flags & NPCB_FREE) == 0) {
522 error = EINVAL;
523 break;
525 if (snatm->snatm_family != AF_NATM) {
526 error = EAFNOSUPPORT;
527 break;
530 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination
531 since ifunit() uses strcmp */
534 * convert interface string to ifp, validate.
537 ifp = ifunit(snatm->snatm_if);
538 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
539 error = ENXIO;
540 break;
542 if (ifp->if_output != atm_output) {
543 error = EAFNOSUPPORT;
544 break;
549 * register us with the NATM PCB layer
552 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
553 error = EADDRINUSE;
554 break;
558 * enable rx
561 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
562 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
563 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
564 api.rxhand = npcb;
565 lwkt_serialize_enter(ifp->if_serializer);
566 if (ifp->if_ioctl == NULL ||
567 ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api,
568 (struct ucred *)NULL) != 0) {
569 lwkt_serialize_exit(ifp->if_serializer);
570 npcb_free(npcb, NPCB_REMOVE);
571 error = EIO;
572 break;
574 lwkt_serialize_exit(ifp->if_serializer);
576 soisconnected(so);
578 break;
580 case PRU_DISCONNECT: /* disconnect from peer */
582 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
583 kprintf("natm: disconnected check\n");
584 error = EIO;
585 break;
587 ifp = npcb->npcb_ifp;
590 * disable rx
593 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
594 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
595 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
596 api.rxhand = npcb;
597 lwkt_serialize_enter(ifp->if_serializer);
598 if (ifp->if_ioctl != NULL)
599 ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api, (struct ucred *)NULL);
600 lwkt_serialize_exit(ifp->if_serializer);
602 npcb_free(npcb, NPCB_REMOVE);
603 soisdisconnected(so);
605 break;
607 case PRU_SHUTDOWN: /* won't send any more data */
608 socantsendmore(so);
609 break;
611 case PRU_SEND: /* send this data */
612 if (control && control->m_len) {
613 m_freem(control);
614 m_freem(m);
615 error = EINVAL;
616 break;
620 * send the data. we must put an atm_pseudohdr on first
623 M_PREPEND(m, sizeof(*aph), M_WAITOK);
624 if (m == NULL) {
625 error = ENOBUFS;
626 break;
628 aph = mtod(m, struct atm_pseudohdr *);
629 ATM_PH_VPI(aph) = npcb->npcb_vpi;
630 ATM_PH_SETVCI(aph, npcb->npcb_vci);
631 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
633 error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
635 break;
637 case PRU_SENSE: /* return status into m */
638 /* return zero? */
639 break;
641 case PRU_PEERADDR: /* fetch peer's address */
642 snatm = mtod(nam, struct sockaddr_natm *);
643 bzero(snatm, sizeof(*snatm));
644 nam->m_len = snatm->snatm_len = sizeof(*snatm);
645 snatm->snatm_family = AF_NATM;
646 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
647 bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if));
648 #elif defined(__DragonFly__)
649 ksnprintf(snatm->snatm_if, sizeof(snatm->snatm_if),
650 "%s%d", npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit);
651 #endif
652 snatm->snatm_vci = npcb->npcb_vci;
653 snatm->snatm_vpi = npcb->npcb_vpi;
654 break;
656 case PRU_CONTROL: /* control operations on protocol */
658 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
659 * SIOCXRAWATM and pass it to the driver.
661 if ((u_long)m == SIOCRAWATM) {
662 if (npcb->npcb_ifp == NULL) {
663 error = ENOTCONN;
664 break;
666 ario.npcb = npcb;
667 ario.rawvalue = *((int *)nam);
668 lwkt_serialize_enter(npcb->npcb_ifp->if_serializer);
669 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, SIOCXRAWATM,
670 (caddr_t) &ario, (struct ucred *)NULL);
671 lwkt_serialize_exit(npcb->npcb_ifp->if_serializer);
672 if (!error) {
673 if (ario.rawvalue)
674 npcb->npcb_flags |= NPCB_RAW;
675 else
676 npcb->npcb_flags &= ~(NPCB_RAW);
679 break;
682 error = EOPNOTSUPP;
683 break;
685 case PRU_BIND: /* bind socket to address */
686 case PRU_LISTEN: /* listen for connection */
687 case PRU_ACCEPT: /* accept connection from peer */
688 case PRU_CONNECT2: /* connect two sockets */
689 case PRU_ABORT: /* abort (fast DISCONNECT, DETATCH) */
690 /* (only happens if LISTEN socket) */
691 case PRU_RCVD: /* have taken data; more room now */
692 case PRU_FASTTIMO: /* 200ms timeout */
693 case PRU_SLOWTIMO: /* 500ms timeout */
694 case PRU_RCVOOB: /* retrieve out of band data */
695 case PRU_SENDOOB: /* send out of band data */
696 case PRU_PROTORCV: /* receive from below */
697 case PRU_PROTOSEND: /* send to below */
698 case PRU_SOCKADDR: /* fetch socket's address */
699 #ifdef DIAGNOSTIC
700 kprintf("natm: PRU #%d unsupported\n", req);
701 #endif
702 error = EOPNOTSUPP;
703 break;
705 default: panic("natm usrreq");
708 done:
709 crit_exit();
710 return(error);
713 #endif /* !FREEBSD_USRREQS */
716 * natm0_sysctl: not used, but here in case we want to add something
717 * later...
721 natm0_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
722 void *newp, size_t newlen)
724 /* All sysctl names at this level are terminal. */
725 if (namelen != 1)
726 return (ENOTDIR);
727 return (ENOPROTOOPT);
731 * natm5_sysctl: not used, but here in case we want to add something
732 * later...
736 natm5_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
737 void *newp, size_t newlen)
739 /* All sysctl names at this level are terminal. */
740 if (namelen != 1)
741 return (ENOTDIR);
742 return (ENOPROTOOPT);
745 static void natmintr(struct netmsg *);
747 #if defined(__DragonFly__)
748 static void
749 netisr_natm_setup(void *dummy __unused)
751 netisr_register(NETISR_NATM, cpu0_portfn, natmintr);
753 SYSINIT(natm_setup, SI_BOOT2_KLD, SI_ORDER_ANY, netisr_natm_setup, NULL);
754 #endif
756 void
757 natm_init(void)
759 LIST_INIT(&natm_pcbs);
761 netisr_register(NETISR_NATM, cpu0_portfn, natmintr);
765 * natmintr: software interrupt
767 * note: we expect a socket pointer in rcvif rather than an interface
768 * pointer. we can get the interface pointer from the so's PCB if
769 * we really need it.
771 static void
772 natmintr(struct netmsg *msg)
774 struct mbuf *m = ((struct netmsg_packet *)msg)->nm_packet;
775 struct socket *so;
776 struct natmpcb *npcb;
778 #ifdef DIAGNOSTIC
779 if ((m->m_flags & M_PKTHDR) == 0)
780 panic("natmintr no HDR");
781 #endif
783 npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
784 so = npcb->npcb_socket;
786 crit_enter();
787 npcb->npcb_inq--;
788 crit_exit();
790 if (npcb->npcb_flags & NPCB_DRAIN) {
791 m_freem(m);
792 if (npcb->npcb_inq == 0)
793 FREE(npcb, M_PCB); /* done! */
794 goto out;
797 if (npcb->npcb_flags & NPCB_FREE) {
798 m_freem(m); /* drop */
799 goto out;
802 #ifdef NEED_TO_RESTORE_IFP
803 m->m_pkthdr.rcvif = npcb->npcb_ifp;
804 #else
805 #ifdef DIAGNOSTIC
806 m->m_pkthdr.rcvif = NULL; /* null it out to be safe */
807 #endif
808 #endif
810 if (ssb_space(&so->so_rcv) > m->m_pkthdr.len ||
811 ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.ssb_cc < NPCB_RAWCC) ) {
812 #ifdef NATM_STAT
813 natm_sookcnt++;
814 natm_sookbytes += m->m_pkthdr.len;
815 #endif
816 sbappendrecord(&so->so_rcv.sb, m);
817 sorwakeup(so);
818 } else {
819 #ifdef NATM_STAT
820 natm_sodropcnt++;
821 natm_sodropbytes += m->m_pkthdr.len;
822 #endif
823 m_freem(m);
825 out:
827 /* msg was embedded in the mbuf, do not reply! */