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 /*
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
_init(void)81 _init(void)
82 {
83 return (mod_install(&modlinkage));
84 }
85
86 int
_fini(void)87 _fini(void)
88 {
89 return (mod_remove(&modlinkage));
90 }
91
92 int
_info(struct modinfo * modinfop)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 int pcktrput(queue_t *, mblk_t *);
101 static int pcktrsrv(queue_t *);
102 static int 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 pcktrput,
146 pcktrsrv,
147 pcktopen,
148 pcktclose,
149 NULL,
150 &pcktiinfo,
151 NULL
152 };
153
154 static struct qinit pcktwinit = {
155 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
dummy_callback(void * arg)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
pcktopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * credp)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 */
225 pip = kmem_zalloc(sizeof (*pip), KM_SLEEP);
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
pcktclose(queue_t * q,int flag,cred_t * credp)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 int
pcktrput(queue_t * q,mblk_t * mp)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 return (0);
410 }
411
412 /*
413 * pcktrsrv - module read service procedure
414 * This function deals with messages left in the queue due to
415 * (a) not enough memory to allocate the header M_PROTO message
416 * (b) flow control reasons
417 * The function will attempt to get the messages off the queue and
418 * process them.
419 */
420 static int
pcktrsrv(queue_t * q)421 pcktrsrv(queue_t *q)
422 {
423 mblk_t *mp;
424
425 while ((mp = getq(q)) != NULL) {
426 if (!canputnext(q)) {
427 /*
428 * For high priority messages, make sure there is no
429 * infinite loop. Disable the queue for this case.
430 * High priority messages get here only for buffer
431 * allocation failures. Thus the bufcall callout
432 * will reenable the q.
433 * XXX bug alert - nooenable will *not* prevent
434 * putbq of a hipri messages frm enabling the queue.
435 */
436 if (!datamsg(mp->b_datap->db_type))
437 noenable(q);
438 (void) putbq(q, mp);
439 return (0);
440 }
441
442 /*
443 * M_FLUSH msgs may also be here if there was a memory
444 * failure.
445 */
446 switch (mp->b_datap->db_type) {
447 case M_FLUSH:
448 case M_PROTO:
449 case M_PCPROTO:
450 case M_STOP:
451 case M_START:
452 case M_IOCTL:
453 case M_DATA:
454 case M_READ:
455 case M_STARTI:
456 case M_STOPI:
457 /*
458 * Prefix an M_PROTO header to msg and pass upstream.
459 */
460 if ((mp = add_ctl_info(q, mp)) == NULL) {
461 /*
462 * Running into memory or flow ctl problems.
463 */
464 return (0);
465 }
466 /* FALL THROUGH */
467
468 default:
469 putnext(q, mp);
470 break;
471 }
472 }
473 return (0);
474 }
475
476 /*
477 * pcktwput - Module write queue put procedure.
478 * All messages are send downstream unchanged
479 */
480
481 static int
pcktwput(queue_t * q,mblk_t * mp)482 pcktwput(
483 queue_t *q, /* Pointer to the read queue */
484 mblk_t *mp) /* Pointer to current message block */
485 {
486 putnext(q, mp);
487 return (0);
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 mblk_t *nmp;
506
507 ASSERT(mp->b_datap->db_ref >= 1);
508
509 /*
510 * No reallocation is needed if there is only one reference
511 * to this data block.
512 */
513 if (mp->b_datap->db_ref == 1)
514 return (mp);
515
516 if ((nmp = copyb(mp)) == NULL) {
517 struct pckt_info *pip = (struct pckt_info *)q->q_ptr;
518
519 noenable(q);
520 if (pip->pi_bufcall_id = qbufcall(q, mp->b_wptr - mp->b_rptr,
521 BPRI_MED, add_ctl_wkup, q)) {
522 /*
523 * Put the message back onto the q.
524 */
525 (void) putq(q, mp);
526 } else {
527 /*
528 * Things are pretty bad and serious if bufcall fails!
529 * Drop the message in this case.
530 */
531 freemsg(mp);
532 }
533 return ((mblk_t *)0);
534 }
535
536 nmp->b_cont = mp->b_cont;
537 freeb(mp);
538 return (nmp);
539 }
540 #endif /* _MULTI_DATAMODEL */
541
542 /*
543 * add_ctl_info: add message control information to in coming
544 * message.
545 */
546 static mblk_t *
add_ctl_info(queue_t * q,mblk_t * mp)547 add_ctl_info(
548 queue_t *q, /* pointer to the read queue */
549 mblk_t *mp) /* pointer to the raw data input message */
550 {
551 struct pckt_info *pip = (struct pckt_info *)q->q_ptr;
552 mblk_t *bp; /* pointer to the unmodified message block */
553
554 /*
555 * Waiting on space for previous message?
556 */
557 if (pip->pi_bufcall_id) {
558 /*
559 * Chain this message on to q for later processing.
560 */
561 (void) putq(q, mp);
562 return (NULL);
563 }
564
565 /*
566 * Need to add the message block header as
567 * an M_PROTO type message.
568 */
569 if ((bp = allocb(sizeof (char), BPRI_MED)) == (mblk_t *)NULL) {
570
571 /*
572 * There are two reasons to disable the q:
573 * (1) Flow control reasons should not wake up the q.
574 * (2) High priority messages will wakeup the q
575 * immediately. Disallow this.
576 */
577 noenable(q);
578 if (pip->pi_bufcall_id = qbufcall(q, sizeof (char), BPRI_MED,
579 add_ctl_wkup, q)) {
580 /*
581 * Add the message to the q.
582 */
583 (void) putq(q, mp);
584 } else {
585 /*
586 * Things are pretty bad and serious if bufcall fails!
587 * Drop the message in this case.
588 */
589 freemsg(mp);
590 }
591
592 return (NULL);
593 }
594
595 /*
596 * Copy the message type information to this message.
597 */
598 bp->b_datap->db_type = M_PROTO;
599 *(unsigned char *)bp->b_rptr = mp->b_datap->db_type;
600 bp->b_wptr++;
601
602 #ifdef _MULTI_DATAMODEL
603 /*
604 * Check the datamodel and if the calling program is
605 * an ILP32 application then we covert the M_IOCTLs and M_READs
606 * into the native ILP32 format before passing them upstream
607 * to user mode.
608 */
609 switch (pip->model) {
610 case DDI_MODEL_ILP32:
611 switch (mp->b_datap->db_type) {
612 /*
613 * This structure must have the same shape as
614 * the * ILP32 compilation of `struct iocblk'
615 * from <sys/stream.h>.
616 */
617 struct iocblk32 {
618 int32_t ioc_cmd;
619 caddr32_t ioc_cr;
620 uint32_t ioc_id;
621 int32_t ioc_count;
622 int32_t ioc_error;
623 int32_t ioc_rval;
624 int32_t ioc_fill1;
625 uint32_t ioc_flag;
626 int32_t ioc_filler[2];
627 } niocblk_32;
628 struct iocblk *iocblk_64;
629
630 case M_IOCTL:
631 if ((mp = pckt_reallocb(q, mp)) == (mblk_t *)0)
632 return ((mblk_t *)0);
633
634 bzero(&niocblk_32, sizeof (niocblk_32));
635 iocblk_64 = (struct iocblk *)mp->b_rptr;
636
637 /* Leave the pointer to cred_t structure as it is. */
638 niocblk_32.ioc_cmd = iocblk_64->ioc_cmd;
639 niocblk_32.ioc_cr = (caddr32_t)(uintptr_t)
640 iocblk_64->ioc_cr;
641 niocblk_32.ioc_id = iocblk_64->ioc_id;
642 niocblk_32.ioc_count = iocblk_64->ioc_count;
643 niocblk_32.ioc_error = iocblk_64->ioc_error;
644 niocblk_32.ioc_rval = iocblk_64->ioc_rval;
645 niocblk_32.ioc_flag = iocblk_64->ioc_flag;
646
647 /* Copy the iocblk structure for ILP32 back */
648 *(struct iocblk32 *)mp->b_rptr = niocblk_32;
649 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk32);
650 break;
651
652 case M_READ:
653 if ((mp = pckt_reallocb(q, mp)) == (mblk_t *)0)
654 return ((mblk_t *)0);
655
656 /* change the size_t to size32_t for ILP32 */
657 *(size32_t *)mp->b_rptr = *(size_t *)mp->b_rptr;
658 mp->b_wptr = mp->b_rptr + sizeof (size32_t);
659 break;
660 }
661 break;
662
663 case DATAMODEL_NONE:
664 break;
665 }
666 #endif /* _MULTI_DATAMODEL */
667
668 /*
669 * Now change the orginal message type to M_DATA and tie them up.
670 */
671 mp->b_datap->db_type = M_DATA;
672 bp->b_cont = mp;
673
674 return (bp);
675 }
676
677 static void
add_ctl_wkup(void * arg)678 add_ctl_wkup(void *arg)
679 {
680 queue_t *q = arg; /* ptr to the read queue */
681 struct pckt_info *pip = (struct pckt_info *)q->q_ptr;
682
683 pip->pi_bufcall_id = 0;
684 /*
685 * Allow enabling of the q to allow the service
686 * function to do its job.
687 *
688 * Also, qenable() to schedule the q immediately.
689 * This is to ensure timely processing of high priority
690 * messages if they are on the q.
691 */
692 enableok(q);
693 qenable(q);
694 }
695