19a8e6225SNuno Antunes /*
29a8e6225SNuno Antunes * ng_frame_relay.c
39a8e6225SNuno Antunes */
49a8e6225SNuno Antunes
59a8e6225SNuno Antunes /*-
69a8e6225SNuno Antunes * Copyright (c) 1996-1999 Whistle Communications, Inc.
79a8e6225SNuno Antunes * All rights reserved.
89a8e6225SNuno Antunes *
99a8e6225SNuno Antunes * Subject to the following obligations and disclaimer of warranty, use and
109a8e6225SNuno Antunes * redistribution of this software, in source or object code forms, with or
119a8e6225SNuno Antunes * without modifications are expressly permitted by Whistle Communications;
129a8e6225SNuno Antunes * provided, however, that:
139a8e6225SNuno Antunes * 1. Any and all reproductions of the source or object code must include the
149a8e6225SNuno Antunes * copyright notice above and the following disclaimer of warranties; and
159a8e6225SNuno Antunes * 2. No rights are granted, in any manner or form, to use Whistle
169a8e6225SNuno Antunes * Communications, Inc. trademarks, including the mark "WHISTLE
179a8e6225SNuno Antunes * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
189a8e6225SNuno Antunes * such appears in the above copyright notice or in the software.
199a8e6225SNuno Antunes *
209a8e6225SNuno Antunes * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
219a8e6225SNuno Antunes * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
229a8e6225SNuno Antunes * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
239a8e6225SNuno Antunes * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
249a8e6225SNuno Antunes * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
259a8e6225SNuno Antunes * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
269a8e6225SNuno Antunes * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
279a8e6225SNuno Antunes * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
289a8e6225SNuno Antunes * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
299a8e6225SNuno Antunes * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
309a8e6225SNuno Antunes * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
319a8e6225SNuno Antunes * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
329a8e6225SNuno Antunes * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
339a8e6225SNuno Antunes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
349a8e6225SNuno Antunes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
359a8e6225SNuno Antunes * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
369a8e6225SNuno Antunes * OF SUCH DAMAGE.
379a8e6225SNuno Antunes *
389a8e6225SNuno Antunes * Author: Julian Elischer <julian@freebsd.org>
399a8e6225SNuno Antunes *
409a8e6225SNuno Antunes * $FreeBSD: src/sys/netgraph/ng_frame_relay.c,v 1.25 2006/01/14 21:49:31 glebius Exp $
419a8e6225SNuno Antunes * $Whistle: ng_frame_relay.c,v 1.20 1999/11/01 09:24:51 julian Exp $
429a8e6225SNuno Antunes */
439a8e6225SNuno Antunes
449a8e6225SNuno Antunes /*
459a8e6225SNuno Antunes * This node implements the frame relay protocol, not including
469a8e6225SNuno Antunes * the LMI line management. This means basically keeping track
479a8e6225SNuno Antunes * of which DLCI's are active, doing frame (de)multiplexing, etc.
489a8e6225SNuno Antunes *
499a8e6225SNuno Antunes * It has a 'downstream' hook that goes to the line, and a
509a8e6225SNuno Antunes * hook for each DLCI (eg, 'dlci16').
519a8e6225SNuno Antunes */
529a8e6225SNuno Antunes
539a8e6225SNuno Antunes #include <sys/param.h>
549a8e6225SNuno Antunes #include <sys/systm.h>
559a8e6225SNuno Antunes #include <sys/kernel.h>
569a8e6225SNuno Antunes #include <sys/errno.h>
579a8e6225SNuno Antunes #include <sys/malloc.h>
589a8e6225SNuno Antunes #include <sys/mbuf.h>
599a8e6225SNuno Antunes #include <sys/syslog.h>
609a8e6225SNuno Antunes #include <sys/ctype.h>
619a8e6225SNuno Antunes
629a8e6225SNuno Antunes #include <netgraph7/ng_message.h>
639a8e6225SNuno Antunes #include <netgraph7/netgraph.h>
649a8e6225SNuno Antunes #include "ng_frame_relay.h"
659a8e6225SNuno Antunes
669a8e6225SNuno Antunes /*
679a8e6225SNuno Antunes * Line info, and status per channel.
689a8e6225SNuno Antunes */
699a8e6225SNuno Antunes struct ctxinfo { /* one per active hook */
709a8e6225SNuno Antunes u_int flags;
719a8e6225SNuno Antunes #define CHAN_VALID 0x01 /* assigned to a channel */
729a8e6225SNuno Antunes #define CHAN_ACTIVE 0x02 /* bottom level active */
739a8e6225SNuno Antunes int dlci; /* the dlci assigned to this context */
749a8e6225SNuno Antunes hook_p hook; /* if there's a hook assigned.. */
759a8e6225SNuno Antunes };
769a8e6225SNuno Antunes
779a8e6225SNuno Antunes #define MAX_CT 16 /* # of dlci's active at a time (POWER OF 2!) */
789a8e6225SNuno Antunes struct frmrel_softc {
799a8e6225SNuno Antunes int unit; /* which card are we? */
809a8e6225SNuno Antunes int datahooks; /* number of data hooks attached */
819a8e6225SNuno Antunes node_p node; /* netgraph node */
829a8e6225SNuno Antunes int addrlen; /* address header length */
839a8e6225SNuno Antunes int flags; /* state */
849a8e6225SNuno Antunes int mtu; /* guess */
859a8e6225SNuno Antunes u_char remote_seq; /* sequence number the remote sent */
869a8e6225SNuno Antunes u_char local_seq; /* sequence number the remote rcvd */
879a8e6225SNuno Antunes u_short ALT[1024]; /* map DLCIs to CTX */
889a8e6225SNuno Antunes #define CTX_VALID 0x8000 /* this bit means it's a valid CTX */
899a8e6225SNuno Antunes #define CTX_VALUE (MAX_CT - 1) /* mask for context part */
909a8e6225SNuno Antunes struct ctxinfo channel[MAX_CT];
919a8e6225SNuno Antunes struct ctxinfo downstream;
929a8e6225SNuno Antunes };
939a8e6225SNuno Antunes typedef struct frmrel_softc *sc_p;
949a8e6225SNuno Antunes
959a8e6225SNuno Antunes #define BYTEX_EA 0x01 /* End Address. Always 0 on byte1 */
969a8e6225SNuno Antunes #define BYTE1_C_R 0x02
979a8e6225SNuno Antunes #define BYTE2_FECN 0x08 /* forwards congestion notification */
989a8e6225SNuno Antunes #define BYTE2_BECN 0x04 /* Backward congestion notification */
999a8e6225SNuno Antunes #define BYTE2_DE 0x02 /* Discard elligability */
1009a8e6225SNuno Antunes #define LASTBYTE_D_C 0x02 /* last byte is dl_core or dlci info */
1019a8e6225SNuno Antunes
1029a8e6225SNuno Antunes /* Used to do headers */
10353f03f86SNuno Antunes static const struct segment {
1049a8e6225SNuno Antunes u_char mask;
1059a8e6225SNuno Antunes u_char shift;
1069a8e6225SNuno Antunes u_char width;
1079a8e6225SNuno Antunes } makeup[] = {
1089a8e6225SNuno Antunes { 0xfc, 2, 6 },
1099a8e6225SNuno Antunes { 0xf0, 4, 4 },
1109a8e6225SNuno Antunes { 0xfe, 1, 7 },
1119a8e6225SNuno Antunes { 0xfc, 2, 6 }
1129a8e6225SNuno Antunes };
1139a8e6225SNuno Antunes
1149a8e6225SNuno Antunes #define SHIFTIN(segment, byte, dlci) \
1159a8e6225SNuno Antunes { \
1169a8e6225SNuno Antunes (dlci) <<= (segment)->width; \
1179a8e6225SNuno Antunes (dlci) |= \
1189a8e6225SNuno Antunes (((byte) & (segment)->mask) >> (segment)->shift); \
1199a8e6225SNuno Antunes }
1209a8e6225SNuno Antunes
1219a8e6225SNuno Antunes #define SHIFTOUT(segment, byte, dlci) \
1229a8e6225SNuno Antunes { \
1239a8e6225SNuno Antunes (byte) |= (((dlci) << (segment)->shift) & (segment)->mask); \
1249a8e6225SNuno Antunes (dlci) >>= (segment)->width; \
1259a8e6225SNuno Antunes }
1269a8e6225SNuno Antunes
1279a8e6225SNuno Antunes /* Netgraph methods */
1289a8e6225SNuno Antunes static ng_constructor_t ngfrm_constructor;
1299a8e6225SNuno Antunes static ng_shutdown_t ngfrm_shutdown;
1309a8e6225SNuno Antunes static ng_newhook_t ngfrm_newhook;
1319a8e6225SNuno Antunes static ng_rcvdata_t ngfrm_rcvdata;
1329a8e6225SNuno Antunes static ng_disconnect_t ngfrm_disconnect;
1339a8e6225SNuno Antunes
1349a8e6225SNuno Antunes /* Other internal functions */
1359a8e6225SNuno Antunes static int ngfrm_decode(node_p node, item_p item);
1369a8e6225SNuno Antunes static int ngfrm_addrlen(char *hdr);
1379a8e6225SNuno Antunes static int ngfrm_allocate_CTX(sc_p sc, int dlci);
1389a8e6225SNuno Antunes
1399a8e6225SNuno Antunes /* Netgraph type */
1409a8e6225SNuno Antunes static struct ng_type typestruct = {
1419a8e6225SNuno Antunes .version = NG_ABI_VERSION,
1429a8e6225SNuno Antunes .name = NG_FRAMERELAY_NODE_TYPE,
1439a8e6225SNuno Antunes .constructor = ngfrm_constructor,
1449a8e6225SNuno Antunes .shutdown = ngfrm_shutdown,
1459a8e6225SNuno Antunes .newhook = ngfrm_newhook,
1469a8e6225SNuno Antunes .rcvdata = ngfrm_rcvdata,
1479a8e6225SNuno Antunes .disconnect = ngfrm_disconnect,
1489a8e6225SNuno Antunes };
1499a8e6225SNuno Antunes NETGRAPH_INIT(framerelay, &typestruct);
1509a8e6225SNuno Antunes
1519a8e6225SNuno Antunes /*
1529a8e6225SNuno Antunes * Given a DLCI, return the index of the context table entry for it,
1539a8e6225SNuno Antunes * Allocating a new one if needs be, or -1 if none available.
1549a8e6225SNuno Antunes */
1559a8e6225SNuno Antunes static int
ngfrm_allocate_CTX(sc_p sc,int dlci)1569a8e6225SNuno Antunes ngfrm_allocate_CTX(sc_p sc, int dlci)
1579a8e6225SNuno Antunes {
1589a8e6225SNuno Antunes u_int ctxnum = -1; /* what ctx number we are using */
1599a8e6225SNuno Antunes volatile struct ctxinfo *CTXp = NULL;
1609a8e6225SNuno Antunes
1619a8e6225SNuno Antunes /* Sanity check the dlci value */
1629a8e6225SNuno Antunes if (dlci > 1023)
1639a8e6225SNuno Antunes return (-1);
1649a8e6225SNuno Antunes
1659a8e6225SNuno Antunes /* Check to see if we already have an entry for this DLCI */
1669a8e6225SNuno Antunes if (sc->ALT[dlci]) {
1679a8e6225SNuno Antunes if ((ctxnum = sc->ALT[dlci] & CTX_VALUE) < MAX_CT) {
1689a8e6225SNuno Antunes CTXp = sc->channel + ctxnum;
1699a8e6225SNuno Antunes } else {
1709a8e6225SNuno Antunes ctxnum = -1;
1719a8e6225SNuno Antunes sc->ALT[dlci] = 0; /* paranoid but... */
1729a8e6225SNuno Antunes }
1739a8e6225SNuno Antunes }
1749a8e6225SNuno Antunes
1759a8e6225SNuno Antunes /*
1769a8e6225SNuno Antunes * If the index has no valid entry yet, then we need to allocate a
1779a8e6225SNuno Antunes * CTX number to it
1789a8e6225SNuno Antunes */
1799a8e6225SNuno Antunes if (CTXp == NULL) {
1809a8e6225SNuno Antunes for (ctxnum = 0; ctxnum < MAX_CT; ctxnum++) {
1819a8e6225SNuno Antunes /*
1829a8e6225SNuno Antunes * If the VALID flag is empty it is unused
1839a8e6225SNuno Antunes */
1849a8e6225SNuno Antunes if ((sc->channel[ctxnum].flags & CHAN_VALID) == 0) {
1859a8e6225SNuno Antunes bzero(sc->channel + ctxnum,
1869a8e6225SNuno Antunes sizeof(struct ctxinfo));
1879a8e6225SNuno Antunes CTXp = sc->channel + ctxnum;
1889a8e6225SNuno Antunes sc->ALT[dlci] = ctxnum | CTX_VALID;
1899a8e6225SNuno Antunes sc->channel[ctxnum].dlci = dlci;
1909a8e6225SNuno Antunes sc->channel[ctxnum].flags = CHAN_VALID;
1919a8e6225SNuno Antunes break;
1929a8e6225SNuno Antunes }
1939a8e6225SNuno Antunes }
1949a8e6225SNuno Antunes }
1959a8e6225SNuno Antunes
1969a8e6225SNuno Antunes /*
1979a8e6225SNuno Antunes * If we still don't have a CTX pointer, then we never found a free
1989a8e6225SNuno Antunes * spot so give up now..
1999a8e6225SNuno Antunes */
2009a8e6225SNuno Antunes if (!CTXp) {
2019a8e6225SNuno Antunes log(LOG_ERR, "No CTX available for dlci %d\n", dlci);
2029a8e6225SNuno Antunes return (-1);
2039a8e6225SNuno Antunes }
2049a8e6225SNuno Antunes return (ctxnum);
2059a8e6225SNuno Antunes }
2069a8e6225SNuno Antunes
2079a8e6225SNuno Antunes /*
2089a8e6225SNuno Antunes * Node constructor
2099a8e6225SNuno Antunes */
2109a8e6225SNuno Antunes static int
ngfrm_constructor(node_p node)2119a8e6225SNuno Antunes ngfrm_constructor(node_p node)
2129a8e6225SNuno Antunes {
2139a8e6225SNuno Antunes sc_p sc;
2149a8e6225SNuno Antunes
2159a8e6225SNuno Antunes sc = kmalloc(sizeof(*sc), M_NETGRAPH, M_WAITOK | M_NULLOK | M_ZERO);
2169a8e6225SNuno Antunes if (!sc)
2179a8e6225SNuno Antunes return (ENOMEM);
2189a8e6225SNuno Antunes sc->addrlen = 2; /* default */
2199a8e6225SNuno Antunes
2209a8e6225SNuno Antunes /* Link the node and our private info */
2219a8e6225SNuno Antunes NG_NODE_SET_PRIVATE(node, sc);
2229a8e6225SNuno Antunes sc->node = node;
2239a8e6225SNuno Antunes return (0);
2249a8e6225SNuno Antunes }
2259a8e6225SNuno Antunes
2269a8e6225SNuno Antunes /*
2279a8e6225SNuno Antunes * Add a new hook
2289a8e6225SNuno Antunes *
2299a8e6225SNuno Antunes * We allow hooks called "debug", "downstream" and dlci[0-1023]
2309a8e6225SNuno Antunes * The hook's private info points to our stash of info about that
2319a8e6225SNuno Antunes * channel. A NULL pointer is debug and a DLCI of -1 means downstream.
2329a8e6225SNuno Antunes */
2339a8e6225SNuno Antunes static int
ngfrm_newhook(node_p node,hook_p hook,const char * name)2349a8e6225SNuno Antunes ngfrm_newhook(node_p node, hook_p hook, const char *name)
2359a8e6225SNuno Antunes {
2369a8e6225SNuno Antunes const sc_p sc = NG_NODE_PRIVATE(node);
2379a8e6225SNuno Antunes const char *cp;
2389a8e6225SNuno Antunes char *eptr;
2399a8e6225SNuno Antunes int dlci = 0;
2409a8e6225SNuno Antunes int ctxnum;
2419a8e6225SNuno Antunes
2429a8e6225SNuno Antunes /* Check if it's our friend the control hook */
2439a8e6225SNuno Antunes if (strcmp(name, NG_FRAMERELAY_HOOK_DEBUG) == 0) {
2449a8e6225SNuno Antunes NG_HOOK_SET_PRIVATE(hook, NULL); /* paranoid */
2459a8e6225SNuno Antunes return (0);
2469a8e6225SNuno Antunes }
2479a8e6225SNuno Antunes
2489a8e6225SNuno Antunes /*
2499a8e6225SNuno Antunes * All other hooks either start with 'dlci' and have a decimal
2509a8e6225SNuno Antunes * trailing channel number up to 4 digits, or are the downstream
2519a8e6225SNuno Antunes * hook.
2529a8e6225SNuno Antunes */
2539a8e6225SNuno Antunes if (strncmp(name, NG_FRAMERELAY_HOOK_DLCI,
2549a8e6225SNuno Antunes strlen(NG_FRAMERELAY_HOOK_DLCI)) != 0) {
2559a8e6225SNuno Antunes
2569a8e6225SNuno Antunes /* It must be the downstream connection */
2579a8e6225SNuno Antunes if (strcmp(name, NG_FRAMERELAY_HOOK_DOWNSTREAM) != 0)
2589a8e6225SNuno Antunes return EINVAL;
2599a8e6225SNuno Antunes
2609a8e6225SNuno Antunes /* Make sure we haven't already got one (paranoid) */
2619a8e6225SNuno Antunes if (sc->downstream.hook)
2629a8e6225SNuno Antunes return (EADDRINUSE);
2639a8e6225SNuno Antunes
2649a8e6225SNuno Antunes /* OK add it */
2659a8e6225SNuno Antunes NG_HOOK_SET_PRIVATE(hook, &sc->downstream);
2669a8e6225SNuno Antunes sc->downstream.hook = hook;
2679a8e6225SNuno Antunes sc->downstream.dlci = -1;
2689a8e6225SNuno Antunes sc->downstream.flags |= CHAN_ACTIVE;
2699a8e6225SNuno Antunes sc->datahooks++;
2709a8e6225SNuno Antunes return (0);
2719a8e6225SNuno Antunes }
2729a8e6225SNuno Antunes
2739a8e6225SNuno Antunes /* Must be a dlci hook at this point */
2749a8e6225SNuno Antunes cp = name + strlen(NG_FRAMERELAY_HOOK_DLCI);
2759a8e6225SNuno Antunes if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0'))
2769a8e6225SNuno Antunes return (EINVAL);
2779a8e6225SNuno Antunes dlci = (int)strtoul(cp, &eptr, 10);
2789a8e6225SNuno Antunes if (*eptr != '\0' || dlci < 0 || dlci > 1023)
2799a8e6225SNuno Antunes return (EINVAL);
2809a8e6225SNuno Antunes
2819a8e6225SNuno Antunes /*
2829a8e6225SNuno Antunes * We have a dlci, now either find it, or allocate it. It's possible
2839a8e6225SNuno Antunes * that we might have seen packets for it already and made an entry
2849a8e6225SNuno Antunes * for it.
2859a8e6225SNuno Antunes */
2869a8e6225SNuno Antunes ctxnum = ngfrm_allocate_CTX(sc, dlci);
2879a8e6225SNuno Antunes if (ctxnum == -1)
2889a8e6225SNuno Antunes return (ENOBUFS);
2899a8e6225SNuno Antunes
2909a8e6225SNuno Antunes /*
2919a8e6225SNuno Antunes * Be paranoid: if it's got a hook already, that dlci is in use .
2929a8e6225SNuno Antunes * Generic code can not catch all the synonyms (e.g. dlci016 vs
2939a8e6225SNuno Antunes * dlci16)
2949a8e6225SNuno Antunes */
2959a8e6225SNuno Antunes if (sc->channel[ctxnum].hook != NULL)
2969a8e6225SNuno Antunes return (EADDRINUSE);
2979a8e6225SNuno Antunes
2989a8e6225SNuno Antunes /*
2999a8e6225SNuno Antunes * Put our hooks into it (pun not intended)
3009a8e6225SNuno Antunes */
3019a8e6225SNuno Antunes sc->channel[ctxnum].flags |= CHAN_ACTIVE;
3029a8e6225SNuno Antunes NG_HOOK_SET_PRIVATE(hook, sc->channel + ctxnum);
3039a8e6225SNuno Antunes sc->channel[ctxnum].hook = hook;
3049a8e6225SNuno Antunes sc->datahooks++;
3059a8e6225SNuno Antunes return (0);
3069a8e6225SNuno Antunes }
3079a8e6225SNuno Antunes
3089a8e6225SNuno Antunes /*
3099a8e6225SNuno Antunes * Count up the size of the address header if we don't already know
3109a8e6225SNuno Antunes */
3119a8e6225SNuno Antunes int
ngfrm_addrlen(char * hdr)3129a8e6225SNuno Antunes ngfrm_addrlen(char *hdr)
3139a8e6225SNuno Antunes {
3149a8e6225SNuno Antunes if (hdr[0] & BYTEX_EA)
3159a8e6225SNuno Antunes return 0;
3169a8e6225SNuno Antunes if (hdr[1] & BYTEX_EA)
3179a8e6225SNuno Antunes return 2;
3189a8e6225SNuno Antunes if (hdr[2] & BYTEX_EA)
3199a8e6225SNuno Antunes return 3;
3209a8e6225SNuno Antunes if (hdr[3] & BYTEX_EA)
3219a8e6225SNuno Antunes return 4;
3229a8e6225SNuno Antunes return 0;
3239a8e6225SNuno Antunes }
3249a8e6225SNuno Antunes
3259a8e6225SNuno Antunes /*
3269a8e6225SNuno Antunes * Receive data packet
3279a8e6225SNuno Antunes */
3289a8e6225SNuno Antunes static int
ngfrm_rcvdata(hook_p hook,item_p item)3299a8e6225SNuno Antunes ngfrm_rcvdata(hook_p hook, item_p item)
3309a8e6225SNuno Antunes {
3319a8e6225SNuno Antunes struct ctxinfo *const ctxp = NG_HOOK_PRIVATE(hook);
3329a8e6225SNuno Antunes struct mbuf *m = NULL;
3339a8e6225SNuno Antunes int error = 0;
3349a8e6225SNuno Antunes int dlci;
3359a8e6225SNuno Antunes sc_p sc;
3369a8e6225SNuno Antunes int alen;
3379a8e6225SNuno Antunes char *data;
3389a8e6225SNuno Antunes
3399a8e6225SNuno Antunes /* Data doesn't come in from just anywhere (e.g debug hook) */
3409a8e6225SNuno Antunes if (ctxp == NULL) {
3419a8e6225SNuno Antunes error = ENETDOWN;
3429a8e6225SNuno Antunes goto bad;
3439a8e6225SNuno Antunes }
3449a8e6225SNuno Antunes
3459a8e6225SNuno Antunes /* If coming from downstream, decode it to a channel */
3469a8e6225SNuno Antunes dlci = ctxp->dlci;
3479a8e6225SNuno Antunes if (dlci == -1)
3489a8e6225SNuno Antunes return (ngfrm_decode(NG_HOOK_NODE(hook), item));
3499a8e6225SNuno Antunes
3509a8e6225SNuno Antunes NGI_GET_M(item, m);
3519a8e6225SNuno Antunes /* Derive the softc we will need */
3529a8e6225SNuno Antunes sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
3539a8e6225SNuno Antunes
3549a8e6225SNuno Antunes /* If there is no live channel, throw it away */
3559a8e6225SNuno Antunes if ((sc->downstream.hook == NULL)
3569a8e6225SNuno Antunes || ((ctxp->flags & CHAN_ACTIVE) == 0)) {
3579a8e6225SNuno Antunes error = ENETDOWN;
3589a8e6225SNuno Antunes goto bad;
3599a8e6225SNuno Antunes }
3609a8e6225SNuno Antunes
3619a8e6225SNuno Antunes /* Store the DLCI on the front of the packet */
3629a8e6225SNuno Antunes alen = sc->addrlen;
3639a8e6225SNuno Antunes if (alen == 0)
3649a8e6225SNuno Antunes alen = 2; /* default value for transmit */
365*b5523eacSSascha Wildner M_PREPEND(m, alen, M_NOWAIT);
3669a8e6225SNuno Antunes if (m == NULL) {
3679a8e6225SNuno Antunes error = ENOBUFS;
3689a8e6225SNuno Antunes goto bad;
3699a8e6225SNuno Antunes }
3709a8e6225SNuno Antunes data = mtod(m, char *);
3719a8e6225SNuno Antunes
3729a8e6225SNuno Antunes /*
3739a8e6225SNuno Antunes * Shift the lowest bits into the address field untill we are done.
3749a8e6225SNuno Antunes * First byte is MSBits of addr so work backwards.
3759a8e6225SNuno Antunes */
3769a8e6225SNuno Antunes switch (alen) {
3779a8e6225SNuno Antunes case 2:
3789a8e6225SNuno Antunes data[0] = data[1] = '\0';
3799a8e6225SNuno Antunes SHIFTOUT(makeup + 1, data[1], dlci);
3809a8e6225SNuno Antunes SHIFTOUT(makeup + 0, data[0], dlci);
3819a8e6225SNuno Antunes data[1] |= BYTEX_EA;
3829a8e6225SNuno Antunes break;
3839a8e6225SNuno Antunes case 3:
3849a8e6225SNuno Antunes data[0] = data[1] = data[2] = '\0';
3859a8e6225SNuno Antunes SHIFTOUT(makeup + 3, data[2], dlci); /* 3 and 2 is correct */
3869a8e6225SNuno Antunes SHIFTOUT(makeup + 1, data[1], dlci);
3879a8e6225SNuno Antunes SHIFTOUT(makeup + 0, data[0], dlci);
3889a8e6225SNuno Antunes data[2] |= BYTEX_EA;
3899a8e6225SNuno Antunes break;
3909a8e6225SNuno Antunes case 4:
3919a8e6225SNuno Antunes data[0] = data[1] = data[2] = data[3] = '\0';
3929a8e6225SNuno Antunes SHIFTOUT(makeup + 3, data[3], dlci);
3939a8e6225SNuno Antunes SHIFTOUT(makeup + 2, data[2], dlci);
3949a8e6225SNuno Antunes SHIFTOUT(makeup + 1, data[1], dlci);
3959a8e6225SNuno Antunes SHIFTOUT(makeup + 0, data[0], dlci);
3969a8e6225SNuno Antunes data[3] |= BYTEX_EA;
3979a8e6225SNuno Antunes break;
3989a8e6225SNuno Antunes default:
3999a8e6225SNuno Antunes panic(__func__);
4009a8e6225SNuno Antunes }
4019a8e6225SNuno Antunes
4029a8e6225SNuno Antunes /* Send it */
4039a8e6225SNuno Antunes NG_FWD_NEW_DATA(error, item, sc->downstream.hook, m);
4049a8e6225SNuno Antunes return (error);
4059a8e6225SNuno Antunes
4069a8e6225SNuno Antunes bad:
4079a8e6225SNuno Antunes NG_FREE_ITEM(item);
4089a8e6225SNuno Antunes NG_FREE_M(m);
4099a8e6225SNuno Antunes return (error);
4109a8e6225SNuno Antunes }
4119a8e6225SNuno Antunes
4129a8e6225SNuno Antunes /*
4139a8e6225SNuno Antunes * Decode an incoming frame coming from the switch
4149a8e6225SNuno Antunes */
4159a8e6225SNuno Antunes static int
ngfrm_decode(node_p node,item_p item)4169a8e6225SNuno Antunes ngfrm_decode(node_p node, item_p item)
4179a8e6225SNuno Antunes {
4189a8e6225SNuno Antunes const sc_p sc = NG_NODE_PRIVATE(node);
4199a8e6225SNuno Antunes char *data;
4209a8e6225SNuno Antunes int alen;
4219a8e6225SNuno Antunes u_int dlci = 0;
4229a8e6225SNuno Antunes int error = 0;
4239a8e6225SNuno Antunes int ctxnum;
4249a8e6225SNuno Antunes struct mbuf *m;
4259a8e6225SNuno Antunes
4269a8e6225SNuno Antunes NGI_GET_M(item, m);
4279a8e6225SNuno Antunes if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) {
4289a8e6225SNuno Antunes error = ENOBUFS;
4299a8e6225SNuno Antunes goto out;
4309a8e6225SNuno Antunes }
4319a8e6225SNuno Antunes data = mtod(m, char *);
4329a8e6225SNuno Antunes if ((alen = sc->addrlen) == 0) {
4339a8e6225SNuno Antunes sc->addrlen = alen = ngfrm_addrlen(data);
4349a8e6225SNuno Antunes }
4359a8e6225SNuno Antunes switch (alen) {
4369a8e6225SNuno Antunes case 2:
4379a8e6225SNuno Antunes SHIFTIN(makeup + 0, data[0], dlci);
4389a8e6225SNuno Antunes SHIFTIN(makeup + 1, data[1], dlci);
4399a8e6225SNuno Antunes break;
4409a8e6225SNuno Antunes case 3:
4419a8e6225SNuno Antunes SHIFTIN(makeup + 0, data[0], dlci);
4429a8e6225SNuno Antunes SHIFTIN(makeup + 1, data[1], dlci);
4439a8e6225SNuno Antunes SHIFTIN(makeup + 3, data[2], dlci); /* 3 and 2 is correct */
4449a8e6225SNuno Antunes break;
4459a8e6225SNuno Antunes case 4:
4469a8e6225SNuno Antunes SHIFTIN(makeup + 0, data[0], dlci);
4479a8e6225SNuno Antunes SHIFTIN(makeup + 1, data[1], dlci);
4489a8e6225SNuno Antunes SHIFTIN(makeup + 2, data[2], dlci);
4499a8e6225SNuno Antunes SHIFTIN(makeup + 3, data[3], dlci);
4509a8e6225SNuno Antunes break;
4519a8e6225SNuno Antunes default:
4529a8e6225SNuno Antunes error = EINVAL;
4539a8e6225SNuno Antunes goto out;
4549a8e6225SNuno Antunes }
4559a8e6225SNuno Antunes
4569a8e6225SNuno Antunes if (dlci > 1023) {
4579a8e6225SNuno Antunes error = EINVAL;
4589a8e6225SNuno Antunes goto out;
4599a8e6225SNuno Antunes }
4609a8e6225SNuno Antunes ctxnum = sc->ALT[dlci];
4619a8e6225SNuno Antunes if ((ctxnum & CTX_VALID) && sc->channel[ctxnum &= CTX_VALUE].hook) {
4629a8e6225SNuno Antunes /* Send it */
4639a8e6225SNuno Antunes m_adj(m, alen);
4649a8e6225SNuno Antunes NG_FWD_NEW_DATA(error, item, sc->channel[ctxnum].hook, m);
4659a8e6225SNuno Antunes return (error);
4669a8e6225SNuno Antunes } else {
4679a8e6225SNuno Antunes error = ENETDOWN;
4689a8e6225SNuno Antunes }
4699a8e6225SNuno Antunes out:
4709a8e6225SNuno Antunes NG_FREE_ITEM(item);
4719a8e6225SNuno Antunes NG_FREE_M(m);
4729a8e6225SNuno Antunes return (error);
4739a8e6225SNuno Antunes }
4749a8e6225SNuno Antunes
4759a8e6225SNuno Antunes /*
4769a8e6225SNuno Antunes * Shutdown node
4779a8e6225SNuno Antunes */
4789a8e6225SNuno Antunes static int
ngfrm_shutdown(node_p node)4799a8e6225SNuno Antunes ngfrm_shutdown(node_p node)
4809a8e6225SNuno Antunes {
4819a8e6225SNuno Antunes const sc_p sc = NG_NODE_PRIVATE(node);
4829a8e6225SNuno Antunes
4839a8e6225SNuno Antunes NG_NODE_SET_PRIVATE(node, NULL);
4849a8e6225SNuno Antunes kfree(sc, M_NETGRAPH);
4859a8e6225SNuno Antunes NG_NODE_UNREF(node);
4869a8e6225SNuno Antunes return (0);
4879a8e6225SNuno Antunes }
4889a8e6225SNuno Antunes
4899a8e6225SNuno Antunes /*
4909a8e6225SNuno Antunes * Hook disconnection
4919a8e6225SNuno Antunes *
4929a8e6225SNuno Antunes * Invalidate the private data associated with this dlci.
4939a8e6225SNuno Antunes * For this type, removal of the last link resets tries to destroy the node.
4949a8e6225SNuno Antunes */
4959a8e6225SNuno Antunes static int
ngfrm_disconnect(hook_p hook)4969a8e6225SNuno Antunes ngfrm_disconnect(hook_p hook)
4979a8e6225SNuno Antunes {
4989a8e6225SNuno Antunes const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
4999a8e6225SNuno Antunes struct ctxinfo *const cp = NG_HOOK_PRIVATE(hook);
5009a8e6225SNuno Antunes int dlci;
5019a8e6225SNuno Antunes
5029a8e6225SNuno Antunes /* If it's a regular dlci hook, then free resources etc.. */
5039a8e6225SNuno Antunes if (cp != NULL) {
5049a8e6225SNuno Antunes cp->hook = NULL;
5059a8e6225SNuno Antunes dlci = cp->dlci;
5069a8e6225SNuno Antunes if (dlci != -1)
5079a8e6225SNuno Antunes sc->ALT[dlci] = 0;
5089a8e6225SNuno Antunes cp->flags = 0;
5099a8e6225SNuno Antunes sc->datahooks--;
5109a8e6225SNuno Antunes }
5119a8e6225SNuno Antunes if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
5129a8e6225SNuno Antunes && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
5139a8e6225SNuno Antunes ng_rmnode_self(NG_HOOK_NODE(hook));
5149a8e6225SNuno Antunes return (0);
5159a8e6225SNuno Antunes }
516