14cf49a43SJulian Elischer /* 24cf49a43SJulian Elischer * ng_async.c 3c398230bSWarner Losh */ 4c398230bSWarner Losh 5c398230bSWarner Losh /*- 64cf49a43SJulian Elischer * Copyright (c) 1996-1999 Whistle Communications, Inc. 74cf49a43SJulian Elischer * All rights reserved. 84cf49a43SJulian Elischer * 94cf49a43SJulian Elischer * Subject to the following obligations and disclaimer of warranty, use and 104cf49a43SJulian Elischer * redistribution of this software, in source or object code forms, with or 114cf49a43SJulian Elischer * without modifications are expressly permitted by Whistle Communications; 124cf49a43SJulian Elischer * provided, however, that: 134cf49a43SJulian Elischer * 1. Any and all reproductions of the source or object code must include the 144cf49a43SJulian Elischer * copyright notice above and the following disclaimer of warranties; and 154cf49a43SJulian Elischer * 2. No rights are granted, in any manner or form, to use Whistle 164cf49a43SJulian Elischer * Communications, Inc. trademarks, including the mark "WHISTLE 174cf49a43SJulian Elischer * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 184cf49a43SJulian Elischer * such appears in the above copyright notice or in the software. 194cf49a43SJulian Elischer * 204cf49a43SJulian Elischer * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 214cf49a43SJulian Elischer * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 224cf49a43SJulian Elischer * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 234cf49a43SJulian Elischer * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 244cf49a43SJulian Elischer * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 254cf49a43SJulian Elischer * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 264cf49a43SJulian Elischer * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 274cf49a43SJulian Elischer * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 284cf49a43SJulian Elischer * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 294cf49a43SJulian Elischer * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 304cf49a43SJulian Elischer * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 314cf49a43SJulian Elischer * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 324cf49a43SJulian Elischer * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 334cf49a43SJulian Elischer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 344cf49a43SJulian Elischer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 354cf49a43SJulian Elischer * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 364cf49a43SJulian Elischer * OF SUCH DAMAGE. 374cf49a43SJulian Elischer * 38cc3bbd68SJulian Elischer * Author: Archie Cobbs <archie@freebsd.org> 394cf49a43SJulian Elischer * 404cf49a43SJulian Elischer * $FreeBSD$ 4174f5c6aaSJulian Elischer * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $ 424cf49a43SJulian Elischer */ 434cf49a43SJulian Elischer 444cf49a43SJulian Elischer /* 454cf49a43SJulian Elischer * This node type implements a PPP style sync <-> async converter. 464cf49a43SJulian Elischer * See RFC 1661 for details of how asynchronous encoding works. 474cf49a43SJulian Elischer */ 484cf49a43SJulian Elischer 494cf49a43SJulian Elischer #include <sys/param.h> 504cf49a43SJulian Elischer #include <sys/systm.h> 514cf49a43SJulian Elischer #include <sys/kernel.h> 524cf49a43SJulian Elischer #include <sys/mbuf.h> 534cf49a43SJulian Elischer #include <sys/malloc.h> 544cf49a43SJulian Elischer #include <sys/errno.h> 554cf49a43SJulian Elischer 564cf49a43SJulian Elischer #include <netgraph/ng_message.h> 574cf49a43SJulian Elischer #include <netgraph/netgraph.h> 584cf49a43SJulian Elischer #include <netgraph/ng_async.h> 59f8307e12SArchie Cobbs #include <netgraph/ng_parse.h> 604cf49a43SJulian Elischer 614cf49a43SJulian Elischer #include <net/ppp_defs.h> 624cf49a43SJulian Elischer 639c8c302fSJulian Elischer #ifdef NG_SEPARATE_MALLOC 649c8c302fSJulian Elischer MALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node "); 659c8c302fSJulian Elischer #else 669c8c302fSJulian Elischer #define M_NETGRAPH_ASYNC M_NETGRAPH 679c8c302fSJulian Elischer #endif 689c8c302fSJulian Elischer 699c8c302fSJulian Elischer 704cf49a43SJulian Elischer /* Async decode state */ 714cf49a43SJulian Elischer #define MODE_HUNT 0 724cf49a43SJulian Elischer #define MODE_NORMAL 1 734cf49a43SJulian Elischer #define MODE_ESC 2 744cf49a43SJulian Elischer 754cf49a43SJulian Elischer /* Private data structure */ 7619a52c59SArchie Cobbs struct ng_async_private { 774cf49a43SJulian Elischer node_p node; /* Our node */ 784cf49a43SJulian Elischer hook_p async; /* Asynchronous side */ 794cf49a43SJulian Elischer hook_p sync; /* Synchronous side */ 804cf49a43SJulian Elischer u_char amode; /* Async hunt/esape mode */ 814cf49a43SJulian Elischer u_int16_t fcs; /* Decoded async FCS (so far) */ 824cf49a43SJulian Elischer u_char *abuf; /* Buffer to encode sync into */ 834cf49a43SJulian Elischer u_char *sbuf; /* Buffer to decode async into */ 844cf49a43SJulian Elischer u_int slen; /* Length of data in sbuf */ 854cf49a43SJulian Elischer long lasttime; /* Time of last async packet sent */ 864cf49a43SJulian Elischer struct ng_async_cfg cfg; /* Configuration */ 874cf49a43SJulian Elischer struct ng_async_stat stats; /* Statistics */ 884cf49a43SJulian Elischer }; 8919a52c59SArchie Cobbs typedef struct ng_async_private *sc_p; 904cf49a43SJulian Elischer 914cf49a43SJulian Elischer /* Useful macros */ 924cf49a43SJulian Elischer #define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10) 934cf49a43SJulian Elischer #define SYNC_BUF_SIZE(amru) ((amru) + 10) 944cf49a43SJulian Elischer #define ERROUT(x) do { error = (x); goto done; } while (0) 954cf49a43SJulian Elischer 964cf49a43SJulian Elischer /* Netgraph methods */ 9774f5c6aaSJulian Elischer static ng_constructor_t nga_constructor; 9874f5c6aaSJulian Elischer static ng_rcvdata_t nga_rcvdata; 9974f5c6aaSJulian Elischer static ng_rcvmsg_t nga_rcvmsg; 10074f5c6aaSJulian Elischer static ng_shutdown_t nga_shutdown; 10174f5c6aaSJulian Elischer static ng_newhook_t nga_newhook; 10274f5c6aaSJulian Elischer static ng_disconnect_t nga_disconnect; 1034cf49a43SJulian Elischer 1044cf49a43SJulian Elischer /* Helper stuff */ 105069154d5SJulian Elischer static int nga_rcv_sync(const sc_p sc, item_p item); 106069154d5SJulian Elischer static int nga_rcv_async(const sc_p sc, item_p item); 1074cf49a43SJulian Elischer 108f8307e12SArchie Cobbs /* Parse type for struct ng_async_cfg */ 109f0184ff8SArchie Cobbs static const struct ng_parse_struct_field nga_config_type_fields[] 110f0184ff8SArchie Cobbs = NG_ASYNC_CONFIG_TYPE_INFO; 111f8307e12SArchie Cobbs static const struct ng_parse_type nga_config_type = { 112f8307e12SArchie Cobbs &ng_parse_struct_type, 113f0184ff8SArchie Cobbs &nga_config_type_fields 114f8307e12SArchie Cobbs }; 115f8307e12SArchie Cobbs 116f8307e12SArchie Cobbs /* Parse type for struct ng_async_stat */ 117f0184ff8SArchie Cobbs static const struct ng_parse_struct_field nga_stats_type_fields[] 118f0184ff8SArchie Cobbs = NG_ASYNC_STATS_TYPE_INFO; 119f8307e12SArchie Cobbs static const struct ng_parse_type nga_stats_type = { 120f8307e12SArchie Cobbs &ng_parse_struct_type, 121f0184ff8SArchie Cobbs &nga_stats_type_fields 122f8307e12SArchie Cobbs }; 123f8307e12SArchie Cobbs 124f8307e12SArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */ 125f8307e12SArchie Cobbs static const struct ng_cmdlist nga_cmdlist[] = { 126f8307e12SArchie Cobbs { 127f8307e12SArchie Cobbs NGM_ASYNC_COOKIE, 128f8307e12SArchie Cobbs NGM_ASYNC_CMD_SET_CONFIG, 129f8307e12SArchie Cobbs "setconfig", 130f8307e12SArchie Cobbs &nga_config_type, 131f8307e12SArchie Cobbs NULL 132f8307e12SArchie Cobbs }, 133f8307e12SArchie Cobbs { 134f8307e12SArchie Cobbs NGM_ASYNC_COOKIE, 135f8307e12SArchie Cobbs NGM_ASYNC_CMD_GET_CONFIG, 136f8307e12SArchie Cobbs "getconfig", 137f8307e12SArchie Cobbs NULL, 138f8307e12SArchie Cobbs &nga_config_type 139f8307e12SArchie Cobbs }, 140f8307e12SArchie Cobbs { 141f8307e12SArchie Cobbs NGM_ASYNC_COOKIE, 142f8307e12SArchie Cobbs NGM_ASYNC_CMD_GET_STATS, 143f8307e12SArchie Cobbs "getstats", 144f8307e12SArchie Cobbs NULL, 145f8307e12SArchie Cobbs &nga_stats_type 146f8307e12SArchie Cobbs }, 147f8307e12SArchie Cobbs { 148f8307e12SArchie Cobbs NGM_ASYNC_COOKIE, 149f8307e12SArchie Cobbs NGM_ASYNC_CMD_CLR_STATS, 150f8307e12SArchie Cobbs "clrstats", 151f8307e12SArchie Cobbs &nga_stats_type, 152f8307e12SArchie Cobbs NULL 153f8307e12SArchie Cobbs }, 154f8307e12SArchie Cobbs { 0 } 155f8307e12SArchie Cobbs }; 156f8307e12SArchie Cobbs 1574cf49a43SJulian Elischer /* Define the netgraph node type */ 1584cf49a43SJulian Elischer static struct ng_type typestruct = { 159f8aae777SJulian Elischer .version = NG_ABI_VERSION, 160f8aae777SJulian Elischer .name = NG_ASYNC_NODE_TYPE, 161f8aae777SJulian Elischer .constructor = nga_constructor, 162f8aae777SJulian Elischer .rcvmsg = nga_rcvmsg, 163f8aae777SJulian Elischer .shutdown = nga_shutdown, 164f8aae777SJulian Elischer .newhook = nga_newhook, 165f8aae777SJulian Elischer .rcvdata = nga_rcvdata, 166f8aae777SJulian Elischer .disconnect = nga_disconnect, 167f8aae777SJulian Elischer .cmdlist = nga_cmdlist 1684cf49a43SJulian Elischer }; 1694cf49a43SJulian Elischer NETGRAPH_INIT(async, &typestruct); 1704cf49a43SJulian Elischer 1714cf49a43SJulian Elischer /* CRC table */ 1724cf49a43SJulian Elischer static const u_int16_t fcstab[]; 1734cf49a43SJulian Elischer 1744cf49a43SJulian Elischer /****************************************************************** 1754cf49a43SJulian Elischer NETGRAPH NODE METHODS 1764cf49a43SJulian Elischer ******************************************************************/ 1774cf49a43SJulian Elischer 1784cf49a43SJulian Elischer /* 1794cf49a43SJulian Elischer * Initialize a new node 1804cf49a43SJulian Elischer */ 1814cf49a43SJulian Elischer static int 182069154d5SJulian Elischer nga_constructor(node_p node) 1834cf49a43SJulian Elischer { 1844cf49a43SJulian Elischer sc_p sc; 1854cf49a43SJulian Elischer 1869c8c302fSJulian Elischer MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH_ASYNC, M_NOWAIT | M_ZERO); 1874cf49a43SJulian Elischer if (sc == NULL) 1884cf49a43SJulian Elischer return (ENOMEM); 1894cf49a43SJulian Elischer sc->amode = MODE_HUNT; 1904cf49a43SJulian Elischer sc->cfg.accm = ~0; 1914cf49a43SJulian Elischer sc->cfg.amru = NG_ASYNC_DEFAULT_MRU; 1924cf49a43SJulian Elischer sc->cfg.smru = NG_ASYNC_DEFAULT_MRU; 1934cf49a43SJulian Elischer MALLOC(sc->abuf, u_char *, 1949c8c302fSJulian Elischer ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH_ASYNC, M_NOWAIT); 1954cf49a43SJulian Elischer if (sc->abuf == NULL) 1964cf49a43SJulian Elischer goto fail; 1974cf49a43SJulian Elischer MALLOC(sc->sbuf, u_char *, 1989c8c302fSJulian Elischer SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH_ASYNC, M_NOWAIT); 1994cf49a43SJulian Elischer if (sc->sbuf == NULL) { 2009c8c302fSJulian Elischer FREE(sc->abuf, M_NETGRAPH_ASYNC); 2014cf49a43SJulian Elischer fail: 2029c8c302fSJulian Elischer FREE(sc, M_NETGRAPH_ASYNC); 2034cf49a43SJulian Elischer return (ENOMEM); 2044cf49a43SJulian Elischer } 20530400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, sc); 206069154d5SJulian Elischer sc->node = node; 2074cf49a43SJulian Elischer return (0); 2084cf49a43SJulian Elischer } 2094cf49a43SJulian Elischer 2104cf49a43SJulian Elischer /* 2114cf49a43SJulian Elischer * Reserve a hook for a pending connection 2124cf49a43SJulian Elischer */ 2134cf49a43SJulian Elischer static int 2144cf49a43SJulian Elischer nga_newhook(node_p node, hook_p hook, const char *name) 2154cf49a43SJulian Elischer { 21630400f03SJulian Elischer const sc_p sc = NG_NODE_PRIVATE(node); 2174cf49a43SJulian Elischer hook_p *hookp; 2184cf49a43SJulian Elischer 219069154d5SJulian Elischer if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) { 220069154d5SJulian Elischer /* 221069154d5SJulian Elischer * We use a static buffer here so only one packet 222069154d5SJulian Elischer * at a time can be allowed to travel in this direction. 223069154d5SJulian Elischer * Force Writer semantics. 224069154d5SJulian Elischer */ 22530400f03SJulian Elischer NG_HOOK_FORCE_WRITER(hook); 2264cf49a43SJulian Elischer hookp = &sc->async; 227069154d5SJulian Elischer } else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) { 228069154d5SJulian Elischer /* 229069154d5SJulian Elischer * We use a static state here so only one packet 230069154d5SJulian Elischer * at a time can be allowed to travel in this direction. 231069154d5SJulian Elischer * Force Writer semantics. 232069154d5SJulian Elischer * Since we set this for both directions 233069154d5SJulian Elischer * we might as well set it for the whole node 234069154d5SJulian Elischer * bit I haven;t done that (yet). 235069154d5SJulian Elischer */ 23630400f03SJulian Elischer NG_HOOK_FORCE_WRITER(hook); 2374cf49a43SJulian Elischer hookp = &sc->sync; 238069154d5SJulian Elischer } else { 2394cf49a43SJulian Elischer return (EINVAL); 240069154d5SJulian Elischer } 241069154d5SJulian Elischer if (*hookp) /* actually can't happen I think [JRE] */ 2424cf49a43SJulian Elischer return (EISCONN); 2434cf49a43SJulian Elischer *hookp = hook; 2444cf49a43SJulian Elischer return (0); 2454cf49a43SJulian Elischer } 2464cf49a43SJulian Elischer 2474cf49a43SJulian Elischer /* 2484cf49a43SJulian Elischer * Receive incoming data 2494cf49a43SJulian Elischer */ 2504cf49a43SJulian Elischer static int 251069154d5SJulian Elischer nga_rcvdata(hook_p hook, item_p item) 2524cf49a43SJulian Elischer { 25330400f03SJulian Elischer const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 2544cf49a43SJulian Elischer 2554cf49a43SJulian Elischer if (hook == sc->sync) 256069154d5SJulian Elischer return (nga_rcv_sync(sc, item)); 257a8e9726dSArchie Cobbs if (hook == sc->async) 258069154d5SJulian Elischer return (nga_rcv_async(sc, item)); 2596e551fb6SDavid E. O'Brien panic(__func__); 2604cf49a43SJulian Elischer } 2614cf49a43SJulian Elischer 2624cf49a43SJulian Elischer /* 2634cf49a43SJulian Elischer * Receive incoming control message 2644cf49a43SJulian Elischer */ 2654cf49a43SJulian Elischer static int 266069154d5SJulian Elischer nga_rcvmsg(node_p node, item_p item, hook_p lasthook) 2674cf49a43SJulian Elischer { 26830400f03SJulian Elischer const sc_p sc = NG_NODE_PRIVATE(node); 2694cf49a43SJulian Elischer struct ng_mesg *resp = NULL; 2704cf49a43SJulian Elischer int error = 0; 271069154d5SJulian Elischer struct ng_mesg *msg; 2724cf49a43SJulian Elischer 273069154d5SJulian Elischer NGI_GET_MSG(item, msg); 2744cf49a43SJulian Elischer switch (msg->header.typecookie) { 2754cf49a43SJulian Elischer case NGM_ASYNC_COOKIE: 2764cf49a43SJulian Elischer switch (msg->header.cmd) { 2774cf49a43SJulian Elischer case NGM_ASYNC_CMD_GET_STATS: 2784cf49a43SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT); 2794cf49a43SJulian Elischer if (resp == NULL) 2804cf49a43SJulian Elischer ERROUT(ENOMEM); 2814cf49a43SJulian Elischer *((struct ng_async_stat *) resp->data) = sc->stats; 2824cf49a43SJulian Elischer break; 2834cf49a43SJulian Elischer case NGM_ASYNC_CMD_CLR_STATS: 2844cf49a43SJulian Elischer bzero(&sc->stats, sizeof(sc->stats)); 2854cf49a43SJulian Elischer break; 2864cf49a43SJulian Elischer case NGM_ASYNC_CMD_SET_CONFIG: 2874cf49a43SJulian Elischer { 2884cf49a43SJulian Elischer struct ng_async_cfg *const cfg = 2894cf49a43SJulian Elischer (struct ng_async_cfg *) msg->data; 2904cf49a43SJulian Elischer u_char *buf; 2914cf49a43SJulian Elischer 2924cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*cfg)) 2934cf49a43SJulian Elischer ERROUT(EINVAL); 2944cf49a43SJulian Elischer if (cfg->amru < NG_ASYNC_MIN_MRU 2954cf49a43SJulian Elischer || cfg->amru > NG_ASYNC_MAX_MRU 2964cf49a43SJulian Elischer || cfg->smru < NG_ASYNC_MIN_MRU 2974cf49a43SJulian Elischer || cfg->smru > NG_ASYNC_MAX_MRU) 2984cf49a43SJulian Elischer ERROUT(EINVAL); 2994cf49a43SJulian Elischer cfg->enabled = !!cfg->enabled; /* normalize */ 3004cf49a43SJulian Elischer if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */ 3014cf49a43SJulian Elischer MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru), 3029c8c302fSJulian Elischer M_NETGRAPH_ASYNC, M_NOWAIT); 3034cf49a43SJulian Elischer if (!buf) 3044cf49a43SJulian Elischer ERROUT(ENOMEM); 3059c8c302fSJulian Elischer FREE(sc->abuf, M_NETGRAPH_ASYNC); 3064cf49a43SJulian Elischer sc->abuf = buf; 3074cf49a43SJulian Elischer } 3084cf49a43SJulian Elischer if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */ 3094cf49a43SJulian Elischer MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru), 3109c8c302fSJulian Elischer M_NETGRAPH_ASYNC, M_NOWAIT); 3114cf49a43SJulian Elischer if (!buf) 3124cf49a43SJulian Elischer ERROUT(ENOMEM); 3139c8c302fSJulian Elischer FREE(sc->sbuf, M_NETGRAPH_ASYNC); 3144cf49a43SJulian Elischer sc->sbuf = buf; 3154cf49a43SJulian Elischer sc->amode = MODE_HUNT; 3164cf49a43SJulian Elischer sc->slen = 0; 3174cf49a43SJulian Elischer } 3184cf49a43SJulian Elischer if (!cfg->enabled) { 3194cf49a43SJulian Elischer sc->amode = MODE_HUNT; 3204cf49a43SJulian Elischer sc->slen = 0; 3214cf49a43SJulian Elischer } 3224cf49a43SJulian Elischer sc->cfg = *cfg; 3234cf49a43SJulian Elischer break; 3244cf49a43SJulian Elischer } 3254cf49a43SJulian Elischer case NGM_ASYNC_CMD_GET_CONFIG: 3264cf49a43SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT); 3274cf49a43SJulian Elischer if (!resp) 3284cf49a43SJulian Elischer ERROUT(ENOMEM); 3294cf49a43SJulian Elischer *((struct ng_async_cfg *) resp->data) = sc->cfg; 3304cf49a43SJulian Elischer break; 3314cf49a43SJulian Elischer default: 3324cf49a43SJulian Elischer ERROUT(EINVAL); 3334cf49a43SJulian Elischer } 3344cf49a43SJulian Elischer break; 3354cf49a43SJulian Elischer default: 3364cf49a43SJulian Elischer ERROUT(EINVAL); 3374cf49a43SJulian Elischer } 3384cf49a43SJulian Elischer done: 339069154d5SJulian Elischer NG_RESPOND_MSG(error, node, item, resp); 340069154d5SJulian Elischer NG_FREE_MSG(msg); 3414cf49a43SJulian Elischer return (error); 3424cf49a43SJulian Elischer } 3434cf49a43SJulian Elischer 3444cf49a43SJulian Elischer /* 3454cf49a43SJulian Elischer * Shutdown this node 3464cf49a43SJulian Elischer */ 3474cf49a43SJulian Elischer static int 3484cf49a43SJulian Elischer nga_shutdown(node_p node) 3494cf49a43SJulian Elischer { 35030400f03SJulian Elischer const sc_p sc = NG_NODE_PRIVATE(node); 3514cf49a43SJulian Elischer 3529c8c302fSJulian Elischer FREE(sc->abuf, M_NETGRAPH_ASYNC); 3539c8c302fSJulian Elischer FREE(sc->sbuf, M_NETGRAPH_ASYNC); 3544cf49a43SJulian Elischer bzero(sc, sizeof(*sc)); 3559c8c302fSJulian Elischer FREE(sc, M_NETGRAPH_ASYNC); 35630400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, NULL); 35730400f03SJulian Elischer NG_NODE_UNREF(node); 3584cf49a43SJulian Elischer return (0); 3594cf49a43SJulian Elischer } 3604cf49a43SJulian Elischer 3614cf49a43SJulian Elischer /* 3624cf49a43SJulian Elischer * Lose a hook. When both hooks go away, we disappear. 3634cf49a43SJulian Elischer */ 3644cf49a43SJulian Elischer static int 3654cf49a43SJulian Elischer nga_disconnect(hook_p hook) 3664cf49a43SJulian Elischer { 36730400f03SJulian Elischer const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 3684cf49a43SJulian Elischer hook_p *hookp; 3694cf49a43SJulian Elischer 3704cf49a43SJulian Elischer if (hook == sc->async) 3714cf49a43SJulian Elischer hookp = &sc->async; 3724cf49a43SJulian Elischer else if (hook == sc->sync) 3734cf49a43SJulian Elischer hookp = &sc->sync; 3744cf49a43SJulian Elischer else 3756e551fb6SDavid E. O'Brien panic(__func__); 3764cf49a43SJulian Elischer if (!*hookp) 3776e551fb6SDavid E. O'Brien panic("%s 2", __func__); 3784cf49a43SJulian Elischer *hookp = NULL; 3794cf49a43SJulian Elischer bzero(&sc->stats, sizeof(sc->stats)); 3804cf49a43SJulian Elischer sc->lasttime = 0; 38130400f03SJulian Elischer if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 38230400f03SJulian Elischer && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 38330400f03SJulian Elischer ng_rmnode_self(NG_HOOK_NODE(hook)); 3844cf49a43SJulian Elischer return (0); 3854cf49a43SJulian Elischer } 3864cf49a43SJulian Elischer 3874cf49a43SJulian Elischer /****************************************************************** 3884cf49a43SJulian Elischer INTERNAL HELPER STUFF 3894cf49a43SJulian Elischer ******************************************************************/ 3904cf49a43SJulian Elischer 3914cf49a43SJulian Elischer /* 3924cf49a43SJulian Elischer * Encode a byte into the async buffer 3934cf49a43SJulian Elischer */ 3945908d366SStefan Farfeleder static __inline void 3954cf49a43SJulian Elischer nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x) 3964cf49a43SJulian Elischer { 3974cf49a43SJulian Elischer *fcs = PPP_FCS(*fcs, x); 3984cf49a43SJulian Elischer if ((x < 32 && ((1 << x) & accm)) 3994cf49a43SJulian Elischer || (x == PPP_ESCAPE) 4004cf49a43SJulian Elischer || (x == PPP_FLAG)) { 4014cf49a43SJulian Elischer sc->abuf[(*len)++] = PPP_ESCAPE; 4024cf49a43SJulian Elischer x ^= PPP_TRANS; 4034cf49a43SJulian Elischer } 4044cf49a43SJulian Elischer sc->abuf[(*len)++] = x; 4054cf49a43SJulian Elischer } 4064cf49a43SJulian Elischer 4074cf49a43SJulian Elischer /* 408a8e9726dSArchie Cobbs * Receive incoming synchronous data. 4094cf49a43SJulian Elischer */ 4104cf49a43SJulian Elischer static int 411069154d5SJulian Elischer nga_rcv_sync(const sc_p sc, item_p item) 4124cf49a43SJulian Elischer { 413069154d5SJulian Elischer struct ifnet *rcvif; 41419a52c59SArchie Cobbs int alen, error = 0; 415a8e9726dSArchie Cobbs struct timeval time; 4164cf49a43SJulian Elischer u_int16_t fcs, fcs0; 417a8e9726dSArchie Cobbs u_int32_t accm; 418069154d5SJulian Elischer struct mbuf *m; 419069154d5SJulian Elischer 4204cf49a43SJulian Elischer 421a8e9726dSArchie Cobbs #define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x)) 4224cf49a43SJulian Elischer 423a8e9726dSArchie Cobbs /* Check for bypass mode */ 4244cf49a43SJulian Elischer if (!sc->cfg.enabled) { 42530400f03SJulian Elischer NG_FWD_ITEM_HOOK(error, item, sc->async ); 4264cf49a43SJulian Elischer return (error); 4274cf49a43SJulian Elischer } 428069154d5SJulian Elischer NGI_GET_M(item, m); 429069154d5SJulian Elischer 430069154d5SJulian Elischer rcvif = m->m_pkthdr.rcvif; 431a8e9726dSArchie Cobbs 43219a52c59SArchie Cobbs /* Get ACCM; special case LCP frames, which use full ACCM */ 433a8e9726dSArchie Cobbs accm = sc->cfg.accm; 43419a52c59SArchie Cobbs if (m->m_pkthdr.len >= 4) { 43519a52c59SArchie Cobbs static const u_char lcphdr[4] = { 43619a52c59SArchie Cobbs PPP_ALLSTATIONS, 43719a52c59SArchie Cobbs PPP_UI, 43819a52c59SArchie Cobbs (u_char)(PPP_LCP >> 8), 43919a52c59SArchie Cobbs (u_char)(PPP_LCP & 0xff) 44019a52c59SArchie Cobbs }; 44119a52c59SArchie Cobbs u_char buf[4]; 442a8e9726dSArchie Cobbs 44319a52c59SArchie Cobbs m_copydata(m, 0, 4, (caddr_t)buf); 44419a52c59SArchie Cobbs if (bcmp(buf, &lcphdr, 4) == 0) 445a8e9726dSArchie Cobbs accm = ~0; 446a8e9726dSArchie Cobbs } 447a8e9726dSArchie Cobbs 448a8e9726dSArchie Cobbs /* Check for overflow */ 4494cf49a43SJulian Elischer if (m->m_pkthdr.len > sc->cfg.smru) { 4504cf49a43SJulian Elischer sc->stats.syncOverflows++; 451069154d5SJulian Elischer NG_FREE_M(m); 452069154d5SJulian Elischer NG_FREE_ITEM(item); 4534cf49a43SJulian Elischer return (EMSGSIZE); 4544cf49a43SJulian Elischer } 455a8e9726dSArchie Cobbs 456a8e9726dSArchie Cobbs /* Update stats */ 4574cf49a43SJulian Elischer sc->stats.syncFrames++; 4584cf49a43SJulian Elischer sc->stats.syncOctets += m->m_pkthdr.len; 4594cf49a43SJulian Elischer 4604cf49a43SJulian Elischer /* Initialize async encoded version of input mbuf */ 4614cf49a43SJulian Elischer alen = 0; 4624cf49a43SJulian Elischer fcs = PPP_INITFCS; 4634cf49a43SJulian Elischer 4644cf49a43SJulian Elischer /* Add beginning sync flag if it's been long enough to need one */ 4654cf49a43SJulian Elischer getmicrotime(&time); 466a8e9726dSArchie Cobbs if (time.tv_sec >= sc->lasttime + 1) { 4674cf49a43SJulian Elischer sc->abuf[alen++] = PPP_FLAG; 4684cf49a43SJulian Elischer sc->lasttime = time.tv_sec; 4694cf49a43SJulian Elischer } 4704cf49a43SJulian Elischer 47119a52c59SArchie Cobbs /* Add packet payload */ 472a8e9726dSArchie Cobbs while (m != NULL) { 4734cf49a43SJulian Elischer while (m->m_len > 0) { 474a8e9726dSArchie Cobbs ADD_BYTE(*mtod(m, u_char *)); 4754cf49a43SJulian Elischer m->m_data++; 4764cf49a43SJulian Elischer m->m_len--; 4774cf49a43SJulian Elischer } 478ecde8f7cSMatthew Dillon m = m_free(m); 4794cf49a43SJulian Elischer } 4804cf49a43SJulian Elischer 4814cf49a43SJulian Elischer /* Add checksum and final sync flag */ 4824cf49a43SJulian Elischer fcs0 = fcs; 4834cf49a43SJulian Elischer ADD_BYTE(~fcs0 & 0xff); 4844cf49a43SJulian Elischer ADD_BYTE(~fcs0 >> 8); 4854cf49a43SJulian Elischer sc->abuf[alen++] = PPP_FLAG; 4864cf49a43SJulian Elischer 4874cf49a43SJulian Elischer /* Put frame in an mbuf and ship it off */ 488a8e9726dSArchie Cobbs if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) { 489069154d5SJulian Elischer NG_FREE_ITEM(item); 4904cf49a43SJulian Elischer error = ENOBUFS; 491069154d5SJulian Elischer } else { 492069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, sc->async, m); 493069154d5SJulian Elischer } 4944cf49a43SJulian Elischer return (error); 4954cf49a43SJulian Elischer } 4964cf49a43SJulian Elischer 4974cf49a43SJulian Elischer /* 4984cf49a43SJulian Elischer * Receive incoming asynchronous data 499a8e9726dSArchie Cobbs * XXX Technically, we should strip out incoming characters 500a8e9726dSArchie Cobbs * that are in our ACCM. Not sure if this is good or not. 5014cf49a43SJulian Elischer */ 5024cf49a43SJulian Elischer static int 503069154d5SJulian Elischer nga_rcv_async(const sc_p sc, item_p item) 5044cf49a43SJulian Elischer { 505069154d5SJulian Elischer struct ifnet *rcvif; 5064cf49a43SJulian Elischer int error; 507069154d5SJulian Elischer struct mbuf *m; 5084cf49a43SJulian Elischer 5094cf49a43SJulian Elischer if (!sc->cfg.enabled) { 51030400f03SJulian Elischer NG_FWD_ITEM_HOOK(error, item, sc->sync); 5114cf49a43SJulian Elischer return (error); 5124cf49a43SJulian Elischer } 513069154d5SJulian Elischer NGI_GET_M(item, m); 514069154d5SJulian Elischer rcvif = m->m_pkthdr.rcvif; 5154cf49a43SJulian Elischer while (m) { 5164cf49a43SJulian Elischer struct mbuf *n; 5174cf49a43SJulian Elischer 5184cf49a43SJulian Elischer for (; m->m_len > 0; m->m_data++, m->m_len--) { 5194cf49a43SJulian Elischer u_char ch = *mtod(m, u_char *); 5204cf49a43SJulian Elischer 5214cf49a43SJulian Elischer sc->stats.asyncOctets++; 5224cf49a43SJulian Elischer if (ch == PPP_FLAG) { /* Flag overrides everything */ 5234cf49a43SJulian Elischer int skip = 0; 5244cf49a43SJulian Elischer 5254cf49a43SJulian Elischer /* Check for runts */ 5264cf49a43SJulian Elischer if (sc->slen < 2) { 5274cf49a43SJulian Elischer if (sc->slen > 0) 5284cf49a43SJulian Elischer sc->stats.asyncRunts++; 5294cf49a43SJulian Elischer goto reset; 5304cf49a43SJulian Elischer } 5314cf49a43SJulian Elischer 5324cf49a43SJulian Elischer /* Verify CRC */ 5334cf49a43SJulian Elischer if (sc->fcs != PPP_GOODFCS) { 5344cf49a43SJulian Elischer sc->stats.asyncBadCheckSums++; 5354cf49a43SJulian Elischer goto reset; 5364cf49a43SJulian Elischer } 5374cf49a43SJulian Elischer sc->slen -= 2; 5384cf49a43SJulian Elischer 5394cf49a43SJulian Elischer /* Strip address and control fields */ 5404cf49a43SJulian Elischer if (sc->slen >= 2 5414cf49a43SJulian Elischer && sc->sbuf[0] == PPP_ALLSTATIONS 5424cf49a43SJulian Elischer && sc->sbuf[1] == PPP_UI) 5434cf49a43SJulian Elischer skip = 2; 5444cf49a43SJulian Elischer 5454cf49a43SJulian Elischer /* Check for frame too big */ 5464cf49a43SJulian Elischer if (sc->slen - skip > sc->cfg.amru) { 5474cf49a43SJulian Elischer sc->stats.asyncOverflows++; 5484cf49a43SJulian Elischer goto reset; 5494cf49a43SJulian Elischer } 5504cf49a43SJulian Elischer 5514cf49a43SJulian Elischer /* OK, ship it out */ 5524cf49a43SJulian Elischer if ((n = m_devget(sc->sbuf + skip, 553069154d5SJulian Elischer sc->slen - skip, 0, rcvif, NULL))) { 554069154d5SJulian Elischer if (item) { /* sets NULL -> item */ 555069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, 556069154d5SJulian Elischer sc->sync, n); 557069154d5SJulian Elischer } else { 558069154d5SJulian Elischer NG_SEND_DATA_ONLY(error, 559069154d5SJulian Elischer sc->sync ,n); 560069154d5SJulian Elischer } 561069154d5SJulian Elischer } 5624cf49a43SJulian Elischer sc->stats.asyncFrames++; 5634cf49a43SJulian Elischer reset: 5644cf49a43SJulian Elischer sc->amode = MODE_NORMAL; 5654cf49a43SJulian Elischer sc->fcs = PPP_INITFCS; 5664cf49a43SJulian Elischer sc->slen = 0; 5674cf49a43SJulian Elischer continue; 5684cf49a43SJulian Elischer } 5694cf49a43SJulian Elischer switch (sc->amode) { 5704cf49a43SJulian Elischer case MODE_NORMAL: 5714cf49a43SJulian Elischer if (ch == PPP_ESCAPE) { 5724cf49a43SJulian Elischer sc->amode = MODE_ESC; 5734cf49a43SJulian Elischer continue; 5744cf49a43SJulian Elischer } 5754cf49a43SJulian Elischer break; 5764cf49a43SJulian Elischer case MODE_ESC: 5774cf49a43SJulian Elischer ch ^= PPP_TRANS; 5784cf49a43SJulian Elischer sc->amode = MODE_NORMAL; 5794cf49a43SJulian Elischer break; 5804cf49a43SJulian Elischer case MODE_HUNT: 5814cf49a43SJulian Elischer default: 5824cf49a43SJulian Elischer continue; 5834cf49a43SJulian Elischer } 5844cf49a43SJulian Elischer 5854cf49a43SJulian Elischer /* Add byte to frame */ 5864cf49a43SJulian Elischer if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) { 5874cf49a43SJulian Elischer sc->stats.asyncOverflows++; 5884cf49a43SJulian Elischer sc->amode = MODE_HUNT; 5894cf49a43SJulian Elischer sc->slen = 0; 5904cf49a43SJulian Elischer } else { 5914cf49a43SJulian Elischer sc->sbuf[sc->slen++] = ch; 5924cf49a43SJulian Elischer sc->fcs = PPP_FCS(sc->fcs, ch); 5934cf49a43SJulian Elischer } 5944cf49a43SJulian Elischer } 595ecde8f7cSMatthew Dillon m = m_free(m); 5964cf49a43SJulian Elischer } 597069154d5SJulian Elischer if (item) 598069154d5SJulian Elischer NG_FREE_ITEM(item); 5994cf49a43SJulian Elischer return (0); 6004cf49a43SJulian Elischer } 6014cf49a43SJulian Elischer 6024cf49a43SJulian Elischer /* 6034cf49a43SJulian Elischer * CRC table 6044cf49a43SJulian Elischer * 6054cf49a43SJulian Elischer * Taken from RFC 1171 Appendix B 6064cf49a43SJulian Elischer */ 6074cf49a43SJulian Elischer static const u_int16_t fcstab[256] = { 6084cf49a43SJulian Elischer 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 6094cf49a43SJulian Elischer 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 6104cf49a43SJulian Elischer 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 6114cf49a43SJulian Elischer 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 6124cf49a43SJulian Elischer 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 6134cf49a43SJulian Elischer 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 6144cf49a43SJulian Elischer 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 6154cf49a43SJulian Elischer 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 6164cf49a43SJulian Elischer 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 6174cf49a43SJulian Elischer 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 6184cf49a43SJulian Elischer 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 6194cf49a43SJulian Elischer 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 6204cf49a43SJulian Elischer 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 6214cf49a43SJulian Elischer 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 6224cf49a43SJulian Elischer 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 6234cf49a43SJulian Elischer 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 6244cf49a43SJulian Elischer 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 6254cf49a43SJulian Elischer 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 6264cf49a43SJulian Elischer 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 6274cf49a43SJulian Elischer 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 6284cf49a43SJulian Elischer 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 6294cf49a43SJulian Elischer 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 6304cf49a43SJulian Elischer 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 6314cf49a43SJulian Elischer 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 6324cf49a43SJulian Elischer 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 6334cf49a43SJulian Elischer 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 6344cf49a43SJulian Elischer 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 6354cf49a43SJulian Elischer 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 6364cf49a43SJulian Elischer 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 6374cf49a43SJulian Elischer 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 6384cf49a43SJulian Elischer 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 6394cf49a43SJulian Elischer 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 6404cf49a43SJulian Elischer }; 641