xref: /dflybsd-src/sys/netgraph7/async/ng_async.c (revision 05d02a3813e2bef176c69d68035311fd2efbd031)
10147868eSNuno Antunes /*
20147868eSNuno Antunes  * ng_async.c
30147868eSNuno Antunes  */
40147868eSNuno Antunes 
50147868eSNuno Antunes /*-
60147868eSNuno Antunes  * Copyright (c) 1996-1999 Whistle Communications, Inc.
70147868eSNuno Antunes  * All rights reserved.
80147868eSNuno Antunes  *
90147868eSNuno Antunes  * Subject to the following obligations and disclaimer of warranty, use and
100147868eSNuno Antunes  * redistribution of this software, in source or object code forms, with or
110147868eSNuno Antunes  * without modifications are expressly permitted by Whistle Communications;
120147868eSNuno Antunes  * provided, however, that:
130147868eSNuno Antunes  * 1. Any and all reproductions of the source or object code must include the
140147868eSNuno Antunes  *    copyright notice above and the following disclaimer of warranties; and
150147868eSNuno Antunes  * 2. No rights are granted, in any manner or form, to use Whistle
160147868eSNuno Antunes  *    Communications, Inc. trademarks, including the mark "WHISTLE
170147868eSNuno Antunes  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
180147868eSNuno Antunes  *    such appears in the above copyright notice or in the software.
190147868eSNuno Antunes  *
200147868eSNuno Antunes  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
210147868eSNuno Antunes  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
220147868eSNuno Antunes  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
230147868eSNuno Antunes  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
240147868eSNuno Antunes  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
250147868eSNuno Antunes  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
260147868eSNuno Antunes  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
270147868eSNuno Antunes  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
280147868eSNuno Antunes  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
290147868eSNuno Antunes  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
300147868eSNuno Antunes  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
310147868eSNuno Antunes  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
320147868eSNuno Antunes  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
330147868eSNuno Antunes  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
340147868eSNuno Antunes  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
350147868eSNuno Antunes  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
360147868eSNuno Antunes  * OF SUCH DAMAGE.
370147868eSNuno Antunes  *
380147868eSNuno Antunes  * Author: Archie Cobbs <archie@freebsd.org>
390147868eSNuno Antunes  *
400147868eSNuno Antunes  * $FreeBSD: src/sys/netgraph/ng_async.c,v 1.22 2005/01/07 01:45:39 imp Exp $
410147868eSNuno Antunes  * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $
420147868eSNuno Antunes  */
430147868eSNuno Antunes 
440147868eSNuno Antunes /*
450147868eSNuno Antunes  * This node type implements a PPP style sync <-> async converter.
460147868eSNuno Antunes  * See RFC 1661 for details of how asynchronous encoding works.
470147868eSNuno Antunes  */
480147868eSNuno Antunes 
490147868eSNuno Antunes #include <sys/param.h>
500147868eSNuno Antunes #include <sys/systm.h>
510147868eSNuno Antunes #include <sys/kernel.h>
520147868eSNuno Antunes #include <sys/mbuf.h>
530147868eSNuno Antunes #include <sys/malloc.h>
540147868eSNuno Antunes #include <sys/errno.h>
550147868eSNuno Antunes 
560147868eSNuno Antunes #include <netgraph7/ng_message.h>
570147868eSNuno Antunes #include <netgraph7/netgraph.h>
580147868eSNuno Antunes #include "ng_async.h"
590147868eSNuno Antunes #include <netgraph7/ng_parse.h>
600147868eSNuno Antunes 
610147868eSNuno Antunes #include <net/ppp_layer/ppp_defs.h>
620147868eSNuno Antunes 
630147868eSNuno Antunes #ifdef NG_SEPARATE_MALLOC
640147868eSNuno Antunes MALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node ");
650147868eSNuno Antunes #else
660147868eSNuno Antunes #define M_NETGRAPH_ASYNC M_NETGRAPH
670147868eSNuno Antunes #endif
680147868eSNuno Antunes 
690147868eSNuno Antunes 
700147868eSNuno Antunes /* Async decode state */
710147868eSNuno Antunes #define MODE_HUNT	0
720147868eSNuno Antunes #define MODE_NORMAL	1
730147868eSNuno Antunes #define MODE_ESC	2
740147868eSNuno Antunes 
750147868eSNuno Antunes /* Private data structure */
760147868eSNuno Antunes struct ng_async_private {
770147868eSNuno Antunes 	node_p  	node;		/* Our node */
780147868eSNuno Antunes 	hook_p  	async;		/* Asynchronous side */
790147868eSNuno Antunes 	hook_p  	sync;		/* Synchronous side */
800147868eSNuno Antunes 	u_char  	amode;		/* Async hunt/esape mode */
810147868eSNuno Antunes 	u_int16_t	fcs;		/* Decoded async FCS (so far) */
820147868eSNuno Antunes 	u_char	       *abuf;		/* Buffer to encode sync into */
830147868eSNuno Antunes 	u_char	       *sbuf;		/* Buffer to decode async into */
840147868eSNuno Antunes 	u_int		slen;		/* Length of data in sbuf */
850147868eSNuno Antunes 	long		lasttime;	/* Time of last async packet sent */
860147868eSNuno Antunes 	struct		ng_async_cfg	cfg;	/* Configuration */
870147868eSNuno Antunes 	struct		ng_async_stat	stats;	/* Statistics */
880147868eSNuno Antunes };
890147868eSNuno Antunes typedef struct ng_async_private *sc_p;
900147868eSNuno Antunes 
910147868eSNuno Antunes /* Useful macros */
920147868eSNuno Antunes #define ASYNC_BUF_SIZE(smru)	(2 * (smru) + 10)
930147868eSNuno Antunes #define SYNC_BUF_SIZE(amru)	((amru) + 10)
940147868eSNuno Antunes #define ERROUT(x)		do { error = (x); goto done; } while (0)
950147868eSNuno Antunes 
960147868eSNuno Antunes /* Netgraph methods */
970147868eSNuno Antunes static ng_constructor_t		nga_constructor;
980147868eSNuno Antunes static ng_rcvdata_t		nga_rcvdata;
990147868eSNuno Antunes static ng_rcvmsg_t		nga_rcvmsg;
1000147868eSNuno Antunes static ng_shutdown_t		nga_shutdown;
1010147868eSNuno Antunes static ng_newhook_t		nga_newhook;
1020147868eSNuno Antunes static ng_disconnect_t		nga_disconnect;
1030147868eSNuno Antunes 
1040147868eSNuno Antunes /* Helper stuff */
1050147868eSNuno Antunes static int	nga_rcv_sync(const sc_p sc, item_p item);
1060147868eSNuno Antunes static int	nga_rcv_async(const sc_p sc, item_p item);
1070147868eSNuno Antunes 
1080147868eSNuno Antunes /* Parse type for struct ng_async_cfg */
1090147868eSNuno Antunes static const struct ng_parse_struct_field nga_config_type_fields[]
1100147868eSNuno Antunes 	= NG_ASYNC_CONFIG_TYPE_INFO;
1110147868eSNuno Antunes static const struct ng_parse_type nga_config_type = {
1120147868eSNuno Antunes 	&ng_parse_struct_type,
1130147868eSNuno Antunes 	&nga_config_type_fields
1140147868eSNuno Antunes };
1150147868eSNuno Antunes 
1160147868eSNuno Antunes /* Parse type for struct ng_async_stat */
1170147868eSNuno Antunes static const struct ng_parse_struct_field nga_stats_type_fields[]
1180147868eSNuno Antunes 	= NG_ASYNC_STATS_TYPE_INFO;
1190147868eSNuno Antunes static const struct ng_parse_type nga_stats_type = {
1200147868eSNuno Antunes 	&ng_parse_struct_type,
1210147868eSNuno Antunes 	&nga_stats_type_fields
1220147868eSNuno Antunes };
1230147868eSNuno Antunes 
1240147868eSNuno Antunes /* List of commands and how to convert arguments to/from ASCII */
1250147868eSNuno Antunes static const struct ng_cmdlist nga_cmdlist[] = {
1260147868eSNuno Antunes 	{
1270147868eSNuno Antunes 	  NGM_ASYNC_COOKIE,
1280147868eSNuno Antunes 	  NGM_ASYNC_CMD_SET_CONFIG,
1290147868eSNuno Antunes 	  "setconfig",
1300147868eSNuno Antunes 	  &nga_config_type,
1310147868eSNuno Antunes 	  NULL
1320147868eSNuno Antunes 	},
1330147868eSNuno Antunes 	{
1340147868eSNuno Antunes 	  NGM_ASYNC_COOKIE,
1350147868eSNuno Antunes 	  NGM_ASYNC_CMD_GET_CONFIG,
1360147868eSNuno Antunes 	  "getconfig",
1370147868eSNuno Antunes 	  NULL,
1380147868eSNuno Antunes 	  &nga_config_type
1390147868eSNuno Antunes 	},
1400147868eSNuno Antunes 	{
1410147868eSNuno Antunes 	  NGM_ASYNC_COOKIE,
1420147868eSNuno Antunes 	  NGM_ASYNC_CMD_GET_STATS,
1430147868eSNuno Antunes 	  "getstats",
1440147868eSNuno Antunes 	  NULL,
1450147868eSNuno Antunes 	  &nga_stats_type
1460147868eSNuno Antunes 	},
1470147868eSNuno Antunes 	{
1480147868eSNuno Antunes 	  NGM_ASYNC_COOKIE,
1490147868eSNuno Antunes 	  NGM_ASYNC_CMD_CLR_STATS,
1500147868eSNuno Antunes 	  "clrstats",
1510147868eSNuno Antunes 	  &nga_stats_type,
1520147868eSNuno Antunes 	  NULL
1530147868eSNuno Antunes 	},
1540147868eSNuno Antunes 	{ 0 }
1550147868eSNuno Antunes };
1560147868eSNuno Antunes 
1570147868eSNuno Antunes /* Define the netgraph node type */
1580147868eSNuno Antunes static struct ng_type typestruct = {
1590147868eSNuno Antunes 	.version =	NG_ABI_VERSION,
1600147868eSNuno Antunes 	.name =		NG_ASYNC_NODE_TYPE,
1610147868eSNuno Antunes 	.constructor =	nga_constructor,
1620147868eSNuno Antunes 	.rcvmsg =	nga_rcvmsg,
1630147868eSNuno Antunes 	.shutdown = 	nga_shutdown,
1640147868eSNuno Antunes 	.newhook =	nga_newhook,
1650147868eSNuno Antunes 	.rcvdata =	nga_rcvdata,
1660147868eSNuno Antunes 	.disconnect =	nga_disconnect,
1670147868eSNuno Antunes 	.cmdlist =	nga_cmdlist
1680147868eSNuno Antunes };
1690147868eSNuno Antunes NETGRAPH_INIT(async, &typestruct);
1700147868eSNuno Antunes 
1710147868eSNuno Antunes /*
1720147868eSNuno Antunes  * CRC table
1730147868eSNuno Antunes  *
1740147868eSNuno Antunes  * Taken from RFC 1171 Appendix B
1750147868eSNuno Antunes  */
1760147868eSNuno Antunes static const u_int16_t fcstab[256] = {
1770147868eSNuno Antunes 	 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1780147868eSNuno Antunes 	 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1790147868eSNuno Antunes 	 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1800147868eSNuno Antunes 	 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1810147868eSNuno Antunes 	 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1820147868eSNuno Antunes 	 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1830147868eSNuno Antunes 	 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1840147868eSNuno Antunes 	 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1850147868eSNuno Antunes 	 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1860147868eSNuno Antunes 	 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1870147868eSNuno Antunes 	 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1880147868eSNuno Antunes 	 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1890147868eSNuno Antunes 	 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1900147868eSNuno Antunes 	 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1910147868eSNuno Antunes 	 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1920147868eSNuno Antunes 	 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1930147868eSNuno Antunes 	 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1940147868eSNuno Antunes 	 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1950147868eSNuno Antunes 	 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1960147868eSNuno Antunes 	 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1970147868eSNuno Antunes 	 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1980147868eSNuno Antunes 	 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1990147868eSNuno Antunes 	 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
2000147868eSNuno Antunes 	 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
2010147868eSNuno Antunes 	 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
2020147868eSNuno Antunes 	 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
2030147868eSNuno Antunes 	 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
2040147868eSNuno Antunes 	 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
2050147868eSNuno Antunes 	 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
2060147868eSNuno Antunes 	 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
2070147868eSNuno Antunes 	 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
2080147868eSNuno Antunes 	 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
2090147868eSNuno Antunes };
2100147868eSNuno Antunes 
2110147868eSNuno Antunes /******************************************************************
2120147868eSNuno Antunes 		    NETGRAPH NODE METHODS
2130147868eSNuno Antunes ******************************************************************/
2140147868eSNuno Antunes 
2150147868eSNuno Antunes /*
2160147868eSNuno Antunes  * Initialize a new node
2170147868eSNuno Antunes  */
2180147868eSNuno Antunes static int
nga_constructor(node_p node)2190147868eSNuno Antunes nga_constructor(node_p node)
2200147868eSNuno Antunes {
2210147868eSNuno Antunes 	sc_p sc;
2220147868eSNuno Antunes 
2230147868eSNuno Antunes 	sc = kmalloc(sizeof(*sc), M_NETGRAPH_ASYNC,
2240147868eSNuno Antunes 		     M_WAITOK | M_NULLOK | M_ZERO);
2250147868eSNuno Antunes 	if (sc == NULL)
2260147868eSNuno Antunes 		return (ENOMEM);
2270147868eSNuno Antunes 	sc->amode = MODE_HUNT;
2280147868eSNuno Antunes 	sc->cfg.accm = ~0;
2290147868eSNuno Antunes 	sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
2300147868eSNuno Antunes 	sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
2310147868eSNuno Antunes 	sc->abuf = kmalloc(ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH_ASYNC,
2320147868eSNuno Antunes 			   M_WAITOK | M_NULLOK);
2330147868eSNuno Antunes 	if (sc->abuf == NULL)
2340147868eSNuno Antunes 		goto fail;
2350147868eSNuno Antunes 	sc->sbuf = kmalloc(SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH_ASYNC,
2360147868eSNuno Antunes 			   M_WAITOK | M_NULLOK);
2370147868eSNuno Antunes 	if (sc->sbuf == NULL) {
2380147868eSNuno Antunes 		kfree(sc->abuf, M_NETGRAPH_ASYNC);
2390147868eSNuno Antunes fail:
2400147868eSNuno Antunes 		kfree(sc, M_NETGRAPH_ASYNC);
2410147868eSNuno Antunes 		return (ENOMEM);
2420147868eSNuno Antunes 	}
2430147868eSNuno Antunes 	NG_NODE_SET_PRIVATE(node, sc);
2440147868eSNuno Antunes 	sc->node = node;
2450147868eSNuno Antunes 	return (0);
2460147868eSNuno Antunes }
2470147868eSNuno Antunes 
2480147868eSNuno Antunes /*
2490147868eSNuno Antunes  * Reserve a hook for a pending connection
2500147868eSNuno Antunes  */
2510147868eSNuno Antunes static int
nga_newhook(node_p node,hook_p hook,const char * name)2520147868eSNuno Antunes nga_newhook(node_p node, hook_p hook, const char *name)
2530147868eSNuno Antunes {
2540147868eSNuno Antunes 	const sc_p sc = NG_NODE_PRIVATE(node);
2550147868eSNuno Antunes 	hook_p *hookp;
2560147868eSNuno Antunes 
2570147868eSNuno Antunes 	if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) {
2580147868eSNuno Antunes 		/*
2590147868eSNuno Antunes 		 * We use a static buffer here so only one packet
2600147868eSNuno Antunes 		 * at a time can be allowed to travel in this direction.
2610147868eSNuno Antunes 		 * Force Writer semantics.
2620147868eSNuno Antunes 		 */
2630147868eSNuno Antunes 		NG_HOOK_FORCE_WRITER(hook);
2640147868eSNuno Antunes 		hookp = &sc->async;
2650147868eSNuno Antunes 	} else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) {
2660147868eSNuno Antunes 		/*
2670147868eSNuno Antunes 		 * We use a static state here so only one packet
2680147868eSNuno Antunes 		 * at a time can be allowed to travel in this direction.
2690147868eSNuno Antunes 		 * Force Writer semantics.
2700147868eSNuno Antunes 		 * Since we set this for both directions
2710147868eSNuno Antunes 		 * we might as well set it for the whole node
2720147868eSNuno Antunes 		 * bit I haven;t done that (yet).
2730147868eSNuno Antunes 		 */
2740147868eSNuno Antunes 		NG_HOOK_FORCE_WRITER(hook);
2750147868eSNuno Antunes 		hookp = &sc->sync;
2760147868eSNuno Antunes 	} else {
2770147868eSNuno Antunes 		return (EINVAL);
2780147868eSNuno Antunes 	}
2790147868eSNuno Antunes 	if (*hookp) /* actually can't happen I think [JRE] */
2800147868eSNuno Antunes 		return (EISCONN);
2810147868eSNuno Antunes 	*hookp = hook;
2820147868eSNuno Antunes 	return (0);
2830147868eSNuno Antunes }
2840147868eSNuno Antunes 
2850147868eSNuno Antunes /*
2860147868eSNuno Antunes  * Receive incoming data
2870147868eSNuno Antunes  */
2880147868eSNuno Antunes static int
nga_rcvdata(hook_p hook,item_p item)2890147868eSNuno Antunes nga_rcvdata(hook_p hook, item_p item)
2900147868eSNuno Antunes {
2910147868eSNuno Antunes 	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
2920147868eSNuno Antunes 
2930147868eSNuno Antunes 	if (hook == sc->sync)
2940147868eSNuno Antunes 		return (nga_rcv_sync(sc, item));
2950147868eSNuno Antunes 	if (hook == sc->async)
2960147868eSNuno Antunes 		return (nga_rcv_async(sc, item));
2970147868eSNuno Antunes 	panic(__func__);
2980147868eSNuno Antunes }
2990147868eSNuno Antunes 
3000147868eSNuno Antunes /*
3010147868eSNuno Antunes  * Receive incoming control message
3020147868eSNuno Antunes  */
3030147868eSNuno Antunes static int
nga_rcvmsg(node_p node,item_p item,hook_p lasthook)3040147868eSNuno Antunes nga_rcvmsg(node_p node, item_p item, hook_p lasthook)
3050147868eSNuno Antunes {
3060147868eSNuno Antunes 	const sc_p sc = NG_NODE_PRIVATE(node);
3070147868eSNuno Antunes 	struct ng_mesg *resp = NULL;
3080147868eSNuno Antunes 	int error = 0;
3090147868eSNuno Antunes 	struct ng_mesg *msg;
3100147868eSNuno Antunes 
3110147868eSNuno Antunes 	NGI_GET_MSG(item, msg);
3120147868eSNuno Antunes 	switch (msg->header.typecookie) {
3130147868eSNuno Antunes 	case NGM_ASYNC_COOKIE:
3140147868eSNuno Antunes 		switch (msg->header.cmd) {
3150147868eSNuno Antunes 		case NGM_ASYNC_CMD_GET_STATS:
3160147868eSNuno Antunes 			NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_WAITOK | M_NULLOK);
3170147868eSNuno Antunes 			if (resp == NULL)
3180147868eSNuno Antunes 				ERROUT(ENOMEM);
3190147868eSNuno Antunes 			*((struct ng_async_stat *) resp->data) = sc->stats;
3200147868eSNuno Antunes 			break;
3210147868eSNuno Antunes 		case NGM_ASYNC_CMD_CLR_STATS:
3220147868eSNuno Antunes 			bzero(&sc->stats, sizeof(sc->stats));
3230147868eSNuno Antunes 			break;
3240147868eSNuno Antunes 		case NGM_ASYNC_CMD_SET_CONFIG:
3250147868eSNuno Antunes 		    {
3260147868eSNuno Antunes 			struct ng_async_cfg *const cfg =
3270147868eSNuno Antunes 				(struct ng_async_cfg *) msg->data;
3280147868eSNuno Antunes 			u_char *buf;
3290147868eSNuno Antunes 
3300147868eSNuno Antunes 			if (msg->header.arglen != sizeof(*cfg))
3310147868eSNuno Antunes 				ERROUT(EINVAL);
3320147868eSNuno Antunes 			if (cfg->amru < NG_ASYNC_MIN_MRU
3330147868eSNuno Antunes 			    || cfg->amru > NG_ASYNC_MAX_MRU
3340147868eSNuno Antunes 			    || cfg->smru < NG_ASYNC_MIN_MRU
3350147868eSNuno Antunes 			    || cfg->smru > NG_ASYNC_MAX_MRU)
3360147868eSNuno Antunes 				ERROUT(EINVAL);
3370147868eSNuno Antunes 			cfg->enabled = !!cfg->enabled;	/* normalize */
3380147868eSNuno Antunes 			if (cfg->smru > sc->cfg.smru) {	/* reallocate buffer */
3390147868eSNuno Antunes 				buf = kmalloc(ASYNC_BUF_SIZE(cfg->smru),
3400147868eSNuno Antunes 					      M_NETGRAPH_ASYNC,
3410147868eSNuno Antunes 					      M_WAITOK | M_NULLOK);
3420147868eSNuno Antunes 				if (!buf)
3430147868eSNuno Antunes 					ERROUT(ENOMEM);
3440147868eSNuno Antunes 				kfree(sc->abuf, M_NETGRAPH_ASYNC);
3450147868eSNuno Antunes 				sc->abuf = buf;
3460147868eSNuno Antunes 			}
3470147868eSNuno Antunes 			if (cfg->amru > sc->cfg.amru) {	/* reallocate buffer */
3480147868eSNuno Antunes 				buf = kmalloc(SYNC_BUF_SIZE(cfg->amru),
3490147868eSNuno Antunes 					      M_NETGRAPH_ASYNC,
3500147868eSNuno Antunes 					      M_WAITOK | M_NULLOK);
3510147868eSNuno Antunes 				if (!buf)
3520147868eSNuno Antunes 					ERROUT(ENOMEM);
3530147868eSNuno Antunes 				kfree(sc->sbuf, M_NETGRAPH_ASYNC);
3540147868eSNuno Antunes 				sc->sbuf = buf;
3550147868eSNuno Antunes 				sc->amode = MODE_HUNT;
3560147868eSNuno Antunes 				sc->slen = 0;
3570147868eSNuno Antunes 			}
3580147868eSNuno Antunes 			if (!cfg->enabled) {
3590147868eSNuno Antunes 				sc->amode = MODE_HUNT;
3600147868eSNuno Antunes 				sc->slen = 0;
3610147868eSNuno Antunes 			}
3620147868eSNuno Antunes 			sc->cfg = *cfg;
3630147868eSNuno Antunes 			break;
3640147868eSNuno Antunes 		    }
3650147868eSNuno Antunes 		case NGM_ASYNC_CMD_GET_CONFIG:
3660147868eSNuno Antunes 			NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_WAITOK | M_NULLOK);
3670147868eSNuno Antunes 			if (!resp)
3680147868eSNuno Antunes 				ERROUT(ENOMEM);
3690147868eSNuno Antunes 			*((struct ng_async_cfg *) resp->data) = sc->cfg;
3700147868eSNuno Antunes 			break;
3710147868eSNuno Antunes 		default:
3720147868eSNuno Antunes 			ERROUT(EINVAL);
3730147868eSNuno Antunes 		}
3740147868eSNuno Antunes 		break;
3750147868eSNuno Antunes 	default:
3760147868eSNuno Antunes 		ERROUT(EINVAL);
3770147868eSNuno Antunes 	}
3780147868eSNuno Antunes done:
3790147868eSNuno Antunes 	NG_RESPOND_MSG(error, node, item, resp);
3800147868eSNuno Antunes 	NG_FREE_MSG(msg);
3810147868eSNuno Antunes 	return (error);
3820147868eSNuno Antunes }
3830147868eSNuno Antunes 
3840147868eSNuno Antunes /*
3850147868eSNuno Antunes  * Shutdown this node
3860147868eSNuno Antunes  */
3870147868eSNuno Antunes static int
nga_shutdown(node_p node)3880147868eSNuno Antunes nga_shutdown(node_p node)
3890147868eSNuno Antunes {
3900147868eSNuno Antunes 	const sc_p sc = NG_NODE_PRIVATE(node);
3910147868eSNuno Antunes 
3920147868eSNuno Antunes 	kfree(sc->abuf, M_NETGRAPH_ASYNC);
3930147868eSNuno Antunes 	kfree(sc->sbuf, M_NETGRAPH_ASYNC);
3940147868eSNuno Antunes 	bzero(sc, sizeof(*sc));
3950147868eSNuno Antunes 	kfree(sc, M_NETGRAPH_ASYNC);
3960147868eSNuno Antunes 	NG_NODE_SET_PRIVATE(node, NULL);
3970147868eSNuno Antunes 	NG_NODE_UNREF(node);
3980147868eSNuno Antunes 	return (0);
3990147868eSNuno Antunes }
4000147868eSNuno Antunes 
4010147868eSNuno Antunes /*
4020147868eSNuno Antunes  * Lose a hook. When both hooks go away, we disappear.
4030147868eSNuno Antunes  */
4040147868eSNuno Antunes static int
nga_disconnect(hook_p hook)4050147868eSNuno Antunes nga_disconnect(hook_p hook)
4060147868eSNuno Antunes {
4070147868eSNuno Antunes 	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
4080147868eSNuno Antunes 	hook_p *hookp;
4090147868eSNuno Antunes 
4100147868eSNuno Antunes 	if (hook == sc->async)
4110147868eSNuno Antunes 		hookp = &sc->async;
4120147868eSNuno Antunes 	else if (hook == sc->sync)
4130147868eSNuno Antunes 		hookp = &sc->sync;
4140147868eSNuno Antunes 	else
4150147868eSNuno Antunes 		panic(__func__);
4160147868eSNuno Antunes 	if (!*hookp)
4170147868eSNuno Antunes 		panic("%s 2", __func__);
4180147868eSNuno Antunes 	*hookp = NULL;
4190147868eSNuno Antunes 	bzero(&sc->stats, sizeof(sc->stats));
4200147868eSNuno Antunes 	sc->lasttime = 0;
4210147868eSNuno Antunes 	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
4220147868eSNuno Antunes 	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
4230147868eSNuno Antunes 		ng_rmnode_self(NG_HOOK_NODE(hook));
4240147868eSNuno Antunes 	return (0);
4250147868eSNuno Antunes }
4260147868eSNuno Antunes 
4270147868eSNuno Antunes /******************************************************************
4280147868eSNuno Antunes 		    INTERNAL HELPER STUFF
4290147868eSNuno Antunes ******************************************************************/
4300147868eSNuno Antunes 
4310147868eSNuno Antunes /*
4320147868eSNuno Antunes  * Encode a byte into the async buffer
4330147868eSNuno Antunes  */
4340147868eSNuno Antunes static __inline void
nga_async_add(const sc_p sc,u_int16_t * fcs,u_int32_t accm,int * len,u_char x)4350147868eSNuno Antunes nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
4360147868eSNuno Antunes {
4370147868eSNuno Antunes 	*fcs = PPP_FCS(*fcs, x);
4380147868eSNuno Antunes 	if ((x < 32 && ((1 << x) & accm))
4390147868eSNuno Antunes 	    || (x == PPP_ESCAPE)
4400147868eSNuno Antunes 	    || (x == PPP_FLAG)) {
4410147868eSNuno Antunes 		sc->abuf[(*len)++] = PPP_ESCAPE;
4420147868eSNuno Antunes 		x ^= PPP_TRANS;
4430147868eSNuno Antunes 	}
4440147868eSNuno Antunes 	sc->abuf[(*len)++] = x;
4450147868eSNuno Antunes }
4460147868eSNuno Antunes 
4470147868eSNuno Antunes /*
4480147868eSNuno Antunes  * Receive incoming synchronous data.
4490147868eSNuno Antunes  */
4500147868eSNuno Antunes static int
nga_rcv_sync(const sc_p sc,item_p item)4510147868eSNuno Antunes nga_rcv_sync(const sc_p sc, item_p item)
4520147868eSNuno Antunes {
4530147868eSNuno Antunes 	struct ifnet *rcvif;
4540147868eSNuno Antunes 	int alen, error = 0;
4550147868eSNuno Antunes 	struct timeval time;
4560147868eSNuno Antunes 	u_int16_t fcs, fcs0;
4570147868eSNuno Antunes 	u_int32_t accm;
4580147868eSNuno Antunes 	struct mbuf *m;
4590147868eSNuno Antunes 
4600147868eSNuno Antunes 
4610147868eSNuno Antunes #define ADD_BYTE(x)	nga_async_add(sc, &fcs, accm, &alen, (x))
4620147868eSNuno Antunes 
4630147868eSNuno Antunes 	/* Check for bypass mode */
4640147868eSNuno Antunes 	if (!sc->cfg.enabled) {
4650147868eSNuno Antunes 		NG_FWD_ITEM_HOOK(error, item, sc->async );
4660147868eSNuno Antunes 		return (error);
4670147868eSNuno Antunes 	}
4680147868eSNuno Antunes 	NGI_GET_M(item, m);
4690147868eSNuno Antunes 
4700147868eSNuno Antunes 	rcvif = m->m_pkthdr.rcvif;
4710147868eSNuno Antunes 
4720147868eSNuno Antunes 	/* Get ACCM; special case LCP frames, which use full ACCM */
4730147868eSNuno Antunes 	accm = sc->cfg.accm;
4740147868eSNuno Antunes 	if (m->m_pkthdr.len >= 4) {
4750147868eSNuno Antunes 		static const u_char lcphdr[4] = {
4760147868eSNuno Antunes 		    PPP_ALLSTATIONS,
4770147868eSNuno Antunes 		    PPP_UI,
4780147868eSNuno Antunes 		    (u_char)(PPP_LCP >> 8),
4790147868eSNuno Antunes 		    (u_char)(PPP_LCP & 0xff)
4800147868eSNuno Antunes 		};
4810147868eSNuno Antunes 		u_char buf[4];
4820147868eSNuno Antunes 
483*05d02a38SAaron LI 		m_copydata(m, 0, 4, buf);
4840147868eSNuno Antunes 		if (bcmp(buf, &lcphdr, 4) == 0)
4850147868eSNuno Antunes 			accm = ~0;
4860147868eSNuno Antunes 	}
4870147868eSNuno Antunes 
4880147868eSNuno Antunes 	/* Check for overflow */
4890147868eSNuno Antunes 	if (m->m_pkthdr.len > sc->cfg.smru) {
4900147868eSNuno Antunes 		sc->stats.syncOverflows++;
4910147868eSNuno Antunes 		NG_FREE_M(m);
4920147868eSNuno Antunes 		NG_FREE_ITEM(item);
4930147868eSNuno Antunes 		return (EMSGSIZE);
4940147868eSNuno Antunes 	}
4950147868eSNuno Antunes 
4960147868eSNuno Antunes 	/* Update stats */
4970147868eSNuno Antunes 	sc->stats.syncFrames++;
4980147868eSNuno Antunes 	sc->stats.syncOctets += m->m_pkthdr.len;
4990147868eSNuno Antunes 
5000147868eSNuno Antunes 	/* Initialize async encoded version of input mbuf */
5010147868eSNuno Antunes 	alen = 0;
5020147868eSNuno Antunes 	fcs = PPP_INITFCS;
5030147868eSNuno Antunes 
5040147868eSNuno Antunes 	/* Add beginning sync flag if it's been long enough to need one */
5050147868eSNuno Antunes 	getmicrotime(&time);
5060147868eSNuno Antunes 	if (time.tv_sec >= sc->lasttime + 1) {
5070147868eSNuno Antunes 		sc->abuf[alen++] = PPP_FLAG;
5080147868eSNuno Antunes 		sc->lasttime = time.tv_sec;
5090147868eSNuno Antunes 	}
5100147868eSNuno Antunes 
5110147868eSNuno Antunes 	/* Add packet payload */
5120147868eSNuno Antunes 	while (m != NULL) {
5130147868eSNuno Antunes 		while (m->m_len > 0) {
5140147868eSNuno Antunes 			ADD_BYTE(*mtod(m, u_char *));
5150147868eSNuno Antunes 			m->m_data++;
5160147868eSNuno Antunes 			m->m_len--;
5170147868eSNuno Antunes 		}
5180147868eSNuno Antunes 		m = m_free(m);
5190147868eSNuno Antunes 	}
5200147868eSNuno Antunes 
5210147868eSNuno Antunes 	/* Add checksum and final sync flag */
5220147868eSNuno Antunes 	fcs0 = fcs;
5230147868eSNuno Antunes 	ADD_BYTE(~fcs0 & 0xff);
5240147868eSNuno Antunes 	ADD_BYTE(~fcs0 >> 8);
5250147868eSNuno Antunes 	sc->abuf[alen++] = PPP_FLAG;
5260147868eSNuno Antunes 
5270147868eSNuno Antunes 	/* Put frame in an mbuf and ship it off */
528afd2da4dSMatthew Dillon 	if (!(m = m_devget(sc->abuf, alen, 0, rcvif))) {
5290147868eSNuno Antunes 		NG_FREE_ITEM(item);
5300147868eSNuno Antunes 		error = ENOBUFS;
5310147868eSNuno Antunes 	} else {
5320147868eSNuno Antunes 		NG_FWD_NEW_DATA(error, item, sc->async, m);
5330147868eSNuno Antunes 	}
5340147868eSNuno Antunes 	return (error);
5350147868eSNuno Antunes }
5360147868eSNuno Antunes 
5370147868eSNuno Antunes /*
5380147868eSNuno Antunes  * Receive incoming asynchronous data
5390147868eSNuno Antunes  * XXX Technically, we should strip out incoming characters
5400147868eSNuno Antunes  *     that are in our ACCM. Not sure if this is good or not.
5410147868eSNuno Antunes  */
5420147868eSNuno Antunes static int
nga_rcv_async(const sc_p sc,item_p item)5430147868eSNuno Antunes nga_rcv_async(const sc_p sc, item_p item)
5440147868eSNuno Antunes {
5450147868eSNuno Antunes 	struct ifnet *rcvif;
5460147868eSNuno Antunes 	int error;
5470147868eSNuno Antunes 	struct mbuf *m;
5480147868eSNuno Antunes 
5490147868eSNuno Antunes 	if (!sc->cfg.enabled) {
5500147868eSNuno Antunes 		NG_FWD_ITEM_HOOK(error, item,  sc->sync);
5510147868eSNuno Antunes 		return (error);
5520147868eSNuno Antunes 	}
5530147868eSNuno Antunes 	NGI_GET_M(item, m);
5540147868eSNuno Antunes 	rcvif = m->m_pkthdr.rcvif;
5550147868eSNuno Antunes 	while (m) {
5560147868eSNuno Antunes 		struct mbuf *n;
5570147868eSNuno Antunes 
5580147868eSNuno Antunes 		for (; m->m_len > 0; m->m_data++, m->m_len--) {
5590147868eSNuno Antunes 			u_char  ch = *mtod(m, u_char *);
5600147868eSNuno Antunes 
5610147868eSNuno Antunes 			sc->stats.asyncOctets++;
5620147868eSNuno Antunes 			if (ch == PPP_FLAG) {	/* Flag overrides everything */
5630147868eSNuno Antunes 				int     skip = 0;
5640147868eSNuno Antunes 
5650147868eSNuno Antunes 				/* Check for runts */
5660147868eSNuno Antunes 				if (sc->slen < 2) {
5670147868eSNuno Antunes 					if (sc->slen > 0)
5680147868eSNuno Antunes 						sc->stats.asyncRunts++;
5690147868eSNuno Antunes 					goto reset;
5700147868eSNuno Antunes 				}
5710147868eSNuno Antunes 
5720147868eSNuno Antunes 				/* Verify CRC */
5730147868eSNuno Antunes 				if (sc->fcs != PPP_GOODFCS) {
5740147868eSNuno Antunes 					sc->stats.asyncBadCheckSums++;
5750147868eSNuno Antunes 					goto reset;
5760147868eSNuno Antunes 				}
5770147868eSNuno Antunes 				sc->slen -= 2;
5780147868eSNuno Antunes 
5790147868eSNuno Antunes 				/* Strip address and control fields */
5800147868eSNuno Antunes 				if (sc->slen >= 2
5810147868eSNuno Antunes 				    && sc->sbuf[0] == PPP_ALLSTATIONS
5820147868eSNuno Antunes 				    && sc->sbuf[1] == PPP_UI)
5830147868eSNuno Antunes 					skip = 2;
5840147868eSNuno Antunes 
5850147868eSNuno Antunes 				/* Check for frame too big */
5860147868eSNuno Antunes 				if (sc->slen - skip > sc->cfg.amru) {
5870147868eSNuno Antunes 					sc->stats.asyncOverflows++;
5880147868eSNuno Antunes 					goto reset;
5890147868eSNuno Antunes 				}
5900147868eSNuno Antunes 
5910147868eSNuno Antunes 				/* OK, ship it out */
5920147868eSNuno Antunes 				if ((n = m_devget(sc->sbuf + skip,
593afd2da4dSMatthew Dillon 					   sc->slen - skip, 0, rcvif))) {
5940147868eSNuno Antunes 					if (item) { /* sets NULL -> item */
5950147868eSNuno Antunes 						NG_FWD_NEW_DATA(error, item,
5960147868eSNuno Antunes 							sc->sync, n);
5970147868eSNuno Antunes 					} else {
5980147868eSNuno Antunes 						NG_SEND_DATA_ONLY(error,
5990147868eSNuno Antunes 							sc->sync ,n);
6000147868eSNuno Antunes 					}
6010147868eSNuno Antunes 				}
6020147868eSNuno Antunes 				sc->stats.asyncFrames++;
6030147868eSNuno Antunes reset:
6040147868eSNuno Antunes 				sc->amode = MODE_NORMAL;
6050147868eSNuno Antunes 				sc->fcs = PPP_INITFCS;
6060147868eSNuno Antunes 				sc->slen = 0;
6070147868eSNuno Antunes 				continue;
6080147868eSNuno Antunes 			}
6090147868eSNuno Antunes 			switch (sc->amode) {
6100147868eSNuno Antunes 			case MODE_NORMAL:
6110147868eSNuno Antunes 				if (ch == PPP_ESCAPE) {
6120147868eSNuno Antunes 					sc->amode = MODE_ESC;
6130147868eSNuno Antunes 					continue;
6140147868eSNuno Antunes 				}
6150147868eSNuno Antunes 				break;
6160147868eSNuno Antunes 			case MODE_ESC:
6170147868eSNuno Antunes 				ch ^= PPP_TRANS;
6180147868eSNuno Antunes 				sc->amode = MODE_NORMAL;
6190147868eSNuno Antunes 				break;
6200147868eSNuno Antunes 			case MODE_HUNT:
6210147868eSNuno Antunes 			default:
6220147868eSNuno Antunes 				continue;
6230147868eSNuno Antunes 			}
6240147868eSNuno Antunes 
6250147868eSNuno Antunes 			/* Add byte to frame */
6260147868eSNuno Antunes 			if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
6270147868eSNuno Antunes 				sc->stats.asyncOverflows++;
6280147868eSNuno Antunes 				sc->amode = MODE_HUNT;
6290147868eSNuno Antunes 				sc->slen = 0;
6300147868eSNuno Antunes 			} else {
6310147868eSNuno Antunes 				sc->sbuf[sc->slen++] = ch;
6320147868eSNuno Antunes 				sc->fcs = PPP_FCS(sc->fcs, ch);
6330147868eSNuno Antunes 			}
6340147868eSNuno Antunes 		}
6350147868eSNuno Antunes 		m = m_free(m);
6360147868eSNuno Antunes 	}
6370147868eSNuno Antunes 	if (item)
6380147868eSNuno Antunes 		NG_FREE_ITEM(item);
6390147868eSNuno Antunes 	return (0);
6400147868eSNuno Antunes }
641