ng_sscfu.c revision 121461
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 for ITU-T Q.2120 UNI SSCF. 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: head/sys/netgraph/atm/sscfu/ng_sscfu.c 121461 2003-10-24 07:39:11Z 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 <machine/stdarg.h> 46 47#include <netgraph/ng_message.h> 48#include <netgraph/netgraph.h> 49#include <netgraph/ng_parse.h> 50#include <netnatm/saal/sscopdef.h> 51#include <netnatm/saal/sscfudef.h> 52#include <netgraph/atm/ng_sscop.h> 53#include <netgraph/atm/ng_sscfu.h> 54#include <netgraph/atm/sscfu/ng_sscfu_cust.h> 55#include <netnatm/saal/sscfu.h> 56 57MALLOC_DEFINE(M_NG_SSCFU, "netgraph_sscfu", "netgraph uni sscf node"); 58 59MODULE_DEPEND(ng_sscfu, ngatmbase, 1, 1, 1); 60 61/* 62 * Private data 63 */ 64struct priv { 65 hook_p upper; /* SAAL interface */ 66 hook_p lower; /* SSCOP interface */ 67 struct sscfu *sscf; /* the instance */ 68 int enabled; 69}; 70 71/* 72 * PARSING 73 */ 74/* 75 * Parse PARAM type 76 */ 77static const struct ng_parse_struct_field ng_sscop_param_type_info[] = 78 NG_SSCOP_PARAM_INFO; 79 80static const struct ng_parse_type ng_sscop_param_type = { 81 &ng_parse_struct_type, 82 ng_sscop_param_type_info 83}; 84 85static const struct ng_parse_struct_field ng_sscfu_getdefparam_type_info[] = 86 NG_SSCFU_GETDEFPARAM_INFO; 87 88static const struct ng_parse_type ng_sscfu_getdefparam_type = { 89 &ng_parse_struct_type, 90 ng_sscfu_getdefparam_type_info 91}; 92 93 94static const struct ng_cmdlist ng_sscfu_cmdlist[] = { 95 { 96 NGM_SSCFU_COOKIE, 97 NGM_SSCFU_GETDEFPARAM, 98 "getdefparam", 99 NULL, 100 &ng_sscfu_getdefparam_type 101 }, 102 { 103 NGM_SSCFU_COOKIE, 104 NGM_SSCFU_ENABLE, 105 "enable", 106 NULL, 107 NULL 108 }, 109 { 110 NGM_SSCFU_COOKIE, 111 NGM_SSCFU_DISABLE, 112 "disable", 113 NULL, 114 NULL 115 }, 116 { 117 NGM_SSCFU_COOKIE, 118 NGM_SSCFU_GETDEBUG, 119 "getdebug", 120 NULL, 121 &ng_parse_hint32_type 122 }, 123 { 124 NGM_SSCFU_COOKIE, 125 NGM_SSCFU_SETDEBUG, 126 "setdebug", 127 &ng_parse_hint32_type, 128 NULL 129 }, 130 { 131 NGM_SSCFU_COOKIE, 132 NGM_SSCFU_GETSTATE, 133 "getstate", 134 NULL, 135 &ng_parse_uint32_type 136 }, 137 { 0 } 138}; 139 140static ng_constructor_t ng_sscfu_constructor; 141static ng_shutdown_t ng_sscfu_shutdown; 142static ng_rcvmsg_t ng_sscfu_rcvmsg; 143static ng_newhook_t ng_sscfu_newhook; 144static ng_disconnect_t ng_sscfu_disconnect; 145static ng_rcvdata_t ng_sscfu_rcvupper; 146static ng_rcvdata_t ng_sscfu_rcvlower; 147 148static int ng_sscfu_mod_event(module_t, int, void *); 149 150static struct ng_type ng_sscfu_typestruct = { 151 NG_ABI_VERSION, 152 NG_SSCFU_NODE_TYPE, 153 ng_sscfu_mod_event, /* Module event handler (optional) */ 154 ng_sscfu_constructor, /* Node constructor */ 155 ng_sscfu_rcvmsg, /* control messages come here */ 156 ng_sscfu_shutdown, /* reset, and free resources */ 157 ng_sscfu_newhook, /* first notification of new hook */ 158 NULL, /* findhook */ 159 NULL, /* connect */ 160 ng_sscfu_rcvupper, /* rcvdata */ 161 ng_sscfu_disconnect, /* notify on disconnect */ 162 ng_sscfu_cmdlist, 163}; 164NETGRAPH_INIT(sscfu, &ng_sscfu_typestruct); 165 166static void sscfu_send_upper(struct sscfu *, void *, enum saal_sig, 167 struct mbuf *); 168static void sscfu_send_lower(struct sscfu *, void *, enum sscop_aasig, 169 struct mbuf *, u_int); 170static void sscfu_window(struct sscfu *, void *, u_int); 171static void sscfu_verbose(struct sscfu *, void *, const char *, ...) 172 __printflike(3, 4); 173 174static const struct sscfu_funcs sscfu_funcs = { 175 sscfu_send_upper, 176 sscfu_send_lower, 177 sscfu_window, 178 sscfu_verbose 179}; 180 181/************************************************************/ 182/* 183 * CONTROL MESSAGES 184 */ 185static int 186text_status(node_p node, struct priv *priv, char *arg, u_int len) 187{ 188 struct sbuf sbuf; 189 190 sbuf_new(&sbuf, arg, len, 0); 191 192 if (priv->upper) 193 sbuf_printf(&sbuf, "upper hook: %s connected to %s:%s\n", 194 NG_HOOK_NAME(priv->upper), 195 NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))), 196 NG_HOOK_NAME(NG_HOOK_PEER(priv->upper))); 197 else 198 sbuf_printf(&sbuf, "upper hook: <not connected>\n"); 199 200 if (priv->lower) 201 sbuf_printf(&sbuf, "lower hook: %s connected to %s:%s\n", 202 NG_HOOK_NAME(priv->lower), 203 NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))), 204 NG_HOOK_NAME(NG_HOOK_PEER(priv->lower))); 205 else 206 sbuf_printf(&sbuf, "lower hook: <not connected>\n"); 207 208 sbuf_printf(&sbuf, "sscf state: %s\n", 209 priv->enabled == NULL ? "<disabled>" : 210 sscfu_statename(sscfu_getstate(priv->sscf))); 211 212 sbuf_finish(&sbuf); 213 return (sbuf_len(&sbuf)); 214} 215 216static int 217ng_sscfu_rcvmsg(node_p node, item_p item, hook_p lasthook) 218{ 219 struct priv *priv = NG_NODE_PRIVATE(node); 220 struct ng_mesg *resp = NULL; 221 struct ng_mesg *msg; 222 int error = 0; 223 224 NGI_GET_MSG(item, msg); 225 226 switch (msg->header.typecookie) { 227 228 case NGM_GENERIC_COOKIE: 229 switch (msg->header.cmd) { 230 231 case NGM_TEXT_STATUS: 232 NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); 233 if (resp == NULL) { 234 error = ENOMEM; 235 break; 236 } 237 resp->header.arglen = text_status(node, priv, 238 (char *)resp->data, resp->header.arglen) + 1; 239 break; 240 241 default: 242 error = EINVAL; 243 break; 244 } 245 break; 246 247 case NGM_SSCFU_COOKIE: 248 switch (msg->header.cmd) { 249 250 case NGM_SSCFU_GETDEFPARAM: 251 { 252 struct ng_sscfu_getdefparam *p; 253 254 if (msg->header.arglen != 0) { 255 error = EINVAL; 256 break; 257 } 258 NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT); 259 if (resp == NULL) { 260 error = ENOMEM; 261 break; 262 } 263 p = (struct ng_sscfu_getdefparam *)resp->data; 264 p->mask = sscfu_getdefparam(&p->param); 265 break; 266 } 267 268 case NGM_SSCFU_ENABLE: 269 if (msg->header.arglen != 0) { 270 error = EINVAL; 271 break; 272 } 273 if (priv->enabled) { 274 error = EISCONN; 275 break; 276 } 277 priv->enabled = 1; 278 break; 279 280 case NGM_SSCFU_DISABLE: 281 if (msg->header.arglen != 0) { 282 error = EINVAL; 283 break; 284 } 285 if (!priv->enabled) { 286 error = ENOTCONN; 287 break; 288 } 289 priv->enabled = 0; 290 sscfu_reset(priv->sscf); 291 break; 292 293 case NGM_SSCFU_GETSTATE: 294 if (msg->header.arglen != 0) { 295 error = EINVAL; 296 break; 297 } 298 NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); 299 if(resp == NULL) { 300 error = ENOMEM; 301 break; 302 } 303 *(uint32_t *)resp->data = 304 priv->enabled ? (sscfu_getstate(priv->sscf) + 1) 305 : 0; 306 break; 307 308 case NGM_SSCFU_GETDEBUG: 309 if (msg->header.arglen != 0) { 310 error = EINVAL; 311 break; 312 } 313 NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT); 314 if(resp == NULL) { 315 error = ENOMEM; 316 break; 317 } 318 *(uint32_t *)resp->data = sscfu_getdebug(priv->sscf); 319 break; 320 321 case NGM_SSCFU_SETDEBUG: 322 if (msg->header.arglen != sizeof(uint32_t)) { 323 error = EINVAL; 324 break; 325 } 326 sscfu_setdebug(priv->sscf, *(uint32_t *)msg->data); 327 break; 328 329 default: 330 error = EINVAL; 331 break; 332 } 333 break; 334 335 default: 336 error = EINVAL; 337 break; 338 } 339 340 NG_RESPOND_MSG(error, node, item, resp); 341 NG_FREE_MSG(msg); 342 343 return (error); 344} 345 346/************************************************************/ 347/* 348 * HOOK MANAGEMENT 349 */ 350static int 351ng_sscfu_newhook(node_p node, hook_p hook, const char *name) 352{ 353 struct priv *priv = NG_NODE_PRIVATE(node); 354 355 if (strcmp(name, "upper") == 0) 356 priv->upper = hook; 357 else if (strcmp(name, "lower") == 0) { 358 priv->lower = hook; 359 NG_HOOK_SET_RCVDATA(hook, ng_sscfu_rcvlower); 360 } else 361 return (EINVAL); 362 return (0); 363} 364 365static int 366ng_sscfu_disconnect(hook_p hook) 367{ 368 node_p node = NG_HOOK_NODE(hook); 369 struct priv *priv = NG_NODE_PRIVATE(node); 370 371 if (hook == priv->upper) 372 priv->upper = NULL; 373 else if (hook == priv->lower) 374 priv->lower = NULL; 375 else { 376 log(LOG_ERR, "bogus hook"); 377 return (EINVAL); 378 } 379 380 if (NG_NODE_NUMHOOKS(node) == 0) { 381 if (NG_NODE_IS_VALID(node)) 382 ng_rmnode_self(node); 383 } else { 384 /* 385 * Because there are no timeouts reset the protocol 386 * if the lower layer is disconnected. 387 */ 388 if (priv->lower == NULL && 389 priv->enabled && 390 sscfu_getstate(priv->sscf) != SSCFU_RELEASED) 391 sscfu_reset(priv->sscf); 392 } 393 return (0); 394} 395 396/************************************************************/ 397/* 398 * DATA 399 */ 400static int 401ng_sscfu_rcvupper(hook_p hook, item_p item) 402{ 403 node_p node = NG_HOOK_NODE(hook); 404 struct priv *priv = NG_NODE_PRIVATE(node); 405 struct mbuf *m; 406 struct sscfu_arg a; 407 408 if (!priv->enabled || priv->lower == NULL) { 409 NG_FREE_ITEM(item); 410 return (0); 411 } 412 413 NGI_GET_M(item, m); 414 NG_FREE_ITEM(item); 415 416 if (!(m->m_flags & M_PKTHDR)) { 417 printf("no pkthdr\n"); 418 m_freem(m); 419 return (EINVAL); 420 } 421 if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL) 422 return (ENOMEM); 423 bcopy((caddr_t)mtod(m, struct sscfu_arg *), &a, sizeof(a)); 424 m_adj(m, sizeof(a)); 425 426 return (sscfu_saalsig(priv->sscf, a.sig, m)); 427} 428 429static void 430sscfu_send_upper(struct sscfu *sscf, void *p, enum saal_sig sig, struct mbuf *m) 431{ 432 node_p node = (node_p)p; 433 struct priv *priv = NG_NODE_PRIVATE(node); 434 int error; 435 struct sscfu_arg *a; 436 437 if (priv->upper == NULL) { 438 if (m != NULL) 439 m_freem(m); 440 return; 441 } 442 if (m == NULL) { 443 MGETHDR(m, M_NOWAIT, MT_DATA); 444 if (m == NULL) 445 return; 446 m->m_len = sizeof(struct sscfu_arg); 447 m->m_pkthdr.len = m->m_len; 448 } else { 449 M_PREPEND(m, sizeof(struct sscfu_arg), M_NOWAIT); 450 if (m == NULL) 451 return; 452 } 453 a = mtod(m, struct sscfu_arg *); 454 a->sig = sig; 455 456 NG_SEND_DATA_ONLY(error, priv->upper, m); 457} 458 459static int 460ng_sscfu_rcvlower(hook_p hook, item_p item) 461{ 462 node_p node = NG_HOOK_NODE(hook); 463 struct priv *priv = NG_NODE_PRIVATE(node); 464 struct mbuf *m; 465 struct sscop_arg a; 466 467 if (!priv->enabled || priv->upper == NULL) { 468 NG_FREE_ITEM(item); 469 return (0); 470 } 471 472 NGI_GET_M(item, m); 473 NG_FREE_ITEM(item); 474 475 if (!(m->m_flags & M_PKTHDR)) { 476 printf("no pkthdr\n"); 477 m_freem(m); 478 return (EINVAL); 479 } 480 481 /* 482 * Strip of the SSCOP header. 483 */ 484 if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL) 485 return (ENOMEM); 486 bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a)); 487 m_adj(m, sizeof(a)); 488 489 sscfu_input(priv->sscf, a.sig, m, a.arg); 490 491 return (0); 492} 493 494static void 495sscfu_send_lower(struct sscfu *sscf, void *p, enum sscop_aasig sig, 496 struct mbuf *m, u_int arg) 497{ 498 node_p node = (node_p)p; 499 struct priv *priv = NG_NODE_PRIVATE(node); 500 int error; 501 struct sscop_arg *a; 502 503 if (priv->lower == NULL) { 504 if (m != NULL) 505 m_freem(m); 506 return; 507 } 508 if (m == NULL) { 509 MGETHDR(m, M_NOWAIT, MT_DATA); 510 if (m == NULL) 511 return; 512 m->m_len = sizeof(struct sscop_arg); 513 m->m_pkthdr.len = m->m_len; 514 } else { 515 M_PREPEND(m, sizeof(struct sscop_arg), M_NOWAIT); 516 if (m == NULL) 517 return; 518 } 519 a = mtod(m, struct sscop_arg *); 520 a->sig = sig; 521 a->arg = arg; 522 523 NG_SEND_DATA_ONLY(error, priv->lower, m); 524} 525 526/* 527 * Window is handled by ng_sscop so make this a NOP. 528 */ 529static void 530sscfu_window(struct sscfu *sscfu, void *arg, u_int w) 531{ 532} 533 534/************************************************************/ 535/* 536 * NODE MANAGEMENT 537 */ 538static int 539ng_sscfu_constructor(node_p node) 540{ 541 struct priv *priv; 542 543 if ((priv = malloc(sizeof(*priv), M_NG_SSCFU, M_NOWAIT|M_ZERO)) == NULL) 544 return (ENOMEM); 545 546 if ((priv->sscf = sscfu_create(node, &sscfu_funcs)) == NULL) { 547 free(priv, M_NG_SSCFU); 548 return (ENOMEM); 549 } 550 551 NG_NODE_SET_PRIVATE(node, priv); 552 553 return (0); 554} 555 556static int 557ng_sscfu_shutdown(node_p node) 558{ 559 struct priv *priv = NG_NODE_PRIVATE(node); 560 561 sscfu_destroy(priv->sscf); 562 563 free(priv, M_NG_SSCFU); 564 NG_NODE_SET_PRIVATE(node, NULL); 565 566 NG_NODE_UNREF(node); 567 568 return (0); 569} 570 571static void 572sscfu_verbose(struct sscfu *sscfu, void *arg, const char *fmt, ...) 573{ 574 va_list ap; 575 576 va_start(ap, fmt); 577 printf("sscfu(%p): ", sscfu); 578 vprintf(fmt, ap); 579 va_end(ap); 580 printf("\n"); 581} 582 583/************************************************************/ 584/* 585 * INITIALISATION 586 */ 587/* 588 * Loading and unloading of node type 589 */ 590static int 591ng_sscfu_mod_event(module_t mod, int event, void *data) 592{ 593 int s; 594 int error = 0; 595 596 s = splnet(); 597 switch (event) { 598 599 case MOD_LOAD: 600 break; 601 602 case MOD_UNLOAD: 603 break; 604 605 default: 606 error = EOPNOTSUPP; 607 break; 608 } 609 splx(s); 610 return (error); 611} 612