ng_async.c revision 90227
152419Sjulian 252419Sjulian/* 352419Sjulian * ng_async.c 452419Sjulian * 552419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 652419Sjulian * All rights reserved. 752419Sjulian * 852419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 952419Sjulian * redistribution of this software, in source or object code forms, with or 1052419Sjulian * without modifications are expressly permitted by Whistle Communications; 1152419Sjulian * provided, however, that: 1252419Sjulian * 1. Any and all reproductions of the source or object code must include the 1352419Sjulian * copyright notice above and the following disclaimer of warranties; and 1452419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1552419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1652419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1752419Sjulian * such appears in the above copyright notice or in the software. 1852419Sjulian * 1952419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2052419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2152419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2252419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2352419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2452419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2552419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2652419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2752419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2852419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2952419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3052419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3152419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3252419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3352419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3452419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3552419Sjulian * OF SUCH DAMAGE. 3652419Sjulian * 3767506Sjulian * Author: Archie Cobbs <archie@freebsd.org> 3852419Sjulian * 3952419Sjulian * $FreeBSD: head/sys/netgraph/ng_async.c 90227 2002-02-05 02:00:56Z dillon $ 4052752Sjulian * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $ 4152419Sjulian */ 4252419Sjulian 4352419Sjulian/* 4452419Sjulian * This node type implements a PPP style sync <-> async converter. 4552419Sjulian * See RFC 1661 for details of how asynchronous encoding works. 4652419Sjulian */ 4752419Sjulian 4852419Sjulian#include <sys/param.h> 4952419Sjulian#include <sys/systm.h> 5052419Sjulian#include <sys/kernel.h> 5152419Sjulian#include <sys/mbuf.h> 5252419Sjulian#include <sys/malloc.h> 5352419Sjulian#include <sys/errno.h> 5452419Sjulian 5552419Sjulian#include <netgraph/ng_message.h> 5652419Sjulian#include <netgraph/netgraph.h> 5752419Sjulian#include <netgraph/ng_async.h> 5853913Sarchie#include <netgraph/ng_parse.h> 5952419Sjulian 6052419Sjulian#include <net/ppp_defs.h> 6152419Sjulian 6270870Sjulian#ifdef NG_SEPARATE_MALLOC 6370870SjulianMALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node "); 6470870Sjulian#else 6570870Sjulian#define M_NETGRAPH_ASYNC M_NETGRAPH 6670870Sjulian#endif 6770870Sjulian 6870870Sjulian 6952419Sjulian/* Async decode state */ 7052419Sjulian#define MODE_HUNT 0 7152419Sjulian#define MODE_NORMAL 1 7252419Sjulian#define MODE_ESC 2 7352419Sjulian 7452419Sjulian/* Private data structure */ 7553394Sarchiestruct ng_async_private { 7652419Sjulian node_p node; /* Our node */ 7752419Sjulian hook_p async; /* Asynchronous side */ 7852419Sjulian hook_p sync; /* Synchronous side */ 7952419Sjulian u_char amode; /* Async hunt/esape mode */ 8052419Sjulian u_int16_t fcs; /* Decoded async FCS (so far) */ 8152419Sjulian u_char *abuf; /* Buffer to encode sync into */ 8252419Sjulian u_char *sbuf; /* Buffer to decode async into */ 8352419Sjulian u_int slen; /* Length of data in sbuf */ 8452419Sjulian long lasttime; /* Time of last async packet sent */ 8552419Sjulian struct ng_async_cfg cfg; /* Configuration */ 8652419Sjulian struct ng_async_stat stats; /* Statistics */ 8752419Sjulian}; 8853394Sarchietypedef struct ng_async_private *sc_p; 8952419Sjulian 9052419Sjulian/* Useful macros */ 9152419Sjulian#define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10) 9252419Sjulian#define SYNC_BUF_SIZE(amru) ((amru) + 10) 9352419Sjulian#define ERROUT(x) do { error = (x); goto done; } while (0) 9452419Sjulian 9552419Sjulian/* Netgraph methods */ 9653913Sarchiestatic ng_constructor_t nga_constructor; 9752752Sjulianstatic ng_rcvdata_t nga_rcvdata; 9852752Sjulianstatic ng_rcvmsg_t nga_rcvmsg; 9952752Sjulianstatic ng_shutdown_t nga_shutdown; 10052752Sjulianstatic ng_newhook_t nga_newhook; 10152752Sjulianstatic ng_disconnect_t nga_disconnect; 10252419Sjulian 10352419Sjulian/* Helper stuff */ 10470700Sjulianstatic int nga_rcv_sync(const sc_p sc, item_p item); 10570700Sjulianstatic int nga_rcv_async(const sc_p sc, item_p item); 10652419Sjulian 10753913Sarchie/* Parse type for struct ng_async_cfg */ 10853913Sarchiestatic const struct ng_parse_struct_info 10953913Sarchie nga_config_type_info = NG_ASYNC_CONFIG_TYPE_INFO; 11053913Sarchiestatic const struct ng_parse_type nga_config_type = { 11153913Sarchie &ng_parse_struct_type, 11253913Sarchie &nga_config_type_info 11353913Sarchie}; 11453913Sarchie 11553913Sarchie/* Parse type for struct ng_async_stat */ 11653913Sarchiestatic const struct ng_parse_struct_info 11753913Sarchie nga_stats_type_info = NG_ASYNC_STATS_TYPE_INFO; 11853913Sarchiestatic const struct ng_parse_type nga_stats_type = { 11953913Sarchie &ng_parse_struct_type, 12053913Sarchie &nga_stats_type_info, 12153913Sarchie}; 12253913Sarchie 12353913Sarchie/* List of commands and how to convert arguments to/from ASCII */ 12453913Sarchiestatic const struct ng_cmdlist nga_cmdlist[] = { 12553913Sarchie { 12653913Sarchie NGM_ASYNC_COOKIE, 12753913Sarchie NGM_ASYNC_CMD_SET_CONFIG, 12853913Sarchie "setconfig", 12953913Sarchie &nga_config_type, 13053913Sarchie NULL 13153913Sarchie }, 13253913Sarchie { 13353913Sarchie NGM_ASYNC_COOKIE, 13453913Sarchie NGM_ASYNC_CMD_GET_CONFIG, 13553913Sarchie "getconfig", 13653913Sarchie NULL, 13753913Sarchie &nga_config_type 13853913Sarchie }, 13953913Sarchie { 14053913Sarchie NGM_ASYNC_COOKIE, 14153913Sarchie NGM_ASYNC_CMD_GET_STATS, 14253913Sarchie "getstats", 14353913Sarchie NULL, 14453913Sarchie &nga_stats_type 14553913Sarchie }, 14653913Sarchie { 14753913Sarchie NGM_ASYNC_COOKIE, 14853913Sarchie NGM_ASYNC_CMD_CLR_STATS, 14953913Sarchie "clrstats", 15053913Sarchie &nga_stats_type, 15153913Sarchie NULL 15253913Sarchie }, 15353913Sarchie { 0 } 15453913Sarchie}; 15553913Sarchie 15652419Sjulian/* Define the netgraph node type */ 15752419Sjulianstatic struct ng_type typestruct = { 15870159Sjulian NG_ABI_VERSION, 15952419Sjulian NG_ASYNC_NODE_TYPE, 16052419Sjulian NULL, 16152419Sjulian nga_constructor, 16252419Sjulian nga_rcvmsg, 16352419Sjulian nga_shutdown, 16452419Sjulian nga_newhook, 16552419Sjulian NULL, 16652419Sjulian NULL, 16752419Sjulian nga_rcvdata, 16853913Sarchie nga_disconnect, 16953913Sarchie nga_cmdlist 17052419Sjulian}; 17152419SjulianNETGRAPH_INIT(async, &typestruct); 17252419Sjulian 17352419Sjulian/* CRC table */ 17452419Sjulianstatic const u_int16_t fcstab[]; 17552419Sjulian 17652419Sjulian/****************************************************************** 17752419Sjulian NETGRAPH NODE METHODS 17852419Sjulian******************************************************************/ 17952419Sjulian 18052419Sjulian/* 18152419Sjulian * Initialize a new node 18252419Sjulian */ 18352419Sjulianstatic int 18470700Sjuliannga_constructor(node_p node) 18552419Sjulian{ 18652419Sjulian sc_p sc; 18752419Sjulian 18870870Sjulian MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH_ASYNC, M_NOWAIT | M_ZERO); 18952419Sjulian if (sc == NULL) 19052419Sjulian return (ENOMEM); 19152419Sjulian sc->amode = MODE_HUNT; 19252419Sjulian sc->cfg.accm = ~0; 19352419Sjulian sc->cfg.amru = NG_ASYNC_DEFAULT_MRU; 19452419Sjulian sc->cfg.smru = NG_ASYNC_DEFAULT_MRU; 19552419Sjulian MALLOC(sc->abuf, u_char *, 19670870Sjulian ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH_ASYNC, M_NOWAIT); 19752419Sjulian if (sc->abuf == NULL) 19852419Sjulian goto fail; 19952419Sjulian MALLOC(sc->sbuf, u_char *, 20070870Sjulian SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH_ASYNC, M_NOWAIT); 20152419Sjulian if (sc->sbuf == NULL) { 20270870Sjulian FREE(sc->abuf, M_NETGRAPH_ASYNC); 20352419Sjulianfail: 20470870Sjulian FREE(sc, M_NETGRAPH_ASYNC); 20552419Sjulian return (ENOMEM); 20652419Sjulian } 20770784Sjulian NG_NODE_SET_PRIVATE(node, sc); 20870700Sjulian sc->node = node; 20952419Sjulian return (0); 21052419Sjulian} 21152419Sjulian 21252419Sjulian/* 21352419Sjulian * Reserve a hook for a pending connection 21452419Sjulian */ 21552419Sjulianstatic int 21652419Sjuliannga_newhook(node_p node, hook_p hook, const char *name) 21752419Sjulian{ 21870784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 21952419Sjulian hook_p *hookp; 22052419Sjulian 22170700Sjulian if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) { 22270700Sjulian /* 22370700Sjulian * We use a static buffer here so only one packet 22470700Sjulian * at a time can be allowed to travel in this direction. 22570700Sjulian * Force Writer semantics. 22670700Sjulian */ 22770784Sjulian NG_HOOK_FORCE_WRITER(hook); 22852419Sjulian hookp = &sc->async; 22970700Sjulian } else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) { 23070700Sjulian /* 23170700Sjulian * We use a static state here so only one packet 23270700Sjulian * at a time can be allowed to travel in this direction. 23370700Sjulian * Force Writer semantics. 23470700Sjulian * Since we set this for both directions 23570700Sjulian * we might as well set it for the whole node 23670700Sjulian * bit I haven;t done that (yet). 23770700Sjulian */ 23870784Sjulian NG_HOOK_FORCE_WRITER(hook); 23952419Sjulian hookp = &sc->sync; 24070700Sjulian } else { 24152419Sjulian return (EINVAL); 24270700Sjulian } 24370700Sjulian if (*hookp) /* actually can't happen I think [JRE] */ 24452419Sjulian return (EISCONN); 24552419Sjulian *hookp = hook; 24652419Sjulian return (0); 24752419Sjulian} 24852419Sjulian 24952419Sjulian/* 25052419Sjulian * Receive incoming data 25152419Sjulian */ 25252419Sjulianstatic int 25370700Sjuliannga_rcvdata(hook_p hook, item_p item) 25452419Sjulian{ 25570784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 25652419Sjulian 25752419Sjulian if (hook == sc->sync) 25870700Sjulian return (nga_rcv_sync(sc, item)); 25952976Sarchie if (hook == sc->async) 26070700Sjulian return (nga_rcv_async(sc, item)); 26187599Sobrien panic(__func__); 26252419Sjulian} 26352419Sjulian 26452419Sjulian/* 26552419Sjulian * Receive incoming control message 26652419Sjulian */ 26752419Sjulianstatic int 26870700Sjuliannga_rcvmsg(node_p node, item_p item, hook_p lasthook) 26952419Sjulian{ 27070784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 27152419Sjulian struct ng_mesg *resp = NULL; 27252419Sjulian int error = 0; 27370700Sjulian struct ng_mesg *msg; 27470700Sjulian 27570700Sjulian NGI_GET_MSG(item, msg); 27652419Sjulian switch (msg->header.typecookie) { 27752419Sjulian case NGM_ASYNC_COOKIE: 27852419Sjulian switch (msg->header.cmd) { 27952419Sjulian case NGM_ASYNC_CMD_GET_STATS: 28052419Sjulian NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT); 28152419Sjulian if (resp == NULL) 28252419Sjulian ERROUT(ENOMEM); 28352419Sjulian *((struct ng_async_stat *) resp->data) = sc->stats; 28452419Sjulian break; 28552419Sjulian case NGM_ASYNC_CMD_CLR_STATS: 28652419Sjulian bzero(&sc->stats, sizeof(sc->stats)); 28752419Sjulian break; 28852419Sjulian case NGM_ASYNC_CMD_SET_CONFIG: 28952419Sjulian { 29052419Sjulian struct ng_async_cfg *const cfg = 29152419Sjulian (struct ng_async_cfg *) msg->data; 29252419Sjulian u_char *buf; 29352419Sjulian 29452419Sjulian if (msg->header.arglen != sizeof(*cfg)) 29552419Sjulian ERROUT(EINVAL); 29652419Sjulian if (cfg->amru < NG_ASYNC_MIN_MRU 29752419Sjulian || cfg->amru > NG_ASYNC_MAX_MRU 29852419Sjulian || cfg->smru < NG_ASYNC_MIN_MRU 29952419Sjulian || cfg->smru > NG_ASYNC_MAX_MRU) 30052419Sjulian ERROUT(EINVAL); 30152419Sjulian cfg->enabled = !!cfg->enabled; /* normalize */ 30252419Sjulian if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */ 30352419Sjulian MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru), 30470870Sjulian M_NETGRAPH_ASYNC, M_NOWAIT); 30552419Sjulian if (!buf) 30652419Sjulian ERROUT(ENOMEM); 30770870Sjulian FREE(sc->abuf, M_NETGRAPH_ASYNC); 30852419Sjulian sc->abuf = buf; 30952419Sjulian } 31052419Sjulian if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */ 31152419Sjulian MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru), 31270870Sjulian M_NETGRAPH_ASYNC, M_NOWAIT); 31352419Sjulian if (!buf) 31452419Sjulian ERROUT(ENOMEM); 31570870Sjulian FREE(sc->sbuf, M_NETGRAPH_ASYNC); 31652419Sjulian sc->sbuf = buf; 31752419Sjulian sc->amode = MODE_HUNT; 31852419Sjulian sc->slen = 0; 31952419Sjulian } 32052419Sjulian if (!cfg->enabled) { 32152419Sjulian sc->amode = MODE_HUNT; 32252419Sjulian sc->slen = 0; 32352419Sjulian } 32452419Sjulian sc->cfg = *cfg; 32552419Sjulian break; 32652419Sjulian } 32752419Sjulian case NGM_ASYNC_CMD_GET_CONFIG: 32852419Sjulian NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT); 32952419Sjulian if (!resp) 33052419Sjulian ERROUT(ENOMEM); 33152419Sjulian *((struct ng_async_cfg *) resp->data) = sc->cfg; 33252419Sjulian break; 33352419Sjulian default: 33452419Sjulian ERROUT(EINVAL); 33552419Sjulian } 33652419Sjulian break; 33752419Sjulian default: 33852419Sjulian ERROUT(EINVAL); 33952419Sjulian } 34052419Sjuliandone: 34170700Sjulian NG_RESPOND_MSG(error, node, item, resp); 34270700Sjulian NG_FREE_MSG(msg); 34352419Sjulian return (error); 34452419Sjulian} 34552419Sjulian 34652419Sjulian/* 34752419Sjulian * Shutdown this node 34852419Sjulian */ 34952419Sjulianstatic int 35052419Sjuliannga_shutdown(node_p node) 35152419Sjulian{ 35270784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 35352419Sjulian 35470870Sjulian FREE(sc->abuf, M_NETGRAPH_ASYNC); 35570870Sjulian FREE(sc->sbuf, M_NETGRAPH_ASYNC); 35652419Sjulian bzero(sc, sizeof(*sc)); 35770870Sjulian FREE(sc, M_NETGRAPH_ASYNC); 35870784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 35970784Sjulian NG_NODE_UNREF(node); 36052419Sjulian return (0); 36152419Sjulian} 36252419Sjulian 36352419Sjulian/* 36452419Sjulian * Lose a hook. When both hooks go away, we disappear. 36552419Sjulian */ 36652419Sjulianstatic int 36752419Sjuliannga_disconnect(hook_p hook) 36852419Sjulian{ 36970784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 37052419Sjulian hook_p *hookp; 37152419Sjulian 37252419Sjulian if (hook == sc->async) 37352419Sjulian hookp = &sc->async; 37452419Sjulian else if (hook == sc->sync) 37552419Sjulian hookp = &sc->sync; 37652419Sjulian else 37787599Sobrien panic(__func__); 37852419Sjulian if (!*hookp) 37987599Sobrien panic("%s 2", __func__); 38052419Sjulian *hookp = NULL; 38152419Sjulian bzero(&sc->stats, sizeof(sc->stats)); 38252419Sjulian sc->lasttime = 0; 38370784Sjulian if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 38470784Sjulian && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 38570784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 38652419Sjulian return (0); 38752419Sjulian} 38852419Sjulian 38952419Sjulian/****************************************************************** 39052419Sjulian INTERNAL HELPER STUFF 39152419Sjulian******************************************************************/ 39252419Sjulian 39352419Sjulian/* 39452419Sjulian * Encode a byte into the async buffer 39552419Sjulian */ 39652419Sjulianstatic __inline__ void 39752419Sjuliannga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x) 39852419Sjulian{ 39952419Sjulian *fcs = PPP_FCS(*fcs, x); 40052419Sjulian if ((x < 32 && ((1 << x) & accm)) 40152419Sjulian || (x == PPP_ESCAPE) 40252419Sjulian || (x == PPP_FLAG)) { 40352419Sjulian sc->abuf[(*len)++] = PPP_ESCAPE; 40452419Sjulian x ^= PPP_TRANS; 40552419Sjulian } 40652419Sjulian sc->abuf[(*len)++] = x; 40752419Sjulian} 40852419Sjulian 40952419Sjulian/* 41052976Sarchie * Receive incoming synchronous data. 41152419Sjulian */ 41252419Sjulianstatic int 41370700Sjuliannga_rcv_sync(const sc_p sc, item_p item) 41452419Sjulian{ 41570700Sjulian struct ifnet *rcvif; 41653394Sarchie int alen, error = 0; 41752976Sarchie struct timeval time; 41852419Sjulian u_int16_t fcs, fcs0; 41952976Sarchie u_int32_t accm; 42070700Sjulian struct mbuf *m; 42152419Sjulian 42270700Sjulian 42352976Sarchie#define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x)) 42452419Sjulian 42552976Sarchie /* Check for bypass mode */ 42652419Sjulian if (!sc->cfg.enabled) { 42770784Sjulian NG_FWD_ITEM_HOOK(error, item, sc->async ); 42852419Sjulian return (error); 42952419Sjulian } 43070700Sjulian NGI_GET_M(item, m); 43152976Sarchie 43270700Sjulian rcvif = m->m_pkthdr.rcvif; 43370700Sjulian 43453394Sarchie /* Get ACCM; special case LCP frames, which use full ACCM */ 43552976Sarchie accm = sc->cfg.accm; 43653394Sarchie if (m->m_pkthdr.len >= 4) { 43753394Sarchie static const u_char lcphdr[4] = { 43853394Sarchie PPP_ALLSTATIONS, 43953394Sarchie PPP_UI, 44053394Sarchie (u_char)(PPP_LCP >> 8), 44153394Sarchie (u_char)(PPP_LCP & 0xff) 44253394Sarchie }; 44353394Sarchie u_char buf[4]; 44452976Sarchie 44553394Sarchie m_copydata(m, 0, 4, (caddr_t)buf); 44653394Sarchie if (bcmp(buf, &lcphdr, 4) == 0) 44752976Sarchie accm = ~0; 44852976Sarchie } 44952976Sarchie 45052976Sarchie /* Check for overflow */ 45152419Sjulian if (m->m_pkthdr.len > sc->cfg.smru) { 45252419Sjulian sc->stats.syncOverflows++; 45370700Sjulian NG_FREE_M(m); 45470700Sjulian NG_FREE_ITEM(item); 45552419Sjulian return (EMSGSIZE); 45652419Sjulian } 45752976Sarchie 45852976Sarchie /* Update stats */ 45952419Sjulian sc->stats.syncFrames++; 46052419Sjulian sc->stats.syncOctets += m->m_pkthdr.len; 46152419Sjulian 46252419Sjulian /* Initialize async encoded version of input mbuf */ 46352419Sjulian alen = 0; 46452419Sjulian fcs = PPP_INITFCS; 46552419Sjulian 46652419Sjulian /* Add beginning sync flag if it's been long enough to need one */ 46752976Sarchie getmicrotime(&time); 46852976Sarchie if (time.tv_sec >= sc->lasttime + 1) { 46952976Sarchie sc->abuf[alen++] = PPP_FLAG; 47052976Sarchie sc->lasttime = time.tv_sec; 47152419Sjulian } 47252419Sjulian 47353394Sarchie /* Add packet payload */ 47452976Sarchie while (m != NULL) { 47552419Sjulian while (m->m_len > 0) { 47652976Sarchie ADD_BYTE(*mtod(m, u_char *)); 47752419Sjulian m->m_data++; 47852419Sjulian m->m_len--; 47952419Sjulian } 48090227Sdillon m = m_free(m); 48152419Sjulian } 48252419Sjulian 48352419Sjulian /* Add checksum and final sync flag */ 48452419Sjulian fcs0 = fcs; 48552419Sjulian ADD_BYTE(~fcs0 & 0xff); 48652419Sjulian ADD_BYTE(~fcs0 >> 8); 48752419Sjulian sc->abuf[alen++] = PPP_FLAG; 48852419Sjulian 48952419Sjulian /* Put frame in an mbuf and ship it off */ 49052976Sarchie if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) { 49170700Sjulian NG_FREE_ITEM(item); 49252419Sjulian error = ENOBUFS; 49370700Sjulian } else { 49470700Sjulian NG_FWD_NEW_DATA(error, item, sc->async, m); 49570700Sjulian } 49652419Sjulian return (error); 49752419Sjulian} 49852419Sjulian 49952419Sjulian/* 50052419Sjulian * Receive incoming asynchronous data 50152976Sarchie * XXX Technically, we should strip out incoming characters 50252976Sarchie * that are in our ACCM. Not sure if this is good or not. 50352419Sjulian */ 50452419Sjulianstatic int 50570700Sjuliannga_rcv_async(const sc_p sc, item_p item) 50652419Sjulian{ 50770700Sjulian struct ifnet *rcvif; 50852419Sjulian int error; 50970700Sjulian struct mbuf *m; 51052419Sjulian 51152419Sjulian if (!sc->cfg.enabled) { 51270784Sjulian NG_FWD_ITEM_HOOK(error, item, sc->sync); 51352419Sjulian return (error); 51452419Sjulian } 51570700Sjulian NGI_GET_M(item, m); 51670700Sjulian rcvif = m->m_pkthdr.rcvif; 51752419Sjulian while (m) { 51852419Sjulian struct mbuf *n; 51952419Sjulian 52052419Sjulian for (; m->m_len > 0; m->m_data++, m->m_len--) { 52152419Sjulian u_char ch = *mtod(m, u_char *); 52252419Sjulian 52352419Sjulian sc->stats.asyncOctets++; 52452419Sjulian if (ch == PPP_FLAG) { /* Flag overrides everything */ 52552419Sjulian int skip = 0; 52652419Sjulian 52752419Sjulian /* Check for runts */ 52852419Sjulian if (sc->slen < 2) { 52952419Sjulian if (sc->slen > 0) 53052419Sjulian sc->stats.asyncRunts++; 53152419Sjulian goto reset; 53252419Sjulian } 53352419Sjulian 53452419Sjulian /* Verify CRC */ 53552419Sjulian if (sc->fcs != PPP_GOODFCS) { 53652419Sjulian sc->stats.asyncBadCheckSums++; 53752419Sjulian goto reset; 53852419Sjulian } 53952419Sjulian sc->slen -= 2; 54052419Sjulian 54152419Sjulian /* Strip address and control fields */ 54252419Sjulian if (sc->slen >= 2 54352419Sjulian && sc->sbuf[0] == PPP_ALLSTATIONS 54452419Sjulian && sc->sbuf[1] == PPP_UI) 54552419Sjulian skip = 2; 54652419Sjulian 54752419Sjulian /* Check for frame too big */ 54852419Sjulian if (sc->slen - skip > sc->cfg.amru) { 54952419Sjulian sc->stats.asyncOverflows++; 55052419Sjulian goto reset; 55152419Sjulian } 55252419Sjulian 55352419Sjulian /* OK, ship it out */ 55452419Sjulian if ((n = m_devget(sc->sbuf + skip, 55570700Sjulian sc->slen - skip, 0, rcvif, NULL))) { 55670700Sjulian if (item) { /* sets NULL -> item */ 55770700Sjulian NG_FWD_NEW_DATA(error, item, 55870700Sjulian sc->sync, n); 55970700Sjulian } else { 56070700Sjulian NG_SEND_DATA_ONLY(error, 56170700Sjulian sc->sync ,n); 56270700Sjulian } 56370700Sjulian } 56452419Sjulian sc->stats.asyncFrames++; 56552419Sjulianreset: 56652419Sjulian sc->amode = MODE_NORMAL; 56752419Sjulian sc->fcs = PPP_INITFCS; 56852419Sjulian sc->slen = 0; 56952419Sjulian continue; 57052419Sjulian } 57152419Sjulian switch (sc->amode) { 57252419Sjulian case MODE_NORMAL: 57352419Sjulian if (ch == PPP_ESCAPE) { 57452419Sjulian sc->amode = MODE_ESC; 57552419Sjulian continue; 57652419Sjulian } 57752419Sjulian break; 57852419Sjulian case MODE_ESC: 57952419Sjulian ch ^= PPP_TRANS; 58052419Sjulian sc->amode = MODE_NORMAL; 58152419Sjulian break; 58252419Sjulian case MODE_HUNT: 58352419Sjulian default: 58452419Sjulian continue; 58552419Sjulian } 58652419Sjulian 58752419Sjulian /* Add byte to frame */ 58852419Sjulian if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) { 58952419Sjulian sc->stats.asyncOverflows++; 59052419Sjulian sc->amode = MODE_HUNT; 59152419Sjulian sc->slen = 0; 59252419Sjulian } else { 59352419Sjulian sc->sbuf[sc->slen++] = ch; 59452419Sjulian sc->fcs = PPP_FCS(sc->fcs, ch); 59552419Sjulian } 59652419Sjulian } 59790227Sdillon m = m_free(m); 59852419Sjulian } 59970700Sjulian if (item) 60070700Sjulian NG_FREE_ITEM(item); 60152419Sjulian return (0); 60252419Sjulian} 60352419Sjulian 60452419Sjulian/* 60552419Sjulian * CRC table 60652419Sjulian * 60752419Sjulian * Taken from RFC 1171 Appendix B 60852419Sjulian */ 60952419Sjulianstatic const u_int16_t fcstab[256] = { 61052419Sjulian 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 61152419Sjulian 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 61252419Sjulian 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 61352419Sjulian 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 61452419Sjulian 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 61552419Sjulian 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 61652419Sjulian 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 61752419Sjulian 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 61852419Sjulian 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 61952419Sjulian 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 62052419Sjulian 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 62152419Sjulian 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 62252419Sjulian 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 62352419Sjulian 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 62452419Sjulian 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 62552419Sjulian 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 62652419Sjulian 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 62752419Sjulian 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 62852419Sjulian 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 62952419Sjulian 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 63052419Sjulian 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 63152419Sjulian 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 63252419Sjulian 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 63352419Sjulian 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 63452419Sjulian 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 63552419Sjulian 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 63652419Sjulian 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 63752419Sjulian 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 63852419Sjulian 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 63952419Sjulian 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 64052419Sjulian 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 64152419Sjulian 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 64252419Sjulian}; 643