]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/netgraph/atm/ng_atm.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / netgraph / atm / ng_atm.c
1 /*-
2  * Copyright (c) 2001-2003
3  *      Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * Author: Hartmut Brandt <harti@freebsd.org>
28  */
29
30 /*
31  * Netgraph module to connect NATM interfaces to netgraph.
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/errno.h>
43 #include <sys/syslog.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/sbuf.h>
47 #include <sys/ioccom.h>
48 #include <sys/sysctl.h>
49
50 #include <net/if.h>
51 #include <net/if_types.h>
52 #include <net/if_arp.h>
53 #include <net/if_var.h>
54 #include <net/if_media.h>
55 #include <net/if_atm.h>
56 #include <net/vnet.h>
57
58 #include <netgraph/ng_message.h>
59 #include <netgraph/netgraph.h>
60 #include <netgraph/ng_parse.h>
61 #include <netgraph/atm/ng_atm.h>
62
63 /*
64  * Hooks in the NATM code
65  */
66 extern void     (*ng_atm_attach_p)(struct ifnet *);
67 extern void     (*ng_atm_detach_p)(struct ifnet *);
68 extern int      (*ng_atm_output_p)(struct ifnet *, struct mbuf **);
69 extern void     (*ng_atm_input_p)(struct ifnet *, struct mbuf **,
70                     struct atm_pseudohdr *, void *);
71 extern void     (*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *,
72                     struct atm_pseudohdr *, void *);
73 extern void     (*ng_atm_event_p)(struct ifnet *, uint32_t, void *);
74
75 /*
76  * Sysctl stuff.
77  */
78 static SYSCTL_NODE(_net_graph, OID_AUTO, atm, CTLFLAG_RW, 0,
79     "atm related stuff");
80
81 #ifdef NGATM_DEBUG
82 static int allow_shutdown;
83
84 SYSCTL_INT(_net_graph_atm, OID_AUTO, allow_shutdown, CTLFLAG_RW,
85     &allow_shutdown, 0, "allow ng_atm nodes to shutdown");
86 #endif
87
88 /*
89  * Hook private data
90  */
91 struct ngvcc {
92         uint16_t        vpi;    /* VPI of this hook */
93         uint16_t        vci;    /* VCI of this hook, 0 if none */
94         uint32_t        flags;  /* private flags */
95         hook_p          hook;   /* the connected hook */
96
97         LIST_ENTRY(ngvcc) link;
98 };
99 #define VCC_OPEN        0x0001  /* open */
100
101 /*
102  * Node private data
103  */
104 struct priv {
105         struct ifnet    *ifp;           /* the ATM interface */
106         hook_p          input;          /* raw input hook */
107         hook_p          orphans;        /* packets to nowhere */
108         hook_p          output;         /* catch output packets */
109         hook_p          manage;         /* has also entry in vccs */
110         uint64_t        in_packets;
111         uint64_t        in_errors;
112         uint64_t        out_packets;
113         uint64_t        out_errors;
114
115         LIST_HEAD(, ngvcc) vccs;
116 };
117
118 /*
119  * Parse ifstate state
120  */
121 static const struct ng_parse_struct_field ng_atm_if_change_info[] =
122     NGM_ATM_IF_CHANGE_INFO;
123 static const struct ng_parse_type ng_atm_if_change_type = {
124         &ng_parse_struct_type,
125         &ng_atm_if_change_info
126 };
127
128 /*
129  * Parse vcc state change
130  */
131 static const struct ng_parse_struct_field ng_atm_vcc_change_info[] =
132     NGM_ATM_VCC_CHANGE_INFO;
133 static const struct ng_parse_type ng_atm_vcc_change_type = {
134         &ng_parse_struct_type,
135         &ng_atm_vcc_change_info
136 };
137
138 /*
139  * Parse acr change
140  */
141 static const struct ng_parse_struct_field ng_atm_acr_change_info[] =
142     NGM_ATM_ACR_CHANGE_INFO;
143 static const struct ng_parse_type ng_atm_acr_change_type = {
144         &ng_parse_struct_type,
145         &ng_atm_acr_change_info
146 };
147
148 /*
149  * Parse the configuration structure ng_atm_config
150  */
151 static const struct ng_parse_struct_field ng_atm_config_type_info[] =
152     NGM_ATM_CONFIG_INFO;
153
154 static const struct ng_parse_type ng_atm_config_type = {
155         &ng_parse_struct_type,
156         &ng_atm_config_type_info
157 };
158
159 /*
160  * Parse a single vcc structure and a variable array of these ng_atm_vccs
161  */
162 static const struct ng_parse_struct_field ng_atm_tparam_type_info[] =
163     NGM_ATM_TPARAM_INFO;
164 static const struct ng_parse_type ng_atm_tparam_type = {
165         &ng_parse_struct_type,
166         &ng_atm_tparam_type_info
167 };
168 static const struct ng_parse_struct_field ng_atm_vcc_type_info[] =
169     NGM_ATM_VCC_INFO;
170 static const struct ng_parse_type ng_atm_vcc_type = {
171         &ng_parse_struct_type,
172         &ng_atm_vcc_type_info
173 };
174
175
176 static int
177 ng_atm_vccarray_getlen(const struct ng_parse_type *type,
178         const u_char *start, const u_char *buf)
179 {
180         const struct atmio_vcctable *vp;
181
182         vp = (const struct atmio_vcctable *)
183             (buf - offsetof(struct atmio_vcctable, vccs));
184
185         return (vp->count);
186 }
187 static const struct ng_parse_array_info ng_atm_vccarray_info =
188     NGM_ATM_VCCARRAY_INFO;
189 static const struct ng_parse_type ng_atm_vccarray_type = {
190         &ng_parse_array_type,
191         &ng_atm_vccarray_info
192 };
193
194
195 static const struct ng_parse_struct_field ng_atm_vcctable_type_info[] =
196     NGM_ATM_VCCTABLE_INFO;
197
198 static const struct ng_parse_type ng_atm_vcctable_type = {
199         &ng_parse_struct_type,
200         &ng_atm_vcctable_type_info
201 };
202
203 /*
204  * Parse CPCS INIT structure ng_atm_cpcs_init
205  */
206 static const struct ng_parse_struct_field ng_atm_cpcs_init_type_info[] =
207     NGM_ATM_CPCS_INIT_INFO;
208
209 static const struct ng_parse_type ng_atm_cpcs_init_type = {
210         &ng_parse_struct_type,
211         &ng_atm_cpcs_init_type_info
212 };
213
214 /*
215  * Parse CPCS TERM structure ng_atm_cpcs_term
216  */
217 static const struct ng_parse_struct_field ng_atm_cpcs_term_type_info[] =
218     NGM_ATM_CPCS_TERM_INFO;
219
220 static const struct ng_parse_type ng_atm_cpcs_term_type = {
221         &ng_parse_struct_type,
222         &ng_atm_cpcs_term_type_info
223 };
224
225 /*
226  * Parse statistic struct
227  */
228 static const struct ng_parse_struct_field ng_atm_stats_type_info[] =
229     NGM_ATM_STATS_INFO;
230
231 static const struct ng_parse_type ng_atm_stats_type = {
232         &ng_parse_struct_type,
233         &ng_atm_stats_type_info
234 };
235
236 static const struct ng_cmdlist ng_atm_cmdlist[] = {
237         {
238           NGM_ATM_COOKIE,
239           NGM_ATM_GET_IFNAME,
240           "getifname",
241           NULL,
242           &ng_parse_string_type
243         },
244         {
245           NGM_ATM_COOKIE,
246           NGM_ATM_GET_CONFIG,
247           "getconfig",
248           NULL,
249           &ng_atm_config_type
250         },
251         {
252           NGM_ATM_COOKIE,
253           NGM_ATM_GET_VCCS,
254           "getvccs",
255           NULL,
256           &ng_atm_vcctable_type
257         },
258         {
259           NGM_ATM_COOKIE,
260           NGM_ATM_CPCS_INIT,
261           "cpcsinit",
262           &ng_atm_cpcs_init_type,
263           NULL
264         },
265         {
266           NGM_ATM_COOKIE,
267           NGM_ATM_CPCS_TERM,
268           "cpcsterm",
269           &ng_atm_cpcs_term_type,
270           NULL
271         },
272         {
273           NGM_ATM_COOKIE,
274           NGM_ATM_GET_VCC,
275           "getvcc",
276           &ng_parse_hookbuf_type,
277           &ng_atm_vcc_type
278         },
279         {
280           NGM_ATM_COOKIE,
281           NGM_ATM_GET_VCCID,
282           "getvccid",
283           &ng_atm_vcc_type,
284           &ng_atm_vcc_type
285         },
286         {
287           NGM_ATM_COOKIE,
288           NGM_ATM_GET_STATS,
289           "getstats",
290           NULL,
291           &ng_atm_stats_type
292         },
293
294         /* events */
295         {
296           NGM_ATM_COOKIE,
297           NGM_ATM_IF_CHANGE,
298           "if_change",
299           &ng_atm_if_change_type,
300           &ng_atm_if_change_type,
301         },
302         {
303           NGM_ATM_COOKIE,
304           NGM_ATM_VCC_CHANGE,
305           "vcc_change",
306           &ng_atm_vcc_change_type,
307           &ng_atm_vcc_change_type,
308         },
309         {
310           NGM_ATM_COOKIE,
311           NGM_ATM_ACR_CHANGE,
312           "acr_change",
313           &ng_atm_acr_change_type,
314           &ng_atm_acr_change_type,
315         },
316         { 0 }
317 };
318
319 static int ng_atm_mod_event(module_t, int, void *);
320
321 static ng_constructor_t ng_atm_constructor;
322 static ng_shutdown_t    ng_atm_shutdown;
323 static ng_rcvmsg_t      ng_atm_rcvmsg;
324 static ng_newhook_t     ng_atm_newhook;
325 static ng_connect_t     ng_atm_connect;
326 static ng_disconnect_t  ng_atm_disconnect;
327 static ng_rcvdata_t     ng_atm_rcvdata;
328 static ng_rcvdata_t     ng_atm_rcvdrop;
329
330 static struct ng_type ng_atm_typestruct = {
331         .version =      NG_ABI_VERSION,
332         .name =         NG_ATM_NODE_TYPE,
333         .mod_event =    ng_atm_mod_event,
334         .constructor =  ng_atm_constructor,
335         .rcvmsg =       ng_atm_rcvmsg,
336         .shutdown =     ng_atm_shutdown,
337         .newhook =      ng_atm_newhook,
338         .connect =      ng_atm_connect,
339         .rcvdata =      ng_atm_rcvdata,
340         .disconnect =   ng_atm_disconnect,
341         .cmdlist =      ng_atm_cmdlist,
342 };
343 NETGRAPH_INIT(atm, &ng_atm_typestruct);
344
345 static const struct {
346         u_int   media;
347         const char *name;
348 } atmmedia[] = IFM_SUBTYPE_ATM_DESCRIPTIONS;
349
350
351 #define IFP2NG(IFP)     ((node_p)((struct ifatm *)(IFP)->if_softc)->ngpriv)
352 #define IFP2NG_SET(IFP, val)    (((struct ifatm *)(IFP)->if_softc)->ngpriv = (val))
353
354 #define IFFLAGS "\020\001UP\002BROADCAST\003DEBUG\004LOOPBACK" \
355                  "\005POINTOPOINT\006SMART\007RUNNING\010NOARP" \
356                  "\011PROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX" \
357                  "\015LINK0\016LINK1\017LINK2\020MULTICAST"
358
359
360 /************************************************************/
361 /*
362  * INPUT
363  */
364 /*
365  * A packet is received from an interface. 
366  * If we have an input hook, prepend the pseudoheader to the data and
367  * deliver it out to that hook. If not, look whether it is destined for
368  * use. If so locate the appropriate hook, deliver the packet without the
369  * header and we are done. If it is not for us, leave it alone.
370  */
371 static void
372 ng_atm_input(struct ifnet *ifp, struct mbuf **mp,
373         struct atm_pseudohdr *ah, void *rxhand)
374 {
375         node_p node = IFP2NG(ifp);
376         struct priv *priv;
377         const struct ngvcc *vcc;
378         int error;
379
380         if (node == NULL)
381                 return;
382         priv = NG_NODE_PRIVATE(node);
383         if (priv->input != NULL) {
384                 /*
385                  * Prepend the atm_pseudoheader.
386                  */
387                 M_PREPEND(*mp, sizeof(*ah), M_NOWAIT);
388                 if (*mp == NULL)
389                         return;
390                 memcpy(mtod(*mp, struct atm_pseudohdr *), ah, sizeof(*ah));
391                 NG_SEND_DATA_ONLY(error, priv->input, *mp);
392                 if (error == 0) {
393                         priv->in_packets++;
394                         *mp = NULL;
395                 } else {
396 #ifdef NGATM_DEBUG
397                         printf("%s: error=%d\n", __func__, error);
398 #endif
399                         priv->in_errors++;
400                 }
401                 return;
402         }
403         if ((ATM_PH_FLAGS(ah) & ATMIO_FLAG_NG) == 0)
404                 return;
405
406         vcc = (struct ngvcc *)rxhand;
407
408         NG_SEND_DATA_ONLY(error, vcc->hook, *mp);
409         if (error == 0) {
410                 priv->in_packets++;
411                 *mp = NULL;
412         } else {
413 #ifdef NGATM_DEBUG
414                 printf("%s: error=%d\n", __func__, error);
415 #endif
416                 priv->in_errors++;
417         }
418 }
419
420 /*
421  * ATM packet is about to be output. The atm_pseudohdr is already prepended.
422  * If the hook is set, reroute the packet to the hook.
423  */
424 static int
425 ng_atm_output(struct ifnet *ifp, struct mbuf **mp)
426 {
427         const node_p node = IFP2NG(ifp);
428         const struct priv *priv;
429         int error = 0;
430
431         if (node == NULL)
432                 return (0);
433         priv = NG_NODE_PRIVATE(node);
434         if (priv->output) {
435                 NG_SEND_DATA_ONLY(error, priv->output, *mp);
436                 *mp = NULL;
437         }
438
439         return (error);
440 }
441
442 /*
443  * Well, this doesn't make much sense for ATM.
444  */
445 static void
446 ng_atm_input_orphans(struct ifnet *ifp, struct mbuf *m,
447         struct atm_pseudohdr *ah, void *rxhand)
448 {
449         node_p node = IFP2NG(ifp);
450         struct priv *priv;
451         int error;
452
453         if (node == NULL) {
454                 m_freem(m);
455                 return;
456         }
457         priv = NG_NODE_PRIVATE(node);
458         if (priv->orphans == NULL) {
459                 m_freem(m);
460                 return;
461         }
462         /*
463          * Prepend the atm_pseudoheader.
464          */
465         M_PREPEND(m, sizeof(*ah), M_NOWAIT);
466         if (m == NULL)
467                 return;
468         memcpy(mtod(m, struct atm_pseudohdr *), ah, sizeof(*ah));
469         NG_SEND_DATA_ONLY(error, priv->orphans, m);
470         if (error == 0)
471                 priv->in_packets++;
472         else {
473                 priv->in_errors++;
474 #ifdef NGATM_DEBUG
475                 printf("%s: error=%d\n", __func__, error);
476 #endif
477         }
478 }
479
480 /************************************************************/
481 /*
482  * OUTPUT
483  */
484 static int
485 ng_atm_rcvdata(hook_p hook, item_p item)
486 {
487         node_p node = NG_HOOK_NODE(hook);
488         struct priv *priv = NG_NODE_PRIVATE(node);
489         const struct ngvcc *vcc = NG_HOOK_PRIVATE(hook);
490         struct mbuf *m;
491         struct atm_pseudohdr *aph;
492         int error;
493
494         if (vcc->vci == 0) {
495                 NG_FREE_ITEM(item);
496                 return (ENOTCONN);
497         }
498
499         NGI_GET_M(item, m);
500         NG_FREE_ITEM(item);
501
502         /*
503          * Prepend pseudo-hdr. Drivers don't care about the flags.
504          */
505         M_PREPEND(m, sizeof(*aph), M_NOWAIT);
506         if (m == NULL) {
507                 NG_FREE_M(m);
508                 return (ENOMEM);
509         }
510         aph = mtod(m, struct atm_pseudohdr *);
511         ATM_PH_VPI(aph) = vcc->vpi;
512         ATM_PH_SETVCI(aph, vcc->vci);
513         ATM_PH_FLAGS(aph) = 0;
514
515         if ((error = atm_output(priv->ifp, m, NULL, NULL)) == 0)
516                 priv->out_packets++;
517         else
518                 priv->out_errors++;
519         return (error);
520 }
521
522 static int
523 ng_atm_rcvdrop(hook_p hook, item_p item)
524 {
525         NG_FREE_ITEM(item);
526         return (0);
527 }
528
529
530 /************************************************************
531  *
532  * Event from driver.
533  */
534 static void
535 ng_atm_event_func(node_p node, hook_p hook, void *arg, int event)
536 {
537         const struct priv *priv = NG_NODE_PRIVATE(node);
538         struct ngvcc *vcc;
539         struct ng_mesg *mesg;
540         int error;
541
542         switch (event) {
543
544           case ATMEV_FLOW_CONTROL:
545             {
546                 struct atmev_flow_control *ev = arg;
547                 struct ngm_queue_state *qstate;
548
549                 /* find the connection */
550                 LIST_FOREACH(vcc, &priv->vccs, link)
551                         if (vcc->vci == ev->vci && vcc->vpi == ev->vpi)
552                                 break;
553                 if (vcc == NULL)
554                         break;
555
556                 /* convert into a flow control message */
557                 NG_MKMESSAGE(mesg, NGM_FLOW_COOKIE,
558                     ev->busy ? NGM_HIGH_WATER_PASSED : NGM_LOW_WATER_PASSED,
559                     sizeof(struct ngm_queue_state), M_NOWAIT);
560                 if (mesg == NULL)
561                         break;
562                 qstate = (struct ngm_queue_state *)mesg->data;
563
564                 /* XXX have to figure out how to get that info */
565
566                 NG_SEND_MSG_HOOK(error, node, mesg, vcc->hook, 0);
567                 break;
568             }
569
570           case ATMEV_VCC_CHANGED:
571             {
572                 struct atmev_vcc_changed *ev = arg;
573                 struct ngm_atm_vcc_change *chg;
574
575                 if (priv->manage == NULL)
576                         break;
577                 NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_VCC_CHANGE,
578                     sizeof(struct ngm_atm_vcc_change), M_NOWAIT);
579                 if (mesg == NULL)
580                         break;
581                 chg = (struct ngm_atm_vcc_change *)mesg->data;
582                 chg->vci = ev->vci;
583                 chg->vpi = ev->vpi;
584                 chg->state = (ev->up != 0);
585                 chg->node = NG_NODE_ID(node);
586                 NG_SEND_MSG_HOOK(error, node, mesg, priv->manage, 0);
587                 break;
588             }
589
590           case ATMEV_IFSTATE_CHANGED:
591             {
592                 struct atmev_ifstate_changed *ev = arg;
593                 struct ngm_atm_if_change *chg;
594
595                 if (priv->manage == NULL)
596                         break;
597                 NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_IF_CHANGE,
598                     sizeof(struct ngm_atm_if_change), M_NOWAIT);
599                 if (mesg == NULL)
600                         break;
601                 chg = (struct ngm_atm_if_change *)mesg->data;
602                 chg->carrier = (ev->carrier != 0);
603                 chg->running = (ev->running != 0);
604                 chg->node = NG_NODE_ID(node);
605                 NG_SEND_MSG_HOOK(error, node, mesg, priv->manage, 0);
606                 break;
607             }
608
609           case ATMEV_ACR_CHANGED:
610             {
611                 struct atmev_acr_changed *ev = arg;
612                 struct ngm_atm_acr_change *acr;
613
614                 /* find the connection */
615                 LIST_FOREACH(vcc, &priv->vccs, link)
616                         if (vcc->vci == ev->vci && vcc->vpi == ev->vpi)
617                                 break;
618                 if (vcc == NULL)
619                         break;
620
621                 /* convert into a flow control message */
622                 NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_ACR_CHANGE,
623                     sizeof(struct ngm_atm_acr_change), M_NOWAIT);
624                 if (mesg == NULL)
625                         break;
626                 acr = (struct ngm_atm_acr_change *)mesg->data;
627                 acr->node = NG_NODE_ID(node);
628                 acr->vci = ev->vci;
629                 acr->vpi = ev->vpi;
630                 acr->acr = ev->acr;
631
632                 NG_SEND_MSG_HOOK(error, node, mesg, vcc->hook, 0);
633                 break;
634             }
635         }
636 }
637
638 /*
639  * Use send_fn to get the right lock
640  */
641 static void
642 ng_atm_event(struct ifnet *ifp, uint32_t event, void *arg)
643 {
644         const node_p node = IFP2NG(ifp);
645
646         if (node != NULL)
647                 /* may happen during attach/detach */
648                 (void)ng_send_fn(node, NULL, ng_atm_event_func, arg, event);
649 }
650
651 /************************************************************
652  *
653  * CPCS
654  */
655 /*
656  * Open a channel for the user
657  */
658 static int
659 ng_atm_cpcs_init(node_p node, const struct ngm_atm_cpcs_init *arg)
660 {
661         struct priv *priv = NG_NODE_PRIVATE(node);
662         const struct ifatm_mib *mib;
663         struct ngvcc *vcc;
664         struct atmio_openvcc data;
665         int err;
666
667         if(priv->ifp->if_ioctl == NULL)
668                 return (ENXIO);
669
670         mib = (const struct ifatm_mib *)(priv->ifp->if_linkmib);
671
672         LIST_FOREACH(vcc, &priv->vccs, link)
673                 if (strcmp(arg->name, NG_HOOK_NAME(vcc->hook)) == 0)
674                         break;
675         if (vcc == NULL)
676                 return (ENOTCONN);
677         if (vcc->flags & VCC_OPEN)
678                 return (EISCONN);
679
680         /*
681          * Check user arguments and construct ioctl argument
682          */
683         memset(&data, 0, sizeof(data));
684
685         data.rxhand = vcc;
686
687         switch (data.param.aal = arg->aal) {
688
689           case ATMIO_AAL_34:
690           case ATMIO_AAL_5:
691           case ATMIO_AAL_0:
692           case ATMIO_AAL_RAW:
693                 break;
694
695           default:
696                 return (EINVAL);
697         }
698
699         if (arg->vpi > 0xff)
700                 return (EINVAL);
701         data.param.vpi = arg->vpi;
702
703         /* allow 0.0 as catch all receive channel */
704         if (arg->vci == 0 && (arg->vpi != 0 || !(arg->flags & ATMIO_FLAG_NOTX)))
705                 return (EINVAL);
706         data.param.vci = arg->vci;
707
708         data.param.tparam.pcr = arg->pcr;
709
710         if (arg->mcr > arg->pcr)
711                 return (EINVAL);
712         data.param.tparam.mcr = arg->mcr;
713
714         if (!(arg->flags & ATMIO_FLAG_NOTX)) {
715                 if (arg->tmtu == 0)
716                         data.param.tmtu = priv->ifp->if_mtu;
717                 else {
718                         data.param.tmtu = arg->tmtu;
719                 }
720         }
721         if (!(arg->flags & ATMIO_FLAG_NORX)) {
722                 if (arg->rmtu == 0)
723                         data.param.rmtu = priv->ifp->if_mtu;
724                 else {
725                         data.param.rmtu = arg->rmtu;
726                 }
727         }
728
729         switch (data.param.traffic = arg->traffic) {
730
731           case ATMIO_TRAFFIC_UBR:
732           case ATMIO_TRAFFIC_CBR:
733                 break;
734
735           case ATMIO_TRAFFIC_VBR:
736                 if (arg->scr > arg->pcr)
737                         return (EINVAL);
738                 data.param.tparam.scr = arg->scr;
739
740                 if (arg->mbs > (1 << 24))
741                         return (EINVAL);
742                 data.param.tparam.mbs = arg->mbs;
743                 break;
744
745           case ATMIO_TRAFFIC_ABR:
746                 if (arg->icr > arg->pcr || arg->icr < arg->mcr)
747                         return (EINVAL);
748                 data.param.tparam.icr = arg->icr;
749
750                 if (arg->tbe == 0 || arg->tbe > (1 << 24))
751                         return (EINVAL);
752                 data.param.tparam.tbe = arg->tbe;
753
754                 if (arg->nrm > 0x7)
755                         return (EINVAL);
756                 data.param.tparam.nrm = arg->nrm;
757
758                 if (arg->trm > 0x7)
759                         return (EINVAL);
760                 data.param.tparam.trm = arg->trm;
761
762                 if (arg->adtf > 0x3ff)
763                         return (EINVAL);
764                 data.param.tparam.adtf = arg->adtf;
765
766                 if (arg->rif > 0xf)
767                         return (EINVAL);
768                 data.param.tparam.rif = arg->rif;
769
770                 if (arg->rdf > 0xf)
771                         return (EINVAL);
772                 data.param.tparam.rdf = arg->rdf;
773
774                 if (arg->cdf > 0x7)
775                         return (EINVAL);
776                 data.param.tparam.cdf = arg->cdf;
777
778                 break;
779
780           default:
781                 return (EINVAL);
782         }
783
784         if ((arg->flags & ATMIO_FLAG_NORX) && (arg->flags & ATMIO_FLAG_NOTX))
785                 return (EINVAL);
786
787         data.param.flags = arg->flags & ~(ATM_PH_AAL5 | ATM_PH_LLCSNAP);
788         data.param.flags |= ATMIO_FLAG_NG;
789
790         err = (*priv->ifp->if_ioctl)(priv->ifp, SIOCATMOPENVCC, (caddr_t)&data);
791
792         if (err == 0) {
793                 vcc->vci = data.param.vci;
794                 vcc->vpi = data.param.vpi;
795                 vcc->flags = VCC_OPEN;
796         }
797
798         return (err);
799 }
800
801 /*
802  * Issue the close command to the driver
803  */
804 static int
805 cpcs_term(const struct priv *priv, u_int vpi, u_int vci)
806 {
807         struct atmio_closevcc data;
808
809         if (priv->ifp->if_ioctl == NULL)
810                 return ENXIO;
811
812         data.vpi = vpi;
813         data.vci = vci;
814
815         return ((*priv->ifp->if_ioctl)(priv->ifp,
816             SIOCATMCLOSEVCC, (caddr_t)&data));
817 }
818
819
820 /*
821  * Close a channel by request of the user
822  */
823 static int
824 ng_atm_cpcs_term(node_p node, const struct ngm_atm_cpcs_term *arg)
825 {
826         struct priv *priv = NG_NODE_PRIVATE(node);
827         struct ngvcc *vcc;
828         int error;
829
830         LIST_FOREACH(vcc, &priv->vccs, link)
831                 if(strcmp(arg->name, NG_HOOK_NAME(vcc->hook)) == 0)
832                         break;
833         if (vcc == NULL)
834                 return (ENOTCONN);
835         if (!(vcc->flags & VCC_OPEN))
836                 return (ENOTCONN);
837
838         error = cpcs_term(priv, vcc->vpi, vcc->vci);
839
840         vcc->vci = 0;
841         vcc->vpi = 0;
842         vcc->flags = 0;
843
844         return (error);
845 }
846
847 /************************************************************/
848 /*
849  * CONTROL MESSAGES
850  */
851
852 /*
853  * Produce a textual description of the current status
854  */
855 static int
856 text_status(node_p node, char *arg, u_int len)
857 {
858         const struct priv *priv = NG_NODE_PRIVATE(node);
859         const struct ifatm_mib *mib;
860         struct sbuf sbuf;
861         u_int i;
862
863         static const struct {
864                 const char      *name;
865                 const char      *vendor;
866         } devices[] = {
867                 ATM_DEVICE_NAMES
868         };
869
870         mib = (const struct ifatm_mib *)(priv->ifp->if_linkmib);
871
872         sbuf_new(&sbuf, arg, len, SBUF_FIXEDLEN);
873         sbuf_printf(&sbuf, "interface: %s\n", priv->ifp->if_xname);
874
875         if (mib->device >= sizeof(devices) / sizeof(devices[0]))
876                 sbuf_printf(&sbuf, "device=unknown\nvendor=unknown\n");
877         else
878                 sbuf_printf(&sbuf, "device=%s\nvendor=%s\n",
879                     devices[mib->device].name, devices[mib->device].vendor);
880
881         for (i = 0; atmmedia[i].name; i++)
882                 if(mib->media == atmmedia[i].media) {
883                         sbuf_printf(&sbuf, "media=%s\n", atmmedia[i].name);
884                         break;
885                 }
886         if(atmmedia[i].name == NULL)
887                 sbuf_printf(&sbuf, "media=unknown\n");
888
889         sbuf_printf(&sbuf, "serial=%u esi=%6D hardware=%u software=%u\n",
890             mib->serial, mib->esi, ":", mib->hw_version, mib->sw_version);
891         sbuf_printf(&sbuf, "pcr=%u vpi_bits=%u vci_bits=%u max_vpcs=%u "
892             "max_vccs=%u\n", mib->pcr, mib->vpi_bits, mib->vci_bits,
893             mib->max_vpcs, mib->max_vccs);
894         sbuf_printf(&sbuf, "ifflags=%b\n", priv->ifp->if_flags, IFFLAGS);
895
896         sbuf_finish(&sbuf);
897
898         return (sbuf_len(&sbuf));
899 }
900
901 /*
902  * Get control message
903  */
904 static int
905 ng_atm_rcvmsg(node_p node, item_p item, hook_p lasthook)
906 {
907         const struct priv *priv = NG_NODE_PRIVATE(node);
908         struct ng_mesg *resp = NULL;
909         struct ng_mesg *msg;
910         struct ifatm_mib *mib = (struct ifatm_mib *)(priv->ifp->if_linkmib);
911         int error = 0;
912
913         NGI_GET_MSG(item, msg);
914
915         switch (msg->header.typecookie) {
916
917           case NGM_GENERIC_COOKIE:
918                 switch (msg->header.cmd) {
919
920                   case NGM_TEXT_STATUS:
921                         NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
922                         if(resp == NULL) {
923                                 error = ENOMEM;
924                                 break;
925                         }
926
927                         resp->header.arglen = text_status(node,
928                             (char *)resp->data, resp->header.arglen) + 1;
929                         break;
930
931                   default:
932                         error = EINVAL;
933                         break;
934                 }
935                 break;
936
937           case NGM_ATM_COOKIE:
938                 switch (msg->header.cmd) {
939
940                   case NGM_ATM_GET_IFNAME:
941                         NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
942                         if (resp == NULL) {
943                                 error = ENOMEM;
944                                 break;
945                         }
946                         strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ);
947                         break;
948
949                   case NGM_ATM_GET_CONFIG:
950                     {
951                         struct ngm_atm_config *config;
952
953                         NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT);
954                         if (resp == NULL) {
955                                 error = ENOMEM;
956                                 break;
957                         }
958                         config = (struct ngm_atm_config *)resp->data;
959                         config->pcr = mib->pcr;
960                         config->vpi_bits = mib->vpi_bits;
961                         config->vci_bits = mib->vci_bits;
962                         config->max_vpcs = mib->max_vpcs;
963                         config->max_vccs = mib->max_vccs;
964                         break;
965                     }
966
967                   case NGM_ATM_GET_VCCS:
968                     {
969                         struct atmio_vcctable *vccs;
970                         size_t len;
971
972                         if (priv->ifp->if_ioctl == NULL) {
973                                 error = ENXIO;
974                                 break;
975                         }
976                         error = (*priv->ifp->if_ioctl)(priv->ifp,
977                             SIOCATMGETVCCS, (caddr_t)&vccs);
978                         if (error)
979                                 break;
980
981                         len = sizeof(*vccs) +
982                             vccs->count * sizeof(vccs->vccs[0]);
983                         NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
984                         if (resp == NULL) {
985                                 error = ENOMEM;
986                                 free(vccs, M_DEVBUF);
987                                 break;
988                         }
989
990                         (void)memcpy(resp->data, vccs, len);
991                         free(vccs, M_DEVBUF);
992
993                         break;
994                     }
995
996                   case NGM_ATM_GET_VCC:
997                     {
998                         char hook[NG_HOOKSIZ];
999                         struct atmio_vcctable *vccs;
1000                         struct ngvcc *vcc;
1001                         u_int i;
1002
1003                         if (priv->ifp->if_ioctl == NULL) {
1004                                 error = ENXIO;
1005                                 break;
1006                         }
1007                         if (msg->header.arglen != NG_HOOKSIZ) {
1008                                 error = EINVAL;
1009                                 break;
1010                         }
1011                         strncpy(hook, msg->data, NG_HOOKSIZ);
1012                         hook[NG_HOOKSIZ - 1] = '\0';
1013                         LIST_FOREACH(vcc, &priv->vccs, link)
1014                                 if (strcmp(NG_HOOK_NAME(vcc->hook), hook) == 0)
1015                                         break;
1016                         if (vcc == NULL) {
1017                                 error = ENOTCONN;
1018                                 break;
1019                         }
1020                         error = (*priv->ifp->if_ioctl)(priv->ifp,
1021                             SIOCATMGETVCCS, (caddr_t)&vccs);
1022                         if (error)
1023                                 break;
1024
1025                         for (i = 0; i < vccs->count; i++)
1026                                 if (vccs->vccs[i].vpi == vcc->vpi &&
1027                                     vccs->vccs[i].vci == vcc->vci)
1028                                         break;
1029                         if (i == vccs->count) {
1030                                 error = ENOTCONN;
1031                                 free(vccs, M_DEVBUF);
1032                                 break;
1033                         }
1034
1035                         NG_MKRESPONSE(resp, msg, sizeof(vccs->vccs[0]),
1036                             M_NOWAIT);
1037                         if (resp == NULL) {
1038                                 error = ENOMEM;
1039                                 free(vccs, M_DEVBUF);
1040                                 break;
1041                         }
1042
1043                         *(struct atmio_vcc *)resp->data = vccs->vccs[i];
1044                         free(vccs, M_DEVBUF);
1045                         break;
1046                     }
1047
1048                   case NGM_ATM_GET_VCCID:
1049                     {
1050                         struct atmio_vcc *arg;
1051                         struct atmio_vcctable *vccs;
1052                         u_int i;
1053
1054                         if (priv->ifp->if_ioctl == NULL) {
1055                                 error = ENXIO;
1056                                 break;
1057                         }
1058                         if (msg->header.arglen != sizeof(*arg)) {
1059                                 error = EINVAL;
1060                                 break;
1061                         }
1062                         arg = (struct atmio_vcc *)msg->data;
1063
1064                         error = (*priv->ifp->if_ioctl)(priv->ifp,
1065                             SIOCATMGETVCCS, (caddr_t)&vccs);
1066                         if (error)
1067                                 break;
1068
1069                         for (i = 0; i < vccs->count; i++)
1070                                 if (vccs->vccs[i].vpi == arg->vpi &&
1071                                     vccs->vccs[i].vci == arg->vci)
1072                                         break;
1073                         if (i == vccs->count) {
1074                                 error = ENOTCONN;
1075                                 free(vccs, M_DEVBUF);
1076                                 break;
1077                         }
1078
1079                         NG_MKRESPONSE(resp, msg, sizeof(vccs->vccs[0]),
1080                             M_NOWAIT);
1081                         if (resp == NULL) {
1082                                 error = ENOMEM;
1083                                 free(vccs, M_DEVBUF);
1084                                 break;
1085                         }
1086
1087                         *(struct atmio_vcc *)resp->data = vccs->vccs[i];
1088                         free(vccs, M_DEVBUF);
1089                         break;
1090                     }
1091
1092                   case NGM_ATM_CPCS_INIT:
1093                         if (msg->header.arglen !=
1094                             sizeof(struct ngm_atm_cpcs_init)) {
1095                                 error = EINVAL;
1096                                 break;
1097                         }
1098                         error = ng_atm_cpcs_init(node,
1099                             (struct ngm_atm_cpcs_init *)msg->data);
1100                         break;
1101
1102                   case NGM_ATM_CPCS_TERM:
1103                         if (msg->header.arglen !=
1104                             sizeof(struct ngm_atm_cpcs_term)) {
1105                                 error = EINVAL;
1106                                 break;
1107                         }
1108                         error = ng_atm_cpcs_term(node,
1109                             (struct ngm_atm_cpcs_term *)msg->data);
1110                         break;
1111
1112                   case NGM_ATM_GET_STATS:
1113                     {
1114                         struct ngm_atm_stats *p;
1115
1116                         if (msg->header.arglen != 0) {
1117                                 error = EINVAL;
1118                                 break;
1119                         }
1120                         NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
1121                         if (resp == NULL) {
1122                                 error = ENOMEM;
1123                                 break;
1124                         }
1125                         p = (struct ngm_atm_stats *)resp->data;
1126                         p->in_packets = priv->in_packets;
1127                         p->out_packets = priv->out_packets;
1128                         p->in_errors = priv->in_errors;
1129                         p->out_errors = priv->out_errors;
1130
1131                         break;
1132                     }
1133
1134                   default:
1135                         error = EINVAL;
1136                         break;
1137                 }
1138                 break;
1139
1140           default:
1141                 error = EINVAL;
1142                 break;
1143         }
1144
1145         NG_RESPOND_MSG(error, node, item, resp);
1146         NG_FREE_MSG(msg);
1147         return (error);
1148 }
1149
1150 /************************************************************/
1151 /*
1152  * HOOK MANAGEMENT
1153  */
1154
1155 /*
1156  * A new hook is create that will be connected to the node.
1157  * Check, whether the name is one of the predefined ones.
1158  * If not, create a new entry into the vcc list.
1159  */
1160 static int
1161 ng_atm_newhook(node_p node, hook_p hook, const char *name)
1162 {
1163         struct priv *priv = NG_NODE_PRIVATE(node);
1164         struct ngvcc *vcc;
1165
1166         if (strcmp(name, "input") == 0) {
1167                 priv->input = hook;
1168                 NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
1169                 return (0);
1170         }
1171         if (strcmp(name, "output") == 0) {
1172                 priv->output = hook;
1173                 NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
1174                 return (0);
1175         }
1176         if (strcmp(name, "orphans") == 0) {
1177                 priv->orphans = hook;
1178                 NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
1179                 return (0);
1180         }
1181
1182         /*
1183          * Allocate a new entry
1184          */
1185         vcc = malloc(sizeof(*vcc), M_NETGRAPH, M_NOWAIT | M_ZERO);
1186         if (vcc == NULL)
1187                 return (ENOMEM);
1188
1189         vcc->hook = hook;
1190         NG_HOOK_SET_PRIVATE(hook, vcc);
1191
1192         LIST_INSERT_HEAD(&priv->vccs, vcc, link);
1193
1194         if (strcmp(name, "manage") == 0)
1195                 priv->manage = hook;
1196
1197         return (0);
1198 }
1199
1200 /*
1201  * Connect. Set the peer to queuing.
1202  */
1203 static int
1204 ng_atm_connect(hook_p hook)
1205 {
1206         if (NG_HOOK_PRIVATE(hook) != NULL)
1207                 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
1208
1209         return (0);
1210 }
1211
1212 /*
1213  * Disconnect a HOOK
1214  */
1215 static int
1216 ng_atm_disconnect(hook_p hook)
1217 {
1218         struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
1219         struct ngvcc *vcc = NG_HOOK_PRIVATE(hook);
1220
1221         if (vcc == NULL) {
1222                 if (hook == priv->output) {
1223                         priv->output = NULL;
1224                         return (0);
1225                 }
1226                 if (hook == priv->input) {
1227                         priv->input = NULL;
1228                         return (0);
1229                 }
1230                 if (hook == priv->orphans) {
1231                         priv->orphans = NULL;
1232                         return (0);
1233                 }
1234                 log(LOG_ERR, "ng_atm: bad hook '%s'", NG_HOOK_NAME(hook));
1235                 return (0);
1236         }
1237
1238         /* don't terminate if we are detaching from the interface */
1239         if ((vcc->flags & VCC_OPEN) && priv->ifp != NULL)
1240                 (void)cpcs_term(priv, vcc->vpi, vcc->vci);
1241
1242         NG_HOOK_SET_PRIVATE(hook, NULL);
1243
1244         LIST_REMOVE(vcc, link);
1245         free(vcc, M_NETGRAPH);
1246
1247         if (hook == priv->manage)
1248                 priv->manage = NULL;
1249
1250         return (0);
1251 }
1252
1253 /************************************************************/
1254 /*
1255  * NODE MANAGEMENT
1256  */
1257
1258 /*
1259  * ATM interface attached - create a node and name it like the interface.
1260  */
1261 static void
1262 ng_atm_attach(struct ifnet *ifp)
1263 {
1264         node_p node;
1265         struct priv *priv;
1266
1267         KASSERT(IFP2NG(ifp) == 0, ("%s: node alreay exists?", __func__));
1268
1269         if (ng_make_node_common(&ng_atm_typestruct, &node) != 0) {
1270                 log(LOG_ERR, "%s: can't create node for %s\n",
1271                     __func__, ifp->if_xname);
1272                 return;
1273         }
1274
1275         priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
1276         if (priv == NULL) {
1277                 log(LOG_ERR, "%s: can't allocate memory for %s\n",
1278                     __func__, ifp->if_xname);
1279                 NG_NODE_UNREF(node);
1280                 return;
1281         }
1282         NG_NODE_SET_PRIVATE(node, priv);
1283         priv->ifp = ifp;
1284         LIST_INIT(&priv->vccs);
1285         IFP2NG_SET(ifp, node);
1286
1287         if (ng_name_node(node, ifp->if_xname) != 0) {
1288                 log(LOG_WARNING, "%s: can't name node %s\n",
1289                     __func__, ifp->if_xname);
1290         }
1291 }
1292
1293 /*
1294  * ATM interface detached - destroy node.
1295  */
1296 static void
1297 ng_atm_detach(struct ifnet *ifp)
1298 {
1299         const node_p node = IFP2NG(ifp);
1300         struct priv *priv;
1301
1302         if(node == NULL)
1303                 return;
1304
1305         NG_NODE_REALLY_DIE(node);
1306
1307         priv = NG_NODE_PRIVATE(node);
1308         IFP2NG_SET(priv->ifp, NULL);
1309         priv->ifp = NULL;
1310
1311         ng_rmnode_self(node);
1312 }
1313
1314 /*
1315  * Shutdown the node. This is called from the shutdown message processing.
1316  */
1317 static int
1318 ng_atm_shutdown(node_p node)
1319 {
1320         struct priv *priv = NG_NODE_PRIVATE(node);
1321
1322         if (node->nd_flags & NGF_REALLY_DIE) {
1323                 /*
1324                  * We are called from unloading the ATM driver. Really,
1325                  * really need to shutdown this node. The ifp was
1326                  * already handled in the detach routine.
1327                  */
1328                 NG_NODE_SET_PRIVATE(node, NULL);
1329                 free(priv, M_NETGRAPH);
1330
1331                 NG_NODE_UNREF(node);
1332                 return (0);
1333         }
1334
1335 #ifdef NGATM_DEBUG
1336         if (!allow_shutdown)
1337                 NG_NODE_REVIVE(node);           /* we persist */
1338         else {
1339                 IFP2NG_SET(priv->ifp, NULL);
1340                 NG_NODE_SET_PRIVATE(node, NULL);
1341                 free(priv, M_NETGRAPH);
1342                 NG_NODE_UNREF(node);
1343         }
1344 #else
1345         /*
1346          * We are persistant - reinitialize
1347          */
1348         NG_NODE_REVIVE(node);
1349 #endif
1350         return (0);
1351 }
1352
1353 /*
1354  * Nodes are constructed only via interface attaches.
1355  */
1356 static int
1357 ng_atm_constructor(node_p nodep)
1358 {
1359         return (EINVAL);
1360 }
1361
1362 /************************************************************/
1363 /*
1364  * INITIALISATION
1365  */
1366 /*
1367  * Loading and unloading of node type
1368  *
1369  * The assignments to the globals for the hooks should be ok without
1370  * a special hook. The use pattern is generally: check that the pointer
1371  * is not NULL, call the function. In the attach case this is no problem.
1372  * In the detach case we can detach only when no ATM node exists. That
1373  * means that there is no ATM interface anymore. So we are sure that
1374  * we are not in the code path in if_atmsubr.c. To prevent someone
1375  * from adding an interface after we have started to unload the node, we
1376  * take the iflist lock so an if_attach will be blocked until we are done.
1377  * XXX: perhaps the function pointers should be 'volatile' for this to work
1378  * properly.
1379  */
1380 static int
1381 ng_atm_mod_event(module_t mod, int event, void *data)
1382 {
1383         VNET_ITERATOR_DECL(vnet_iter);
1384         struct ifnet *ifp;
1385         int error = 0;
1386
1387         switch (event) {
1388
1389           case MOD_LOAD:
1390                 /*
1391                  * Register function hooks
1392                  */
1393                 if (ng_atm_attach_p != NULL) {
1394                         error = EEXIST;
1395                         break;
1396                 }
1397                 IFNET_RLOCK();
1398
1399                 ng_atm_attach_p = ng_atm_attach;
1400                 ng_atm_detach_p = ng_atm_detach;
1401                 ng_atm_output_p = ng_atm_output;
1402                 ng_atm_input_p = ng_atm_input;
1403                 ng_atm_input_orphan_p = ng_atm_input_orphans;
1404                 ng_atm_event_p = ng_atm_event;
1405
1406                 /* Create nodes for existing ATM interfaces */
1407                 VNET_LIST_RLOCK();
1408                 VNET_FOREACH(vnet_iter) {
1409                         CURVNET_SET_QUIET(vnet_iter);
1410                         TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1411                                 if (ifp->if_type == IFT_ATM)
1412                                         ng_atm_attach(ifp);
1413                         }
1414                         CURVNET_RESTORE();
1415                 }
1416                 VNET_LIST_RUNLOCK();
1417                 IFNET_RUNLOCK();
1418                 break;
1419
1420           case MOD_UNLOAD:
1421                 IFNET_RLOCK();
1422
1423                 ng_atm_attach_p = NULL;
1424                 ng_atm_detach_p = NULL;
1425                 ng_atm_output_p = NULL;
1426                 ng_atm_input_p = NULL;
1427                 ng_atm_input_orphan_p = NULL;
1428                 ng_atm_event_p = NULL;
1429
1430                 VNET_LIST_RLOCK();
1431                 VNET_FOREACH(vnet_iter) {
1432                         CURVNET_SET_QUIET(vnet_iter);
1433                         TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1434                                 if (ifp->if_type == IFT_ATM)
1435                                         ng_atm_detach(ifp);
1436                         }
1437                         CURVNET_RESTORE();
1438                 }
1439                 VNET_LIST_RUNLOCK();
1440                 IFNET_RUNLOCK();
1441                 break;
1442
1443           default:
1444                 error = EOPNOTSUPP;
1445                 break;
1446         }
1447         return (error);
1448 }