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(>i);
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