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>
3974f5c6aaSJulian Elischer * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $
404cf49a43SJulian Elischer */
414cf49a43SJulian Elischer
424cf49a43SJulian Elischer /*
434cf49a43SJulian Elischer * This node type implements a PPP style sync <-> async converter.
444cf49a43SJulian Elischer * See RFC 1661 for details of how asynchronous encoding works.
454cf49a43SJulian Elischer */
464cf49a43SJulian Elischer
474cf49a43SJulian Elischer #include <sys/param.h>
484cf49a43SJulian Elischer #include <sys/systm.h>
494cf49a43SJulian Elischer #include <sys/kernel.h>
504cf49a43SJulian Elischer #include <sys/mbuf.h>
514cf49a43SJulian Elischer #include <sys/malloc.h>
524cf49a43SJulian Elischer #include <sys/errno.h>
534cf49a43SJulian Elischer
544cf49a43SJulian Elischer #include <netgraph/ng_message.h>
554cf49a43SJulian Elischer #include <netgraph/netgraph.h>
564cf49a43SJulian Elischer #include <netgraph/ng_async.h>
57f8307e12SArchie Cobbs #include <netgraph/ng_parse.h>
584cf49a43SJulian Elischer
594cf49a43SJulian Elischer #include <net/ppp_defs.h>
604cf49a43SJulian Elischer
619c8c302fSJulian Elischer #ifdef NG_SEPARATE_MALLOC
62*d745c852SEd Schouten static MALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node");
639c8c302fSJulian Elischer #else
649c8c302fSJulian Elischer #define M_NETGRAPH_ASYNC M_NETGRAPH
659c8c302fSJulian Elischer #endif
669c8c302fSJulian Elischer
674cf49a43SJulian Elischer /* Async decode state */
684cf49a43SJulian Elischer #define MODE_HUNT 0
694cf49a43SJulian Elischer #define MODE_NORMAL 1
704cf49a43SJulian Elischer #define MODE_ESC 2
714cf49a43SJulian Elischer
724cf49a43SJulian Elischer /* Private data structure */
7319a52c59SArchie Cobbs struct ng_async_private {
744cf49a43SJulian Elischer node_p node; /* Our node */
754cf49a43SJulian Elischer hook_p async; /* Asynchronous side */
764cf49a43SJulian Elischer hook_p sync; /* Synchronous side */
774cf49a43SJulian Elischer u_char amode; /* Async hunt/esape mode */
784cf49a43SJulian Elischer u_int16_t fcs; /* Decoded async FCS (so far) */
794cf49a43SJulian Elischer u_char *abuf; /* Buffer to encode sync into */
804cf49a43SJulian Elischer u_char *sbuf; /* Buffer to decode async into */
814cf49a43SJulian Elischer u_int slen; /* Length of data in sbuf */
824cf49a43SJulian Elischer long lasttime; /* Time of last async packet sent */
834cf49a43SJulian Elischer struct ng_async_cfg cfg; /* Configuration */
844cf49a43SJulian Elischer struct ng_async_stat stats; /* Statistics */
854cf49a43SJulian Elischer };
8619a52c59SArchie Cobbs typedef struct ng_async_private *sc_p;
874cf49a43SJulian Elischer
884cf49a43SJulian Elischer /* Useful macros */
894cf49a43SJulian Elischer #define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10)
904cf49a43SJulian Elischer #define SYNC_BUF_SIZE(amru) ((amru) + 10)
914cf49a43SJulian Elischer #define ERROUT(x) do { error = (x); goto done; } while (0)
924cf49a43SJulian Elischer
934cf49a43SJulian Elischer /* Netgraph methods */
9474f5c6aaSJulian Elischer static ng_constructor_t nga_constructor;
9574f5c6aaSJulian Elischer static ng_rcvdata_t nga_rcvdata;
9674f5c6aaSJulian Elischer static ng_rcvmsg_t nga_rcvmsg;
9774f5c6aaSJulian Elischer static ng_shutdown_t nga_shutdown;
9874f5c6aaSJulian Elischer static ng_newhook_t nga_newhook;
9974f5c6aaSJulian Elischer static ng_disconnect_t nga_disconnect;
1004cf49a43SJulian Elischer
1014cf49a43SJulian Elischer /* Helper stuff */
102069154d5SJulian Elischer static int nga_rcv_sync(const sc_p sc, item_p item);
103069154d5SJulian Elischer static int nga_rcv_async(const sc_p sc, item_p item);
1044cf49a43SJulian Elischer
105f8307e12SArchie Cobbs /* Parse type for struct ng_async_cfg */
106f0184ff8SArchie Cobbs static const struct ng_parse_struct_field nga_config_type_fields[]
107f0184ff8SArchie Cobbs = NG_ASYNC_CONFIG_TYPE_INFO;
108f8307e12SArchie Cobbs static const struct ng_parse_type nga_config_type = {
109f8307e12SArchie Cobbs &ng_parse_struct_type,
110f0184ff8SArchie Cobbs &nga_config_type_fields
111f8307e12SArchie Cobbs };
112f8307e12SArchie Cobbs
113f8307e12SArchie Cobbs /* Parse type for struct ng_async_stat */
114f0184ff8SArchie Cobbs static const struct ng_parse_struct_field nga_stats_type_fields[]
115f0184ff8SArchie Cobbs = NG_ASYNC_STATS_TYPE_INFO;
116f8307e12SArchie Cobbs static const struct ng_parse_type nga_stats_type = {
117f8307e12SArchie Cobbs &ng_parse_struct_type,
118f0184ff8SArchie Cobbs &nga_stats_type_fields
119f8307e12SArchie Cobbs };
120f8307e12SArchie Cobbs
121f8307e12SArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */
122f8307e12SArchie Cobbs static const struct ng_cmdlist nga_cmdlist[] = {
123f8307e12SArchie Cobbs {
124f8307e12SArchie Cobbs NGM_ASYNC_COOKIE,
125f8307e12SArchie Cobbs NGM_ASYNC_CMD_SET_CONFIG,
126f8307e12SArchie Cobbs "setconfig",
127f8307e12SArchie Cobbs &nga_config_type,
128f8307e12SArchie Cobbs NULL
129f8307e12SArchie Cobbs },
130f8307e12SArchie Cobbs {
131f8307e12SArchie Cobbs NGM_ASYNC_COOKIE,
132f8307e12SArchie Cobbs NGM_ASYNC_CMD_GET_CONFIG,
133f8307e12SArchie Cobbs "getconfig",
134f8307e12SArchie Cobbs NULL,
135f8307e12SArchie Cobbs &nga_config_type
136f8307e12SArchie Cobbs },
137f8307e12SArchie Cobbs {
138f8307e12SArchie Cobbs NGM_ASYNC_COOKIE,
139f8307e12SArchie Cobbs NGM_ASYNC_CMD_GET_STATS,
140f8307e12SArchie Cobbs "getstats",
141f8307e12SArchie Cobbs NULL,
142f8307e12SArchie Cobbs &nga_stats_type
143f8307e12SArchie Cobbs },
144f8307e12SArchie Cobbs {
145f8307e12SArchie Cobbs NGM_ASYNC_COOKIE,
146f8307e12SArchie Cobbs NGM_ASYNC_CMD_CLR_STATS,
147f8307e12SArchie Cobbs "clrstats",
148f8307e12SArchie Cobbs &nga_stats_type,
149f8307e12SArchie Cobbs NULL
150f8307e12SArchie Cobbs },
151f8307e12SArchie Cobbs { 0 }
152f8307e12SArchie Cobbs };
153f8307e12SArchie Cobbs
1544cf49a43SJulian Elischer /* Define the netgraph node type */
1554cf49a43SJulian Elischer static struct ng_type typestruct = {
156f8aae777SJulian Elischer .version = NG_ABI_VERSION,
157f8aae777SJulian Elischer .name = NG_ASYNC_NODE_TYPE,
158f8aae777SJulian Elischer .constructor = nga_constructor,
159f8aae777SJulian Elischer .rcvmsg = nga_rcvmsg,
160f8aae777SJulian Elischer .shutdown = nga_shutdown,
161f8aae777SJulian Elischer .newhook = nga_newhook,
162f8aae777SJulian Elischer .rcvdata = nga_rcvdata,
163f8aae777SJulian Elischer .disconnect = nga_disconnect,
164f8aae777SJulian Elischer .cmdlist = nga_cmdlist
1654cf49a43SJulian Elischer };
1664cf49a43SJulian Elischer NETGRAPH_INIT(async, &typestruct);
1674cf49a43SJulian Elischer
1684cf49a43SJulian Elischer /* CRC table */
1694cf49a43SJulian Elischer static const u_int16_t fcstab[];
1704cf49a43SJulian Elischer
1714cf49a43SJulian Elischer /******************************************************************
1724cf49a43SJulian Elischer NETGRAPH NODE METHODS
1734cf49a43SJulian Elischer ******************************************************************/
1744cf49a43SJulian Elischer
1754cf49a43SJulian Elischer /*
1764cf49a43SJulian Elischer * Initialize a new node
1774cf49a43SJulian Elischer */
1784cf49a43SJulian Elischer static int
nga_constructor(node_p node)179069154d5SJulian Elischer nga_constructor(node_p node)
1804cf49a43SJulian Elischer {
1814cf49a43SJulian Elischer sc_p sc;
1824cf49a43SJulian Elischer
183674d86bfSGleb Smirnoff sc = malloc(sizeof(*sc), M_NETGRAPH_ASYNC, M_WAITOK | M_ZERO);
1844cf49a43SJulian Elischer sc->amode = MODE_HUNT;
1854cf49a43SJulian Elischer sc->cfg.accm = ~0;
1864cf49a43SJulian Elischer sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
1874cf49a43SJulian Elischer sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
188e11e3f18SDag-Erling Smørgrav sc->abuf = malloc(ASYNC_BUF_SIZE(sc->cfg.smru),
189674d86bfSGleb Smirnoff M_NETGRAPH_ASYNC, M_WAITOK);
190e11e3f18SDag-Erling Smørgrav sc->sbuf = malloc(SYNC_BUF_SIZE(sc->cfg.amru),
191674d86bfSGleb Smirnoff M_NETGRAPH_ASYNC, M_WAITOK);
19230400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, sc);
193069154d5SJulian Elischer sc->node = node;
1944cf49a43SJulian Elischer return (0);
1954cf49a43SJulian Elischer }
1964cf49a43SJulian Elischer
1974cf49a43SJulian Elischer /*
1984cf49a43SJulian Elischer * Reserve a hook for a pending connection
1994cf49a43SJulian Elischer */
2004cf49a43SJulian Elischer static int
nga_newhook(node_p node,hook_p hook,const char * name)2014cf49a43SJulian Elischer nga_newhook(node_p node, hook_p hook, const char *name)
2024cf49a43SJulian Elischer {
20330400f03SJulian Elischer const sc_p sc = NG_NODE_PRIVATE(node);
2044cf49a43SJulian Elischer hook_p *hookp;
2054cf49a43SJulian Elischer
206069154d5SJulian Elischer if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) {
207069154d5SJulian Elischer /*
208069154d5SJulian Elischer * We use a static buffer here so only one packet
209069154d5SJulian Elischer * at a time can be allowed to travel in this direction.
210069154d5SJulian Elischer * Force Writer semantics.
211069154d5SJulian Elischer */
21230400f03SJulian Elischer NG_HOOK_FORCE_WRITER(hook);
2134cf49a43SJulian Elischer hookp = &sc->async;
214069154d5SJulian Elischer } else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) {
215069154d5SJulian Elischer /*
216069154d5SJulian Elischer * We use a static state here so only one packet
217069154d5SJulian Elischer * at a time can be allowed to travel in this direction.
218069154d5SJulian Elischer * Force Writer semantics.
219069154d5SJulian Elischer * Since we set this for both directions
220069154d5SJulian Elischer * we might as well set it for the whole node
221069154d5SJulian Elischer * bit I haven;t done that (yet).
222069154d5SJulian Elischer */
22330400f03SJulian Elischer NG_HOOK_FORCE_WRITER(hook);
2244cf49a43SJulian Elischer hookp = &sc->sync;
225069154d5SJulian Elischer } else {
2264cf49a43SJulian Elischer return (EINVAL);
227069154d5SJulian Elischer }
228069154d5SJulian Elischer if (*hookp) /* actually can't happen I think [JRE] */
2294cf49a43SJulian Elischer return (EISCONN);
2304cf49a43SJulian Elischer *hookp = hook;
2314cf49a43SJulian Elischer return (0);
2324cf49a43SJulian Elischer }
2334cf49a43SJulian Elischer
2344cf49a43SJulian Elischer /*
2354cf49a43SJulian Elischer * Receive incoming data
2364cf49a43SJulian Elischer */
2374cf49a43SJulian Elischer static int
nga_rcvdata(hook_p hook,item_p item)238069154d5SJulian Elischer nga_rcvdata(hook_p hook, item_p item)
2394cf49a43SJulian Elischer {
24030400f03SJulian Elischer const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
2414cf49a43SJulian Elischer
2424cf49a43SJulian Elischer if (hook == sc->sync)
243069154d5SJulian Elischer return (nga_rcv_sync(sc, item));
244a8e9726dSArchie Cobbs if (hook == sc->async)
245069154d5SJulian Elischer return (nga_rcv_async(sc, item));
246d28843a4SRui Paulo panic("%s", __func__);
2474cf49a43SJulian Elischer }
2484cf49a43SJulian Elischer
2494cf49a43SJulian Elischer /*
2504cf49a43SJulian Elischer * Receive incoming control message
2514cf49a43SJulian Elischer */
2524cf49a43SJulian Elischer static int
nga_rcvmsg(node_p node,item_p item,hook_p lasthook)253069154d5SJulian Elischer nga_rcvmsg(node_p node, item_p item, hook_p lasthook)
2544cf49a43SJulian Elischer {
25530400f03SJulian Elischer const sc_p sc = NG_NODE_PRIVATE(node);
2564cf49a43SJulian Elischer struct ng_mesg *resp = NULL;
2574cf49a43SJulian Elischer int error = 0;
258069154d5SJulian Elischer struct ng_mesg *msg;
2594cf49a43SJulian Elischer
260069154d5SJulian Elischer NGI_GET_MSG(item, msg);
2614cf49a43SJulian Elischer switch (msg->header.typecookie) {
2624cf49a43SJulian Elischer case NGM_ASYNC_COOKIE:
2634cf49a43SJulian Elischer switch (msg->header.cmd) {
2644cf49a43SJulian Elischer case NGM_ASYNC_CMD_GET_STATS:
2654cf49a43SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
2664cf49a43SJulian Elischer if (resp == NULL)
2674cf49a43SJulian Elischer ERROUT(ENOMEM);
2684cf49a43SJulian Elischer *((struct ng_async_stat *) resp->data) = sc->stats;
2694cf49a43SJulian Elischer break;
2704cf49a43SJulian Elischer case NGM_ASYNC_CMD_CLR_STATS:
2714cf49a43SJulian Elischer bzero(&sc->stats, sizeof(sc->stats));
2724cf49a43SJulian Elischer break;
2734cf49a43SJulian Elischer case NGM_ASYNC_CMD_SET_CONFIG:
2744cf49a43SJulian Elischer {
2754cf49a43SJulian Elischer struct ng_async_cfg *const cfg =
2764cf49a43SJulian Elischer (struct ng_async_cfg *) msg->data;
2774cf49a43SJulian Elischer u_char *buf;
2784cf49a43SJulian Elischer
2794cf49a43SJulian Elischer if (msg->header.arglen != sizeof(*cfg))
2804cf49a43SJulian Elischer ERROUT(EINVAL);
2814cf49a43SJulian Elischer if (cfg->amru < NG_ASYNC_MIN_MRU
2824cf49a43SJulian Elischer || cfg->amru > NG_ASYNC_MAX_MRU
2834cf49a43SJulian Elischer || cfg->smru < NG_ASYNC_MIN_MRU
2844cf49a43SJulian Elischer || cfg->smru > NG_ASYNC_MAX_MRU)
2854cf49a43SJulian Elischer ERROUT(EINVAL);
2864cf49a43SJulian Elischer cfg->enabled = !!cfg->enabled; /* normalize */
2874cf49a43SJulian Elischer if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */
2881ede983cSDag-Erling Smørgrav buf = malloc(ASYNC_BUF_SIZE(cfg->smru),
2899c8c302fSJulian Elischer M_NETGRAPH_ASYNC, M_NOWAIT);
2904cf49a43SJulian Elischer if (!buf)
2914cf49a43SJulian Elischer ERROUT(ENOMEM);
2921ede983cSDag-Erling Smørgrav free(sc->abuf, M_NETGRAPH_ASYNC);
2934cf49a43SJulian Elischer sc->abuf = buf;
2944cf49a43SJulian Elischer }
2954cf49a43SJulian Elischer if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */
2961ede983cSDag-Erling Smørgrav buf = malloc(SYNC_BUF_SIZE(cfg->amru),
2979c8c302fSJulian Elischer M_NETGRAPH_ASYNC, M_NOWAIT);
2984cf49a43SJulian Elischer if (!buf)
2994cf49a43SJulian Elischer ERROUT(ENOMEM);
3001ede983cSDag-Erling Smørgrav free(sc->sbuf, M_NETGRAPH_ASYNC);
3014cf49a43SJulian Elischer sc->sbuf = buf;
3024cf49a43SJulian Elischer sc->amode = MODE_HUNT;
3034cf49a43SJulian Elischer sc->slen = 0;
3044cf49a43SJulian Elischer }
3054cf49a43SJulian Elischer if (!cfg->enabled) {
3064cf49a43SJulian Elischer sc->amode = MODE_HUNT;
3074cf49a43SJulian Elischer sc->slen = 0;
3084cf49a43SJulian Elischer }
3094cf49a43SJulian Elischer sc->cfg = *cfg;
3104cf49a43SJulian Elischer break;
3114cf49a43SJulian Elischer }
3124cf49a43SJulian Elischer case NGM_ASYNC_CMD_GET_CONFIG:
3134cf49a43SJulian Elischer NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
3144cf49a43SJulian Elischer if (!resp)
3154cf49a43SJulian Elischer ERROUT(ENOMEM);
3164cf49a43SJulian Elischer *((struct ng_async_cfg *) resp->data) = sc->cfg;
3174cf49a43SJulian Elischer break;
3184cf49a43SJulian Elischer default:
3194cf49a43SJulian Elischer ERROUT(EINVAL);
3204cf49a43SJulian Elischer }
3214cf49a43SJulian Elischer break;
3224cf49a43SJulian Elischer default:
3234cf49a43SJulian Elischer ERROUT(EINVAL);
3244cf49a43SJulian Elischer }
3254cf49a43SJulian Elischer done:
326069154d5SJulian Elischer NG_RESPOND_MSG(error, node, item, resp);
327069154d5SJulian Elischer NG_FREE_MSG(msg);
3284cf49a43SJulian Elischer return (error);
3294cf49a43SJulian Elischer }
3304cf49a43SJulian Elischer
3314cf49a43SJulian Elischer /*
3324cf49a43SJulian Elischer * Shutdown this node
3334cf49a43SJulian Elischer */
3344cf49a43SJulian Elischer static int
nga_shutdown(node_p node)3354cf49a43SJulian Elischer nga_shutdown(node_p node)
3364cf49a43SJulian Elischer {
33730400f03SJulian Elischer const sc_p sc = NG_NODE_PRIVATE(node);
3384cf49a43SJulian Elischer
3391ede983cSDag-Erling Smørgrav free(sc->abuf, M_NETGRAPH_ASYNC);
3401ede983cSDag-Erling Smørgrav free(sc->sbuf, M_NETGRAPH_ASYNC);
3414cf49a43SJulian Elischer bzero(sc, sizeof(*sc));
3421ede983cSDag-Erling Smørgrav free(sc, M_NETGRAPH_ASYNC);
34330400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, NULL);
34430400f03SJulian Elischer NG_NODE_UNREF(node);
3454cf49a43SJulian Elischer return (0);
3464cf49a43SJulian Elischer }
3474cf49a43SJulian Elischer
3484cf49a43SJulian Elischer /*
3494cf49a43SJulian Elischer * Lose a hook. When both hooks go away, we disappear.
3504cf49a43SJulian Elischer */
3514cf49a43SJulian Elischer static int
nga_disconnect(hook_p hook)3524cf49a43SJulian Elischer nga_disconnect(hook_p hook)
3534cf49a43SJulian Elischer {
35430400f03SJulian Elischer const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
3554cf49a43SJulian Elischer hook_p *hookp;
3564cf49a43SJulian Elischer
3574cf49a43SJulian Elischer if (hook == sc->async)
3584cf49a43SJulian Elischer hookp = &sc->async;
3594cf49a43SJulian Elischer else if (hook == sc->sync)
3604cf49a43SJulian Elischer hookp = &sc->sync;
3614cf49a43SJulian Elischer else
362d28843a4SRui Paulo panic("%s", __func__);
3634cf49a43SJulian Elischer if (!*hookp)
3646e551fb6SDavid E. O'Brien panic("%s 2", __func__);
3654cf49a43SJulian Elischer *hookp = NULL;
3664cf49a43SJulian Elischer bzero(&sc->stats, sizeof(sc->stats));
3674cf49a43SJulian Elischer sc->lasttime = 0;
36830400f03SJulian Elischer if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
36930400f03SJulian Elischer && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
37030400f03SJulian Elischer ng_rmnode_self(NG_HOOK_NODE(hook));
3714cf49a43SJulian Elischer return (0);
3724cf49a43SJulian Elischer }
3734cf49a43SJulian Elischer
3744cf49a43SJulian Elischer /******************************************************************
3754cf49a43SJulian Elischer INTERNAL HELPER STUFF
3764cf49a43SJulian Elischer ******************************************************************/
3774cf49a43SJulian Elischer
3784cf49a43SJulian Elischer /*
3794cf49a43SJulian Elischer * Encode a byte into the async buffer
3804cf49a43SJulian Elischer */
3815908d366SStefan Farfeleder static __inline void
nga_async_add(const sc_p sc,u_int16_t * fcs,u_int32_t accm,int * len,u_char x)3824cf49a43SJulian Elischer nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
3834cf49a43SJulian Elischer {
3844cf49a43SJulian Elischer *fcs = PPP_FCS(*fcs, x);
3854cf49a43SJulian Elischer if ((x < 32 && ((1 << x) & accm))
3864cf49a43SJulian Elischer || (x == PPP_ESCAPE)
3874cf49a43SJulian Elischer || (x == PPP_FLAG)) {
3884cf49a43SJulian Elischer sc->abuf[(*len)++] = PPP_ESCAPE;
3894cf49a43SJulian Elischer x ^= PPP_TRANS;
3904cf49a43SJulian Elischer }
3914cf49a43SJulian Elischer sc->abuf[(*len)++] = x;
3924cf49a43SJulian Elischer }
3934cf49a43SJulian Elischer
3944cf49a43SJulian Elischer /*
395a8e9726dSArchie Cobbs * Receive incoming synchronous data.
3964cf49a43SJulian Elischer */
3974cf49a43SJulian Elischer static int
nga_rcv_sync(const sc_p sc,item_p item)398069154d5SJulian Elischer nga_rcv_sync(const sc_p sc, item_p item)
3994cf49a43SJulian Elischer {
400069154d5SJulian Elischer struct ifnet *rcvif;
40119a52c59SArchie Cobbs int alen, error = 0;
402a8e9726dSArchie Cobbs struct timeval time;
4034cf49a43SJulian Elischer u_int16_t fcs, fcs0;
404a8e9726dSArchie Cobbs u_int32_t accm;
405069154d5SJulian Elischer struct mbuf *m;
406069154d5SJulian Elischer
407a8e9726dSArchie Cobbs #define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x))
4084cf49a43SJulian Elischer
409a8e9726dSArchie Cobbs /* Check for bypass mode */
4104cf49a43SJulian Elischer if (!sc->cfg.enabled) {
41130400f03SJulian Elischer NG_FWD_ITEM_HOOK(error, item, sc->async );
4124cf49a43SJulian Elischer return (error);
4134cf49a43SJulian Elischer }
414069154d5SJulian Elischer NGI_GET_M(item, m);
415069154d5SJulian Elischer
416069154d5SJulian Elischer rcvif = m->m_pkthdr.rcvif;
417a8e9726dSArchie Cobbs
41819a52c59SArchie Cobbs /* Get ACCM; special case LCP frames, which use full ACCM */
419a8e9726dSArchie Cobbs accm = sc->cfg.accm;
42019a52c59SArchie Cobbs if (m->m_pkthdr.len >= 4) {
42119a52c59SArchie Cobbs static const u_char lcphdr[4] = {
42219a52c59SArchie Cobbs PPP_ALLSTATIONS,
42319a52c59SArchie Cobbs PPP_UI,
42419a52c59SArchie Cobbs (u_char)(PPP_LCP >> 8),
42519a52c59SArchie Cobbs (u_char)(PPP_LCP & 0xff)
42619a52c59SArchie Cobbs };
42719a52c59SArchie Cobbs u_char buf[4];
428a8e9726dSArchie Cobbs
42919a52c59SArchie Cobbs m_copydata(m, 0, 4, (caddr_t)buf);
43019a52c59SArchie Cobbs if (bcmp(buf, &lcphdr, 4) == 0)
431a8e9726dSArchie Cobbs accm = ~0;
432a8e9726dSArchie Cobbs }
433a8e9726dSArchie Cobbs
434a8e9726dSArchie Cobbs /* Check for overflow */
4354cf49a43SJulian Elischer if (m->m_pkthdr.len > sc->cfg.smru) {
4364cf49a43SJulian Elischer sc->stats.syncOverflows++;
437069154d5SJulian Elischer NG_FREE_M(m);
438069154d5SJulian Elischer NG_FREE_ITEM(item);
4394cf49a43SJulian Elischer return (EMSGSIZE);
4404cf49a43SJulian Elischer }
441a8e9726dSArchie Cobbs
442a8e9726dSArchie Cobbs /* Update stats */
4434cf49a43SJulian Elischer sc->stats.syncFrames++;
4444cf49a43SJulian Elischer sc->stats.syncOctets += m->m_pkthdr.len;
4454cf49a43SJulian Elischer
4464cf49a43SJulian Elischer /* Initialize async encoded version of input mbuf */
4474cf49a43SJulian Elischer alen = 0;
4484cf49a43SJulian Elischer fcs = PPP_INITFCS;
4494cf49a43SJulian Elischer
4504cf49a43SJulian Elischer /* Add beginning sync flag if it's been long enough to need one */
4514cf49a43SJulian Elischer getmicrotime(&time);
452a8e9726dSArchie Cobbs if (time.tv_sec >= sc->lasttime + 1) {
4534cf49a43SJulian Elischer sc->abuf[alen++] = PPP_FLAG;
4544cf49a43SJulian Elischer sc->lasttime = time.tv_sec;
4554cf49a43SJulian Elischer }
4564cf49a43SJulian Elischer
45719a52c59SArchie Cobbs /* Add packet payload */
458a8e9726dSArchie Cobbs while (m != NULL) {
4594cf49a43SJulian Elischer while (m->m_len > 0) {
460a8e9726dSArchie Cobbs ADD_BYTE(*mtod(m, u_char *));
4614cf49a43SJulian Elischer m->m_data++;
4624cf49a43SJulian Elischer m->m_len--;
4634cf49a43SJulian Elischer }
464ecde8f7cSMatthew Dillon m = m_free(m);
4654cf49a43SJulian Elischer }
4664cf49a43SJulian Elischer
4674cf49a43SJulian Elischer /* Add checksum and final sync flag */
4684cf49a43SJulian Elischer fcs0 = fcs;
4694cf49a43SJulian Elischer ADD_BYTE(~fcs0 & 0xff);
4704cf49a43SJulian Elischer ADD_BYTE(~fcs0 >> 8);
4714cf49a43SJulian Elischer sc->abuf[alen++] = PPP_FLAG;
4724cf49a43SJulian Elischer
4734cf49a43SJulian Elischer /* Put frame in an mbuf and ship it off */
474a8e9726dSArchie Cobbs if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) {
475069154d5SJulian Elischer NG_FREE_ITEM(item);
4764cf49a43SJulian Elischer error = ENOBUFS;
477069154d5SJulian Elischer } else {
478069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item, sc->async, m);
479069154d5SJulian Elischer }
4804cf49a43SJulian Elischer return (error);
4814cf49a43SJulian Elischer }
4824cf49a43SJulian Elischer
4834cf49a43SJulian Elischer /*
4844cf49a43SJulian Elischer * Receive incoming asynchronous data
485a8e9726dSArchie Cobbs * XXX Technically, we should strip out incoming characters
486a8e9726dSArchie Cobbs * that are in our ACCM. Not sure if this is good or not.
4874cf49a43SJulian Elischer */
4884cf49a43SJulian Elischer static int
nga_rcv_async(const sc_p sc,item_p item)489069154d5SJulian Elischer nga_rcv_async(const sc_p sc, item_p item)
4904cf49a43SJulian Elischer {
491069154d5SJulian Elischer struct ifnet *rcvif;
4924cf49a43SJulian Elischer int error;
493069154d5SJulian Elischer struct mbuf *m;
4944cf49a43SJulian Elischer
4954cf49a43SJulian Elischer if (!sc->cfg.enabled) {
49630400f03SJulian Elischer NG_FWD_ITEM_HOOK(error, item, sc->sync);
4974cf49a43SJulian Elischer return (error);
4984cf49a43SJulian Elischer }
499069154d5SJulian Elischer NGI_GET_M(item, m);
500069154d5SJulian Elischer rcvif = m->m_pkthdr.rcvif;
5014cf49a43SJulian Elischer while (m) {
5024cf49a43SJulian Elischer struct mbuf *n;
5034cf49a43SJulian Elischer
5044cf49a43SJulian Elischer for (; m->m_len > 0; m->m_data++, m->m_len--) {
5054cf49a43SJulian Elischer u_char ch = *mtod(m, u_char *);
5064cf49a43SJulian Elischer
5074cf49a43SJulian Elischer sc->stats.asyncOctets++;
5084cf49a43SJulian Elischer if (ch == PPP_FLAG) { /* Flag overrides everything */
5094cf49a43SJulian Elischer int skip = 0;
5104cf49a43SJulian Elischer
5114cf49a43SJulian Elischer /* Check for runts */
5124cf49a43SJulian Elischer if (sc->slen < 2) {
5134cf49a43SJulian Elischer if (sc->slen > 0)
5144cf49a43SJulian Elischer sc->stats.asyncRunts++;
5154cf49a43SJulian Elischer goto reset;
5164cf49a43SJulian Elischer }
5174cf49a43SJulian Elischer
5184cf49a43SJulian Elischer /* Verify CRC */
5194cf49a43SJulian Elischer if (sc->fcs != PPP_GOODFCS) {
5204cf49a43SJulian Elischer sc->stats.asyncBadCheckSums++;
5214cf49a43SJulian Elischer goto reset;
5224cf49a43SJulian Elischer }
5234cf49a43SJulian Elischer sc->slen -= 2;
5244cf49a43SJulian Elischer
5254cf49a43SJulian Elischer /* Strip address and control fields */
5264cf49a43SJulian Elischer if (sc->slen >= 2
5274cf49a43SJulian Elischer && sc->sbuf[0] == PPP_ALLSTATIONS
5284cf49a43SJulian Elischer && sc->sbuf[1] == PPP_UI)
5294cf49a43SJulian Elischer skip = 2;
5304cf49a43SJulian Elischer
5314cf49a43SJulian Elischer /* Check for frame too big */
5324cf49a43SJulian Elischer if (sc->slen - skip > sc->cfg.amru) {
5334cf49a43SJulian Elischer sc->stats.asyncOverflows++;
5344cf49a43SJulian Elischer goto reset;
5354cf49a43SJulian Elischer }
5364cf49a43SJulian Elischer
5374cf49a43SJulian Elischer /* OK, ship it out */
5384cf49a43SJulian Elischer if ((n = m_devget(sc->sbuf + skip,
539069154d5SJulian Elischer sc->slen - skip, 0, rcvif, NULL))) {
540069154d5SJulian Elischer if (item) { /* sets NULL -> item */
541069154d5SJulian Elischer NG_FWD_NEW_DATA(error, item,
542069154d5SJulian Elischer sc->sync, n);
543069154d5SJulian Elischer } else {
544069154d5SJulian Elischer NG_SEND_DATA_ONLY(error,
545069154d5SJulian Elischer sc->sync ,n);
546069154d5SJulian Elischer }
547069154d5SJulian Elischer }
5484cf49a43SJulian Elischer sc->stats.asyncFrames++;
5494cf49a43SJulian Elischer reset:
5504cf49a43SJulian Elischer sc->amode = MODE_NORMAL;
5514cf49a43SJulian Elischer sc->fcs = PPP_INITFCS;
5524cf49a43SJulian Elischer sc->slen = 0;
5534cf49a43SJulian Elischer continue;
5544cf49a43SJulian Elischer }
5554cf49a43SJulian Elischer switch (sc->amode) {
5564cf49a43SJulian Elischer case MODE_NORMAL:
5574cf49a43SJulian Elischer if (ch == PPP_ESCAPE) {
5584cf49a43SJulian Elischer sc->amode = MODE_ESC;
5594cf49a43SJulian Elischer continue;
5604cf49a43SJulian Elischer }
5614cf49a43SJulian Elischer break;
5624cf49a43SJulian Elischer case MODE_ESC:
5634cf49a43SJulian Elischer ch ^= PPP_TRANS;
5644cf49a43SJulian Elischer sc->amode = MODE_NORMAL;
5654cf49a43SJulian Elischer break;
5664cf49a43SJulian Elischer case MODE_HUNT:
5674cf49a43SJulian Elischer default:
5684cf49a43SJulian Elischer continue;
5694cf49a43SJulian Elischer }
5704cf49a43SJulian Elischer
5714cf49a43SJulian Elischer /* Add byte to frame */
5724cf49a43SJulian Elischer if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
5734cf49a43SJulian Elischer sc->stats.asyncOverflows++;
5744cf49a43SJulian Elischer sc->amode = MODE_HUNT;
5754cf49a43SJulian Elischer sc->slen = 0;
5764cf49a43SJulian Elischer } else {
5774cf49a43SJulian Elischer sc->sbuf[sc->slen++] = ch;
5784cf49a43SJulian Elischer sc->fcs = PPP_FCS(sc->fcs, ch);
5794cf49a43SJulian Elischer }
5804cf49a43SJulian Elischer }
581ecde8f7cSMatthew Dillon m = m_free(m);
5824cf49a43SJulian Elischer }
583069154d5SJulian Elischer if (item)
584069154d5SJulian Elischer NG_FREE_ITEM(item);
5854cf49a43SJulian Elischer return (0);
5864cf49a43SJulian Elischer }
5874cf49a43SJulian Elischer
5884cf49a43SJulian Elischer /*
5894cf49a43SJulian Elischer * CRC table
5904cf49a43SJulian Elischer *
5914cf49a43SJulian Elischer * Taken from RFC 1171 Appendix B
5924cf49a43SJulian Elischer */
5934cf49a43SJulian Elischer static const u_int16_t fcstab[256] = {
5944cf49a43SJulian Elischer 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
5954cf49a43SJulian Elischer 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
5964cf49a43SJulian Elischer 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
5974cf49a43SJulian Elischer 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
5984cf49a43SJulian Elischer 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
5994cf49a43SJulian Elischer 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
6004cf49a43SJulian Elischer 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
6014cf49a43SJulian Elischer 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
6024cf49a43SJulian Elischer 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
6034cf49a43SJulian Elischer 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
6044cf49a43SJulian Elischer 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
6054cf49a43SJulian Elischer 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
6064cf49a43SJulian Elischer 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
6074cf49a43SJulian Elischer 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
6084cf49a43SJulian Elischer 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
6094cf49a43SJulian Elischer 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
6104cf49a43SJulian Elischer 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
6114cf49a43SJulian Elischer 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
6124cf49a43SJulian Elischer 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
6134cf49a43SJulian Elischer 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
6144cf49a43SJulian Elischer 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
6154cf49a43SJulian Elischer 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
6164cf49a43SJulian Elischer 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
6174cf49a43SJulian Elischer 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
6184cf49a43SJulian Elischer 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
6194cf49a43SJulian Elischer 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
6204cf49a43SJulian Elischer 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
6214cf49a43SJulian Elischer 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
6224cf49a43SJulian Elischer 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
6234cf49a43SJulian Elischer 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
6244cf49a43SJulian Elischer 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
6254cf49a43SJulian Elischer 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
6264cf49a43SJulian Elischer };
627