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