ng_async.c revision 213794
152419Sjulian/* 252419Sjulian * ng_async.c 3139823Simp */ 4139823Simp 5139823Simp/*- 652419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 752419Sjulian * All rights reserved. 852419Sjulian * 952419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 1052419Sjulian * redistribution of this software, in source or object code forms, with or 1152419Sjulian * without modifications are expressly permitted by Whistle Communications; 1252419Sjulian * provided, however, that: 1352419Sjulian * 1. Any and all reproductions of the source or object code must include the 1452419Sjulian * copyright notice above and the following disclaimer of warranties; and 1552419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1652419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1752419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1852419Sjulian * such appears in the above copyright notice or in the software. 1952419Sjulian * 2052419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2152419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2252419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2352419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2452419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2552419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2652419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2752419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2852419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2952419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3052419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3152419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3252419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3352419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3452419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3552419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3652419Sjulian * OF SUCH DAMAGE. 3752419Sjulian * 3867506Sjulian * Author: Archie Cobbs <archie@freebsd.org> 3952419Sjulian * 4052419Sjulian * $FreeBSD: head/sys/netgraph/ng_async.c 213794 2010-10-13 17:21:21Z rpaulo $ 4152752Sjulian * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $ 4252419Sjulian */ 4352419Sjulian 4452419Sjulian/* 4552419Sjulian * This node type implements a PPP style sync <-> async converter. 4652419Sjulian * See RFC 1661 for details of how asynchronous encoding works. 4752419Sjulian */ 4852419Sjulian 4952419Sjulian#include <sys/param.h> 5052419Sjulian#include <sys/systm.h> 5152419Sjulian#include <sys/kernel.h> 5252419Sjulian#include <sys/mbuf.h> 5352419Sjulian#include <sys/malloc.h> 5452419Sjulian#include <sys/errno.h> 5552419Sjulian 5652419Sjulian#include <netgraph/ng_message.h> 5752419Sjulian#include <netgraph/netgraph.h> 5852419Sjulian#include <netgraph/ng_async.h> 5953913Sarchie#include <netgraph/ng_parse.h> 6052419Sjulian 6152419Sjulian#include <net/ppp_defs.h> 6252419Sjulian 6370870Sjulian#ifdef NG_SEPARATE_MALLOC 6470870SjulianMALLOC_DEFINE(M_NETGRAPH_ASYNC, "netgraph_async", "netgraph async node "); 6570870Sjulian#else 6670870Sjulian#define M_NETGRAPH_ASYNC M_NETGRAPH 6770870Sjulian#endif 6870870Sjulian 6970870Sjulian 7052419Sjulian/* Async decode state */ 7152419Sjulian#define MODE_HUNT 0 7252419Sjulian#define MODE_NORMAL 1 7352419Sjulian#define MODE_ESC 2 7452419Sjulian 7552419Sjulian/* Private data structure */ 7653394Sarchiestruct ng_async_private { 7752419Sjulian node_p node; /* Our node */ 7852419Sjulian hook_p async; /* Asynchronous side */ 7952419Sjulian hook_p sync; /* Synchronous side */ 8052419Sjulian u_char amode; /* Async hunt/esape mode */ 8152419Sjulian u_int16_t fcs; /* Decoded async FCS (so far) */ 8252419Sjulian u_char *abuf; /* Buffer to encode sync into */ 8352419Sjulian u_char *sbuf; /* Buffer to decode async into */ 8452419Sjulian u_int slen; /* Length of data in sbuf */ 8552419Sjulian long lasttime; /* Time of last async packet sent */ 8652419Sjulian struct ng_async_cfg cfg; /* Configuration */ 8752419Sjulian struct ng_async_stat stats; /* Statistics */ 8852419Sjulian}; 8953394Sarchietypedef struct ng_async_private *sc_p; 9052419Sjulian 9152419Sjulian/* Useful macros */ 9252419Sjulian#define ASYNC_BUF_SIZE(smru) (2 * (smru) + 10) 9352419Sjulian#define SYNC_BUF_SIZE(amru) ((amru) + 10) 9452419Sjulian#define ERROUT(x) do { error = (x); goto done; } while (0) 9552419Sjulian 9652419Sjulian/* Netgraph methods */ 9753913Sarchiestatic ng_constructor_t nga_constructor; 9852752Sjulianstatic ng_rcvdata_t nga_rcvdata; 9952752Sjulianstatic ng_rcvmsg_t nga_rcvmsg; 10052752Sjulianstatic ng_shutdown_t nga_shutdown; 10152752Sjulianstatic ng_newhook_t nga_newhook; 10252752Sjulianstatic ng_disconnect_t nga_disconnect; 10352419Sjulian 10452419Sjulian/* Helper stuff */ 10570700Sjulianstatic int nga_rcv_sync(const sc_p sc, item_p item); 10670700Sjulianstatic int nga_rcv_async(const sc_p sc, item_p item); 10752419Sjulian 10853913Sarchie/* Parse type for struct ng_async_cfg */ 10997685Sarchiestatic const struct ng_parse_struct_field nga_config_type_fields[] 11097685Sarchie = NG_ASYNC_CONFIG_TYPE_INFO; 11153913Sarchiestatic const struct ng_parse_type nga_config_type = { 11253913Sarchie &ng_parse_struct_type, 11397685Sarchie &nga_config_type_fields 11453913Sarchie}; 11553913Sarchie 11653913Sarchie/* Parse type for struct ng_async_stat */ 11797685Sarchiestatic const struct ng_parse_struct_field nga_stats_type_fields[] 11897685Sarchie = NG_ASYNC_STATS_TYPE_INFO; 11953913Sarchiestatic const struct ng_parse_type nga_stats_type = { 12053913Sarchie &ng_parse_struct_type, 12197685Sarchie &nga_stats_type_fields 12253913Sarchie}; 12353913Sarchie 12453913Sarchie/* List of commands and how to convert arguments to/from ASCII */ 12553913Sarchiestatic const struct ng_cmdlist nga_cmdlist[] = { 12653913Sarchie { 12753913Sarchie NGM_ASYNC_COOKIE, 12853913Sarchie NGM_ASYNC_CMD_SET_CONFIG, 12953913Sarchie "setconfig", 13053913Sarchie &nga_config_type, 13153913Sarchie NULL 13253913Sarchie }, 13353913Sarchie { 13453913Sarchie NGM_ASYNC_COOKIE, 13553913Sarchie NGM_ASYNC_CMD_GET_CONFIG, 13653913Sarchie "getconfig", 13753913Sarchie NULL, 13853913Sarchie &nga_config_type 13953913Sarchie }, 14053913Sarchie { 14153913Sarchie NGM_ASYNC_COOKIE, 14253913Sarchie NGM_ASYNC_CMD_GET_STATS, 14353913Sarchie "getstats", 14453913Sarchie NULL, 14553913Sarchie &nga_stats_type 14653913Sarchie }, 14753913Sarchie { 14853913Sarchie NGM_ASYNC_COOKIE, 14953913Sarchie NGM_ASYNC_CMD_CLR_STATS, 15053913Sarchie "clrstats", 15153913Sarchie &nga_stats_type, 15253913Sarchie NULL 15353913Sarchie }, 15453913Sarchie { 0 } 15553913Sarchie}; 15653913Sarchie 15752419Sjulian/* Define the netgraph node type */ 15852419Sjulianstatic struct ng_type typestruct = { 159129823Sjulian .version = NG_ABI_VERSION, 160129823Sjulian .name = NG_ASYNC_NODE_TYPE, 161129823Sjulian .constructor = nga_constructor, 162129823Sjulian .rcvmsg = nga_rcvmsg, 163129823Sjulian .shutdown = nga_shutdown, 164129823Sjulian .newhook = nga_newhook, 165129823Sjulian .rcvdata = nga_rcvdata, 166129823Sjulian .disconnect = nga_disconnect, 167129823Sjulian .cmdlist = nga_cmdlist 16852419Sjulian}; 16952419SjulianNETGRAPH_INIT(async, &typestruct); 17052419Sjulian 17152419Sjulian/* CRC table */ 17252419Sjulianstatic const u_int16_t fcstab[]; 17352419Sjulian 17452419Sjulian/****************************************************************** 17552419Sjulian NETGRAPH NODE METHODS 17652419Sjulian******************************************************************/ 17752419Sjulian 17852419Sjulian/* 17952419Sjulian * Initialize a new node 18052419Sjulian */ 18152419Sjulianstatic int 18270700Sjuliannga_constructor(node_p node) 18352419Sjulian{ 18452419Sjulian sc_p sc; 18552419Sjulian 186184205Sdes sc = malloc(sizeof(*sc), M_NETGRAPH_ASYNC, M_NOWAIT | M_ZERO); 18752419Sjulian if (sc == NULL) 18852419Sjulian return (ENOMEM); 18952419Sjulian sc->amode = MODE_HUNT; 19052419Sjulian sc->cfg.accm = ~0; 19152419Sjulian sc->cfg.amru = NG_ASYNC_DEFAULT_MRU; 19252419Sjulian sc->cfg.smru = NG_ASYNC_DEFAULT_MRU; 193184214Sdes sc->abuf = malloc(ASYNC_BUF_SIZE(sc->cfg.smru), 194184214Sdes M_NETGRAPH_ASYNC, M_NOWAIT); 19552419Sjulian if (sc->abuf == NULL) 19652419Sjulian goto fail; 197184214Sdes sc->sbuf = malloc(SYNC_BUF_SIZE(sc->cfg.amru), 198184214Sdes M_NETGRAPH_ASYNC, M_NOWAIT); 19952419Sjulian if (sc->sbuf == NULL) { 200184205Sdes free(sc->abuf, M_NETGRAPH_ASYNC); 20152419Sjulianfail: 202184205Sdes free(sc, M_NETGRAPH_ASYNC); 20352419Sjulian return (ENOMEM); 20452419Sjulian } 20570784Sjulian NG_NODE_SET_PRIVATE(node, sc); 20670700Sjulian sc->node = node; 20752419Sjulian return (0); 20852419Sjulian} 20952419Sjulian 21052419Sjulian/* 21152419Sjulian * Reserve a hook for a pending connection 21252419Sjulian */ 21352419Sjulianstatic int 21452419Sjuliannga_newhook(node_p node, hook_p hook, const char *name) 21552419Sjulian{ 21670784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 21752419Sjulian hook_p *hookp; 21852419Sjulian 21970700Sjulian if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) { 22070700Sjulian /* 22170700Sjulian * We use a static buffer here so only one packet 22270700Sjulian * at a time can be allowed to travel in this direction. 22370700Sjulian * Force Writer semantics. 22470700Sjulian */ 22570784Sjulian NG_HOOK_FORCE_WRITER(hook); 22652419Sjulian hookp = &sc->async; 22770700Sjulian } else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) { 22870700Sjulian /* 22970700Sjulian * We use a static state here so only one packet 23070700Sjulian * at a time can be allowed to travel in this direction. 23170700Sjulian * Force Writer semantics. 23270700Sjulian * Since we set this for both directions 23370700Sjulian * we might as well set it for the whole node 23470700Sjulian * bit I haven;t done that (yet). 23570700Sjulian */ 23670784Sjulian NG_HOOK_FORCE_WRITER(hook); 23752419Sjulian hookp = &sc->sync; 23870700Sjulian } else { 23952419Sjulian return (EINVAL); 24070700Sjulian } 24170700Sjulian if (*hookp) /* actually can't happen I think [JRE] */ 24252419Sjulian return (EISCONN); 24352419Sjulian *hookp = hook; 24452419Sjulian return (0); 24552419Sjulian} 24652419Sjulian 24752419Sjulian/* 24852419Sjulian * Receive incoming data 24952419Sjulian */ 25052419Sjulianstatic int 25170700Sjuliannga_rcvdata(hook_p hook, item_p item) 25252419Sjulian{ 25370784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 25452419Sjulian 25552419Sjulian if (hook == sc->sync) 25670700Sjulian return (nga_rcv_sync(sc, item)); 25752976Sarchie if (hook == sc->async) 25870700Sjulian return (nga_rcv_async(sc, item)); 259213794Srpaulo panic("%s", __func__); 26052419Sjulian} 26152419Sjulian 26252419Sjulian/* 26352419Sjulian * Receive incoming control message 26452419Sjulian */ 26552419Sjulianstatic int 26670700Sjuliannga_rcvmsg(node_p node, item_p item, hook_p lasthook) 26752419Sjulian{ 26870784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 26952419Sjulian struct ng_mesg *resp = NULL; 27052419Sjulian int error = 0; 27170700Sjulian struct ng_mesg *msg; 27270700Sjulian 27370700Sjulian NGI_GET_MSG(item, msg); 27452419Sjulian switch (msg->header.typecookie) { 27552419Sjulian case NGM_ASYNC_COOKIE: 27652419Sjulian switch (msg->header.cmd) { 27752419Sjulian case NGM_ASYNC_CMD_GET_STATS: 27852419Sjulian NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT); 27952419Sjulian if (resp == NULL) 28052419Sjulian ERROUT(ENOMEM); 28152419Sjulian *((struct ng_async_stat *) resp->data) = sc->stats; 28252419Sjulian break; 28352419Sjulian case NGM_ASYNC_CMD_CLR_STATS: 28452419Sjulian bzero(&sc->stats, sizeof(sc->stats)); 28552419Sjulian break; 28652419Sjulian case NGM_ASYNC_CMD_SET_CONFIG: 28752419Sjulian { 28852419Sjulian struct ng_async_cfg *const cfg = 28952419Sjulian (struct ng_async_cfg *) msg->data; 29052419Sjulian u_char *buf; 29152419Sjulian 29252419Sjulian if (msg->header.arglen != sizeof(*cfg)) 29352419Sjulian ERROUT(EINVAL); 29452419Sjulian if (cfg->amru < NG_ASYNC_MIN_MRU 29552419Sjulian || cfg->amru > NG_ASYNC_MAX_MRU 29652419Sjulian || cfg->smru < NG_ASYNC_MIN_MRU 29752419Sjulian || cfg->smru > NG_ASYNC_MAX_MRU) 29852419Sjulian ERROUT(EINVAL); 29952419Sjulian cfg->enabled = !!cfg->enabled; /* normalize */ 30052419Sjulian if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */ 301184205Sdes buf = malloc(ASYNC_BUF_SIZE(cfg->smru), 30270870Sjulian M_NETGRAPH_ASYNC, M_NOWAIT); 30352419Sjulian if (!buf) 30452419Sjulian ERROUT(ENOMEM); 305184205Sdes free(sc->abuf, M_NETGRAPH_ASYNC); 30652419Sjulian sc->abuf = buf; 30752419Sjulian } 30852419Sjulian if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */ 309184205Sdes buf = malloc(SYNC_BUF_SIZE(cfg->amru), 31070870Sjulian M_NETGRAPH_ASYNC, M_NOWAIT); 31152419Sjulian if (!buf) 31252419Sjulian ERROUT(ENOMEM); 313184205Sdes free(sc->sbuf, M_NETGRAPH_ASYNC); 31452419Sjulian sc->sbuf = buf; 31552419Sjulian sc->amode = MODE_HUNT; 31652419Sjulian sc->slen = 0; 31752419Sjulian } 31852419Sjulian if (!cfg->enabled) { 31952419Sjulian sc->amode = MODE_HUNT; 32052419Sjulian sc->slen = 0; 32152419Sjulian } 32252419Sjulian sc->cfg = *cfg; 32352419Sjulian break; 32452419Sjulian } 32552419Sjulian case NGM_ASYNC_CMD_GET_CONFIG: 32652419Sjulian NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT); 32752419Sjulian if (!resp) 32852419Sjulian ERROUT(ENOMEM); 32952419Sjulian *((struct ng_async_cfg *) resp->data) = sc->cfg; 33052419Sjulian break; 33152419Sjulian default: 33252419Sjulian ERROUT(EINVAL); 33352419Sjulian } 33452419Sjulian break; 33552419Sjulian default: 33652419Sjulian ERROUT(EINVAL); 33752419Sjulian } 33852419Sjuliandone: 33970700Sjulian NG_RESPOND_MSG(error, node, item, resp); 34070700Sjulian NG_FREE_MSG(msg); 34152419Sjulian return (error); 34252419Sjulian} 34352419Sjulian 34452419Sjulian/* 34552419Sjulian * Shutdown this node 34652419Sjulian */ 34752419Sjulianstatic int 34852419Sjuliannga_shutdown(node_p node) 34952419Sjulian{ 35070784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 35152419Sjulian 352184205Sdes free(sc->abuf, M_NETGRAPH_ASYNC); 353184205Sdes free(sc->sbuf, M_NETGRAPH_ASYNC); 35452419Sjulian bzero(sc, sizeof(*sc)); 355184205Sdes free(sc, M_NETGRAPH_ASYNC); 35670784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 35770784Sjulian NG_NODE_UNREF(node); 35852419Sjulian return (0); 35952419Sjulian} 36052419Sjulian 36152419Sjulian/* 36252419Sjulian * Lose a hook. When both hooks go away, we disappear. 36352419Sjulian */ 36452419Sjulianstatic int 36552419Sjuliannga_disconnect(hook_p hook) 36652419Sjulian{ 36770784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 36852419Sjulian hook_p *hookp; 36952419Sjulian 37052419Sjulian if (hook == sc->async) 37152419Sjulian hookp = &sc->async; 37252419Sjulian else if (hook == sc->sync) 37352419Sjulian hookp = &sc->sync; 37452419Sjulian else 375213794Srpaulo panic("%s", __func__); 37652419Sjulian if (!*hookp) 37787599Sobrien panic("%s 2", __func__); 37852419Sjulian *hookp = NULL; 37952419Sjulian bzero(&sc->stats, sizeof(sc->stats)); 38052419Sjulian sc->lasttime = 0; 38170784Sjulian if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 38270784Sjulian && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 38370784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 38452419Sjulian return (0); 38552419Sjulian} 38652419Sjulian 38752419Sjulian/****************************************************************** 38852419Sjulian INTERNAL HELPER STUFF 38952419Sjulian******************************************************************/ 39052419Sjulian 39152419Sjulian/* 39252419Sjulian * Encode a byte into the async buffer 39352419Sjulian */ 394131575Sstefanfstatic __inline void 39552419Sjuliannga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x) 39652419Sjulian{ 39752419Sjulian *fcs = PPP_FCS(*fcs, x); 39852419Sjulian if ((x < 32 && ((1 << x) & accm)) 39952419Sjulian || (x == PPP_ESCAPE) 40052419Sjulian || (x == PPP_FLAG)) { 40152419Sjulian sc->abuf[(*len)++] = PPP_ESCAPE; 40252419Sjulian x ^= PPP_TRANS; 40352419Sjulian } 40452419Sjulian sc->abuf[(*len)++] = x; 40552419Sjulian} 40652419Sjulian 40752419Sjulian/* 40852976Sarchie * Receive incoming synchronous data. 40952419Sjulian */ 41052419Sjulianstatic int 41170700Sjuliannga_rcv_sync(const sc_p sc, item_p item) 41252419Sjulian{ 41370700Sjulian struct ifnet *rcvif; 41453394Sarchie int alen, error = 0; 41552976Sarchie struct timeval time; 41652419Sjulian u_int16_t fcs, fcs0; 41752976Sarchie u_int32_t accm; 41870700Sjulian struct mbuf *m; 41952419Sjulian 42070700Sjulian 42152976Sarchie#define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x)) 42252419Sjulian 42352976Sarchie /* Check for bypass mode */ 42452419Sjulian if (!sc->cfg.enabled) { 42570784Sjulian NG_FWD_ITEM_HOOK(error, item, sc->async ); 42652419Sjulian return (error); 42752419Sjulian } 42870700Sjulian NGI_GET_M(item, m); 42952976Sarchie 43070700Sjulian rcvif = m->m_pkthdr.rcvif; 43170700Sjulian 43253394Sarchie /* Get ACCM; special case LCP frames, which use full ACCM */ 43352976Sarchie accm = sc->cfg.accm; 43453394Sarchie if (m->m_pkthdr.len >= 4) { 43553394Sarchie static const u_char lcphdr[4] = { 43653394Sarchie PPP_ALLSTATIONS, 43753394Sarchie PPP_UI, 43853394Sarchie (u_char)(PPP_LCP >> 8), 43953394Sarchie (u_char)(PPP_LCP & 0xff) 44053394Sarchie }; 44153394Sarchie u_char buf[4]; 44252976Sarchie 44353394Sarchie m_copydata(m, 0, 4, (caddr_t)buf); 44453394Sarchie if (bcmp(buf, &lcphdr, 4) == 0) 44552976Sarchie accm = ~0; 44652976Sarchie } 44752976Sarchie 44852976Sarchie /* Check for overflow */ 44952419Sjulian if (m->m_pkthdr.len > sc->cfg.smru) { 45052419Sjulian sc->stats.syncOverflows++; 45170700Sjulian NG_FREE_M(m); 45270700Sjulian NG_FREE_ITEM(item); 45352419Sjulian return (EMSGSIZE); 45452419Sjulian } 45552976Sarchie 45652976Sarchie /* Update stats */ 45752419Sjulian sc->stats.syncFrames++; 45852419Sjulian sc->stats.syncOctets += m->m_pkthdr.len; 45952419Sjulian 46052419Sjulian /* Initialize async encoded version of input mbuf */ 46152419Sjulian alen = 0; 46252419Sjulian fcs = PPP_INITFCS; 46352419Sjulian 46452419Sjulian /* Add beginning sync flag if it's been long enough to need one */ 46552976Sarchie getmicrotime(&time); 46652976Sarchie if (time.tv_sec >= sc->lasttime + 1) { 46752976Sarchie sc->abuf[alen++] = PPP_FLAG; 46852976Sarchie sc->lasttime = time.tv_sec; 46952419Sjulian } 47052419Sjulian 47153394Sarchie /* Add packet payload */ 47252976Sarchie while (m != NULL) { 47352419Sjulian while (m->m_len > 0) { 47452976Sarchie ADD_BYTE(*mtod(m, u_char *)); 47552419Sjulian m->m_data++; 47652419Sjulian m->m_len--; 47752419Sjulian } 47890227Sdillon m = m_free(m); 47952419Sjulian } 48052419Sjulian 48152419Sjulian /* Add checksum and final sync flag */ 48252419Sjulian fcs0 = fcs; 48352419Sjulian ADD_BYTE(~fcs0 & 0xff); 48452419Sjulian ADD_BYTE(~fcs0 >> 8); 48552419Sjulian sc->abuf[alen++] = PPP_FLAG; 48652419Sjulian 48752419Sjulian /* Put frame in an mbuf and ship it off */ 48852976Sarchie if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) { 48970700Sjulian NG_FREE_ITEM(item); 49052419Sjulian error = ENOBUFS; 49170700Sjulian } else { 49270700Sjulian NG_FWD_NEW_DATA(error, item, sc->async, m); 49370700Sjulian } 49452419Sjulian return (error); 49552419Sjulian} 49652419Sjulian 49752419Sjulian/* 49852419Sjulian * Receive incoming asynchronous data 49952976Sarchie * XXX Technically, we should strip out incoming characters 50052976Sarchie * that are in our ACCM. Not sure if this is good or not. 50152419Sjulian */ 50252419Sjulianstatic int 50370700Sjuliannga_rcv_async(const sc_p sc, item_p item) 50452419Sjulian{ 50570700Sjulian struct ifnet *rcvif; 50652419Sjulian int error; 50770700Sjulian struct mbuf *m; 50852419Sjulian 50952419Sjulian if (!sc->cfg.enabled) { 51070784Sjulian NG_FWD_ITEM_HOOK(error, item, sc->sync); 51152419Sjulian return (error); 51252419Sjulian } 51370700Sjulian NGI_GET_M(item, m); 51470700Sjulian rcvif = m->m_pkthdr.rcvif; 51552419Sjulian while (m) { 51652419Sjulian struct mbuf *n; 51752419Sjulian 51852419Sjulian for (; m->m_len > 0; m->m_data++, m->m_len--) { 51952419Sjulian u_char ch = *mtod(m, u_char *); 52052419Sjulian 52152419Sjulian sc->stats.asyncOctets++; 52252419Sjulian if (ch == PPP_FLAG) { /* Flag overrides everything */ 52352419Sjulian int skip = 0; 52452419Sjulian 52552419Sjulian /* Check for runts */ 52652419Sjulian if (sc->slen < 2) { 52752419Sjulian if (sc->slen > 0) 52852419Sjulian sc->stats.asyncRunts++; 52952419Sjulian goto reset; 53052419Sjulian } 53152419Sjulian 53252419Sjulian /* Verify CRC */ 53352419Sjulian if (sc->fcs != PPP_GOODFCS) { 53452419Sjulian sc->stats.asyncBadCheckSums++; 53552419Sjulian goto reset; 53652419Sjulian } 53752419Sjulian sc->slen -= 2; 53852419Sjulian 53952419Sjulian /* Strip address and control fields */ 54052419Sjulian if (sc->slen >= 2 54152419Sjulian && sc->sbuf[0] == PPP_ALLSTATIONS 54252419Sjulian && sc->sbuf[1] == PPP_UI) 54352419Sjulian skip = 2; 54452419Sjulian 54552419Sjulian /* Check for frame too big */ 54652419Sjulian if (sc->slen - skip > sc->cfg.amru) { 54752419Sjulian sc->stats.asyncOverflows++; 54852419Sjulian goto reset; 54952419Sjulian } 55052419Sjulian 55152419Sjulian /* OK, ship it out */ 55252419Sjulian if ((n = m_devget(sc->sbuf + skip, 55370700Sjulian sc->slen - skip, 0, rcvif, NULL))) { 55470700Sjulian if (item) { /* sets NULL -> item */ 55570700Sjulian NG_FWD_NEW_DATA(error, item, 55670700Sjulian sc->sync, n); 55770700Sjulian } else { 55870700Sjulian NG_SEND_DATA_ONLY(error, 55970700Sjulian sc->sync ,n); 56070700Sjulian } 56170700Sjulian } 56252419Sjulian sc->stats.asyncFrames++; 56352419Sjulianreset: 56452419Sjulian sc->amode = MODE_NORMAL; 56552419Sjulian sc->fcs = PPP_INITFCS; 56652419Sjulian sc->slen = 0; 56752419Sjulian continue; 56852419Sjulian } 56952419Sjulian switch (sc->amode) { 57052419Sjulian case MODE_NORMAL: 57152419Sjulian if (ch == PPP_ESCAPE) { 57252419Sjulian sc->amode = MODE_ESC; 57352419Sjulian continue; 57452419Sjulian } 57552419Sjulian break; 57652419Sjulian case MODE_ESC: 57752419Sjulian ch ^= PPP_TRANS; 57852419Sjulian sc->amode = MODE_NORMAL; 57952419Sjulian break; 58052419Sjulian case MODE_HUNT: 58152419Sjulian default: 58252419Sjulian continue; 58352419Sjulian } 58452419Sjulian 58552419Sjulian /* Add byte to frame */ 58652419Sjulian if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) { 58752419Sjulian sc->stats.asyncOverflows++; 58852419Sjulian sc->amode = MODE_HUNT; 58952419Sjulian sc->slen = 0; 59052419Sjulian } else { 59152419Sjulian sc->sbuf[sc->slen++] = ch; 59252419Sjulian sc->fcs = PPP_FCS(sc->fcs, ch); 59352419Sjulian } 59452419Sjulian } 59590227Sdillon m = m_free(m); 59652419Sjulian } 59770700Sjulian if (item) 59870700Sjulian NG_FREE_ITEM(item); 59952419Sjulian return (0); 60052419Sjulian} 60152419Sjulian 60252419Sjulian/* 60352419Sjulian * CRC table 60452419Sjulian * 60552419Sjulian * Taken from RFC 1171 Appendix B 60652419Sjulian */ 60752419Sjulianstatic const u_int16_t fcstab[256] = { 60852419Sjulian 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 60952419Sjulian 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 61052419Sjulian 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 61152419Sjulian 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 61252419Sjulian 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 61352419Sjulian 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 61452419Sjulian 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 61552419Sjulian 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 61652419Sjulian 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 61752419Sjulian 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 61852419Sjulian 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 61952419Sjulian 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 62052419Sjulian 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 62152419Sjulian 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 62252419Sjulian 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 62352419Sjulian 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 62452419Sjulian 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 62552419Sjulian 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 62652419Sjulian 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 62752419Sjulian 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 62852419Sjulian 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 62952419Sjulian 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 63052419Sjulian 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 63152419Sjulian 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 63252419Sjulian 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 63352419Sjulian 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 63452419Sjulian 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 63552419Sjulian 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 63652419Sjulian 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 63752419Sjulian 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 63852419Sjulian 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 63952419Sjulian 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 64052419Sjulian}; 641