ng_atm.c revision 117642
1116808Sharti/*
2116808Sharti * Copyright (c) 2001-2003
3116808Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4116808Sharti * 	All rights reserved.
5116808Sharti *
6116808Sharti * Redistribution and use in source and binary forms, with or without
7116808Sharti * modification, are permitted provided that the following conditions
8116808Sharti * are met:
9116808Sharti * 1. Redistributions of source code must retain the above copyright
10116808Sharti *    notice, this list of conditions and the following disclaimer.
11116808Sharti * 2. Redistributions in binary form must reproduce the above copyright
12116808Sharti *    notice, this list of conditions and the following disclaimer in the
13116808Sharti *    documentation and/or other materials provided with the distribution.
14116808Sharti *
15116808Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16116808Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17116808Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18116808Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19116808Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20116808Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21116808Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22116808Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23116808Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24116808Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25116808Sharti * SUCH DAMAGE.
26116808Sharti *
27116808Sharti * Author: Hartmut Brandt <harti@freebsd.org>
28116808Sharti *
29116808Sharti * Netgraph module to connect NATM interfaces to netgraph.
30116808Sharti */
31116808Sharti
32116808Sharti#include <sys/cdefs.h>
33116808Sharti__FBSDID("$FreeBSD: head/sys/netgraph/atm/ng_atm.c 117642 2003-07-15 15:48:10Z harti $");
34116808Sharti
35116808Sharti#include <sys/param.h>
36116808Sharti#include <sys/systm.h>
37116808Sharti#include <sys/kernel.h>
38116808Sharti#include <sys/malloc.h>
39116808Sharti#include <sys/mbuf.h>
40116808Sharti#include <sys/errno.h>
41116808Sharti#include <sys/syslog.h>
42116808Sharti#include <sys/socket.h>
43116808Sharti#include <sys/socketvar.h>
44116808Sharti#include <sys/sbuf.h>
45116808Sharti#include <sys/ioccom.h>
46116808Sharti#include <sys/sysctl.h>
47116808Sharti
48116808Sharti#include <net/if.h>
49116808Sharti#include <net/if_types.h>
50116808Sharti#include <net/if_arp.h>
51116808Sharti#include <net/if_var.h>
52116808Sharti#include <net/if_media.h>
53116808Sharti#include <net/if_atm.h>
54116808Sharti
55116808Sharti#include <netgraph/ng_message.h>
56116808Sharti#include <netgraph/netgraph.h>
57116808Sharti#include <netgraph/ng_parse.h>
58116808Sharti#include <netgraph/atm/ng_atm.h>
59116808Sharti
60116808Sharti/*
61116808Sharti * Hooks in the NATM code
62116808Sharti */
63116808Shartiextern void	(*ng_atm_attach_p)(struct ifnet *);
64116808Shartiextern void	(*ng_atm_detach_p)(struct ifnet *);
65116808Shartiextern int	(*ng_atm_output_p)(struct ifnet *, struct mbuf **);
66116808Shartiextern void	(*ng_atm_input_p)(struct ifnet *, struct mbuf **,
67116808Sharti		    struct atm_pseudohdr *, void *);
68116808Shartiextern void	(*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *,
69116808Sharti		    struct atm_pseudohdr *, void *);
70116808Shartiextern void	(*ng_atm_message_p)(struct ifnet *, uint32_t, uint32_t);
71116808Sharti
72116808Sharti/*
73116808Sharti * Sysctl stuff.
74116808Sharti */
75116808ShartiSYSCTL_NODE(_net_graph, OID_AUTO, atm, CTLFLAG_RW, 0, "atm related stuff");
76116808Sharti
77116808Sharti#ifdef NGATM_DEBUG
78116808Shartistatic int allow_shutdown;
79116808Sharti
80116808ShartiSYSCTL_INT(_net_graph_atm, OID_AUTO, allow_shutdown, CTLFLAG_RW,
81116808Sharti    &allow_shutdown, 0, "allow ng_atm nodes to shutdown");
82116808Sharti#endif
83116808Sharti
84116808Sharti/*
85116808Sharti * Hook private data
86116808Sharti */
87116808Shartistruct ngvcc {
88116808Sharti	uint16_t	vpi;	/* VPI of this hook */
89116808Sharti	uint16_t	vci;	/* VCI of this hook, 0 if none */
90116808Sharti	uint32_t	flags;	/* private flags */
91116808Sharti	hook_p		hook;	/* the connected hook */
92116808Sharti
93116808Sharti	LIST_ENTRY(ngvcc) link;
94116808Sharti};
95117157Sharti#define	VCC_OPEN	0x0001	/* open */
96116808Sharti
97116808Sharti/*
98116808Sharti * Node private data
99116808Sharti */
100116808Shartistruct priv {
101116808Sharti	struct ifnet	*ifp;		/* the ATM interface */
102116808Sharti	hook_p		input;		/* raw input hook */
103116808Sharti	hook_p		orphans;	/* packets to nowhere */
104116808Sharti	hook_p		output;		/* catch output packets */
105116808Sharti	hook_p		manage;		/* has also entry in vccs */
106116808Sharti	uint64_t	in_packets;
107116808Sharti	uint64_t	in_errors;
108116808Sharti	uint64_t	out_packets;
109116808Sharti	uint64_t	out_errors;
110116808Sharti
111116808Sharti	LIST_HEAD(, ngvcc) vccs;
112116808Sharti};
113116808Sharti
114116808Sharti/*
115116808Sharti * Parse carrier state
116116808Sharti */
117116808Shartistatic const struct ng_parse_struct_field ng_atm_carrier_change_info[] =
118116808Sharti    NGM_ATM_CARRIER_CHANGE_INFO;
119116808Shartistatic const struct ng_parse_type ng_atm_carrier_change_type = {
120116808Sharti	&ng_parse_struct_type,
121116808Sharti	&ng_atm_carrier_change_info
122116808Sharti};
123116808Sharti
124116808Sharti/*
125116808Sharti * Parse the configuration structure ng_atm_config
126116808Sharti */
127116808Shartistatic const struct ng_parse_struct_field ng_atm_config_type_info[] =
128116808Sharti    NGM_ATM_CONFIG_INFO;
129116808Sharti
130116808Shartistatic const struct ng_parse_type ng_atm_config_type = {
131116808Sharti	&ng_parse_struct_type,
132116808Sharti	&ng_atm_config_type_info
133116808Sharti};
134116808Sharti
135116808Sharti/*
136116808Sharti * Parse a single vcc structure and a variable array of these ng_atm_vccs
137116808Sharti */
138116808Shartistatic const struct ng_parse_struct_field ng_atm_tparam_type_info[] =
139116808Sharti    NGM_ATM_TPARAM_INFO;
140116808Shartistatic const struct ng_parse_type ng_atm_tparam_type = {
141116808Sharti	&ng_parse_struct_type,
142116808Sharti	&ng_atm_tparam_type_info
143116808Sharti};
144116808Shartistatic const struct ng_parse_struct_field ng_atm_vcc_type_info[] =
145116808Sharti    NGM_ATM_VCC_INFO;
146116808Shartistatic const struct ng_parse_type ng_atm_vcc_type = {
147116808Sharti	&ng_parse_struct_type,
148116808Sharti	&ng_atm_vcc_type_info
149116808Sharti};
150116808Sharti
151116808Sharti
152116808Shartistatic int
153116808Sharting_atm_vccarray_getlen(const struct ng_parse_type *type,
154116808Sharti	const u_char *start, const u_char *buf)
155116808Sharti{
156116808Sharti	const struct atmio_vcctable *vp;
157116808Sharti
158116808Sharti	vp = (const struct atmio_vcctable *)
159116808Sharti	    (buf - offsetof(struct atmio_vcctable, vccs));
160116808Sharti
161116808Sharti	return (vp->count);
162116808Sharti}
163116808Shartistatic const struct ng_parse_array_info ng_atm_vccarray_info =
164116808Sharti    NGM_ATM_VCCARRAY_INFO;
165116808Shartistatic const struct ng_parse_type ng_atm_vccarray_type = {
166116808Sharti	&ng_parse_array_type,
167116808Sharti	&ng_atm_vccarray_info
168116808Sharti};
169116808Sharti
170116808Sharti
171116808Shartistatic const struct ng_parse_struct_field ng_atm_vcctable_type_info[] =
172116808Sharti    NGM_ATM_VCCTABLE_INFO;
173116808Sharti
174116808Shartistatic const struct ng_parse_type ng_atm_vcctable_type = {
175116808Sharti	&ng_parse_struct_type,
176116808Sharti	&ng_atm_vcctable_type_info
177116808Sharti};
178116808Sharti
179116808Sharti/*
180116808Sharti * Parse CPCS INIT structure ng_atm_cpcs_init
181116808Sharti */
182116808Shartistatic const struct ng_parse_struct_field ng_atm_cpcs_init_type_info[] =
183116808Sharti    NGM_ATM_CPCS_INIT_INFO;
184116808Sharti
185116808Shartistatic const struct ng_parse_type ng_atm_cpcs_init_type = {
186116808Sharti	&ng_parse_struct_type,
187116808Sharti	&ng_atm_cpcs_init_type_info
188116808Sharti};
189116808Sharti
190116808Sharti/*
191116808Sharti * Parse CPCS TERM structure ng_atm_cpcs_term
192116808Sharti */
193116808Shartistatic const struct ng_parse_struct_field ng_atm_cpcs_term_type_info[] =
194116808Sharti    NGM_ATM_CPCS_TERM_INFO;
195116808Sharti
196116808Shartistatic const struct ng_parse_type ng_atm_cpcs_term_type = {
197116808Sharti	&ng_parse_struct_type,
198116808Sharti	&ng_atm_cpcs_term_type_info
199116808Sharti};
200116808Sharti
201116808Sharti/*
202116808Sharti * Parse statistic struct
203116808Sharti */
204116808Shartistatic const struct ng_parse_struct_field ng_atm_stats_type_info[] =
205116808Sharti    NGM_ATM_STATS_INFO;
206116808Sharti
207116808Shartistatic const struct ng_parse_type ng_atm_stats_type = {
208116808Sharti	&ng_parse_struct_type,
209116808Sharti	&ng_atm_stats_type_info
210116808Sharti};
211116808Sharti
212116808Shartistatic const struct ng_cmdlist ng_atm_cmdlist[] = {
213116808Sharti	{
214116808Sharti	  NGM_ATM_COOKIE,
215116808Sharti	  NGM_ATM_GET_IFNAME,
216116808Sharti	  "getifname",
217116808Sharti	  NULL,
218116808Sharti	  &ng_parse_string_type
219116808Sharti	},
220116808Sharti	{
221116808Sharti	  NGM_ATM_COOKIE,
222116808Sharti	  NGM_ATM_GET_CONFIG,
223116808Sharti	  "getconfig",
224116808Sharti	  NULL,
225116808Sharti	  &ng_atm_config_type
226116808Sharti	},
227116808Sharti	{
228116808Sharti	  NGM_ATM_COOKIE,
229116808Sharti	  NGM_ATM_GET_VCCS,
230116808Sharti	  "getvccs",
231116808Sharti	  NULL,
232116808Sharti	  &ng_atm_vcctable_type
233116808Sharti	},
234116808Sharti	{
235116808Sharti	  NGM_ATM_COOKIE,
236116808Sharti	  NGM_ATM_CPCS_INIT,
237116808Sharti	  "cpcsinit",
238116808Sharti	  &ng_atm_cpcs_init_type,
239116808Sharti	  NULL
240116808Sharti	},
241116808Sharti	{
242116808Sharti	  NGM_ATM_COOKIE,
243116808Sharti	  NGM_ATM_CPCS_TERM,
244116808Sharti	  "cpcsterm",
245116808Sharti	  &ng_atm_cpcs_term_type,
246116808Sharti	  NULL
247116808Sharti	},
248116808Sharti	{
249116808Sharti	  NGM_ATM_COOKIE,
250116808Sharti	  NGM_ATM_CARRIER_CHANGE,
251116808Sharti	  "carrier",
252116808Sharti	  &ng_atm_carrier_change_type,
253116808Sharti	  &ng_atm_carrier_change_type,
254116808Sharti	},
255116808Sharti	{
256116808Sharti	  NGM_ATM_COOKIE,
257116808Sharti	  NGM_ATM_GET_VCC,
258116808Sharti	  "getvcc",
259116808Sharti	  &ng_parse_hookbuf_type,
260116808Sharti	  &ng_atm_vcc_type
261116808Sharti	},
262116808Sharti	{
263116808Sharti	  NGM_ATM_COOKIE,
264116808Sharti	  NGM_ATM_GET_VCCID,
265116808Sharti	  "getvccid",
266116808Sharti	  &ng_atm_vcc_type,
267116808Sharti	  &ng_atm_vcc_type
268116808Sharti	},
269116808Sharti	{
270116808Sharti	  NGM_ATM_COOKIE,
271116808Sharti	  NGM_ATM_GET_STATS,
272116808Sharti	  "getstats",
273116808Sharti	  NULL,
274116808Sharti	  &ng_atm_stats_type
275116808Sharti	},
276116808Sharti	{ 0 }
277116808Sharti};
278116808Sharti
279116808Shartistatic int ng_atm_mod_event(module_t, int, void *);
280116808Sharti
281116808Shartistatic ng_constructor_t ng_atm_constructor;
282116808Shartistatic ng_shutdown_t	ng_atm_shutdown;
283116808Shartistatic ng_rcvmsg_t	ng_atm_rcvmsg;
284116808Shartistatic ng_newhook_t	ng_atm_newhook;
285116808Shartistatic ng_connect_t	ng_atm_connect;
286116808Shartistatic ng_disconnect_t	ng_atm_disconnect;
287116808Shartistatic ng_rcvdata_t	ng_atm_rcvdata;
288116808Shartistatic ng_rcvdata_t	ng_atm_rcvdrop;
289116808Sharti
290116808Shartistatic struct ng_type ng_atm_typestruct = {
291116808Sharti	NG_ABI_VERSION,
292116808Sharti	NG_ATM_NODE_TYPE,
293116808Sharti	ng_atm_mod_event,	/* Module event handler (optional) */
294116808Sharti	ng_atm_constructor,	/* Node constructor */
295116808Sharti	ng_atm_rcvmsg,		/* control messages come here */
296116808Sharti	ng_atm_shutdown,	/* reset, and free resources */
297116808Sharti	ng_atm_newhook,		/* first notification of new hook */
298116808Sharti	NULL,			/* findhook */
299116808Sharti	ng_atm_connect,		/* connect */
300116808Sharti	ng_atm_rcvdata,		/* rcvdata */
301116808Sharti	ng_atm_disconnect,	/* notify on disconnect */
302116808Sharti	ng_atm_cmdlist,
303116808Sharti};
304116808ShartiNETGRAPH_INIT(atm, &ng_atm_typestruct);
305116808Sharti
306116808Shartistatic const struct {
307116808Sharti	u_int	media;
308116808Sharti	const char *name;
309116808Sharti} atmmedia[] = IFM_SUBTYPE_ATM_DESCRIPTIONS;
310116808Sharti
311116808Sharti
312116808Sharti#define	IFP2NG(IFP)	((node_p)((struct ifatm *)(IFP))->ngpriv)
313116808Sharti
314116808Sharti#define	IFFLAGS "\020\001UP\002BROADCAST\003DEBUG\004LOOPBACK" \
315116808Sharti		 "\005POINTOPOINT\006SMART\007RUNNING\010NOARP" \
316116808Sharti		 "\011PROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX" \
317116808Sharti		 "\015LINK0\016LINK1\017LINK2\020MULTICAST"
318116808Sharti
319116808Sharti
320116808Sharti/************************************************************/
321116808Sharti/*
322116808Sharti * INPUT
323116808Sharti */
324116808Sharti/*
325116808Sharti * A packet is received from an interface.
326116808Sharti * If we have an input hook, prepend the pseudoheader to the data and
327116808Sharti * deliver it out to that hook. If not, look whether it is destined for
328116808Sharti * use. If so locate the appropriate hook, deliver the packet without the
329116808Sharti * header and we are done. If it is not for us, leave it alone.
330116808Sharti */
331116808Shartistatic void
332116808Sharting_atm_input(struct ifnet *ifp, struct mbuf **mp,
333116808Sharti	struct atm_pseudohdr *ah, void *rxhand)
334116808Sharti{
335116808Sharti	node_p node = IFP2NG(ifp);
336116808Sharti	struct priv *priv;
337116808Sharti	const struct ngvcc *vcc;
338116808Sharti	int error;
339116808Sharti
340116808Sharti	if (node == NULL)
341116808Sharti		return;
342116808Sharti	priv = NG_NODE_PRIVATE(node);
343116808Sharti	if (priv->input != NULL) {
344116808Sharti		/*
345116808Sharti		 * Prepend the atm_pseudoheader.
346116808Sharti		 */
347116808Sharti		M_PREPEND(*mp, sizeof(*ah), M_DONTWAIT);
348116808Sharti		if (*mp == NULL)
349116808Sharti			return;
350116808Sharti		memcpy(mtod(*mp, struct atm_pseudohdr *), ah, sizeof(*ah));
351116808Sharti		NG_SEND_DATA_ONLY(error, priv->input, *mp);
352116808Sharti		if (error == 0) {
353116808Sharti			priv->in_packets++;
354116808Sharti			*mp = NULL;
355116808Sharti		} else {
356116808Sharti#ifdef NGATM_DEBUG
357116808Sharti			printf("%s: error=%d\n", __func__, error);
358116808Sharti#endif
359116808Sharti			priv->in_errors++;
360116808Sharti		}
361116808Sharti		return;
362116808Sharti	}
363116808Sharti	if ((ATM_PH_FLAGS(ah) & ATMIO_FLAG_NG) == 0)
364116808Sharti		return;
365116808Sharti
366116808Sharti	vcc = (struct ngvcc *)rxhand;
367116808Sharti
368116808Sharti	NG_SEND_DATA_ONLY(error, vcc->hook, *mp);
369116808Sharti	if (error == 0) {
370116808Sharti		priv->in_packets++;
371116808Sharti		*mp = NULL;
372116808Sharti	} else {
373116808Sharti#ifdef NGATM_DEBUG
374116808Sharti		printf("%s: error=%d\n", __func__, error);
375116808Sharti#endif
376116808Sharti		priv->in_errors++;
377116808Sharti	}
378116808Sharti}
379116808Sharti
380116808Sharti/*
381116808Sharti * ATM packet is about to be output. The atm_pseudohdr is already prepended.
382116808Sharti * If the hook is set, reroute the packet to the hook.
383116808Sharti */
384116808Shartistatic int
385116808Sharting_atm_output(struct ifnet *ifp, struct mbuf **mp)
386116808Sharti{
387116808Sharti	const node_p node = IFP2NG(ifp);
388116808Sharti	const struct priv *priv;
389116808Sharti	int error = 0;
390116808Sharti
391116808Sharti	if (node == NULL)
392116808Sharti		return (0);
393116808Sharti	priv = NG_NODE_PRIVATE(node);
394116808Sharti	if (priv->output) {
395116808Sharti		NG_SEND_DATA_ONLY(error, priv->output, *mp);
396116808Sharti		*mp = NULL;
397116808Sharti	}
398116808Sharti
399116808Sharti	return (error);
400116808Sharti}
401116808Sharti
402116808Sharti/*
403116808Sharti * Well, this doesn't make much sense for ATM.
404116808Sharti */
405116808Shartistatic void
406116808Sharting_atm_input_orphans(struct ifnet *ifp, struct mbuf *m,
407116808Sharti	struct atm_pseudohdr *ah, void *rxhand)
408116808Sharti{
409116808Sharti	node_p node = IFP2NG(ifp);
410116808Sharti	struct priv *priv;
411116808Sharti	int error;
412116808Sharti
413116808Sharti	if (node == NULL) {
414116808Sharti		m_freem(m);
415116808Sharti		return;
416116808Sharti	}
417116808Sharti	priv = NG_NODE_PRIVATE(node);
418116808Sharti	if (priv->orphans == NULL) {
419116808Sharti		m_freem(m);
420116808Sharti		return;
421116808Sharti	}
422116808Sharti	/*
423116808Sharti	 * Prepend the atm_pseudoheader.
424116808Sharti	 */
425116808Sharti	M_PREPEND(m, sizeof(*ah), M_DONTWAIT);
426116808Sharti	if (m == NULL)
427116808Sharti		return;
428116808Sharti	memcpy(mtod(m, struct atm_pseudohdr *), ah, sizeof(*ah));
429116808Sharti	NG_SEND_DATA_ONLY(error, priv->orphans, m);
430116808Sharti	if (error == 0)
431116808Sharti		priv->in_packets++;
432116808Sharti	else {
433116808Sharti		priv->in_errors++;
434116808Sharti#ifdef NGATM_DEBUG
435116808Sharti		printf("%s: error=%d\n", __func__, error);
436116808Sharti#endif
437116808Sharti	}
438116808Sharti}
439116808Sharti
440116808Sharti/************************************************************/
441116808Sharti/*
442116808Sharti * OUTPUT
443116808Sharti */
444116808Shartistatic int
445116808Sharting_atm_rcvdata(hook_p hook, item_p item)
446116808Sharti{
447116808Sharti	node_p node = NG_HOOK_NODE(hook);
448116808Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
449116808Sharti	const struct ngvcc *vcc = NG_HOOK_PRIVATE(hook);
450116808Sharti	struct mbuf *m;
451116808Sharti	struct atm_pseudohdr *aph;
452116808Sharti	int error;
453116808Sharti
454116808Sharti	if (vcc->vci == 0) {
455116808Sharti		NG_FREE_ITEM(item);
456116808Sharti		return (ENOTCONN);
457116808Sharti	}
458116808Sharti
459116808Sharti	NGI_GET_M(item, m);
460116808Sharti	NG_FREE_ITEM(item);
461116808Sharti
462116808Sharti	/*
463116808Sharti	 * Prepend pseudo-hdr. Drivers don't care about the flags.
464116808Sharti	 */
465116808Sharti	M_PREPEND(m, sizeof(*aph), M_DONTWAIT);
466116808Sharti	if (m == NULL) {
467116808Sharti		NG_FREE_M(m);
468116808Sharti		return (ENOMEM);
469116808Sharti	}
470116808Sharti	aph = mtod(m, struct atm_pseudohdr *);
471116808Sharti	ATM_PH_VPI(aph) = vcc->vpi;
472116808Sharti	ATM_PH_SETVCI(aph, vcc->vci);
473116808Sharti	ATM_PH_FLAGS(aph) = 0;
474116808Sharti
475116808Sharti	if ((error = atm_output(priv->ifp, m, NULL, NULL)) == 0)
476116808Sharti		priv->out_packets++;
477116808Sharti	else
478116808Sharti		priv->out_errors++;
479116808Sharti	return (error);
480116808Sharti}
481116808Sharti
482116808Shartistatic int
483116808Sharting_atm_rcvdrop(hook_p hook, item_p item)
484116808Sharti{
485116808Sharti	NG_FREE_ITEM(item);
486116808Sharti	return (0);
487116808Sharti}
488116808Sharti
489116808Sharti
490116808Sharti/************************************************************
491116808Sharti *
492116808Sharti * Message from driver.
493116808Sharti */
494116808Sharti#ifdef notyet
495116808Shartistatic void
496116808Sharting_atm_message_func(node_p node, hook_p hook, void *arg1, int arg2)
497116808Sharti{
498116808Sharti	uint32_t msg = (uintptr_t)arg1;
499116808Sharti	uint32_t arg = (uint32_t)arg2;
500116808Sharti	const struct priv *priv = NG_NODE_PRIVATE(node);
501116808Sharti	struct ngvcc *vcc;
502116808Sharti	u_int vci, vpi, state;
503116808Sharti	struct ng_mesg *mesg;
504116808Sharti	int error;
505116808Sharti
506116808Sharti	switch (msg) {
507116808Sharti
508116808Sharti	  case ATM_MSG_FLOW_CONTROL:
509116808Sharti	    {
510116808Sharti		struct ngm_queue_state *qstate;
511116808Sharti
512116808Sharti		/* find the connection */
513116808Sharti		vci = arg & 0xffff;
514116808Sharti		vpi = (arg >> 16) & 0xff;
515116808Sharti		state = (arg >> 24) & 1;
516116808Sharti		LIST_FOREACH(vcc, &priv->vccs, link)
517116808Sharti			if (vcc->vci == vci && vcc->vpi == vpi)
518116808Sharti				break;
519116808Sharti		if (vcc == NULL)
520116808Sharti			break;
521116808Sharti
522116808Sharti		/* convert into a flow control message */
523116808Sharti		NG_MKMESSAGE(mesg, NGM_FLOW_COOKIE,
524116808Sharti		    state ? NGM_HIGH_WATER_PASSED : NGM_LOW_WATER_PASSED,
525116808Sharti		    sizeof(struct ngm_queue_state), M_NOWAIT);
526116808Sharti		if (mesg == NULL)
527116808Sharti			break;
528116808Sharti		qstate = (struct ngm_queue_state *)mesg->data;
529116808Sharti
530116808Sharti		/* XXX have to figure out how to get that info */
531116808Sharti
532116808Sharti		NG_SEND_MSG_HOOK(error, node, mesg, vcc->hook, NULL);
533116808Sharti		break;
534116808Sharti	    }
535116808Sharti
536116808Sharti	  case ATM_MSG_VCC_CHANGED:
537116808Sharti	    {
538116808Sharti		struct ngm_atm_vcc_change *chg;
539116808Sharti
540116808Sharti		if (priv->manage == NULL)
541116808Sharti			break;
542116808Sharti		NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_VCC_CHANGE,
543116808Sharti		    sizeof(struct ngm_atm_vcc_change), M_NOWAIT);
544116808Sharti		if (mesg == NULL)
545116808Sharti			break;
546116808Sharti		chg = (struct ngm_atm_vcc_change *)mesg->data;
547116808Sharti		chg->vci = arg & 0xffff;
548116808Sharti		chg->vpi = (arg >> 16) & 0xff;
549116808Sharti		chg->state = (arg >> 24) & 1;
550116808Sharti		chg->node = NG_NODE_ID(node);
551116808Sharti		NG_SEND_MSG_HOOK(error, node, mesg, priv->manage, NULL);
552116808Sharti		break;
553116808Sharti	    }
554116808Sharti
555116808Sharti	  case ATM_MSG_CARRIER_CHANGE:
556116808Sharti	    {
557116808Sharti		struct ngm_atm_carrier_change *chg;
558116808Sharti
559116808Sharti		if (priv->manage == NULL)
560116808Sharti			break;
561116808Sharti		NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_CARRIER_CHANGE,
562116808Sharti		    sizeof(struct ngm_atm_carrier_change), M_NOWAIT);
563116808Sharti		if (mesg == NULL)
564116808Sharti			break;
565116808Sharti		chg = (struct ngm_atm_carrier_change *)mesg->data;
566116808Sharti		chg->state = arg & 1;
567116808Sharti		chg->node = NG_NODE_ID(node);
568116808Sharti		NG_SEND_MSG_HOOK(error, node, mesg, priv->manage, NULL);
569116808Sharti		break;
570116808Sharti	    }
571116808Sharti	}
572116808Sharti}
573116808Sharti#endif
574116808Sharti
575116808Sharti/*
576116808Sharti * Use send_fn to get the right lock
577116808Sharti */
578116808Shartistatic void
579116808Sharting_atm_message(struct ifnet *ifp, uint32_t msg, uint32_t arg)
580116808Sharti{
581116808Sharti#ifdef notyet
582116808Sharti	const node_p node = IFP2NG(ifp);
583116808Sharti
584116808Sharti	(void)ng_send_fn(node, NULL, ng_atm_message_func,
585116808Sharti	    (void *)(uintptr_t)msg, arg);
586116808Sharti#endif
587116808Sharti}
588116808Sharti
589116808Sharti/************************************************************
590116808Sharti *
591116808Sharti * CPCS
592116808Sharti */
593116808Sharti/*
594116808Sharti * Open a channel for the user
595116808Sharti */
596116808Shartistatic int
597116808Sharting_atm_cpcs_init(node_p node, const struct ngm_atm_cpcs_init *arg)
598116808Sharti{
599116808Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
600116808Sharti	const struct ifatm_mib *mib;
601116808Sharti	struct ngvcc *vcc;
602116808Sharti	struct atmio_openvcc data;
603116808Sharti	int err;
604116808Sharti
605116808Sharti	if(priv->ifp->if_ioctl == NULL)
606116808Sharti		return (ENXIO);
607116808Sharti
608116808Sharti	mib = (const struct ifatm_mib *)(priv->ifp->if_linkmib);
609116808Sharti
610116808Sharti	LIST_FOREACH(vcc, &priv->vccs, link)
611116808Sharti		if (strcmp(arg->name, NG_HOOK_NAME(vcc->hook)) == 0)
612116808Sharti			break;
613116808Sharti	if (vcc == NULL)
614116808Sharti		return (ENOTCONN);
615117642Sharti	if (vcc->flags & VCC_OPEN)
616116808Sharti		return (EISCONN);
617116808Sharti
618116808Sharti	/*
619116808Sharti	 * Check user arguments and construct ioctl argument
620116808Sharti	 */
621116808Sharti	memset(&data, 0, sizeof(data));
622116808Sharti
623116808Sharti	data.rxhand = vcc;
624116808Sharti
625116808Sharti	switch (data.param.aal = arg->aal) {
626116808Sharti
627117157Sharti	  case ATMIO_AAL_34:
628116808Sharti	  case ATMIO_AAL_5:
629116808Sharti	  case ATMIO_AAL_0:
630116808Sharti	  case ATMIO_AAL_RAW:
631116808Sharti		break;
632116808Sharti
633116808Sharti	  default:
634116808Sharti		return (EINVAL);
635116808Sharti	}
636116808Sharti
637116808Sharti	if (arg->vpi > 0xff)
638116808Sharti		return (EINVAL);
639116808Sharti	data.param.vpi = arg->vpi;
640116808Sharti
641117157Sharti	/* allow 0.0 as catch all receive channel */
642117157Sharti	if (arg->vci == 0 && (arg->vpi != 0 || !(arg->flags & ATMIO_FLAG_NOTX)))
643117157Sharti		return (EINVAL);
644116808Sharti	data.param.vci = arg->vci;
645116808Sharti
646116808Sharti	data.param.tparam.pcr = arg->pcr;
647116808Sharti
648116808Sharti	if (arg->mcr > arg->pcr)
649116808Sharti		return (EINVAL);
650116808Sharti	data.param.tparam.mcr = arg->mcr;
651116808Sharti
652116808Sharti	if (!(arg->flags & ATMIO_FLAG_NOTX)) {
653117157Sharti		if (arg->tmtu == 0)
654117157Sharti			data.param.tmtu = priv->ifp->if_mtu;
655117157Sharti		else {
656117157Sharti			data.param.tmtu = arg->tmtu;
657117157Sharti		}
658116808Sharti	}
659116808Sharti	if (!(arg->flags & ATMIO_FLAG_NORX)) {
660117157Sharti		if (arg->rmtu == 0)
661117157Sharti			data.param.rmtu = priv->ifp->if_mtu;
662117157Sharti		else {
663117157Sharti			data.param.rmtu = arg->rmtu;
664117157Sharti		}
665116808Sharti	}
666116808Sharti
667116808Sharti	switch (data.param.traffic = arg->traffic) {
668116808Sharti
669116808Sharti	  case ATMIO_TRAFFIC_UBR:
670116808Sharti	  case ATMIO_TRAFFIC_CBR:
671116808Sharti		break;
672116808Sharti
673116808Sharti	  case ATMIO_TRAFFIC_VBR:
674116808Sharti		if (arg->scr > arg->pcr)
675116808Sharti			return (EINVAL);
676116808Sharti		data.param.tparam.scr = arg->scr;
677116808Sharti
678116808Sharti		if (arg->mbs > (1 << 24))
679116808Sharti			return (EINVAL);
680116808Sharti		data.param.tparam.mbs = arg->mbs;
681116808Sharti		break;
682116808Sharti
683116808Sharti	  case ATMIO_TRAFFIC_ABR:
684116808Sharti		if (arg->icr > arg->pcr || arg->icr < arg->mcr)
685116808Sharti			return (EINVAL);
686116808Sharti		data.param.tparam.icr = arg->icr;
687116808Sharti
688116808Sharti		if (arg->tbe == 0 || arg->tbe > (1 << 24))
689116808Sharti			return (EINVAL);
690116808Sharti		data.param.tparam.tbe = arg->tbe;
691116808Sharti
692116808Sharti		if (arg->nrm > 0x7)
693116808Sharti			return (EINVAL);
694116808Sharti		data.param.tparam.nrm = arg->nrm;
695116808Sharti
696116808Sharti		if (arg->trm > 0x7)
697116808Sharti			return (EINVAL);
698116808Sharti		data.param.tparam.trm = arg->trm;
699116808Sharti
700116808Sharti		if (arg->adtf > 0x3ff)
701116808Sharti			return (EINVAL);
702116808Sharti		data.param.tparam.adtf = arg->adtf;
703116808Sharti
704116808Sharti		if (arg->rif > 0xf)
705116808Sharti			return (EINVAL);
706116808Sharti		data.param.tparam.rif = arg->rif;
707116808Sharti
708116808Sharti		if (arg->rdf > 0xf)
709116808Sharti			return (EINVAL);
710116808Sharti		data.param.tparam.rdf = arg->rdf;
711116808Sharti
712116808Sharti		if (arg->cdf > 0x7)
713116808Sharti			return (EINVAL);
714116808Sharti		data.param.tparam.cdf = arg->cdf;
715116808Sharti
716116808Sharti		break;
717116808Sharti
718116808Sharti	  default:
719116808Sharti		return (EINVAL);
720116808Sharti	}
721116808Sharti
722116808Sharti	if ((arg->flags & ATMIO_FLAG_NORX) && (arg->flags & ATMIO_FLAG_NOTX))
723116808Sharti		return (EINVAL);
724116808Sharti
725116808Sharti	data.param.flags = arg->flags & ~(ATM_PH_AAL5 | ATM_PH_LLCSNAP);
726116808Sharti	data.param.flags |= ATMIO_FLAG_NG;
727116808Sharti
728116808Sharti	err = (*priv->ifp->if_ioctl)(priv->ifp, SIOCATMOPENVCC, (caddr_t)&data);
729116808Sharti
730116808Sharti	if (err == 0) {
731116808Sharti		vcc->vci = data.param.vci;
732116808Sharti		vcc->vpi = data.param.vpi;
733117157Sharti		vcc->flags = VCC_OPEN;
734116808Sharti	}
735116808Sharti
736116808Sharti	return (err);
737116808Sharti}
738116808Sharti
739116808Sharti/*
740116808Sharti * Issue the close command to the driver
741116808Sharti */
742116808Shartistatic int
743116808Sharticpcs_term(const struct priv *priv, u_int vpi, u_int vci)
744116808Sharti{
745116808Sharti	struct atmio_closevcc data;
746116808Sharti
747116808Sharti	if (priv->ifp->if_ioctl == NULL)
748116808Sharti		return ENXIO;
749116808Sharti
750116808Sharti	data.vpi = vpi;
751116808Sharti	data.vci = vci;
752116808Sharti
753116808Sharti	return ((*priv->ifp->if_ioctl)(priv->ifp,
754116808Sharti	    SIOCATMCLOSEVCC, (caddr_t)&data));
755116808Sharti}
756116808Sharti
757116808Sharti
758116808Sharti/*
759116808Sharti * Close a channel by request of the user
760116808Sharti */
761116808Shartistatic int
762116808Sharting_atm_cpcs_term(node_p node, const struct ngm_atm_cpcs_term *arg)
763116808Sharti{
764116808Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
765116808Sharti	struct ngvcc *vcc;
766116808Sharti	int error;
767116808Sharti
768116808Sharti	LIST_FOREACH(vcc, &priv->vccs, link)
769116808Sharti		if(strcmp(arg->name, NG_HOOK_NAME(vcc->hook)) == 0)
770116808Sharti			break;
771116808Sharti	if (vcc == NULL)
772116808Sharti		return (ENOTCONN);
773117642Sharti	if (!(vcc->flags & VCC_OPEN))
774116808Sharti		return (ENOTCONN);
775116808Sharti
776116808Sharti	error = cpcs_term(priv, vcc->vpi, vcc->vci);
777116808Sharti
778116808Sharti	vcc->vci = 0;
779116808Sharti	vcc->vpi = 0;
780116808Sharti	vcc->flags = 0;
781116808Sharti
782116808Sharti	return (error);
783116808Sharti}
784116808Sharti
785116808Sharti/************************************************************/
786116808Sharti/*
787116808Sharti * CONTROL MESSAGES
788116808Sharti */
789116808Sharti
790116808Sharti/*
791116808Sharti * Produce a textual description of the current status
792116808Sharti */
793116808Shartistatic int
794116808Shartitext_status(node_p node, char *arg, u_int len)
795116808Sharti{
796116808Sharti	const struct priv *priv = NG_NODE_PRIVATE(node);
797116808Sharti	const struct ifatm_mib *mib;
798116808Sharti	struct sbuf sbuf;
799116808Sharti	u_int i;
800116808Sharti
801116808Sharti	static const struct {
802116808Sharti		const char	*name;
803116808Sharti		const char	*vendor;
804116808Sharti	} devices[] = {
805116808Sharti		ATM_DEVICE_NAMES
806116808Sharti	};
807116808Sharti
808116808Sharti	mib = (const struct ifatm_mib *)(priv->ifp->if_linkmib);
809116808Sharti
810116808Sharti	sbuf_new(&sbuf, arg, len, SBUF_FIXEDLEN);
811116808Sharti	sbuf_printf(&sbuf, "interface: %s%d\n", priv->ifp->if_name,
812116808Sharti	    priv->ifp->if_unit);
813116808Sharti
814116808Sharti	if (mib->device >= sizeof(devices) / sizeof(devices[0]))
815116808Sharti		sbuf_printf(&sbuf, "device=unknown\nvendor=unknown\n");
816116808Sharti	else
817116808Sharti		sbuf_printf(&sbuf, "device=%s\nvendor=%s\n",
818116808Sharti		    devices[mib->device].name, devices[mib->device].vendor);
819116808Sharti
820116808Sharti	for (i = 0; atmmedia[i].name; i++)
821116808Sharti		if(mib->media == atmmedia[i].media) {
822116808Sharti			sbuf_printf(&sbuf, "media=%s\n", atmmedia[i].name);
823116808Sharti			break;
824116808Sharti		}
825116808Sharti	if(atmmedia[i].name == NULL)
826116808Sharti		sbuf_printf(&sbuf, "media=unknown\n");
827116808Sharti
828116808Sharti	sbuf_printf(&sbuf, "serial=%u esi=%6D hardware=%u software=%u\n",
829116808Sharti	    mib->serial, mib->esi, ":", mib->hw_version, mib->sw_version);
830116808Sharti	sbuf_printf(&sbuf, "pcr=%u vpi_bits=%u vci_bits=%u max_vpcs=%u "
831116808Sharti	    "max_vccs=%u\n", mib->pcr, mib->vpi_bits, mib->vci_bits,
832116808Sharti	    mib->max_vpcs, mib->max_vccs);
833116808Sharti	sbuf_printf(&sbuf, "ifflags=%b\n", priv->ifp->if_flags, IFFLAGS);
834116808Sharti
835116808Sharti	sbuf_finish(&sbuf);
836116808Sharti
837116808Sharti	return (sbuf_len(&sbuf));
838116808Sharti}
839116808Sharti
840116808Sharti/*
841116808Sharti * Get control message
842116808Sharti */
843116808Shartistatic int
844116808Sharting_atm_rcvmsg(node_p node, item_p item, hook_p lasthook)
845116808Sharti{
846116808Sharti	const struct priv *priv = NG_NODE_PRIVATE(node);
847116808Sharti	struct ng_mesg *resp = NULL;
848116808Sharti	struct ng_mesg *msg;
849116808Sharti	struct ifatm_mib *mib = (struct ifatm_mib *)(priv->ifp->if_linkmib);
850116808Sharti	int error = 0;
851116808Sharti
852116808Sharti	NGI_GET_MSG(item, msg);
853116808Sharti
854116808Sharti	switch (msg->header.typecookie) {
855116808Sharti
856116808Sharti	  case NGM_GENERIC_COOKIE:
857116808Sharti		switch (msg->header.cmd) {
858116808Sharti
859116808Sharti		  case NGM_TEXT_STATUS:
860116808Sharti			NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
861116808Sharti			if(resp == NULL) {
862116808Sharti				error = ENOMEM;
863116808Sharti				break;
864116808Sharti			}
865116808Sharti
866116808Sharti			resp->header.arglen = text_status(node,
867116808Sharti			    (char *)resp->data, resp->header.arglen) + 1;
868116808Sharti			break;
869116808Sharti
870116808Sharti		  default:
871116808Sharti			error = EINVAL;
872116808Sharti			break;
873116808Sharti		}
874116808Sharti		break;
875116808Sharti
876116808Sharti	  case NGM_ATM_COOKIE:
877116808Sharti		switch (msg->header.cmd) {
878116808Sharti
879116808Sharti		  case NGM_ATM_GET_IFNAME:
880116808Sharti			NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT);
881116808Sharti			if (resp == NULL) {
882116808Sharti				error = ENOMEM;
883116808Sharti				break;
884116808Sharti			}
885116808Sharti			snprintf(resp->data, IFNAMSIZ + 1, "%s%d",
886116808Sharti			    priv->ifp->if_name, priv->ifp->if_unit);
887116808Sharti			break;
888116808Sharti
889116808Sharti		  case NGM_ATM_GET_CONFIG:
890116808Sharti		    {
891116808Sharti			struct ngm_atm_config *config;
892116808Sharti
893116808Sharti			NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT);
894116808Sharti			if (resp == NULL) {
895116808Sharti				error = ENOMEM;
896116808Sharti				break;
897116808Sharti			}
898116808Sharti			config = (struct ngm_atm_config *)resp->data;
899116808Sharti			config->pcr = mib->pcr;
900116808Sharti			config->vpi_bits = mib->vpi_bits;
901116808Sharti			config->vci_bits = mib->vci_bits;
902116808Sharti			config->max_vpcs = mib->max_vpcs;
903116808Sharti			config->max_vccs = mib->max_vccs;
904116808Sharti			break;
905116808Sharti		    }
906116808Sharti
907116808Sharti		  case NGM_ATM_GET_VCCS:
908116808Sharti		    {
909116808Sharti			struct atmio_vcctable *vccs;
910116808Sharti			size_t len;
911116808Sharti
912116808Sharti			if (priv->ifp->if_ioctl == NULL) {
913116808Sharti				error = ENXIO;
914116808Sharti				break;
915116808Sharti			}
916116808Sharti			error = (*priv->ifp->if_ioctl)(priv->ifp,
917116808Sharti			    SIOCATMGETVCCS, (caddr_t)&vccs);
918116808Sharti			if (error)
919116808Sharti				break;
920116808Sharti
921116808Sharti			len = sizeof(*vccs) +
922116808Sharti			    vccs->count * sizeof(vccs->vccs[0]);
923116808Sharti			NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
924116808Sharti			if (resp == NULL) {
925116808Sharti				error = ENOMEM;
926116808Sharti				free(vccs, M_DEVBUF);
927116808Sharti				break;
928116808Sharti			}
929116808Sharti
930116808Sharti			(void)memcpy(resp->data, vccs, len);
931116808Sharti			free(vccs, M_DEVBUF);
932116808Sharti
933116808Sharti			break;
934116808Sharti		    }
935116808Sharti
936116808Sharti		  case NGM_ATM_GET_VCC:
937116808Sharti		    {
938116808Sharti			char hook[NG_HOOKLEN + 1];
939116808Sharti			struct atmio_vcctable *vccs;
940116808Sharti			struct ngvcc *vcc;
941116808Sharti			u_int i;
942116808Sharti
943116808Sharti			if (priv->ifp->if_ioctl == NULL) {
944116808Sharti				error = ENXIO;
945116808Sharti				break;
946116808Sharti			}
947116808Sharti			if (msg->header.arglen != NG_HOOKLEN + 1) {
948116808Sharti				error = EINVAL;
949116808Sharti				break;
950116808Sharti			}
951116808Sharti			strncpy(hook, msg->data, NG_HOOKLEN + 1);
952116808Sharti			hook[NG_HOOKLEN] = '\0';
953116808Sharti			LIST_FOREACH(vcc, &priv->vccs, link)
954116808Sharti				if (strcmp(NG_HOOK_NAME(vcc->hook), hook) == 0)
955116808Sharti					break;
956116808Sharti			if (vcc == NULL) {
957116808Sharti				error = ENOTCONN;
958116808Sharti				break;
959116808Sharti			}
960116808Sharti			error = (*priv->ifp->if_ioctl)(priv->ifp,
961116808Sharti			    SIOCATMGETVCCS, (caddr_t)&vccs);
962116808Sharti			if (error)
963116808Sharti				break;
964116808Sharti
965116808Sharti			for (i = 0; i < vccs->count; i++)
966116808Sharti				if (vccs->vccs[i].vpi == vcc->vpi &&
967116808Sharti				    vccs->vccs[i].vci == vcc->vci)
968116808Sharti					break;
969116808Sharti			if (i == vccs->count) {
970116808Sharti				error = ENOTCONN;
971116808Sharti				free(vccs, M_DEVBUF);
972116808Sharti				break;
973116808Sharti			}
974116808Sharti
975116808Sharti			NG_MKRESPONSE(resp, msg, sizeof(vccs->vccs[0]),
976116808Sharti			    M_NOWAIT);
977116808Sharti			if (resp == NULL) {
978116808Sharti				error = ENOMEM;
979116808Sharti				free(vccs, M_DEVBUF);
980116808Sharti				break;
981116808Sharti			}
982116808Sharti
983116808Sharti			*(struct atmio_vcc *)resp->data = vccs->vccs[i];
984116808Sharti			free(vccs, M_DEVBUF);
985116808Sharti			break;
986116808Sharti		    }
987116808Sharti
988116808Sharti		  case NGM_ATM_GET_VCCID:
989116808Sharti		    {
990116808Sharti			struct atmio_vcc *arg;
991116808Sharti			struct atmio_vcctable *vccs;
992116808Sharti			u_int i;
993116808Sharti
994116808Sharti			if (priv->ifp->if_ioctl == NULL) {
995116808Sharti				error = ENXIO;
996116808Sharti				break;
997116808Sharti			}
998116808Sharti			if (msg->header.arglen != sizeof(*arg)) {
999116808Sharti				error = EINVAL;
1000116808Sharti				break;
1001116808Sharti			}
1002116808Sharti			arg = (struct atmio_vcc *)msg->data;
1003116808Sharti
1004116808Sharti			error = (*priv->ifp->if_ioctl)(priv->ifp,
1005116808Sharti			    SIOCATMGETVCCS, (caddr_t)&vccs);
1006116808Sharti			if (error)
1007116808Sharti				break;
1008116808Sharti
1009116808Sharti			for (i = 0; i < vccs->count; i++)
1010116808Sharti				if (vccs->vccs[i].vpi == arg->vpi &&
1011116808Sharti				    vccs->vccs[i].vci == arg->vci)
1012116808Sharti					break;
1013116808Sharti			if (i == vccs->count) {
1014116808Sharti				error = ENOTCONN;
1015116808Sharti				free(vccs, M_DEVBUF);
1016116808Sharti				break;
1017116808Sharti			}
1018116808Sharti
1019116808Sharti			NG_MKRESPONSE(resp, msg, sizeof(vccs->vccs[0]),
1020116808Sharti			    M_NOWAIT);
1021116808Sharti			if (resp == NULL) {
1022116808Sharti				error = ENOMEM;
1023116808Sharti				free(vccs, M_DEVBUF);
1024116808Sharti				break;
1025116808Sharti			}
1026116808Sharti
1027116808Sharti			*(struct atmio_vcc *)resp->data = vccs->vccs[i];
1028116808Sharti			free(vccs, M_DEVBUF);
1029116808Sharti			break;
1030116808Sharti		    }
1031116808Sharti
1032116808Sharti		  case NGM_ATM_CPCS_INIT:
1033116808Sharti			if (msg->header.arglen !=
1034116808Sharti			    sizeof(struct ngm_atm_cpcs_init)) {
1035116808Sharti				error = EINVAL;
1036116808Sharti				break;
1037116808Sharti			}
1038116808Sharti			error = ng_atm_cpcs_init(node,
1039116808Sharti			    (struct ngm_atm_cpcs_init *)msg->data);
1040116808Sharti			break;
1041116808Sharti
1042116808Sharti		  case NGM_ATM_CPCS_TERM:
1043116808Sharti			if (msg->header.arglen !=
1044116808Sharti			    sizeof(struct ngm_atm_cpcs_term)) {
1045116808Sharti				error = EINVAL;
1046116808Sharti				break;
1047116808Sharti			}
1048116808Sharti			error = ng_atm_cpcs_term(node,
1049116808Sharti			    (struct ngm_atm_cpcs_term *)msg->data);
1050116808Sharti			break;
1051116808Sharti
1052116808Sharti		  case NGM_ATM_GET_STATS:
1053116808Sharti		    {
1054116808Sharti			struct ngm_atm_stats *p;
1055116808Sharti
1056116808Sharti			if (msg->header.arglen != 0) {
1057116808Sharti				error = EINVAL;
1058116808Sharti				break;
1059116808Sharti			}
1060116808Sharti			NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
1061116808Sharti			if (resp == NULL) {
1062116808Sharti				error = ENOMEM;
1063116808Sharti				break;
1064116808Sharti			}
1065116808Sharti			p = (struct ngm_atm_stats *)resp->data;
1066116808Sharti			p->in_packets = priv->in_packets;
1067116808Sharti			p->out_packets = priv->out_packets;
1068116808Sharti			p->in_errors = priv->in_errors;
1069116808Sharti			p->out_errors = priv->out_errors;
1070116808Sharti
1071116808Sharti			break;
1072116808Sharti		    }
1073116808Sharti
1074116808Sharti		  default:
1075116808Sharti			error = EINVAL;
1076116808Sharti			break;
1077116808Sharti		}
1078116808Sharti		break;
1079116808Sharti
1080116808Sharti	  default:
1081116808Sharti		error = EINVAL;
1082116808Sharti		break;
1083116808Sharti	}
1084116808Sharti
1085116808Sharti	NG_RESPOND_MSG(error, node, item, resp);
1086116808Sharti	NG_FREE_MSG(msg);
1087116808Sharti	return (error);
1088116808Sharti}
1089116808Sharti
1090116808Sharti/************************************************************/
1091116808Sharti/*
1092116808Sharti * HOOK MANAGEMENT
1093116808Sharti */
1094116808Sharti
1095116808Sharti/*
1096116808Sharti * A new hook is create that will be connected to the node.
1097116808Sharti * Check, whether the name is one of the predefined ones.
1098116808Sharti * If not, create a new entry into the vcc list.
1099116808Sharti */
1100116808Shartistatic int
1101116808Sharting_atm_newhook(node_p node, hook_p hook, const char *name)
1102116808Sharti{
1103116808Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
1104116808Sharti	struct ngvcc *vcc;
1105116808Sharti
1106116808Sharti	if (strcmp(name, "input") == 0) {
1107116808Sharti		priv->input = hook;
1108116808Sharti		NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
1109116808Sharti		return (0);
1110116808Sharti	}
1111116808Sharti	if (strcmp(name, "output") == 0) {
1112116808Sharti		priv->output = hook;
1113116808Sharti		NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
1114116808Sharti		return (0);
1115116808Sharti	}
1116116808Sharti	if (strcmp(name, "orphans") == 0) {
1117116808Sharti		priv->orphans = hook;
1118116808Sharti		NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
1119116808Sharti		return (0);
1120116808Sharti	}
1121116808Sharti
1122116808Sharti	/*
1123116808Sharti	 * Allocate a new entry
1124116808Sharti	 */
1125116808Sharti	vcc = malloc(sizeof(*vcc), M_NETGRAPH, M_NOWAIT | M_ZERO);
1126116808Sharti	if (vcc == NULL)
1127116808Sharti		return (ENOMEM);
1128116808Sharti
1129116808Sharti	vcc->hook = hook;
1130116808Sharti	NG_HOOK_SET_PRIVATE(hook, vcc);
1131116808Sharti
1132116808Sharti	LIST_INSERT_HEAD(&priv->vccs, vcc, link);
1133116808Sharti
1134116808Sharti	if (strcmp(name, "manage") == 0)
1135116808Sharti		priv->manage = hook;
1136116808Sharti
1137116808Sharti	return (0);
1138116808Sharti}
1139116808Sharti
1140116808Sharti/*
1141116808Sharti * Connect. Set the peer to queuing.
1142116808Sharti */
1143116808Shartistatic int
1144116808Sharting_atm_connect(hook_p hook)
1145116808Sharti{
1146116808Sharti	if (NG_HOOK_PRIVATE(hook) != NULL)
1147116808Sharti		NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
1148116808Sharti
1149116808Sharti	return (0);
1150116808Sharti}
1151116808Sharti
1152116808Sharti/*
1153116808Sharti * Disconnect a HOOK
1154116808Sharti */
1155116808Shartistatic int
1156116808Sharting_atm_disconnect(hook_p hook)
1157116808Sharti{
1158116808Sharti	struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
1159116808Sharti	struct ngvcc *vcc = NG_HOOK_PRIVATE(hook);
1160116808Sharti
1161116808Sharti	if (vcc == NULL) {
1162116808Sharti		if (hook == priv->output) {
1163116808Sharti			priv->output = NULL;
1164116808Sharti			return (0);
1165116808Sharti		}
1166116808Sharti		if (hook == priv->input) {
1167116808Sharti			priv->input = NULL;
1168116808Sharti			return (0);
1169116808Sharti		}
1170116808Sharti		if (hook == priv->orphans) {
1171116808Sharti			priv->orphans = NULL;
1172116808Sharti			return (0);
1173116808Sharti		}
1174116808Sharti		log(LOG_ERR, "ng_atm: bad hook '%s'", NG_HOOK_NAME(hook));
1175116808Sharti		return (0);
1176116808Sharti	}
1177116808Sharti
1178116808Sharti	/* don't terminate if we are detaching from the interface */
1179117157Sharti	if ((vcc->flags & VCC_OPEN) && priv->ifp != NULL)
1180116808Sharti		(void)cpcs_term(priv, vcc->vpi, vcc->vci);
1181116808Sharti
1182116808Sharti	NG_HOOK_SET_PRIVATE(hook, NULL);
1183116808Sharti
1184116808Sharti	LIST_REMOVE(vcc, link);
1185116808Sharti	free(vcc, M_NETGRAPH);
1186116808Sharti
1187116808Sharti	if (hook == priv->manage)
1188116808Sharti		priv->manage = NULL;
1189116808Sharti
1190116808Sharti	return (0);
1191116808Sharti}
1192116808Sharti
1193116808Sharti/************************************************************/
1194116808Sharti/*
1195116808Sharti * NODE MANAGEMENT
1196116808Sharti */
1197116808Sharti
1198116808Sharti/*
1199116808Sharti * ATM interface attached - create a node and name it like the interface.
1200116808Sharti */
1201116808Shartistatic void
1202116808Sharting_atm_attach(struct ifnet *ifp)
1203116808Sharti{
1204116808Sharti	char name[IFNAMSIZ+1];
1205116808Sharti	node_p node;
1206116808Sharti	struct priv *priv;
1207116808Sharti
1208116808Sharti	KASSERT(IFP2NG(ifp) == 0, ("%s: node alreay exists?", __FUNCTION__));
1209116808Sharti
1210116808Sharti	snprintf(name, sizeof(name), "%s%d", ifp->if_name, ifp->if_unit);
1211116808Sharti
1212116808Sharti	if (ng_make_node_common(&ng_atm_typestruct, &node) != 0) {
1213116808Sharti		log(LOG_ERR, "%s: can't create node for %s\n",
1214116808Sharti		    __FUNCTION__, name);
1215116808Sharti		return;
1216116808Sharti	}
1217116808Sharti
1218116808Sharti	priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
1219116808Sharti	if (priv == NULL) {
1220116808Sharti		log(LOG_ERR, "%s: can't allocate memory for %s\n",
1221116808Sharti		    __FUNCTION__, name);
1222116808Sharti		NG_NODE_UNREF(node);
1223116808Sharti		return;
1224116808Sharti	}
1225116808Sharti	NG_NODE_SET_PRIVATE(node, priv);
1226116808Sharti	priv->ifp = ifp;
1227116808Sharti	LIST_INIT(&priv->vccs);
1228116808Sharti	IFP2NG(ifp) = node;
1229116808Sharti
1230116808Sharti	if (ng_name_node(node, name) != 0) {
1231116808Sharti		log(LOG_WARNING, "%s: can't name node %s\n",
1232116808Sharti		    __FUNCTION__, name);
1233116808Sharti	}
1234116808Sharti}
1235116808Sharti
1236116808Sharti/*
1237116808Sharti * ATM interface detached - destroy node.
1238116808Sharti */
1239116808Shartistatic void
1240116808Sharting_atm_detach(struct ifnet *ifp)
1241116808Sharti{
1242116808Sharti	const node_p node = IFP2NG(ifp);
1243116808Sharti	struct priv *priv;
1244116808Sharti
1245116808Sharti	if(node == NULL)
1246116808Sharti		return;
1247116808Sharti
1248116808Sharti	NG_NODE_REALLY_DIE(node);
1249116808Sharti
1250116808Sharti	priv = NG_NODE_PRIVATE(node);
1251116808Sharti	IFP2NG(priv->ifp) = NULL;
1252116808Sharti	priv->ifp = NULL;
1253116808Sharti
1254116808Sharti	ng_rmnode_self(node);
1255116808Sharti}
1256116808Sharti
1257116808Sharti/*
1258116808Sharti * Shutdown the node. This is called from the shutdown message processing.
1259116808Sharti */
1260116808Shartistatic int
1261116808Sharting_atm_shutdown(node_p node)
1262116808Sharti{
1263116808Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
1264116808Sharti
1265116808Sharti	if (node->nd_flags & NG_REALLY_DIE) {
1266116808Sharti		/*
1267116808Sharti		 * We are called from unloading the ATM driver. Really,
1268116808Sharti		 * really need to shutdown this node. The ifp was
1269116808Sharti		 * already handled in the detach routine.
1270116808Sharti		 */
1271116808Sharti		NG_NODE_SET_PRIVATE(node, NULL);
1272116808Sharti		free(priv, M_NETGRAPH);
1273116808Sharti
1274116808Sharti		NG_NODE_UNREF(node);
1275116808Sharti		return (0);
1276116808Sharti	}
1277116808Sharti
1278116808Sharti#ifdef NGATM_DEBUG
1279116808Sharti	if (!allow_shutdown)
1280116808Sharti		node->nd_flags &= ~NG_INVALID;
1281116808Sharti	else {
1282116808Sharti		IFP2NG(priv->ifp) = NULL;
1283116808Sharti		NG_NODE_SET_PRIVATE(node, NULL);
1284116808Sharti		free(priv, M_NETGRAPH);
1285116808Sharti		NG_NODE_UNREF(node);
1286116808Sharti	}
1287116808Sharti#else
1288116808Sharti	/*
1289116808Sharti	 * We are persistant - reinitialize
1290116808Sharti	 */
1291116808Sharti	node->nd_flags &= ~NG_INVALID;
1292116808Sharti#endif
1293116808Sharti	return (0);
1294116808Sharti}
1295116808Sharti
1296116808Sharti/*
1297116808Sharti * Nodes are constructed only via interface attaches.
1298116808Sharti */
1299116808Shartistatic int
1300116808Sharting_atm_constructor(node_p nodep)
1301116808Sharti{
1302116808Sharti	return (EINVAL);
1303116808Sharti}
1304116808Sharti
1305116808Sharti/************************************************************/
1306116808Sharti/*
1307116808Sharti * INITIALISATION
1308116808Sharti */
1309116808Sharti/*
1310116808Sharti * Loading and unloading of node type
1311116808Sharti *
1312116808Sharti * The assignments to the globals for the hooks should be ok without
1313116808Sharti * a special hook. The use pattern is generally: check that the pointer
1314116808Sharti * is not NULL, call the function. In the attach case this is no problem.
1315116808Sharti * In the detach case we can detach only when no ATM node exists. That
1316116808Sharti * means that there is no ATM interface anymore. So we are sure that
1317116808Sharti * we are not in the code path in if_atmsubr.c. To prevent someone
1318116808Sharti * from adding an interface after we have started to unload the node, we
1319116808Sharti * take the iflist lock so an if_attach will be blocked until we are done.
1320116808Sharti * XXX: perhaps the function pointers should be 'volatile' for this to work
1321116808Sharti * properly.
1322116808Sharti */
1323116808Shartistatic int
1324116808Sharting_atm_mod_event(module_t mod, int event, void *data)
1325116808Sharti{
1326116808Sharti	struct ifnet *ifp;
1327116808Sharti	int error = 0;
1328116808Sharti
1329116808Sharti	switch (event) {
1330116808Sharti
1331116808Sharti	  case MOD_LOAD:
1332116808Sharti		/*
1333116808Sharti		 * Register function hooks
1334116808Sharti		 */
1335116808Sharti		if (ng_atm_attach_p != NULL) {
1336116808Sharti			error = EEXIST;
1337116808Sharti			break;
1338116808Sharti		}
1339116808Sharti		IFNET_RLOCK();
1340116808Sharti
1341116808Sharti		ng_atm_attach_p = ng_atm_attach;
1342116808Sharti		ng_atm_detach_p = ng_atm_detach;
1343116808Sharti		ng_atm_output_p = ng_atm_output;
1344116808Sharti		ng_atm_input_p = ng_atm_input;
1345116808Sharti		ng_atm_input_orphan_p = ng_atm_input_orphans;
1346116808Sharti		ng_atm_message_p = ng_atm_message;
1347116808Sharti
1348116808Sharti		/* Create nodes for existing ATM interfaces */
1349116808Sharti		TAILQ_FOREACH(ifp, &ifnet, if_link) {
1350116808Sharti			if (ifp->if_type == IFT_ATM)
1351116808Sharti				ng_atm_attach(ifp);
1352116808Sharti		}
1353116808Sharti		IFNET_RUNLOCK();
1354116808Sharti		break;
1355116808Sharti
1356116808Sharti	  case MOD_UNLOAD:
1357116808Sharti		IFNET_RLOCK();
1358116808Sharti
1359116808Sharti		ng_atm_attach_p = NULL;
1360116808Sharti		ng_atm_detach_p = NULL;
1361116808Sharti		ng_atm_output_p = NULL;
1362116808Sharti		ng_atm_input_p = NULL;
1363116808Sharti		ng_atm_input_orphan_p = NULL;
1364116808Sharti		ng_atm_message_p = NULL;
1365116808Sharti
1366116808Sharti		TAILQ_FOREACH(ifp, &ifnet, if_link) {
1367116808Sharti			if (ifp->if_type == IFT_ATM)
1368116808Sharti				ng_atm_detach(ifp);
1369116808Sharti		}
1370116808Sharti		IFNET_RUNLOCK();
1371116808Sharti		break;
1372116808Sharti
1373116808Sharti	  default:
1374116808Sharti		error = EOPNOTSUPP;
1375116808Sharti		break;
1376116808Sharti	}
1377116808Sharti	return (error);
1378116808Sharti}
1379