1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 
  31 #pragma ident   "%Z%%M% %I%     %E% SMI"        /* from S5R4 1.10 */
  32 
  33 /*
  34  * Description: The pckt module packetizes messages on
  35  *              its read queue by pre-fixing an M_PROTO
  36  *              message type to certain incoming messages.
  37  */
  38 
  39 #include <sys/types.h>
  40 #include <sys/param.h>
  41 #include <sys/stream.h>
  42 #include <sys/stropts.h>
  43 #include <sys/kmem.h>
  44 #include <sys/errno.h>
  45 #include <sys/ddi.h>
  46 #include <sys/sunddi.h>
  47 #include <sys/debug.h>
  48 
  49 /*
  50  * This is the loadable module wrapper.
  51  */
  52 #include <sys/conf.h>
  53 #include <sys/modctl.h>
  54 
  55 static struct streamtab pcktinfo;
  56 
  57 /*
  58  * Per queue instances are single-threaded since the q_ptr
  59  * field of queues need to be shared among threads.
  60  */
  61 static struct fmodsw fsw = {
  62         "pckt",
  63         &pcktinfo,
  64         D_NEW | D_MTPERQ | D_MP
  65 };
  66 
  67 /*
  68  * Module linkage information for the kernel.
  69  */
  70 
  71 static struct modlstrmod modlstrmod = {
  72         &mod_strmodops,
  73         "pckt module",
  74         &fsw
  75 };
  76 
  77 static struct modlinkage modlinkage = {
  78         MODREV_1, &modlstrmod, NULL
  79 };
  80 
  81 
  82 int
  83 _init(void)
  84 {
  85         return (mod_install(&modlinkage));
  86 }
  87 
  88 int
  89 _fini(void)
  90 {
  91         return (mod_remove(&modlinkage));
  92 }
  93 
  94 int
  95 _info(struct modinfo *modinfop)
  96 {
  97         return (mod_info(&modlinkage, modinfop));
  98 }
  99 
 100 static int      pcktopen(queue_t *, dev_t *, int, int, cred_t *);
 101 static int      pcktclose(queue_t *, int, cred_t *);
 102 static void     pcktrput(queue_t *, mblk_t *);
 103 static void     pcktrsrv(queue_t *);
 104 static void     pcktwput(queue_t *, mblk_t *);
 105 static mblk_t   *add_ctl_info(queue_t *, mblk_t *);
 106 static void     add_ctl_wkup(void *);
 107 
 108 
 109 /*
 110  * Stream module data structure definitions.
 111  * Sits over the ptm module generally.
 112  *
 113  * Read side flow control strategy: Since we may be putting messages on
 114  * the read q due to allocb failures, these failures must get
 115  * reflected fairly quickly to the module below us.
 116  * No sense in piling on messages in times of memory shortage.
 117  * Further, for the case of upper level flow control, there is no
 118  * compelling reason to have more buffering in this module.
 119  * Thus use a hi-water mark of one.
 120  * This module imposes no max packet size, there is no inherent reason
 121  * in the code to do so.
 122  */
 123 static struct module_info pcktiinfo = {
 124         0x9898,                                 /* module id number */
 125         "pckt",                                 /* module name */
 126         0,                                      /* minimum packet size */
 127         INFPSZ,                                 /* maximum packet size */
 128         1,                                      /* hi-water mark */
 129         0                                       /* lo-water mark */
 130 };
 131 
 132 /*
 133  * Write side flow control strategy: There is no write service procedure.
 134  * The write put function is pass thru, thus there is no reason to have any
 135  * limits on the maximum packet size.
 136  */
 137 static struct module_info pcktoinfo = {
 138         0x9898,                                 /* module id number */
 139         "pckt",                                 /* module name */
 140         0,                                      /* minimum packet size */
 141         INFPSZ,                                 /* maximum packet size */
 142         0,                                      /* hi-water mark */
 143         0                                       /* lo-water mark */
 144 };
 145 
 146 static struct qinit pcktrinit = {
 147         (int (*)())pcktrput,
 148         (int (*)())pcktrsrv,
 149         pcktopen,
 150         pcktclose,
 151         NULL,
 152         &pcktiinfo,
 153         NULL
 154 };
 155 
 156 static struct qinit pcktwinit = {
 157         (int (*)())pcktwput,
 158         NULL,
 159         NULL,
 160         NULL,
 161         NULL,
 162         &pcktoinfo,
 163         NULL
 164 };
 165 
 166 static struct streamtab pcktinfo = {
 167         &pcktrinit,
 168         &pcktwinit,
 169         NULL,
 170         NULL
 171 };
 172 
 173 
 174 /*
 175  * Per-instance state struct for the pckt module.
 176  */
 177 struct pckt_info {
 178         queue_t         *pi_qptr;               /* back pointer to q */
 179         bufcall_id_t    pi_bufcall_id;
 180 #ifdef _MULTI_DATAMODEL
 181         model_t         model;
 182 #endif /* _MULTI_DATAMODEL */
 183 };
 184 
 185 /*
 186  * Dummy qbufcall callback routine used by open and close.
 187  * The framework will wake up qwait_sig when we return from
 188  * this routine (as part of leaving the perimeters.)
 189  * (The framework enters the perimeters before calling the qbufcall() callback
 190  * and leaves the perimeters after the callback routine has executed. The
 191  * framework performs an implicit wakeup of any thread in qwait/qwait_sig
 192  * when it leaves the perimeter. See qwait(9E).)
 193  */
 194 /* ARGSUSED */
 195 static void
 196 dummy_callback(void *arg)
 197 {}
 198 
 199 /*
 200  * pcktopen - open routine gets called when the
 201  *          module gets pushed onto the stream.
 202  */
 203 /*ARGSUSED*/
 204 static int
 205 pcktopen(
 206         queue_t *q,             /* pointer to the read side queue */
 207         dev_t   *devp,          /* pointer to stream tail's dev */
 208         int     oflag,          /* the user open(2) supplied flags */
 209         int     sflag,          /* open state flag */
 210         cred_t  *credp)         /* credentials */
 211 {
 212         struct pckt_info        *pip;
 213         mblk_t                  *mop; /* ptr to a setopts msg block */
 214         struct stroptions       *sop;
 215 
 216         if (sflag != MODOPEN)
 217                 return (EINVAL);
 218 
 219         if (q->q_ptr != NULL) {
 220                 /* It's already attached. */
 221                 return (0);
 222         }
 223 
 224         /*
 225          * Allocate state structure.
 226          */
 227         pip = kmem_alloc(sizeof (*pip), KM_SLEEP);
 228         bzero(pip, sizeof (*pip));
 229 
 230 #ifdef _MULTI_DATAMODEL
 231         pip->model = ddi_model_convert_from(get_udatamodel());
 232 #endif /* _MULTI_DATAMODEL */
 233 
 234         /*
 235          * Cross-link.
 236          */
 237         pip->pi_qptr = q;
 238         q->q_ptr = pip;
 239         WR(q)->q_ptr = pip;
 240 
 241         qprocson(q);
 242 
 243         /*
 244          * Initialize an M_SETOPTS message to set up hi/lo water marks on
 245          * stream head read queue.
 246          */
 247 
 248         while ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
 249                 bufcall_id_t id = qbufcall(q, sizeof (struct stroptions),
 250                     BPRI_MED, dummy_callback, NULL);
 251                 if (!qwait_sig(q)) {
 252                         qunbufcall(q, id);
 253                         kmem_free(pip, sizeof (*pip));
 254                         qprocsoff(q);
 255                         return (EINTR);
 256                 }
 257                 qunbufcall(q, id);
 258         }
 259 
 260 
 261         /*
 262          * XXX: Should this module really control the hi/low water marks?
 263          * Is there any reason in this code to do so?
 264          */
 265         mop->b_datap->db_type = M_SETOPTS;
 266         mop->b_wptr += sizeof (struct stroptions);
 267         sop = (struct stroptions *)mop->b_rptr;
 268         sop->so_flags = SO_HIWAT | SO_LOWAT;
 269         sop->so_hiwat = 512;
 270         sop->so_lowat = 256;
 271 
 272         /*
 273          * Commit to the open and send the M_SETOPTS off to the stream head.
 274          */
 275         putnext(q, mop);
 276 
 277         return (0);
 278 }
 279 
 280 
 281 /*
 282  * pcktclose - This routine gets called when the module
 283  *      gets popped off of the stream.
 284  */
 285 
 286 /*ARGSUSED*/
 287 static int
 288 pcktclose(
 289         queue_t *q,     /* Pointer to the read queue */
 290         int     flag,
 291         cred_t  *credp)
 292 {
 293         struct pckt_info        *pip = (struct pckt_info *)q->q_ptr;
 294 
 295         qprocsoff(q);
 296         /*
 297          * Cancel outstanding qbufcall
 298          */
 299         if (pip->pi_bufcall_id) {
 300                 qunbufcall(q, pip->pi_bufcall_id);
 301                 pip->pi_bufcall_id = 0;
 302         }
 303         /*
 304          * Do not worry about msgs queued on the q, the framework
 305          * will free them up.
 306          */
 307         kmem_free(q->q_ptr, sizeof (struct pckt_info));
 308         q->q_ptr = WR(q)->q_ptr = NULL;
 309         return (0);
 310 }
 311 
 312 /*
 313  * pcktrput - Module read queue put procedure.
 314  *      This is called from the module or
 315  *      driver downstream.
 316  */
 317 static void
 318 pcktrput(
 319         queue_t *q,     /* Pointer to the read queue */
 320         mblk_t *mp)     /* Pointer to the current message block */
 321 {
 322         mblk_t          *pckt_msgp;
 323 
 324 
 325         switch (mp->b_datap->db_type) {
 326         case M_FLUSH:
 327                 /*
 328                  * The PTS driver swaps the FLUSHR and FLUSHW flags
 329                  * we need to swap them back to reflect the actual
 330                  * slave side FLUSH mode.
 331                  */
 332                 if ((*mp->b_rptr & FLUSHRW) != FLUSHRW)
 333                         if ((*mp->b_rptr & FLUSHRW) == FLUSHR)
 334                                 *mp->b_rptr = FLUSHW;
 335                         else if ((*mp->b_rptr & FLUSHRW) == FLUSHW)
 336                                 *mp->b_rptr = FLUSHR;
 337 
 338                 pckt_msgp = copymsg(mp);
 339                 if (*mp->b_rptr & FLUSHW) {
 340                         /*
 341                          * In the packet model we are not allowing
 342                          * flushes of the master's stream head read
 343                          * side queue. This is because all packet
 344                          * state information is stored there and
 345                          * a flush could destroy this data before
 346                          * it is read.
 347                          */
 348                         *mp->b_rptr = FLUSHW;
 349                         putnext(q, mp);
 350                 } else {
 351                         /*
 352                          * Free messages that only flush the
 353                          * master's read queue.
 354                          */
 355                         freemsg(mp);
 356                 }
 357 
 358                 if (pckt_msgp == NULL)
 359                         break;
 360 
 361                 mp = pckt_msgp;
 362                 /*
 363                  * Prefix M_PROTO and putnext.
 364                  */
 365                 goto prefix_head;
 366 
 367         case M_DATA:
 368         case M_IOCTL:
 369         case M_PROTO:
 370                 /*
 371                  * For non-priority messages, follow flow-control rules.
 372                  * Also, if there are messages on the q already, keep
 373                  * queueing them since they need to be processed in order.
 374                  */
 375                 if (!canputnext(q) || (qsize(q) > 0)) {
 376                         (void) putq(q, mp);
 377                         break;
 378                 }
 379                 /* FALLTHROUGH */
 380 
 381         /*
 382          * For high priority messages, skip flow control checks.
 383          */
 384         case M_PCPROTO:
 385         case M_READ:
 386         case M_STOP:
 387         case M_START:
 388         case M_STARTI:
 389         case M_STOPI:
 390 prefix_head:
 391                 /*
 392                  * Prefix an M_PROTO header to message and pass upstream.
 393                  */
 394                 if ((mp = add_ctl_info(q, mp)) != NULL)
 395                         putnext(q, mp);
 396                 break;
 397 
 398         default:
 399                 /*
 400                  * For data messages, queue them back on the queue if
 401                  * there are messages on the queue already. This is
 402                  * done to preserve the order of messages.
 403                  * For high priority messages or for no messages on the
 404                  * q, simply putnext() and pass it on.
 405                  */
 406                 if ((datamsg(mp->b_datap->db_type)) && (qsize(q) > 0))
 407                         (void) putq(q, mp);
 408                 else
 409                         putnext(q, mp);
 410                 break;
 411         }
 412 }
 413 
 414 /*
 415  * pcktrsrv - module read service procedure
 416  * This function deals with messages left in the queue due to
 417  *      (a) not enough memory to allocate the header M_PROTO message
 418  *      (b) flow control reasons
 419  * The function will attempt to get the messages off the queue and
 420  * process them.
 421  */
 422 static void
 423 pcktrsrv(queue_t *q)
 424 {
 425         mblk_t *mp;
 426 
 427         while ((mp = getq(q)) != NULL) {
 428                 if (!canputnext(q)) {
 429                         /*
 430                          * For high priority messages, make sure there is no
 431                          * infinite loop. Disable the queue for this case.
 432                          * High priority messages get here only for buffer
 433                          * allocation failures. Thus the bufcall callout
 434                          * will reenable the q.
 435                          * XXX bug alert - nooenable will *not* prevent
 436                          * putbq of a hipri messages frm enabling the queue.
 437                          */
 438                         if (!datamsg(mp->b_datap->db_type))
 439                                 noenable(q);
 440                         (void) putbq(q, mp);
 441                         return;
 442                 }
 443 
 444                 /*
 445                  * M_FLUSH msgs may also be here if there was a memory
 446                  * failure.
 447                  */
 448                 switch (mp->b_datap->db_type) {
 449                 case M_FLUSH:
 450                 case M_PROTO:
 451                 case M_PCPROTO:
 452                 case M_STOP:
 453                 case M_START:
 454                 case M_IOCTL:
 455                 case M_DATA:
 456                 case M_READ:
 457                 case M_STARTI:
 458                 case M_STOPI:
 459                         /*
 460                          * Prefix an M_PROTO header to msg and pass upstream.
 461                          */
 462                         if ((mp = add_ctl_info(q, mp)) == NULL) {
 463                                 /*
 464                                  * Running into memory or flow ctl problems.
 465                                  */
 466                                 return;
 467                         }
 468                         /* FALL THROUGH */
 469 
 470                 default:
 471                         putnext(q, mp);
 472                         break;
 473                 }
 474         }
 475 }
 476 
 477 /*
 478  * pcktwput - Module write queue put procedure.
 479  *      All messages are send downstream unchanged
 480  */
 481 
 482 static void
 483 pcktwput(
 484         queue_t *q,     /* Pointer to the read queue */
 485         mblk_t *mp)     /* Pointer to current message block */
 486 {
 487         putnext(q, mp);
 488 }
 489 
 490 #ifdef _MULTI_DATAMODEL
 491 /*
 492  * reallocb - copy the data block from the given message block into a new block.
 493  * This function is used in case data block had another message block
 494  * pointing to it (and hence we just copy this one data block).
 495  *
 496  * Returns new message block if successful. On failure it returns NULL.
 497  * It also tries to do a qbufcall and if that also fails,
 498  * it frees the message block.
 499  */
 500 static mblk_t *
 501 pckt_reallocb(
 502         queue_t *q,     /* Pointer to the read queue */
 503         mblk_t *mp      /* Pointer to the message block to be changed */
 504 )
 505 {
 506         mblk_t  *nmp;
 507 
 508         ASSERT(mp->b_datap->db_ref >= 1);
 509 
 510         /*
 511          * No reallocation is needed if there is only one reference
 512          * to this data block.
 513          */
 514         if (mp->b_datap->db_ref == 1)
 515                 return (mp);
 516 
 517         if ((nmp = copyb(mp)) == NULL) {
 518                 struct pckt_info        *pip = (struct pckt_info *)q->q_ptr;
 519 
 520                 noenable(q);
 521                 if (pip->pi_bufcall_id = qbufcall(q, mp->b_wptr - mp->b_rptr,
 522                     BPRI_MED, add_ctl_wkup, q)) {
 523                         /*
 524                          * Put the message back onto the q.
 525                          */
 526                         (void) putq(q, mp);
 527                 } else {
 528                         /*
 529                          * Things are pretty bad and serious if bufcall fails!
 530                          * Drop the message in this case.
 531                          */
 532                         freemsg(mp);
 533                 }
 534                 return ((mblk_t *)0);
 535         }
 536 
 537         nmp->b_cont = mp->b_cont;
 538         freeb(mp);
 539         return (nmp);
 540 }
 541 #endif /* _MULTI_DATAMODEL */
 542 
 543 /*
 544  * add_ctl_info: add message control information to in coming
 545  *      message.
 546  */
 547 static mblk_t *
 548 add_ctl_info(
 549         queue_t *q,             /* pointer to the read queue */
 550         mblk_t  *mp)            /* pointer to the raw data input message */
 551 {
 552         struct pckt_info        *pip = (struct pckt_info *)q->q_ptr;
 553         mblk_t  *bp;            /* pointer to the unmodified message block */
 554 
 555         /*
 556          * Waiting on space for previous message?
 557          */
 558         if (pip->pi_bufcall_id) {
 559                 /*
 560                  * Chain this message on to q for later processing.
 561                  */
 562                 (void) putq(q, mp);
 563                 return (NULL);
 564         }
 565 
 566         /*
 567          * Need to add the message block header as
 568          * an M_PROTO type message.
 569          */
 570         if ((bp = allocb(sizeof (char), BPRI_MED)) == (mblk_t *)NULL) {
 571 
 572                 /*
 573                  * There are two reasons to disable the q:
 574                  * (1) Flow control reasons should not wake up the q.
 575                  * (2) High priority messages will wakeup the q
 576                  *      immediately. Disallow this.
 577                  */
 578                 noenable(q);
 579                 if (pip->pi_bufcall_id = qbufcall(q, sizeof (char), BPRI_MED,
 580                     add_ctl_wkup, q)) {
 581                         /*
 582                          * Add the message to the q.
 583                          */
 584                         (void) putq(q, mp);
 585                 } else {
 586                         /*
 587                          * Things are pretty bad and serious if bufcall fails!
 588                          * Drop the message in this case.
 589                          */
 590                         freemsg(mp);
 591                 }
 592 
 593                 return (NULL);
 594         }
 595 
 596         /*
 597          * Copy the message type information to this message.
 598          */
 599         bp->b_datap->db_type = M_PROTO;
 600         *(unsigned char *)bp->b_rptr = mp->b_datap->db_type;
 601         bp->b_wptr++;
 602 
 603 #ifdef _MULTI_DATAMODEL
 604         /*
 605          * Check the datamodel and if the calling program is
 606          * an ILP32 application then we covert the M_IOCTLs and M_READs
 607          * into the native ILP32 format before passing them upstream
 608          * to user mode.
 609          */
 610         switch (pip->model) {
 611         case DDI_MODEL_ILP32:
 612                 switch (mp->b_datap->db_type) {
 613                         /*
 614                          * This structure must have the same shape as
 615                          * the * ILP32 compilation of `struct iocblk'
 616                          * from <sys/stream.h>.
 617                          */
 618                         struct iocblk32 {
 619                                 int32_t         ioc_cmd;
 620                                 caddr32_t       ioc_cr;
 621                                 uint32_t        ioc_id;
 622                                 int32_t         ioc_count;
 623                                 int32_t         ioc_error;
 624                                 int32_t         ioc_rval;
 625                                 int32_t         ioc_fill1;
 626                                 uint32_t        ioc_flag;
 627                                 int32_t         ioc_filler[2];
 628                         } niocblk_32;
 629                         struct iocblk           *iocblk_64;
 630 
 631                 case M_IOCTL:
 632                         if ((mp = pckt_reallocb(q, mp)) == (mblk_t *)0)
 633                                 return ((mblk_t *)0);
 634 
 635                         bzero(&niocblk_32, sizeof (niocblk_32));
 636                         iocblk_64 = (struct iocblk *)mp->b_rptr;
 637 
 638                         /* Leave the pointer to cred_t structure as it is. */
 639                         niocblk_32.ioc_cmd = iocblk_64->ioc_cmd;
 640                         niocblk_32.ioc_cr = (caddr32_t)(uintptr_t)
 641                             iocblk_64->ioc_cr;
 642                         niocblk_32.ioc_id = iocblk_64->ioc_id;
 643                         niocblk_32.ioc_count = iocblk_64->ioc_count;
 644                         niocblk_32.ioc_error = iocblk_64->ioc_error;
 645                         niocblk_32.ioc_rval = iocblk_64->ioc_rval;
 646                         niocblk_32.ioc_flag = iocblk_64->ioc_flag;
 647 
 648                         /* Copy the iocblk structure for ILP32 back */
 649                         *(struct iocblk32 *)mp->b_rptr = niocblk_32;
 650                         mp->b_wptr = mp->b_rptr + sizeof (struct iocblk32);
 651                         break;
 652 
 653                 case M_READ:
 654                         if ((mp = pckt_reallocb(q, mp)) == (mblk_t *)0)
 655                                 return ((mblk_t *)0);
 656 
 657                         /* change the size_t to size32_t for ILP32 */
 658                         *(size32_t *)mp->b_rptr = *(size_t *)mp->b_rptr;
 659                         mp->b_wptr = mp->b_rptr + sizeof (size32_t);
 660                         break;
 661                 }
 662                 break;
 663 
 664         case DATAMODEL_NONE:
 665                 break;
 666         }
 667 #endif /* _MULTI_DATAMODEL */
 668 
 669         /*
 670          * Now change the orginal message type to M_DATA and tie them up.
 671          */
 672         mp->b_datap->db_type = M_DATA;
 673         bp->b_cont = mp;
 674 
 675         return (bp);
 676 }
 677 
 678 static void
 679 add_ctl_wkup(void *arg)
 680 {
 681         queue_t *q = arg;       /* ptr to the read queue */
 682         struct pckt_info *pip = (struct pckt_info *)q->q_ptr;
 683 
 684         pip->pi_bufcall_id = 0;
 685         /*
 686          * Allow enabling of the q to allow the service
 687          * function to do its job.
 688          *
 689          * Also, qenable() to schedule the q immediately.
 690          * This is to ensure timely processing of high priority
 691          * messages if they are on the q.
 692          */
 693         enableok(q);
 694         qenable(q);
 695 }