ng_frame_relay.c revision 52843
152419Sjulian 252419Sjulian/* 352419Sjulian * ng_frame_relay.c 452419Sjulian * 552419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 652419Sjulian * All rights reserved. 752419Sjulian * 852419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 952419Sjulian * redistribution of this software, in source or object code forms, with or 1052419Sjulian * without modifications are expressly permitted by Whistle Communications; 1152419Sjulian * provided, however, that: 1252419Sjulian * 1. Any and all reproductions of the source or object code must include the 1352419Sjulian * copyright notice above and the following disclaimer of warranties; and 1452419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1552419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1652419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1752419Sjulian * such appears in the above copyright notice or in the software. 1852419Sjulian * 1952419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2052419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2152419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2252419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2352419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2452419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2552419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2652419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2752419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2852419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2952419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3052419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3152419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3252419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3352419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3452419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3552419Sjulian * OF SUCH DAMAGE. 3652419Sjulian * 3752419Sjulian * Author: Julian Elisher <julian@whistle.com> 3852419Sjulian * 3952419Sjulian * $FreeBSD: head/sys/netgraph/ng_frame_relay.c 52843 1999-11-03 17:54:26Z phk $ 4052752Sjulian * $Whistle: ng_frame_relay.c,v 1.20 1999/11/01 09:24:51 julian Exp $ 4152419Sjulian */ 4252419Sjulian 4352419Sjulian/* 4452419Sjulian * This node implements the frame relay protocol, not including 4552419Sjulian * the LMI line management. This means basically keeping track 4652419Sjulian * of which DLCI's are active, doing frame (de)multiplexing, etc. 4752419Sjulian * 4852419Sjulian * It has a 'downstream' hook that goes to the line, and a 4952419Sjulian * hook for each DLCI (eg, 'dlci16'). 5052419Sjulian */ 5152419Sjulian 5252419Sjulian#include <sys/param.h> 5352419Sjulian#include <sys/systm.h> 5452419Sjulian#include <sys/kernel.h> 5552419Sjulian#include <sys/conf.h> 5652419Sjulian#include <sys/errno.h> 5752419Sjulian#include <sys/malloc.h> 5852419Sjulian#include <sys/mbuf.h> 5952419Sjulian#include <sys/socket.h> 6052419Sjulian#include <sys/syslog.h> 6152843Sphk#include <sys/ctype.h> 6252419Sjulian#include <machine/clock.h> 6352419Sjulian 6452419Sjulian#include <netgraph/ng_message.h> 6552419Sjulian#include <netgraph/netgraph.h> 6652419Sjulian#include <netgraph/ng_frame_relay.h> 6752419Sjulian 6852419Sjulian/* 6952419Sjulian * Line info, and status per channel. 7052419Sjulian */ 7152419Sjulianstruct ctxinfo { /* one per active hook */ 7252419Sjulian u_int flags; 7352419Sjulian#define CHAN_VALID 0x01 /* assigned to a channel */ 7452419Sjulian#define CHAN_ACTIVE 0x02 /* bottom level active */ 7552419Sjulian int dlci; /* the dlci assigned to this context */ 7652419Sjulian hook_p hook; /* if there's a hook assigned.. */ 7752419Sjulian}; 7852419Sjulian 7952419Sjulian#define MAX_CT 16 /* # of dlci's active at a time (POWER OF 2!) */ 8052419Sjulianstruct frmrel_softc { 8152419Sjulian int unit; /* which card are we? */ 8252419Sjulian int datahooks; /* number of data hooks attached */ 8352419Sjulian node_p node; /* netgraph node */ 8452419Sjulian int addrlen; /* address header length */ 8552419Sjulian int flags; /* state */ 8652419Sjulian int mtu; /* guess */ 8752419Sjulian u_char remote_seq; /* sequence number the remote sent */ 8852419Sjulian u_char local_seq; /* sequence number the remote rcvd */ 8952419Sjulian u_short ALT[1024]; /* map DLCIs to CTX */ 9052419Sjulian#define CTX_VALID 0x8000 /* this bit means it's a valid CTX */ 9152419Sjulian#define CTX_VALUE (MAX_CT - 1) /* mask for context part */ 9252419Sjulian struct ctxinfo channel[MAX_CT]; 9352419Sjulian struct ctxinfo downstream; 9452419Sjulian}; 9552419Sjuliantypedef struct frmrel_softc *sc_p; 9652419Sjulian 9752419Sjulian#define BYTEX_EA 0x01 /* End Address. Always 0 on byte1 */ 9852419Sjulian#define BYTE1_C_R 0x02 9952419Sjulian#define BYTE2_FECN 0x08 /* forwards congestion notification */ 10052419Sjulian#define BYTE2_BECN 0x04 /* Backward congestion notification */ 10152419Sjulian#define BYTE2_DE 0x02 /* Discard elligability */ 10252419Sjulian#define LASTBYTE_D_C 0x02 /* last byte is dl_core or dlci info */ 10352419Sjulian 10452419Sjulian/* Used to do headers */ 10552419Sjulianstatic struct segment { 10652419Sjulian u_char mask; 10752419Sjulian u_char shift; 10852419Sjulian u_char width; 10952419Sjulian} makeup[] = { 11052419Sjulian { 0xfc, 2, 6 }, 11152419Sjulian { 0xf0, 4, 4 }, 11252419Sjulian { 0xfe, 1, 7 }, 11352419Sjulian { 0xfc, 2, 6 } 11452419Sjulian}; 11552419Sjulian 11652419Sjulian#define SHIFTIN(segment, byte, dlci) \ 11752419Sjulian { \ 11852419Sjulian (dlci) <<= (segment)->width; \ 11952419Sjulian (dlci) |= \ 12052419Sjulian (((byte) & (segment)->mask) >> (segment)->shift); \ 12152419Sjulian } 12252419Sjulian 12352419Sjulian#define SHIFTOUT(segment, byte, dlci) \ 12452419Sjulian { \ 12552419Sjulian (byte) |= (((dlci) << (segment)->shift) & (segment)->mask); \ 12652419Sjulian (dlci) >>= (segment)->width; \ 12752419Sjulian } 12852419Sjulian 12952419Sjulian/* Netgraph methods */ 13052752Sjulianstatic ng_constructor_t ngfrm_constructor; 13152752Sjulianstatic ng_shutdown_t ngfrm_rmnode; 13252752Sjulianstatic ng_newhook_t ngfrm_newhook; 13352752Sjulianstatic ng_rcvdata_t ngfrm_rcvdata; 13452752Sjulianstatic ng_disconnect_t ngfrm_disconnect; 13552419Sjulian 13652419Sjulian/* Other internal functions */ 13752419Sjulianstatic int ngfrm_decode(node_p node, struct mbuf * m, meta_p meta); 13852419Sjulianstatic int ngfrm_addrlen(char *hdr); 13952419Sjulianstatic int ngfrm_allocate_CTX(sc_p sc, int dlci); 14052419Sjulian 14152419Sjulian/* Netgraph type */ 14252419Sjulianstatic struct ng_type typestruct = { 14352419Sjulian NG_VERSION, 14452419Sjulian NG_FRAMERELAY_NODE_TYPE, 14552419Sjulian NULL, 14652419Sjulian ngfrm_constructor, 14752419Sjulian NULL, 14852419Sjulian ngfrm_rmnode, 14952419Sjulian ngfrm_newhook, 15052419Sjulian NULL, 15152419Sjulian NULL, 15252419Sjulian ngfrm_rcvdata, 15352419Sjulian ngfrm_rcvdata, 15452419Sjulian ngfrm_disconnect 15552419Sjulian}; 15652419SjulianNETGRAPH_INIT(framerelay, &typestruct); 15752419Sjulian 15852419Sjulian/* 15952419Sjulian * Given a DLCI, return the index of the context table entry for it, 16052419Sjulian * Allocating a new one if needs be, or -1 if none available. 16152419Sjulian */ 16252419Sjulianstatic int 16352419Sjulianngfrm_allocate_CTX(sc_p sc, int dlci) 16452419Sjulian{ 16552419Sjulian u_int ctxnum = -1; /* what ctx number we are using */ 16652419Sjulian volatile struct ctxinfo *CTXp = NULL; 16752419Sjulian 16852419Sjulian /* Sanity check the dlci value */ 16952419Sjulian if (dlci > 1023) 17052419Sjulian return (-1); 17152419Sjulian 17252419Sjulian /* Check to see if we already have an entry for this DLCI */ 17352419Sjulian if (sc->ALT[dlci]) { 17452419Sjulian if ((ctxnum = sc->ALT[dlci] & CTX_VALUE) < MAX_CT) { 17552419Sjulian CTXp = sc->channel + ctxnum; 17652419Sjulian } else { 17752419Sjulian ctxnum = -1; 17852419Sjulian sc->ALT[dlci] = 0; /* paranoid but... */ 17952419Sjulian } 18052419Sjulian } 18152419Sjulian 18252419Sjulian /* 18352419Sjulian * If the index has no valid entry yet, then we need to allocate a 18452419Sjulian * CTX number to it 18552419Sjulian */ 18652419Sjulian if (CTXp == NULL) { 18752419Sjulian for (ctxnum = 0; ctxnum < MAX_CT; ctxnum++) { 18852419Sjulian /* 18952419Sjulian * If the VALID flag is empty it is unused 19052419Sjulian */ 19152419Sjulian if ((sc->channel[ctxnum].flags & CHAN_VALID) == 0) { 19252419Sjulian bzero(sc->channel + ctxnum, 19352419Sjulian sizeof(struct ctxinfo)); 19452419Sjulian CTXp = sc->channel + ctxnum; 19552419Sjulian sc->ALT[dlci] = ctxnum | CTX_VALID; 19652419Sjulian sc->channel[ctxnum].dlci = dlci; 19752419Sjulian sc->channel[ctxnum].flags = CHAN_VALID; 19852419Sjulian break; 19952419Sjulian } 20052419Sjulian } 20152419Sjulian } 20252419Sjulian 20352419Sjulian /* 20452419Sjulian * If we still don't have a CTX pointer, then we never found a free 20552419Sjulian * spot so give up now.. 20652419Sjulian */ 20752419Sjulian if (!CTXp) { 20852419Sjulian log(LOG_ERR, "No CTX available for dlci %d\n", dlci); 20952419Sjulian return (-1); 21052419Sjulian } 21152419Sjulian return (ctxnum); 21252419Sjulian} 21352419Sjulian 21452419Sjulian/* 21552419Sjulian * Node constructor 21652419Sjulian */ 21752419Sjulianstatic int 21852419Sjulianngfrm_constructor(node_p *nodep) 21952419Sjulian{ 22052419Sjulian sc_p sc; 22152419Sjulian int error = 0; 22252419Sjulian 22352419Sjulian MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_NOWAIT); 22452419Sjulian if (!sc) 22552419Sjulian return (ENOMEM); 22652419Sjulian bzero(sc, sizeof(*sc)); 22752419Sjulian if ((error = ng_make_node_common(&typestruct, nodep))) { 22852419Sjulian FREE(sc, M_NETGRAPH); 22952419Sjulian return (error); 23052419Sjulian } 23152419Sjulian sc->addrlen = 2; /* default */ 23252419Sjulian 23352419Sjulian /* Link the node and our private info */ 23452419Sjulian (*nodep)->private = sc; 23552419Sjulian sc->node = *nodep; 23652419Sjulian return (0); 23752419Sjulian} 23852419Sjulian 23952419Sjulian/* 24052419Sjulian * Add a new hook 24152419Sjulian * 24252419Sjulian * We allow hooks called "debug", "downstream" and dlci[0-1023] 24352419Sjulian * The hook's private info points to our stash of info about that 24452419Sjulian * channel. A NULL pointer is debug and a DLCI of -1 means downstream. 24552419Sjulian */ 24652419Sjulianstatic int 24752419Sjulianngfrm_newhook(node_p node, hook_p hook, const char *name) 24852419Sjulian{ 24952419Sjulian const sc_p sc = node->private; 25052816Sarchie const char *cp, *eptr; 25152419Sjulian int dlci = 0; 25252419Sjulian int ctxnum; 25352419Sjulian 25452419Sjulian /* Check if it's our friend the control hook */ 25552419Sjulian if (strcmp(name, NG_FRAMERELAY_HOOK_DEBUG) == 0) { 25652419Sjulian hook->private = NULL; /* paranoid */ 25752419Sjulian return (0); 25852419Sjulian } 25952419Sjulian 26052419Sjulian /* 26152419Sjulian * All other hooks either start with 'dlci' and have a decimal 26252419Sjulian * trailing channel number up to 4 digits, or are the downstream 26352419Sjulian * hook. 26452419Sjulian */ 26552419Sjulian if (strncmp(name, NG_FRAMERELAY_HOOK_DLCI, 26652419Sjulian strlen(NG_FRAMERELAY_HOOK_DLCI)) != 0) { 26752419Sjulian 26852419Sjulian /* It must be the downstream connection */ 26952419Sjulian if (strcmp(name, NG_FRAMERELAY_HOOK_DOWNSTREAM) != 0) 27052419Sjulian return EINVAL; 27152419Sjulian 27252419Sjulian /* Make sure we haven't already got one (paranoid) */ 27352419Sjulian if (sc->downstream.hook) 27452419Sjulian return (EADDRINUSE); 27552419Sjulian 27652419Sjulian /* OK add it */ 27752419Sjulian hook->private = &sc->downstream; 27852419Sjulian sc->downstream.hook = hook; 27952419Sjulian sc->downstream.dlci = -1; 28052419Sjulian sc->downstream.flags |= CHAN_ACTIVE; 28152419Sjulian sc->datahooks++; 28252419Sjulian return (0); 28352419Sjulian } 28452419Sjulian 28552419Sjulian /* Must be a dlci hook at this point */ 28652419Sjulian cp = name + strlen(NG_FRAMERELAY_HOOK_DLCI); 28752816Sarchie if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0')) 28852419Sjulian return (EINVAL); 28952816Sarchie dlci = (int)strtoul(cp, &eptr, 10); 29052816Sarchie if (*eptr != '\0' || dlci < 0 || dlci > 1023) 29152816Sarchie return (EINVAL); 29252816Sarchie 29352419Sjulian /* 29452419Sjulian * We have a dlci, now either find it, or allocate it. It's possible 29552419Sjulian * that we might have seen packets for it already and made an entry 29652419Sjulian * for it. 29752419Sjulian */ 29852419Sjulian ctxnum = ngfrm_allocate_CTX(sc, dlci); 29952419Sjulian if (ctxnum == -1) 30052419Sjulian return (ENOBUFS); 30152419Sjulian 30252419Sjulian /* 30352419Sjulian * Be paranoid: if it's got a hook already, that dlci is in use . 30452419Sjulian * Generic code can not catch all the synonyms (e.g. dlci016 vs 30552419Sjulian * dlci16) 30652419Sjulian */ 30752419Sjulian if (sc->channel[ctxnum].hook != NULL) 30852419Sjulian return (EADDRINUSE); 30952419Sjulian 31052419Sjulian /* 31152419Sjulian * Put our hooks into it (pun not intended) 31252419Sjulian */ 31352419Sjulian sc->channel[ctxnum].flags |= CHAN_ACTIVE; 31452419Sjulian hook->private = sc->channel + ctxnum; 31552419Sjulian sc->channel[ctxnum].hook = hook; 31652419Sjulian sc->datahooks++; 31752419Sjulian return (0); 31852419Sjulian} 31952419Sjulian 32052419Sjulian/* 32152419Sjulian * Count up the size of the address header if we don't already know 32252419Sjulian */ 32352419Sjulianint 32452419Sjulianngfrm_addrlen(char *hdr) 32552419Sjulian{ 32652419Sjulian if (hdr[0] & BYTEX_EA) 32752419Sjulian return 0; 32852419Sjulian if (hdr[1] & BYTEX_EA) 32952419Sjulian return 2; 33052419Sjulian if (hdr[2] & BYTEX_EA) 33152419Sjulian return 3; 33252419Sjulian if (hdr[3] & BYTEX_EA) 33352419Sjulian return 4; 33452419Sjulian return 0; 33552419Sjulian} 33652419Sjulian 33752419Sjulian/* 33852419Sjulian * Receive data packet 33952419Sjulian */ 34052419Sjulianstatic int 34152419Sjulianngfrm_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 34252419Sjulian{ 34352419Sjulian struct ctxinfo *const ctxp = hook->private; 34452419Sjulian int error = 0; 34552419Sjulian int dlci; 34652419Sjulian sc_p sc; 34752419Sjulian int alen; 34852419Sjulian char *data; 34952419Sjulian 35052419Sjulian /* Data doesn't come in from just anywhere (e.g debug hook) */ 35152419Sjulian if (ctxp == NULL) { 35252419Sjulian error = ENETDOWN; 35352419Sjulian goto bad; 35452419Sjulian } 35552419Sjulian 35652419Sjulian /* If coming from downstream, decode it to a channel */ 35752419Sjulian dlci = ctxp->dlci; 35852419Sjulian if (dlci == -1) 35952419Sjulian return (ngfrm_decode(hook->node, m, meta)); 36052419Sjulian 36152419Sjulian /* Derive the softc we will need */ 36252419Sjulian sc = hook->node->private; 36352419Sjulian 36452419Sjulian /* If there is no live channel, throw it away */ 36552419Sjulian if ((sc->downstream.hook == NULL) 36652419Sjulian || ((ctxp->flags & CHAN_ACTIVE) == 0)) { 36752419Sjulian error = ENETDOWN; 36852419Sjulian goto bad; 36952419Sjulian } 37052419Sjulian 37152419Sjulian /* Store the DLCI on the front of the packet */ 37252419Sjulian alen = sc->addrlen; 37352419Sjulian if (alen == 0) 37452419Sjulian alen = 2; /* default value for transmit */ 37552419Sjulian M_PREPEND(m, alen, M_DONTWAIT); 37652419Sjulian if (m == NULL) { 37752419Sjulian error = ENOBUFS; 37852419Sjulian goto bad; 37952419Sjulian } 38052419Sjulian data = mtod(m, char *); 38152419Sjulian 38252419Sjulian /* 38352419Sjulian * Shift the lowest bits into the address field untill we are done. 38452419Sjulian * First byte is MSBits of addr so work backwards. 38552419Sjulian */ 38652419Sjulian switch (alen) { 38752419Sjulian case 2: 38852419Sjulian data[0] = data[1] = '\0'; 38952419Sjulian SHIFTOUT(makeup + 1, data[1], dlci); 39052419Sjulian SHIFTOUT(makeup + 0, data[0], dlci); 39152419Sjulian data[1] |= BYTEX_EA; 39252419Sjulian break; 39352419Sjulian case 3: 39452419Sjulian data[0] = data[1] = data[2] = '\0'; 39552419Sjulian SHIFTOUT(makeup + 3, data[2], dlci); /* 3 and 2 is correct */ 39652419Sjulian SHIFTOUT(makeup + 1, data[1], dlci); 39752419Sjulian SHIFTOUT(makeup + 0, data[0], dlci); 39852419Sjulian data[2] |= BYTEX_EA; 39952419Sjulian break; 40052419Sjulian case 4: 40152419Sjulian data[0] = data[1] = data[2] = data[3] = '\0'; 40252419Sjulian SHIFTOUT(makeup + 3, data[3], dlci); 40352419Sjulian SHIFTOUT(makeup + 2, data[2], dlci); 40452419Sjulian SHIFTOUT(makeup + 1, data[1], dlci); 40552419Sjulian SHIFTOUT(makeup + 0, data[0], dlci); 40652419Sjulian data[3] |= BYTEX_EA; 40752419Sjulian break; 40852419Sjulian default: 40952419Sjulian panic(__FUNCTION__); 41052419Sjulian } 41152419Sjulian 41252419Sjulian /* Send it */ 41352419Sjulian NG_SEND_DATA(error, sc->downstream.hook, m, meta); 41452419Sjulian return (error); 41552419Sjulian 41652419Sjulianbad: 41752419Sjulian NG_FREE_DATA(m, meta); 41852419Sjulian return (error); 41952419Sjulian} 42052419Sjulian 42152419Sjulian/* 42252419Sjulian * Decode an incoming frame coming from the switch 42352419Sjulian */ 42452419Sjulianstatic int 42552419Sjulianngfrm_decode(node_p node, struct mbuf *m, meta_p meta) 42652419Sjulian{ 42752419Sjulian const sc_p sc = node->private; 42852419Sjulian char *data; 42952419Sjulian int alen; 43052419Sjulian u_int dlci = 0; 43152419Sjulian int error = 0; 43252419Sjulian int ctxnum; 43352419Sjulian 43452539Sjulian if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) { 43552419Sjulian error = ENOBUFS; 43652419Sjulian goto out; 43752419Sjulian } 43852419Sjulian data = mtod(m, char *); 43952419Sjulian if ((alen = sc->addrlen) == 0) { 44052419Sjulian sc->addrlen = alen = ngfrm_addrlen(data); 44152419Sjulian } 44252419Sjulian switch (alen) { 44352419Sjulian case 2: 44452419Sjulian SHIFTIN(makeup + 0, data[0], dlci); 44552419Sjulian SHIFTIN(makeup + 1, data[1], dlci); 44652419Sjulian break; 44752419Sjulian case 3: 44852419Sjulian SHIFTIN(makeup + 0, data[0], dlci); 44952419Sjulian SHIFTIN(makeup + 1, data[1], dlci); 45052419Sjulian SHIFTIN(makeup + 3, data[2], dlci); /* 3 and 2 is correct */ 45152419Sjulian break; 45252419Sjulian case 4: 45352419Sjulian SHIFTIN(makeup + 0, data[0], dlci); 45452419Sjulian SHIFTIN(makeup + 1, data[1], dlci); 45552419Sjulian SHIFTIN(makeup + 2, data[2], dlci); 45652419Sjulian SHIFTIN(makeup + 3, data[3], dlci); 45752419Sjulian break; 45852419Sjulian default: 45952419Sjulian error = EINVAL; 46052419Sjulian goto out; 46152419Sjulian } 46252419Sjulian 46352419Sjulian if (dlci > 1023) { 46452419Sjulian error = EINVAL; 46552419Sjulian goto out; 46652419Sjulian } 46752419Sjulian ctxnum = sc->ALT[dlci]; 46852419Sjulian if ((ctxnum & CTX_VALID) && sc->channel[ctxnum &= CTX_VALUE].hook) { 46952419Sjulian /* Send it */ 47052419Sjulian m_adj(m, alen); 47152419Sjulian NG_SEND_DATA(error, sc->channel[ctxnum].hook, m, meta); 47252419Sjulian return (error); 47352419Sjulian } else { 47452419Sjulian error = ENETDOWN; 47552419Sjulian } 47652419Sjulianout: 47752419Sjulian NG_FREE_DATA(m, meta); 47852419Sjulian return (error); 47952419Sjulian} 48052419Sjulian 48152419Sjulian/* 48252419Sjulian * Shutdown node 48352419Sjulian */ 48452419Sjulianstatic int 48552419Sjulianngfrm_rmnode(node_p node) 48652419Sjulian{ 48752419Sjulian const sc_p sc = node->private; 48852419Sjulian 48952419Sjulian node->flags |= NG_INVALID; 49052419Sjulian ng_cutlinks(node); 49152419Sjulian ng_unname(node); 49252419Sjulian node->private = NULL; 49352419Sjulian FREE(sc, M_NETGRAPH); 49452419Sjulian ng_unref(sc->node); 49552419Sjulian return (0); 49652419Sjulian} 49752419Sjulian 49852419Sjulian/* 49952419Sjulian * Hook disconnection 50052419Sjulian * 50152419Sjulian * Invalidate the private data associated with this dlci. 50252419Sjulian * For this type, removal of the last link resets tries to destroy the node. 50352419Sjulian */ 50452419Sjulianstatic int 50552419Sjulianngfrm_disconnect(hook_p hook) 50652419Sjulian{ 50752419Sjulian const sc_p sc = hook->node->private; 50852419Sjulian struct ctxinfo *const cp = hook->private; 50952419Sjulian int dlci; 51052419Sjulian 51152419Sjulian /* If it's a regular dlci hook, then free resources etc.. */ 51252419Sjulian if (cp != NULL) { 51352419Sjulian cp->hook = NULL; 51452419Sjulian dlci = cp->dlci; 51552419Sjulian if (dlci != -1) 51652419Sjulian sc->ALT[dlci] = 0; 51752419Sjulian cp->flags = 0; 51852419Sjulian sc->datahooks--; 51952419Sjulian } 52052419Sjulian if (hook->node->numhooks == 0) 52152419Sjulian ng_rmnode(hook->node); 52252419Sjulian return (0); 52352419Sjulian} 524