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