6324 Add an `ndp' tool for manipulating the neighbors table
[illumos-gate.git] / usr / src / uts / common / io / timod.c
blob57817c2f79d17a8b4244c24b446bba10a5ba16e3
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>
52 #include <c2/audit.h>
55 * This is the loadable module wrapper.
57 #include <sys/conf.h>
58 #include <sys/modctl.h>
60 static struct streamtab timinfo;
62 static struct fmodsw fsw = {
63 "timod",
64 &timinfo,
65 D_MTQPAIR | D_MP,
69 * Module linkage information for the kernel.
72 static struct modlstrmod modlstrmod = {
73 &mod_strmodops, "transport interface str mod", &fsw
76 static struct modlinkage modlinkage = {
77 MODREV_1, &modlstrmod, NULL
80 static krwlock_t tim_list_rwlock;
83 * This module keeps track of capabilities of underlying transport. Information
84 * is persistent through module invocations (open/close). Currently it remembers
85 * whether underlying transport supports TI_GET{MY,PEER}NAME ioctls and
86 * T_CAPABILITY_REQ message. This module either passes ioctl/messages to the
87 * transport or emulates it when transport doesn't understand these
88 * ioctl/messages.
90 * It is assumed that transport supports T_CAPABILITY_REQ when timod receives
91 * T_CAPABILITY_ACK from the transport. There is no current standard describing
92 * transport behaviour when it receives unknown message type, so following
93 * reactions are expected and handled:
95 * 1) Transport drops unknown T_CAPABILITY_REQ message type. In this case timod
96 * will wait for tcap_wait time and assume that transport doesn't provide
97 * this message type. T_CAPABILITY_REQ should never travel over the wire, so
98 * timeout value should only take into consideration internal processing time
99 * for the message. From user standpoint it may mean that an application will
100 * hang for TCAP_WAIT time in the kernel the first time this message is used
101 * with some particular transport (e.g. TCP/IP) during system uptime.
103 * 2) Transport responds with T_ERROR_ACK specifying T_CAPABILITY_REQ as
104 * original message type. In this case it is assumed that transport doesn't
105 * support it (which may not always be true - some transports return
106 * T_ERROR_ACK in other cases like lack of system memory).
108 * 3) Transport responds with M_ERROR, effectively shutting down the
109 * stream. Unfortunately there is no standard way to pass the reason of
110 * M_ERROR message back to the caller, so it is assumed that if M_ERROR was
111 * sent in response to T_CAPABILITY_REQ message, transport doesn't support
112 * it.
114 * It is possible under certain circumstances that timod will incorrectly assume
115 * that underlying transport doesn't provide T_CAPABILITY_REQ message type. In
116 * this "worst-case" scenario timod will emulate its functionality by itself and
117 * will provide only TC1_INFO capability. All other bits in CAP_bits1 field are
118 * cleaned. TC1_INFO is emulated by sending T_INFO_REQ down to transport
119 * provider.
123 * Notes about locking:
125 * tim_list_rwlock protects the list of tim_tim structures itself. When this
126 * lock is held, the list itself is stable, but the contents of the entries
127 * themselves might not be.
129 * The rest of the members are generally protected by D_MTQPAIR, which
130 * specifies a default exclusive inner perimeter. If you're looking at
131 * q->q_ptr, then it's stable.
133 * There's one exception to this rule: tim_peer{maxlen,len,name}. These members
134 * are touched without entering the associated STREAMS perimeter because we
135 * get the pointer via tim_findlink() rather than q_ptr. These are protected
136 * by tim_mutex instead. If you don't hold that lock, don't look at them.
138 * (It would be possible to separate out the 'set by T_CONN_RES' cases from the
139 * others, but there appears to be no reason to do so.)
141 struct tim_tim {
142 uint32_t tim_flags;
143 t_uscalar_t tim_backlog;
144 mblk_t *tim_iocsave;
145 t_scalar_t tim_mymaxlen;
146 t_scalar_t tim_mylen;
147 caddr_t tim_myname;
148 t_scalar_t tim_peermaxlen;
149 t_scalar_t tim_peerlen;
150 caddr_t tim_peername;
151 cred_t *tim_peercred;
152 mblk_t *tim_consave;
153 bufcall_id_t tim_wbufcid;
154 bufcall_id_t tim_rbufcid;
155 timeout_id_t tim_wtimoutid;
156 timeout_id_t tim_rtimoutid;
157 /* Protected by the global tim_list_rwlock for all instances */
158 struct tim_tim *tim_next;
159 struct tim_tim **tim_ptpn;
160 t_uscalar_t tim_acceptor;
161 t_scalar_t tim_saved_prim; /* Primitive from message */
162 /* part of ioctl. */
163 timeout_id_t tim_tcap_timoutid; /* For T_CAP_REQ timeout */
164 tpi_provinfo_t *tim_provinfo; /* Transport description */
165 kmutex_t tim_mutex; /* protect tim_peer* */
166 pid_t tim_cpid;
171 * Local flags used with tim_flags field in instance structure of
172 * type 'struct _ti_user' declared above.
173 * Historical note:
174 * This namespace constants were previously declared in a
175 * a very messed up namespace in timod.h
177 * There may be 3 states for transport:
179 * 1) It provides T_CAPABILITY_REQ
180 * 2) It does not provide T_CAPABILITY_REQ
181 * 3) It is not known yet whether transport provides T_CAPABILITY_REQ or not.
183 * It is assumed that the underlying transport either provides
184 * T_CAPABILITY_REQ or not and this does not changes during the
185 * system lifetime.
188 #define PEEK_RDQ_EXPIND 0x0001 /* look for expinds on stream rd queues */
189 #define WAITIOCACK 0x0002 /* waiting for info for ioctl act */
190 #define CLTS 0x0004 /* connectionless transport */
191 #define COTS 0x0008 /* connection-oriented transport */
192 #define CONNWAIT 0x0010 /* waiting for connect confirmation */
193 #define LOCORDREL 0x0020 /* local end has orderly released */
194 #define REMORDREL 0x0040 /* remote end had orderly released */
195 #define NAMEPROC 0x0080 /* processing a NAME ioctl */
196 #define DO_MYNAME 0x0100 /* timod handles TI_GETMYNAME */
197 #define DO_PEERNAME 0x0200 /* timod handles TI_GETPEERNAME */
198 #define TI_CAP_RECVD 0x0400 /* TI_CAPABILITY received */
199 #define CAP_WANTS_INFO 0x0800 /* TI_CAPABILITY has TC1_INFO set */
200 #define WAIT_IOCINFOACK 0x1000 /* T_INFO_REQ generated from ioctl */
201 #define WAIT_CONNRESACK 0x2000 /* waiting for T_OK_ACK to T_CONN_RES */
204 /* Debugging facilities */
206 * Logging needed for debugging timod should only appear in DEBUG kernel.
208 #ifdef DEBUG
209 #define TILOG(msg, arg) tilog((msg), (arg))
210 #define TILOGP(msg, arg) tilogp((msg), (arg))
211 #else
212 #define TILOG(msg, arg)
213 #define TILOGP(msg, arg)
214 #endif
218 * Sleep timeout for T_CAPABILITY_REQ. This message never travels across
219 * network, so timeout value should be enough to cover all internal processing
220 * time.
222 clock_t tim_tcap_wait = 2;
224 /* Sleep timeout in tim_recover() */
225 #define TIMWAIT (1*hz)
226 /* Sleep timeout in tim_ioctl_retry() 0.2 seconds */
227 #define TIMIOCWAIT (200*hz/1000)
230 * Return values for ti_doname().
232 #define DONAME_FAIL 0 /* failing ioctl (done) */
233 #define DONAME_DONE 1 /* done processing */
234 #define DONAME_CONT 2 /* continue proceesing (not done yet) */
237 * Function prototypes
239 static int ti_doname(queue_t *, mblk_t *);
240 static int ti_expind_on_rdqueues(queue_t *);
241 static void tim_ioctl_send_reply(queue_t *, mblk_t *, mblk_t *);
242 static void tim_send_ioc_error_ack(queue_t *, struct tim_tim *, mblk_t *);
243 static void tim_tcap_timer(void *);
244 static void tim_tcap_genreply(queue_t *, struct tim_tim *);
245 static void tim_send_reply(queue_t *, mblk_t *, struct tim_tim *, t_scalar_t);
246 static void tim_answer_ti_sync(queue_t *, mblk_t *, struct tim_tim *,
247 mblk_t *, uint32_t);
248 static void tim_send_ioctl_tpi_msg(queue_t *, mblk_t *, struct tim_tim *,
249 struct iocblk *);
250 static void tim_clear_peer(struct tim_tim *);
253 _init(void)
255 int error;
257 rw_init(&tim_list_rwlock, NULL, RW_DRIVER, NULL);
258 error = mod_install(&modlinkage);
259 if (error != 0) {
260 rw_destroy(&tim_list_rwlock);
261 return (error);
264 return (0);
268 _fini(void)
270 int error;
272 error = mod_remove(&modlinkage);
273 if (error != 0)
274 return (error);
275 rw_destroy(&tim_list_rwlock);
276 return (0);
280 _info(struct modinfo *modinfop)
282 return (mod_info(&modlinkage, modinfop));
287 * Hash list for all instances. Used to find tim_tim structure based on
288 * ACCEPTOR_id in T_CONN_RES. Protected by tim_list_rwlock.
290 #define TIM_HASH_SIZE 256
291 #ifdef _ILP32
292 #define TIM_HASH(id) (((uintptr_t)(id) >> 8) % TIM_HASH_SIZE)
293 #else
294 #define TIM_HASH(id) ((uintptr_t)(id) % TIM_HASH_SIZE)
295 #endif /* _ILP32 */
296 static struct tim_tim *tim_hash[TIM_HASH_SIZE];
297 int tim_cnt = 0;
299 static void tilog(char *, t_scalar_t);
300 static void tilogp(char *, uintptr_t);
301 static mblk_t *tim_filladdr(queue_t *, mblk_t *, boolean_t);
302 static void tim_addlink(struct tim_tim *);
303 static void tim_dellink(struct tim_tim *);
304 static struct tim_tim *tim_findlink(t_uscalar_t);
305 static void tim_recover(queue_t *, mblk_t *, t_scalar_t);
306 static void tim_ioctl_retry(queue_t *);
308 int dotilog = 0;
310 #define TIMOD_ID 3
312 static int timodopen(queue_t *, dev_t *, int, int, cred_t *);
313 static int timodclose(queue_t *, int, cred_t *);
314 static void timodwput(queue_t *, mblk_t *);
315 static void timodrput(queue_t *, mblk_t *);
316 static void timodrsrv(queue_t *);
317 static void timodwsrv(queue_t *);
318 static int timodrproc(queue_t *, mblk_t *);
319 static int timodwproc(queue_t *, mblk_t *);
321 /* stream data structure definitions */
323 static struct module_info timod_info =
324 {TIMOD_ID, "timod", 0, INFPSZ, 512, 128};
325 static struct qinit timodrinit = {
326 (int (*)())timodrput,
327 (int (*)())timodrsrv,
328 timodopen,
329 timodclose,
330 nulldev,
331 &timod_info,
332 NULL
334 static struct qinit timodwinit = {
335 (int (*)())timodwput,
336 (int (*)())timodwsrv,
337 timodopen,
338 timodclose,
339 nulldev,
340 &timod_info,
341 NULL
343 static struct streamtab timinfo = { &timodrinit, &timodwinit, NULL, NULL };
346 * timodopen - open routine gets called when the module gets pushed
347 * onto the stream.
349 /*ARGSUSED*/
350 static int
351 timodopen(
352 queue_t *q,
353 dev_t *devp,
354 int flag,
355 int sflag,
356 cred_t *crp)
358 struct tim_tim *tp;
359 struct stroptions *sop;
360 mblk_t *bp;
362 ASSERT(q != NULL);
364 if (q->q_ptr) {
365 return (0);
368 if ((bp = allocb(sizeof (struct stroptions), BPRI_MED)) == 0)
369 return (ENOMEM);
371 tp = kmem_zalloc(sizeof (struct tim_tim), KM_SLEEP);
373 tp->tim_cpid = -1;
374 tp->tim_saved_prim = -1;
376 mutex_init(&tp->tim_mutex, NULL, MUTEX_DEFAULT, NULL);
378 q->q_ptr = (caddr_t)tp;
379 WR(q)->q_ptr = (caddr_t)tp;
381 tilogp("timodopen: Allocated for tp %lx\n", (uintptr_t)tp);
382 tilogp("timodopen: Allocated for q %lx\n", (uintptr_t)q);
384 /* Must be done before tpi_findprov and _ILP32 q_next walk below */
385 qprocson(q);
387 tp->tim_provinfo = tpi_findprov(q);
390 * Defer allocation of the buffers for the local address and
391 * the peer's address until we need them.
392 * Assume that timod has to handle getname until we here
393 * an iocack from the transport provider or we know that
394 * transport provider doesn't understand it.
396 if (tp->tim_provinfo->tpi_myname != PI_YES) {
397 TILOG("timodopen: setting DO_MYNAME\n", 0);
398 tp->tim_flags |= DO_MYNAME;
401 if (tp->tim_provinfo->tpi_peername != PI_YES) {
402 TILOG("timodopen: setting DO_PEERNAME\n", 0);
403 tp->tim_flags |= DO_PEERNAME;
406 #ifdef _ILP32
408 queue_t *driverq;
411 * Find my driver's read queue (for T_CONN_RES handling)
413 driverq = WR(q);
414 while (SAMESTR(driverq))
415 driverq = driverq->q_next;
417 tp->tim_acceptor = (t_uscalar_t)RD(driverq);
419 #else
420 tp->tim_acceptor = (t_uscalar_t)getminor(*devp);
421 #endif /* _ILP32 */
424 * Add this one to the list.
426 tim_addlink(tp);
429 * Send M_SETOPTS to stream head to make sure M_PCPROTO messages
430 * are not flushed. This prevents application deadlocks.
432 bp->b_datap->db_type = M_SETOPTS;
433 bp->b_wptr += sizeof (struct stroptions);
434 sop = (struct stroptions *)bp->b_rptr;
435 sop->so_flags = SO_READOPT;
436 sop->so_readopt = RFLUSHPCPROT;
438 putnext(q, bp);
440 return (0);
443 static void
444 tim_timer(void *arg)
446 queue_t *q = arg;
447 struct tim_tim *tp = (struct tim_tim *)q->q_ptr;
449 ASSERT(tp);
451 if (q->q_flag & QREADR) {
452 ASSERT(tp->tim_rtimoutid);
453 tp->tim_rtimoutid = 0;
454 } else {
455 ASSERT(tp->tim_wtimoutid);
456 tp->tim_wtimoutid = 0;
458 enableok(q);
459 qenable(q);
462 static void
463 tim_buffer(void *arg)
465 queue_t *q = arg;
466 struct tim_tim *tp = (struct tim_tim *)q->q_ptr;
468 ASSERT(tp);
470 if (q->q_flag & QREADR) {
471 ASSERT(tp->tim_rbufcid);
472 tp->tim_rbufcid = 0;
473 } else {
474 ASSERT(tp->tim_wbufcid);
475 tp->tim_wbufcid = 0;
477 enableok(q);
478 qenable(q);
482 * timodclose - This routine gets called when the module gets popped
483 * off of the stream.
485 /*ARGSUSED*/
486 static int
487 timodclose(
488 queue_t *q,
489 int flag,
490 cred_t *crp)
492 struct tim_tim *tp;
493 mblk_t *mp;
494 mblk_t *nmp;
496 ASSERT(q != NULL);
498 tp = (struct tim_tim *)q->q_ptr;
499 q->q_ptr = NULL;
501 ASSERT(tp != NULL);
503 tilogp("timodclose: Entered for tp %lx\n", (uintptr_t)tp);
504 tilogp("timodclose: Entered for q %lx\n", (uintptr_t)q);
506 qprocsoff(q);
507 tim_dellink(tp);
510 * Cancel any outstanding bufcall
511 * or timeout requests.
513 if (tp->tim_wbufcid) {
514 qunbufcall(q, tp->tim_wbufcid);
515 tp->tim_wbufcid = 0;
517 if (tp->tim_rbufcid) {
518 qunbufcall(q, tp->tim_rbufcid);
519 tp->tim_rbufcid = 0;
521 if (tp->tim_wtimoutid) {
522 (void) quntimeout(q, tp->tim_wtimoutid);
523 tp->tim_wtimoutid = 0;
525 if (tp->tim_rtimoutid) {
526 (void) quntimeout(q, tp->tim_rtimoutid);
527 tp->tim_rtimoutid = 0;
530 if (tp->tim_tcap_timoutid != 0) {
531 (void) quntimeout(q, tp->tim_tcap_timoutid);
532 tp->tim_tcap_timoutid = 0;
535 if (tp->tim_iocsave != NULL)
536 freemsg(tp->tim_iocsave);
537 mp = tp->tim_consave;
538 while (mp) {
539 nmp = mp->b_next;
540 mp->b_next = NULL;
541 freemsg(mp);
542 mp = nmp;
544 ASSERT(tp->tim_mymaxlen >= 0);
545 if (tp->tim_mymaxlen != 0)
546 kmem_free(tp->tim_myname, (size_t)tp->tim_mymaxlen);
547 ASSERT(tp->tim_peermaxlen >= 0);
548 if (tp->tim_peermaxlen != 0)
549 kmem_free(tp->tim_peername, (size_t)tp->tim_peermaxlen);
551 q->q_ptr = WR(q)->q_ptr = NULL;
553 mutex_destroy(&tp->tim_mutex);
555 if (tp->tim_peercred != NULL)
556 crfree(tp->tim_peercred);
558 kmem_free(tp, sizeof (struct tim_tim));
560 return (0);
564 * timodrput - Module read put procedure. This is called from
565 * the module, driver, or stream head upstream/downstream.
566 * Handles M_FLUSH, M_DATA and some M_PROTO (T_DATA_IND,
567 * and T_UNITDATA_IND) messages. All others are queued to
568 * be handled by the service procedures.
570 static void
571 timodrput(queue_t *q, mblk_t *mp)
573 union T_primitives *pptr;
576 * During flow control and other instances when messages
577 * are on queue, queue up a non high priority message
579 if (q->q_first != 0 && mp->b_datap->db_type < QPCTL) {
580 (void) putq(q, mp);
581 return;
585 * Inline processing of data (to avoid additional procedure call).
586 * Rest is handled in timodrproc.
589 switch (mp->b_datap->db_type) {
590 case M_DATA:
591 if (bcanputnext(q, mp->b_band))
592 putnext(q, mp);
593 else
594 (void) putq(q, mp);
595 break;
596 case M_PROTO:
597 case M_PCPROTO:
598 if (MBLKL(mp) < sizeof (t_scalar_t)) {
599 if (mp->b_datap->db_type == M_PCPROTO ||
600 bcanputnext(q, mp->b_band)) {
601 putnext(q, mp);
602 } else {
603 (void) putq(q, mp);
605 break;
607 pptr = (union T_primitives *)mp->b_rptr;
608 switch (pptr->type) {
609 case T_EXDATA_IND:
610 case T_DATA_IND:
611 case T_UNITDATA_IND:
612 if (bcanputnext(q, mp->b_band))
613 putnext(q, mp);
614 else
615 (void) putq(q, mp);
616 break;
617 default:
618 (void) timodrproc(q, mp);
619 break;
621 break;
622 default:
623 (void) timodrproc(q, mp);
624 break;
629 * timodrsrv - Module read queue service procedure. This is called when
630 * messages are placed on an empty queue, when high priority
631 * messages are placed on the queue, and when flow control
632 * restrictions subside. This code used to be included in a
633 * put procedure, but it was moved to a service procedure
634 * because several points were added where memory allocation
635 * could fail, and there is no reasonable recovery mechanism
636 * from the put procedure.
638 /*ARGSUSED*/
639 static void
640 timodrsrv(queue_t *q)
642 mblk_t *mp;
643 struct tim_tim *tp;
645 ASSERT(q != NULL);
647 tp = (struct tim_tim *)q->q_ptr;
648 if (!tp)
649 return;
651 while ((mp = getq(q)) != NULL) {
652 if (timodrproc(q, mp)) {
654 * timodrproc did a putbq - stop processing
655 * messages.
657 return;
663 * Perform common processing when a T_CAPABILITY_ACK or T_INFO_ACK
664 * arrive. Set the queue properties and adjust the tim_flags according
665 * to the service type.
667 static void
668 timodprocessinfo(queue_t *q, struct tim_tim *tp, struct T_info_ack *tia)
670 TILOG("timodprocessinfo: strqset(%d)\n", tia->TIDU_size);
671 (void) strqset(q, QMAXPSZ, 0, tia->TIDU_size);
672 (void) strqset(OTHERQ(q), QMAXPSZ, 0, tia->TIDU_size);
674 if ((tia->SERV_type == T_COTS) || (tia->SERV_type == T_COTS_ORD))
675 tp->tim_flags = (tp->tim_flags & ~CLTS) | COTS;
676 else if (tia->SERV_type == T_CLTS)
677 tp->tim_flags = (tp->tim_flags & ~COTS) | CLTS;
680 static int
681 timodrproc(queue_t *q, mblk_t *mp)
683 uint32_t auditing = AU_AUDITING();
684 union T_primitives *pptr;
685 struct tim_tim *tp;
686 struct iocblk *iocbp;
687 mblk_t *nbp;
688 size_t blen;
690 tp = (struct tim_tim *)q->q_ptr;
692 switch (mp->b_datap->db_type) {
693 default:
694 putnext(q, mp);
695 break;
697 case M_ERROR:
698 TILOG("timodrproc: Got M_ERROR, flags = %x\n", tp->tim_flags);
700 * There is no specified standard response for driver when it
701 * receives unknown message type and M_ERROR is one
702 * possibility. If we send T_CAPABILITY_REQ down and transport
703 * provider responds with M_ERROR we assume that it doesn't
704 * understand this message type. This assumption may be
705 * sometimes incorrect (transport may reply with M_ERROR for
706 * some other reason) but there is no way for us to distinguish
707 * between different cases. In the worst case timod and everyone
708 * else sharing global transport description with it may end up
709 * emulating T_CAPABILITY_REQ.
713 * Check that we are waiting for T_CAPABILITY_ACK and
714 * T_CAPABILITY_REQ is not implemented by transport or emulated
715 * by timod.
717 if ((tp->tim_provinfo->tpi_capability == PI_DONTKNOW) &&
718 ((tp->tim_flags & TI_CAP_RECVD) != 0)) {
720 * Good chances that this transport doesn't provide
721 * T_CAPABILITY_REQ. Mark this information permanently
722 * for the module + transport combination.
724 PI_PROVLOCK(tp->tim_provinfo);
725 if (tp->tim_provinfo->tpi_capability == PI_DONTKNOW)
726 tp->tim_provinfo->tpi_capability = PI_NO;
727 PI_PROVUNLOCK(tp->tim_provinfo);
728 if (tp->tim_tcap_timoutid != 0) {
729 (void) quntimeout(q, tp->tim_tcap_timoutid);
730 tp->tim_tcap_timoutid = 0;
733 putnext(q, mp);
734 break;
735 case M_DATA:
736 if (!bcanputnext(q, mp->b_band)) {
737 (void) putbq(q, mp);
738 return (1);
740 putnext(q, mp);
741 break;
743 case M_PROTO:
744 case M_PCPROTO:
745 blen = MBLKL(mp);
746 if (blen < sizeof (t_scalar_t)) {
748 * Note: it's not actually possible to get
749 * here with db_type M_PCPROTO, because
750 * timodrput has already checked MBLKL, and
751 * thus the assertion below. If the length
752 * was too short, then the message would have
753 * already been putnext'd, and would thus
754 * never appear here. Just the same, the code
755 * below handles the impossible case since
756 * it's easy to do and saves future
757 * maintainers from unfortunate accidents.
759 ASSERT(mp->b_datap->db_type == M_PROTO);
760 if (mp->b_datap->db_type == M_PROTO &&
761 !bcanputnext(q, mp->b_band)) {
762 (void) putbq(q, mp);
763 return (1);
765 putnext(q, mp);
766 break;
769 pptr = (union T_primitives *)mp->b_rptr;
770 switch (pptr->type) {
771 default:
773 if (auditing)
774 audit_sock(T_UNITDATA_IND, q, mp, TIMOD_ID);
775 putnext(q, mp);
776 break;
778 case T_ERROR_ACK:
779 /* Restore db_type - recover() might have changed it */
780 mp->b_datap->db_type = M_PCPROTO;
781 if (blen < sizeof (struct T_error_ack)) {
782 putnext(q, mp);
783 break;
786 tilog("timodrproc: Got T_ERROR_ACK, flags = %x\n",
787 tp->tim_flags);
789 if ((tp->tim_flags & WAIT_CONNRESACK) &&
790 tp->tim_saved_prim == pptr->error_ack.ERROR_prim) {
791 tp->tim_flags &=
792 ~(WAIT_CONNRESACK | WAITIOCACK);
793 freemsg(tp->tim_iocsave);
794 tp->tim_iocsave = NULL;
795 tp->tim_saved_prim = -1;
796 putnext(q, mp);
797 } else if (tp->tim_flags & WAITIOCACK) {
798 tim_send_ioc_error_ack(q, tp, mp);
799 } else {
800 putnext(q, mp);
802 break;
804 case T_OK_ACK:
805 if (blen < sizeof (pptr->ok_ack)) {
806 mp->b_datap->db_type = M_PCPROTO;
807 putnext(q, mp);
808 break;
811 tilog("timodrproc: Got T_OK_ACK\n", 0);
813 if (pptr->ok_ack.CORRECT_prim == T_UNBIND_REQ)
814 tp->tim_mylen = 0;
816 if ((tp->tim_flags & WAIT_CONNRESACK) &&
817 tp->tim_saved_prim == pptr->ok_ack.CORRECT_prim) {
818 struct T_conn_res *resp;
819 struct T_conn_ind *indp;
820 struct tim_tim *ntp;
821 caddr_t ptr;
823 rw_enter(&tim_list_rwlock, RW_READER);
824 resp = (struct T_conn_res *)
825 tp->tim_iocsave->b_rptr;
826 ntp = tim_findlink(resp->ACCEPTOR_id);
827 if (ntp == NULL)
828 goto cresackout;
830 mutex_enter(&ntp->tim_mutex);
831 if (ntp->tim_peercred != NULL)
832 crfree(ntp->tim_peercred);
833 ntp->tim_peercred =
834 msg_getcred(tp->tim_iocsave->b_cont,
835 &ntp->tim_cpid);
836 if (ntp->tim_peercred != NULL)
837 crhold(ntp->tim_peercred);
839 if (!(ntp->tim_flags & DO_PEERNAME)) {
840 mutex_exit(&ntp->tim_mutex);
841 goto cresackout;
844 indp = (struct T_conn_ind *)
845 tp->tim_iocsave->b_cont->b_rptr;
846 /* true as message is put on list */
847 ASSERT(indp->SRC_length >= 0);
849 if (indp->SRC_length > ntp->tim_peermaxlen) {
850 ptr = kmem_alloc(indp->SRC_length,
851 KM_NOSLEEP);
852 if (ptr == NULL) {
853 mutex_exit(&ntp->tim_mutex);
854 rw_exit(&tim_list_rwlock);
855 tilog("timodwproc: kmem_alloc "
856 "failed, attempting "
857 "recovery\n", 0);
858 tim_recover(q, mp,
859 indp->SRC_length);
860 return (1);
862 if (ntp->tim_peermaxlen > 0)
863 kmem_free(ntp->tim_peername,
864 ntp->tim_peermaxlen);
865 ntp->tim_peername = ptr;
866 ntp->tim_peermaxlen = indp->SRC_length;
868 ntp->tim_peerlen = indp->SRC_length;
869 ptr = (caddr_t)indp + indp->SRC_offset;
870 bcopy(ptr, ntp->tim_peername, ntp->tim_peerlen);
872 mutex_exit(&ntp->tim_mutex);
874 cresackout:
875 rw_exit(&tim_list_rwlock);
876 tp->tim_flags &=
877 ~(WAIT_CONNRESACK | WAITIOCACK);
878 freemsg(tp->tim_iocsave);
879 tp->tim_iocsave = NULL;
880 tp->tim_saved_prim = -1;
883 tim_send_reply(q, mp, tp, pptr->ok_ack.CORRECT_prim);
884 break;
886 case T_BIND_ACK: {
887 struct T_bind_ack *ackp =
888 (struct T_bind_ack *)mp->b_rptr;
890 /* Restore db_type - recover() might have changed it */
891 mp->b_datap->db_type = M_PCPROTO;
892 if (blen < sizeof (*ackp)) {
893 putnext(q, mp);
894 break;
897 /* save negotiated backlog */
898 tp->tim_backlog = ackp->CONIND_number;
900 if (((tp->tim_flags & WAITIOCACK) == 0) ||
901 ((tp->tim_saved_prim != O_T_BIND_REQ) &&
902 (tp->tim_saved_prim != T_BIND_REQ))) {
903 putnext(q, mp);
904 break;
906 ASSERT(tp->tim_iocsave != NULL);
908 if (tp->tim_flags & DO_MYNAME) {
909 caddr_t p;
911 if (ackp->ADDR_length < 0 ||
912 mp->b_rptr + ackp->ADDR_offset +
913 ackp->ADDR_length > mp->b_wptr) {
914 putnext(q, mp);
915 break;
917 if (ackp->ADDR_length > tp->tim_mymaxlen) {
918 p = kmem_alloc(ackp->ADDR_length,
919 KM_NOSLEEP);
920 if (p == NULL) {
921 tilog("timodrproc: kmem_alloc "
922 "failed attempt recovery",
925 tim_recover(q, mp,
926 ackp->ADDR_length);
927 return (1);
929 ASSERT(tp->tim_mymaxlen >= 0);
930 if (tp->tim_mymaxlen != NULL) {
931 kmem_free(tp->tim_myname,
932 tp->tim_mymaxlen);
934 tp->tim_myname = p;
935 tp->tim_mymaxlen = ackp->ADDR_length;
937 tp->tim_mylen = ackp->ADDR_length;
938 bcopy(mp->b_rptr + ackp->ADDR_offset,
939 tp->tim_myname, tp->tim_mylen);
941 tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
942 tp->tim_iocsave = NULL;
943 tp->tim_saved_prim = -1;
944 tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
945 TI_CAP_RECVD | CAP_WANTS_INFO);
946 break;
949 case T_OPTMGMT_ACK:
951 tilog("timodrproc: Got T_OPTMGMT_ACK\n", 0);
953 /* Restore db_type - recover() might have change it */
954 mp->b_datap->db_type = M_PCPROTO;
956 if (((tp->tim_flags & WAITIOCACK) == 0) ||
957 ((tp->tim_saved_prim != T_SVR4_OPTMGMT_REQ) &&
958 (tp->tim_saved_prim != T_OPTMGMT_REQ))) {
959 putnext(q, mp);
960 } else {
961 ASSERT(tp->tim_iocsave != NULL);
962 tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
963 tp->tim_iocsave = NULL;
964 tp->tim_saved_prim = -1;
965 tp->tim_flags &= ~(WAITIOCACK |
966 WAIT_IOCINFOACK | TI_CAP_RECVD |
967 CAP_WANTS_INFO);
969 break;
971 case T_INFO_ACK: {
972 struct T_info_ack *tia = (struct T_info_ack *)pptr;
974 /* Restore db_type - recover() might have changed it */
975 mp->b_datap->db_type = M_PCPROTO;
977 if (blen < sizeof (*tia)) {
978 putnext(q, mp);
979 break;
982 tilog("timodrproc: Got T_INFO_ACK, flags = %x\n",
983 tp->tim_flags);
985 timodprocessinfo(q, tp, tia);
987 TILOG("timodrproc: flags = %x\n", tp->tim_flags);
988 if ((tp->tim_flags & WAITIOCACK) != 0) {
989 size_t expected_ack_size;
990 ssize_t deficit;
991 int ioc_cmd;
992 struct T_capability_ack *tcap;
995 * The only case when T_INFO_ACK may be received back
996 * when we are waiting for ioctl to complete is when
997 * this ioctl sent T_INFO_REQ down.
999 if (!(tp->tim_flags & WAIT_IOCINFOACK)) {
1000 putnext(q, mp);
1001 break;
1003 ASSERT(tp->tim_iocsave != NULL);
1005 iocbp = (struct iocblk *)tp->tim_iocsave->b_rptr;
1006 ioc_cmd = iocbp->ioc_cmd;
1009 * Was it sent from TI_CAPABILITY emulation?
1011 if (ioc_cmd == TI_CAPABILITY) {
1012 struct T_info_ack saved_info;
1015 * Perform sanity checks. The only case when we
1016 * send T_INFO_REQ from TI_CAPABILITY is when
1017 * timod emulates T_CAPABILITY_REQ and CAP_bits1
1018 * has TC1_INFO set.
1020 if ((tp->tim_flags &
1021 (TI_CAP_RECVD | CAP_WANTS_INFO)) !=
1022 (TI_CAP_RECVD | CAP_WANTS_INFO)) {
1023 putnext(q, mp);
1024 break;
1027 TILOG("timodrproc: emulating TI_CAPABILITY/"
1028 "info\n", 0);
1030 /* Save info & reuse mp for T_CAPABILITY_ACK */
1031 saved_info = *tia;
1033 mp = tpi_ack_alloc(mp,
1034 sizeof (struct T_capability_ack),
1035 M_PCPROTO, T_CAPABILITY_ACK);
1037 if (mp == NULL) {
1038 tilog("timodrproc: realloc failed, "
1039 "no recovery attempted\n", 0);
1040 return (1);
1044 * Copy T_INFO information into T_CAPABILITY_ACK
1046 tcap = (struct T_capability_ack *)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, tp->tim_iocsave, mp);
1053 tp->tim_iocsave = NULL;
1054 tp->tim_saved_prim = -1;
1055 break;
1059 * The code for TI_SYNC/TI_GETINFO is left here only for
1060 * backward compatibility with staticaly linked old
1061 * applications. New TLI/XTI code should use
1062 * TI_CAPABILITY for getting transport info and should
1063 * not use TI_GETINFO/TI_SYNC for this purpose.
1067 * make sure the message sent back is the size of
1068 * the "expected ack"
1069 * For TI_GETINFO, expected ack size is
1070 * sizeof (T_info_ack)
1071 * For TI_SYNC, expected ack size is
1072 * sizeof (struct ti_sync_ack);
1074 if (ioc_cmd != TI_GETINFO && ioc_cmd != TI_SYNC) {
1075 putnext(q, mp);
1076 break;
1079 expected_ack_size =
1080 sizeof (struct T_info_ack); /* TI_GETINFO */
1081 if (iocbp->ioc_cmd == TI_SYNC) {
1082 expected_ack_size = 2 * sizeof (uint32_t) +
1083 sizeof (struct ti_sync_ack);
1085 deficit = expected_ack_size - blen;
1087 if (deficit != 0) {
1088 if (mp->b_datap->db_lim - mp->b_wptr <
1089 deficit) {
1090 mblk_t *tmp = allocb(expected_ack_size,
1091 BPRI_HI);
1092 if (tmp == NULL) {
1093 ASSERT(MBLKSIZE(mp) >=
1094 sizeof (struct T_error_ack));
1096 tilog("timodrproc: allocb failed no "
1097 "recovery attempt\n", 0);
1099 mp->b_rptr = mp->b_datap->db_base;
1100 pptr = (union T_primitives *)
1101 mp->b_rptr;
1102 pptr->error_ack.ERROR_prim = T_INFO_REQ;
1103 pptr->error_ack.TLI_error = TSYSERR;
1104 pptr->error_ack.UNIX_error = EAGAIN;
1105 pptr->error_ack.PRIM_type = T_ERROR_ACK;
1106 mp->b_datap->db_type = M_PCPROTO;
1107 tim_send_ioc_error_ack(q, tp, mp);
1108 break;
1109 } else {
1110 bcopy(mp->b_rptr, tmp->b_rptr, blen);
1111 tmp->b_wptr += blen;
1112 pptr = (union T_primitives *)
1113 tmp->b_rptr;
1114 freemsg(mp);
1115 mp = tmp;
1120 * We now have "mp" which has enough space for an
1121 * appropriate ack and contains struct T_info_ack
1122 * that the transport provider returned. We now
1123 * stuff it with more stuff to fullfill
1124 * TI_SYNC ioctl needs, as necessary
1126 if (iocbp->ioc_cmd == TI_SYNC) {
1128 * Assumes struct T_info_ack is first embedded
1129 * type in struct ti_sync_ack so it is
1130 * automatically there.
1132 struct ti_sync_ack *tsap =
1133 (struct ti_sync_ack *)mp->b_rptr;
1136 * tsap->tsa_qlen needs to be set only if
1137 * TSRF_QLEN_REQ flag is set, but for
1138 * compatibility with statically linked
1139 * applications it is set here regardless of the
1140 * flag since old XTI library expected it to be
1141 * set.
1143 tsap->tsa_qlen = tp->tim_backlog;
1144 tsap->tsa_flags = 0x0; /* intialize clear */
1145 if (tp->tim_flags & PEEK_RDQ_EXPIND) {
1147 * Request to peek for EXPIND in
1148 * rcvbuf.
1150 if (ti_expind_on_rdqueues(q)) {
1152 * Expedited data is
1153 * queued on the stream
1154 * read side
1156 tsap->tsa_flags |=
1157 TSAF_EXP_QUEUED;
1159 tp->tim_flags &=
1160 ~PEEK_RDQ_EXPIND;
1162 mp->b_wptr += 2*sizeof (uint32_t);
1164 tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
1165 tp->tim_iocsave = NULL;
1166 tp->tim_saved_prim = -1;
1167 tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
1168 TI_CAP_RECVD | CAP_WANTS_INFO);
1169 break;
1173 putnext(q, mp);
1174 break;
1176 case T_ADDR_ACK:
1177 tilog("timodrproc: Got T_ADDR_ACK\n", 0);
1178 tim_send_reply(q, mp, tp, T_ADDR_REQ);
1179 break;
1181 case T_CONN_IND: {
1182 struct T_conn_ind *tcip =
1183 (struct T_conn_ind *)mp->b_rptr;
1185 tilog("timodrproc: Got T_CONN_IND\n", 0);
1187 if (blen >= sizeof (*tcip) &&
1188 MBLKIN(mp, tcip->SRC_offset, tcip->SRC_length)) {
1189 if (((nbp = dupmsg(mp)) != NULL) ||
1190 ((nbp = copymsg(mp)) != NULL)) {
1191 nbp->b_next = tp->tim_consave;
1192 tp->tim_consave = nbp;
1193 } else {
1194 tim_recover(q, mp,
1195 (t_scalar_t)sizeof (mblk_t));
1196 return (1);
1199 if (auditing)
1200 audit_sock(T_CONN_IND, q, mp, TIMOD_ID);
1201 putnext(q, mp);
1202 break;
1205 case T_CONN_CON:
1206 mutex_enter(&tp->tim_mutex);
1207 if (tp->tim_peercred != NULL)
1208 crfree(tp->tim_peercred);
1209 tp->tim_peercred = msg_getcred(mp, &tp->tim_cpid);
1210 if (tp->tim_peercred != NULL)
1211 crhold(tp->tim_peercred);
1212 mutex_exit(&tp->tim_mutex);
1214 tilog("timodrproc: Got T_CONN_CON\n", 0);
1216 tp->tim_flags &= ~CONNWAIT;
1217 putnext(q, mp);
1218 break;
1220 case T_DISCON_IND: {
1221 struct T_discon_ind *disp;
1222 struct T_conn_ind *conp;
1223 mblk_t *pbp = NULL;
1225 if (q->q_first != 0)
1226 tilog("timodrput: T_DISCON_IND - flow control\n", 0);
1228 if (blen < sizeof (*disp)) {
1229 putnext(q, mp);
1230 break;
1233 disp = (struct T_discon_ind *)mp->b_rptr;
1235 tilog("timodrproc: Got T_DISCON_IND Reason: %d\n",
1236 disp->DISCON_reason);
1238 tp->tim_flags &= ~(CONNWAIT|LOCORDREL|REMORDREL);
1239 tim_clear_peer(tp);
1240 for (nbp = tp->tim_consave; nbp; nbp = nbp->b_next) {
1241 conp = (struct T_conn_ind *)nbp->b_rptr;
1242 if (conp->SEQ_number == disp->SEQ_number)
1243 break;
1244 pbp = nbp;
1246 if (nbp) {
1247 if (pbp)
1248 pbp->b_next = nbp->b_next;
1249 else
1250 tp->tim_consave = nbp->b_next;
1251 nbp->b_next = NULL;
1252 freemsg(nbp);
1254 putnext(q, mp);
1255 break;
1258 case T_ORDREL_IND:
1260 tilog("timodrproc: Got T_ORDREL_IND\n", 0);
1262 if (tp->tim_flags & LOCORDREL) {
1263 tp->tim_flags &= ~(LOCORDREL|REMORDREL);
1264 tim_clear_peer(tp);
1265 } else {
1266 tp->tim_flags |= REMORDREL;
1268 putnext(q, mp);
1269 break;
1271 case T_EXDATA_IND:
1272 case T_DATA_IND:
1273 case T_UNITDATA_IND:
1274 if (pptr->type == T_EXDATA_IND)
1275 tilog("timodrproc: Got T_EXDATA_IND\n", 0);
1277 if (!bcanputnext(q, mp->b_band)) {
1278 (void) putbq(q, mp);
1279 return (1);
1281 putnext(q, mp);
1282 break;
1284 case T_CAPABILITY_ACK: {
1285 struct T_capability_ack *tca;
1287 if (blen < sizeof (*tca)) {
1288 putnext(q, mp);
1289 break;
1292 /* This transport supports T_CAPABILITY_REQ */
1293 tilog("timodrproc: Got T_CAPABILITY_ACK\n", 0);
1295 PI_PROVLOCK(tp->tim_provinfo);
1296 if (tp->tim_provinfo->tpi_capability != PI_YES)
1297 tp->tim_provinfo->tpi_capability = PI_YES;
1298 PI_PROVUNLOCK(tp->tim_provinfo);
1300 /* Reset possible pending timeout */
1301 if (tp->tim_tcap_timoutid != 0) {
1302 (void) quntimeout(q, tp->tim_tcap_timoutid);
1303 tp->tim_tcap_timoutid = 0;
1306 tca = (struct T_capability_ack *)mp->b_rptr;
1308 if (tca->CAP_bits1 & TC1_INFO)
1309 timodprocessinfo(q, tp, &tca->INFO_ack);
1311 tim_send_reply(q, mp, tp, T_CAPABILITY_REQ);
1313 break;
1315 break;
1317 case M_FLUSH:
1319 tilog("timodrproc: Got M_FLUSH\n", 0);
1321 if (*mp->b_rptr & FLUSHR) {
1322 if (*mp->b_rptr & FLUSHBAND)
1323 flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
1324 else
1325 flushq(q, FLUSHDATA);
1327 putnext(q, mp);
1328 break;
1330 case M_IOCACK:
1331 iocbp = (struct iocblk *)mp->b_rptr;
1333 tilog("timodrproc: Got M_IOCACK\n", 0);
1335 if (iocbp->ioc_cmd == TI_GETMYNAME) {
1338 * Transport provider supports this ioctl,
1339 * so I don't have to.
1341 if ((tp->tim_flags & DO_MYNAME) != 0) {
1342 tp->tim_flags &= ~DO_MYNAME;
1343 PI_PROVLOCK(tp->tim_provinfo);
1344 tp->tim_provinfo->tpi_myname = PI_YES;
1345 PI_PROVUNLOCK(tp->tim_provinfo);
1348 ASSERT(tp->tim_mymaxlen >= 0);
1349 if (tp->tim_mymaxlen != 0) {
1350 kmem_free(tp->tim_myname, (size_t)tp->tim_mymaxlen);
1351 tp->tim_myname = NULL;
1352 tp->tim_mymaxlen = 0;
1354 /* tim_iocsave may already be overwritten. */
1355 if (tp->tim_saved_prim == -1) {
1356 freemsg(tp->tim_iocsave);
1357 tp->tim_iocsave = NULL;
1359 } else if (iocbp->ioc_cmd == TI_GETPEERNAME) {
1360 boolean_t clearit;
1363 * Transport provider supports this ioctl,
1364 * so I don't have to.
1366 if ((tp->tim_flags & DO_PEERNAME) != 0) {
1367 tp->tim_flags &= ~DO_PEERNAME;
1368 PI_PROVLOCK(tp->tim_provinfo);
1369 tp->tim_provinfo->tpi_peername = PI_YES;
1370 PI_PROVUNLOCK(tp->tim_provinfo);
1373 mutex_enter(&tp->tim_mutex);
1374 ASSERT(tp->tim_peermaxlen >= 0);
1375 clearit = tp->tim_peermaxlen != 0;
1376 if (clearit) {
1377 kmem_free(tp->tim_peername, tp->tim_peermaxlen);
1378 tp->tim_peername = NULL;
1379 tp->tim_peermaxlen = 0;
1380 tp->tim_peerlen = 0;
1382 mutex_exit(&tp->tim_mutex);
1383 if (clearit) {
1384 mblk_t *bp;
1386 bp = tp->tim_consave;
1387 while (bp != NULL) {
1388 nbp = bp->b_next;
1389 bp->b_next = NULL;
1390 freemsg(bp);
1391 bp = nbp;
1393 tp->tim_consave = NULL;
1395 /* tim_iocsave may already be overwritten. */
1396 if (tp->tim_saved_prim == -1) {
1397 freemsg(tp->tim_iocsave);
1398 tp->tim_iocsave = NULL;
1401 putnext(q, mp);
1402 break;
1404 case M_IOCNAK:
1406 tilog("timodrproc: Got M_IOCNAK\n", 0);
1408 iocbp = (struct iocblk *)mp->b_rptr;
1409 if (((iocbp->ioc_cmd == TI_GETMYNAME) ||
1410 (iocbp->ioc_cmd == TI_GETPEERNAME)) &&
1411 ((iocbp->ioc_error == EINVAL) || (iocbp->ioc_error == 0))) {
1412 PI_PROVLOCK(tp->tim_provinfo);
1413 if (iocbp->ioc_cmd == TI_GETMYNAME) {
1414 if (tp->tim_provinfo->tpi_myname == PI_DONTKNOW)
1415 tp->tim_provinfo->tpi_myname = PI_NO;
1416 } else if (iocbp->ioc_cmd == TI_GETPEERNAME) {
1417 if (tp->tim_provinfo->tpi_peername == PI_DONTKNOW)
1418 tp->tim_provinfo->tpi_peername = PI_NO;
1420 PI_PROVUNLOCK(tp->tim_provinfo);
1421 /* tim_iocsave may already be overwritten. */
1422 if ((tp->tim_iocsave != NULL) &&
1423 (tp->tim_saved_prim == -1)) {
1424 freemsg(mp);
1425 mp = tp->tim_iocsave;
1426 tp->tim_iocsave = NULL;
1427 tp->tim_flags |= NAMEPROC;
1428 if (ti_doname(WR(q), mp) != DONAME_CONT) {
1429 tp->tim_flags &= ~NAMEPROC;
1431 break;
1434 putnext(q, mp);
1435 break;
1438 return (0);
1442 * timodwput - Module write put procedure. This is called from
1443 * the module, driver, or stream head upstream/downstream.
1444 * Handles M_FLUSH, M_DATA and some M_PROTO (T_DATA_REQ,
1445 * and T_UNITDATA_REQ) messages. All others are queued to
1446 * be handled by the service procedures.
1449 static void
1450 timodwput(queue_t *q, mblk_t *mp)
1452 union T_primitives *pptr;
1453 struct tim_tim *tp;
1454 struct iocblk *iocbp;
1457 * Enqueue normal-priority messages if our queue already
1458 * holds some messages for deferred processing but don't
1459 * enqueue those M_IOCTLs which will result in an
1460 * M_PCPROTO (ie, high priority) message being created.
1462 if (q->q_first != 0 && mp->b_datap->db_type < QPCTL) {
1463 if (mp->b_datap->db_type == M_IOCTL) {
1464 iocbp = (struct iocblk *)mp->b_rptr;
1465 switch (iocbp->ioc_cmd) {
1466 default:
1467 (void) putq(q, mp);
1468 return;
1470 case TI_GETINFO:
1471 case TI_SYNC:
1472 case TI_CAPABILITY:
1473 break;
1475 } else {
1476 (void) putq(q, mp);
1477 return;
1481 * Inline processing of data (to avoid additional procedure call).
1482 * Rest is handled in timodwproc.
1485 switch (mp->b_datap->db_type) {
1486 case M_DATA:
1487 tp = (struct tim_tim *)q->q_ptr;
1488 ASSERT(tp);
1489 if (tp->tim_flags & CLTS) {
1490 mblk_t *tmp;
1492 if ((tmp = tim_filladdr(q, mp, B_FALSE)) == NULL) {
1493 (void) putq(q, mp);
1494 break;
1495 } else {
1496 mp = tmp;
1499 if (bcanputnext(q, mp->b_band))
1500 putnext(q, mp);
1501 else
1502 (void) putq(q, mp);
1503 break;
1504 case M_PROTO:
1505 case M_PCPROTO:
1506 pptr = (union T_primitives *)mp->b_rptr;
1507 switch (pptr->type) {
1508 case T_UNITDATA_REQ:
1509 tp = (struct tim_tim *)q->q_ptr;
1510 ASSERT(tp);
1511 if (tp->tim_flags & CLTS) {
1512 mblk_t *tmp;
1514 tmp = tim_filladdr(q, mp, B_FALSE);
1515 if (tmp == NULL) {
1516 (void) putq(q, mp);
1517 break;
1518 } else {
1519 mp = tmp;
1522 if (bcanputnext(q, mp->b_band))
1523 putnext(q, mp);
1524 else
1525 (void) putq(q, mp);
1526 break;
1528 case T_DATA_REQ:
1529 case T_EXDATA_REQ:
1530 if (bcanputnext(q, mp->b_band))
1531 putnext(q, mp);
1532 else
1533 (void) putq(q, mp);
1534 break;
1535 default:
1536 (void) timodwproc(q, mp);
1537 break;
1539 break;
1540 default:
1541 (void) timodwproc(q, mp);
1542 break;
1546 * timodwsrv - Module write queue service procedure.
1547 * This is called when messages are placed on an empty queue,
1548 * when high priority messages are placed on the queue, and
1549 * when flow control restrictions subside. This code used to
1550 * be included in a put procedure, but it was moved to a
1551 * service procedure because several points were added where
1552 * memory allocation could fail, and there is no reasonable
1553 * recovery mechanism from the put procedure.
1555 static void
1556 timodwsrv(queue_t *q)
1558 mblk_t *mp;
1560 ASSERT(q != NULL);
1561 if (q->q_ptr == NULL)
1562 return;
1564 while ((mp = getq(q)) != NULL) {
1565 if (timodwproc(q, mp)) {
1567 * timodwproc did a putbq - stop processing
1568 * messages.
1570 return;
1576 * Common routine to process write side messages
1579 static int
1580 timodwproc(queue_t *q, mblk_t *mp)
1582 union T_primitives *pptr;
1583 struct tim_tim *tp;
1584 uint32_t auditing = AU_AUDITING();
1585 mblk_t *tmp;
1586 struct iocblk *iocbp;
1587 int error;
1589 tp = (struct tim_tim *)q->q_ptr;
1591 switch (mp->b_datap->db_type) {
1592 default:
1593 putnext(q, mp);
1594 break;
1596 case M_DATA:
1597 if (tp->tim_flags & CLTS) {
1598 if ((tmp = tim_filladdr(q, mp, B_TRUE)) == NULL) {
1599 return (1);
1600 } else {
1601 mp = tmp;
1604 if (!bcanputnext(q, mp->b_band)) {
1605 (void) putbq(q, mp);
1606 return (1);
1608 putnext(q, mp);
1609 break;
1611 case M_IOCTL:
1613 iocbp = (struct iocblk *)mp->b_rptr;
1614 TILOG("timodwproc: Got M_IOCTL(%d)\n", iocbp->ioc_cmd);
1616 ASSERT(MBLKL(mp) == sizeof (struct iocblk));
1619 * TPI requires we await response to a previously sent message
1620 * before handling another, put it back on the head of queue.
1621 * Since putbq() may see QWANTR unset when called from the
1622 * service procedure, the queue must be explicitly scheduled
1623 * for service, as no backenable will occur for this case.
1624 * tim_ioctl_retry() sets a timer to handle the qenable.
1626 if (tp->tim_flags & WAITIOCACK) {
1627 TILOG("timodwproc: putbq M_IOCTL(%d)\n",
1628 iocbp->ioc_cmd);
1629 (void) putbq(q, mp);
1630 /* Called from timodwsrv() and messages on queue */
1631 if (!(q->q_flag & QWANTR))
1632 tim_ioctl_retry(q);
1633 return (1);
1636 switch (iocbp->ioc_cmd) {
1637 default:
1638 putnext(q, mp);
1639 break;
1641 case _I_GETPEERCRED:
1642 if ((tp->tim_flags & COTS) == 0) {
1643 miocnak(q, mp, 0, ENOTSUP);
1644 } else {
1645 mblk_t *cmp = mp->b_cont;
1646 k_peercred_t *kp = NULL;
1648 mutex_enter(&tp->tim_mutex);
1649 if (cmp != NULL &&
1650 iocbp->ioc_flag == IOC_NATIVE &&
1651 (tp->tim_flags &
1652 (CONNWAIT|LOCORDREL|REMORDREL)) == 0 &&
1653 tp->tim_peercred != NULL &&
1654 DB_TYPE(cmp) == M_DATA &&
1655 MBLKL(cmp) == sizeof (k_peercred_t)) {
1656 kp = (k_peercred_t *)cmp->b_rptr;
1657 crhold(kp->pc_cr = tp->tim_peercred);
1658 kp->pc_cpid = tp->tim_cpid;
1660 mutex_exit(&tp->tim_mutex);
1661 if (kp != NULL)
1662 miocack(q, mp, sizeof (*kp), 0);
1663 else
1664 miocnak(q, mp, 0, ENOTCONN);
1666 break;
1667 case TI_BIND:
1668 case TI_UNBIND:
1669 case TI_OPTMGMT:
1670 case TI_GETADDRS:
1671 TILOG("timodwproc: TI_{BIND|UNBIND|OPTMGMT|GETADDRS}"
1672 "\n", 0);
1675 * We know that tim_send_ioctl_tpi_msg() is only
1676 * going to examine the `type' field, so we only
1677 * check that we can access that much data.
1679 error = miocpullup(mp, sizeof (t_scalar_t));
1680 if (error != 0) {
1681 miocnak(q, mp, 0, error);
1682 break;
1684 tim_send_ioctl_tpi_msg(q, mp, tp, iocbp);
1685 break;
1687 case TI_GETINFO:
1688 TILOG("timodwproc: TI_GETINFO\n", 0);
1689 error = miocpullup(mp, sizeof (struct T_info_req));
1690 if (error != 0) {
1691 miocnak(q, mp, 0, error);
1692 break;
1694 tp->tim_flags |= WAIT_IOCINFOACK;
1695 tim_send_ioctl_tpi_msg(q, mp, tp, iocbp);
1696 break;
1698 case TI_SYNC: {
1699 mblk_t *tsr_mp;
1700 struct ti_sync_req *tsr;
1701 uint32_t tsr_flags;
1703 error = miocpullup(mp, sizeof (struct ti_sync_req));
1704 if (error != 0) {
1705 miocnak(q, mp, 0, error);
1706 break;
1709 tsr_mp = mp->b_cont;
1710 tsr = (struct ti_sync_req *)tsr_mp->b_rptr;
1711 TILOG("timodwproc: TI_SYNC(%x)\n", tsr->tsr_flags);
1714 * Save out the value of tsr_flags, in case we
1715 * reallocb() tsr_mp (below).
1717 tsr_flags = tsr->tsr_flags;
1718 if ((tsr_flags & TSRF_INFO_REQ) == 0) {
1719 mblk_t *ack_mp = reallocb(tsr_mp,
1720 sizeof (struct ti_sync_ack), 0);
1722 /* Can reply immediately. */
1723 mp->b_cont = NULL;
1724 if (ack_mp == NULL) {
1725 tilog("timodwproc: allocb failed no "
1726 "recovery attempt\n", 0);
1727 freemsg(tsr_mp);
1728 miocnak(q, mp, 0, ENOMEM);
1729 } else {
1730 tim_answer_ti_sync(q, mp, tp,
1731 ack_mp, tsr_flags);
1733 break;
1737 * This code is retained for compatibility with
1738 * old statically linked applications. New code
1739 * should use TI_CAPABILITY for all TPI
1740 * information and should not use TSRF_INFO_REQ
1741 * flag.
1743 * defer processsing necessary to rput procedure
1744 * as we need to get information from transport
1745 * driver. Set flags that will tell the read
1746 * side the work needed on this request.
1749 if (tsr_flags & TSRF_IS_EXP_IN_RCVBUF)
1750 tp->tim_flags |= PEEK_RDQ_EXPIND;
1753 * Convert message to a T_INFO_REQ message; relies
1754 * on sizeof (struct ti_sync_req) >= sizeof (struct
1755 * T_info_req)).
1757 ASSERT(MBLKL(tsr_mp) >= sizeof (struct T_info_req));
1759 ((struct T_info_req *)tsr_mp->b_rptr)->PRIM_type =
1760 T_INFO_REQ;
1761 tsr_mp->b_wptr = tsr_mp->b_rptr +
1762 sizeof (struct T_info_req);
1763 tp->tim_flags |= WAIT_IOCINFOACK;
1764 tim_send_ioctl_tpi_msg(q, mp, tp, iocbp);
1766 break;
1768 case TI_CAPABILITY: {
1769 mblk_t *tcsr_mp;
1770 struct T_capability_req *tcr;
1772 error = miocpullup(mp, sizeof (*tcr));
1773 if (error != 0) {
1774 miocnak(q, mp, 0, error);
1775 break;
1778 tcsr_mp = mp->b_cont;
1779 tcr = (struct T_capability_req *)tcsr_mp->b_rptr;
1780 TILOG("timodwproc: TI_CAPABILITY(CAP_bits1 = %x)\n",
1781 tcr->CAP_bits1);
1783 if (tcr->PRIM_type != T_CAPABILITY_REQ) {
1784 TILOG("timodwproc: invalid msg type %d\n",
1785 tcr->PRIM_type);
1786 miocnak(q, mp, 0, EPROTO);
1787 break;
1790 switch (tp->tim_provinfo->tpi_capability) {
1791 case PI_YES:
1792 /* Just send T_CAPABILITY_REQ down */
1793 tim_send_ioctl_tpi_msg(q, mp, tp, iocbp);
1794 break;
1796 case PI_DONTKNOW:
1798 * It is unknown yet whether transport provides
1799 * T_CAPABILITY_REQ or not. Send message down
1800 * and wait for reply.
1803 ASSERT(tp->tim_tcap_timoutid == 0);
1804 if ((tcr->CAP_bits1 & TC1_INFO) == 0) {
1805 tp->tim_flags |= TI_CAP_RECVD;
1806 } else {
1807 tp->tim_flags |= (TI_CAP_RECVD |
1808 CAP_WANTS_INFO);
1811 tp->tim_tcap_timoutid = qtimeout(q,
1812 tim_tcap_timer, q, tim_tcap_wait * hz);
1813 tim_send_ioctl_tpi_msg(q, mp, tp, iocbp);
1814 break;
1816 case PI_NO:
1818 * Transport doesn't support T_CAPABILITY_REQ.
1819 * Either reply immediately or send T_INFO_REQ
1820 * if needed.
1822 if ((tcr->CAP_bits1 & TC1_INFO) != 0) {
1823 tp->tim_flags |= (TI_CAP_RECVD |
1824 CAP_WANTS_INFO | WAIT_IOCINFOACK);
1825 TILOG("timodwproc: sending down "
1826 "T_INFO_REQ, flags = %x\n",
1827 tp->tim_flags);
1830 * Generate T_INFO_REQ message and send
1831 * it down
1833 ((struct T_info_req *)tcsr_mp->b_rptr)->
1834 PRIM_type = T_INFO_REQ;
1835 tcsr_mp->b_wptr = tcsr_mp->b_rptr +
1836 sizeof (struct T_info_req);
1837 tim_send_ioctl_tpi_msg(q, mp, tp,
1838 iocbp);
1839 break;
1844 * Can reply immediately. Just send back
1845 * T_CAPABILITY_ACK with CAP_bits1 set to 0.
1847 mp->b_cont = tcsr_mp = tpi_ack_alloc(mp->b_cont,
1848 sizeof (struct T_capability_ack), M_PCPROTO,
1849 T_CAPABILITY_ACK);
1851 if (tcsr_mp == NULL) {
1852 tilog("timodwproc: allocb failed no "
1853 "recovery attempt\n", 0);
1854 miocnak(q, mp, 0, ENOMEM);
1855 break;
1858 tp->tim_flags &= ~(WAITIOCACK | TI_CAP_RECVD |
1859 WAIT_IOCINFOACK | CAP_WANTS_INFO);
1860 ((struct T_capability_ack *)
1861 tcsr_mp->b_rptr)->CAP_bits1 = 0;
1862 tim_ioctl_send_reply(q, mp, tcsr_mp);
1865 * It could happen when timod is awaiting ack
1866 * for TI_GETPEERNAME/TI_GETMYNAME.
1868 if (tp->tim_iocsave != NULL) {
1869 freemsg(tp->tim_iocsave);
1870 tp->tim_iocsave = NULL;
1871 tp->tim_saved_prim = -1;
1873 break;
1875 default:
1876 cmn_err(CE_PANIC,
1877 "timodwproc: unknown tpi_capability value "
1878 "%d\n", tp->tim_provinfo->tpi_capability);
1879 break;
1882 break;
1884 case TI_GETMYNAME:
1886 tilog("timodwproc: Got TI_GETMYNAME\n", 0);
1888 if (tp->tim_provinfo->tpi_myname == PI_YES) {
1889 putnext(q, mp);
1890 break;
1892 goto getname;
1894 case TI_GETPEERNAME:
1896 tilog("timodwproc: Got TI_GETPEERNAME\n", 0);
1898 if (tp->tim_provinfo->tpi_peername == PI_YES) {
1899 putnext(q, mp);
1900 break;
1902 getname:
1903 if ((tmp = copymsg(mp)) == NULL) {
1904 tim_recover(q, mp, msgsize(mp));
1905 return (1);
1908 * tim_iocsave may be non-NULL when timod is awaiting
1909 * ack for another TI_GETPEERNAME/TI_GETMYNAME.
1911 freemsg(tp->tim_iocsave);
1912 tp->tim_iocsave = mp;
1913 tp->tim_saved_prim = -1;
1914 putnext(q, tmp);
1915 break;
1917 break;
1919 case M_IOCDATA:
1921 if (tp->tim_flags & NAMEPROC) {
1922 if (ti_doname(q, mp) != DONAME_CONT) {
1923 tp->tim_flags &= ~NAMEPROC;
1925 } else
1926 putnext(q, mp);
1927 break;
1929 case M_PROTO:
1930 case M_PCPROTO:
1931 if (MBLKL(mp) < sizeof (t_scalar_t)) {
1932 merror(q, mp, EPROTO);
1933 return (1);
1936 pptr = (union T_primitives *)mp->b_rptr;
1937 switch (pptr->type) {
1938 default:
1939 putnext(q, mp);
1940 break;
1942 case T_EXDATA_REQ:
1943 case T_DATA_REQ:
1944 if (pptr->type == T_EXDATA_REQ)
1945 tilog("timodwproc: Got T_EXDATA_REQ\n", 0);
1947 if (!bcanputnext(q, mp->b_band)) {
1948 (void) putbq(q, mp);
1949 return (1);
1951 putnext(q, mp);
1952 break;
1954 case T_UNITDATA_REQ:
1955 if (tp->tim_flags & CLTS) {
1956 tmp = tim_filladdr(q, mp, B_TRUE);
1957 if (tmp == NULL) {
1958 return (1);
1959 } else {
1960 mp = tmp;
1963 if (auditing)
1964 audit_sock(T_UNITDATA_REQ, q, mp, TIMOD_ID);
1965 if (!bcanputnext(q, mp->b_band)) {
1966 (void) putbq(q, mp);
1967 return (1);
1969 putnext(q, mp);
1970 break;
1972 case T_CONN_REQ: {
1973 struct T_conn_req *reqp = (struct T_conn_req *)
1974 mp->b_rptr;
1975 void *p;
1977 tilog("timodwproc: Got T_CONN_REQ\n", 0);
1979 if (MBLKL(mp) < sizeof (struct T_conn_req)) {
1980 merror(q, mp, EPROTO);
1981 return (1);
1984 if (tp->tim_flags & DO_PEERNAME) {
1985 if (!MBLKIN(mp, reqp->DEST_offset,
1986 reqp->DEST_length)) {
1987 merror(q, mp, EPROTO);
1988 return (1);
1990 ASSERT(reqp->DEST_length >= 0);
1991 mutex_enter(&tp->tim_mutex);
1992 if (reqp->DEST_length > tp->tim_peermaxlen) {
1993 p = kmem_alloc(reqp->DEST_length,
1994 KM_NOSLEEP);
1995 if (p == NULL) {
1996 mutex_exit(&tp->tim_mutex);
1997 tilog("timodwproc: kmem_alloc "
1998 "failed, attempting "
1999 "recovery\n", 0);
2000 tim_recover(q, mp,
2001 reqp->DEST_length);
2002 return (1);
2004 if (tp->tim_peermaxlen)
2005 kmem_free(tp->tim_peername,
2006 tp->tim_peermaxlen);
2007 tp->tim_peername = p;
2008 tp->tim_peermaxlen = reqp->DEST_length;
2010 tp->tim_peerlen = reqp->DEST_length;
2011 p = mp->b_rptr + reqp->DEST_offset;
2012 bcopy(p, tp->tim_peername, tp->tim_peerlen);
2013 mutex_exit(&tp->tim_mutex);
2015 if (tp->tim_flags & COTS)
2016 tp->tim_flags |= CONNWAIT;
2017 if (auditing)
2018 audit_sock(T_CONN_REQ, q, mp, TIMOD_ID);
2019 putnext(q, mp);
2020 break;
2023 case O_T_CONN_RES:
2024 case T_CONN_RES: {
2025 struct T_conn_res *resp;
2026 struct T_conn_ind *indp;
2027 mblk_t *pmp = NULL;
2028 mblk_t *nbp;
2030 if (MBLKL(mp) < sizeof (struct T_conn_res) ||
2031 (tp->tim_flags & WAITIOCACK)) {
2032 merror(q, mp, EPROTO);
2033 return (1);
2036 resp = (struct T_conn_res *)mp->b_rptr;
2037 for (tmp = tp->tim_consave; tmp != NULL;
2038 tmp = tmp->b_next) {
2039 indp = (struct T_conn_ind *)tmp->b_rptr;
2040 if (indp->SEQ_number == resp->SEQ_number)
2041 break;
2042 pmp = tmp;
2044 if (tmp == NULL)
2045 goto cresout;
2047 if ((nbp = dupb(mp)) == NULL &&
2048 (nbp = copyb(mp)) == NULL) {
2049 tim_recover(q, mp, msgsize(mp));
2050 return (1);
2053 if (pmp != NULL)
2054 pmp->b_next = tmp->b_next;
2055 else
2056 tp->tim_consave = tmp->b_next;
2057 tmp->b_next = NULL;
2060 * Construct a list with:
2061 * nbp - copy of user's original request
2062 * tmp - the extracted T_conn_ind
2064 nbp->b_cont = tmp;
2066 * tim_iocsave may be non-NULL when timod is awaiting
2067 * ack for TI_GETPEERNAME/TI_GETMYNAME.
2069 freemsg(tp->tim_iocsave);
2070 tp->tim_iocsave = nbp;
2071 tp->tim_saved_prim = pptr->type;
2072 tp->tim_flags |= WAIT_CONNRESACK | WAITIOCACK;
2074 cresout:
2075 putnext(q, mp);
2076 break;
2079 case T_DISCON_REQ: {
2080 struct T_discon_req *disp;
2081 struct T_conn_ind *conp;
2082 mblk_t *pmp = NULL;
2084 if (MBLKL(mp) < sizeof (struct T_discon_req)) {
2085 merror(q, mp, EPROTO);
2086 return (1);
2089 disp = (struct T_discon_req *)mp->b_rptr;
2090 tp->tim_flags &= ~(CONNWAIT|LOCORDREL|REMORDREL);
2091 tim_clear_peer(tp);
2094 * If we are already connected, there won't
2095 * be any messages on tim_consave.
2097 for (tmp = tp->tim_consave; tmp; tmp = tmp->b_next) {
2098 conp = (struct T_conn_ind *)tmp->b_rptr;
2099 if (conp->SEQ_number == disp->SEQ_number)
2100 break;
2101 pmp = tmp;
2103 if (tmp) {
2104 if (pmp)
2105 pmp->b_next = tmp->b_next;
2106 else
2107 tp->tim_consave = tmp->b_next;
2108 tmp->b_next = NULL;
2109 freemsg(tmp);
2111 putnext(q, mp);
2112 break;
2115 case T_ORDREL_REQ:
2116 if (tp->tim_flags & REMORDREL) {
2117 tp->tim_flags &= ~(LOCORDREL|REMORDREL);
2118 tim_clear_peer(tp);
2119 } else {
2120 tp->tim_flags |= LOCORDREL;
2122 putnext(q, mp);
2123 break;
2125 case T_CAPABILITY_REQ:
2126 tilog("timodwproc: Got T_CAPABILITY_REQ\n", 0);
2128 * XXX: We may know at this point whether transport
2129 * provides T_CAPABILITY_REQ or not and we may utilise
2130 * this knowledge here.
2132 putnext(q, mp);
2133 break;
2135 break;
2136 case M_FLUSH:
2138 tilog("timodwproc: Got M_FLUSH\n", 0);
2140 if (*mp->b_rptr & FLUSHW) {
2141 if (*mp->b_rptr & FLUSHBAND)
2142 flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
2143 else
2144 flushq(q, FLUSHDATA);
2146 putnext(q, mp);
2147 break;
2150 return (0);
2153 static void
2154 tilog(char *str, t_scalar_t arg)
2156 if (dotilog) {
2157 if (dotilog & 2)
2158 cmn_err(CE_CONT, str, arg);
2159 if (dotilog & 4)
2160 (void) strlog(TIMOD_ID, -1, 0, SL_TRACE | SL_ERROR,
2161 str, arg);
2162 else
2163 (void) strlog(TIMOD_ID, -1, 0, SL_TRACE, str, arg);
2167 static void
2168 tilogp(char *str, uintptr_t arg)
2170 if (dotilog) {
2171 if (dotilog & 2)
2172 cmn_err(CE_CONT, str, arg);
2173 if (dotilog & 4)
2174 (void) strlog(TIMOD_ID, -1, 0, SL_TRACE | SL_ERROR,
2175 str, arg);
2176 else
2177 (void) strlog(TIMOD_ID, -1, 0, SL_TRACE, str, arg);
2183 * Process the TI_GETNAME ioctl. If no name exists, return len = 0
2184 * in strbuf structures. The state transitions are determined by what
2185 * is hung of cq_private (cp_private) in the copyresp (copyreq) structure.
2186 * The high-level steps in the ioctl processing are as follows:
2188 * 1) we recieve an transparent M_IOCTL with the arg in the second message
2189 * block of the message.
2190 * 2) we send up an M_COPYIN request for the strbuf structure pointed to
2191 * by arg. The block containing arg is hung off cq_private.
2192 * 3) we receive an M_IOCDATA response with cp->cp_private->b_cont == NULL.
2193 * This means that the strbuf structure is found in the message block
2194 * mp->b_cont.
2195 * 4) we send up an M_COPYOUT request with the strbuf message hung off
2196 * cq_private->b_cont. The address we are copying to is strbuf.buf.
2197 * we set strbuf.len to 0 to indicate that we should copy the strbuf
2198 * structure the next time. The message mp->b_cont contains the
2199 * address info.
2200 * 5) we receive an M_IOCDATA with cp_private->b_cont != NULL and
2201 * strbuf.len == 0. Restore strbuf.len to either tp->tim_mylen or
2202 * tp->tim_peerlen.
2203 * 6) we send up an M_COPYOUT request with a copy of the strbuf message
2204 * hung off mp->b_cont. In the strbuf structure in the message hung
2205 * off cq_private->b_cont, we set strbuf.len to 0 and strbuf.maxlen
2206 * to 0. This means that the next step is to ACK the ioctl.
2207 * 7) we receive an M_IOCDATA message with cp_private->b_cont != NULL and
2208 * strbuf.len == 0 and strbuf.maxlen == 0. Free up cp->private and
2209 * send an M_IOCACK upstream, and we are done.
2212 static int
2213 ti_doname(
2214 queue_t *q, /* queue message arrived at */
2215 mblk_t *mp) /* M_IOCTL or M_IOCDATA message only */
2217 struct iocblk *iocp;
2218 struct copyreq *cqp;
2219 STRUCT_HANDLE(strbuf, sb);
2220 struct copyresp *csp;
2221 int ret;
2222 mblk_t *bp;
2223 struct tim_tim *tp = q->q_ptr;
2224 boolean_t getpeer;
2226 switch (mp->b_datap->db_type) {
2227 case M_IOCTL:
2228 iocp = (struct iocblk *)mp->b_rptr;
2229 if ((iocp->ioc_cmd != TI_GETMYNAME) &&
2230 (iocp->ioc_cmd != TI_GETPEERNAME)) {
2231 tilog("ti_doname: bad M_IOCTL command\n", 0);
2232 miocnak(q, mp, 0, EINVAL);
2233 ret = DONAME_FAIL;
2234 break;
2236 if ((iocp->ioc_count != TRANSPARENT)) {
2237 miocnak(q, mp, 0, EINVAL);
2238 ret = DONAME_FAIL;
2239 break;
2242 cqp = (struct copyreq *)mp->b_rptr;
2243 cqp->cq_private = mp->b_cont;
2244 cqp->cq_addr = (caddr_t)*(intptr_t *)mp->b_cont->b_rptr;
2245 mp->b_cont = NULL;
2246 cqp->cq_size = SIZEOF_STRUCT(strbuf, iocp->ioc_flag);
2247 cqp->cq_flag = 0;
2248 mp->b_datap->db_type = M_COPYIN;
2249 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
2250 qreply(q, mp);
2251 ret = DONAME_CONT;
2252 break;
2254 case M_IOCDATA:
2255 csp = (struct copyresp *)mp->b_rptr;
2256 iocp = (struct iocblk *)mp->b_rptr;
2257 cqp = (struct copyreq *)mp->b_rptr;
2258 if ((csp->cp_cmd != TI_GETMYNAME) &&
2259 (csp->cp_cmd != TI_GETPEERNAME)) {
2260 cmn_err(CE_WARN, "ti_doname: bad M_IOCDATA command\n");
2261 miocnak(q, mp, 0, EINVAL);
2262 ret = DONAME_FAIL;
2263 break;
2265 if (csp->cp_rval) { /* error */
2266 freemsg(csp->cp_private);
2267 freemsg(mp);
2268 ret = DONAME_FAIL;
2269 break;
2271 ASSERT(csp->cp_private != NULL);
2272 getpeer = csp->cp_cmd == TI_GETPEERNAME;
2273 if (getpeer)
2274 mutex_enter(&tp->tim_mutex);
2275 if (csp->cp_private->b_cont == NULL) { /* got strbuf */
2276 ASSERT(mp->b_cont);
2277 STRUCT_SET_HANDLE(sb, iocp->ioc_flag,
2278 (void *)mp->b_cont->b_rptr);
2279 if (getpeer) {
2280 if (tp->tim_peerlen == 0) {
2281 /* copy just strbuf */
2282 STRUCT_FSET(sb, len, 0);
2283 } else if (tp->tim_peerlen >
2284 STRUCT_FGET(sb, maxlen)) {
2285 mutex_exit(&tp->tim_mutex);
2286 miocnak(q, mp, 0, ENAMETOOLONG);
2287 ret = DONAME_FAIL;
2288 break;
2289 } else {
2290 /* copy buffer */
2291 STRUCT_FSET(sb, len, tp->tim_peerlen);
2293 } else {
2294 if (tp->tim_mylen == 0) {
2295 /* copy just strbuf */
2296 STRUCT_FSET(sb, len, 0);
2297 } else if (tp->tim_mylen >
2298 STRUCT_FGET(sb, maxlen)) {
2299 freemsg(csp->cp_private);
2300 miocnak(q, mp, 0, ENAMETOOLONG);
2301 ret = DONAME_FAIL;
2302 break;
2303 } else {
2304 /* copy buffer */
2305 STRUCT_FSET(sb, len, tp->tim_mylen);
2308 csp->cp_private->b_cont = mp->b_cont;
2309 mp->b_cont = NULL;
2311 STRUCT_SET_HANDLE(sb, iocp->ioc_flag,
2312 (void *)csp->cp_private->b_cont->b_rptr);
2313 if (STRUCT_FGET(sb, len) == 0) {
2315 * restore strbuf.len
2317 if (getpeer)
2318 STRUCT_FSET(sb, len, tp->tim_peerlen);
2319 else
2320 STRUCT_FSET(sb, len, tp->tim_mylen);
2322 if (getpeer)
2323 mutex_exit(&tp->tim_mutex);
2324 if (STRUCT_FGET(sb, maxlen) == 0) {
2327 * ack the ioctl
2329 freemsg(csp->cp_private);
2330 tim_ioctl_send_reply(q, mp, NULL);
2331 ret = DONAME_DONE;
2332 break;
2335 if ((bp = allocb(STRUCT_SIZE(sb), BPRI_MED)) == NULL) {
2337 tilog(
2338 "ti_doname: allocb failed no recovery attempt\n", 0);
2340 freemsg(csp->cp_private);
2341 miocnak(q, mp, 0, EAGAIN);
2342 ret = DONAME_FAIL;
2343 break;
2345 bp->b_wptr += STRUCT_SIZE(sb);
2346 bcopy(STRUCT_BUF(sb), bp->b_rptr, STRUCT_SIZE(sb));
2347 cqp->cq_addr =
2348 (caddr_t)*(intptr_t *)csp->cp_private->b_rptr;
2349 cqp->cq_size = STRUCT_SIZE(sb);
2350 cqp->cq_flag = 0;
2351 mp->b_datap->db_type = M_COPYOUT;
2352 mp->b_cont = bp;
2353 STRUCT_FSET(sb, len, 0);
2354 STRUCT_FSET(sb, maxlen, 0); /* ack next time around */
2355 qreply(q, mp);
2356 ret = DONAME_CONT;
2357 break;
2361 * copy the address to the user
2363 if ((bp = allocb((size_t)STRUCT_FGET(sb, len), BPRI_MED))
2364 == NULL) {
2365 if (getpeer)
2366 mutex_exit(&tp->tim_mutex);
2368 tilog("ti_doname: allocb failed no recovery attempt\n",
2371 freemsg(csp->cp_private);
2372 miocnak(q, mp, 0, EAGAIN);
2373 ret = DONAME_FAIL;
2374 break;
2376 bp->b_wptr += STRUCT_FGET(sb, len);
2377 if (getpeer) {
2378 bcopy(tp->tim_peername, bp->b_rptr,
2379 STRUCT_FGET(sb, len));
2380 mutex_exit(&tp->tim_mutex);
2381 } else {
2382 bcopy(tp->tim_myname, bp->b_rptr, STRUCT_FGET(sb, len));
2384 cqp->cq_addr = (caddr_t)STRUCT_FGETP(sb, buf);
2385 cqp->cq_size = STRUCT_FGET(sb, len);
2386 cqp->cq_flag = 0;
2387 mp->b_datap->db_type = M_COPYOUT;
2388 mp->b_cont = bp;
2389 STRUCT_FSET(sb, len, 0); /* copy the strbuf next time around */
2390 qreply(q, mp);
2391 ret = DONAME_CONT;
2392 break;
2394 default:
2395 tilog("ti_doname: freeing bad message type = %d\n",
2396 mp->b_datap->db_type);
2397 freemsg(mp);
2398 ret = DONAME_FAIL;
2399 break;
2401 return (ret);
2406 * Fill in the address of a connectionless data packet if a connect
2407 * had been done on this endpoint.
2409 static mblk_t *
2410 tim_filladdr(queue_t *q, mblk_t *mp, boolean_t dorecover)
2412 mblk_t *bp;
2413 struct tim_tim *tp;
2414 struct T_unitdata_req *up;
2415 struct T_unitdata_req *nup;
2416 size_t plen;
2418 tp = (struct tim_tim *)q->q_ptr;
2419 if (mp->b_datap->db_type == M_DATA) {
2420 mutex_enter(&tp->tim_mutex);
2421 bp = allocb(sizeof (struct T_unitdata_req) + tp->tim_peerlen,
2422 BPRI_MED);
2423 if (bp != NULL) {
2424 bp->b_datap->db_type = M_PROTO;
2425 up = (struct T_unitdata_req *)bp->b_rptr;
2426 up->PRIM_type = T_UNITDATA_REQ;
2427 up->DEST_length = tp->tim_peerlen;
2428 bp->b_wptr += sizeof (struct T_unitdata_req);
2429 up->DEST_offset = sizeof (struct T_unitdata_req);
2430 up->OPT_length = 0;
2431 up->OPT_offset = 0;
2432 if (tp->tim_peerlen > 0) {
2433 bcopy(tp->tim_peername, bp->b_wptr,
2434 tp->tim_peerlen);
2435 bp->b_wptr += tp->tim_peerlen;
2437 bp->b_cont = mp;
2439 } else {
2440 ASSERT(mp->b_datap->db_type == M_PROTO);
2441 up = (struct T_unitdata_req *)mp->b_rptr;
2442 ASSERT(up->PRIM_type == T_UNITDATA_REQ);
2443 if (up->DEST_length != 0)
2444 return (mp);
2445 mutex_enter(&tp->tim_mutex);
2446 bp = allocb(sizeof (struct T_unitdata_req) + up->OPT_length +
2447 tp->tim_peerlen, BPRI_MED);
2448 if (bp != NULL) {
2449 bp->b_datap->db_type = M_PROTO;
2450 nup = (struct T_unitdata_req *)bp->b_rptr;
2451 nup->PRIM_type = T_UNITDATA_REQ;
2452 nup->DEST_length = plen = tp->tim_peerlen;
2453 bp->b_wptr += sizeof (struct T_unitdata_req);
2454 nup->DEST_offset = sizeof (struct T_unitdata_req);
2455 if (plen > 0) {
2456 bcopy(tp->tim_peername, bp->b_wptr, plen);
2457 bp->b_wptr += plen;
2459 mutex_exit(&tp->tim_mutex);
2460 if (up->OPT_length == 0) {
2461 nup->OPT_length = 0;
2462 nup->OPT_offset = 0;
2463 } else {
2464 nup->OPT_length = up->OPT_length;
2465 nup->OPT_offset =
2466 sizeof (struct T_unitdata_req) + plen;
2467 bcopy((mp->b_wptr + up->OPT_offset), bp->b_wptr,
2468 up->OPT_length);
2469 bp->b_wptr += up->OPT_length;
2471 bp->b_cont = mp->b_cont;
2472 mp->b_cont = NULL;
2473 freeb(mp);
2474 return (bp);
2477 ASSERT(MUTEX_HELD(&tp->tim_mutex));
2478 if (bp == NULL && dorecover) {
2479 tim_recover(q, mp,
2480 sizeof (struct T_unitdata_req) + tp->tim_peerlen);
2482 mutex_exit(&tp->tim_mutex);
2483 return (bp);
2486 static void
2487 tim_addlink(struct tim_tim *tp)
2489 struct tim_tim **tpp;
2490 struct tim_tim *next;
2492 tpp = &tim_hash[TIM_HASH(tp->tim_acceptor)];
2493 rw_enter(&tim_list_rwlock, RW_WRITER);
2495 if ((next = *tpp) != NULL)
2496 next->tim_ptpn = &tp->tim_next;
2497 tp->tim_next = next;
2498 tp->tim_ptpn = tpp;
2499 *tpp = tp;
2501 tim_cnt++;
2503 rw_exit(&tim_list_rwlock);
2506 static void
2507 tim_dellink(struct tim_tim *tp)
2509 struct tim_tim *next;
2511 rw_enter(&tim_list_rwlock, RW_WRITER);
2513 if ((next = tp->tim_next) != NULL)
2514 next->tim_ptpn = tp->tim_ptpn;
2515 *(tp->tim_ptpn) = next;
2517 tim_cnt--;
2519 rw_exit(&tim_list_rwlock);
2522 static struct tim_tim *
2523 tim_findlink(t_uscalar_t id)
2525 struct tim_tim *tp;
2527 ASSERT(rw_lock_held(&tim_list_rwlock));
2529 for (tp = tim_hash[TIM_HASH(id)]; tp != NULL; tp = tp->tim_next) {
2530 if (tp->tim_acceptor == id) {
2531 break;
2534 return (tp);
2537 static void
2538 tim_recover(queue_t *q, mblk_t *mp, t_scalar_t size)
2540 struct tim_tim *tp;
2541 bufcall_id_t bid;
2542 timeout_id_t tid;
2544 tp = (struct tim_tim *)q->q_ptr;
2547 * Avoid re-enabling the queue.
2549 if (mp->b_datap->db_type == M_PCPROTO)
2550 mp->b_datap->db_type = M_PROTO;
2551 noenable(q);
2552 (void) putbq(q, mp);
2555 * Make sure there is at most one outstanding request per queue.
2557 if (q->q_flag & QREADR) {
2558 if (tp->tim_rtimoutid || tp->tim_rbufcid)
2559 return;
2560 } else {
2561 if (tp->tim_wtimoutid || tp->tim_wbufcid)
2562 return;
2564 if (!(bid = qbufcall(RD(q), (size_t)size, BPRI_MED, tim_buffer, q))) {
2565 tid = qtimeout(RD(q), tim_timer, q, TIMWAIT);
2566 if (q->q_flag & QREADR)
2567 tp->tim_rtimoutid = tid;
2568 else
2569 tp->tim_wtimoutid = tid;
2570 } else {
2571 if (q->q_flag & QREADR)
2572 tp->tim_rbufcid = bid;
2573 else
2574 tp->tim_wbufcid = bid;
2579 * Timod is waiting on a downstream ioctl reply, come back soon
2580 * to reschedule the write side service routine, which will check
2581 * if the ioctl is done and another can proceed.
2583 static void
2584 tim_ioctl_retry(queue_t *q)
2586 struct tim_tim *tp;
2588 tp = (struct tim_tim *)q->q_ptr;
2591 * Make sure there is at most one outstanding request per wqueue.
2593 if (tp->tim_wtimoutid || tp->tim_wbufcid)
2594 return;
2596 tp->tim_wtimoutid = qtimeout(RD(q), tim_timer, q, TIMIOCWAIT);
2600 * Inspect the data on read queues starting from read queues passed as
2601 * paramter (timod read queue) and traverse until
2602 * q_next is NULL (stream head). Look for a TPI T_EXDATA_IND message
2603 * reutrn 1 if found, 0 if not found.
2605 static int
2606 ti_expind_on_rdqueues(queue_t *rq)
2608 mblk_t *bp;
2609 queue_t *q;
2611 q = rq;
2613 * We are going to walk q_next, so protect stream from plumbing
2614 * changes.
2616 claimstr(q);
2617 do {
2619 * Hold QLOCK while referencing data on queues
2621 mutex_enter(QLOCK(rq));
2622 bp = rq->q_first;
2623 while (bp != NULL) {
2625 * Walk the messages on the queue looking
2626 * for a possible T_EXDATA_IND
2628 if ((bp->b_datap->db_type == M_PROTO) &&
2629 ((bp->b_wptr - bp->b_rptr) >=
2630 sizeof (struct T_exdata_ind)) &&
2631 (((struct T_exdata_ind *)bp->b_rptr)->PRIM_type
2632 == T_EXDATA_IND)) {
2633 /* bp is T_EXDATA_IND */
2634 mutex_exit(QLOCK(rq));
2635 releasestr(q); /* decrement sd_refcnt */
2636 return (1); /* expdata is on a read queue */
2638 bp = bp->b_next; /* next message */
2640 mutex_exit(QLOCK(rq));
2641 rq = rq->q_next; /* next upstream queue */
2642 } while (rq != NULL);
2643 releasestr(q);
2644 return (0); /* no expdata on read queues */
2647 static void
2648 tim_tcap_timer(void *q_ptr)
2650 queue_t *q = (queue_t *)q_ptr;
2651 struct tim_tim *tp = (struct tim_tim *)q->q_ptr;
2653 ASSERT(tp != NULL && tp->tim_tcap_timoutid != 0);
2654 ASSERT((tp->tim_flags & TI_CAP_RECVD) != 0);
2656 tp->tim_tcap_timoutid = 0;
2657 TILOG("tim_tcap_timer: fired\n", 0);
2658 tim_tcap_genreply(q, tp);
2662 * tim_tcap_genreply() is called either from timeout routine or when
2663 * T_ERROR_ACK is received. In both cases it means that underlying
2664 * transport doesn't provide T_CAPABILITY_REQ.
2666 static void
2667 tim_tcap_genreply(queue_t *q, struct tim_tim *tp)
2669 mblk_t *mp = tp->tim_iocsave;
2670 struct iocblk *iocbp;
2672 TILOG("timodrproc: tim_tcap_genreply\n", 0);
2674 ASSERT(tp == (struct tim_tim *)q->q_ptr);
2675 ASSERT(mp != NULL);
2677 iocbp = (struct iocblk *)mp->b_rptr;
2678 ASSERT(iocbp != NULL);
2679 ASSERT(MBLKL(mp) == sizeof (struct iocblk));
2680 ASSERT(iocbp->ioc_cmd == TI_CAPABILITY);
2681 ASSERT(mp->b_cont == NULL);
2683 /* Save this information permanently in the module */
2684 PI_PROVLOCK(tp->tim_provinfo);
2685 if (tp->tim_provinfo->tpi_capability == PI_DONTKNOW)
2686 tp->tim_provinfo->tpi_capability = PI_NO;
2687 PI_PROVUNLOCK(tp->tim_provinfo);
2689 if (tp->tim_tcap_timoutid != 0) {
2690 (void) quntimeout(q, tp->tim_tcap_timoutid);
2691 tp->tim_tcap_timoutid = 0;
2694 if ((tp->tim_flags & CAP_WANTS_INFO) != 0) {
2695 /* Send T_INFO_REQ down */
2696 mblk_t *tirmp = tpi_ack_alloc(NULL,
2697 sizeof (struct T_info_req), M_PCPROTO, T_INFO_REQ);
2699 if (tirmp != NULL) {
2700 /* Emulate TC1_INFO */
2701 TILOG("emulate_tcap_ioc_req: sending T_INFO_REQ\n", 0);
2702 tp->tim_flags |= WAIT_IOCINFOACK;
2703 putnext(WR(q), tirmp);
2704 } else {
2705 tilog("emulate_tcap_req: allocb fail, "
2706 "no recovery attmpt\n", 0);
2707 tp->tim_iocsave = NULL;
2708 tp->tim_saved_prim = -1;
2709 tp->tim_flags &= ~(TI_CAP_RECVD | WAITIOCACK |
2710 CAP_WANTS_INFO | WAIT_IOCINFOACK);
2711 miocnak(q, mp, 0, ENOMEM);
2713 } else {
2714 /* Reply immediately */
2715 mblk_t *ackmp = tpi_ack_alloc(NULL,
2716 sizeof (struct T_capability_ack), M_PCPROTO,
2717 T_CAPABILITY_ACK);
2719 mp->b_cont = ackmp;
2721 if (ackmp != NULL) {
2722 ((struct T_capability_ack *)
2723 ackmp->b_rptr)->CAP_bits1 = 0;
2724 tim_ioctl_send_reply(q, mp, ackmp);
2725 tp->tim_iocsave = NULL;
2726 tp->tim_saved_prim = -1;
2727 tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
2728 TI_CAP_RECVD | CAP_WANTS_INFO);
2729 } else {
2730 tilog("timodwproc:allocb failed no "
2731 "recovery attempt\n", 0);
2732 tp->tim_iocsave = NULL;
2733 tp->tim_saved_prim = -1;
2734 tp->tim_flags &= ~(TI_CAP_RECVD | WAITIOCACK |
2735 CAP_WANTS_INFO | WAIT_IOCINFOACK);
2736 miocnak(q, mp, 0, ENOMEM);
2742 static void
2743 tim_ioctl_send_reply(queue_t *q, mblk_t *ioc_mp, mblk_t *mp)
2745 struct iocblk *iocbp;
2747 ASSERT(q != NULL && ioc_mp != NULL);
2749 ioc_mp->b_datap->db_type = M_IOCACK;
2750 if (mp != NULL)
2751 mp->b_datap->db_type = M_DATA;
2753 if (ioc_mp->b_cont != mp) {
2754 /* It is safe to call freemsg for NULL pointers */
2755 freemsg(ioc_mp->b_cont);
2756 ioc_mp->b_cont = mp;
2758 iocbp = (struct iocblk *)ioc_mp->b_rptr;
2759 iocbp->ioc_error = 0;
2760 iocbp->ioc_rval = 0;
2762 * All ioctl's may return more data than was specified by
2763 * count arg. For TI_CAPABILITY count is treated as maximum data size.
2765 if (mp == NULL)
2766 iocbp->ioc_count = 0;
2767 else if (iocbp->ioc_cmd != TI_CAPABILITY)
2768 iocbp->ioc_count = msgsize(mp);
2769 else {
2770 iocbp->ioc_count = MIN(MBLKL(mp), iocbp->ioc_count);
2771 /* Truncate message if too large */
2772 mp->b_wptr = mp->b_rptr + iocbp->ioc_count;
2775 TILOG("iosendreply: ioc_cmd = %d, ", iocbp->ioc_cmd);
2776 putnext(RD(q), ioc_mp);
2780 * Send M_IOCACK for errors.
2782 static void
2783 tim_send_ioc_error_ack(queue_t *q, struct tim_tim *tp, mblk_t *mp)
2785 struct T_error_ack *tea = (struct T_error_ack *)mp->b_rptr;
2786 t_scalar_t error_prim;
2788 mp->b_wptr = mp->b_rptr + sizeof (struct T_error_ack);
2789 ASSERT(mp->b_wptr <= mp->b_datap->db_lim);
2790 error_prim = tea->ERROR_prim;
2792 ASSERT(tp->tim_iocsave != NULL);
2793 ASSERT(tp->tim_iocsave->b_cont != mp);
2795 /* Always send this to the read side of the queue */
2796 q = RD(q);
2798 TILOG("tim_send_ioc_error_ack: prim = %d\n", tp->tim_saved_prim);
2800 if (tp->tim_saved_prim != error_prim) {
2801 putnext(q, mp);
2802 } else if (error_prim == T_CAPABILITY_REQ) {
2803 TILOG("timodrproc: T_ERROR_ACK/T_CAPABILITY_REQ\n", 0);
2804 ASSERT(tp->tim_iocsave->b_cont == NULL);
2806 tim_tcap_genreply(q, tp);
2807 freemsg(mp);
2808 } else {
2809 struct iocblk *iocbp = (struct iocblk *)tp->tim_iocsave->b_rptr;
2811 TILOG("tim_send_ioc_error_ack: T_ERROR_ACK: prim %d\n",
2812 error_prim);
2813 ASSERT(tp->tim_iocsave->b_cont == NULL);
2815 switch (error_prim) {
2816 default:
2817 TILOG("timodrproc: Unknown T_ERROR_ACK: tlierror %d\n",
2818 tea->TLI_error);
2820 putnext(q, mp);
2821 break;
2823 case T_INFO_REQ:
2824 case T_SVR4_OPTMGMT_REQ:
2825 case T_OPTMGMT_REQ:
2826 case O_T_BIND_REQ:
2827 case T_BIND_REQ:
2828 case T_UNBIND_REQ:
2829 case T_ADDR_REQ:
2830 case T_CAPABILITY_REQ:
2832 TILOG("ioc_err_ack: T_ERROR_ACK: tlierror %x\n",
2833 tea->TLI_error);
2835 /* get saved ioctl msg and set values */
2836 iocbp->ioc_count = 0;
2837 iocbp->ioc_error = 0;
2838 iocbp->ioc_rval = tea->TLI_error;
2839 if (iocbp->ioc_rval == TSYSERR)
2840 iocbp->ioc_rval |= tea->UNIX_error << 8;
2841 tp->tim_iocsave->b_datap->db_type = M_IOCACK;
2842 freemsg(mp);
2843 putnext(q, tp->tim_iocsave);
2844 tp->tim_iocsave = NULL;
2845 tp->tim_saved_prim = -1;
2846 tp->tim_flags &= ~(WAITIOCACK | TI_CAP_RECVD |
2847 CAP_WANTS_INFO | WAIT_IOCINFOACK);
2848 break;
2854 * Send reply to a usual message or ioctl message upstream.
2855 * Should be called from the read side only.
2857 static void
2858 tim_send_reply(queue_t *q, mblk_t *mp, struct tim_tim *tp, t_scalar_t prim)
2860 ASSERT(mp != NULL && q != NULL && tp != NULL);
2861 ASSERT(q == RD(q));
2863 /* Restore db_type - recover() might have changed it */
2864 mp->b_datap->db_type = M_PCPROTO;
2866 if (((tp->tim_flags & WAITIOCACK) == 0) || (tp->tim_saved_prim != prim))
2867 putnext(q, mp);
2868 else {
2869 ASSERT(tp->tim_iocsave != NULL);
2870 tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
2871 tp->tim_iocsave = NULL;
2872 tp->tim_saved_prim = -1;
2873 tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
2874 TI_CAP_RECVD | CAP_WANTS_INFO);
2879 * Reply to TI_SYNC reequest without sending anything downstream.
2881 static void
2882 tim_answer_ti_sync(queue_t *q, mblk_t *mp, struct tim_tim *tp,
2883 mblk_t *ackmp, uint32_t tsr_flags)
2885 struct ti_sync_ack *tsap;
2887 ASSERT(q != NULL && q == WR(q) && ackmp != NULL);
2889 tsap = (struct ti_sync_ack *)ackmp->b_rptr;
2890 bzero(tsap, sizeof (struct ti_sync_ack));
2891 ackmp->b_wptr = ackmp->b_rptr + sizeof (struct ti_sync_ack);
2893 if (tsr_flags == 0 ||
2894 (tsr_flags & ~(TSRF_QLEN_REQ | TSRF_IS_EXP_IN_RCVBUF)) != 0) {
2896 * unsupported/bad flag setting
2897 * or no flag set.
2899 TILOG("timodwproc: unsupported/bad flag setting %x\n",
2900 tsr_flags);
2901 freemsg(ackmp);
2902 miocnak(q, mp, 0, EINVAL);
2903 return;
2906 if ((tsr_flags & TSRF_QLEN_REQ) != 0)
2907 tsap->tsa_qlen = tp->tim_backlog;
2909 if ((tsr_flags & TSRF_IS_EXP_IN_RCVBUF) != 0 &&
2910 ti_expind_on_rdqueues(RD(q))) {
2912 * Expedited data is queued on
2913 * the stream read side
2915 tsap->tsa_flags |= TSAF_EXP_QUEUED;
2918 tim_ioctl_send_reply(q, mp, ackmp);
2919 tp->tim_iocsave = NULL;
2920 tp->tim_saved_prim = -1;
2921 tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
2922 TI_CAP_RECVD | CAP_WANTS_INFO);
2926 * Send TPI message from IOCTL message, ssave original ioctl header and TPI
2927 * message type. Should be called from write side only.
2929 static void
2930 tim_send_ioctl_tpi_msg(queue_t *q, mblk_t *mp, struct tim_tim *tp,
2931 struct iocblk *iocb)
2933 mblk_t *tmp;
2934 int ioc_cmd = iocb->ioc_cmd;
2936 ASSERT(q != NULL && mp != NULL && tp != NULL);
2937 ASSERT(q == WR(q));
2938 ASSERT(mp->b_cont != NULL);
2940 tp->tim_iocsave = mp;
2941 tmp = mp->b_cont;
2943 mp->b_cont = NULL;
2944 tp->tim_flags |= WAITIOCACK;
2945 tp->tim_saved_prim = ((union T_primitives *)tmp->b_rptr)->type;
2948 * For TI_GETINFO, the attached message is a T_INFO_REQ
2949 * For TI_SYNC, we generate the T_INFO_REQ message above
2950 * For TI_CAPABILITY the attached message is either
2951 * T_CAPABILITY_REQ or T_INFO_REQ.
2952 * Among TPI request messages possible,
2953 * T_INFO_REQ/T_CAPABILITY_ACK messages are a M_PCPROTO, rest
2954 * are M_PROTO
2956 if (ioc_cmd == TI_GETINFO || ioc_cmd == TI_SYNC ||
2957 ioc_cmd == TI_CAPABILITY) {
2958 tmp->b_datap->db_type = M_PCPROTO;
2959 } else {
2960 tmp->b_datap->db_type = M_PROTO;
2963 /* Verify credentials in STREAM */
2964 ASSERT(iocb->ioc_cr == NULL || iocb->ioc_cr == DB_CRED(tmp));
2966 ASSERT(DB_CRED(tmp) != NULL);
2968 TILOG("timodwproc: sending down %d\n", tp->tim_saved_prim);
2969 putnext(q, tmp);
2972 static void
2973 tim_clear_peer(struct tim_tim *tp)
2975 mutex_enter(&tp->tim_mutex);
2976 if (tp->tim_peercred != NULL) {
2977 crfree(tp->tim_peercred);
2978 tp->tim_peercred = NULL;
2980 tp->tim_peerlen = 0;
2981 mutex_exit(&tp->tim_mutex);