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