1139823Simp/*-
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>
28139823Simp */
29139823Simp
30139823Simp/*
31116808Sharti * Netgraph module to connect NATM interfaces to netgraph.
32116808Sharti */
33116808Sharti
34116808Sharti#include <sys/cdefs.h>
35116808Sharti__FBSDID("$FreeBSD$");
36116808Sharti
37116808Sharti#include <sys/param.h>
38116808Sharti#include <sys/systm.h>
39116808Sharti#include <sys/kernel.h>
40116808Sharti#include <sys/malloc.h>
41116808Sharti#include <sys/mbuf.h>
42116808Sharti#include <sys/errno.h>
43116808Sharti#include <sys/syslog.h>
44116808Sharti#include <sys/socket.h>
45116808Sharti#include <sys/socketvar.h>
46116808Sharti#include <sys/sbuf.h>
47116808Sharti#include <sys/ioccom.h>
48116808Sharti#include <sys/sysctl.h>
49116808Sharti
50116808Sharti#include <net/if.h>
51116808Sharti#include <net/if_types.h>
52116808Sharti#include <net/if_arp.h>
53116808Sharti#include <net/if_var.h>
54116808Sharti#include <net/if_media.h>
55116808Sharti#include <net/if_atm.h>
56185571Sbz#include <net/vnet.h>
57116808Sharti
58116808Sharti#include <netgraph/ng_message.h>
59116808Sharti#include <netgraph/netgraph.h>
60116808Sharti#include <netgraph/ng_parse.h>
61116808Sharti#include <netgraph/atm/ng_atm.h>
62116808Sharti
63116808Sharti/*
64116808Sharti * Hooks in the NATM code
65116808Sharti */
66116808Shartiextern void	(*ng_atm_attach_p)(struct ifnet *);
67116808Shartiextern void	(*ng_atm_detach_p)(struct ifnet *);
68116808Shartiextern int	(*ng_atm_output_p)(struct ifnet *, struct mbuf **);
69116808Shartiextern void	(*ng_atm_input_p)(struct ifnet *, struct mbuf **,
70116808Sharti		    struct atm_pseudohdr *, void *);
71116808Shartiextern void	(*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *,
72116808Sharti		    struct atm_pseudohdr *, void *);
73118175Shartiextern void	(*ng_atm_event_p)(struct ifnet *, uint32_t, void *);
74116808Sharti
75116808Sharti/*
76116808Sharti * Sysctl stuff.
77116808Sharti */
78227309Sedstatic SYSCTL_NODE(_net_graph, OID_AUTO, atm, CTLFLAG_RW, 0,
79227309Sed    "atm related stuff");
80116808Sharti
81116808Sharti#ifdef NGATM_DEBUG
82116808Shartistatic int allow_shutdown;
83116808Sharti
84116808ShartiSYSCTL_INT(_net_graph_atm, OID_AUTO, allow_shutdown, CTLFLAG_RW,
85116808Sharti    &allow_shutdown, 0, "allow ng_atm nodes to shutdown");
86116808Sharti#endif
87116808Sharti
88116808Sharti/*
89116808Sharti * Hook private data
90116808Sharti */
91116808Shartistruct ngvcc {
92116808Sharti	uint16_t	vpi;	/* VPI of this hook */
93116808Sharti	uint16_t	vci;	/* VCI of this hook, 0 if none */
94116808Sharti	uint32_t	flags;	/* private flags */
95116808Sharti	hook_p		hook;	/* the connected hook */
96116808Sharti
97116808Sharti	LIST_ENTRY(ngvcc) link;
98116808Sharti};
99117157Sharti#define	VCC_OPEN	0x0001	/* open */
100116808Sharti
101116808Sharti/*
102116808Sharti * Node private data
103116808Sharti */
104116808Shartistruct priv {
105116808Sharti	struct ifnet	*ifp;		/* the ATM interface */
106116808Sharti	hook_p		input;		/* raw input hook */
107116808Sharti	hook_p		orphans;	/* packets to nowhere */
108116808Sharti	hook_p		output;		/* catch output packets */
109116808Sharti	hook_p		manage;		/* has also entry in vccs */
110116808Sharti	uint64_t	in_packets;
111116808Sharti	uint64_t	in_errors;
112116808Sharti	uint64_t	out_packets;
113116808Sharti	uint64_t	out_errors;
114116808Sharti
115116808Sharti	LIST_HEAD(, ngvcc) vccs;
116116808Sharti};
117116808Sharti
118116808Sharti/*
119118175Sharti * Parse ifstate state
120116808Sharti */
121118175Shartistatic const struct ng_parse_struct_field ng_atm_if_change_info[] =
122118175Sharti    NGM_ATM_IF_CHANGE_INFO;
123118175Shartistatic const struct ng_parse_type ng_atm_if_change_type = {
124116808Sharti	&ng_parse_struct_type,
125118175Sharti	&ng_atm_if_change_info
126116808Sharti};
127116808Sharti
128116808Sharti/*
129118175Sharti * Parse vcc state change
130118175Sharti */
131118175Shartistatic const struct ng_parse_struct_field ng_atm_vcc_change_info[] =
132118175Sharti    NGM_ATM_VCC_CHANGE_INFO;
133118175Shartistatic const struct ng_parse_type ng_atm_vcc_change_type = {
134118175Sharti	&ng_parse_struct_type,
135118175Sharti	&ng_atm_vcc_change_info
136118175Sharti};
137118175Sharti
138118175Sharti/*
139118175Sharti * Parse acr change
140118175Sharti */
141118175Shartistatic const struct ng_parse_struct_field ng_atm_acr_change_info[] =
142118175Sharti    NGM_ATM_ACR_CHANGE_INFO;
143118175Shartistatic const struct ng_parse_type ng_atm_acr_change_type = {
144118175Sharti	&ng_parse_struct_type,
145118175Sharti	&ng_atm_acr_change_info
146118175Sharti};
147118175Sharti
148118175Sharti/*
149116808Sharti * Parse the configuration structure ng_atm_config
150116808Sharti */
151116808Shartistatic const struct ng_parse_struct_field ng_atm_config_type_info[] =
152116808Sharti    NGM_ATM_CONFIG_INFO;
153116808Sharti
154116808Shartistatic const struct ng_parse_type ng_atm_config_type = {
155116808Sharti	&ng_parse_struct_type,
156116808Sharti	&ng_atm_config_type_info
157116808Sharti};
158116808Sharti
159116808Sharti/*
160116808Sharti * Parse a single vcc structure and a variable array of these ng_atm_vccs
161116808Sharti */
162116808Shartistatic const struct ng_parse_struct_field ng_atm_tparam_type_info[] =
163116808Sharti    NGM_ATM_TPARAM_INFO;
164116808Shartistatic const struct ng_parse_type ng_atm_tparam_type = {
165116808Sharti	&ng_parse_struct_type,
166116808Sharti	&ng_atm_tparam_type_info
167116808Sharti};
168116808Shartistatic const struct ng_parse_struct_field ng_atm_vcc_type_info[] =
169116808Sharti    NGM_ATM_VCC_INFO;
170116808Shartistatic const struct ng_parse_type ng_atm_vcc_type = {
171116808Sharti	&ng_parse_struct_type,
172116808Sharti	&ng_atm_vcc_type_info
173116808Sharti};
174116808Sharti
175116808Sharti
176116808Shartistatic int
177116808Sharting_atm_vccarray_getlen(const struct ng_parse_type *type,
178116808Sharti	const u_char *start, const u_char *buf)
179116808Sharti{
180116808Sharti	const struct atmio_vcctable *vp;
181116808Sharti
182116808Sharti	vp = (const struct atmio_vcctable *)
183116808Sharti	    (buf - offsetof(struct atmio_vcctable, vccs));
184116808Sharti
185116808Sharti	return (vp->count);
186116808Sharti}
187116808Shartistatic const struct ng_parse_array_info ng_atm_vccarray_info =
188116808Sharti    NGM_ATM_VCCARRAY_INFO;
189116808Shartistatic const struct ng_parse_type ng_atm_vccarray_type = {
190116808Sharti	&ng_parse_array_type,
191116808Sharti	&ng_atm_vccarray_info
192116808Sharti};
193116808Sharti
194116808Sharti
195116808Shartistatic const struct ng_parse_struct_field ng_atm_vcctable_type_info[] =
196116808Sharti    NGM_ATM_VCCTABLE_INFO;
197116808Sharti
198116808Shartistatic const struct ng_parse_type ng_atm_vcctable_type = {
199116808Sharti	&ng_parse_struct_type,
200116808Sharti	&ng_atm_vcctable_type_info
201116808Sharti};
202116808Sharti
203116808Sharti/*
204116808Sharti * Parse CPCS INIT structure ng_atm_cpcs_init
205116808Sharti */
206116808Shartistatic const struct ng_parse_struct_field ng_atm_cpcs_init_type_info[] =
207116808Sharti    NGM_ATM_CPCS_INIT_INFO;
208116808Sharti
209116808Shartistatic const struct ng_parse_type ng_atm_cpcs_init_type = {
210116808Sharti	&ng_parse_struct_type,
211116808Sharti	&ng_atm_cpcs_init_type_info
212116808Sharti};
213116808Sharti
214116808Sharti/*
215116808Sharti * Parse CPCS TERM structure ng_atm_cpcs_term
216116808Sharti */
217116808Shartistatic const struct ng_parse_struct_field ng_atm_cpcs_term_type_info[] =
218116808Sharti    NGM_ATM_CPCS_TERM_INFO;
219116808Sharti
220116808Shartistatic const struct ng_parse_type ng_atm_cpcs_term_type = {
221116808Sharti	&ng_parse_struct_type,
222116808Sharti	&ng_atm_cpcs_term_type_info
223116808Sharti};
224116808Sharti
225116808Sharti/*
226116808Sharti * Parse statistic struct
227116808Sharti */
228116808Shartistatic const struct ng_parse_struct_field ng_atm_stats_type_info[] =
229116808Sharti    NGM_ATM_STATS_INFO;
230116808Sharti
231116808Shartistatic const struct ng_parse_type ng_atm_stats_type = {
232116808Sharti	&ng_parse_struct_type,
233116808Sharti	&ng_atm_stats_type_info
234116808Sharti};
235116808Sharti
236116808Shartistatic const struct ng_cmdlist ng_atm_cmdlist[] = {
237116808Sharti	{
238116808Sharti	  NGM_ATM_COOKIE,
239116808Sharti	  NGM_ATM_GET_IFNAME,
240116808Sharti	  "getifname",
241116808Sharti	  NULL,
242116808Sharti	  &ng_parse_string_type
243116808Sharti	},
244116808Sharti	{
245116808Sharti	  NGM_ATM_COOKIE,
246116808Sharti	  NGM_ATM_GET_CONFIG,
247116808Sharti	  "getconfig",
248116808Sharti	  NULL,
249116808Sharti	  &ng_atm_config_type
250116808Sharti	},
251116808Sharti	{
252116808Sharti	  NGM_ATM_COOKIE,
253116808Sharti	  NGM_ATM_GET_VCCS,
254116808Sharti	  "getvccs",
255116808Sharti	  NULL,
256116808Sharti	  &ng_atm_vcctable_type
257116808Sharti	},
258116808Sharti	{
259116808Sharti	  NGM_ATM_COOKIE,
260116808Sharti	  NGM_ATM_CPCS_INIT,
261116808Sharti	  "cpcsinit",
262116808Sharti	  &ng_atm_cpcs_init_type,
263116808Sharti	  NULL
264116808Sharti	},
265116808Sharti	{
266116808Sharti	  NGM_ATM_COOKIE,
267116808Sharti	  NGM_ATM_CPCS_TERM,
268116808Sharti	  "cpcsterm",
269116808Sharti	  &ng_atm_cpcs_term_type,
270116808Sharti	  NULL
271116808Sharti	},
272116808Sharti	{
273116808Sharti	  NGM_ATM_COOKIE,
274116808Sharti	  NGM_ATM_GET_VCC,
275116808Sharti	  "getvcc",
276116808Sharti	  &ng_parse_hookbuf_type,
277116808Sharti	  &ng_atm_vcc_type
278116808Sharti	},
279116808Sharti	{
280116808Sharti	  NGM_ATM_COOKIE,
281116808Sharti	  NGM_ATM_GET_VCCID,
282116808Sharti	  "getvccid",
283116808Sharti	  &ng_atm_vcc_type,
284116808Sharti	  &ng_atm_vcc_type
285116808Sharti	},
286116808Sharti	{
287116808Sharti	  NGM_ATM_COOKIE,
288116808Sharti	  NGM_ATM_GET_STATS,
289116808Sharti	  "getstats",
290116808Sharti	  NULL,
291116808Sharti	  &ng_atm_stats_type
292116808Sharti	},
293118175Sharti
294118175Sharti	/* events */
295118175Sharti	{
296118175Sharti	  NGM_ATM_COOKIE,
297118175Sharti	  NGM_ATM_IF_CHANGE,
298118175Sharti	  "if_change",
299118175Sharti	  &ng_atm_if_change_type,
300118175Sharti	  &ng_atm_if_change_type,
301118175Sharti	},
302118175Sharti	{
303118175Sharti	  NGM_ATM_COOKIE,
304118175Sharti	  NGM_ATM_VCC_CHANGE,
305118175Sharti	  "vcc_change",
306118175Sharti	  &ng_atm_vcc_change_type,
307118175Sharti	  &ng_atm_vcc_change_type,
308118175Sharti	},
309118175Sharti	{
310118175Sharti	  NGM_ATM_COOKIE,
311118175Sharti	  NGM_ATM_ACR_CHANGE,
312118175Sharti	  "acr_change",
313118175Sharti	  &ng_atm_acr_change_type,
314118175Sharti	  &ng_atm_acr_change_type,
315118175Sharti	},
316116808Sharti	{ 0 }
317116808Sharti};
318116808Sharti
319116808Shartistatic int ng_atm_mod_event(module_t, int, void *);
320116808Sharti
321116808Shartistatic ng_constructor_t ng_atm_constructor;
322116808Shartistatic ng_shutdown_t	ng_atm_shutdown;
323116808Shartistatic ng_rcvmsg_t	ng_atm_rcvmsg;
324116808Shartistatic ng_newhook_t	ng_atm_newhook;
325116808Shartistatic ng_connect_t	ng_atm_connect;
326116808Shartistatic ng_disconnect_t	ng_atm_disconnect;
327116808Shartistatic ng_rcvdata_t	ng_atm_rcvdata;
328116808Shartistatic ng_rcvdata_t	ng_atm_rcvdrop;
329116808Sharti
330116808Shartistatic struct ng_type ng_atm_typestruct = {
331129823Sjulian	.version =	NG_ABI_VERSION,
332129823Sjulian	.name =		NG_ATM_NODE_TYPE,
333129823Sjulian	.mod_event =	ng_atm_mod_event,
334129823Sjulian	.constructor =	ng_atm_constructor,
335129823Sjulian	.rcvmsg =	ng_atm_rcvmsg,
336129823Sjulian	.shutdown =	ng_atm_shutdown,
337129823Sjulian	.newhook =	ng_atm_newhook,
338129823Sjulian	.connect =	ng_atm_connect,
339129823Sjulian	.rcvdata =	ng_atm_rcvdata,
340129823Sjulian	.disconnect =	ng_atm_disconnect,
341129823Sjulian	.cmdlist =	ng_atm_cmdlist,
342116808Sharti};
343116808ShartiNETGRAPH_INIT(atm, &ng_atm_typestruct);
344116808Sharti
345116808Shartistatic const struct {
346116808Sharti	u_int	media;
347116808Sharti	const char *name;
348116808Sharti} atmmedia[] = IFM_SUBTYPE_ATM_DESCRIPTIONS;
349116808Sharti
350116808Sharti
351147256Sbrooks#define	IFP2NG(IFP)	((node_p)((struct ifatm *)(IFP)->if_softc)->ngpriv)
352147256Sbrooks#define	IFP2NG_SET(IFP, val)	(((struct ifatm *)(IFP)->if_softc)->ngpriv = (val))
353116808Sharti
354116808Sharti#define	IFFLAGS "\020\001UP\002BROADCAST\003DEBUG\004LOOPBACK" \
355116808Sharti		 "\005POINTOPOINT\006SMART\007RUNNING\010NOARP" \
356116808Sharti		 "\011PROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX" \
357116808Sharti		 "\015LINK0\016LINK1\017LINK2\020MULTICAST"
358116808Sharti
359116808Sharti
360116808Sharti/************************************************************/
361116808Sharti/*
362116808Sharti * INPUT
363116808Sharti */
364116808Sharti/*
365116808Sharti * A packet is received from an interface.
366116808Sharti * If we have an input hook, prepend the pseudoheader to the data and
367116808Sharti * deliver it out to that hook. If not, look whether it is destined for
368116808Sharti * use. If so locate the appropriate hook, deliver the packet without the
369116808Sharti * header and we are done. If it is not for us, leave it alone.
370116808Sharti */
371116808Shartistatic void
372116808Sharting_atm_input(struct ifnet *ifp, struct mbuf **mp,
373116808Sharti	struct atm_pseudohdr *ah, void *rxhand)
374116808Sharti{
375116808Sharti	node_p node = IFP2NG(ifp);
376116808Sharti	struct priv *priv;
377116808Sharti	const struct ngvcc *vcc;
378116808Sharti	int error;
379116808Sharti
380116808Sharti	if (node == NULL)
381116808Sharti		return;
382116808Sharti	priv = NG_NODE_PRIVATE(node);
383116808Sharti	if (priv->input != NULL) {
384116808Sharti		/*
385116808Sharti		 * Prepend the atm_pseudoheader.
386116808Sharti		 */
387243882Sglebius		M_PREPEND(*mp, sizeof(*ah), M_NOWAIT);
388116808Sharti		if (*mp == NULL)
389116808Sharti			return;
390116808Sharti		memcpy(mtod(*mp, struct atm_pseudohdr *), ah, sizeof(*ah));
391116808Sharti		NG_SEND_DATA_ONLY(error, priv->input, *mp);
392116808Sharti		if (error == 0) {
393116808Sharti			priv->in_packets++;
394116808Sharti			*mp = NULL;
395116808Sharti		} else {
396116808Sharti#ifdef NGATM_DEBUG
397116808Sharti			printf("%s: error=%d\n", __func__, error);
398116808Sharti#endif
399116808Sharti			priv->in_errors++;
400116808Sharti		}
401116808Sharti		return;
402116808Sharti	}
403116808Sharti	if ((ATM_PH_FLAGS(ah) & ATMIO_FLAG_NG) == 0)
404116808Sharti		return;
405116808Sharti
406116808Sharti	vcc = (struct ngvcc *)rxhand;
407116808Sharti
408116808Sharti	NG_SEND_DATA_ONLY(error, vcc->hook, *mp);
409116808Sharti	if (error == 0) {
410116808Sharti		priv->in_packets++;
411116808Sharti		*mp = NULL;
412116808Sharti	} else {
413116808Sharti#ifdef NGATM_DEBUG
414116808Sharti		printf("%s: error=%d\n", __func__, error);
415116808Sharti#endif
416116808Sharti		priv->in_errors++;
417116808Sharti	}
418116808Sharti}
419116808Sharti
420116808Sharti/*
421116808Sharti * ATM packet is about to be output. The atm_pseudohdr is already prepended.
422116808Sharti * If the hook is set, reroute the packet to the hook.
423116808Sharti */
424116808Shartistatic int
425116808Sharting_atm_output(struct ifnet *ifp, struct mbuf **mp)
426116808Sharti{
427116808Sharti	const node_p node = IFP2NG(ifp);
428116808Sharti	const struct priv *priv;
429116808Sharti	int error = 0;
430116808Sharti
431116808Sharti	if (node == NULL)
432116808Sharti		return (0);
433116808Sharti	priv = NG_NODE_PRIVATE(node);
434116808Sharti	if (priv->output) {
435116808Sharti		NG_SEND_DATA_ONLY(error, priv->output, *mp);
436116808Sharti		*mp = NULL;
437116808Sharti	}
438116808Sharti
439116808Sharti	return (error);
440116808Sharti}
441116808Sharti
442116808Sharti/*
443116808Sharti * Well, this doesn't make much sense for ATM.
444116808Sharti */
445116808Shartistatic void
446116808Sharting_atm_input_orphans(struct ifnet *ifp, struct mbuf *m,
447116808Sharti	struct atm_pseudohdr *ah, void *rxhand)
448116808Sharti{
449116808Sharti	node_p node = IFP2NG(ifp);
450116808Sharti	struct priv *priv;
451116808Sharti	int error;
452116808Sharti
453116808Sharti	if (node == NULL) {
454116808Sharti		m_freem(m);
455116808Sharti		return;
456116808Sharti	}
457116808Sharti	priv = NG_NODE_PRIVATE(node);
458116808Sharti	if (priv->orphans == NULL) {
459116808Sharti		m_freem(m);
460116808Sharti		return;
461116808Sharti	}
462116808Sharti	/*
463116808Sharti	 * Prepend the atm_pseudoheader.
464116808Sharti	 */
465243882Sglebius	M_PREPEND(m, sizeof(*ah), M_NOWAIT);
466116808Sharti	if (m == NULL)
467116808Sharti		return;
468116808Sharti	memcpy(mtod(m, struct atm_pseudohdr *), ah, sizeof(*ah));
469116808Sharti	NG_SEND_DATA_ONLY(error, priv->orphans, m);
470116808Sharti	if (error == 0)
471116808Sharti		priv->in_packets++;
472116808Sharti	else {
473116808Sharti		priv->in_errors++;
474116808Sharti#ifdef NGATM_DEBUG
475116808Sharti		printf("%s: error=%d\n", __func__, error);
476116808Sharti#endif
477116808Sharti	}
478116808Sharti}
479116808Sharti
480116808Sharti/************************************************************/
481116808Sharti/*
482116808Sharti * OUTPUT
483116808Sharti */
484116808Shartistatic int
485116808Sharting_atm_rcvdata(hook_p hook, item_p item)
486116808Sharti{
487116808Sharti	node_p node = NG_HOOK_NODE(hook);
488116808Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
489116808Sharti	const struct ngvcc *vcc = NG_HOOK_PRIVATE(hook);
490116808Sharti	struct mbuf *m;
491116808Sharti	struct atm_pseudohdr *aph;
492116808Sharti	int error;
493116808Sharti
494116808Sharti	if (vcc->vci == 0) {
495116808Sharti		NG_FREE_ITEM(item);
496116808Sharti		return (ENOTCONN);
497116808Sharti	}
498116808Sharti
499116808Sharti	NGI_GET_M(item, m);
500116808Sharti	NG_FREE_ITEM(item);
501116808Sharti
502116808Sharti	/*
503116808Sharti	 * Prepend pseudo-hdr. Drivers don't care about the flags.
504116808Sharti	 */
505243882Sglebius	M_PREPEND(m, sizeof(*aph), M_NOWAIT);
506116808Sharti	if (m == NULL) {
507116808Sharti		NG_FREE_M(m);
508116808Sharti		return (ENOMEM);
509116808Sharti	}
510116808Sharti	aph = mtod(m, struct atm_pseudohdr *);
511116808Sharti	ATM_PH_VPI(aph) = vcc->vpi;
512116808Sharti	ATM_PH_SETVCI(aph, vcc->vci);
513116808Sharti	ATM_PH_FLAGS(aph) = 0;
514116808Sharti
515116808Sharti	if ((error = atm_output(priv->ifp, m, NULL, NULL)) == 0)
516116808Sharti		priv->out_packets++;
517116808Sharti	else
518116808Sharti		priv->out_errors++;
519116808Sharti	return (error);
520116808Sharti}
521116808Sharti
522116808Shartistatic int
523116808Sharting_atm_rcvdrop(hook_p hook, item_p item)
524116808Sharti{
525116808Sharti	NG_FREE_ITEM(item);
526116808Sharti	return (0);
527116808Sharti}
528116808Sharti
529116808Sharti
530116808Sharti/************************************************************
531116808Sharti *
532118175Sharti * Event from driver.
533116808Sharti */
534116808Shartistatic void
535118175Sharting_atm_event_func(node_p node, hook_p hook, void *arg, int event)
536116808Sharti{
537116808Sharti	const struct priv *priv = NG_NODE_PRIVATE(node);
538116808Sharti	struct ngvcc *vcc;
539116808Sharti	struct ng_mesg *mesg;
540116808Sharti	int error;
541116808Sharti
542118175Sharti	switch (event) {
543116808Sharti
544118175Sharti	  case ATMEV_FLOW_CONTROL:
545116808Sharti	    {
546118175Sharti		struct atmev_flow_control *ev = arg;
547116808Sharti		struct ngm_queue_state *qstate;
548116808Sharti
549116808Sharti		/* find the connection */
550116808Sharti		LIST_FOREACH(vcc, &priv->vccs, link)
551118175Sharti			if (vcc->vci == ev->vci && vcc->vpi == ev->vpi)
552116808Sharti				break;
553116808Sharti		if (vcc == NULL)
554116808Sharti			break;
555116808Sharti
556116808Sharti		/* convert into a flow control message */
557116808Sharti		NG_MKMESSAGE(mesg, NGM_FLOW_COOKIE,
558118175Sharti		    ev->busy ? NGM_HIGH_WATER_PASSED : NGM_LOW_WATER_PASSED,
559116808Sharti		    sizeof(struct ngm_queue_state), M_NOWAIT);
560116808Sharti		if (mesg == NULL)
561116808Sharti			break;
562116808Sharti		qstate = (struct ngm_queue_state *)mesg->data;
563116808Sharti
564116808Sharti		/* XXX have to figure out how to get that info */
565116808Sharti
566123812Salfred		NG_SEND_MSG_HOOK(error, node, mesg, vcc->hook, 0);
567116808Sharti		break;
568116808Sharti	    }
569116808Sharti
570118175Sharti	  case ATMEV_VCC_CHANGED:
571116808Sharti	    {
572118175Sharti		struct atmev_vcc_changed *ev = arg;
573116808Sharti		struct ngm_atm_vcc_change *chg;
574116808Sharti
575116808Sharti		if (priv->manage == NULL)
576116808Sharti			break;
577116808Sharti		NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_VCC_CHANGE,
578116808Sharti		    sizeof(struct ngm_atm_vcc_change), M_NOWAIT);
579116808Sharti		if (mesg == NULL)
580116808Sharti			break;
581116808Sharti		chg = (struct ngm_atm_vcc_change *)mesg->data;
582118175Sharti		chg->vci = ev->vci;
583118175Sharti		chg->vpi = ev->vpi;
584118175Sharti		chg->state = (ev->up != 0);
585116808Sharti		chg->node = NG_NODE_ID(node);
586123812Salfred		NG_SEND_MSG_HOOK(error, node, mesg, priv->manage, 0);
587116808Sharti		break;
588116808Sharti	    }
589116808Sharti
590118175Sharti	  case ATMEV_IFSTATE_CHANGED:
591116808Sharti	    {
592118175Sharti		struct atmev_ifstate_changed *ev = arg;
593118175Sharti		struct ngm_atm_if_change *chg;
594116808Sharti
595116808Sharti		if (priv->manage == NULL)
596116808Sharti			break;
597118175Sharti		NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_IF_CHANGE,
598118175Sharti		    sizeof(struct ngm_atm_if_change), M_NOWAIT);
599116808Sharti		if (mesg == NULL)
600116808Sharti			break;
601118175Sharti		chg = (struct ngm_atm_if_change *)mesg->data;
602118175Sharti		chg->carrier = (ev->carrier != 0);
603118175Sharti		chg->running = (ev->running != 0);
604116808Sharti		chg->node = NG_NODE_ID(node);
605123812Salfred		NG_SEND_MSG_HOOK(error, node, mesg, priv->manage, 0);
606116808Sharti		break;
607116808Sharti	    }
608118175Sharti
609118175Sharti	  case ATMEV_ACR_CHANGED:
610118175Sharti	    {
611118175Sharti		struct atmev_acr_changed *ev = arg;
612118175Sharti		struct ngm_atm_acr_change *acr;
613118175Sharti
614118175Sharti		/* find the connection */
615118175Sharti		LIST_FOREACH(vcc, &priv->vccs, link)
616118175Sharti			if (vcc->vci == ev->vci && vcc->vpi == ev->vpi)
617118175Sharti				break;
618118175Sharti		if (vcc == NULL)
619118175Sharti			break;
620118175Sharti
621118175Sharti		/* convert into a flow control message */
622118175Sharti		NG_MKMESSAGE(mesg, NGM_ATM_COOKIE, NGM_ATM_ACR_CHANGE,
623118175Sharti		    sizeof(struct ngm_atm_acr_change), M_NOWAIT);
624118175Sharti		if (mesg == NULL)
625118175Sharti			break;
626118175Sharti		acr = (struct ngm_atm_acr_change *)mesg->data;
627118175Sharti		acr->node = NG_NODE_ID(node);
628118175Sharti		acr->vci = ev->vci;
629118175Sharti		acr->vpi = ev->vpi;
630118175Sharti		acr->acr = ev->acr;
631118175Sharti
632123812Salfred		NG_SEND_MSG_HOOK(error, node, mesg, vcc->hook, 0);
633118175Sharti		break;
634118175Sharti	    }
635116808Sharti	}
636116808Sharti}
637116808Sharti
638116808Sharti/*
639116808Sharti * Use send_fn to get the right lock
640116808Sharti */
641116808Shartistatic void
642118175Sharting_atm_event(struct ifnet *ifp, uint32_t event, void *arg)
643116808Sharti{
644116808Sharti	const node_p node = IFP2NG(ifp);
645116808Sharti
646118175Sharti	if (node != NULL)
647118175Sharti		/* may happen during attach/detach */
648118175Sharti		(void)ng_send_fn(node, NULL, ng_atm_event_func, arg, event);
649116808Sharti}
650116808Sharti
651116808Sharti/************************************************************
652116808Sharti *
653116808Sharti * CPCS
654116808Sharti */
655116808Sharti/*
656116808Sharti * Open a channel for the user
657116808Sharti */
658116808Shartistatic int
659116808Sharting_atm_cpcs_init(node_p node, const struct ngm_atm_cpcs_init *arg)
660116808Sharti{
661116808Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
662116808Sharti	const struct ifatm_mib *mib;
663116808Sharti	struct ngvcc *vcc;
664116808Sharti	struct atmio_openvcc data;
665116808Sharti	int err;
666116808Sharti
667116808Sharti	if(priv->ifp->if_ioctl == NULL)
668116808Sharti		return (ENXIO);
669116808Sharti
670116808Sharti	mib = (const struct ifatm_mib *)(priv->ifp->if_linkmib);
671116808Sharti
672116808Sharti	LIST_FOREACH(vcc, &priv->vccs, link)
673116808Sharti		if (strcmp(arg->name, NG_HOOK_NAME(vcc->hook)) == 0)
674116808Sharti			break;
675116808Sharti	if (vcc == NULL)
676116808Sharti		return (ENOTCONN);
677117642Sharti	if (vcc->flags & VCC_OPEN)
678116808Sharti		return (EISCONN);
679116808Sharti
680116808Sharti	/*
681116808Sharti	 * Check user arguments and construct ioctl argument
682116808Sharti	 */
683116808Sharti	memset(&data, 0, sizeof(data));
684116808Sharti
685116808Sharti	data.rxhand = vcc;
686116808Sharti
687116808Sharti	switch (data.param.aal = arg->aal) {
688116808Sharti
689117157Sharti	  case ATMIO_AAL_34:
690116808Sharti	  case ATMIO_AAL_5:
691116808Sharti	  case ATMIO_AAL_0:
692116808Sharti	  case ATMIO_AAL_RAW:
693116808Sharti		break;
694116808Sharti
695116808Sharti	  default:
696116808Sharti		return (EINVAL);
697116808Sharti	}
698116808Sharti
699116808Sharti	if (arg->vpi > 0xff)
700116808Sharti		return (EINVAL);
701116808Sharti	data.param.vpi = arg->vpi;
702116808Sharti
703117157Sharti	/* allow 0.0 as catch all receive channel */
704117157Sharti	if (arg->vci == 0 && (arg->vpi != 0 || !(arg->flags & ATMIO_FLAG_NOTX)))
705117157Sharti		return (EINVAL);
706116808Sharti	data.param.vci = arg->vci;
707116808Sharti
708116808Sharti	data.param.tparam.pcr = arg->pcr;
709116808Sharti
710116808Sharti	if (arg->mcr > arg->pcr)
711116808Sharti		return (EINVAL);
712116808Sharti	data.param.tparam.mcr = arg->mcr;
713116808Sharti
714116808Sharti	if (!(arg->flags & ATMIO_FLAG_NOTX)) {
715117157Sharti		if (arg->tmtu == 0)
716117157Sharti			data.param.tmtu = priv->ifp->if_mtu;
717117157Sharti		else {
718117157Sharti			data.param.tmtu = arg->tmtu;
719117157Sharti		}
720116808Sharti	}
721116808Sharti	if (!(arg->flags & ATMIO_FLAG_NORX)) {
722117157Sharti		if (arg->rmtu == 0)
723117157Sharti			data.param.rmtu = priv->ifp->if_mtu;
724117157Sharti		else {
725117157Sharti			data.param.rmtu = arg->rmtu;
726117157Sharti		}
727116808Sharti	}
728116808Sharti
729116808Sharti	switch (data.param.traffic = arg->traffic) {
730116808Sharti
731116808Sharti	  case ATMIO_TRAFFIC_UBR:
732116808Sharti	  case ATMIO_TRAFFIC_CBR:
733116808Sharti		break;
734116808Sharti
735116808Sharti	  case ATMIO_TRAFFIC_VBR:
736116808Sharti		if (arg->scr > arg->pcr)
737116808Sharti			return (EINVAL);
738116808Sharti		data.param.tparam.scr = arg->scr;
739116808Sharti
740116808Sharti		if (arg->mbs > (1 << 24))
741116808Sharti			return (EINVAL);
742116808Sharti		data.param.tparam.mbs = arg->mbs;
743116808Sharti		break;
744116808Sharti
745116808Sharti	  case ATMIO_TRAFFIC_ABR:
746116808Sharti		if (arg->icr > arg->pcr || arg->icr < arg->mcr)
747116808Sharti			return (EINVAL);
748116808Sharti		data.param.tparam.icr = arg->icr;
749116808Sharti
750116808Sharti		if (arg->tbe == 0 || arg->tbe > (1 << 24))
751116808Sharti			return (EINVAL);
752116808Sharti		data.param.tparam.tbe = arg->tbe;
753116808Sharti
754116808Sharti		if (arg->nrm > 0x7)
755116808Sharti			return (EINVAL);
756116808Sharti		data.param.tparam.nrm = arg->nrm;
757116808Sharti
758116808Sharti		if (arg->trm > 0x7)
759116808Sharti			return (EINVAL);
760116808Sharti		data.param.tparam.trm = arg->trm;
761116808Sharti
762116808Sharti		if (arg->adtf > 0x3ff)
763116808Sharti			return (EINVAL);
764116808Sharti		data.param.tparam.adtf = arg->adtf;
765116808Sharti
766116808Sharti		if (arg->rif > 0xf)
767116808Sharti			return (EINVAL);
768116808Sharti		data.param.tparam.rif = arg->rif;
769116808Sharti
770116808Sharti		if (arg->rdf > 0xf)
771116808Sharti			return (EINVAL);
772116808Sharti		data.param.tparam.rdf = arg->rdf;
773116808Sharti
774116808Sharti		if (arg->cdf > 0x7)
775116808Sharti			return (EINVAL);
776116808Sharti		data.param.tparam.cdf = arg->cdf;
777116808Sharti
778116808Sharti		break;
779116808Sharti
780116808Sharti	  default:
781116808Sharti		return (EINVAL);
782116808Sharti	}
783116808Sharti
784116808Sharti	if ((arg->flags & ATMIO_FLAG_NORX) && (arg->flags & ATMIO_FLAG_NOTX))
785116808Sharti		return (EINVAL);
786116808Sharti
787116808Sharti	data.param.flags = arg->flags & ~(ATM_PH_AAL5 | ATM_PH_LLCSNAP);
788116808Sharti	data.param.flags |= ATMIO_FLAG_NG;
789116808Sharti
790116808Sharti	err = (*priv->ifp->if_ioctl)(priv->ifp, SIOCATMOPENVCC, (caddr_t)&data);
791116808Sharti
792116808Sharti	if (err == 0) {
793116808Sharti		vcc->vci = data.param.vci;
794116808Sharti		vcc->vpi = data.param.vpi;
795117157Sharti		vcc->flags = VCC_OPEN;
796116808Sharti	}
797116808Sharti
798116808Sharti	return (err);
799116808Sharti}
800116808Sharti
801116808Sharti/*
802116808Sharti * Issue the close command to the driver
803116808Sharti */
804116808Shartistatic int
805116808Sharticpcs_term(const struct priv *priv, u_int vpi, u_int vci)
806116808Sharti{
807116808Sharti	struct atmio_closevcc data;
808116808Sharti
809116808Sharti	if (priv->ifp->if_ioctl == NULL)
810116808Sharti		return ENXIO;
811116808Sharti
812116808Sharti	data.vpi = vpi;
813116808Sharti	data.vci = vci;
814116808Sharti
815116808Sharti	return ((*priv->ifp->if_ioctl)(priv->ifp,
816116808Sharti	    SIOCATMCLOSEVCC, (caddr_t)&data));
817116808Sharti}
818116808Sharti
819116808Sharti
820116808Sharti/*
821116808Sharti * Close a channel by request of the user
822116808Sharti */
823116808Shartistatic int
824116808Sharting_atm_cpcs_term(node_p node, const struct ngm_atm_cpcs_term *arg)
825116808Sharti{
826116808Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
827116808Sharti	struct ngvcc *vcc;
828116808Sharti	int error;
829116808Sharti
830116808Sharti	LIST_FOREACH(vcc, &priv->vccs, link)
831116808Sharti		if(strcmp(arg->name, NG_HOOK_NAME(vcc->hook)) == 0)
832116808Sharti			break;
833116808Sharti	if (vcc == NULL)
834116808Sharti		return (ENOTCONN);
835117642Sharti	if (!(vcc->flags & VCC_OPEN))
836116808Sharti		return (ENOTCONN);
837116808Sharti
838116808Sharti	error = cpcs_term(priv, vcc->vpi, vcc->vci);
839116808Sharti
840116808Sharti	vcc->vci = 0;
841116808Sharti	vcc->vpi = 0;
842116808Sharti	vcc->flags = 0;
843116808Sharti
844116808Sharti	return (error);
845116808Sharti}
846116808Sharti
847116808Sharti/************************************************************/
848116808Sharti/*
849116808Sharti * CONTROL MESSAGES
850116808Sharti */
851116808Sharti
852116808Sharti/*
853116808Sharti * Produce a textual description of the current status
854116808Sharti */
855116808Shartistatic int
856116808Shartitext_status(node_p node, char *arg, u_int len)
857116808Sharti{
858116808Sharti	const struct priv *priv = NG_NODE_PRIVATE(node);
859116808Sharti	const struct ifatm_mib *mib;
860116808Sharti	struct sbuf sbuf;
861116808Sharti	u_int i;
862116808Sharti
863116808Sharti	static const struct {
864116808Sharti		const char	*name;
865116808Sharti		const char	*vendor;
866116808Sharti	} devices[] = {
867116808Sharti		ATM_DEVICE_NAMES
868116808Sharti	};
869116808Sharti
870116808Sharti	mib = (const struct ifatm_mib *)(priv->ifp->if_linkmib);
871116808Sharti
872116808Sharti	sbuf_new(&sbuf, arg, len, SBUF_FIXEDLEN);
873121816Sbrooks	sbuf_printf(&sbuf, "interface: %s\n", priv->ifp->if_xname);
874116808Sharti
875298431Spfg	if (mib->device >= nitems(devices))
876116808Sharti		sbuf_printf(&sbuf, "device=unknown\nvendor=unknown\n");
877116808Sharti	else
878116808Sharti		sbuf_printf(&sbuf, "device=%s\nvendor=%s\n",
879116808Sharti		    devices[mib->device].name, devices[mib->device].vendor);
880116808Sharti
881116808Sharti	for (i = 0; atmmedia[i].name; i++)
882116808Sharti		if(mib->media == atmmedia[i].media) {
883116808Sharti			sbuf_printf(&sbuf, "media=%s\n", atmmedia[i].name);
884116808Sharti			break;
885116808Sharti		}
886116808Sharti	if(atmmedia[i].name == NULL)
887116808Sharti		sbuf_printf(&sbuf, "media=unknown\n");
888116808Sharti
889116808Sharti	sbuf_printf(&sbuf, "serial=%u esi=%6D hardware=%u software=%u\n",
890116808Sharti	    mib->serial, mib->esi, ":", mib->hw_version, mib->sw_version);
891116808Sharti	sbuf_printf(&sbuf, "pcr=%u vpi_bits=%u vci_bits=%u max_vpcs=%u "
892116808Sharti	    "max_vccs=%u\n", mib->pcr, mib->vpi_bits, mib->vci_bits,
893116808Sharti	    mib->max_vpcs, mib->max_vccs);
894116808Sharti	sbuf_printf(&sbuf, "ifflags=%b\n", priv->ifp->if_flags, IFFLAGS);
895116808Sharti
896116808Sharti	sbuf_finish(&sbuf);
897116808Sharti
898116808Sharti	return (sbuf_len(&sbuf));
899116808Sharti}
900116808Sharti
901116808Sharti/*
902116808Sharti * Get control message
903116808Sharti */
904116808Shartistatic int
905116808Sharting_atm_rcvmsg(node_p node, item_p item, hook_p lasthook)
906116808Sharti{
907116808Sharti	const struct priv *priv = NG_NODE_PRIVATE(node);
908116808Sharti	struct ng_mesg *resp = NULL;
909116808Sharti	struct ng_mesg *msg;
910116808Sharti	struct ifatm_mib *mib = (struct ifatm_mib *)(priv->ifp->if_linkmib);
911116808Sharti	int error = 0;
912116808Sharti
913116808Sharti	NGI_GET_MSG(item, msg);
914116808Sharti
915116808Sharti	switch (msg->header.typecookie) {
916116808Sharti
917116808Sharti	  case NGM_GENERIC_COOKIE:
918116808Sharti		switch (msg->header.cmd) {
919116808Sharti
920116808Sharti		  case NGM_TEXT_STATUS:
921116808Sharti			NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
922116808Sharti			if(resp == NULL) {
923116808Sharti				error = ENOMEM;
924116808Sharti				break;
925116808Sharti			}
926116808Sharti
927116808Sharti			resp->header.arglen = text_status(node,
928116808Sharti			    (char *)resp->data, resp->header.arglen) + 1;
929116808Sharti			break;
930116808Sharti
931116808Sharti		  default:
932116808Sharti			error = EINVAL;
933116808Sharti			break;
934116808Sharti		}
935116808Sharti		break;
936116808Sharti
937116808Sharti	  case NGM_ATM_COOKIE:
938116808Sharti		switch (msg->header.cmd) {
939116808Sharti
940116808Sharti		  case NGM_ATM_GET_IFNAME:
941141196Sru			NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
942116808Sharti			if (resp == NULL) {
943116808Sharti				error = ENOMEM;
944116808Sharti				break;
945116808Sharti			}
946141196Sru			strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ);
947116808Sharti			break;
948116808Sharti
949116808Sharti		  case NGM_ATM_GET_CONFIG:
950116808Sharti		    {
951116808Sharti			struct ngm_atm_config *config;
952116808Sharti
953116808Sharti			NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT);
954116808Sharti			if (resp == NULL) {
955116808Sharti				error = ENOMEM;
956116808Sharti				break;
957116808Sharti			}
958116808Sharti			config = (struct ngm_atm_config *)resp->data;
959116808Sharti			config->pcr = mib->pcr;
960116808Sharti			config->vpi_bits = mib->vpi_bits;
961116808Sharti			config->vci_bits = mib->vci_bits;
962116808Sharti			config->max_vpcs = mib->max_vpcs;
963116808Sharti			config->max_vccs = mib->max_vccs;
964116808Sharti			break;
965116808Sharti		    }
966116808Sharti
967116808Sharti		  case NGM_ATM_GET_VCCS:
968116808Sharti		    {
969116808Sharti			struct atmio_vcctable *vccs;
970116808Sharti			size_t len;
971116808Sharti
972116808Sharti			if (priv->ifp->if_ioctl == NULL) {
973116808Sharti				error = ENXIO;
974116808Sharti				break;
975116808Sharti			}
976116808Sharti			error = (*priv->ifp->if_ioctl)(priv->ifp,
977116808Sharti			    SIOCATMGETVCCS, (caddr_t)&vccs);
978116808Sharti			if (error)
979116808Sharti				break;
980116808Sharti
981116808Sharti			len = sizeof(*vccs) +
982116808Sharti			    vccs->count * sizeof(vccs->vccs[0]);
983116808Sharti			NG_MKRESPONSE(resp, msg, len, M_NOWAIT);
984116808Sharti			if (resp == NULL) {
985116808Sharti				error = ENOMEM;
986116808Sharti				free(vccs, M_DEVBUF);
987116808Sharti				break;
988116808Sharti			}
989116808Sharti
990116808Sharti			(void)memcpy(resp->data, vccs, len);
991116808Sharti			free(vccs, M_DEVBUF);
992116808Sharti
993116808Sharti			break;
994116808Sharti		    }
995116808Sharti
996116808Sharti		  case NGM_ATM_GET_VCC:
997116808Sharti		    {
998125035Sharti			char hook[NG_HOOKSIZ];
999116808Sharti			struct atmio_vcctable *vccs;
1000116808Sharti			struct ngvcc *vcc;
1001116808Sharti			u_int i;
1002116808Sharti
1003116808Sharti			if (priv->ifp->if_ioctl == NULL) {
1004116808Sharti				error = ENXIO;
1005116808Sharti				break;
1006116808Sharti			}
1007125035Sharti			if (msg->header.arglen != NG_HOOKSIZ) {
1008116808Sharti				error = EINVAL;
1009116808Sharti				break;
1010116808Sharti			}
1011125035Sharti			strncpy(hook, msg->data, NG_HOOKSIZ);
1012125035Sharti			hook[NG_HOOKSIZ - 1] = '\0';
1013116808Sharti			LIST_FOREACH(vcc, &priv->vccs, link)
1014116808Sharti				if (strcmp(NG_HOOK_NAME(vcc->hook), hook) == 0)
1015116808Sharti					break;
1016116808Sharti			if (vcc == NULL) {
1017116808Sharti				error = ENOTCONN;
1018116808Sharti				break;
1019116808Sharti			}
1020116808Sharti			error = (*priv->ifp->if_ioctl)(priv->ifp,
1021116808Sharti			    SIOCATMGETVCCS, (caddr_t)&vccs);
1022116808Sharti			if (error)
1023116808Sharti				break;
1024116808Sharti
1025116808Sharti			for (i = 0; i < vccs->count; i++)
1026116808Sharti				if (vccs->vccs[i].vpi == vcc->vpi &&
1027116808Sharti				    vccs->vccs[i].vci == vcc->vci)
1028116808Sharti					break;
1029116808Sharti			if (i == vccs->count) {
1030116808Sharti				error = ENOTCONN;
1031116808Sharti				free(vccs, M_DEVBUF);
1032116808Sharti				break;
1033116808Sharti			}
1034116808Sharti
1035116808Sharti			NG_MKRESPONSE(resp, msg, sizeof(vccs->vccs[0]),
1036116808Sharti			    M_NOWAIT);
1037116808Sharti			if (resp == NULL) {
1038116808Sharti				error = ENOMEM;
1039116808Sharti				free(vccs, M_DEVBUF);
1040116808Sharti				break;
1041116808Sharti			}
1042116808Sharti
1043116808Sharti			*(struct atmio_vcc *)resp->data = vccs->vccs[i];
1044116808Sharti			free(vccs, M_DEVBUF);
1045116808Sharti			break;
1046116808Sharti		    }
1047116808Sharti
1048116808Sharti		  case NGM_ATM_GET_VCCID:
1049116808Sharti		    {
1050116808Sharti			struct atmio_vcc *arg;
1051116808Sharti			struct atmio_vcctable *vccs;
1052116808Sharti			u_int i;
1053116808Sharti
1054116808Sharti			if (priv->ifp->if_ioctl == NULL) {
1055116808Sharti				error = ENXIO;
1056116808Sharti				break;
1057116808Sharti			}
1058116808Sharti			if (msg->header.arglen != sizeof(*arg)) {
1059116808Sharti				error = EINVAL;
1060116808Sharti				break;
1061116808Sharti			}
1062116808Sharti			arg = (struct atmio_vcc *)msg->data;
1063116808Sharti
1064116808Sharti			error = (*priv->ifp->if_ioctl)(priv->ifp,
1065116808Sharti			    SIOCATMGETVCCS, (caddr_t)&vccs);
1066116808Sharti			if (error)
1067116808Sharti				break;
1068116808Sharti
1069116808Sharti			for (i = 0; i < vccs->count; i++)
1070116808Sharti				if (vccs->vccs[i].vpi == arg->vpi &&
1071116808Sharti				    vccs->vccs[i].vci == arg->vci)
1072116808Sharti					break;
1073116808Sharti			if (i == vccs->count) {
1074116808Sharti				error = ENOTCONN;
1075116808Sharti				free(vccs, M_DEVBUF);
1076116808Sharti				break;
1077116808Sharti			}
1078116808Sharti
1079116808Sharti			NG_MKRESPONSE(resp, msg, sizeof(vccs->vccs[0]),
1080116808Sharti			    M_NOWAIT);
1081116808Sharti			if (resp == NULL) {
1082116808Sharti				error = ENOMEM;
1083116808Sharti				free(vccs, M_DEVBUF);
1084116808Sharti				break;
1085116808Sharti			}
1086116808Sharti
1087116808Sharti			*(struct atmio_vcc *)resp->data = vccs->vccs[i];
1088116808Sharti			free(vccs, M_DEVBUF);
1089116808Sharti			break;
1090116808Sharti		    }
1091116808Sharti
1092116808Sharti		  case NGM_ATM_CPCS_INIT:
1093116808Sharti			if (msg->header.arglen !=
1094116808Sharti			    sizeof(struct ngm_atm_cpcs_init)) {
1095116808Sharti				error = EINVAL;
1096116808Sharti				break;
1097116808Sharti			}
1098116808Sharti			error = ng_atm_cpcs_init(node,
1099116808Sharti			    (struct ngm_atm_cpcs_init *)msg->data);
1100116808Sharti			break;
1101116808Sharti
1102116808Sharti		  case NGM_ATM_CPCS_TERM:
1103116808Sharti			if (msg->header.arglen !=
1104116808Sharti			    sizeof(struct ngm_atm_cpcs_term)) {
1105116808Sharti				error = EINVAL;
1106116808Sharti				break;
1107116808Sharti			}
1108116808Sharti			error = ng_atm_cpcs_term(node,
1109116808Sharti			    (struct ngm_atm_cpcs_term *)msg->data);
1110116808Sharti			break;
1111116808Sharti
1112116808Sharti		  case NGM_ATM_GET_STATS:
1113116808Sharti		    {
1114116808Sharti			struct ngm_atm_stats *p;
1115116808Sharti
1116116808Sharti			if (msg->header.arglen != 0) {
1117116808Sharti				error = EINVAL;
1118116808Sharti				break;
1119116808Sharti			}
1120116808Sharti			NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT);
1121116808Sharti			if (resp == NULL) {
1122116808Sharti				error = ENOMEM;
1123116808Sharti				break;
1124116808Sharti			}
1125116808Sharti			p = (struct ngm_atm_stats *)resp->data;
1126116808Sharti			p->in_packets = priv->in_packets;
1127116808Sharti			p->out_packets = priv->out_packets;
1128116808Sharti			p->in_errors = priv->in_errors;
1129116808Sharti			p->out_errors = priv->out_errors;
1130116808Sharti
1131116808Sharti			break;
1132116808Sharti		    }
1133116808Sharti
1134116808Sharti		  default:
1135116808Sharti			error = EINVAL;
1136116808Sharti			break;
1137116808Sharti		}
1138116808Sharti		break;
1139116808Sharti
1140116808Sharti	  default:
1141116808Sharti		error = EINVAL;
1142116808Sharti		break;
1143116808Sharti	}
1144116808Sharti
1145116808Sharti	NG_RESPOND_MSG(error, node, item, resp);
1146116808Sharti	NG_FREE_MSG(msg);
1147116808Sharti	return (error);
1148116808Sharti}
1149116808Sharti
1150116808Sharti/************************************************************/
1151116808Sharti/*
1152116808Sharti * HOOK MANAGEMENT
1153116808Sharti */
1154116808Sharti
1155116808Sharti/*
1156116808Sharti * A new hook is create that will be connected to the node.
1157116808Sharti * Check, whether the name is one of the predefined ones.
1158116808Sharti * If not, create a new entry into the vcc list.
1159116808Sharti */
1160116808Shartistatic int
1161116808Sharting_atm_newhook(node_p node, hook_p hook, const char *name)
1162116808Sharti{
1163116808Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
1164116808Sharti	struct ngvcc *vcc;
1165116808Sharti
1166116808Sharti	if (strcmp(name, "input") == 0) {
1167116808Sharti		priv->input = hook;
1168116808Sharti		NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
1169116808Sharti		return (0);
1170116808Sharti	}
1171116808Sharti	if (strcmp(name, "output") == 0) {
1172116808Sharti		priv->output = hook;
1173116808Sharti		NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
1174116808Sharti		return (0);
1175116808Sharti	}
1176116808Sharti	if (strcmp(name, "orphans") == 0) {
1177116808Sharti		priv->orphans = hook;
1178116808Sharti		NG_HOOK_SET_RCVDATA(hook, ng_atm_rcvdrop);
1179116808Sharti		return (0);
1180116808Sharti	}
1181116808Sharti
1182116808Sharti	/*
1183116808Sharti	 * Allocate a new entry
1184116808Sharti	 */
1185116808Sharti	vcc = malloc(sizeof(*vcc), M_NETGRAPH, M_NOWAIT | M_ZERO);
1186116808Sharti	if (vcc == NULL)
1187116808Sharti		return (ENOMEM);
1188116808Sharti
1189116808Sharti	vcc->hook = hook;
1190116808Sharti	NG_HOOK_SET_PRIVATE(hook, vcc);
1191116808Sharti
1192116808Sharti	LIST_INSERT_HEAD(&priv->vccs, vcc, link);
1193116808Sharti
1194116808Sharti	if (strcmp(name, "manage") == 0)
1195116808Sharti		priv->manage = hook;
1196116808Sharti
1197116808Sharti	return (0);
1198116808Sharti}
1199116808Sharti
1200116808Sharti/*
1201116808Sharti * Connect. Set the peer to queuing.
1202116808Sharti */
1203116808Shartistatic int
1204116808Sharting_atm_connect(hook_p hook)
1205116808Sharti{
1206116808Sharti	if (NG_HOOK_PRIVATE(hook) != NULL)
1207116808Sharti		NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
1208116808Sharti
1209116808Sharti	return (0);
1210116808Sharti}
1211116808Sharti
1212116808Sharti/*
1213116808Sharti * Disconnect a HOOK
1214116808Sharti */
1215116808Shartistatic int
1216116808Sharting_atm_disconnect(hook_p hook)
1217116808Sharti{
1218116808Sharti	struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
1219116808Sharti	struct ngvcc *vcc = NG_HOOK_PRIVATE(hook);
1220116808Sharti
1221116808Sharti	if (vcc == NULL) {
1222116808Sharti		if (hook == priv->output) {
1223116808Sharti			priv->output = NULL;
1224116808Sharti			return (0);
1225116808Sharti		}
1226116808Sharti		if (hook == priv->input) {
1227116808Sharti			priv->input = NULL;
1228116808Sharti			return (0);
1229116808Sharti		}
1230116808Sharti		if (hook == priv->orphans) {
1231116808Sharti			priv->orphans = NULL;
1232116808Sharti			return (0);
1233116808Sharti		}
1234116808Sharti		log(LOG_ERR, "ng_atm: bad hook '%s'", NG_HOOK_NAME(hook));
1235116808Sharti		return (0);
1236116808Sharti	}
1237116808Sharti
1238116808Sharti	/* don't terminate if we are detaching from the interface */
1239117157Sharti	if ((vcc->flags & VCC_OPEN) && priv->ifp != NULL)
1240116808Sharti		(void)cpcs_term(priv, vcc->vpi, vcc->vci);
1241116808Sharti
1242116808Sharti	NG_HOOK_SET_PRIVATE(hook, NULL);
1243116808Sharti
1244116808Sharti	LIST_REMOVE(vcc, link);
1245116808Sharti	free(vcc, M_NETGRAPH);
1246116808Sharti
1247116808Sharti	if (hook == priv->manage)
1248116808Sharti		priv->manage = NULL;
1249116808Sharti
1250116808Sharti	return (0);
1251116808Sharti}
1252116808Sharti
1253116808Sharti/************************************************************/
1254116808Sharti/*
1255116808Sharti * NODE MANAGEMENT
1256116808Sharti */
1257116808Sharti
1258116808Sharti/*
1259116808Sharti * ATM interface attached - create a node and name it like the interface.
1260116808Sharti */
1261116808Shartistatic void
1262116808Sharting_atm_attach(struct ifnet *ifp)
1263116808Sharti{
1264116808Sharti	node_p node;
1265116808Sharti	struct priv *priv;
1266116808Sharti
1267148915Sobrien	KASSERT(IFP2NG(ifp) == 0, ("%s: node alreay exists?", __func__));
1268116808Sharti
1269116808Sharti	if (ng_make_node_common(&ng_atm_typestruct, &node) != 0) {
1270116808Sharti		log(LOG_ERR, "%s: can't create node for %s\n",
1271148915Sobrien		    __func__, ifp->if_xname);
1272116808Sharti		return;
1273116808Sharti	}
1274116808Sharti
1275116808Sharti	priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
1276116808Sharti	if (priv == NULL) {
1277116808Sharti		log(LOG_ERR, "%s: can't allocate memory for %s\n",
1278148915Sobrien		    __func__, ifp->if_xname);
1279116808Sharti		NG_NODE_UNREF(node);
1280116808Sharti		return;
1281116808Sharti	}
1282116808Sharti	NG_NODE_SET_PRIVATE(node, priv);
1283116808Sharti	priv->ifp = ifp;
1284116808Sharti	LIST_INIT(&priv->vccs);
1285132780Skan	IFP2NG_SET(ifp, node);
1286116808Sharti
1287141196Sru	if (ng_name_node(node, ifp->if_xname) != 0) {
1288116808Sharti		log(LOG_WARNING, "%s: can't name node %s\n",
1289148915Sobrien		    __func__, ifp->if_xname);
1290116808Sharti	}
1291116808Sharti}
1292116808Sharti
1293116808Sharti/*
1294116808Sharti * ATM interface detached - destroy node.
1295116808Sharti */
1296116808Shartistatic void
1297116808Sharting_atm_detach(struct ifnet *ifp)
1298116808Sharti{
1299116808Sharti	const node_p node = IFP2NG(ifp);
1300116808Sharti	struct priv *priv;
1301116808Sharti
1302116808Sharti	if(node == NULL)
1303116808Sharti		return;
1304116808Sharti
1305116808Sharti	NG_NODE_REALLY_DIE(node);
1306116808Sharti
1307116808Sharti	priv = NG_NODE_PRIVATE(node);
1308132780Skan	IFP2NG_SET(priv->ifp, NULL);
1309116808Sharti	priv->ifp = NULL;
1310116808Sharti
1311116808Sharti	ng_rmnode_self(node);
1312116808Sharti}
1313116808Sharti
1314116808Sharti/*
1315116808Sharti * Shutdown the node. This is called from the shutdown message processing.
1316116808Sharti */
1317116808Shartistatic int
1318116808Sharting_atm_shutdown(node_p node)
1319116808Sharti{
1320116808Sharti	struct priv *priv = NG_NODE_PRIVATE(node);
1321116808Sharti
1322132464Sjulian	if (node->nd_flags & NGF_REALLY_DIE) {
1323116808Sharti		/*
1324116808Sharti		 * We are called from unloading the ATM driver. Really,
1325116808Sharti		 * really need to shutdown this node. The ifp was
1326116808Sharti		 * already handled in the detach routine.
1327116808Sharti		 */
1328116808Sharti		NG_NODE_SET_PRIVATE(node, NULL);
1329116808Sharti		free(priv, M_NETGRAPH);
1330116808Sharti
1331116808Sharti		NG_NODE_UNREF(node);
1332116808Sharti		return (0);
1333116808Sharti	}
1334116808Sharti
1335116808Sharti#ifdef NGATM_DEBUG
1336116808Sharti	if (!allow_shutdown)
1337132464Sjulian		NG_NODE_REVIVE(node);		/* we persist */
1338116808Sharti	else {
1339132780Skan		IFP2NG_SET(priv->ifp, NULL);
1340116808Sharti		NG_NODE_SET_PRIVATE(node, NULL);
1341116808Sharti		free(priv, M_NETGRAPH);
1342116808Sharti		NG_NODE_UNREF(node);
1343116808Sharti	}
1344116808Sharti#else
1345116808Sharti	/*
1346298813Spfg	 * We are persistent - reinitialize.
1347116808Sharti	 */
1348132464Sjulian	NG_NODE_REVIVE(node);
1349116808Sharti#endif
1350116808Sharti	return (0);
1351116808Sharti}
1352116808Sharti
1353116808Sharti/*
1354116808Sharti * Nodes are constructed only via interface attaches.
1355116808Sharti */
1356116808Shartistatic int
1357116808Sharting_atm_constructor(node_p nodep)
1358116808Sharti{
1359116808Sharti	return (EINVAL);
1360116808Sharti}
1361116808Sharti
1362116808Sharti/************************************************************/
1363116808Sharti/*
1364116808Sharti * INITIALISATION
1365116808Sharti */
1366116808Sharti/*
1367116808Sharti * Loading and unloading of node type
1368116808Sharti *
1369116808Sharti * The assignments to the globals for the hooks should be ok without
1370116808Sharti * a special hook. The use pattern is generally: check that the pointer
1371116808Sharti * is not NULL, call the function. In the attach case this is no problem.
1372116808Sharti * In the detach case we can detach only when no ATM node exists. That
1373116808Sharti * means that there is no ATM interface anymore. So we are sure that
1374116808Sharti * we are not in the code path in if_atmsubr.c. To prevent someone
1375116808Sharti * from adding an interface after we have started to unload the node, we
1376116808Sharti * take the iflist lock so an if_attach will be blocked until we are done.
1377116808Sharti * XXX: perhaps the function pointers should be 'volatile' for this to work
1378116808Sharti * properly.
1379116808Sharti */
1380116808Shartistatic int
1381116808Sharting_atm_mod_event(module_t mod, int event, void *data)
1382116808Sharti{
1383183550Szec	VNET_ITERATOR_DECL(vnet_iter);
1384116808Sharti	struct ifnet *ifp;
1385116808Sharti	int error = 0;
1386116808Sharti
1387116808Sharti	switch (event) {
1388116808Sharti
1389116808Sharti	  case MOD_LOAD:
1390116808Sharti		/*
1391116808Sharti		 * Register function hooks
1392116808Sharti		 */
1393116808Sharti		if (ng_atm_attach_p != NULL) {
1394116808Sharti			error = EEXIST;
1395116808Sharti			break;
1396116808Sharti		}
1397116808Sharti		IFNET_RLOCK();
1398116808Sharti
1399116808Sharti		ng_atm_attach_p = ng_atm_attach;
1400116808Sharti		ng_atm_detach_p = ng_atm_detach;
1401116808Sharti		ng_atm_output_p = ng_atm_output;
1402116808Sharti		ng_atm_input_p = ng_atm_input;
1403116808Sharti		ng_atm_input_orphan_p = ng_atm_input_orphans;
1404118175Sharti		ng_atm_event_p = ng_atm_event;
1405116808Sharti
1406116808Sharti		/* Create nodes for existing ATM interfaces */
1407183550Szec		VNET_LIST_RLOCK();
1408183550Szec		VNET_FOREACH(vnet_iter) {
1409183550Szec			CURVNET_SET_QUIET(vnet_iter);
1410183550Szec			TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1411183550Szec				if (ifp->if_type == IFT_ATM)
1412183550Szec					ng_atm_attach(ifp);
1413183550Szec			}
1414183550Szec			CURVNET_RESTORE();
1415116808Sharti		}
1416183550Szec		VNET_LIST_RUNLOCK();
1417116808Sharti		IFNET_RUNLOCK();
1418116808Sharti		break;
1419116808Sharti
1420116808Sharti	  case MOD_UNLOAD:
1421116808Sharti		IFNET_RLOCK();
1422116808Sharti
1423116808Sharti		ng_atm_attach_p = NULL;
1424116808Sharti		ng_atm_detach_p = NULL;
1425116808Sharti		ng_atm_output_p = NULL;
1426116808Sharti		ng_atm_input_p = NULL;
1427116808Sharti		ng_atm_input_orphan_p = NULL;
1428118175Sharti		ng_atm_event_p = NULL;
1429116808Sharti
1430183550Szec		VNET_LIST_RLOCK();
1431183550Szec		VNET_FOREACH(vnet_iter) {
1432183550Szec			CURVNET_SET_QUIET(vnet_iter);
1433183550Szec			TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1434183550Szec				if (ifp->if_type == IFT_ATM)
1435183550Szec					ng_atm_detach(ifp);
1436183550Szec			}
1437183550Szec			CURVNET_RESTORE();
1438116808Sharti		}
1439183550Szec		VNET_LIST_RUNLOCK();
1440116808Sharti		IFNET_RUNLOCK();
1441116808Sharti		break;
1442116808Sharti
1443116808Sharti	  default:
1444116808Sharti		error = EOPNOTSUPP;
1445116808Sharti		break;
1446116808Sharti	}
1447116808Sharti	return (error);
1448116808Sharti}
1449