1139823Simp/*- 2121461Sharti * Copyright (c) 2001-2003 3121461Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4121461Sharti * All rights reserved. 5121461Sharti * 6121461Sharti * Author: Harti Brandt <harti@freebsd.org> 7121461Sharti * 8121461Sharti * Redistribution of this software and documentation and use in source and 9121461Sharti * binary forms, with or without modification, are permitted provided that 10121461Sharti * the following conditions are met: 11121461Sharti * 12121461Sharti * 1. Redistributions of source code or documentation must retain the above 13121461Sharti * copyright notice, this list of conditions and the following disclaimer. 14121461Sharti * 2. Redistributions in binary form must reproduce the above copyright 15121461Sharti * notice, this list of conditions and the following disclaimer in the 16121461Sharti * documentation and/or other materials provided with the distribution. 17121461Sharti * 18121461Sharti * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 19121461Sharti * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 20121461Sharti * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21121461Sharti * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22121461Sharti * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23121461Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24121461Sharti * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 25121461Sharti * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26121461Sharti * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27121461Sharti * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 28121461Sharti * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29121461Sharti * 30121461Sharti * Netgraph module for ITU-T Q.2110 SSCOP. 31121461Sharti */ 32121461Sharti 33121461Sharti#include <sys/cdefs.h> 34121461Sharti__FBSDID("$FreeBSD$"); 35121461Sharti 36121461Sharti#include <sys/param.h> 37121461Sharti#include <sys/systm.h> 38121461Sharti#include <sys/kernel.h> 39121461Sharti#include <sys/malloc.h> 40121461Sharti#include <sys/mbuf.h> 41121461Sharti#include <sys/errno.h> 42121461Sharti#include <sys/syslog.h> 43121461Sharti#include <sys/socket.h> 44121461Sharti#include <sys/socketvar.h> 45121461Sharti#include <sys/callout.h> 46121461Sharti#include <sys/sbuf.h> 47121461Sharti#include <sys/stdint.h> 48121461Sharti#include <machine/stdarg.h> 49121461Sharti 50121461Sharti#include <netgraph/ng_message.h> 51121461Sharti#include <netgraph/netgraph.h> 52121461Sharti#include <netgraph/ng_parse.h> 53121461Sharti#include <netnatm/saal/sscopdef.h> 54121461Sharti#include <netgraph/atm/ng_sscop.h> 55121461Sharti#include <netgraph/atm/sscop/ng_sscop_cust.h> 56121461Sharti#include <netnatm/saal/sscop.h> 57121461Sharti 58148915Sobrien#define DDD printf("%s: %d\n", __func__, __LINE__) 59121461Sharti 60121461Sharti#ifdef SSCOP_DEBUG 61121461Sharti#define VERBOSE(P,M,F) \ 62121461Sharti do { \ 63121461Sharti if (sscop_getdebug((P)->sscop) & (M)) \ 64121461Sharti sscop_verbose F ; \ 65121461Sharti } while(0) 66121461Sharti#else 67121461Sharti#define VERBOSE(P,M,F) 68121461Sharti#endif 69121461Sharti 70121461ShartiMALLOC_DEFINE(M_NG_SSCOP, "netgraph_sscop", "netgraph sscop node"); 71121461Sharti 72121461ShartiMODULE_DEPEND(ng_sscop, ngatmbase, 1, 1, 1); 73121461Sharti 74121461Shartistruct stats { 75121461Sharti uint64_t in_packets; 76121461Sharti uint64_t out_packets; 77121461Sharti uint64_t aa_signals; 78121461Sharti uint64_t errors; 79121461Sharti uint64_t data_delivered; 80121461Sharti uint64_t aa_dropped; 81121461Sharti uint64_t maa_dropped; 82121461Sharti uint64_t maa_signals; 83121461Sharti uint64_t in_dropped; 84121461Sharti uint64_t out_dropped; 85121461Sharti}; 86121461Sharti 87121461Sharti/* 88121461Sharti * Private data 89121461Sharti */ 90121461Shartistruct priv { 91121461Sharti hook_p upper; /* SAAL interface */ 92121461Sharti hook_p lower; /* AAL5 interface */ 93121461Sharti hook_p manage; /* management interface */ 94121461Sharti 95121461Sharti struct sscop *sscop; /* sscop state */ 96121461Sharti int enabled; /* whether the protocol is enabled */ 97121461Sharti int flow; /* flow control states */ 98121461Sharti struct stats stats; /* sadistics */ 99121461Sharti}; 100121461Sharti 101121461Sharti/* 102121461Sharti * Parse PARAM type 103121461Sharti */ 104121461Shartistatic const struct ng_parse_struct_field ng_sscop_param_type_info[] = 105121461Sharti NG_SSCOP_PARAM_INFO; 106121461Sharti 107121461Shartistatic const struct ng_parse_type ng_sscop_param_type = { 108121461Sharti &ng_parse_struct_type, 109121461Sharti ng_sscop_param_type_info 110121461Sharti}; 111121461Sharti 112121461Sharti/* 113121461Sharti * Parse a SET PARAM type. 114121461Sharti */ 115121461Shartistatic const struct ng_parse_struct_field ng_sscop_setparam_type_info[] = 116121461Sharti NG_SSCOP_SETPARAM_INFO; 117121461Sharti 118121461Shartistatic const struct ng_parse_type ng_sscop_setparam_type = { 119121461Sharti &ng_parse_struct_type, 120121461Sharti ng_sscop_setparam_type_info, 121121461Sharti}; 122121461Sharti 123121461Sharti/* 124121461Sharti * Parse a SET PARAM response 125121461Sharti */ 126121461Shartistatic const struct ng_parse_struct_field ng_sscop_setparam_resp_type_info[] = 127121461Sharti NG_SSCOP_SETPARAM_RESP_INFO; 128121461Sharti 129121461Shartistatic const struct ng_parse_type ng_sscop_setparam_resp_type = { 130121461Sharti &ng_parse_struct_type, 131121461Sharti ng_sscop_setparam_resp_type_info, 132121461Sharti}; 133121461Sharti 134121461Shartistatic const struct ng_cmdlist ng_sscop_cmdlist[] = { 135121461Sharti { 136121461Sharti NGM_SSCOP_COOKIE, 137121461Sharti NGM_SSCOP_GETPARAM, 138121461Sharti "getparam", 139121461Sharti NULL, 140121461Sharti &ng_sscop_param_type 141121461Sharti }, 142121461Sharti { 143121461Sharti NGM_SSCOP_COOKIE, 144121461Sharti NGM_SSCOP_SETPARAM, 145121461Sharti "setparam", 146121461Sharti &ng_sscop_setparam_type, 147121461Sharti &ng_sscop_setparam_resp_type 148121461Sharti }, 149121461Sharti { 150121461Sharti NGM_SSCOP_COOKIE, 151121461Sharti NGM_SSCOP_ENABLE, 152121461Sharti "enable", 153121461Sharti NULL, 154121461Sharti NULL 155121461Sharti }, 156121461Sharti { 157121461Sharti NGM_SSCOP_COOKIE, 158121461Sharti NGM_SSCOP_DISABLE, 159121461Sharti "disable", 160121461Sharti NULL, 161121461Sharti NULL 162121461Sharti }, 163121461Sharti { 164121461Sharti NGM_SSCOP_COOKIE, 165121461Sharti NGM_SSCOP_GETDEBUG, 166121461Sharti "getdebug", 167121461Sharti NULL, 168121461Sharti &ng_parse_hint32_type 169121461Sharti }, 170121461Sharti { 171121461Sharti NGM_SSCOP_COOKIE, 172121461Sharti NGM_SSCOP_SETDEBUG, 173121461Sharti "setdebug", 174121461Sharti &ng_parse_hint32_type, 175121461Sharti NULL 176121461Sharti }, 177121461Sharti { 178121461Sharti NGM_SSCOP_COOKIE, 179121461Sharti NGM_SSCOP_GETSTATE, 180121461Sharti "getstate", 181121461Sharti NULL, 182121461Sharti &ng_parse_uint32_type 183121461Sharti }, 184121461Sharti { 0 } 185121461Sharti}; 186121461Sharti 187121461Shartistatic ng_constructor_t ng_sscop_constructor; 188121461Shartistatic ng_shutdown_t ng_sscop_shutdown; 189121461Shartistatic ng_rcvmsg_t ng_sscop_rcvmsg; 190121461Shartistatic ng_newhook_t ng_sscop_newhook; 191121461Shartistatic ng_disconnect_t ng_sscop_disconnect; 192121461Shartistatic ng_rcvdata_t ng_sscop_rcvlower; 193121461Shartistatic ng_rcvdata_t ng_sscop_rcvupper; 194121461Shartistatic ng_rcvdata_t ng_sscop_rcvmanage; 195121461Sharti 196121461Shartistatic int ng_sscop_mod_event(module_t, int, void *); 197121461Sharti 198121461Shartistatic struct ng_type ng_sscop_typestruct = { 199129823Sjulian .version = NG_ABI_VERSION, 200129823Sjulian .name = NG_SSCOP_NODE_TYPE, 201129823Sjulian .mod_event = ng_sscop_mod_event, 202129823Sjulian .constructor = ng_sscop_constructor, 203129823Sjulian .rcvmsg = ng_sscop_rcvmsg, 204129823Sjulian .shutdown = ng_sscop_shutdown, 205129823Sjulian .newhook = ng_sscop_newhook, 206129823Sjulian .rcvdata = ng_sscop_rcvlower, 207129823Sjulian .disconnect = ng_sscop_disconnect, 208129823Sjulian .cmdlist = ng_sscop_cmdlist, 209121461Sharti}; 210121461ShartiNETGRAPH_INIT(sscop, &ng_sscop_typestruct); 211121461Sharti 212121461Shartistatic void sscop_send_manage(struct sscop *, void *, enum sscop_maasig, 213121461Sharti struct SSCOP_MBUF_T *, u_int, u_int); 214121461Shartistatic void sscop_send_upper(struct sscop *, void *, enum sscop_aasig, 215121461Sharti struct SSCOP_MBUF_T *, u_int); 216121461Shartistatic void sscop_send_lower(struct sscop *, void *, 217121461Sharti struct SSCOP_MBUF_T *); 218121461Shartistatic void sscop_verbose(struct sscop *, void *, const char *, ...) 219121461Sharti __printflike(3, 4); 220121461Sharti 221121461Shartistatic const struct sscop_funcs sscop_funcs = { 222121461Sharti sscop_send_manage, 223121461Sharti sscop_send_upper, 224121461Sharti sscop_send_lower, 225121461Sharti sscop_verbose 226121461Sharti}; 227121461Sharti 228121461Shartistatic void 229121461Shartisscop_verbose(struct sscop *sscop, void *arg, const char *fmt, ...) 230121461Sharti{ 231121461Sharti va_list ap; 232121461Sharti 233121461Sharti va_start(ap, fmt); 234121461Sharti printf("sscop(%p): ", sscop); 235121461Sharti vprintf(fmt, ap); 236121461Sharti va_end(ap); 237121461Sharti printf("\n"); 238121461Sharti} 239121461Sharti 240121461Sharti/************************************************************/ 241121461Sharti/* 242121461Sharti * NODE MANAGEMENT 243121461Sharti */ 244121461Shartistatic int 245121461Sharting_sscop_constructor(node_p node) 246121461Sharti{ 247121461Sharti struct priv *p; 248121461Sharti 249220768Sglebius p = malloc(sizeof(*p), M_NG_SSCOP, M_WAITOK | M_ZERO); 250121461Sharti 251121461Sharti if ((p->sscop = sscop_create(node, &sscop_funcs)) == NULL) { 252121461Sharti free(p, M_NG_SSCOP); 253121461Sharti return (ENOMEM); 254121461Sharti } 255121461Sharti NG_NODE_SET_PRIVATE(node, p); 256121461Sharti 257121461Sharti /* All data message received by the node are expected to change the 258121461Sharti * node's state. Therefor we must ensure, that we have a writer lock. */ 259121461Sharti NG_NODE_FORCE_WRITER(node); 260121461Sharti 261121461Sharti return (0); 262121461Sharti} 263121461Shartistatic int 264121461Sharting_sscop_shutdown(node_p node) 265121461Sharti{ 266121461Sharti struct priv *priv = NG_NODE_PRIVATE(node); 267121461Sharti 268121461Sharti sscop_destroy(priv->sscop); 269121461Sharti 270121461Sharti free(priv, M_NG_SSCOP); 271121461Sharti NG_NODE_SET_PRIVATE(node, NULL); 272121461Sharti 273121461Sharti NG_NODE_UNREF(node); 274121461Sharti 275121461Sharti return (0); 276121461Sharti} 277121461Sharti 278121461Sharti/************************************************************/ 279121461Sharti/* 280121461Sharti * CONTROL MESSAGES 281121461Sharti */ 282121461Sharti/* 283121461Sharti * Flow control message from upper layer. 284121461Sharti * This is very experimental: 285121461Sharti * If we get a message from the upper layer, that somebody has passed its 286121461Sharti * high water mark, we stop updating the receive window. 287121461Sharti * If we get a low watermark passed, then we raise the window up 288121461Sharti * to max - current. 289121461Sharti * If we get a queue status and it indicates a current below the 290121461Sharti * high watermark, we unstop window updates (if they are stopped) and 291121461Sharti * raise the window to highwater - current. 292121461Sharti */ 293121461Shartistatic int 294121461Shartiflow_upper(node_p node, struct ng_mesg *msg) 295121461Sharti{ 296121461Sharti struct ngm_queue_state *q; 297121461Sharti struct priv *priv = NG_NODE_PRIVATE(node); 298121461Sharti u_int window, space; 299121461Sharti 300121461Sharti if (msg->header.arglen != sizeof(struct ngm_queue_state)) 301121461Sharti return (EINVAL); 302121461Sharti q = (struct ngm_queue_state *)msg->data; 303121461Sharti 304121461Sharti switch (msg->header.cmd) { 305121461Sharti 306121461Sharti case NGM_HIGH_WATER_PASSED: 307121461Sharti if (priv->flow) { 308121461Sharti VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv, 309121461Sharti "flow control stopped")); 310121461Sharti priv->flow = 0; 311121461Sharti } 312121461Sharti break; 313121461Sharti 314121461Sharti case NGM_LOW_WATER_PASSED: 315121461Sharti window = sscop_window(priv->sscop, 0); 316121461Sharti space = q->max_queuelen_packets - q->current; 317121461Sharti if (space > window) { 318121461Sharti VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv, 319121461Sharti "flow control opened window by %u messages", 320121461Sharti space - window)); 321121461Sharti (void)sscop_window(priv->sscop, space - window); 322121461Sharti } 323121461Sharti priv->flow = 1; 324121461Sharti break; 325121461Sharti 326121461Sharti case NGM_SYNC_QUEUE_STATE: 327121461Sharti if (q->high_watermark <= q->current) 328121461Sharti break; 329121461Sharti window = sscop_window(priv->sscop, 0); 330121461Sharti if (priv->flow) 331121461Sharti space = q->max_queuelen_packets - q->current; 332121461Sharti else 333121461Sharti space = q->high_watermark - q->current; 334121461Sharti if (space > window) { 335121461Sharti VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv, 336121461Sharti "flow control opened window by %u messages", 337121461Sharti space - window)); 338121461Sharti (void)sscop_window(priv->sscop, space - window); 339121461Sharti } 340121461Sharti priv->flow = 1; 341121461Sharti break; 342121461Sharti 343121461Sharti default: 344121461Sharti return (EINVAL); 345121461Sharti } 346121461Sharti return (0); 347121461Sharti} 348121461Sharti 349121461Shartistatic int 350121461Shartiflow_lower(node_p node, struct ng_mesg *msg) 351121461Sharti{ 352121461Sharti struct priv *priv = NG_NODE_PRIVATE(node); 353121461Sharti 354121461Sharti if (msg->header.arglen != sizeof(struct ngm_queue_state)) 355121461Sharti return (EINVAL); 356121461Sharti 357121461Sharti switch (msg->header.cmd) { 358121461Sharti 359121461Sharti case NGM_HIGH_WATER_PASSED: 360121461Sharti sscop_setbusy(priv->sscop, 1); 361121461Sharti break; 362121461Sharti 363121461Sharti case NGM_LOW_WATER_PASSED: 364121461Sharti sscop_setbusy(priv->sscop, 1); 365121461Sharti break; 366121461Sharti 367121461Sharti default: 368121461Sharti return (EINVAL); 369121461Sharti } 370121461Sharti return (0); 371121461Sharti} 372121461Sharti 373121461Sharti/* 374121461Sharti * Produce a readable status description 375121461Sharti */ 376121461Shartistatic int 377121461Shartitext_status(node_p node, struct priv *priv, char *arg, u_int len) 378121461Sharti{ 379121461Sharti struct sbuf sbuf; 380121461Sharti 381121461Sharti sbuf_new(&sbuf, arg, len, 0); 382121461Sharti 383121461Sharti if (priv->upper) 384121461Sharti sbuf_printf(&sbuf, "upper hook: %s connected to %s:%s\n", 385121461Sharti NG_HOOK_NAME(priv->upper), 386121461Sharti NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))), 387121461Sharti NG_HOOK_NAME(NG_HOOK_PEER(priv->upper))); 388121461Sharti else 389121461Sharti sbuf_printf(&sbuf, "upper hook: <not connected>\n"); 390121461Sharti 391121461Sharti if (priv->lower) 392121461Sharti sbuf_printf(&sbuf, "lower hook: %s connected to %s:%s\n", 393121461Sharti NG_HOOK_NAME(priv->lower), 394121461Sharti NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))), 395121461Sharti NG_HOOK_NAME(NG_HOOK_PEER(priv->lower))); 396121461Sharti else 397121461Sharti sbuf_printf(&sbuf, "lower hook: <not connected>\n"); 398121461Sharti 399121461Sharti if (priv->manage) 400121461Sharti sbuf_printf(&sbuf, "manage hook: %s connected to %s:%s\n", 401121461Sharti NG_HOOK_NAME(priv->manage), 402121461Sharti NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->manage))), 403121461Sharti NG_HOOK_NAME(NG_HOOK_PEER(priv->manage))); 404121461Sharti else 405121461Sharti sbuf_printf(&sbuf, "manage hook: <not connected>\n"); 406121461Sharti 407121461Sharti sbuf_printf(&sbuf, "sscop state: %s\n", 408121461Sharti !priv->enabled ? "<disabled>" : 409121461Sharti sscop_statename(sscop_getstate(priv->sscop))); 410121461Sharti 411121461Sharti sbuf_printf(&sbuf, "input packets: %ju\n", 412121461Sharti (uintmax_t)priv->stats.in_packets); 413121461Sharti sbuf_printf(&sbuf, "input dropped: %ju\n", 414121461Sharti (uintmax_t)priv->stats.in_dropped); 415121461Sharti sbuf_printf(&sbuf, "output packets: %ju\n", 416121461Sharti (uintmax_t)priv->stats.out_packets); 417121461Sharti sbuf_printf(&sbuf, "output dropped: %ju\n", 418121461Sharti (uintmax_t)priv->stats.out_dropped); 419121461Sharti sbuf_printf(&sbuf, "aa signals: %ju\n", 420121461Sharti (uintmax_t)priv->stats.aa_signals); 421121461Sharti sbuf_printf(&sbuf, "aa dropped: %ju\n", 422121461Sharti (uintmax_t)priv->stats.aa_dropped); 423121461Sharti sbuf_printf(&sbuf, "maa signals: %ju\n", 424121461Sharti (uintmax_t)priv->stats.maa_signals); 425121461Sharti sbuf_printf(&sbuf, "maa dropped: %ju\n", 426121461Sharti (uintmax_t)priv->stats.maa_dropped); 427121461Sharti sbuf_printf(&sbuf, "errors: %ju\n", 428121461Sharti (uintmax_t)priv->stats.errors); 429121461Sharti sbuf_printf(&sbuf, "data delivered: %ju\n", 430121461Sharti (uintmax_t)priv->stats.data_delivered); 431121461Sharti sbuf_printf(&sbuf, "window: %u\n", 432121461Sharti sscop_window(priv->sscop, 0)); 433121461Sharti 434121461Sharti sbuf_finish(&sbuf); 435121461Sharti return (sbuf_len(&sbuf)); 436121461Sharti} 437121461Sharti 438121461Sharti 439121461Sharti/* 440121461Sharti * Control message received. 441121461Sharti */ 442121461Shartistatic int 443121461Sharting_sscop_rcvmsg(node_p node, item_p item, hook_p lasthook) 444121461Sharti{ 445121461Sharti struct priv *priv = NG_NODE_PRIVATE(node); 446121461Sharti struct ng_mesg *resp = NULL; 447121461Sharti struct ng_mesg *msg; 448121461Sharti int error = 0; 449121461Sharti 450121461Sharti NGI_GET_MSG(item, msg); 451121461Sharti 452121461Sharti switch (msg->header.typecookie) { 453121461Sharti 454121461Sharti case NGM_GENERIC_COOKIE: 455121461Sharti switch (msg->header.cmd) { 456121461Sharti 457121461Sharti case NGM_TEXT_STATUS: 458121461Sharti NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT); 459121461Sharti if (resp == NULL) { 460121461Sharti error = ENOMEM; 461121461Sharti break; 462121461Sharti } 463121461Sharti 464121461Sharti resp->header.arglen = text_status(node, priv, 465121461Sharti (char *)resp->data, resp->header.arglen) + 1; 466121461Sharti break; 467121461Sharti 468121461Sharti default: 469121461Sharti error = EINVAL; 470121461Sharti break; 471121461Sharti } 472121461Sharti break; 473121461Sharti 474121461Sharti case NGM_FLOW_COOKIE: 475121461Sharti if (priv->enabled && lasthook != NULL) { 476121461Sharti if (lasthook == priv->upper) 477121461Sharti error = flow_upper(node, msg); 478121461Sharti else if (lasthook == priv->lower) 479121461Sharti error = flow_lower(node, msg); 480121461Sharti } 481121461Sharti break; 482121461Sharti 483121461Sharti case NGM_SSCOP_COOKIE: 484121461Sharti switch (msg->header.cmd) { 485121461Sharti 486121461Sharti case NGM_SSCOP_GETPARAM: 487121461Sharti { 488121461Sharti struct sscop_param *p; 489121461Sharti 490121461Sharti NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT); 491121461Sharti if (resp == NULL) { 492121461Sharti error = ENOMEM; 493121461Sharti break; 494121461Sharti } 495121461Sharti p = (struct sscop_param *)resp->data; 496121461Sharti sscop_getparam(priv->sscop, p); 497121461Sharti break; 498121461Sharti } 499121461Sharti 500121461Sharti case NGM_SSCOP_SETPARAM: 501121461Sharti { 502121461Sharti struct ng_sscop_setparam *arg; 503121461Sharti struct ng_sscop_setparam_resp *p; 504121461Sharti 505121461Sharti if (msg->header.arglen != sizeof(*arg)) { 506121461Sharti error = EINVAL; 507121461Sharti break; 508121461Sharti } 509121461Sharti if (priv->enabled) { 510121461Sharti error = EISCONN; 511121461Sharti break; 512121461Sharti } 513121461Sharti arg = (struct ng_sscop_setparam *)msg->data; 514121461Sharti NG_MKRESPONSE(resp, msg, sizeof(*p), M_NOWAIT); 515121461Sharti if (resp == NULL) { 516121461Sharti error = ENOMEM; 517121461Sharti break; 518121461Sharti } 519121461Sharti p = (struct ng_sscop_setparam_resp *)resp->data; 520121461Sharti p->mask = arg->mask; 521121461Sharti p->error = sscop_setparam(priv->sscop, 522121461Sharti &arg->param, &p->mask); 523121461Sharti break; 524121461Sharti } 525121461Sharti 526121461Sharti case NGM_SSCOP_ENABLE: 527121461Sharti if (msg->header.arglen != 0) { 528121461Sharti error = EINVAL; 529121461Sharti break; 530121461Sharti } 531121461Sharti if (priv->enabled) { 532121461Sharti error = EBUSY; 533121461Sharti break; 534121461Sharti } 535121461Sharti priv->enabled = 1; 536121461Sharti priv->flow = 1; 537121461Sharti memset(&priv->stats, 0, sizeof(priv->stats)); 538121461Sharti break; 539121461Sharti 540121461Sharti case NGM_SSCOP_DISABLE: 541121461Sharti if (msg->header.arglen != 0) { 542121461Sharti error = EINVAL; 543121461Sharti break; 544121461Sharti } 545121461Sharti if (!priv->enabled) { 546121461Sharti error = ENOTCONN; 547121461Sharti break; 548121461Sharti } 549121461Sharti priv->enabled = 0; 550121461Sharti sscop_reset(priv->sscop); 551121461Sharti break; 552121461Sharti 553121461Sharti case NGM_SSCOP_GETDEBUG: 554121461Sharti if (msg->header.arglen != 0) { 555121461Sharti error = EINVAL; 556121461Sharti break; 557121461Sharti } 558121461Sharti NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 559121461Sharti if(resp == NULL) { 560121461Sharti error = ENOMEM; 561121461Sharti break; 562121461Sharti } 563121461Sharti *(u_int32_t *)resp->data = sscop_getdebug(priv->sscop); 564121461Sharti break; 565121461Sharti 566121461Sharti case NGM_SSCOP_SETDEBUG: 567121461Sharti if (msg->header.arglen != sizeof(u_int32_t)) { 568121461Sharti error = EINVAL; 569121461Sharti break; 570121461Sharti } 571121461Sharti sscop_setdebug(priv->sscop, *(u_int32_t *)msg->data); 572121461Sharti break; 573121461Sharti 574121461Sharti case NGM_SSCOP_GETSTATE: 575121461Sharti if (msg->header.arglen != 0) { 576121461Sharti error = EINVAL; 577121461Sharti break; 578121461Sharti } 579121461Sharti NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 580121461Sharti if(resp == NULL) { 581121461Sharti error = ENOMEM; 582121461Sharti break; 583121461Sharti } 584121461Sharti *(u_int32_t *)resp->data = 585121461Sharti priv->enabled ? (sscop_getstate(priv->sscop) + 1) 586121461Sharti : 0; 587121461Sharti break; 588121461Sharti 589121461Sharti default: 590121461Sharti error = EINVAL; 591121461Sharti break; 592121461Sharti } 593121461Sharti break; 594121461Sharti 595121461Sharti default: 596121461Sharti error = EINVAL; 597121461Sharti break; 598121461Sharti } 599121461Sharti 600121461Sharti NG_RESPOND_MSG(error, node, item, resp); 601121461Sharti NG_FREE_MSG(msg); 602121461Sharti 603121461Sharti return (error); 604121461Sharti} 605121461Sharti 606121461Sharti/************************************************************/ 607121461Sharti/* 608121461Sharti * HOOK MANAGEMENT 609121461Sharti */ 610121461Shartistatic int 611121461Sharting_sscop_newhook(node_p node, hook_p hook, const char *name) 612121461Sharti{ 613121461Sharti struct priv *priv = NG_NODE_PRIVATE(node); 614121461Sharti 615121461Sharti if(strcmp(name, "upper") == 0) { 616121461Sharti priv->upper = hook; 617121461Sharti NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvupper); 618121461Sharti } else if(strcmp(name, "lower") == 0) { 619121461Sharti priv->lower = hook; 620121461Sharti } else if(strcmp(name, "manage") == 0) { 621121461Sharti priv->manage = hook; 622121461Sharti NG_HOOK_SET_RCVDATA(hook, ng_sscop_rcvmanage); 623121461Sharti } else 624121461Sharti return EINVAL; 625121461Sharti 626121461Sharti return 0; 627121461Sharti} 628121461Shartistatic int 629121461Sharting_sscop_disconnect(hook_p hook) 630121461Sharti{ 631121461Sharti node_p node = NG_HOOK_NODE(hook); 632121461Sharti struct priv *priv = NG_NODE_PRIVATE(node); 633121461Sharti 634121461Sharti if(hook == priv->upper) 635121461Sharti priv->upper = NULL; 636121461Sharti else if(hook == priv->lower) 637121461Sharti priv->lower = NULL; 638121461Sharti else if(hook == priv->manage) 639121461Sharti priv->manage = NULL; 640121461Sharti 641121461Sharti if(NG_NODE_NUMHOOKS(node) == 0) { 642121461Sharti if(NG_NODE_IS_VALID(node)) 643121461Sharti ng_rmnode_self(node); 644121461Sharti } else { 645121461Sharti /* 646121461Sharti * Imply a release request, if the upper layer is 647121461Sharti * disconnected. 648121461Sharti */ 649121461Sharti if(priv->upper == NULL && priv->lower != NULL && 650121461Sharti priv->enabled && 651121461Sharti sscop_getstate(priv->sscop) != SSCOP_IDLE) { 652121461Sharti sscop_aasig(priv->sscop, SSCOP_RELEASE_request, 653121461Sharti NULL, 0); 654121461Sharti } 655121461Sharti } 656121461Sharti return 0; 657121461Sharti} 658121461Sharti 659121461Sharti/************************************************************/ 660121461Sharti/* 661121461Sharti * DATA 662121461Sharti */ 663121461Shartistatic int 664121461Sharting_sscop_rcvlower(hook_p hook, item_p item) 665121461Sharti{ 666121461Sharti struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 667121461Sharti struct mbuf *m; 668121461Sharti 669121461Sharti if (!priv->enabled) { 670121461Sharti NG_FREE_ITEM(item); 671121461Sharti return EINVAL; 672121461Sharti } 673121461Sharti 674121461Sharti /* 675121461Sharti * If we are disconnected at the upper layer and in the IDLE 676121461Sharti * state, drop any incoming packet. 677121461Sharti */ 678121461Sharti if (priv->upper != NULL || sscop_getstate(priv->sscop) != SSCOP_IDLE) { 679121461Sharti NGI_GET_M(item, m); 680121461Sharti priv->stats.in_packets++; 681121461Sharti sscop_input(priv->sscop, m); 682121461Sharti } else { 683121461Sharti priv->stats.in_dropped++; 684121461Sharti } 685121461Sharti NG_FREE_ITEM(item); 686121461Sharti 687121461Sharti return (0); 688121461Sharti} 689121461Sharti 690121461Shartistatic void 691121461Shartisscop_send_lower(struct sscop *sscop, void *p, struct mbuf *m) 692121461Sharti{ 693121461Sharti node_p node = (node_p)p; 694121461Sharti struct priv *priv = NG_NODE_PRIVATE(node); 695121461Sharti int error; 696121461Sharti 697121461Sharti if (priv->lower == NULL) { 698121461Sharti m_freem(m); 699121461Sharti priv->stats.out_dropped++; 700121461Sharti return; 701121461Sharti } 702121461Sharti 703121461Sharti priv->stats.out_packets++; 704121461Sharti NG_SEND_DATA_ONLY(error, priv->lower, m); 705121461Sharti} 706121461Sharti 707121461Shartistatic int 708121461Sharting_sscop_rcvupper(hook_p hook, item_p item) 709121461Sharti{ 710121461Sharti struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 711121461Sharti struct sscop_arg a; 712121461Sharti struct mbuf *m; 713121461Sharti 714121461Sharti if (!priv->enabled) { 715121461Sharti NG_FREE_ITEM(item); 716121461Sharti return (EINVAL); 717121461Sharti } 718121461Sharti 719121461Sharti /* 720121461Sharti * If the lower layer is not connected allow to proceed. 721121461Sharti * The lower layer sending function will drop outgoing frames, 722121461Sharti * and the sscop will timeout any establish requests. 723121461Sharti */ 724121461Sharti NGI_GET_M(item, m); 725121461Sharti NG_FREE_ITEM(item); 726121461Sharti 727121461Sharti if (!(m->m_flags & M_PKTHDR)) { 728121461Sharti printf("no pkthdr\n"); 729121461Sharti m_freem(m); 730121461Sharti return (EINVAL); 731121461Sharti } 732121461Sharti if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL) 733121461Sharti return (ENOBUFS); 734121461Sharti bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a)); 735121461Sharti m_adj(m, sizeof(a)); 736121461Sharti 737121461Sharti return (sscop_aasig(priv->sscop, a.sig, m, a.arg)); 738121461Sharti} 739121461Sharti 740121461Shartistatic void 741121461Shartisscop_send_upper(struct sscop *sscop, void *p, enum sscop_aasig sig, 742121461Sharti struct SSCOP_MBUF_T *m, u_int arg) 743121461Sharti{ 744121461Sharti node_p node = (node_p)p; 745121461Sharti struct priv *priv = NG_NODE_PRIVATE(node); 746121461Sharti int error; 747121461Sharti struct sscop_arg *a; 748121461Sharti 749121461Sharti if (sig == SSCOP_DATA_indication && priv->flow) 750121461Sharti sscop_window(priv->sscop, 1); 751121461Sharti 752121461Sharti if (priv->upper == NULL) { 753121461Sharti if (m != NULL) 754121461Sharti m_freem(m); 755121461Sharti priv->stats.aa_dropped++; 756121461Sharti return; 757121461Sharti } 758121461Sharti 759121461Sharti priv->stats.aa_signals++; 760121461Sharti if (sig == SSCOP_DATA_indication) 761121461Sharti priv->stats.data_delivered++; 762121461Sharti 763121461Sharti if (m == NULL) { 764121461Sharti MGETHDR(m, M_NOWAIT, MT_DATA); 765121461Sharti if (m == NULL) 766121461Sharti return; 767121461Sharti m->m_len = sizeof(struct sscop_arg); 768121461Sharti m->m_pkthdr.len = m->m_len; 769121461Sharti } else { 770121461Sharti M_PREPEND(m, sizeof(struct sscop_arg), M_NOWAIT); 771121461Sharti if (m == NULL) 772121461Sharti return; 773121461Sharti } 774121461Sharti a = mtod(m, struct sscop_arg *); 775121461Sharti a->sig = sig; 776121461Sharti a->arg = arg; 777121461Sharti 778121461Sharti NG_SEND_DATA_ONLY(error, priv->upper, m); 779121461Sharti} 780121461Sharti 781121461Shartistatic int 782121461Sharting_sscop_rcvmanage(hook_p hook, item_p item) 783121461Sharti{ 784121461Sharti struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 785121461Sharti struct sscop_marg a; 786121461Sharti struct mbuf *m; 787121461Sharti 788121461Sharti if (!priv->enabled) { 789121461Sharti NG_FREE_ITEM(item); 790121461Sharti return (EINVAL); 791121461Sharti } 792121461Sharti 793121461Sharti NGI_GET_M(item, m); 794121461Sharti NG_FREE_ITEM(item); 795121461Sharti 796121461Sharti if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL) 797121461Sharti return (ENOBUFS); 798121461Sharti bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a)); 799121461Sharti m_adj(m, sizeof(a)); 800121461Sharti 801121461Sharti return (sscop_maasig(priv->sscop, a.sig, m)); 802121461Sharti} 803121461Sharti 804121461Shartistatic void 805121461Shartisscop_send_manage(struct sscop *sscop, void *p, enum sscop_maasig sig, 806121461Sharti struct SSCOP_MBUF_T *m, u_int err, u_int cnt) 807121461Sharti{ 808121461Sharti node_p node = (node_p)p; 809121461Sharti struct priv *priv = NG_NODE_PRIVATE(node); 810121461Sharti int error; 811121461Sharti struct sscop_merr *e; 812121461Sharti struct sscop_marg *a; 813121461Sharti 814121461Sharti if (priv->manage == NULL) { 815121461Sharti if (m != NULL) 816121461Sharti m_freem(m); 817121461Sharti priv->stats.maa_dropped++; 818121461Sharti return; 819121461Sharti } 820121461Sharti 821121461Sharti if (sig == SSCOP_MERROR_indication) { 822121461Sharti MGETHDR(m, M_NOWAIT, MT_DATA); 823121461Sharti if (m == NULL) 824121461Sharti return; 825121461Sharti m->m_len = sizeof(*e); 826121461Sharti m->m_pkthdr.len = m->m_len; 827121461Sharti e = mtod(m, struct sscop_merr *); 828121461Sharti e->sig = sig; 829121461Sharti e->err = err; 830121461Sharti e->cnt = cnt; 831121461Sharti priv->stats.errors++; 832121461Sharti } else if (m == NULL) { 833121461Sharti MGETHDR(m, M_NOWAIT, MT_DATA); 834121461Sharti if (m == NULL) 835121461Sharti return; 836121461Sharti m->m_len = sizeof(*a); 837121461Sharti m->m_pkthdr.len = m->m_len; 838121461Sharti a = mtod(m, struct sscop_marg *); 839121461Sharti a->sig = sig; 840121461Sharti priv->stats.maa_signals++; 841121461Sharti } else { 842121461Sharti M_PREPEND(m, sizeof(*a), M_NOWAIT); 843121461Sharti if (m == NULL) 844121461Sharti return; 845121461Sharti a = mtod(m, struct sscop_marg *); 846121461Sharti a->sig = sig; 847121461Sharti priv->stats.maa_signals++; 848121461Sharti } 849121461Sharti 850121461Sharti NG_SEND_DATA_ONLY(error, priv->manage, m); 851121461Sharti} 852121461Sharti 853121461Sharti/************************************************************/ 854121461Sharti/* 855121461Sharti * INITIALISATION 856121461Sharti */ 857121461Sharti 858121461Sharti/* 859121461Sharti * Loading and unloading of node type 860121461Sharti */ 861121461Shartistatic int 862121461Sharting_sscop_mod_event(module_t mod, int event, void *data) 863121461Sharti{ 864121461Sharti int error = 0; 865121461Sharti 866121461Sharti switch (event) { 867121461Sharti 868121461Sharti case MOD_LOAD: 869121461Sharti break; 870121461Sharti 871121461Sharti case MOD_UNLOAD: 872121461Sharti break; 873121461Sharti 874121461Sharti default: 875121461Sharti error = EOPNOTSUPP; 876121461Sharti break; 877121461Sharti } 878121461Sharti return (error); 879121461Sharti} 880