xref: /illumos-gate/usr/src/lib/libnsl/nsl/t_alloc.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 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.4.1.2 */
33 
34 #include "mt.h"
35 #include <stdlib.h>
36 #include <rpc/trace.h>
37 #include <unistd.h>
38 #include <stropts.h>
39 #include <sys/stream.h>
40 #define	_SUN_TPI_VERSION 2
41 #include <sys/tihdr.h>
42 #include <sys/timod.h>
43 #include <xti.h>
44 #include <stdio.h>
45 #include <errno.h>
46 #include <signal.h>
47 #include "tx.h"
48 
49 /*
50  * Function protoypes
51  */
52 static int _alloc_buf(struct netbuf *buf, t_scalar_t n, int fields,
53     int api_semantics);
54 
55 char *
56 _tx_alloc(int fd, int struct_type, int fields, int api_semantics)
57 {
58 	struct strioctl strioc;
59 	struct T_info_ack info;
60 	union structptrs {
61 		char	*caddr;
62 		struct t_bind *bind;
63 		struct t_call *call;
64 		struct t_discon *dis;
65 		struct t_optmgmt *opt;
66 		struct t_unitdata *udata;
67 		struct t_uderr *uderr;
68 		struct t_info *info;
69 	} p;
70 	unsigned int dsize;
71 	struct _ti_user *tiptr;
72 	int retval, sv_errno;
73 	t_scalar_t optsize;
74 
75 	trace4(TR_t_alloc, 0, fd, struct_type, fields);
76 	if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL) {
77 		sv_errno = errno;
78 		trace4(TR_t_alloc, 1, fd, struct_type, fields);
79 		errno = sv_errno;
80 		return (NULL);
81 	}
82 	sig_mutex_lock(&tiptr->ti_lock);
83 
84 	/*
85 	 * Get size info for T_ADDR, T_OPT, and T_UDATA fields
86 	 */
87 	info.PRIM_type = T_INFO_REQ;
88 	strioc.ic_cmd = TI_GETINFO;
89 	strioc.ic_timout = -1;
90 	strioc.ic_len = (int)sizeof (struct T_info_req);
91 	strioc.ic_dp = (char *)&info;
92 	do {
93 		retval = _ioctl(fd, I_STR, &strioc);
94 	} while (retval < 0 && errno == EINTR);
95 
96 	if (retval < 0) {
97 		sv_errno = errno;
98 		sig_mutex_unlock(&tiptr->ti_lock);
99 		t_errno = TSYSERR;
100 		trace4(TR_t_alloc, 1, fd, struct_type, fields);
101 		errno = sv_errno;
102 		return (NULL);
103 	}
104 
105 	if (strioc.ic_len != (int)sizeof (struct T_info_ack)) {
106 		t_errno = TSYSERR;
107 		sig_mutex_unlock(&tiptr->ti_lock);
108 		trace4(TR_t_alloc, 1, fd, struct_type, fields);
109 		errno = EIO;
110 		return (NULL);
111 	}
112 
113 
114 	/*
115 	 * Malloc appropriate structure and the specified
116 	 * fields within each structure.  Initialize the
117 	 * 'buf' and 'maxlen' fields of each.
118 	 */
119 	switch (struct_type) {
120 
121 	case T_BIND:
122 		if ((p.bind = (struct t_bind *)
123 		    calloc(1, sizeof (struct t_bind))) == NULL)
124 				goto errout;
125 		if (fields & T_ADDR) {
126 			if (_alloc_buf(&p.bind->addr,
127 			    info.ADDR_size,
128 			    fields, api_semantics) < 0)
129 				goto errout;
130 		}
131 		trace4(TR_t_alloc, 1, fd, struct_type, fields);
132 		sig_mutex_unlock(&tiptr->ti_lock);
133 		return ((char *)p.bind);
134 
135 	case T_CALL:
136 		if ((p.call = (struct t_call *)
137 			calloc(1, sizeof (struct t_call))) == NULL)
138 				goto errout;
139 		if (fields & T_ADDR) {
140 			if (_alloc_buf(&p.call->addr,
141 			    info.ADDR_size,
142 			    fields, api_semantics) < 0)
143 				goto errout;
144 		}
145 		if (fields & T_OPT) {
146 			if (info.OPT_size >= 0 && _T_IS_XTI(api_semantics))
147 				/* compensate for XTI level options */
148 				optsize = info.OPT_size +
149 				    TX_XTI_LEVEL_MAX_OPTBUF;
150 			else
151 				optsize = info.OPT_size;
152 			if (_alloc_buf(&p.call->opt, optsize,
153 			    fields, api_semantics) < 0)
154 				goto errout;
155 		}
156 		if (fields & T_UDATA) {
157 			dsize = _T_MAX((int)info.CDATA_size,
158 					(int)info.DDATA_size);
159 			if (_alloc_buf(&p.call->udata, (t_scalar_t)dsize,
160 					fields, api_semantics) < 0)
161 				goto errout;
162 		}
163 		sig_mutex_unlock(&tiptr->ti_lock);
164 		trace4(TR_t_alloc, 1, fd, struct_type, fields);
165 		return ((char *)p.call);
166 
167 	case T_OPTMGMT:
168 		if ((p.opt = (struct t_optmgmt *)
169 			calloc(1, sizeof (struct t_optmgmt))) == NULL)
170 				goto errout;
171 		if (fields & T_OPT) {
172 			if (info.OPT_size >= 0 && _T_IS_XTI(api_semantics))
173 				/* compensate for XTI level options */
174 				optsize = info.OPT_size +
175 				    TX_XTI_LEVEL_MAX_OPTBUF;
176 			else
177 				optsize = info.OPT_size;
178 			if (_alloc_buf(&p.opt->opt, optsize,
179 				fields, api_semantics) < 0)
180 				goto errout;
181 		}
182 		sig_mutex_unlock(&tiptr->ti_lock);
183 		trace4(TR_t_alloc, 1, fd, struct_type, fields);
184 		return ((char *)p.opt);
185 
186 	case T_DIS:
187 		if ((p.dis = (struct t_discon *)
188 		    calloc(1, sizeof (struct t_discon))) == NULL)
189 			goto errout;
190 		if (fields & T_UDATA) {
191 			if (_alloc_buf(&p.dis->udata, info.DDATA_size,
192 				fields, api_semantics) < 0)
193 				goto errout;
194 		}
195 		sig_mutex_unlock(&tiptr->ti_lock);
196 		trace4(TR_t_alloc, 1, fd, struct_type, fields);
197 		return ((char *)p.dis);
198 
199 	case T_UNITDATA:
200 		if ((p.udata = (struct t_unitdata *)
201 		    calloc(1, sizeof (struct t_unitdata))) == NULL)
202 				goto errout;
203 		if (fields & T_ADDR) {
204 			if (_alloc_buf(&p.udata->addr, info.ADDR_size,
205 				fields, api_semantics) < 0)
206 				goto errout;
207 		}
208 		if (fields & T_OPT) {
209 			if (info.OPT_size >= 0 && _T_IS_XTI(api_semantics))
210 				/* compensate for XTI level options */
211 				optsize = info.OPT_size +
212 				    TX_XTI_LEVEL_MAX_OPTBUF;
213 			else
214 				optsize = info.OPT_size;
215 			if (_alloc_buf(&p.udata->opt, optsize,
216 				fields, api_semantics) < 0)
217 				goto errout;
218 		}
219 		if (fields & T_UDATA) {
220 			if (_alloc_buf(&p.udata->udata, info.TSDU_size,
221 				fields, api_semantics) < 0)
222 				goto errout;
223 		}
224 		sig_mutex_unlock(&tiptr->ti_lock);
225 		trace4(TR_t_alloc, 1, fd, struct_type, fields);
226 		return ((char *)p.udata);
227 
228 	case T_UDERROR:
229 		if ((p.uderr = (struct t_uderr *)
230 			calloc(1, sizeof (struct t_uderr))) == NULL)
231 				goto errout;
232 		if (fields & T_ADDR) {
233 			if (_alloc_buf(&p.uderr->addr, info.ADDR_size,
234 				fields, api_semantics) < 0)
235 				goto errout;
236 		}
237 		if (fields & T_OPT) {
238 			if (info.OPT_size >= 0 && _T_IS_XTI(api_semantics))
239 				/* compensate for XTI level options */
240 				optsize = info.OPT_size +
241 				    TX_XTI_LEVEL_MAX_OPTBUF;
242 			else
243 				optsize = info.OPT_size;
244 			if (_alloc_buf(&p.uderr->opt, optsize,
245 				fields, api_semantics) < 0)
246 				goto errout;
247 		}
248 		sig_mutex_unlock(&tiptr->ti_lock);
249 		trace4(TR_t_alloc, 1, fd, struct_type, fields);
250 		return ((char *)p.uderr);
251 
252 	case T_INFO:
253 		if ((p.info = (struct t_info *)
254 			calloc(1, sizeof (struct t_info))) == NULL)
255 				goto errout;
256 		sig_mutex_unlock(&tiptr->ti_lock);
257 		trace4(TR_t_alloc, 1, fd, struct_type, fields);
258 		return ((char *)p.info);
259 
260 	default:
261 		if (_T_IS_XTI(api_semantics)) {
262 			t_errno = TNOSTRUCTYPE;
263 			sig_mutex_unlock(&tiptr->ti_lock);
264 			trace4(TR_t_alloc, 1, fd, struct_type, fields);
265 		} else {	/* TX_TLI_API */
266 			t_errno = TSYSERR;
267 			sig_mutex_unlock(&tiptr->ti_lock);
268 			trace4(TR_t_alloc, 1, fd, struct_type, fields);
269 			errno = EINVAL;
270 		}
271 		return (NULL);
272 	}
273 
274 	/*
275 	 * Clean up. Set t_errno to TSYSERR.
276 	 * If it is because memory could not be allocated
277 	 * then errno already should have been set to
278 	 * ENOMEM
279 	 */
280 errout:
281 	if (p.caddr)
282 		(void) t_free(p.caddr, struct_type);
283 
284 	t_errno = TSYSERR;
285 	sig_mutex_unlock(&tiptr->ti_lock);
286 	trace4(TR_t_alloc, 1, fd, struct_type, fields);
287 	return (NULL);
288 }
289 
290 static int
291 _alloc_buf(struct netbuf *buf, t_scalar_t n, int fields, int api_semantics)
292 {
293 	trace2(TR__alloc_buf, 0, n);
294 	switch (n) {
295 	case T_INFINITE /* -1 */:
296 		if (_T_IS_XTI(api_semantics)) {
297 			buf->buf = NULL;
298 			buf->maxlen = 0;
299 			if (fields != T_ALL) {
300 				/*
301 				 * Do not return error
302 				 * if T_ALL is used.
303 				 */
304 				trace2(TR__alloc_buf, 1, n);
305 				errno = EINVAL;
306 				return (-1);
307 			}
308 		} else {	/* TX_TLI_API */
309 			/*
310 			 * retain TLI behavior
311 			 */
312 			if ((buf->buf = calloc(1, 1024)) == NULL) {
313 				trace2(TR__alloc_buf, 1, n);
314 				errno = ENOMEM;
315 				return (-1);
316 			} else
317 				buf->maxlen = 1024;
318 		}
319 		break;
320 
321 	case 0:
322 		buf->buf = NULL;
323 		buf->maxlen = 0;
324 		break;
325 
326 	case T_INVALID /* -2 */:
327 		if (_T_IS_XTI(api_semantics)) {
328 			buf->buf = NULL;
329 			buf->maxlen = 0;
330 			if (fields != T_ALL) {
331 				/*
332 				 * Do not return error
333 				 * if T_ALL is used.
334 				 */
335 				trace2(TR__alloc_buf, 1, n);
336 				errno = EINVAL;
337 				return (-1);
338 			}
339 		} else {	/* TX_TLI_API */
340 			/*
341 			 * retain TLI behavior
342 			 */
343 			buf->buf = NULL;
344 			buf->maxlen = 0;
345 		}
346 		break;
347 
348 	default:
349 		if ((buf->buf = calloc(1, (size_t)n)) == NULL) {
350 			trace2(TR__alloc_buf, 1, n);
351 			errno = ENOMEM;
352 			return (-1);
353 		} else
354 			buf->maxlen = n;
355 		break;
356 	}
357 	trace2(TR__alloc_buf, 1, n);
358 	return (0);
359 }
360