blob: 67a542e987c54b1c946e18101ab4359d5d8c1903 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/*
2 * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC.
3 *
4 * Re-written by Adi Masputra <adi.masputra@sun.com>, based on
5 * the original ppp_ahdlc.c
6 *
7 * Copyright (c) 2000 by Sun Microsystems, Inc.
8 * All rights reserved.
9 *
10 * Permission to use, copy, modify, and distribute this software and its
11 * documentation is hereby granted, provided that the above copyright
12 * notice appears in all copies.
13 *
14 * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
15 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
16 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
17 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
18 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
19 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
20 *
21 * Copyright (c) 1994 Paul Mackerras. All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 *
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 *
30 * 2. Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in
32 * the documentation and/or other materials provided with the
33 * distribution.
34 *
35 * 3. The name(s) of the authors of this software must not be used to
36 * endorse or promote products derived from this software without
37 * prior written permission.
38 *
39 * 4. Redistributions of any form whatsoever must retain the following
40 * acknowledgment:
41 * "This product includes software developed by Paul Mackerras
42 * <paulus@samba.org>".
43 *
44 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
45 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
46 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
47 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
48 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
49 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
50 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
51 *
52 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
55 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
56 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
57 * OR MODIFICATIONS.
58 *
59 * $Id: ppp_ahdlc.c,v 1.2 2007-06-08 04:02:37 gerg Exp $
60 */
61
62/*
63 * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
64 */
65#include <sys/types.h>
66#include <sys/param.h>
67#include <sys/stream.h>
68#include <sys/errno.h>
69
70#ifdef SVR4
71#include <sys/conf.h>
72#include <sys/kmem.h>
73#include <sys/cmn_err.h>
74#include <sys/ddi.h>
75#else
76#include <sys/user.h>
77#ifdef __osf__
78#include <sys/cmn_err.h>
79#endif
80#endif /* SVR4 */
81
82#include <net/ppp_defs.h>
83#include <net/pppio.h>
84#include "ppp_mod.h"
85
86/*
87 * Right now, mutex is only enabled for Solaris 2.x
88 */
89#if defined(SOL2)
90#define USE_MUTEX
91#endif /* SOL2 */
92
93/*
94 * intpointer_t and uintpointer_t are signed and unsigned integer types
95 * large enough to hold any data pointer; that is, data pointers can be
96 * assigned into or from these integer types without losing precision.
97 * On recent Solaris releases, these types are defined in sys/int_types.h,
98 * but not on SunOS 4.x or the earlier Solaris versions.
99 */
100#if defined(_LP64) || defined(_I32LPx)
101typedef long intpointer_t;
102typedef unsigned long uintpointer_t;
103#else
104typedef int intpointer_t;
105typedef unsigned int uintpointer_t;
106#endif
107
108MOD_OPEN_DECL(ahdlc_open);
109MOD_CLOSE_DECL(ahdlc_close);
110static int ahdlc_wput __P((queue_t *, mblk_t *));
111static int ahdlc_rput __P((queue_t *, mblk_t *));
112static void ahdlc_encode __P((queue_t *, mblk_t *));
113static void ahdlc_decode __P((queue_t *, mblk_t *));
114static int msg_byte __P((mblk_t *, unsigned int));
115
116#if defined(SOL2)
117/*
118 * Don't send HDLC start flag is last transmit is within 1.5 seconds -
119 * FLAG_TIME is defined is microseconds
120 */
121#define FLAG_TIME 1500
122#define ABS(x) (x >= 0 ? x : (-x))
123#endif /* SOL2 */
124
125/*
126 * Extract byte i of message mp
127 */
128#define MSG_BYTE(mp, i) ((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \
129 msg_byte((mp), (i)))
130
131/*
132 * Is this LCP packet one we have to transmit using LCP defaults?
133 */
134#define LCP_USE_DFLT(mp) (1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)
135
136/*
137 * Standard STREAMS declarations
138 */
139static struct module_info minfo = {
140 0x7d23, "ppp_ahdl", 0, INFPSZ, 32768, 512
141};
142
143static struct qinit rinit = {
144 ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
145};
146
147static struct qinit winit = {
148 ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
149};
150
151#if defined(SVR4) && !defined(SOL2)
152int phdldevflag = 0;
153#define ppp_ahdlcinfo phdlinfo
154#endif /* defined(SVR4) && !defined(SOL2) */
155
156struct streamtab ppp_ahdlcinfo = {
157 &rinit, /* ptr to st_rdinit */
158 &winit, /* ptr to st_wrinit */
159 NULL, /* ptr to st_muxrinit */
160 NULL, /* ptr to st_muxwinit */
161#if defined(SUNOS4)
162 NULL /* ptr to ptr to st_modlist */
163#endif /* SUNOS4 */
164};
165
166#if defined(SUNOS4)
167int ppp_ahdlc_count = 0; /* open counter */
168#endif /* SUNOS4 */
169
170/*
171 * Per-stream state structure
172 */
173typedef struct ahdlc_state {
174#if defined(USE_MUTEX)
175 kmutex_t lock; /* lock for this structure */
176#endif /* USE_MUTEX */
177 int flags; /* link flags */
178 mblk_t *rx_buf; /* ptr to receive buffer */
179 int rx_buf_size; /* receive buffer size */
180 ushort_t infcs; /* calculated rx HDLC FCS */
181 u_int32_t xaccm[8]; /* 256-bit xmit ACCM */
182 u_int32_t raccm; /* 32-bit rcv ACCM */
183 int mtu; /* interface MTU */
184 int mru; /* link MRU */
185 int unit; /* current PPP unit number */
186 struct pppstat stats; /* statistic structure */
187#if defined(SOL2)
188 clock_t flag_time; /* time in usec between flags */
189 clock_t lbolt; /* last updated lbolt */
190#endif /* SOL2 */
191} ahdlc_state_t;
192
193/*
194 * Values for flags
195 */
196#define ESCAPED 0x100 /* last saw escape char on input */
197#define IFLUSH 0x200 /* flushing input due to error */
198
199/*
200 * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also.
201 */
202#define RCV_FLAGS (RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)
203
204/*
205 * FCS lookup table as calculated by genfcstab.
206 */
207static u_short fcstab[256] = {
208 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
209 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
210 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
211 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
212 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
213 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
214 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
215 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
216 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
217 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
218 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
219 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
220 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
221 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
222 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
223 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
224 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
225 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
226 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
227 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
228 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
229 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
230 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
231 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
232 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
233 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
234 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
235 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
236 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
237 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
238 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
239 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
240};
241
242static u_int32_t paritytab[8] =
243{
244 0x96696996, 0x69969669, 0x69969669, 0x96696996,
245 0x69969669, 0x96696996, 0x96696996, 0x69969669
246};
247
248/*
249 * STREAMS module open (entry) point
250 */
251MOD_OPEN(ahdlc_open)
252{
253 ahdlc_state_t *state;
254
255 /*
256 * Return if it's already opened
257 */
258 if (q->q_ptr) {
259 return 0;
260 }
261
262 /*
263 * This can only be opened as a module
264 */
265 if (sflag != MODOPEN) {
266 return 0;
267 }
268
269 state = (ahdlc_state_t *) ALLOC_NOSLEEP(sizeof(ahdlc_state_t));
270 if (state == 0)
271 OPEN_ERROR(ENOSR);
272 bzero((caddr_t) state, sizeof(ahdlc_state_t));
273
274 q->q_ptr = (caddr_t) state;
275 WR(q)->q_ptr = (caddr_t) state;
276
277#if defined(USE_MUTEX)
278 mutex_init(&state->lock, NULL, MUTEX_DEFAULT, NULL);
279 mutex_enter(&state->lock);
280#endif /* USE_MUTEX */
281
282 state->xaccm[0] = ~0; /* escape 0x00 through 0x1f */
283 state->xaccm[3] = 0x60000000; /* escape 0x7d and 0x7e */
284 state->mru = PPP_MRU; /* default of 1500 bytes */
285#if defined(SOL2)
286 state->flag_time = drv_usectohz(FLAG_TIME);
287#endif /* SOL2 */
288
289#if defined(USE_MUTEX)
290 mutex_exit(&state->lock);
291#endif /* USE_MUTEX */
292
293#if defined(SUNOS4)
294 ppp_ahdlc_count++;
295#endif /* SUNOS4 */
296
297 qprocson(q);
298
299 return 0;
300}
301
302/*
303 * STREAMS module close (exit) point
304 */
305MOD_CLOSE(ahdlc_close)
306{
307 ahdlc_state_t *state;
308
309 qprocsoff(q);
310
311 state = (ahdlc_state_t *) q->q_ptr;
312
313 if (state == 0) {
314 DPRINT("state == 0 in ahdlc_close\n");
315 return 0;
316 }
317
318#if defined(USE_MUTEX)
319 mutex_enter(&state->lock);
320#endif /* USE_MUTEX */
321
322 if (state->rx_buf != 0) {
323 freemsg(state->rx_buf);
324 state->rx_buf = 0;
325 }
326
327#if defined(USE_MUTEX)
328 mutex_exit(&state->lock);
329 mutex_destroy(&state->lock);
330#endif /* USE_MUTEX */
331
332 FREE(q->q_ptr, sizeof(ahdlc_state_t));
333 q->q_ptr = NULL;
334 OTHERQ(q)->q_ptr = NULL;
335
336#if defined(SUNOS4)
337 if (ppp_ahdlc_count)
338 ppp_ahdlc_count--;
339#endif /* SUNOS4 */
340
341 return 0;
342}
343
344/*
345 * Write side put routine
346 */
347static int
348ahdlc_wput(q, mp)
349 queue_t *q;
350 mblk_t *mp;
351{
352 ahdlc_state_t *state;
353 struct iocblk *iop;
354 int error;
355 mblk_t *np;
356 struct ppp_stats *psp;
357
358 state = (ahdlc_state_t *) q->q_ptr;
359 if (state == 0) {
360 DPRINT("state == 0 in ahdlc_wput\n");
361 freemsg(mp);
362 return 0;
363 }
364
365 switch (mp->b_datap->db_type) {
366 case M_DATA:
367 /*
368 * A data packet - do character-stuffing and FCS, and
369 * send it onwards.
370 */
371 ahdlc_encode(q, mp);
372 freemsg(mp);
373 break;
374
375 case M_IOCTL:
376 iop = (struct iocblk *) mp->b_rptr;
377 error = EINVAL;
378 switch (iop->ioc_cmd) {
379 case PPPIO_XACCM:
380 if ((iop->ioc_count < sizeof(u_int32_t)) ||
381 (iop->ioc_count > sizeof(ext_accm))) {
382 break;
383 }
384 if (mp->b_cont == 0) {
385 DPRINT1("ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n", state->unit);
386 break;
387 }
388#if defined(USE_MUTEX)
389 mutex_enter(&state->lock);
390#endif /* USE_MUTEX */
391 bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
392 iop->ioc_count);
393 state->xaccm[2] &= ~0x40000000; /* don't escape 0x5e */
394 state->xaccm[3] |= 0x60000000; /* do escape 0x7d, 0x7e */
395#if defined(USE_MUTEX)
396 mutex_exit(&state->lock);
397#endif /* USE_MUTEX */
398 iop->ioc_count = 0;
399 error = 0;
400 break;
401
402 case PPPIO_RACCM:
403 if (iop->ioc_count != sizeof(u_int32_t))
404 break;
405 if (mp->b_cont == 0) {
406 DPRINT1("ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n", state->unit);
407 break;
408 }
409#if defined(USE_MUTEX)
410 mutex_enter(&state->lock);
411#endif /* USE_MUTEX */
412 bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
413 sizeof(u_int32_t));
414#if defined(USE_MUTEX)
415 mutex_exit(&state->lock);
416#endif /* USE_MUTEX */
417 iop->ioc_count = 0;
418 error = 0;
419 break;
420
421 case PPPIO_GCLEAN:
422 np = allocb(sizeof(int), BPRI_HI);
423 if (np == 0) {
424 error = ENOSR;
425 break;
426 }
427 if (mp->b_cont != 0)
428 freemsg(mp->b_cont);
429 mp->b_cont = np;
430#if defined(USE_MUTEX)
431 mutex_enter(&state->lock);
432#endif /* USE_MUTEX */
433 *(int *)np->b_wptr = state->flags & RCV_FLAGS;
434#if defined(USE_MUTEX)
435 mutex_exit(&state->lock);
436#endif /* USE_MUTEX */
437 np->b_wptr += sizeof(int);
438 iop->ioc_count = sizeof(int);
439 error = 0;
440 break;
441
442 case PPPIO_GETSTAT:
443 np = allocb(sizeof(struct ppp_stats), BPRI_HI);
444 if (np == 0) {
445 error = ENOSR;
446 break;
447 }
448 if (mp->b_cont != 0)
449 freemsg(mp->b_cont);
450 mp->b_cont = np;
451 psp = (struct ppp_stats *) np->b_wptr;
452 np->b_wptr += sizeof(struct ppp_stats);
453 bzero((caddr_t)psp, sizeof(struct ppp_stats));
454 psp->p = state->stats;
455 iop->ioc_count = sizeof(struct ppp_stats);
456 error = 0;
457 break;
458
459 case PPPIO_LASTMOD:
460 /* we knew this anyway */
461 error = 0;
462 break;
463
464 default:
465 error = -1;
466 break;
467 }
468
469 if (error < 0)
470 putnext(q, mp);
471 else if (error == 0) {
472 mp->b_datap->db_type = M_IOCACK;
473 qreply(q, mp);
474 } else {
475 mp->b_datap->db_type = M_IOCNAK;
476 iop->ioc_count = 0;
477 iop->ioc_error = error;
478 qreply(q, mp);
479 }
480 break;
481
482 case M_CTL:
483 switch (*mp->b_rptr) {
484 case PPPCTL_MTU:
485#if defined(USE_MUTEX)
486 mutex_enter(&state->lock);
487#endif /* USE_MUTEX */
488 state->mtu = ((unsigned short *)mp->b_rptr)[1];
489#if defined(USE_MUTEX)
490 mutex_exit(&state->lock);
491#endif /* USE_MUTEX */
492 freemsg(mp);
493 break;
494 case PPPCTL_MRU:
495#if defined(USE_MUTEX)
496 mutex_enter(&state->lock);
497#endif /* USE_MUTEX */
498 state->mru = ((unsigned short *)mp->b_rptr)[1];
499#if defined(USE_MUTEX)
500 mutex_exit(&state->lock);
501#endif /* USE_MUTEX */
502 freemsg(mp);
503 break;
504 case PPPCTL_UNIT:
505#if defined(USE_MUTEX)
506 mutex_enter(&state->lock);
507#endif /* USE_MUTEX */
508 state->unit = mp->b_rptr[1];
509#if defined(USE_MUTEX)
510 mutex_exit(&state->lock);
511#endif /* USE_MUTEX */
512 break;
513 default:
514 putnext(q, mp);
515 }
516 break;
517
518 default:
519 putnext(q, mp);
520 }
521
522 return 0;
523}
524
525/*
526 * Read side put routine
527 */
528static int
529ahdlc_rput(q, mp)
530 queue_t *q;
531 mblk_t *mp;
532{
533 ahdlc_state_t *state;
534
535 state = (ahdlc_state_t *) q->q_ptr;
536 if (state == 0) {
537 DPRINT("state == 0 in ahdlc_rput\n");
538 freemsg(mp);
539 return 0;
540 }
541
542 switch (mp->b_datap->db_type) {
543 case M_DATA:
544 ahdlc_decode(q, mp);
545 break;
546
547 case M_HANGUP:
548#if defined(USE_MUTEX)
549 mutex_enter(&state->lock);
550#endif /* USE_MUTEX */
551 if (state->rx_buf != 0) {
552 /* XXX would like to send this up for debugging */
553 freemsg(state->rx_buf);
554 state->rx_buf = 0;
555 }
556 state->flags = IFLUSH;
557#if defined(USE_MUTEX)
558 mutex_exit(&state->lock);
559#endif /* USE_MUTEX */
560 putnext(q, mp);
561 break;
562
563 default:
564 putnext(q, mp);
565 }
566 return 0;
567}
568
569/*
570 * Extract bit c from map m, to determine if c needs to be escaped
571 */
572#define IN_TX_MAP(c, m) ((m)[(c) >> 5] & (1 << ((c) & 0x1f)))
573
574static void
575ahdlc_encode(q, mp)
576 queue_t *q;
577 mblk_t *mp;
578{
579 ahdlc_state_t *state;
580 u_int32_t *xaccm, loc_xaccm[8];
581 ushort_t fcs;
582 size_t outmp_len;
583 mblk_t *outmp, *tmp;
584 uchar_t *dp, fcs_val;
585 int is_lcp, code;
586#if defined(SOL2)
587 clock_t lbolt;
588#endif /* SOL2 */
589
590 if (msgdsize(mp) < 4) {
591 return;
592 }
593
594 state = (ahdlc_state_t *)q->q_ptr;
595#if defined(USE_MUTEX)
596 mutex_enter(&state->lock);
597#endif /* USE_MUTEX */
598
599 /*
600 * Allocate an output buffer large enough to handle a case where all
601 * characters need to be escaped
602 */
603 outmp_len = (msgdsize(mp) << 1) + /* input block x 2 */
604 (sizeof(fcs) << 2) + /* HDLC FCS x 4 */
605 (sizeof(uchar_t) << 1); /* HDLC flags x 2 */
606
607 outmp = allocb(outmp_len, BPRI_MED);
608 if (outmp == NULL) {
609 state->stats.ppp_oerrors++;
610#if defined(USE_MUTEX)
611 mutex_exit(&state->lock);
612#endif /* USE_MUTEX */
613 putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
614 return;
615 }
616
617#if defined(SOL2)
618 /*
619 * Check if our last transmit happenned within flag_time, using
620 * the system's LBOLT value in clock ticks
621 */
622 if (drv_getparm(LBOLT, &lbolt) != -1) {
623 if (ABS((clock_t)lbolt - state->lbolt) > state->flag_time) {
624 *outmp->b_wptr++ = PPP_FLAG;
625 }
626 state->lbolt = lbolt;
627 } else {
628 *outmp->b_wptr++ = PPP_FLAG;
629 }
630#else
631 /*
632 * If the driver below still has a message to process, skip the
633 * HDLC flag, otherwise, put one in the beginning
634 */
635 if (qsize(q->q_next) == 0) {
636 *outmp->b_wptr++ = PPP_FLAG;
637 }
638#endif
639
640 /*
641 * All control characters must be escaped for LCP packets with code
642 * values between 1 (Conf-Req) and 7 (Code-Rej).
643 */
644 is_lcp = ((MSG_BYTE(mp, 0) == PPP_ALLSTATIONS) &&
645 (MSG_BYTE(mp, 1) == PPP_UI) &&
646 (MSG_BYTE(mp, 2) == (PPP_LCP >> 8)) &&
647 (MSG_BYTE(mp, 3) == (PPP_LCP & 0xff)) &&
648 LCP_USE_DFLT(mp));
649
650 xaccm = state->xaccm;
651 if (is_lcp) {
652 bcopy((caddr_t)state->xaccm, (caddr_t)loc_xaccm, sizeof(loc_xaccm));
653 loc_xaccm[0] = ~0; /* force escape on 0x00 through 0x1f */
654 xaccm = loc_xaccm;
655 }
656
657 fcs = PPP_INITFCS; /* Initial FCS is 0xffff */
658
659 /*
660 * Process this block and the rest (if any) attached to the this one
661 */
662 for (tmp = mp; tmp; tmp = tmp->b_cont) {
663 if (tmp->b_datap->db_type == M_DATA) {
664 for (dp = tmp->b_rptr; dp < tmp->b_wptr; dp++) {
665 fcs = PPP_FCS(fcs, *dp);
666 if (IN_TX_MAP(*dp, xaccm)) {
667 *outmp->b_wptr++ = PPP_ESCAPE;
668 *outmp->b_wptr++ = *dp ^ PPP_TRANS;
669 } else {
670 *outmp->b_wptr++ = *dp;
671 }
672 }
673 } else {
674 continue; /* skip if db_type is something other than M_DATA */
675 }
676 }
677
678 /*
679 * Append the HDLC FCS, making sure that escaping is done on any
680 * necessary bytes
681 */
682 fcs_val = (fcs ^ 0xffff) & 0xff;
683 if (IN_TX_MAP(fcs_val, xaccm)) {
684 *outmp->b_wptr++ = PPP_ESCAPE;
685 *outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
686 } else {
687 *outmp->b_wptr++ = fcs_val;
688 }
689
690 fcs_val = ((fcs ^ 0xffff) >> 8) & 0xff;
691 if (IN_TX_MAP(fcs_val, xaccm)) {
692 *outmp->b_wptr++ = PPP_ESCAPE;
693 *outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
694 } else {
695 *outmp->b_wptr++ = fcs_val;
696 }
697
698 /*
699 * And finally, append the HDLC flag, and send it away
700 */
701 *outmp->b_wptr++ = PPP_FLAG;
702
703 state->stats.ppp_obytes += msgdsize(outmp);
704 state->stats.ppp_opackets++;
705
706#if defined(USE_MUTEX)
707 mutex_exit(&state->lock);
708#endif /* USE_MUTEX */
709
710 putnext(q, outmp);
711 return;
712}
713
714/*
715 * Checks the 32-bit receive ACCM to see if the byte needs un-escaping
716 */
717#define IN_RX_MAP(c, m) ((((unsigned int) (uchar_t) (c)) < 0x20) && \
718 (m) & (1 << (c)))
719
720
721/*
722 * Process received characters.
723 */
724static void
725ahdlc_decode(q, mp)
726 queue_t *q;
727 mblk_t *mp;
728{
729 ahdlc_state_t *state;
730 mblk_t *om;
731 uchar_t *dp;
732
733 state = (ahdlc_state_t *) q->q_ptr;
734
735#if defined(USE_MUTEX)
736 mutex_enter(&state->lock);
737#endif /* USE_MUTEX */
738
739 state->stats.ppp_ibytes += msgdsize(mp);
740
741 for (; mp != 0; om = mp->b_cont, freeb(mp), mp = om)
742 for (dp = mp->b_rptr; dp < mp->b_wptr; dp++) {
743
744 /*
745 * This should detect the lack of 8-bit communication channel
746 * which is necessary for PPP to work. In addition, it also
747 * checks on the parity.
748 */
749 if (*dp & 0x80)
750 state->flags |= RCV_B7_1;
751 else
752 state->flags |= RCV_B7_0;
753
754 if (paritytab[*dp >> 5] & (1 << (*dp & 0x1f)))
755 state->flags |= RCV_ODDP;
756 else
757 state->flags |= RCV_EVNP;
758
759 /*
760 * So we have a HDLC flag ...
761 */
762 if (*dp == PPP_FLAG) {
763
764 /*
765 * If we think that it marks the beginning of the frame,
766 * then continue to process the next octects
767 */
768 if ((state->flags & IFLUSH) ||
769 (state->rx_buf == 0) ||
770 (msgdsize(state->rx_buf) == 0)) {
771
772 state->flags &= ~IFLUSH;
773 continue;
774 }
775
776 /*
777 * We get here because the above condition isn't true,
778 * in which case the HDLC flag was there to mark the end
779 * of the frame (or so we think)
780 */
781 om = state->rx_buf;
782
783 if (state->infcs == PPP_GOODFCS) {
784 state->stats.ppp_ipackets++;
785 adjmsg(om, -PPP_FCSLEN);
786 putnext(q, om);
787 } else {
788 DPRINT2("ppp%d: bad fcs (len=%d)\n",
789 state->unit, msgdsize(state->rx_buf));
790 freemsg(state->rx_buf);
791 state->flags &= ~(IFLUSH | ESCAPED);
792 state->stats.ppp_ierrors++;
793 putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
794 }
795
796 state->rx_buf = 0;
797 continue;
798 }
799
800 if (state->flags & IFLUSH) {
801 continue;
802 }
803
804 /*
805 * Allocate a receive buffer, large enough to store a frame (after
806 * un-escaping) of at least 1500 octets. If MRU is negotiated to
807 * be more than the default, then allocate that much. In addition,
808 * we add an extra 32-bytes for a fudge factor
809 */
810 if (state->rx_buf == 0) {
811 state->rx_buf_size = (state->mru < PPP_MRU ? PPP_MRU : state->mru);
812 state->rx_buf_size += (sizeof(u_int32_t) << 3);
813 state->rx_buf = allocb(state->rx_buf_size, BPRI_MED);
814
815 /*
816 * If allocation fails, try again on the next frame
817 */
818 if (state->rx_buf == 0) {
819 state->flags |= IFLUSH;
820 continue;
821 }
822 state->flags &= ~(IFLUSH | ESCAPED);
823 state->infcs = PPP_INITFCS;
824 }
825
826 if (*dp == PPP_ESCAPE) {
827 state->flags |= ESCAPED;
828 continue;
829 }
830
831 /*
832 * Make sure we un-escape the necessary characters, as well as the
833 * ones in our receive async control character map
834 */
835 if (state->flags & ESCAPED) {
836 *dp ^= PPP_TRANS;
837 state->flags &= ~ESCAPED;
838 } else if (IN_RX_MAP(*dp, state->raccm))
839 continue;
840
841 /*
842 * Unless the peer lied to us about the negotiated MRU, we should
843 * never get a frame which is too long. If it happens, toss it away
844 * and grab the next incoming one
845 */
846 if (msgdsize(state->rx_buf) < state->rx_buf_size) {
847 state->infcs = PPP_FCS(state->infcs, *dp);
848 *state->rx_buf->b_wptr++ = *dp;
849 } else {
850 DPRINT2("ppp%d: frame too long (%d)\n",
851 state->unit, msgdsize(state->rx_buf));
852 freemsg(state->rx_buf);
853 state->rx_buf = 0;
854 state->flags |= IFLUSH;
855 }
856 }
857
858#if defined(USE_MUTEX)
859 mutex_exit(&state->lock);
860#endif /* USE_MUTEX */
861}
862
863static int
864msg_byte(mp, i)
865 mblk_t *mp;
866 unsigned int i;
867{
868 while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
869 mp = mp->b_cont;
870 if (mp == 0)
871 return -1;
872 return mp->b_rptr[i];
873}