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