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