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