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