async.c revision 30715
1/*
2 *	             PPP Async HDLC Module
3 *
4 *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc.  The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $Id: async.c,v 1.11 1997/08/25 00:29:05 brian Exp $
21 *
22 */
23#include <sys/param.h>
24#include <netinet/in.h>
25
26#include <stdio.h>
27#include <string.h>
28#include <termios.h>
29
30#include "mbuf.h"
31#include "log.h"
32#include "defs.h"
33#include "timer.h"
34#include "fsm.h"
35#include "hdlc.h"
36#include "lcp.h"
37#include "lcpproto.h"
38#include "modem.h"
39#include "loadalias.h"
40#include "command.h"
41#include "vars.h"
42#include "os.h"
43#include "async.h"
44
45#define HDLCSIZE	(MAX_MRU*2+6)
46
47static struct async_state {
48  int mode;
49  int length;
50  u_char hbuff[HDLCSIZE];	/* recv buffer */
51  u_char xbuff[HDLCSIZE];	/* xmit buffer */
52  u_long my_accmap;
53  u_long his_accmap;
54} AsyncState;
55
56#define MODE_HUNT 0x01
57#define MODE_ESC  0x02
58
59void
60AsyncInit()
61{
62  struct async_state *stp = &AsyncState;
63
64  stp->mode = MODE_HUNT;
65  stp->length = 0;
66  stp->my_accmap = stp->his_accmap = 0xffffffff;
67}
68
69void
70SetLinkParams(struct lcpstate *lcp)
71{
72  struct async_state *stp = &AsyncState;
73
74  stp->my_accmap = lcp->want_accmap;
75  stp->his_accmap = lcp->his_accmap;
76}
77
78/*
79 * Encode into async HDLC byte code if necessary
80 */
81static void
82HdlcPutByte(u_char **cp, u_char c, int proto)
83{
84  u_char *wp;
85
86  wp = *cp;
87  if ((c < 0x20 && (proto == PROTO_LCP || (AsyncState.his_accmap & (1 << c))))
88      || (c == HDLC_ESC) || (c == HDLC_SYN)) {
89    *wp++ = HDLC_ESC;
90    c ^= HDLC_XOR;
91  }
92  if (EscMap[32] && EscMap[c >> 3] & (1 << (c & 7))) {
93    *wp++ = HDLC_ESC;
94    c ^= HDLC_XOR;
95  }
96  *wp++ = c;
97  *cp = wp;
98}
99
100void
101AsyncOutput(int pri, struct mbuf *bp, int proto)
102{
103  struct async_state *hs = &AsyncState;
104  u_char *cp, *sp, *ep;
105  struct mbuf *wp;
106  int cnt;
107
108  if (plength(bp) > HDLCSIZE) {
109    pfree(bp);
110    return;
111  }
112  cp = hs->xbuff;
113  ep = cp + HDLCSIZE - 10;
114  wp = bp;
115  *cp++ = HDLC_SYN;
116  while (wp) {
117    sp = MBUF_CTOP(wp);
118    for (cnt = wp->cnt; cnt > 0; cnt--) {
119      HdlcPutByte(&cp, *sp++, proto);
120      if (cp >= ep) {
121	pfree(bp);
122	return;
123      }
124    }
125    wp = wp->next;
126  }
127  *cp++ = HDLC_SYN;
128
129  cnt = cp - hs->xbuff;
130  LogDumpBuff(LogASYNC, "WriteModem", hs->xbuff, cnt);
131  WriteModem(pri, (char *) hs->xbuff, cnt);
132  OsAddOutOctets(cnt);
133  pfree(bp);
134}
135
136static struct mbuf *
137AsyncDecode(u_char c)
138{
139  struct async_state *hs = &AsyncState;
140  struct mbuf *bp;
141
142  if ((hs->mode & MODE_HUNT) && c != HDLC_SYN)
143    return (NULLBUFF);
144
145  switch (c) {
146  case HDLC_SYN:
147    hs->mode &= ~MODE_HUNT;
148    if (hs->length) {		/* packet is ready. */
149      bp = mballoc(hs->length, MB_ASYNC);
150      mbwrite(bp, hs->hbuff, hs->length);
151      hs->length = 0;
152      return (bp);
153    }
154    break;
155  case HDLC_ESC:
156    if (!(hs->mode & MODE_ESC)) {
157      hs->mode |= MODE_ESC;
158      break;
159    }
160    /* Fall into ... */
161  default:
162    if (hs->length >= HDLCSIZE) {
163      /* packet is too large, discard it */
164      LogPrintf(LogERROR, "Packet too large (%d), discarding.\n", hs->length);
165      hs->length = 0;
166      hs->mode = MODE_HUNT;
167      break;
168    }
169    if (hs->mode & MODE_ESC) {
170      c ^= HDLC_XOR;
171      hs->mode &= ~MODE_ESC;
172    }
173    hs->hbuff[hs->length++] = c;
174    break;
175  }
176  return NULLBUFF;
177}
178
179void
180AsyncInput(u_char *buff, int cnt)
181{
182  struct mbuf *bp;
183
184  OsAddInOctets(cnt);
185  if (DEV_IS_SYNC) {
186    bp = mballoc(cnt, MB_ASYNC);
187    memcpy(MBUF_CTOP(bp), buff, cnt);
188    bp->cnt = cnt;
189    HdlcInput(bp);
190  } else {
191    while (cnt > 0) {
192      bp = AsyncDecode(*buff++);
193      if (bp)
194	HdlcInput(bp);
195      cnt--;
196    }
197  }
198}
199