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 */ 66extern void (*ng_atm_attach_p)(struct ifnet *); 67extern void (*ng_atm_detach_p)(struct ifnet *); 68extern int (*ng_atm_output_p)(struct ifnet *, struct mbuf **); 69extern void (*ng_atm_input_p)(struct ifnet *, struct mbuf **, 70 struct atm_pseudohdr *, void *); 71extern void (*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *, 72 struct atm_pseudohdr *, void *); 73extern void (*ng_atm_event_p)(struct ifnet *, uint32_t, void *); 74 75/* 76 * Sysctl stuff. 77 */ 78static SYSCTL_NODE(_net_graph, OID_AUTO, atm, CTLFLAG_RW, 0, 79 "atm related stuff"); 80 81#ifdef NGATM_DEBUG 82static int allow_shutdown; 83 84SYSCTL_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 */ 91struct 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 */ 104struct 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 */ 121static const struct ng_parse_struct_field ng_atm_if_change_info[] = 122 NGM_ATM_IF_CHANGE_INFO; 123static 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 */ 131static const struct ng_parse_struct_field ng_atm_vcc_change_info[] = 132 NGM_ATM_VCC_CHANGE_INFO; 133static 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 */ 141static const struct ng_parse_struct_field ng_atm_acr_change_info[] = 142 NGM_ATM_ACR_CHANGE_INFO; 143static 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 */ 151static const struct ng_parse_struct_field ng_atm_config_type_info[] = 152 NGM_ATM_CONFIG_INFO; 153 154static 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 */ 162static const struct ng_parse_struct_field ng_atm_tparam_type_info[] = 163 NGM_ATM_TPARAM_INFO; 164static const struct ng_parse_type ng_atm_tparam_type = { 165 &ng_parse_struct_type, 166 &ng_atm_tparam_type_info 167}; 168static const struct ng_parse_struct_field ng_atm_vcc_type_info[] = 169 NGM_ATM_VCC_INFO; 170static const struct ng_parse_type ng_atm_vcc_type = { 171 &ng_parse_struct_type, 172 &ng_atm_vcc_type_info 173}; 174 175 176static int 177ng_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} 187static const struct ng_parse_array_info ng_atm_vccarray_info = 188 NGM_ATM_VCCARRAY_INFO; 189static const struct ng_parse_type ng_atm_vccarray_type = { 190 &ng_parse_array_type, 191 &ng_atm_vccarray_info 192}; 193 194 195static const struct ng_parse_struct_field ng_atm_vcctable_type_info[] = 196 NGM_ATM_VCCTABLE_INFO; 197 198static 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 */ 206static const struct ng_parse_struct_field ng_atm_cpcs_init_type_info[] = 207 NGM_ATM_CPCS_INIT_INFO; 208 209static 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 */ 217static const struct ng_parse_struct_field ng_atm_cpcs_term_type_info[] = 218 NGM_ATM_CPCS_TERM_INFO; 219 220static 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 */ 228static const struct ng_parse_struct_field ng_atm_stats_type_info[] = 229 NGM_ATM_STATS_INFO; 230 231static const struct ng_parse_type ng_atm_stats_type = { 232 &ng_parse_struct_type, 233 &ng_atm_stats_type_info 234}; 235 236static 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 319static int ng_atm_mod_event(module_t, int, void *); 320 321static ng_constructor_t ng_atm_constructor; 322static ng_shutdown_t ng_atm_shutdown; 323static ng_rcvmsg_t ng_atm_rcvmsg; 324static ng_newhook_t ng_atm_newhook; 325static ng_connect_t ng_atm_connect; 326static ng_disconnect_t ng_atm_disconnect; 327static ng_rcvdata_t ng_atm_rcvdata; 328static ng_rcvdata_t ng_atm_rcvdrop; 329 330static 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}; 343NETGRAPH_INIT(atm, &ng_atm_typestruct); 344 345static 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 */ 371static void 372ng_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 */ 424static int 425ng_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 */ 445static void 446ng_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 */ 484static int 485ng_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 522static int 523ng_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 */ 534static void 535ng_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 */ 641static void 642ng_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 */ 658static int 659ng_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 */ 804static int 805cpcs_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 */ 823static int 824ng_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 */ 855static int 856text_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
| 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 */ 66extern void (*ng_atm_attach_p)(struct ifnet *); 67extern void (*ng_atm_detach_p)(struct ifnet *); 68extern int (*ng_atm_output_p)(struct ifnet *, struct mbuf **); 69extern void (*ng_atm_input_p)(struct ifnet *, struct mbuf **, 70 struct atm_pseudohdr *, void *); 71extern void (*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *, 72 struct atm_pseudohdr *, void *); 73extern void (*ng_atm_event_p)(struct ifnet *, uint32_t, void *); 74 75/* 76 * Sysctl stuff. 77 */ 78static SYSCTL_NODE(_net_graph, OID_AUTO, atm, CTLFLAG_RW, 0, 79 "atm related stuff"); 80 81#ifdef NGATM_DEBUG 82static int allow_shutdown; 83 84SYSCTL_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 */ 91struct 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 */ 104struct 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 */ 121static const struct ng_parse_struct_field ng_atm_if_change_info[] = 122 NGM_ATM_IF_CHANGE_INFO; 123static 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 */ 131static const struct ng_parse_struct_field ng_atm_vcc_change_info[] = 132 NGM_ATM_VCC_CHANGE_INFO; 133static 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 */ 141static const struct ng_parse_struct_field ng_atm_acr_change_info[] = 142 NGM_ATM_ACR_CHANGE_INFO; 143static 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 */ 151static const struct ng_parse_struct_field ng_atm_config_type_info[] = 152 NGM_ATM_CONFIG_INFO; 153 154static 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 */ 162static const struct ng_parse_struct_field ng_atm_tparam_type_info[] = 163 NGM_ATM_TPARAM_INFO; 164static const struct ng_parse_type ng_atm_tparam_type = { 165 &ng_parse_struct_type, 166 &ng_atm_tparam_type_info 167}; 168static const struct ng_parse_struct_field ng_atm_vcc_type_info[] = 169 NGM_ATM_VCC_INFO; 170static const struct ng_parse_type ng_atm_vcc_type = { 171 &ng_parse_struct_type, 172 &ng_atm_vcc_type_info 173}; 174 175 176static int 177ng_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} 187static const struct ng_parse_array_info ng_atm_vccarray_info = 188 NGM_ATM_VCCARRAY_INFO; 189static const struct ng_parse_type ng_atm_vccarray_type = { 190 &ng_parse_array_type, 191 &ng_atm_vccarray_info 192}; 193 194 195static const struct ng_parse_struct_field ng_atm_vcctable_type_info[] = 196 NGM_ATM_VCCTABLE_INFO; 197 198static 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 */ 206static const struct ng_parse_struct_field ng_atm_cpcs_init_type_info[] = 207 NGM_ATM_CPCS_INIT_INFO; 208 209static 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 */ 217static const struct ng_parse_struct_field ng_atm_cpcs_term_type_info[] = 218 NGM_ATM_CPCS_TERM_INFO; 219 220static 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 */ 228static const struct ng_parse_struct_field ng_atm_stats_type_info[] = 229 NGM_ATM_STATS_INFO; 230 231static const struct ng_parse_type ng_atm_stats_type = { 232 &ng_parse_struct_type, 233 &ng_atm_stats_type_info 234}; 235 236static 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 319static int ng_atm_mod_event(module_t, int, void *); 320 321static ng_constructor_t ng_atm_constructor; 322static ng_shutdown_t ng_atm_shutdown; 323static ng_rcvmsg_t ng_atm_rcvmsg; 324static ng_newhook_t ng_atm_newhook; 325static ng_connect_t ng_atm_connect; 326static ng_disconnect_t ng_atm_disconnect; 327static ng_rcvdata_t ng_atm_rcvdata; 328static ng_rcvdata_t ng_atm_rcvdrop; 329 330static 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}; 343NETGRAPH_INIT(atm, &ng_atm_typestruct); 344 345static 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 */ 371static void 372ng_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 */ 424static int 425ng_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 */ 445static void 446ng_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 */ 484static int 485ng_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 522static int 523ng_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 */ 534static void 535ng_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 */ 641static void 642ng_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 */ 658static int 659ng_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 */ 804static int 805cpcs_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 */ 823static int 824ng_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 */ 855static int 856text_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
|
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 */ 904static int 905ng_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 */ 1160static int 1161ng_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 */ 1203static int 1204ng_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 */ 1215static int 1216ng_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 */ 1261static void 1262ng_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 */ 1296static void 1297ng_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 */ 1317static int 1318ng_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 */ 1356static int 1357ng_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 */ 1380static int 1381ng_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}
| 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 */ 904static int 905ng_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 */ 1160static int 1161ng_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 */ 1203static int 1204ng_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 */ 1215static int 1216ng_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 */ 1261static void 1262ng_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 */ 1296static void 1297ng_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 */ 1317static int 1318ng_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 */ 1356static int 1357ng_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 */ 1380static int 1381ng_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}
|