Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / timod.c
blob643e3b783d5f3209d239b8d1f71125ca2d1202e6
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
30 * Transport Interface Library cooperating module - issue 2
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/stream.h>
36 #include <sys/stropts.h>
37 #include <sys/strsubr.h>
38 #define _SUN_TPI_VERSION 2
39 #include <sys/tihdr.h>
40 #include <sys/timod.h>
41 #include <sys/suntpi.h>
42 #include <sys/debug.h>
43 #include <sys/strlog.h>
44 #include <sys/errno.h>
45 #include <sys/cred.h>
46 #include <sys/cmn_err.h>
47 #include <sys/kmem.h>
48 #include <sys/sysmacros.h>
49 #include <sys/ddi.h>
50 #include <sys/sunddi.h>
51 #include <sys/strsun.h>
54 * This is the loadable module wrapper.
56 #include <sys/conf.h>
57 #include <sys/modctl.h>
59 static struct streamtab timinfo;
61 static struct fmodsw fsw = {
62 "timod",
63 &timinfo,
64 D_MTQPAIR | D_MP,
68 * Module linkage information for the kernel.
71 static struct modlstrmod modlstrmod = {
72 &mod_strmodops, "transport interface str mod", &fsw
75 static struct modlinkage modlinkage = {
76 MODREV_1, &modlstrmod, NULL
79 static krwlock_t tim_list_rwlock;
82 * This module keeps track of capabilities of underlying transport. Information
83 * is persistent through module invocations (open/close). Currently it remembers
84 * whether underlying transport supports TI_GET{MY,PEER}NAME ioctls and
85 * T_CAPABILITY_REQ message. This module either passes ioctl/messages to the
86 * transport or emulates it when transport doesn't understand these
87 * ioctl/messages.
89 * It is assumed that transport supports T_CAPABILITY_REQ when timod receives
90 * T_CAPABILITY_ACK from the transport. There is no current standard describing
91 * transport behaviour when it receives unknown message type, so following
92 * reactions are expected and handled:
94 * 1) Transport drops unknown T_CAPABILITY_REQ message type. In this case timod
95 * will wait for tcap_wait time and assume that transport doesn't provide
96 * this message type. T_CAPABILITY_REQ should never travel over the wire, so
97 * timeout value should only take into consideration internal processing time
98 * for the message. From user standpoint it may mean that an application will
99 * hang for TCAP_WAIT time in the kernel the first time this message is used
100 * with some particular transport (e.g. TCP/IP) during system uptime.
102 * 2) Transport responds with T_ERROR_ACK specifying T_CAPABILITY_REQ as
103 * original message type. In this case it is assumed that transport doesn't
104 * support it (which may not always be true - some transports return
105 * T_ERROR_ACK in other cases like lack of system memory).
107 * 3) Transport responds with M_ERROR, effectively shutting down the
108 * stream. Unfortunately there is no standard way to pass the reason of
109 * M_ERROR message back to the caller, so it is assumed that if M_ERROR was
110 * sent in response to T_CAPABILITY_REQ message, transport doesn't support
111 * it.
113 * It is possible under certain circumstances that timod will incorrectly assume
114 * that underlying transport doesn't provide T_CAPABILITY_REQ message type. In
115 * this "worst-case" scenario timod will emulate its functionality by itself and
116 * will provide only TC1_INFO capability. All other bits in CAP_bits1 field are
117 * cleaned. TC1_INFO is emulated by sending T_INFO_REQ down to transport
118 * provider.
122 * Notes about locking:
124 * tim_list_rwlock protects the list of tim_tim structures itself. When this
125 * lock is held, the list itself is stable, but the contents of the entries
126 * themselves might not be.
128 * The rest of the members are generally protected by D_MTQPAIR, which
129 * specifies a default exclusive inner perimeter. If you're looking at
130 * q->q_ptr, then it's stable.
132 * There's one exception to this rule: tim_peer{maxlen,len,name}. These members
133 * are touched without entering the associated STREAMS perimeter because we
134 * get the pointer via tim_findlink() rather than q_ptr. These are protected
135 * by tim_mutex instead. If you don't hold that lock, don't look at them.
137 * (It would be possible to separate out the 'set by T_CONN_RES' cases from the
138 * others, but there appears to be no reason to do so.)
140 struct tim_tim {
141 uint32_t tim_flags;
142 t_uscalar_t tim_backlog;
143 mblk_t *tim_iocsave;
144 t_scalar_t tim_mymaxlen;
145 t_scalar_t tim_mylen;
146 caddr_t tim_myname;
147 t_scalar_t tim_peermaxlen;
148 t_scalar_t tim_peerlen;
149 caddr_t tim_peername;
150 cred_t *tim_peercred;
151 mblk_t *tim_consave;
152 bufcall_id_t tim_wbufcid;
153 bufcall_id_t tim_rbufcid;
154 timeout_id_t tim_wtimoutid;
155 timeout_id_t tim_rtimoutid;
156 /* Protected by the global tim_list_rwlock for all instances */
157 struct tim_tim *tim_next;
158 struct tim_tim **tim_ptpn;
159 t_uscalar_t tim_acceptor;
160 t_scalar_t tim_saved_prim; /* Primitive from message */
161 /* part of ioctl. */
162 timeout_id_t tim_tcap_timoutid; /* For T_CAP_REQ timeout */
163 tpi_provinfo_t *tim_provinfo; /* Transport description */
164 kmutex_t tim_mutex; /* protect tim_peer* */
165 pid_t tim_cpid;
170 * Local flags used with tim_flags field in instance structure of
171 * type 'struct _ti_user' declared above.
172 * Historical note:
173 * This namespace constants were previously declared in a
174 * a very messed up namespace in timod.h
176 * There may be 3 states for transport:
178 * 1) It provides T_CAPABILITY_REQ
179 * 2) It does not provide T_CAPABILITY_REQ
180 * 3) It is not known yet whether transport provides T_CAPABILITY_REQ or not.
182 * It is assumed that the underlying transport either provides
183 * T_CAPABILITY_REQ or not and this does not changes during the
184 * system lifetime.
187 #define PEEK_RDQ_EXPIND 0x0001 /* look for expinds on stream rd queues */
188 #define WAITIOCACK 0x0002 /* waiting for info for ioctl act */
189 #define CLTS 0x0004 /* connectionless transport */
190 #define COTS 0x0008 /* connection-oriented transport */
191 #define CONNWAIT 0x0010 /* waiting for connect confirmation */
192 #define LOCORDREL 0x0020 /* local end has orderly released */
193 #define REMORDREL 0x0040 /* remote end had orderly released */
194 #define NAMEPROC 0x0080 /* processing a NAME ioctl */
195 #define DO_MYNAME 0x0100 /* timod handles TI_GETMYNAME */
196 #define DO_PEERNAME 0x0200 /* timod handles TI_GETPEERNAME */
197 #define TI_CAP_RECVD 0x0400 /* TI_CAPABILITY received */
198 #define CAP_WANTS_INFO 0x0800 /* TI_CAPABILITY has TC1_INFO set */
199 #define WAIT_IOCINFOACK 0x1000 /* T_INFO_REQ generated from ioctl */
200 #define WAIT_CONNRESACK 0x2000 /* waiting for T_OK_ACK to T_CONN_RES */
203 /* Debugging facilities */
205 * Logging needed for debugging timod should only appear in DEBUG kernel.
207 #ifdef DEBUG
208 #define TILOG(msg, arg) tilog((msg), (arg))
209 #define TILOGP(msg, arg) tilogp((msg), (arg))
210 #else
211 #define TILOG(msg, arg)
212 #define TILOGP(msg, arg)
213 #endif
217 * Sleep timeout for T_CAPABILITY_REQ. This message never travels across
218 * network, so timeout value should be enough to cover all internal processing
219 * time.
221 clock_t tim_tcap_wait = 2;
223 /* Sleep timeout in tim_recover() */
224 #define TIMWAIT (1*hz)
225 /* Sleep timeout in tim_ioctl_retry() 0.2 seconds */
226 #define TIMIOCWAIT (200*hz/1000)
229 * Return values for ti_doname().
231 #define DONAME_FAIL 0 /* failing ioctl (done) */
232 #define DONAME_DONE 1 /* done processing */
233 #define DONAME_CONT 2 /* continue proceesing (not done yet) */
236 * Function prototypes
238 static int ti_doname(queue_t *, mblk_t *);
239 static int ti_expind_on_rdqueues(queue_t *);
240 static void tim_ioctl_send_reply(queue_t *, mblk_t *, mblk_t *);
241 static void tim_send_ioc_error_ack(queue_t *, struct tim_tim *, mblk_t *);
242 static void tim_tcap_timer(void *);
243 static void tim_tcap_genreply(queue_t *, struct tim_tim *);
244 static void tim_send_reply(queue_t *, mblk_t *, struct tim_tim *, t_scalar_t);
245 static void tim_answer_ti_sync(queue_t *, mblk_t *, struct tim_tim *,
246 mblk_t *, uint32_t);
247 static void tim_send_ioctl_tpi_msg(queue_t *, mblk_t *, struct tim_tim *,
248 struct iocblk *);
249 static void tim_clear_peer(struct tim_tim *);
252 _init(void)
254 int error;
256 rw_init(&tim_list_rwlock, NULL, RW_DRIVER, NULL);
257 error = mod_install(&modlinkage);
258 if (error != 0) {
259 rw_destroy(&tim_list_rwlock);
260 return (error);
263 return (0);
267 _fini(void)
269 int error;
271 error = mod_remove(&modlinkage);
272 if (error != 0)
273 return (error);
274 rw_destroy(&tim_list_rwlock);
275 return (0);
279 _info(struct modinfo *modinfop)
281 return (mod_info(&modlinkage, modinfop));
286 * Hash list for all instances. Used to find tim_tim structure based on
287 * ACCEPTOR_id in T_CONN_RES. Protected by tim_list_rwlock.
289 #define TIM_HASH_SIZE 256
290 #ifdef _ILP32
291 #define TIM_HASH(id) (((uintptr_t)(id) >> 8) % TIM_HASH_SIZE)
292 #else
293 #define TIM_HASH(id) ((uintptr_t)(id) % TIM_HASH_SIZE)
294 #endif /* _ILP32 */
295 static struct tim_tim *tim_hash[TIM_HASH_SIZE];
296 int tim_cnt = 0;
298 static void tilog(char *, t_scalar_t);
299 static void tilogp(char *, uintptr_t);
300 static mblk_t *tim_filladdr(queue_t *, mblk_t *, boolean_t);
301 static void tim_addlink(struct tim_tim *);
302 static void tim_dellink(struct tim_tim *);
303 static struct tim_tim *tim_findlink(t_uscalar_t);
304 static void tim_recover(queue_t *, mblk_t *, t_scalar_t);
305 static void tim_ioctl_retry(queue_t *);
307 int dotilog = 0;
309 #define TIMOD_ID 3
311 static int timodopen(queue_t *, dev_t *, int, int, cred_t *);
312 static int timodclose(queue_t *, int, cred_t *);
313 static void timodwput(queue_t *, mblk_t *);
314 static void timodrput(queue_t *, mblk_t *);
315 static void timodrsrv(queue_t *);
316 static void timodwsrv(queue_t *);
317 static int timodrproc(queue_t *, mblk_t *);
318 static int timodwproc(queue_t *, mblk_t *);
320 /* stream data structure definitions */
322 static struct module_info timod_info =
323 {TIMOD_ID, "timod", 0, INFPSZ, 512, 128};
324 static struct qinit timodrinit = {
325 (int (*)())timodrput,
326 (int (*)())timodrsrv,
327 timodopen,
328 timodclose,
329 nulldev,
330 &timod_info,
331 NULL
333 static struct qinit timodwinit = {
334 (int (*)())timodwput,
335 (int (*)())timodwsrv,
336 timodopen,
337 timodclose,
338 nulldev,
339 &timod_info,
340 NULL
342 static struct streamtab timinfo = { &timodrinit, &timodwinit, NULL, NULL };
345 * timodopen - open routine gets called when the module gets pushed
346 * onto the stream.
348 /*ARGSUSED*/
349 static int
350 timodopen(
351 queue_t *q,
352 dev_t *devp,
353 int flag,
354 int sflag,
355 cred_t *crp)
357 struct tim_tim *tp;
358 struct stroptions *sop;
359 mblk_t *bp;
361 ASSERT(q != NULL);
363 if (q->q_ptr) {
364 return (0);
367 if ((bp = allocb(sizeof (struct stroptions), BPRI_MED)) == 0)
368 return (ENOMEM);
370 tp = kmem_zalloc(sizeof (struct tim_tim), KM_SLEEP);
372 tp->tim_cpid = -1;
373 tp->tim_saved_prim = -1;
375 mutex_init(&tp->tim_mutex, NULL, MUTEX_DEFAULT, NULL);
377 q->q_ptr = (caddr_t)tp;
378 WR(q)->q_ptr = (caddr_t)tp;
380 tilogp("timodopen: Allocated for tp %lx\n", (uintptr_t)tp);
381 tilogp("timodopen: Allocated for q %lx\n", (uintptr_t)q);
383 /* Must be done before tpi_findprov and _ILP32 q_next walk below */
384 qprocson(q);
386 tp->tim_provinfo = tpi_findprov(q);
389 * Defer allocation of the buffers for the local address and
390 * the peer's address until we need them.
391 * Assume that timod has to handle getname until we here
392 * an iocack from the transport provider or we know that
393 * transport provider doesn't understand it.
395 if (tp->tim_provinfo->tpi_myname != PI_YES) {
396 TILOG("timodopen: setting DO_MYNAME\n", 0);
397 tp->tim_flags |= DO_MYNAME;
400 if (tp->tim_provinfo->tpi_peername != PI_YES) {
401 TILOG("timodopen: setting DO_PEERNAME\n", 0);
402 tp->tim_flags |= DO_PEERNAME;
405 #ifdef _ILP32
407 queue_t *driverq;
410 * Find my driver's read queue (for T_CONN_RES handling)
412 driverq = WR(q);
413 while (SAMESTR(driverq))
414 driverq = driverq->q_next;
416 tp->tim_acceptor = (t_uscalar_t)RD(driverq);
418 #else
419 tp->tim_acceptor = (t_uscalar_t)getminor(*devp);
420 #endif /* _ILP32 */
423 * Add this one to the list.
425 tim_addlink(tp);
428 * Send M_SETOPTS to stream head to make sure M_PCPROTO messages
429 * are not flushed. This prevents application deadlocks.
431 bp->b_datap->db_type = M_SETOPTS;
432 bp->b_wptr += sizeof (struct stroptions);
433 sop = (struct stroptions *)bp->b_rptr;
434 sop->so_flags = SO_READOPT;
435 sop->so_readopt = RFLUSHPCPROT;
437 putnext(q, bp);
439 return (0);
442 static void
443 tim_timer(void *arg)
445 queue_t *q = arg;
446 struct tim_tim *tp = (struct tim_tim *)q->q_ptr;
448 ASSERT(tp);
450 if (q->q_flag & QREADR) {
451 ASSERT(tp->tim_rtimoutid);
452 tp->tim_rtimoutid = 0;
453 } else {
454 ASSERT(tp->tim_wtimoutid);
455 tp->tim_wtimoutid = 0;
457 enableok(q);
458 qenable(q);
461 static void
462 tim_buffer(void *arg)
464 queue_t *q = arg;
465 struct tim_tim *tp = (struct tim_tim *)q->q_ptr;
467 ASSERT(tp);
469 if (q->q_flag & QREADR) {
470 ASSERT(tp->tim_rbufcid);
471 tp->tim_rbufcid = 0;
472 } else {
473 ASSERT(tp->tim_wbufcid);
474 tp->tim_wbufcid = 0;
476 enableok(q);
477 qenable(q);
481 * timodclose - This routine gets called when the module gets popped
482 * off of the stream.
484 /*ARGSUSED*/
485 static int
486 timodclose(
487 queue_t *q,
488 int flag,
489 cred_t *crp)
491 struct tim_tim *tp;
492 mblk_t *mp;
493 mblk_t *nmp;
495 ASSERT(q != NULL);
497 tp = (struct tim_tim *)q->q_ptr;
498 q->q_ptr = NULL;
500 ASSERT(tp != NULL);
502 tilogp("timodclose: Entered for tp %lx\n", (uintptr_t)tp);
503 tilogp("timodclose: Entered for q %lx\n", (uintptr_t)q);
505 qprocsoff(q);
506 tim_dellink(tp);
509 * Cancel any outstanding bufcall
510 * or timeout requests.
512 if (tp->tim_wbufcid) {
513 qunbufcall(q, tp->tim_wbufcid);
514 tp->tim_wbufcid = 0;
516 if (tp->tim_rbufcid) {
517 qunbufcall(q, tp->tim_rbufcid);
518 tp->tim_rbufcid = 0;
520 if (tp->tim_wtimoutid) {
521 (void) quntimeout(q, tp->tim_wtimoutid);
522 tp->tim_wtimoutid = 0;
524 if (tp->tim_rtimoutid) {
525 (void) quntimeout(q, tp->tim_rtimoutid);
526 tp->tim_rtimoutid = 0;
529 if (tp->tim_tcap_timoutid != 0) {
530 (void) quntimeout(q, tp->tim_tcap_timoutid);
531 tp->tim_tcap_timoutid = 0;
534 if (tp->tim_iocsave != NULL)
535 freemsg(tp->tim_iocsave);
536 mp = tp->tim_consave;
537 while (mp) {
538 nmp = mp->b_next;
539 mp->b_next = NULL;
540 freemsg(mp);
541 mp = nmp;
543 ASSERT(tp->tim_mymaxlen >= 0);
544 if (tp->tim_mymaxlen != 0)
545 kmem_free(tp->tim_myname, (size_t)tp->tim_mymaxlen);
546 ASSERT(tp->tim_peermaxlen >= 0);
547 if (tp->tim_peermaxlen != 0)
548 kmem_free(tp->tim_peername, (size_t)tp->tim_peermaxlen);
550 q->q_ptr = WR(q)->q_ptr = NULL;
552 mutex_destroy(&tp->tim_mutex);
554 if (tp->tim_peercred != NULL)
555 crfree(tp->tim_peercred);
557 kmem_free(tp, sizeof (struct tim_tim));
559 return (0);
563 * timodrput - Module read put procedure. This is called from
564 * the module, driver, or stream head upstream/downstream.
565 * Handles M_FLUSH, M_DATA and some M_PROTO (T_DATA_IND,
566 * and T_UNITDATA_IND) messages. All others are queued to
567 * be handled by the service procedures.
569 static void
570 timodrput(queue_t *q, mblk_t *mp)
572 union T_primitives *pptr;
575 * During flow control and other instances when messages
576 * are on queue, queue up a non high priority message
578 if (q->q_first != 0 && mp->b_datap->db_type < QPCTL) {
579 (void) putq(q, mp);
580 return;
584 * Inline processing of data (to avoid additional procedure call).
585 * Rest is handled in timodrproc.
588 switch (mp->b_datap->db_type) {
589 case M_DATA:
590 if (bcanputnext(q, mp->b_band))
591 putnext(q, mp);
592 else
593 (void) putq(q, mp);
594 break;
595 case M_PROTO:
596 case M_PCPROTO:
597 if (MBLKL(mp) < sizeof (t_scalar_t)) {
598 if (mp->b_datap->db_type == M_PCPROTO ||
599 bcanputnext(q, mp->b_band)) {
600 putnext(q, mp);
601 } else {
602 (void) putq(q, mp);
604 break;
606 pptr = (union T_primitives *)mp->b_rptr;
607 switch (pptr->type) {
608 case T_EXDATA_IND:
609 case T_DATA_IND:
610 case T_UNITDATA_IND:
611 if (bcanputnext(q, mp->b_band))
612 putnext(q, mp);
613 else
614 (void) putq(q, mp);
615 break;
616 default:
617 (void) timodrproc(q, mp);
618 break;
620 break;
621 default:
622 (void) timodrproc(q, mp);
623 break;
628 * timodrsrv - Module read queue service procedure. This is called when
629 * messages are placed on an empty queue, when high priority
630 * messages are placed on the queue, and when flow control
631 * restrictions subside. This code used to be included in a
632 * put procedure, but it was moved to a service procedure
633 * because several points were added where memory allocation
634 * could fail, and there is no reasonable recovery mechanism
635 * from the put procedure.
637 /*ARGSUSED*/
638 static void
639 timodrsrv(queue_t *q)
641 mblk_t *mp;
642 struct tim_tim *tp;
644 ASSERT(q != NULL);
646 tp = (struct tim_tim *)q->q_ptr;
647 if (!tp)
648 return;
650 while ((mp = getq(q)) != NULL) {
651 if (timodrproc(q, mp)) {
653 * timodrproc did a putbq - stop processing
654 * messages.
656 return;
662 * Perform common processing when a T_CAPABILITY_ACK or T_INFO_ACK
663 * arrive. Set the queue properties and adjust the tim_flags according
664 * to the service type.
666 static void
667 timodprocessinfo(queue_t *q, struct tim_tim *tp, struct T_info_ack *tia)
669 TILOG("timodprocessinfo: strqset(%d)\n", tia->TIDU_size);
670 (void) strqset(q, QMAXPSZ, 0, tia->TIDU_size);
671 (void) strqset(OTHERQ(q), QMAXPSZ, 0, tia->TIDU_size);
673 if ((tia->SERV_type == T_COTS) || (tia->SERV_type == T_COTS_ORD))
674 tp->tim_flags = (tp->tim_flags & ~CLTS) | COTS;
675 else if (tia->SERV_type == T_CLTS)
676 tp->tim_flags = (tp->tim_flags & ~COTS) | CLTS;
679 static int
680 timodrproc(queue_t *q, mblk_t *mp)
682 union T_primitives *pptr;
683 struct tim_tim *tp;
684 struct iocblk *iocbp;
685 mblk_t *nbp;
686 size_t blen;
688 tp = (struct tim_tim *)q->q_ptr;
690 switch (mp->b_datap->db_type) {
691 default:
692 putnext(q, mp);
693 break;
695 case M_ERROR:
696 TILOG("timodrproc: Got M_ERROR, flags = %x\n", tp->tim_flags);
698 * There is no specified standard response for driver when it
699 * receives unknown message type and M_ERROR is one
700 * possibility. If we send T_CAPABILITY_REQ down and transport
701 * provider responds with M_ERROR we assume that it doesn't
702 * understand this message type. This assumption may be
703 * sometimes incorrect (transport may reply with M_ERROR for
704 * some other reason) but there is no way for us to distinguish
705 * between different cases. In the worst case timod and everyone
706 * else sharing global transport description with it may end up
707 * emulating T_CAPABILITY_REQ.
711 * Check that we are waiting for T_CAPABILITY_ACK and
712 * T_CAPABILITY_REQ is not implemented by transport or emulated
713 * by timod.
715 if ((tp->tim_provinfo->tpi_capability == PI_DONTKNOW) &&
716 ((tp->tim_flags & TI_CAP_RECVD) != 0)) {
718 * Good chances that this transport doesn't provide
719 * T_CAPABILITY_REQ. Mark this information permanently
720 * for the module + transport combination.
722 PI_PROVLOCK(tp->tim_provinfo);
723 if (tp->tim_provinfo->tpi_capability == PI_DONTKNOW)
724 tp->tim_provinfo->tpi_capability = PI_NO;
725 PI_PROVUNLOCK(tp->tim_provinfo);
726 if (tp->tim_tcap_timoutid != 0) {
727 (void) quntimeout(q, tp->tim_tcap_timoutid);
728 tp->tim_tcap_timoutid = 0;
731 putnext(q, mp);
732 break;
733 case M_DATA:
734 if (!bcanputnext(q, mp->b_band)) {
735 (void) putbq(q, mp);
736 return (1);
738 putnext(q, mp);
739 break;
741 case M_PROTO:
742 case M_PCPROTO:
743 blen = MBLKL(mp);
744 if (blen < sizeof (t_scalar_t)) {
746 * Note: it's not actually possible to get
747 * here with db_type M_PCPROTO, because
748 * timodrput has already checked MBLKL, and
749 * thus the assertion below. If the length
750 * was too short, then the message would have
751 * already been putnext'd, and would thus
752 * never appear here. Just the same, the code
753 * below handles the impossible case since
754 * it's easy to do and saves future
755 * maintainers from unfortunate accidents.
757 ASSERT(mp->b_datap->db_type == M_PROTO);
758 if (mp->b_datap->db_type == M_PROTO &&
759 !bcanputnext(q, mp->b_band)) {
760 (void) putbq(q, mp);
761 return (1);
763 putnext(q, mp);
764 break;
767 pptr = (union T_primitives *)mp->b_rptr;
768 switch (pptr->type) {
769 default:
771 putnext(q, mp);
772 break;
774 case T_ERROR_ACK:
775 /* Restore db_type - recover() might have changed it */
776 mp->b_datap->db_type = M_PCPROTO;
777 if (blen < sizeof (struct T_error_ack)) {
778 putnext(q, mp);
779 break;
782 tilog("timodrproc: Got T_ERROR_ACK, flags = %x\n",
783 tp->tim_flags);
785 if ((tp->tim_flags & WAIT_CONNRESACK) &&
786 tp->tim_saved_prim == pptr->error_ack.ERROR_prim) {
787 tp->tim_flags &=
788 ~(WAIT_CONNRESACK | WAITIOCACK);
789 freemsg(tp->tim_iocsave);
790 tp->tim_iocsave = NULL;
791 tp->tim_saved_prim = -1;
792 putnext(q, mp);
793 } else if (tp->tim_flags & WAITIOCACK) {
794 tim_send_ioc_error_ack(q, tp, mp);
795 } else {
796 putnext(q, mp);
798 break;
800 case T_OK_ACK:
801 if (blen < sizeof (pptr->ok_ack)) {
802 mp->b_datap->db_type = M_PCPROTO;
803 putnext(q, mp);
804 break;
807 tilog("timodrproc: Got T_OK_ACK\n", 0);
809 if (pptr->ok_ack.CORRECT_prim == T_UNBIND_REQ)
810 tp->tim_mylen = 0;
812 if ((tp->tim_flags & WAIT_CONNRESACK) &&
813 tp->tim_saved_prim == pptr->ok_ack.CORRECT_prim) {
814 struct T_conn_res *resp;
815 struct T_conn_ind *indp;
816 struct tim_tim *ntp;
817 caddr_t ptr;
819 rw_enter(&tim_list_rwlock, RW_READER);
820 resp = (struct T_conn_res *)
821 tp->tim_iocsave->b_rptr;
822 ntp = tim_findlink(resp->ACCEPTOR_id);
823 if (ntp == NULL)
824 goto cresackout;
826 mutex_enter(&ntp->tim_mutex);
827 if (ntp->tim_peercred != NULL)
828 crfree(ntp->tim_peercred);
829 ntp->tim_peercred =
830 msg_getcred(tp->tim_iocsave->b_cont,
831 &ntp->tim_cpid);
832 if (ntp->tim_peercred != NULL)
833 crhold(ntp->tim_peercred);
835 if (!(ntp->tim_flags & DO_PEERNAME)) {
836 mutex_exit(&ntp->tim_mutex);
837 goto cresackout;
840 indp = (struct T_conn_ind *)
841 tp->tim_iocsave->b_cont->b_rptr;
842 /* true as message is put on list */
843 ASSERT(indp->SRC_length >= 0);
845 if (indp->SRC_length > ntp->tim_peermaxlen) {
846 ptr = kmem_alloc(indp->SRC_length,
847 KM_NOSLEEP);
848 if (ptr == NULL) {
849 mutex_exit(&ntp->tim_mutex);
850 rw_exit(&tim_list_rwlock);
851 tilog("timodwproc: kmem_alloc "
852 "failed, attempting "
853 "recovery\n", 0);
854 tim_recover(q, mp,
855 indp->SRC_length);
856 return (1);
858 if (ntp->tim_peermaxlen > 0)
859 kmem_free(ntp->tim_peername,
860 ntp->tim_peermaxlen);
861 ntp->tim_peername = ptr;
862 ntp->tim_peermaxlen = indp->SRC_length;
864 ntp->tim_peerlen = indp->SRC_length;
865 ptr = (caddr_t)indp + indp->SRC_offset;
866 bcopy(ptr, ntp->tim_peername, ntp->tim_peerlen);
868 mutex_exit(&ntp->tim_mutex);
870 cresackout:
871 rw_exit(&tim_list_rwlock);
872 tp->tim_flags &=
873 ~(WAIT_CONNRESACK | WAITIOCACK);
874 freemsg(tp->tim_iocsave);
875 tp->tim_iocsave = NULL;
876 tp->tim_saved_prim = -1;
879 tim_send_reply(q, mp, tp, pptr->ok_ack.CORRECT_prim);
880 break;
882 case T_BIND_ACK: {
883 struct T_bind_ack *ackp =
884 (struct T_bind_ack *)mp->b_rptr;
886 /* Restore db_type - recover() might have changed it */
887 mp->b_datap->db_type = M_PCPROTO;
888 if (blen < sizeof (*ackp)) {
889 putnext(q, mp);
890 break;
893 /* save negotiated backlog */
894 tp->tim_backlog = ackp->CONIND_number;
896 if (((tp->tim_flags & WAITIOCACK) == 0) ||
897 ((tp->tim_saved_prim != O_T_BIND_REQ) &&
898 (tp->tim_saved_prim != T_BIND_REQ))) {
899 putnext(q, mp);
900 break;
902 ASSERT(tp->tim_iocsave != NULL);
904 if (tp->tim_flags & DO_MYNAME) {
905 caddr_t p;
907 if (ackp->ADDR_length < 0 ||
908 mp->b_rptr + ackp->ADDR_offset +
909 ackp->ADDR_length > mp->b_wptr) {
910 putnext(q, mp);
911 break;
913 if (ackp->ADDR_length > tp->tim_mymaxlen) {
914 p = kmem_alloc(ackp->ADDR_length,
915 KM_NOSLEEP);
916 if (p == NULL) {
917 tilog("timodrproc: kmem_alloc "
918 "failed attempt recovery",
921 tim_recover(q, mp,
922 ackp->ADDR_length);
923 return (1);
925 ASSERT(tp->tim_mymaxlen >= 0);
926 if (tp->tim_mymaxlen != 0) {
927 kmem_free(tp->tim_myname,
928 tp->tim_mymaxlen);
930 tp->tim_myname = p;
931 tp->tim_mymaxlen = ackp->ADDR_length;
933 tp->tim_mylen = ackp->ADDR_length;
934 bcopy(mp->b_rptr + ackp->ADDR_offset,
935 tp->tim_myname, tp->tim_mylen);
937 tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
938 tp->tim_iocsave = NULL;
939 tp->tim_saved_prim = -1;
940 tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
941 TI_CAP_RECVD | CAP_WANTS_INFO);
942 break;
945 case T_OPTMGMT_ACK:
947 tilog("timodrproc: Got T_OPTMGMT_ACK\n", 0);
949 /* Restore db_type - recover() might have change it */
950 mp->b_datap->db_type = M_PCPROTO;
952 if (((tp->tim_flags & WAITIOCACK) == 0) ||
953 ((tp->tim_saved_prim != T_SVR4_OPTMGMT_REQ) &&
954 (tp->tim_saved_prim != T_OPTMGMT_REQ))) {
955 putnext(q, mp);
956 } else {
957 ASSERT(tp->tim_iocsave != NULL);
958 tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
959 tp->tim_iocsave = NULL;
960 tp->tim_saved_prim = -1;
961 tp->tim_flags &= ~(WAITIOCACK |
962 WAIT_IOCINFOACK | TI_CAP_RECVD |
963 CAP_WANTS_INFO);
965 break;
967 case T_INFO_ACK: {
968 struct T_info_ack *tia = (struct T_info_ack *)pptr;
970 /* Restore db_type - recover() might have changed it */
971 mp->b_datap->db_type = M_PCPROTO;
973 if (blen < sizeof (*tia)) {
974 putnext(q, mp);
975 break;
978 tilog("timodrproc: Got T_INFO_ACK, flags = %x\n",
979 tp->tim_flags);
981 timodprocessinfo(q, tp, tia);
983 TILOG("timodrproc: flags = %x\n", tp->tim_flags);
984 if ((tp->tim_flags & WAITIOCACK) != 0) {
985 size_t expected_ack_size;
986 ssize_t deficit;
987 int ioc_cmd;
988 struct T_capability_ack *tcap;
991 * The only case when T_INFO_ACK may be received back
992 * when we are waiting for ioctl to complete is when
993 * this ioctl sent T_INFO_REQ down.
995 if (!(tp->tim_flags & WAIT_IOCINFOACK)) {
996 putnext(q, mp);
997 break;
999 ASSERT(tp->tim_iocsave != NULL);
1001 iocbp = (struct iocblk *)
1002 tp->tim_iocsave->b_rptr;
1003 ioc_cmd = iocbp->ioc_cmd;
1006 * Was it sent from TI_CAPABILITY emulation?
1008 if (ioc_cmd == TI_CAPABILITY) {
1009 struct T_info_ack saved_info;
1012 * Perform sanity checks. The only case when we
1013 * send T_INFO_REQ from TI_CAPABILITY is when
1014 * timod emulates T_CAPABILITY_REQ and
1015 * CAP_bits1 has TC1_INFO set.
1017 if ((tp->tim_flags &
1018 (TI_CAP_RECVD | CAP_WANTS_INFO)) !=
1019 (TI_CAP_RECVD | CAP_WANTS_INFO)) {
1020 putnext(q, mp);
1021 break;
1024 TILOG("timodrproc:"
1025 " emulating TI_CAPABILITY/"
1026 "info\n", 0);
1028 /* Save info & reuse mp for T_CAPABILITY_ACK */
1029 saved_info = *tia;
1031 mp = tpi_ack_alloc(mp,
1032 sizeof (struct T_capability_ack),
1033 M_PCPROTO, T_CAPABILITY_ACK);
1035 if (mp == NULL) {
1036 tilog("timodrproc:"
1037 " realloc failed, no "
1038 "recovery attempted\n", 0);
1039 return (1);
1043 * Copy T_INFO information into T_CAPABILITY_ACK
1045 tcap = (struct T_capability_ack *)
1046 mp->b_rptr;
1047 tcap->CAP_bits1 = TC1_INFO;
1048 tcap->INFO_ack = saved_info;
1049 tp->tim_flags &= ~(WAITIOCACK |
1050 WAIT_IOCINFOACK | TI_CAP_RECVD |
1051 CAP_WANTS_INFO);
1052 tim_ioctl_send_reply(q,
1053 tp->tim_iocsave, mp);
1054 tp->tim_iocsave = NULL;
1055 tp->tim_saved_prim = -1;
1056 break;
1060 * The code for TI_SYNC/TI_GETINFO is left here only for
1061 * backward compatibility with staticaly linked old
1062 * applications. New TLI/XTI code should use
1063 * TI_CAPABILITY for getting transport info and should
1064 * not use TI_GETINFO/TI_SYNC for this purpose.
1068 * make sure the message sent back is the size of
1069 * the "expected ack"
1070 * For TI_GETINFO, expected ack size is
1071 * sizeof (T_info_ack)
1072 * For TI_SYNC, expected ack size is
1073 * sizeof (struct ti_sync_ack);
1075 if (ioc_cmd != TI_GETINFO &&
1076 ioc_cmd != TI_SYNC) {
1077 putnext(q, mp);
1078 break;
1081 expected_ack_size =
1082 sizeof (struct T_info_ack); /* TI_GETINFO */
1083 if (iocbp->ioc_cmd == TI_SYNC) {
1084 expected_ack_size = 2 *
1085 sizeof (uint32_t) +
1086 sizeof (struct ti_sync_ack);
1088 deficit = expected_ack_size - blen;
1090 if (deficit != 0) {
1091 if (mp->b_datap->db_lim - mp->b_wptr <
1092 deficit) { /* BEGIN CSTYLED */
1093 mblk_t *tmp = allocb(expected_ack_size,
1094 BPRI_HI);
1095 if (tmp == NULL) {
1096 ASSERT(MBLKSIZE(mp) >=
1097 sizeof (struct T_error_ack));
1099 tilog("timodrproc: allocb failed no "
1100 "recovery attempt\n", 0);
1102 mp->b_rptr = mp->b_datap->db_base;
1103 pptr = (union T_primitives *)
1104 mp->b_rptr;
1105 pptr->error_ack.ERROR_prim = T_INFO_REQ;
1106 pptr->error_ack.TLI_error = TSYSERR;
1107 pptr->error_ack.UNIX_error = EAGAIN;
1108 pptr->error_ack.PRIM_type = T_ERROR_ACK;
1109 mp->b_datap->db_type = M_PCPROTO;
1110 tim_send_ioc_error_ack(q, tp, mp);
1111 break;
1112 } else {
1113 bcopy(mp->b_rptr, tmp->b_rptr,
1114 blen);
1115 tmp->b_wptr += blen;
1116 pptr = (union T_primitives *)
1117 tmp->b_rptr;
1118 freemsg(mp);
1119 mp = tmp;
1120 } /* END CSTYLED */
1125 * We now have "mp" which has enough space for an
1126 * appropriate ack and contains struct T_info_ack
1127 * that the transport provider returned. We now
1128 * stuff it with more stuff to fullfill
1129 * TI_SYNC ioctl needs, as necessary
1131 if (iocbp->ioc_cmd == TI_SYNC) {
1133 * Assumes struct T_info_ack is first embedded
1134 * type in struct ti_sync_ack so it is
1135 * automatically there.
1137 struct ti_sync_ack *tsap =
1138 (struct ti_sync_ack *)mp->b_rptr;
1141 * tsap->tsa_qlen needs to be set only if
1142 * TSRF_QLEN_REQ flag is set, but for
1143 * compatibility with statically linked
1144 * applications it is set here regardless of the
1145 * flag since old XTI library expected it to be
1146 * set.
1148 tsap->tsa_qlen = tp->tim_backlog;
1149 /* intialize clear */
1150 tsap->tsa_flags = 0x0;
1151 if (tp->tim_flags & PEEK_RDQ_EXPIND) {
1153 * Request to peek for EXPIND in
1154 * rcvbuf.
1156 if (ti_expind_on_rdqueues(q)) {
1158 * Expedited data is
1159 * queued on the stream
1160 * read side
1162 tsap->tsa_flags |=
1163 TSAF_EXP_QUEUED;
1165 tp->tim_flags &=
1166 ~PEEK_RDQ_EXPIND;
1168 mp->b_wptr += 2*sizeof (uint32_t);
1170 tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
1171 tp->tim_iocsave = NULL;
1172 tp->tim_saved_prim = -1;
1173 tp->tim_flags &=
1174 ~(WAITIOCACK | WAIT_IOCINFOACK |
1175 TI_CAP_RECVD | CAP_WANTS_INFO);
1176 break;
1180 putnext(q, mp);
1181 break;
1183 case T_ADDR_ACK:
1184 tilog("timodrproc: Got T_ADDR_ACK\n", 0);
1185 tim_send_reply(q, mp, tp, T_ADDR_REQ);
1186 break;
1188 case T_CONN_IND: {
1189 struct T_conn_ind *tcip =
1190 (struct T_conn_ind *)mp->b_rptr;
1192 tilog("timodrproc: Got T_CONN_IND\n", 0);
1194 if (blen >= sizeof (*tcip) &&
1195 MBLKIN(mp, tcip->SRC_offset, tcip->SRC_length)) {
1196 if (((nbp = dupmsg(mp)) != NULL) ||
1197 ((nbp = copymsg(mp)) != NULL)) {
1198 nbp->b_next = tp->tim_consave;
1199 tp->tim_consave = nbp;
1200 } else {
1201 tim_recover(q, mp,
1202 (t_scalar_t)sizeof (mblk_t));
1203 return (1);
1206 putnext(q, mp);
1207 break;
1210 case T_CONN_CON:
1211 mutex_enter(&tp->tim_mutex);
1212 if (tp->tim_peercred != NULL)
1213 crfree(tp->tim_peercred);
1214 tp->tim_peercred = msg_getcred(mp, &tp->tim_cpid);
1215 if (tp->tim_peercred != NULL)
1216 crhold(tp->tim_peercred);
1217 mutex_exit(&tp->tim_mutex);
1219 tilog("timodrproc: Got T_CONN_CON\n", 0);
1221 tp->tim_flags &= ~CONNWAIT;
1222 putnext(q, mp);
1223 break;
1225 case T_DISCON_IND: {
1226 struct T_discon_ind *disp;
1227 struct T_conn_ind *conp;
1228 mblk_t *pbp = NULL;
1230 if (q->q_first != 0)
1231 tilog("timodrput: T_DISCON_IND -"
1232 " flow control\n", 0);
1234 if (blen < sizeof (*disp)) {
1235 putnext(q, mp);
1236 break;
1239 disp = (struct T_discon_ind *)mp->b_rptr;
1241 tilog("timodrproc: Got T_DISCON_IND Reason: %d\n",
1242 disp->DISCON_reason);
1244 tp->tim_flags &= ~(CONNWAIT|LOCORDREL|REMORDREL);
1245 tim_clear_peer(tp);
1246 for (nbp = tp->tim_consave; nbp; nbp = nbp->b_next) {
1247 conp = (struct T_conn_ind *)nbp->b_rptr;
1248 if (conp->SEQ_number == disp->SEQ_number)
1249 break;
1250 pbp = nbp;
1252 if (nbp) {
1253 if (pbp)
1254 pbp->b_next = nbp->b_next;
1255 else
1256 tp->tim_consave = nbp->b_next;
1257 nbp->b_next = NULL;
1258 freemsg(nbp);
1260 putnext(q, mp);
1261 break;
1264 case T_ORDREL_IND:
1266 tilog("timodrproc: Got T_ORDREL_IND\n", 0);
1268 if (tp->tim_flags & LOCORDREL) {
1269 tp->tim_flags &= ~(LOCORDREL|REMORDREL);
1270 tim_clear_peer(tp);
1271 } else {
1272 tp->tim_flags |= REMORDREL;
1274 putnext(q, mp);
1275 break;
1277 case T_EXDATA_IND:
1278 case T_DATA_IND:
1279 case T_UNITDATA_IND:
1280 if (pptr->type == T_EXDATA_IND)
1281 tilog("timodrproc: Got T_EXDATA_IND\n", 0);
1283 if (!bcanputnext(q, mp->b_band)) {
1284 (void) putbq(q, mp);
1285 return (1);
1287 putnext(q, mp);
1288 break;
1290 case T_CAPABILITY_ACK: {
1291 struct T_capability_ack *tca;
1293 if (blen < sizeof (*tca)) {
1294 putnext(q, mp);
1295 break;
1298 /* This transport supports T_CAPABILITY_REQ */
1299 tilog("timodrproc: Got T_CAPABILITY_ACK\n", 0);
1301 PI_PROVLOCK(tp->tim_provinfo);
1302 if (tp->tim_provinfo->tpi_capability != PI_YES)
1303 tp->tim_provinfo->tpi_capability = PI_YES;
1304 PI_PROVUNLOCK(tp->tim_provinfo);
1306 /* Reset possible pending timeout */
1307 if (tp->tim_tcap_timoutid != 0) {
1308 (void) quntimeout(q, tp->tim_tcap_timoutid);
1309 tp->tim_tcap_timoutid = 0;
1312 tca = (struct T_capability_ack *)mp->b_rptr;
1314 if (tca->CAP_bits1 & TC1_INFO)
1315 timodprocessinfo(q, tp, &tca->INFO_ack);
1317 tim_send_reply(q, mp, tp, T_CAPABILITY_REQ);
1319 break;
1321 break;
1323 case M_FLUSH:
1325 tilog("timodrproc: Got M_FLUSH\n", 0);
1327 if (*mp->b_rptr & FLUSHR) {
1328 if (*mp->b_rptr & FLUSHBAND)
1329 flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
1330 else
1331 flushq(q, FLUSHDATA);
1333 putnext(q, mp);
1334 break;
1336 case M_IOCACK:
1337 iocbp = (struct iocblk *)mp->b_rptr;
1339 tilog("timodrproc: Got M_IOCACK\n", 0);
1341 if (iocbp->ioc_cmd == TI_GETMYNAME) {
1344 * Transport provider supports this ioctl,
1345 * so I don't have to.
1347 if ((tp->tim_flags & DO_MYNAME) != 0) {
1348 tp->tim_flags &= ~DO_MYNAME;
1349 PI_PROVLOCK(tp->tim_provinfo);
1350 tp->tim_provinfo->tpi_myname = PI_YES;
1351 PI_PROVUNLOCK(tp->tim_provinfo);
1354 ASSERT(tp->tim_mymaxlen >= 0);
1355 if (tp->tim_mymaxlen != 0) {
1356 kmem_free(tp->tim_myname,
1357 (size_t)tp->tim_mymaxlen);
1358 tp->tim_myname = NULL;
1359 tp->tim_mymaxlen = 0;
1361 /* tim_iocsave may already be overwritten. */
1362 if (tp->tim_saved_prim == -1) {
1363 freemsg(tp->tim_iocsave);
1364 tp->tim_iocsave = NULL;
1366 } else if (iocbp->ioc_cmd == TI_GETPEERNAME) {
1367 boolean_t clearit;
1370 * Transport provider supports this ioctl,
1371 * so I don't have to.
1373 if ((tp->tim_flags & DO_PEERNAME) != 0) {
1374 tp->tim_flags &= ~DO_PEERNAME;
1375 PI_PROVLOCK(tp->tim_provinfo);
1376 tp->tim_provinfo->tpi_peername = PI_YES;
1377 PI_PROVUNLOCK(tp->tim_provinfo);
1380 mutex_enter(&tp->tim_mutex);
1381 ASSERT(tp->tim_peermaxlen >= 0);
1382 clearit = tp->tim_peermaxlen != 0;
1383 if (clearit) {
1384 kmem_free(tp->tim_peername, tp->tim_peermaxlen);
1385 tp->tim_peername = NULL;
1386 tp->tim_peermaxlen = 0;
1387 tp->tim_peerlen = 0;
1389 mutex_exit(&tp->tim_mutex);
1390 if (clearit) {
1391 mblk_t *bp;
1393 bp = tp->tim_consave;
1394 while (bp != NULL) {
1395 nbp = bp->b_next;
1396 bp->b_next = NULL;
1397 freemsg(bp);
1398 bp = nbp;
1400 tp->tim_consave = NULL;
1402 /* tim_iocsave may already be overwritten. */
1403 if (tp->tim_saved_prim == -1) {
1404 freemsg(tp->tim_iocsave);
1405 tp->tim_iocsave = NULL;
1408 putnext(q, mp);
1409 break;
1411 case M_IOCNAK:
1413 tilog("timodrproc: Got M_IOCNAK\n", 0);
1415 iocbp = (struct iocblk *)mp->b_rptr;
1416 if (((iocbp->ioc_cmd == TI_GETMYNAME) ||
1417 (iocbp->ioc_cmd == TI_GETPEERNAME)) &&
1418 ((iocbp->ioc_error == EINVAL) || (iocbp->ioc_error == 0))) {
1419 PI_PROVLOCK(tp->tim_provinfo);
1420 if (iocbp->ioc_cmd == TI_GETMYNAME) {
1421 if (tp->tim_provinfo->tpi_myname == PI_DONTKNOW)
1422 tp->tim_provinfo->tpi_myname = PI_NO;
1423 } else if (iocbp->ioc_cmd == TI_GETPEERNAME) {
1424 if (tp->tim_provinfo->tpi_peername ==
1425 PI_DONTKNOW)
1426 tp->tim_provinfo->tpi_peername = PI_NO;
1428 PI_PROVUNLOCK(tp->tim_provinfo);
1429 /* tim_iocsave may already be overwritten. */
1430 if ((tp->tim_iocsave != NULL) &&
1431 (tp->tim_saved_prim == -1)) {
1432 freemsg(mp);
1433 mp = tp->tim_iocsave;
1434 tp->tim_iocsave = NULL;
1435 tp->tim_flags |= NAMEPROC;
1436 if (ti_doname(WR(q), mp) != DONAME_CONT) {
1437 tp->tim_flags &= ~NAMEPROC;
1439 break;
1442 putnext(q, mp);
1443 break;
1446 return (0);
1450 * timodwput - Module write put procedure. This is called from
1451 * the module, driver, or stream head upstream/downstream.
1452 * Handles M_FLUSH, M_DATA and some M_PROTO (T_DATA_REQ,
1453 * and T_UNITDATA_REQ) messages. All others are queued to
1454 * be handled by the service procedures.
1457 static void
1458 timodwput(queue_t *q, mblk_t *mp)
1460 union T_primitives *pptr;
1461 struct tim_tim *tp;
1462 struct iocblk *iocbp;
1465 * Enqueue normal-priority messages if our queue already
1466 * holds some messages for deferred processing but don't
1467 * enqueue those M_IOCTLs which will result in an
1468 * M_PCPROTO (ie, high priority) message being created.
1470 if (q->q_first != 0 && mp->b_datap->db_type < QPCTL) {
1471 if (mp->b_datap->db_type == M_IOCTL) {
1472 iocbp = (struct iocblk *)mp->b_rptr;
1473 switch (iocbp->ioc_cmd) {
1474 default:
1475 (void) putq(q, mp);
1476 return;
1478 case TI_GETINFO:
1479 case TI_SYNC:
1480 case TI_CAPABILITY:
1481 break;
1483 } else {
1484 (void) putq(q, mp);
1485 return;
1489 * Inline processing of data (to avoid additional procedure call).
1490 * Rest is handled in timodwproc.
1493 switch (mp->b_datap->db_type) {
1494 case M_DATA:
1495 tp = (struct tim_tim *)q->q_ptr;
1496 ASSERT(tp);
1497 if (tp->tim_flags & CLTS) {
1498 mblk_t *tmp;
1500 if ((tmp = tim_filladdr(q, mp, B_FALSE)) == NULL) {
1501 (void) putq(q, mp);
1502 break;
1503 } else {
1504 mp = tmp;
1507 if (bcanputnext(q, mp->b_band))
1508 putnext(q, mp);
1509 else
1510 (void) putq(q, mp);
1511 break;
1512 case M_PROTO:
1513 case M_PCPROTO:
1514 pptr = (union T_primitives *)mp->b_rptr;
1515 switch (pptr->type) {
1516 case T_UNITDATA_REQ:
1517 tp = (struct tim_tim *)q->q_ptr;
1518 ASSERT(tp);
1519 if (tp->tim_flags & CLTS) {
1520 mblk_t *tmp;
1522 tmp = tim_filladdr(q, mp, B_FALSE);
1523 if (tmp == NULL) {
1524 (void) putq(q, mp);
1525 break;
1526 } else {
1527 mp = tmp;
1530 if (bcanputnext(q, mp->b_band))
1531 putnext(q, mp);
1532 else
1533 (void) putq(q, mp);
1534 break;
1536 case T_DATA_REQ:
1537 case T_EXDATA_REQ:
1538 if (bcanputnext(q, mp->b_band))
1539 putnext(q, mp);
1540 else
1541 (void) putq(q, mp);
1542 break;
1543 default:
1544 (void) timodwproc(q, mp);
1545 break;
1547 break;
1548 default:
1549 (void) timodwproc(q, mp);
1550 break;
1554 * timodwsrv - Module write queue service procedure.
1555 * This is called when messages are placed on an empty queue,
1556 * when high priority messages are placed on the queue, and
1557 * when flow control restrictions subside. This code used to
1558 * be included in a put procedure, but it was moved to a
1559 * service procedure because several points were added where
1560 * memory allocation could fail, and there is no reasonable
1561 * recovery mechanism from the put procedure.
1563 static void
1564 timodwsrv(queue_t *q)
1566 mblk_t *mp;
1568 ASSERT(q != NULL);
1569 if (q->q_ptr == NULL)
1570 return;
1572 while ((mp = getq(q)) != NULL) {
1573 if (timodwproc(q, mp)) {
1575 * timodwproc did a putbq - stop processing
1576 * messages.
1578 return;
1584 * Common routine to process write side messages
1587 static int
1588 timodwproc(queue_t *q, mblk_t *mp)
1590 union T_primitives *pptr;
1591 struct tim_tim *tp;
1592 mblk_t *tmp;
1593 struct iocblk *iocbp;
1594 int error;
1596 tp = (struct tim_tim *)q->q_ptr;
1598 switch (mp->b_datap->db_type) {
1599 default:
1600 putnext(q, mp);
1601 break;
1603 case M_DATA:
1604 if (tp->tim_flags & CLTS) {
1605 if ((tmp = tim_filladdr(q, mp, B_TRUE)) == NULL) {
1606 return (1);
1607 } else {
1608 mp = tmp;
1611 if (!bcanputnext(q, mp->b_band)) {
1612 (void) putbq(q, mp);
1613 return (1);
1615 putnext(q, mp);
1616 break;
1618 case M_IOCTL:
1620 iocbp = (struct iocblk *)mp->b_rptr;
1621 TILOG("timodwproc: Got M_IOCTL(%d)\n", iocbp->ioc_cmd);
1623 ASSERT(MBLKL(mp) == sizeof (struct iocblk));
1626 * TPI requires we await response to a previously sent message
1627 * before handling another, put it back on the head of queue.
1628 * Since putbq() may see QWANTR unset when called from the
1629 * service procedure, the queue must be explicitly scheduled
1630 * for service, as no backenable will occur for this case.
1631 * tim_ioctl_retry() sets a timer to handle the qenable.
1633 if (tp->tim_flags & WAITIOCACK) {
1634 TILOG("timodwproc: putbq M_IOCTL(%d)\n",
1635 iocbp->ioc_cmd);
1636 (void) putbq(q, mp);
1637 /* Called from timodwsrv() and messages on queue */
1638 if (!(q->q_flag & QWANTR))
1639 tim_ioctl_retry(q);
1640 return (1);
1643 switch (iocbp->ioc_cmd) {
1644 default:
1645 putnext(q, mp);
1646 break;
1648 case _I_GETPEERCRED:
1649 if ((tp->tim_flags & COTS) == 0) {
1650 miocnak(q, mp, 0, ENOTSUP);
1651 } else {
1652 mblk_t *cmp = mp->b_cont;
1653 k_peercred_t *kp = NULL;
1655 mutex_enter(&tp->tim_mutex);
1656 if (cmp != NULL &&
1657 iocbp->ioc_flag == IOC_NATIVE &&
1658 (tp->tim_flags &
1659 (CONNWAIT|LOCORDREL|REMORDREL)) == 0 &&
1660 tp->tim_peercred != NULL &&
1661 DB_TYPE(cmp) == M_DATA &&
1662 MBLKL(cmp) == sizeof (k_peercred_t)) {
1663 kp = (k_peercred_t *)cmp->b_rptr;
1664 crhold(kp->pc_cr = tp->tim_peercred);
1665 kp->pc_cpid = tp->tim_cpid;
1667 mutex_exit(&tp->tim_mutex);
1668 if (kp != NULL)
1669 miocack(q, mp, sizeof (*kp), 0);
1670 else
1671 miocnak(q, mp, 0, ENOTCONN);
1673 break;
1674 case TI_BIND:
1675 case TI_UNBIND:
1676 case TI_OPTMGMT:
1677 case TI_GETADDRS:
1678 TILOG("timodwproc: TI_{BIND|UNBIND|OPTMGMT|GETADDRS}"
1679 "\n", 0);
1682 * We know that tim_send_ioctl_tpi_msg() is only
1683 * going to examine the `type' field, so we only
1684 * check that we can access that much data.
1686 error = miocpullup(mp, sizeof (t_scalar_t));
1687 if (error != 0) {
1688 miocnak(q, mp, 0, error);
1689 break;
1691 tim_send_ioctl_tpi_msg(q, mp, tp, iocbp);
1692 break;
1694 case TI_GETINFO:
1695 TILOG("timodwproc: TI_GETINFO\n", 0);
1696 error = miocpullup(mp, sizeof (struct T_info_req));
1697 if (error != 0) {
1698 miocnak(q, mp, 0, error);
1699 break;
1701 tp->tim_flags |= WAIT_IOCINFOACK;
1702 tim_send_ioctl_tpi_msg(q, mp, tp, iocbp);
1703 break;
1705 case TI_SYNC: {
1706 mblk_t *tsr_mp;
1707 struct ti_sync_req *tsr;
1708 uint32_t tsr_flags;
1710 error = miocpullup(mp, sizeof (struct ti_sync_req));
1711 if (error != 0) {
1712 miocnak(q, mp, 0, error);
1713 break;
1716 tsr_mp = mp->b_cont;
1717 tsr = (struct ti_sync_req *)tsr_mp->b_rptr;
1718 TILOG("timodwproc: TI_SYNC(%x)\n", tsr->tsr_flags);
1721 * Save out the value of tsr_flags, in case we
1722 * reallocb() tsr_mp (below).
1724 tsr_flags = tsr->tsr_flags;
1725 if ((tsr_flags & TSRF_INFO_REQ) == 0) {
1726 mblk_t *ack_mp = reallocb(tsr_mp,
1727 sizeof (struct ti_sync_ack), 0);
1729 /* Can reply immediately. */
1730 mp->b_cont = NULL;
1731 if (ack_mp == NULL) {
1732 tilog("timodwproc: allocb failed no "
1733 "recovery attempt\n", 0);
1734 freemsg(tsr_mp);
1735 miocnak(q, mp, 0, ENOMEM);
1736 } else {
1737 tim_answer_ti_sync(q, mp, tp,
1738 ack_mp, tsr_flags);
1740 break;
1744 * This code is retained for compatibility with
1745 * old statically linked applications. New code
1746 * should use TI_CAPABILITY for all TPI
1747 * information and should not use TSRF_INFO_REQ
1748 * flag.
1750 * defer processsing necessary to rput procedure
1751 * as we need to get information from transport
1752 * driver. Set flags that will tell the read
1753 * side the work needed on this request.
1756 if (tsr_flags & TSRF_IS_EXP_IN_RCVBUF)
1757 tp->tim_flags |= PEEK_RDQ_EXPIND;
1760 * Convert message to a T_INFO_REQ message; relies
1761 * on sizeof (struct ti_sync_req) >= sizeof (struct
1762 * T_info_req)).
1764 ASSERT(MBLKL(tsr_mp) >= sizeof (struct T_info_req));
1766 ((struct T_info_req *)tsr_mp->b_rptr)->PRIM_type =
1767 T_INFO_REQ;
1768 tsr_mp->b_wptr = tsr_mp->b_rptr +
1769 sizeof (struct T_info_req);
1770 tp->tim_flags |= WAIT_IOCINFOACK;
1771 tim_send_ioctl_tpi_msg(q, mp, tp, iocbp);
1773 break;
1775 case TI_CAPABILITY: {
1776 mblk_t *tcsr_mp;
1777 struct T_capability_req *tcr;
1779 error = miocpullup(mp, sizeof (*tcr));
1780 if (error != 0) {
1781 miocnak(q, mp, 0, error);
1782 break;
1785 tcsr_mp = mp->b_cont;
1786 tcr = (struct T_capability_req *)tcsr_mp->b_rptr;
1787 TILOG("timodwproc: TI_CAPABILITY(CAP_bits1 = %x)\n",
1788 tcr->CAP_bits1);
1790 if (tcr->PRIM_type != T_CAPABILITY_REQ) {
1791 TILOG("timodwproc: invalid msg type %d\n",
1792 tcr->PRIM_type);
1793 miocnak(q, mp, 0, EPROTO);
1794 break;
1797 switch (tp->tim_provinfo->tpi_capability) {
1798 case PI_YES:
1799 /* Just send T_CAPABILITY_REQ down */
1800 tim_send_ioctl_tpi_msg(q, mp, tp, iocbp);
1801 break;
1803 case PI_DONTKNOW:
1805 * It is unknown yet whether transport provides
1806 * T_CAPABILITY_REQ or not. Send message down
1807 * and wait for reply.
1810 ASSERT(tp->tim_tcap_timoutid == 0);
1811 if ((tcr->CAP_bits1 & TC1_INFO) == 0) {
1812 tp->tim_flags |= TI_CAP_RECVD;
1813 } else {
1814 tp->tim_flags |= (TI_CAP_RECVD |
1815 CAP_WANTS_INFO);
1818 tp->tim_tcap_timoutid = qtimeout(q,
1819 tim_tcap_timer, q, tim_tcap_wait * hz);
1820 tim_send_ioctl_tpi_msg(q, mp, tp, iocbp);
1821 break;
1823 case PI_NO:
1825 * Transport doesn't support T_CAPABILITY_REQ.
1826 * Either reply immediately or send T_INFO_REQ
1827 * if needed.
1829 if ((tcr->CAP_bits1 & TC1_INFO) != 0) {
1830 tp->tim_flags |= (TI_CAP_RECVD |
1831 CAP_WANTS_INFO | WAIT_IOCINFOACK);
1832 TILOG("timodwproc: sending down "
1833 "T_INFO_REQ, flags = %x\n",
1834 tp->tim_flags);
1837 * Generate T_INFO_REQ message and send
1838 * it down
1840 ((struct T_info_req *)tcsr_mp->b_rptr)->
1841 PRIM_type = T_INFO_REQ;
1842 tcsr_mp->b_wptr = tcsr_mp->b_rptr +
1843 sizeof (struct T_info_req);
1844 tim_send_ioctl_tpi_msg(q, mp, tp,
1845 iocbp);
1846 break;
1851 * Can reply immediately. Just send back
1852 * T_CAPABILITY_ACK with CAP_bits1 set to 0.
1854 mp->b_cont = tcsr_mp = tpi_ack_alloc(mp->b_cont,
1855 sizeof (struct T_capability_ack), M_PCPROTO,
1856 T_CAPABILITY_ACK);
1858 if (tcsr_mp == NULL) {
1859 tilog("timodwproc: allocb failed no "
1860 "recovery attempt\n", 0);
1861 miocnak(q, mp, 0, ENOMEM);
1862 break;
1865 tp->tim_flags &= ~(WAITIOCACK | TI_CAP_RECVD |
1866 WAIT_IOCINFOACK | CAP_WANTS_INFO);
1867 ((struct T_capability_ack *)
1868 tcsr_mp->b_rptr)->CAP_bits1 = 0;
1869 tim_ioctl_send_reply(q, mp, tcsr_mp);
1872 * It could happen when timod is awaiting ack
1873 * for TI_GETPEERNAME/TI_GETMYNAME.
1875 if (tp->tim_iocsave != NULL) {
1876 freemsg(tp->tim_iocsave);
1877 tp->tim_iocsave = NULL;
1878 tp->tim_saved_prim = -1;
1880 break;
1882 default:
1883 cmn_err(CE_PANIC,
1884 "timodwproc: unknown tpi_capability value "
1885 "%d\n", tp->tim_provinfo->tpi_capability);
1886 break;
1889 break;
1891 case TI_GETMYNAME:
1893 tilog("timodwproc: Got TI_GETMYNAME\n", 0);
1895 if (tp->tim_provinfo->tpi_myname == PI_YES) {
1896 putnext(q, mp);
1897 break;
1899 goto getname;
1901 case TI_GETPEERNAME:
1903 tilog("timodwproc: Got TI_GETPEERNAME\n", 0);
1905 if (tp->tim_provinfo->tpi_peername == PI_YES) {
1906 putnext(q, mp);
1907 break;
1909 getname:
1910 if ((tmp = copymsg(mp)) == NULL) {
1911 tim_recover(q, mp, msgsize(mp));
1912 return (1);
1915 * tim_iocsave may be non-NULL when timod is awaiting
1916 * ack for another TI_GETPEERNAME/TI_GETMYNAME.
1918 freemsg(tp->tim_iocsave);
1919 tp->tim_iocsave = mp;
1920 tp->tim_saved_prim = -1;
1921 putnext(q, tmp);
1922 break;
1924 break;
1926 case M_IOCDATA:
1928 if (tp->tim_flags & NAMEPROC) {
1929 if (ti_doname(q, mp) != DONAME_CONT) {
1930 tp->tim_flags &= ~NAMEPROC;
1932 } else
1933 putnext(q, mp);
1934 break;
1936 case M_PROTO:
1937 case M_PCPROTO:
1938 if (MBLKL(mp) < sizeof (t_scalar_t)) {
1939 merror(q, mp, EPROTO);
1940 return (1);
1943 pptr = (union T_primitives *)mp->b_rptr;
1944 switch (pptr->type) {
1945 default:
1946 putnext(q, mp);
1947 break;
1949 case T_EXDATA_REQ:
1950 case T_DATA_REQ:
1951 if (pptr->type == T_EXDATA_REQ)
1952 tilog("timodwproc: Got T_EXDATA_REQ\n", 0);
1954 if (!bcanputnext(q, mp->b_band)) {
1955 (void) putbq(q, mp);
1956 return (1);
1958 putnext(q, mp);
1959 break;
1961 case T_UNITDATA_REQ:
1962 if (tp->tim_flags & CLTS) {
1963 tmp = tim_filladdr(q, mp, B_TRUE);
1964 if (tmp == NULL) {
1965 return (1);
1966 } else {
1967 mp = tmp;
1970 if (!bcanputnext(q, mp->b_band)) {
1971 (void) putbq(q, mp);
1972 return (1);
1974 putnext(q, mp);
1975 break;
1977 case T_CONN_REQ: {
1978 struct T_conn_req *reqp = (struct T_conn_req *)
1979 mp->b_rptr;
1980 void *p;
1982 tilog("timodwproc: Got T_CONN_REQ\n", 0);
1984 if (MBLKL(mp) < sizeof (struct T_conn_req)) {
1985 merror(q, mp, EPROTO);
1986 return (1);
1989 if (tp->tim_flags & DO_PEERNAME) {
1990 if (!MBLKIN(mp, reqp->DEST_offset,
1991 reqp->DEST_length)) {
1992 merror(q, mp, EPROTO);
1993 return (1);
1995 ASSERT(reqp->DEST_length >= 0);
1996 mutex_enter(&tp->tim_mutex);
1997 if (reqp->DEST_length > tp->tim_peermaxlen) {
1998 p = kmem_alloc(reqp->DEST_length,
1999 KM_NOSLEEP);
2000 if (p == NULL) {
2001 mutex_exit(&tp->tim_mutex);
2002 tilog("timodwproc: kmem_alloc "
2003 "failed, attempting "
2004 "recovery\n", 0);
2005 tim_recover(q, mp,
2006 reqp->DEST_length);
2007 return (1);
2009 if (tp->tim_peermaxlen)
2010 kmem_free(tp->tim_peername,
2011 tp->tim_peermaxlen);
2012 tp->tim_peername = p;
2013 tp->tim_peermaxlen = reqp->DEST_length;
2015 tp->tim_peerlen = reqp->DEST_length;
2016 p = mp->b_rptr + reqp->DEST_offset;
2017 bcopy(p, tp->tim_peername, tp->tim_peerlen);
2018 mutex_exit(&tp->tim_mutex);
2020 if (tp->tim_flags & COTS)
2021 tp->tim_flags |= CONNWAIT;
2022 putnext(q, mp);
2023 break;
2026 case O_T_CONN_RES:
2027 case T_CONN_RES: {
2028 struct T_conn_res *resp;
2029 struct T_conn_ind *indp;
2030 mblk_t *pmp = NULL;
2031 mblk_t *nbp;
2033 if (MBLKL(mp) < sizeof (struct T_conn_res) ||
2034 (tp->tim_flags & WAITIOCACK)) {
2035 merror(q, mp, EPROTO);
2036 return (1);
2039 resp = (struct T_conn_res *)mp->b_rptr;
2040 for (tmp = tp->tim_consave; tmp != NULL;
2041 tmp = tmp->b_next) {
2042 indp = (struct T_conn_ind *)tmp->b_rptr;
2043 if (indp->SEQ_number == resp->SEQ_number)
2044 break;
2045 pmp = tmp;
2047 if (tmp == NULL)
2048 goto cresout;
2050 if ((nbp = dupb(mp)) == NULL &&
2051 (nbp = copyb(mp)) == NULL) {
2052 tim_recover(q, mp, msgsize(mp));
2053 return (1);
2056 if (pmp != NULL)
2057 pmp->b_next = tmp->b_next;
2058 else
2059 tp->tim_consave = tmp->b_next;
2060 tmp->b_next = NULL;
2063 * Construct a list with:
2064 * nbp - copy of user's original request
2065 * tmp - the extracted T_conn_ind
2067 nbp->b_cont = tmp;
2069 * tim_iocsave may be non-NULL when timod is awaiting
2070 * ack for TI_GETPEERNAME/TI_GETMYNAME.
2072 freemsg(tp->tim_iocsave);
2073 tp->tim_iocsave = nbp;
2074 tp->tim_saved_prim = pptr->type;
2075 tp->tim_flags |= WAIT_CONNRESACK | WAITIOCACK;
2077 cresout:
2078 putnext(q, mp);
2079 break;
2082 case T_DISCON_REQ: {
2083 struct T_discon_req *disp;
2084 struct T_conn_ind *conp;
2085 mblk_t *pmp = NULL;
2087 if (MBLKL(mp) < sizeof (struct T_discon_req)) {
2088 merror(q, mp, EPROTO);
2089 return (1);
2092 disp = (struct T_discon_req *)mp->b_rptr;
2093 tp->tim_flags &= ~(CONNWAIT|LOCORDREL|REMORDREL);
2094 tim_clear_peer(tp);
2097 * If we are already connected, there won't
2098 * be any messages on tim_consave.
2100 for (tmp = tp->tim_consave; tmp; tmp = tmp->b_next) {
2101 conp = (struct T_conn_ind *)tmp->b_rptr;
2102 if (conp->SEQ_number == disp->SEQ_number)
2103 break;
2104 pmp = tmp;
2106 if (tmp) {
2107 if (pmp)
2108 pmp->b_next = tmp->b_next;
2109 else
2110 tp->tim_consave = tmp->b_next;
2111 tmp->b_next = NULL;
2112 freemsg(tmp);
2114 putnext(q, mp);
2115 break;
2118 case T_ORDREL_REQ:
2119 if (tp->tim_flags & REMORDREL) {
2120 tp->tim_flags &= ~(LOCORDREL|REMORDREL);
2121 tim_clear_peer(tp);
2122 } else {
2123 tp->tim_flags |= LOCORDREL;
2125 putnext(q, mp);
2126 break;
2128 case T_CAPABILITY_REQ:
2129 tilog("timodwproc: Got T_CAPABILITY_REQ\n", 0);
2131 * XXX: We may know at this point whether transport
2132 * provides T_CAPABILITY_REQ or not and we may utilise
2133 * this knowledge here.
2135 putnext(q, mp);
2136 break;
2138 break;
2139 case M_FLUSH:
2141 tilog("timodwproc: Got M_FLUSH\n", 0);
2143 if (*mp->b_rptr & FLUSHW) {
2144 if (*mp->b_rptr & FLUSHBAND)
2145 flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
2146 else
2147 flushq(q, FLUSHDATA);
2149 putnext(q, mp);
2150 break;
2153 return (0);
2156 static void
2157 tilog(char *str, t_scalar_t arg)
2159 if (dotilog) {
2160 if (dotilog & 2)
2161 cmn_err(CE_CONT, str, arg);
2162 if (dotilog & 4)
2163 (void) strlog(TIMOD_ID, -1, 0, SL_TRACE | SL_ERROR,
2164 str, arg);
2165 else
2166 (void) strlog(TIMOD_ID, -1, 0, SL_TRACE, str, arg);
2170 static void
2171 tilogp(char *str, uintptr_t arg)
2173 if (dotilog) {
2174 if (dotilog & 2)
2175 cmn_err(CE_CONT, str, arg);
2176 if (dotilog & 4)
2177 (void) strlog(TIMOD_ID, -1, 0, SL_TRACE | SL_ERROR,
2178 str, arg);
2179 else
2180 (void) strlog(TIMOD_ID, -1, 0, SL_TRACE, str, arg);
2186 * Process the TI_GETNAME ioctl. If no name exists, return len = 0
2187 * in strbuf structures. The state transitions are determined by what
2188 * is hung of cq_private (cp_private) in the copyresp (copyreq) structure.
2189 * The high-level steps in the ioctl processing are as follows:
2191 * 1) we recieve an transparent M_IOCTL with the arg in the second message
2192 * block of the message.
2193 * 2) we send up an M_COPYIN request for the strbuf structure pointed to
2194 * by arg. The block containing arg is hung off cq_private.
2195 * 3) we receive an M_IOCDATA response with cp->cp_private->b_cont == NULL.
2196 * This means that the strbuf structure is found in the message block
2197 * mp->b_cont.
2198 * 4) we send up an M_COPYOUT request with the strbuf message hung off
2199 * cq_private->b_cont. The address we are copying to is strbuf.buf.
2200 * we set strbuf.len to 0 to indicate that we should copy the strbuf
2201 * structure the next time. The message mp->b_cont contains the
2202 * address info.
2203 * 5) we receive an M_IOCDATA with cp_private->b_cont != NULL and
2204 * strbuf.len == 0. Restore strbuf.len to either tp->tim_mylen or
2205 * tp->tim_peerlen.
2206 * 6) we send up an M_COPYOUT request with a copy of the strbuf message
2207 * hung off mp->b_cont. In the strbuf structure in the message hung
2208 * off cq_private->b_cont, we set strbuf.len to 0 and strbuf.maxlen
2209 * to 0. This means that the next step is to ACK the ioctl.
2210 * 7) we receive an M_IOCDATA message with cp_private->b_cont != NULL and
2211 * strbuf.len == 0 and strbuf.maxlen == 0. Free up cp->private and
2212 * send an M_IOCACK upstream, and we are done.
2215 static int
2216 ti_doname(
2217 queue_t *q, /* queue message arrived at */
2218 mblk_t *mp) /* M_IOCTL or M_IOCDATA message only */
2220 struct iocblk *iocp;
2221 struct copyreq *cqp;
2222 STRUCT_HANDLE(strbuf, sb);
2223 struct copyresp *csp;
2224 int ret;
2225 mblk_t *bp;
2226 struct tim_tim *tp = q->q_ptr;
2227 boolean_t getpeer;
2229 switch (mp->b_datap->db_type) {
2230 case M_IOCTL:
2231 iocp = (struct iocblk *)mp->b_rptr;
2232 if ((iocp->ioc_cmd != TI_GETMYNAME) &&
2233 (iocp->ioc_cmd != TI_GETPEERNAME)) {
2234 tilog("ti_doname: bad M_IOCTL command\n", 0);
2235 miocnak(q, mp, 0, EINVAL);
2236 ret = DONAME_FAIL;
2237 break;
2239 if ((iocp->ioc_count != TRANSPARENT)) {
2240 miocnak(q, mp, 0, EINVAL);
2241 ret = DONAME_FAIL;
2242 break;
2245 cqp = (struct copyreq *)mp->b_rptr;
2246 cqp->cq_private = mp->b_cont;
2247 cqp->cq_addr = (caddr_t)*(intptr_t *)mp->b_cont->b_rptr;
2248 mp->b_cont = NULL;
2249 cqp->cq_size = SIZEOF_STRUCT(strbuf, iocp->ioc_flag);
2250 cqp->cq_flag = 0;
2251 mp->b_datap->db_type = M_COPYIN;
2252 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
2253 qreply(q, mp);
2254 ret = DONAME_CONT;
2255 break;
2257 case M_IOCDATA:
2258 csp = (struct copyresp *)mp->b_rptr;
2259 iocp = (struct iocblk *)mp->b_rptr;
2260 cqp = (struct copyreq *)mp->b_rptr;
2261 if ((csp->cp_cmd != TI_GETMYNAME) &&
2262 (csp->cp_cmd != TI_GETPEERNAME)) {
2263 cmn_err(CE_WARN, "ti_doname: bad M_IOCDATA command\n");
2264 miocnak(q, mp, 0, EINVAL);
2265 ret = DONAME_FAIL;
2266 break;
2268 if (csp->cp_rval) { /* error */
2269 freemsg(csp->cp_private);
2270 freemsg(mp);
2271 ret = DONAME_FAIL;
2272 break;
2274 ASSERT(csp->cp_private != NULL);
2275 getpeer = csp->cp_cmd == TI_GETPEERNAME;
2276 if (getpeer)
2277 mutex_enter(&tp->tim_mutex);
2278 if (csp->cp_private->b_cont == NULL) { /* got strbuf */
2279 ASSERT(mp->b_cont);
2280 STRUCT_SET_HANDLE(sb, iocp->ioc_flag,
2281 (void *)mp->b_cont->b_rptr);
2282 if (getpeer) {
2283 if (tp->tim_peerlen == 0) {
2284 /* copy just strbuf */
2285 STRUCT_FSET(sb, len, 0);
2286 } else if (tp->tim_peerlen >
2287 STRUCT_FGET(sb, maxlen)) {
2288 mutex_exit(&tp->tim_mutex);
2289 miocnak(q, mp, 0, ENAMETOOLONG);
2290 ret = DONAME_FAIL;
2291 break;
2292 } else {
2293 /* copy buffer */
2294 STRUCT_FSET(sb, len, tp->tim_peerlen);
2296 } else {
2297 if (tp->tim_mylen == 0) {
2298 /* copy just strbuf */
2299 STRUCT_FSET(sb, len, 0);
2300 } else if (tp->tim_mylen >
2301 STRUCT_FGET(sb, maxlen)) {
2302 freemsg(csp->cp_private);
2303 miocnak(q, mp, 0, ENAMETOOLONG);
2304 ret = DONAME_FAIL;
2305 break;
2306 } else {
2307 /* copy buffer */
2308 STRUCT_FSET(sb, len, tp->tim_mylen);
2311 csp->cp_private->b_cont = mp->b_cont;
2312 mp->b_cont = NULL;
2314 STRUCT_SET_HANDLE(sb, iocp->ioc_flag,
2315 (void *)csp->cp_private->b_cont->b_rptr);
2316 if (STRUCT_FGET(sb, len) == 0) {
2318 * restore strbuf.len
2320 if (getpeer)
2321 STRUCT_FSET(sb, len, tp->tim_peerlen);
2322 else
2323 STRUCT_FSET(sb, len, tp->tim_mylen);
2325 if (getpeer)
2326 mutex_exit(&tp->tim_mutex);
2327 if (STRUCT_FGET(sb, maxlen) == 0) {
2330 * ack the ioctl
2332 freemsg(csp->cp_private);
2333 tim_ioctl_send_reply(q, mp, NULL);
2334 ret = DONAME_DONE;
2335 break;
2338 if ((bp = allocb(STRUCT_SIZE(sb), BPRI_MED)) == NULL) {
2340 tilog(
2341 "ti_doname: allocb failed no recovery attempt\n", 0);
2343 freemsg(csp->cp_private);
2344 miocnak(q, mp, 0, EAGAIN);
2345 ret = DONAME_FAIL;
2346 break;
2348 bp->b_wptr += STRUCT_SIZE(sb);
2349 bcopy(STRUCT_BUF(sb), bp->b_rptr, STRUCT_SIZE(sb));
2350 cqp->cq_addr =
2351 (caddr_t)*(intptr_t *)csp->cp_private->b_rptr;
2352 cqp->cq_size = STRUCT_SIZE(sb);
2353 cqp->cq_flag = 0;
2354 mp->b_datap->db_type = M_COPYOUT;
2355 mp->b_cont = bp;
2356 STRUCT_FSET(sb, len, 0);
2357 STRUCT_FSET(sb, maxlen, 0); /* ack next time around */
2358 qreply(q, mp);
2359 ret = DONAME_CONT;
2360 break;
2364 * copy the address to the user
2366 if ((bp = allocb((size_t)STRUCT_FGET(sb, len), BPRI_MED))
2367 == NULL) {
2368 if (getpeer)
2369 mutex_exit(&tp->tim_mutex);
2371 tilog("ti_doname: allocb failed no recovery attempt\n",
2374 freemsg(csp->cp_private);
2375 miocnak(q, mp, 0, EAGAIN);
2376 ret = DONAME_FAIL;
2377 break;
2379 bp->b_wptr += STRUCT_FGET(sb, len);
2380 if (getpeer) {
2381 bcopy(tp->tim_peername, bp->b_rptr,
2382 STRUCT_FGET(sb, len));
2383 mutex_exit(&tp->tim_mutex);
2384 } else {
2385 bcopy(tp->tim_myname, bp->b_rptr, STRUCT_FGET(sb, len));
2387 cqp->cq_addr = (caddr_t)STRUCT_FGETP(sb, buf);
2388 cqp->cq_size = STRUCT_FGET(sb, len);
2389 cqp->cq_flag = 0;
2390 mp->b_datap->db_type = M_COPYOUT;
2391 mp->b_cont = bp;
2392 STRUCT_FSET(sb, len, 0); /* copy the strbuf next time around */
2393 qreply(q, mp);
2394 ret = DONAME_CONT;
2395 break;
2397 default:
2398 tilog("ti_doname: freeing bad message type = %d\n",
2399 mp->b_datap->db_type);
2400 freemsg(mp);
2401 ret = DONAME_FAIL;
2402 break;
2404 return (ret);
2409 * Fill in the address of a connectionless data packet if a connect
2410 * had been done on this endpoint.
2412 static mblk_t *
2413 tim_filladdr(queue_t *q, mblk_t *mp, boolean_t dorecover)
2415 mblk_t *bp;
2416 struct tim_tim *tp;
2417 struct T_unitdata_req *up;
2418 struct T_unitdata_req *nup;
2419 size_t plen;
2421 tp = (struct tim_tim *)q->q_ptr;
2422 if (mp->b_datap->db_type == M_DATA) {
2423 mutex_enter(&tp->tim_mutex);
2424 bp = allocb(sizeof (struct T_unitdata_req) + tp->tim_peerlen,
2425 BPRI_MED);
2426 if (bp != NULL) {
2427 bp->b_datap->db_type = M_PROTO;
2428 up = (struct T_unitdata_req *)bp->b_rptr;
2429 up->PRIM_type = T_UNITDATA_REQ;
2430 up->DEST_length = tp->tim_peerlen;
2431 bp->b_wptr += sizeof (struct T_unitdata_req);
2432 up->DEST_offset = sizeof (struct T_unitdata_req);
2433 up->OPT_length = 0;
2434 up->OPT_offset = 0;
2435 if (tp->tim_peerlen > 0) {
2436 bcopy(tp->tim_peername, bp->b_wptr,
2437 tp->tim_peerlen);
2438 bp->b_wptr += tp->tim_peerlen;
2440 bp->b_cont = mp;
2442 } else {
2443 ASSERT(mp->b_datap->db_type == M_PROTO);
2444 up = (struct T_unitdata_req *)mp->b_rptr;
2445 ASSERT(up->PRIM_type == T_UNITDATA_REQ);
2446 if (up->DEST_length != 0)
2447 return (mp);
2448 mutex_enter(&tp->tim_mutex);
2449 bp = allocb(sizeof (struct T_unitdata_req) + up->OPT_length +
2450 tp->tim_peerlen, BPRI_MED);
2451 if (bp != NULL) {
2452 bp->b_datap->db_type = M_PROTO;
2453 nup = (struct T_unitdata_req *)bp->b_rptr;
2454 nup->PRIM_type = T_UNITDATA_REQ;
2455 nup->DEST_length = plen = tp->tim_peerlen;
2456 bp->b_wptr += sizeof (struct T_unitdata_req);
2457 nup->DEST_offset = sizeof (struct T_unitdata_req);
2458 if (plen > 0) {
2459 bcopy(tp->tim_peername, bp->b_wptr, plen);
2460 bp->b_wptr += plen;
2462 mutex_exit(&tp->tim_mutex);
2463 if (up->OPT_length == 0) {
2464 nup->OPT_length = 0;
2465 nup->OPT_offset = 0;
2466 } else {
2467 nup->OPT_length = up->OPT_length;
2468 nup->OPT_offset =
2469 sizeof (struct T_unitdata_req) + plen;
2470 bcopy((mp->b_wptr + up->OPT_offset), bp->b_wptr,
2471 up->OPT_length);
2472 bp->b_wptr += up->OPT_length;
2474 bp->b_cont = mp->b_cont;
2475 mp->b_cont = NULL;
2476 freeb(mp);
2477 return (bp);
2480 ASSERT(MUTEX_HELD(&tp->tim_mutex));
2481 if (bp == NULL && dorecover) {
2482 tim_recover(q, mp,
2483 sizeof (struct T_unitdata_req) + tp->tim_peerlen);
2485 mutex_exit(&tp->tim_mutex);
2486 return (bp);
2489 static void
2490 tim_addlink(struct tim_tim *tp)
2492 struct tim_tim **tpp;
2493 struct tim_tim *next;
2495 tpp = &tim_hash[TIM_HASH(tp->tim_acceptor)];
2496 rw_enter(&tim_list_rwlock, RW_WRITER);
2498 if ((next = *tpp) != NULL)
2499 next->tim_ptpn = &tp->tim_next;
2500 tp->tim_next = next;
2501 tp->tim_ptpn = tpp;
2502 *tpp = tp;
2504 tim_cnt++;
2506 rw_exit(&tim_list_rwlock);
2509 static void
2510 tim_dellink(struct tim_tim *tp)
2512 struct tim_tim *next;
2514 rw_enter(&tim_list_rwlock, RW_WRITER);
2516 if ((next = tp->tim_next) != NULL)
2517 next->tim_ptpn = tp->tim_ptpn;
2518 *(tp->tim_ptpn) = next;
2520 tim_cnt--;
2522 rw_exit(&tim_list_rwlock);
2525 static struct tim_tim *
2526 tim_findlink(t_uscalar_t id)
2528 struct tim_tim *tp;
2530 ASSERT(rw_lock_held(&tim_list_rwlock));
2532 for (tp = tim_hash[TIM_HASH(id)]; tp != NULL; tp = tp->tim_next) {
2533 if (tp->tim_acceptor == id) {
2534 break;
2537 return (tp);
2540 static void
2541 tim_recover(queue_t *q, mblk_t *mp, t_scalar_t size)
2543 struct tim_tim *tp;
2544 bufcall_id_t bid;
2545 timeout_id_t tid;
2547 tp = (struct tim_tim *)q->q_ptr;
2550 * Avoid re-enabling the queue.
2552 if (mp->b_datap->db_type == M_PCPROTO)
2553 mp->b_datap->db_type = M_PROTO;
2554 noenable(q);
2555 (void) putbq(q, mp);
2558 * Make sure there is at most one outstanding request per queue.
2560 if (q->q_flag & QREADR) {
2561 if (tp->tim_rtimoutid || tp->tim_rbufcid)
2562 return;
2563 } else {
2564 if (tp->tim_wtimoutid || tp->tim_wbufcid)
2565 return;
2567 if (!(bid = qbufcall(RD(q), (size_t)size, BPRI_MED, tim_buffer, q))) {
2568 tid = qtimeout(RD(q), tim_timer, q, TIMWAIT);
2569 if (q->q_flag & QREADR)
2570 tp->tim_rtimoutid = tid;
2571 else
2572 tp->tim_wtimoutid = tid;
2573 } else {
2574 if (q->q_flag & QREADR)
2575 tp->tim_rbufcid = bid;
2576 else
2577 tp->tim_wbufcid = bid;
2582 * Timod is waiting on a downstream ioctl reply, come back soon
2583 * to reschedule the write side service routine, which will check
2584 * if the ioctl is done and another can proceed.
2586 static void
2587 tim_ioctl_retry(queue_t *q)
2589 struct tim_tim *tp;
2591 tp = (struct tim_tim *)q->q_ptr;
2594 * Make sure there is at most one outstanding request per wqueue.
2596 if (tp->tim_wtimoutid || tp->tim_wbufcid)
2597 return;
2599 tp->tim_wtimoutid = qtimeout(RD(q), tim_timer, q, TIMIOCWAIT);
2603 * Inspect the data on read queues starting from read queues passed as
2604 * paramter (timod read queue) and traverse until
2605 * q_next is NULL (stream head). Look for a TPI T_EXDATA_IND message
2606 * reutrn 1 if found, 0 if not found.
2608 static int
2609 ti_expind_on_rdqueues(queue_t *rq)
2611 mblk_t *bp;
2612 queue_t *q;
2614 q = rq;
2616 * We are going to walk q_next, so protect stream from plumbing
2617 * changes.
2619 claimstr(q);
2620 do {
2622 * Hold QLOCK while referencing data on queues
2624 mutex_enter(QLOCK(rq));
2625 bp = rq->q_first;
2626 while (bp != NULL) {
2628 * Walk the messages on the queue looking
2629 * for a possible T_EXDATA_IND
2631 if ((bp->b_datap->db_type == M_PROTO) &&
2632 ((bp->b_wptr - bp->b_rptr) >=
2633 sizeof (struct T_exdata_ind)) &&
2634 (((struct T_exdata_ind *)bp->b_rptr)->PRIM_type
2635 == T_EXDATA_IND)) {
2636 /* bp is T_EXDATA_IND */
2637 mutex_exit(QLOCK(rq));
2638 releasestr(q); /* decrement sd_refcnt */
2639 return (1); /* expdata is on a read queue */
2641 bp = bp->b_next; /* next message */
2643 mutex_exit(QLOCK(rq));
2644 rq = rq->q_next; /* next upstream queue */
2645 } while (rq != NULL);
2646 releasestr(q);
2647 return (0); /* no expdata on read queues */
2650 static void
2651 tim_tcap_timer(void *q_ptr)
2653 queue_t *q = (queue_t *)q_ptr;
2654 struct tim_tim *tp = (struct tim_tim *)q->q_ptr;
2656 ASSERT(tp != NULL && tp->tim_tcap_timoutid != 0);
2657 ASSERT((tp->tim_flags & TI_CAP_RECVD) != 0);
2659 tp->tim_tcap_timoutid = 0;
2660 TILOG("tim_tcap_timer: fired\n", 0);
2661 tim_tcap_genreply(q, tp);
2665 * tim_tcap_genreply() is called either from timeout routine or when
2666 * T_ERROR_ACK is received. In both cases it means that underlying
2667 * transport doesn't provide T_CAPABILITY_REQ.
2669 static void
2670 tim_tcap_genreply(queue_t *q, struct tim_tim *tp)
2672 mblk_t *mp = tp->tim_iocsave;
2673 struct iocblk *iocbp;
2675 TILOG("timodrproc: tim_tcap_genreply\n", 0);
2677 ASSERT(tp == (struct tim_tim *)q->q_ptr);
2678 ASSERT(mp != NULL);
2680 iocbp = (struct iocblk *)mp->b_rptr;
2681 ASSERT(iocbp != NULL);
2682 ASSERT(MBLKL(mp) == sizeof (struct iocblk));
2683 ASSERT(iocbp->ioc_cmd == TI_CAPABILITY);
2684 ASSERT(mp->b_cont == NULL);
2686 /* Save this information permanently in the module */
2687 PI_PROVLOCK(tp->tim_provinfo);
2688 if (tp->tim_provinfo->tpi_capability == PI_DONTKNOW)
2689 tp->tim_provinfo->tpi_capability = PI_NO;
2690 PI_PROVUNLOCK(tp->tim_provinfo);
2692 if (tp->tim_tcap_timoutid != 0) {
2693 (void) quntimeout(q, tp->tim_tcap_timoutid);
2694 tp->tim_tcap_timoutid = 0;
2697 if ((tp->tim_flags & CAP_WANTS_INFO) != 0) {
2698 /* Send T_INFO_REQ down */
2699 mblk_t *tirmp = tpi_ack_alloc(NULL,
2700 sizeof (struct T_info_req), M_PCPROTO, T_INFO_REQ);
2702 if (tirmp != NULL) {
2703 /* Emulate TC1_INFO */
2704 TILOG("emulate_tcap_ioc_req: sending T_INFO_REQ\n", 0);
2705 tp->tim_flags |= WAIT_IOCINFOACK;
2706 putnext(WR(q), tirmp);
2707 } else {
2708 tilog("emulate_tcap_req: allocb fail, "
2709 "no recovery attmpt\n", 0);
2710 tp->tim_iocsave = NULL;
2711 tp->tim_saved_prim = -1;
2712 tp->tim_flags &= ~(TI_CAP_RECVD | WAITIOCACK |
2713 CAP_WANTS_INFO | WAIT_IOCINFOACK);
2714 miocnak(q, mp, 0, ENOMEM);
2716 } else {
2717 /* Reply immediately */
2718 mblk_t *ackmp = tpi_ack_alloc(NULL,
2719 sizeof (struct T_capability_ack), M_PCPROTO,
2720 T_CAPABILITY_ACK);
2722 mp->b_cont = ackmp;
2724 if (ackmp != NULL) {
2725 ((struct T_capability_ack *)
2726 ackmp->b_rptr)->CAP_bits1 = 0;
2727 tim_ioctl_send_reply(q, mp, ackmp);
2728 tp->tim_iocsave = NULL;
2729 tp->tim_saved_prim = -1;
2730 tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
2731 TI_CAP_RECVD | CAP_WANTS_INFO);
2732 } else {
2733 tilog("timodwproc:allocb failed no "
2734 "recovery attempt\n", 0);
2735 tp->tim_iocsave = NULL;
2736 tp->tim_saved_prim = -1;
2737 tp->tim_flags &= ~(TI_CAP_RECVD | WAITIOCACK |
2738 CAP_WANTS_INFO | WAIT_IOCINFOACK);
2739 miocnak(q, mp, 0, ENOMEM);
2745 static void
2746 tim_ioctl_send_reply(queue_t *q, mblk_t *ioc_mp, mblk_t *mp)
2748 struct iocblk *iocbp;
2750 ASSERT(q != NULL && ioc_mp != NULL);
2752 ioc_mp->b_datap->db_type = M_IOCACK;
2753 if (mp != NULL)
2754 mp->b_datap->db_type = M_DATA;
2756 if (ioc_mp->b_cont != mp) {
2757 /* It is safe to call freemsg for NULL pointers */
2758 freemsg(ioc_mp->b_cont);
2759 ioc_mp->b_cont = mp;
2761 iocbp = (struct iocblk *)ioc_mp->b_rptr;
2762 iocbp->ioc_error = 0;
2763 iocbp->ioc_rval = 0;
2765 * All ioctl's may return more data than was specified by
2766 * count arg. For TI_CAPABILITY count is treated as maximum data size.
2768 if (mp == NULL)
2769 iocbp->ioc_count = 0;
2770 else if (iocbp->ioc_cmd != TI_CAPABILITY)
2771 iocbp->ioc_count = msgsize(mp);
2772 else {
2773 iocbp->ioc_count = MIN(MBLKL(mp), iocbp->ioc_count);
2774 /* Truncate message if too large */
2775 mp->b_wptr = mp->b_rptr + iocbp->ioc_count;
2778 TILOG("iosendreply: ioc_cmd = %d, ", iocbp->ioc_cmd);
2779 putnext(RD(q), ioc_mp);
2783 * Send M_IOCACK for errors.
2785 static void
2786 tim_send_ioc_error_ack(queue_t *q, struct tim_tim *tp, mblk_t *mp)
2788 struct T_error_ack *tea = (struct T_error_ack *)mp->b_rptr;
2789 t_scalar_t error_prim;
2791 mp->b_wptr = mp->b_rptr + sizeof (struct T_error_ack);
2792 ASSERT(mp->b_wptr <= mp->b_datap->db_lim);
2793 error_prim = tea->ERROR_prim;
2795 ASSERT(tp->tim_iocsave != NULL);
2796 ASSERT(tp->tim_iocsave->b_cont != mp);
2798 /* Always send this to the read side of the queue */
2799 q = RD(q);
2801 TILOG("tim_send_ioc_error_ack: prim = %d\n", tp->tim_saved_prim);
2803 if (tp->tim_saved_prim != error_prim) {
2804 putnext(q, mp);
2805 } else if (error_prim == T_CAPABILITY_REQ) {
2806 TILOG("timodrproc: T_ERROR_ACK/T_CAPABILITY_REQ\n", 0);
2807 ASSERT(tp->tim_iocsave->b_cont == NULL);
2809 tim_tcap_genreply(q, tp);
2810 freemsg(mp);
2811 } else {
2812 struct iocblk *iocbp = (struct iocblk *)tp->tim_iocsave->b_rptr;
2814 TILOG("tim_send_ioc_error_ack: T_ERROR_ACK: prim %d\n",
2815 error_prim);
2816 ASSERT(tp->tim_iocsave->b_cont == NULL);
2818 switch (error_prim) {
2819 default:
2820 TILOG("timodrproc: Unknown T_ERROR_ACK: tlierror %d\n",
2821 tea->TLI_error);
2823 putnext(q, mp);
2824 break;
2826 case T_INFO_REQ:
2827 case T_SVR4_OPTMGMT_REQ:
2828 case T_OPTMGMT_REQ:
2829 case O_T_BIND_REQ:
2830 case T_BIND_REQ:
2831 case T_UNBIND_REQ:
2832 case T_ADDR_REQ:
2833 case T_CAPABILITY_REQ:
2835 TILOG("ioc_err_ack: T_ERROR_ACK: tlierror %x\n",
2836 tea->TLI_error);
2838 /* get saved ioctl msg and set values */
2839 iocbp->ioc_count = 0;
2840 iocbp->ioc_error = 0;
2841 iocbp->ioc_rval = tea->TLI_error;
2842 if (iocbp->ioc_rval == TSYSERR)
2843 iocbp->ioc_rval |= tea->UNIX_error << 8;
2844 tp->tim_iocsave->b_datap->db_type = M_IOCACK;
2845 freemsg(mp);
2846 putnext(q, tp->tim_iocsave);
2847 tp->tim_iocsave = NULL;
2848 tp->tim_saved_prim = -1;
2849 tp->tim_flags &= ~(WAITIOCACK | TI_CAP_RECVD |
2850 CAP_WANTS_INFO | WAIT_IOCINFOACK);
2851 break;
2857 * Send reply to a usual message or ioctl message upstream.
2858 * Should be called from the read side only.
2860 static void
2861 tim_send_reply(queue_t *q, mblk_t *mp, struct tim_tim *tp, t_scalar_t prim)
2863 ASSERT(mp != NULL && q != NULL && tp != NULL);
2864 ASSERT(q == RD(q));
2866 /* Restore db_type - recover() might have changed it */
2867 mp->b_datap->db_type = M_PCPROTO;
2869 if (((tp->tim_flags & WAITIOCACK) == 0) || (tp->tim_saved_prim != prim))
2870 putnext(q, mp);
2871 else {
2872 ASSERT(tp->tim_iocsave != NULL);
2873 tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
2874 tp->tim_iocsave = NULL;
2875 tp->tim_saved_prim = -1;
2876 tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
2877 TI_CAP_RECVD | CAP_WANTS_INFO);
2882 * Reply to TI_SYNC reequest without sending anything downstream.
2884 static void
2885 tim_answer_ti_sync(queue_t *q, mblk_t *mp, struct tim_tim *tp,
2886 mblk_t *ackmp, uint32_t tsr_flags)
2888 struct ti_sync_ack *tsap;
2890 ASSERT(q != NULL && q == WR(q) && ackmp != NULL);
2892 tsap = (struct ti_sync_ack *)ackmp->b_rptr;
2893 bzero(tsap, sizeof (struct ti_sync_ack));
2894 ackmp->b_wptr = ackmp->b_rptr + sizeof (struct ti_sync_ack);
2896 if (tsr_flags == 0 ||
2897 (tsr_flags & ~(TSRF_QLEN_REQ | TSRF_IS_EXP_IN_RCVBUF)) != 0) {
2899 * unsupported/bad flag setting
2900 * or no flag set.
2902 TILOG("timodwproc: unsupported/bad flag setting %x\n",
2903 tsr_flags);
2904 freemsg(ackmp);
2905 miocnak(q, mp, 0, EINVAL);
2906 return;
2909 if ((tsr_flags & TSRF_QLEN_REQ) != 0)
2910 tsap->tsa_qlen = tp->tim_backlog;
2912 if ((tsr_flags & TSRF_IS_EXP_IN_RCVBUF) != 0 &&
2913 ti_expind_on_rdqueues(RD(q))) {
2915 * Expedited data is queued on
2916 * the stream read side
2918 tsap->tsa_flags |= TSAF_EXP_QUEUED;
2921 tim_ioctl_send_reply(q, mp, ackmp);
2922 tp->tim_iocsave = NULL;
2923 tp->tim_saved_prim = -1;
2924 tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
2925 TI_CAP_RECVD | CAP_WANTS_INFO);
2929 * Send TPI message from IOCTL message, ssave original ioctl header and TPI
2930 * message type. Should be called from write side only.
2932 static void
2933 tim_send_ioctl_tpi_msg(queue_t *q, mblk_t *mp, struct tim_tim *tp,
2934 struct iocblk *iocb)
2936 mblk_t *tmp;
2937 int ioc_cmd = iocb->ioc_cmd;
2939 ASSERT(q != NULL && mp != NULL && tp != NULL);
2940 ASSERT(q == WR(q));
2941 ASSERT(mp->b_cont != NULL);
2943 tp->tim_iocsave = mp;
2944 tmp = mp->b_cont;
2946 mp->b_cont = NULL;
2947 tp->tim_flags |= WAITIOCACK;
2948 tp->tim_saved_prim = ((union T_primitives *)tmp->b_rptr)->type;
2951 * For TI_GETINFO, the attached message is a T_INFO_REQ
2952 * For TI_SYNC, we generate the T_INFO_REQ message above
2953 * For TI_CAPABILITY the attached message is either
2954 * T_CAPABILITY_REQ or T_INFO_REQ.
2955 * Among TPI request messages possible,
2956 * T_INFO_REQ/T_CAPABILITY_ACK messages are a M_PCPROTO, rest
2957 * are M_PROTO
2959 if (ioc_cmd == TI_GETINFO || ioc_cmd == TI_SYNC ||
2960 ioc_cmd == TI_CAPABILITY) {
2961 tmp->b_datap->db_type = M_PCPROTO;
2962 } else {
2963 tmp->b_datap->db_type = M_PROTO;
2966 /* Verify credentials in STREAM */
2967 ASSERT(iocb->ioc_cr == NULL || iocb->ioc_cr == DB_CRED(tmp));
2969 ASSERT(DB_CRED(tmp) != NULL);
2971 TILOG("timodwproc: sending down %d\n", tp->tim_saved_prim);
2972 putnext(q, tmp);
2975 static void
2976 tim_clear_peer(struct tim_tim *tp)
2978 mutex_enter(&tp->tim_mutex);
2979 if (tp->tim_peercred != NULL) {
2980 crfree(tp->tim_peercred);
2981 tp->tim_peercred = NULL;
2983 tp->tim_peerlen = 0;
2984 mutex_exit(&tp->tim_mutex);