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$ 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 64227293Sedstatic MALLOC_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 186220768Sglebius sc = malloc(sizeof(*sc), M_NETGRAPH_ASYNC, M_WAITOK | M_ZERO); 18752419Sjulian sc->amode = MODE_HUNT; 18852419Sjulian sc->cfg.accm = ~0; 18952419Sjulian sc->cfg.amru = NG_ASYNC_DEFAULT_MRU; 19052419Sjulian sc->cfg.smru = NG_ASYNC_DEFAULT_MRU; 191184214Sdes sc->abuf = malloc(ASYNC_BUF_SIZE(sc->cfg.smru), 192220768Sglebius M_NETGRAPH_ASYNC, M_WAITOK); 193184214Sdes sc->sbuf = malloc(SYNC_BUF_SIZE(sc->cfg.amru), 194220768Sglebius M_NETGRAPH_ASYNC, M_WAITOK); 19570784Sjulian NG_NODE_SET_PRIVATE(node, sc); 19670700Sjulian sc->node = node; 19752419Sjulian return (0); 19852419Sjulian} 19952419Sjulian 20052419Sjulian/* 20152419Sjulian * Reserve a hook for a pending connection 20252419Sjulian */ 20352419Sjulianstatic int 20452419Sjuliannga_newhook(node_p node, hook_p hook, const char *name) 20552419Sjulian{ 20670784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 20752419Sjulian hook_p *hookp; 20852419Sjulian 20970700Sjulian if (!strcmp(name, NG_ASYNC_HOOK_ASYNC)) { 21070700Sjulian /* 21170700Sjulian * We use a static buffer here so only one packet 21270700Sjulian * at a time can be allowed to travel in this direction. 21370700Sjulian * Force Writer semantics. 21470700Sjulian */ 21570784Sjulian NG_HOOK_FORCE_WRITER(hook); 21652419Sjulian hookp = &sc->async; 21770700Sjulian } else if (!strcmp(name, NG_ASYNC_HOOK_SYNC)) { 21870700Sjulian /* 21970700Sjulian * We use a static state here so only one packet 22070700Sjulian * at a time can be allowed to travel in this direction. 22170700Sjulian * Force Writer semantics. 22270700Sjulian * Since we set this for both directions 22370700Sjulian * we might as well set it for the whole node 22470700Sjulian * bit I haven;t done that (yet). 22570700Sjulian */ 22670784Sjulian NG_HOOK_FORCE_WRITER(hook); 22752419Sjulian hookp = &sc->sync; 22870700Sjulian } else { 22952419Sjulian return (EINVAL); 23070700Sjulian } 23170700Sjulian if (*hookp) /* actually can't happen I think [JRE] */ 23252419Sjulian return (EISCONN); 23352419Sjulian *hookp = hook; 23452419Sjulian return (0); 23552419Sjulian} 23652419Sjulian 23752419Sjulian/* 23852419Sjulian * Receive incoming data 23952419Sjulian */ 24052419Sjulianstatic int 24170700Sjuliannga_rcvdata(hook_p hook, item_p item) 24252419Sjulian{ 24370784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 24452419Sjulian 24552419Sjulian if (hook == sc->sync) 24670700Sjulian return (nga_rcv_sync(sc, item)); 24752976Sarchie if (hook == sc->async) 24870700Sjulian return (nga_rcv_async(sc, item)); 249213794Srpaulo panic("%s", __func__); 25052419Sjulian} 25152419Sjulian 25252419Sjulian/* 25352419Sjulian * Receive incoming control message 25452419Sjulian */ 25552419Sjulianstatic int 25670700Sjuliannga_rcvmsg(node_p node, item_p item, hook_p lasthook) 25752419Sjulian{ 25870784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 25952419Sjulian struct ng_mesg *resp = NULL; 26052419Sjulian int error = 0; 26170700Sjulian struct ng_mesg *msg; 26270700Sjulian 26370700Sjulian NGI_GET_MSG(item, msg); 26452419Sjulian switch (msg->header.typecookie) { 26552419Sjulian case NGM_ASYNC_COOKIE: 26652419Sjulian switch (msg->header.cmd) { 26752419Sjulian case NGM_ASYNC_CMD_GET_STATS: 26852419Sjulian NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT); 26952419Sjulian if (resp == NULL) 27052419Sjulian ERROUT(ENOMEM); 27152419Sjulian *((struct ng_async_stat *) resp->data) = sc->stats; 27252419Sjulian break; 27352419Sjulian case NGM_ASYNC_CMD_CLR_STATS: 27452419Sjulian bzero(&sc->stats, sizeof(sc->stats)); 27552419Sjulian break; 27652419Sjulian case NGM_ASYNC_CMD_SET_CONFIG: 27752419Sjulian { 27852419Sjulian struct ng_async_cfg *const cfg = 27952419Sjulian (struct ng_async_cfg *) msg->data; 28052419Sjulian u_char *buf; 28152419Sjulian 28252419Sjulian if (msg->header.arglen != sizeof(*cfg)) 28352419Sjulian ERROUT(EINVAL); 28452419Sjulian if (cfg->amru < NG_ASYNC_MIN_MRU 28552419Sjulian || cfg->amru > NG_ASYNC_MAX_MRU 28652419Sjulian || cfg->smru < NG_ASYNC_MIN_MRU 28752419Sjulian || cfg->smru > NG_ASYNC_MAX_MRU) 28852419Sjulian ERROUT(EINVAL); 28952419Sjulian cfg->enabled = !!cfg->enabled; /* normalize */ 29052419Sjulian if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */ 291184205Sdes buf = malloc(ASYNC_BUF_SIZE(cfg->smru), 29270870Sjulian M_NETGRAPH_ASYNC, M_NOWAIT); 29352419Sjulian if (!buf) 29452419Sjulian ERROUT(ENOMEM); 295184205Sdes free(sc->abuf, M_NETGRAPH_ASYNC); 29652419Sjulian sc->abuf = buf; 29752419Sjulian } 29852419Sjulian if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */ 299184205Sdes buf = malloc(SYNC_BUF_SIZE(cfg->amru), 30070870Sjulian M_NETGRAPH_ASYNC, M_NOWAIT); 30152419Sjulian if (!buf) 30252419Sjulian ERROUT(ENOMEM); 303184205Sdes free(sc->sbuf, M_NETGRAPH_ASYNC); 30452419Sjulian sc->sbuf = buf; 30552419Sjulian sc->amode = MODE_HUNT; 30652419Sjulian sc->slen = 0; 30752419Sjulian } 30852419Sjulian if (!cfg->enabled) { 30952419Sjulian sc->amode = MODE_HUNT; 31052419Sjulian sc->slen = 0; 31152419Sjulian } 31252419Sjulian sc->cfg = *cfg; 31352419Sjulian break; 31452419Sjulian } 31552419Sjulian case NGM_ASYNC_CMD_GET_CONFIG: 31652419Sjulian NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT); 31752419Sjulian if (!resp) 31852419Sjulian ERROUT(ENOMEM); 31952419Sjulian *((struct ng_async_cfg *) resp->data) = sc->cfg; 32052419Sjulian break; 32152419Sjulian default: 32252419Sjulian ERROUT(EINVAL); 32352419Sjulian } 32452419Sjulian break; 32552419Sjulian default: 32652419Sjulian ERROUT(EINVAL); 32752419Sjulian } 32852419Sjuliandone: 32970700Sjulian NG_RESPOND_MSG(error, node, item, resp); 33070700Sjulian NG_FREE_MSG(msg); 33152419Sjulian return (error); 33252419Sjulian} 33352419Sjulian 33452419Sjulian/* 33552419Sjulian * Shutdown this node 33652419Sjulian */ 33752419Sjulianstatic int 33852419Sjuliannga_shutdown(node_p node) 33952419Sjulian{ 34070784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 34152419Sjulian 342184205Sdes free(sc->abuf, M_NETGRAPH_ASYNC); 343184205Sdes free(sc->sbuf, M_NETGRAPH_ASYNC); 34452419Sjulian bzero(sc, sizeof(*sc)); 345184205Sdes free(sc, M_NETGRAPH_ASYNC); 34670784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 34770784Sjulian NG_NODE_UNREF(node); 34852419Sjulian return (0); 34952419Sjulian} 35052419Sjulian 35152419Sjulian/* 35252419Sjulian * Lose a hook. When both hooks go away, we disappear. 35352419Sjulian */ 35452419Sjulianstatic int 35552419Sjuliannga_disconnect(hook_p hook) 35652419Sjulian{ 35770784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 35852419Sjulian hook_p *hookp; 35952419Sjulian 36052419Sjulian if (hook == sc->async) 36152419Sjulian hookp = &sc->async; 36252419Sjulian else if (hook == sc->sync) 36352419Sjulian hookp = &sc->sync; 36452419Sjulian else 365213794Srpaulo panic("%s", __func__); 36652419Sjulian if (!*hookp) 36787599Sobrien panic("%s 2", __func__); 36852419Sjulian *hookp = NULL; 36952419Sjulian bzero(&sc->stats, sizeof(sc->stats)); 37052419Sjulian sc->lasttime = 0; 37170784Sjulian if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 37270784Sjulian && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 37370784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 37452419Sjulian return (0); 37552419Sjulian} 37652419Sjulian 37752419Sjulian/****************************************************************** 37852419Sjulian INTERNAL HELPER STUFF 37952419Sjulian******************************************************************/ 38052419Sjulian 38152419Sjulian/* 38252419Sjulian * Encode a byte into the async buffer 38352419Sjulian */ 384131575Sstefanfstatic __inline void 38552419Sjuliannga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x) 38652419Sjulian{ 38752419Sjulian *fcs = PPP_FCS(*fcs, x); 38852419Sjulian if ((x < 32 && ((1 << x) & accm)) 38952419Sjulian || (x == PPP_ESCAPE) 39052419Sjulian || (x == PPP_FLAG)) { 39152419Sjulian sc->abuf[(*len)++] = PPP_ESCAPE; 39252419Sjulian x ^= PPP_TRANS; 39352419Sjulian } 39452419Sjulian sc->abuf[(*len)++] = x; 39552419Sjulian} 39652419Sjulian 39752419Sjulian/* 39852976Sarchie * Receive incoming synchronous data. 39952419Sjulian */ 40052419Sjulianstatic int 40170700Sjuliannga_rcv_sync(const sc_p sc, item_p item) 40252419Sjulian{ 40370700Sjulian struct ifnet *rcvif; 40453394Sarchie int alen, error = 0; 40552976Sarchie struct timeval time; 40652419Sjulian u_int16_t fcs, fcs0; 40752976Sarchie u_int32_t accm; 40870700Sjulian struct mbuf *m; 40952419Sjulian 41070700Sjulian 41152976Sarchie#define ADD_BYTE(x) nga_async_add(sc, &fcs, accm, &alen, (x)) 41252419Sjulian 41352976Sarchie /* Check for bypass mode */ 41452419Sjulian if (!sc->cfg.enabled) { 41570784Sjulian NG_FWD_ITEM_HOOK(error, item, sc->async ); 41652419Sjulian return (error); 41752419Sjulian } 41870700Sjulian NGI_GET_M(item, m); 41952976Sarchie 42070700Sjulian rcvif = m->m_pkthdr.rcvif; 42170700Sjulian 42253394Sarchie /* Get ACCM; special case LCP frames, which use full ACCM */ 42352976Sarchie accm = sc->cfg.accm; 42453394Sarchie if (m->m_pkthdr.len >= 4) { 42553394Sarchie static const u_char lcphdr[4] = { 42653394Sarchie PPP_ALLSTATIONS, 42753394Sarchie PPP_UI, 42853394Sarchie (u_char)(PPP_LCP >> 8), 42953394Sarchie (u_char)(PPP_LCP & 0xff) 43053394Sarchie }; 43153394Sarchie u_char buf[4]; 43252976Sarchie 43353394Sarchie m_copydata(m, 0, 4, (caddr_t)buf); 43453394Sarchie if (bcmp(buf, &lcphdr, 4) == 0) 43552976Sarchie accm = ~0; 43652976Sarchie } 43752976Sarchie 43852976Sarchie /* Check for overflow */ 43952419Sjulian if (m->m_pkthdr.len > sc->cfg.smru) { 44052419Sjulian sc->stats.syncOverflows++; 44170700Sjulian NG_FREE_M(m); 44270700Sjulian NG_FREE_ITEM(item); 44352419Sjulian return (EMSGSIZE); 44452419Sjulian } 44552976Sarchie 44652976Sarchie /* Update stats */ 44752419Sjulian sc->stats.syncFrames++; 44852419Sjulian sc->stats.syncOctets += m->m_pkthdr.len; 44952419Sjulian 45052419Sjulian /* Initialize async encoded version of input mbuf */ 45152419Sjulian alen = 0; 45252419Sjulian fcs = PPP_INITFCS; 45352419Sjulian 45452419Sjulian /* Add beginning sync flag if it's been long enough to need one */ 45552976Sarchie getmicrotime(&time); 45652976Sarchie if (time.tv_sec >= sc->lasttime + 1) { 45752976Sarchie sc->abuf[alen++] = PPP_FLAG; 45852976Sarchie sc->lasttime = time.tv_sec; 45952419Sjulian } 46052419Sjulian 46153394Sarchie /* Add packet payload */ 46252976Sarchie while (m != NULL) { 46352419Sjulian while (m->m_len > 0) { 46452976Sarchie ADD_BYTE(*mtod(m, u_char *)); 46552419Sjulian m->m_data++; 46652419Sjulian m->m_len--; 46752419Sjulian } 46890227Sdillon m = m_free(m); 46952419Sjulian } 47052419Sjulian 47152419Sjulian /* Add checksum and final sync flag */ 47252419Sjulian fcs0 = fcs; 47352419Sjulian ADD_BYTE(~fcs0 & 0xff); 47452419Sjulian ADD_BYTE(~fcs0 >> 8); 47552419Sjulian sc->abuf[alen++] = PPP_FLAG; 47652419Sjulian 47752419Sjulian /* Put frame in an mbuf and ship it off */ 47852976Sarchie if (!(m = m_devget(sc->abuf, alen, 0, rcvif, NULL))) { 47970700Sjulian NG_FREE_ITEM(item); 48052419Sjulian error = ENOBUFS; 48170700Sjulian } else { 48270700Sjulian NG_FWD_NEW_DATA(error, item, sc->async, m); 48370700Sjulian } 48452419Sjulian return (error); 48552419Sjulian} 48652419Sjulian 48752419Sjulian/* 48852419Sjulian * Receive incoming asynchronous data 48952976Sarchie * XXX Technically, we should strip out incoming characters 49052976Sarchie * that are in our ACCM. Not sure if this is good or not. 49152419Sjulian */ 49252419Sjulianstatic int 49370700Sjuliannga_rcv_async(const sc_p sc, item_p item) 49452419Sjulian{ 49570700Sjulian struct ifnet *rcvif; 49652419Sjulian int error; 49770700Sjulian struct mbuf *m; 49852419Sjulian 49952419Sjulian if (!sc->cfg.enabled) { 50070784Sjulian NG_FWD_ITEM_HOOK(error, item, sc->sync); 50152419Sjulian return (error); 50252419Sjulian } 50370700Sjulian NGI_GET_M(item, m); 50470700Sjulian rcvif = m->m_pkthdr.rcvif; 50552419Sjulian while (m) { 50652419Sjulian struct mbuf *n; 50752419Sjulian 50852419Sjulian for (; m->m_len > 0; m->m_data++, m->m_len--) { 50952419Sjulian u_char ch = *mtod(m, u_char *); 51052419Sjulian 51152419Sjulian sc->stats.asyncOctets++; 51252419Sjulian if (ch == PPP_FLAG) { /* Flag overrides everything */ 51352419Sjulian int skip = 0; 51452419Sjulian 51552419Sjulian /* Check for runts */ 51652419Sjulian if (sc->slen < 2) { 51752419Sjulian if (sc->slen > 0) 51852419Sjulian sc->stats.asyncRunts++; 51952419Sjulian goto reset; 52052419Sjulian } 52152419Sjulian 52252419Sjulian /* Verify CRC */ 52352419Sjulian if (sc->fcs != PPP_GOODFCS) { 52452419Sjulian sc->stats.asyncBadCheckSums++; 52552419Sjulian goto reset; 52652419Sjulian } 52752419Sjulian sc->slen -= 2; 52852419Sjulian 52952419Sjulian /* Strip address and control fields */ 53052419Sjulian if (sc->slen >= 2 53152419Sjulian && sc->sbuf[0] == PPP_ALLSTATIONS 53252419Sjulian && sc->sbuf[1] == PPP_UI) 53352419Sjulian skip = 2; 53452419Sjulian 53552419Sjulian /* Check for frame too big */ 53652419Sjulian if (sc->slen - skip > sc->cfg.amru) { 53752419Sjulian sc->stats.asyncOverflows++; 53852419Sjulian goto reset; 53952419Sjulian } 54052419Sjulian 54152419Sjulian /* OK, ship it out */ 54252419Sjulian if ((n = m_devget(sc->sbuf + skip, 54370700Sjulian sc->slen - skip, 0, rcvif, NULL))) { 54470700Sjulian if (item) { /* sets NULL -> item */ 54570700Sjulian NG_FWD_NEW_DATA(error, item, 54670700Sjulian sc->sync, n); 54770700Sjulian } else { 54870700Sjulian NG_SEND_DATA_ONLY(error, 54970700Sjulian sc->sync ,n); 55070700Sjulian } 55170700Sjulian } 55252419Sjulian sc->stats.asyncFrames++; 55352419Sjulianreset: 55452419Sjulian sc->amode = MODE_NORMAL; 55552419Sjulian sc->fcs = PPP_INITFCS; 55652419Sjulian sc->slen = 0; 55752419Sjulian continue; 55852419Sjulian } 55952419Sjulian switch (sc->amode) { 56052419Sjulian case MODE_NORMAL: 56152419Sjulian if (ch == PPP_ESCAPE) { 56252419Sjulian sc->amode = MODE_ESC; 56352419Sjulian continue; 56452419Sjulian } 56552419Sjulian break; 56652419Sjulian case MODE_ESC: 56752419Sjulian ch ^= PPP_TRANS; 56852419Sjulian sc->amode = MODE_NORMAL; 56952419Sjulian break; 57052419Sjulian case MODE_HUNT: 57152419Sjulian default: 57252419Sjulian continue; 57352419Sjulian } 57452419Sjulian 57552419Sjulian /* Add byte to frame */ 57652419Sjulian if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) { 57752419Sjulian sc->stats.asyncOverflows++; 57852419Sjulian sc->amode = MODE_HUNT; 57952419Sjulian sc->slen = 0; 58052419Sjulian } else { 58152419Sjulian sc->sbuf[sc->slen++] = ch; 58252419Sjulian sc->fcs = PPP_FCS(sc->fcs, ch); 58352419Sjulian } 58452419Sjulian } 58590227Sdillon m = m_free(m); 58652419Sjulian } 58770700Sjulian if (item) 58870700Sjulian NG_FREE_ITEM(item); 58952419Sjulian return (0); 59052419Sjulian} 59152419Sjulian 59252419Sjulian/* 59352419Sjulian * CRC table 59452419Sjulian * 59552419Sjulian * Taken from RFC 1171 Appendix B 59652419Sjulian */ 59752419Sjulianstatic const u_int16_t fcstab[256] = { 59852419Sjulian 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 59952419Sjulian 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 60052419Sjulian 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 60152419Sjulian 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 60252419Sjulian 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 60352419Sjulian 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 60452419Sjulian 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 60552419Sjulian 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 60652419Sjulian 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 60752419Sjulian 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 60852419Sjulian 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 60952419Sjulian 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 61052419Sjulian 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 61152419Sjulian 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 61252419Sjulian 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 61352419Sjulian 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 61452419Sjulian 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 61552419Sjulian 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 61652419Sjulian 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 61752419Sjulian 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 61852419Sjulian 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 61952419Sjulian 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 62052419Sjulian 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 62152419Sjulian 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 62252419Sjulian 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 62352419Sjulian 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 62452419Sjulian 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 62552419Sjulian 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 62652419Sjulian 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 62752419Sjulian 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 62852419Sjulian 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 62952419Sjulian 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 63052419Sjulian}; 631