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