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