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