nrelease - fix/improve livecd
[dragonfly.git] / sys / netgraph / async / ng_async.c
1
2 /*
3  * ng_async.c
4  *
5  * Copyright (c) 1996-1999 Whistle Communications, Inc.
6  * All rights reserved.
7  * 
8  * Subject to the following obligations and disclaimer of warranty, use and
9  * redistribution of this software, in source or object code forms, with or
10  * without modifications are expressly permitted by Whistle Communications;
11  * provided, however, that:
12  * 1. Any and all reproductions of the source or object code must include the
13  *    copyright notice above and the following disclaimer of warranties; and
14  * 2. No rights are granted, in any manner or form, to use Whistle
15  *    Communications, Inc. trademarks, including the mark "WHISTLE
16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17  *    such appears in the above copyright notice or in the software.
18  * 
19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35  * OF SUCH DAMAGE.
36  *
37  * Author: Archie Cobbs <archie@freebsd.org>
38  *
39  * $FreeBSD: src/sys/netgraph/ng_async.c,v 1.6.2.5 2002/07/02 23:44:02 archie Exp $
40  * $Whistle: ng_async.c,v 1.17 1999/11/01 09:24:51 julian Exp $
41  */
42
43 /*
44  * This node type implements a PPP style sync <-> async converter.
45  * See RFC 1661 for details of how asynchronous encoding works.
46  */
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/mbuf.h>
52 #include <sys/malloc.h>
53 #include <sys/errno.h>
54
55 #include <netgraph/ng_message.h>
56 #include <netgraph/netgraph.h>
57 #include "ng_async.h"
58 #include <netgraph/ng_parse.h>
59
60 #include <net/ppp_layer/ppp_defs.h>
61
62 /* Async decode state */
63 #define MODE_HUNT       0
64 #define MODE_NORMAL     1
65 #define MODE_ESC        2
66
67 /* Private data structure */
68 struct ng_async_private {
69         node_p          node;           /* Our node */
70         hook_p          async;          /* Asynchronous side */
71         hook_p          sync;           /* Synchronous side */
72         u_char          amode;          /* Async hunt/esape mode */
73         u_int16_t       fcs;            /* Decoded async FCS (so far) */
74         u_char         *abuf;           /* Buffer to encode sync into */
75         u_char         *sbuf;           /* Buffer to decode async into */
76         u_int           slen;           /* Length of data in sbuf */
77         long            lasttime;       /* Time of last async packet sent */
78         struct          ng_async_cfg    cfg;    /* Configuration */
79         struct          ng_async_stat   stats;  /* Statistics */
80 };
81 typedef struct ng_async_private *sc_p;
82
83 /* Useful macros */
84 #define ASYNC_BUF_SIZE(smru)    (2 * (smru) + 10)
85 #define SYNC_BUF_SIZE(amru)     ((amru) + 10)
86 #define ERROUT(x)               do { error = (x); goto done; } while (0)
87
88 /* Netgraph methods */
89 static ng_constructor_t         nga_constructor;
90 static ng_rcvdata_t             nga_rcvdata;
91 static ng_rcvmsg_t              nga_rcvmsg;
92 static ng_shutdown_t            nga_shutdown;
93 static ng_newhook_t             nga_newhook;
94 static ng_disconnect_t          nga_disconnect;
95
96 /* Helper stuff */
97 static int      nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta);
98 static int      nga_rcv_async(const sc_p sc, struct mbuf *m, meta_p meta);
99
100 /* Parse type for struct ng_async_cfg */
101 static const struct ng_parse_struct_field nga_config_type_fields[]
102         = NG_ASYNC_CONFIG_TYPE_INFO;
103 static const struct ng_parse_type nga_config_type = {
104         &ng_parse_struct_type,
105         &nga_config_type_fields
106 };
107
108 /* Parse type for struct ng_async_stat */
109 static const struct ng_parse_struct_field nga_stats_type_fields[]
110         = NG_ASYNC_STATS_TYPE_INFO;
111 static const struct ng_parse_type nga_stats_type = {
112         &ng_parse_struct_type,
113         &nga_stats_type_fields
114 };
115
116 /* List of commands and how to convert arguments to/from ASCII */
117 static const struct ng_cmdlist nga_cmdlist[] = {
118         {
119           NGM_ASYNC_COOKIE,
120           NGM_ASYNC_CMD_SET_CONFIG,
121           "setconfig",
122           &nga_config_type,
123           NULL
124         },
125         {
126           NGM_ASYNC_COOKIE,
127           NGM_ASYNC_CMD_GET_CONFIG,
128           "getconfig",
129           NULL,
130           &nga_config_type
131         },
132         {
133           NGM_ASYNC_COOKIE,
134           NGM_ASYNC_CMD_GET_STATS,
135           "getstats",
136           NULL,
137           &nga_stats_type
138         },
139         {
140           NGM_ASYNC_COOKIE,
141           NGM_ASYNC_CMD_CLR_STATS,
142           "clrstats",
143           &nga_stats_type,
144           NULL
145         },
146         { 0 }
147 };
148
149 /* Define the netgraph node type */
150 static struct ng_type typestruct = {
151         NG_VERSION,
152         NG_ASYNC_NODE_TYPE,
153         NULL,
154         nga_constructor,
155         nga_rcvmsg,
156         nga_shutdown,
157         nga_newhook,
158         NULL,
159         NULL,
160         nga_rcvdata,
161         nga_rcvdata,
162         nga_disconnect,
163         nga_cmdlist
164 };
165 NETGRAPH_INIT(async, &typestruct);
166
167 /*
168  * CRC table
169  *
170  * Taken from RFC 1171 Appendix B
171  */
172 static const u_int16_t fcstab[256] = {
173          0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
174          0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
175          0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
176          0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
177          0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
178          0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
179          0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
180          0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
181          0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
182          0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
183          0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
184          0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
185          0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
186          0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
187          0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
188          0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
189          0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
190          0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
191          0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
192          0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
193          0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
194          0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
195          0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
196          0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
197          0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
198          0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
199          0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
200          0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
201          0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
202          0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
203          0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
204          0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
205 };
206
207 /******************************************************************
208                     NETGRAPH NODE METHODS
209 ******************************************************************/
210
211 /*
212  * Initialize a new node
213  */
214 static int
215 nga_constructor(node_p *nodep)
216 {
217         sc_p sc;
218         int error;
219
220         if ((error = ng_make_node_common(&typestruct, nodep)))
221                 return (error);
222         sc = kmalloc(sizeof(*sc), M_NETGRAPH, M_NOWAIT | M_ZERO);
223         if (sc == NULL)
224                 return (ENOMEM);
225         sc->amode = MODE_HUNT;
226         sc->cfg.accm = ~0;
227         sc->cfg.amru = NG_ASYNC_DEFAULT_MRU;
228         sc->cfg.smru = NG_ASYNC_DEFAULT_MRU;
229         sc->abuf = kmalloc(ASYNC_BUF_SIZE(sc->cfg.smru), M_NETGRAPH, M_NOWAIT);
230         if (sc->abuf == NULL)
231                 goto fail;
232         sc->sbuf = kmalloc(SYNC_BUF_SIZE(sc->cfg.amru), M_NETGRAPH, M_NOWAIT);
233         if (sc->sbuf == NULL) {
234                 kfree(sc->abuf, M_NETGRAPH);
235 fail:
236                 kfree(sc, M_NETGRAPH);
237                 return (ENOMEM);
238         }
239         (*nodep)->private = sc;
240         sc->node = *nodep;
241         return (0);
242 }
243
244 /*
245  * Reserve a hook for a pending connection
246  */
247 static int
248 nga_newhook(node_p node, hook_p hook, const char *name)
249 {
250         const sc_p sc = node->private;
251         hook_p *hookp;
252
253         if (!strcmp(name, NG_ASYNC_HOOK_ASYNC))
254                 hookp = &sc->async;
255         else if (!strcmp(name, NG_ASYNC_HOOK_SYNC))
256                 hookp = &sc->sync;
257         else
258                 return (EINVAL);
259         if (*hookp)
260                 return (EISCONN);
261         *hookp = hook;
262         return (0);
263 }
264
265 /*
266  * Receive incoming data
267  */
268 static int
269 nga_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
270 {
271         const sc_p sc = hook->node->private;
272
273         if (hook == sc->sync)
274                 return (nga_rcv_sync(sc, m, meta));
275         if (hook == sc->async)
276                 return (nga_rcv_async(sc, m, meta));
277         panic(__func__);
278 }
279
280 /*
281  * Receive incoming control message
282  */
283 static int
284 nga_rcvmsg(node_p node, struct ng_mesg *msg,
285         const char *rtn, struct ng_mesg **rptr)
286 {
287         const sc_p sc = (sc_p) node->private;
288         struct ng_mesg *resp = NULL;
289         int error = 0;
290
291         switch (msg->header.typecookie) {
292         case NGM_ASYNC_COOKIE:
293                 switch (msg->header.cmd) {
294                 case NGM_ASYNC_CMD_GET_STATS:
295                         NG_MKRESPONSE(resp, msg, sizeof(sc->stats), M_NOWAIT);
296                         if (resp == NULL)
297                                 ERROUT(ENOMEM);
298                         *((struct ng_async_stat *) resp->data) = sc->stats;
299                         break;
300                 case NGM_ASYNC_CMD_CLR_STATS:
301                         bzero(&sc->stats, sizeof(sc->stats));
302                         break;
303                 case NGM_ASYNC_CMD_SET_CONFIG:
304                     {
305                         struct ng_async_cfg *const cfg =
306                                 (struct ng_async_cfg *) msg->data;
307                         u_char *buf;
308
309                         if (msg->header.arglen != sizeof(*cfg))
310                                 ERROUT(EINVAL);
311                         if (cfg->amru < NG_ASYNC_MIN_MRU
312                             || cfg->amru > NG_ASYNC_MAX_MRU
313                             || cfg->smru < NG_ASYNC_MIN_MRU
314                             || cfg->smru > NG_ASYNC_MAX_MRU)
315                                 ERROUT(EINVAL);
316                         cfg->enabled = !!cfg->enabled;  /* normalize */
317                         if (cfg->smru > sc->cfg.smru) { /* reallocate buffer */
318                                 buf = kmalloc(ASYNC_BUF_SIZE(cfg->smru),
319                                               M_NETGRAPH, M_NOWAIT);
320                                 if (!buf)
321                                         ERROUT(ENOMEM);
322                                 kfree(sc->abuf, M_NETGRAPH);
323                                 sc->abuf = buf;
324                         }
325                         if (cfg->amru > sc->cfg.amru) { /* reallocate buffer */
326                                 buf = kmalloc(SYNC_BUF_SIZE(cfg->amru),
327                                               M_NETGRAPH, M_NOWAIT);
328                                 if (!buf)
329                                         ERROUT(ENOMEM);
330                                 kfree(sc->sbuf, M_NETGRAPH);
331                                 sc->sbuf = buf;
332                                 sc->amode = MODE_HUNT;
333                                 sc->slen = 0;
334                         }
335                         if (!cfg->enabled) {
336                                 sc->amode = MODE_HUNT;
337                                 sc->slen = 0;
338                         }
339                         sc->cfg = *cfg;
340                         break;
341                     }
342                 case NGM_ASYNC_CMD_GET_CONFIG:
343                         NG_MKRESPONSE(resp, msg, sizeof(sc->cfg), M_NOWAIT);
344                         if (!resp)
345                                 ERROUT(ENOMEM);
346                         *((struct ng_async_cfg *) resp->data) = sc->cfg;
347                         break;
348                 default:
349                         ERROUT(EINVAL);
350                 }
351                 break;
352         default:
353                 ERROUT(EINVAL);
354         }
355         if (rptr)
356                 *rptr = resp;
357         else if (resp)
358                 kfree(resp, M_NETGRAPH);
359
360 done:
361         kfree(msg, M_NETGRAPH);
362         return (error);
363 }
364
365 /*
366  * Shutdown this node
367  */
368 static int
369 nga_shutdown(node_p node)
370 {
371         const sc_p sc = node->private;
372
373         ng_cutlinks(node);
374         ng_unname(node);
375         kfree(sc->abuf, M_NETGRAPH);
376         kfree(sc->sbuf, M_NETGRAPH);
377         bzero(sc, sizeof(*sc));
378         kfree(sc, M_NETGRAPH);
379         node->private = NULL;
380         ng_unref(node);
381         return (0);
382 }
383
384 /*
385  * Lose a hook. When both hooks go away, we disappear.
386  */
387 static int
388 nga_disconnect(hook_p hook)
389 {
390         const sc_p sc = hook->node->private;
391         hook_p *hookp;
392
393         if (hook == sc->async)
394                 hookp = &sc->async;
395         else if (hook == sc->sync)
396                 hookp = &sc->sync;
397         else
398                 panic(__func__);
399         if (!*hookp)
400                 panic("%s2", __func__);
401         *hookp = NULL;
402         bzero(&sc->stats, sizeof(sc->stats));
403         sc->lasttime = 0;
404         if (hook->node->numhooks == 0)
405                 ng_rmnode(hook->node);
406         return (0);
407 }
408
409 /******************************************************************
410                     INTERNAL HELPER STUFF
411 ******************************************************************/
412
413 /*
414  * Encode a byte into the async buffer
415  */
416 static __inline__ void
417 nga_async_add(const sc_p sc, u_int16_t *fcs, u_int32_t accm, int *len, u_char x)
418 {
419         *fcs = PPP_FCS(*fcs, x);
420         if ((x < 32 && ((1 << x) & accm))
421             || (x == PPP_ESCAPE)
422             || (x == PPP_FLAG)) {
423                 sc->abuf[(*len)++] = PPP_ESCAPE;
424                 x ^= PPP_TRANS;
425         }
426         sc->abuf[(*len)++] = x;
427 }
428
429 /*
430  * Receive incoming synchronous data.
431  */
432 static int
433 nga_rcv_sync(const sc_p sc, struct mbuf *m, meta_p meta)
434 {
435         struct ifnet *const rcvif = m->m_pkthdr.rcvif;
436         int alen, error = 0;
437         struct timeval time;
438         u_int16_t fcs, fcs0;
439         u_int32_t accm;
440
441 #define ADD_BYTE(x)     nga_async_add(sc, &fcs, accm, &alen, (x))
442
443         /* Check for bypass mode */
444         if (!sc->cfg.enabled) {
445                 NG_SEND_DATA(error, sc->async, m, meta);
446                 return (error);
447         }
448
449         /* Get ACCM; special case LCP frames, which use full ACCM */
450         accm = sc->cfg.accm;
451         if (m->m_pkthdr.len >= 4) {
452                 static const u_char lcphdr[4] = {
453                     PPP_ALLSTATIONS,
454                     PPP_UI,
455                     (u_char)(PPP_LCP >> 8),
456                     (u_char)(PPP_LCP & 0xff)
457                 };
458                 u_char buf[4];
459
460                 m_copydata(m, 0, 4, buf);
461                 if (bcmp(buf, &lcphdr, 4) == 0)
462                         accm = ~0;
463         }
464
465         /* Check for overflow */
466         if (m->m_pkthdr.len > sc->cfg.smru) {
467                 sc->stats.syncOverflows++;
468                 NG_FREE_DATA(m, meta);
469                 return (EMSGSIZE);
470         }
471
472         /* Update stats */
473         sc->stats.syncFrames++;
474         sc->stats.syncOctets += m->m_pkthdr.len;
475
476         /* Initialize async encoded version of input mbuf */
477         alen = 0;
478         fcs = PPP_INITFCS;
479
480         /* Add beginning sync flag if it's been long enough to need one */
481         getmicrotime(&time);
482         if (time.tv_sec >= sc->lasttime + 1) {
483                 sc->abuf[alen++] = PPP_FLAG;
484                 sc->lasttime = time.tv_sec;
485         }
486
487         /* Add packet payload */
488         while (m != NULL) {
489                 while (m->m_len > 0) {
490                         ADD_BYTE(*mtod(m, u_char *));
491                         m->m_data++;
492                         m->m_len--;
493                 }
494                 m = m_free(m);
495         }
496
497         /* Add checksum and final sync flag */
498         fcs0 = fcs;
499         ADD_BYTE(~fcs0 & 0xff);
500         ADD_BYTE(~fcs0 >> 8);
501         sc->abuf[alen++] = PPP_FLAG;
502
503         /* Put frame in an mbuf and ship it off */
504         if (!(m = m_devget(sc->abuf, alen, 0, rcvif))) {
505                 NG_FREE_META(meta);
506                 error = ENOBUFS;
507         } else {
508                 NG_SEND_DATA(error, sc->async, m, meta);
509         }
510         return (error);
511 }
512
513 /*
514  * Receive incoming asynchronous data
515  * XXX Technically, we should strip out incoming characters
516  *     that are in our ACCM. Not sure if this is good or not.
517  */
518 static int
519 nga_rcv_async(const sc_p sc, struct mbuf * m, meta_p meta)
520 {
521         struct ifnet *const rcvif = m->m_pkthdr.rcvif;
522         int error;
523
524         if (!sc->cfg.enabled) {
525                 NG_SEND_DATA(error, sc->sync, m, meta);
526                 return (error);
527         }
528         NG_FREE_META(meta);
529         while (m) {
530                 struct mbuf *n;
531
532                 for (; m->m_len > 0; m->m_data++, m->m_len--) {
533                         u_char  ch = *mtod(m, u_char *);
534
535                         sc->stats.asyncOctets++;
536                         if (ch == PPP_FLAG) {   /* Flag overrides everything */
537                                 int     skip = 0;
538
539                                 /* Check for runts */
540                                 if (sc->slen < 2) {
541                                         if (sc->slen > 0)
542                                                 sc->stats.asyncRunts++;
543                                         goto reset;
544                                 }
545
546                                 /* Verify CRC */
547                                 if (sc->fcs != PPP_GOODFCS) {
548                                         sc->stats.asyncBadCheckSums++;
549                                         goto reset;
550                                 }
551                                 sc->slen -= 2;
552
553                                 /* Strip address and control fields */
554                                 if (sc->slen >= 2
555                                     && sc->sbuf[0] == PPP_ALLSTATIONS
556                                     && sc->sbuf[1] == PPP_UI)
557                                         skip = 2;
558
559                                 /* Check for frame too big */
560                                 if (sc->slen - skip > sc->cfg.amru) {
561                                         sc->stats.asyncOverflows++;
562                                         goto reset;
563                                 }
564
565                                 /* OK, ship it out */
566                                 if ((n = m_devget(sc->sbuf + skip,
567                                                   sc->slen - skip,
568                                                   0, rcvif))) {
569                                         NG_SEND_DATA(error, sc->sync, n, meta);
570                                 }
571                                 sc->stats.asyncFrames++;
572 reset:
573                                 sc->amode = MODE_NORMAL;
574                                 sc->fcs = PPP_INITFCS;
575                                 sc->slen = 0;
576                                 continue;
577                         }
578                         switch (sc->amode) {
579                         case MODE_NORMAL:
580                                 if (ch == PPP_ESCAPE) {
581                                         sc->amode = MODE_ESC;
582                                         continue;
583                                 }
584                                 break;
585                         case MODE_ESC:
586                                 ch ^= PPP_TRANS;
587                                 sc->amode = MODE_NORMAL;
588                                 break;
589                         case MODE_HUNT:
590                         default:
591                                 continue;
592                         }
593
594                         /* Add byte to frame */
595                         if (sc->slen >= SYNC_BUF_SIZE(sc->cfg.amru)) {
596                                 sc->stats.asyncOverflows++;
597                                 sc->amode = MODE_HUNT;
598                                 sc->slen = 0;
599                         } else {
600                                 sc->sbuf[sc->slen++] = ch;
601                                 sc->fcs = PPP_FCS(sc->fcs, ch);
602                         }
603                 }
604                 m = m_free(m);
605         }
606         return (0);
607 }