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