isns_pdu.c revision 1.1 1 1.1 agc /* $NetBSD: isns_pdu.c,v 1.1 2011/01/16 01:22:50 agc 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.1 agc __RCSID("$NetBSD: isns_pdu.c,v 1.1 2011/01/16 01:22:50 agc 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.1 agc isns_init_buffer_pool()
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.1 agc return isns_add_tlv(trans, tag, (int)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.1 agc isns_add_tlv(ISNS_TRANS trans, uint32_t tag, int data_len, const void *data_p)
588 1.1 agc {
589 1.1 agc struct isns_trans_s *trans_p;
590 1.1 agc uint8_t tlv_buf[ISNS_TLV_HDR_SIZE];
591 1.1 agc int rval;
592 1.1 agc
593 1.1 agc DBG("isns_add_tlv: trans=%p, tag=%d, data_len=%d, data_p=%p\n",
594 1.1 agc trans, tag, data_len, data_p);
595 1.1 agc
596 1.1 agc if (trans == ISNS_INVALID_TRANS) {
597 1.1 agc DBG("isns_add_tlv: error - trans=%p\n", trans);
598 1.1 agc return EINVAL;
599 1.1 agc }
600 1.1 agc
601 1.1 agc if ((data_len > 0) && (data_p == NULL)) {
602 1.1 agc DBG("isns_add_tlv: error data_len=%d, data_p=%p\n",
603 1.1 agc data_len, data_p);
604 1.1 agc return EINVAL;
605 1.1 agc }
606 1.1 agc
607 1.1 agc /* Set tag, length in header buffer and add to PDU payload data. */
608 1.1 agc trans_p = (struct isns_trans_s *)trans;
609 1.1 agc ISNS_TLV_SET_TAG(tlv_buf, tag);
610 1.1 agc ISNS_TLV_SET_LEN(tlv_buf, ISNS_PAD4_LEN(data_len));
611 1.1 agc rval = isns_add_pdu_payload_data(trans_p, tlv_buf, ISNS_TLV_HDR_SIZE);
612 1.1 agc
613 1.1 agc /* If header added okay, add value portion to PDU payload data. */
614 1.1 agc if ((rval == 0) && (data_len > 0))
615 1.1 agc rval = isns_add_pdu_payload_data(trans_p, data_p, data_len);
616 1.1 agc
617 1.1 agc return rval;
618 1.1 agc }
619 1.1 agc
620 1.1 agc
621 1.1 agc /*
622 1.1 agc * isns_get_tlv - get TLV value from response PDU for transaction
623 1.1 agc *
624 1.1 agc * returns:
625 1.1 agc * 0 - success
626 1.1 agc * ENOENT - no (more) TLVs in this transaction
627 1.1 agc * EINVAL - invalid arg
628 1.1 agc * EPERM - operation not permitted - transaction not complete
629 1.1 agc * ENOMEM - could not allocate storage for spanning TLV data
630 1.1 agc */
631 1.1 agc int
632 1.1 agc isns_get_tlv(ISNS_TRANS trans, int which_tlv, uint32_t *tag_p, int *data_len_p,
633 1.1 agc void **data_pp)
634 1.1 agc {
635 1.1 agc struct isns_trans_s *trans_p;
636 1.1 agc struct isns_get_tlv_info_s *info_p;
637 1.1 agc struct isns_pdu_s *pdu_p;
638 1.1 agc int rval;
639 1.1 agc
640 1.1 agc if (trans == ISNS_INVALID_TRANS) {
641 1.1 agc DBG("isns_get_tlv: error - trans=%p\n", trans);
642 1.1 agc return EINVAL;
643 1.1 agc }
644 1.1 agc
645 1.1 agc trans_p = (struct isns_trans_s *)trans;
646 1.1 agc if ((isns_get_trans_flags(trans_p) & ISNS_TRANSF_COMPLETE) == 0) {
647 1.1 agc DBG("isns_get_tlv: error - trans not complete\n");
648 1.1 agc return EPERM;
649 1.1 agc }
650 1.1 agc
651 1.1 agc /* Get response PDU for this transaction. */
652 1.1 agc pdu_p = isns_get_pdu_response(trans_p);
653 1.1 agc if (pdu_p == NULL) {
654 1.1 agc DBG("isns_get_tlv: error - no response PDU in transaction\n");
655 1.1 agc return EINVAL;
656 1.1 agc }
657 1.1 agc
658 1.1 agc if (pdu_p->payload_p->cur_len == 0) {
659 1.1 agc DBG("isns_get_tlv: error - zero length PDU payload\n");
660 1.1 agc return EINVAL;
661 1.1 agc }
662 1.1 agc
663 1.1 agc /* If get_tlv_info unset, treat ISNS_TLV_NEXT as ISNS_TLV_FIRST. */
664 1.1 agc info_p = &trans_p->get_tlv_info;
665 1.1 agc if ((which_tlv == ISNS_TLV_NEXT) && (info_p->pdu_p == NULL))
666 1.1 agc which_tlv = ISNS_TLV_FIRST;
667 1.1 agc
668 1.1 agc /*!!! make sure PDU uses TLVs here */
669 1.1 agc
670 1.1 agc switch (which_tlv) {
671 1.1 agc case ISNS_TLV_NEXT:
672 1.1 agc /* For next TLV, nothing to do here - use get_tlv_info as-is. */
673 1.1 agc break;
674 1.1 agc
675 1.1 agc case ISNS_TLV_FIRST:
676 1.1 agc /* For first TLV, reset get_tlv_info. */
677 1.1 agc info_p->pdu_p = pdu_p;
678 1.1 agc info_p->buf_p = isns_get_pdu_head_buffer(pdu_p);
679 1.1 agc info_p->buf_ofs = 4;
680 1.1 agc break;
681 1.1 agc
682 1.1 agc default:
683 1.1 agc DBG("isns_get_tlv: invalid arg (which_tlv=%d)\n", which_tlv);
684 1.1 agc return EINVAL;
685 1.1 agc }
686 1.1 agc
687 1.1 agc /*
688 1.1 agc * Get the type, length, and data (value) for the TLV. The get calls
689 1.1 agc * below will advance the pointers in get_tlv_info_s *info_p. Note that
690 1.1 agc * if the get of the TAG type fails, ENOENT is returned indicating that
691 1.1 agc * no more TLVs exist for this request PDU.
692 1.1 agc */
693 1.1 agc if ((rval = isns_get_tlv_uint32(info_p, tag_p)) != 0) {
694 1.1 agc DBG("isns_get_tlv: error on isns_get_tlv_uint32() tag\n");
695 1.1 agc return ENOENT;
696 1.1 agc }
697 1.1 agc
698 1.1 agc if ((rval = isns_get_tlv_uint32(info_p, (uint32_t *)data_len_p)) != 0) {
699 1.1 agc DBG("isns_get_tlv: error on isns_get_tlv_uint32() data len\n");
700 1.1 agc return rval;
701 1.1 agc }
702 1.1 agc
703 1.1 agc rval = isns_get_tlv_data(info_p, *data_len_p, data_pp);
704 1.1 agc if (rval != 0) {
705 1.1 agc DBG("isns_get_tlv: error on isns_get_tlv_data()\n");
706 1.1 agc return rval;
707 1.1 agc }
708 1.1 agc
709 1.1 agc return 0;
710 1.1 agc }
711 1.1 agc
712 1.1 agc
713 1.1 agc /*
714 1.1 agc * isns_set_trans_flags - sets flag bit(s) in transaction flags member
715 1.1 agc */
716 1.1 agc uint32_t
717 1.1 agc isns_set_trans_flags(struct isns_trans_s *trans_p, uint32_t flags)
718 1.1 agc {
719 1.1 agc pthread_mutex_lock(&trans_p->cfg_p->trans_mutex);
720 1.1 agc trans_p->flags |= flags;
721 1.1 agc flags = trans_p->flags;
722 1.1 agc pthread_mutex_unlock(&trans_p->cfg_p->trans_mutex);
723 1.1 agc
724 1.1 agc return flags;
725 1.1 agc }
726 1.1 agc
727 1.1 agc
728 1.1 agc /*
729 1.1 agc * isns_add_pdu_request - adds PDU to transaction request PDU list
730 1.1 agc */
731 1.1 agc void
732 1.1 agc isns_add_pdu_request(struct isns_trans_s *trans_p, struct isns_pdu_s *pdu_p)
733 1.1 agc {
734 1.1 agc DBG("isns_add_pdu_request: trans_p=%p, pdu_p=%p\n", trans_p, pdu_p);
735 1.1 agc
736 1.1 agc isns_add_pdu_list(&trans_p->pdu_req_list, pdu_p);
737 1.1 agc }
738 1.1 agc
739 1.1 agc
740 1.1 agc /*
741 1.1 agc * isns_add_pdu_response - adds PDU to transaction response PDU list
742 1.1 agc */
743 1.1 agc void
744 1.1 agc isns_add_pdu_response(struct isns_trans_s *trans_p, struct isns_pdu_s *pdu_p)
745 1.1 agc {
746 1.1 agc DBG("isns_add_pdu_response: trans_p=%p, pdu_p=%p\n", trans_p, pdu_p);
747 1.1 agc
748 1.1 agc isns_add_pdu_list(&trans_p->pdu_rsp_list, pdu_p);
749 1.1 agc }
750 1.1 agc
751 1.1 agc
752 1.1 agc /*
753 1.1 agc * isns_get_pdu_request_tail - returns last PDU in request PDU chain
754 1.1 agc */
755 1.1 agc struct isns_pdu_s *
756 1.1 agc isns_get_pdu_request_tail(struct isns_trans_s *trans_p)
757 1.1 agc {
758 1.1 agc struct isns_pdu_s *pdu_p;
759 1.1 agc
760 1.1 agc if ((pdu_p = isns_get_pdu_request(trans_p)) != NULL) {
761 1.1 agc while (pdu_p->next != NULL)
762 1.1 agc pdu_p = pdu_p->next;
763 1.1 agc }
764 1.1 agc
765 1.1 agc return pdu_p;
766 1.1 agc }
767 1.1 agc
768 1.1 agc
769 1.1 agc /*
770 1.1 agc * isns_new_pdu - allocates a new PDU and assigns funtion ID and flags
771 1.1 agc */
772 1.1 agc struct isns_pdu_s *
773 1.1 agc isns_new_pdu(struct isns_config_s *cfg_p, uint16_t trans_id, uint16_t func_id,
774 1.1 agc uint16_t flags)
775 1.1 agc {
776 1.1 agc struct isns_buffer_s *buf_p;
777 1.1 agc
778 1.1 agc /*
779 1.1 agc * Allocate a buffer at least large enough for our isns_pdu_s struct
780 1.1 agc * and the embedded isns_buffer_s struct for the PDU payload data and 4
781 1.1 agc * bytes of actual payload data.
782 1.1 agc */
783 1.1 agc buf_p = isns_new_buffer(/* CONSTCOND */(int)MAX(ISNS_BUF_SIZE,
784 1.1 agc sizeof(struct isns_pdu_s) + sizeof(struct isns_buffer_s) + 4));
785 1.1 agc if (buf_p == NULL) {
786 1.1 agc DBG("isns_new_pdu: error on isns_new_buffer()\n");
787 1.1 agc return NULL;
788 1.1 agc }
789 1.1 agc
790 1.1 agc return isns_init_pdu(buf_p, cfg_p, trans_id, func_id, flags);
791 1.1 agc }
792 1.1 agc
793 1.1 agc
794 1.1 agc /*
795 1.1 agc * isns_free_pdu - frees a PDU and all associated buffers
796 1.1 agc */
797 1.1 agc void
798 1.1 agc isns_free_pdu(struct isns_pdu_s *pdu_p)
799 1.1 agc {
800 1.1 agc struct isns_buffer_s *buf_p, *free_buf_p;
801 1.1 agc
802 1.1 agc DBG("isns_free_pdu: %p\n", pdu_p);
803 1.1 agc
804 1.1 agc if (pdu_p != NULL) {
805 1.1 agc /* Free all payload buffers. */
806 1.1 agc buf_p = pdu_p->payload_p;
807 1.1 agc while (buf_p != NULL) {
808 1.1 agc free_buf_p = buf_p;
809 1.1 agc buf_p = buf_p->next;
810 1.1 agc isns_free_buffer(free_buf_p);
811 1.1 agc }
812 1.1 agc /*
813 1.1 agc * Get a pointer to the ISNS buffer in which this PDU is
814 1.1 agc * contained, and then free it.
815 1.1 agc */
816 1.1 agc buf_p = ((struct isns_buffer_s *)(void *)(pdu_p))-1 ;
817 1.1 agc isns_free_buffer(buf_p);
818 1.1 agc }
819 1.1 agc }
820 1.1 agc
821 1.1 agc
822 1.1 agc /*
823 1.1 agc * isns_send_pdu - initiates the send PDU task
824 1.1 agc */
825 1.1 agc int
826 1.1 agc isns_send_pdu(ISNS_TRANS trans, struct isns_pdu_s *pdu_p,
827 1.1 agc const struct timespec *timeout_p)
828 1.1 agc {
829 1.1 agc struct isns_trans_s *trans_p;
830 1.1 agc struct isns_task_s* task_p;
831 1.1 agc int rval;
832 1.1 agc
833 1.1 agc if (trans == ISNS_INVALID_TRANS) {
834 1.1 agc DBG("isns_send_pdu: error - trans=%p\n", trans);
835 1.1 agc return EINVAL;
836 1.1 agc }
837 1.1 agc
838 1.1 agc if (pdu_p == NULL) {
839 1.1 agc DBG("isns_send_pdu: error - pdu_p=%p\n", pdu_p);
840 1.1 agc return EINVAL;
841 1.1 agc }
842 1.1 agc
843 1.1 agc trans_p = (struct isns_trans_s *)trans;
844 1.1 agc
845 1.1 agc /* Build SEND_PDU task, insert on queue and issue command. */
846 1.1 agc task_p = isns_new_task(pdu_p->cfg_p, ISNS_TASK_SEND_PDU,
847 1.1 agc (timeout_p != NULL));
848 1.1 agc task_p->var.send_pdu.trans_p = trans_p;
849 1.1 agc task_p->var.send_pdu.pdu_p = pdu_p;
850 1.1 agc
851 1.1 agc isns_taskq_insert_tail(pdu_p->cfg_p, task_p);
852 1.1 agc
853 1.1 agc isns_issue_cmd(pdu_p->cfg_p, ISNS_CMD_PROCESS_TASKQ);
854 1.1 agc
855 1.1 agc if (timeout_p == NULL)
856 1.1 agc rval = 0;
857 1.1 agc else {
858 1.1 agc rval = isns_wait_task(task_p, timeout_p);
859 1.1 agc if (rval == ETIMEDOUT) {
860 1.1 agc DBG("isns_send_pdu: "
861 1.1 agc "timeout on isns_wait_task() trans_id=%d\n",
862 1.1 agc trans_p->id);
863 1.1 agc
864 1.1 agc isns_issue_cmd_with_data(task_p->cfg_p,
865 1.1 agc ISNS_CMD_ABORT_TRANS, (void *)&trans_p->id,
866 1.1 agc (int)sizeof(trans_p->id));
867 1.1 agc }
868 1.1 agc }
869 1.1 agc
870 1.1 agc return rval;
871 1.1 agc }
872 1.1 agc
873 1.1 agc
874 1.1 agc /*
875 1.1 agc * isns_init_pdu - initialize ISNS buffer to be a PDU
876 1.1 agc */
877 1.1 agc static struct isns_pdu_s *
878 1.1 agc isns_init_pdu(struct isns_buffer_s *buf_p, struct isns_config_s *cfg_p,
879 1.1 agc uint16_t trans_id, uint16_t func_id, uint16_t flags)
880 1.1 agc {
881 1.1 agc struct isns_pdu_s *pdu_p;
882 1.1 agc
883 1.1 agc /* The config and buffer pointers must be valid here. */
884 1.1 agc assert(cfg_p != NULL);
885 1.1 agc assert(buf_p != NULL);
886 1.1 agc
887 1.1 agc /* The PDU starts at offset 0 for the ISNS buffer data. */
888 1.1 agc pdu_p = isns_buffer_data(buf_p, 0);
889 1.1 agc buf_p->cur_len = sizeof(struct isns_pdu_s);
890 1.1 agc
891 1.1 agc /* Assign PDU members. */
892 1.1 agc pdu_p->cfg_p = cfg_p;
893 1.1 agc pdu_p->hdr.isnsp_version = ISNSP_VERSION;
894 1.1 agc pdu_p->hdr.func_id = func_id;
895 1.1 agc pdu_p->hdr.payload_len = 0;
896 1.1 agc pdu_p->hdr.flags = flags;
897 1.1 agc pdu_p->hdr.trans_id = trans_id;
898 1.1 agc pdu_p->hdr.seq_id = 0;
899 1.1 agc pdu_p->byteorder_host = 1;
900 1.1 agc pdu_p->next = NULL;
901 1.1 agc
902 1.1 agc /*
903 1.1 agc * The PDU payload buffer starts after the PDU struct portion in the
904 1.1 agc * ISNS buffer passed in to this function. So, assign the payload_p
905 1.1 agc * pointer accordingly, and then init the buffer with the proper length
906 1.1 agc * and ISNS_BUF_STATIC type.
907 1.1 agc */
908 1.1 agc pdu_p->payload_p = (struct isns_buffer_s *)
909 1.1 agc isns_buffer_data(buf_p, buf_p->cur_len);
910 1.1 agc ISNS_INIT_BUFFER(pdu_p->payload_p, (unsigned)(buf_p->alloc_len -
911 1.1 agc sizeof(struct isns_pdu_s) - sizeof(struct isns_buffer_s)),
912 1.1 agc ISNS_BUF_STATIC);
913 1.1 agc
914 1.1 agc DBG("isns_init_pdu: %p\n", pdu_p);
915 1.1 agc
916 1.1 agc return pdu_p;
917 1.1 agc }
918 1.1 agc
919 1.1 agc
920 1.1 agc /*
921 1.1 agc * isns_add_pdu_payload_data - add data to PDU payload
922 1.1 agc */
923 1.1 agc static int
924 1.1 agc isns_add_pdu_payload_data(struct isns_trans_s *trans_p, const void *data_p,
925 1.1 agc int len)
926 1.1 agc {
927 1.1 agc struct isns_pdu_s *pdu_p, *new_pdu_p;
928 1.1 agc struct isns_buffer_s *buf_p, *new_buf_p;
929 1.1 agc const uint8_t *src_p;
930 1.1 agc uint8_t *dst_p;
931 1.1 agc int pad_bytes;
932 1.1 agc
933 1.1 agc /* Get the request PDU for this transaction. */
934 1.1 agc if ((pdu_p = isns_get_pdu_request_tail(trans_p)) == NULL) {
935 1.1 agc DBG("isns_add_pdu_payload_data: no request PDU\n");
936 1.1 agc return EINVAL;
937 1.1 agc }
938 1.1 agc /* Get the active buffer for this PDU (where data should be copied). */
939 1.1 agc buf_p = isns_get_pdu_active_buffer(pdu_p);
940 1.1 agc
941 1.1 agc /* Set up source and destination pointers. Calculate pad bytes. */
942 1.1 agc src_p = data_p;
943 1.1 agc dst_p = isns_buffer_data(buf_p, buf_p->cur_len);
944 1.1 agc pad_bytes = ISNS_PAD4_BYTES(len);
945 1.1 agc
946 1.1 agc /*
947 1.1 agc * Move data from source to PDU buffer(s), allocated new pdus and
948 1.1 agc * buffers as necessary to accomodate the data.
949 1.1 agc */
950 1.1 agc while (len--) {
951 1.1 agc /* If at max for one PDU payload, add a new PDU. */
952 1.1 agc if (pdu_p->hdr.payload_len == ISNS_MAX_PDU_PAYLOAD) {
953 1.1 agc new_pdu_p = isns_new_pdu(trans_p->cfg_p,
954 1.1 agc trans_p->id, trans_p->func_id, pdu_p->hdr.flags);
955 1.1 agc if (new_pdu_p == NULL)
956 1.1 agc return ENOMEM;
957 1.1 agc isns_add_pdu_request(trans_p, new_pdu_p);
958 1.1 agc pdu_p = new_pdu_p;
959 1.1 agc buf_p = pdu_p->payload_p;
960 1.1 agc dst_p = isns_buffer_data(buf_p, 0);
961 1.1 agc }
962 1.1 agc /* If at end of current buffer, add a new buffer. */
963 1.1 agc if (buf_p->cur_len == buf_p->alloc_len) {
964 1.1 agc if (buf_p->next != NULL)
965 1.1 agc buf_p = buf_p->next;
966 1.1 agc else {
967 1.1 agc new_buf_p = isns_new_buffer(0);
968 1.1 agc if (new_buf_p == NULL)
969 1.1 agc return ENOMEM;
970 1.1 agc buf_p->next = new_buf_p;
971 1.1 agc buf_p = new_buf_p;
972 1.1 agc }
973 1.1 agc dst_p = isns_buffer_data(buf_p, 0);
974 1.1 agc }
975 1.1 agc pdu_p->hdr.payload_len++;
976 1.1 agc buf_p->cur_len++;
977 1.1 agc *dst_p++ = *src_p++;
978 1.1 agc }
979 1.1 agc
980 1.1 agc /*
981 1.1 agc * Since the buffer alloc length is always a multiple of 4, we are
982 1.1 agc * guaranteed to have enough room for the pad bytes.
983 1.1 agc */
984 1.1 agc if (pad_bytes > 0) {
985 1.1 agc pdu_p->hdr.payload_len += pad_bytes;
986 1.1 agc buf_p->cur_len += pad_bytes;
987 1.1 agc while (pad_bytes--)
988 1.1 agc *dst_p++ = 0;
989 1.1 agc }
990 1.1 agc
991 1.1 agc return 0;
992 1.1 agc }
993 1.1 agc
994 1.1 agc
995 1.1 agc /*
996 1.1 agc * isns_get_tlv_info_advance - advances pdu/buffer pointers if at end of
997 1.1 agc * current buffer.
998 1.1 agc */
999 1.1 agc static void
1000 1.1 agc isns_get_tlv_info_advance(struct isns_get_tlv_info_s *info_p)
1001 1.1 agc {
1002 1.1 agc if ((info_p->buf_p != NULL) &&
1003 1.1 agc (info_p->buf_ofs == (int)info_p->buf_p->cur_len)) {
1004 1.1 agc info_p->buf_p = info_p->buf_p->next;
1005 1.1 agc info_p->buf_ofs = 0;
1006 1.1 agc }
1007 1.1 agc
1008 1.1 agc if ((info_p->buf_p == NULL) && (info_p->pdu_p->next != NULL)) {
1009 1.1 agc info_p->pdu_p = info_p->pdu_p->next;
1010 1.1 agc info_p->buf_p = isns_get_pdu_head_buffer(info_p->pdu_p);
1011 1.1 agc info_p->buf_ofs = 0;
1012 1.1 agc }
1013 1.1 agc }
1014 1.1 agc
1015 1.1 agc
1016 1.1 agc /*
1017 1.1 agc * isns_get_tlv_uint32 - retrieve host-ordered uint32_t from PDU buffer at
1018 1.1 agc * starting offset and adjusts isns_get_tlv_info
1019 1.1 agc * pointers accordingly.
1020 1.1 agc */
1021 1.1 agc static int
1022 1.1 agc isns_get_tlv_uint32(struct isns_get_tlv_info_s *info_p, uint32_t *uint32_p)
1023 1.1 agc {
1024 1.1 agc /* Advance to next buffer/pdu (if necessary). */
1025 1.1 agc isns_get_tlv_info_advance(info_p);
1026 1.1 agc
1027 1.1 agc if ((info_p->buf_p == NULL) ||
1028 1.1 agc ((info_p->buf_ofs + 4) > (int)info_p->buf_p->cur_len)) {
1029 1.1 agc DBG("isns_get_tlv_uint32: end of buffer reached\n");
1030 1.1 agc return EFAULT;
1031 1.1 agc }
1032 1.1 agc
1033 1.1 agc *uint32_p = ntohl(*(uint32_t *)isns_buffer_data(info_p->buf_p,
1034 1.1 agc info_p->buf_ofs));
1035 1.1 agc info_p->buf_ofs += 4;
1036 1.1 agc
1037 1.1 agc return 0;
1038 1.1 agc }
1039 1.1 agc
1040 1.1 agc
1041 1.1 agc /*
1042 1.1 agc * isns_get_tlv_data - retrieves data from PDU buffer at starting offset
1043 1.1 agc * for TLV data contained in specified isns_get_tlv_info.
1044 1.1 agc */
1045 1.1 agc static int
1046 1.1 agc isns_get_tlv_data(struct isns_get_tlv_info_s *info_p, int data_len,
1047 1.1 agc void **data_pp)
1048 1.1 agc {
1049 1.1 agc struct isns_buffer_s *extra_buf_p;
1050 1.1 agc struct isns_get_tlv_info_s gti;
1051 1.1 agc uint8_t *data_p, *extra_data_p;
1052 1.1 agc int bytes_remaining, cbytes;
1053 1.1 agc
1054 1.1 agc /* First, NULL return data pointer. */
1055 1.1 agc *data_pp = NULL;
1056 1.1 agc
1057 1.1 agc /* Advance to next buffer/pdu (if necessary). */
1058 1.1 agc isns_get_tlv_info_advance(info_p);
1059 1.1 agc
1060 1.1 agc /* Make sure we have a current get tlv info buffer. */
1061 1.1 agc if (info_p->buf_p == NULL) {
1062 1.1 agc DBG("isns_get_tlv_data: no next buffer\n");
1063 1.1 agc return EFAULT;
1064 1.1 agc }
1065 1.1 agc
1066 1.1 agc /* Get pointer into buffer where desired TLV resides. */
1067 1.1 agc data_p = isns_buffer_data(info_p->buf_p, info_p->buf_ofs);
1068 1.1 agc
1069 1.1 agc /* TLV data completely resides in current buffer. */
1070 1.1 agc if ((info_p->buf_ofs + data_len) <= (int)info_p->buf_p->cur_len) {
1071 1.1 agc info_p->buf_ofs += data_len;
1072 1.1 agc *data_pp = data_p;
1073 1.1 agc return 0;
1074 1.1 agc }
1075 1.1 agc
1076 1.1 agc /*
1077 1.1 agc * TLV data extends into next buffer so an "extra" buffer is allocated
1078 1.1 agc * that is large enough to hold the entire data value. The extra buffer
1079 1.1 agc * is added to the transaction's extra buffer list so we can free it
1080 1.1 agc * when the transaction is freed.
1081 1.1 agc */
1082 1.1 agc
1083 1.1 agc if ((extra_buf_p = isns_new_buffer(data_len)) == NULL) {
1084 1.1 agc DBG("isns_get_tlv_data: error on isns_new_buffer()\n");
1085 1.1 agc return ENOMEM;
1086 1.1 agc }
1087 1.1 agc if (info_p->extra_buf_list == NULL)
1088 1.1 agc info_p->extra_buf_list = extra_buf_p;
1089 1.1 agc else {
1090 1.1 agc extra_buf_p->next = info_p->extra_buf_list;
1091 1.1 agc info_p->extra_buf_list = extra_buf_p;
1092 1.1 agc }
1093 1.1 agc
1094 1.1 agc /* Setup to copy data bytes out to extra buffer. */
1095 1.1 agc gti = *info_p;
1096 1.1 agc extra_data_p = isns_buffer_data(extra_buf_p, 0);
1097 1.1 agc bytes_remaining = data_len;
1098 1.1 agc
1099 1.1 agc while (bytes_remaining > 0) {
1100 1.1 agc /*
1101 1.1 agc * Advance to next buffer/pdu (if necessary), using local copy
1102 1.1 agc * of the get_tlv_info structure.
1103 1.1 agc */
1104 1.1 agc isns_get_tlv_info_advance(>i);
1105 1.1 agc if (gti.buf_p == NULL) {
1106 1.1 agc DBG("isns_get_tlv_data: no next buffer\n");
1107 1.1 agc return EFAULT;
1108 1.1 agc }
1109 1.1 agc
1110 1.1 agc data_p = isns_buffer_data(gti.buf_p, gti.buf_ofs);
1111 1.1 agc
1112 1.1 agc cbytes = MIN(bytes_remaining, ((int)gti.buf_p->cur_len - gti.buf_ofs));
1113 1.1 agc bytes_remaining -= cbytes;
1114 1.1 agc gti.buf_ofs += cbytes;
1115 1.1 agc while (cbytes--)
1116 1.1 agc *extra_data_p++ = *data_p++;
1117 1.1 agc }
1118 1.1 agc
1119 1.1 agc /* Update isns_get_tlv_info with our local copy. */
1120 1.1 agc *info_p = gti;
1121 1.1 agc
1122 1.1 agc /* Assign return data pointer. */
1123 1.1 agc *data_pp = isns_buffer_data(extra_buf_p, 0);
1124 1.1 agc
1125 1.1 agc return 0;
1126 1.1 agc }
1127 1.1 agc
1128 1.1 agc
1129 1.1 agc /*
1130 1.1 agc * isns_get_pdu_response_status - returns status in PDU response
1131 1.1 agc *
1132 1.1 agc * Returns: 0 - success
1133 1.1 agc * EPERM - operation not permitted, trans not complete
1134 1.1 agc * EINVAL - invalid trans PDU response/payload
1135 1.1 agc */
1136 1.1 agc int
1137 1.1 agc isns_get_pdu_response_status(struct isns_trans_s *trans_p, uint32_t *status_p)
1138 1.1 agc {
1139 1.1 agc struct isns_pdu_s *pdu_p;
1140 1.1 agc
1141 1.1 agc if ((isns_get_trans_flags(trans_p) & ISNS_TRANSF_COMPLETE) == 0)
1142 1.1 agc return EPERM;
1143 1.1 agc
1144 1.1 agc pdu_p = isns_get_pdu_response(trans_p);
1145 1.1 agc if ((pdu_p == NULL)
1146 1.1 agc || (pdu_p->payload_p == NULL)
1147 1.1 agc || (pdu_p->payload_p->cur_len < 4))
1148 1.1 agc return EINVAL;
1149 1.1 agc
1150 1.1 agc *status_p = htonl(*(uint32_t *)isns_buffer_data(pdu_p->payload_p, 0));
1151 1.1 agc
1152 1.1 agc return 0;
1153 1.1 agc }
1154 1.1 agc
1155 1.1 agc
1156 1.1 agc /*
1157 1.1 agc * isns_add_pdu_list - adds pdu to specified pdu list
1158 1.1 agc */
1159 1.1 agc static void
1160 1.1 agc isns_add_pdu_list(struct isns_pdu_s **list_pp, struct isns_pdu_s *pdu_p)
1161 1.1 agc {
1162 1.1 agc struct isns_pdu_s *p, *p_prev;
1163 1.1 agc
1164 1.1 agc
1165 1.1 agc if (*list_pp == NULL) {
1166 1.1 agc *list_pp = pdu_p;
1167 1.1 agc pdu_p->next = NULL;
1168 1.1 agc return;
1169 1.1 agc }
1170 1.1 agc
1171 1.1 agc p = *list_pp;
1172 1.1 agc while (p != NULL) {
1173 1.1 agc if (pdu_p->hdr.seq_id < p->hdr.seq_id) {
1174 1.1 agc if (p == *list_pp) {
1175 1.1 agc *list_pp = pdu_p;
1176 1.1 agc pdu_p->next = p;
1177 1.1 agc } else {
1178 1.1 agc p_prev = *list_pp;
1179 1.1 agc while (p_prev->next != p)
1180 1.1 agc p_prev = p_prev->next;
1181 1.1 agc p_prev->next = pdu_p;
1182 1.1 agc pdu_p->next = p;
1183 1.1 agc }
1184 1.1 agc
1185 1.1 agc return;
1186 1.1 agc }
1187 1.1 agc p = p->next;
1188 1.1 agc }
1189 1.1 agc
1190 1.1 agc /* pdu_p->hdr.seq_id > hdr.seq_id of all list elements */
1191 1.1 agc p = *list_pp;
1192 1.1 agc while (p->next != NULL)
1193 1.1 agc p = p->next;
1194 1.1 agc p->next = pdu_p;
1195 1.1 agc pdu_p->next = NULL;
1196 1.1 agc }
1197 1.1 agc
1198 1.1 agc
1199 1.1 agc /*
1200 1.1 agc * isns_get_pdu_head_buffer - returns PDU payload head buffer
1201 1.1 agc */
1202 1.1 agc static struct isns_buffer_s *
1203 1.1 agc isns_get_pdu_head_buffer(struct isns_pdu_s *pdu_p)
1204 1.1 agc {
1205 1.1 agc return pdu_p->payload_p;
1206 1.1 agc }
1207 1.1 agc
1208 1.1 agc
1209 1.1 agc #if 0
1210 1.1 agc /*
1211 1.1 agc * isns_get_pdu_tail_buffer - returns PDU payload tail buffer
1212 1.1 agc */
1213 1.1 agc static struct isns_buffer_s *
1214 1.1 agc isns_get_pdu_tail_buffer(struct isns_pdu_s *pdu_p)
1215 1.1 agc {
1216 1.1 agc struct isns_buffer_s *buf_p;
1217 1.1 agc
1218 1.1 agc buf_p = pdu_p->payload_p;
1219 1.1 agc if (buf_p != NULL)
1220 1.1 agc while (buf_p->next != NULL) buf_p = buf_p->next;
1221 1.1 agc
1222 1.1 agc return buf_p;
1223 1.1 agc }
1224 1.1 agc #endif
1225 1.1 agc
1226 1.1 agc
1227 1.1 agc /*
1228 1.1 agc * isns_get_pdu_active_buffer - returns PDU payload "active buffer where the
1229 1.1 agc * next TLV/data should be written
1230 1.1 agc */
1231 1.1 agc static struct isns_buffer_s *
1232 1.1 agc isns_get_pdu_active_buffer(struct isns_pdu_s *pdu_p)
1233 1.1 agc {
1234 1.1 agc struct isns_buffer_s *buf_p;
1235 1.1 agc
1236 1.1 agc buf_p = pdu_p->payload_p;
1237 1.1 agc while ((buf_p->next != NULL) && (buf_p->cur_len == buf_p->alloc_len)) {
1238 1.1 agc buf_p = buf_p->next;
1239 1.1 agc }
1240 1.1 agc
1241 1.1 agc return buf_p;
1242 1.1 agc }
1243 1.1 agc
1244 1.1 agc
1245 1.1 agc /*
1246 1.1 agc * isns_get_next_trans_id - returns next ISNS transaction ID to use
1247 1.1 agc */
1248 1.1 agc static uint32_t
1249 1.1 agc isns_get_next_trans_id(void)
1250 1.1 agc {
1251 1.1 agc static int trans_id = 1;
1252 1.1 agc
1253 1.1 agc return trans_id++;
1254 1.1 agc }
1255 1.1 agc
1256 1.1 agc
1257 1.1 agc #ifdef ISNS_DEBUG
1258 1.1 agc /*
1259 1.1 agc * isns_dump_pdu - dumps PDU contents
1260 1.1 agc */
1261 1.1 agc void
1262 1.1 agc isns_dump_pdu(struct isns_pdu_s *pdu_p)
1263 1.1 agc {
1264 1.1 agc int n, pos;
1265 1.1 agc struct isns_buffer_s *buf_p;
1266 1.1 agc uint8_t *p;
1267 1.1 agc char text[17];
1268 1.1 agc
1269 1.1 agc if (pdu_p == NULL) {
1270 1.1 agc DBG("isns_dump_pdu: pdu_p is NULL\n");
1271 1.1 agc return;
1272 1.1 agc }
1273 1.1 agc
1274 1.1 agc DBG("pdu header:\n");
1275 1.1 agc if (pdu_p->byteorder_host) {
1276 1.1 agc DBG("ver=0x%04X, func=%d(%s), len=%d, flags=0x%04X, trans=%d, "
1277 1.1 agc "seq=%d\n",
1278 1.1 agc pdu_p->hdr.isnsp_version,
1279 1.1 agc pdu_p->hdr.func_id & ~0x8000,
1280 1.1 agc (pdu_p->hdr.func_id & 0x8000 ? "rsp" : "req"),
1281 1.1 agc pdu_p->hdr.payload_len,
1282 1.1 agc pdu_p->hdr.flags,
1283 1.1 agc pdu_p->hdr.trans_id,
1284 1.1 agc pdu_p->hdr.seq_id);
1285 1.1 agc } else {
1286 1.1 agc DBG("ver=0x%04X, func=%d(%s), len=%d, flags=0x%04X, trans=%d, "
1287 1.1 agc "seq=%d\n",
1288 1.1 agc isns_ntohs(pdu_p->hdr.isnsp_version),
1289 1.1 agc isns_ntohs(pdu_p->hdr.func_id) & ~0x8000,
1290 1.1 agc (pdu_p->hdr.func_id & 0x0080 ? "rsp" : "req"),
1291 1.1 agc isns_ntohs(pdu_p->hdr.payload_len),
1292 1.1 agc isns_ntohs(pdu_p->hdr.flags),
1293 1.1 agc isns_ntohs(pdu_p->hdr.trans_id),
1294 1.1 agc isns_ntohs(pdu_p->hdr.seq_id));
1295 1.1 agc }
1296 1.1 agc
1297 1.1 agc DBG("pdu buffers:\n");
1298 1.1 agc buf_p = pdu_p->payload_p;
1299 1.1 agc while (buf_p != NULL) {
1300 1.1 agc DBG("[%p]: alloc_len=%d, cur_len=%d\n",
1301 1.1 agc buf_p, buf_p->alloc_len, buf_p->cur_len);
1302 1.1 agc buf_p = buf_p->next;
1303 1.1 agc }
1304 1.1 agc
1305 1.1 agc DBG("pdu payload:\n");
1306 1.1 agc buf_p = pdu_p->payload_p;
1307 1.1 agc if (buf_p == NULL) {
1308 1.1 agc DBG("<none>\n");
1309 1.1 agc return;
1310 1.1 agc }
1311 1.1 agc
1312 1.1 agc pos = 0;
1313 1.1 agc memset(text, 0, 17);
1314 1.1 agc while (buf_p != NULL) {
1315 1.1 agc p = isns_buffer_data(buf_p, 0);
1316 1.1 agc for (n = 0; n < buf_p->cur_len; n++) {
1317 1.1 agc DBG("%02X ", *p);
1318 1.1 agc text[pos] = (isprint(*p) ? *p : '.');
1319 1.1 agc pos++;
1320 1.1 agc p++;
1321 1.1 agc
1322 1.1 agc if ((pos % 16) == 0) {
1323 1.1 agc DBG(" %s\n", text);
1324 1.1 agc memset(text, 0, 17);
1325 1.1 agc pos = 0;
1326 1.1 agc }
1327 1.1 agc }
1328 1.1 agc buf_p = buf_p->next;
1329 1.1 agc }
1330 1.1 agc
1331 1.1 agc if ((pos % 16) != 0)
1332 1.1 agc DBG("%*c %s\n", (16 - (pos % 16)) * 3, ' ', text);
1333 1.1 agc }
1334 1.1 agc #endif /* ISNS_DEBUG */
1335