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