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