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