isns_pdu.c revision 1.5 1 1.5 andvar /* $NetBSD: isns_pdu.c,v 1.5 2021/08/21 23:00:30 andvar Exp $ */
2 1.1 agc
3 1.1 agc /*-
4 1.1 agc * Copyright (c) 2004,2009 The NetBSD Foundation, Inc.
5 1.1 agc * All rights reserved.
6 1.1 agc *
7 1.1 agc * This code is derived from software contributed to The NetBSD Foundation
8 1.1 agc * by Wasabi Systems, Inc.
9 1.1 agc *
10 1.1 agc * Redistribution and use in source and binary forms, with or without
11 1.1 agc * modification, are permitted provided that the following conditions
12 1.1 agc * are met:
13 1.1 agc * 1. Redistributions of source code must retain the above copyright
14 1.1 agc * notice, this list of conditions and the following disclaimer.
15 1.1 agc * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 agc * notice, this list of conditions and the following disclaimer in the
17 1.1 agc * documentation and/or other materials provided with the distribution.
18 1.1 agc *
19 1.1 agc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 agc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 agc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 agc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 agc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 agc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 agc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 agc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 agc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 agc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 agc * POSSIBILITY OF SUCH DAMAGE.
30 1.1 agc */
31 1.1 agc
32 1.1 agc /*
33 1.1 agc * isns_pdu.c
34 1.1 agc */
35 1.1 agc
36 1.1 agc
37 1.1 agc #include <sys/cdefs.h>
38 1.5 andvar __RCSID("$NetBSD: isns_pdu.c,v 1.5 2021/08/21 23:00:30 andvar Exp $");
39 1.1 agc
40 1.1 agc
41 1.1 agc #include <sys/types.h>
42 1.1 agc #include <sys/param.h>
43 1.1 agc
44 1.1 agc #include <assert.h>
45 1.1 agc #include <errno.h>
46 1.1 agc #include <string.h>
47 1.1 agc
48 1.1 agc #include "isns.h"
49 1.1 agc #include "isns_config.h"
50 1.1 agc
51 1.1 agc
52 1.1 agc /*
53 1.1 agc * Local function prototypes.
54 1.1 agc */
55 1.1 agc static struct isns_buffer_list_s *isns_lookup_buffer_list(int);
56 1.1 agc
57 1.1 agc static struct isns_pdu_s *isns_init_pdu(struct isns_buffer_s *,
58 1.1 agc struct isns_config_s *, uint16_t, uint16_t, uint16_t);
59 1.1 agc static int isns_add_pdu_payload_data(struct isns_trans_s *, const void *, int);
60 1.1 agc static void isns_get_tlv_info_advance(struct isns_get_tlv_info_s *);
61 1.1 agc static int isns_get_tlv_uint32(struct isns_get_tlv_info_s *, uint32_t *);
62 1.1 agc static int isns_get_tlv_data(struct isns_get_tlv_info_s *, int, void **);
63 1.1 agc
64 1.1 agc static void isns_add_pdu_list(struct isns_pdu_s **, struct isns_pdu_s *);
65 1.1 agc static struct isns_buffer_s *isns_get_pdu_head_buffer(struct isns_pdu_s *);
66 1.1 agc #if 0
67 1.1 agc static struct isns_buffer_s *isns_get_pdu_tail_buffer(struct isns_pdu_s *);
68 1.1 agc #endif
69 1.1 agc static struct isns_buffer_s *isns_get_pdu_active_buffer(struct isns_pdu_s *);
70 1.1 agc
71 1.1 agc static uint32_t isns_get_next_trans_id(void);
72 1.1 agc
73 1.1 agc /*
74 1.1 agc * Buffer pool structures and global (static) var.
75 1.1 agc */
76 1.1 agc struct isns_buffer_list_s {
77 1.1 agc int buf_size;
78 1.1 agc int alloc_count;
79 1.1 agc struct isns_buffer_s *head;
80 1.1 agc struct isns_buffer_list_s *next;
81 1.1 agc };
82 1.1 agc
83 1.1 agc struct isns_buffer_pool_s {
84 1.1 agc int active;
85 1.1 agc struct isns_buffer_list_s *list_p;
86 1.1 agc pthread_mutex_t mutex;
87 1.1 agc };
88 1.1 agc
89 1.1 agc static struct isns_buffer_pool_s G_buffer_pool;
90 1.1 agc
91 1.1 agc
92 1.1 agc /*
93 1.1 agc * isns_init_buffer_pool - initialize buffer pool for use
94 1.1 agc */
95 1.1 agc void
96 1.3 matt isns_init_buffer_pool(void)
97 1.1 agc {
98 1.1 agc pthread_mutexattr_t mutexattr;
99 1.1 agc
100 1.1 agc DBG("isns_init_buffer_pool: entered\n");
101 1.1 agc
102 1.1 agc assert(!G_buffer_pool.active);
103 1.1 agc
104 1.1 agc pthread_mutexattr_init(&mutexattr);
105 1.1 agc pthread_mutexattr_settype(&mutexattr, ISNS_MUTEX_TYPE_NORMAL);
106 1.1 agc pthread_mutex_init(&G_buffer_pool.mutex, &mutexattr);
107 1.1 agc
108 1.1 agc G_buffer_pool.active = 1;
109 1.1 agc }
110 1.1 agc
111 1.1 agc
112 1.1 agc /*
113 1.1 agc * isns_lookup_buffer_list - locates the pool buffer list for the buf_size
114 1.1 agc * specified.
115 1.1 agc *
116 1.1 agc * Returns: pointer to list in pool containing buf_size buffers
117 1.1 agc * NULL if no list for size indicated exists
118 1.1 agc */
119 1.1 agc static struct isns_buffer_list_s *
120 1.1 agc isns_lookup_buffer_list(int buf_size)
121 1.1 agc {
122 1.1 agc struct isns_buffer_list_s *list_p;
123 1.1 agc
124 1.1 agc /*
125 1.1 agc * WARNING: G_buffer_pool.mutex MUST already be locked.
126 1.1 agc */
127 1.1 agc
128 1.1 agc list_p = G_buffer_pool.list_p;
129 1.1 agc while (list_p != NULL) {
130 1.1 agc if (list_p->buf_size == buf_size)
131 1.1 agc break;
132 1.1 agc list_p = list_p->next;
133 1.1 agc }
134 1.1 agc
135 1.1 agc return list_p;
136 1.1 agc }
137 1.1 agc
138 1.1 agc
139 1.1 agc /*
140 1.1 agc * isns_add_buffer_pool - allocates buffers of in pool
141 1.1 agc *
142 1.1 agc * If a list containing buf_size buffers already exists in pool, additional
143 1.1 agc * buffers are added (allocated) to the list.
144 1.1 agc */
145 1.1 agc int
146 1.1 agc isns_add_buffer_pool(int buf_size, int count)
147 1.1 agc {
148 1.1 agc struct isns_buffer_list_s *list_p, *p, *p_next;
149 1.1 agc struct isns_buffer_s *buf_p;
150 1.1 agc int n;
151 1.1 agc
152 1.1 agc DBG("isns_add_buffer_pool: buf_size=%d, count=%d\n", buf_size, count);
153 1.1 agc
154 1.1 agc assert(G_buffer_pool.active);
155 1.1 agc
156 1.1 agc /* Make our buffer lengths always a multiple of 4. */
157 1.1 agc buf_size = (buf_size + 0x03) & ~0x03;
158 1.1 agc
159 1.1 agc /*
160 1.1 agc * Lookup existing list for size specified. If no exists, allocate
161 1.1 agc * a new list and initialize.
162 1.1 agc */
163 1.1 agc pthread_mutex_lock(&G_buffer_pool.mutex);
164 1.1 agc list_p = isns_lookup_buffer_list(buf_size);
165 1.1 agc if (list_p == NULL) {
166 1.1 agc pthread_mutex_unlock(&G_buffer_pool.mutex);
167 1.1 agc list_p = (struct isns_buffer_list_s *)
168 1.1 agc isns_malloc(sizeof(struct isns_buffer_list_s));
169 1.1 agc if (list_p == NULL) {
170 1.1 agc DBG("isns_add_buffer_pool: error on isns_malloc()\n");
171 1.1 agc return ENOMEM;
172 1.1 agc }
173 1.1 agc list_p->buf_size = buf_size;
174 1.1 agc list_p->alloc_count = 0;
175 1.1 agc list_p->head = NULL;
176 1.1 agc }
177 1.1 agc
178 1.1 agc /* If this is a new list, insert into pool in buf_size order. */
179 1.1 agc if (list_p->alloc_count == 0) {
180 1.1 agc pthread_mutex_lock(&G_buffer_pool.mutex);
181 1.1 agc if (G_buffer_pool.list_p == NULL) {
182 1.1 agc G_buffer_pool.list_p = list_p;
183 1.1 agc list_p->next = NULL;
184 1.1 agc } else if (G_buffer_pool.list_p->buf_size > buf_size) {
185 1.1 agc list_p->next = G_buffer_pool.list_p;
186 1.1 agc G_buffer_pool.list_p = list_p;
187 1.1 agc } else {
188 1.1 agc p = G_buffer_pool.list_p;
189 1.1 agc while (p->next != NULL) {
190 1.1 agc p_next = p->next;
191 1.1 agc if (p_next->buf_size > buf_size) {
192 1.1 agc p->next = list_p;
193 1.1 agc list_p->next = p_next;
194 1.1 agc break;
195 1.1 agc }
196 1.1 agc p = p->next;
197 1.1 agc }
198 1.1 agc if (p->next == NULL) {
199 1.1 agc p->next = list_p;
200 1.1 agc list_p->next = NULL;
201 1.1 agc }
202 1.1 agc }
203 1.1 agc }
204 1.1 agc
205 1.1 agc /* Allocate (possibly additional) buffers for list. */
206 1.1 agc for (n = 0; n < count; n++) {
207 1.1 agc buf_p = (struct isns_buffer_s *)
208 1.1 agc isns_malloc(buf_size + sizeof(struct isns_buffer_s));
209 1.1 agc if (buf_p == NULL)
210 1.1 agc break;
211 1.1 agc buf_p->next = list_p->head;
212 1.1 agc list_p->head = buf_p;
213 1.1 agc }
214 1.1 agc list_p->alloc_count += n;
215 1.1 agc pthread_mutex_unlock(&G_buffer_pool.mutex);
216 1.1 agc
217 1.1 agc DBG("isns_init_buffer_pool: %d %d-byte buffers allocated\n",
218 1.1 agc n, buf_size);
219 1.1 agc
220 1.1 agc return (n > 0 ? 0 : ENOMEM);
221 1.1 agc }
222 1.1 agc
223 1.1 agc
224 1.1 agc /*
225 1.1 agc * isns_destroy_buffer_pool - destroys previously allocated buffer pool
226 1.1 agc */
227 1.1 agc void
228 1.1 agc isns_destroy_buffer_pool(void)
229 1.1 agc {
230 1.1 agc struct isns_buffer_list_s *list_p;
231 1.1 agc struct isns_buffer_s *buf_p;
232 1.1 agc #ifdef ISNS_DEBUG
233 1.1 agc char dbg_buffer[1024] = { 0 };
234 1.1 agc #endif
235 1.1 agc
236 1.1 agc DBG("isns_destroy_buffer_pool: entered\n");
237 1.1 agc
238 1.1 agc assert(G_buffer_pool.active);
239 1.1 agc
240 1.1 agc pthread_mutex_lock(&G_buffer_pool.mutex);
241 1.1 agc while (G_buffer_pool.list_p != NULL) {
242 1.1 agc list_p = G_buffer_pool.list_p;
243 1.1 agc while (list_p->head != NULL) {
244 1.1 agc buf_p = list_p->head;
245 1.1 agc list_p->head = buf_p->next;
246 1.1 agc list_p->alloc_count--;
247 1.1 agc isns_free(buf_p);
248 1.1 agc }
249 1.1 agc #ifdef ISNS_DEBUG
250 1.1 agc if (list_p->alloc_count > 0) {
251 1.1 agc snprintf(&dbg_buffer[(int) strlen(dbg_buffer)],
252 1.1 agc (sizeof(dbg_buffer) - strlen(dbg_buffer)),
253 1.1 agc "isns_destroy_buffer_pool: "
254 1.1 agc "%d %d-byte buffer(s) not freed\n",
255 1.1 agc list_p->alloc_count, list_p->buf_size);
256 1.1 agc }
257 1.1 agc #endif
258 1.1 agc G_buffer_pool.list_p = list_p->next;
259 1.1 agc isns_free(list_p);
260 1.1 agc }
261 1.1 agc G_buffer_pool.active = 0;
262 1.1 agc
263 1.1 agc pthread_mutex_unlock(&G_buffer_pool.mutex);
264 1.1 agc pthread_mutex_destroy(&G_buffer_pool.mutex);
265 1.1 agc
266 1.1 agc DBG(dbg_buffer);
267 1.1 agc }
268 1.1 agc
269 1.1 agc
270 1.1 agc /*
271 1.1 agc * isns_new_buffer - allocates a new ISNS buffer
272 1.1 agc *
273 1.1 agc * Typically, the buffer is returned from the pool, but if no free buffers
274 1.1 agc * are available in the pool, or a buf size larger than the largest pool buffer
275 1.1 agc * size is requested, a normal malloc is used to allocate the buffer. The
276 1.1 agc * buffer type is recorded so that a subsequent isns_free_buffer will correctly
277 1.1 agc * free the buffer or return it to the pool.
278 1.1 agc */
279 1.1 agc struct isns_buffer_s *
280 1.1 agc isns_new_buffer(int buf_size)
281 1.1 agc {
282 1.1 agc struct isns_buffer_list_s *list_p;
283 1.1 agc struct isns_buffer_s *buf_p;
284 1.1 agc int buf_type;
285 1.1 agc
286 1.1 agc if (buf_size == 0)
287 1.1 agc buf_size = ISNS_BUF_SIZE;
288 1.1 agc buf_p = NULL;
289 1.1 agc
290 1.1 agc pthread_mutex_lock(&G_buffer_pool.mutex);
291 1.1 agc list_p = G_buffer_pool.list_p;
292 1.1 agc while (list_p != NULL) {
293 1.1 agc if ((list_p->head != NULL)
294 1.1 agc && (list_p->buf_size >= buf_size)) {
295 1.1 agc buf_p = list_p->head;
296 1.1 agc list_p->head = buf_p->next;
297 1.1 agc buf_size = list_p->buf_size;
298 1.1 agc buf_type = ISNS_BUF_POOL;
299 1.1 agc break;
300 1.1 agc }
301 1.1 agc list_p = list_p->next;
302 1.1 agc }
303 1.1 agc pthread_mutex_unlock(&G_buffer_pool.mutex);
304 1.1 agc
305 1.1 agc if (buf_p == NULL) {
306 1.1 agc buf_p = (struct isns_buffer_s *)isns_malloc(
307 1.1 agc buf_size + sizeof(struct isns_buffer_s));
308 1.1 agc buf_type = ISNS_BUF_MALLOC;
309 1.1 agc }
310 1.1 agc
311 1.1 agc if (buf_p != NULL)
312 1.1 agc ISNS_INIT_BUFFER(buf_p, buf_size, buf_type);
313 1.1 agc
314 1.1 agc DBG("isns_new_buffer: %p (buf_size=%d, type=%d)\n", buf_p, buf_size,
315 1.1 agc buf_type);
316 1.1 agc
317 1.1 agc return buf_p;
318 1.1 agc }
319 1.1 agc
320 1.1 agc
321 1.1 agc /*
322 1.1 agc * isns_free_buffer - free a ISNS buffer
323 1.1 agc */
324 1.1 agc void
325 1.1 agc isns_free_buffer(struct isns_buffer_s *buf_p)
326 1.1 agc {
327 1.1 agc struct isns_buffer_list_s *list_p;
328 1.1 agc
329 1.1 agc DBG("isns_free_buffer: %p (type=%d, alloc_len=%d)\n",
330 1.1 agc buf_p, (buf_p == NULL ? 0 : buf_p->buf_type),
331 1.1 agc (buf_p == NULL ? 0 : buf_p->alloc_len));
332 1.1 agc
333 1.1 agc if (buf_p != NULL) {
334 1.1 agc switch (buf_p->buf_type) {
335 1.1 agc case ISNS_BUF_POOL:
336 1.1 agc /* Return buffer to proper pool list. */
337 1.1 agc pthread_mutex_lock(&G_buffer_pool.mutex);
338 1.1 agc list_p = isns_lookup_buffer_list((int)buf_p->alloc_len);
339 1.1 agc if (list_p != NULL) {
340 1.1 agc buf_p->next = list_p->head;
341 1.1 agc list_p->head = buf_p;
342 1.1 agc }
343 1.1 agc pthread_mutex_unlock(&G_buffer_pool.mutex);
344 1.1 agc break;
345 1.1 agc case ISNS_BUF_MALLOC:
346 1.1 agc /* Malloc allocated buf, so free normally. */
347 1.1 agc isns_free(buf_p);
348 1.1 agc break;
349 1.1 agc case ISNS_BUF_STATIC:
350 1.1 agc /* Static buf with no allocation, so do nothing here. */
351 1.1 agc break;
352 1.1 agc }
353 1.1 agc }
354 1.1 agc }
355 1.1 agc
356 1.1 agc
357 1.1 agc /*
358 1.1 agc * isns_new_trans - create a new ISNS transaction
359 1.1 agc */
360 1.1 agc ISNS_TRANS
361 1.1 agc isns_new_trans(ISNS_HANDLE isns_handle, uint16_t func_id, uint16_t pdu_flags)
362 1.1 agc {
363 1.1 agc struct isns_trans_s *trans_p;
364 1.1 agc struct isns_pdu_s *pdu_p;
365 1.1 agc struct isns_buffer_s *buf_p;
366 1.1 agc
367 1.1 agc if (isns_handle == ISNS_INVALID_HANDLE) {
368 1.1 agc DBG("isns_new_trans: error - handle=%p\n", isns_handle);
369 1.1 agc return ISNS_INVALID_TRANS;
370 1.1 agc }
371 1.1 agc
372 1.1 agc buf_p = isns_new_buffer((int)sizeof(struct isns_trans_s));
373 1.1 agc if (buf_p == NULL) {
374 1.1 agc DBG("isns_new_trans: error on isns_new_buffer()\n");
375 1.1 agc return ISNS_INVALID_TRANS;
376 1.1 agc }
377 1.1 agc
378 1.1 agc trans_p = (struct isns_trans_s *)isns_buffer_data(buf_p, 0);
379 1.1 agc trans_p->id = isns_get_next_trans_id();
380 1.1 agc trans_p->func_id = func_id;
381 1.1 agc trans_p->flags = 0;
382 1.1 agc trans_p->cfg_p = (struct isns_config_s *)isns_handle;
383 1.1 agc trans_p->pdu_req_list = NULL;
384 1.1 agc trans_p->pdu_rsp_list = NULL;
385 1.1 agc trans_p->disconnect_cnt = 0;
386 1.1 agc
387 1.1 agc trans_p->get_tlv_info.pdu_p = NULL;
388 1.1 agc trans_p->get_tlv_info.buf_p = NULL;
389 1.1 agc trans_p->get_tlv_info.extra_buf_list = NULL;
390 1.1 agc trans_p->get_tlv_info.buf_ofs = 0;
391 1.1 agc
392 1.1 agc buf_p->cur_len = sizeof(struct isns_trans_s);
393 1.1 agc
394 1.1 agc /*
395 1.1 agc * Mask off all but the AUTH and possibly REPLACE_REG pdu flags. Then,
396 1.1 agc * set the appropriate server/client sender flag. The first/last PDU
397 1.1 agc * flags will be set when the PDU is sent.
398 1.1 agc */
399 1.1 agc if (func_id == isnsp_DevAttrReg)
400 1.1 agc pdu_flags &= (ISNS_FLAG_AUTH | ISNS_FLAG_REPLACE_REG);
401 1.1 agc else
402 1.1 agc pdu_flags &= ISNS_FLAG_AUTH;
403 1.1 agc
404 1.1 agc if (trans_p->cfg_p->is_server)
405 1.1 agc pdu_flags |= ISNS_FLAG_SND_SERVER;
406 1.1 agc else
407 1.1 agc pdu_flags |= ISNS_FLAG_SND_CLIENT;
408 1.1 agc
409 1.1 agc pdu_p = isns_new_pdu(trans_p->cfg_p, trans_p->id, func_id, pdu_flags);
410 1.1 agc if (pdu_p == NULL) {
411 1.1 agc DBG("isns_new_trans: error on isns_new_pdu()\n");
412 1.1 agc isns_free_buffer(buf_p);
413 1.1 agc return ISNS_INVALID_TRANS;
414 1.1 agc }
415 1.1 agc
416 1.1 agc isns_add_pdu_request((ISNS_TRANS)trans_p, pdu_p);
417 1.1 agc
418 1.1 agc DBG("isns_new_trans: %p\n", trans_p);
419 1.1 agc
420 1.1 agc return (ISNS_TRANS)trans_p;
421 1.1 agc }
422 1.1 agc
423 1.1 agc
424 1.1 agc /*
425 1.1 agc * isns_free_trans - free ISNS transaction created with isns_new_trans
426 1.1 agc */
427 1.1 agc void
428 1.1 agc isns_free_trans(ISNS_TRANS trans)
429 1.1 agc {
430 1.1 agc struct isns_trans_s *trans_p;
431 1.1 agc struct isns_pdu_s *pdu_p;
432 1.1 agc struct isns_buffer_s *buf_p, *free_buf_p;
433 1.1 agc uint32_t trans_flags;
434 1.1 agc
435 1.1 agc DBG("isns_free_trans: %p\n", trans);
436 1.1 agc
437 1.1 agc if (trans != ISNS_INVALID_TRANS) {
438 1.1 agc trans_p = (struct isns_trans_s *)trans;
439 1.1 agc
440 1.1 agc trans_flags = isns_set_trans_flags(trans_p,
441 1.1 agc ISNS_TRANSF_FREE_WHEN_COMPLETE);
442 1.1 agc
443 1.1 agc if ((trans_flags & ISNS_TRANSF_COMPLETE) == 0) {
444 1.1 agc DBG("isns_free_trans: deferred - trans not complete\n");
445 1.1 agc return;
446 1.1 agc }
447 1.1 agc
448 1.1 agc DBG("isns_free_trans: pdu_req_list=%p\n",
449 1.1 agc trans_p->pdu_req_list);
450 1.1 agc while ((pdu_p = trans_p->pdu_req_list) != NULL) {
451 1.1 agc trans_p->pdu_req_list = pdu_p->next;
452 1.1 agc isns_free_pdu(pdu_p);
453 1.1 agc }
454 1.1 agc DBG("isns_free_trans: pdu_rsp_list=%p\n",
455 1.1 agc trans_p->pdu_rsp_list);
456 1.1 agc while ((pdu_p = trans_p->pdu_rsp_list) != NULL) {
457 1.1 agc trans_p->pdu_rsp_list = pdu_p->next;
458 1.1 agc isns_free_pdu(pdu_p);
459 1.1 agc }
460 1.1 agc DBG("isns_free_trans: extra_buf_list=%p\n",
461 1.1 agc trans_p->get_tlv_info.extra_buf_list);
462 1.1 agc buf_p = trans_p->get_tlv_info.extra_buf_list;
463 1.1 agc while (buf_p != NULL) {
464 1.1 agc free_buf_p = buf_p;
465 1.1 agc buf_p = buf_p->next;
466 1.1 agc isns_free_buffer(free_buf_p);
467 1.1 agc }
468 1.1 agc
469 1.1 agc DBG("isns_free_trans: freeing base trans buffer\n");
470 1.1 agc buf_p = ((struct isns_buffer_s *)(void *)(trans_p))-1;
471 1.1 agc isns_free_buffer(buf_p);
472 1.1 agc }
473 1.1 agc }
474 1.1 agc
475 1.1 agc
476 1.1 agc /*
477 1.1 agc * isns_send_trans - send ISNS transaction PDU(s) and optionally wait
478 1.1 agc *
479 1.1 agc * If a successful wait occurs (i.e., the transaction completes without
480 1.1 agc * a timeout), then the response PDU status is place in *status_p. For
481 1.1 agc * all other cases, the data returned in *status_p is undefined.
482 1.1 agc *
483 1.1 agc */
484 1.1 agc int
485 1.1 agc isns_send_trans(ISNS_TRANS trans, const struct timespec *timeout_p,
486 1.1 agc uint32_t *status_p)
487 1.1 agc {
488 1.1 agc struct isns_trans_s *trans_p;
489 1.1 agc struct isns_pdu_s *pdu_p;
490 1.1 agc int rval;
491 1.1 agc
492 1.1 agc trans_p = (struct isns_trans_s *)trans;
493 1.1 agc
494 1.1 agc DBG("isns_send_trans: trans_p=%p, timeout_p=%p\n", trans_p, timeout_p);
495 1.1 agc
496 1.1 agc if (status_p != NULL)
497 1.1 agc *status_p = 0;
498 1.1 agc
499 1.1 agc if (!isns_is_socket_init_done(trans_p->cfg_p)) {
500 1.1 agc DBG("isns_send_trans: socket not initialized\n");
501 1.1 agc isns_complete_trans(trans_p);
502 1.1 agc return EINVAL;
503 1.1 agc }
504 1.1 agc
505 1.1 agc if ((pdu_p = isns_get_pdu_request(trans)) == NULL) {
506 1.1 agc DBG("isns_send_trans: no request PDU\n");
507 1.1 agc return EINVAL;
508 1.1 agc }
509 1.1 agc
510 1.1 agc /* Set the FIRST_PDU flag in the first PDU. */
511 1.1 agc pdu_p->hdr.flags |= ISNS_FLAG_FIRST_PDU;
512 1.1 agc
513 1.1 agc /* Set our PDU sequence numbers for the PDU chain. */
514 1.1 agc while (pdu_p->next != NULL) {
515 1.1 agc pdu_p->next->hdr.seq_id = pdu_p->hdr.seq_id + 1;
516 1.1 agc pdu_p = pdu_p->next;
517 1.1 agc }
518 1.1 agc
519 1.1 agc /* Set the LAST_PDU flag in the last PDU. */
520 1.1 agc pdu_p->hdr.flags |= ISNS_FLAG_LAST_PDU;
521 1.1 agc
522 1.1 agc rval = isns_send_pdu(trans, isns_get_pdu_request(trans), timeout_p);
523 1.1 agc if ((rval == 0) && (status_p != NULL))
524 1.1 agc isns_get_pdu_response_status(trans, status_p);
525 1.1 agc
526 1.1 agc return rval;
527 1.1 agc }
528 1.1 agc
529 1.1 agc
530 1.1 agc
531 1.1 agc void
532 1.1 agc isns_complete_trans(struct isns_trans_s *trans_p)
533 1.1 agc {
534 1.1 agc uint32_t flags;
535 1.1 agc
536 1.1 agc DBG("isns_complete_trans: trans_p=%p\n", trans_p);
537 1.1 agc
538 1.1 agc flags = isns_set_trans_flags(trans_p, ISNS_TRANSF_COMPLETE);
539 1.1 agc
540 1.1 agc if ((flags & ISNS_TRANSF_FREE_WHEN_COMPLETE) != 0)
541 1.1 agc isns_free_trans(trans_p);
542 1.1 agc }
543 1.1 agc
544 1.1 agc
545 1.1 agc int
546 1.1 agc isns_abort_trans(struct isns_config_s *cfg_p, uint16_t trans_id)
547 1.1 agc {
548 1.1 agc struct isns_task_s *task_p;
549 1.1 agc
550 1.1 agc /* First, look at current task. */
551 1.1 agc if (((task_p = cfg_p->curtask_p) != NULL)
552 1.1 agc && (task_p->task_type == ISNS_TASK_SEND_PDU)
553 1.1 agc && (task_p->var.send_pdu.trans_p->id == trans_id)) {
554 1.1 agc isns_complete_trans(task_p->var.send_pdu.trans_p);
555 1.1 agc isns_end_task(task_p);
556 1.1 agc return 0;
557 1.1 agc }
558 1.1 agc
559 1.1 agc /* If not current task, look in task queue. */
560 1.1 agc task_p = isns_taskq_remove_trans(cfg_p, trans_id);
561 1.1 agc if (task_p) {
562 1.1 agc isns_complete_trans(task_p->var.send_pdu.trans_p);
563 1.1 agc isns_end_task(task_p);
564 1.1 agc return 0;
565 1.1 agc }
566 1.1 agc
567 1.1 agc return EINVAL;
568 1.1 agc }
569 1.1 agc
570 1.1 agc /*
571 1.1 agc * isns_add_string - add a TLV which is a C string
572 1.1 agc *
573 1.1 agc * Wrapper around isns_add_tlv()
574 1.1 agc */
575 1.1 agc int
576 1.1 agc isns_add_string(ISNS_TRANS trans, uint32_t tag, const char *s)
577 1.1 agc {
578 1.1 agc /* Add string, including required NULL. */
579 1.2 christos return isns_add_tlv(trans, tag, (uint32_t)strlen(s) + 1, s);
580 1.1 agc }
581 1.1 agc
582 1.1 agc
583 1.1 agc /*
584 1.1 agc * isns_add_tlv - adds a TLV to an existing transaction
585 1.1 agc */
586 1.1 agc int
587 1.2 christos isns_add_tlv(ISNS_TRANS trans, uint32_t tag, uint32_t data_len,
588 1.2 christos const void *data_p)
589 1.1 agc {
590 1.1 agc struct isns_trans_s *trans_p;
591 1.1 agc uint8_t tlv_buf[ISNS_TLV_HDR_SIZE];
592 1.1 agc int rval;
593 1.1 agc
594 1.1 agc DBG("isns_add_tlv: trans=%p, tag=%d, data_len=%d, data_p=%p\n",
595 1.1 agc trans, tag, data_len, data_p);
596 1.1 agc
597 1.1 agc if (trans == ISNS_INVALID_TRANS) {
598 1.1 agc DBG("isns_add_tlv: error - trans=%p\n", trans);
599 1.1 agc return EINVAL;
600 1.1 agc }
601 1.1 agc
602 1.1 agc if ((data_len > 0) && (data_p == NULL)) {
603 1.1 agc DBG("isns_add_tlv: error data_len=%d, data_p=%p\n",
604 1.1 agc data_len, data_p);
605 1.1 agc return EINVAL;
606 1.1 agc }
607 1.1 agc
608 1.1 agc /* Set tag, length in header buffer and add to PDU payload data. */
609 1.1 agc trans_p = (struct isns_trans_s *)trans;
610 1.1 agc ISNS_TLV_SET_TAG(tlv_buf, tag);
611 1.1 agc ISNS_TLV_SET_LEN(tlv_buf, ISNS_PAD4_LEN(data_len));
612 1.1 agc rval = isns_add_pdu_payload_data(trans_p, tlv_buf, ISNS_TLV_HDR_SIZE);
613 1.1 agc
614 1.1 agc /* If header added okay, add value portion to PDU payload data. */
615 1.1 agc if ((rval == 0) && (data_len > 0))
616 1.1 agc rval = isns_add_pdu_payload_data(trans_p, data_p, data_len);
617 1.1 agc
618 1.1 agc return rval;
619 1.1 agc }
620 1.1 agc
621 1.1 agc
622 1.1 agc /*
623 1.1 agc * isns_get_tlv - get TLV value from response PDU for transaction
624 1.1 agc *
625 1.1 agc * returns:
626 1.1 agc * 0 - success
627 1.1 agc * ENOENT - no (more) TLVs in this transaction
628 1.1 agc * EINVAL - invalid arg
629 1.1 agc * EPERM - operation not permitted - transaction not complete
630 1.1 agc * ENOMEM - could not allocate storage for spanning TLV data
631 1.1 agc */
632 1.1 agc int
633 1.2 christos isns_get_tlv(ISNS_TRANS trans, int which_tlv, uint32_t *tag_p,
634 1.2 christos uint32_t *data_len_p, void **data_pp)
635 1.1 agc {
636 1.1 agc struct isns_trans_s *trans_p;
637 1.1 agc struct isns_get_tlv_info_s *info_p;
638 1.1 agc struct isns_pdu_s *pdu_p;
639 1.1 agc int rval;
640 1.1 agc
641 1.1 agc if (trans == ISNS_INVALID_TRANS) {
642 1.1 agc DBG("isns_get_tlv: error - trans=%p\n", trans);
643 1.1 agc return EINVAL;
644 1.1 agc }
645 1.1 agc
646 1.1 agc trans_p = (struct isns_trans_s *)trans;
647 1.1 agc if ((isns_get_trans_flags(trans_p) & ISNS_TRANSF_COMPLETE) == 0) {
648 1.1 agc DBG("isns_get_tlv: error - trans not complete\n");
649 1.1 agc return EPERM;
650 1.1 agc }
651 1.1 agc
652 1.1 agc /* Get response PDU for this transaction. */
653 1.1 agc pdu_p = isns_get_pdu_response(trans_p);
654 1.1 agc if (pdu_p == NULL) {
655 1.1 agc DBG("isns_get_tlv: error - no response PDU in transaction\n");
656 1.1 agc return EINVAL;
657 1.1 agc }
658 1.1 agc
659 1.1 agc if (pdu_p->payload_p->cur_len == 0) {
660 1.1 agc DBG("isns_get_tlv: error - zero length PDU payload\n");
661 1.1 agc return EINVAL;
662 1.1 agc }
663 1.1 agc
664 1.1 agc /* If get_tlv_info unset, treat ISNS_TLV_NEXT as ISNS_TLV_FIRST. */
665 1.1 agc info_p = &trans_p->get_tlv_info;
666 1.1 agc if ((which_tlv == ISNS_TLV_NEXT) && (info_p->pdu_p == NULL))
667 1.1 agc which_tlv = ISNS_TLV_FIRST;
668 1.1 agc
669 1.1 agc /*!!! make sure PDU uses TLVs here */
670 1.1 agc
671 1.1 agc switch (which_tlv) {
672 1.1 agc case ISNS_TLV_NEXT:
673 1.1 agc /* For next TLV, nothing to do here - use get_tlv_info as-is. */
674 1.1 agc break;
675 1.1 agc
676 1.1 agc case ISNS_TLV_FIRST:
677 1.1 agc /* For first TLV, reset get_tlv_info. */
678 1.1 agc info_p->pdu_p = pdu_p;
679 1.1 agc info_p->buf_p = isns_get_pdu_head_buffer(pdu_p);
680 1.1 agc info_p->buf_ofs = 4;
681 1.1 agc break;
682 1.1 agc
683 1.1 agc default:
684 1.1 agc DBG("isns_get_tlv: invalid arg (which_tlv=%d)\n", which_tlv);
685 1.1 agc return EINVAL;
686 1.1 agc }
687 1.1 agc
688 1.1 agc /*
689 1.1 agc * Get the type, length, and data (value) for the TLV. The get calls
690 1.1 agc * below will advance the pointers in get_tlv_info_s *info_p. Note that
691 1.1 agc * if the get of the TAG type fails, ENOENT is returned indicating that
692 1.1 agc * no more TLVs exist for this request PDU.
693 1.1 agc */
694 1.1 agc if ((rval = isns_get_tlv_uint32(info_p, tag_p)) != 0) {
695 1.1 agc DBG("isns_get_tlv: error on isns_get_tlv_uint32() tag\n");
696 1.1 agc return ENOENT;
697 1.1 agc }
698 1.1 agc
699 1.1 agc if ((rval = isns_get_tlv_uint32(info_p, (uint32_t *)data_len_p)) != 0) {
700 1.1 agc DBG("isns_get_tlv: error on isns_get_tlv_uint32() data len\n");
701 1.1 agc return rval;
702 1.1 agc }
703 1.1 agc
704 1.1 agc rval = isns_get_tlv_data(info_p, *data_len_p, data_pp);
705 1.1 agc if (rval != 0) {
706 1.1 agc DBG("isns_get_tlv: error on isns_get_tlv_data()\n");
707 1.1 agc return rval;
708 1.1 agc }
709 1.1 agc
710 1.1 agc return 0;
711 1.1 agc }
712 1.1 agc
713 1.1 agc
714 1.1 agc /*
715 1.1 agc * isns_set_trans_flags - sets flag bit(s) in transaction flags member
716 1.1 agc */
717 1.1 agc uint32_t
718 1.1 agc isns_set_trans_flags(struct isns_trans_s *trans_p, uint32_t flags)
719 1.1 agc {
720 1.1 agc pthread_mutex_lock(&trans_p->cfg_p->trans_mutex);
721 1.1 agc trans_p->flags |= flags;
722 1.1 agc flags = trans_p->flags;
723 1.1 agc pthread_mutex_unlock(&trans_p->cfg_p->trans_mutex);
724 1.1 agc
725 1.1 agc return flags;
726 1.1 agc }
727 1.1 agc
728 1.1 agc
729 1.1 agc /*
730 1.1 agc * isns_add_pdu_request - adds PDU to transaction request PDU list
731 1.1 agc */
732 1.1 agc void
733 1.1 agc isns_add_pdu_request(struct isns_trans_s *trans_p, struct isns_pdu_s *pdu_p)
734 1.1 agc {
735 1.1 agc DBG("isns_add_pdu_request: trans_p=%p, pdu_p=%p\n", trans_p, pdu_p);
736 1.1 agc
737 1.1 agc isns_add_pdu_list(&trans_p->pdu_req_list, pdu_p);
738 1.1 agc }
739 1.1 agc
740 1.1 agc
741 1.1 agc /*
742 1.1 agc * isns_add_pdu_response - adds PDU to transaction response PDU list
743 1.1 agc */
744 1.1 agc void
745 1.1 agc isns_add_pdu_response(struct isns_trans_s *trans_p, struct isns_pdu_s *pdu_p)
746 1.1 agc {
747 1.1 agc DBG("isns_add_pdu_response: trans_p=%p, pdu_p=%p\n", trans_p, pdu_p);
748 1.1 agc
749 1.1 agc isns_add_pdu_list(&trans_p->pdu_rsp_list, pdu_p);
750 1.1 agc }
751 1.1 agc
752 1.1 agc
753 1.1 agc /*
754 1.1 agc * isns_get_pdu_request_tail - returns last PDU in request PDU chain
755 1.1 agc */
756 1.1 agc struct isns_pdu_s *
757 1.1 agc isns_get_pdu_request_tail(struct isns_trans_s *trans_p)
758 1.1 agc {
759 1.1 agc struct isns_pdu_s *pdu_p;
760 1.1 agc
761 1.1 agc if ((pdu_p = isns_get_pdu_request(trans_p)) != NULL) {
762 1.1 agc while (pdu_p->next != NULL)
763 1.1 agc pdu_p = pdu_p->next;
764 1.1 agc }
765 1.1 agc
766 1.1 agc return pdu_p;
767 1.1 agc }
768 1.1 agc
769 1.1 agc
770 1.1 agc /*
771 1.5 andvar * isns_new_pdu - allocates a new PDU and assigns function ID and flags
772 1.1 agc */
773 1.1 agc struct isns_pdu_s *
774 1.1 agc isns_new_pdu(struct isns_config_s *cfg_p, uint16_t trans_id, uint16_t func_id,
775 1.1 agc uint16_t flags)
776 1.1 agc {
777 1.1 agc struct isns_buffer_s *buf_p;
778 1.1 agc
779 1.1 agc /*
780 1.1 agc * Allocate a buffer at least large enough for our isns_pdu_s struct
781 1.1 agc * and the embedded isns_buffer_s struct for the PDU payload data and 4
782 1.1 agc * bytes of actual payload data.
783 1.1 agc */
784 1.1 agc buf_p = isns_new_buffer(/* CONSTCOND */(int)MAX(ISNS_BUF_SIZE,
785 1.1 agc sizeof(struct isns_pdu_s) + sizeof(struct isns_buffer_s) + 4));
786 1.1 agc if (buf_p == NULL) {
787 1.1 agc DBG("isns_new_pdu: error on isns_new_buffer()\n");
788 1.1 agc return NULL;
789 1.1 agc }
790 1.1 agc
791 1.1 agc return isns_init_pdu(buf_p, cfg_p, trans_id, func_id, flags);
792 1.1 agc }
793 1.1 agc
794 1.1 agc
795 1.1 agc /*
796 1.1 agc * isns_free_pdu - frees a PDU and all associated buffers
797 1.1 agc */
798 1.1 agc void
799 1.1 agc isns_free_pdu(struct isns_pdu_s *pdu_p)
800 1.1 agc {
801 1.1 agc struct isns_buffer_s *buf_p, *free_buf_p;
802 1.1 agc
803 1.1 agc DBG("isns_free_pdu: %p\n", pdu_p);
804 1.1 agc
805 1.1 agc if (pdu_p != NULL) {
806 1.1 agc /* Free all payload buffers. */
807 1.1 agc buf_p = pdu_p->payload_p;
808 1.1 agc while (buf_p != NULL) {
809 1.1 agc free_buf_p = buf_p;
810 1.1 agc buf_p = buf_p->next;
811 1.1 agc isns_free_buffer(free_buf_p);
812 1.1 agc }
813 1.1 agc /*
814 1.1 agc * Get a pointer to the ISNS buffer in which this PDU is
815 1.1 agc * contained, and then free it.
816 1.1 agc */
817 1.1 agc buf_p = ((struct isns_buffer_s *)(void *)(pdu_p))-1 ;
818 1.1 agc isns_free_buffer(buf_p);
819 1.1 agc }
820 1.1 agc }
821 1.1 agc
822 1.1 agc
823 1.1 agc /*
824 1.1 agc * isns_send_pdu - initiates the send PDU task
825 1.1 agc */
826 1.1 agc int
827 1.1 agc isns_send_pdu(ISNS_TRANS trans, struct isns_pdu_s *pdu_p,
828 1.1 agc const struct timespec *timeout_p)
829 1.1 agc {
830 1.1 agc struct isns_trans_s *trans_p;
831 1.1 agc struct isns_task_s* task_p;
832 1.1 agc int rval;
833 1.1 agc
834 1.1 agc if (trans == ISNS_INVALID_TRANS) {
835 1.1 agc DBG("isns_send_pdu: error - trans=%p\n", trans);
836 1.1 agc return EINVAL;
837 1.1 agc }
838 1.1 agc
839 1.1 agc if (pdu_p == NULL) {
840 1.1 agc DBG("isns_send_pdu: error - pdu_p=%p\n", pdu_p);
841 1.1 agc return EINVAL;
842 1.1 agc }
843 1.1 agc
844 1.1 agc trans_p = (struct isns_trans_s *)trans;
845 1.1 agc
846 1.1 agc /* Build SEND_PDU task, insert on queue and issue command. */
847 1.1 agc task_p = isns_new_task(pdu_p->cfg_p, ISNS_TASK_SEND_PDU,
848 1.1 agc (timeout_p != NULL));
849 1.1 agc task_p->var.send_pdu.trans_p = trans_p;
850 1.1 agc task_p->var.send_pdu.pdu_p = pdu_p;
851 1.1 agc
852 1.1 agc isns_taskq_insert_tail(pdu_p->cfg_p, task_p);
853 1.1 agc
854 1.1 agc isns_issue_cmd(pdu_p->cfg_p, ISNS_CMD_PROCESS_TASKQ);
855 1.1 agc
856 1.1 agc if (timeout_p == NULL)
857 1.1 agc rval = 0;
858 1.1 agc else {
859 1.1 agc rval = isns_wait_task(task_p, timeout_p);
860 1.1 agc if (rval == ETIMEDOUT) {
861 1.1 agc DBG("isns_send_pdu: "
862 1.1 agc "timeout on isns_wait_task() trans_id=%d\n",
863 1.1 agc trans_p->id);
864 1.1 agc
865 1.1 agc isns_issue_cmd_with_data(task_p->cfg_p,
866 1.1 agc ISNS_CMD_ABORT_TRANS, (void *)&trans_p->id,
867 1.1 agc (int)sizeof(trans_p->id));
868 1.1 agc }
869 1.1 agc }
870 1.1 agc
871 1.1 agc return rval;
872 1.1 agc }
873 1.1 agc
874 1.1 agc
875 1.1 agc /*
876 1.1 agc * isns_init_pdu - initialize ISNS buffer to be a PDU
877 1.1 agc */
878 1.1 agc static struct isns_pdu_s *
879 1.1 agc isns_init_pdu(struct isns_buffer_s *buf_p, struct isns_config_s *cfg_p,
880 1.1 agc uint16_t trans_id, uint16_t func_id, uint16_t flags)
881 1.1 agc {
882 1.1 agc struct isns_pdu_s *pdu_p;
883 1.1 agc
884 1.1 agc /* The config and buffer pointers must be valid here. */
885 1.1 agc assert(cfg_p != NULL);
886 1.1 agc assert(buf_p != NULL);
887 1.1 agc
888 1.1 agc /* The PDU starts at offset 0 for the ISNS buffer data. */
889 1.1 agc pdu_p = isns_buffer_data(buf_p, 0);
890 1.1 agc buf_p->cur_len = sizeof(struct isns_pdu_s);
891 1.1 agc
892 1.1 agc /* Assign PDU members. */
893 1.1 agc pdu_p->cfg_p = cfg_p;
894 1.1 agc pdu_p->hdr.isnsp_version = ISNSP_VERSION;
895 1.1 agc pdu_p->hdr.func_id = func_id;
896 1.1 agc pdu_p->hdr.payload_len = 0;
897 1.1 agc pdu_p->hdr.flags = flags;
898 1.1 agc pdu_p->hdr.trans_id = trans_id;
899 1.1 agc pdu_p->hdr.seq_id = 0;
900 1.1 agc pdu_p->byteorder_host = 1;
901 1.1 agc pdu_p->next = NULL;
902 1.1 agc
903 1.1 agc /*
904 1.1 agc * The PDU payload buffer starts after the PDU struct portion in the
905 1.1 agc * ISNS buffer passed in to this function. So, assign the payload_p
906 1.1 agc * pointer accordingly, and then init the buffer with the proper length
907 1.1 agc * and ISNS_BUF_STATIC type.
908 1.1 agc */
909 1.1 agc pdu_p->payload_p = (struct isns_buffer_s *)
910 1.1 agc isns_buffer_data(buf_p, buf_p->cur_len);
911 1.1 agc ISNS_INIT_BUFFER(pdu_p->payload_p, (unsigned)(buf_p->alloc_len -
912 1.1 agc sizeof(struct isns_pdu_s) - sizeof(struct isns_buffer_s)),
913 1.1 agc ISNS_BUF_STATIC);
914 1.1 agc
915 1.1 agc DBG("isns_init_pdu: %p\n", pdu_p);
916 1.1 agc
917 1.1 agc return pdu_p;
918 1.1 agc }
919 1.1 agc
920 1.1 agc
921 1.1 agc /*
922 1.1 agc * isns_add_pdu_payload_data - add data to PDU payload
923 1.1 agc */
924 1.1 agc static int
925 1.1 agc isns_add_pdu_payload_data(struct isns_trans_s *trans_p, const void *data_p,
926 1.1 agc int len)
927 1.1 agc {
928 1.1 agc struct isns_pdu_s *pdu_p, *new_pdu_p;
929 1.1 agc struct isns_buffer_s *buf_p, *new_buf_p;
930 1.1 agc const uint8_t *src_p;
931 1.1 agc uint8_t *dst_p;
932 1.1 agc int pad_bytes;
933 1.1 agc
934 1.1 agc /* Get the request PDU for this transaction. */
935 1.1 agc if ((pdu_p = isns_get_pdu_request_tail(trans_p)) == NULL) {
936 1.1 agc DBG("isns_add_pdu_payload_data: no request PDU\n");
937 1.1 agc return EINVAL;
938 1.1 agc }
939 1.1 agc /* Get the active buffer for this PDU (where data should be copied). */
940 1.1 agc buf_p = isns_get_pdu_active_buffer(pdu_p);
941 1.1 agc
942 1.1 agc /* Set up source and destination pointers. Calculate pad bytes. */
943 1.1 agc src_p = data_p;
944 1.1 agc dst_p = isns_buffer_data(buf_p, buf_p->cur_len);
945 1.1 agc pad_bytes = ISNS_PAD4_BYTES(len);
946 1.1 agc
947 1.1 agc /*
948 1.1 agc * Move data from source to PDU buffer(s), allocated new pdus and
949 1.4 dholland * buffers as necessary to accommodate the data.
950 1.1 agc */
951 1.1 agc while (len--) {
952 1.1 agc /* If at max for one PDU payload, add a new PDU. */
953 1.1 agc if (pdu_p->hdr.payload_len == ISNS_MAX_PDU_PAYLOAD) {
954 1.1 agc new_pdu_p = isns_new_pdu(trans_p->cfg_p,
955 1.1 agc trans_p->id, trans_p->func_id, pdu_p->hdr.flags);
956 1.1 agc if (new_pdu_p == NULL)
957 1.1 agc return ENOMEM;
958 1.1 agc isns_add_pdu_request(trans_p, new_pdu_p);
959 1.1 agc pdu_p = new_pdu_p;
960 1.1 agc buf_p = pdu_p->payload_p;
961 1.1 agc dst_p = isns_buffer_data(buf_p, 0);
962 1.1 agc }
963 1.1 agc /* If at end of current buffer, add a new buffer. */
964 1.1 agc if (buf_p->cur_len == buf_p->alloc_len) {
965 1.1 agc if (buf_p->next != NULL)
966 1.1 agc buf_p = buf_p->next;
967 1.1 agc else {
968 1.1 agc new_buf_p = isns_new_buffer(0);
969 1.1 agc if (new_buf_p == NULL)
970 1.1 agc return ENOMEM;
971 1.1 agc buf_p->next = new_buf_p;
972 1.1 agc buf_p = new_buf_p;
973 1.1 agc }
974 1.1 agc dst_p = isns_buffer_data(buf_p, 0);
975 1.1 agc }
976 1.1 agc pdu_p->hdr.payload_len++;
977 1.1 agc buf_p->cur_len++;
978 1.1 agc *dst_p++ = *src_p++;
979 1.1 agc }
980 1.1 agc
981 1.1 agc /*
982 1.1 agc * Since the buffer alloc length is always a multiple of 4, we are
983 1.1 agc * guaranteed to have enough room for the pad bytes.
984 1.1 agc */
985 1.1 agc if (pad_bytes > 0) {
986 1.1 agc pdu_p->hdr.payload_len += pad_bytes;
987 1.1 agc buf_p->cur_len += pad_bytes;
988 1.1 agc while (pad_bytes--)
989 1.1 agc *dst_p++ = 0;
990 1.1 agc }
991 1.1 agc
992 1.1 agc return 0;
993 1.1 agc }
994 1.1 agc
995 1.1 agc
996 1.1 agc /*
997 1.1 agc * isns_get_tlv_info_advance - advances pdu/buffer pointers if at end of
998 1.1 agc * current buffer.
999 1.1 agc */
1000 1.1 agc static void
1001 1.1 agc isns_get_tlv_info_advance(struct isns_get_tlv_info_s *info_p)
1002 1.1 agc {
1003 1.1 agc if ((info_p->buf_p != NULL) &&
1004 1.1 agc (info_p->buf_ofs == (int)info_p->buf_p->cur_len)) {
1005 1.1 agc info_p->buf_p = info_p->buf_p->next;
1006 1.1 agc info_p->buf_ofs = 0;
1007 1.1 agc }
1008 1.1 agc
1009 1.1 agc if ((info_p->buf_p == NULL) && (info_p->pdu_p->next != NULL)) {
1010 1.1 agc info_p->pdu_p = info_p->pdu_p->next;
1011 1.1 agc info_p->buf_p = isns_get_pdu_head_buffer(info_p->pdu_p);
1012 1.1 agc info_p->buf_ofs = 0;
1013 1.1 agc }
1014 1.1 agc }
1015 1.1 agc
1016 1.1 agc
1017 1.1 agc /*
1018 1.1 agc * isns_get_tlv_uint32 - retrieve host-ordered uint32_t from PDU buffer at
1019 1.1 agc * starting offset and adjusts isns_get_tlv_info
1020 1.1 agc * pointers accordingly.
1021 1.1 agc */
1022 1.1 agc static int
1023 1.1 agc isns_get_tlv_uint32(struct isns_get_tlv_info_s *info_p, uint32_t *uint32_p)
1024 1.1 agc {
1025 1.1 agc /* Advance to next buffer/pdu (if necessary). */
1026 1.1 agc isns_get_tlv_info_advance(info_p);
1027 1.1 agc
1028 1.1 agc if ((info_p->buf_p == NULL) ||
1029 1.1 agc ((info_p->buf_ofs + 4) > (int)info_p->buf_p->cur_len)) {
1030 1.1 agc DBG("isns_get_tlv_uint32: end of buffer reached\n");
1031 1.1 agc return EFAULT;
1032 1.1 agc }
1033 1.1 agc
1034 1.1 agc *uint32_p = ntohl(*(uint32_t *)isns_buffer_data(info_p->buf_p,
1035 1.1 agc info_p->buf_ofs));
1036 1.1 agc info_p->buf_ofs += 4;
1037 1.1 agc
1038 1.1 agc return 0;
1039 1.1 agc }
1040 1.1 agc
1041 1.1 agc
1042 1.1 agc /*
1043 1.1 agc * isns_get_tlv_data - retrieves data from PDU buffer at starting offset
1044 1.1 agc * for TLV data contained in specified isns_get_tlv_info.
1045 1.1 agc */
1046 1.1 agc static int
1047 1.1 agc isns_get_tlv_data(struct isns_get_tlv_info_s *info_p, int data_len,
1048 1.1 agc void **data_pp)
1049 1.1 agc {
1050 1.1 agc struct isns_buffer_s *extra_buf_p;
1051 1.1 agc struct isns_get_tlv_info_s gti;
1052 1.1 agc uint8_t *data_p, *extra_data_p;
1053 1.1 agc int bytes_remaining, cbytes;
1054 1.1 agc
1055 1.1 agc /* First, NULL return data pointer. */
1056 1.1 agc *data_pp = NULL;
1057 1.1 agc
1058 1.1 agc /* Advance to next buffer/pdu (if necessary). */
1059 1.1 agc isns_get_tlv_info_advance(info_p);
1060 1.1 agc
1061 1.1 agc /* Make sure we have a current get tlv info buffer. */
1062 1.1 agc if (info_p->buf_p == NULL) {
1063 1.1 agc DBG("isns_get_tlv_data: no next buffer\n");
1064 1.1 agc return EFAULT;
1065 1.1 agc }
1066 1.1 agc
1067 1.1 agc /* Get pointer into buffer where desired TLV resides. */
1068 1.1 agc data_p = isns_buffer_data(info_p->buf_p, info_p->buf_ofs);
1069 1.1 agc
1070 1.1 agc /* TLV data completely resides in current buffer. */
1071 1.1 agc if ((info_p->buf_ofs + data_len) <= (int)info_p->buf_p->cur_len) {
1072 1.1 agc info_p->buf_ofs += data_len;
1073 1.1 agc *data_pp = data_p;
1074 1.1 agc return 0;
1075 1.1 agc }
1076 1.1 agc
1077 1.1 agc /*
1078 1.1 agc * TLV data extends into next buffer so an "extra" buffer is allocated
1079 1.1 agc * that is large enough to hold the entire data value. The extra buffer
1080 1.1 agc * is added to the transaction's extra buffer list so we can free it
1081 1.1 agc * when the transaction is freed.
1082 1.1 agc */
1083 1.1 agc
1084 1.1 agc if ((extra_buf_p = isns_new_buffer(data_len)) == NULL) {
1085 1.1 agc DBG("isns_get_tlv_data: error on isns_new_buffer()\n");
1086 1.1 agc return ENOMEM;
1087 1.1 agc }
1088 1.1 agc if (info_p->extra_buf_list == NULL)
1089 1.1 agc info_p->extra_buf_list = extra_buf_p;
1090 1.1 agc else {
1091 1.1 agc extra_buf_p->next = info_p->extra_buf_list;
1092 1.1 agc info_p->extra_buf_list = extra_buf_p;
1093 1.1 agc }
1094 1.1 agc
1095 1.1 agc /* Setup to copy data bytes out to extra buffer. */
1096 1.1 agc gti = *info_p;
1097 1.1 agc extra_data_p = isns_buffer_data(extra_buf_p, 0);
1098 1.1 agc bytes_remaining = data_len;
1099 1.1 agc
1100 1.1 agc while (bytes_remaining > 0) {
1101 1.1 agc /*
1102 1.1 agc * Advance to next buffer/pdu (if necessary), using local copy
1103 1.1 agc * of the get_tlv_info structure.
1104 1.1 agc */
1105 1.1 agc isns_get_tlv_info_advance(>i);
1106 1.1 agc if (gti.buf_p == NULL) {
1107 1.1 agc DBG("isns_get_tlv_data: no next buffer\n");
1108 1.1 agc return EFAULT;
1109 1.1 agc }
1110 1.1 agc
1111 1.1 agc data_p = isns_buffer_data(gti.buf_p, gti.buf_ofs);
1112 1.1 agc
1113 1.1 agc cbytes = MIN(bytes_remaining, ((int)gti.buf_p->cur_len - gti.buf_ofs));
1114 1.1 agc bytes_remaining -= cbytes;
1115 1.1 agc gti.buf_ofs += cbytes;
1116 1.1 agc while (cbytes--)
1117 1.1 agc *extra_data_p++ = *data_p++;
1118 1.1 agc }
1119 1.1 agc
1120 1.1 agc /* Update isns_get_tlv_info with our local copy. */
1121 1.1 agc *info_p = gti;
1122 1.1 agc
1123 1.1 agc /* Assign return data pointer. */
1124 1.1 agc *data_pp = isns_buffer_data(extra_buf_p, 0);
1125 1.1 agc
1126 1.1 agc return 0;
1127 1.1 agc }
1128 1.1 agc
1129 1.1 agc
1130 1.1 agc /*
1131 1.1 agc * isns_get_pdu_response_status - returns status in PDU response
1132 1.1 agc *
1133 1.1 agc * Returns: 0 - success
1134 1.1 agc * EPERM - operation not permitted, trans not complete
1135 1.1 agc * EINVAL - invalid trans PDU response/payload
1136 1.1 agc */
1137 1.1 agc int
1138 1.1 agc isns_get_pdu_response_status(struct isns_trans_s *trans_p, uint32_t *status_p)
1139 1.1 agc {
1140 1.1 agc struct isns_pdu_s *pdu_p;
1141 1.1 agc
1142 1.1 agc if ((isns_get_trans_flags(trans_p) & ISNS_TRANSF_COMPLETE) == 0)
1143 1.1 agc return EPERM;
1144 1.1 agc
1145 1.1 agc pdu_p = isns_get_pdu_response(trans_p);
1146 1.1 agc if ((pdu_p == NULL)
1147 1.1 agc || (pdu_p->payload_p == NULL)
1148 1.1 agc || (pdu_p->payload_p->cur_len < 4))
1149 1.1 agc return EINVAL;
1150 1.1 agc
1151 1.1 agc *status_p = htonl(*(uint32_t *)isns_buffer_data(pdu_p->payload_p, 0));
1152 1.1 agc
1153 1.1 agc return 0;
1154 1.1 agc }
1155 1.1 agc
1156 1.1 agc
1157 1.1 agc /*
1158 1.1 agc * isns_add_pdu_list - adds pdu to specified pdu list
1159 1.1 agc */
1160 1.1 agc static void
1161 1.1 agc isns_add_pdu_list(struct isns_pdu_s **list_pp, struct isns_pdu_s *pdu_p)
1162 1.1 agc {
1163 1.1 agc struct isns_pdu_s *p, *p_prev;
1164 1.1 agc
1165 1.1 agc
1166 1.1 agc if (*list_pp == NULL) {
1167 1.1 agc *list_pp = pdu_p;
1168 1.1 agc pdu_p->next = NULL;
1169 1.1 agc return;
1170 1.1 agc }
1171 1.1 agc
1172 1.1 agc p = *list_pp;
1173 1.1 agc while (p != NULL) {
1174 1.1 agc if (pdu_p->hdr.seq_id < p->hdr.seq_id) {
1175 1.1 agc if (p == *list_pp) {
1176 1.1 agc *list_pp = pdu_p;
1177 1.1 agc pdu_p->next = p;
1178 1.1 agc } else {
1179 1.1 agc p_prev = *list_pp;
1180 1.1 agc while (p_prev->next != p)
1181 1.1 agc p_prev = p_prev->next;
1182 1.1 agc p_prev->next = pdu_p;
1183 1.1 agc pdu_p->next = p;
1184 1.1 agc }
1185 1.1 agc
1186 1.1 agc return;
1187 1.1 agc }
1188 1.1 agc p = p->next;
1189 1.1 agc }
1190 1.1 agc
1191 1.1 agc /* pdu_p->hdr.seq_id > hdr.seq_id of all list elements */
1192 1.1 agc p = *list_pp;
1193 1.1 agc while (p->next != NULL)
1194 1.1 agc p = p->next;
1195 1.1 agc p->next = pdu_p;
1196 1.1 agc pdu_p->next = NULL;
1197 1.1 agc }
1198 1.1 agc
1199 1.1 agc
1200 1.1 agc /*
1201 1.1 agc * isns_get_pdu_head_buffer - returns PDU payload head buffer
1202 1.1 agc */
1203 1.1 agc static struct isns_buffer_s *
1204 1.1 agc isns_get_pdu_head_buffer(struct isns_pdu_s *pdu_p)
1205 1.1 agc {
1206 1.1 agc return pdu_p->payload_p;
1207 1.1 agc }
1208 1.1 agc
1209 1.1 agc
1210 1.1 agc #if 0
1211 1.1 agc /*
1212 1.1 agc * isns_get_pdu_tail_buffer - returns PDU payload tail buffer
1213 1.1 agc */
1214 1.1 agc static struct isns_buffer_s *
1215 1.1 agc isns_get_pdu_tail_buffer(struct isns_pdu_s *pdu_p)
1216 1.1 agc {
1217 1.1 agc struct isns_buffer_s *buf_p;
1218 1.1 agc
1219 1.1 agc buf_p = pdu_p->payload_p;
1220 1.1 agc if (buf_p != NULL)
1221 1.1 agc while (buf_p->next != NULL) buf_p = buf_p->next;
1222 1.1 agc
1223 1.1 agc return buf_p;
1224 1.1 agc }
1225 1.1 agc #endif
1226 1.1 agc
1227 1.1 agc
1228 1.1 agc /*
1229 1.1 agc * isns_get_pdu_active_buffer - returns PDU payload "active buffer where the
1230 1.1 agc * next TLV/data should be written
1231 1.1 agc */
1232 1.1 agc static struct isns_buffer_s *
1233 1.1 agc isns_get_pdu_active_buffer(struct isns_pdu_s *pdu_p)
1234 1.1 agc {
1235 1.1 agc struct isns_buffer_s *buf_p;
1236 1.1 agc
1237 1.1 agc buf_p = pdu_p->payload_p;
1238 1.1 agc while ((buf_p->next != NULL) && (buf_p->cur_len == buf_p->alloc_len)) {
1239 1.1 agc buf_p = buf_p->next;
1240 1.1 agc }
1241 1.1 agc
1242 1.1 agc return buf_p;
1243 1.1 agc }
1244 1.1 agc
1245 1.1 agc
1246 1.1 agc /*
1247 1.1 agc * isns_get_next_trans_id - returns next ISNS transaction ID to use
1248 1.1 agc */
1249 1.1 agc static uint32_t
1250 1.1 agc isns_get_next_trans_id(void)
1251 1.1 agc {
1252 1.1 agc static int trans_id = 1;
1253 1.1 agc
1254 1.1 agc return trans_id++;
1255 1.1 agc }
1256 1.1 agc
1257 1.1 agc
1258 1.1 agc #ifdef ISNS_DEBUG
1259 1.1 agc /*
1260 1.1 agc * isns_dump_pdu - dumps PDU contents
1261 1.1 agc */
1262 1.1 agc void
1263 1.1 agc isns_dump_pdu(struct isns_pdu_s *pdu_p)
1264 1.1 agc {
1265 1.1 agc int n, pos;
1266 1.1 agc struct isns_buffer_s *buf_p;
1267 1.1 agc uint8_t *p;
1268 1.1 agc char text[17];
1269 1.1 agc
1270 1.1 agc if (pdu_p == NULL) {
1271 1.1 agc DBG("isns_dump_pdu: pdu_p is NULL\n");
1272 1.1 agc return;
1273 1.1 agc }
1274 1.1 agc
1275 1.1 agc DBG("pdu header:\n");
1276 1.1 agc if (pdu_p->byteorder_host) {
1277 1.1 agc DBG("ver=0x%04X, func=%d(%s), len=%d, flags=0x%04X, trans=%d, "
1278 1.1 agc "seq=%d\n",
1279 1.1 agc pdu_p->hdr.isnsp_version,
1280 1.1 agc pdu_p->hdr.func_id & ~0x8000,
1281 1.1 agc (pdu_p->hdr.func_id & 0x8000 ? "rsp" : "req"),
1282 1.1 agc pdu_p->hdr.payload_len,
1283 1.1 agc pdu_p->hdr.flags,
1284 1.1 agc pdu_p->hdr.trans_id,
1285 1.1 agc pdu_p->hdr.seq_id);
1286 1.1 agc } else {
1287 1.1 agc DBG("ver=0x%04X, func=%d(%s), len=%d, flags=0x%04X, trans=%d, "
1288 1.1 agc "seq=%d\n",
1289 1.1 agc isns_ntohs(pdu_p->hdr.isnsp_version),
1290 1.1 agc isns_ntohs(pdu_p->hdr.func_id) & ~0x8000,
1291 1.1 agc (pdu_p->hdr.func_id & 0x0080 ? "rsp" : "req"),
1292 1.1 agc isns_ntohs(pdu_p->hdr.payload_len),
1293 1.1 agc isns_ntohs(pdu_p->hdr.flags),
1294 1.1 agc isns_ntohs(pdu_p->hdr.trans_id),
1295 1.1 agc isns_ntohs(pdu_p->hdr.seq_id));
1296 1.1 agc }
1297 1.1 agc
1298 1.1 agc DBG("pdu buffers:\n");
1299 1.1 agc buf_p = pdu_p->payload_p;
1300 1.1 agc while (buf_p != NULL) {
1301 1.1 agc DBG("[%p]: alloc_len=%d, cur_len=%d\n",
1302 1.1 agc buf_p, buf_p->alloc_len, buf_p->cur_len);
1303 1.1 agc buf_p = buf_p->next;
1304 1.1 agc }
1305 1.1 agc
1306 1.1 agc DBG("pdu payload:\n");
1307 1.1 agc buf_p = pdu_p->payload_p;
1308 1.1 agc if (buf_p == NULL) {
1309 1.1 agc DBG("<none>\n");
1310 1.1 agc return;
1311 1.1 agc }
1312 1.1 agc
1313 1.1 agc pos = 0;
1314 1.1 agc memset(text, 0, 17);
1315 1.1 agc while (buf_p != NULL) {
1316 1.1 agc p = isns_buffer_data(buf_p, 0);
1317 1.1 agc for (n = 0; n < buf_p->cur_len; n++) {
1318 1.1 agc DBG("%02X ", *p);
1319 1.1 agc text[pos] = (isprint(*p) ? *p : '.');
1320 1.1 agc pos++;
1321 1.1 agc p++;
1322 1.1 agc
1323 1.1 agc if ((pos % 16) == 0) {
1324 1.1 agc DBG(" %s\n", text);
1325 1.1 agc memset(text, 0, 17);
1326 1.1 agc pos = 0;
1327 1.1 agc }
1328 1.1 agc }
1329 1.1 agc buf_p = buf_p->next;
1330 1.1 agc }
1331 1.1 agc
1332 1.1 agc if ((pos % 16) != 0)
1333 1.1 agc DBG("%*c %s\n", (16 - (pos % 16)) * 3, ' ', text);
1334 1.1 agc }
1335 1.1 agc #endif /* ISNS_DEBUG */
1336