ng_async.c revision 129823
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 129823 2004-05-29 00:51:19Z julian $ 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 */ 10897685Sarchiestatic const struct ng_parse_struct_field nga_config_type_fields[] 10997685Sarchie = NG_ASYNC_CONFIG_TYPE_INFO; 11053913Sarchiestatic const struct ng_parse_type nga_config_type = { 11153913Sarchie &ng_parse_struct_type, 11297685Sarchie &nga_config_type_fields 11353913Sarchie}; 11453913Sarchie 11553913Sarchie/* Parse type for struct ng_async_stat */ 11697685Sarchiestatic const struct ng_parse_struct_field nga_stats_type_fields[] 11797685Sarchie = NG_ASYNC_STATS_TYPE_INFO; 11853913Sarchiestatic const struct ng_parse_type nga_stats_type = { 11953913Sarchie &ng_parse_struct_type, 12097685Sarchie &nga_stats_type_fields 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 = { 158129823Sjulian .version = NG_ABI_VERSION, 159129823Sjulian .name = NG_ASYNC_NODE_TYPE, 160129823Sjulian .constructor = nga_constructor, 161129823Sjulian .rcvmsg = nga_rcvmsg, 162129823Sjulian .shutdown = nga_shutdown, 163129823Sjulian .newhook = nga_newhook, 164129823Sjulian .rcvdata = nga_rcvdata, 165129823Sjulian .disconnect = nga_disconnect, 166129823Sjulian .cmdlist = nga_cmdlist 16752419Sjulian}; 16852419SjulianNETGRAPH_INIT(async, &typestruct); 16952419Sjulian 17052419Sjulian/* CRC table */ 17152419Sjulianstatic const u_int16_t fcstab[]; 17252419Sjulian 17352419Sjulian/****************************************************************** 17452419Sjulian NETGRAPH NODE METHODS 17552419Sjulian******************************************************************/ 17652419Sjulian 17752419Sjulian/* 17852419Sjulian * Initialize a new node 17952419Sjulian */ 18052419Sjulianstatic int 18170700Sjuliannga_constructor(node_p node) 18252419Sjulian{ 18352419Sjulian sc_p sc; 18452419Sjulian 18570870Sjulian MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH_ASYNC, M_NOWAIT | M_ZERO); 18652419Sjulian if (sc == NULL) 18752419Sjulian return (ENOMEM); 18852419Sjulian sc->amode = MODE_HUNT; 18952419Sjulian sc->cfg.accm = ~0; 19052419Sjulian sc->cfg.amru = NG_ASYNC_DEFAULT_MRU; 19152419Sjulian sc->cfg.smru = NG_ASYNC_DEFAULT_MRU; 19252419Sjulian MALLOC(sc->abuf, u_char *, 19370870Sjulian ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH_ASYNC, M_NOWAIT); 19452419Sjulian if (sc->abuf == NULL) 19552419Sjulian goto fail; 19652419Sjulian MALLOC(sc->sbuf, u_char *, 19770870Sjulian SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH_ASYNC, M_NOWAIT); 19852419Sjulian if (sc->sbuf == NULL) { 19970870Sjulian FREE(sc->abuf, M_NETGRAPH_ASYNC); 20052419Sjulianfail: 20170870Sjulian FREE(sc, M_NETGRAPH_ASYNC); 20252419Sjulian return (ENOMEM); 20352419Sjulian } 20470784Sjulian NG_NODE_SET_PRIVATE(node, sc); 20570700Sjulian sc->node = node; 20652419Sjulian return (0); 20752419Sjulian} 20852419Sjulian 20952419Sjulian/* 21052419Sjulian * Reserve a hook for a pending connection 21152419Sjulian */ 21252419Sjulianstatic int 21352419Sjuliannga_newhook(node_p node, hook_p hook, const char *name) 21452419Sjulian{ 21570784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 21652419Sjulian hook_p *hookp; 21752419Sjulian 21870700Sjulian if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) { 21970700Sjulian /* 22070700Sjulian * We use a static buffer here so only one packet 22170700Sjulian * at a time can be allowed to travel in this direction. 22270700Sjulian * Force Writer semantics. 22370700Sjulian */ 22470784Sjulian NG_HOOK_FORCE_WRITER(hook); 22552419Sjulian hookp = &sc->async; 22670700Sjulian } else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) { 22770700Sjulian /* 22870700Sjulian * We use a static state here so only one packet 22970700Sjulian * at a time can be allowed to travel in this direction. 23070700Sjulian * Force Writer semantics. 23170700Sjulian * Since we set this for both directions 23270700Sjulian * we might as well set it for the whole node 23370700Sjulian * bit I haven;t done that (yet). 23470700Sjulian */ 23570784Sjulian NG_HOOK_FORCE_WRITER(hook); 23652419Sjulian hookp = &sc->sync; 23770700Sjulian } else { 23852419Sjulian return (EINVAL); 23970700Sjulian } 24070700Sjulian if (*hookp) /* actually can't happen I think [JRE] */ 24152419Sjulian return (EISCONN); 24252419Sjulian *hookp = hook; 24352419Sjulian return (0); 24452419Sjulian} 24552419Sjulian 24652419Sjulian/* 24752419Sjulian * Receive incoming data 24852419Sjulian */ 24952419Sjulianstatic int 25070700Sjuliannga_rcvdata(hook_p hook, item_p item) 25152419Sjulian{ 25270784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 25352419Sjulian 25452419Sjulian if (hook == sc->sync) 25570700Sjulian return (nga_rcv_sync(sc, item)); 25652976Sarchie if (hook == sc->async) 25770700Sjulian return (nga_rcv_async(sc, item)); 25887599Sobrien panic(__func__); 25952419Sjulian} 26052419Sjulian 26152419Sjulian/* 26252419Sjulian * Receive incoming control message 26352419Sjulian */ 26452419Sjulianstatic int 26570700Sjuliannga_rcvmsg(node_p node, item_p item, hook_p lasthook) 26652419Sjulian{ 26770784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 26852419Sjulian struct ng_mesg *resp = NULL; 26952419Sjulian int error = 0; 27070700Sjulian struct ng_mesg *msg; 27170700Sjulian 27270700Sjulian NGI_GET_MSG(item, msg); 27352419Sjulian switch (msg->header.typecookie) { 27452419Sjulian case NGM_ASYNC_COOKIE: 27552419Sjulian switch (msg->header.cmd) { 27652419Sjulian case NGM_ASYNC_CMD_GET_STATS: 27752419Sjulian NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT); 27852419Sjulian if (resp == NULL) 27952419Sjulian ERROUT(ENOMEM); 28052419Sjulian *((struct ng_async_stat *) resp->data) = sc->stats; 28152419Sjulian break; 28252419Sjulian case NGM_ASYNC_CMD_CLR_STATS: 28352419Sjulian bzero(&sc->stats, sizeof(sc->stats)); 28452419Sjulian break; 28552419Sjulian case NGM_ASYNC_CMD_SET_CONFIG: 28652419Sjulian { 28752419Sjulian struct ng_async_cfg *const cfg = 28852419Sjulian (struct ng_async_cfg *) msg->data; 28952419Sjulian u_char *buf; 29052419Sjulian 29152419Sjulian if (msg->header.arglen != sizeof(*cfg)) 29252419Sjulian ERROUT(EINVAL); 29352419Sjulian if (cfg->amru < NG_ASYNC_MIN_MRU 29452419Sjulian || cfg->amru > NG_ASYNC_MAX_MRU 29552419Sjulian || cfg->smru < NG_ASYNC_MIN_MRU 29652419Sjulian || cfg->smru > NG_ASYNC_MAX_MRU) 29752419Sjulian ERROUT(EINVAL); 29852419Sjulian cfg->enabled = !!cfg->enabled; /* normalize */ 29952419Sjulian if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */ 30052419Sjulian MALLOC(buf, u_char *, ASYNC_BUF_SIZE(cfg->smru), 30170870Sjulian M_NETGRAPH_ASYNC, M_NOWAIT); 30252419Sjulian if (!buf) 30352419Sjulian ERROUT(ENOMEM); 30470870Sjulian FREE(sc->abuf, M_NETGRAPH_ASYNC); 30552419Sjulian sc->abuf = buf; 30652419Sjulian } 30752419Sjulian if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */ 30852419Sjulian MALLOC(buf, u_char *, SYNC_BUF_SIZE(cfg->amru), 30970870Sjulian M_NETGRAPH_ASYNC, M_NOWAIT); 31052419Sjulian if (!buf) 31152419Sjulian ERROUT(ENOMEM); 31270870Sjulian FREE(sc->sbuf, M_NETGRAPH_ASYNC); 31352419Sjulian sc->sbuf = buf; 31452419Sjulian sc->amode = MODE_HUNT; 31552419Sjulian sc->slen = 0; 31652419Sjulian } 31752419Sjulian if (!cfg->enabled) { 31852419Sjulian sc->amode = MODE_HUNT; 31952419Sjulian sc->slen = 0; 32052419Sjulian } 32152419Sjulian sc->cfg = *cfg; 32252419Sjulian break; 32352419Sjulian } 32452419Sjulian case NGM_ASYNC_CMD_GET_CONFIG: 32552419Sjulian NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT); 32652419Sjulian if (!resp) 32752419Sjulian ERROUT(ENOMEM); 32852419Sjulian *((struct ng_async_cfg *) resp->data) = sc->cfg; 32952419Sjulian break; 33052419Sjulian default: 33152419Sjulian ERROUT(EINVAL); 33252419Sjulian } 33352419Sjulian break; 33452419Sjulian default: 33552419Sjulian ERROUT(EINVAL); 33652419Sjulian } 33752419Sjuliandone: 33870700Sjulian NG_RESPOND_MSG(error, node, item, resp); 33970700Sjulian NG_FREE_MSG(msg); 34052419Sjulian return (error); 34152419Sjulian} 34252419Sjulian 34352419Sjulian/* 34452419Sjulian * Shutdown this node 34552419Sjulian */ 34652419Sjulianstatic int 34752419Sjuliannga_shutdown(node_p node) 34852419Sjulian{ 34970784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 35052419Sjulian 35170870Sjulian FREE(sc->abuf, M_NETGRAPH_ASYNC); 35270870Sjulian FREE(sc->sbuf, M_NETGRAPH_ASYNC); 35352419Sjulian bzero(sc, sizeof(*sc)); 35470870Sjulian FREE(sc, M_NETGRAPH_ASYNC); 35570784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 35670784Sjulian NG_NODE_UNREF(node); 35752419Sjulian return (0); 35852419Sjulian} 35952419Sjulian 36052419Sjulian/* 36152419Sjulian * Lose a hook. When both hooks go away, we disappear. 36252419Sjulian */ 36352419Sjulianstatic int 36452419Sjuliannga_disconnect(hook_p hook) 36552419Sjulian{ 36670784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 36752419Sjulian hook_p *hookp; 36852419Sjulian 36952419Sjulian if (hook == sc->async) 37052419Sjulian hookp = &sc->async; 37152419Sjulian else if (hook == sc->sync) 37252419Sjulian hookp = &sc->sync; 37352419Sjulian else 37487599Sobrien panic(__func__); 37552419Sjulian if (!*hookp) 37687599Sobrien panic("%s 2", __func__); 37752419Sjulian *hookp = NULL; 37852419Sjulian bzero(&sc->stats, sizeof(sc->stats)); 37952419Sjulian sc->lasttime = 0; 38070784Sjulian if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 38170784Sjulian && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 38270784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 38352419Sjulian return (0); 38452419Sjulian} 38552419Sjulian 38652419Sjulian/****************************************************************** 38752419Sjulian INTERNAL HELPER STUFF 38852419Sjulian******************************************************************/ 38952419Sjulian 39052419Sjulian/* 39152419Sjulian * Encode a byte into the async buffer 39252419Sjulian */ 39352419Sjulianstatic __inline__ void 39452419Sjuliannga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x) 39552419Sjulian{ 39652419Sjulian *fcs = PPP_FCS(*fcs, x); 39752419Sjulian if ((x < 32 && ((1 << x) & accm)) 39852419Sjulian || (x == PPP_ESCAPE) 39952419Sjulian || (x == PPP_FLAG)) { 40052419Sjulian sc->abuf[(*len)++] = PPP_ESCAPE; 40152419Sjulian x ^= PPP_TRANS; 40252419Sjulian } 40352419Sjulian sc->abuf[(*len)++] = x; 40452419Sjulian} 40552419Sjulian 40652419Sjulian/* 40752976Sarchie * Receive incoming synchronous data. 40852419Sjulian */ 40952419Sjulianstatic int 41070700Sjuliannga_rcv_sync(const sc_p sc, item_p item) 41152419Sjulian{ 41270700Sjulian struct ifnet *rcvif; 41353394Sarchie int alen, error = 0; 41452976Sarchie struct timeval time; 41552419Sjulian u_int16_t fcs, fcs0; 41652976Sarchie u_int32_t accm; 41770700Sjulian struct mbuf *m; 41852419Sjulian 41970700Sjulian 42052976Sarchie#define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x)) 42152419Sjulian 42252976Sarchie /* Check for bypass mode */ 42352419Sjulian if (!sc->cfg.enabled) { 42470784Sjulian NG_FWD_ITEM_HOOK(error, item, sc->async ); 42552419Sjulian return (error); 42652419Sjulian } 42770700Sjulian NGI_GET_M(item, m); 42852976Sarchie 42970700Sjulian rcvif = m->m_pkthdr.rcvif; 43070700Sjulian 43153394Sarchie /* Get ACCM; special case LCP frames, which use full ACCM */ 43252976Sarchie accm = sc->cfg.accm; 43353394Sarchie if (m->m_pkthdr.len >= 4) { 43453394Sarchie static const u_char lcphdr[4] = { 43553394Sarchie PPP_ALLSTATIONS, 43653394Sarchie PPP_UI, 43753394Sarchie (u_char)(PPP_LCP >> 8), 43853394Sarchie (u_char)(PPP_LCP & 0xff) 43953394Sarchie }; 44053394Sarchie u_char buf[4]; 44152976Sarchie 44253394Sarchie m_copydata(m, 0, 4, (caddr_t)buf); 44353394Sarchie if (bcmp(buf, &lcphdr, 4) == 0) 44452976Sarchie accm = ~0; 44552976Sarchie } 44652976Sarchie 44752976Sarchie /* Check for overflow */ 44852419Sjulian if (m->m_pkthdr.len > sc->cfg.smru) { 44952419Sjulian sc->stats.syncOverflows++; 45070700Sjulian NG_FREE_M(m); 45170700Sjulian NG_FREE_ITEM(item); 45252419Sjulian return (EMSGSIZE); 45352419Sjulian } 45452976Sarchie 45552976Sarchie /* Update stats */ 45652419Sjulian sc->stats.syncFrames++; 45752419Sjulian sc->stats.syncOctets += m->m_pkthdr.len; 45852419Sjulian 45952419Sjulian /* Initialize async encoded version of input mbuf */ 46052419Sjulian alen = 0; 46152419Sjulian fcs = PPP_INITFCS; 46252419Sjulian 46352419Sjulian /* Add beginning sync flag if it's been long enough to need one */ 46452976Sarchie getmicrotime(&time); 46552976Sarchie if (time.tv_sec >= sc->lasttime + 1) { 46652976Sarchie sc->abuf[alen++] = PPP_FLAG; 46752976Sarchie sc->lasttime = time.tv_sec; 46852419Sjulian } 46952419Sjulian 47053394Sarchie /* Add packet payload */ 47152976Sarchie while (m != NULL) { 47252419Sjulian while (m->m_len > 0) { 47352976Sarchie ADD_BYTE(*mtod(m, u_char *)); 47452419Sjulian m->m_data++; 47552419Sjulian m->m_len--; 47652419Sjulian } 47790227Sdillon m = m_free(m); 47852419Sjulian } 47952419Sjulian 48052419Sjulian /* Add checksum and final sync flag */ 48152419Sjulian fcs0 = fcs; 48252419Sjulian ADD_BYTE(~fcs0 & 0xff); 48352419Sjulian ADD_BYTE(~fcs0 >> 8); 48452419Sjulian sc->abuf[alen++] = PPP_FLAG; 48552419Sjulian 48652419Sjulian /* Put frame in an mbuf and ship it off */ 48752976Sarchie if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) { 48870700Sjulian NG_FREE_ITEM(item); 48952419Sjulian error = ENOBUFS; 49070700Sjulian } else { 49170700Sjulian NG_FWD_NEW_DATA(error, item, sc->async, m); 49270700Sjulian } 49352419Sjulian return (error); 49452419Sjulian} 49552419Sjulian 49652419Sjulian/* 49752419Sjulian * Receive incoming asynchronous data 49852976Sarchie * XXX Technically, we should strip out incoming characters 49952976Sarchie * that are in our ACCM. Not sure if this is good or not. 50052419Sjulian */ 50152419Sjulianstatic int 50270700Sjuliannga_rcv_async(const sc_p sc, item_p item) 50352419Sjulian{ 50470700Sjulian struct ifnet *rcvif; 50552419Sjulian int error; 50670700Sjulian struct mbuf *m; 50752419Sjulian 50852419Sjulian if (!sc->cfg.enabled) { 50970784Sjulian NG_FWD_ITEM_HOOK(error, item, sc->sync); 51052419Sjulian return (error); 51152419Sjulian } 51270700Sjulian NGI_GET_M(item, m); 51370700Sjulian rcvif = m->m_pkthdr.rcvif; 51452419Sjulian while (m) { 51552419Sjulian struct mbuf *n; 51652419Sjulian 51752419Sjulian for (; m->m_len > 0; m->m_data++, m->m_len--) { 51852419Sjulian u_char ch = *mtod(m, u_char *); 51952419Sjulian 52052419Sjulian sc->stats.asyncOctets++; 52152419Sjulian if (ch == PPP_FLAG) { /* Flag overrides everything */ 52252419Sjulian int skip = 0; 52352419Sjulian 52452419Sjulian /* Check for runts */ 52552419Sjulian if (sc->slen < 2) { 52652419Sjulian if (sc->slen > 0) 52752419Sjulian sc->stats.asyncRunts++; 52852419Sjulian goto reset; 52952419Sjulian } 53052419Sjulian 53152419Sjulian /* Verify CRC */ 53252419Sjulian if (sc->fcs != PPP_GOODFCS) { 53352419Sjulian sc->stats.asyncBadCheckSums++; 53452419Sjulian goto reset; 53552419Sjulian } 53652419Sjulian sc->slen -= 2; 53752419Sjulian 53852419Sjulian /* Strip address and control fields */ 53952419Sjulian if (sc->slen >= 2 54052419Sjulian && sc->sbuf[0] == PPP_ALLSTATIONS 54152419Sjulian && sc->sbuf[1] == PPP_UI) 54252419Sjulian skip = 2; 54352419Sjulian 54452419Sjulian /* Check for frame too big */ 54552419Sjulian if (sc->slen - skip > sc->cfg.amru) { 54652419Sjulian sc->stats.asyncOverflows++; 54752419Sjulian goto reset; 54852419Sjulian } 54952419Sjulian 55052419Sjulian /* OK, ship it out */ 55152419Sjulian if ((n = m_devget(sc->sbuf + skip, 55270700Sjulian sc->slen - skip, 0, rcvif, NULL))) { 55370700Sjulian if (item) { /* sets NULL -> item */ 55470700Sjulian NG_FWD_NEW_DATA(error, item, 55570700Sjulian sc->sync, n); 55670700Sjulian } else { 55770700Sjulian NG_SEND_DATA_ONLY(error, 55870700Sjulian sc->sync ,n); 55970700Sjulian } 56070700Sjulian } 56152419Sjulian sc->stats.asyncFrames++; 56252419Sjulianreset: 56352419Sjulian sc->amode = MODE_NORMAL; 56452419Sjulian sc->fcs = PPP_INITFCS; 56552419Sjulian sc->slen = 0; 56652419Sjulian continue; 56752419Sjulian } 56852419Sjulian switch (sc->amode) { 56952419Sjulian case MODE_NORMAL: 57052419Sjulian if (ch == PPP_ESCAPE) { 57152419Sjulian sc->amode = MODE_ESC; 57252419Sjulian continue; 57352419Sjulian } 57452419Sjulian break; 57552419Sjulian case MODE_ESC: 57652419Sjulian ch ^= PPP_TRANS; 57752419Sjulian sc->amode = MODE_NORMAL; 57852419Sjulian break; 57952419Sjulian case MODE_HUNT: 58052419Sjulian default: 58152419Sjulian continue; 58252419Sjulian } 58352419Sjulian 58452419Sjulian /* Add byte to frame */ 58552419Sjulian if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) { 58652419Sjulian sc->stats.asyncOverflows++; 58752419Sjulian sc->amode = MODE_HUNT; 58852419Sjulian sc->slen = 0; 58952419Sjulian } else { 59052419Sjulian sc->sbuf[sc->slen++] = ch; 59152419Sjulian sc->fcs = PPP_FCS(sc->fcs, ch); 59252419Sjulian } 59352419Sjulian } 59490227Sdillon m = m_free(m); 59552419Sjulian } 59670700Sjulian if (item) 59770700Sjulian NG_FREE_ITEM(item); 59852419Sjulian return (0); 59952419Sjulian} 60052419Sjulian 60152419Sjulian/* 60252419Sjulian * CRC table 60352419Sjulian * 60452419Sjulian * Taken from RFC 1171 Appendix B 60552419Sjulian */ 60652419Sjulianstatic const u_int16_t fcstab[256] = { 60752419Sjulian 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 60852419Sjulian 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 60952419Sjulian 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 61052419Sjulian 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 61152419Sjulian 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 61252419Sjulian 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 61352419Sjulian 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 61452419Sjulian 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 61552419Sjulian 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 61652419Sjulian 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 61752419Sjulian 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 61852419Sjulian 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 61952419Sjulian 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 62052419Sjulian 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 62152419Sjulian 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 62252419Sjulian 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 62352419Sjulian 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 62452419Sjulian 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 62552419Sjulian 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 62652419Sjulian 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 62752419Sjulian 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 62852419Sjulian 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 62952419Sjulian 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 63052419Sjulian 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 63152419Sjulian 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 63252419Sjulian 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 63352419Sjulian 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 63452419Sjulian 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 63552419Sjulian 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 63652419Sjulian 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 63752419Sjulian 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 63852419Sjulian 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 63952419Sjulian}; 640