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