atm_output() must be serialized.
[dragonfly.git] / sys / netproto / natm / natm.c
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.28 2008/04/05 05:30:29 sephe Exp $ */
4
5 /*
6  *
7  * Copyright (c) 1996 Charles D. Cranor and Washington University.
8  * All rights reserved.
9  *
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.
24  *
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.
35  */
36
37 /*
38  * natm.c: native mode ATM access (both aal0 and aal5).
39  */
40
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>
51
52 #include <sys/thread2.h>
53 #include <sys/msgport2.h>
54
55 #include <net/if.h>
56 #include <net/if_atm.h>
57 #include <net/netisr.h>
58
59 #include <netinet/in.h>
60
61 #include "natm.h"
62
63 static u_long natm5_sendspace = 16*1024;
64 static u_long natm5_recvspace = 16*1024;
65
66 static u_long natm0_sendspace = 16*1024;
67 static u_long natm0_recvspace = 16*1024;
68
69 /*
70  * user requests
71  */
72 #ifdef FREEBSD_USRREQS
73 /*
74  * FreeBSD new usrreqs supersedes pr_usrreq.
75  */
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 **);
92
93 static int
94 natm_usr_attach(struct socket *so, int proto, struct pru_attach_info *ai)
95 {
96     struct natmpcb *npcb;
97     int error = 0;
98
99     crit_enter();
100     npcb = (struct natmpcb *) so->so_pcb;
101
102     if (npcb) {
103         error = EISCONN;
104         goto out;
105     }
106
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;
116     }
117
118     so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
119     npcb->npcb_socket = so;
120  out:
121     crit_exit();
122     return (error);
123 }
124
125 static int
126 natm_usr_detach(struct socket *so)
127 {
128     struct natmpcb *npcb;
129     int error = 0;
130
131     crit_enter();
132     npcb = (struct natmpcb *) so->so_pcb;
133     if (npcb == NULL) {
134         error = EINVAL;
135         goto out;
136     }
137
138     /*
139      * we turn on 'drain' *before* we sofree.
140      */
141     npcb_free(npcb, NPCB_DESTROY);      /* drain */
142     so->so_pcb = NULL;
143     sofree(so);
144  out:
145     crit_exit();
146     return (error);
147 }
148
149 static int
150 natm_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
151 {
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;
158
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;
165     }
166
167     /*
168      * validate nam and npcb
169      */
170
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;
176     }
177     if (snatm->snatm_family != AF_NATM) {
178         error = EAFNOSUPPORT;
179         goto out;
180     }
181
182     snatm->snatm_if[IFNAMSIZ-1] = '\0';  /* XXX ensure null termination
183                                             since ifunit() uses strcmp */
184
185     /*
186      * convert interface string to ifp, validate.
187      */
188
189     ifp = ifunit(snatm->snatm_if);
190     if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
191         error = ENXIO;
192         goto out;
193     }
194     if (ifp->if_output != atm_output) {
195         error = EAFNOSUPPORT;
196         goto out;
197     }
198
199     /*
200      * register us with the NATM PCB layer
201      */
202
203     if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
204         error = EADDRINUSE;
205         goto out;
206     }
207
208     /*
209      * enable rx
210      */
211
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;
224     }
225     lwkt_serialize_exit(ifp->if_serializer);
226
227     soisconnected(so);
228
229  out:
230     crit_exit();
231     return (error);
232 }
233
234 static int
235 natm_usr_disconnect(struct socket *so)
236 {
237     struct natmpcb *npcb;
238     struct atm_pseudoioctl api;
239     struct ifnet *ifp;
240     int error = 0;
241
242     crit_enter();
243     npcb = (struct natmpcb *) so->so_pcb;
244     if (npcb == NULL) {
245         error = EINVAL;
246         goto out;
247     }
248
249     if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
250         kprintf("natm: disconnected check\n");
251         error = EIO;
252         goto out;
253     }
254     ifp = npcb->npcb_ifp;
255
256     /*
257      * disable rx
258      */
259
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);
268     }
269
270     npcb_free(npcb, NPCB_REMOVE);
271     soisdisconnected(so);
272
273  out:
274     crit_exit();
275     return (error);
276 }
277
278 static int
279 natm_usr_shutdown(struct socket *so)
280 {
281     socantsendmore(so);
282     return 0;
283 }
284
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)
288 {
289     struct natmpcb *npcb;
290     struct atm_pseudohdr *aph;
291     int error = 0;
292     int proto = so->so_proto->pr_protocol;
293
294     crit_enter();
295
296     npcb = (struct natmpcb *) so->so_pcb;
297     if (npcb == NULL) {
298         error = EINVAL;
299         goto out;
300     }
301
302     if (control && control->m_len) {
303         m_freem(control);
304         m_freem(m);
305         error = EINVAL;
306         goto out;
307     }
308
309     /*
310      * send the data.   we must put an atm_pseudohdr on first
311      */
312
313     M_PREPEND(m, sizeof(*aph), M_WAITOK);
314     if (m == NULL) {
315         error = ENOBUFS;
316         goto out;
317     }
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;
322
323     lwkt_serialize_enter(npcb->npcb_ifp->if_serializer);
324     error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
325     lwkt_serialize_exit(npcb->npcb_ifp->if_serializer);
326
327  out:
328     crit_exit();
329     return (error);
330 }
331
332 static int
333 natm_usr_peeraddr(struct socket *so, struct sockaddr **nam)
334 {
335     struct natmpcb *npcb;
336     struct sockaddr_natm *snatm, ssnatm;
337     int error = 0;
338
339     crit_enter();
340     npcb = (struct natmpcb *) so->so_pcb;
341     if (npcb == NULL) {
342         error = EINVAL;
343         goto out;
344     }
345
346     snatm = &ssnatm;
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);
355
356  out:
357     crit_exit();
358     return (error);
359 }
360
361 static int
362 natm_usr_control(struct socket *so, u_long cmd, caddr_t arg,
363                  struct ifnet *ifp, struct thread *td)
364 {
365     struct natmpcb *npcb;
366     struct atm_rawioctl ario;
367     int error = 0;
368
369     npcb = (struct natmpcb *) so->so_pcb;
370     if (npcb == NULL) {
371         error = EINVAL;
372         goto out;
373     }
374
375     /*
376      * raw atm ioctl.   comes in as a SIOCRAWATM.   we convert it to
377      * SIOCXRAWATM and pass it to the driver.
378      */
379     if (cmd == SIOCRAWATM) {
380         if (npcb->npcb_ifp == NULL) {
381             error = ENOTCONN;
382             goto out;
383         }
384         ario.npcb = npcb;
385         ario.rawvalue = *((int *)arg);
386         lwkt_serialize_enter(ifp->if_serializer);
387         error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, 
388                                          SIOCXRAWATM, (caddr_t) &ario,
389                                          td->td_proc->p_ucred);
390         lwkt_serialize_exit(ifp->if_serializer);
391         if (!error) {
392             if (ario.rawvalue) 
393                 npcb->npcb_flags |= NPCB_RAW;
394             else
395                 npcb->npcb_flags &= ~(NPCB_RAW);
396         }
397     }
398     else
399         error = EOPNOTSUPP;
400  out:
401     return (error);
402 }
403
404 static int
405 natm_usr_abort(struct socket *so)
406 {
407     return natm_usr_shutdown(so);
408 }
409
410 static int
411 natm_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
412 {
413     return EOPNOTSUPP;
414 }
415
416 static int
417 natm_usr_sockaddr(struct socket *so, struct sockaddr **nam)
418 {
419     return EOPNOTSUPP;
420 }
421
422 /* xxx - should be const */
423 struct pr_usrreqs natm_usrreqs = {
424         .pru_abort = natm_usr_abort,
425         .pru_accept = pru_accept_notsupp,
426         .pru_attach = natm_usr_attach,
427         .pru_bind = natm_usr_bind,
428         .pru_connect = natm_usr_connect,
429         .pru_connect2 = pru_connect2_notsupp,
430         .pru_control = natm_usr_control,
431         .pru_detach = natm_usr_detach,
432         .pru_disconnect = natm_usr_disconnect,
433         .pru_listen = pru_listen_notsupp,
434         .pru_peeraddr = natm_usr_peeraddr,
435         .pru_rcvd = pru_rcvd_notsupp,
436         .pru_rcvoob = pru_rcvoob_notsupp,
437         .pru_send = natm_usr_send,
438         .pru_sense = pru_sense_null,
439         .pru_shutdown = natm_usr_shutdown,
440         .pru_sockaddr = natm_usr_sockaddr,
441         .pru_sosend = sosend,
442         .pru_soreceive = soreceive,
443         .pru_sopoll = sopoll
444 };
445
446 #else  /* !FREEBSD_USRREQS */
447
448 #if defined(__NetBSD__) || defined(__OpenBSD__)
449 int
450 natm_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
451             struct mbuf *control, struct proc *p)
452 #elif defined(__DragonFly__)
453 int
454 natm_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
455             struct mbuf *control)
456 #endif
457 {
458   int error = 0;
459   struct natmpcb *npcb;
460   struct sockaddr_natm *snatm;
461   struct atm_pseudoioctl api;
462   struct atm_pseudohdr *aph;
463   struct atm_rawioctl ario;
464   struct ifnet *ifp;
465   int proto = so->so_proto->pr_protocol;
466
467   crit_enter();
468
469   npcb = (struct natmpcb *) so->so_pcb;
470
471   if (npcb == NULL && req != PRU_ATTACH) {
472     error = EINVAL;
473     goto done;
474   }
475     
476
477   switch (req) {
478     case PRU_ATTACH:                    /* attach protocol to up */
479
480       if (npcb) {
481         error = EISCONN;
482         break;
483       }
484
485       if (so->so_snd.ssb_hiwat == 0 || so->so_rcv.ssb_hiwat == 0) {
486         if (proto == PROTO_NATMAAL5) 
487           error = soreserve(so, natm5_sendspace, natm5_recvspace);
488         else
489           error = soreserve(so, natm0_sendspace, natm0_recvspace);
490         if (error)
491           break;
492       }
493
494       so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
495       npcb->npcb_socket = so;
496
497       break;
498
499     case PRU_DETACH:                    /* detach protocol from up */
500
501       /*
502        * we turn on 'drain' *before* we sofree.
503        */
504
505       npcb_free(npcb, NPCB_DESTROY);    /* drain */
506       so->so_pcb = NULL;
507       sofree(so);
508
509       break;
510
511     case PRU_CONNECT:                   /* establish connection to peer */
512
513       /*
514        * validate nam and npcb
515        */
516
517       if (nam->m_len != sizeof(*snatm)) {
518         error = EINVAL;
519         break;
520       }
521       snatm = mtod(nam, struct sockaddr_natm *);
522       if (snatm->snatm_len != sizeof(*snatm) ||
523                 (npcb->npcb_flags & NPCB_FREE) == 0) {
524         error = EINVAL;
525         break;
526       }
527       if (snatm->snatm_family != AF_NATM) {
528         error = EAFNOSUPPORT;
529         break;
530       }
531
532       snatm->snatm_if[IFNAMSIZ-1] = '\0';  /* XXX ensure null termination
533                                                 since ifunit() uses strcmp */
534
535       /*
536        * convert interface string to ifp, validate.
537        */
538
539       ifp = ifunit(snatm->snatm_if);
540       if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
541         error = ENXIO;
542         break;
543       }
544       if (ifp->if_output != atm_output) {
545         error = EAFNOSUPPORT;
546         break;
547       }
548
549
550       /*
551        * register us with the NATM PCB layer
552        */
553
554       if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
555         error = EADDRINUSE;
556         break;
557       }
558
559       /*
560        * enable rx
561        */
562
563       ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
564       ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
565       ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
566       api.rxhand = npcb;
567       lwkt_serialize_enter(ifp->if_serializer);
568       if (ifp->if_ioctl == NULL || 
569           ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api,
570                         (struct ucred *)NULL) != 0) {
571         lwkt_serialize_exit(ifp->if_serializer);
572         npcb_free(npcb, NPCB_REMOVE);
573         error = EIO;
574         break;
575       }
576       lwkt_serialize_exit(ifp->if_serializer);
577
578       soisconnected(so);
579
580       break;
581
582     case PRU_DISCONNECT:                /* disconnect from peer */
583
584       if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
585         kprintf("natm: disconnected check\n");
586         error = EIO;
587         break;
588       }
589       ifp = npcb->npcb_ifp;
590
591       /*
592        * disable rx
593        */
594
595       ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
596       ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
597       ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
598       api.rxhand = npcb;
599       lwkt_serialize_enter(ifp->if_serializer);
600       if (ifp->if_ioctl != NULL)
601           ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api, (struct ucred *)NULL);
602       lwkt_serialize_exit(ifp->if_serializer);
603
604       npcb_free(npcb, NPCB_REMOVE);
605       soisdisconnected(so);
606
607       break;
608
609     case PRU_SHUTDOWN:                  /* won't send any more data */
610       socantsendmore(so);
611       break;
612
613     case PRU_SEND:                      /* send this data */
614       if (control && control->m_len) {
615         m_freem(control);
616         m_freem(m);
617         error = EINVAL;
618         break;
619       }
620
621       /*
622        * send the data.   we must put an atm_pseudohdr on first
623        */
624
625       M_PREPEND(m, sizeof(*aph), M_WAITOK);
626       if (m == NULL) {
627         error = ENOBUFS;
628         break;
629       }
630       aph = mtod(m, struct atm_pseudohdr *);
631       ATM_PH_VPI(aph) = npcb->npcb_vpi;
632       ATM_PH_SETVCI(aph, npcb->npcb_vci);
633       ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
634
635       lwkt_serialize_enter(npcb->npcb_ifp->if_serializer);
636       error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
637       lwkt_serialize_exit(npcb->npcb_ifp->if_serializer);
638
639       break;
640
641     case PRU_SENSE:                     /* return status into m */
642       /* return zero? */
643       break;
644
645     case PRU_PEERADDR:                  /* fetch peer's address */
646       snatm = mtod(nam, struct sockaddr_natm *);
647       bzero(snatm, sizeof(*snatm));
648       nam->m_len = snatm->snatm_len = sizeof(*snatm);
649       snatm->snatm_family = AF_NATM;
650 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
651       bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if));
652 #elif defined(__DragonFly__)
653       ksnprintf(snatm->snatm_if, sizeof(snatm->snatm_if),
654         "%s%d", npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit);
655 #endif
656       snatm->snatm_vci = npcb->npcb_vci;
657       snatm->snatm_vpi = npcb->npcb_vpi;
658       break;
659
660     case PRU_CONTROL:                   /* control operations on protocol */
661       /*
662        * raw atm ioctl.   comes in as a SIOCRAWATM.   we convert it to
663        * SIOCXRAWATM and pass it to the driver.
664        */
665       if ((u_long)m == SIOCRAWATM) {
666         if (npcb->npcb_ifp == NULL) {
667           error = ENOTCONN;
668           break;
669         }
670         ario.npcb = npcb;
671         ario.rawvalue = *((int *)nam);
672         lwkt_serialize_enter(npcb->npcb_ifp->if_serializer);
673         error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, SIOCXRAWATM,
674                                          (caddr_t) &ario, (struct ucred *)NULL);
675         lwkt_serialize_exit(npcb->npcb_ifp->if_serializer);
676         if (!error) {
677           if (ario.rawvalue) 
678             npcb->npcb_flags |= NPCB_RAW;
679           else
680             npcb->npcb_flags &= ~(NPCB_RAW);
681         }
682
683         break;
684       }
685
686       error = EOPNOTSUPP;
687       break;
688
689     case PRU_BIND:                      /* bind socket to address */
690     case PRU_LISTEN:                    /* listen for connection */
691     case PRU_ACCEPT:                    /* accept connection from peer */
692     case PRU_CONNECT2:                  /* connect two sockets */
693     case PRU_ABORT:                     /* abort (fast DISCONNECT, DETATCH) */
694                                         /* (only happens if LISTEN socket) */
695     case PRU_RCVD:                      /* have taken data; more room now */
696     case PRU_FASTTIMO:                  /* 200ms timeout */
697     case PRU_SLOWTIMO:                  /* 500ms timeout */
698     case PRU_RCVOOB:                    /* retrieve out of band data */
699     case PRU_SENDOOB:                   /* send out of band data */
700     case PRU_PROTORCV:                  /* receive from below */
701     case PRU_PROTOSEND:                 /* send to below */
702     case PRU_SOCKADDR:                  /* fetch socket's address */
703 #ifdef DIAGNOSTIC
704       kprintf("natm: PRU #%d unsupported\n", req);
705 #endif
706       error = EOPNOTSUPP;
707       break;
708    
709     default: panic("natm usrreq");
710   }
711
712 done:
713   crit_exit();
714   return(error);
715 }
716
717 #endif  /* !FREEBSD_USRREQS */
718
719 /* 
720  * natm0_sysctl: not used, but here in case we want to add something
721  * later...
722  */
723
724 int
725 natm0_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
726              void *newp, size_t newlen)
727 {
728   /* All sysctl names at this level are terminal. */
729   if (namelen != 1)
730     return (ENOTDIR);
731   return (ENOPROTOOPT);
732 }
733
734 /* 
735  * natm5_sysctl: not used, but here in case we want to add something
736  * later...
737  */
738
739 int
740 natm5_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
741              void *newp, size_t newlen)
742 {
743   /* All sysctl names at this level are terminal. */
744   if (namelen != 1)
745     return (ENOTDIR);
746   return (ENOPROTOOPT);
747 }
748
749 static void natmintr(struct netmsg *);
750
751 #if defined(__DragonFly__)
752 static void
753 netisr_natm_setup(void *dummy __unused)
754 {
755         netisr_register(NETISR_NATM, cpu0_portfn, natmintr);
756 }
757 SYSINIT(natm_setup, SI_BOOT2_KLD, SI_ORDER_ANY, netisr_natm_setup, NULL);
758 #endif
759
760 void
761 natm_init(void)
762 {
763   LIST_INIT(&natm_pcbs);
764
765   netisr_register(NETISR_NATM, cpu0_portfn, natmintr);
766 }
767
768 /*
769  * natmintr: software interrupt
770  *
771  * note: we expect a socket pointer in rcvif rather than an interface
772  * pointer.    we can get the interface pointer from the so's PCB if
773  * we really need it.
774  */
775 static void
776 natmintr(struct netmsg *msg)
777 {
778   struct mbuf *m = ((struct netmsg_packet *)msg)->nm_packet;
779   struct socket *so;
780   struct natmpcb *npcb;
781
782 #ifdef DIAGNOSTIC
783   if ((m->m_flags & M_PKTHDR) == 0)
784     panic("natmintr no HDR");
785 #endif
786
787   npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
788   so = npcb->npcb_socket;
789
790   crit_enter();
791   npcb->npcb_inq--;
792   crit_exit();
793
794   if (npcb->npcb_flags & NPCB_DRAIN) {
795     m_freem(m);
796     if (npcb->npcb_inq == 0)
797       FREE(npcb, M_PCB);                        /* done! */
798     goto out;
799   }
800
801   if (npcb->npcb_flags & NPCB_FREE) {
802     m_freem(m);                                 /* drop */
803     goto out;
804   }
805
806 #ifdef NEED_TO_RESTORE_IFP
807   m->m_pkthdr.rcvif = npcb->npcb_ifp;
808 #else
809 #ifdef DIAGNOSTIC
810 m->m_pkthdr.rcvif = NULL;       /* null it out to be safe */
811 #endif
812 #endif
813
814   if (ssb_space(&so->so_rcv) > m->m_pkthdr.len ||
815      ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.ssb_cc < NPCB_RAWCC) ) {
816 #ifdef NATM_STAT
817     natm_sookcnt++;
818     natm_sookbytes += m->m_pkthdr.len;
819 #endif
820     sbappendrecord(&so->so_rcv.sb, m);
821     sorwakeup(so);
822   } else {
823 #ifdef NATM_STAT
824     natm_sodropcnt++;
825     natm_sodropbytes += m->m_pkthdr.len;
826 #endif
827     m_freem(m);
828   }
829 out:
830   ;
831   /* msg was embedded in the mbuf, do not reply! */
832 }
833