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