1/*- 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> 7 * 8 * Redistribution of this software and documentation and use in source and 9 * binary forms, with or without modification, are permitted provided that 10 * the following conditions are met: 11 * 12 * 1. Redistributions of source code or documentation must retain the above 13 * copyright notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 19 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 25 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Netgraph module for ITU-T Q.2110 SSCOP. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD$"); 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/kernel.h> 39#include <sys/malloc.h> 40#include <sys/mbuf.h> 41#include <sys/errno.h> 42#include <sys/syslog.h> 43#include <sys/socket.h> 44#include <sys/socketvar.h> 45#include <sys/callout.h> 46#include <sys/sbuf.h> 47#include <sys/stdint.h> 48#include <machine/stdarg.h> 49 50#include <netgraph/ng_message.h> 51#include <netgraph/netgraph.h> 52#include <netgraph/ng_parse.h> 53#include <netnatm/saal/sscopdef.h> 54#include <netgraph/atm/ng_sscop.h> 55#include <netgraph/atm/sscop/ng_sscop_cust.h> 56#include <netnatm/saal/sscop.h> 57 58#define DDD printf("%s: %d\n", __func__, __LINE__) 59 60#ifdef SSCOP_DEBUG 61#define VERBOSE(P,M,F) \ 62 do { \ 63 if (sscop_getdebug((P)->sscop) & (M)) \ 64 sscop_verbose F ; \ 65 } while(0) 66#else 67#define VERBOSE(P,M,F) 68#endif 69 70MALLOC_DEFINE(M_NG_SSCOP, "netgraph_sscop", "netgraph sscop node"); 71 72MODULE_DEPEND(ng_sscop, ngatmbase, 1, 1, 1); 73 74struct stats { 75 uint64_t in_packets; 76 uint64_t out_packets; 77 uint64_t aa_signals; 78 uint64_t errors; 79 uint64_t data_delivered; 80 uint64_t aa_dropped; 81 uint64_t maa_dropped; 82 uint64_t maa_signals; 83 uint64_t in_dropped; 84 uint64_t out_dropped; 85}; 86 87/* 88 * Private data 89 */ 90struct priv { 91 hook_p upper; /* SAAL interface */ 92 hook_p lower; /* AAL5 interface */ 93 hook_p manage; /* management interface */ 94 95 struct sscop *sscop; /* sscop state */ 96 int enabled; /* whether the protocol is enabled */ 97 int flow; /* flow control states */ 98 struct stats stats; /* sadistics */ 99}; 100 101/* 102 * Parse PARAM type 103 */ 104static const struct ng_parse_struct_field ng_sscop_param_type_info[] = 105 NG_SSCOP_PARAM_INFO; 106 107static const struct ng_parse_type ng_sscop_param_type = { 108 &ng_parse_struct_type, 109 ng_sscop_param_type_info 110}; 111 112/* 113 * Parse a SET PARAM type. 114 */ 115static const struct ng_parse_struct_field ng_sscop_setparam_type_info[] = 116 NG_SSCOP_SETPARAM_INFO; 117 118static const struct ng_parse_type ng_sscop_setparam_type = { 119 &ng_parse_struct_type, 120 ng_sscop_setparam_type_info, 121}; 122 123/* 124 * Parse a SET PARAM response 125 */ 126static const struct ng_parse_struct_field ng_sscop_setparam_resp_type_info[] = 127 NG_SSCOP_SETPARAM_RESP_INFO; 128 129static const struct ng_parse_type ng_sscop_setparam_resp_type = { 130 &ng_parse_struct_type, 131 ng_sscop_setparam_resp_type_info, 132}; 133 134static const struct ng_cmdlist ng_sscop_cmdlist[] = { 135 { 136 NGM_SSCOP_COOKIE, 137 NGM_SSCOP_GETPARAM, 138 "getparam", 139 NULL, 140 &ng_sscop_param_type 141 }, 142 { 143 NGM_SSCOP_COOKIE, 144 NGM_SSCOP_SETPARAM, 145 "setparam", 146 &ng_sscop_setparam_type, 147 &ng_sscop_setparam_resp_type 148 }, 149 { 150 NGM_SSCOP_COOKIE, 151 NGM_SSCOP_ENABLE, 152 "enable", 153 NULL, 154 NULL 155 }, 156 { 157 NGM_SSCOP_COOKIE, 158 NGM_SSCOP_DISABLE, 159 "disable", 160 NULL, 161 NULL 162 }, 163 { 164 NGM_SSCOP_COOKIE, 165 NGM_SSCOP_GETDEBUG, 166 "getdebug", 167 NULL, 168 &ng_parse_hint32_type 169 }, 170 { 171 NGM_SSCOP_COOKIE, 172 NGM_SSCOP_SETDEBUG, 173 "setdebug", 174 &ng_parse_hint32_type, 175 NULL 176 }, 177 { 178 NGM_SSCOP_COOKIE, 179 NGM_SSCOP_GETSTATE, 180 "getstate", 181 NULL, 182 &ng_parse_uint32_type 183 }, 184 { 0 } 185}; 186 187static ng_constructor_t ng_sscop_constructor; 188static ng_shutdown_t ng_sscop_shutdown; 189static ng_rcvmsg_t ng_sscop_rcvmsg; 190static ng_newhook_t ng_sscop_newhook; 191static ng_disconnect_t ng_sscop_disconnect; 192static ng_rcvdata_t ng_sscop_rcvlower; 193static ng_rcvdata_t ng_sscop_rcvupper; 194static ng_rcvdata_t ng_sscop_rcvmanage; 195 196static int ng_sscop_mod_event(module_t, int, void *); 197 198static struct ng_type ng_sscop_typestruct = { 199 .version = NG_ABI_VERSION, 200 .name = NG_SSCOP_NODE_TYPE, 201 .mod_event = ng_sscop_mod_event, 202 .constructor = ng_sscop_constructor, 203 .rcvmsg = ng_sscop_rcvmsg, 204 .shutdown = ng_sscop_shutdown, 205 .newhook = ng_sscop_newhook, 206 .rcvdata = ng_sscop_rcvlower, 207 .disconnect = ng_sscop_disconnect, 208 .cmdlist = ng_sscop_cmdlist, 209}; 210NETGRAPH_INIT(sscop, &ng_sscop_typestruct); 211 212static void sscop_send_manage(struct sscop *, void *, enum sscop_maasig, 213 struct SSCOP_MBUF_T *, u_int, u_int); 214static void sscop_send_upper(struct sscop *, void *, enum sscop_aasig, 215 struct SSCOP_MBUF_T *, u_int); 216static void sscop_send_lower(struct sscop *, void *, 217 struct SSCOP_MBUF_T *); 218static void sscop_verbose(struct sscop *, void *, const char *, ...) 219 __printflike(3, 4); 220 221static const struct sscop_funcs sscop_funcs = { 222 sscop_send_manage, 223 sscop_send_upper, 224 sscop_send_lower, 225 sscop_verbose 226}; 227 228static void 229sscop_verbose(struct sscop *sscop, void *arg, const char *fmt, ...) 230{ 231 va_list ap; 232 233 va_start(ap, fmt); 234 printf("sscop(%p): ", sscop); 235 vprintf(fmt, ap); 236 va_end(ap); 237 printf("\n"); 238} 239 240/************************************************************/ 241/* 242 * NODE MANAGEMENT 243 */ 244static int 245ng_sscop_constructor(node_p node) 246{ 247 struct priv *p; 248 249 p = malloc(sizeof(*p), M_NG_SSCOP, M_WAITOK | M_ZERO); 250 251 if ((p->sscop = sscop_create(node, &sscop_funcs)) == NULL) { 252 free(p, M_NG_SSCOP); 253 return (ENOMEM); 254 } 255 NG_NODE_SET_PRIVATE(node, p); 256 257 /* All data message received by the node are expected to change the 258 * node's state. Therefor we must ensure, that we have a writer lock. */ 259 NG_NODE_FORCE_WRITER(node); 260 261 return (0); 262} 263static int 264ng_sscop_shutdown(node_p node) 265{ 266 struct priv *priv = NG_NODE_PRIVATE(node); 267 268 sscop_destroy(priv->sscop); 269 270 free(priv, M_NG_SSCOP); 271 NG_NODE_SET_PRIVATE(node, NULL); 272 273 NG_NODE_UNREF(node); 274 275 return (0); 276} 277 278/************************************************************/ 279/* 280 * CONTROL MESSAGES 281 */ 282/* 283 * Flow control message from upper layer. 284 * This is very experimental: 285 * If we get a message from the upper layer, that somebody has passed its 286 * high water mark, we stop updating the receive window. 287 * If we get a low watermark passed, then we raise the window up 288 * to max - current. 289 * If we get a queue status and it indicates a current below the 290 * high watermark, we unstop window updates (if they are stopped) and 291 * raise the window to highwater - current. 292 */ 293static int 294flow_upper(node_p node, struct ng_mesg *msg) 295{ 296 struct ngm_queue_state *q; 297 struct priv *priv = NG_NODE_PRIVATE(node); 298 u_int window, space; 299 300 if (msg->header.arglen != sizeof(struct ngm_queue_state)) 301 return (EINVAL); 302 q = (struct ngm_queue_state *)msg->data; 303 304 switch (msg->header.cmd) { 305 306 case NGM_HIGH_WATER_PASSED: 307 if (priv->flow) { 308 VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv, 309 "flow control stopped")); 310 priv->flow = 0; 311 } 312 break; 313 314 case NGM_LOW_WATER_PASSED: 315 window = sscop_window(priv->sscop, 0); 316 space = q->max_queuelen_packets - q->current; 317 if (space > window) { 318 VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv, 319 "flow control opened window by %u messages", 320 space - window)); 321 (void)sscop_window(priv->sscop, space - window); 322 } 323 priv->flow = 1; 324 break; 325 326 case NGM_SYNC_QUEUE_STATE: 327 if (q->high_watermark <= q->current) 328 break; 329 window = sscop_window(priv->sscop, 0); 330 if (priv->flow) 331 space = q->max_queuelen_packets - q->current; 332 else 333 space = q->high_watermark - q->current; 334 if (space > window) { 335 VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv, 336 "flow control opened window by %u messages", 337 space - window)); 338 (void)sscop_window(priv->sscop, space - window); 339 } 340 priv->flow = 1; 341 break; 342 343 default: 344 return (EINVAL); 345 } 346 return (0); 347} 348 349static int 350flow_lower(node_p node, struct ng_mesg *msg) 351{ 352 struct priv *priv = NG_NODE_PRIVATE(node); 353 354 if (msg->header.arglen != sizeof(struct ngm_queue_state)) 355 return (EINVAL); 356 357 switch (msg->header.cmd) { 358 359 case NGM_HIGH_WATER_PASSED: 360 sscop_setbusy(priv->sscop, 1); 361 break; 362 363 case NGM_LOW_WATER_PASSED: 364 sscop_setbusy(priv->sscop, 1); 365 break; 366 367 default: 368 return (EINVAL); 369 } 370 return (0); 371} 372 373/* 374 * Produce a readable status description 375 */ 376static int 377text_status(node_p node, struct priv *priv, char *arg, u_int len) 378{ 379 struct sbuf sbuf; 380 381 sbuf_new(&sbuf, arg, len, 0); 382 383 if (priv->upper) 384 sbuf_printf(&sbuf, "upper hook: %s connected to %s:%s\n", 385 NG_HOOK_NAME(priv->upper), 386 NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))), 387 NG_HOOK_NAME(NG_HOOK_PEER(priv->upper))); 388 else 389 sbuf_printf(&sbuf, "upper hook: <not connected>\n"); 390 391 if (priv->lower) 392 sbuf_printf(&sbuf, "lower hook: %s connected to %s:%s\n", 393 NG_HOOK_NAME(priv->lower), 394 NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))), 395 NG_HOOK_NAME(NG_HOOK_PEER(priv->lower))); 396 else 397 sbuf_printf(&sbuf, "lower hook: <not connected>\n"); 398 399 if (priv->manage) 400 sbuf_printf(&sbuf, "manage hook: %s connected to %s:%s\n", 401 NG_HOOK_NAME(priv->manage), 402 NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->manage))), 403 NG_HOOK_NAME(NG_HOOK_PEER(priv->manage))); 404 else 405 sbuf_printf(&sbuf, "manage hook: <not connected>\n"); 406 407 sbuf_printf(&sbuf, "sscop state: %s\n", 408 !priv->enabled ? "<disabled>" : 409 sscop_statename(sscop_getstate(priv->sscop))); 410 411 sbuf_printf(&sbuf, "input packets: %ju\n", 412 (uintmax_t)priv->stats.in_packets); 413 sbuf_printf(&sbuf, "input dropped: %ju\n", 414 (uintmax_t)priv->stats.in_dropped); 415 sbuf_printf(&sbuf, "output packets: %ju\n", 416 (uintmax_t)priv->stats.out_packets); 417 sbuf_printf(&sbuf, "output dropped: %ju\n", 418 (uintmax_t)priv->stats.out_dropped); 419 sbuf_printf(&sbuf, "aa signals: %ju\n", 420 (uintmax_t)priv->stats.aa_signals); 421 sbuf_printf(&sbuf, "aa dropped: %ju\n", 422 (uintmax_t)priv->stats.aa_dropped); 423 sbuf_printf(&sbuf, "maa signals: %ju\n", 424 (uintmax_t)priv->stats.maa_signals); 425 sbuf_printf(&sbuf, "maa dropped: %ju\n", 426 (uintmax_t)priv->stats.maa_dropped); 427 sbuf_printf(&sbuf, "errors: %ju\n", 428 (uintmax_t)priv->stats.errors); 429 sbuf_printf(&sbuf, "data delivered: %ju\n", 430 (uintmax_t)priv->stats.data_delivered); 431 sbuf_printf(&sbuf, "window: %u\n", 432 sscop_window(priv->sscop, 0)); 433 434 sbuf_finish(&sbuf); 435 return (sbuf_len(&sbuf)); 436} 437 438 439/* 440 * Control message received. 441 */ 442static int 443ng_sscop_rcvmsg(node_p node, item_p item, hook_p lasthook) 444{ 445 struct priv *priv = NG_NODE_PRIVATE(node); 446 struct ng_mesg *resp = NULL; 447 struct ng_mesg *msg; 448 int error = 0; 449 450 NGI_GET_MSG(item, msg); 451 452 switch (msg->header.typecookie) { 453 454 case NGM_GENERIC_COOKIE: 455 switch (msg->header.cmd) { 456 457 case NGM_TEXT_STATUS: 458 NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); 459 if (resp == NULL) { 460 error = ENOMEM; 461 break; 462 } 463 464 resp->header.arglen = text_status(node, priv, 465 (char *)resp->data, resp->header.arglen) + 1; 466 break; 467 468 default: 469 error = EINVAL; 470 break; 471 } 472 break; 473 474 case NGM_FLOW_COOKIE: 475 if (priv->enabled && lasthook != NULL) { 476 if (lasthook == priv->upper) 477 error = flow_upper(node, msg); 478 else if (lasthook == priv->lower) 479 error = flow_lower(node, msg); 480 } 481 break; 482 483 case NGM_SSCOP_COOKIE: 484 switch (msg->header.cmd) { 485 486 case NGM_SSCOP_GETPARAM: 487 { 488 struct sscop_param *p; 489 490 NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT); 491 if (resp == NULL) { 492 error = ENOMEM; 493 break; 494 } 495 p = (struct sscop_param *)resp->data; 496 sscop_getparam(priv->sscop, p); 497 break; 498 } 499 500 case NGM_SSCOP_SETPARAM: 501 { 502 struct ng_sscop_setparam *arg; 503 struct ng_sscop_setparam_resp *p; 504 505 if (msg->header.arglen != sizeof(*arg)) { 506 error = EINVAL; 507 break; 508 } 509 if (priv->enabled) { 510 error = EISCONN; 511 break; 512 } 513 arg = (struct ng_sscop_setparam *)msg->data; 514 NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT); 515 if (resp == NULL) { 516 error = ENOMEM; 517 break; 518 } 519 p = (struct ng_sscop_setparam_resp *)resp->data; 520 p->mask = arg->mask; 521 p->error = sscop_setparam(priv->sscop, 522 &arg->param, &p->mask); 523 break; 524 } 525 526 case NGM_SSCOP_ENABLE: 527 if (msg->header.arglen != 0) { 528 error = EINVAL; 529 break; 530 } 531 if (priv->enabled) { 532 error = EBUSY; 533 break; 534 } 535 priv->enabled = 1; 536 priv->flow = 1; 537 memset(&priv->stats, 0, sizeof(priv->stats)); 538 break; 539 540 case NGM_SSCOP_DISABLE: 541 if (msg->header.arglen != 0) { 542 error = EINVAL; 543 break; 544 } 545 if (!priv->enabled) { 546 error = ENOTCONN; 547 break; 548 } 549 priv->enabled = 0; 550 sscop_reset(priv->sscop); 551 break; 552 553 case NGM_SSCOP_GETDEBUG: 554 if (msg->header.arglen != 0) { 555 error = EINVAL; 556 break; 557 } 558 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 559 if(resp == NULL) { 560 error = ENOMEM; 561 break; 562 } 563 *(u_int32_t *)resp->data = sscop_getdebug(priv->sscop); 564 break; 565 566 case NGM_SSCOP_SETDEBUG: 567 if (msg->header.arglen != sizeof(u_int32_t)) { 568 error = EINVAL; 569 break; 570 } 571 sscop_setdebug(priv->sscop, *(u_int32_t *)msg->data); 572 break; 573 574 case NGM_SSCOP_GETSTATE: 575 if (msg->header.arglen != 0) { 576 error = EINVAL; 577 break; 578 } 579 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 580 if(resp == NULL) { 581 error = ENOMEM; 582 break; 583 } 584 *(u_int32_t *)resp->data = 585 priv->enabled ? (sscop_getstate(priv->sscop) + 1) 586 : 0; 587 break; 588 589 default: 590 error = EINVAL; 591 break; 592 } 593 break; 594 595 default: 596 error = EINVAL; 597 break; 598 } 599 600 NG_RESPOND_MSG(error, node, item, resp); 601 NG_FREE_MSG(msg); 602 603 return (error); 604} 605 606/************************************************************/ 607/* 608 * HOOK MANAGEMENT 609 */ 610static int 611ng_sscop_newhook(node_p node, hook_p hook, const char *name) 612{ 613 struct priv *priv = NG_NODE_PRIVATE(node); 614 615 if(strcmp(name, "upper") == 0) { 616 priv->upper = hook; 617 NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvupper); 618 } else if(strcmp(name, "lower") == 0) { 619 priv->lower = hook; 620 } else if(strcmp(name, "manage") == 0) { 621 priv->manage = hook; 622 NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvmanage); 623 } else 624 return EINVAL; 625 626 return 0; 627} 628static int 629ng_sscop_disconnect(hook_p hook) 630{ 631 node_p node = NG_HOOK_NODE(hook); 632 struct priv *priv = NG_NODE_PRIVATE(node); 633 634 if(hook == priv->upper) 635 priv->upper = NULL; 636 else if(hook == priv->lower) 637 priv->lower = NULL; 638 else if(hook == priv->manage) 639 priv->manage = NULL; 640 641 if(NG_NODE_NUMHOOKS(node) == 0) { 642 if(NG_NODE_IS_VALID(node)) 643 ng_rmnode_self(node); 644 } else { 645 /* 646 * Imply a release request, if the upper layer is 647 * disconnected. 648 */ 649 if(priv->upper == NULL && priv->lower != NULL && 650 priv->enabled && 651 sscop_getstate(priv->sscop) != SSCOP_IDLE) { 652 sscop_aasig(priv->sscop, SSCOP_RELEASE_request, 653 NULL, 0); 654 } 655 } 656 return 0; 657} 658 659/************************************************************/ 660/* 661 * DATA 662 */ 663static int 664ng_sscop_rcvlower(hook_p hook, item_p item) 665{ 666 struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 667 struct mbuf *m; 668 669 if (!priv->enabled) { 670 NG_FREE_ITEM(item); 671 return EINVAL; 672 } 673 674 /* 675 * If we are disconnected at the upper layer and in the IDLE 676 * state, drop any incoming packet. 677 */ 678 if (priv->upper != NULL || sscop_getstate(priv->sscop) != SSCOP_IDLE) { 679 NGI_GET_M(item, m); 680 priv->stats.in_packets++; 681 sscop_input(priv->sscop, m); 682 } else { 683 priv->stats.in_dropped++; 684 } 685 NG_FREE_ITEM(item); 686 687 return (0); 688} 689 690static void 691sscop_send_lower(struct sscop *sscop, void *p, struct mbuf *m) 692{ 693 node_p node = (node_p)p; 694 struct priv *priv = NG_NODE_PRIVATE(node); 695 int error; 696 697 if (priv->lower == NULL) { 698 m_freem(m); 699 priv->stats.out_dropped++; 700 return; 701 } 702 703 priv->stats.out_packets++; 704 NG_SEND_DATA_ONLY(error, priv->lower, m); 705} 706 707static int 708ng_sscop_rcvupper(hook_p hook, item_p item) 709{ 710 struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 711 struct sscop_arg a; 712 struct mbuf *m; 713 714 if (!priv->enabled) { 715 NG_FREE_ITEM(item); 716 return (EINVAL); 717 } 718 719 /* 720 * If the lower layer is not connected allow to proceed. 721 * The lower layer sending function will drop outgoing frames, 722 * and the sscop will timeout any establish requests. 723 */ 724 NGI_GET_M(item, m); 725 NG_FREE_ITEM(item); 726 727 if (!(m->m_flags & M_PKTHDR)) { 728 printf("no pkthdr\n"); 729 m_freem(m); 730 return (EINVAL); 731 } 732 if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL) 733 return (ENOBUFS); 734 bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a)); 735 m_adj(m, sizeof(a)); 736 737 return (sscop_aasig(priv->sscop, a.sig, m, a.arg)); 738} 739 740static void 741sscop_send_upper(struct sscop *sscop, void *p, enum sscop_aasig sig, 742 struct SSCOP_MBUF_T *m, u_int arg) 743{ 744 node_p node = (node_p)p; 745 struct priv *priv = NG_NODE_PRIVATE(node); 746 int error; 747 struct sscop_arg *a; 748 749 if (sig == SSCOP_DATA_indication && priv->flow) 750 sscop_window(priv->sscop, 1); 751 752 if (priv->upper == NULL) { 753 if (m != NULL) 754 m_freem(m); 755 priv->stats.aa_dropped++; 756 return; 757 } 758 759 priv->stats.aa_signals++; 760 if (sig == SSCOP_DATA_indication) 761 priv->stats.data_delivered++; 762 763 if (m == NULL) { 764 MGETHDR(m, M_NOWAIT, MT_DATA); 765 if (m == NULL) 766 return; 767 m->m_len = sizeof(struct sscop_arg); 768 m->m_pkthdr.len = m->m_len; 769 } else { 770 M_PREPEND(m, sizeof(struct sscop_arg), M_NOWAIT); 771 if (m == NULL) 772 return; 773 } 774 a = mtod(m, struct sscop_arg *); 775 a->sig = sig; 776 a->arg = arg; 777 778 NG_SEND_DATA_ONLY(error, priv->upper, m); 779} 780 781static int 782ng_sscop_rcvmanage(hook_p hook, item_p item) 783{ 784 struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 785 struct sscop_marg a; 786 struct mbuf *m; 787 788 if (!priv->enabled) { 789 NG_FREE_ITEM(item); 790 return (EINVAL); 791 } 792 793 NGI_GET_M(item, m); 794 NG_FREE_ITEM(item); 795 796 if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL) 797 return (ENOBUFS); 798 bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a)); 799 m_adj(m, sizeof(a)); 800 801 return (sscop_maasig(priv->sscop, a.sig, m)); 802} 803 804static void 805sscop_send_manage(struct sscop *sscop, void *p, enum sscop_maasig sig, 806 struct SSCOP_MBUF_T *m, u_int err, u_int cnt) 807{ 808 node_p node = (node_p)p; 809 struct priv *priv = NG_NODE_PRIVATE(node); 810 int error; 811 struct sscop_merr *e; 812 struct sscop_marg *a; 813 814 if (priv->manage == NULL) { 815 if (m != NULL) 816 m_freem(m); 817 priv->stats.maa_dropped++; 818 return; 819 } 820 821 if (sig == SSCOP_MERROR_indication) { 822 MGETHDR(m, M_NOWAIT, MT_DATA); 823 if (m == NULL) 824 return; 825 m->m_len = sizeof(*e); 826 m->m_pkthdr.len = m->m_len; 827 e = mtod(m, struct sscop_merr *); 828 e->sig = sig; 829 e->err = err; 830 e->cnt = cnt; 831 priv->stats.errors++; 832 } else if (m == NULL) { 833 MGETHDR(m, M_NOWAIT, MT_DATA); 834 if (m == NULL) 835 return; 836 m->m_len = sizeof(*a); 837 m->m_pkthdr.len = m->m_len; 838 a = mtod(m, struct sscop_marg *); 839 a->sig = sig; 840 priv->stats.maa_signals++; 841 } else { 842 M_PREPEND(m, sizeof(*a), M_NOWAIT); 843 if (m == NULL) 844 return; 845 a = mtod(m, struct sscop_marg *); 846 a->sig = sig; 847 priv->stats.maa_signals++; 848 } 849 850 NG_SEND_DATA_ONLY(error, priv->manage, m); 851} 852 853/************************************************************/ 854/* 855 * INITIALISATION 856 */ 857 858/* 859 * Loading and unloading of node type 860 */ 861static int 862ng_sscop_mod_event(module_t mod, int event, void *data) 863{ 864 int error = 0; 865 866 switch (event) { 867 868 case MOD_LOAD: 869 break; 870 871 case MOD_UNLOAD: 872 break; 873 874 default: 875 error = EOPNOTSUPP; 876 break; 877 } 878 return (error); 879} 880