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