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 * 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.18 2002/12/06 09:49:15 paulus 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} 874