xref: /titanic_50/usr/src/lib/libnsl/nsl/_utility.c (revision c62da27859e36f9fdd8cee3c6df3ad567543dcf9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 /*
26  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29 /*
30  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
31  */
32 
33 #include "mt.h"
34 #include <stdlib.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <stropts.h>
40 #include <sys/stream.h>
41 #define	_SUN_TPI_VERSION 2
42 #include <sys/tihdr.h>
43 #include <sys/timod.h>
44 #include <sys/stat.h>
45 #include <xti.h>
46 #include <fcntl.h>
47 #include <signal.h>
48 #include <assert.h>
49 #include <syslog.h>
50 #include <limits.h>
51 #include <ucred.h>
52 #include "tx.h"
53 
54 #define	DEFSIZE 2048
55 
56 /*
57  * The following used to be in tiuser.h, but was causing too much namespace
58  * pollution.
59  */
60 #define	ROUNDUP32(X)	((X + 0x03)&~0x03)
61 
62 static struct _ti_user	*find_tilink(int s);
63 static struct _ti_user	*add_tilink(int s);
64 static void _t_free_lookbufs(struct _ti_user *tiptr);
65 static unsigned int _t_setsize(t_scalar_t infosize, boolean_t option);
66 static int _t_cbuf_alloc(struct _ti_user *tiptr, char **retbuf);
67 static int _t_rbuf_alloc(struct _ti_user *tiptr, char **retbuf);
68 static int _t_adjust_state(int fd, int instate);
69 static int _t_alloc_bufs(int fd, struct _ti_user *tiptr,
70 	struct T_info_ack *tsap);
71 
72 mutex_t	_ti_userlock = DEFAULTMUTEX;	/* Protects hash_bucket[] */
73 
74 /*
75  * Checkfd - checks validity of file descriptor
76  */
77 struct _ti_user *
78 _t_checkfd(int fd, int force_sync, int api_semantics)
79 {
80 	sigset_t mask;
81 	struct _ti_user *tiptr;
82 	int retval, timodpushed;
83 
84 	if (fd < 0) {
85 		t_errno = TBADF;
86 		return (NULL);
87 	}
88 
89 	if (!force_sync) {
90 		sig_mutex_lock(&_ti_userlock);
91 		tiptr = find_tilink(fd);
92 		sig_mutex_unlock(&_ti_userlock);
93 		if (tiptr != NULL)
94 			return (tiptr);
95 	}
96 
97 	/*
98 	 * Not found or a forced sync is required.
99 	 * check if this is a valid TLI/XTI descriptor.
100 	 */
101 	timodpushed = 0;
102 	do {
103 		retval = ioctl(fd, I_FIND, "timod");
104 	} while (retval < 0 && errno == EINTR);
105 
106 	if (retval < 0 || (retval == 0 && _T_IS_TLI(api_semantics))) {
107 		/*
108 		 * not a stream or a TLI endpoint with no timod
109 		 * XXX Note: If it is a XTI call, we push "timod" and
110 		 * try to convert it into a transport endpoint later.
111 		 * We do not do it for TLI and "retain" the old buggy
112 		 * behavior because ypbind and a lot of other deamons seem
113 		 * to use a buggy logic test of the form
114 		 * "(t_getstate(0) != -1 || t_errno != TBADF)" to see if
115 		 * they we ever invoked with request on stdin and drop into
116 		 * untested code. This test is in code generated by rpcgen
117 		 * which is why it is replicated test in many daemons too.
118 		 * We will need to fix that test too with "IsaTLIendpoint"
119 		 * test if we ever fix this for TLI
120 		 */
121 		t_errno = TBADF;
122 		return (NULL);
123 	}
124 
125 	if (retval == 0) {
126 		/*
127 		 * "timod" not already on stream, then push it
128 		 */
129 		do {
130 			/*
131 			 * Assumes (correctly) that I_PUSH  is
132 			 * atomic w.r.t signals (EINTR error)
133 			 */
134 			retval = ioctl(fd, I_PUSH, "timod");
135 		} while (retval < 0 && errno == EINTR);
136 
137 		if (retval < 0) {
138 			t_errno = TSYSERR;
139 			return (NULL);
140 		}
141 		timodpushed = 1;
142 	}
143 	/*
144 	 * Try to (re)constitute the info at user level from state
145 	 * in the kernel. This could be information that lost due
146 	 * to an exec or being instantiated at a new descriptor due
147 	 * to , open(), dup2() etc.
148 	 *
149 	 * _t_create() requires that all signals be blocked.
150 	 * Note that sig_mutex_lock() only defers signals, it does not
151 	 * block them, so interruptible syscalls could still get EINTR.
152 	 */
153 	(void) thr_sigsetmask(SIG_SETMASK, &fillset, &mask);
154 	sig_mutex_lock(&_ti_userlock);
155 	tiptr = _t_create(fd, NULL, api_semantics, NULL);
156 	if (tiptr == NULL) {
157 		int sv_errno = errno;
158 		sig_mutex_unlock(&_ti_userlock);
159 		(void) thr_sigsetmask(SIG_SETMASK, &mask, NULL);
160 		/*
161 		 * restore to stream before timod pushed. It may
162 		 * not have been a network transport stream.
163 		 */
164 		if (timodpushed)
165 			(void) ioctl(fd, I_POP, 0);
166 		errno = sv_errno;
167 		return (NULL);
168 	}
169 	sig_mutex_unlock(&_ti_userlock);
170 	(void) thr_sigsetmask(SIG_SETMASK, &mask, NULL);
171 	return (tiptr);
172 }
173 
174 /*
175  * copy data to output buffer making sure the output buffer is 32 bit
176  * aligned, even though the input buffer may not be.
177  */
178 int
179 _t_aligned_copy(
180 	struct strbuf *strbufp,
181 	int len,
182 	int init_offset,
183 	char *datap,
184 	t_scalar_t *rtn_offset)
185 {
186 	*rtn_offset = ROUNDUP32(init_offset);
187 	if ((*rtn_offset + len) > strbufp->maxlen) {
188 		/*
189 		 * Aligned copy will overflow buffer
190 		 */
191 		return (-1);
192 	}
193 	(void) memcpy(strbufp->buf + *rtn_offset, datap, (size_t)len);
194 
195 	return (0);
196 }
197 
198 
199 /*
200  * append data and control info in look buffer (list in the MT case)
201  *
202  * The only thing that can be in look buffer is a T_DISCON_IND,
203  * T_ORDREL_IND or a T_UDERROR_IND.
204  *
205  * It also enforces priority of T_DISCONDs over any T_ORDREL_IND
206  * already in the buffer. It assumes no T_ORDREL_IND is appended
207  * when there is already something on the looklist (error case) and
208  * that a T_ORDREL_IND if present will always be the first on the
209  * list.
210  *
211  * This also assumes ti_lock is held via sig_mutex_lock(),
212  * so signals are deferred here.
213  */
214 int
215 _t_register_lookevent(
216 	struct _ti_user *tiptr,
217 	caddr_t dptr,
218 	int dsize,
219 	caddr_t cptr,
220 	int csize)
221 {
222 	struct _ti_lookbufs *tlbs;
223 	int cbuf_size, dbuf_size;
224 
225 	assert(MUTEX_HELD(&tiptr->ti_lock));
226 
227 	cbuf_size = tiptr->ti_ctlsize;
228 	dbuf_size = tiptr->ti_rcvsize;
229 
230 	if ((csize > cbuf_size) || dsize > dbuf_size) {
231 		/* can't fit - return error */
232 		return (-1);	/* error */
233 	}
234 	/*
235 	 * Enforce priority of T_DISCON_IND over T_ORDREL_IND
236 	 * queued earlier.
237 	 * Note: Since there can be only at most one T_ORDREL_IND
238 	 * queued (more than one is error case), and we look for it
239 	 * on each append of T_DISCON_IND, it can only be at the
240 	 * head of the list if it is there.
241 	 */
242 	if (tiptr->ti_lookcnt > 0) { /* something already on looklist */
243 		if (cptr && csize >= (int)sizeof (struct T_discon_ind) &&
244 		    /* LINTED pointer cast */
245 		    *(t_scalar_t *)cptr == T_DISCON_IND) {
246 			/* appending discon ind */
247 			assert(tiptr->ti_servtype != T_CLTS);
248 			/* LINTED pointer cast */
249 			if (*(t_scalar_t *)tiptr->ti_lookbufs.tl_lookcbuf ==
250 			    T_ORDREL_IND) { /* T_ORDREL_IND is on list */
251 				/*
252 				 * Blow away T_ORDREL_IND
253 				 */
254 				_t_free_looklist_head(tiptr);
255 			}
256 		}
257 	}
258 	tlbs = &tiptr->ti_lookbufs;
259 	if (tiptr->ti_lookcnt > 0) {
260 		int listcount = 0;
261 		/*
262 		 * Allocate and append a new lookbuf to the
263 		 * existing list. (Should only happen in MT case)
264 		 */
265 		while (tlbs->tl_next != NULL) {
266 			listcount++;
267 			tlbs = tlbs->tl_next;
268 		}
269 		assert(tiptr->ti_lookcnt == listcount);
270 
271 		/*
272 		 * signals are deferred, calls to malloc() are safe.
273 		 */
274 		if ((tlbs->tl_next = malloc(sizeof (struct _ti_lookbufs))) ==
275 		    NULL)
276 			return (-1); /* error */
277 		tlbs = tlbs->tl_next;
278 		/*
279 		 * Allocate the buffers. The sizes derived from the
280 		 * sizes of other related buffers. See _t_alloc_bufs()
281 		 * for details.
282 		 */
283 		if ((tlbs->tl_lookcbuf = malloc(cbuf_size)) == NULL) {
284 			/* giving up - free other memory chunks */
285 			free(tlbs);
286 			return (-1); /* error */
287 		}
288 		if ((dsize > 0) &&
289 		    ((tlbs->tl_lookdbuf = malloc(dbuf_size)) == NULL)) {
290 			/* giving up - free other memory chunks */
291 			free(tlbs->tl_lookcbuf);
292 			free(tlbs);
293 			return (-1); /* error */
294 		}
295 	}
296 
297 	(void) memcpy(tlbs->tl_lookcbuf, cptr, csize);
298 	if (dsize > 0)
299 		(void) memcpy(tlbs->tl_lookdbuf, dptr, dsize);
300 	tlbs->tl_lookdlen = dsize;
301 	tlbs->tl_lookclen = csize;
302 	tlbs->tl_next = NULL;
303 	tiptr->ti_lookcnt++;
304 	return (0);		/* ok return */
305 }
306 
307 /*
308  * Is there something that needs attention?
309  * Assumes tiptr->ti_lock held and this threads signals blocked
310  * in MT case.
311  */
312 int
313 _t_is_event(int fd, struct _ti_user *tiptr)
314 {
315 	int size, retval;
316 
317 	assert(MUTEX_HELD(&tiptr->ti_lock));
318 	if ((retval = ioctl(fd, I_NREAD, &size)) < 0) {
319 		t_errno = TSYSERR;
320 		return (-1);
321 	}
322 
323 	if ((retval > 0) || (tiptr->ti_lookcnt > 0)) {
324 		t_errno = TLOOK;
325 		return (-1);
326 	}
327 	return (0);
328 }
329 
330 /*
331  * wait for T_OK_ACK
332  * assumes tiptr->ti_lock held in MT case
333  */
334 int
335 _t_is_ok(int fd, struct _ti_user *tiptr, t_scalar_t type)
336 {
337 	struct strbuf ctlbuf;
338 	struct strbuf databuf;
339 	union T_primitives *pptr;
340 	int retval, cntlflag;
341 	int size;
342 	int didalloc, didralloc;
343 	int flags = 0;
344 
345 	assert(MUTEX_HELD(&tiptr->ti_lock));
346 	/*
347 	 * Acquire ctlbuf for use in sending/receiving control part
348 	 * of the message.
349 	 */
350 	if (_t_acquire_ctlbuf(tiptr, &ctlbuf, &didalloc) < 0)
351 		return (-1);
352 	/*
353 	 * Acquire databuf for use in sending/receiving data part
354 	 */
355 	if (_t_acquire_databuf(tiptr, &databuf, &didralloc) < 0) {
356 		if (didalloc)
357 			free(ctlbuf.buf);
358 		else
359 			tiptr->ti_ctlbuf = ctlbuf.buf;
360 		return (-1);
361 	}
362 
363 	/*
364 	 * Temporarily convert a non blocking endpoint to a
365 	 * blocking one and restore status later
366 	 */
367 	cntlflag = fcntl(fd, F_GETFL, 0);
368 	if (cntlflag & (O_NDELAY | O_NONBLOCK))
369 		(void) fcntl(fd, F_SETFL, cntlflag & ~(O_NDELAY | O_NONBLOCK));
370 
371 	flags = RS_HIPRI;
372 
373 	while ((retval = getmsg(fd, &ctlbuf, &databuf, &flags)) < 0) {
374 		if (errno == EINTR)
375 			continue;
376 		if (cntlflag & (O_NDELAY | O_NONBLOCK))
377 			(void) fcntl(fd, F_SETFL, cntlflag);
378 		t_errno = TSYSERR;
379 		goto err_out;
380 	}
381 
382 	/* did I get entire message */
383 	if (retval > 0) {
384 		if (cntlflag & (O_NDELAY | O_NONBLOCK))
385 			(void) fcntl(fd, F_SETFL, cntlflag);
386 		t_errno = TSYSERR;
387 		errno = EIO;
388 		goto err_out;
389 	}
390 
391 	/*
392 	 * is ctl part large enough to determine type?
393 	 */
394 	if (ctlbuf.len < (int)sizeof (t_scalar_t)) {
395 		if (cntlflag & (O_NDELAY | O_NONBLOCK))
396 			(void) fcntl(fd, F_SETFL, cntlflag);
397 		t_errno = TSYSERR;
398 		errno = EPROTO;
399 		goto err_out;
400 	}
401 
402 	if (cntlflag & (O_NDELAY | O_NONBLOCK))
403 		(void) fcntl(fd, F_SETFL, cntlflag);
404 
405 	/* LINTED pointer cast */
406 	pptr = (union T_primitives *)ctlbuf.buf;
407 
408 	switch (pptr->type) {
409 	case T_OK_ACK:
410 		if ((ctlbuf.len < (int)sizeof (struct T_ok_ack)) ||
411 		    (pptr->ok_ack.CORRECT_prim != type)) {
412 			t_errno = TSYSERR;
413 			errno = EPROTO;
414 			goto err_out;
415 		}
416 		if (didalloc)
417 			free(ctlbuf.buf);
418 		else
419 			tiptr->ti_ctlbuf = ctlbuf.buf;
420 		if (didralloc)
421 			free(databuf.buf);
422 		else
423 			tiptr->ti_rcvbuf = databuf.buf;
424 		return (0);
425 
426 	case T_ERROR_ACK:
427 		if ((ctlbuf.len < (int)sizeof (struct T_error_ack)) ||
428 		    (pptr->error_ack.ERROR_prim != type)) {
429 			t_errno = TSYSERR;
430 			errno = EPROTO;
431 			goto err_out;
432 		}
433 		/*
434 		 * if error is out of state and there is something
435 		 * on read queue, then indicate to user that
436 		 * there is something that needs attention
437 		 */
438 		if (pptr->error_ack.TLI_error == TOUTSTATE) {
439 			if ((retval = ioctl(fd, I_NREAD, &size)) < 0) {
440 				t_errno = TSYSERR;
441 				goto err_out;
442 			}
443 			if (retval > 0)
444 				t_errno = TLOOK;
445 			else
446 				t_errno = TOUTSTATE;
447 		} else {
448 			t_errno = pptr->error_ack.TLI_error;
449 			if (t_errno == TSYSERR)
450 				errno = pptr->error_ack.UNIX_error;
451 		}
452 		goto err_out;
453 	default:
454 		t_errno = TSYSERR;
455 		errno = EPROTO;
456 		/* fallthru to err_out: */
457 	}
458 err_out:
459 	if (didalloc)
460 		free(ctlbuf.buf);
461 	else
462 		tiptr->ti_ctlbuf = ctlbuf.buf;
463 	if (didralloc)
464 		free(databuf.buf);
465 	else
466 		tiptr->ti_rcvbuf = databuf.buf;
467 	return (-1);
468 }
469 
470 /*
471  * timod ioctl
472  */
473 int
474 _t_do_ioctl(int fd, char *buf, int size, int cmd, int *retlenp)
475 {
476 	int retval;
477 	struct strioctl strioc;
478 
479 	strioc.ic_cmd = cmd;
480 	strioc.ic_timout = -1;
481 	strioc.ic_len = size;
482 	strioc.ic_dp = buf;
483 
484 	if ((retval = ioctl(fd, I_STR, &strioc)) < 0) {
485 		t_errno = TSYSERR;
486 		return (-1);
487 	}
488 
489 	if (retval > 0) {
490 		t_errno = retval & 0xff;
491 		if (t_errno == TSYSERR)
492 			errno = (retval >> 8) & 0xff;
493 		return (-1);
494 	}
495 	if (retlenp)
496 		*retlenp = strioc.ic_len;
497 	return (0);
498 }
499 
500 /*
501  * alloc scratch buffers and look buffers
502  */
503 /* ARGSUSED */
504 static int
505 _t_alloc_bufs(int fd, struct _ti_user *tiptr, struct T_info_ack *tsap)
506 {
507 	unsigned int size1, size2;
508 	t_scalar_t optsize;
509 	unsigned int csize, dsize, asize, osize;
510 	char *ctlbuf, *rcvbuf;
511 	char *lookdbuf, *lookcbuf;
512 
513 	csize = _t_setsize(tsap->CDATA_size, B_FALSE);
514 	dsize = _t_setsize(tsap->DDATA_size, B_FALSE);
515 
516 	size1 = _T_MAX(csize, dsize);
517 
518 	if (size1 != 0) {
519 		if ((rcvbuf = malloc(size1)) == NULL)
520 			return (-1);
521 		if ((lookdbuf = malloc(size1)) == NULL) {
522 			free(rcvbuf);
523 			return (-1);
524 		}
525 	} else {
526 		rcvbuf = NULL;
527 		lookdbuf = NULL;
528 	}
529 
530 	asize = _t_setsize(tsap->ADDR_size, B_FALSE);
531 	if (tsap->OPT_size >= 0)
532 		/* compensate for XTI level options */
533 		optsize = tsap->OPT_size + TX_XTI_LEVEL_MAX_OPTBUF;
534 	else
535 		optsize = tsap->OPT_size;
536 	osize = _t_setsize(optsize, B_TRUE);
537 
538 	/*
539 	 * We compute the largest buffer size needed for this provider by
540 	 * adding the components. [ An extra sizeof (t_scalar_t) is added to
541 	 * take care of rounding off for alignment) for each buffer ]
542 	 * The goal here is compute the size of largest possible buffer that
543 	 * might be needed to hold a TPI message for the transport provider
544 	 * on this endpoint.
545 	 * Note: T_ADDR_ACK contains potentially two address buffers.
546 	 */
547 
548 	size2 = (unsigned int)sizeof (union T_primitives) /* TPI struct */
549 	    + asize + (unsigned int)sizeof (t_scalar_t) +
550 		/* first addr buffer plus alignment */
551 	    asize + (unsigned int)sizeof (t_scalar_t) +
552 		/* second addr buffer plus ailignment */
553 	    osize + (unsigned int)sizeof (t_scalar_t);
554 		/* option buffer plus alignment */
555 
556 	if ((ctlbuf = malloc(size2)) == NULL) {
557 		if (size1 != 0) {
558 			free(rcvbuf);
559 			free(lookdbuf);
560 		}
561 		return (-1);
562 	}
563 
564 	if ((lookcbuf = malloc(size2)) == NULL) {
565 		if (size1 != 0) {
566 			free(rcvbuf);
567 			free(lookdbuf);
568 		}
569 		free(ctlbuf);
570 		return (-1);
571 	}
572 
573 	tiptr->ti_rcvsize = size1;
574 	tiptr->ti_rcvbuf = rcvbuf;
575 	tiptr->ti_ctlsize = size2;
576 	tiptr->ti_ctlbuf = ctlbuf;
577 
578 	/*
579 	 * Note: The head of the lookbuffers list (and associated buffers)
580 	 * is allocated here on initialization.
581 	 * More allocated on demand.
582 	 */
583 	tiptr->ti_lookbufs.tl_lookclen = 0;
584 	tiptr->ti_lookbufs.tl_lookcbuf = lookcbuf;
585 	tiptr->ti_lookbufs.tl_lookdlen = 0;
586 	tiptr->ti_lookbufs.tl_lookdbuf = lookdbuf;
587 
588 	return (0);
589 }
590 
591 
592 /*
593  * set sizes of buffers
594  */
595 static unsigned int
596 _t_setsize(t_scalar_t infosize, boolean_t option)
597 {
598 	static size_t optinfsize;
599 
600 	switch (infosize) {
601 	case T_INFINITE /* -1 */:
602 		if (option) {
603 			if (optinfsize == 0) {
604 				size_t uc = ucred_size();
605 				if (uc < DEFSIZE/2)
606 					optinfsize = DEFSIZE;
607 				else
608 					optinfsize = ucred_size() + DEFSIZE/2;
609 			}
610 			return ((unsigned int)optinfsize);
611 		}
612 		return (DEFSIZE);
613 	case T_INVALID /* -2 */:
614 		return (0);
615 	default:
616 		return ((unsigned int) infosize);
617 	}
618 }
619 
620 static void
621 _t_reinit_tiptr(struct _ti_user *tiptr)
622 {
623 	/*
624 	 * Note: This routine is designed for a "reinitialization"
625 	 * Following fields are not modified here and preserved.
626 	 *	 - ti_fd field
627 	 *	 - ti_lock
628 	 *	 - ti_next
629 	 *	 - ti_prev
630 	 * The above fields have to be separately initialized if this
631 	 * is used for a fresh initialization.
632 	 */
633 
634 	tiptr->ti_flags = 0;
635 	tiptr->ti_rcvsize = 0;
636 	tiptr->ti_rcvbuf = NULL;
637 	tiptr->ti_ctlsize = 0;
638 	tiptr->ti_ctlbuf = NULL;
639 	tiptr->ti_lookbufs.tl_lookdbuf = NULL;
640 	tiptr->ti_lookbufs.tl_lookcbuf = NULL;
641 	tiptr->ti_lookbufs.tl_lookdlen = 0;
642 	tiptr->ti_lookbufs.tl_lookclen = 0;
643 	tiptr->ti_lookbufs.tl_next = NULL;
644 	tiptr->ti_maxpsz = 0;
645 	tiptr->ti_tsdusize = 0;
646 	tiptr->ti_etsdusize = 0;
647 	tiptr->ti_cdatasize = 0;
648 	tiptr->ti_ddatasize = 0;
649 	tiptr->ti_servtype = 0;
650 	tiptr->ti_lookcnt = 0;
651 	tiptr->ti_state = 0;
652 	tiptr->ti_ocnt = 0;
653 	tiptr->ti_prov_flag = 0;
654 	tiptr->ti_qlen = 0;
655 }
656 
657 /*
658  * Link manipulation routines.
659  *
660  * NBUCKETS hash buckets are used to give fast
661  * access. The number is derived the file descriptor softlimit
662  * number (64).
663  */
664 
665 #define	NBUCKETS	64
666 static struct _ti_user		*hash_bucket[NBUCKETS];
667 
668 /*
669  * Allocates a new link and returns a pointer to it.
670  * Assumes that the caller is holding _ti_userlock via sig_mutex_lock(),
671  * so signals are deferred here.
672  */
673 static struct _ti_user *
674 add_tilink(int s)
675 {
676 	struct _ti_user	*tiptr;
677 	struct _ti_user	*prevptr;
678 	struct _ti_user	*curptr;
679 	int	x;
680 	struct stat stbuf;
681 
682 	assert(MUTEX_HELD(&_ti_userlock));
683 
684 	if (s < 0 || fstat(s, &stbuf) != 0)
685 		return (NULL);
686 
687 	x = s % NBUCKETS;
688 	if (hash_bucket[x] != NULL) {
689 		/*
690 		 * Walk along the bucket looking for
691 		 * duplicate entry or the end.
692 		 */
693 		for (curptr = hash_bucket[x]; curptr != NULL;
694 		    curptr = curptr->ti_next) {
695 			if (curptr->ti_fd == s) {
696 				/*
697 				 * This can happen when the user has close(2)'ed
698 				 * a descriptor and then been allocated it again
699 				 * via t_open().
700 				 *
701 				 * We will re-use the existing _ti_user struct
702 				 * in this case rather than using the one
703 				 * we allocated above.  If there are buffers
704 				 * associated with the existing _ti_user
705 				 * struct, they may not be the correct size,
706 				 * so we can not use it.  We free them
707 				 * here and re-allocate a new ones
708 				 * later on.
709 				 */
710 				if (curptr->ti_rcvbuf != NULL)
711 					free(curptr->ti_rcvbuf);
712 				free(curptr->ti_ctlbuf);
713 				_t_free_lookbufs(curptr);
714 				_t_reinit_tiptr(curptr);
715 				curptr->ti_rdev = stbuf.st_rdev;
716 				curptr->ti_ino = stbuf.st_ino;
717 				return (curptr);
718 			}
719 			prevptr = curptr;
720 		}
721 		/*
722 		 * Allocate and link in a new one.
723 		 */
724 		if ((tiptr = malloc(sizeof (*tiptr))) == NULL)
725 			return (NULL);
726 		/*
727 		 * First initialize fields common with reinitialization and
728 		 * then other fields too
729 		 */
730 		_t_reinit_tiptr(tiptr);
731 		prevptr->ti_next = tiptr;
732 		tiptr->ti_prev = prevptr;
733 	} else {
734 		/*
735 		 * First entry.
736 		 */
737 		if ((tiptr = malloc(sizeof (*tiptr))) == NULL)
738 			return (NULL);
739 		_t_reinit_tiptr(tiptr);
740 		hash_bucket[x] = tiptr;
741 		tiptr->ti_prev = NULL;
742 	}
743 	tiptr->ti_next = NULL;
744 	tiptr->ti_fd = s;
745 	tiptr->ti_rdev = stbuf.st_rdev;
746 	tiptr->ti_ino = stbuf.st_ino;
747 	(void) mutex_init(&tiptr->ti_lock, USYNC_THREAD, NULL);
748 	return (tiptr);
749 }
750 
751 /*
752  * Find a link by descriptor
753  * Assumes that the caller is holding _ti_userlock.
754  */
755 static struct _ti_user *
756 find_tilink(int s)
757 {
758 	struct _ti_user	*curptr;
759 	int	x;
760 	struct stat stbuf;
761 
762 	assert(MUTEX_HELD(&_ti_userlock));
763 
764 	if (s < 0 || fstat(s, &stbuf) != 0)
765 		return (NULL);
766 
767 	x = s % NBUCKETS;
768 	/*
769 	 * Walk along the bucket looking for the descriptor.
770 	 */
771 	for (curptr = hash_bucket[x]; curptr; curptr = curptr->ti_next) {
772 		if (curptr->ti_fd == s) {
773 			if (curptr->ti_rdev == stbuf.st_rdev &&
774 			    curptr->ti_ino == stbuf.st_ino)
775 				return (curptr);
776 			(void) _t_delete_tilink(s);
777 		}
778 	}
779 	return (NULL);
780 }
781 
782 /*
783  * Assumes that the caller is holding _ti_userlock.
784  * Also assumes that all signals are blocked.
785  */
786 int
787 _t_delete_tilink(int s)
788 {
789 	struct _ti_user	*curptr;
790 	int	x;
791 
792 	/*
793 	 * Find the link.
794 	 */
795 	assert(MUTEX_HELD(&_ti_userlock));
796 	if (s < 0)
797 		return (-1);
798 	x = s % NBUCKETS;
799 	/*
800 	 * Walk along the bucket looking for
801 	 * the descriptor.
802 	 */
803 	for (curptr = hash_bucket[x]; curptr; curptr = curptr->ti_next) {
804 		if (curptr->ti_fd == s) {
805 			struct _ti_user	*nextptr;
806 			struct _ti_user	*prevptr;
807 
808 			nextptr = curptr->ti_next;
809 			prevptr = curptr->ti_prev;
810 			if (prevptr)
811 				prevptr->ti_next = nextptr;
812 			else
813 				hash_bucket[x] = nextptr;
814 			if (nextptr)
815 				nextptr->ti_prev = prevptr;
816 
817 			/*
818 			 * free resource associated with the curptr
819 			 */
820 			if (curptr->ti_rcvbuf != NULL)
821 				free(curptr->ti_rcvbuf);
822 			free(curptr->ti_ctlbuf);
823 			_t_free_lookbufs(curptr);
824 			(void) mutex_destroy(&curptr->ti_lock);
825 			free(curptr);
826 			return (0);
827 		}
828 	}
829 	return (-1);
830 }
831 
832 /*
833  * Allocate a TLI state structure and synch it with the kernel
834  * *tiptr is returned
835  * Assumes that the caller is holding the _ti_userlock and has blocked signals.
836  *
837  * This function may fail the first time it is called with given transport if it
838  * doesn't support T_CAPABILITY_REQ TPI message.
839  */
840 struct _ti_user *
841 _t_create(int fd, struct t_info *info, int api_semantics, int *t_capreq_failed)
842 {
843 	/*
844 	 * Aligned data buffer for ioctl.
845 	 */
846 	union {
847 		struct ti_sync_req ti_req;
848 		struct ti_sync_ack ti_ack;
849 		union T_primitives t_prim;
850 		char pad[128];
851 	} ioctl_data;
852 	void *ioctlbuf = &ioctl_data; /* TI_SYNC/GETINFO with room to grow */
853 			    /* preferred location first local variable */
854 			    /*  see note below */
855 	/*
856 	 * Note: We use "ioctlbuf" allocated on stack above with
857 	 * room to grow since (struct ti_sync_ack) can grow in size
858 	 * on future kernels. (We do not use malloc'd "ti_ctlbuf" as that
859 	 * part of instance structure which may not exist yet)
860 	 * Its preferred declaration location is first local variable in this
861 	 * procedure as bugs causing overruns will be detectable on
862 	 * platforms where procedure calling conventions place return
863 	 * address on stack (such as x86) instead of causing silent
864 	 * memory corruption.
865 	 */
866 	struct ti_sync_req *tsrp = (struct ti_sync_req *)ioctlbuf;
867 	struct ti_sync_ack *tsap = (struct ti_sync_ack *)ioctlbuf;
868 	struct T_capability_req *tcrp = (struct T_capability_req *)ioctlbuf;
869 	struct T_capability_ack *tcap = (struct T_capability_ack *)ioctlbuf;
870 	struct T_info_ack *tiap = &tcap->INFO_ack;
871 	struct _ti_user	*ntiptr;
872 	int expected_acksize;
873 	int retlen, rstate, sv_errno, rval;
874 
875 	assert(MUTEX_HELD(&_ti_userlock));
876 
877 	/*
878 	 * Use ioctl required for sync'ing state with kernel.
879 	 * We use two ioctls. TI_CAPABILITY is used to get TPI information and
880 	 * TI_SYNC is used to synchronise state with timod. Statically linked
881 	 * TLI applications will no longer work on older releases where there
882 	 * are no TI_SYNC and TI_CAPABILITY.
883 	 */
884 
885 	/*
886 	 * Request info about transport.
887 	 * Assumes that TC1_INFO should always be implemented.
888 	 * For TI_CAPABILITY size argument to ioctl specifies maximum buffer
889 	 * size.
890 	 */
891 	tcrp->PRIM_type = T_CAPABILITY_REQ;
892 	tcrp->CAP_bits1 = TC1_INFO | TC1_ACCEPTOR_ID;
893 	rval = _t_do_ioctl(fd, (char *)ioctlbuf,
894 	    (int)sizeof (struct T_capability_ack), TI_CAPABILITY, &retlen);
895 	expected_acksize = (int)sizeof (struct T_capability_ack);
896 
897 	if (rval < 0) {
898 		/*
899 		 * TI_CAPABILITY may fail when transport provider doesn't
900 		 * support T_CAPABILITY_REQ message type. In this case file
901 		 * descriptor may be unusable (when transport provider sent
902 		 * M_ERROR in response to T_CAPABILITY_REQ). This should only
903 		 * happen once during system lifetime for given transport
904 		 * provider since timod will emulate TI_CAPABILITY after it
905 		 * detected the failure.
906 		 */
907 		if (t_capreq_failed != NULL)
908 			*t_capreq_failed = 1;
909 		return (NULL);
910 	}
911 
912 	if (retlen != expected_acksize) {
913 		t_errno = TSYSERR;
914 		errno = EIO;
915 		return (NULL);
916 	}
917 
918 	if ((tcap->CAP_bits1 & TC1_INFO) == 0) {
919 		t_errno = TSYSERR;
920 		errno = EPROTO;
921 		return (NULL);
922 	}
923 	if (info != NULL) {
924 		if (tiap->PRIM_type != T_INFO_ACK) {
925 			t_errno = TSYSERR;
926 			errno = EPROTO;
927 			return (NULL);
928 		}
929 		info->addr = tiap->ADDR_size;
930 		info->options = tiap->OPT_size;
931 		info->tsdu = tiap->TSDU_size;
932 		info->etsdu = tiap->ETSDU_size;
933 		info->connect = tiap->CDATA_size;
934 		info->discon = tiap->DDATA_size;
935 		info->servtype = tiap->SERV_type;
936 		if (_T_IS_XTI(api_semantics)) {
937 			/*
938 			 * XTI ONLY - TLI "struct t_info" does not
939 			 * have "flags"
940 			 */
941 			info->flags = 0;
942 			if (tiap->PROVIDER_flag & (SENDZERO|OLD_SENDZERO))
943 				info->flags |= T_SENDZERO;
944 			/*
945 			 * Some day there MAY be a NEW bit in T_info_ack
946 			 * PROVIDER_flag namespace exposed by TPI header
947 			 * <sys/tihdr.h> which will functionally correspond to
948 			 * role played by T_ORDRELDATA in info->flags namespace
949 			 * When that bit exists, we can add a test to see if
950 			 * it is set and set T_ORDRELDATA.
951 			 * Note: Currently only mOSI ("minimal OSI") provider
952 			 * is specified to use T_ORDRELDATA so probability of
953 			 * needing it is minimal.
954 			 */
955 		}
956 	}
957 
958 	/*
959 	 * if first time or no instance (after fork/exec, dup etc,
960 	 * then create initialize data structure
961 	 * and allocate buffers
962 	 */
963 	ntiptr = add_tilink(fd);
964 	if (ntiptr == NULL) {
965 		t_errno = TSYSERR;
966 		errno = ENOMEM;
967 		return (NULL);
968 	}
969 	sig_mutex_lock(&ntiptr->ti_lock);
970 
971 	/*
972 	 * Allocate buffers for the new descriptor
973 	 */
974 	if (_t_alloc_bufs(fd, ntiptr, tiap) < 0) {
975 		sv_errno = errno;
976 		(void) _t_delete_tilink(fd);
977 		t_errno = TSYSERR;
978 		sig_mutex_unlock(&ntiptr->ti_lock);
979 		errno = sv_errno;
980 		return (NULL);
981 	}
982 
983 	/* Fill instance structure */
984 
985 	ntiptr->ti_lookcnt = 0;
986 	ntiptr->ti_flags = USED;
987 	ntiptr->ti_state = T_UNINIT;
988 	ntiptr->ti_ocnt = 0;
989 
990 	assert(tiap->TIDU_size > 0);
991 	ntiptr->ti_maxpsz = tiap->TIDU_size;
992 	assert(tiap->TSDU_size >= -2);
993 	ntiptr->ti_tsdusize = tiap->TSDU_size;
994 	assert(tiap->ETSDU_size >= -2);
995 	ntiptr->ti_etsdusize = tiap->ETSDU_size;
996 	assert(tiap->CDATA_size >= -2);
997 	ntiptr->ti_cdatasize = tiap->CDATA_size;
998 	assert(tiap->DDATA_size >= -2);
999 	ntiptr->ti_ddatasize = tiap->DDATA_size;
1000 	ntiptr->ti_servtype = tiap->SERV_type;
1001 	ntiptr->ti_prov_flag = tiap->PROVIDER_flag;
1002 
1003 	if ((tcap->CAP_bits1 & TC1_ACCEPTOR_ID) != 0) {
1004 		ntiptr->acceptor_id = tcap->ACCEPTOR_id;
1005 		ntiptr->ti_flags |= V_ACCEPTOR_ID;
1006 	}
1007 	else
1008 		ntiptr->ti_flags &= ~V_ACCEPTOR_ID;
1009 
1010 	/*
1011 	 * Restore state from kernel (caveat some heuristics)
1012 	 */
1013 	switch (tiap->CURRENT_state) {
1014 
1015 	case TS_UNBND:
1016 		ntiptr->ti_state = T_UNBND;
1017 		break;
1018 
1019 	case TS_IDLE:
1020 		if ((rstate = _t_adjust_state(fd, T_IDLE)) < 0) {
1021 			sv_errno = errno;
1022 			(void) _t_delete_tilink(fd);
1023 			sig_mutex_unlock(&ntiptr->ti_lock);
1024 			errno = sv_errno;
1025 			return (NULL);
1026 		}
1027 		ntiptr->ti_state = rstate;
1028 		break;
1029 
1030 	case TS_WRES_CIND:
1031 		ntiptr->ti_state = T_INCON;
1032 		break;
1033 
1034 	case TS_WCON_CREQ:
1035 		ntiptr->ti_state = T_OUTCON;
1036 		break;
1037 
1038 	case TS_DATA_XFER:
1039 		if ((rstate = _t_adjust_state(fd, T_DATAXFER)) < 0)  {
1040 			sv_errno = errno;
1041 			(void) _t_delete_tilink(fd);
1042 			sig_mutex_unlock(&ntiptr->ti_lock);
1043 			errno = sv_errno;
1044 			return (NULL);
1045 		}
1046 		ntiptr->ti_state = rstate;
1047 		break;
1048 
1049 	case TS_WIND_ORDREL:
1050 		ntiptr->ti_state = T_OUTREL;
1051 		break;
1052 
1053 	case TS_WREQ_ORDREL:
1054 		if ((rstate = _t_adjust_state(fd, T_INREL)) < 0)  {
1055 			sv_errno = errno;
1056 			(void) _t_delete_tilink(fd);
1057 			sig_mutex_unlock(&ntiptr->ti_lock);
1058 			errno = sv_errno;
1059 			return (NULL);
1060 		}
1061 		ntiptr->ti_state = rstate;
1062 		break;
1063 	default:
1064 		t_errno = TSTATECHNG;
1065 		(void) _t_delete_tilink(fd);
1066 		sig_mutex_unlock(&ntiptr->ti_lock);
1067 		return (NULL);
1068 	}
1069 
1070 	/*
1071 	 * Sync information with timod.
1072 	 */
1073 	tsrp->tsr_flags = TSRF_QLEN_REQ;
1074 
1075 	rval = _t_do_ioctl(fd, ioctlbuf,
1076 	    (int)sizeof (struct ti_sync_req), TI_SYNC, &retlen);
1077 	expected_acksize = (int)sizeof (struct ti_sync_ack);
1078 
1079 	if (rval < 0) {
1080 		sv_errno = errno;
1081 		(void) _t_delete_tilink(fd);
1082 		t_errno = TSYSERR;
1083 		sig_mutex_unlock(&ntiptr->ti_lock);
1084 		errno = sv_errno;
1085 		return (NULL);
1086 	}
1087 
1088 	/*
1089 	 * This is a "less than" check as "struct ti_sync_ack" returned by
1090 	 * TI_SYNC can grow in size in future kernels. If/when a statically
1091 	 * linked application is run on a future kernel, it should not fail.
1092 	 */
1093 	if (retlen < expected_acksize) {
1094 		sv_errno = errno;
1095 		(void) _t_delete_tilink(fd);
1096 		t_errno = TSYSERR;
1097 		sig_mutex_unlock(&ntiptr->ti_lock);
1098 		errno = sv_errno;
1099 		return (NULL);
1100 	}
1101 
1102 	if (_T_IS_TLI(api_semantics))
1103 		tsap->tsa_qlen = 0; /* not needed for TLI */
1104 
1105 	ntiptr->ti_qlen = tsap->tsa_qlen;
1106 	sig_mutex_unlock(&ntiptr->ti_lock);
1107 	return (ntiptr);
1108 }
1109 
1110 
1111 static int
1112 _t_adjust_state(int fd, int instate)
1113 {
1114 	char ctlbuf[sizeof (t_scalar_t)];
1115 	char databuf[sizeof (int)]; /* size unimportant - anything > 0 */
1116 	struct strpeek arg;
1117 	int outstate, retval;
1118 
1119 	/*
1120 	 * Peek at message on stream head (if any)
1121 	 * and see if it is data
1122 	 */
1123 	arg.ctlbuf.buf = ctlbuf;
1124 	arg.ctlbuf.maxlen = (int)sizeof (ctlbuf);
1125 	arg.ctlbuf.len = 0;
1126 
1127 	arg.databuf.buf = databuf;
1128 	arg.databuf.maxlen = (int)sizeof (databuf);
1129 	arg.databuf.len = 0;
1130 
1131 	arg.flags = 0;
1132 
1133 	if ((retval = ioctl(fd, I_PEEK, &arg)) < 0)  {
1134 		t_errno = TSYSERR;
1135 		return (-1);
1136 	}
1137 	outstate = instate;
1138 	/*
1139 	 * If peek shows something at stream head, then
1140 	 * Adjust "outstate" based on some heuristics.
1141 	 */
1142 	if (retval > 0) {
1143 		switch (instate) {
1144 		case T_IDLE:
1145 			/*
1146 			 * The following heuristic is to handle data
1147 			 * ahead of T_DISCON_IND indications that might
1148 			 * be at the stream head waiting to be
1149 			 * read (T_DATA_IND or M_DATA)
1150 			 */
1151 			if (((arg.ctlbuf.len == 4) &&
1152 			    /* LINTED pointer cast */
1153 			    ((*(int32_t *)arg.ctlbuf.buf) == T_DATA_IND)) ||
1154 			    ((arg.ctlbuf.len == 0) && arg.databuf.len)) {
1155 				outstate = T_DATAXFER;
1156 			}
1157 			break;
1158 		case T_DATAXFER:
1159 			/*
1160 			 * The following heuristic is to handle
1161 			 * the case where the connection is established
1162 			 * and in data transfer state at the provider
1163 			 * but the T_CONN_CON has not yet been read
1164 			 * from the stream head.
1165 			 */
1166 			if ((arg.ctlbuf.len == 4) &&
1167 			    /* LINTED pointer cast */
1168 			    ((*(int32_t *)arg.ctlbuf.buf) == T_CONN_CON))
1169 				outstate = T_OUTCON;
1170 			break;
1171 		case T_INREL:
1172 			/*
1173 			 * The following heuristic is to handle data
1174 			 * ahead of T_ORDREL_IND indications that might
1175 			 * be at the stream head waiting to be
1176 			 * read (T_DATA_IND or M_DATA)
1177 			 */
1178 			if (((arg.ctlbuf.len == 4) &&
1179 			    /* LINTED pointer cast */
1180 			    ((*(int32_t *)arg.ctlbuf.buf) == T_DATA_IND)) ||
1181 			    ((arg.ctlbuf.len == 0) && arg.databuf.len)) {
1182 				outstate = T_DATAXFER;
1183 			}
1184 			break;
1185 		default:
1186 			break;
1187 		}
1188 	}
1189 	return (outstate);
1190 }
1191 
1192 /*
1193  * Assumes caller has blocked signals at least in this thread (for safe
1194  * malloc/free operations)
1195  */
1196 static int
1197 _t_cbuf_alloc(struct _ti_user *tiptr, char **retbuf)
1198 {
1199 	unsigned	size2;
1200 
1201 	assert(MUTEX_HELD(&tiptr->ti_lock));
1202 	size2 = tiptr->ti_ctlsize; /* same size as default ctlbuf */
1203 
1204 	if ((*retbuf = malloc(size2)) == NULL) {
1205 		return (-1);
1206 	}
1207 	return (size2);
1208 }
1209 
1210 
1211 /*
1212  * Assumes caller has blocked signals at least in this thread (for safe
1213  * malloc/free operations)
1214  */
1215 int
1216 _t_rbuf_alloc(struct _ti_user *tiptr, char **retbuf)
1217 {
1218 	unsigned	size1;
1219 
1220 	assert(MUTEX_HELD(&tiptr->ti_lock));
1221 	size1 = tiptr->ti_rcvsize; /* same size as default rcvbuf */
1222 
1223 	if ((*retbuf = malloc(size1)) == NULL) {
1224 		return (-1);
1225 	}
1226 	return (size1);
1227 }
1228 
1229 /*
1230  * Free lookbuffer structures and associated resources
1231  * Assumes ti_lock held for MT case.
1232  */
1233 static void
1234 _t_free_lookbufs(struct _ti_user *tiptr)
1235 {
1236 	struct _ti_lookbufs *tlbs, *prev_tlbs, *head_tlbs;
1237 
1238 	/*
1239 	 * Assertion:
1240 	 * The structure lock should be held or the global list
1241 	 * manipulation lock. The assumption is that nothing
1242 	 * else can access the descriptor since global list manipulation
1243 	 * lock is held so it is OK to manipulate fields without the
1244 	 * structure lock
1245 	 */
1246 	assert(MUTEX_HELD(&tiptr->ti_lock) || MUTEX_HELD(&_ti_userlock));
1247 
1248 	/*
1249 	 * Free only the buffers in the first lookbuf
1250 	 */
1251 	head_tlbs = &tiptr->ti_lookbufs;
1252 	if (head_tlbs->tl_lookdbuf != NULL) {
1253 		free(head_tlbs->tl_lookdbuf);
1254 		head_tlbs->tl_lookdbuf = NULL;
1255 	}
1256 	free(head_tlbs->tl_lookcbuf);
1257 	head_tlbs->tl_lookcbuf = NULL;
1258 	/*
1259 	 * Free the node and the buffers in the rest of the
1260 	 * list
1261 	 */
1262 
1263 	tlbs = head_tlbs->tl_next;
1264 	head_tlbs->tl_next = NULL;
1265 
1266 	while (tlbs != NULL) {
1267 		if (tlbs->tl_lookdbuf != NULL)
1268 			free(tlbs->tl_lookdbuf);
1269 		free(tlbs->tl_lookcbuf);
1270 		prev_tlbs = tlbs;
1271 		tlbs = tlbs->tl_next;
1272 		free(prev_tlbs);
1273 	}
1274 }
1275 
1276 /*
1277  * Free lookbuffer event list head.
1278  * Consume current lookbuffer event
1279  * Assumes ti_lock held for MT case.
1280  * Note: The head of this list is part of the instance
1281  * structure so the code is a little unorthodox.
1282  */
1283 void
1284 _t_free_looklist_head(struct _ti_user *tiptr)
1285 {
1286 	struct _ti_lookbufs *tlbs, *next_tlbs;
1287 
1288 	tlbs = &tiptr->ti_lookbufs;
1289 
1290 	if (tlbs->tl_next) {
1291 		/*
1292 		 * Free the control and data buffers
1293 		 */
1294 		if (tlbs->tl_lookdbuf != NULL)
1295 			free(tlbs->tl_lookdbuf);
1296 		free(tlbs->tl_lookcbuf);
1297 		/*
1298 		 * Replace with next lookbuf event contents
1299 		 */
1300 		next_tlbs = tlbs->tl_next;
1301 		tlbs->tl_next = next_tlbs->tl_next;
1302 		tlbs->tl_lookcbuf = next_tlbs->tl_lookcbuf;
1303 		tlbs->tl_lookclen = next_tlbs->tl_lookclen;
1304 		tlbs->tl_lookdbuf = next_tlbs->tl_lookdbuf;
1305 		tlbs->tl_lookdlen = next_tlbs->tl_lookdlen;
1306 		free(next_tlbs);
1307 		/*
1308 		 * Decrement the flag - should never get to zero.
1309 		 * in this path
1310 		 */
1311 		tiptr->ti_lookcnt--;
1312 		assert(tiptr->ti_lookcnt > 0);
1313 	} else {
1314 		/*
1315 		 * No more look buffer events - just clear the flag
1316 		 * and leave the buffers alone
1317 		 */
1318 		assert(tiptr->ti_lookcnt == 1);
1319 		tiptr->ti_lookcnt = 0;
1320 	}
1321 }
1322 
1323 /*
1324  * Discard lookbuffer events.
1325  * Assumes ti_lock held for MT case.
1326  */
1327 void
1328 _t_flush_lookevents(struct _ti_user *tiptr)
1329 {
1330 	struct _ti_lookbufs *tlbs, *prev_tlbs;
1331 
1332 	/*
1333 	 * Leave the first nodes buffers alone (i.e. allocated)
1334 	 * but reset the flag.
1335 	 */
1336 	assert(MUTEX_HELD(&tiptr->ti_lock));
1337 	tiptr->ti_lookcnt = 0;
1338 	/*
1339 	 * Blow away the rest of the list
1340 	 */
1341 	tlbs = tiptr->ti_lookbufs.tl_next;
1342 	tiptr->ti_lookbufs.tl_next = NULL;
1343 	while (tlbs != NULL) {
1344 		if (tlbs->tl_lookdbuf != NULL)
1345 			free(tlbs->tl_lookdbuf);
1346 		free(tlbs->tl_lookcbuf);
1347 		prev_tlbs = tlbs;
1348 		tlbs = tlbs->tl_next;
1349 		free(prev_tlbs);
1350 	}
1351 }
1352 
1353 
1354 /*
1355  * This routine checks if the receive. buffer in the instance structure
1356  * is available (non-null). If it is, the buffer is acquired and marked busy
1357  * (null). If it is busy (possible in MT programs), it allocates a new
1358  * buffer and sets a flag indicating new memory was allocated and the caller
1359  * has to free it.
1360  */
1361 int
1362 _t_acquire_ctlbuf(
1363 	struct _ti_user *tiptr,
1364 	struct strbuf *ctlbufp,
1365 	int *didallocp)
1366 {
1367 	*didallocp = 0;
1368 
1369 	ctlbufp->len = 0;
1370 	if (tiptr->ti_ctlbuf) {
1371 		ctlbufp->buf = tiptr->ti_ctlbuf;
1372 		tiptr->ti_ctlbuf = NULL;
1373 		ctlbufp->maxlen = tiptr->ti_ctlsize;
1374 	} else {
1375 		/*
1376 		 * tiptr->ti_ctlbuf is in use
1377 		 * allocate new buffer and free after use.
1378 		 */
1379 		if ((ctlbufp->maxlen = _t_cbuf_alloc(tiptr,
1380 		    &ctlbufp->buf)) < 0) {
1381 			t_errno = TSYSERR;
1382 			return (-1);
1383 		}
1384 		*didallocp = 1;
1385 	}
1386 	return (0);
1387 }
1388 
1389 /*
1390  * This routine checks if the receive buffer in the instance structure
1391  * is available (non-null). If it is, the buffer is acquired and marked busy
1392  * (null). If it is busy (possible in MT programs), it allocates a new
1393  * buffer and sets a flag indicating new memory was allocated and the caller
1394  * has to free it.
1395  * Note: The receive buffer pointer can also be null if the transport
1396  * provider does not support connect/disconnect data, (e.g. TCP) - not
1397  * just when it is "busy". In that case, ti_rcvsize will be 0 and that is
1398  * used to instantiate the databuf which points to a null buffer of
1399  * length 0 which is the right thing to do for that case.
1400  */
1401 int
1402 _t_acquire_databuf(
1403 	struct _ti_user *tiptr,
1404 	struct strbuf *databufp,
1405 	int *didallocp)
1406 {
1407 	*didallocp = 0;
1408 
1409 	databufp->len = 0;
1410 	if (tiptr->ti_rcvbuf) {
1411 		assert(tiptr->ti_rcvsize != 0);
1412 		databufp->buf = tiptr->ti_rcvbuf;
1413 		tiptr->ti_rcvbuf = NULL;
1414 		databufp->maxlen = tiptr->ti_rcvsize;
1415 	} else if (tiptr->ti_rcvsize == 0) {
1416 		databufp->buf = NULL;
1417 		databufp->maxlen = 0;
1418 	} else {
1419 		/*
1420 		 * tiptr->ti_rcvbuf is in use
1421 		 * allocate new buffer and free after use.
1422 		 */
1423 		if ((databufp->maxlen = _t_rbuf_alloc(tiptr,
1424 		    &databufp->buf)) < 0) {
1425 			t_errno = TSYSERR;
1426 			return (-1);
1427 		}
1428 		*didallocp = 1;
1429 	}
1430 	return (0);
1431 }
1432 
1433 /*
1434  * This routine requests timod to look for any expedited data
1435  * queued in the "receive buffers" in the kernel. Used for XTI
1436  * t_look() semantics for transports that send expedited data
1437  * data inline (e.g TCP).
1438  * Returns -1 for failure
1439  * Returns 0 for success
1440  * 	On a successful return, the location pointed by "expedited_queuedp"
1441  * 	contains
1442  *		0 if no expedited data is found queued in "receive buffers"
1443  *		1 if expedited data is found queued in "receive buffers"
1444  */
1445 
1446 int
1447 _t_expinline_queued(int fd, int *expedited_queuedp)
1448 {
1449 	union {
1450 		struct ti_sync_req ti_req;
1451 		struct ti_sync_ack ti_ack;
1452 		char pad[128];
1453 	} ioctl_data;
1454 	void *ioctlbuf = &ioctl_data; /* for TI_SYNC with room to grow */
1455 			    /* preferred location first local variable */
1456 			    /* see note in _t_create above */
1457 	struct ti_sync_req *tsrp = (struct ti_sync_req *)ioctlbuf;
1458 	struct ti_sync_ack *tsap = (struct ti_sync_ack *)ioctlbuf;
1459 	int rval, retlen;
1460 
1461 	*expedited_queuedp = 0;
1462 	/* request info on rq expinds  */
1463 	tsrp->tsr_flags = TSRF_IS_EXP_IN_RCVBUF;
1464 	do {
1465 		rval = _t_do_ioctl(fd, ioctlbuf,
1466 		    (int)sizeof (struct T_info_req), TI_SYNC, &retlen);
1467 	} while (rval < 0 && errno == EINTR);
1468 
1469 	if (rval < 0)
1470 		return (-1);
1471 
1472 	/*
1473 	 * This is a "less than" check as "struct ti_sync_ack" returned by
1474 	 * TI_SYNC can grow in size in future kernels. If/when a statically
1475 	 * linked application is run on a future kernel, it should not fail.
1476 	 */
1477 	if (retlen < (int)sizeof (struct ti_sync_ack)) {
1478 		t_errno = TSYSERR;
1479 		errno = EIO;
1480 		return (-1);
1481 	}
1482 	if (tsap->tsa_flags & TSAF_EXP_QUEUED)
1483 		*expedited_queuedp = 1;
1484 	return (0);
1485 }
1486 
1487 /*
1488  * Support functions for use by functions that do scatter/gather
1489  * like t_sndv(), t_rcvv() etc..follow below.
1490  */
1491 
1492 /*
1493  * _t_bytecount_upto_intmax() :
1494  *	    Sum of the lengths of the individual buffers in
1495  *	    the t_iovec array. If the sum exceeds INT_MAX
1496  *	    it is truncated to INT_MAX.
1497  */
1498 unsigned int
1499 _t_bytecount_upto_intmax(const struct t_iovec *tiov, unsigned int tiovcount)
1500 {
1501 	size_t nbytes;
1502 	int i;
1503 
1504 	nbytes = 0;
1505 	for (i = 0; i < tiovcount && nbytes < INT_MAX; i++) {
1506 		if (tiov[i].iov_len >= INT_MAX) {
1507 			nbytes = INT_MAX;
1508 			break;
1509 		}
1510 		nbytes += tiov[i].iov_len;
1511 	}
1512 
1513 	if (nbytes > INT_MAX)
1514 		nbytes = INT_MAX;
1515 
1516 	return ((unsigned int)nbytes);
1517 }
1518 
1519 /*
1520  * Gather the data in the t_iovec buffers, into a single linear buffer
1521  * starting at dataptr. Caller must have allocated sufficient space
1522  * starting at dataptr. The total amount of data that is gathered is
1523  * limited to INT_MAX. Any remaining data in the t_iovec buffers is
1524  * not copied.
1525  */
1526 void
1527 _t_gather(char *dataptr, const struct t_iovec *tiov, unsigned int tiovcount)
1528 {
1529 	char *curptr;
1530 	unsigned int cur_count;
1531 	unsigned int nbytes_remaining;
1532 	int i;
1533 
1534 	curptr = dataptr;
1535 	cur_count = 0;
1536 
1537 	nbytes_remaining = _t_bytecount_upto_intmax(tiov, tiovcount);
1538 	for (i = 0; i < tiovcount && nbytes_remaining != 0; i++) {
1539 		if (tiov[i].iov_len <= nbytes_remaining)
1540 			cur_count = (int)tiov[i].iov_len;
1541 		else
1542 			cur_count = nbytes_remaining;
1543 		(void) memcpy(curptr, tiov[i].iov_base, cur_count);
1544 		curptr += cur_count;
1545 		nbytes_remaining -= cur_count;
1546 	}
1547 }
1548 
1549 /*
1550  * Scatter the data from the single linear buffer at pdatabuf->buf into
1551  * the t_iovec buffers.
1552  */
1553 void
1554 _t_scatter(struct strbuf *pdatabuf, struct t_iovec *tiov, int tiovcount)
1555 {
1556 	char *curptr;
1557 	unsigned int nbytes_remaining;
1558 	unsigned int curlen;
1559 	int i;
1560 
1561 	/*
1562 	 * There cannot be any uncopied data leftover in pdatabuf
1563 	 * at the conclusion of this function. (asserted below)
1564 	 */
1565 	assert(pdatabuf->len <= _t_bytecount_upto_intmax(tiov, tiovcount));
1566 	curptr = pdatabuf->buf;
1567 	nbytes_remaining = pdatabuf->len;
1568 	for (i = 0; i < tiovcount && nbytes_remaining != 0; i++) {
1569 		if (tiov[i].iov_len < nbytes_remaining)
1570 			curlen = (unsigned int)tiov[i].iov_len;
1571 		else
1572 			curlen = nbytes_remaining;
1573 		(void) memcpy(tiov[i].iov_base, curptr, curlen);
1574 		curptr += curlen;
1575 		nbytes_remaining -= curlen;
1576 	}
1577 }
1578 
1579 /*
1580  * Adjust the iovec array, for subsequent use. Examine each element in the
1581  * iovec array,and zero out the iov_len if the buffer was sent fully.
1582  * otherwise the buffer was only partially sent, so adjust both iov_len and
1583  * iov_base.
1584  *
1585  */
1586 void
1587 _t_adjust_iov(int bytes_sent, struct iovec *iov, int *iovcountp)
1588 {
1589 
1590 	int i;
1591 
1592 	for (i = 0; i < *iovcountp && bytes_sent; i++) {
1593 		if (iov[i].iov_len == 0)
1594 			continue;
1595 		if (bytes_sent < iov[i].iov_len)
1596 			break;
1597 		else {
1598 			bytes_sent -= iov[i].iov_len;
1599 			iov[i].iov_len = 0;
1600 		}
1601 	}
1602 	iov[i].iov_len -= bytes_sent;
1603 	iov[i].iov_base += bytes_sent;
1604 }
1605 
1606 /*
1607  * Copy the t_iovec array to the iovec array while taking care to see
1608  * that the sum of the buffer lengths in the result is not more than
1609  * INT_MAX. This function requires that T_IOV_MAX is no larger than
1610  * IOV_MAX. Otherwise the resulting array is not a suitable input to
1611  * writev(). If the sum of the lengths in t_iovec is zero, so is the
1612  * resulting iovec.
1613  */
1614 void
1615 _t_copy_tiov_to_iov(const struct t_iovec *tiov, int tiovcount,
1616     struct iovec *iov, int *iovcountp)
1617 {
1618 	int i;
1619 	unsigned int nbytes_remaining;
1620 
1621 	nbytes_remaining = _t_bytecount_upto_intmax(tiov, tiovcount);
1622 	i = 0;
1623 	do {
1624 		iov[i].iov_base = tiov[i].iov_base;
1625 		if (tiov[i].iov_len > nbytes_remaining)
1626 			iov[i].iov_len = nbytes_remaining;
1627 		else
1628 			iov[i].iov_len  = tiov[i].iov_len;
1629 		nbytes_remaining -= iov[i].iov_len;
1630 		i++;
1631 	} while (nbytes_remaining != 0 && i < tiovcount);
1632 
1633 	*iovcountp = i;
1634 }
1635 
1636 /*
1637  * Routine called after connection establishment on transports where
1638  * connection establishment changes certain transport attributes such as
1639  * TIDU_size
1640  */
1641 int
1642 _t_do_postconn_sync(int fd, struct _ti_user *tiptr)
1643 {
1644 	union {
1645 		struct T_capability_req tc_req;
1646 		struct T_capability_ack tc_ack;
1647 	} ioctl_data;
1648 
1649 	void *ioctlbuf = &ioctl_data;
1650 	int expected_acksize;
1651 	int retlen, rval;
1652 	struct T_capability_req *tc_reqp = (struct T_capability_req *)ioctlbuf;
1653 	struct T_capability_ack *tc_ackp = (struct T_capability_ack *)ioctlbuf;
1654 	struct T_info_ack *tiap;
1655 
1656 	/*
1657 	 * This T_CAPABILITY_REQ should not fail, even if it is unsupported
1658 	 * by the transport provider. timod will emulate it in that case.
1659 	 */
1660 	tc_reqp->PRIM_type = T_CAPABILITY_REQ;
1661 	tc_reqp->CAP_bits1 = TC1_INFO;
1662 	rval = _t_do_ioctl(fd, (char *)ioctlbuf,
1663 	    (int)sizeof (struct T_capability_ack), TI_CAPABILITY, &retlen);
1664 	expected_acksize = (int)sizeof (struct T_capability_ack);
1665 
1666 	if (rval < 0)
1667 		return (-1);
1668 
1669 	/*
1670 	 * T_capability TPI messages are extensible and can grow in future.
1671 	 * However timod will take care of returning no more information
1672 	 * than what was requested, and truncating the "extended"
1673 	 * information towards the end of the T_capability_ack, if necessary.
1674 	 */
1675 	if (retlen != expected_acksize) {
1676 		t_errno = TSYSERR;
1677 		errno = EIO;
1678 		return (-1);
1679 	}
1680 
1681 	/*
1682 	 * The T_info_ack part of the T_capability_ack is guaranteed to be
1683 	 * present only if the corresponding TC1_INFO bit is set
1684 	 */
1685 	if ((tc_ackp->CAP_bits1 & TC1_INFO) == 0) {
1686 		t_errno = TSYSERR;
1687 		errno = EPROTO;
1688 		return (-1);
1689 	}
1690 
1691 	tiap = &tc_ackp->INFO_ack;
1692 	if (tiap->PRIM_type != T_INFO_ACK) {
1693 		t_errno = TSYSERR;
1694 		errno = EPROTO;
1695 		return (-1);
1696 	}
1697 
1698 	/*
1699 	 * Note: Sync with latest information returned in "struct T_info_ack
1700 	 * but we deliberately not sync the state here as user level state
1701 	 * construction here is not required, only update of attributes which
1702 	 * may have changed because of negotations during connection
1703 	 * establsihment
1704 	 */
1705 	assert(tiap->TIDU_size > 0);
1706 	tiptr->ti_maxpsz = tiap->TIDU_size;
1707 	assert(tiap->TSDU_size >= T_INVALID);
1708 	tiptr->ti_tsdusize = tiap->TSDU_size;
1709 	assert(tiap->ETSDU_size >= T_INVALID);
1710 	tiptr->ti_etsdusize = tiap->ETSDU_size;
1711 	assert(tiap->CDATA_size >= T_INVALID);
1712 	tiptr->ti_cdatasize = tiap->CDATA_size;
1713 	assert(tiap->DDATA_size >= T_INVALID);
1714 	tiptr->ti_ddatasize = tiap->DDATA_size;
1715 	tiptr->ti_prov_flag = tiap->PROVIDER_flag;
1716 
1717 	return (0);
1718 }
1719