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