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
_init(void)83 _init(void)
84 {
85 return (mod_install(&modlinkage));
86 }
87
88 int
_fini(void)89 _fini(void)
90 {
91 return (mod_remove(&modlinkage));
92 }
93
94 int
_info(struct modinfo * modinfop)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
dummy_callback(void * arg)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
pcktopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * credp)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
pcktclose(queue_t * q,int flag,cred_t * credp)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
pcktrput(queue_t * q,mblk_t * mp)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
pcktrsrv(queue_t * q)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
pcktwput(queue_t * q,mblk_t * mp)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 *
pckt_reallocb(queue_t * q,mblk_t * mp)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 *
add_ctl_info(queue_t * q,mblk_t * mp)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
add_ctl_wkup(void * arg)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 }
696