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 $
30 * $DragonFly: src/sys/netgraph7/atm/ng_atm.c,v 1.2 2008/06/26 23:05:37 dillon Exp $
31 * $DragonFly: src/sys/netgraph7/atm/ng_atm.c,v 1.2 2008/06/26 23:05:37 dillon Exp $
35 * Netgraph module to connect NATM interfaces to netgraph.
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
42 #include <sys/errno.h>
43 #include <sys/syslog.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
47 #include <sys/ioccom.h>
48 #include <sys/sysctl.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>
57 #include "ng_message.h"
60 #include "atm/ng_atm.h"
63 * Hooks in the NATM code
65 extern void (*ng_atm_attach_p
)(struct ifnet
*);
66 extern void (*ng_atm_detach_p
)(struct ifnet
*);
67 extern int (*ng_atm_output_p
)(struct ifnet
*, struct mbuf
**);
68 extern void (*ng_atm_input_p
)(struct ifnet
*, struct mbuf
**,
69 struct atm_pseudohdr
*, void *);
70 extern void (*ng_atm_input_orphan_p
)(struct ifnet
*, struct mbuf
*,
71 struct atm_pseudohdr
*, void *);
72 extern void (*ng_atm_event_p
)(struct ifnet
*, uint32_t, void *);
77 SYSCTL_NODE(_net_graph
, OID_AUTO
, atm
, CTLFLAG_RW
, 0, "atm related stuff");
80 static int allow_shutdown
;
82 SYSCTL_INT(_net_graph_atm
, OID_AUTO
, allow_shutdown
, CTLFLAG_RW
,
83 &allow_shutdown
, 0, "allow ng_atm nodes to shutdown");
90 uint16_t vpi
; /* VPI of this hook */
91 uint16_t vci
; /* VCI of this hook, 0 if none */
92 uint32_t flags
; /* private flags */
93 hook_p hook
; /* the connected hook */
95 LIST_ENTRY(ngvcc
) link
;
97 #define VCC_OPEN 0x0001 /* open */
103 struct ifnet
*ifp
; /* the ATM interface */
104 hook_p input
; /* raw input hook */
105 hook_p orphans
; /* packets to nowhere */
106 hook_p output
; /* catch output packets */
107 hook_p manage
; /* has also entry in vccs */
110 uint64_t out_packets
;
113 LIST_HEAD(, ngvcc
) vccs
;
117 * Parse ifstate state
119 static const struct ng_parse_struct_field ng_atm_if_change_info
[] =
120 NGM_ATM_IF_CHANGE_INFO
;
121 static const struct ng_parse_type ng_atm_if_change_type
= {
122 &ng_parse_struct_type
,
123 &ng_atm_if_change_info
127 * Parse vcc state change
129 static const struct ng_parse_struct_field ng_atm_vcc_change_info
[] =
130 NGM_ATM_VCC_CHANGE_INFO
;
131 static const struct ng_parse_type ng_atm_vcc_change_type
= {
132 &ng_parse_struct_type
,
133 &ng_atm_vcc_change_info
139 static const struct ng_parse_struct_field ng_atm_acr_change_info
[] =
140 NGM_ATM_ACR_CHANGE_INFO
;
141 static const struct ng_parse_type ng_atm_acr_change_type
= {
142 &ng_parse_struct_type
,
143 &ng_atm_acr_change_info
147 * Parse the configuration structure ng_atm_config
149 static const struct ng_parse_struct_field ng_atm_config_type_info
[] =
152 static const struct ng_parse_type ng_atm_config_type
= {
153 &ng_parse_struct_type
,
154 &ng_atm_config_type_info
158 * Parse a single vcc structure and a variable array of these ng_atm_vccs
160 static const struct ng_parse_struct_field ng_atm_tparam_type_info
[] =
162 static const struct ng_parse_type ng_atm_tparam_type
= {
163 &ng_parse_struct_type
,
164 &ng_atm_tparam_type_info
166 static const struct ng_parse_struct_field ng_atm_vcc_type_info
[] =
168 static const struct ng_parse_type ng_atm_vcc_type
= {
169 &ng_parse_struct_type
,
170 &ng_atm_vcc_type_info
175 ng_atm_vccarray_getlen(const struct ng_parse_type
*type
,
176 const u_char
*start
, const u_char
*buf
)
178 const struct atmio_vcctable
*vp
;
180 vp
= (const struct atmio_vcctable
*)
181 (buf
- offsetof(struct atmio_vcctable
, vccs
));
185 static const struct ng_parse_array_info ng_atm_vccarray_info
=
186 NGM_ATM_VCCARRAY_INFO
;
187 static const struct ng_parse_type ng_atm_vccarray_type
= {
188 &ng_parse_array_type
,
189 &ng_atm_vccarray_info
193 static const struct ng_parse_struct_field ng_atm_vcctable_type_info
[] =
194 NGM_ATM_VCCTABLE_INFO
;
196 static const struct ng_parse_type ng_atm_vcctable_type
= {
197 &ng_parse_struct_type
,
198 &ng_atm_vcctable_type_info
202 * Parse CPCS INIT structure ng_atm_cpcs_init
204 static const struct ng_parse_struct_field ng_atm_cpcs_init_type_info
[] =
205 NGM_ATM_CPCS_INIT_INFO
;
207 static const struct ng_parse_type ng_atm_cpcs_init_type
= {
208 &ng_parse_struct_type
,
209 &ng_atm_cpcs_init_type_info
213 * Parse CPCS TERM structure ng_atm_cpcs_term
215 static const struct ng_parse_struct_field ng_atm_cpcs_term_type_info
[] =
216 NGM_ATM_CPCS_TERM_INFO
;
218 static const struct ng_parse_type ng_atm_cpcs_term_type
= {
219 &ng_parse_struct_type
,
220 &ng_atm_cpcs_term_type_info
224 * Parse statistic struct
226 static const struct ng_parse_struct_field ng_atm_stats_type_info
[] =
229 static const struct ng_parse_type ng_atm_stats_type
= {
230 &ng_parse_struct_type
,
231 &ng_atm_stats_type_info
234 static const struct ng_cmdlist ng_atm_cmdlist
[] = {
240 &ng_parse_string_type
254 &ng_atm_vcctable_type
260 &ng_atm_cpcs_init_type
,
267 &ng_atm_cpcs_term_type
,
274 &ng_parse_hookbuf_type
,
297 &ng_atm_if_change_type
,
298 &ng_atm_if_change_type
,
304 &ng_atm_vcc_change_type
,
305 &ng_atm_vcc_change_type
,
311 &ng_atm_acr_change_type
,
312 &ng_atm_acr_change_type
,
317 static int ng_atm_mod_event(module_t
, int, void *);
319 static ng_constructor_t ng_atm_constructor
;
320 static ng_shutdown_t ng_atm_shutdown
;
321 static ng_rcvmsg_t ng_atm_rcvmsg
;
322 static ng_newhook_t ng_atm_newhook
;
323 static ng_connect_t ng_atm_connect
;
324 static ng_disconnect_t ng_atm_disconnect
;
325 static ng_rcvdata_t ng_atm_rcvdata
;
326 static ng_rcvdata_t ng_atm_rcvdrop
;
328 static struct ng_type ng_atm_typestruct
= {
329 .version
= NG_ABI_VERSION
,
330 .name
= NG_ATM_NODE_TYPE
,
331 .mod_event
= ng_atm_mod_event
,
332 .constructor
= ng_atm_constructor
,
333 .rcvmsg
= ng_atm_rcvmsg
,
334 .shutdown
= ng_atm_shutdown
,
335 .newhook
= ng_atm_newhook
,
336 .connect
= ng_atm_connect
,
337 .rcvdata
= ng_atm_rcvdata
,
338 .disconnect
= ng_atm_disconnect
,
339 .cmdlist
= ng_atm_cmdlist
,
341 NETGRAPH_INIT(atm
, &ng_atm_typestruct
);
343 static const struct {
346 } atmmedia
[] = IFM_SUBTYPE_ATM_DESCRIPTIONS
;
349 #define IFP2NG(IFP) ((node_p)((struct ifatm *)(IFP)->if_softc)->ngpriv)
350 #define IFP2NG_SET(IFP, val) (((struct ifatm *)(IFP)->if_softc)->ngpriv = (val))
352 #define IFFLAGS "\020\001UP\002BROADCAST\003DEBUG\004LOOPBACK" \
353 "\005POINTOPOINT\006SMART\007RUNNING\010NOARP" \
354 "\011PROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX" \
355 "\015LINK0\016LINK1\017LINK2\020MULTICAST"
358 /************************************************************/
363 * A packet is received from an interface.
364 * If we have an input hook, prepend the pseudoheader to the data and
365 * deliver it out to that hook. If not, look whether it is destined for
366 * use. If so locate the appropriate hook, deliver the packet without the
367 * header and we are done. If it is not for us, leave it alone.
370 ng_atm_input(struct ifnet
*ifp
, struct mbuf
**mp
,
371 struct atm_pseudohdr
*ah
, void *rxhand
)
373 node_p node
= IFP2NG(ifp
);
375 const struct ngvcc
*vcc
;
380 priv
= NG_NODE_PRIVATE(node
);
381 if (priv
->input
!= NULL
) {
383 * Prepend the atm_pseudoheader.
385 M_PREPEND(*mp
, sizeof(*ah
), MB_DONTWAIT
);
388 memcpy(mtod(*mp
, struct atm_pseudohdr
*), ah
, sizeof(*ah
));
389 NG_SEND_DATA_ONLY(error
, priv
->input
, *mp
);
395 printf("%s: error=%d\n", __func__
, error
);
401 if ((ATM_PH_FLAGS(ah
) & ATMIO_FLAG_NG
) == 0)
404 vcc
= (struct ngvcc
*)rxhand
;
406 NG_SEND_DATA_ONLY(error
, vcc
->hook
, *mp
);
412 printf("%s: error=%d\n", __func__
, error
);
419 * ATM packet is about to be output. The atm_pseudohdr is already prepended.
420 * If the hook is set, reroute the packet to the hook.
423 ng_atm_output(struct ifnet
*ifp
, struct mbuf
**mp
)
425 const node_p node
= IFP2NG(ifp
);
426 const struct priv
*priv
;
431 priv
= NG_NODE_PRIVATE(node
);
433 NG_SEND_DATA_ONLY(error
, priv
->output
, *mp
);
441 * Well, this doesn't make much sense for ATM.
444 ng_atm_input_orphans(struct ifnet
*ifp
, struct mbuf
*m
,
445 struct atm_pseudohdr
*ah
, void *rxhand
)
447 node_p node
= IFP2NG(ifp
);
455 priv
= NG_NODE_PRIVATE(node
);
456 if (priv
->orphans
== NULL
) {
461 * Prepend the atm_pseudoheader.
463 M_PREPEND(m
, sizeof(*ah
), MB_DONTWAIT
);
466 memcpy(mtod(m
, struct atm_pseudohdr
*), ah
, sizeof(*ah
));
467 NG_SEND_DATA_ONLY(error
, priv
->orphans
, m
);
473 printf("%s: error=%d\n", __func__
, error
);
478 /************************************************************/
483 ng_atm_rcvdata(hook_p hook
, item_p item
)
485 node_p node
= NG_HOOK_NODE(hook
);
486 struct priv
*priv
= NG_NODE_PRIVATE(node
);
487 const struct ngvcc
*vcc
= NG_HOOK_PRIVATE(hook
);
489 struct atm_pseudohdr
*aph
;
501 * Prepend pseudo-hdr. Drivers don't care about the flags.
503 M_PREPEND(m
, sizeof(*aph
), MB_DONTWAIT
);
508 aph
= mtod(m
, struct atm_pseudohdr
*);
509 ATM_PH_VPI(aph
) = vcc
->vpi
;
510 ATM_PH_SETVCI(aph
, vcc
->vci
);
511 ATM_PH_FLAGS(aph
) = 0;
513 if ((error
= atm_output(priv
->ifp
, m
, NULL
, NULL
)) == 0)
521 ng_atm_rcvdrop(hook_p hook
, item_p item
)
528 /************************************************************
533 ng_atm_event_func(node_p node
, hook_p hook
, void *arg
, int event
)
535 const struct priv
*priv
= NG_NODE_PRIVATE(node
);
537 struct ng_mesg
*mesg
;
542 case ATMEV_FLOW_CONTROL
:
544 struct atmev_flow_control
*ev
= arg
;
545 struct ngm_queue_state
*qstate
;
547 /* find the connection */
548 LIST_FOREACH(vcc
, &priv
->vccs
, link
)
549 if (vcc
->vci
== ev
->vci
&& vcc
->vpi
== ev
->vpi
)
554 /* convert into a flow control message */
555 NG_MKMESSAGE(mesg
, NGM_FLOW_COOKIE
,
556 ev
->busy
? NGM_HIGH_WATER_PASSED
: NGM_LOW_WATER_PASSED
,
557 sizeof(struct ngm_queue_state
), M_WAITOK
| M_NULLOK
);
560 qstate
= (struct ngm_queue_state
*)mesg
->data
;
562 /* XXX have to figure out how to get that info */
564 NG_SEND_MSG_HOOK(error
, node
, mesg
, vcc
->hook
, 0);
568 case ATMEV_VCC_CHANGED
:
570 struct atmev_vcc_changed
*ev
= arg
;
571 struct ngm_atm_vcc_change
*chg
;
573 if (priv
->manage
== NULL
)
575 NG_MKMESSAGE(mesg
, NGM_ATM_COOKIE
, NGM_ATM_VCC_CHANGE
,
576 sizeof(struct ngm_atm_vcc_change
), M_WAITOK
| M_NULLOK
);
579 chg
= (struct ngm_atm_vcc_change
*)mesg
->data
;
582 chg
->state
= (ev
->up
!= 0);
583 chg
->node
= NG_NODE_ID(node
);
584 NG_SEND_MSG_HOOK(error
, node
, mesg
, priv
->manage
, 0);
588 case ATMEV_IFSTATE_CHANGED
:
590 struct atmev_ifstate_changed
*ev
= arg
;
591 struct ngm_atm_if_change
*chg
;
593 if (priv
->manage
== NULL
)
595 NG_MKMESSAGE(mesg
, NGM_ATM_COOKIE
, NGM_ATM_IF_CHANGE
,
596 sizeof(struct ngm_atm_if_change
), M_WAITOK
| M_NULLOK
);
599 chg
= (struct ngm_atm_if_change
*)mesg
->data
;
600 chg
->carrier
= (ev
->carrier
!= 0);
601 chg
->running
= (ev
->running
!= 0);
602 chg
->node
= NG_NODE_ID(node
);
603 NG_SEND_MSG_HOOK(error
, node
, mesg
, priv
->manage
, 0);
607 case ATMEV_ACR_CHANGED
:
609 struct atmev_acr_changed
*ev
= arg
;
610 struct ngm_atm_acr_change
*acr
;
612 /* find the connection */
613 LIST_FOREACH(vcc
, &priv
->vccs
, link
)
614 if (vcc
->vci
== ev
->vci
&& vcc
->vpi
== ev
->vpi
)
619 /* convert into a flow control message */
620 NG_MKMESSAGE(mesg
, NGM_ATM_COOKIE
, NGM_ATM_ACR_CHANGE
,
621 sizeof(struct ngm_atm_acr_change
), M_WAITOK
| M_NULLOK
);
624 acr
= (struct ngm_atm_acr_change
*)mesg
->data
;
625 acr
->node
= NG_NODE_ID(node
);
630 NG_SEND_MSG_HOOK(error
, node
, mesg
, vcc
->hook
, 0);
637 * Use send_fn to get the right lock
640 ng_atm_event(struct ifnet
*ifp
, uint32_t event
, void *arg
)
642 const node_p node
= IFP2NG(ifp
);
645 /* may happen during attach/detach */
646 (void)ng_send_fn(node
, NULL
, ng_atm_event_func
, arg
, event
);
649 /************************************************************
654 * Open a channel for the user
657 ng_atm_cpcs_init(node_p node
, const struct ngm_atm_cpcs_init
*arg
)
659 struct priv
*priv
= NG_NODE_PRIVATE(node
);
660 const struct ifatm_mib
*mib
;
662 struct atmio_openvcc data
;
665 if(priv
->ifp
->if_ioctl
== NULL
)
668 mib
= (const struct ifatm_mib
*)(priv
->ifp
->if_linkmib
);
670 LIST_FOREACH(vcc
, &priv
->vccs
, link
)
671 if (strcmp(arg
->name
, NG_HOOK_NAME(vcc
->hook
)) == 0)
675 if (vcc
->flags
& VCC_OPEN
)
679 * Check user arguments and construct ioctl argument
681 memset(&data
, 0, sizeof(data
));
685 switch (data
.param
.aal
= arg
->aal
) {
699 data
.param
.vpi
= arg
->vpi
;
701 /* allow 0.0 as catch all receive channel */
702 if (arg
->vci
== 0 && (arg
->vpi
!= 0 || !(arg
->flags
& ATMIO_FLAG_NOTX
)))
704 data
.param
.vci
= arg
->vci
;
706 data
.param
.tparam
.pcr
= arg
->pcr
;
708 if (arg
->mcr
> arg
->pcr
)
710 data
.param
.tparam
.mcr
= arg
->mcr
;
712 if (!(arg
->flags
& ATMIO_FLAG_NOTX
)) {
714 data
.param
.tmtu
= priv
->ifp
->if_mtu
;
716 data
.param
.tmtu
= arg
->tmtu
;
719 if (!(arg
->flags
& ATMIO_FLAG_NORX
)) {
721 data
.param
.rmtu
= priv
->ifp
->if_mtu
;
723 data
.param
.rmtu
= arg
->rmtu
;
727 switch (data
.param
.traffic
= arg
->traffic
) {
729 case ATMIO_TRAFFIC_UBR
:
730 case ATMIO_TRAFFIC_CBR
:
733 case ATMIO_TRAFFIC_VBR
:
734 if (arg
->scr
> arg
->pcr
)
736 data
.param
.tparam
.scr
= arg
->scr
;
738 if (arg
->mbs
> (1 << 24))
740 data
.param
.tparam
.mbs
= arg
->mbs
;
743 case ATMIO_TRAFFIC_ABR
:
744 if (arg
->icr
> arg
->pcr
|| arg
->icr
< arg
->mcr
)
746 data
.param
.tparam
.icr
= arg
->icr
;
748 if (arg
->tbe
== 0 || arg
->tbe
> (1 << 24))
750 data
.param
.tparam
.tbe
= arg
->tbe
;
754 data
.param
.tparam
.nrm
= arg
->nrm
;
758 data
.param
.tparam
.trm
= arg
->trm
;
760 if (arg
->adtf
> 0x3ff)
762 data
.param
.tparam
.adtf
= arg
->adtf
;
766 data
.param
.tparam
.rif
= arg
->rif
;
770 data
.param
.tparam
.rdf
= arg
->rdf
;
774 data
.param
.tparam
.cdf
= arg
->cdf
;
782 if ((arg
->flags
& ATMIO_FLAG_NORX
) && (arg
->flags
& ATMIO_FLAG_NOTX
))
785 data
.param
.flags
= arg
->flags
& ~(ATM_PH_AAL5
| ATM_PH_LLCSNAP
);
786 data
.param
.flags
|= ATMIO_FLAG_NG
;
788 err
= (*priv
->ifp
->if_ioctl
)(priv
->ifp
, SIOCATMOPENVCC
, (caddr_t
)&data
);
791 vcc
->vci
= data
.param
.vci
;
792 vcc
->vpi
= data
.param
.vpi
;
793 vcc
->flags
= VCC_OPEN
;
800 * Issue the close command to the driver
803 cpcs_term(const struct priv
*priv
, u_int vpi
, u_int vci
)
805 struct atmio_closevcc data
;
807 if (priv
->ifp
->if_ioctl
== NULL
)
813 return ((*priv
->ifp
->if_ioctl
)(priv
->ifp
,
814 SIOCATMCLOSEVCC
, (caddr_t
)&data
));
819 * Close a channel by request of the user
822 ng_atm_cpcs_term(node_p node
, const struct ngm_atm_cpcs_term
*arg
)
824 struct priv
*priv
= NG_NODE_PRIVATE(node
);
828 LIST_FOREACH(vcc
, &priv
->vccs
, link
)
829 if(strcmp(arg
->name
, NG_HOOK_NAME(vcc
->hook
)) == 0)
833 if (!(vcc
->flags
& VCC_OPEN
))
836 error
= cpcs_term(priv
, vcc
->vpi
, vcc
->vci
);
845 /************************************************************/
851 * Produce a textual description of the current status
854 text_status(node_p node
, char *arg
, u_int len
)
856 const struct priv
*priv
= NG_NODE_PRIVATE(node
);
857 const struct ifatm_mib
*mib
;
861 static const struct {
868 mib
= (const struct ifatm_mib
*)(priv
->ifp
->if_linkmib
);
870 sbuf_new(&sbuf
, arg
, len
, SBUF_FIXEDLEN
);
871 sbuf_printf(&sbuf
, "interface: %s\n", priv
->ifp
->if_xname
);
873 if (mib
->device
>= sizeof(devices
) / sizeof(devices
[0]))
874 sbuf_printf(&sbuf
, "device=unknown\nvendor=unknown\n");
876 sbuf_printf(&sbuf
, "device=%s\nvendor=%s\n",
877 devices
[mib
->device
].name
, devices
[mib
->device
].vendor
);
879 for (i
= 0; atmmedia
[i
].name
; i
++)
880 if(mib
->media
== atmmedia
[i
].media
) {
881 sbuf_printf(&sbuf
, "media=%s\n", atmmedia
[i
].name
);
884 if(atmmedia
[i
].name
== NULL
)
885 sbuf_printf(&sbuf
, "media=unknown\n");
887 sbuf_printf(&sbuf
, "serial=%u esi=%6D hardware=%u software=%u\n",
888 mib
->serial
, mib
->esi
, ":", mib
->hw_version
, mib
->sw_version
);
889 sbuf_printf(&sbuf
, "pcr=%u vpi_bits=%u vci_bits=%u max_vpcs=%u "
890 "max_vccs=%u\n", mib
->pcr
, mib
->vpi_bits
, mib
->vci_bits
,
891 mib
->max_vpcs
, mib
->max_vccs
);
892 sbuf_printf(&sbuf
, "ifflags=%b\n", priv
->ifp
->if_flags
, IFFLAGS
);
896 return (sbuf_len(&sbuf
));
900 * Get control message
903 ng_atm_rcvmsg(node_p node
, item_p item
, hook_p lasthook
)
905 const struct priv
*priv
= NG_NODE_PRIVATE(node
);
906 struct ng_mesg
*resp
= NULL
;
908 struct ifatm_mib
*mib
= (struct ifatm_mib
*)(priv
->ifp
->if_linkmib
);
911 NGI_GET_MSG(item
, msg
);
913 switch (msg
->header
.typecookie
) {
915 case NGM_GENERIC_COOKIE
:
916 switch (msg
->header
.cmd
) {
918 case NGM_TEXT_STATUS
:
919 NG_MKRESPONSE(resp
, msg
, NG_TEXTRESPONSE
, M_WAITOK
| M_NULLOK
);
925 resp
->header
.arglen
= text_status(node
,
926 (char *)resp
->data
, resp
->header
.arglen
) + 1;
936 switch (msg
->header
.cmd
) {
938 case NGM_ATM_GET_IFNAME
:
939 NG_MKRESPONSE(resp
, msg
, IFNAMSIZ
, M_WAITOK
| M_NULLOK
);
944 strlcpy(resp
->data
, priv
->ifp
->if_xname
, IFNAMSIZ
);
947 case NGM_ATM_GET_CONFIG
:
949 struct ngm_atm_config
*config
;
951 NG_MKRESPONSE(resp
, msg
, sizeof(*config
), M_WAITOK
| M_NULLOK
);
956 config
= (struct ngm_atm_config
*)resp
->data
;
957 config
->pcr
= mib
->pcr
;
958 config
->vpi_bits
= mib
->vpi_bits
;
959 config
->vci_bits
= mib
->vci_bits
;
960 config
->max_vpcs
= mib
->max_vpcs
;
961 config
->max_vccs
= mib
->max_vccs
;
965 case NGM_ATM_GET_VCCS
:
967 struct atmio_vcctable
*vccs
;
970 if (priv
->ifp
->if_ioctl
== NULL
) {
974 error
= (*priv
->ifp
->if_ioctl
)(priv
->ifp
,
975 SIOCATMGETVCCS
, (caddr_t
)&vccs
);
979 len
= sizeof(*vccs
) +
980 vccs
->count
* sizeof(vccs
->vccs
[0]);
981 NG_MKRESPONSE(resp
, msg
, len
, M_WAITOK
| M_NULLOK
);
984 kfree(vccs
, M_DEVBUF
);
988 (void)memcpy(resp
->data
, vccs
, len
);
989 kfree(vccs
, M_DEVBUF
);
994 case NGM_ATM_GET_VCC
:
996 char hook
[NG_HOOKSIZ
];
997 struct atmio_vcctable
*vccs
;
1001 if (priv
->ifp
->if_ioctl
== NULL
) {
1005 if (msg
->header
.arglen
!= NG_HOOKSIZ
) {
1009 strncpy(hook
, msg
->data
, NG_HOOKSIZ
);
1010 hook
[NG_HOOKSIZ
- 1] = '\0';
1011 LIST_FOREACH(vcc
, &priv
->vccs
, link
)
1012 if (strcmp(NG_HOOK_NAME(vcc
->hook
), hook
) == 0)
1018 error
= (*priv
->ifp
->if_ioctl
)(priv
->ifp
,
1019 SIOCATMGETVCCS
, (caddr_t
)&vccs
);
1023 for (i
= 0; i
< vccs
->count
; i
++)
1024 if (vccs
->vccs
[i
].vpi
== vcc
->vpi
&&
1025 vccs
->vccs
[i
].vci
== vcc
->vci
)
1027 if (i
== vccs
->count
) {
1029 kfree(vccs
, M_DEVBUF
);
1033 NG_MKRESPONSE(resp
, msg
, sizeof(vccs
->vccs
[0]),
1034 M_WAITOK
| M_NULLOK
);
1037 kfree(vccs
, M_DEVBUF
);
1041 *(struct atmio_vcc
*)resp
->data
= vccs
->vccs
[i
];
1042 kfree(vccs
, M_DEVBUF
);
1046 case NGM_ATM_GET_VCCID
:
1048 struct atmio_vcc
*arg
;
1049 struct atmio_vcctable
*vccs
;
1052 if (priv
->ifp
->if_ioctl
== NULL
) {
1056 if (msg
->header
.arglen
!= sizeof(*arg
)) {
1060 arg
= (struct atmio_vcc
*)msg
->data
;
1062 error
= (*priv
->ifp
->if_ioctl
)(priv
->ifp
,
1063 SIOCATMGETVCCS
, (caddr_t
)&vccs
);
1067 for (i
= 0; i
< vccs
->count
; i
++)
1068 if (vccs
->vccs
[i
].vpi
== arg
->vpi
&&
1069 vccs
->vccs
[i
].vci
== arg
->vci
)
1071 if (i
== vccs
->count
) {
1073 kfree(vccs
, M_DEVBUF
);
1077 NG_MKRESPONSE(resp
, msg
, sizeof(vccs
->vccs
[0]),
1078 M_WAITOK
| M_NULLOK
);
1081 kfree(vccs
, M_DEVBUF
);
1085 *(struct atmio_vcc
*)resp
->data
= vccs
->vccs
[i
];
1086 kfree(vccs
, M_DEVBUF
);
1090 case NGM_ATM_CPCS_INIT
:
1091 if (msg
->header
.arglen
!=
1092 sizeof(struct ngm_atm_cpcs_init
)) {
1096 error
= ng_atm_cpcs_init(node
,
1097 (struct ngm_atm_cpcs_init
*)msg
->data
);
1100 case NGM_ATM_CPCS_TERM
:
1101 if (msg
->header
.arglen
!=
1102 sizeof(struct ngm_atm_cpcs_term
)) {
1106 error
= ng_atm_cpcs_term(node
,
1107 (struct ngm_atm_cpcs_term
*)msg
->data
);
1110 case NGM_ATM_GET_STATS
:
1112 struct ngm_atm_stats
*p
;
1114 if (msg
->header
.arglen
!= 0) {
1118 NG_MKRESPONSE(resp
, msg
, sizeof(*p
), M_WAITOK
| M_NULLOK
);
1123 p
= (struct ngm_atm_stats
*)resp
->data
;
1124 p
->in_packets
= priv
->in_packets
;
1125 p
->out_packets
= priv
->out_packets
;
1126 p
->in_errors
= priv
->in_errors
;
1127 p
->out_errors
= priv
->out_errors
;
1143 NG_RESPOND_MSG(error
, node
, item
, resp
);
1148 /************************************************************/
1154 * A new hook is create that will be connected to the node.
1155 * Check, whether the name is one of the predefined ones.
1156 * If not, create a new entry into the vcc list.
1159 ng_atm_newhook(node_p node
, hook_p hook
, const char *name
)
1161 struct priv
*priv
= NG_NODE_PRIVATE(node
);
1164 if (strcmp(name
, "input") == 0) {
1166 NG_HOOK_SET_RCVDATA(hook
, ng_atm_rcvdrop
);
1169 if (strcmp(name
, "output") == 0) {
1170 priv
->output
= hook
;
1171 NG_HOOK_SET_RCVDATA(hook
, ng_atm_rcvdrop
);
1174 if (strcmp(name
, "orphans") == 0) {
1175 priv
->orphans
= hook
;
1176 NG_HOOK_SET_RCVDATA(hook
, ng_atm_rcvdrop
);
1181 * Allocate a new entry
1183 vcc
= kmalloc(sizeof(*vcc
), M_NETGRAPH
, M_WAITOK
| M_NULLOK
| M_ZERO
);
1188 NG_HOOK_SET_PRIVATE(hook
, vcc
);
1190 LIST_INSERT_HEAD(&priv
->vccs
, vcc
, link
);
1192 if (strcmp(name
, "manage") == 0)
1193 priv
->manage
= hook
;
1199 * Connect. Set the peer to queuing.
1202 ng_atm_connect(hook_p hook
)
1204 if (NG_HOOK_PRIVATE(hook
) != NULL
)
1205 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook
));
1214 ng_atm_disconnect(hook_p hook
)
1216 struct priv
*priv
= NG_NODE_PRIVATE(NG_HOOK_NODE(hook
));
1217 struct ngvcc
*vcc
= NG_HOOK_PRIVATE(hook
);
1220 if (hook
== priv
->output
) {
1221 priv
->output
= NULL
;
1224 if (hook
== priv
->input
) {
1228 if (hook
== priv
->orphans
) {
1229 priv
->orphans
= NULL
;
1232 log(LOG_ERR
, "ng_atm: bad hook '%s'", NG_HOOK_NAME(hook
));
1236 /* don't terminate if we are detaching from the interface */
1237 if ((vcc
->flags
& VCC_OPEN
) && priv
->ifp
!= NULL
)
1238 (void)cpcs_term(priv
, vcc
->vpi
, vcc
->vci
);
1240 NG_HOOK_SET_PRIVATE(hook
, NULL
);
1242 LIST_REMOVE(vcc
, link
);
1243 kfree(vcc
, M_NETGRAPH
);
1245 if (hook
== priv
->manage
)
1246 priv
->manage
= NULL
;
1251 /************************************************************/
1257 * ATM interface attached - create a node and name it like the interface.
1260 ng_atm_attach(struct ifnet
*ifp
)
1265 KASSERT(IFP2NG(ifp
) == 0, ("%s: node alreay exists?", __func__
));
1267 if (ng_make_node_common(&ng_atm_typestruct
, &node
) != 0) {
1268 log(LOG_ERR
, "%s: can't create node for %s\n",
1269 __func__
, ifp
->if_xname
);
1273 priv
= kmalloc(sizeof(*priv
), M_NETGRAPH
, M_WAITOK
| M_NULLOK
| M_ZERO
);
1275 log(LOG_ERR
, "%s: can't allocate memory for %s\n",
1276 __func__
, ifp
->if_xname
);
1277 NG_NODE_UNREF(node
);
1280 NG_NODE_SET_PRIVATE(node
, priv
);
1282 LIST_INIT(&priv
->vccs
);
1283 IFP2NG_SET(ifp
, node
);
1285 if (ng_name_node(node
, ifp
->if_xname
) != 0) {
1286 log(LOG_WARNING
, "%s: can't name node %s\n",
1287 __func__
, ifp
->if_xname
);
1292 * ATM interface detached - destroy node.
1295 ng_atm_detach(struct ifnet
*ifp
)
1297 const node_p node
= IFP2NG(ifp
);
1303 NG_NODE_REALLY_DIE(node
);
1305 priv
= NG_NODE_PRIVATE(node
);
1306 IFP2NG_SET(priv
->ifp
, NULL
);
1309 ng_rmnode_self(node
);
1313 * Shutdown the node. This is called from the shutdown message processing.
1316 ng_atm_shutdown(node_p node
)
1318 struct priv
*priv
= NG_NODE_PRIVATE(node
);
1320 if (node
->nd_flags
& NGF_REALLY_DIE
) {
1322 * We are called from unloading the ATM driver. Really,
1323 * really need to shutdown this node. The ifp was
1324 * already handled in the detach routine.
1326 NG_NODE_SET_PRIVATE(node
, NULL
);
1327 kfree(priv
, M_NETGRAPH
);
1329 NG_NODE_UNREF(node
);
1334 if (!allow_shutdown
)
1335 NG_NODE_REVIVE(node
); /* we persist */
1337 IFP2NG_SET(priv
->ifp
, NULL
);
1338 NG_NODE_SET_PRIVATE(node
, NULL
);
1339 kfree(priv
, M_NETGRAPH
);
1340 NG_NODE_UNREF(node
);
1344 * We are persistant - reinitialize
1346 NG_NODE_REVIVE(node
);
1352 * Nodes are constructed only via interface attaches.
1355 ng_atm_constructor(node_p nodep
)
1360 /************************************************************/
1365 * Loading and unloading of node type
1367 * The assignments to the globals for the hooks should be ok without
1368 * a special hook. The use pattern is generally: check that the pointer
1369 * is not NULL, call the function. In the attach case this is no problem.
1370 * In the detach case we can detach only when no ATM node exists. That
1371 * means that there is no ATM interface anymore. So we are sure that
1372 * we are not in the code path in if_atmsubr.c. To prevent someone
1373 * from adding an interface after we have started to unload the node, we
1374 * take the iflist lock so an if_attach will be blocked until we are done.
1375 * XXX: perhaps the function pointers should be 'volatile' for this to work
1379 ng_atm_mod_event(module_t mod
, int event
, void *data
)
1388 * Register function hooks
1390 if (ng_atm_attach_p
!= NULL
) {
1396 ng_atm_attach_p
= ng_atm_attach
;
1397 ng_atm_detach_p
= ng_atm_detach
;
1398 ng_atm_output_p
= ng_atm_output
;
1399 ng_atm_input_p
= ng_atm_input
;
1400 ng_atm_input_orphan_p
= ng_atm_input_orphans
;
1401 ng_atm_event_p
= ng_atm_event
;
1403 /* Create nodes for existing ATM interfaces */
1404 TAILQ_FOREACH(ifp
, &ifnet
, if_link
) {
1405 if (ifp
->if_type
== IFT_ATM
)
1414 ng_atm_attach_p
= NULL
;
1415 ng_atm_detach_p
= NULL
;
1416 ng_atm_output_p
= NULL
;
1417 ng_atm_input_p
= NULL
;
1418 ng_atm_input_orphan_p
= NULL
;
1419 ng_atm_event_p
= NULL
;
1421 TAILQ_FOREACH(ifp
, &ifnet
, if_link
) {
1422 if (ifp
->if_type
== IFT_ATM
)