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