1 /* 2 * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 3 * By downloading, copying, installing or using the software you agree 4 * to this license. If you do not agree to this license, do not 5 * download, install, copy or use the software. 6 * 7 * Intel License Agreement 8 * 9 * Copyright (c) 2000, Intel Corporation 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 16 * -Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 19 * -Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the 22 * distribution. 23 * 24 * -The name of Intel Corporation may not be used to endorse or 25 * promote products derived from this software without specific prior 26 * written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL 32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 35 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 36 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 37 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 38 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 */ 41 #include "config.h" 42 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 46 #ifdef HAVE_SYS_SOCKET_H 47 #include <sys/socket.h> 48 #endif 49 50 #ifdef HAVE_SYS_UIO_H 51 #include <sys/uio.h> 52 #endif 53 54 #ifdef HAVE_ARPA_INET_H 55 #include <arpa/inet.h> 56 #endif 57 58 #ifdef HAVE_NETINET_IN_H 59 #include <netinet/in.h> 60 #endif 61 62 #ifdef HAVE_NETINET_TCP_H 63 #include <netinet/tcp.h> 64 #endif 65 66 #ifdef HAVE_NETDB_H 67 #include <netdb.h> 68 #endif 69 70 #ifdef HAVE_CTYPE_H 71 #include <ctype.h> 72 #endif 73 74 #ifdef HAVE_ERRNO_H 75 #include <errno.h> 76 #endif 77 78 #ifdef HAVE_PTHREAD_H 79 #include <pthread.h> 80 #endif 81 82 #ifdef HAVE_STDARG_H 83 #include <stdarg.h> 84 #endif 85 86 #ifdef HAVE_SYS_SELECT_H 87 #include <sys/select.h> 88 #endif 89 90 #ifdef HAVE_POLL_H 91 #include <poll.h> 92 #endif 93 94 #include <stdio.h> 95 #include <stdlib.h> 96 97 #ifdef HAVE_STRING_H 98 #include <string.h> 99 #endif 100 101 #include <unistd.h> 102 103 #include "compat.h" 104 105 #define EXTERN 106 #include "iscsiutil.h" 107 108 109 110 /* 111 * Memory Allocation 112 */ 113 114 void * 115 iscsi_malloc_atomic(unsigned n) 116 { 117 void *ptr; 118 119 ptr = malloc(n); 120 iscsi_trace(TRACE_MEM, "iscsi_malloc_atomic(%u) = %p\n", n, ptr); 121 return ptr; 122 } 123 124 void * 125 iscsi_malloc(unsigned n) 126 { 127 void *ptr; 128 129 ptr = malloc(n); 130 iscsi_trace(TRACE_MEM, "iscsi_malloc(%u) = %p\n", n, ptr); 131 return ptr; 132 } 133 134 void 135 iscsi_free_atomic(void *ptr) 136 { 137 iscsi_trace(TRACE_MEM, "iscsi_free_atomic(%p)\n", ptr); 138 (void) free(ptr); 139 } 140 141 void 142 iscsi_free(void *ptr) 143 { 144 iscsi_trace(TRACE_MEM, "iscsi_free(%p)\n", ptr); 145 (void) free(ptr); 146 } 147 148 /* debugging levels */ 149 void 150 set_debug(const char *level) 151 { 152 if (strcmp(level, "net") == 0) { 153 iscsi_debug_level |= TRACE_NET_ALL; 154 } else if (strcmp(level, "iscsi") == 0) { 155 iscsi_debug_level |= TRACE_ISCSI_ALL; 156 } else if (strcmp(level, "scsi") == 0) { 157 iscsi_debug_level |= TRACE_SCSI_ALL; 158 } else if (strcmp(level, "osd") == 0) { 159 iscsi_debug_level |= TRACE_OSD; 160 } else if (strcmp(level, "all") == 0) { 161 iscsi_debug_level |= TRACE_ALL; 162 } 163 } 164 165 /* 166 * Threading Routines 167 */ 168 int 169 iscsi_thread_create(iscsi_thread_t * thread, void *(*proc) (void *), void *arg) 170 { 171 if (pthread_create(&thread->pthread, NULL, proc, arg) != 0) { 172 iscsi_err(__FILE__, __LINE__, "pthread_create() failed\n"); 173 return -1; 174 } 175 if (pthread_detach(thread->pthread) != 0) { 176 iscsi_err(__FILE__, __LINE__, "pthread_detach() failed\n"); 177 return -1; 178 } 179 return 0; 180 } 181 182 /* 183 * Queuing Functions 184 */ 185 int 186 iscsi_queue_init(iscsi_queue_t * q, int depth) 187 { 188 q->head = q->tail = q->count = 0; 189 q->depth = depth; 190 q->elem = iscsi_malloc_atomic((unsigned)(depth * sizeof(void *))); 191 if (q->elem == NULL) { 192 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); 193 return -1; 194 } 195 iscsi_spin_init(&q->lock); 196 return 0; 197 } 198 199 void 200 iscsi_queue_destroy(iscsi_queue_t * q) 201 { 202 iscsi_free_atomic(q->elem); 203 } 204 205 int 206 iscsi_queue_full(iscsi_queue_t * q) 207 { 208 return (q->count == q->depth); 209 } 210 211 int 212 iscsi_queue_depth(iscsi_queue_t * q) 213 { 214 return q->count; 215 } 216 217 int 218 iscsi_queue_insert(iscsi_queue_t * q, void *ptr) 219 { 220 uint32_t flags; 221 222 iscsi_spin_lock_irqsave(&q->lock, &flags); 223 if (iscsi_queue_full(q)) { 224 iscsi_err(__FILE__, __LINE__, "QUEUE FULL\n"); 225 iscsi_spin_unlock_irqrestore(&q->lock, &flags); 226 return -1; 227 } 228 q->elem[q->tail] = ptr; 229 q->tail++; 230 if (q->tail == q->depth) { 231 q->tail = 0; 232 } 233 q->count++; 234 iscsi_spin_unlock_irqrestore(&q->lock, &flags); 235 return 0; 236 } 237 238 void * 239 iscsi_queue_remove(iscsi_queue_t *q) 240 { 241 uint32_t flags = 0; 242 void *ptr; 243 244 iscsi_spin_lock_irqsave(&q->lock, &flags); 245 if (!iscsi_queue_depth(q)) { 246 iscsi_trace(TRACE_QUEUE, "QUEUE EMPTY\n"); 247 iscsi_spin_unlock_irqrestore(&q->lock, &flags); 248 return NULL; 249 } 250 q->count--; 251 ptr = q->elem[q->head]; 252 q->head++; 253 if (q->head == q->depth) { 254 q->head = 0; 255 } 256 iscsi_spin_unlock_irqrestore(&q->lock, &flags); 257 return ptr; 258 } 259 260 void 261 iscsi_trace(const int trace, const char *fmt, ...) 262 { 263 #ifdef CONFIG_ISCSI_DEBUG 264 va_list vp; 265 char buf[8192]; 266 267 if (iscsi_debug_level & trace) { 268 va_start(vp, fmt); 269 (void) vsnprintf(buf, sizeof(buf), fmt, vp); 270 printf("pid %d: %s", (int) getpid(), buf); 271 va_end(vp); 272 } 273 #endif 274 } 275 276 void 277 iscsi_warn(const char *f, const int line, const char *fmt, ...) 278 { 279 #ifdef CONFIG_ISCSI_DEBUG 280 va_list vp; 281 char buf[8192]; 282 283 if (iscsi_debug_level & TRACE_WARN) { 284 va_start(vp, fmt); 285 (void) vsnprintf(buf, sizeof(buf), fmt, vp); 286 printf("pid %d:%s:%d: ***WARNING*** %s", 287 (int) getpid(), f, line, 288 buf); 289 va_end(vp); 290 } 291 #endif 292 } 293 294 void 295 iscsi_err(const char *f, const int line, const char *fmt, ...) 296 { 297 #ifdef CONFIG_ISCSI_DEBUG 298 va_list vp; 299 char buf[8192]; 300 301 va_start(vp, fmt); 302 (void) vsnprintf(buf, sizeof(buf), fmt, vp); 303 va_end(vp); 304 printf("pid %d:%s:%d: ***ERROR*** %s", (int) getpid(), f, line, buf); 305 # ifdef HAVE_SYSLOG 306 syslog(LOG_ERR, "pid %d:%s:%d: ***ERROR*** %s", getpid(), f, line, buf); 307 # endif /* HAVE_SYSLOG */ 308 #endif 309 } 310 311 void 312 iscsi_print_buffer(const char *buf, const size_t len) 313 { 314 #ifdef CONFIG_ISCSI_DEBUG 315 size_t i; 316 317 if (iscsi_debug_level & TRACE_NET_BUFF) { 318 for (i=0 ; i < len; i++) { 319 if (i % 4 == 0) { 320 if (i) { 321 printf("\n"); 322 } 323 printf("%4zu:", i); 324 } 325 printf("%2x ", (uint8_t) (buf)[i]); 326 } 327 if ((len + 1) % 32) { 328 printf("\n"); 329 } 330 } 331 #endif 332 } 333 334 /* 335 * Hashing Functions 336 */ 337 #include "initiator.h" 338 339 int 340 hash_init(hash_t * h, int n) 341 { 342 int i; 343 344 iscsi_spin_init(&h->lock); 345 h->n = n; 346 h->insertions = 0; 347 h->collisions = 0; 348 h->bucket = iscsi_malloc_atomic(n * sizeof(initiator_cmd_t *)); 349 if (h->bucket == NULL) { 350 iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); 351 return -1; 352 } 353 for (i = 0; i < n; i++) 354 h->bucket[i] = NULL; 355 return 0; 356 } 357 358 int 359 hash_insert(hash_t * h, initiator_cmd_t * cmd, unsigned key) 360 { 361 int i; 362 363 iscsi_spin_lock(&h->lock); 364 cmd->hash_next = NULL; 365 cmd->key = key; 366 367 i = key % (h->n); 368 if (h->bucket[i] == NULL) { 369 iscsi_trace(TRACE_HASH, 370 "inserting key %u (val 0x%p) into bucket[%d]\n", 371 key, cmd, i); 372 h->bucket[i] = cmd; 373 } else { 374 cmd->hash_next = h->bucket[i]; 375 h->bucket[i] = cmd; 376 h->collisions++; 377 iscsi_trace(TRACE_HASH, 378 "inserting key %u (val 0x%p) into bucket[%d] " 379 "(collision)\n", key, cmd, i); 380 } 381 h->insertions++; 382 iscsi_spin_unlock(&h->lock); 383 return 0; 384 } 385 386 struct initiator_cmd_t * 387 hash_remove(hash_t * h, unsigned key) 388 { 389 initiator_cmd_t *prev; 390 initiator_cmd_t *curr; 391 int i; 392 393 iscsi_spin_lock(&h->lock); 394 i = key % (h->n); 395 if (h->bucket[i] == NULL) { 396 iscsi_err(__FILE__, __LINE__, "bucket emtpy\n"); 397 curr = NULL; 398 } else { 399 prev = NULL; 400 curr = h->bucket[i]; 401 while ((curr->key != key) && (curr->hash_next != NULL)) { 402 prev = curr; 403 curr = curr->hash_next; 404 } 405 if (curr->key != key) { 406 iscsi_err(__FILE__, __LINE__, 407 "key %u (%#x) not found in bucket[%d]\n", 408 key, key, i); 409 curr = NULL; 410 } else { 411 if (prev == NULL) { 412 h->bucket[i] = h->bucket[i]->hash_next; 413 iscsi_trace(TRACE_HASH, 414 "removed key %u (val 0x%p) from head " 415 "of bucket\n", key, curr); 416 } else { 417 prev->hash_next = curr->hash_next; 418 if (prev->hash_next == NULL) { 419 iscsi_trace(TRACE_HASH, 420 "removed key %u (val 0x%p) " 421 "from end of bucket\n", key, 422 curr); 423 } else { 424 iscsi_trace(TRACE_HASH, 425 "removed key %u (val 0x%p) " 426 "from middle of bucket\n", 427 key, curr); 428 } 429 } 430 } 431 } 432 iscsi_spin_unlock(&h->lock); 433 return curr; 434 } 435 436 int 437 hash_destroy(hash_t * h) 438 { 439 iscsi_free_atomic(h->bucket); 440 return 0; 441 } 442 443 /* 444 * Socket Functions 445 */ 446 447 int 448 modify_iov(struct iovec ** iov_ptr, int *iovc, uint32_t offset, uint32_t length) 449 { 450 size_t len; 451 int disp = offset; 452 int i; 453 struct iovec *iov = *iov_ptr; 454 char *basep; 455 456 /* Given <offset>, find beginning iovec and modify its base 457 * and length */ 458 len = 0; 459 for (i = 0; i < *iovc; i++) { 460 len += iov[i].iov_len; 461 if (len > offset) { 462 iscsi_trace(TRACE_NET_IOV, 463 "found offset %u in iov[%d]\n", offset, i); 464 break; 465 } 466 disp -= iov[i].iov_len; 467 } 468 if (i == *iovc) { 469 iscsi_err(__FILE__, __LINE__, 470 "sum of iov lens (%zu) < offset (%u)\n", len, offset); 471 return -1; 472 } 473 iov[i].iov_len -= disp; 474 basep = iov[i].iov_base; 475 basep += disp; 476 iov[i].iov_base = basep; 477 *iovc -= i; 478 *iov_ptr = &(iov[i]); 479 iov = *iov_ptr; 480 481 /* 482 * Given <length>, find ending iovec and modify its length (base does 483 * not change) 484 */ 485 len = 0; /* we should re-use len and i here... */ 486 for (i = 0; i < *iovc; i++) { 487 len += iov[i].iov_len; 488 if (len >= length) { 489 iscsi_trace(TRACE_NET_IOV, 490 "length %u ends in iovec[%d]\n", length, i); 491 break; 492 } 493 } 494 if (i == *iovc) { 495 iscsi_err(__FILE__, __LINE__, 496 "sum of iovec lens (%zu) < length (%u)\n", len, length); 497 for (i = 0; i < *iovc; i++) { 498 iscsi_err(__FILE__, __LINE__, 499 "iov[%d].iov_base = %p (len %u)\n", 500 i, iov[i].iov_base, (unsigned)iov[i].iov_len); 501 } 502 return -1; 503 } 504 iov[i].iov_len -= (len - length); 505 *iovc = i + 1; 506 507 #ifdef CONFIG_ISCSI_DEBUG 508 iscsi_trace(TRACE_NET_IOV, "new iov:\n"); 509 len = 0; 510 for (i = 0; i < *iovc; i++) { 511 iscsi_trace(TRACE_NET_IOV, "iov[%d].iov_base = %p (len %u)\n", 512 i, iov[i].iov_base, (unsigned)iov[i].iov_len); 513 len += iov[i].iov_len; 514 } 515 iscsi_trace(TRACE_NET_IOV, "new iov length: %zu bytes\n", len); 516 #endif 517 518 return 0; 519 } 520 521 int 522 iscsi_sock_setsockopt(int * sock, int level, int optname, void *optval, 523 unsigned optlen) 524 { 525 int rc; 526 527 if ((rc = setsockopt(*sock, level, optname, optval, optlen)) != 0) { 528 iscsi_err(__FILE__, __LINE__, 529 "sock->ops->setsockopt() failed: rc %d errno %d\n", 530 rc, errno); 531 return 0; 532 } 533 return 1; 534 } 535 536 int 537 iscsi_sock_getsockopt(int * sock, int level, int optname, void *optval, unsigned *optlen) 538 { 539 int rc; 540 541 if ((rc = getsockopt(*sock, level, optname, optval, optlen)) != 0) { 542 iscsi_err(__FILE__, __LINE__, 543 "sock->ops->getsockopt() failed: rc %d errno %d\n", 544 rc, errno); 545 return 0; 546 } 547 return 1; 548 } 549 550 int 551 iscsi_sock_create(int * sock) 552 { 553 int rc; 554 555 if ((*sock = rc = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 556 iscsi_err(__FILE__, __LINE__, 557 "socket() failed: rc %d errno %d\n", rc, errno); 558 return 0; 559 } 560 return 1; 561 } 562 563 int 564 iscsi_sock_bind(int sock, int port) 565 { 566 struct sockaddr_in laddr; 567 int rc; 568 569 (void) memset(&laddr, 0x0, sizeof(laddr)); 570 laddr.sin_family = AF_INET; 571 laddr.sin_addr.s_addr = INADDR_ANY; 572 laddr.sin_port = ISCSI_HTONS(port); 573 rc = bind(sock, (struct sockaddr *) (void *) &laddr, sizeof(laddr)); 574 if (rc < 0) { 575 iscsi_err(__FILE__, __LINE__, 576 "bind() failed: rc %d errno %d\n", rc, errno); 577 return 0; 578 } 579 return 1; 580 } 581 582 int 583 iscsi_sock_listen(int sock) 584 { 585 int rc; 586 587 if ((rc = listen(sock, 32)) < 0) { 588 iscsi_err(__FILE__, __LINE__, 589 "listen() failed: rc %d errno %d\n", rc, errno); 590 return 0; 591 } 592 return 1; 593 } 594 595 #ifndef ISCSI_MAXSOCK 596 #define ISCSI_MAXSOCK 8 597 #endif 598 599 int 600 iscsi_socks_establish(int *sockv, int *famv, int *sockc, char *family, int port) 601 { 602 struct addrinfo hints; 603 struct addrinfo *res; 604 struct addrinfo *res0; 605 const char *cause = NULL; 606 char portnum[31]; 607 int one = 1; 608 int error; 609 610 (void) memset(&hints, 0x0, sizeof(hints)); 611 hints.ai_family = (strcmp(family, "unspec") == 0) ? PF_UNSPEC : 612 (strcmp(family, "4") == 0) ? AF_INET : AF_INET6; 613 hints.ai_socktype = SOCK_STREAM; 614 hints.ai_flags = AI_PASSIVE; 615 #ifdef AI_NUMERICSERV 616 hints.ai_flags |= AI_NUMERICSERV; 617 #endif 618 (void) snprintf(portnum, sizeof(portnum), "%d", port); 619 if ((error = getaddrinfo(NULL, portnum, &hints, &res0)) != 0) { 620 hints.ai_flags = AI_PASSIVE; 621 if ((error = getaddrinfo(NULL, "iscsi-target", &hints, 622 &res0)) != 0 || 623 (error = getaddrinfo(NULL, "iscsi", &hints, &res0)) != 0) { 624 iscsi_err(__FILE__, __LINE__, "getaddrinfo: %s", 625 gai_strerror(error)); 626 return 0; 627 } 628 } 629 *sockc = 0; 630 for (res = res0; res && *sockc < ISCSI_MAXSOCK; res = res->ai_next) { 631 sockv[*sockc] = socket(res->ai_family, res->ai_socktype, 632 res->ai_protocol); 633 if (sockv[*sockc] < 0) { 634 cause = "socket"; 635 continue; 636 } 637 famv[*sockc] = res->ai_family; 638 if (!iscsi_sock_setsockopt(&sockv[*sockc], SOL_SOCKET, 639 SO_REUSEADDR, &one, sizeof(one))) { 640 iscsi_err(__FILE__, __LINE__, 641 "iscsi_sock_setsockopt() failed\n"); 642 continue; 643 } 644 if (!iscsi_sock_setsockopt(&sockv[*sockc], SOL_TCP, 645 TCP_NODELAY, &one, sizeof(one))) { 646 iscsi_err(__FILE__, __LINE__, 647 "iscsi_sock_setsockopt() failed\n"); 648 continue; 649 } 650 651 if (bind(sockv[*sockc], res->ai_addr, res->ai_addrlen) < 0) { 652 cause = "bind"; 653 close(sockv[*sockc]); 654 continue; 655 } 656 (void) listen(sockv[*sockc], 32); 657 *sockc += 1; 658 } 659 if (*sockc == 0) { 660 iscsi_err(__FILE__, __LINE__, 661 "iscsi_sock_establish: no sockets found: %s", cause); 662 freeaddrinfo(res0); 663 return 0; 664 } 665 freeaddrinfo(res0); 666 return 1; 667 } 668 669 /* return the address family for the socket */ 670 const char * 671 iscsi_address_family(int fam) 672 { 673 switch(fam) { 674 case 4: 675 return "IPv4"; 676 case 6: 677 return "IPv6"; 678 default: 679 return "[unknown type]"; 680 } 681 } 682 683 /* wait for a connection to come in on a socket */ 684 /* ARGSUSED2 */ 685 int 686 iscsi_waitfor_connection(int *sockv, int sockc, const char *cf, int *sock) 687 { 688 #ifdef HAVE_POLL 689 struct pollfd socks[ISCSI_MAXSOCK]; 690 int i; 691 692 for (;;) { 693 for (i = 0 ; i < sockc ; i++) { 694 socks[i].fd = sockv[i]; 695 socks[i].events = POLLIN; 696 socks[i].revents = 0; 697 } 698 switch(poll(socks, (unsigned)sockc, INFTIM)) { 699 case -1: 700 /* interrupted system call */ 701 continue; 702 case 0: 703 /* timeout */ 704 continue; 705 default: 706 for (i = 0 ; i < sockc ; i++) { 707 if (socks[i].revents & POLLIN) { 708 iscsi_trace(TRACE_NET_DEBUG, 709 "connection %d selected\n", 710 sockv[i]); 711 *sock = sockv[i]; 712 return i; 713 } 714 } 715 } 716 } 717 #else 718 fd_set infds; 719 int i; 720 721 for (;;) { 722 FD_ZERO(&infds); 723 for (i = 0 ; i < sockc ; i++) { 724 FD_SET(sockv[i], &infds); 725 } 726 iscsi_trace(TRACE_NET_DEBUG, "waiting for connection\n"); 727 switch (select(32, &infds, NULL, NULL, NULL)) { 728 case -1: 729 /* interrupted system call */ 730 continue; 731 case 0: 732 /* timeout */ 733 continue; 734 default: 735 for (i = 0 ; i < sockc ; i++) { 736 if (FD_ISSET(sockv[i], &infds)) { 737 iscsi_trace(TRACE_NET_DEBUG, 738 "connection %d selected\n", 739 sockv[i]); 740 *sock = sockv[i]; 741 return i; 742 } 743 } 744 } 745 } 746 #endif 747 } 748 749 int 750 iscsi_sock_accept(int sock, int *conn) 751 { 752 struct sockaddr_in peer; 753 socklen_t peerlen; 754 755 peerlen = sizeof(peer); 756 (void) memset(&peer, 0, sizeof(peer)); 757 *conn = accept(sock, (struct sockaddr *)(void *)&peer, &peerlen); 758 if (*conn < 0) { 759 iscsi_trace(TRACE_NET_DEBUG, 760 "accept() failed: rc %d errno %d\n", *conn, errno); 761 return 0; 762 } 763 764 return 1; 765 } 766 767 int 768 iscsi_sock_getsockname(int sock, struct sockaddr * name, unsigned *namelen) 769 { 770 if (getsockname(sock, name, namelen) != 0) { 771 iscsi_err(__FILE__, __LINE__, 772 "getsockame() failed (errno %d)\n", errno); 773 return 0; 774 } 775 return 1; 776 } 777 778 int 779 iscsi_sock_getpeername(int sock, struct sockaddr * name, unsigned *namelen) 780 { 781 if (getpeername(sock, name, namelen) != 0) { 782 iscsi_err(__FILE__, __LINE__, 783 "getpeername() failed (errno %d)\n", errno); 784 return 0; 785 } 786 return 1; 787 } 788 789 int 790 iscsi_sock_shutdown(int sock, int how) 791 { 792 int rc; 793 794 if ((rc = shutdown(sock, how)) != 0) { 795 iscsi_trace(TRACE_NET_DEBUG, 796 "shutdown() failed: rc %d, errno %d\n", rc, errno); 797 } 798 return 0; 799 } 800 801 int 802 iscsi_sock_close(int sock) 803 { 804 int rc; 805 806 if ((rc = close(sock)) != 0) { 807 iscsi_err(__FILE__, __LINE__, 808 "close() failed: rc %d errno %d\n", rc, errno); 809 return -1; 810 } 811 return 0; 812 } 813 814 int 815 iscsi_sock_connect(int sock, char *hostname, int port) 816 { 817 struct addrinfo hints; 818 struct addrinfo *res; 819 char portstr[32]; 820 int rc = 0; 821 int i; 822 823 (void) memset(&hints, 0, sizeof(hints)); 824 hints.ai_family = AF_INET; 825 hints.ai_socktype = SOCK_STREAM; 826 (void) snprintf(portstr, sizeof(portstr), "%d", port); 827 828 for (i = 0; i < ISCSI_SOCK_CONNECT_TIMEOUT; i++) { 829 /* Attempt connection */ 830 #ifdef AI_NUMERICSERV 831 hints.ai_flags = AI_NUMERICSERV; 832 #endif 833 if ((rc = getaddrinfo(hostname, portstr, &hints, &res)) != 0) { 834 hints.ai_flags = 0; 835 if ((rc = getaddrinfo(hostname, "iscsi-target", &hints, 836 &res)) != 0 || 837 (rc = getaddrinfo(hostname, "iscsi", &hints, 838 &res)) != 0) { 839 iscsi_err(__FILE__, __LINE__, 840 "getaddrinfo: %s", gai_strerror(rc)); 841 return 0; 842 } 843 } 844 845 #if ISCSI_SOCK_CONNECT_NONBLOCK == 1 846 if (fcntl(sock, F_SETFL, O_NONBLOCK) != 0) { 847 iscsi_err(__FILE__, __LINE__, 848 "fcntl O_NONBLOCK failed"); 849 freeaddrinfo(res); 850 return -1; 851 } 852 #endif 853 rc = connect(sock, res->ai_addr, res->ai_addrlen); 854 #if ISCSI_SOCK_CONNECT_NONBLOCK == 1 855 if (fcntl(sock, F_SETFL, O_SYNC) != 0) { 856 iscsi_err(__FILE__, __LINE__, "fcntl O_SYNC failed\n"); 857 freeaddrinfo(res); 858 return -1; 859 } 860 #endif 861 862 /* Check errno */ 863 if (errno == EISCONN) { 864 rc = 0; 865 break; 866 } 867 if (errno == EAGAIN || 868 errno == EINPROGRESS || 869 errno == EALREADY) { 870 if (i != ISCSI_SOCK_CONNECT_TIMEOUT - 1) { 871 printf("***SLEEPING***\n"); 872 sleep(1); 873 } 874 } else { 875 break; 876 } 877 } 878 freeaddrinfo(res); 879 if (rc < 0) { 880 iscsi_err(__FILE__, __LINE__, 881 "connect() to %s:%d failed (errno %d)\n", hostname, 882 port, errno); 883 } 884 return rc; 885 } 886 887 /* 888 * NOTE: iscsi_sock_msg() alters *sg when socket sends and recvs 889 * return having only transfered a portion of the iovec. When this 890 * happens, the iovec is modified and resent with the appropriate 891 * offsets. 892 */ 893 894 int 895 iscsi_sock_msg(int sock, int xmit, unsigned len, void *data, int iovc, 896 int hdigest) 897 { 898 struct iovec singleton; 899 struct iovec *iov; 900 struct iovec *iov_padding = NULL; 901 unsigned n = 0; 902 uint32_t remainder; 903 uint32_t padding_len = 0; 904 uint8_t padding[ISCSI_SOCK_MSG_BYTE_ALIGN]; 905 size_t total_len = 0; 906 int rc; 907 int i; 908 909 iscsi_trace(TRACE_NET_DEBUG, "%s %d bytes on sock\n", 910 xmit ? "sending" : "receiving", len); 911 if (iovc == 0) { 912 iscsi_trace(TRACE_NET_DEBUG, 913 "building singleton iovec (data %p, len %u)\n", 914 data, len); 915 singleton.iov_base = data; 916 singleton.iov_len = len; 917 iov = &singleton; 918 iovc = 1; 919 } else { 920 iov = (struct iovec *) data; 921 } 922 923 /* Add padding */ 924 925 if ((remainder = len % ISCSI_SOCK_MSG_BYTE_ALIGN) != 0) { 926 iov_padding = iscsi_malloc_atomic((iovc + 1) * 927 sizeof(struct iovec)); 928 if (iov_padding == NULL) { 929 iscsi_err(__FILE__, __LINE__, 930 "iscsi_malloc_atomic() failed\n"); 931 return -1; 932 } 933 memcpy(iov_padding, iov, iovc * sizeof(struct iovec)); 934 iov_padding[iovc].iov_base = padding; 935 padding_len = ISCSI_SOCK_MSG_BYTE_ALIGN - remainder; 936 iov_padding[iovc].iov_len = padding_len; 937 iov = iov_padding; 938 iovc++; 939 memset(padding, 0, padding_len); 940 len += padding_len; 941 iscsi_trace(TRACE_NET_DEBUG, 942 "Added iovec for padding (len %u)\n", padding_len); 943 } 944 945 /* 946 * We make copy of iovec if we're in debugging mode, as we'll 947 * print out the iovec and the buffer contents at the end of 948 * this subroutine and 949 */ 950 do { 951 /* Check iovec */ 952 953 total_len = 0; 954 iscsi_trace(TRACE_NET_DEBUG, "%s %d buffers\n", 955 xmit ? "gathering from" : "scattering into", iovc); 956 for (i = 0; i < iovc; i++) { 957 iscsi_trace(TRACE_NET_IOV, 958 "iov[%d].iov_base = %p, len %u\n", 959 i, iov[i].iov_base, (unsigned)iov[i].iov_len); 960 total_len += iov[i].iov_len; 961 } 962 if (total_len != len - n) { 963 iscsi_err(__FILE__, __LINE__, 964 "iovcs sum to %zu != total len of %u\n", 965 total_len, len - n); 966 iscsi_err(__FILE__, __LINE__, "iov = %p\n", iov); 967 for (i = 0; i < iovc; i++) { 968 iscsi_err(__FILE__, __LINE__, 969 "iov[%d].iov_base = %p, len %u\n", 970 i, iov[i].iov_base, 971 (unsigned)iov[i].iov_len); 972 } 973 return -1; 974 } 975 if ((rc = (xmit) ? writev(sock, iov, iovc) : 976 readv(sock, iov, iovc)) == 0) { 977 iscsi_trace(TRACE_NET_DEBUG, 978 "%s() failed: rc %d errno %d\n", 979 (xmit) ? "writev" : "readv", rc, errno); 980 break; 981 } else if (rc < 0) { 982 /* Temp FIXME */ 983 iscsi_err(__FILE__, __LINE__, 984 "%s() failed: rc %d errno %d\n", 985 (xmit) ? "writev" : "readv", rc, errno); 986 break; 987 } 988 n += rc; 989 if (n < len) { 990 iscsi_trace(TRACE_NET_DEBUG, 991 "Got partial %s: %d bytes of %u\n", 992 (xmit) ? "send" : "recv", rc, len - n + rc); 993 total_len = 0; 994 for (i = 0; i < iovc; i++) { 995 total_len += iov[i].iov_len; 996 } 997 iscsi_trace(TRACE_NET_IOV, 998 "before modify_iov: %s %d buffers, " 999 "total_len = %zu, n = %u, rc = %u\n", 1000 xmit ? "gathering from" : "scattering into", 1001 iovc, total_len, n, rc); 1002 if (modify_iov(&iov, &iovc, (unsigned) rc, len - n) 1003 != 0) { 1004 iscsi_err(__FILE__, __LINE__, 1005 "modify_iov() failed\n"); 1006 break; 1007 } 1008 total_len = 0; 1009 for (i = 0; i < iovc; i++) { 1010 total_len += iov[i].iov_len; 1011 } 1012 iscsi_trace(TRACE_NET_IOV, 1013 "after modify_iov: %s %d buffers, " 1014 "total_len = %zu, n = %u, rc = %u\n\n", 1015 xmit ? "gathering from" : "scattering into", 1016 iovc, total_len, n, rc); 1017 } 1018 } while (n < len); 1019 1020 if (remainder) { 1021 iscsi_free_atomic(iov_padding); 1022 } 1023 iscsi_trace(TRACE_NET_DEBUG, 1024 "successfully %s %u bytes on sock (%u bytes padding)\n", 1025 xmit ? "sent" : "received", n, padding_len); 1026 return n - padding_len; 1027 } 1028 1029 int 1030 iscsi_sock_send_header_and_data(int sock, 1031 void *header, unsigned header_len, 1032 const void *data, unsigned data_len, int iovc, 1033 int hdigest, int ddigest) 1034 { 1035 struct iovec iov[ISCSI_MAX_IOVECS+2]; 1036 const struct iovec *diov; 1037 uint32_t digest; 1038 int i; 1039 size_t total_len; 1040 1041 /* combine header and data into one iovec */ 1042 if (iovc + 1 + (ddigest != 0) > ISCSI_MAX_IOVECS) { 1043 iscsi_err(__FILE__, __LINE__, 1044 "iscsi_sock_msg() failed, iovc %d >= %d\n", 1045 iovc, ISCSI_MAX_IOVECS); 1046 return -1; 1047 } 1048 if (iovc == 0) { 1049 iscsi_trace(TRACE_NET_IOV, 1050 "combining header %u and data %u into iovec\n", 1051 header_len, data_len); 1052 iov[0].iov_base = header; 1053 iov[0].iov_len = header_len; 1054 iovc = 1; 1055 if (data_len > 0) { 1056 iov[1].iov_base = __UNCONST((const char *)data); 1057 iov[1].iov_len = data_len; 1058 iovc += 1; 1059 } 1060 } else { 1061 iscsi_trace(TRACE_NET_IOV, 1062 "prepending header %u to iovec %u\n", 1063 header_len, iovc); 1064 iov[0].iov_base = header; 1065 iov[0].iov_len = header_len; 1066 1067 diov = (const struct iovec *)data; 1068 total_len = 0; 1069 for (i=0; i<iovc; ++i) { 1070 iov[1+i] = diov[i]; 1071 total_len += diov[i].iov_len; 1072 if (total_len > data_len) { 1073 total_len -= diov[i].iov_len; 1074 iov[1+i].iov_len = data_len - total_len; 1075 iovc = 1+i; 1076 break; 1077 } 1078 } 1079 iovc += 1; 1080 } 1081 if (ddigest) { 1082 iscsi_trace(TRACE_NET_IOV, 1083 "appending data digest to iovec %u\n", 1084 iovc); 1085 1086 digest = 0; 1087 for (i=1; i<iovc; ++i) { 1088 digest = gen_digest(iov[i].iov_base, 1089 iov[i].iov_len, digest); 1090 } 1091 data_len += sizeof(digest); 1092 iov[iovc].iov_base = &digest; 1093 iov[iovc].iov_len = sizeof(digest); 1094 iovc += 1; 1095 } 1096 1097 if ((unsigned)iscsi_sock_msg(sock, Transmit, 1098 header_len + data_len, iov, iovc, hdigest) != 1099 header_len + data_len) { 1100 iscsi_err(__FILE__, __LINE__, 1101 "iscsi_sock_msg() failed\n"); 1102 return -1; 1103 } 1104 return header_len + data_len; 1105 } 1106 1107 1108 /* spin lock functions */ 1109 int 1110 iscsi_spin_init(iscsi_spin_t * lock) 1111 { 1112 pthread_mutexattr_t mattr; 1113 1114 pthread_mutexattr_init(&mattr); 1115 #ifdef PTHREAD_MUTEX_ADAPTIVE_NP 1116 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ADAPTIVE_NP); 1117 #endif 1118 if (pthread_mutex_init(lock, &mattr) != 0) 1119 return -1; 1120 return 0; 1121 } 1122 1123 int 1124 iscsi_spin_lock(iscsi_spin_t * lock) 1125 { 1126 return pthread_mutex_lock(lock); 1127 } 1128 1129 int 1130 iscsi_spin_unlock(iscsi_spin_t * lock) 1131 { 1132 return pthread_mutex_unlock(lock); 1133 } 1134 1135 /* ARGSUSED1 */ 1136 int 1137 iscsi_spin_lock_irqsave(iscsi_spin_t * lock, uint32_t *flags) 1138 { 1139 return pthread_mutex_lock(lock); 1140 } 1141 1142 /* ARGSUSED1 */ 1143 int 1144 iscsi_spin_unlock_irqrestore(iscsi_spin_t * lock, uint32_t *flags) 1145 { 1146 return pthread_mutex_unlock(lock); 1147 } 1148 1149 int 1150 iscsi_spin_destroy(iscsi_spin_t * lock) 1151 { 1152 return pthread_mutex_destroy(lock); 1153 } 1154 1155 1156 /* 1157 * Mutex Functions, kernel module doesn't require mutex for locking. 1158 * For thread sync, 'down' & 'up' have been wrapped into condition 1159 * varibles, which is kernel semaphores in kernel module. 1160 */ 1161 1162 int 1163 iscsi_mutex_init(iscsi_mutex_t * m) 1164 { 1165 return (pthread_mutex_init(m, NULL) != 0) ? -1 : 0; 1166 } 1167 1168 int 1169 iscsi_mutex_lock(iscsi_mutex_t * m) 1170 { 1171 return pthread_mutex_lock(m); 1172 } 1173 1174 int 1175 iscsi_mutex_unlock(iscsi_mutex_t * m) 1176 { 1177 return pthread_mutex_unlock(m); 1178 } 1179 1180 int 1181 iscsi_mutex_destroy(iscsi_mutex_t * m) 1182 { 1183 return pthread_mutex_destroy(m); 1184 } 1185 1186 /* 1187 * Condition Functions 1188 */ 1189 1190 int 1191 iscsi_cond_init(iscsi_cond_t * c) 1192 { 1193 return pthread_cond_init(c, NULL); 1194 } 1195 1196 int 1197 iscsi_cond_wait(iscsi_cond_t * c, iscsi_mutex_t * m) 1198 { 1199 return pthread_cond_wait(c, m); 1200 } 1201 1202 int 1203 iscsi_cond_signal(iscsi_cond_t * c) 1204 { 1205 return pthread_cond_signal(c); 1206 } 1207 1208 int 1209 iscsi_cond_destroy(iscsi_cond_t * c) 1210 { 1211 return pthread_cond_destroy(c); 1212 } 1213 1214 /* 1215 * Misc. Functions 1216 */ 1217 1218 uint32_t 1219 iscsi_atoi(char *value) 1220 { 1221 if (value == NULL) { 1222 iscsi_err(__FILE__, __LINE__, 1223 "iscsi_atoi() called with NULL value\n"); 1224 return 0; 1225 } 1226 return atoi(value); 1227 } 1228 1229 static const char HexString[] = "0123456789abcdef"; 1230 1231 /* get the hex value (subscript) of the character */ 1232 static int 1233 HexStringIndex(const char *s, int c) 1234 { 1235 const char *cp; 1236 1237 return (c == '0') ? 0 : 1238 ((cp = strchr(s, tolower(c))) == NULL) ? -1 : (int)(cp - s); 1239 } 1240 1241 int 1242 HexDataToText(uint8_t *data, uint32_t dataLength, 1243 char *text, uint32_t textLength) 1244 { 1245 uint32_t n; 1246 1247 if (!text || textLength == 0) { 1248 return -1; 1249 } 1250 if (!data || dataLength == 0) { 1251 *text = 0x0; 1252 return -1; 1253 } 1254 if (textLength < 3) { 1255 *text = 0x0; 1256 return -1; 1257 } 1258 *text++ = '0'; 1259 *text++ = 'x'; 1260 1261 textLength -= 2; 1262 1263 while (dataLength > 0) { 1264 1265 if (textLength < 3) { 1266 *text = 0x0; 1267 return -1; 1268 } 1269 n = *data++; 1270 dataLength--; 1271 1272 *text++ = HexString[(n >> 4) & 0xf]; 1273 *text++ = HexString[n & 0xf]; 1274 1275 textLength -= 2; 1276 } 1277 1278 *text = 0x0; 1279 1280 return 0; 1281 } 1282 1283 1284 int 1285 HexTextToData(const char *text, uint32_t textLength, 1286 uint8_t *data, uint32_t dataLength) 1287 { 1288 int i; 1289 uint32_t n1; 1290 uint32_t n2; 1291 uint32_t len = 0; 1292 1293 if ((text[0] == '0') && (text[1] == 'x' || text[1] == 'X')) { 1294 /* skip prefix */ 1295 text += 2; 1296 textLength -= 2; 1297 } 1298 if ((textLength % 2) == 1) { 1299 1300 i = HexStringIndex(HexString, *text++); 1301 if (i < 0) 1302 return -1; /* error, bad character */ 1303 1304 n2 = i; 1305 1306 if (dataLength < 1) { 1307 return -1; /* error, too much data */ 1308 } 1309 *data++ = n2; 1310 len++; 1311 } 1312 while (*text != 0x0) { 1313 1314 if ((i = HexStringIndex(HexString, *text++)) < 0) { 1315 /* error, bad character */ 1316 return -1; 1317 } 1318 1319 n1 = i; 1320 1321 if (*text == 0x0) { 1322 /* error, odd string length */ 1323 return -1; 1324 } 1325 1326 if ((i = HexStringIndex(HexString, *text++)) < 0) { 1327 /* error, bad character */ 1328 return -1; 1329 } 1330 1331 n2 = i; 1332 1333 if (len >= dataLength) { 1334 /* error, too much data */ 1335 return len; 1336 } 1337 *data++ = (n1 << 4) | n2; 1338 len++; 1339 } 1340 1341 return (len == 0) ? -1 : 0; 1342 } 1343 1344 void 1345 GenRandomData(uint8_t *data, uint32_t length) 1346 { 1347 uint32_t n; 1348 size_t i; 1349 1350 for (i = 0 ; i < length ; i += sizeof(n)) { 1351 n = random(); 1352 (void) memcpy(&data[i], &n, MIN(length - i, sizeof(n))); 1353 } 1354 } 1355