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 *
iscsi_malloc_atomic(unsigned n)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 *
iscsi_malloc(unsigned n)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
iscsi_free_atomic(void * ptr)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
iscsi_free(void * ptr)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
set_debug(const char * level)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
iscsi_thread_create(iscsi_thread_t * thread,void * (* proc)(void *),void * arg)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
iscsi_queue_init(iscsi_queue_t * q,int depth)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
iscsi_queue_destroy(iscsi_queue_t * q)200 iscsi_queue_destroy(iscsi_queue_t * q)
201 {
202 iscsi_free_atomic(q->elem);
203 }
204
205 int
iscsi_queue_full(iscsi_queue_t * q)206 iscsi_queue_full(iscsi_queue_t * q)
207 {
208 return (q->count == q->depth);
209 }
210
211 int
iscsi_queue_depth(iscsi_queue_t * q)212 iscsi_queue_depth(iscsi_queue_t * q)
213 {
214 return q->count;
215 }
216
217 int
iscsi_queue_insert(iscsi_queue_t * q,void * ptr)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 *
iscsi_queue_remove(iscsi_queue_t * q)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
iscsi_trace(const int trace,const char * fmt,...)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
iscsi_warn(const char * f,const int line,const char * fmt,...)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
iscsi_err(const char * f,const int line,const char * fmt,...)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
iscsi_print_buffer(const char * buf,const size_t len)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
hash_init(hash_t * h,int n)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
hash_insert(hash_t * h,initiator_cmd_t * cmd,unsigned key)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 *
hash_remove(hash_t * h,unsigned key)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
hash_destroy(hash_t * h)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
modify_iov(struct iovec ** iov_ptr,int * iovc,uint32_t offset,uint32_t length)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
iscsi_sock_setsockopt(int * sock,int level,int optname,void * optval,unsigned optlen)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
iscsi_sock_getsockopt(int * sock,int level,int optname,void * optval,unsigned * optlen)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
iscsi_sock_create(int * sock)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
iscsi_sock_bind(int sock,int port)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
iscsi_sock_listen(int sock)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
iscsi_socks_establish(int * sockv,int * famv,int * sockc,char * family,int port)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 *
iscsi_address_family(int fam)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
iscsi_waitfor_connection(int * sockv,int sockc,const char * cf,int * sock)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
iscsi_sock_accept(int sock,int * conn)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
iscsi_sock_getsockname(int sock,struct sockaddr * name,unsigned * namelen)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
iscsi_sock_getpeername(int sock,struct sockaddr * name,unsigned * namelen)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
iscsi_sock_shutdown(int sock,int how)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
iscsi_sock_close(int sock)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
iscsi_sock_connect(int sock,char * hostname,int port)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
iscsi_sock_msg(int sock,int xmit,unsigned len,void * data,int iovc)895 iscsi_sock_msg(int sock, int xmit, unsigned len, void *data, int iovc)
896 {
897 struct iovec singleton;
898 struct iovec *iov;
899 struct iovec *iov_padding = NULL;
900 unsigned n = 0;
901 uint32_t remainder;
902 uint32_t padding_len = 0;
903 uint8_t padding[ISCSI_SOCK_MSG_BYTE_ALIGN];
904 size_t total_len = 0;
905 int rc;
906 int i;
907
908 iscsi_trace(TRACE_NET_DEBUG, "%s %d bytes on sock\n",
909 xmit ? "sending" : "receiving", len);
910 if (iovc == 0) {
911 iscsi_trace(TRACE_NET_DEBUG,
912 "building singleton iovec (data %p, len %u)\n",
913 data, len);
914 singleton.iov_base = data;
915 singleton.iov_len = len;
916 iov = &singleton;
917 iovc = 1;
918 } else {
919 iov = (struct iovec *) data;
920 }
921
922 /* Add padding */
923
924 if ((remainder = len % ISCSI_SOCK_MSG_BYTE_ALIGN) != 0) {
925 iov_padding = iscsi_malloc_atomic((iovc + 1) *
926 sizeof(struct iovec));
927 if (iov_padding == NULL) {
928 iscsi_err(__FILE__, __LINE__,
929 "iscsi_malloc_atomic() failed\n");
930 return -1;
931 }
932 memcpy(iov_padding, iov, iovc * sizeof(struct iovec));
933 iov_padding[iovc].iov_base = padding;
934 padding_len = ISCSI_SOCK_MSG_BYTE_ALIGN - remainder;
935 iov_padding[iovc].iov_len = padding_len;
936 iov = iov_padding;
937 iovc++;
938 memset(padding, 0, padding_len);
939 len += padding_len;
940 iscsi_trace(TRACE_NET_DEBUG,
941 "Added iovec for padding (len %u)\n", padding_len);
942 }
943
944 /*
945 * We make copy of iovec if we're in debugging mode, as we'll
946 * print out the iovec and the buffer contents at the end of
947 * this subroutine and
948 */
949 do {
950 /* Check iovec */
951
952 total_len = 0;
953 iscsi_trace(TRACE_NET_DEBUG, "%s %d buffers\n",
954 xmit ? "gathering from" : "scattering into", iovc);
955 for (i = 0; i < iovc; i++) {
956 iscsi_trace(TRACE_NET_IOV,
957 "iov[%d].iov_base = %p, len %u\n",
958 i, iov[i].iov_base, (unsigned)iov[i].iov_len);
959 total_len += iov[i].iov_len;
960 }
961 if (total_len != len - n) {
962 iscsi_err(__FILE__, __LINE__,
963 "iovcs sum to %zu != total len of %u\n",
964 total_len, len - n);
965 iscsi_err(__FILE__, __LINE__, "iov = %p\n", iov);
966 for (i = 0; i < iovc; i++) {
967 iscsi_err(__FILE__, __LINE__,
968 "iov[%d].iov_base = %p, len %u\n",
969 i, iov[i].iov_base,
970 (unsigned)iov[i].iov_len);
971 }
972 return -1;
973 }
974 if ((rc = (xmit) ? writev(sock, iov, iovc) :
975 readv(sock, iov, iovc)) == 0) {
976 iscsi_trace(TRACE_NET_DEBUG,
977 "%s() failed: rc %d errno %d\n",
978 (xmit) ? "writev" : "readv", rc, errno);
979 break;
980 } else if (rc < 0) {
981 /* Temp FIXME */
982 iscsi_err(__FILE__, __LINE__,
983 "%s() failed: rc %d errno %d\n",
984 (xmit) ? "writev" : "readv", rc, errno);
985 break;
986 }
987 n += rc;
988 if (n < len) {
989 iscsi_trace(TRACE_NET_DEBUG,
990 "Got partial %s: %d bytes of %u\n",
991 (xmit) ? "send" : "recv", rc, len - n + rc);
992 total_len = 0;
993 for (i = 0; i < iovc; i++) {
994 total_len += iov[i].iov_len;
995 }
996 iscsi_trace(TRACE_NET_IOV,
997 "before modify_iov: %s %d buffers, "
998 "total_len = %zu, n = %u, rc = %u\n",
999 xmit ? "gathering from" : "scattering into",
1000 iovc, total_len, n, rc);
1001 if (modify_iov(&iov, &iovc, (unsigned) rc, len - n)
1002 != 0) {
1003 iscsi_err(__FILE__, __LINE__,
1004 "modify_iov() failed\n");
1005 break;
1006 }
1007 total_len = 0;
1008 for (i = 0; i < iovc; i++) {
1009 total_len += iov[i].iov_len;
1010 }
1011 iscsi_trace(TRACE_NET_IOV,
1012 "after modify_iov: %s %d buffers, "
1013 "total_len = %zu, n = %u, rc = %u\n\n",
1014 xmit ? "gathering from" : "scattering into",
1015 iovc, total_len, n, rc);
1016 }
1017 } while (n < len);
1018
1019 if (remainder) {
1020 iscsi_free_atomic(iov_padding);
1021 }
1022 iscsi_trace(TRACE_NET_DEBUG,
1023 "successfully %s %u bytes on sock (%u bytes padding)\n",
1024 xmit ? "sent" : "received", n, padding_len);
1025 return n - padding_len;
1026 }
1027
1028 /*
1029 * Temporary Hack:
1030 *
1031 * TCP's Nagle algorithm and delayed-ack lead to poor performance when we send
1032 * two small messages back to back (i.e., header+data). The TCP_NODELAY option
1033 * is supposed to turn off Nagle, but it doesn't seem to work on Linux 2.4.
1034 * Because of this, if our data payload is small, we'll combine the header and
1035 * data, else send as two separate messages.
1036 */
1037
1038 int
iscsi_sock_send_header_and_data(int sock,void * header,unsigned header_len,const void * data,unsigned data_len,int iovc)1039 iscsi_sock_send_header_and_data(int sock,
1040 void *header, unsigned header_len,
1041 const void *data, unsigned data_len, int iovc)
1042 {
1043 struct iovec iov[ISCSI_MAX_IOVECS];
1044
1045 if (data_len && data_len <= ISCSI_SOCK_HACK_CROSSOVER) {
1046 /* combine header and data into one iovec */
1047 if (iovc >= ISCSI_MAX_IOVECS) {
1048 iscsi_err(__FILE__, __LINE__,
1049 "iscsi_sock_msg() failed\n");
1050 return -1;
1051 }
1052 if (iovc == 0) {
1053 iov[0].iov_base = header;
1054 iov[0].iov_len = header_len;
1055 iov[1].iov_base = __UNCONST((const char *)data);
1056 iov[1].iov_len = data_len;
1057 iovc = 2;
1058 } else {
1059 iov[0].iov_base = header;
1060 iov[0].iov_len = header_len;
1061 (void) memcpy(&iov[1], data, sizeof(struct iovec) *
1062 iovc);
1063 iovc += 1;
1064 }
1065 if ((unsigned)iscsi_sock_msg(sock, Transmit,
1066 header_len + data_len, iov, iovc) !=
1067 header_len + data_len) {
1068 iscsi_err(__FILE__, __LINE__,
1069 "iscsi_sock_msg() failed\n");
1070 return -1;
1071 }
1072 } else {
1073 if ((unsigned)iscsi_sock_msg(sock, Transmit, header_len,
1074 header, 0) != header_len) {
1075 iscsi_err(__FILE__, __LINE__,
1076 "iscsi_sock_msg() failed\n");
1077 return -1;
1078 }
1079 if (data_len != 0 &&
1080 (unsigned)iscsi_sock_msg(sock, Transmit, data_len,
1081 __UNCONST((const char *) data), iovc) != data_len) {
1082 iscsi_err(__FILE__, __LINE__,
1083 "iscsi_sock_msg() failed\n");
1084 return -1;
1085 }
1086 }
1087 return header_len + data_len;
1088 }
1089
1090
1091 /* spin lock functions */
1092 int
iscsi_spin_init(iscsi_spin_t * lock)1093 iscsi_spin_init(iscsi_spin_t * lock)
1094 {
1095 pthread_mutexattr_t mattr;
1096
1097 pthread_mutexattr_init(&mattr);
1098 #ifdef PTHREAD_MUTEX_ADAPTIVE_NP
1099 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ADAPTIVE_NP);
1100 #endif
1101 if (pthread_mutex_init(lock, &mattr) != 0)
1102 return -1;
1103 return 0;
1104 }
1105
1106 int
iscsi_spin_lock(iscsi_spin_t * lock)1107 iscsi_spin_lock(iscsi_spin_t * lock)
1108 {
1109 return pthread_mutex_lock(lock);
1110 }
1111
1112 int
iscsi_spin_unlock(iscsi_spin_t * lock)1113 iscsi_spin_unlock(iscsi_spin_t * lock)
1114 {
1115 return pthread_mutex_unlock(lock);
1116 }
1117
1118 /* ARGSUSED1 */
1119 int
iscsi_spin_lock_irqsave(iscsi_spin_t * lock,uint32_t * flags)1120 iscsi_spin_lock_irqsave(iscsi_spin_t * lock, uint32_t *flags)
1121 {
1122 return pthread_mutex_lock(lock);
1123 }
1124
1125 /* ARGSUSED1 */
1126 int
iscsi_spin_unlock_irqrestore(iscsi_spin_t * lock,uint32_t * flags)1127 iscsi_spin_unlock_irqrestore(iscsi_spin_t * lock, uint32_t *flags)
1128 {
1129 return pthread_mutex_unlock(lock);
1130 }
1131
1132 int
iscsi_spin_destroy(iscsi_spin_t * lock)1133 iscsi_spin_destroy(iscsi_spin_t * lock)
1134 {
1135 return pthread_mutex_destroy(lock);
1136 }
1137
1138
1139 /*
1140 * Mutex Functions, kernel module doesn't require mutex for locking.
1141 * For thread sync, 'down' & 'up' have been wrapped into condition
1142 * varibles, which is kernel semaphores in kernel module.
1143 */
1144
1145 int
iscsi_mutex_init(iscsi_mutex_t * m)1146 iscsi_mutex_init(iscsi_mutex_t * m)
1147 {
1148 return (pthread_mutex_init(m, NULL) != 0) ? -1 : 0;
1149 }
1150
1151 int
iscsi_mutex_lock(iscsi_mutex_t * m)1152 iscsi_mutex_lock(iscsi_mutex_t * m)
1153 {
1154 return pthread_mutex_lock(m);
1155 }
1156
1157 int
iscsi_mutex_unlock(iscsi_mutex_t * m)1158 iscsi_mutex_unlock(iscsi_mutex_t * m)
1159 {
1160 return pthread_mutex_unlock(m);
1161 }
1162
1163 int
iscsi_mutex_destroy(iscsi_mutex_t * m)1164 iscsi_mutex_destroy(iscsi_mutex_t * m)
1165 {
1166 return pthread_mutex_destroy(m);
1167 }
1168
1169 /*
1170 * Condition Functions
1171 */
1172
1173 int
iscsi_cond_init(iscsi_cond_t * c)1174 iscsi_cond_init(iscsi_cond_t * c)
1175 {
1176 return pthread_cond_init(c, NULL);
1177 }
1178
1179 int
iscsi_cond_wait(iscsi_cond_t * c,iscsi_mutex_t * m)1180 iscsi_cond_wait(iscsi_cond_t * c, iscsi_mutex_t * m)
1181 {
1182 return pthread_cond_wait(c, m);
1183 }
1184
1185 int
iscsi_cond_signal(iscsi_cond_t * c)1186 iscsi_cond_signal(iscsi_cond_t * c)
1187 {
1188 return pthread_cond_signal(c);
1189 }
1190
1191 int
iscsi_cond_destroy(iscsi_cond_t * c)1192 iscsi_cond_destroy(iscsi_cond_t * c)
1193 {
1194 return pthread_cond_destroy(c);
1195 }
1196
1197 /*
1198 * Misc. Functions
1199 */
1200
1201 uint32_t
iscsi_atoi(char * value)1202 iscsi_atoi(char *value)
1203 {
1204 if (value == NULL) {
1205 iscsi_err(__FILE__, __LINE__,
1206 "iscsi_atoi() called with NULL value\n");
1207 return 0;
1208 }
1209 return atoi(value);
1210 }
1211
1212 static const char HexString[] = "0123456789abcdef";
1213
1214 /* get the hex value (subscript) of the character */
1215 static int
HexStringIndex(const char * s,int c)1216 HexStringIndex(const char *s, int c)
1217 {
1218 const char *cp;
1219
1220 return (c == '0') ? 0 :
1221 ((cp = strchr(s, tolower(c))) == NULL) ? -1 : (int)(cp - s);
1222 }
1223
1224 int
HexDataToText(uint8_t * data,uint32_t dataLength,char * text,uint32_t textLength)1225 HexDataToText(uint8_t *data, uint32_t dataLength,
1226 char *text, uint32_t textLength)
1227 {
1228 uint32_t n;
1229
1230 if (!text || textLength == 0) {
1231 return -1;
1232 }
1233 if (!data || dataLength == 0) {
1234 *text = 0x0;
1235 return -1;
1236 }
1237 if (textLength < 3) {
1238 *text = 0x0;
1239 return -1;
1240 }
1241 *text++ = '0';
1242 *text++ = 'x';
1243
1244 textLength -= 2;
1245
1246 while (dataLength > 0) {
1247
1248 if (textLength < 3) {
1249 *text = 0x0;
1250 return -1;
1251 }
1252 n = *data++;
1253 dataLength--;
1254
1255 *text++ = HexString[(n >> 4) & 0xf];
1256 *text++ = HexString[n & 0xf];
1257
1258 textLength -= 2;
1259 }
1260
1261 *text = 0x0;
1262
1263 return 0;
1264 }
1265
1266
1267 int
HexTextToData(const char * text,uint32_t textLength,uint8_t * data,uint32_t dataLength)1268 HexTextToData(const char *text, uint32_t textLength,
1269 uint8_t *data, uint32_t dataLength)
1270 {
1271 int i;
1272 uint32_t n1;
1273 uint32_t n2;
1274 uint32_t len = 0;
1275
1276 if ((text[0] == '0') && (text[1] == 'x' || text[1] == 'X')) {
1277 /* skip prefix */
1278 text += 2;
1279 textLength -= 2;
1280 }
1281 if ((textLength % 2) == 1) {
1282
1283 i = HexStringIndex(HexString, *text++);
1284 if (i < 0)
1285 return -1; /* error, bad character */
1286
1287 n2 = i;
1288
1289 if (dataLength < 1) {
1290 return -1; /* error, too much data */
1291 }
1292 *data++ = n2;
1293 len++;
1294 }
1295 while (*text != 0x0) {
1296
1297 if ((i = HexStringIndex(HexString, *text++)) < 0) {
1298 /* error, bad character */
1299 return -1;
1300 }
1301
1302 n1 = i;
1303
1304 if (*text == 0x0) {
1305 /* error, odd string length */
1306 return -1;
1307 }
1308
1309 if ((i = HexStringIndex(HexString, *text++)) < 0) {
1310 /* error, bad character */
1311 return -1;
1312 }
1313
1314 n2 = i;
1315
1316 if (len >= dataLength) {
1317 /* error, too much data */
1318 return len;
1319 }
1320 *data++ = (n1 << 4) | n2;
1321 len++;
1322 }
1323
1324 return (len == 0) ? -1 : 0;
1325 }
1326
1327 void
GenRandomData(uint8_t * data,uint32_t length)1328 GenRandomData(uint8_t *data, uint32_t length)
1329 {
1330 uint32_t n;
1331 size_t i;
1332
1333 for (i = 0 ; i < length ; i += sizeof(n)) {
1334 n = random();
1335 (void) memcpy(&data[i], &n, MIN(length - i, sizeof(n)));
1336 }
1337 }
1338