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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
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.
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/stream.h>
40 #include <sys/stropts.h>
42 #include <sys/errno.h>
44 #include <sys/sunddi.h>
45 #include <sys/debug.h>
48 * This is the loadable module wrapper.
51 #include <sys/modctl.h>
53 static struct streamtab pcktinfo
;
56 * Per queue instances are single-threaded since the q_ptr
57 * field of queues need to be shared among threads.
59 static struct fmodsw fsw
= {
62 D_NEW
| D_MTPERQ
| D_MP
66 * Module linkage information for the kernel.
69 static struct modlstrmod modlstrmod
= {
75 static struct modlinkage modlinkage
= {
76 MODREV_1
, &modlstrmod
, NULL
83 return (mod_install(&modlinkage
));
89 return (mod_remove(&modlinkage
));
93 _info(struct modinfo
*modinfop
)
95 return (mod_info(&modlinkage
, modinfop
));
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 *);
108 * Stream module data structure definitions.
109 * Sits over the ptm module generally.
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.
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 */
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.
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 */
144 static struct qinit pcktrinit
= {
154 static struct qinit pcktwinit
= {
164 static struct streamtab pcktinfo
= {
173 * Per-instance state struct for the pckt module.
176 queue_t
*pi_qptr
; /* back pointer to q */
177 bufcall_id_t pi_bufcall_id
;
178 #ifdef _MULTI_DATAMODEL
180 #endif /* _MULTI_DATAMODEL */
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).)
194 dummy_callback(void *arg
)
198 * pcktopen - open routine gets called when the
199 * module gets pushed onto the stream.
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 */
210 struct pckt_info
*pip
;
211 mblk_t
*mop
; /* ptr to a setopts msg block */
212 struct stroptions
*sop
;
214 if (sflag
!= MODOPEN
)
217 if (q
->q_ptr
!= NULL
) {
218 /* It's already attached. */
223 * Allocate state structure.
225 pip
= kmem_zalloc(sizeof (*pip
), KM_SLEEP
);
227 #ifdef _MULTI_DATAMODEL
228 pip
->model
= ddi_model_convert_from(get_udatamodel());
229 #endif /* _MULTI_DATAMODEL */
241 * Initialize an M_SETOPTS message to set up hi/lo water marks on
242 * stream head read queue.
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
);
250 kmem_free(pip
, sizeof (*pip
));
259 * XXX: Should this module really control the hi/low water marks?
260 * Is there any reason in this code to do so?
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
;
270 * Commit to the open and send the M_SETOPTS off to the stream head.
279 * pcktclose - This routine gets called when the module
280 * gets popped off of the stream.
286 queue_t
*q
, /* Pointer to the read queue */
290 struct pckt_info
*pip
= (struct pckt_info
*)q
->q_ptr
;
294 * Cancel outstanding qbufcall
296 if (pip
->pi_bufcall_id
) {
297 qunbufcall(q
, pip
->pi_bufcall_id
);
298 pip
->pi_bufcall_id
= 0;
301 * Do not worry about msgs queued on the q, the framework
304 kmem_free(q
->q_ptr
, sizeof (struct pckt_info
));
305 q
->q_ptr
= WR(q
)->q_ptr
= NULL
;
310 * pcktrput - Module read queue put procedure.
311 * This is called from the module or
316 queue_t
*q
, /* Pointer to the read queue */
317 mblk_t
*mp
) /* Pointer to the current message block */
322 switch (mp
->b_datap
->db_type
) {
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.
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
;
335 pckt_msgp
= copymsg(mp
);
336 if (*mp
->b_rptr
& FLUSHW
) {
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
345 *mp
->b_rptr
= FLUSHW
;
349 * Free messages that only flush the
350 * master's read queue.
355 if (pckt_msgp
== NULL
)
360 * Prefix M_PROTO and putnext.
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.
372 if (!canputnext(q
) || (qsize(q
) > 0)) {
379 * For high priority messages, skip flow control checks.
389 * Prefix an M_PROTO header to message and pass upstream.
391 if ((mp
= add_ctl_info(q
, mp
)) != NULL
)
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.
403 if ((datamsg(mp
->b_datap
->db_type
)) && (qsize(q
) > 0))
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
424 while ((mp
= getq(q
)) != NULL
) {
425 if (!canputnext(q
)) {
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.
435 if (!datamsg(mp
->b_datap
->db_type
))
442 * M_FLUSH msgs may also be here if there was a memory
445 switch (mp
->b_datap
->db_type
) {
457 * Prefix an M_PROTO header to msg and pass upstream.
459 if ((mp
= add_ctl_info(q
, mp
)) == NULL
) {
461 * Running into memory or flow ctl problems.
475 * pcktwput - Module write queue put procedure.
476 * All messages are send downstream unchanged
481 queue_t
*q
, /* Pointer to the read queue */
482 mblk_t
*mp
) /* Pointer to current message block */
487 #ifdef _MULTI_DATAMODEL
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).
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.
499 queue_t
*q
, /* Pointer to the read queue */
500 mblk_t
*mp
/* Pointer to the message block to be changed */
505 ASSERT(mp
->b_datap
->db_ref
>= 1);
508 * No reallocation is needed if there is only one reference
509 * to this data block.
511 if (mp
->b_datap
->db_ref
== 1)
514 if ((nmp
= copyb(mp
)) == NULL
) {
515 struct pckt_info
*pip
= (struct pckt_info
*)q
->q_ptr
;
518 if (pip
->pi_bufcall_id
= qbufcall(q
, mp
->b_wptr
- mp
->b_rptr
,
519 BPRI_MED
, add_ctl_wkup
, q
)) {
521 * Put the message back onto the q.
526 * Things are pretty bad and serious if bufcall fails!
527 * Drop the message in this case.
531 return ((mblk_t
*)0);
534 nmp
->b_cont
= mp
->b_cont
;
538 #endif /* _MULTI_DATAMODEL */
541 * add_ctl_info: add message control information to in coming
546 queue_t
*q
, /* pointer to the read queue */
547 mblk_t
*mp
) /* pointer to the raw data input message */
549 struct pckt_info
*pip
= (struct pckt_info
*)q
->q_ptr
;
550 mblk_t
*bp
; /* pointer to the unmodified message block */
553 * Waiting on space for previous message?
555 if (pip
->pi_bufcall_id
) {
557 * Chain this message on to q for later processing.
564 * Need to add the message block header as
565 * an M_PROTO type message.
567 if ((bp
= allocb(sizeof (char), BPRI_MED
)) == NULL
) {
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.
576 if (pip
->pi_bufcall_id
= qbufcall(q
, sizeof (char), BPRI_MED
,
579 * Add the message to the q.
584 * Things are pretty bad and serious if bufcall fails!
585 * Drop the message in this case.
594 * Copy the message type information to this message.
596 bp
->b_datap
->db_type
= M_PROTO
;
597 *(unsigned char *)bp
->b_rptr
= mp
->b_datap
->db_type
;
600 #ifdef _MULTI_DATAMODEL
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
607 switch (pip
->model
) {
608 case DDI_MODEL_ILP32
:
609 switch (mp
->b_datap
->db_type
) {
611 * This structure must have the same shape as
612 * the * ILP32 compilation of `struct iocblk'
613 * from <sys/stream.h>.
624 int32_t ioc_filler
[2];
626 struct iocblk
*iocblk_64
;
629 if ((mp
= pckt_reallocb(q
, mp
)) == (mblk_t
*)0)
630 return ((mblk_t
*)0);
632 bzero(&niocblk_32
, sizeof (niocblk_32
));
633 iocblk_64
= (struct iocblk
*)mp
->b_rptr
;
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)
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
;
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
);
651 if ((mp
= pckt_reallocb(q
, mp
)) == (mblk_t
*)0)
652 return ((mblk_t
*)0);
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
);
664 #endif /* _MULTI_DATAMODEL */
667 * Now change the orginal message type to M_DATA and tie them up.
669 mp
->b_datap
->db_type
= M_DATA
;
676 add_ctl_wkup(void *arg
)
678 queue_t
*q
= arg
; /* ptr to the read queue */
679 struct pckt_info
*pip
= (struct pckt_info
*)q
->q_ptr
;
681 pip
->pi_bufcall_id
= 0;
683 * Allow enabling of the q to allow the service
684 * function to do its job.
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.