ng_sample.c revision 52752
1250199Sgrehan 2250199Sgrehan/* 3250199Sgrehan * ng_sample.c 4250199Sgrehan * 5250199Sgrehan * Copyright (c) 1996-1999 Whistle Communications, Inc. 6250199Sgrehan * All rights reserved. 7250199Sgrehan * 8250199Sgrehan * Subject to the following obligations and disclaimer of warranty, use and 9250199Sgrehan * redistribution of this software, in source or object code forms, with or 10250199Sgrehan * without modifications are expressly permitted by Whistle Communications; 11250199Sgrehan * provided, however, that: 12250199Sgrehan * 1. Any and all reproductions of the source or object code must include the 13250199Sgrehan * copyright notice above and the following disclaimer of warranties; and 14250199Sgrehan * 2. No rights are granted, in any manner or form, to use Whistle 15250199Sgrehan * Communications, Inc. trademarks, including the mark "WHISTLE 16250199Sgrehan * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17250199Sgrehan * such appears in the above copyright notice or in the software. 18250199Sgrehan * 19250199Sgrehan * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20250199Sgrehan * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21250199Sgrehan * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22250199Sgrehan * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23250199Sgrehan * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24250199Sgrehan * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25250199Sgrehan * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26250199Sgrehan * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27250199Sgrehan * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28250199Sgrehan * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29250199Sgrehan * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30250199Sgrehan * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31250199Sgrehan * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32250199Sgrehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33250199Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34250199Sgrehan * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35250199Sgrehan * OF SUCH DAMAGE. 36250199Sgrehan * 37250199Sgrehan * Author: Julian Elischer <julian@whistle.com> 38250199Sgrehan * 39250199Sgrehan * $FreeBSD: head/sys/netgraph/ng_sample.c 52752 1999-11-01 10:00:40Z julian $ 40250199Sgrehan * $Whistle: ng_sample.c,v 1.13 1999/11/01 09:24:52 julian Exp $ 41250199Sgrehan */ 42250199Sgrehan 43250199Sgrehan#include <sys/param.h> 44250199Sgrehan#include <sys/systm.h> 45250199Sgrehan#include <sys/kernel.h> 46250199Sgrehan#include <sys/mbuf.h> 47250199Sgrehan#include <sys/malloc.h> 48282212Swhu#include <sys/errno.h> 49282212Swhu#include <sys/syslog.h> 50282212Swhu 51282212Swhu#include <netgraph/ng_message.h> 52282212Swhu#include <netgraph/ng_sample.h> 53282212Swhu#include <netgraph/netgraph.h> 54282212Swhu 55282212Swhu/* 56282212Swhu * This section contains the netgraph method declarations for the 57282212Swhu * sample node. These methods define the netgraph 'type'. 58282212Swhu */ 59282212Swhu 60282212Swhustatic ng_constructor_t ng_xxx_constructor; 61282212Swhustatic ng_rcvmsg_t ng_xxx_rcvmsg; 62282212Swhustatic ng_shutdown_t ng_xxx_rmnode; 63282212Swhustatic ng_newhook_t ng_xxx_newhook; 64282212Swhustatic ng_connect_t ng_xxx_connect; 65282212Swhustatic ng_rcvdata_t ng_xxx_rcvdata; /* note these are both ng_rcvdata_t */ 66282212Swhustatic ng_rcvdata_t ng_xxx_rcvdataq; /* note these are both ng_rcvdata_t */ 67282212Swhustatic ng_disconnect_t ng_xxx_disconnect; 68282212Swhu 69250199Sgrehan/* Netgraph node type descriptor */ 70282212Swhustatic struct ng_type typestruct = { 71282212Swhu NG_VERSION, 72282212Swhu NG_XXX_NODE_TYPE, 73282212Swhu NULL, 74282212Swhu ng_xxx_constructor, 75282212Swhu ng_xxx_rcvmsg, 76282212Swhu ng_xxx_rmnode, 77282212Swhu ng_xxx_newhook, 78282212Swhu NULL, 79282212Swhu ng_xxx_connect, 80282212Swhu ng_xxx_rcvdata, 81282212Swhu ng_xxx_rcvdataq, 82282212Swhu ng_xxx_disconnect 83282212Swhu}; 84282212SwhuNETGRAPH_INIT(xxx, &typestruct); 85282212Swhu 86282212Swhu/* Information we store for each hook on each node */ 87282212Swhustruct XXX_hookinfo { 88282212Swhu int dlci; /* The DLCI it represents, -1 == downstream */ 89282212Swhu int channel; /* The channel representing this DLCI */ 90282212Swhu hook_p hook; 91282212Swhu}; 92282212Swhu 93282212Swhu/* Information we store for each node */ 94282212Swhustruct XXX { 95282212Swhu struct XXX_hookinfo channel[XXX_NUM_DLCIS]; 96282212Swhu struct XXX_hookinfo downstream_hook; 97282212Swhu node_p node; /* back pointer to node */ 98282212Swhu hook_p debughook; 99282212Swhu u_int packets_in; /* packets in from downstream */ 100282212Swhu u_int packets_out; /* packets out towards downstream */ 101282212Swhu u_int32_t flags; 102282212Swhu}; 103282212Swhutypedef struct XXX *xxx_p; 104282212Swhu 105282212Swhu/* 106282212Swhu * Allocate the private data structure and the generic node 107282212Swhu * and link them together. 108282212Swhu * 109282212Swhu * ng_make_node_common() returns with a generic node struct 110282212Swhu * with a single reference for us.. we transfer it to the 111282212Swhu * private structure.. when we free the private struct we must 112282212Swhu * unref the node so it gets freed too. 113282212Swhu * 114282212Swhu * If this were a device node than this work would be done in the attach() 115282212Swhu * routine and the constructor would return EINVAL as you should not be able 116282212Swhu * to creatednodes that depend on hardware (unless you can add the hardware :) 117282212Swhu */ 118282212Swhustatic int 119282212Swhung_xxx_constructor(node_p *nodep) 120282212Swhu{ 121282212Swhu xxx_p privdata; 122282212Swhu int i, error; 123282212Swhu 124282212Swhu /* Initialize private descriptor */ 125282212Swhu MALLOC(privdata, xxx_p, sizeof(*privdata), M_NETGRAPH, M_WAITOK); 126282212Swhu if (privdata == NULL) 127282212Swhu return (ENOMEM); 128282212Swhu bzero(privdata, sizeof(struct XXX)); 129282212Swhu for (i = 0; i < XXX_NUM_DLCIS; i++) { 130282212Swhu privdata->channel[i].dlci = -2; 131282212Swhu privdata->channel[i].channel = i; 132282212Swhu } 133282212Swhu 134282212Swhu /* Call the 'generic' (ie, superclass) node constructor */ 135282212Swhu if ((error = ng_make_node_common(&typestruct, nodep))) { 136282212Swhu FREE(privdata, M_NETGRAPH); 137282212Swhu return (error); 138282212Swhu } 139282212Swhu 140282212Swhu /* Link structs together; this counts as our one reference to *nodep */ 141282212Swhu (*nodep)->private = privdata; 142282212Swhu privdata->node = *nodep; 143282212Swhu return (0); 144282212Swhu} 145282212Swhu 146282212Swhu/* 147282212Swhu * Give our ok for a hook to be added... 148250199Sgrehan * If we are not running this might kick a device into life. 149250199Sgrehan * Possibly decode information out of the hook name. 150250199Sgrehan * Add the hook's private info to the hook structure. 151250199Sgrehan * (if we had some). In this example, we assume that there is a 152250199Sgrehan * an array of structs, called 'channel' in the private info, 153282212Swhu * one for each active channel. The private 154250199Sgrehan * pointer of each hook points to the appropriate XXX_hookinfo struct 155250199Sgrehan * so that the source of an input packet is easily identified. 156250199Sgrehan * (a dlci is a frame relay channel) 157250199Sgrehan */ 158250199Sgrehanstatic int 159250199Sgrehanng_xxx_newhook(node_p node, hook_p hook, const char *name) 160250199Sgrehan{ 161250199Sgrehan const xxx_p xxxp = node->private; 162250199Sgrehan const char *cp; 163250199Sgrehan char c = '\0'; 164250199Sgrehan int digits = 0; 165250199Sgrehan int dlci = 0; 166250199Sgrehan int chan; 167250199Sgrehan 168250199Sgrehan#if 0 169250199Sgrehan /* Possibly start up the device if it's not already going */ 170250199Sgrehan if ((xxxp->flags & SCF_RUNNING) == 0) { 171250199Sgrehan ng_xxx_start_hardware(xxxp); 172250199Sgrehan } 173250199Sgrehan#endif 174250199Sgrehan 175250199Sgrehan /* Example of how one might use hooks with embedded numbers: All 176282212Swhu * hooks start with 'dlci' and have a decimal trailing channel 177250199Sgrehan * number up to 4 digits Use the leadin defined int he associated .h 178250199Sgrehan * file. */ 179250199Sgrehan if (strncmp(name, NG_XXX_HOOK_DLCI_LEADIN, 4) == 0) { 180250199Sgrehan cp = name + sizeof(NG_XXX_HOOK_DLCI_LEADIN); 181250199Sgrehan while ((digits < 5) 182250199Sgrehan && ((c = *cp++) > '0') && (c < '9')) { 183250199Sgrehan dlci *= 10; 184250199Sgrehan dlci += c - '0'; 185250199Sgrehan digits++; 186250199Sgrehan } 187250199Sgrehan if ((c != 0) || (digits == 5) 188250199Sgrehan || (dlci <= 0) || (dlci > 1023)) 189250199Sgrehan return (EINVAL); 190250199Sgrehan /* We have a dlci, now either find it, or allocate it */ 191250199Sgrehan for (chan = 0; chan < XXX_NUM_DLCIS; chan++) 192250199Sgrehan if (xxxp->channel[chan].dlci == dlci) 193250199Sgrehan break; 194250199Sgrehan if (chan == XXX_NUM_DLCIS) { 195250199Sgrehan for (chan = 0; chan < XXX_NUM_DLCIS; chan++) 196250199Sgrehan if (xxxp->channel[chan].dlci != -2) 197250199Sgrehan continue; 198250199Sgrehan if (chan == XXX_NUM_DLCIS) 199250199Sgrehan return (ENOBUFS); 200250199Sgrehan } 201250199Sgrehan if (xxxp->channel[chan].hook != NULL) 202250199Sgrehan return (EADDRINUSE); 203250199Sgrehan hook->private = xxxp->channel + chan; 204250199Sgrehan xxxp->channel[chan].hook = hook; 205250199Sgrehan return (0); 206250199Sgrehan } else if (strcmp(name, NG_XXX_HOOK_DOWNSTREAM) == 0) { 207250199Sgrehan /* Example of simple predefined hooks. */ 208250199Sgrehan /* do something specific to the downstream connection */ 209250199Sgrehan xxxp->downstream_hook.hook = hook; 210250199Sgrehan hook->private = &xxxp->downstream_hook; 211250199Sgrehan } else if (strcmp(name, NG_XXX_HOOK_DEBUG) == 0) { 212250199Sgrehan /* do something specific to a debug connection */ 213250199Sgrehan xxxp->debughook = hook; 214250199Sgrehan hook->private = NULL; 215250199Sgrehan } else 216250199Sgrehan return (EINVAL); /* not a hook we know about */ 217250199Sgrehan return(0); 218250199Sgrehan} 219250199Sgrehan 220250199Sgrehan/* 221250199Sgrehan * Get a netgraph control message. 222250199Sgrehan * Check it is one we understand. If needed, send a response. 223250199Sgrehan * We could save the address for an async action later, but don't here. 224250199Sgrehan * Always free the message. 225250199Sgrehan * The response should be in a malloc'd region that the caller can 'free'. 226250199Sgrehan * A response is not required. 227250199Sgrehan * Theoretically you could respond defferently to old message types if 228250199Sgrehan * the cookie in the header didn't match what we consider to be current 229250199Sgrehan * (so that old userland programs could continue to work). 230250199Sgrehan */ 231250199Sgrehanstatic int 232294553Ssepheng_xxx_rcvmsg(node_p node, 233294553Ssephe struct ng_mesg *msg, const char *retaddr, struct ng_mesg **rptr) 234294553Ssephe{ 235282212Swhu const xxx_p xxxp = node->private; 236282212Swhu struct ng_mesg *resp = NULL; 237250199Sgrehan int error = 0; 238282212Swhu 239250199Sgrehan /* Deal with message according to cookie and command */ 240282212Swhu switch (msg->header.typecookie) { 241282212Swhu case NGM_XXX_COOKIE: 242282212Swhu switch (msg->header.cmd) { 243282212Swhu case NGM_XXX_GET_STATUS: 244282212Swhu { 245282212Swhu struct ngxxxstat *stats; 246282212Swhu 247282212Swhu NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT); 248250199Sgrehan if (!resp) { 249282212Swhu error = ENOMEM; 250282212Swhu break; 251250199Sgrehan } 252282212Swhu stats = (struct ngxxxstat *) resp->data; 253282212Swhu stats->packets_in = xxxp->packets_in; 254250199Sgrehan stats->packets_out = xxxp->packets_out; 255282212Swhu break; 256282212Swhu } 257293870Ssephe case NGM_XXX_SET_FLAG: 258282212Swhu if (msg->header.arglen != sizeof(u_int32_t)) { 259250199Sgrehan error = EINVAL; 260250199Sgrehan break; 261250199Sgrehan } 262250199Sgrehan xxxp->flags = *((u_int32_t *) msg->data); 263250199Sgrehan break; 264250199Sgrehan default: 265250199Sgrehan error = EINVAL; /* unknown command */ 266250199Sgrehan break; 267250199Sgrehan } 268250199Sgrehan break; 269250199Sgrehan default: 270250199Sgrehan error = EINVAL; /* unknown cookie type */ 271250199Sgrehan break; 272250199Sgrehan } 273250199Sgrehan 274250199Sgrehan /* Take care of synchronous response, if any */ 275250199Sgrehan if (rptr) 276250199Sgrehan *rptr = resp; 277250199Sgrehan else if (resp) 278250199Sgrehan FREE(resp, M_NETGRAPH); 279250199Sgrehan 280250199Sgrehan /* Free the message and return */ 281250199Sgrehan FREE(msg, M_NETGRAPH); 282250199Sgrehan return(error); 283250199Sgrehan} 284250199Sgrehan 285250199Sgrehan/* 286250199Sgrehan * Receive data, and do something with it. 287250199Sgrehan * Possibly send it out on another link after processing. 288250199Sgrehan * Possibly do something different if it comes from different 289250199Sgrehan * hooks. the caller will never free m or meta, so 290250199Sgrehan * if we use up this data or abort we must free BOTH of these. 291250199Sgrehan * 292250199Sgrehan * If we want, we may decide to force this data to be queued and reprocessed 293250199Sgrehan * at the netgraph NETISR time. (at which time it will be entered using ng_xxx_rcvdataq(). 294250199Sgrehan */ 295250199Sgrehanstatic int 296250199Sgrehanng_xxx_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 297250199Sgrehan{ 298294553Ssephe int dlci = -2; 299250199Sgrehan int error; 300250199Sgrehan 301250199Sgrehan if (hook->private) { 302250199Sgrehan /* 303250199Sgrehan * If it's dlci 1023, requeue it so that it's handled at a lower priority. 304250199Sgrehan * This is how a node decides to defer a data message. 305250199Sgrehan */ 306250199Sgrehan dlci = ((struct XXX_hookinfo *) hook->private)->dlci; 307250199Sgrehan if (dlci == 1023) { 308250199Sgrehan return(ng_queue_data(hook->peer, m, meta)); 309250199Sgrehan } 310250199Sgrehan } 311250199Sgrehan return(ng_xxx_rcvdataq(hook, m, meta)); 312250199Sgrehan} 313250199Sgrehan 314250199Sgrehan/* 315250199Sgrehan * Always accept the data. This version of rcvdata is called from the dequeueing routine. 316250199Sgrehan */ 317250199Sgrehanstatic int 318250199Sgrehanng_xxx_rcvdataq(hook_p hook, struct mbuf *m, meta_p meta) 319250199Sgrehan{ 320250199Sgrehan const xxx_p xxxp = hook->node->private; 321250199Sgrehan int chan = -2; 322250199Sgrehan int dlci = -2; 323250199Sgrehan int error; 324250199Sgrehan 325250199Sgrehan if (hook->private) { 326250199Sgrehan dlci = ((struct XXX_hookinfo *) hook->private)->dlci; 327250199Sgrehan chan = ((struct XXX_hookinfo *) hook->private)->channel; 328250199Sgrehan if (dlci != -1) { 329294553Ssephe /* If received on a DLCI hook process for this 330250199Sgrehan * channel and pass it to the downstream module. 331250199Sgrehan * Normally one would add a multiplexing header at 332250199Sgrehan * the front here */ 333250199Sgrehan /* M_PREPEND(....) ; */ 334250199Sgrehan /* mtod(m, xxxxxx)->dlci = dlci; */ 335250199Sgrehan error = ng_send_data(xxxp->downstream_hook.hook, 336250199Sgrehan m, meta); 337250199Sgrehan xxxp->packets_out++; 338250199Sgrehan } else { 339250199Sgrehan /* data came from the multiplexed link */ 340250199Sgrehan dlci = 1; /* get dlci from header */ 341250199Sgrehan /* madjust(....) *//* chop off header */ 342250199Sgrehan for (chan = 0; chan < XXX_NUM_DLCIS; chan++) 343282212Swhu if (xxxp->channel[chan].dlci == dlci) 344282212Swhu break; 345250199Sgrehan if (chan == XXX_NUM_DLCIS) { 346282212Swhu NG_FREE_DATA(m, meta); 347250199Sgrehan return (ENETUNREACH); 348250199Sgrehan } 349250199Sgrehan /* If we were called at splnet, use the following: 350250199Sgrehan * NG_SEND_DATA(error, otherhook, m, meta); if this 351250199Sgrehan * node is running at some SPL other than SPLNET 352250199Sgrehan * then you should use instead: error = 353294553Ssephe * ng_queueit(otherhook, m, meta); m = NULL: meta = 354250199Sgrehan * NULL; this queues the data using the standard 355250199Sgrehan * NETISR system and schedules the data to be picked 356250199Sgrehan * up again once the system has moved to SPLNET and 357250199Sgrehan * the processing of the data can continue. after 358250199Sgrehan * these are run 'm' and 'meta' should be considered 359250199Sgrehan * as invalid and NG_SEND_DATA actually zaps them. */ 360250199Sgrehan NG_SEND_DATA(error, xxxp->channel[chan].hook, m, meta); 361250199Sgrehan xxxp->packets_in++; 362250199Sgrehan } 363250199Sgrehan } else { 364250199Sgrehan /* It's the debug hook, throw it away.. */ 365250199Sgrehan if (hook == xxxp->downstream_hook.hook) 366250199Sgrehan NG_FREE_DATA(m, meta); 367282212Swhu } 368282212Swhu return 0; 369282212Swhu} 370282212Swhu 371282212Swhu#if 0 372282212Swhu/* 373250199Sgrehan * If this were a device node, the data may have been received in response 374282212Swhu * to some interrupt. 375282212Swhu * in which case it would probably look as follows: 376282212Swhu */ 377282212Swhudevintr() 378282212Swhu{ 379282212Swhu meta_p meta = NULL; /* whatever metadata we might imagine goes 380282212Swhu * here */ 381282212Swhu 382282212Swhu /* get packet from device and send on */ 383282212Swhu m = MGET(blah blah) 384282212Swhu error = ng_queueit(upstream, m, meta); /* see note above in 385282212Swhu * xxx_rcvdata() */ 386282212Swhu} 387282212Swhu 388282212Swhu#endif /* 0 */ 389282212Swhu 390282212Swhu/* 391282212Swhu * Do local shutdown processing.. 392282212Swhu * If we are a persistant device, we might refuse to go away, and 393282212Swhu * we'd only remove our links and reset ourself. 394282212Swhu */ 395282212Swhustatic int 396282212Swhung_xxx_rmnode(node_p node) 397282212Swhu{ 398250199Sgrehan const xxx_p privdata = node->private; 399282212Swhu 400250199Sgrehan node->flags |= NG_INVALID; 401250199Sgrehan ng_cutlinks(node); 402250199Sgrehan#ifndef PERSISTANT_NODE 403250199Sgrehan ng_unname(node); 404250199Sgrehan node->private = NULL; 405250199Sgrehan ng_unref(privdata->node); 406250199Sgrehan FREE(privdata, M_NETGRAPH); 407250199Sgrehan#else 408282212Swhu privdata->packets_in = 0; /* reset stats */ 409282212Swhu privdata->packets_out = 0; 410250199Sgrehan node->flags &= ~NG_INVALID; /* reset invalid flag */ 411282212Swhu#endif /* PERSISTANT_NODE */ 412282212Swhu return (0); 413250199Sgrehan} 414282212Swhu 415282212Swhu/* 416250199Sgrehan * This is called once we've already connected a new hook to the other node. 417250199Sgrehan * It gives us a chance to balk at the last minute. 418282212Swhu */ 419282212Swhustatic int 420282212Swhung_xxx_connect(hook_p hook) 421250199Sgrehan{ 422282212Swhu /* be really amiable and just say "YUP that's OK by me! " */ 423282212Swhu return (0); 424282212Swhu} 425282212Swhu 426282212Swhu/* 427282212Swhu * Dook disconnection 428282212Swhu * 429282212Swhu * For this type, removal of the last link destroys the node 430282212Swhu */ 431282212Swhustatic int 432282212Swhung_xxx_disconnect(hook_p hook) 433282212Swhu{ 434282212Swhu if (hook->private) 435282212Swhu ((struct XXX_hookinfo *) (hook->private))->hook == NULL; 436282212Swhu if (hook->node->numhooks == 0) 437282212Swhu ng_rmnode(hook->node); 438282212Swhu return (0); 439282212Swhu} 440282212Swhu 441282212Swhu