17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25eb00302cSRyan Zezeski * Copyright 2018 Joyent, Inc.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate * STREAMS Buffering module
307c478bd9Sstevel@tonic-gate *
317c478bd9Sstevel@tonic-gate * This streams module collects incoming messages from modules below
327c478bd9Sstevel@tonic-gate * it on the stream and buffers them up into a smaller number of
337c478bd9Sstevel@tonic-gate * aggregated messages. Its main purpose is to reduce overhead by
347c478bd9Sstevel@tonic-gate * cutting down on the number of read (or getmsg) calls its client
357c478bd9Sstevel@tonic-gate * user process makes.
367c478bd9Sstevel@tonic-gate * - only M_DATA is buffered.
377c478bd9Sstevel@tonic-gate * - multithreading assumes configured as D_MTQPAIR
387c478bd9Sstevel@tonic-gate * - packets are lost only if flag SB_NO_HEADER is clear and buffer
397c478bd9Sstevel@tonic-gate * allocation fails.
407c478bd9Sstevel@tonic-gate * - in order message transmission. This is enforced for messages other
417c478bd9Sstevel@tonic-gate * than high priority messages.
427c478bd9Sstevel@tonic-gate * - zero length messages on the read side are not passed up the
437c478bd9Sstevel@tonic-gate * stream but used internally for synchronization.
447c478bd9Sstevel@tonic-gate * FLAGS:
457c478bd9Sstevel@tonic-gate * - SB_NO_PROTO_CVT - no conversion of M_PROTO messages to M_DATA.
467c478bd9Sstevel@tonic-gate * (conversion is the default for backwards compatibility
477c478bd9Sstevel@tonic-gate * hence the negative logic).
487c478bd9Sstevel@tonic-gate * - SB_NO_HEADER - no headers in buffered data.
497c478bd9Sstevel@tonic-gate * (adding headers is the default for backwards compatibility
507c478bd9Sstevel@tonic-gate * hence the negative logic).
517c478bd9Sstevel@tonic-gate * - SB_DEFER_CHUNK - provides improved response time in question-answer
527c478bd9Sstevel@tonic-gate * applications. Buffering is not enabled until the second message
537c478bd9Sstevel@tonic-gate * is received on the read side within the sb_ticks interval.
547c478bd9Sstevel@tonic-gate * This option will often be used in combination with flag SB_SEND_ON_WRITE.
557c478bd9Sstevel@tonic-gate * - SB_SEND_ON_WRITE - a write message results in any pending buffered read
567c478bd9Sstevel@tonic-gate * data being immediately sent upstream.
577c478bd9Sstevel@tonic-gate * - SB_NO_DROPS - bufmod behaves transparently in flow control and propagates
587c478bd9Sstevel@tonic-gate * the blocked flow condition downstream. If this flag is clear (default)
597c478bd9Sstevel@tonic-gate * messages will be dropped if the upstream flow is blocked.
607c478bd9Sstevel@tonic-gate */
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate #include <sys/types.h>
647c478bd9Sstevel@tonic-gate #include <sys/errno.h>
657c478bd9Sstevel@tonic-gate #include <sys/debug.h>
667c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
677c478bd9Sstevel@tonic-gate #include <sys/time.h>
687c478bd9Sstevel@tonic-gate #include <sys/stream.h>
697c478bd9Sstevel@tonic-gate #include <sys/conf.h>
707c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
717c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
727c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
737c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
747c478bd9Sstevel@tonic-gate #include <sys/bufmod.h>
757c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
767c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate * Per-Stream state information.
807c478bd9Sstevel@tonic-gate *
817c478bd9Sstevel@tonic-gate * If sb_ticks is negative, we don't deliver chunks until they're
827c478bd9Sstevel@tonic-gate * full. If it's zero, we deliver every packet as it arrives. (In
837c478bd9Sstevel@tonic-gate * this case we force sb_chunk to zero, to make the implementation
847c478bd9Sstevel@tonic-gate * easier.) Otherwise, sb_ticks gives the number of ticks in a
857c478bd9Sstevel@tonic-gate * buffering interval. The interval begins when the a read side data
867c478bd9Sstevel@tonic-gate * message is received and a timeout is not active. If sb_snap is
877c478bd9Sstevel@tonic-gate * zero, no truncation of the msg is done.
887c478bd9Sstevel@tonic-gate */
897c478bd9Sstevel@tonic-gate struct sb {
907c478bd9Sstevel@tonic-gate queue_t *sb_rq; /* our rq */
917c478bd9Sstevel@tonic-gate mblk_t *sb_mp; /* partial chunk */
927c478bd9Sstevel@tonic-gate mblk_t *sb_head; /* pre-allocated space for the next header */
937c478bd9Sstevel@tonic-gate mblk_t *sb_tail; /* first mblk of last message appended */
947c478bd9Sstevel@tonic-gate uint_t sb_mlen; /* sb_mp length */
957c478bd9Sstevel@tonic-gate uint_t sb_mcount; /* input msg count in sb_mp */
967c478bd9Sstevel@tonic-gate uint_t sb_chunk; /* max chunk size */
977c478bd9Sstevel@tonic-gate clock_t sb_ticks; /* timeout interval */
987c478bd9Sstevel@tonic-gate timeout_id_t sb_timeoutid; /* qtimeout() id */
997c478bd9Sstevel@tonic-gate uint_t sb_drops; /* cumulative # discarded msgs */
1007c478bd9Sstevel@tonic-gate uint_t sb_snap; /* snapshot length */
1017c478bd9Sstevel@tonic-gate uint_t sb_flags; /* flags field */
1027c478bd9Sstevel@tonic-gate uint_t sb_state; /* state variable */
1037c478bd9Sstevel@tonic-gate };
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate * Function prototypes.
1077c478bd9Sstevel@tonic-gate */
1087c478bd9Sstevel@tonic-gate static int sbopen(queue_t *, dev_t *, int, int, cred_t *);
1097c478bd9Sstevel@tonic-gate static int sbclose(queue_t *, int, cred_t *);
110*57198255SToomas Soome static int sbwput(queue_t *, mblk_t *);
111*57198255SToomas Soome static int sbrput(queue_t *, mblk_t *);
112*57198255SToomas Soome static int sbrsrv(queue_t *);
1137c478bd9Sstevel@tonic-gate static void sbioctl(queue_t *, mblk_t *);
1147c478bd9Sstevel@tonic-gate static void sbaddmsg(queue_t *, mblk_t *);
1157c478bd9Sstevel@tonic-gate static void sbtick(void *);
1167c478bd9Sstevel@tonic-gate static void sbclosechunk(struct sb *);
1177c478bd9Sstevel@tonic-gate static void sbsendit(queue_t *, mblk_t *);
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate static struct module_info sb_minfo = {
1207c478bd9Sstevel@tonic-gate 21, /* mi_idnum */
1217c478bd9Sstevel@tonic-gate "bufmod", /* mi_idname */
1227c478bd9Sstevel@tonic-gate 0, /* mi_minpsz */
1237c478bd9Sstevel@tonic-gate INFPSZ, /* mi_maxpsz */
1247c478bd9Sstevel@tonic-gate 1, /* mi_hiwat */
1257c478bd9Sstevel@tonic-gate 0 /* mi_lowat */
1267c478bd9Sstevel@tonic-gate };
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate static struct qinit sb_rinit = {
129*57198255SToomas Soome sbrput, /* qi_putp */
130*57198255SToomas Soome sbrsrv, /* qi_srvp */
1317c478bd9Sstevel@tonic-gate sbopen, /* qi_qopen */
1327c478bd9Sstevel@tonic-gate sbclose, /* qi_qclose */
1337c478bd9Sstevel@tonic-gate NULL, /* qi_qadmin */
1347c478bd9Sstevel@tonic-gate &sb_minfo, /* qi_minfo */
1357c478bd9Sstevel@tonic-gate NULL /* qi_mstat */
1367c478bd9Sstevel@tonic-gate };
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate static struct qinit sb_winit = {
139*57198255SToomas Soome sbwput, /* qi_putp */
1407c478bd9Sstevel@tonic-gate NULL, /* qi_srvp */
1417c478bd9Sstevel@tonic-gate NULL, /* qi_qopen */
1427c478bd9Sstevel@tonic-gate NULL, /* qi_qclose */
1437c478bd9Sstevel@tonic-gate NULL, /* qi_qadmin */
1447c478bd9Sstevel@tonic-gate &sb_minfo, /* qi_minfo */
1457c478bd9Sstevel@tonic-gate NULL /* qi_mstat */
1467c478bd9Sstevel@tonic-gate };
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate static struct streamtab sb_info = {
1497c478bd9Sstevel@tonic-gate &sb_rinit, /* st_rdinit */
1507c478bd9Sstevel@tonic-gate &sb_winit, /* st_wrinit */
1517c478bd9Sstevel@tonic-gate NULL, /* st_muxrinit */
1527c478bd9Sstevel@tonic-gate NULL /* st_muxwinit */
1537c478bd9Sstevel@tonic-gate };
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate * This is the loadable module wrapper.
1587c478bd9Sstevel@tonic-gate */
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate static struct fmodsw fsw = {
1617c478bd9Sstevel@tonic-gate "bufmod",
1627c478bd9Sstevel@tonic-gate &sb_info,
1637c478bd9Sstevel@tonic-gate D_MTQPAIR | D_MP
1647c478bd9Sstevel@tonic-gate };
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate * Module linkage information for the kernel.
1687c478bd9Sstevel@tonic-gate */
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
1717c478bd9Sstevel@tonic-gate &mod_strmodops, "streams buffer mod", &fsw
1727c478bd9Sstevel@tonic-gate };
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1757c478bd9Sstevel@tonic-gate MODREV_1, &modlstrmod, NULL
1767c478bd9Sstevel@tonic-gate };
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate int
_init(void)1807c478bd9Sstevel@tonic-gate _init(void)
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage));
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate int
_fini(void)1867c478bd9Sstevel@tonic-gate _fini(void)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage));
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1927c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate /* ARGSUSED */
1997c478bd9Sstevel@tonic-gate static int
sbopen(queue_t * rq,dev_t * dev,int oflag,int sflag,cred_t * crp)2007c478bd9Sstevel@tonic-gate sbopen(queue_t *rq, dev_t *dev, int oflag, int sflag, cred_t *crp)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate struct sb *sbp;
2037c478bd9Sstevel@tonic-gate ASSERT(rq);
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate if (sflag != MODOPEN)
2067c478bd9Sstevel@tonic-gate return (EINVAL);
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate if (rq->q_ptr)
2097c478bd9Sstevel@tonic-gate return (0);
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate /*
2127c478bd9Sstevel@tonic-gate * Allocate and initialize per-Stream structure.
2137c478bd9Sstevel@tonic-gate */
2147c478bd9Sstevel@tonic-gate sbp = kmem_alloc(sizeof (struct sb), KM_SLEEP);
2157c478bd9Sstevel@tonic-gate sbp->sb_rq = rq;
2167c478bd9Sstevel@tonic-gate sbp->sb_ticks = -1;
2177c478bd9Sstevel@tonic-gate sbp->sb_chunk = SB_DFLT_CHUNK;
2187c478bd9Sstevel@tonic-gate sbp->sb_tail = sbp->sb_mp = sbp->sb_head = NULL;
2197c478bd9Sstevel@tonic-gate sbp->sb_mlen = 0;
2207c478bd9Sstevel@tonic-gate sbp->sb_mcount = 0;
2217c478bd9Sstevel@tonic-gate sbp->sb_timeoutid = 0;
2227c478bd9Sstevel@tonic-gate sbp->sb_drops = 0;
2237c478bd9Sstevel@tonic-gate sbp->sb_snap = 0;
2247c478bd9Sstevel@tonic-gate sbp->sb_flags = 0;
2257c478bd9Sstevel@tonic-gate sbp->sb_state = 0;
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = sbp;
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate qprocson(rq);
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate return (0);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
2367c478bd9Sstevel@tonic-gate static int
sbclose(queue_t * rq,int flag,cred_t * credp)2377c478bd9Sstevel@tonic-gate sbclose(queue_t *rq, int flag, cred_t *credp)
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate struct sb *sbp = (struct sb *)rq->q_ptr;
2407c478bd9Sstevel@tonic-gate
2417c478bd9Sstevel@tonic-gate ASSERT(sbp);
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate qprocsoff(rq);
2447c478bd9Sstevel@tonic-gate /*
2457c478bd9Sstevel@tonic-gate * Cancel an outstanding timeout
2467c478bd9Sstevel@tonic-gate */
2477c478bd9Sstevel@tonic-gate if (sbp->sb_timeoutid != 0) {
2487c478bd9Sstevel@tonic-gate (void) quntimeout(rq, sbp->sb_timeoutid);
2497c478bd9Sstevel@tonic-gate sbp->sb_timeoutid = 0;
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate /*
2527c478bd9Sstevel@tonic-gate * Free the current chunk.
2537c478bd9Sstevel@tonic-gate */
2547c478bd9Sstevel@tonic-gate if (sbp->sb_mp) {
2557c478bd9Sstevel@tonic-gate freemsg(sbp->sb_mp);
2567c478bd9Sstevel@tonic-gate sbp->sb_tail = sbp->sb_mp = sbp->sb_head = NULL;
2577c478bd9Sstevel@tonic-gate sbp->sb_mlen = 0;
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate /*
2617c478bd9Sstevel@tonic-gate * Free the per-Stream structure.
2627c478bd9Sstevel@tonic-gate */
2637c478bd9Sstevel@tonic-gate kmem_free((caddr_t)sbp, sizeof (struct sb));
2647c478bd9Sstevel@tonic-gate rq->q_ptr = WR(rq)->q_ptr = NULL;
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate return (0);
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate /*
2707c478bd9Sstevel@tonic-gate * the correction factor is introduced to compensate for
2717c478bd9Sstevel@tonic-gate * whatever assumptions the modules below have made about
2727c478bd9Sstevel@tonic-gate * how much traffic is flowing through the stream and the fact
2737c478bd9Sstevel@tonic-gate * that bufmod may be snipping messages with the sb_snap length.
2747c478bd9Sstevel@tonic-gate */
2757c478bd9Sstevel@tonic-gate #define SNIT_HIWAT(msgsize, fudge) ((4 * msgsize * fudge) + 512)
2767c478bd9Sstevel@tonic-gate #define SNIT_LOWAT(msgsize, fudge) ((2 * msgsize * fudge) + 256)
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate static void
sbioc(queue_t * wq,mblk_t * mp)2807c478bd9Sstevel@tonic-gate sbioc(queue_t *wq, mblk_t *mp)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate struct iocblk *iocp;
2837c478bd9Sstevel@tonic-gate struct sb *sbp = (struct sb *)wq->q_ptr;
2847c478bd9Sstevel@tonic-gate clock_t ticks;
2857c478bd9Sstevel@tonic-gate mblk_t *mop;
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
2907c478bd9Sstevel@tonic-gate case SBIOCGCHUNK:
2917c478bd9Sstevel@tonic-gate case SBIOCGSNAP:
2927c478bd9Sstevel@tonic-gate case SBIOCGFLAGS:
2937c478bd9Sstevel@tonic-gate case SBIOCGTIME:
2947c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0);
2957c478bd9Sstevel@tonic-gate return;
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate case SBIOCSTIME:
2987c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
2997c478bd9Sstevel@tonic-gate if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
3007c478bd9Sstevel@tonic-gate struct timeval32 *t32;
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate t32 = (struct timeval32 *)mp->b_cont->b_rptr;
3037c478bd9Sstevel@tonic-gate if (t32->tv_sec < 0 || t32->tv_usec < 0) {
3047c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL);
3057c478bd9Sstevel@tonic-gate break;
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate ticks = TIMEVAL_TO_TICK(t32);
3087c478bd9Sstevel@tonic-gate } else
3097c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
3107c478bd9Sstevel@tonic-gate {
3117c478bd9Sstevel@tonic-gate struct timeval *tb;
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate tb = (struct timeval *)mp->b_cont->b_rptr;
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate if (tb->tv_sec < 0 || tb->tv_usec < 0) {
3167c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL);
3177c478bd9Sstevel@tonic-gate break;
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate ticks = TIMEVAL_TO_TICK(tb);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate sbp->sb_ticks = ticks;
3227c478bd9Sstevel@tonic-gate if (ticks == 0)
3237c478bd9Sstevel@tonic-gate sbp->sb_chunk = 0;
3247c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0);
3257c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
3267c478bd9Sstevel@tonic-gate return;
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate case SBIOCSCHUNK:
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate * set up hi/lo water marks on stream head read queue.
3317c478bd9Sstevel@tonic-gate * unlikely to run out of resources. Fix at later date.
3327c478bd9Sstevel@tonic-gate */
3337c478bd9Sstevel@tonic-gate if ((mop = allocb(sizeof (struct stroptions),
3347c478bd9Sstevel@tonic-gate BPRI_MED)) != NULL) {
3357c478bd9Sstevel@tonic-gate struct stroptions *sop;
3367c478bd9Sstevel@tonic-gate uint_t chunk;
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate chunk = *(uint_t *)mp->b_cont->b_rptr;
3397c478bd9Sstevel@tonic-gate mop->b_datap->db_type = M_SETOPTS;
3407c478bd9Sstevel@tonic-gate mop->b_wptr += sizeof (struct stroptions);
3417c478bd9Sstevel@tonic-gate sop = (struct stroptions *)mop->b_rptr;
3427c478bd9Sstevel@tonic-gate sop->so_flags = SO_HIWAT | SO_LOWAT;
3437c478bd9Sstevel@tonic-gate sop->so_hiwat = SNIT_HIWAT(chunk, 1);
3447c478bd9Sstevel@tonic-gate sop->so_lowat = SNIT_LOWAT(chunk, 1);
3457c478bd9Sstevel@tonic-gate qreply(wq, mop);
3467c478bd9Sstevel@tonic-gate }
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate sbp->sb_chunk = *(uint_t *)mp->b_cont->b_rptr;
3497c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0);
3507c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
3517c478bd9Sstevel@tonic-gate return;
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate case SBIOCSFLAGS:
3547c478bd9Sstevel@tonic-gate sbp->sb_flags = *(uint_t *)mp->b_cont->b_rptr;
3557c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0);
3567c478bd9Sstevel@tonic-gate return;
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate case SBIOCSSNAP:
3597c478bd9Sstevel@tonic-gate /*
3607c478bd9Sstevel@tonic-gate * if chunking dont worry about effects of
3617c478bd9Sstevel@tonic-gate * snipping of message size on head flow control
3627c478bd9Sstevel@tonic-gate * since it has a relatively small bearing on the
3637c478bd9Sstevel@tonic-gate * data rate onto the streamn head.
3647c478bd9Sstevel@tonic-gate */
3657c478bd9Sstevel@tonic-gate if (!sbp->sb_chunk) {
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate * set up hi/lo water marks on stream head read queue.
3687c478bd9Sstevel@tonic-gate * unlikely to run out of resources. Fix at later date.
3697c478bd9Sstevel@tonic-gate */
3707c478bd9Sstevel@tonic-gate if ((mop = allocb(sizeof (struct stroptions),
3717c478bd9Sstevel@tonic-gate BPRI_MED)) != NULL) {
3727c478bd9Sstevel@tonic-gate struct stroptions *sop;
3737c478bd9Sstevel@tonic-gate uint_t snap;
3747c478bd9Sstevel@tonic-gate int fudge;
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate snap = *(uint_t *)mp->b_cont->b_rptr;
3777c478bd9Sstevel@tonic-gate mop->b_datap->db_type = M_SETOPTS;
3787c478bd9Sstevel@tonic-gate mop->b_wptr += sizeof (struct stroptions);
3797c478bd9Sstevel@tonic-gate sop = (struct stroptions *)mop->b_rptr;
3807c478bd9Sstevel@tonic-gate sop->so_flags = SO_HIWAT | SO_LOWAT;
3817c478bd9Sstevel@tonic-gate fudge = snap <= 100 ? 4 :
3827c478bd9Sstevel@tonic-gate snap <= 400 ? 2 :
3837c478bd9Sstevel@tonic-gate 1;
3847c478bd9Sstevel@tonic-gate sop->so_hiwat = SNIT_HIWAT(snap, fudge);
3857c478bd9Sstevel@tonic-gate sop->so_lowat = SNIT_LOWAT(snap, fudge);
3867c478bd9Sstevel@tonic-gate qreply(wq, mop);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate sbp->sb_snap = *(uint_t *)mp->b_cont->b_rptr;
3917c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0);
3927c478bd9Sstevel@tonic-gate return;
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate default:
3957c478bd9Sstevel@tonic-gate ASSERT(0);
3967c478bd9Sstevel@tonic-gate return;
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate * Write-side put procedure. Its main task is to detect ioctls
4027c478bd9Sstevel@tonic-gate * for manipulating the buffering state and hand them to sbioctl.
4037c478bd9Sstevel@tonic-gate * Other message types are passed on through.
4047c478bd9Sstevel@tonic-gate */
405*57198255SToomas Soome static int
sbwput(queue_t * wq,mblk_t * mp)4067c478bd9Sstevel@tonic-gate sbwput(queue_t *wq, mblk_t *mp)
4077c478bd9Sstevel@tonic-gate {
4087c478bd9Sstevel@tonic-gate struct sb *sbp = (struct sb *)wq->q_ptr;
4097c478bd9Sstevel@tonic-gate struct copyresp *resp;
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate if (sbp->sb_flags & SB_SEND_ON_WRITE)
4127c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
4137c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
4147c478bd9Sstevel@tonic-gate case M_IOCTL:
4157c478bd9Sstevel@tonic-gate sbioctl(wq, mp);
4167c478bd9Sstevel@tonic-gate break;
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate case M_IOCDATA:
4197c478bd9Sstevel@tonic-gate resp = (struct copyresp *)mp->b_rptr;
4207c478bd9Sstevel@tonic-gate if (resp->cp_rval) {
4217c478bd9Sstevel@tonic-gate /*
4227c478bd9Sstevel@tonic-gate * Just free message on failure.
4237c478bd9Sstevel@tonic-gate */
4247c478bd9Sstevel@tonic-gate freemsg(mp);
4257c478bd9Sstevel@tonic-gate break;
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate
4287c478bd9Sstevel@tonic-gate switch (resp->cp_cmd) {
4297c478bd9Sstevel@tonic-gate case SBIOCSTIME:
4307c478bd9Sstevel@tonic-gate case SBIOCSCHUNK:
4317c478bd9Sstevel@tonic-gate case SBIOCSFLAGS:
4327c478bd9Sstevel@tonic-gate case SBIOCSSNAP:
4337c478bd9Sstevel@tonic-gate case SBIOCGTIME:
4347c478bd9Sstevel@tonic-gate case SBIOCGCHUNK:
4357c478bd9Sstevel@tonic-gate case SBIOCGSNAP:
4367c478bd9Sstevel@tonic-gate case SBIOCGFLAGS:
4377c478bd9Sstevel@tonic-gate sbioc(wq, mp);
4387c478bd9Sstevel@tonic-gate break;
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate default:
4417c478bd9Sstevel@tonic-gate putnext(wq, mp);
4427c478bd9Sstevel@tonic-gate break;
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate break;
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate default:
4477c478bd9Sstevel@tonic-gate putnext(wq, mp);
4487c478bd9Sstevel@tonic-gate break;
4497c478bd9Sstevel@tonic-gate }
450*57198255SToomas Soome return (0);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate /*
4547c478bd9Sstevel@tonic-gate * Read-side put procedure. It's responsible for buffering up incoming
4557c478bd9Sstevel@tonic-gate * messages and grouping them into aggregates according to the current
4567c478bd9Sstevel@tonic-gate * buffering parameters.
4577c478bd9Sstevel@tonic-gate */
458*57198255SToomas Soome static int
sbrput(queue_t * rq,mblk_t * mp)4597c478bd9Sstevel@tonic-gate sbrput(queue_t *rq, mblk_t *mp)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate struct sb *sbp = (struct sb *)rq->q_ptr;
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate ASSERT(sbp);
4647c478bd9Sstevel@tonic-gate
4657c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
4667c478bd9Sstevel@tonic-gate case M_PROTO:
4677c478bd9Sstevel@tonic-gate if (sbp->sb_flags & SB_NO_PROTO_CVT) {
4687c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
4697c478bd9Sstevel@tonic-gate sbsendit(rq, mp);
4707c478bd9Sstevel@tonic-gate break;
4717c478bd9Sstevel@tonic-gate } else {
4727c478bd9Sstevel@tonic-gate /*
4737c478bd9Sstevel@tonic-gate * Convert M_PROTO to M_DATA.
4747c478bd9Sstevel@tonic-gate */
4757c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_DATA;
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate /* FALLTHRU */
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate case M_DATA:
4807c478bd9Sstevel@tonic-gate if ((sbp->sb_flags & SB_DEFER_CHUNK) &&
4817c478bd9Sstevel@tonic-gate !(sbp->sb_state & SB_FRCVD)) {
4827c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
4837c478bd9Sstevel@tonic-gate sbsendit(rq, mp);
4847c478bd9Sstevel@tonic-gate sbp->sb_state |= SB_FRCVD;
4857c478bd9Sstevel@tonic-gate } else
4867c478bd9Sstevel@tonic-gate sbaddmsg(rq, mp);
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate if ((sbp->sb_ticks > 0) && !(sbp->sb_timeoutid))
4897c478bd9Sstevel@tonic-gate sbp->sb_timeoutid = qtimeout(sbp->sb_rq, sbtick,
4907c478bd9Sstevel@tonic-gate sbp, sbp->sb_ticks);
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate break;
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate case M_FLUSH:
4957c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) {
4967c478bd9Sstevel@tonic-gate /*
4977c478bd9Sstevel@tonic-gate * Reset timeout, flush the chunk currently in
4987c478bd9Sstevel@tonic-gate * progress, and start a new chunk.
4997c478bd9Sstevel@tonic-gate */
5007c478bd9Sstevel@tonic-gate if (sbp->sb_timeoutid) {
5017c478bd9Sstevel@tonic-gate (void) quntimeout(sbp->sb_rq,
5027c478bd9Sstevel@tonic-gate sbp->sb_timeoutid);
5037c478bd9Sstevel@tonic-gate sbp->sb_timeoutid = 0;
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate if (sbp->sb_mp) {
5067c478bd9Sstevel@tonic-gate freemsg(sbp->sb_mp);
5077c478bd9Sstevel@tonic-gate sbp->sb_tail = sbp->sb_mp = sbp->sb_head = NULL;
5087c478bd9Sstevel@tonic-gate sbp->sb_mlen = 0;
5097c478bd9Sstevel@tonic-gate sbp->sb_mcount = 0;
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate flushq(rq, FLUSHALL);
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate putnext(rq, mp);
5147c478bd9Sstevel@tonic-gate break;
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate case M_CTL:
5177c478bd9Sstevel@tonic-gate /*
5187c478bd9Sstevel@tonic-gate * Zero-length M_CTL means our timeout() popped.
5197c478bd9Sstevel@tonic-gate */
5207c478bd9Sstevel@tonic-gate if (MBLKL(mp) == 0) {
5217c478bd9Sstevel@tonic-gate freemsg(mp);
5227c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
5237c478bd9Sstevel@tonic-gate } else {
5247c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
5257c478bd9Sstevel@tonic-gate sbsendit(rq, mp);
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate break;
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate default:
5307c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type <= QPCTL) {
5317c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
5327c478bd9Sstevel@tonic-gate sbsendit(rq, mp);
5337c478bd9Sstevel@tonic-gate } else {
5347c478bd9Sstevel@tonic-gate /* Note: out of band */
5357c478bd9Sstevel@tonic-gate putnext(rq, mp);
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate break;
5387c478bd9Sstevel@tonic-gate }
539*57198255SToomas Soome return (0);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate /*
5437c478bd9Sstevel@tonic-gate * read service procedure.
5447c478bd9Sstevel@tonic-gate */
5457c478bd9Sstevel@tonic-gate /* ARGSUSED */
546*57198255SToomas Soome static int
sbrsrv(queue_t * rq)5477c478bd9Sstevel@tonic-gate sbrsrv(queue_t *rq)
5487c478bd9Sstevel@tonic-gate {
5497c478bd9Sstevel@tonic-gate mblk_t *mp;
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate /*
5527c478bd9Sstevel@tonic-gate * High priority messages shouldn't get here but if
5537c478bd9Sstevel@tonic-gate * one does, jam it through to avoid infinite loop.
5547c478bd9Sstevel@tonic-gate */
5557c478bd9Sstevel@tonic-gate while ((mp = getq(rq)) != NULL) {
5567c478bd9Sstevel@tonic-gate if (!canputnext(rq) && (mp->b_datap->db_type <= QPCTL)) {
5577c478bd9Sstevel@tonic-gate /* should only get here if SB_NO_SROPS */
5587c478bd9Sstevel@tonic-gate (void) putbq(rq, mp);
559*57198255SToomas Soome return (0);
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate putnext(rq, mp);
5627c478bd9Sstevel@tonic-gate }
563*57198255SToomas Soome return (0);
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate /*
5677c478bd9Sstevel@tonic-gate * Handle write-side M_IOCTL messages.
5687c478bd9Sstevel@tonic-gate */
5697c478bd9Sstevel@tonic-gate static void
sbioctl(queue_t * wq,mblk_t * mp)5707c478bd9Sstevel@tonic-gate sbioctl(queue_t *wq, mblk_t *mp)
5717c478bd9Sstevel@tonic-gate {
5727c478bd9Sstevel@tonic-gate struct sb *sbp = (struct sb *)wq->q_ptr;
5737c478bd9Sstevel@tonic-gate struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
5747c478bd9Sstevel@tonic-gate struct timeval *t;
5757c478bd9Sstevel@tonic-gate clock_t ticks;
5767c478bd9Sstevel@tonic-gate mblk_t *mop;
5777c478bd9Sstevel@tonic-gate int transparent = iocp->ioc_count;
5787c478bd9Sstevel@tonic-gate mblk_t *datamp;
5797c478bd9Sstevel@tonic-gate int error;
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
5827c478bd9Sstevel@tonic-gate case SBIOCSTIME:
5837c478bd9Sstevel@tonic-gate if (iocp->ioc_count == TRANSPARENT) {
5847c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
5857c478bd9Sstevel@tonic-gate if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
5867c478bd9Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (struct timeval32),
5877c478bd9Sstevel@tonic-gate NULL);
5887c478bd9Sstevel@tonic-gate } else
5897c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
5907c478bd9Sstevel@tonic-gate {
5917c478bd9Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (*t), NULL);
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate qreply(wq, mp);
5947c478bd9Sstevel@tonic-gate } else {
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate * Verify argument length.
5977c478bd9Sstevel@tonic-gate */
5987c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
5997c478bd9Sstevel@tonic-gate if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
6007c478bd9Sstevel@tonic-gate struct timeval32 *t32;
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate error = miocpullup(mp,
6037c478bd9Sstevel@tonic-gate sizeof (struct timeval32));
6047c478bd9Sstevel@tonic-gate if (error != 0) {
6057c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, error);
6067c478bd9Sstevel@tonic-gate break;
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate t32 = (struct timeval32 *)mp->b_cont->b_rptr;
6097c478bd9Sstevel@tonic-gate if (t32->tv_sec < 0 || t32->tv_usec < 0) {
6107c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL);
6117c478bd9Sstevel@tonic-gate break;
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate ticks = TIMEVAL_TO_TICK(t32);
6147c478bd9Sstevel@tonic-gate } else
6157c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct timeval));
6187c478bd9Sstevel@tonic-gate if (error != 0) {
6197c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, error);
6207c478bd9Sstevel@tonic-gate break;
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate t = (struct timeval *)mp->b_cont->b_rptr;
6247c478bd9Sstevel@tonic-gate if (t->tv_sec < 0 || t->tv_usec < 0) {
6257c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL);
6267c478bd9Sstevel@tonic-gate break;
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate ticks = TIMEVAL_TO_TICK(t);
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate sbp->sb_ticks = ticks;
6317c478bd9Sstevel@tonic-gate if (ticks == 0)
6327c478bd9Sstevel@tonic-gate sbp->sb_chunk = 0;
6337c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0);
6347c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
6357c478bd9Sstevel@tonic-gate }
6367c478bd9Sstevel@tonic-gate break;
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate case SBIOCGTIME: {
6397c478bd9Sstevel@tonic-gate struct timeval *t;
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate /*
6427c478bd9Sstevel@tonic-gate * Verify argument length.
6437c478bd9Sstevel@tonic-gate */
6447c478bd9Sstevel@tonic-gate if (transparent != TRANSPARENT) {
6457c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
6467c478bd9Sstevel@tonic-gate if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
6477c478bd9Sstevel@tonic-gate error = miocpullup(mp,
6487c478bd9Sstevel@tonic-gate sizeof (struct timeval32));
6497c478bd9Sstevel@tonic-gate if (error != 0) {
6507c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, error);
6517c478bd9Sstevel@tonic-gate break;
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate } else
6547c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
6557c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct timeval));
6567c478bd9Sstevel@tonic-gate if (error != 0) {
6577c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, error);
6587c478bd9Sstevel@tonic-gate break;
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate
6627c478bd9Sstevel@tonic-gate /*
6637c478bd9Sstevel@tonic-gate * If infinite timeout, return range error
6647c478bd9Sstevel@tonic-gate * for the ioctl.
6657c478bd9Sstevel@tonic-gate */
6667c478bd9Sstevel@tonic-gate if (sbp->sb_ticks < 0) {
6677c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, ERANGE);
6687c478bd9Sstevel@tonic-gate break;
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
6727c478bd9Sstevel@tonic-gate if ((iocp->ioc_flag & IOC_MODELS) != IOC_NATIVE) {
6737c478bd9Sstevel@tonic-gate struct timeval32 *t32;
6747c478bd9Sstevel@tonic-gate
6757c478bd9Sstevel@tonic-gate if (transparent == TRANSPARENT) {
6767c478bd9Sstevel@tonic-gate datamp = allocb(sizeof (*t32), BPRI_MED);
6777c478bd9Sstevel@tonic-gate if (datamp == NULL) {
6787c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EAGAIN);
6797c478bd9Sstevel@tonic-gate break;
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (*t32), NULL, datamp);
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate t32 = (struct timeval32 *)mp->b_cont->b_rptr;
6857c478bd9Sstevel@tonic-gate TICK_TO_TIMEVAL32(sbp->sb_ticks, t32);
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate if (transparent == TRANSPARENT)
6887c478bd9Sstevel@tonic-gate qreply(wq, mp);
6897c478bd9Sstevel@tonic-gate else
6907c478bd9Sstevel@tonic-gate miocack(wq, mp, sizeof (*t32), 0);
6917c478bd9Sstevel@tonic-gate } else
6927c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
6937c478bd9Sstevel@tonic-gate {
6947c478bd9Sstevel@tonic-gate if (transparent == TRANSPARENT) {
6957c478bd9Sstevel@tonic-gate datamp = allocb(sizeof (*t), BPRI_MED);
6967c478bd9Sstevel@tonic-gate if (datamp == NULL) {
6977c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EAGAIN);
6987c478bd9Sstevel@tonic-gate break;
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (*t), NULL, datamp);
7017c478bd9Sstevel@tonic-gate }
7027c478bd9Sstevel@tonic-gate
7037c478bd9Sstevel@tonic-gate t = (struct timeval *)mp->b_cont->b_rptr;
7047c478bd9Sstevel@tonic-gate TICK_TO_TIMEVAL(sbp->sb_ticks, t);
7057c478bd9Sstevel@tonic-gate
7067c478bd9Sstevel@tonic-gate if (transparent == TRANSPARENT)
7077c478bd9Sstevel@tonic-gate qreply(wq, mp);
7087c478bd9Sstevel@tonic-gate else
7097c478bd9Sstevel@tonic-gate miocack(wq, mp, sizeof (*t), 0);
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate break;
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate case SBIOCCTIME:
7157c478bd9Sstevel@tonic-gate sbp->sb_ticks = -1;
7167c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0);
7177c478bd9Sstevel@tonic-gate break;
7187c478bd9Sstevel@tonic-gate
7197c478bd9Sstevel@tonic-gate case SBIOCSCHUNK:
7207c478bd9Sstevel@tonic-gate if (iocp->ioc_count == TRANSPARENT) {
7217c478bd9Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (uint_t), NULL);
7227c478bd9Sstevel@tonic-gate qreply(wq, mp);
7237c478bd9Sstevel@tonic-gate } else {
7247c478bd9Sstevel@tonic-gate /*
7257c478bd9Sstevel@tonic-gate * Verify argument length.
7267c478bd9Sstevel@tonic-gate */
7277c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (uint_t));
7287c478bd9Sstevel@tonic-gate if (error != 0) {
7297c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, error);
7307c478bd9Sstevel@tonic-gate break;
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate
7337c478bd9Sstevel@tonic-gate /*
7347c478bd9Sstevel@tonic-gate * set up hi/lo water marks on stream head read queue.
7357c478bd9Sstevel@tonic-gate * unlikely to run out of resources. Fix at later date.
7367c478bd9Sstevel@tonic-gate */
7377c478bd9Sstevel@tonic-gate if ((mop = allocb(sizeof (struct stroptions),
7387c478bd9Sstevel@tonic-gate BPRI_MED)) != NULL) {
7397c478bd9Sstevel@tonic-gate struct stroptions *sop;
7407c478bd9Sstevel@tonic-gate uint_t chunk;
7417c478bd9Sstevel@tonic-gate
7427c478bd9Sstevel@tonic-gate chunk = *(uint_t *)mp->b_cont->b_rptr;
7437c478bd9Sstevel@tonic-gate mop->b_datap->db_type = M_SETOPTS;
7447c478bd9Sstevel@tonic-gate mop->b_wptr += sizeof (struct stroptions);
7457c478bd9Sstevel@tonic-gate sop = (struct stroptions *)mop->b_rptr;
7467c478bd9Sstevel@tonic-gate sop->so_flags = SO_HIWAT | SO_LOWAT;
7477c478bd9Sstevel@tonic-gate sop->so_hiwat = SNIT_HIWAT(chunk, 1);
7487c478bd9Sstevel@tonic-gate sop->so_lowat = SNIT_LOWAT(chunk, 1);
7497c478bd9Sstevel@tonic-gate qreply(wq, mop);
7507c478bd9Sstevel@tonic-gate }
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate sbp->sb_chunk = *(uint_t *)mp->b_cont->b_rptr;
7537c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0);
7547c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate break;
7577c478bd9Sstevel@tonic-gate
7587c478bd9Sstevel@tonic-gate case SBIOCGCHUNK:
7597c478bd9Sstevel@tonic-gate /*
7607c478bd9Sstevel@tonic-gate * Verify argument length.
7617c478bd9Sstevel@tonic-gate */
7627c478bd9Sstevel@tonic-gate if (transparent != TRANSPARENT) {
7637c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (uint_t));
7647c478bd9Sstevel@tonic-gate if (error != 0) {
7657c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, error);
7667c478bd9Sstevel@tonic-gate break;
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate }
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate if (transparent == TRANSPARENT) {
7717c478bd9Sstevel@tonic-gate datamp = allocb(sizeof (uint_t), BPRI_MED);
7727c478bd9Sstevel@tonic-gate if (datamp == NULL) {
7737c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EAGAIN);
7747c478bd9Sstevel@tonic-gate break;
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (uint_t), NULL, datamp);
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate
7797c478bd9Sstevel@tonic-gate *(uint_t *)mp->b_cont->b_rptr = sbp->sb_chunk;
7807c478bd9Sstevel@tonic-gate
7817c478bd9Sstevel@tonic-gate if (transparent == TRANSPARENT)
7827c478bd9Sstevel@tonic-gate qreply(wq, mp);
7837c478bd9Sstevel@tonic-gate else
7847c478bd9Sstevel@tonic-gate miocack(wq, mp, sizeof (uint_t), 0);
7857c478bd9Sstevel@tonic-gate break;
7867c478bd9Sstevel@tonic-gate
7877c478bd9Sstevel@tonic-gate case SBIOCSSNAP:
7887c478bd9Sstevel@tonic-gate if (iocp->ioc_count == TRANSPARENT) {
7897c478bd9Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (uint_t), NULL);
7907c478bd9Sstevel@tonic-gate qreply(wq, mp);
7917c478bd9Sstevel@tonic-gate } else {
7927c478bd9Sstevel@tonic-gate /*
7937c478bd9Sstevel@tonic-gate * Verify argument length.
7947c478bd9Sstevel@tonic-gate */
7957c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (uint_t));
7967c478bd9Sstevel@tonic-gate if (error != 0) {
7977c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, error);
7987c478bd9Sstevel@tonic-gate break;
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate
8017c478bd9Sstevel@tonic-gate /*
8027c478bd9Sstevel@tonic-gate * if chunking dont worry about effects of
8037c478bd9Sstevel@tonic-gate * snipping of message size on head flow control
8047c478bd9Sstevel@tonic-gate * since it has a relatively small bearing on the
8057c478bd9Sstevel@tonic-gate * data rate onto the streamn head.
8067c478bd9Sstevel@tonic-gate */
8077c478bd9Sstevel@tonic-gate if (!sbp->sb_chunk) {
8087c478bd9Sstevel@tonic-gate /*
8097c478bd9Sstevel@tonic-gate * set up hi/lo water marks on stream
8107c478bd9Sstevel@tonic-gate * head read queue. unlikely to run out
8117c478bd9Sstevel@tonic-gate * of resources. Fix at later date.
8127c478bd9Sstevel@tonic-gate */
8137c478bd9Sstevel@tonic-gate if ((mop = allocb(sizeof (struct stroptions),
8147c478bd9Sstevel@tonic-gate BPRI_MED)) != NULL) {
8157c478bd9Sstevel@tonic-gate struct stroptions *sop;
8167c478bd9Sstevel@tonic-gate uint_t snap;
8177c478bd9Sstevel@tonic-gate int fudge;
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate snap = *(uint_t *)mp->b_cont->b_rptr;
8207c478bd9Sstevel@tonic-gate mop->b_datap->db_type = M_SETOPTS;
8217c478bd9Sstevel@tonic-gate mop->b_wptr += sizeof (*sop);
8227c478bd9Sstevel@tonic-gate sop = (struct stroptions *)mop->b_rptr;
8237c478bd9Sstevel@tonic-gate sop->so_flags = SO_HIWAT | SO_LOWAT;
8247c478bd9Sstevel@tonic-gate fudge = (snap <= 100) ? 4 :
8257c478bd9Sstevel@tonic-gate (snap <= 400) ? 2 : 1;
8267c478bd9Sstevel@tonic-gate sop->so_hiwat = SNIT_HIWAT(snap, fudge);
8277c478bd9Sstevel@tonic-gate sop->so_lowat = SNIT_LOWAT(snap, fudge);
8287c478bd9Sstevel@tonic-gate qreply(wq, mop);
8297c478bd9Sstevel@tonic-gate }
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate sbp->sb_snap = *(uint_t *)mp->b_cont->b_rptr;
8337c478bd9Sstevel@tonic-gate
8347c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0);
8357c478bd9Sstevel@tonic-gate }
8367c478bd9Sstevel@tonic-gate break;
8377c478bd9Sstevel@tonic-gate
8387c478bd9Sstevel@tonic-gate case SBIOCGSNAP:
8397c478bd9Sstevel@tonic-gate /*
8407c478bd9Sstevel@tonic-gate * Verify argument length
8417c478bd9Sstevel@tonic-gate */
8427c478bd9Sstevel@tonic-gate if (transparent != TRANSPARENT) {
8437c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (uint_t));
8447c478bd9Sstevel@tonic-gate if (error != 0) {
8457c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, error);
8467c478bd9Sstevel@tonic-gate break;
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate if (transparent == TRANSPARENT) {
8517c478bd9Sstevel@tonic-gate datamp = allocb(sizeof (uint_t), BPRI_MED);
8527c478bd9Sstevel@tonic-gate if (datamp == NULL) {
8537c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EAGAIN);
8547c478bd9Sstevel@tonic-gate break;
8557c478bd9Sstevel@tonic-gate }
8567c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (uint_t), NULL, datamp);
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate *(uint_t *)mp->b_cont->b_rptr = sbp->sb_snap;
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate if (transparent == TRANSPARENT)
8627c478bd9Sstevel@tonic-gate qreply(wq, mp);
8637c478bd9Sstevel@tonic-gate else
8647c478bd9Sstevel@tonic-gate miocack(wq, mp, sizeof (uint_t), 0);
8657c478bd9Sstevel@tonic-gate break;
8667c478bd9Sstevel@tonic-gate
8677c478bd9Sstevel@tonic-gate case SBIOCSFLAGS:
8687c478bd9Sstevel@tonic-gate /*
8697c478bd9Sstevel@tonic-gate * set the flags.
8707c478bd9Sstevel@tonic-gate */
8717c478bd9Sstevel@tonic-gate if (iocp->ioc_count == TRANSPARENT) {
8727c478bd9Sstevel@tonic-gate mcopyin(mp, NULL, sizeof (uint_t), NULL);
8737c478bd9Sstevel@tonic-gate qreply(wq, mp);
8747c478bd9Sstevel@tonic-gate } else {
8757c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (uint_t));
8767c478bd9Sstevel@tonic-gate if (error != 0) {
8777c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, error);
8787c478bd9Sstevel@tonic-gate break;
8797c478bd9Sstevel@tonic-gate }
8807c478bd9Sstevel@tonic-gate sbp->sb_flags = *(uint_t *)mp->b_cont->b_rptr;
8817c478bd9Sstevel@tonic-gate miocack(wq, mp, 0, 0);
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate break;
8847c478bd9Sstevel@tonic-gate
8857c478bd9Sstevel@tonic-gate case SBIOCGFLAGS:
8867c478bd9Sstevel@tonic-gate /*
8877c478bd9Sstevel@tonic-gate * Verify argument length
8887c478bd9Sstevel@tonic-gate */
8897c478bd9Sstevel@tonic-gate if (transparent != TRANSPARENT) {
8907c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (uint_t));
8917c478bd9Sstevel@tonic-gate if (error != 0) {
8927c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, error);
8937c478bd9Sstevel@tonic-gate break;
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate }
8967c478bd9Sstevel@tonic-gate
8977c478bd9Sstevel@tonic-gate if (transparent == TRANSPARENT) {
8987c478bd9Sstevel@tonic-gate datamp = allocb(sizeof (uint_t), BPRI_MED);
8997c478bd9Sstevel@tonic-gate if (datamp == NULL) {
9007c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EAGAIN);
9017c478bd9Sstevel@tonic-gate break;
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate mcopyout(mp, NULL, sizeof (uint_t), NULL, datamp);
9047c478bd9Sstevel@tonic-gate }
9057c478bd9Sstevel@tonic-gate
9067c478bd9Sstevel@tonic-gate *(uint_t *)mp->b_cont->b_rptr = sbp->sb_flags;
9077c478bd9Sstevel@tonic-gate
9087c478bd9Sstevel@tonic-gate if (transparent == TRANSPARENT)
9097c478bd9Sstevel@tonic-gate qreply(wq, mp);
9107c478bd9Sstevel@tonic-gate else
9117c478bd9Sstevel@tonic-gate miocack(wq, mp, sizeof (uint_t), 0);
9127c478bd9Sstevel@tonic-gate break;
9137c478bd9Sstevel@tonic-gate
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate default:
9167c478bd9Sstevel@tonic-gate putnext(wq, mp);
9177c478bd9Sstevel@tonic-gate break;
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate }
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate /*
9227c478bd9Sstevel@tonic-gate * Given a length l, calculate the amount of extra storage
9237c478bd9Sstevel@tonic-gate * required to round it up to the next multiple of the alignment a.
9247c478bd9Sstevel@tonic-gate */
9257c478bd9Sstevel@tonic-gate #define RoundUpAmt(l, a) ((l) % (a) ? (a) - ((l) % (a)) : 0)
9267c478bd9Sstevel@tonic-gate /*
9277c478bd9Sstevel@tonic-gate * Calculate additional amount of space required for alignment.
9287c478bd9Sstevel@tonic-gate */
9297c478bd9Sstevel@tonic-gate #define Align(l) RoundUpAmt(l, sizeof (ulong_t))
9307c478bd9Sstevel@tonic-gate /*
9317c478bd9Sstevel@tonic-gate * Smallest possible message size when headers are enabled.
9327c478bd9Sstevel@tonic-gate * This is used to calculate whether a chunk is nearly full.
9337c478bd9Sstevel@tonic-gate */
9347c478bd9Sstevel@tonic-gate #define SMALLEST_MESSAGE sizeof (struct sb_hdr) + _POINTER_ALIGNMENT
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate /*
9377c478bd9Sstevel@tonic-gate * Process a read-side M_DATA message.
9387c478bd9Sstevel@tonic-gate *
9397c478bd9Sstevel@tonic-gate * If the currently accumulating chunk doesn't have enough room
9407c478bd9Sstevel@tonic-gate * for the message, close off the chunk, pass it upward, and start
9417c478bd9Sstevel@tonic-gate * a new one. Then add the message to the current chunk, taking
9427c478bd9Sstevel@tonic-gate * account of the possibility that the message's size exceeds the
9437c478bd9Sstevel@tonic-gate * chunk size.
9447c478bd9Sstevel@tonic-gate *
9457c478bd9Sstevel@tonic-gate * If headers are enabled add an sb_hdr header and trailing alignment padding.
9467c478bd9Sstevel@tonic-gate *
9477c478bd9Sstevel@tonic-gate * To optimise performance the total number of msgbs should be kept
9487c478bd9Sstevel@tonic-gate * to a minimum. This is achieved by using any remaining space in message N
9497c478bd9Sstevel@tonic-gate * for both its own padding as well as the header of message N+1 if possible.
9507c478bd9Sstevel@tonic-gate * If there's insufficient space we allocate one message to hold this 'wrapper'.
9517c478bd9Sstevel@tonic-gate * (there's likely to be space beyond message N, since allocb would have
9527c478bd9Sstevel@tonic-gate * rounded up the required size to one of the dblk_sizes).
9537c478bd9Sstevel@tonic-gate *
9547c478bd9Sstevel@tonic-gate */
9557c478bd9Sstevel@tonic-gate static void
sbaddmsg(queue_t * rq,mblk_t * mp)9567c478bd9Sstevel@tonic-gate sbaddmsg(queue_t *rq, mblk_t *mp)
9577c478bd9Sstevel@tonic-gate {
9587c478bd9Sstevel@tonic-gate struct sb *sbp;
9597c478bd9Sstevel@tonic-gate struct timeval t;
9607c478bd9Sstevel@tonic-gate struct sb_hdr hp;
9617c478bd9Sstevel@tonic-gate mblk_t *wrapper; /* padding for msg N, header for msg N+1 */
9627c478bd9Sstevel@tonic-gate mblk_t *last; /* last mblk of current message */
9637c478bd9Sstevel@tonic-gate size_t wrapperlen; /* length of header + padding */
9647c478bd9Sstevel@tonic-gate size_t origlen; /* data length before truncation */
9657c478bd9Sstevel@tonic-gate size_t pad; /* bytes required to align header */
9667c478bd9Sstevel@tonic-gate
9677c478bd9Sstevel@tonic-gate sbp = (struct sb *)rq->q_ptr;
9687c478bd9Sstevel@tonic-gate
9697c478bd9Sstevel@tonic-gate origlen = msgdsize(mp);
9707c478bd9Sstevel@tonic-gate
9717c478bd9Sstevel@tonic-gate /*
9727c478bd9Sstevel@tonic-gate * Truncate the message.
9737c478bd9Sstevel@tonic-gate */
9747c478bd9Sstevel@tonic-gate if ((sbp->sb_snap > 0) && (origlen > sbp->sb_snap) &&
975*57198255SToomas Soome (adjmsg(mp, -(origlen - sbp->sb_snap)) == 1))
9767c478bd9Sstevel@tonic-gate hp.sbh_totlen = hp.sbh_msglen = sbp->sb_snap;
9777c478bd9Sstevel@tonic-gate else
9787c478bd9Sstevel@tonic-gate hp.sbh_totlen = hp.sbh_msglen = origlen;
9797c478bd9Sstevel@tonic-gate
9807c478bd9Sstevel@tonic-gate if (sbp->sb_flags & SB_NO_HEADER) {
9817c478bd9Sstevel@tonic-gate
9827c478bd9Sstevel@tonic-gate /*
9837c478bd9Sstevel@tonic-gate * Would the inclusion of this message overflow the current
9847c478bd9Sstevel@tonic-gate * chunk? If so close the chunk off and start a new one.
9857c478bd9Sstevel@tonic-gate */
9867c478bd9Sstevel@tonic-gate if ((hp.sbh_totlen + sbp->sb_mlen) > sbp->sb_chunk)
9877c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
9887c478bd9Sstevel@tonic-gate /*
9897c478bd9Sstevel@tonic-gate * First message too big for chunk - just send it up.
9907c478bd9Sstevel@tonic-gate * This will always be true when we're not chunking.
9917c478bd9Sstevel@tonic-gate */
9927c478bd9Sstevel@tonic-gate if (hp.sbh_totlen > sbp->sb_chunk) {
9937c478bd9Sstevel@tonic-gate sbsendit(rq, mp);
9947c478bd9Sstevel@tonic-gate return;
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate
9977c478bd9Sstevel@tonic-gate /*
9987c478bd9Sstevel@tonic-gate * We now know that the msg will fit in the chunk.
9997c478bd9Sstevel@tonic-gate * Link it onto the end of the chunk.
10007c478bd9Sstevel@tonic-gate * Since linkb() walks the entire chain, we keep a pointer to
10017c478bd9Sstevel@tonic-gate * the first mblk of the last msgb added and call linkb on that
10027c478bd9Sstevel@tonic-gate * that last message, rather than performing the
10037c478bd9Sstevel@tonic-gate * O(n) linkb() operation on the whole chain.
10047c478bd9Sstevel@tonic-gate * sb_head isn't needed in this SB_NO_HEADER mode.
10057c478bd9Sstevel@tonic-gate */
10067c478bd9Sstevel@tonic-gate if (sbp->sb_mp)
10077c478bd9Sstevel@tonic-gate linkb(sbp->sb_tail, mp);
10087c478bd9Sstevel@tonic-gate else
10097c478bd9Sstevel@tonic-gate sbp->sb_mp = mp;
10107c478bd9Sstevel@tonic-gate
10117c478bd9Sstevel@tonic-gate sbp->sb_tail = mp;
10127c478bd9Sstevel@tonic-gate sbp->sb_mlen += hp.sbh_totlen;
10137c478bd9Sstevel@tonic-gate sbp->sb_mcount++;
10147c478bd9Sstevel@tonic-gate } else {
10157c478bd9Sstevel@tonic-gate /* Timestamp must be done immediately */
10167c478bd9Sstevel@tonic-gate uniqtime(&t);
10177c478bd9Sstevel@tonic-gate TIMEVAL_TO_TIMEVAL32(&hp.sbh_timestamp, &t);
10187c478bd9Sstevel@tonic-gate
10197c478bd9Sstevel@tonic-gate pad = Align(hp.sbh_totlen);
10207c478bd9Sstevel@tonic-gate hp.sbh_totlen += sizeof (hp);
1021eb00302cSRyan Zezeski
1022eb00302cSRyan Zezeski /* We can't fit this message on the current chunk. */
1023eb00302cSRyan Zezeski if ((sbp->sb_mlen + hp.sbh_totlen) > sbp->sb_chunk)
1024eb00302cSRyan Zezeski sbclosechunk(sbp);
10257c478bd9Sstevel@tonic-gate
10267c478bd9Sstevel@tonic-gate /*
1027eb00302cSRyan Zezeski * If we closed it (just now or during a previous
1028eb00302cSRyan Zezeski * call) then allocate the head of a new chunk.
10297c478bd9Sstevel@tonic-gate */
10307c478bd9Sstevel@tonic-gate if (sbp->sb_head == NULL) {
10317c478bd9Sstevel@tonic-gate /* Allocate leading header of new chunk */
10327c478bd9Sstevel@tonic-gate sbp->sb_head = allocb(sizeof (hp), BPRI_MED);
10337c478bd9Sstevel@tonic-gate if (sbp->sb_head == NULL) {
10347c478bd9Sstevel@tonic-gate /*
10357c478bd9Sstevel@tonic-gate * Memory allocation failure.
10367c478bd9Sstevel@tonic-gate * This will need to be revisited
10377c478bd9Sstevel@tonic-gate * since using certain flag combinations
10387c478bd9Sstevel@tonic-gate * can result in messages being dropped
10397c478bd9Sstevel@tonic-gate * silently.
10407c478bd9Sstevel@tonic-gate */
10417c478bd9Sstevel@tonic-gate freemsg(mp);
10427c478bd9Sstevel@tonic-gate sbp->sb_drops++;
10437c478bd9Sstevel@tonic-gate return;
10447c478bd9Sstevel@tonic-gate }
10457c478bd9Sstevel@tonic-gate sbp->sb_mp = sbp->sb_head;
10467c478bd9Sstevel@tonic-gate }
10477c478bd9Sstevel@tonic-gate
10487c478bd9Sstevel@tonic-gate /*
1049eb00302cSRyan Zezeski * Set the header values and join the message to the
1050eb00302cSRyan Zezeski * chunk. The header values are copied into the chunk
1051eb00302cSRyan Zezeski * after we adjust for padding below.
10527c478bd9Sstevel@tonic-gate */
10537c478bd9Sstevel@tonic-gate hp.sbh_drops = sbp->sb_drops;
10547c478bd9Sstevel@tonic-gate hp.sbh_origlen = origlen;
10557c478bd9Sstevel@tonic-gate linkb(sbp->sb_head, mp);
10567c478bd9Sstevel@tonic-gate sbp->sb_mcount++;
10577c478bd9Sstevel@tonic-gate sbp->sb_mlen += hp.sbh_totlen;
10587c478bd9Sstevel@tonic-gate
10597c478bd9Sstevel@tonic-gate /*
1060eb00302cSRyan Zezeski * There's no chance to fit another message on the
1061eb00302cSRyan Zezeski * chunk -- forgo the padding and close the chunk.
10627c478bd9Sstevel@tonic-gate */
1063eb00302cSRyan Zezeski if ((sbp->sb_mlen + pad + SMALLEST_MESSAGE) > sbp->sb_chunk) {
1064eb00302cSRyan Zezeski (void) memcpy(sbp->sb_head->b_wptr, (char *)&hp,
1065eb00302cSRyan Zezeski sizeof (hp));
1066eb00302cSRyan Zezeski sbp->sb_head->b_wptr += sizeof (hp);
1067eb00302cSRyan Zezeski ASSERT(sbp->sb_head->b_wptr <=
1068eb00302cSRyan Zezeski sbp->sb_head->b_datap->db_lim);
10697c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
10707c478bd9Sstevel@tonic-gate return;
10717c478bd9Sstevel@tonic-gate }
10727c478bd9Sstevel@tonic-gate
1073eb00302cSRyan Zezeski /*
1074eb00302cSRyan Zezeski * We may add another message to this chunk -- adjust
1075eb00302cSRyan Zezeski * the headers for padding to be added below.
1076eb00302cSRyan Zezeski */
1077eb00302cSRyan Zezeski hp.sbh_totlen += pad;
1078eb00302cSRyan Zezeski (void) memcpy(sbp->sb_head->b_wptr, (char *)&hp, sizeof (hp));
1079eb00302cSRyan Zezeski sbp->sb_head->b_wptr += sizeof (hp);
1080eb00302cSRyan Zezeski ASSERT(sbp->sb_head->b_wptr <= sbp->sb_head->b_datap->db_lim);
1081eb00302cSRyan Zezeski sbp->sb_mlen += pad;
1082eb00302cSRyan Zezeski
10837c478bd9Sstevel@tonic-gate /*
10847c478bd9Sstevel@tonic-gate * Find space for the wrapper. The wrapper consists of:
10857c478bd9Sstevel@tonic-gate *
10867c478bd9Sstevel@tonic-gate * 1) Padding for this message (this is to ensure each header
10877c478bd9Sstevel@tonic-gate * begins on an 8 byte boundary in the userland buffer).
10887c478bd9Sstevel@tonic-gate *
10897c478bd9Sstevel@tonic-gate * 2) Space for the next message's header, in case the next
10907c478bd9Sstevel@tonic-gate * next message will fit in this chunk.
10917c478bd9Sstevel@tonic-gate *
10927c478bd9Sstevel@tonic-gate * It may be possible to append the wrapper to the last mblk
10937c478bd9Sstevel@tonic-gate * of the message, but only if we 'own' the data. If the dblk
10947c478bd9Sstevel@tonic-gate * has been shared through dupmsg() we mustn't alter it.
10957c478bd9Sstevel@tonic-gate */
10967c478bd9Sstevel@tonic-gate wrapperlen = (sizeof (hp) + pad);
10977c478bd9Sstevel@tonic-gate
10987c478bd9Sstevel@tonic-gate /* Is there space for the wrapper beyond the message's data ? */
10997c478bd9Sstevel@tonic-gate for (last = mp; last->b_cont; last = last->b_cont)
11007c478bd9Sstevel@tonic-gate ;
11017c478bd9Sstevel@tonic-gate
11027c478bd9Sstevel@tonic-gate if ((wrapperlen <= MBLKTAIL(last)) &&
1103*57198255SToomas Soome (last->b_datap->db_ref == 1)) {
11047c478bd9Sstevel@tonic-gate if (pad > 0) {
11057c478bd9Sstevel@tonic-gate /*
11067c478bd9Sstevel@tonic-gate * Pad with zeroes to the next pointer boundary
11077c478bd9Sstevel@tonic-gate * (we don't want to disclose kernel data to
11087c478bd9Sstevel@tonic-gate * users), then advance wptr.
11097c478bd9Sstevel@tonic-gate */
11107c478bd9Sstevel@tonic-gate (void) memset(last->b_wptr, 0, pad);
11117c478bd9Sstevel@tonic-gate last->b_wptr += pad;
11127c478bd9Sstevel@tonic-gate }
11137c478bd9Sstevel@tonic-gate /* Remember where to write the header information */
11147c478bd9Sstevel@tonic-gate sbp->sb_head = last;
11157c478bd9Sstevel@tonic-gate } else {
11167c478bd9Sstevel@tonic-gate /* Have to allocate additional space for the wrapper */
11177c478bd9Sstevel@tonic-gate wrapper = allocb(wrapperlen, BPRI_MED);
11187c478bd9Sstevel@tonic-gate if (wrapper == NULL) {
11197c478bd9Sstevel@tonic-gate sbclosechunk(sbp);
11207c478bd9Sstevel@tonic-gate return;
11217c478bd9Sstevel@tonic-gate }
11227c478bd9Sstevel@tonic-gate if (pad > 0) {
11237c478bd9Sstevel@tonic-gate /*
11247c478bd9Sstevel@tonic-gate * Pad with zeroes (we don't want to disclose
11257c478bd9Sstevel@tonic-gate * kernel data to users).
11267c478bd9Sstevel@tonic-gate */
11277c478bd9Sstevel@tonic-gate (void) memset(wrapper->b_wptr, 0, pad);
11287c478bd9Sstevel@tonic-gate wrapper->b_wptr += pad;
11297c478bd9Sstevel@tonic-gate }
11307c478bd9Sstevel@tonic-gate /* Link the wrapper msg onto the end of the chunk */
11317c478bd9Sstevel@tonic-gate linkb(mp, wrapper);
11327c478bd9Sstevel@tonic-gate /* Remember to write the next header in this wrapper */
11337c478bd9Sstevel@tonic-gate sbp->sb_head = wrapper;
11347c478bd9Sstevel@tonic-gate }
11357c478bd9Sstevel@tonic-gate }
11367c478bd9Sstevel@tonic-gate }
11377c478bd9Sstevel@tonic-gate
11387c478bd9Sstevel@tonic-gate /*
11397c478bd9Sstevel@tonic-gate * Called from timeout().
11407c478bd9Sstevel@tonic-gate * Signal a timeout by passing a zero-length M_CTL msg in the read-side
11417c478bd9Sstevel@tonic-gate * to synchronize with any active module threads (open, close, wput, rput).
11427c478bd9Sstevel@tonic-gate */
11437c478bd9Sstevel@tonic-gate static void
sbtick(void * arg)11447c478bd9Sstevel@tonic-gate sbtick(void *arg)
11457c478bd9Sstevel@tonic-gate {
11467c478bd9Sstevel@tonic-gate struct sb *sbp = arg;
11477c478bd9Sstevel@tonic-gate queue_t *rq;
11487c478bd9Sstevel@tonic-gate
11497c478bd9Sstevel@tonic-gate ASSERT(sbp);
11507c478bd9Sstevel@tonic-gate
11517c478bd9Sstevel@tonic-gate rq = sbp->sb_rq;
11527c478bd9Sstevel@tonic-gate sbp->sb_timeoutid = 0; /* timeout has fired */
11537c478bd9Sstevel@tonic-gate
11547c478bd9Sstevel@tonic-gate if (putctl(rq, M_CTL) == 0) /* failure */
11557c478bd9Sstevel@tonic-gate sbp->sb_timeoutid = qtimeout(rq, sbtick, sbp, sbp->sb_ticks);
11567c478bd9Sstevel@tonic-gate }
11577c478bd9Sstevel@tonic-gate
11587c478bd9Sstevel@tonic-gate /*
11597c478bd9Sstevel@tonic-gate * Close off the currently accumulating chunk and pass
11607c478bd9Sstevel@tonic-gate * it upward. Takes care of resetting timers as well.
11617c478bd9Sstevel@tonic-gate *
11627c478bd9Sstevel@tonic-gate * This routine is called both directly and as a result
11637c478bd9Sstevel@tonic-gate * of the chunk timeout expiring.
11647c478bd9Sstevel@tonic-gate */
11657c478bd9Sstevel@tonic-gate static void
sbclosechunk(struct sb * sbp)11667c478bd9Sstevel@tonic-gate sbclosechunk(struct sb *sbp)
11677c478bd9Sstevel@tonic-gate {
11687c478bd9Sstevel@tonic-gate mblk_t *mp;
11697c478bd9Sstevel@tonic-gate queue_t *rq;
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate ASSERT(sbp);
11727c478bd9Sstevel@tonic-gate
11737c478bd9Sstevel@tonic-gate if (sbp->sb_timeoutid) {
11747c478bd9Sstevel@tonic-gate (void) quntimeout(sbp->sb_rq, sbp->sb_timeoutid);
11757c478bd9Sstevel@tonic-gate sbp->sb_timeoutid = 0;
11767c478bd9Sstevel@tonic-gate }
11777c478bd9Sstevel@tonic-gate
11787c478bd9Sstevel@tonic-gate mp = sbp->sb_mp;
11797c478bd9Sstevel@tonic-gate rq = sbp->sb_rq;
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gate /*
11827c478bd9Sstevel@tonic-gate * If there's currently a chunk in progress, close it off
11837c478bd9Sstevel@tonic-gate * and try to send it up.
11847c478bd9Sstevel@tonic-gate */
11857c478bd9Sstevel@tonic-gate if (mp) {
11867c478bd9Sstevel@tonic-gate sbsendit(rq, mp);
11877c478bd9Sstevel@tonic-gate }
11887c478bd9Sstevel@tonic-gate
11897c478bd9Sstevel@tonic-gate /*
11907c478bd9Sstevel@tonic-gate * Clear old chunk. Ready for new msgs.
11917c478bd9Sstevel@tonic-gate */
11927c478bd9Sstevel@tonic-gate sbp->sb_tail = sbp->sb_mp = sbp->sb_head = NULL;
11937c478bd9Sstevel@tonic-gate sbp->sb_mlen = 0;
11947c478bd9Sstevel@tonic-gate sbp->sb_mcount = 0;
11957c478bd9Sstevel@tonic-gate if (sbp->sb_flags & SB_DEFER_CHUNK)
11967c478bd9Sstevel@tonic-gate sbp->sb_state &= ~SB_FRCVD;
11977c478bd9Sstevel@tonic-gate
11987c478bd9Sstevel@tonic-gate }
11997c478bd9Sstevel@tonic-gate
12007c478bd9Sstevel@tonic-gate static void
sbsendit(queue_t * rq,mblk_t * mp)12017c478bd9Sstevel@tonic-gate sbsendit(queue_t *rq, mblk_t *mp)
12027c478bd9Sstevel@tonic-gate {
12037c478bd9Sstevel@tonic-gate struct sb *sbp = (struct sb *)rq->q_ptr;
12047c478bd9Sstevel@tonic-gate
12057c478bd9Sstevel@tonic-gate if (!canputnext(rq)) {
12067c478bd9Sstevel@tonic-gate if (sbp->sb_flags & SB_NO_DROPS)
12077c478bd9Sstevel@tonic-gate (void) putq(rq, mp);
12087c478bd9Sstevel@tonic-gate else {
12097c478bd9Sstevel@tonic-gate freemsg(mp);
12107c478bd9Sstevel@tonic-gate sbp->sb_drops += sbp->sb_mcount;
12117c478bd9Sstevel@tonic-gate }
12127c478bd9Sstevel@tonic-gate return;
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate /*
12157c478bd9Sstevel@tonic-gate * If there are messages on the q already, keep
12167c478bd9Sstevel@tonic-gate * queueing them since they need to be processed in order.
12177c478bd9Sstevel@tonic-gate */
12187c478bd9Sstevel@tonic-gate if (qsize(rq) > 0) {
12197c478bd9Sstevel@tonic-gate /* should only get here if SB_NO_DROPS */
12207c478bd9Sstevel@tonic-gate (void) putq(rq, mp);
12217c478bd9Sstevel@tonic-gate }
12227c478bd9Sstevel@tonic-gate else
12237c478bd9Sstevel@tonic-gate putnext(rq, mp);
12247c478bd9Sstevel@tonic-gate }
1225