Initial import of binutils 2.22 on the new vendor branch
[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 /*
76  * FreeBSD new usrreqs supersedes pr_usrreq.
77  */
78
79 static void
80 natm_usr_attach(netmsg_t msg)
81 {
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;
85     struct natmpcb *npcb;
86     int error = 0;
87
88     crit_enter();
89     npcb = (struct natmpcb *) so->so_pcb;
90
91     if (npcb) {
92         error = EISCONN;
93         goto out;
94     }
95
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,
99                               ai->sb_rlimit);
100         else
101             error = soreserve(so, natm0_sendspace, natm0_recvspace,
102                               ai->sb_rlimit);
103         if (error)
104           goto out;
105     }
106
107     so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
108     npcb->npcb_socket = so;
109  out:
110     crit_exit();
111     lwkt_replymsg(&msg->lmsg, error);
112 }
113
114 static void
115 natm_usr_detach(netmsg_t msg)
116 {
117     struct socket *so = msg->base.nm_so;
118     struct natmpcb *npcb;
119     int error = 0;
120
121     crit_enter();
122     npcb = (struct natmpcb *) so->so_pcb;
123     if (npcb == NULL) {
124         error = EINVAL;
125         goto out;
126     }
127
128     /*
129      * we turn on 'drain' *before* we sofree.
130      */
131     so->so_pcb = NULL;
132     npcb_free(npcb, NPCB_DESTROY);      /* drain */
133     sofree(so);                         /* remove pcb ref */
134  out:
135     crit_exit();
136     lwkt_replymsg(&msg->lmsg, error);
137 }
138
139 static void
140 natm_usr_connect(netmsg_t msg)
141 {
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;
148     struct ifnet *ifp;
149     int error = 0;
150     int proto;
151
152     crit_enter();
153     proto = so->so_proto->pr_protocol;
154     npcb = (struct natmpcb *) so->so_pcb;
155     if (npcb == NULL) {
156         error = EINVAL;
157         goto out;
158     }
159
160     /*
161      * validate nam and npcb
162      */
163
164     snatm = (struct sockaddr_natm *)nam;
165     if (snatm->snatm_len != sizeof(*snatm) ||
166         (npcb->npcb_flags & NPCB_FREE) == 0) {
167         error = EINVAL;
168         goto out;
169     }
170     if (snatm->snatm_family != AF_NATM) {
171         error = EAFNOSUPPORT;
172         goto out;
173     }
174
175     snatm->snatm_if[IFNAMSIZ-1] = '\0';  /* XXX ensure null termination
176                                             since ifunit() uses strcmp */
177
178     /*
179      * convert interface string to ifp, validate.
180      */
181
182     ifp = ifunit(snatm->snatm_if);
183     if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
184         error = ENXIO;
185         goto out;
186     }
187     if (ifp->if_output != atm_output) {
188         error = EAFNOSUPPORT;
189         goto out;
190     }
191
192     /*
193      * register us with the NATM PCB layer
194      */
195
196     if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
197         error = EADDRINUSE;
198         goto out;
199     }
200
201     /*
202      * enable rx
203      */
204
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);
208     api.rxhand = npcb;
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);
215         error = EIO;
216         goto out;
217     }
218     ifnet_deserialize_all(ifp);
219
220     soisconnected(so);
221
222  out:
223     crit_exit();
224     lwkt_replymsg(&msg->lmsg, error);
225 }
226
227 static void
228 natm_usr_disconnect(netmsg_t msg)
229 {
230     struct socket *so = msg->base.nm_so;
231     struct natmpcb *npcb;
232     struct atm_pseudoioctl api;
233     struct ifnet *ifp;
234     int error = 0;
235
236     crit_enter();
237     npcb = (struct natmpcb *) so->so_pcb;
238     if (npcb == NULL) {
239         error = EINVAL;
240         goto out;
241     }
242
243     if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
244         kprintf("natm: disconnected check\n");
245         error = EIO;
246         goto out;
247     }
248     ifp = npcb->npcb_ifp;
249
250     /*
251      * disable rx
252      */
253
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);
257     api.rxhand = npcb;
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);
262     }
263
264     npcb_free(npcb, NPCB_REMOVE);
265     soisdisconnected(so);
266
267  out:
268     crit_exit();
269     lwkt_replymsg(&msg->lmsg, error);
270 }
271
272 static void
273 natm_usr_shutdown(netmsg_t msg)
274 {
275     struct socket *so = msg->base.nm_so;
276
277     socantsendmore(so);
278
279     lwkt_replymsg(&msg->lmsg, 0);
280 }
281
282 static void
283 natm_usr_send(netmsg_t msg)
284 {
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;
290     int error = 0;
291     int proto = so->so_proto->pr_protocol;
292
293     crit_enter();
294
295     npcb = (struct natmpcb *) so->so_pcb;
296     if (npcb == NULL) {
297         error = EINVAL;
298         goto out;
299     }
300
301     if (control && control->m_len) {
302         m_freem(control);
303         m_freem(m);
304         error = EINVAL;
305         goto out;
306     }
307
308     /*
309      * send the data.   we must put an atm_pseudohdr on first
310      */
311
312     M_PREPEND(m, sizeof(*aph), M_WAITOK);
313     if (m == NULL) {
314         error = ENOBUFS;
315         goto out;
316     }
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;
321
322     error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
323
324  out:
325     crit_exit();
326     lwkt_replymsg(&msg->lmsg, error);
327
328 }
329
330 static void
331 natm_usr_peeraddr(netmsg_t msg)
332 {
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;
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     lwkt_replymsg(&msg->lmsg, error);
359 }
360
361 static void
362 natm_usr_control(netmsg_t msg)
363 {
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;
370     int error = 0;
371
372     npcb = (struct natmpcb *) so->so_pcb;
373     if (npcb == NULL) {
374         error = EINVAL;
375         goto out;
376     }
377
378     /*
379      * raw atm ioctl.   comes in as a SIOCRAWATM.   we convert it to
380      * SIOCXRAWATM and pass it to the driver.
381      */
382     if (cmd == SIOCRAWATM) {
383         if (npcb->npcb_ifp == NULL) {
384             error = ENOTCONN;
385             goto out;
386         }
387         ario.npcb = npcb;
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);
394         if (!error) {
395             if (ario.rawvalue) 
396                 npcb->npcb_flags |= NPCB_RAW;
397             else
398                 npcb->npcb_flags &= ~(NPCB_RAW);
399         }
400     } else {
401         error = EOPNOTSUPP;
402     }
403 out:
404     lwkt_replymsg(&msg->lmsg, error);
405 }
406
407 /*
408  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
409  *       will sofree() it when we return.
410  */
411 static void
412 natm_usr_abort(netmsg_t msg)
413 {
414     natm_usr_shutdown(msg);
415     /* msg now invalid */
416 }
417
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
439 };
440
441 #else  /* !FREEBSD_USRREQS */
442
443 #if defined(__NetBSD__) || defined(__OpenBSD__)
444 int
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__)
448 int
449 natm_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
450             struct mbuf *control)
451 #endif
452 {
453   int error = 0;
454   struct natmpcb *npcb;
455   struct sockaddr_natm *snatm;
456   struct atm_pseudoioctl api;
457   struct atm_pseudohdr *aph;
458   struct atm_rawioctl ario;
459   struct ifnet *ifp;
460   int proto = so->so_proto->pr_protocol;
461
462   crit_enter();
463
464   npcb = (struct natmpcb *) so->so_pcb;
465
466   if (npcb == NULL && req != PRU_ATTACH) {
467     error = EINVAL;
468     goto done;
469   }
470     
471
472   switch (req) {
473     case PRU_ATTACH:                    /* attach protocol to up */
474
475       if (npcb) {
476         error = EISCONN;
477         break;
478       }
479
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);
483         else
484           error = soreserve(so, natm0_sendspace, natm0_recvspace);
485         if (error)
486           break;
487       }
488
489       so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
490       npcb->npcb_socket = so;
491
492       break;
493
494     case PRU_DETACH:                    /* detach protocol from up */
495
496       /*
497        * we turn on 'drain' *before* we sofree.
498        */
499
500       so->so_pcb = NULL;
501       npcb_free(npcb, NPCB_DESTROY);    /* drain */
502       sofree(so);                       /* remove pcb ref */
503
504       break;
505
506     case PRU_CONNECT:                   /* establish connection to peer */
507
508       /*
509        * validate nam and npcb
510        */
511
512       if (nam->m_len != sizeof(*snatm)) {
513         error = EINVAL;
514         break;
515       }
516       snatm = mtod(nam, struct sockaddr_natm *);
517       if (snatm->snatm_len != sizeof(*snatm) ||
518                 (npcb->npcb_flags & NPCB_FREE) == 0) {
519         error = EINVAL;
520         break;
521       }
522       if (snatm->snatm_family != AF_NATM) {
523         error = EAFNOSUPPORT;
524         break;
525       }
526
527       snatm->snatm_if[IFNAMSIZ-1] = '\0';  /* XXX ensure null termination
528                                                 since ifunit() uses strcmp */
529
530       /*
531        * convert interface string to ifp, validate.
532        */
533
534       ifp = ifunit(snatm->snatm_if);
535       if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
536         error = ENXIO;
537         break;
538       }
539       if (ifp->if_output != atm_output) {
540         error = EAFNOSUPPORT;
541         break;
542       }
543
544
545       /*
546        * register us with the NATM PCB layer
547        */
548
549       if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
550         error = EADDRINUSE;
551         break;
552       }
553
554       /*
555        * enable rx
556        */
557
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);
561       api.rxhand = npcb;
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);
567         error = EIO;
568         break;
569       }
570       ifnet_deserialize_all(ifp);
571
572       soisconnected(so);
573
574       break;
575
576     case PRU_DISCONNECT:                /* disconnect from peer */
577
578       if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
579         kprintf("natm: disconnected check\n");
580         error = EIO;
581         break;
582       }
583       ifp = npcb->npcb_ifp;
584
585       /*
586        * disable rx
587        */
588
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);
592       api.rxhand = npcb;
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);
597
598       npcb_free(npcb, NPCB_REMOVE);
599       soisdisconnected(so);
600
601       break;
602
603     case PRU_SHUTDOWN:                  /* won't send any more data */
604       socantsendmore(so);
605       break;
606
607     case PRU_SEND:                      /* send this data */
608       if (control && control->m_len) {
609         m_freem(control);
610         m_freem(m);
611         error = EINVAL;
612         break;
613       }
614
615       /*
616        * send the data.   we must put an atm_pseudohdr on first
617        */
618
619       M_PREPEND(m, sizeof(*aph), M_WAITOK);
620       if (m == NULL) {
621         error = ENOBUFS;
622         break;
623       }
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;
628
629       error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
630
631       break;
632
633     case PRU_SENSE:                     /* return status into m */
634       /* return zero? */
635       break;
636
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);
647 #endif
648       snatm->snatm_vci = npcb->npcb_vci;
649       snatm->snatm_vpi = npcb->npcb_vpi;
650       break;
651
652     case PRU_CONTROL:                   /* control operations on protocol */
653       /*
654        * raw atm ioctl.   comes in as a SIOCRAWATM.   we convert it to
655        * SIOCXRAWATM and pass it to the driver.
656        */
657       if ((u_long)m == SIOCRAWATM) {
658         if (npcb->npcb_ifp == NULL) {
659           error = ENOTCONN;
660           break;
661         }
662         ario.npcb = npcb;
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);
668         if (!error) {
669           if (ario.rawvalue) 
670             npcb->npcb_flags |= NPCB_RAW;
671           else
672             npcb->npcb_flags &= ~(NPCB_RAW);
673         }
674
675         break;
676       }
677
678       error = EOPNOTSUPP;
679       break;
680
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 */
695 #ifdef DIAGNOSTIC
696       kprintf("natm: PRU #%d unsupported\n", req);
697 #endif
698       error = EOPNOTSUPP;
699       break;
700    
701     default: panic("natm usrreq");
702   }
703
704 done:
705   crit_exit();
706   return(error);
707 }
708
709 #endif  /* !FREEBSD_USRREQS */
710
711 /* 
712  * natm0_sysctl: not used, but here in case we want to add something
713  * later...
714  */
715
716 int
717 natm0_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
718              void *newp, size_t newlen)
719 {
720   /* All sysctl names at this level are terminal. */
721   if (namelen != 1)
722     return (ENOTDIR);
723   return (ENOPROTOOPT);
724 }
725
726 /* 
727  * natm5_sysctl: not used, but here in case we want to add something
728  * later...
729  */
730
731 int
732 natm5_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
733              void *newp, size_t newlen)
734 {
735   /* All sysctl names at this level are terminal. */
736   if (namelen != 1)
737     return (ENOTDIR);
738   return (ENOPROTOOPT);
739 }
740
741 static void natmintr(netmsg_t);
742
743 #if defined(__DragonFly__)
744 static void
745 netisr_natm_setup(void *dummy __unused)
746 {
747         netisr_register(NETISR_NATM, natmintr, NULL);
748 }
749 SYSINIT(natm_setup, SI_BOOT2_KLD, SI_ORDER_ANY, netisr_natm_setup, NULL);
750 #endif
751
752 void
753 natm_init(void)
754 {
755   LIST_INIT(&natm_pcbs);
756
757   netisr_register(NETISR_NATM, natmintr, NULL);
758 }
759
760 /*
761  * natmintr: software interrupt
762  *
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
765  * we really need it.
766  */
767 static void
768 natmintr(netmsg_t msg)
769 {
770   struct mbuf *m = msg->packet.nm_packet;
771   struct socket *so;
772   struct natmpcb *npcb;
773
774 #ifdef DIAGNOSTIC
775   if ((m->m_flags & M_PKTHDR) == 0)
776     panic("natmintr no HDR");
777 #endif
778
779   get_mplock();
780
781   npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
782   so = npcb->npcb_socket;
783
784   crit_enter();
785   npcb->npcb_inq--;
786   crit_exit();
787
788   if (npcb->npcb_flags & NPCB_DRAIN) {
789     m_freem(m);
790     if (npcb->npcb_inq == 0)
791       FREE(npcb, M_PCB);                        /* done! */
792     goto out;
793   }
794
795   if (npcb->npcb_flags & NPCB_FREE) {
796     m_freem(m);                                 /* drop */
797     goto out;
798   }
799
800 #ifdef NEED_TO_RESTORE_IFP
801   m->m_pkthdr.rcvif = npcb->npcb_ifp;
802 #else
803 #ifdef DIAGNOSTIC
804 m->m_pkthdr.rcvif = NULL;       /* null it out to be safe */
805 #endif
806 #endif
807
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) ) {
810 #ifdef NATM_STAT
811     natm_sookcnt++;
812     natm_sookbytes += m->m_pkthdr.len;
813 #endif
814     sbappendrecord(&so->so_rcv.sb, m);
815     sorwakeup(so);
816   } else {
817 #ifdef NATM_STAT
818     natm_sodropcnt++;
819     natm_sodropbytes += m->m_pkthdr.len;
820 #endif
821     m_freem(m);
822   }
823 out:
824   rel_mplock();
825   /* msg was embedded in the mbuf, do not reply! */
826 }
827