2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 * Author: Hartmut Brandt <harti@freebsd.org>
29 * $FreeBSD: src/sys/netgraph/atm/ng_atm.c,v 1.15 2005/08/10 06:25:40 obrien Exp $
33 * Netgraph module to connect NATM interfaces to netgraph.
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
40 #include <sys/errno.h>
41 #include <sys/syslog.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
45 #include <sys/sysctl.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>
54 #include "ng_message.h"
57 #include "atm/ng_atm.h"
60 * Hooks in the NATM code
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 *);
74 SYSCTL_NODE(_net_graph, OID_AUTO, atm, CTLFLAG_RW, 0, "atm related stuff");
77 static int allow_shutdown;
79 SYSCTL_INT(_net_graph_atm, OID_AUTO, allow_shutdown, CTLFLAG_RW,
80 &allow_shutdown, 0, "allow ng_atm nodes to shutdown");
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 */
92 LIST_ENTRY(ngvcc) link;
94 #define VCC_OPEN 0x0001 /* open */
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 */
107 uint64_t out_packets;
110 LIST_HEAD(, ngvcc) vccs;
114 * Parse ifstate state
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
124 * Parse vcc state change
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
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
144 * Parse the configuration structure ng_atm_config
146 static const struct ng_parse_struct_field ng_atm_config_type_info[] =
149 static const struct ng_parse_type ng_atm_config_type = {
150 &ng_parse_struct_type,
151 &ng_atm_config_type_info
155 * Parse a single vcc structure and a variable array of these ng_atm_vccs
157 static const struct ng_parse_struct_field ng_atm_tparam_type_info[] =
159 static const struct ng_parse_type ng_atm_tparam_type = {
160 &ng_parse_struct_type,
161 &ng_atm_tparam_type_info
163 static const struct ng_parse_struct_field ng_atm_vcc_type_info[] =
165 static const struct ng_parse_type ng_atm_vcc_type = {
166 &ng_parse_struct_type,
167 &ng_atm_vcc_type_info
172 ng_atm_vccarray_getlen(const struct ng_parse_type *type,
173 const u_char *start, const u_char *buf)
175 const struct atmio_vcctable *vp;
177 vp = (const struct atmio_vcctable *)
178 (buf - offsetof(struct atmio_vcctable, vccs));
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
190 static const struct ng_parse_struct_field ng_atm_vcctable_type_info[] =
191 NGM_ATM_VCCTABLE_INFO;
193 static const struct ng_parse_type ng_atm_vcctable_type = {
194 &ng_parse_struct_type,
195 &ng_atm_vcctable_type_info
199 * Parse CPCS INIT structure ng_atm_cpcs_init
201 static const struct ng_parse_struct_field ng_atm_cpcs_init_type_info[] =
202 NGM_ATM_CPCS_INIT_INFO;
204 static const struct ng_parse_type ng_atm_cpcs_init_type = {
205 &ng_parse_struct_type,
206 &ng_atm_cpcs_init_type_info
210 * Parse CPCS TERM structure ng_atm_cpcs_term
212 static const struct ng_parse_struct_field ng_atm_cpcs_term_type_info[] =
213 NGM_ATM_CPCS_TERM_INFO;
215 static const struct ng_parse_type ng_atm_cpcs_term_type = {
216 &ng_parse_struct_type,
217 &ng_atm_cpcs_term_type_info
221 * Parse statistic struct
223 static const struct ng_parse_struct_field ng_atm_stats_type_info[] =
226 static const struct ng_parse_type ng_atm_stats_type = {
227 &ng_parse_struct_type,
228 &ng_atm_stats_type_info
231 static const struct ng_cmdlist ng_atm_cmdlist[] = {
237 &ng_parse_string_type
251 &ng_atm_vcctable_type
257 &ng_atm_cpcs_init_type,
264 &ng_atm_cpcs_term_type,
271 &ng_parse_hookbuf_type,
294 &ng_atm_if_change_type,
295 &ng_atm_if_change_type,
301 &ng_atm_vcc_change_type,
302 &ng_atm_vcc_change_type,
308 &ng_atm_acr_change_type,
309 &ng_atm_acr_change_type,
314 static int ng_atm_mod_event(module_t, int, void *);
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;
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,
338 NETGRAPH_INIT(atm, &ng_atm_typestruct);
340 static const struct {
343 } atmmedia[] = IFM_SUBTYPE_ATM_DESCRIPTIONS;
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))
349 #define IFFLAGS "\020\001UP\002BROADCAST\003DEBUG\004LOOPBACK" \
350 "\005POINTOPOINT\006SMART\007RUNNING\010NOARP" \
351 "\011PROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX" \
352 "\015LINK0\016LINK1\017LINK2\020MULTICAST"
355 /************************************************************/
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.
367 ng_atm_input(struct ifnet *ifp, struct mbuf **mp,
368 struct atm_pseudohdr *ah, void *rxhand)
370 node_p node = IFP2NG(ifp);
372 const struct ngvcc *vcc;
377 priv = NG_NODE_PRIVATE(node);
378 if (priv->input != NULL) {
380 * Prepend the atm_pseudoheader.
382 M_PREPEND(*mp, sizeof(*ah), MB_DONTWAIT);
385 memcpy(mtod(*mp, struct atm_pseudohdr *), ah, sizeof(*ah));
386 NG_SEND_DATA_ONLY(error, priv->input, *mp);
392 printf("%s: error=%d\n", __func__, error);
398 if ((ATM_PH_FLAGS(ah) & ATMIO_FLAG_NG) == 0)
401 vcc = (struct ngvcc *)rxhand;
403 NG_SEND_DATA_ONLY(error, vcc->hook, *mp);
409 printf("%s: error=%d\n", __func__, error);
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.
420 ng_atm_output(struct ifnet *ifp, struct mbuf **mp)
422 const node_p node = IFP2NG(ifp);
423 const struct priv *priv;
428 priv = NG_NODE_PRIVATE(node);
430 NG_SEND_DATA_ONLY(error, priv->output, *mp);
438 * Well, this doesn't make much sense for ATM.
441 ng_atm_input_orphans(struct ifnet *ifp, struct mbuf *m,
442 struct atm_pseudohdr *ah, void *rxhand)
444 node_p node = IFP2NG(ifp);
452 priv = NG_NODE_PRIVATE(node);
453 if (priv->orphans == NULL) {
458 * Prepend the atm_pseudoheader.
460 M_PREPEND(m, sizeof(*ah), MB_DONTWAIT);
463 memcpy(mtod(m, struct atm_pseudohdr *), ah, sizeof(*ah));
464 NG_SEND_DATA_ONLY(error, priv->orphans, m);
470 printf("%s: error=%d\n", __func__, error);
475 /************************************************************/
480 ng_atm_rcvdata(hook_p hook, item_p item)
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);
486 struct atm_pseudohdr *aph;
498 * Prepend pseudo-hdr. Drivers don't care about the flags.
500 M_PREPEND(m, sizeof(*aph), MB_DONTWAIT);
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;
510 if ((error = atm_output(priv->ifp, m, NULL, NULL)) == 0)
518 ng_atm_rcvdrop(hook_p hook, item_p item)
525 /************************************************************
530 ng_atm_event_func(node_p node, hook_p hook, void *arg, int event)
532 const struct priv *priv = NG_NODE_PRIVATE(node);
534 struct ng_mesg *mesg;
539 case ATMEV_FLOW_CONTROL:
541 struct atmev_flow_control *ev = arg;
542 struct ngm_queue_state *qstate;
544 /* find the connection */
545 LIST_FOREACH(vcc, &priv->vccs, link)
546 if (vcc->vci == ev->vci && vcc->vpi == ev->vpi)
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);
557 qstate = (struct ngm_queue_state *)mesg->data;
559 /* XXX have to figure out how to get that info */
561 NG_SEND_MSG_HOOK(error, node, mesg, vcc->hook, 0);
565 case ATMEV_VCC_CHANGED:
567 struct atmev_vcc_changed *ev = arg;
568 struct ngm_atm_vcc_change *chg;
570 if (priv->manage == NULL)
572 NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_VCC_CHANGE,
573 sizeof(struct ngm_atm_vcc_change), M_WAITOK | M_NULLOK);
576 chg = (struct ngm_atm_vcc_change *)mesg->data;
579 chg->state = (ev->up != 0);
580 chg->node = NG_NODE_ID(node);
581 NG_SEND_MSG_HOOK(error, node, mesg, priv->manage, 0);
585 case ATMEV_IFSTATE_CHANGED:
587 struct atmev_ifstate_changed *ev = arg;
588 struct ngm_atm_if_change *chg;
590 if (priv->manage == NULL)
592 NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_IF_CHANGE,
593 sizeof(struct ngm_atm_if_change), M_WAITOK | M_NULLOK);
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);
604 case ATMEV_ACR_CHANGED:
606 struct atmev_acr_changed *ev = arg;
607 struct ngm_atm_acr_change *acr;
609 /* find the connection */
610 LIST_FOREACH(vcc, &priv->vccs, link)
611 if (vcc->vci == ev->vci && vcc->vpi == ev->vpi)
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);
621 acr = (struct ngm_atm_acr_change *)mesg->data;
622 acr->node = NG_NODE_ID(node);
627 NG_SEND_MSG_HOOK(error, node, mesg, vcc->hook, 0);
634 * Use send_fn to get the right lock
637 ng_atm_event(struct ifnet *ifp, uint32_t event, void *arg)
639 const node_p node = IFP2NG(ifp);
642 /* may happen during attach/detach */
643 (void)ng_send_fn(node, NULL, ng_atm_event_func, arg, event);
646 /************************************************************
651 * Open a channel for the user
654 ng_atm_cpcs_init(node_p node, const struct ngm_atm_cpcs_init *arg)
656 struct priv *priv = NG_NODE_PRIVATE(node);
657 const struct ifatm_mib *mib;
659 struct atmio_openvcc data;
662 if(priv->ifp->if_ioctl == NULL)
665 mib = (const struct ifatm_mib *)(priv->ifp->if_linkmib);
667 LIST_FOREACH(vcc, &priv->vccs, link)
668 if (strcmp(arg->name, NG_HOOK_NAME(vcc->hook)) == 0)
672 if (vcc->flags & VCC_OPEN)
676 * Check user arguments and construct ioctl argument
678 memset(&data, 0, sizeof(data));
682 switch (data.param.aal = arg->aal) {
696 data.param.vpi = arg->vpi;
698 /* allow 0.0 as catch all receive channel */
699 if (arg->vci == 0 && (arg->vpi != 0 || !(arg->flags & ATMIO_FLAG_NOTX)))
701 data.param.vci = arg->vci;
703 data.param.tparam.pcr = arg->pcr;
705 if (arg->mcr > arg->pcr)
707 data.param.tparam.mcr = arg->mcr;
709 if (!(arg->flags & ATMIO_FLAG_NOTX)) {
711 data.param.tmtu = priv->ifp->if_mtu;
713 data.param.tmtu = arg->tmtu;
716 if (!(arg->flags & ATMIO_FLAG_NORX)) {
718 data.param.rmtu = priv->ifp->if_mtu;
720 data.param.rmtu = arg->rmtu;
724 switch (data.param.traffic = arg->traffic) {
726 case ATMIO_TRAFFIC_UBR:
727 case ATMIO_TRAFFIC_CBR:
730 case ATMIO_TRAFFIC_VBR:
731 if (arg->scr > arg->pcr)
733 data.param.tparam.scr = arg->scr;
735 if (arg->mbs > (1 << 24))
737 data.param.tparam.mbs = arg->mbs;
740 case ATMIO_TRAFFIC_ABR:
741 if (arg->icr > arg->pcr || arg->icr < arg->mcr)
743 data.param.tparam.icr = arg->icr;
745 if (arg->tbe == 0 || arg->tbe > (1 << 24))
747 data.param.tparam.tbe = arg->tbe;
751 data.param.tparam.nrm = arg->nrm;
755 data.param.tparam.trm = arg->trm;
757 if (arg->adtf > 0x3ff)
759 data.param.tparam.adtf = arg->adtf;
763 data.param.tparam.rif = arg->rif;
767 data.param.tparam.rdf = arg->rdf;
771 data.param.tparam.cdf = arg->cdf;
779 if ((arg->flags & ATMIO_FLAG_NORX) && (arg->flags & ATMIO_FLAG_NOTX))
782 data.param.flags = arg->flags & ~(ATM_PH_AAL5 | ATM_PH_LLCSNAP);
783 data.param.flags |= ATMIO_FLAG_NG;
785 err = (*priv->ifp->if_ioctl)(priv->ifp, SIOCATMOPENVCC, (caddr_t)&data);
788 vcc->vci = data.param.vci;
789 vcc->vpi = data.param.vpi;
790 vcc->flags = VCC_OPEN;
797 * Issue the close command to the driver
800 cpcs_term(const struct priv *priv, u_int vpi, u_int vci)
802 struct atmio_closevcc data;
804 if (priv->ifp->if_ioctl == NULL)
810 return ((*priv->ifp->if_ioctl)(priv->ifp,
811 SIOCATMCLOSEVCC, (caddr_t)&data));
816 * Close a channel by request of the user
819 ng_atm_cpcs_term(node_p node, const struct ngm_atm_cpcs_term *arg)
821 struct priv *priv = NG_NODE_PRIVATE(node);
825 LIST_FOREACH(vcc, &priv->vccs, link)
826 if(strcmp(arg->name, NG_HOOK_NAME(vcc->hook)) == 0)
830 if (!(vcc->flags & VCC_OPEN))
833 error = cpcs_term(priv, vcc->vpi, vcc->vci);
842 /************************************************************/
848 * Produce a textual description of the current status
851 text_status(node_p node, char *arg, u_int len)
853 const struct priv *priv = NG_NODE_PRIVATE(node);
854 const struct ifatm_mib *mib;
858 static const struct {
865 mib = (const struct ifatm_mib *)(priv->ifp->if_linkmib);
867 sbuf_new(&sbuf, arg, len, SBUF_FIXEDLEN);
868 sbuf_printf(&sbuf, "interface: %s\n", priv->ifp->if_xname);
870 if (mib->device >= NELEM(devices))
871 sbuf_printf(&sbuf, "device=unknown\nvendor=unknown\n");
873 sbuf_printf(&sbuf, "device=%s\nvendor=%s\n",
874 devices[mib->device].name, devices[mib->device].vendor);
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);
881 if(atmmedia[i].name == NULL)
882 sbuf_printf(&sbuf, "media=unknown\n");
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);
893 return (sbuf_len(&sbuf));
897 * Get control message
900 ng_atm_rcvmsg(node_p node, item_p item, hook_p lasthook)
902 const struct priv *priv = NG_NODE_PRIVATE(node);
903 struct ng_mesg *resp = NULL;
905 struct ifatm_mib *mib = (struct ifatm_mib *)(priv->ifp->if_linkmib);
908 NGI_GET_MSG(item, msg);
910 switch (msg->header.typecookie) {
912 case NGM_GENERIC_COOKIE:
913 switch (msg->header.cmd) {
915 case NGM_TEXT_STATUS:
916 NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_WAITOK | M_NULLOK);
922 resp->header.arglen = text_status(node,
923 (char *)resp->data, resp->header.arglen) + 1;
933 switch (msg->header.cmd) {
935 case NGM_ATM_GET_IFNAME:
936 NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_WAITOK | M_NULLOK);
941 strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ);
944 case NGM_ATM_GET_CONFIG:
946 struct ngm_atm_config *config;
948 NG_MKRESPONSE(resp, msg, sizeof(*config), M_WAITOK | M_NULLOK);
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;
962 case NGM_ATM_GET_VCCS:
964 struct atmio_vcctable *vccs;
967 if (priv->ifp->if_ioctl == NULL) {
971 error = (*priv->ifp->if_ioctl)(priv->ifp,
972 SIOCATMGETVCCS, (caddr_t)&vccs);
976 len = sizeof(*vccs) +
977 vccs->count * sizeof(vccs->vccs[0]);
978 NG_MKRESPONSE(resp, msg, len, M_WAITOK | M_NULLOK);
981 kfree(vccs, M_DEVBUF);
985 (void)memcpy(resp->data, vccs, len);
986 kfree(vccs, M_DEVBUF);
991 case NGM_ATM_GET_VCC:
993 char hook[NG_HOOKSIZ];
994 struct atmio_vcctable *vccs;
998 if (priv->ifp->if_ioctl == NULL) {
1002 if (msg->header.arglen != NG_HOOKSIZ) {
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)
1015 error = (*priv->ifp->if_ioctl)(priv->ifp,
1016 SIOCATMGETVCCS, (caddr_t)&vccs);
1020 for (i = 0; i < vccs->count; i++)
1021 if (vccs->vccs[i].vpi == vcc->vpi &&
1022 vccs->vccs[i].vci == vcc->vci)
1024 if (i == vccs->count) {
1026 kfree(vccs, M_DEVBUF);
1030 NG_MKRESPONSE(resp, msg, sizeof(vccs->vccs[0]),
1031 M_WAITOK | M_NULLOK);
1034 kfree(vccs, M_DEVBUF);
1038 *(struct atmio_vcc *)resp->data = vccs->vccs[i];
1039 kfree(vccs, M_DEVBUF);
1043 case NGM_ATM_GET_VCCID:
1045 struct atmio_vcc *arg;
1046 struct atmio_vcctable *vccs;
1049 if (priv->ifp->if_ioctl == NULL) {
1053 if (msg->header.arglen != sizeof(*arg)) {
1057 arg = (struct atmio_vcc *)msg->data;
1059 error = (*priv->ifp->if_ioctl)(priv->ifp,
1060 SIOCATMGETVCCS, (caddr_t)&vccs);
1064 for (i = 0; i < vccs->count; i++)
1065 if (vccs->vccs[i].vpi == arg->vpi &&
1066 vccs->vccs[i].vci == arg->vci)
1068 if (i == vccs->count) {
1070 kfree(vccs, M_DEVBUF);
1074 NG_MKRESPONSE(resp, msg, sizeof(vccs->vccs[0]),
1075 M_WAITOK | M_NULLOK);
1078 kfree(vccs, M_DEVBUF);
1082 *(struct atmio_vcc *)resp->data = vccs->vccs[i];
1083 kfree(vccs, M_DEVBUF);
1087 case NGM_ATM_CPCS_INIT:
1088 if (msg->header.arglen !=
1089 sizeof(struct ngm_atm_cpcs_init)) {
1093 error = ng_atm_cpcs_init(node,
1094 (struct ngm_atm_cpcs_init *)msg->data);
1097 case NGM_ATM_CPCS_TERM:
1098 if (msg->header.arglen !=
1099 sizeof(struct ngm_atm_cpcs_term)) {
1103 error = ng_atm_cpcs_term(node,
1104 (struct ngm_atm_cpcs_term *)msg->data);
1107 case NGM_ATM_GET_STATS:
1109 struct ngm_atm_stats *p;
1111 if (msg->header.arglen != 0) {
1115 NG_MKRESPONSE(resp, msg, sizeof(*p), M_WAITOK | M_NULLOK);
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;
1140 NG_RESPOND_MSG(error, node, item, resp);
1145 /************************************************************/
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.
1156 ng_atm_newhook(node_p node, hook_p hook, const char *name)
1158 struct priv *priv = NG_NODE_PRIVATE(node);
1161 if (strcmp(name, "input") == 0) {
1163 NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
1166 if (strcmp(name, "output") == 0) {
1167 priv->output = hook;
1168 NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
1171 if (strcmp(name, "orphans") == 0) {
1172 priv->orphans = hook;
1173 NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
1178 * Allocate a new entry
1180 vcc = kmalloc(sizeof(*vcc), M_NETGRAPH, M_WAITOK | M_NULLOK | M_ZERO);
1185 NG_HOOK_SET_PRIVATE(hook, vcc);
1187 LIST_INSERT_HEAD(&priv->vccs, vcc, link);
1189 if (strcmp(name, "manage") == 0)
1190 priv->manage = hook;
1196 * Connect. Set the peer to queuing.
1199 ng_atm_connect(hook_p hook)
1201 if (NG_HOOK_PRIVATE(hook) != NULL)
1202 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
1211 ng_atm_disconnect(hook_p hook)
1213 struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
1214 struct ngvcc *vcc = NG_HOOK_PRIVATE(hook);
1217 if (hook == priv->output) {
1218 priv->output = NULL;
1221 if (hook == priv->input) {
1225 if (hook == priv->orphans) {
1226 priv->orphans = NULL;
1229 log(LOG_ERR, "ng_atm: bad hook '%s'", NG_HOOK_NAME(hook));
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);
1237 NG_HOOK_SET_PRIVATE(hook, NULL);
1239 LIST_REMOVE(vcc, link);
1240 kfree(vcc, M_NETGRAPH);
1242 if (hook == priv->manage)
1243 priv->manage = NULL;
1248 /************************************************************/
1254 * ATM interface attached - create a node and name it like the interface.
1257 ng_atm_attach(struct ifnet *ifp)
1262 KASSERT(IFP2NG(ifp) == 0, ("%s: node alreay exists?", __func__));
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);
1270 priv = kmalloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_NULLOK | M_ZERO);
1272 log(LOG_ERR, "%s: can't allocate memory for %s\n",
1273 __func__, ifp->if_xname);
1274 NG_NODE_UNREF(node);
1277 NG_NODE_SET_PRIVATE(node, priv);
1279 LIST_INIT(&priv->vccs);
1280 IFP2NG_SET(ifp, node);
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);
1289 * ATM interface detached - destroy node.
1292 ng_atm_detach(struct ifnet *ifp)
1294 const node_p node = IFP2NG(ifp);
1300 NG_NODE_REALLY_DIE(node);
1302 priv = NG_NODE_PRIVATE(node);
1303 IFP2NG_SET(priv->ifp, NULL);
1306 ng_rmnode_self(node);
1310 * Shutdown the node. This is called from the shutdown message processing.
1313 ng_atm_shutdown(node_p node)
1315 struct priv *priv = NG_NODE_PRIVATE(node);
1317 if (node->nd_flags & NGF_REALLY_DIE) {
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.
1323 NG_NODE_SET_PRIVATE(node, NULL);
1324 kfree(priv, M_NETGRAPH);
1326 NG_NODE_UNREF(node);
1331 if (!allow_shutdown)
1332 NG_NODE_REVIVE(node); /* we persist */
1334 IFP2NG_SET(priv->ifp, NULL);
1335 NG_NODE_SET_PRIVATE(node, NULL);
1336 kfree(priv, M_NETGRAPH);
1337 NG_NODE_UNREF(node);
1341 * We are persistant - reinitialize
1343 NG_NODE_REVIVE(node);
1349 * Nodes are constructed only via interface attaches.
1352 ng_atm_constructor(node_p nodep)
1357 /************************************************************/
1362 * Loading and unloading of node type
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
1376 ng_atm_mod_event(module_t mod, int event, void *data)
1385 * Register function hooks
1387 if (ng_atm_attach_p != NULL) {
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;
1400 /* Create nodes for existing ATM interfaces */
1401 TAILQ_FOREACH(ifp, &ifnet, if_link) {
1402 if (ifp->if_type == IFT_ATM)
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;
1418 TAILQ_FOREACH(ifp, &ifnet, if_link) {
1419 if (ifp->if_type == IFT_ATM)