xref: /dflybsd-src/sys/netgraph7/frame_relay/ng_frame_relay.c (revision b5523eac31a95e6876e05e20e6fe836ec3a45202)
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