1 /* 2 * spppcomp.c - STREAMS module for kernel-level compression and CCP support. 3 * 4 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 5 * Use is subject to license terms. 6 * Copyright (c) 2016 by Delphix. All rights reserved. 7 * 8 * Permission to use, copy, modify, and distribute this software and its 9 * documentation is hereby granted, provided that the above copyright 10 * notice appears in all copies. 11 * 12 * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF 13 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 14 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 15 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR 16 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR 17 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES 18 * 19 * Copyright (c) 1994 The Australian National University. 20 * All rights reserved. 21 * 22 * Permission to use, copy, modify, and distribute this software and its 23 * documentation is hereby granted, provided that the above copyright 24 * notice appears in all copies. This software is provided without any 25 * warranty, express or implied. The Australian National University 26 * makes no representations about the suitability of this software for 27 * any purpose. 28 * 29 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY 30 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 31 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 32 * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY 33 * OF SUCH DAMAGE. 34 * 35 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, 36 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 37 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 38 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO 39 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, 40 * OR MODIFICATIONS. 41 * 42 * This module is derived from the original SVR4 STREAMS PPP compression 43 * module originally written by Paul Mackerras <paul.mackerras@cs.anu.edu.au>. 44 * 45 * James Carlson <james.d.carlson@sun.com> and Adi Masputra 46 * <adi.masputra@sun.com> rewrote and restructured the code for improved 47 * performance and scalability. 48 */ 49 50 #define RCSID "$Id: spppcomp.c,v 1.0 2000/05/08 01:10:12 masputra Exp $" 51 52 #include <sys/types.h> 53 #include <sys/debug.h> 54 #include <sys/param.h> 55 #include <sys/stream.h> 56 #include <sys/stropts.h> 57 #include <sys/errno.h> 58 #include <sys/conf.h> 59 #include <sys/cpuvar.h> 60 #include <sys/cmn_err.h> 61 #include <sys/kmem.h> 62 #include <sys/ddi.h> 63 #include <sys/kstat.h> 64 #include <sys/strsun.h> 65 #include <sys/sysmacros.h> 66 #include <netinet/in.h> 67 #include <netinet/ip.h> 68 #include <net/ppp_defs.h> 69 #include <net/pppio.h> 70 #include <net/vjcompress.h> 71 72 /* Defined for platform-neutral include file */ 73 #define PACKETPTR mblk_t * 74 #include <net/ppp-comp.h> 75 76 #include "s_common.h" 77 78 #ifdef DEBUG 79 #define SPC_DEBUG 80 #endif 81 #include "spppcomp.h" 82 83 /* 84 * This is used to tag official Solaris sources. Please do not define 85 * "INTERNAL_BUILD" when building this software outside of Sun 86 * Microsystems. 87 */ 88 #ifdef INTERNAL_BUILD 89 /* MODINFO is limited to 32 characters. */ 90 const char spppcomp_module_description[] = "PPP 4.0 compression"; 91 #else /* INTERNAL_BUILD */ 92 const char spppcomp_module_description[] = 93 "ANU PPP compression $Revision: 1.16$ "; 94 95 /* LINTED */ 96 static const char buildtime[] = "Built " __DATE__ " at " __TIME__ 97 #ifdef DEBUG 98 " DEBUG" 99 #endif 100 "\n"; 101 #endif /* INTERNAL_BUILD */ 102 103 static int spppcomp_open(queue_t *, dev_t *, int, int, cred_t *); 104 static int spppcomp_close(queue_t *, int, cred_t *); 105 static void spppcomp_rput(queue_t *, mblk_t *); 106 static void spppcomp_rsrv(queue_t *); 107 static void spppcomp_wput(queue_t *, mblk_t *); 108 static void spppcomp_wsrv(queue_t *); 109 110 #define PPPCOMP_MI_MINPSZ (0) 111 #define PPPCOMP_MI_MAXPSZ (INFPSZ) 112 #define PPPCOMP_MI_HIWAT (PPP_MTU * 20) 113 #define PPPCOMP_MI_LOWAT (PPP_MTU * 18) 114 115 static struct module_info spppcomp_modinfo = { 116 COMP_MOD_ID, /* mi_idnum */ 117 COMP_MOD_NAME, /* mi_idname */ 118 PPPCOMP_MI_MINPSZ, /* mi_minpsz */ 119 PPPCOMP_MI_MAXPSZ, /* mi_maxpsz */ 120 PPPCOMP_MI_HIWAT, /* mi_hiwat */ 121 PPPCOMP_MI_LOWAT /* mi_lowat */ 122 }; 123 124 static struct qinit spppcomp_rinit = { 125 (int (*)())spppcomp_rput, /* qi_putp */ 126 (int (*)())spppcomp_rsrv, /* qi_srvp */ 127 spppcomp_open, /* qi_qopen */ 128 spppcomp_close, /* qi_qclose */ 129 NULL, /* qi_qadmin */ 130 &spppcomp_modinfo, /* qi_minfo */ 131 NULL /* qi_mstat */ 132 }; 133 134 static struct qinit spppcomp_winit = { 135 (int (*)())spppcomp_wput, /* qi_putp */ 136 (int (*)())spppcomp_wsrv, /* qi_srvp */ 137 NULL, /* qi_qopen */ 138 NULL, /* qi_qclose */ 139 NULL, /* qi_qadmin */ 140 &spppcomp_modinfo, /* qi_minfo */ 141 NULL /* qi_mstat */ 142 }; 143 144 struct streamtab spppcomp_tab = { 145 &spppcomp_rinit, /* st_rdinit */ 146 &spppcomp_winit, /* st_wrinit */ 147 NULL, /* st_muxrinit */ 148 NULL /* st_muxwinit */ 149 }; 150 151 /* Set non-zero to debug algorithm-specific problems alone. */ 152 #define ALG_DEBUG 0 153 154 #define MAX_IPHLEN (0x0f << 2) 155 #define MAX_TCPHLEN (0x0f << 2) 156 #define MAX_TCPIPHLEN (MAX_IPHLEN + MAX_TCPHLEN) /* max TCP/IP header size */ 157 #define MAX_VJHDR (20) /* max VJ compressed header size (?) */ 158 159 #if 0 160 #define DBGSTART CE_CONT, COMP_MOD_NAME "%d: " 161 #define CKDEBUG(x) cmn_err x 162 #else 163 #define DBGSTART COMP_MOD_NAME "%d: " 164 #define CKDEBUG(x) printf x 165 #endif 166 #define CPDEBUG(x) (IS_CP_KDEBUG(cp) ? CKDEBUG(x) : (void)0) 167 168 /* 169 * List of compressors we know about. 170 */ 171 #if DO_BSD_COMPRESS 172 extern struct compressor ppp_bsd_compress; 173 #endif 174 #if DO_DEFLATE 175 extern struct compressor ppp_deflate; 176 extern struct compressor ppp_deflate_draft; 177 #endif 178 179 struct compressor *ppp_compressors[] = { 180 #if DO_BSD_COMPRESS 181 &ppp_bsd_compress, 182 #endif 183 #if DO_DEFLATE 184 &ppp_deflate, 185 &ppp_deflate_draft, 186 #endif 187 NULL 188 }; 189 190 /* 191 * LCP_USE_DFLT() removed by James Carlson. RFC 1661 section 6.6 has 192 * this to say on the topic: 193 * 194 * The Address and Control fields MUST NOT be compressed when sending 195 * any LCP packet. This rule guarantees unambiguous recognition of 196 * LCP packets. 197 */ 198 199 static void spppcomp_ioctl(queue_t *, mblk_t *, sppp_comp_t *); 200 static int spppcomp_mctl(queue_t *, mblk_t *); 201 static mblk_t *spppcomp_outpkt(queue_t *, mblk_t *); 202 static mblk_t *spppcomp_inpkt(queue_t *, mblk_t *); 203 static int spppcomp_kstat_update(kstat_t *, int); 204 static void comp_ccp(queue_t *, mblk_t *, sppp_comp_t *, boolean_t); 205 206 /* 207 * Values for checking inter-arrival times on interrupt stacks. These 208 * are used to prevent CPU hogging in interrupt context. 209 */ 210 #define MIN_ARRIVAL_TIME 5000000 /* interarrival time in nanoseconds */ 211 #define MAX_FAST_ARRIVALS 10 /* maximum packet count */ 212 hrtime_t spppcomp_min_arrival = MIN_ARRIVAL_TIME; 213 214 static const char *kstats_names[] = { 215 #ifdef SPCDEBUG_KSTATS_NAMES 216 SPPPCOMP_KSTATS_NAMES, 217 SPCDEBUG_KSTATS_NAMES 218 #else 219 SPPPCOMP_KSTATS_NAMES 220 #endif 221 }; 222 static const char *kstats64_names[] = { SPPPCOMP_KSTATS64_NAMES }; 223 224 /* 225 * spppcomp_open() 226 * 227 * MT-Perimeters: 228 * exclusive inner. 229 * 230 * Description: 231 * Common open procedure for module. 232 */ 233 /* ARGSUSED */ 234 static int 235 spppcomp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 236 { 237 sppp_comp_t *cp; 238 239 if (q->q_ptr != NULL) { 240 return (0); 241 } 242 if (sflag != MODOPEN) { 243 return (EINVAL); 244 } 245 cp = kmem_zalloc(sizeof (sppp_comp_t), KM_SLEEP); 246 q->q_ptr = WR(q)->q_ptr = (caddr_t)cp; 247 248 cp->cp_mru = PPP_MRU; 249 cp->cp_mtu = PPP_MTU; 250 251 mutex_init(&cp->cp_pair_lock, NULL, MUTEX_DRIVER, NULL); 252 vj_compress_init(&cp->cp_vj, -1); 253 cp->cp_nxslots = -1; 254 cp->cp_effort = -1; 255 256 qprocson(q); 257 return (0); 258 } 259 260 /* 261 * spppcomp_close() 262 * 263 * MT-Perimeters: 264 * exclusive inner. 265 * 266 * Description: 267 * Common close procedure for module. 268 */ 269 /* ARGSUSED */ 270 static int 271 spppcomp_close(queue_t *q, int flag, cred_t *credp) 272 { 273 sppp_comp_t *cp = q->q_ptr; 274 275 qprocsoff(q); 276 277 CPDEBUG((DBGSTART "close flags=0x%b\n", 278 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), cp->cp_flags, 279 CP_FLAGSSTR)); 280 mutex_destroy(&cp->cp_pair_lock); 281 if (cp->cp_kstats) { 282 ASSERT(IS_CP_HASUNIT(cp)); 283 kstat_delete(cp->cp_kstats); 284 } 285 if (cp->cp_xstate != NULL) { 286 (*cp->cp_xcomp->comp_free)(cp->cp_xstate); 287 } 288 if (cp->cp_rstate != NULL) { 289 (*cp->cp_rcomp->decomp_free)(cp->cp_rstate); 290 } 291 kmem_free(cp, sizeof (sppp_comp_t)); 292 q->q_ptr = WR(q)->q_ptr = NULL; 293 294 return (0); 295 } 296 297 /* 298 * spppcomp_wput() 299 * 300 * MT-Perimeters: 301 * exclusive inner. 302 * 303 * Description: 304 * Write-side put procedure. Packets from above us arrive here. 305 * 306 * The data handling logic is a little tricky here. We defer to 307 * the service routine if q_first isn't NULL (to preserve message 308 * ordering after deferring a previous message), bcanputnext() is 309 * FALSE (to handle flow control), or we need a lot of processing 310 * and we're in an interrupt context (on the theory that we're 311 * already on a very long call stack at that point). Since many 312 * callers will be in a non-interrupt context, this means that 313 * most processing will be performed here in-line, and deferral 314 * occurs only when necessary. 315 */ 316 static void 317 spppcomp_wput(queue_t *q, mblk_t *mp) 318 { 319 sppp_comp_t *cp = q->q_ptr; 320 int flag; 321 322 switch (MTYPE(mp)) { 323 case M_DATA: 324 if (q->q_first != NULL || !bcanputnext(q, mp->b_band) || 325 ((cp->cp_flags & (COMP_VJC|CCP_COMP_RUN)) && 326 servicing_interrupt())) { 327 #ifdef SPC_DEBUG 328 cp->cp_out_queued++; 329 #endif 330 if (!putq(q, mp)) 331 freemsg(mp); 332 } else { 333 #ifdef SPC_DEBUG 334 cp->cp_out_handled++; 335 #endif 336 if ((mp = spppcomp_outpkt(q, mp)) != NULL) 337 putnext(q, mp); 338 } 339 break; 340 case M_IOCTL: 341 spppcomp_ioctl(q, mp, cp); 342 break; 343 case M_CTL: 344 mutex_enter(&cp->cp_pair_lock); 345 flag = spppcomp_mctl(q, mp); 346 mutex_exit(&cp->cp_pair_lock); 347 if (flag != 0) 348 putnext(q, mp); 349 else 350 freemsg(mp); 351 break; 352 case M_FLUSH: 353 CPDEBUG((DBGSTART "wput M_FLUSH (0x%x) flags=0x%b\n", 354 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), 355 *mp->b_rptr, cp->cp_flags, CP_FLAGSSTR)); 356 /* 357 * Just discard pending data. For CCP, any compressor 358 * dictionary sequencing problems caused by this will 359 * have to be handled by the compression protocol in 360 * use. For VJ, we need to tell the compressor to 361 * start over. 362 */ 363 if (*mp->b_rptr & FLUSHW) { 364 mutex_enter(&cp->cp_pair_lock); 365 flushq(q, FLUSHDATA); 366 vj_compress_init(&cp->cp_vj, cp->cp_nxslots); 367 mutex_exit(&cp->cp_pair_lock); 368 } 369 putnext(q, mp); 370 break; 371 default: 372 if (bcanputnext(q, mp->b_band)) 373 putnext(q, mp); 374 else if (!putq(q, mp)) 375 freemsg(mp); 376 break; 377 } 378 } 379 380 /* 381 * spppcomp_wsrv() 382 * 383 * MT-Perimeters: 384 * exclusive inner 385 * 386 * Description: 387 * Write-side service procedure. 388 */ 389 static void 390 spppcomp_wsrv(queue_t *q) 391 { 392 mblk_t *mp; 393 394 while ((mp = getq(q)) != NULL) { 395 /* 396 * If the module below us is flow-controlled, then put 397 * this message back on the queue again. 398 */ 399 if (!bcanputnext(q, mp->b_band)) { 400 (void) putbq(q, mp); 401 break; 402 } 403 if (MTYPE(mp) != M_DATA || 404 (mp = spppcomp_outpkt(q, mp)) != NULL) 405 putnext(q, mp); 406 } 407 } 408 409 /* 410 * spppcomp_outpkt() 411 * 412 * MT-Perimeters: 413 * exclusive inner 414 * 415 * Description: 416 * Process outgoing packet. Returns new mblk_t pointer on success 417 * (caller should do putnext through q), NULL on failure (packet has 418 * been discarded). 419 */ 420 static mblk_t * 421 spppcomp_outpkt(queue_t *q, mblk_t *mp) 422 { 423 mblk_t *zmp; 424 int len; 425 ushort_t proto; 426 sppp_comp_t *cp = q->q_ptr; 427 428 /* 429 * If the entire data size of the mblk is less than the length of the 430 * PPP header, then free it. We can't do much with such message anyway, 431 * since we can't determine what the PPP protocol is. 432 */ 433 len = msgsize(mp); 434 if (MBLKL(mp) < PPP_HDRLEN) { 435 #ifdef SPC_DEBUG 436 mutex_enter(&cp->cp_pair_lock); 437 cp->cp_omsg_pull++; 438 mutex_exit(&cp->cp_pair_lock); 439 #endif 440 zmp = msgpullup(mp, PPP_HDRLEN); 441 freemsg(mp); 442 if ((mp = zmp) == NULL) 443 goto msg_oerror; 444 } 445 446 proto = PPP_PROTOCOL(mp->b_rptr); 447 448 /* 449 * Do VJ compression if requested. 450 */ 451 if (proto == PPP_IP && IS_COMP_VJC(cp) && 452 MSG_BYTE(mp, PPP_HDRLEN+offsetof(struct ip, ip_p)) == 453 IPPROTO_TCP) { 454 uchar_t *vjhdr; 455 int type; 456 uint32_t indata[(PPP_HDRLEN+MAX_TCPIPHLEN) / 457 sizeof (uint32_t)]; 458 uchar_t *dp; 459 int tocopy, copied; 460 mblk_t *fmb; 461 void *srcp; 462 int thislen; 463 464 465 tocopy = copied = MIN(len, sizeof (indata)); 466 /* 467 * If we can alter this dblk, and there's enough data 468 * here to work with, and it's nicely aligned, then 469 * avoid the data copy. 470 */ 471 if (DB_REF(mp) == 1 && MBLKL(mp) >= tocopy && 472 ((uintptr_t)mp->b_rptr & 3) == 0) { 473 /* Save off the address/control */ 474 indata[0] = *(uint32_t *)mp->b_rptr; 475 srcp = (void *)(mp->b_rptr + PPP_HDRLEN); 476 } else { 477 fmb = mp; 478 dp = (uchar_t *)indata; 479 while (tocopy > 0) { 480 thislen = MBLKL(fmb); 481 if (tocopy > thislen) { 482 bcopy(fmb->b_rptr, dp, thislen); 483 dp += thislen; 484 tocopy -= thislen; 485 fmb = fmb->b_cont; 486 } else { 487 bcopy(fmb->b_rptr, dp, tocopy); 488 break; 489 } 490 } 491 srcp = (void *)(indata + PPP_HDRLEN/sizeof (*indata)); 492 } 493 494 type = vj_compress_tcp((struct ip *)srcp, len - PPP_HDRLEN, 495 &cp->cp_vj, IS_COMP_VJCCID(cp), &vjhdr); 496 497 /* 498 * If we're going to modify this packet, then we can't modify 499 * someone else's data. Copy instead. 500 * 501 * (It would be nice to be able to avoid this data copy if CCP 502 * is also enabled. That would require extensive 503 * modifications to the compression code. Users should be 504 * told to disable VJ compression when using CCP.) 505 */ 506 if (type != TYPE_IP && DB_REF(mp) > 1) { 507 #ifdef SPC_DEBUG 508 mutex_enter(&cp->cp_pair_lock); 509 cp->cp_omsg_dcopy++; 510 mutex_exit(&cp->cp_pair_lock); 511 #endif 512 /* Copy just altered portion. */ 513 zmp = msgpullup(mp, copied); 514 freemsg(mp); 515 if ((mp = zmp) == NULL) 516 goto msg_oerror; 517 } 518 519 switch (type) { 520 case TYPE_UNCOMPRESSED_TCP: 521 mp->b_rptr[3] = proto = PPP_VJC_UNCOMP; 522 /* No need to update if it was done in place. */ 523 if (srcp == 524 (void *)(indata + PPP_HDRLEN / sizeof (*indata))) { 525 thislen = PPP_HDRLEN + 526 offsetof(struct ip, ip_p); 527 zmp = mp; 528 while (zmp != NULL) { 529 if (MBLKL(zmp) > thislen) { 530 zmp->b_rptr[thislen] = 531 ((struct ip *)srcp)->ip_p; 532 break; 533 } 534 thislen -= MBLKL(zmp); 535 zmp = zmp->b_cont; 536 } 537 } 538 break; 539 540 case TYPE_COMPRESSED_TCP: 541 /* Calculate amount to remove from front */ 542 thislen = vjhdr - (uchar_t *)srcp; 543 ASSERT(thislen >= 0); 544 545 /* Try to do a cheap adjmsg by arithmetic first. */ 546 dp = mp->b_rptr + thislen; 547 if (dp > mp->b_wptr) { 548 if (!adjmsg(mp, thislen)) { 549 freemsg(mp); 550 goto msg_oerror; 551 } 552 dp = mp->b_rptr; 553 } 554 555 /* 556 * Now make sure first block is big enough to 557 * receive modified data. If we modified in 558 * place, then no need to check or copy. 559 */ 560 copied -= thislen; 561 ASSERT(copied >= PPP_HDRLEN); 562 if (srcp != 563 (void *)(indata + PPP_HDRLEN / sizeof (*indata))) 564 copied = 0; 565 mp->b_rptr = dp; 566 if (MBLKL(mp) < copied) { 567 zmp = msgpullup(mp, copied); 568 freemsg(mp); 569 if ((mp = zmp) == NULL) 570 goto msg_oerror; 571 dp = mp->b_rptr; 572 } 573 574 *dp++ = ((uchar_t *)indata)[0]; /* address */ 575 *dp++ = ((uchar_t *)indata)[1]; /* control */ 576 *dp++ = 0; /* protocol */ 577 *dp++ = proto = PPP_VJC_COMP; /* protocol */ 578 copied -= PPP_HDRLEN; 579 if (copied > 0) { 580 bcopy(vjhdr, dp, copied); 581 } 582 break; 583 } 584 } 585 586 /* 587 * Do packet compression if enabled. 588 */ 589 if (proto == PPP_CCP) { 590 /* 591 * Handle any negotiation packets by changing compressor 592 * state. Doing this here rather than with an ioctl keeps 593 * the negotiation and the data flow in sync. 594 */ 595 mutex_enter(&cp->cp_pair_lock); 596 comp_ccp(q, mp, cp, B_FALSE); 597 mutex_exit(&cp->cp_pair_lock); 598 } else if (proto != PPP_LCP && IS_CCP_COMP_RUN(cp) && 599 IS_CCP_ISUP(cp) && cp->cp_xstate != NULL) { 600 mblk_t *cmp = NULL; 601 602 len = msgsize(mp); 603 len = (*cp->cp_xcomp->compress)(cp->cp_xstate, &cmp, mp, len, 604 cp->cp_mtu + PPP_HDRLEN); 605 606 if (cmp != NULL) { 607 /* Success! Discard uncompressed version */ 608 cmp->b_band = mp->b_band; 609 freemsg(mp); 610 mp = cmp; 611 } 612 if (len < 0) { 613 /* 614 * Compressor failure; must discard this 615 * packet because the compressor dictionary is 616 * now corrupt. 617 */ 618 freemsg(mp); 619 mutex_enter(&cp->cp_pair_lock); 620 cp->cp_stats.ppp_oerrors++; 621 mutex_exit(&cp->cp_pair_lock); 622 (void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR); 623 return (NULL); 624 } 625 } 626 627 /* 628 * If either address and control field compression or protocol field 629 * compression is enabled, then we'll need a writable packet. Copy if 630 * necessary. 631 */ 632 if ((cp->cp_flags & (COMP_AC|COMP_PROT)) && DB_REF(mp) > 1) { 633 #ifdef SPC_DEBUG 634 mutex_enter(&cp->cp_pair_lock); 635 cp->cp_omsg_dcopy++; 636 mutex_exit(&cp->cp_pair_lock); 637 #endif 638 zmp = copymsg(mp); 639 freemsg(mp); 640 if ((mp = zmp) == NULL) 641 goto msg_oerror; 642 } 643 644 /* 645 * Do address/control and protocol compression if enabled. 646 */ 647 if (IS_COMP_AC(cp) && (proto != PPP_LCP)) { 648 mp->b_rptr += 2; /* drop address & ctrl fields */ 649 /* 650 * Protocol field compression omits the first byte if 651 * it would be 0x00, thus the check for < 0x100. 652 */ 653 if (proto < 0x100 && IS_COMP_PROT(cp)) { 654 ++mp->b_rptr; /* drop high protocol byte */ 655 } 656 } else if ((proto < 0x100) && IS_COMP_PROT(cp)) { 657 /* 658 * shuffle up the address & ctrl fields 659 */ 660 mp->b_rptr[2] = mp->b_rptr[1]; 661 mp->b_rptr[1] = mp->b_rptr[0]; 662 ++mp->b_rptr; 663 } 664 mutex_enter(&cp->cp_pair_lock); 665 cp->cp_stats.ppp_opackets++; 666 cp->cp_stats.ppp_obytes += msgsize(mp); 667 mutex_exit(&cp->cp_pair_lock); 668 669 CPDEBUG((DBGSTART "send (%ld bytes) flags=0x%b\n", 670 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), msgsize(mp), 671 cp->cp_flags, CP_FLAGSSTR)); 672 return (mp); 673 674 msg_oerror: 675 mutex_enter(&cp->cp_pair_lock); 676 cp->cp_stats.ppp_oerrors++; 677 mutex_exit(&cp->cp_pair_lock); 678 (void) putnextctl1(RD(q), M_CTL, PPPCTL_OERROR); 679 return (NULL); 680 } 681 682 /* 683 * spppcomp_inner_ioctl() 684 * 685 * MT-Perimeters: 686 * exclusive inner; queue pair lock held. 687 * 688 * Description: 689 * Called by spppcomp_ioctl to handle state-affecting ioctls. 690 * Returns -1 if caller should do putnext, 0 for miocack, or >0 691 * for miocnak. Must *NOT* do putnext in this routine, since 692 * lock is held here. 693 */ 694 static int 695 spppcomp_inner_ioctl(queue_t *q, mblk_t *mp) 696 { 697 sppp_comp_t *cp = q->q_ptr; 698 int flags; 699 int mask; 700 int rc; 701 int len; 702 int cmd; 703 int nxslots; 704 int nrslots; 705 int val; 706 uchar_t *opt_data; 707 uint32_t opt_len; 708 struct compressor **comp; 709 struct compressor *ccomp; 710 struct iocblk *iop; 711 void *xtemp; 712 713 iop = (struct iocblk *)mp->b_rptr; 714 rc = EINVAL; 715 len = 0; 716 switch (iop->ioc_cmd) { 717 case PPPIO_CFLAGS: 718 if (iop->ioc_count != 2 * sizeof (uint32_t) || 719 mp->b_cont == NULL) 720 break; 721 722 flags = ((uint32_t *)mp->b_cont->b_rptr)[0]; 723 mask = ((uint32_t *)mp->b_cont->b_rptr)[1]; 724 725 cp->cp_flags = (cp->cp_flags & ~mask) | (flags & mask); 726 727 if ((mask & CCP_ISOPEN) && !(flags & CCP_ISOPEN)) { 728 cp->cp_flags &= ~CCP_ISUP & ~CCP_COMP_RUN & 729 ~CCP_DECOMP_RUN; 730 if (cp->cp_xstate != NULL) { 731 (*cp->cp_xcomp->comp_free)(cp->cp_xstate); 732 cp->cp_xstate = NULL; 733 } 734 if (cp->cp_rstate != NULL) { 735 (*cp->cp_rcomp->decomp_free)(cp->cp_rstate); 736 cp->cp_rstate = NULL; 737 } 738 } 739 740 CPDEBUG((DBGSTART 741 "PPPIO_CFLAGS xflags=0x%b xmask=0x%b flags=0x%b\n", 742 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), 743 flags, CP_FLAGSSTR, mask, 744 CP_FLAGSSTR, cp->cp_flags, CP_FLAGSSTR)); 745 746 /* If we're not the last PPP-speaker, then pass along. */ 747 if (!IS_CP_LASTMOD(cp)) { 748 return (-1); /* putnext */ 749 } 750 751 *(uint32_t *)mp->b_cont->b_rptr = cp->cp_flags; 752 len = sizeof (uint32_t); 753 rc = 0; 754 break; 755 756 case PPPIO_VJINIT: 757 if (iop->ioc_count != 2 || mp->b_cont == NULL) 758 break; 759 /* 760 * Even though it's not passed along, we have to 761 * validate nrslots so that we don't agree to 762 * decompress anything we cannot. 763 */ 764 nxslots = mp->b_cont->b_rptr[0] + 1; 765 nrslots = mp->b_cont->b_rptr[1] + 1; 766 if (nxslots > MAX_STATES || nrslots > MAX_STATES) 767 break; 768 769 /* No need to lock here; just reading a word is atomic */ 770 /* mutex_enter(&cp->cp_pair_lock); */ 771 cp->cp_vj_last_ierrors = cp->cp_stats.ppp_ierrors; 772 /* mutex_exit(&cp->cp_pair_lock); */ 773 vj_compress_init(&cp->cp_vj, nxslots); 774 cp->cp_nxslots = nxslots; 775 776 CPDEBUG((DBGSTART 777 "PPPIO_VJINIT txslots=%d rxslots=%d flags=0x%b\n", 778 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), nxslots, 779 nrslots, cp->cp_flags, CP_FLAGSSTR)); 780 rc = 0; 781 break; 782 783 case PPPIO_XCOMP: 784 case PPPIO_RCOMP: 785 if (iop->ioc_count < 2 || mp->b_cont == NULL) 786 break; 787 /* 788 * The input data here is the raw CCP algorithm option 789 * from negotiation. The format is always one byte of 790 * algorithm number, one byte of length, and 791 * (length-2) bytes of algorithm-dependent data. The 792 * alloc routine is expected to parse and validate 793 * this. 794 */ 795 opt_data = mp->b_cont->b_rptr; 796 opt_len = mp->b_cont->b_wptr - opt_data; 797 if (opt_len > iop->ioc_count) { 798 opt_len = iop->ioc_count; 799 } 800 len = mp->b_cont->b_rptr[1]; 801 if (len < 2 || len > opt_len) 802 break; 803 len = 0; 804 for (comp = ppp_compressors; *comp != NULL; ++comp) { 805 806 if ((*comp)->compress_proto != opt_data[0]) { 807 continue; 808 } 809 rc = 0; 810 if (iop->ioc_cmd == PPPIO_XCOMP) { 811 /* 812 * A previous call may have fetched 813 * memory for a compressor that's now 814 * being retired or reset. Free it 815 * using its mechanism for freeing 816 * stuff. 817 */ 818 if ((xtemp = cp->cp_xstate) != NULL) { 819 cp->cp_flags &= ~CCP_ISUP & 820 ~CCP_COMP_RUN; 821 cp->cp_xstate = NULL; 822 (*cp->cp_xcomp->comp_free)(xtemp); 823 } 824 cp->cp_xcomp = *comp; 825 cp->cp_xstate = (*comp)->comp_alloc(opt_data, 826 opt_len); 827 828 if (cp->cp_xstate == NULL) { 829 rc = ENOSR; 830 } 831 832 CPDEBUG((DBGSTART "PPPIO_XCOMP opt_proto=0x%x " 833 "opt_len=0x%d flags=0x%b\n", 834 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), 835 (uchar_t)opt_data[0], opt_len, 836 cp->cp_flags, 837 CP_FLAGSSTR)); 838 } else { 839 if ((xtemp = cp->cp_rstate) != NULL) { 840 cp->cp_flags &= ~CCP_ISUP & 841 ~CCP_DECOMP_RUN; 842 cp->cp_rstate = NULL; 843 (*cp->cp_rcomp->decomp_free)(xtemp); 844 } 845 cp->cp_rcomp = *comp; 846 cp->cp_rstate = 847 (*comp)->decomp_alloc(opt_data, opt_len); 848 849 if (cp->cp_rstate == NULL) { 850 rc = ENOSR; 851 } 852 853 CPDEBUG((DBGSTART "PPPIO_RCOMP opt_proto=0x%x " 854 "opt_len=0x%d flags=0x%b\n", 855 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), 856 (uchar_t)opt_data[0], opt_len, 857 cp->cp_flags, 858 CP_FLAGSSTR)); 859 } 860 if (rc == 0 && (*comp)->set_effort != NULL) { 861 rc = (*(*comp)->set_effort)(cp-> 862 cp_xcomp == *comp ? cp->cp_xstate : NULL, 863 cp->cp_rcomp == *comp ? cp->cp_rstate : 864 NULL, cp->cp_effort); 865 if (rc != 0) { 866 CKDEBUG((DBGSTART 867 "cannot set effort %d", 868 cp->cp_unit, cp->cp_effort)); 869 rc = 0; 870 } 871 } 872 break; 873 } 874 break; 875 876 case PPPIO_DEBUG: 877 if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL) 878 break; 879 880 cmd = *(uint32_t *)mp->b_cont->b_rptr; 881 882 /* If it's not for us, then pass along. */ 883 if (cmd != PPPDBG_LOG + PPPDBG_COMP) { 884 return (-1); /* putnext */ 885 } 886 cp->cp_flags |= CP_KDEBUG; 887 888 CKDEBUG((DBGSTART "PPPIO_DEBUG log enabled flags=0x%b\n", 889 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), 890 cp->cp_flags, CP_FLAGSSTR)); 891 rc = 0; 892 break; 893 894 case PPPIO_LASTMOD: 895 cp->cp_flags |= CP_LASTMOD; 896 CPDEBUG((DBGSTART "PPPIO_LASTMOD last module flags=0x%b\n", 897 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), 898 cp->cp_flags, CP_FLAGSSTR)); 899 rc = 0; 900 break; 901 902 case PPPIO_COMPLEV: /* set compression effort level */ 903 if (iop->ioc_count != sizeof (uint32_t) || mp->b_cont == NULL) 904 break; 905 val = *(uint32_t *)mp->b_cont->b_rptr; 906 cp->cp_effort = val; 907 /* Silently ignore if compressor doesn't understand this. */ 908 rc = 0; 909 if ((ccomp = cp->cp_xcomp) != NULL && 910 ccomp->set_effort != NULL) { 911 rc = (*ccomp->set_effort)(cp->cp_xstate, 912 ccomp == cp->cp_rcomp ? cp->cp_rstate : NULL, val); 913 if (rc != 0) 914 break; 915 } 916 if ((ccomp = cp->cp_rcomp) != NULL && ccomp != cp->cp_xcomp && 917 ccomp->set_effort != NULL) 918 rc = (*ccomp->set_effort)(NULL, cp->cp_rstate, val); 919 break; 920 } 921 if (rc == 0 && mp->b_cont != NULL) 922 mp->b_cont->b_wptr = mp->b_cont->b_rptr + len; 923 return (rc); 924 } 925 926 /* 927 * spppcomp_getcstat() 928 * 929 * MT-Perimeters: 930 * exclusive inner. 931 * 932 * Description: 933 * Called by spppcomp_ioctl as the result of receiving a PPPIO_GETCSTAT. 934 */ 935 static void 936 spppcomp_getcstat(queue_t *q, mblk_t *mp, sppp_comp_t *cp) 937 { 938 mblk_t *mpnext; 939 struct ppp_comp_stats *csp; 940 941 ASSERT(cp != NULL); 942 943 mpnext = allocb(sizeof (struct ppp_comp_stats), BPRI_MED); 944 if (mpnext == NULL) { 945 miocnak(q, mp, 0, ENOSR); 946 return; 947 } 948 if (mp->b_cont != NULL) { 949 freemsg(mp->b_cont); 950 } 951 mp->b_cont = mpnext; 952 csp = (struct ppp_comp_stats *)mpnext->b_wptr; 953 mpnext->b_wptr += sizeof (struct ppp_comp_stats); 954 bzero((caddr_t)csp, sizeof (struct ppp_comp_stats)); 955 956 if (cp->cp_xstate != NULL) { 957 (*cp->cp_xcomp->comp_stat)(cp->cp_xstate, &csp->c); 958 } 959 if (cp->cp_rstate != NULL) { 960 (*cp->cp_rcomp->decomp_stat)(cp->cp_rstate, &csp->d); 961 } 962 963 miocack(q, mp, sizeof (struct ppp_comp_stats), 0); 964 } 965 966 /* 967 * spppcomp_ioctl() 968 * 969 * MT-Perimeters: 970 * exclusive inner. 971 * 972 * Description: 973 * Called by spppcomp_wput as the result of receiving an M_IOCTL 974 * command. 975 */ 976 static void 977 spppcomp_ioctl(queue_t *q, mblk_t *mp, sppp_comp_t *cp) 978 { 979 struct iocblk *iop; 980 int flag; 981 982 ASSERT(cp != NULL); 983 984 iop = (struct iocblk *)mp->b_rptr; 985 switch (iop->ioc_cmd) { 986 case PPPIO_CFLAGS: 987 case PPPIO_VJINIT: 988 case PPPIO_XCOMP: 989 case PPPIO_RCOMP: 990 case PPPIO_DEBUG: 991 case PPPIO_LASTMOD: 992 case PPPIO_COMPLEV: 993 mutex_enter(&cp->cp_pair_lock); 994 flag = spppcomp_inner_ioctl(q, mp); 995 mutex_exit(&cp->cp_pair_lock); 996 if (flag == -1) { 997 putnext(q, mp); 998 } else if (flag == 0) { 999 miocack(q, mp, 1000 mp->b_cont == NULL ? 0 : MBLKL(mp->b_cont), 0); 1001 } else { 1002 miocnak(q, mp, 0, flag); 1003 } 1004 break; 1005 1006 case PPPIO_GETCSTAT: 1007 spppcomp_getcstat(q, mp, cp); 1008 break; 1009 1010 case PPPIO_GTYPE: /* get existing driver type */ 1011 if (!IS_CP_LASTMOD(cp)) { 1012 putnext(q, mp); 1013 break; 1014 } 1015 freemsg(mp->b_next); 1016 mp->b_next = allocb(sizeof (uint32_t), BPRI_MED); 1017 if (mp->b_next == NULL) { 1018 miocnak(q, mp, 0, ENOSR); 1019 } else { 1020 *(uint32_t *)mp->b_cont->b_wptr = PPPTYP_HC; 1021 mp->b_cont->b_wptr += sizeof (uint32_t); 1022 miocack(q, mp, sizeof (uint32_t), 0); 1023 } 1024 break; 1025 1026 default: 1027 putnext(q, mp); 1028 break; 1029 } 1030 } 1031 1032 /* 1033 * spppcomp_mctl() 1034 * 1035 * MT-Perimeters: 1036 * exclusive inner; queue pair lock held. 1037 * 1038 * Description: 1039 * Called by spppcomp_wput as the result of receiving an M_CTL 1040 * message from another STREAMS module, and returns non-zero if 1041 * caller should do putnext or zero for freemsg. Must *NOT* do 1042 * putnext in this routine, since lock is held here. 1043 */ 1044 static int 1045 spppcomp_mctl(queue_t *q, mblk_t *mp) 1046 { 1047 sppp_comp_t *cp = q->q_ptr; 1048 kstat_t *ksp; 1049 char unit[32]; 1050 const char **cpp; 1051 kstat_named_t *knt; 1052 1053 switch (*mp->b_rptr) { 1054 case PPPCTL_MTU: 1055 if (MBLKL(mp) < 4) { 1056 break; 1057 } 1058 cp->cp_mtu = ((ushort_t *)mp->b_rptr)[1]; 1059 1060 CPDEBUG((DBGSTART "PPPCTL_MTU (%d) flags=0x%b\n", 1061 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), 1062 cp->cp_mtu, cp->cp_flags, CP_FLAGSSTR)); 1063 break; 1064 case PPPCTL_MRU: 1065 if (MBLKL(mp) < 4) { 1066 break; 1067 } 1068 cp->cp_mru = ((ushort_t *)mp->b_rptr)[1]; 1069 1070 CPDEBUG((DBGSTART "PPPCTL_MRU (%d) flags=0x%b\n", 1071 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), 1072 cp->cp_mru, cp->cp_flags, CP_FLAGSSTR)); 1073 break; 1074 case PPPCTL_UNIT: 1075 if (MBLKL(mp) < 8) { 1076 break; 1077 } 1078 /* If PPPCTL_UNIT has already been issued, then ignore. */ 1079 if (IS_CP_HASUNIT(cp)) { 1080 break; 1081 } 1082 ASSERT(cp->cp_kstats == NULL); 1083 cp->cp_unit = ((uint32_t *)mp->b_rptr)[1]; 1084 1085 /* Create kstats for this unit. */ 1086 (void) sprintf(unit, "%s" "%d", COMP_MOD_NAME, cp->cp_unit); 1087 ksp = kstat_create(COMP_MOD_NAME, cp->cp_unit, unit, "net", 1088 KSTAT_TYPE_NAMED, sizeof (spppcomp_kstats_t) / 1089 sizeof (kstat_named_t), 0); 1090 1091 if (ksp != NULL) { 1092 cp->cp_flags |= CP_HASUNIT; 1093 cp->cp_kstats = ksp; 1094 1095 knt = (kstat_named_t *)ksp->ks_data; 1096 for (cpp = kstats_names; 1097 cpp < kstats_names + Dim(kstats_names); cpp++) { 1098 kstat_named_init(knt, *cpp, 1099 KSTAT_DATA_UINT32); 1100 knt++; 1101 } 1102 for (cpp = kstats64_names; 1103 cpp < kstats64_names + Dim(kstats64_names); cpp++) { 1104 kstat_named_init(knt, *cpp, 1105 KSTAT_DATA_UINT64); 1106 knt++; 1107 } 1108 ksp->ks_update = spppcomp_kstat_update; 1109 ksp->ks_private = (void *)cp; 1110 kstat_install(ksp); 1111 1112 CPDEBUG((DBGSTART "PPPCTL_UNIT flags=0x%b\n", 1113 cp->cp_unit, cp->cp_flags, CP_FLAGSSTR)); 1114 } 1115 break; 1116 1117 default: 1118 /* Forward unknown M_CTL messages along */ 1119 return (1); 1120 } 1121 1122 /* 1123 * For known PPP M_CTL messages, forward along only if we're not the 1124 * last PPP-aware module. 1125 */ 1126 if (IS_CP_LASTMOD(cp)) 1127 return (0); 1128 return (1); 1129 } 1130 1131 /* 1132 * spppcomp_rput() 1133 * 1134 * MT-Perimeters: 1135 * exclusive inner. 1136 * 1137 * Description: 1138 * Upper read-side put procedure. Messages get here from below. 1139 * 1140 * The data handling logic is a little more tricky here. We 1141 * defer to the service routine if q_first isn't NULL (to 1142 * preserve message ordering after deferring a previous message), 1143 * bcanputnext() is FALSE (to handle flow control), or we have 1144 * done a lot of processing recently and we're about to do a lot 1145 * more and we're in an interrupt context (on the theory that 1146 * we're hogging the CPU in this case). 1147 */ 1148 static void 1149 spppcomp_rput(queue_t *q, mblk_t *mp) 1150 { 1151 sppp_comp_t *cp = q->q_ptr; 1152 struct iocblk *iop; 1153 struct ppp_stats64 *psp; 1154 boolean_t inter; 1155 hrtime_t curtime; 1156 1157 switch (MTYPE(mp)) { 1158 case M_DATA: 1159 inter = servicing_interrupt(); 1160 if (inter) { 1161 curtime = gethrtime(); 1162 1163 /* 1164 * If little time has passed since last 1165 * arrival, then bump the counter. 1166 */ 1167 if (curtime - cp->cp_lastfinish < spppcomp_min_arrival) 1168 cp->cp_fastin++; 1169 else 1170 cp->cp_fastin >>= 1; /* a guess */ 1171 } 1172 /* 1173 * If we're not decompressing, then we'll be fast, so 1174 * we don't have to worry about hogging here. If we 1175 * are decompressing, then we have to check the 1176 * cp_fastin count. 1177 */ 1178 if ((!(cp->cp_flags & (CCP_DECOMP_RUN | DECOMP_VJC)) || 1179 cp->cp_fastin < MAX_FAST_ARRIVALS) && 1180 q->q_first == NULL && bcanputnext(q, mp->b_band)) { 1181 #ifdef SPC_DEBUG 1182 cp->cp_in_handled++; 1183 #endif 1184 if ((mp = spppcomp_inpkt(q, mp)) != NULL) 1185 putnext(q, mp); 1186 if (inter) { 1187 cp->cp_lastfinish = gethrtime(); 1188 } 1189 } else { 1190 /* Deferring; provide a clean slate */ 1191 cp->cp_fastin = 0; 1192 #ifdef SPC_DEBUG 1193 cp->cp_in_queued++; 1194 #endif 1195 if (!putq(q, mp)) 1196 freemsg(mp); 1197 } 1198 break; 1199 case M_IOCACK: 1200 iop = (struct iocblk *)mp->b_rptr; 1201 /* 1202 * Bundled with pppstats; no need to handle PPPIO_GETSTAT 1203 * here since we'll never see it. 1204 */ 1205 if (iop->ioc_cmd == PPPIO_GETSTAT64 && 1206 iop->ioc_count == sizeof (struct ppp_stats64) && 1207 mp->b_cont != NULL) { 1208 /* 1209 * This crock is to handle a badly-designed 1210 * but well-known ioctl for ANU PPP. Both 1211 * link statistics and VJ statistics are 1212 * requested together. 1213 * 1214 * Catch this on the way back from the 1215 * spppasyn module so we can fill in the VJ 1216 * stats. This happens only when we have 1217 * PPP-aware modules beneath us. 1218 */ 1219 psp = (struct ppp_stats64 *)mp->b_cont->b_rptr; 1220 psp->vj = cp->cp_vj.stats; 1221 CPDEBUG((DBGSTART 1222 "PPPIO_GETSTAT64 (VJ filled) flags=0x%b\n", 1223 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), 1224 cp->cp_flags, CP_FLAGSSTR)); 1225 } 1226 putnext(q, mp); 1227 break; 1228 case M_CTL: 1229 /* Increase our statistics and forward it upstream. */ 1230 mutex_enter(&cp->cp_pair_lock); 1231 if (*mp->b_rptr == PPPCTL_IERROR) { 1232 cp->cp_stats.ppp_ierrors++; 1233 cp->cp_ierr_low++; 1234 } else if (*mp->b_rptr == PPPCTL_OERROR) { 1235 cp->cp_stats.ppp_oerrors++; 1236 cp->cp_oerr_low++; 1237 } 1238 mutex_exit(&cp->cp_pair_lock); 1239 putnext(q, mp); 1240 break; 1241 1242 case M_FLUSH: 1243 CPDEBUG((DBGSTART "rput M_FLUSH (0x%x) flags=0x%b\n", 1244 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), 1245 *mp->b_rptr, cp->cp_flags, CP_FLAGSSTR)); 1246 /* 1247 * Just discard pending data. For CCP, any 1248 * decompressor dictionary sequencing problems caused 1249 * by this will have to be handled by the compression 1250 * protocol in use. For VJ, we need to give the 1251 * decompressor a heads-up. 1252 */ 1253 if (*mp->b_rptr & FLUSHR) { 1254 mutex_enter(&cp->cp_pair_lock); 1255 flushq(q, FLUSHDATA); 1256 cp->cp_vj_last_ierrors = cp->cp_stats.ppp_ierrors; 1257 vj_uncompress_err(&cp->cp_vj); 1258 mutex_exit(&cp->cp_pair_lock); 1259 } 1260 putnext(q, mp); 1261 break; 1262 1263 default: 1264 if (bcanputnext(q, mp->b_band)) 1265 putnext(q, mp); 1266 else if (!putq(q, mp)) 1267 freemsg(mp); 1268 break; 1269 } 1270 } 1271 1272 /* 1273 * spppcomp_rsrv() 1274 * 1275 * MT-Perimeters: 1276 * exclusive inner. 1277 * 1278 * Description: 1279 * Upper read-side service procedure. We handle data deferred from 1280 * spppcomp_rput here. 1281 * 1282 * The data on the queue are always compressed (unprocessed). 1283 * The rput procedure tries to do decompression, but if it can't, 1284 * it will put the unprocessed data on the queue for later 1285 * handling. 1286 */ 1287 static void 1288 spppcomp_rsrv(queue_t *q) 1289 { 1290 mblk_t *mp; 1291 1292 while ((mp = getq(q)) != NULL) { 1293 /* 1294 * If the module above us is flow-controlled, then put 1295 * this message back on the queue again. 1296 */ 1297 if (!bcanputnext(q, mp->b_band)) { 1298 (void) putbq(q, mp); 1299 break; 1300 } 1301 if (MTYPE(mp) != M_DATA || 1302 (mp = spppcomp_inpkt(q, mp)) != NULL) 1303 putnext(q, mp); 1304 } 1305 } 1306 1307 /* 1308 * spppcomp_inpkt() 1309 * 1310 * MT-Perimeters: 1311 * exclusive inner 1312 * 1313 * Description: 1314 * Process incoming packet. 1315 */ 1316 static mblk_t * 1317 spppcomp_inpkt(queue_t *q, mblk_t *mp) 1318 { 1319 ushort_t proto; 1320 int i; 1321 mblk_t *zmp; 1322 mblk_t *np; 1323 uchar_t *dp; 1324 int len; 1325 int hlen; 1326 sppp_comp_t *cp = q->q_ptr; 1327 1328 len = msgsize(mp); 1329 1330 mutex_enter(&cp->cp_pair_lock); 1331 cp->cp_stats.ppp_ibytes += len; 1332 cp->cp_stats.ppp_ipackets++; 1333 mutex_exit(&cp->cp_pair_lock); 1334 /* 1335 * First work out the protocol and where the PPP header ends. 1336 */ 1337 i = 0; 1338 proto = MSG_BYTE(mp, 0); 1339 if (proto == PPP_ALLSTATIONS) { 1340 i = 2; 1341 proto = MSG_BYTE(mp, 2); 1342 } 1343 if ((proto & 1) == 0) { 1344 ++i; 1345 proto = (proto << 8) + MSG_BYTE(mp, i); 1346 } 1347 hlen = i + 1; 1348 /* 1349 * Now reconstruct a complete, contiguous PPP header at the 1350 * start of the packet. 1351 */ 1352 if (hlen < (IS_DECOMP_AC(cp) ? 0 : 2) + (IS_DECOMP_PROT(cp) ? 1 : 2)) { 1353 /* count these? */ 1354 goto bad; 1355 } 1356 if (mp->b_rptr + hlen > mp->b_wptr) { 1357 /* 1358 * Header is known to be intact here; so adjmsg will do the 1359 * right thing here. 1360 */ 1361 if (!adjmsg(mp, hlen)) { 1362 goto bad; 1363 } 1364 hlen = 0; 1365 } 1366 if (hlen != PPP_HDRLEN) { 1367 /* 1368 * We need to put some bytes on the front of the packet 1369 * to make a full-length PPP header. If we can put them 1370 * in mp, we do, otherwise we tack another mblk on the 1371 * front. 1372 * 1373 * XXX we really shouldn't need to carry around the address 1374 * and control at this stage. ACFC and PFC need to be 1375 * reworked. 1376 */ 1377 dp = mp->b_rptr + hlen - PPP_HDRLEN; 1378 if ((dp < mp->b_datap->db_base) || (DB_REF(mp) > 1)) { 1379 1380 np = allocb(PPP_HDRLEN, BPRI_MED); 1381 if (np == 0) { 1382 goto bad; 1383 } 1384 np->b_cont = mp; 1385 mp->b_rptr += hlen; 1386 mp = np; 1387 dp = mp->b_wptr; 1388 mp->b_wptr += PPP_HDRLEN; 1389 } else { 1390 mp->b_rptr = dp; 1391 } 1392 dp[0] = PPP_ALLSTATIONS; 1393 dp[1] = PPP_UI; 1394 dp[2] = (proto >> 8) & 0xff; 1395 dp[3] = proto & 0xff; 1396 } 1397 /* 1398 * Now see if we have a compressed packet to decompress, or a 1399 * CCP negotiation packet to take notice of. It's guaranteed 1400 * that at least PPP_HDRLEN bytes are contiguous in the first 1401 * block now. 1402 */ 1403 proto = PPP_PROTOCOL(mp->b_rptr); 1404 if (proto == PPP_CCP) { 1405 len = msgsize(mp); 1406 if (mp->b_wptr < mp->b_rptr + len) { 1407 #ifdef SPC_DEBUG 1408 mutex_enter(&cp->cp_pair_lock); 1409 cp->cp_imsg_ccp_pull++; 1410 mutex_exit(&cp->cp_pair_lock); 1411 #endif 1412 zmp = msgpullup(mp, len); 1413 freemsg(mp); 1414 mp = zmp; 1415 if (mp == 0) { 1416 goto bad; 1417 } 1418 } 1419 mutex_enter(&cp->cp_pair_lock); 1420 comp_ccp(q, mp, cp, B_TRUE); 1421 mutex_exit(&cp->cp_pair_lock); 1422 } else if ((cp->cp_flags & (CCP_ISUP | CCP_DECOMP_RUN | CCP_ERR)) == 1423 (CCP_ISUP | CCP_DECOMP_RUN) && cp->cp_rstate != NULL) { 1424 int rv; 1425 1426 if ((proto == PPP_COMP) || (proto == PPP_COMPFRAG)) { 1427 rv = (*cp->cp_rcomp->decompress)(cp->cp_rstate, &mp); 1428 switch (rv) { 1429 case DECOMP_OK: 1430 break; 1431 case DECOMP_ERROR: 1432 cp->cp_flags |= CCP_ERROR; 1433 mutex_enter(&cp->cp_pair_lock); 1434 ++cp->cp_stats.ppp_ierrors; 1435 mutex_exit(&cp->cp_pair_lock); 1436 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR); 1437 break; 1438 case DECOMP_FATALERROR: 1439 cp->cp_flags |= CCP_FATALERROR; 1440 mutex_enter(&cp->cp_pair_lock); 1441 ++cp->cp_stats.ppp_ierrors; 1442 mutex_exit(&cp->cp_pair_lock); 1443 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR); 1444 break; 1445 } 1446 if (mp == NULL) { 1447 /* Decompress failed; data are gone. */ 1448 return (NULL); 1449 } 1450 } else { 1451 /* 1452 * For RFCs 1977 and 1979 (BSD Compress and Deflate), 1453 * the compressor should send incompressible data 1454 * without encapsulation and the receiver must update 1455 * its decompression dictionary as though this data 1456 * were received and decompressed. This keeps the 1457 * dictionaries in sync. 1458 */ 1459 rv = (*cp->cp_rcomp->incomp)(cp->cp_rstate, mp); 1460 if (rv < 0) { 1461 cp->cp_flags |= CCP_FATALERROR; 1462 mutex_enter(&cp->cp_pair_lock); 1463 ++cp->cp_stats.ppp_ierrors; 1464 mutex_exit(&cp->cp_pair_lock); 1465 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR); 1466 } 1467 } 1468 } 1469 /* 1470 * Now do VJ decompression. 1471 */ 1472 proto = PPP_PROTOCOL(mp->b_rptr); 1473 if ((proto == PPP_VJC_COMP) || (proto == PPP_VJC_UNCOMP)) { 1474 1475 len = msgsize(mp) - PPP_HDRLEN; 1476 1477 if (!IS_DECOMP_VJC(cp) || (len <= 0)) { 1478 goto bad; 1479 } 1480 /* 1481 * Advance past the ppp header. Here we assume that the whole 1482 * PPP header is in the first mblk. (This should be true 1483 * because the above code does pull-ups as necessary on raw 1484 * data, and the decompressor engines all produce large blocks 1485 * on output.) 1486 */ 1487 np = mp; 1488 dp = np->b_rptr + PPP_HDRLEN; 1489 if (dp >= mp->b_wptr) { 1490 np = np->b_cont; 1491 dp = np->b_rptr; 1492 } 1493 /* 1494 * Make sure we have sufficient contiguous data at this point, 1495 * which in most cases we will always do. 1496 */ 1497 hlen = (proto == PPP_VJC_COMP) ? MAX_VJHDR : MAX_TCPIPHLEN; 1498 if (hlen > len) { 1499 hlen = len; 1500 } 1501 if ((np->b_wptr < dp + hlen) || DB_REF(np) > 1) { 1502 #ifdef SPC_DEBUG 1503 mutex_enter(&cp->cp_pair_lock); 1504 cp->cp_imsg_vj_pull++; 1505 mutex_exit(&cp->cp_pair_lock); 1506 #endif 1507 zmp = msgpullup(mp, hlen + PPP_HDRLEN); 1508 freemsg(mp); 1509 mp = zmp; 1510 if (mp == NULL) { 1511 goto bad; 1512 } 1513 np = mp; 1514 dp = np->b_rptr + PPP_HDRLEN; 1515 } 1516 1517 if (proto == PPP_VJC_COMP) { 1518 uchar_t *iphdr; 1519 int vjlen; 1520 uint_t iphlen; 1521 int errcnt; 1522 1523 /* 1524 * Decompress VJ-compressed packet. First 1525 * reset compressor if an input error has 1526 * occurred. (No need to lock statistics 1527 * structure for read of a single word.) 1528 */ 1529 errcnt = cp->cp_stats.ppp_ierrors; 1530 if (errcnt != cp->cp_vj_last_ierrors) { 1531 cp->cp_vj_last_ierrors = errcnt; 1532 vj_uncompress_err(&cp->cp_vj); 1533 } 1534 1535 vjlen = vj_uncompress_tcp(dp, np->b_wptr - dp, len, 1536 &cp->cp_vj, &iphdr, &iphlen); 1537 1538 if (vjlen < 0 || iphlen == 0) { 1539 /* 1540 * so we don't reset next time 1541 */ 1542 mutex_enter(&cp->cp_pair_lock); 1543 ++cp->cp_vj_last_ierrors; 1544 mutex_exit(&cp->cp_pair_lock); 1545 goto bad; 1546 } 1547 /* 1548 * drop ppp and vj headers off 1549 */ 1550 if (mp != np) { 1551 freeb(mp); 1552 mp = np; 1553 } 1554 mp->b_rptr = dp + vjlen; 1555 /* 1556 * allocate a new mblk for the ppp and 1557 * ip headers 1558 */ 1559 np = allocb(iphlen + PPP_HDRLEN, BPRI_MED); 1560 if (np == NULL) 1561 goto bad; 1562 dp = np->b_rptr; 1563 /* 1564 * reconstruct PPP header 1565 */ 1566 dp[0] = PPP_ALLSTATIONS; 1567 dp[1] = PPP_UI; 1568 dp[2] = PPP_IP >> 8; 1569 dp[3] = PPP_IP; 1570 /* 1571 * prepend mblk with reconstructed TCP/IP header. 1572 */ 1573 bcopy((caddr_t)iphdr, (caddr_t)dp + PPP_HDRLEN, iphlen); 1574 np->b_wptr = dp + iphlen + PPP_HDRLEN; 1575 np->b_cont = mp; 1576 mp = np; 1577 } else { 1578 /* 1579 * "Decompress" a VJ-uncompressed packet. 1580 */ 1581 mutex_enter(&cp->cp_pair_lock); 1582 cp->cp_vj_last_ierrors = cp->cp_stats.ppp_ierrors; 1583 mutex_exit(&cp->cp_pair_lock); 1584 if (!vj_uncompress_uncomp(dp, hlen, &cp->cp_vj)) { 1585 /* 1586 * don't need to reset next time 1587 */ 1588 mutex_enter(&cp->cp_pair_lock); 1589 ++cp->cp_vj_last_ierrors; 1590 mutex_exit(&cp->cp_pair_lock); 1591 goto bad; 1592 } 1593 /* 1594 * fix up the PPP protocol field 1595 */ 1596 mp->b_rptr[3] = PPP_IP; 1597 } 1598 } 1599 CPDEBUG((DBGSTART "recv (%ld bytes) flags=0x%b\n", 1600 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), msgsize(mp), 1601 cp->cp_flags, CP_FLAGSSTR)); 1602 return (mp); 1603 1604 bad: 1605 if (mp != 0) { 1606 freemsg(mp); 1607 } 1608 mutex_enter(&cp->cp_pair_lock); 1609 cp->cp_stats.ppp_ierrors++; 1610 mutex_exit(&cp->cp_pair_lock); 1611 (void) putnextctl1(q, M_CTL, PPPCTL_IERROR); 1612 return (NULL); 1613 } 1614 1615 /* 1616 * comp_ccp() 1617 * 1618 * Description: 1619 * Called by spppcomp_outpkt and spppcomp_inpkt to handle a CCP 1620 * negotiation packet being sent or received. Here all the data in 1621 * the packet is in a single mbuf. 1622 * 1623 * Global state is updated. Must be called with mutex held. 1624 */ 1625 /* ARGSUSED */ 1626 static void 1627 comp_ccp(queue_t *q, mblk_t *mp, sppp_comp_t *cp, boolean_t rcvd) 1628 { 1629 int len; 1630 int clen; 1631 uchar_t *dp; 1632 1633 len = msgsize(mp); 1634 if (len < PPP_HDRLEN + CCP_HDRLEN) { 1635 return; 1636 } 1637 dp = mp->b_rptr + PPP_HDRLEN; 1638 1639 len -= PPP_HDRLEN; 1640 clen = CCP_LENGTH(dp); 1641 if (clen > len) { 1642 return; 1643 } 1644 1645 CPDEBUG((DBGSTART "CCP code=%d flags=0x%b\n", 1646 (IS_CP_HASUNIT(cp) ? cp->cp_unit : -1), CCP_CODE(dp), 1647 cp->cp_flags, CP_FLAGSSTR)); 1648 switch (CCP_CODE(dp)) { 1649 case CCP_CONFREQ: 1650 case CCP_TERMREQ: 1651 case CCP_TERMACK: 1652 cp->cp_flags &= ~CCP_ISUP; 1653 break; 1654 case CCP_CONFACK: 1655 if ((cp->cp_flags & (CCP_ISOPEN | CCP_ISUP)) == CCP_ISOPEN && 1656 clen >= CCP_HDRLEN + CCP_OPT_MINLEN && 1657 clen >= CCP_HDRLEN + CCP_OPT_LENGTH(dp + CCP_HDRLEN)) { 1658 1659 int rc; 1660 1661 if (!rcvd) { 1662 rc = (*cp->cp_xcomp->comp_init)(cp->cp_xstate, 1663 dp + CCP_HDRLEN, clen - CCP_HDRLEN, 1664 cp->cp_unit, 0, 1665 IS_CP_KDEBUG(cp) | ALG_DEBUG); 1666 1667 if (cp->cp_xstate != NULL && rc != 0) { 1668 cp->cp_flags |= CCP_COMP_RUN; 1669 } 1670 } else { 1671 rc = (*cp->cp_rcomp->decomp_init)(cp-> 1672 cp_rstate, dp + CCP_HDRLEN, 1673 clen - CCP_HDRLEN, cp->cp_unit, 0, 1674 cp->cp_mru, 1675 IS_CP_KDEBUG(cp) | ALG_DEBUG); 1676 1677 if (cp->cp_rstate != NULL && rc != 0) { 1678 cp->cp_flags &= ~CCP_ERR; 1679 cp->cp_flags |= CCP_DECOMP_RUN; 1680 } 1681 } 1682 } 1683 break; 1684 case CCP_RESETACK: 1685 if (IS_CCP_ISUP(cp)) { 1686 if (!rcvd) { 1687 if (cp->cp_xstate != NULL && 1688 IS_CCP_COMP_RUN(cp)) { 1689 (*cp->cp_xcomp->comp_reset)(cp-> 1690 cp_xstate); 1691 } 1692 } else { 1693 if (cp->cp_rstate != NULL && 1694 IS_CCP_DECOMP_RUN(cp)) { 1695 (*cp->cp_rcomp->decomp_reset)(cp-> 1696 cp_rstate); 1697 cp->cp_flags &= ~CCP_ERROR; 1698 } 1699 } 1700 } 1701 break; 1702 } 1703 } 1704 1705 /* 1706 * spppcomp_kstat_update() 1707 * 1708 * Description: 1709 * Update per-unit kstat statistics. 1710 */ 1711 static int 1712 spppcomp_kstat_update(kstat_t *ksp, int rw) 1713 { 1714 sppp_comp_t *cp = ksp->ks_private; 1715 spppcomp_kstats_t *cpkp; 1716 struct vjstat *sp; 1717 struct pppstat64 *psp; 1718 struct ppp_comp_stats csp; 1719 1720 if (rw == KSTAT_WRITE) { 1721 return (EACCES); 1722 } 1723 1724 cpkp = (spppcomp_kstats_t *)ksp->ks_data; 1725 bzero((caddr_t)&csp, sizeof (struct ppp_comp_stats)); 1726 1727 mutex_enter(&cp->cp_pair_lock); 1728 1729 if (cp->cp_xstate != NULL) { 1730 (*cp->cp_xcomp->comp_stat)(cp->cp_xstate, &csp.c); 1731 } 1732 if (cp->cp_rstate != NULL) { 1733 (*cp->cp_rcomp->decomp_stat)(cp->cp_rstate, &csp.d); 1734 } 1735 1736 sp = &cp->cp_vj.stats; 1737 1738 cpkp->vj_out_pkts.value.ui32 = sp->vjs_packets; 1739 cpkp->vj_out_pkts_comp.value.ui32 = sp->vjs_compressed; 1740 cpkp->vj_cs_searches.value.ui32 = sp->vjs_searches; 1741 cpkp->vj_cs_misses.value.ui32 = sp->vjs_misses; 1742 cpkp->vj_in_pkts_uncomp.value.ui32 = sp->vjs_uncompressedin; 1743 cpkp->vj_in_pkts_comp.value.ui32 = sp->vjs_compressedin; 1744 cpkp->vj_in_error.value.ui32 = sp->vjs_errorin; 1745 cpkp->vj_in_tossed.value.ui32 = sp->vjs_tossed; 1746 1747 psp = &cp->cp_stats; 1748 1749 cpkp->out_bytes.value.ui64 = psp->ppp_obytes; 1750 cpkp->out_pkts.value.ui64 = psp->ppp_opackets; 1751 cpkp->out_errors.value.ui64 = psp->ppp_oerrors; 1752 cpkp->out_errors_low.value.ui32 = cp->cp_oerr_low; 1753 cpkp->out_uncomp_bytes.value.ui32 = csp.c.unc_bytes; 1754 cpkp->out_uncomp_pkts.value.ui32 = csp.c.unc_packets; 1755 cpkp->out_comp_bytes.value.ui32 = csp.c.comp_bytes; 1756 cpkp->out_comp_pkts.value.ui32 = csp.c.comp_packets; 1757 cpkp->out_incomp_bytes.value.ui32 = csp.c.inc_bytes; 1758 cpkp->out_incomp_pkts.value.ui32 = csp.c.inc_packets; 1759 1760 cpkp->in_bytes.value.ui64 = psp->ppp_ibytes; 1761 cpkp->in_pkts.value.ui64 = psp->ppp_ipackets; 1762 cpkp->in_errors.value.ui64 = psp->ppp_ierrors; 1763 cpkp->in_errors_low.value.ui32 = cp->cp_ierr_low; 1764 cpkp->in_uncomp_bytes.value.ui32 = csp.d.unc_bytes; 1765 cpkp->in_uncomp_pkts.value.ui32 = csp.d.unc_packets; 1766 cpkp->in_comp_bytes.value.ui32 = csp.d.comp_bytes; 1767 cpkp->in_comp_pkts.value.ui32 = csp.d.comp_packets; 1768 cpkp->in_incomp_bytes.value.ui32 = csp.d.inc_bytes; 1769 cpkp->in_incomp_pkts.value.ui32 = csp.d.inc_packets; 1770 #ifdef SPC_DEBUG 1771 cpkp->in_msg_ccp_pulledup.value.ui32 = cp->cp_imsg_ccp_pull; 1772 cpkp->in_msg_vj_pulledup.value.ui32 = cp->cp_imsg_vj_pull; 1773 cpkp->out_msg_pulledup.value.ui32 = cp->cp_omsg_pull; 1774 cpkp->out_msg_copied.value.ui32 = cp->cp_omsg_dcopy; 1775 cpkp->out_queued.value.ui32 = cp->cp_out_queued; 1776 cpkp->out_handled.value.ui32 = cp->cp_out_handled; 1777 cpkp->in_queued.value.ui32 = cp->cp_in_queued; 1778 cpkp->in_handled.value.ui32 = cp->cp_in_handled; 1779 #endif 1780 mutex_exit(&cp->cp_pair_lock); 1781 return (0); 1782 } 1783