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