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/param.h>
45 
46 #include <assert.h>
47 #include <stdlib.h>
48 
49 #ifdef HAVE_NETINET_TCP_H
50 #include <netinet/tcp.h>
51 #endif
52 
53 #ifdef HAVE_SYS_UIO_H
54 #include <sys/uio.h>
55 #endif
56 
57 #ifdef HAVE_SYS_SOCKET_H
58 #include <sys/socket.h>
59 #endif
60 
61 #ifdef HAVE_NETINET_IN_H
62 #include <netinet/in.h>
63 #endif
64 
65 #ifdef HAVE_STRING_H
66 #include <string.h>
67 #endif
68 
69 #ifdef HAVE_SIGNAL_H
70 #include <signal.h>
71 #endif
72 
73 #ifdef HAVE_SYSLOG_H
74 #include <syslog.h>
75 #endif
76 
77 #ifdef HAVE_ERRNO_H
78 #include <errno.h>
79 #endif
80 
81 #ifdef HAVE_NETDB_H
82 #include <netdb.h>
83 #endif
84 
85 #ifdef HAVE_ARPA_INET_H
86 #include <arpa/inet.h>
87 #endif
88 
89 #ifdef HAVE_INTTYPES_H
90 #include <inttypes.h>
91 #endif
92 
93 
94 #include "iscsiprotocol.h"
95 #include "conffile.h"
96 #include "storage.h"
97 #include "target.h"
98 #include "device.h"
99 #include "iscsi-md5.h"
100 #include "parameters.h"
101 #include "iscsi.h"
102 
103 enum {
104           TARGET_SHUT_DOWN     = 0,
105           TARGET_INITIALIZING  = 1,
106           TARGET_INITIALIZED   = 2,
107           TARGET_SHUTTING_DOWN = 3
108 };
109 
110 /***********
111  * Private *
112  ***********/
113 
114 static target_session_t       *g_session;
115 static iscsi_queue_t          g_session_q;
116 static iscsi_mutex_t          g_session_q_mutex;
117 
118 /*********************
119  * Private Functions *
120  *********************/
121 
122 static char *
get_iqn(target_session_t * sess,uint32_t t,char * buf,size_t size)123 get_iqn(target_session_t *sess, uint32_t t, char *buf, size_t size)
124 {
125           targv_t   *targv;
126 
127           targv = sess->target->lunv;
128           if (targv->v[t].iqn != NULL) {
129                     (void) strlcpy(buf, targv->v[t].iqn, size);
130                     return buf;
131           }
132           (void) snprintf(buf, size, "%s:%s",
133                               iscsi_target_getvar(sess->target, "iqn"),
134                               targv->v[t].target);
135           return buf;
136 }
137 
138 static int
reject_t(target_session_t * sess,uint8_t * header,uint8_t reason)139 reject_t(target_session_t * sess, uint8_t *header, uint8_t reason)
140 {
141           iscsi_reject_t  reject;
142           uint8_t   rsp_header[ISCSI_HEADER_LEN];
143 
144           iscsi_err(__FILE__, __LINE__, "reject %x\n", reason);
145           reject.reason = reason;
146           reject.length = ISCSI_HEADER_LEN;
147           reject.StatSN = ++(sess->StatSN);
148           reject.ExpCmdSN = sess->ExpCmdSN;
149           reject.MaxCmdSN = sess->MaxCmdSN;
150           reject.DataSN = 0;  /* SNACK not yet implemented */
151 
152           if (iscsi_reject_encap(rsp_header, &reject) != 0) {
153                     iscsi_err(__FILE__, __LINE__,
154                                         "iscsi_reject_encap() failed\n");
155                     return -1;
156           }
157           if (iscsi_sock_send_header_and_data(sess->sock, rsp_header,
158                               ISCSI_HEADER_LEN, header, ISCSI_HEADER_LEN, 0) !=
159                               2 * ISCSI_HEADER_LEN) {
160                     iscsi_err(__FILE__, __LINE__,
161                               "iscsi_sock_send_header_and_data() failed\n");
162                     return -1;
163           }
164           return 0;
165 }
166 
167 static int
scsi_command_t(target_session_t * sess,uint8_t * header)168 scsi_command_t(target_session_t *sess, uint8_t *header)
169 {
170           iscsi_scsi_cmd_args_t         scsi_cmd;
171           iscsi_read_data_t   data;
172           iscsi_scsi_rsp_t    scsi_rsp;
173           target_cmd_t                  cmd;
174           uint32_t            DataSN = 0;
175           uint8_t                       rsp_header[ISCSI_HEADER_LEN];
176           struct iovec                  *sg_new = NULL;
177           int                           result;
178 
179           (void) memset(&scsi_cmd, 0x0, sizeof(scsi_cmd));
180           scsi_cmd.ahs = NULL;
181           scsi_cmd.send_buffer = NULL;
182           if (iscsi_scsi_cmd_decap(header, &scsi_cmd) != 0) {
183                     iscsi_err(__FILE__, __LINE__,
184                                         "iscsi_scsi_cmd_decap() failed\n");
185                     result = -1;
186                     goto out;
187           }
188           iscsi_trace(TRACE_ISCSI_DEBUG,
189                     "session %d: SCSI Command (CmdSN %u, op %#x)\n",
190                     sess->id, scsi_cmd.CmdSN, scsi_cmd.cdb[0]);
191 
192           /* For Non-immediate commands, the CmdSN should be between ExpCmdSN  */
193           /* and MaxCmdSN, inclusive of both.  Otherwise, ignore the command */
194           if (!scsi_cmd.immediate &&
195               (scsi_cmd.CmdSN < sess->ExpCmdSN ||
196                scsi_cmd.CmdSN > sess->MaxCmdSN)) {
197                     iscsi_err(__FILE__, __LINE__,
198                               "CmdSN(%d) of SCSI Command not valid, "
199                               "ExpCmdSN(%d) MaxCmdSN(%d). Ignoring the command\n",
200                               scsi_cmd.CmdSN, sess->ExpCmdSN, sess->MaxCmdSN);
201                     result = 0;
202                     goto out;
203           }
204           /* Arg check.   */
205           scsi_cmd.attr = 0;  /* Temp fix FIXME */
206           /*
207            * RETURN_NOT_EQUAL("ATTR (FIX ME)", scsi_cmd.attr, 0, NO_CLEANUP,
208            * -1);
209            */
210 
211           /* Check Numbering */
212 
213           if (scsi_cmd.CmdSN != sess->ExpCmdSN) {
214                     iscsi_warn(__FILE__, __LINE__,
215                               "Expected CmdSN %d, got %d. "
216                               "(ignoring and resetting expectations)\n",
217                               sess->ExpCmdSN, scsi_cmd.CmdSN);
218                     sess->ExpCmdSN = scsi_cmd.CmdSN;
219           }
220           /* Check Transfer Lengths */
221           if (sess->sess_params.first_burst_length
222               && (scsi_cmd.length > sess->sess_params.first_burst_length)) {
223                     iscsi_err(__FILE__, __LINE__,
224                               "scsi_cmd.length (%u) > FirstBurstLength (%u)\n",
225                               scsi_cmd.length, sess->sess_params.first_burst_length);
226                     scsi_cmd.status = 0x02;
227                     scsi_cmd.length = 0;
228                     goto response;
229           }
230           if (sess->sess_params.max_dataseg_len &&
231               scsi_cmd.length > sess->sess_params.max_dataseg_len) {
232                     iscsi_err(__FILE__, __LINE__,
233                               "scsi_cmd.length (%u) > MaxRecvDataSegmentLength "
234                               "(%u)\n",
235                               scsi_cmd.length, sess->sess_params.max_dataseg_len);
236                     result = -1;
237                     goto out;
238           }
239 
240 #if 0
241           /* commented out in original Intel reference code */
242           if (scsi_cmd.final && scsi_cmd.output) {
243                     RETURN_NOT_EQUAL("Length", scsi_cmd.length,
244                               scsi_cmd.trans_len, NO_CLEANUP, -1);
245           }
246 #endif
247 
248           /* Read AHS.  Need to optimize/clean this.   */
249           /* We should not be calling malloc(). */
250           /* We need to check for properly formated AHS segments. */
251 
252           if (scsi_cmd.ahs_len) {
253                     uint32_t        ahs_len;
254                     uint8_t  *ahs_ptr;
255                     uint8_t   ahs_type;
256 
257                     iscsi_trace(TRACE_ISCSI_DEBUG,
258                                         "reading %u bytes AHS\n", scsi_cmd.ahs_len);
259                     scsi_cmd.ahs = iscsi_malloc_atomic((unsigned)scsi_cmd.ahs_len);
260                     if (scsi_cmd.ahs == NULL) {
261                               iscsi_err(__FILE__, __LINE__,
262                                         "iscsi_malloc_atomic() failed\n");
263                               result = -1;
264                               goto out;
265                     }
266                     if (iscsi_sock_msg(sess->sock, 0, (unsigned)scsi_cmd.ahs_len,
267                                         scsi_cmd.ahs, 0) != scsi_cmd.ahs_len) {
268                               iscsi_err(__FILE__, __LINE__,
269                                         "iscsi_sock_msg() failed\n");
270                               result = -1;
271                               goto out;
272                     }
273                     iscsi_trace(TRACE_ISCSI_DEBUG,
274                                         "read %u bytes AHS\n", scsi_cmd.ahs_len);
275                     for (ahs_ptr = scsi_cmd.ahs;
276                          ahs_ptr < (scsi_cmd.ahs + scsi_cmd.ahs_len - 1) ;
277                          ahs_ptr += ahs_len) {
278                               ahs_len = ISCSI_NTOHS(*((uint16_t *) (void *)ahs_ptr));
279                               if (ahs_len == 0) {
280                                         iscsi_err(__FILE__, __LINE__,
281                                                             "Zero ahs_len\n");
282                                         result = -1;
283                                         goto out;
284                               }
285                               switch (ahs_type = *(ahs_ptr + 2)) {
286                               case ISCSI_AHS_EXTENDED_CDB:
287                                         iscsi_trace(TRACE_ISCSI_DEBUG,
288                                                   "Got ExtendedCDB AHS - %u bytes extra "
289                                                   "CDB)\n", ahs_len - 1);
290                                         scsi_cmd.ext_cdb = ahs_ptr + 4;
291                                         break;
292                               case ISCSI_AHS_BIDI_READ:
293                                         scsi_cmd.bidi_trans_len =
294                                                   ISCSI_NTOHL(*((uint32_t *)(void *)
295                                                                       (ahs_ptr + 4)));
296                                         *((uint32_t *)(void *)(ahs_ptr + 4)) =
297                                                             scsi_cmd.bidi_trans_len;
298                                         iscsi_trace(TRACE_ISCSI_DEBUG,
299                                                   "Got Bidirectional Read AHS "
300                                                   "(expected read length %u)\n",
301                                                   scsi_cmd.bidi_trans_len);
302                                         break;
303                               default:
304                                         iscsi_err(__FILE__, __LINE__,
305                                                   "unknown AHS type %x\n", ahs_type);
306                                         result = -1;
307                                         goto out;
308                               }
309                     }
310                     iscsi_trace(TRACE_ISCSI_DEBUG,
311                               "done parsing %u bytes AHS\n", scsi_cmd.ahs_len);
312           } else {
313                     iscsi_trace(TRACE_ISCSI_DEBUG, "no AHS to read\n");
314                     scsi_cmd.ahs = NULL;
315           }
316 
317           sess->ExpCmdSN++;
318           sess->MaxCmdSN++;
319 
320           /* Execute cdb.  device_command() will set scsi_cmd.input if
321           * there is input data and set the length of the input to
322           * either scsi_cmd.trans_len or scsi_cmd.bidi_trans_len,
323           * depending on whether scsi_cmd.output was set.  */
324           scsi_cmd.send_data = sess->buff;
325           scsi_cmd.input = 0;
326           cmd.scsi_cmd = &scsi_cmd;
327           cmd.callback = NULL;
328           if (device_command(sess, &cmd) != 0) {
329                     iscsi_err(__FILE__, __LINE__,
330                                         "device_command() failed\n");
331                     result = -1;
332                     goto out;
333           }
334           /* Send any input data */
335 
336           scsi_cmd.bytes_sent = 0;
337           if (!scsi_cmd.status && scsi_cmd.input) {
338                     struct iovec    sg_singleton;
339                     struct iovec   *sg, *sg_orig;
340                     int             sg_len_orig, sg_len;
341                     uint32_t        offset, trans_len;
342                     int             fragment_flag = 0;
343                     int             offset_inc;
344 
345                     if (scsi_cmd.output) {
346                               iscsi_trace(TRACE_ISCSI_DEBUG,
347                                         "sending %u bytes bi-directional input data\n",
348                                         scsi_cmd.bidi_trans_len);
349                               trans_len = scsi_cmd.bidi_trans_len;
350                     } else {
351                               trans_len = scsi_cmd.trans_len;
352                     }
353                     iscsi_trace(TRACE_ISCSI_DEBUG,
354                               "sending %u bytes input data as separate PDUs\n",
355                               trans_len);
356 
357                     if (scsi_cmd.send_sg_len) {
358                               sg_orig = (struct iovec *)(void *)scsi_cmd.send_data;
359                               sg_len_orig = scsi_cmd.send_sg_len;
360                     } else {
361                               sg_len_orig = 1;
362                               sg_singleton.iov_base = scsi_cmd.send_data;
363                               sg_singleton.iov_len = trans_len;
364                               sg_orig = &sg_singleton;
365                     }
366                     sg = sg_orig;
367                     sg_len = sg_len_orig;
368 
369                     offset_inc = (sess->sess_params.max_dataseg_len) ?
370                               sess->sess_params.max_dataseg_len : trans_len;
371 
372                     for (offset = 0; offset < trans_len; offset += offset_inc) {
373                               (void) memset(&data, 0x0, sizeof(data));
374                               data.length = (sess->sess_params.max_dataseg_len) ?
375                                         MIN(trans_len - offset,
376                                                   sess->sess_params.max_dataseg_len) :
377                                         trans_len - offset;
378                               if (data.length != trans_len) {
379                                         if (!fragment_flag) {
380                                                   sg_new = iscsi_malloc_atomic(sizeof(struct iovec) * sg_len_orig);
381                                                   if (sg_new == NULL) {
382                                                             iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
383                                                             result = -1;
384                                                             goto out;
385                                                   }
386                                                   fragment_flag++;
387                                         }
388                                         sg = sg_new;
389                                         sg_len = sg_len_orig;
390                                         (void) memcpy(sg, sg_orig, sizeof(struct iovec) * sg_len_orig);
391                                         if (modify_iov(&sg, &sg_len, offset, data.length) != 0) {
392                                                   iscsi_err(__FILE__, __LINE__, "modify_iov() failed\n");
393                                                   result = -1;
394                                                   goto out;
395                                         }
396                               }
397                               iscsi_trace(TRACE_ISCSI_DEBUG, "sending read data PDU (offset %u, len %u)\n", offset, data.length);
398                               if (offset + data.length == trans_len) {
399                                         data.final = 1;
400 
401                                         if (sess->UsePhaseCollapsedRead) {
402                                                   data.status = 1;
403                                                   data.status = scsi_cmd.status;
404                                                   data.StatSN = ++(sess->StatSN);
405                                                   iscsi_trace(TRACE_ISCSI_DEBUG, "status %#x collapsed into last data PDU\n", data.status);
406                                         } else {
407                                                   iscsi_trace(TRACE_ISCSI_DEBUG, "NOT collapsing status with last data PDU\n");
408                                         }
409                               } else if (offset + data.length > trans_len) {
410                                         iscsi_err(__FILE__, __LINE__, "offset+data.length > trans_len??\n");
411                                         result = -1;
412                                         goto out;
413                               }
414                               data.task_tag = scsi_cmd.tag;
415                               data.ExpCmdSN = sess->ExpCmdSN;
416                               data.MaxCmdSN = sess->MaxCmdSN;
417                               data.DataSN = DataSN++;
418                               data.offset = offset;
419                               if (iscsi_read_data_encap(rsp_header, &data) != 0) {
420                                         iscsi_err(__FILE__, __LINE__, "iscsi_read_data_encap() failed\n");
421                                         result = -1;
422                                         goto out;
423                               }
424                               if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock, rsp_header, ISCSI_HEADER_LEN, sg, data.length, sg_len)
425                                   != ISCSI_HEADER_LEN + data.length) {
426                                         iscsi_err(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n");
427                                         result = -1;
428                                         goto out;
429                               }
430                               scsi_cmd.bytes_sent += data.length;
431                               iscsi_trace(TRACE_ISCSI_DEBUG, "sent read data PDU ok (offset %u, len %u)\n", data.offset, data.length);
432                     }
433                     iscsi_trace(TRACE_ISCSI_DEBUG, "successfully sent %u bytes read data\n", trans_len);
434           }
435           /*
436          * Send a response PDU if
437          *
438          * 1) we're not using phase collapsed input (and status was good)
439          * 2) we are using phase collapsed input, but there was no input data (e.g., TEST UNIT READY)
440          * 3) command had non-zero status and possible sense data
441          */
442 response:
443           if (!sess->UsePhaseCollapsedRead || !scsi_cmd.length || scsi_cmd.status) {
444                     iscsi_trace(TRACE_ISCSI_DEBUG, "sending SCSI response PDU\n");
445                     (void) memset(&scsi_rsp, 0x0, sizeof(scsi_rsp));
446                     scsi_rsp.length = scsi_cmd.status ? scsi_cmd.length : 0;
447                     scsi_rsp.tag = scsi_cmd.tag;
448                     /* If r2t send, then the StatSN is already incremented */
449                     if (sess->StatSN < scsi_cmd.ExpStatSN) {
450                               ++sess->StatSN;
451                     }
452                     scsi_rsp.StatSN = sess->StatSN;
453                     scsi_rsp.ExpCmdSN = sess->ExpCmdSN;
454                     scsi_rsp.MaxCmdSN = sess->MaxCmdSN;
455                     scsi_rsp.ExpDataSN = (!scsi_cmd.status && scsi_cmd.input) ? DataSN : 0;
456                     scsi_rsp.response = 0x00;     /* iSCSI response */
457                     scsi_rsp.status = scsi_cmd.status;      /* SCSI status */
458                     if (iscsi_scsi_rsp_encap(rsp_header, &scsi_rsp) != 0) {
459                               iscsi_err(__FILE__, __LINE__, "iscsi_scsi_rsp_encap() failed\n");
460                               result = -1;
461                               goto out;
462                     }
463                     if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock, rsp_header, ISCSI_HEADER_LEN,
464                       scsi_cmd.send_data, scsi_rsp.length, scsi_cmd.send_sg_len)
465                         != ISCSI_HEADER_LEN + scsi_rsp.length) {
466                               iscsi_err(__FILE__, __LINE__,
467                                         "iscsi_sock_send_header_and_data() failed\n");
468                               result = -1;
469                               goto out;
470                     }
471                     /* Make sure all data was transferred */
472 
473                     if (scsi_cmd.output) {
474                               if (scsi_cmd.bytes_recv != scsi_cmd.trans_len) {
475                                         iscsi_err(__FILE__, __LINE__,
476                                                   "scsi_cmd.bytes_recv");
477                                         result = -1;
478                                         goto out;
479                               }
480                               if (scsi_cmd.input) {
481                                         if (scsi_cmd.bytes_sent !=
482                                                             scsi_cmd.bidi_trans_len) {
483                                                   iscsi_err(__FILE__, __LINE__,
484                                                             "scsi_cmd.bytes_sent");
485                                                   result = -1;
486                                                   goto out;
487                                         }
488                               }
489                     } else {
490                               if (scsi_cmd.input) {
491                                         if (scsi_cmd.bytes_sent != scsi_cmd.trans_len) {
492                                                   iscsi_err(__FILE__, __LINE__,
493                                                             "scsi_cmd.bytes_sent");
494                                                   result = -1;
495                                                   goto out;
496                                         }
497                               }
498                     }
499           }
500 
501           /* Device callback after command has completed */
502           if (cmd.callback) {
503                     iscsi_trace(TRACE_ISCSI_DEBUG, "issuing device callback\n");
504                     if ((*cmd.callback)(cmd.callback_arg) != 0) {
505                               iscsi_err(__FILE__, __LINE__,
506                                         "device callback failed\n");
507                               result = -1;
508                               goto out;
509                     }
510           }
511           result = 0;
512 out:
513           if (scsi_cmd.ahs != NULL) {                                           \
514                     iscsi_free_atomic(scsi_cmd.ahs);                            \
515           }                                                                               \
516           if (sg_new != NULL) {
517                     iscsi_free_atomic(sg_new);
518           }
519           free(scsi_cmd.send_buffer);
520           return result;
521 }
522 
523 static int
task_command_t(target_session_t * sess,uint8_t * header)524 task_command_t(target_session_t * sess, uint8_t *header)
525 {
526           iscsi_task_cmd_t cmd;
527           iscsi_task_rsp_t rsp;
528           uint8_t   rsp_header[ISCSI_HEADER_LEN];
529 
530           /* Get & check args */
531 
532           if (iscsi_task_cmd_decap(header, &cmd) != 0) {
533                     iscsi_err(__FILE__, __LINE__,
534                                         "iscsi_task_cmd_decap() failed\n");
535                     return -1;
536           }
537           if (cmd.CmdSN != sess->ExpCmdSN) {
538                     iscsi_warn(__FILE__, __LINE__,
539                               "Expected CmdSN %d, got %d. "
540                               "(ignoring and resetting expectations)\n",
541                                cmd.CmdSN, sess->ExpCmdSN);
542                     sess->ExpCmdSN = cmd.CmdSN;
543           }
544           sess->MaxCmdSN++;
545 
546           (void) memset(&rsp, 0x0, sizeof(rsp));
547           rsp.response = ISCSI_TASK_RSP_FUNCTION_COMPLETE;
548 
549           switch (cmd.function) {
550           case ISCSI_TASK_CMD_ABORT_TASK:
551                     printf("ISCSI_TASK_CMD_ABORT_TASK\n");
552                     break;
553           case ISCSI_TASK_CMD_ABORT_TASK_SET:
554                     printf("ISCSI_TASK_CMD_ABORT_TASK_SET\n");
555                     break;
556           case ISCSI_TASK_CMD_CLEAR_ACA:
557                     printf("ISCSI_TASK_CMD_CLEAR_ACA\n");
558                     break;
559           case ISCSI_TASK_CMD_CLEAR_TASK_SET:
560                     printf("ISCSI_TASK_CMD_CLEAR_TASK_SET\n");
561                     break;
562           case ISCSI_TASK_CMD_LOGICAL_UNIT_RESET:
563                     printf("ISCSI_TASK_CMD_LOGICAL_UNIT_RESET\n");
564                     break;
565           case ISCSI_TASK_CMD_TARGET_WARM_RESET:
566                     printf("ISCSI_TASK_CMD_TARGET_WARM_RESET\n");
567                     break;
568           case ISCSI_TASK_CMD_TARGET_COLD_RESET:
569                     printf("ISCSI_TASK_CMD_TARGET_COLD_RESET\n");
570                     break;
571           case ISCSI_TASK_CMD_TARGET_REASSIGN:
572                     printf("ISCSI_TASK_CMD_TARGET_REASSIGN\n");
573                     break;
574           default:
575                     iscsi_err(__FILE__, __LINE__, "Unknown task function %d\n", cmd.function);
576                     rsp.response = ISCSI_TASK_RSP_REJECTED;
577           }
578 
579           rsp.tag = cmd.tag;
580           rsp.StatSN = ++(sess->StatSN);
581           rsp.ExpCmdSN = sess->ExpCmdSN;
582           rsp.MaxCmdSN = sess->MaxCmdSN;
583 
584           if (iscsi_task_rsp_encap(rsp_header, &rsp) != 0) {
585                     iscsi_err(__FILE__, __LINE__, "iscsi_task_cmd_decap() failed\n");
586                     return -1;
587           }
588           if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, rsp_header, 0) != ISCSI_HEADER_LEN) {
589                     iscsi_err(__FILE__, __LINE__, "iscsi_sock_msg() failed\n");
590                     return -1;
591 
592           }
593           return 0;
594 }
595 
596 static int
nop_out_t(target_session_t * sess,uint8_t * header)597 nop_out_t(target_session_t * sess, uint8_t *header)
598 {
599           iscsi_nop_out_args_t nop_out;
600           char           *ping_data = NULL;
601 
602           if (iscsi_nop_out_decap(header, &nop_out) != 0) {
603                     iscsi_err(__FILE__, __LINE__, "iscsi_nop_out_decap() failed\n");
604                     return -1;
605           }
606           if (nop_out.CmdSN != sess->ExpCmdSN) {
607                     iscsi_warn(__FILE__, __LINE__, "Expected CmdSN %d, got %d. (ignoring and resetting expectations)\n",
608                                     nop_out.CmdSN, sess->ExpCmdSN);
609                     sess->ExpCmdSN = nop_out.CmdSN;
610           }
611           /* TODO Clarify whether we need to update the CmdSN */
612           /* sess->ExpCmdSN++;  */
613           /* sess->MaxCmdSN++;  */
614 
615           if (nop_out.length) {
616                     iscsi_trace(TRACE_ISCSI_DEBUG, "reading %u bytes ping data\n", nop_out.length);
617                     if ((ping_data = iscsi_malloc(nop_out.length)) == NULL) {
618                               iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
619                               return -1;
620                     }
621                     if ((uint32_t)iscsi_sock_msg(sess->sock, 0, nop_out.length, ping_data, 0) != nop_out.length) {
622                               iscsi_err(__FILE__, __LINE__, "iscsi_sock_msg() failed\n");
623                               if (ping_data) {
624                                         iscsi_free(ping_data);
625                               }
626                               return -1;
627                     }
628                     iscsi_trace(TRACE_ISCSI_DEBUG, "successfully read %u bytes ping data:\n", nop_out.length);
629                     iscsi_print_buffer(ping_data, nop_out.length);
630           }
631           if (nop_out.tag != 0xffffffff) {
632                     iscsi_nop_in_args_t  nop_in;
633                     uint8_t   rsp_header[ISCSI_HEADER_LEN];
634 
635                     iscsi_trace(TRACE_ISCSI_DEBUG, "sending %u bytes ping response\n", nop_out.length);
636                     (void) memset(&nop_in, 0x0, sizeof(nop_in));
637                     nop_in.length = nop_out.length;
638                     nop_in.lun = nop_out.lun;
639                     nop_in.tag = nop_out.tag;
640                     nop_in.transfer_tag = 0xffffffff;
641                     nop_in.StatSN = ++(sess->StatSN);
642                     nop_in.ExpCmdSN = sess->ExpCmdSN;
643                     nop_in.MaxCmdSN = sess->MaxCmdSN;
644 
645                     if (iscsi_nop_in_encap(rsp_header, &nop_in) != 0) {
646                               iscsi_err(__FILE__, __LINE__, "iscsi_nop_in_encap() failed\n");
647                               if (ping_data) {
648                                         iscsi_free(ping_data);
649                               }
650                               return -1;
651                     }
652                     if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock, rsp_header, ISCSI_HEADER_LEN,
653                                                                 ping_data, nop_in.length, 0) != ISCSI_HEADER_LEN + nop_in.length) {
654                               iscsi_err(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n");
655                               if (ping_data) {
656                                         iscsi_free(ping_data);
657                               }
658                               return -1;
659                     }
660                     iscsi_trace(TRACE_ISCSI_DEBUG, "successfully sent %u bytes ping response\n", nop_out.length);
661           }
662           if (ping_data) {
663                     iscsi_free(ping_data);
664           }
665           return 0;
666 }
667 
668 /*
669  * text_command_t
670  */
671 
672 static int
text_command_t(target_session_t * sess,uint8_t * header)673 text_command_t(target_session_t * sess, uint8_t *header)
674 {
675           iscsi_text_cmd_args_t          text_cmd;
676           iscsi_text_rsp_args_t          text_rsp;
677           unsigned             len_in;
678           uint32_t             i;
679           uint8_t                        rsp_header[ISCSI_HEADER_LEN];
680           targv_t                       *targv;
681           char                          *text_in = NULL;
682           char                          *text_out = NULL;
683           char                           buf[BUFSIZ];
684           int                            len_out = 0;
685 
686 #define TC_CLEANUP do {                                                                   \
687           if (text_in != NULL) {                                                          \
688                     iscsi_free_atomic(text_in);                                 \
689           }                                                                               \
690           if (text_out != NULL) {                                                         \
691                     iscsi_free_atomic(text_out);                                \
692           }                                                                               \
693 } while (/* CONSTCOND */ 0)
694 #define TC_ERROR {                                                              \
695           TC_CLEANUP;                                                                     \
696           return -1;                                                                      \
697 }
698           /* Get text args */
699 
700           if (iscsi_text_cmd_decap(header, &text_cmd) != 0) {
701                     iscsi_err(__FILE__, __LINE__, "iscsi_text_cmd_decap() failed\n");
702                     return -1;
703           }
704           /* Check args & update numbering */
705 #if 0
706           RETURN_NOT_EQUAL("Continue", text_cmd.cont, 0, NO_CLEANUP, -1);
707           RETURN_NOT_EQUAL("CmdSN", text_cmd.CmdSN, sess->ExpCmdSN, NO_CLEANUP, -1);
708 #else
709           if (text_cmd.cont != 0) {
710                     iscsi_err(__FILE__, __LINE__, "Continue");
711                     NO_CLEANUP;
712                     return -1;
713           }
714           if (text_cmd.CmdSN != sess->ExpCmdSN) {
715                     iscsi_err(__FILE__, __LINE__, "CmdSN");
716                     NO_CLEANUP;
717                     return -1;
718           }
719 #endif
720 
721           sess->ExpCmdSN++;
722           sess->MaxCmdSN++;
723 
724           if ((text_out = iscsi_malloc_atomic(2048)) == NULL) {
725                     iscsi_err(__FILE__, __LINE__,
726                                         "iscsi_malloc_atomic() failed\n");
727                     return -1;
728           }
729 
730           /* Read text parameters */
731           if ((len_in = text_cmd.length) != 0) {
732                     iscsi_parameter_t *ptr;
733 
734                     if ((text_in = iscsi_malloc_atomic(len_in + 1)) == NULL) {
735                               iscsi_err(__FILE__, __LINE__,
736                                         "iscsi_malloc_atomic() failed\n");
737                               TC_CLEANUP;
738                               return -1;
739                     }
740                     iscsi_trace(TRACE_ISCSI_DEBUG,
741                               "reading %u bytes text parameters\n", len_in);
742                     if ((unsigned)iscsi_sock_msg(sess->sock, 0, len_in, text_in,
743                                         0) != len_in) {
744                               iscsi_err(__FILE__, __LINE__,
745                                         "iscsi_sock_msg() failed\n");
746                               TC_CLEANUP;
747                               return -1;
748                     }
749                     text_in[len_in] = 0x0;
750                     PARAM_TEXT_PARSE(sess->params, &sess->sess_params.cred,
751                               text_in, (int) len_in, text_out,
752                               (int *)(void *)&len_out, 2048, 0, TC_ERROR);
753 
754                     /*
755                      * Handle exceptional cases not covered by parameters.c
756                      * (e.g., SendTargets)
757                      */
758                     if ((ptr = param_get(sess->params, "SendTargets")) == NULL) {
759                               iscsi_err(__FILE__, __LINE__,
760                                                   "param_get() failed\n");
761                               TC_CLEANUP;
762                               return -1;
763                     }
764                     if (ptr->rx_offer) {
765                               if (strcmp(ptr->offer_rx, "All") == 0 &&
766                                   !param_equiv(sess->params, "SessionType",
767                                         "Discovery")) {
768                                         iscsi_trace(TRACE_ISCSI_DEBUG,
769                                                   "Rejecting SendTargets=All in a "
770                                                   "non Discovery session\n");
771                                         PARAM_TEXT_ADD(sess->params, "SendTargets",
772                                                   "Reject", text_out, &len_out, 2048,
773                                                   0, TC_ERROR);
774                               } else {
775                                         targv = sess->target->lunv;
776                                         for (i = 0 ; i < targv->c ; i++) {
777                                                   if (sess->address_family == 6 ||
778                                                       (sess->address_family == 4 &&
779                                                             allow_netmask(targv->v[i].mask,
780                                                             sess->initiator))) {
781                                                             (void) get_iqn(sess, i, buf,
782                                                                       sizeof(buf));
783                                                             PARAM_TEXT_ADD(sess->params,
784                                                                       "TargetName", buf,
785                                                                       text_out, &len_out,
786                                                                       2048, 0, TC_ERROR);
787                                                             PARAM_TEXT_ADD(sess->params,
788                                                                       "TargetAddress",
789                               iscsi_target_getvar(sess->target, "target address"),
790                                                                       text_out, &len_out,
791                                                                       2048, 0, TC_ERROR);
792                                                   } else {
793 #ifdef HAVE_SYSLOG_H
794                                                             syslog(LOG_INFO,
795                                                                       "WARNING: attempt to "
796                                                                       "discover targets from "
797                                                                       "%s (not allowed by %s)"
798                                                                       " has been rejected",
799                                                                       sess->initiator,
800                                                                       targv->v[0].mask);
801 #endif
802                                                   }
803                                         }
804                               }
805                               ptr->rx_offer = 0;
806                     }
807                     /* Parse outgoing offer */
808 
809                     if (len_out) {
810                               PARAM_TEXT_PARSE(sess->params,
811                                         &sess->sess_params.cred, text_out, len_out,
812                                         NULL, NULL, 2048, 1, TC_ERROR);
813                     }
814           }
815           if (sess->IsFullFeature) {
816                     set_session_parameters(sess->params, &sess->sess_params);
817           }
818           /* Send response */
819 
820           text_rsp.final = text_cmd.final;
821           text_rsp.cont = 0;
822           text_rsp.length = len_out;
823           text_rsp.lun = text_cmd.lun;
824           text_rsp.tag = text_cmd.tag;
825           text_rsp.transfer_tag = (text_rsp.final) ? 0xffffffff : 0x1234;
826           text_rsp.StatSN = ++(sess->StatSN);
827           text_rsp.ExpCmdSN = sess->ExpCmdSN;
828           text_rsp.MaxCmdSN = sess->MaxCmdSN;
829           if (iscsi_text_rsp_encap(rsp_header, &text_rsp) != 0) {
830                     iscsi_err(__FILE__, __LINE__,
831                               "iscsi_text_rsp_encap() failed\n");
832                     TC_CLEANUP;
833                     return -1;
834           }
835           if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, rsp_header, 0) !=
836                               ISCSI_HEADER_LEN) {
837                     iscsi_err(__FILE__, __LINE__,
838                               "iscsi_sock_msg() failed\n");
839                     TC_CLEANUP;
840                     return -1;
841           }
842           if (len_out && iscsi_sock_msg(sess->sock, 1, (unsigned) len_out,
843                               text_out, 0) != len_out) {
844                     iscsi_err(__FILE__, __LINE__,
845                               "iscsi_sock_msg() failed\n");
846                     TC_CLEANUP;
847                     return -1;
848           }
849           TC_CLEANUP;
850           return 0;
851 }
852 
853 /* given a target's iqn, find the relevant target that we're exporting */
854 int
find_target_iqn(target_session_t * sess)855 find_target_iqn(target_session_t *sess)
856 {
857           uint32_t   i;
858           targv_t             *targv;
859           char                 buf[BUFSIZ];
860 
861           targv = sess->target->lunv;
862           for (i = 0 ; i < targv->c ; i++) {
863                     if (param_equiv(sess->params, "TargetName",
864                                         get_iqn(sess, i, buf, sizeof(buf)))) {
865                               return sess->d = i;
866                     }
867           }
868           return -1;
869 }
870 
871 /* given a tsih, find the relevant target that we're exporting */
872 int
find_target_tsih(iscsi_target_t * target,int tsih)873 find_target_tsih(iscsi_target_t *target, int tsih)
874 {
875           uint32_t   i;
876           targv_t             *targv;
877 
878           targv = target->lunv;
879           for (i = 0 ; i < targv->c ; i++) {
880                     if (targv->v[i].tsih == tsih) {
881                               return i;
882                     }
883           }
884           return -1;
885 }
886 
887 /*
888  * login_command_t() handles login requests and replies.
889  */
890 
891 static int
login_command_t(target_session_t * sess,uint8_t * header)892 login_command_t(target_session_t * sess, uint8_t *header)
893 {
894           iscsi_login_cmd_args_t cmd;
895           iscsi_login_rsp_args_t rsp;
896           uint8_t             rsp_header[ISCSI_HEADER_LEN];
897           targv_t             *targv;
898           char           *text_in = NULL;
899           char           *text_out = NULL;
900           char                logbuf[BUFSIZ];
901           int             len_in = 0;
902           int             len_out = 0;
903           int             status = 0;
904           int                 i;
905 
906           /* Initialize response */
907 
908 #define LC_CLEANUP do {                                                                   \
909           if (text_in != NULL) {                                                          \
910                     iscsi_free_atomic(text_in);                                 \
911           }                                                                               \
912           if (text_out != NULL) {                                                         \
913                     iscsi_free_atomic(text_out);                                \
914           }                                                                               \
915 } while (/* CONSTCOND */ 0)
916 #define LC_ERROR {                                                              \
917           TC_CLEANUP;                                                                     \
918           return -1;                                                                      \
919 }
920 
921           (void) memset(&rsp, 0x0, sizeof(rsp));
922           rsp.status_class = ISCSI_LOGIN_STATUS_INITIATOR_ERROR;
923 
924           /* Get login args & check preconditions */
925 
926           if (iscsi_login_cmd_decap(header, &cmd) != 0) {
927                     iscsi_err(__FILE__, __LINE__,
928                               "iscsi_login_cmd_decap() failed\n");
929                     goto response;
930           }
931           if (sess->IsLoggedIn) {
932                     iscsi_err(__FILE__, __LINE__,
933                               "duplicate login attempt on sess %d\n", sess->id);
934                     goto response;
935           }
936           if ((cmd.cont != 0) && (cmd.transit != 0)) {
937                     iscsi_err(__FILE__, __LINE__,
938                               "Bad cmd.continue.  Expected 0.\n");
939                     goto response;
940           } else if ((cmd.version_max < ISCSI_VERSION) ||
941                        (cmd.version_min > ISCSI_VERSION)) {
942                     iscsi_err(__FILE__, __LINE__,
943                               "Target iscsi version (%u) not supported by initiator "
944                               "[Max Ver (%u) and Min Ver (%u)]\n",
945                               ISCSI_VERSION, cmd.version_max, cmd.version_min);
946                     rsp.status_class = ISCSI_LOGIN_STATUS_INITIATOR_ERROR;
947                     rsp.status_detail = ISCSI_LOGIN_DETAIL_VERSION_NOT_SUPPORTED;
948                     rsp.version_max = ISCSI_VERSION;
949                     rsp.version_active = ISCSI_VERSION;
950                     goto response;
951           } else if (cmd.tsih != 0) {
952                     iscsi_err(__FILE__, __LINE__,
953                               "Bad cmd.tsih (%u). Expected 0.\n", cmd.tsih);
954                     goto response;
955           }
956 
957           /* Parse text parameters and build response */
958           if ((text_out = iscsi_malloc_atomic(2048)) == NULL) {
959                     iscsi_err(__FILE__, __LINE__,
960                               "iscsi_malloc_atomic() failed\n");
961                     return -1;
962           }
963           if ((len_in = cmd.length) != 0) {
964                     iscsi_trace(TRACE_ISCSI_DEBUG,
965                               "reading %d bytes text data\n", len_in);
966                     text_in = iscsi_malloc_atomic((unsigned)(len_in + 1));
967                     if (text_in == NULL) {
968                               iscsi_err(__FILE__, __LINE__,
969                                         "iscsi_malloc() failed\n");
970                               LC_CLEANUP;
971                               return -1;
972                     }
973                     if (iscsi_sock_msg(sess->sock, 0, (unsigned) len_in, text_in,
974                                         0) != len_in) {
975                               iscsi_err(__FILE__, __LINE__,
976                                         "iscsi_sock_msg() failed\n");
977                               LC_CLEANUP;
978                               return -1;
979                     }
980                     text_in[len_in] = 0x0;
981                     iscsi_trace(TRACE_ISCSI_DEBUG,
982                               "successfully read %d bytes text data\n", len_in);
983 
984                     /*
985                      * Parse incoming parameters (text_out will contain the
986                      * response we need
987                      */
988 
989                     /* to send back to the initiator */
990 
991 
992                     status = param_text_parse(sess->params,
993                                         &sess->sess_params.cred, text_in, len_in,
994                                         text_out, &len_out, 2048, 0);
995                     if (status != 0) {
996                               switch (status) {
997                               case ISCSI_PARAM_STATUS_FAILED:
998                                         rsp.status_detail = ISCSI_LOGIN_DETAIL_SUCCESS;
999                                         break;
1000                               case ISCSI_PARAM_STATUS_AUTH_FAILED:
1001                                         rsp.status_detail =
1002                                                   ISCSI_LOGIN_DETAIL_INIT_AUTH_FAILURE;
1003                                         break;
1004                               default:
1005                                         /*
1006                                          * We will need to set the detail
1007                                          * field based on more detailed error
1008                                          * cases.  Will need to fix this if
1009                                          * compliciance test break
1010                                      * (status_detail field).
1011                                      */
1012                                         break;
1013                               }
1014                               goto response;
1015                     }
1016                     /* Parse the outgoing offer */
1017                     if (!sess->LoginStarted) {
1018                               PARAM_TEXT_ADD(sess->params, "TargetPortalGroupTag",
1019                                         "1", text_out, &len_out, 2048, 0, LC_ERROR);
1020                     }
1021                     if (len_out) {
1022                               PARAM_TEXT_PARSE(sess->params,
1023                                         &sess->sess_params.cred, text_out, len_out,
1024                                         NULL, NULL, 2048, 1, LC_ERROR;
1025                               );
1026                     }
1027           }
1028           if (!sess->LoginStarted) {
1029                     sess->LoginStarted = 1;
1030           }
1031           /*
1032            * For now, we accept what ever the initiators' current and next
1033            * states are. And le are always
1034            */
1035           /* ready to transitition to that state. */
1036 
1037           rsp.csg = cmd.csg;
1038           rsp.nsg = cmd.nsg;
1039           rsp.transit = cmd.transit;
1040 
1041           if (cmd.csg == ISCSI_LOGIN_STAGE_SECURITY) {
1042                     if (param_equiv(sess->params, "AuthResult", "No")) {
1043                               rsp.transit = 0;
1044                     } else if (param_equiv(sess->params, "AuthResult", "Fail")) {
1045                               rsp.status_class = rsp.status_detail =
1046                                         ISCSI_LOGIN_DETAIL_INIT_AUTH_FAILURE;
1047                               goto response;
1048                     }
1049           }
1050           if (cmd.transit && cmd.nsg == ISCSI_LOGIN_STAGE_FULL_FEATURE) {
1051                     iscsi_trace(TRACE_ISCSI_DEBUG,
1052                               "transitioning to ISCSI_LOGIN_STAGE_FULL_FEATURE\n");
1053 
1054                     /* Check post conditions */
1055                     if (param_equiv(sess->params, "InitiatorName", "")) {
1056                               iscsi_err(__FILE__, __LINE__,
1057                                         "InitiatorName not specified\n");
1058                               goto response;
1059                     }
1060                     if (param_equiv(sess->params, "SessionType", "Normal")) {
1061                               if (param_equiv(sess->params, "TargetName", "")) {
1062                                         iscsi_err(__FILE__, __LINE__,
1063                                                   "TargetName not specified\n");
1064                                         goto response;
1065                               }
1066                               if ((i = find_target_iqn(sess)) < 0) {
1067                                         iscsi_err(__FILE__, __LINE__,
1068                                                   "Bad TargetName \"%s\"\n",
1069                                                   param_val(sess->params, "TargetName"));
1070                                         goto response;
1071                               }
1072                               if (cmd.tsih != 0 &&
1073                                   find_target_tsih(sess->target, cmd.tsih) != i) {
1074                                         targv = sess->target->lunv;
1075                                         iscsi_err(__FILE__, __LINE__,
1076                                                   "target tsih expected %d, cmd.tsih %d, "
1077                                                   "i %d\n", targv->v[i].tsih, cmd.tsih,
1078                                                   i);
1079                               }
1080                               sess->d = i;
1081                     } else if ((i = find_target_tsih(sess->target, cmd.tsih)) < 0) {
1082                               iscsi_err(__FILE__, __LINE__,
1083                                         "Abnormal SessionType cmd.tsih %d not found\n",
1084                                         cmd.tsih);
1085                               i = sess->d;
1086                     }
1087                     if (param_equiv(sess->params, "SessionType", "")) {
1088                               iscsi_err(__FILE__, __LINE__,
1089                                         "SessionType not specified\n");
1090                               goto response;
1091                     }
1092                     sess->ExpCmdSN = sess->MaxCmdSN = cmd.CmdSN;
1093                     sess->cid = cmd.cid;
1094                     sess->isid = cmd.isid;
1095 
1096                     targv = sess->target->lunv;
1097                     targv->v[i].tsih = sess->tsih = ++sess->target->last_tsih;
1098                     sess->IsFullFeature = 1;
1099 
1100                     sess->IsLoggedIn = 1;
1101                     if (!param_equiv(sess->params, "SessionType", "Discovery")) {
1102                               (void) strlcpy(param_val(sess->params,
1103                                                   "MaxConnections"), "1", 2);
1104                     }
1105                     set_session_parameters(sess->params, &sess->sess_params);
1106           } else {
1107                     if ((i = find_target_tsih(sess->target, cmd.tsih)) < 0) {
1108                               iscsi_err(__FILE__, __LINE__,
1109                                         "cmd.tsih %d not found\n", cmd.tsih);
1110                     }
1111           }
1112 
1113           /* No errors */
1114           rsp.status_class = rsp.status_detail = ISCSI_LOGIN_DETAIL_SUCCESS;
1115           rsp.length = len_out;
1116 
1117           /* Send login response */
1118 response:
1119           sess->ExpCmdSN = sess->MaxCmdSN = cmd.CmdSN;
1120           rsp.isid = cmd.isid;
1121           rsp.StatSN = cmd.ExpStatSN;   /* debug  */
1122           rsp.tag = cmd.tag;
1123           rsp.cont = cmd.cont;
1124           rsp.ExpCmdSN = sess->ExpCmdSN;
1125           rsp.MaxCmdSN = sess->MaxCmdSN;
1126           if (!rsp.status_class) {
1127                     if (rsp.transit &&
1128                         (rsp.nsg == ISCSI_LOGIN_STAGE_FULL_FEATURE)) {
1129                               rsp.version_max = ISCSI_VERSION;
1130                               rsp.version_active = ISCSI_VERSION;
1131                               rsp.StatSN = ++(sess->StatSN);
1132                               rsp.tsih = sess->tsih;
1133                     }
1134           }
1135           if (iscsi_login_rsp_encap(rsp_header, &rsp) != 0) {
1136                     iscsi_err(__FILE__, __LINE__,
1137                               "iscsi_login_rsp_encap() failed\n");
1138                     LC_CLEANUP;
1139                     return -1;
1140           }
1141           iscsi_trace(TRACE_ISCSI_DEBUG, "sending login response\n");
1142           if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock, rsp_header,
1143                               ISCSI_HEADER_LEN, text_out, rsp.length, 0) !=
1144                               ISCSI_HEADER_LEN + rsp.length) {
1145                     iscsi_err(__FILE__, __LINE__,
1146                               "iscsi_sock_send_header_and_data() failed\n");
1147                     LC_CLEANUP;
1148                     return -1;
1149           }
1150           iscsi_trace(TRACE_ISCSI_DEBUG,
1151                     "sent login response ok\n");
1152           if (rsp.status_class != 0) {
1153                     LC_CLEANUP;
1154                     return -1;
1155           }
1156           if (cmd.transit && cmd.nsg == ISCSI_LOGIN_STAGE_FULL_FEATURE) {
1157 
1158                     /* log information to stdout */
1159                     (void) snprintf(logbuf, sizeof(logbuf),
1160                               "> iSCSI %s login  successful from %s on %s disk %d, "
1161                               "ISID %" PRIu64 ", TSIH %u",
1162                               param_val(sess->params, "SessionType"),
1163                               param_val(sess->params, "InitiatorName"),
1164                               sess->initiator,
1165                               sess->d,
1166                               sess->isid,
1167                               sess->tsih);
1168                     printf("%s\n", logbuf);
1169 #ifdef HAVE_SYSLOG_H
1170                     /* log information to syslog */
1171                     syslog(LOG_INFO, "%s", logbuf);
1172 #endif
1173 
1174                     /* Buffer for data xfers to/from the scsi device */
1175                     if (!param_equiv(sess->params, "MaxRecvDataSegmentLength",
1176                                                   "0")) {
1177                               sess->buff = iscsi_malloc((unsigned)(
1178                                                   param_atoi(sess->params,
1179                                                   "MaxRecvDataSegmentLength")));
1180                               if (sess->buff == NULL) {
1181                                         iscsi_err(__FILE__, __LINE__,
1182                                                   "iscsi_malloc() failed\n");
1183                                         LC_CLEANUP;
1184                                         return -1;
1185                               }
1186                     } else {
1187                               iscsi_err(__FILE__, __LINE__,
1188                                         "0 MaxRecvDataSegmentLength not supported\n");
1189                               LC_CLEANUP;
1190                               return -1;
1191                     }
1192           }
1193           LC_CLEANUP;
1194           return 0;
1195 }
1196 
1197 static int
logout_command_t(target_session_t * sess,uint8_t * header)1198 logout_command_t(target_session_t * sess, uint8_t *header)
1199 {
1200           iscsi_logout_cmd_args_t       cmd;
1201           iscsi_logout_rsp_args_t       rsp;
1202           targv_t                       *targv;
1203           uint8_t                       rsp_header[ISCSI_HEADER_LEN];
1204           char                          logbuf[BUFSIZ];
1205           int                           i;
1206 
1207           (void) memset(&rsp, 0x0, sizeof(rsp));
1208           if (iscsi_logout_cmd_decap(header, &cmd) != 0) {
1209                     iscsi_err(__FILE__, __LINE__,
1210                               "iscsi_logout_cmd_decap() failed\n");
1211                     return -1;
1212           }
1213           sess->StatSN = cmd.ExpStatSN;
1214           if ((cmd.reason == ISCSI_LOGOUT_CLOSE_RECOVERY) &&
1215               (param_equiv(sess->params, "ErrorRecoveryLevel", "0"))) {
1216                     rsp.response = ISCSI_LOGOUT_STATUS_NO_RECOVERY;
1217           }
1218 #if 0
1219           RETURN_NOT_EQUAL("CmdSN", cmd.CmdSN, sess->ExpCmdSN, NO_CLEANUP, -1);
1220           RETURN_NOT_EQUAL("ExpStatSN", cmd.ExpStatSN, sess->StatSN, NO_CLEANUP, -1);
1221 #else
1222           if (cmd.CmdSN != sess->ExpCmdSN) {
1223                     iscsi_err(__FILE__, __LINE__, "CmdSN");
1224                     NO_CLEANUP;
1225                     return -1;
1226           }
1227           if (cmd.ExpStatSN != sess->StatSN) {
1228                     iscsi_err(__FILE__, __LINE__, "ExpStatSN");
1229                     NO_CLEANUP;
1230                     return -1;
1231           }
1232 #endif
1233 
1234           rsp.tag = cmd.tag;
1235           rsp.StatSN = sess->StatSN;
1236           rsp.ExpCmdSN = ++sess->ExpCmdSN;
1237           rsp.MaxCmdSN = sess->MaxCmdSN;
1238           if (iscsi_logout_rsp_encap(rsp_header, &rsp) != 0) {
1239                     iscsi_err(__FILE__, __LINE__,
1240                                         "iscsi_logout_rsp_encap() failed\n");
1241                     return -1;
1242           }
1243           if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, rsp_header, 0) !=
1244                               ISCSI_HEADER_LEN) {
1245                     iscsi_err(__FILE__, __LINE__,
1246                               "iscsi_sock_msg() failed\n");
1247                     return -1;
1248           }
1249           iscsi_trace(TRACE_ISCSI_DEBUG, "sent logout response OK\n");
1250 
1251           /* log information to stdout */
1252           (void) snprintf(logbuf, sizeof(logbuf),
1253                     "< iSCSI %s logout successful from %s on %s "
1254                     "disk %d, ISID %" PRIu64 ", TSIH %u",
1255                     param_val(sess->params, "SessionType"),
1256                     param_val(sess->params, "InitiatorName"),
1257                     sess->initiator,
1258                     sess->d,
1259                     sess->isid,
1260                     sess->tsih);
1261           printf("%s\n", logbuf);
1262 #ifdef HAVE_SYSLOG
1263           /* log information to syslog */
1264           syslog(LOG_INFO, "%s", logbuf);
1265 #endif
1266 
1267           sess->IsLoggedIn = 0;
1268 
1269           if (sess->sess_params.cred.user) {
1270                     free(sess->sess_params.cred.user);
1271                     sess->sess_params.cred.user = NULL;
1272           }
1273 
1274           if ((i = find_target_tsih(sess->target, sess->tsih)) < 0) {
1275                     iscsi_err(__FILE__, __LINE__,
1276                               "logout sess->tsih %d not found\n", sess->tsih);
1277           } else {
1278                     targv = sess->target->lunv;
1279                     targv->v[i].tsih = 0;
1280           }
1281           sess->tsih = 0;
1282 
1283           return 0;
1284 }
1285 
1286 static int
verify_cmd_t(target_session_t * sess,uint8_t * header)1287 verify_cmd_t(target_session_t * sess, uint8_t *header)
1288 {
1289           int             op = ISCSI_OPCODE(header);
1290 
1291           if ((!sess->LoginStarted) && (op != ISCSI_LOGIN_CMD)) {
1292                     /* Terminate the connection */
1293                     iscsi_err(__FILE__, __LINE__,
1294                               "session %d: iSCSI op %#x attempted "
1295                               "before LOGIN PHASE\n",
1296                                   sess->id, op);
1297                     return -1;
1298           }
1299           if (!sess->IsFullFeature &&
1300               ((op != ISCSI_LOGIN_CMD) && (op != ISCSI_LOGOUT_CMD))) {
1301                     iscsi_login_rsp_args_t rsp;
1302                     uint8_t   rsp_header[ISCSI_HEADER_LEN];
1303                     iscsi_err(__FILE__, __LINE__,
1304                               "session %d: iSCSI op %#x before FULL FEATURE\n",
1305                               sess->id, op);
1306                     /* Create Login Reject response */
1307                     (void) memset(&rsp, 0x0, sizeof(rsp));
1308                     rsp.status_class = ISCSI_LOGIN_STATUS_INITIATOR_ERROR;
1309                     rsp.status_detail = ISCSI_LOGIN_DETAIL_NOT_LOGGED_IN;
1310                     rsp.version_max = ISCSI_VERSION;
1311                     rsp.version_active = ISCSI_VERSION;
1312 
1313                     if (iscsi_login_rsp_encap(rsp_header, &rsp) != 0) {
1314                               iscsi_err(__FILE__, __LINE__,
1315                                         "iscsi_login_rsp_encap() failed\n");
1316                               return -1;
1317                     }
1318                     iscsi_trace(TRACE_ISCSI_DEBUG, "sending login response\n");
1319                     if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock,
1320                                         rsp_header, ISCSI_HEADER_LEN, NULL, 0, 0) !=
1321                                         ISCSI_HEADER_LEN + rsp.length) {
1322                               iscsi_err(__FILE__, __LINE__,
1323                                         "iscsi_sock_send_header_and_data() failed\n");
1324                               return -1;
1325                     }
1326                     iscsi_trace(TRACE_ISCSI_DEBUG, "sent login response ok\n");
1327                     return -1;
1328           }
1329           return 0;
1330 }
1331 
1332 /*
1333  * this function looks at the opcode in the received header for the session,
1334  * and does a switch on the opcode to call the required function.
1335  */
1336 static int
execute_t(target_session_t * sess,uint8_t * header)1337 execute_t(target_session_t *sess, uint8_t *header)
1338 {
1339           int             op = ISCSI_OPCODE(header);
1340 
1341           if (verify_cmd_t(sess, header) != 0) {
1342                     return -1;
1343           }
1344           switch (op) {
1345           case ISCSI_TASK_CMD:
1346                     iscsi_trace(TRACE_ISCSI_CMD,
1347                                         "session %d: Task Command\n", sess->id);
1348                     if (task_command_t(sess, header) != 0) {
1349                               iscsi_err(__FILE__, __LINE__,
1350                                         "task_command_t() failed\n");
1351                               return -1;
1352                     }
1353                     break;
1354 
1355           case ISCSI_NOP_OUT:
1356                     iscsi_trace(TRACE_ISCSI_CMD, "session %d: NOP-Out\n", sess->id);
1357                     if (nop_out_t(sess, header) != 0) {
1358                               iscsi_err(__FILE__, __LINE__,
1359                                         "nop_out_t() failed\n");
1360                               return -1;
1361                     }
1362                     break;
1363 
1364           case ISCSI_LOGIN_CMD:
1365                     iscsi_trace(TRACE_ISCSI_CMD,
1366                                         "session %d: Login Command\n", sess->id);
1367                     if (login_command_t(sess, header) != 0) {
1368                               iscsi_err(__FILE__, __LINE__,
1369                                         "login_command_t() failed\n");
1370                               return -1;
1371                     }
1372                     break;
1373 
1374           case ISCSI_TEXT_CMD:
1375                     iscsi_trace(TRACE_ISCSI_CMD,
1376                                         "session %d: Text Command\n", sess->id);
1377                     if (text_command_t(sess, header) != 0) {
1378                               iscsi_err(__FILE__, __LINE__,
1379                                         "text_command_t() failed\n");
1380                               return -1;
1381                     }
1382                     break;
1383 
1384           case ISCSI_LOGOUT_CMD:
1385                     iscsi_trace(TRACE_ISCSI_CMD,
1386                               "session %d: Logout Command\n", sess->id);
1387                     if (logout_command_t(sess, header) != 0) {
1388                               iscsi_err(__FILE__, __LINE__,
1389                                         "logout_command_t() failed\n");
1390                               return -1;
1391                     }
1392                     break;
1393 
1394           case ISCSI_SCSI_CMD:
1395                     iscsi_trace(TRACE_ISCSI_CMD,
1396                               "session %d: SCSI Command\n", sess->id);
1397                     if (scsi_command_t(sess, header) != 0) {
1398                               iscsi_err(__FILE__, __LINE__,
1399                                         "scsi_command_t() failed\n");
1400                               return -1;
1401                     }
1402                     break;
1403 
1404           default:
1405                     iscsi_err(__FILE__, __LINE__, "Unknown Opcode %#x\n",
1406                               ISCSI_OPCODE(header));
1407                     if (reject_t(sess, header, 0x04) != 0) {
1408                               iscsi_err(__FILE__, __LINE__,
1409                                         "reject_t() failed\n");
1410                               return -1;
1411                     }
1412                     break;
1413           }
1414           return 0;
1415 }
1416 
1417 /*
1418  * Currently one thread per session, used for both Rx and Tx.
1419  */
1420 static int
worker_proc_t(void * arg)1421 worker_proc_t(void *arg)
1422 {
1423           target_session_t *sess = (target_session_t *) arg;
1424           uint8_t   header[ISCSI_HEADER_LEN];
1425           iscsi_parameter_t **l = &sess->params;
1426 
1427           ISCSI_THREAD_START("worker_thread");
1428           sess->worker.pid = getpid();
1429           sess->worker.state |= ISCSI_WORKER_STATE_STARTED;
1430           iscsi_trace(TRACE_ISCSI_DEBUG, "session %d: started\n", sess->id);
1431 
1432           /*
1433          * ISCSI_PARAM_TYPE_LIST format:        <type> <key> <dflt> <valid list values>
1434          * ISCSI_PARAM_TYPE_BINARY format:      <type> <key> <dflt> <valid binary values>
1435          * ISCSI_PARAM_TYPE_NUMERICAL format:   <type> <key> <dflt> <max>
1436          * ISCSI_PARAM_TYPE_DECLARATIVE format: <type> <key> <dflt> ""
1437          */
1438 
1439           sess->params = NULL;
1440           l = &sess->params;
1441 
1442           /* CHAP Parameters */
1443           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "AuthMethod", "CHAP", "CHAP,None", return -1);
1444           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "CHAP_A", "None", "5", return -1);
1445           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_N", "", "", return -1);
1446           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_R", "", "", return -1);
1447           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_I", "", "", return -1);
1448           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_C", "", "", return -1);
1449           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetPortalGroupTag", "1", "1", return -1);
1450           /* CHAP Parameters */
1451           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "HeaderDigest", "None", "None", return -1);
1452           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "DataDigest", "None", "None", return -1);
1453           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "MaxConnections", "1", "1", return -1);
1454           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "SendTargets", "", "", return -1);
1455           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetName", "", "", return -1);
1456           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "InitiatorName", "", "", return -1);
1457           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetAlias", "", "", return -1);
1458           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "InitiatorAlias", "", "", return -1);
1459           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetAddress", "", "", return -1);
1460           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_OR, "InitialR2T", "Yes", "Yes,No", return -1);
1461           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_AND, "OFMarker", "No", "Yes,No", return -1);
1462           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_AND, "IFMarker", "No", "Yes,No", return -1);
1463           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "OFMarkInt", "1", "65536", return -1);
1464           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "IFMarkInt", "1", "65536", return -1);
1465           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_AND, "ImmediateData", "Yes", "Yes,No", return -1);
1466           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "MaxRecvDataSegmentLength", "8192", "16777215", return -1);
1467           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "MaxBurstLength", "262144", "16777215", return -1);
1468           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "FirstBurstLength", "65536", "16777215", return -1);
1469           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "DefaultTime2Wait", "2", "2", return -1);
1470           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "DefaultTime2Retain", "20", "20", return -1);
1471           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "MaxOutstandingR2T", "1", "1", return -1);
1472           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_OR, "DataPDUInOrder", "Yes", "Yes,No", return -1);
1473           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_OR, "DataSequenceInOrder", "Yes", "Yes,No", return -1);
1474           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "ErrorRecoveryLevel", "0", "0", return -1);
1475           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "SessionType", "Normal", "Normal,Discovery", return -1);
1476           /*
1477            * Auth Result is not in specs, we use this key to pass
1478            * authentication result
1479            */
1480           PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "AuthResult", "No", "Yes,No,Fail", return -1);
1481 
1482           /* Set remaining session parameters  */
1483 
1484           sess->UsePhaseCollapsedRead = ISCSI_USE_PHASE_COLLAPSED_READ_DFLT;
1485 
1486           /* Loop for commands */
1487 
1488           while (sess->target->state != TARGET_SHUT_DOWN) {
1489                     iscsi_trace(TRACE_ISCSI_DEBUG,
1490                               "session %d: reading header\n", sess->id);
1491                     if (iscsi_sock_msg(sess->sock, 0, ISCSI_HEADER_LEN, header, 0)
1492                                         != ISCSI_HEADER_LEN) {
1493                               iscsi_trace(TRACE_ISCSI_DEBUG,
1494                                         "session %d: iscsi_sock_msg() failed\n",
1495                                         sess->id);
1496                               break;
1497                     }
1498                     iscsi_trace(TRACE_ISCSI_DEBUG,
1499                               "session %d: iscsi op %#x\n", sess->id,
1500                               ISCSI_OPCODE(header));
1501                     if (execute_t(sess, header) != 0) {
1502                               iscsi_err(__FILE__, __LINE__,
1503                                         "execute_t() failed\n");
1504                               break;
1505                     }
1506                     iscsi_trace(TRACE_ISCSI_DEBUG,
1507                               "session %d: iscsi op %#x complete\n", sess->id,
1508                               ISCSI_OPCODE(header));
1509                     if (ISCSI_OPCODE(header) == ISCSI_LOGOUT_CMD) {
1510                               iscsi_trace(TRACE_ISCSI_DEBUG,
1511                                         "session %d: logout received, ending session\n",
1512                                         sess->id);
1513                               break;
1514                     }
1515           }
1516 
1517           /* Clean up */
1518 
1519           iscsi_free(sess->buff);
1520           if (param_list_destroy(sess->params) != 0) {
1521                     iscsi_err(__FILE__, __LINE__,
1522                               "param_list_destroy() failed\n");
1523                     return -1;
1524           }
1525           /* Terminate connection */
1526 
1527           if (iscsi_sock_close(sess->sock) != 0) {
1528                     iscsi_err(__FILE__, __LINE__,
1529                               "iscsi_sock_close() failed\n");
1530           }
1531           /* Make session available */
1532 
1533           ISCSI_LOCK(&g_session_q_mutex, return -1);
1534           (void) memset(sess, 0x0, sizeof(*sess));
1535           sess->d = -1;
1536           if (iscsi_queue_insert(&g_session_q, sess) != 0) {
1537                     iscsi_err(__FILE__, __LINE__,
1538                                         "iscsi_queue_insert() failed\n");
1539                     return -1;
1540           }
1541           ISCSI_UNLOCK(&g_session_q_mutex, return -1);
1542           iscsi_trace(TRACE_ISCSI_DEBUG, "session %d: ended\n", sess->id);
1543 
1544           return 0;
1545 }
1546 
1547 static int
read_data_pdu(target_session_t * sess,iscsi_write_data_t * data,iscsi_scsi_cmd_args_t * args)1548 read_data_pdu(target_session_t * sess,
1549                 iscsi_write_data_t * data,
1550                 iscsi_scsi_cmd_args_t * args)
1551 {
1552           uint8_t   header[ISCSI_HEADER_LEN];
1553           int             ret_val = -1;
1554 
1555           if (iscsi_sock_msg(sess->sock, 0, ISCSI_HEADER_LEN, header, 0) !=
1556                               ISCSI_HEADER_LEN) {
1557                     iscsi_err(__FILE__, __LINE__,
1558                               "iscsi_sock_msg() failed\n");
1559                     return -1;
1560           }
1561           if ((ret_val = iscsi_write_data_decap(header, data)) != 0) {
1562                     iscsi_err(__FILE__, __LINE__,
1563                               "iscsi_write_data_decap() failed\n");
1564                     return ret_val;
1565           }
1566           /* Check args */
1567           if (sess->sess_params.max_dataseg_len) {
1568                     if (data->length > sess->sess_params.max_dataseg_len) {
1569                               args->status = 0x02;
1570                               return -1;
1571                     }
1572           }
1573           if ((args->bytes_recv + data->length) > args->trans_len) {
1574                     args->status = 0x02;
1575                     return -1;
1576           }
1577           if (data->tag != args->tag) {
1578                     iscsi_trace(TRACE_ISCSI_DEBUG,
1579                               "Data ITT (%d) does not match with command ITT (%d)\n",
1580                               data->tag, args->tag);
1581                     if (data->final) {
1582                               args->status = 0x02;
1583                               return -1;
1584                     } else {
1585                               /* Send a reject PDU */
1586                               iscsi_trace(TRACE_ISCSI_DEBUG, "Sending Reject PDU\n");
1587                               if (reject_t(sess, header, 0x09) != 0) {
1588                                         /* Invalid PDU Field */
1589                                         iscsi_trace(TRACE_ISCSI_DEBUG,
1590                                                   "Sending Reject PDU failed\n");
1591                                         return 1;
1592                               }
1593                     }
1594           }
1595           return 0;
1596 }
1597 
1598 int
target_transfer_data(target_session_t * sess,iscsi_scsi_cmd_args_t * args,struct iovec * sg,int sg_len)1599 target_transfer_data(target_session_t * sess, iscsi_scsi_cmd_args_t * args,
1600                     struct iovec * sg, int sg_len)
1601 {
1602           iscsi_write_data_t data;
1603           struct iovec   *iov, *iov_ptr = NULL;
1604           int             iov_len;
1605 
1606 #define TTD_CLEANUP do {                                                        \
1607           if (iov_ptr != NULL) {                                                          \
1608                     iscsi_free_atomic(iov_ptr);                                 \
1609           }                                                                               \
1610 } while (/* CONSTCOND */ 0)
1611 
1612           args->bytes_recv = 0;
1613           if ((!sess->sess_params.immediate_data) && args->length) {
1614                     iscsi_trace(TRACE_ISCSI_DEBUG,
1615                               "Cannot accept any Immediate data\n");
1616                     args->status = 0x02;
1617                     return -1;
1618           }
1619 
1620           /* Make a copy of the iovec */
1621           iov_ptr = iscsi_malloc_atomic(sizeof(struct iovec) * sg_len);
1622           if (iov_ptr == NULL) {
1623                     iscsi_err(__FILE__, __LINE__,
1624                                         "iscsi_malloc_atomic() failed\n");
1625                     return -1;
1626           }
1627           iov = iov_ptr;
1628           (void) memcpy(iov, sg, sizeof(struct iovec) * sg_len);
1629           iov_len = sg_len;
1630 
1631           /*
1632          * Read any immediate data.
1633          */
1634 
1635           if (sess->sess_params.immediate_data && args->length) {
1636                     if (sess->sess_params.max_dataseg_len &&
1637                         args->length > sess->sess_params.max_dataseg_len) {
1638                               iscsi_err(__FILE__, __LINE__,
1639                                         "args->length (%u) too long\n",
1640                                         args->length);
1641                                         TTD_CLEANUP;
1642                                         return -1;
1643                     }
1644 
1645                     /* Modify iov to include just immediate data */
1646                     if (modify_iov(&iov, &iov_len, 0, args->length) != 0) {
1647                               iscsi_err(__FILE__, __LINE__,
1648                                         "modify_iov() failed\n");
1649                               TTD_CLEANUP;
1650                               return -1;
1651                     }
1652                     iscsi_trace(TRACE_SCSI_DATA,
1653                               "reading %u bytes immediate write data\n",
1654                               args->length);
1655                     if ((uint32_t)iscsi_sock_msg(sess->sock, 0, args->length, iov,
1656                                         iov_len) != args->length) {
1657                               iscsi_err(__FILE__, __LINE__,
1658                                         "iscsi_sock_msg() failed\n");
1659                               TTD_CLEANUP;
1660                               return -1;
1661                     }
1662                     iscsi_trace(TRACE_SCSI_DATA,
1663                               "successfully read %u bytes immediate write data\n",
1664                               args->length);
1665                     args->bytes_recv += args->length;
1666           }
1667 
1668           /*
1669          * Read iSCSI data PDUs
1670          */
1671           if (args->bytes_recv < args->trans_len) {
1672                     int             r2t_flag = 0;
1673                     int             read_status = 0;
1674                     iscsi_r2t_t     r2t;
1675                     int             desired_xfer_len;
1676 
1677                     desired_xfer_len = MIN(sess->sess_params.first_burst_length,
1678                                               args->trans_len) - args->bytes_recv;
1679                     (void) memset(&r2t, 0x0, sizeof(r2t));
1680                     do {
1681 
1682                               /*
1683                                * Send R2T if we're either operating in solicted
1684                                * mode or we're operating in unsolicted
1685                                */
1686                               /* mode and have reached the first burst */
1687                               if (!r2t_flag &&
1688                                    (sess->sess_params.initial_r2t ||
1689                                       (sess->sess_params.first_burst_length &&
1690                                         (args->bytes_recv >=
1691                                         sess->sess_params.first_burst_length)))) {
1692                                         uint8_t   header[ISCSI_HEADER_LEN];
1693 
1694                                         desired_xfer_len = MIN(args->trans_len -
1695                                                                       args->bytes_recv,
1696                                                   sess->sess_params.max_burst_length);
1697                                         iscsi_trace(TRACE_ISCSI_DEBUG,
1698                                                   "sending R2T for %u bytes data\n",
1699                                                   desired_xfer_len);
1700                                         r2t.tag = args->tag;
1701 
1702                                         r2t.transfer_tag = 0x1234;
1703 
1704                                         r2t.ExpCmdSN = sess->ExpCmdSN;
1705                                         r2t.MaxCmdSN = sess->MaxCmdSN;
1706                                         r2t.StatSN = ++(sess->StatSN);
1707                                         r2t.length = desired_xfer_len;
1708                                         r2t.offset = args->bytes_recv;
1709                                         if (iscsi_r2t_encap(header, &r2t) != 0) {
1710                                                   iscsi_err(__FILE__, __LINE__,
1711                                                             "r2t_encap() failed\n");
1712                                                   TTD_CLEANUP;
1713                                                   return -1;
1714                                         }
1715                                         iscsi_trace(TRACE_ISCSI_DEBUG,
1716                                                   "sending R2T tag %u transfer tag "
1717                                                   "%u len %u offset %u\n",
1718                                                   r2t.tag, r2t.transfer_tag, r2t.length,
1719                                                   r2t.offset);
1720                                         if (iscsi_sock_msg(sess->sock, 1,
1721                                                   ISCSI_HEADER_LEN, header, 0) !=
1722                                                   ISCSI_HEADER_LEN) {
1723                                                   iscsi_err(__FILE__, __LINE__,
1724                                                             "iscsi_sock_msg() failed\n");
1725                                                   TTD_CLEANUP;
1726                                                   return -1;
1727                                         }
1728                                         r2t_flag = 1;
1729                                         r2t.R2TSN += 1;
1730                               }
1731 
1732                               /* Read iSCSI data PDU */
1733                               iscsi_trace(TRACE_ISCSI_DEBUG, "reading data pdu\n");
1734                               read_status = read_data_pdu(sess, &data, args);
1735                               if (read_status != 0) {
1736                                         if (read_status == 1) {
1737                                                   iscsi_trace(TRACE_ISCSI_DEBUG,
1738                                                             "Unknown PDU received and "
1739                                                             "ignored. Expecting "
1740                                                             "Data PDU\n");
1741                                                   continue;
1742                                         } else {
1743                                                   iscsi_err(__FILE__, __LINE__,
1744                                                             "read_data_pdu() failed\n");
1745                                                   args->status = 0x02;
1746                                                   TTD_CLEANUP;
1747                                                   return -1;
1748                                         }
1749                               }
1750                               if (data.ExpStatSN != sess->StatSN) {
1751                                         iscsi_warn(__FILE__, __LINE__,
1752                                                   "Bad \"ExpStatSN\": Got %u "
1753                                                   "expected %u.\n",
1754                                                   data.ExpStatSN, sess->StatSN);
1755                               }
1756                               iscsi_trace(TRACE_ISCSI_DEBUG,
1757                                         "read data pdu OK (offset %u, length %u)\n",
1758                                         data.offset, data.length);
1759 
1760                               /* Modify iov with offset and length. */
1761                               iov = iov_ptr;
1762                               (void) memcpy(iov, sg, sizeof(struct iovec) * sg_len);
1763                               iov_len = sg_len;
1764                               if (modify_iov(&iov, &iov_len, data.offset,
1765                                                   data.length) != 0) {
1766                                         iscsi_err(__FILE__, __LINE__,
1767                                                   "modify_iov() failed\n");
1768                                         TTD_CLEANUP;
1769                                         return -1;
1770                               }
1771 
1772                               /* Scatter into destination buffers */
1773                               if ((uint32_t)iscsi_sock_msg(sess->sock, 0,
1774                                         data.length, iov, iov_len) != data.length) {
1775                                         iscsi_err(__FILE__, __LINE__,
1776                                                   "iscsi_sock_msg() failed\n");
1777                                         TTD_CLEANUP;
1778                                         return -1;
1779                               }
1780                               iscsi_trace(TRACE_ISCSI_DEBUG,
1781                                         "successfully scattered %u bytes\n",
1782                                         data.length);
1783                               args->bytes_recv += data.length;
1784                               desired_xfer_len -= data.length;
1785                               if ((!r2t_flag) &&
1786                                   (args->bytes_recv >
1787                                         sess->sess_params.first_burst_length)) {
1788                                         iscsi_err(__FILE__, __LINE__,
1789                                                   "Received unsolicited data (%u) "
1790                                                   "more than first_burst_length (%u)\n",
1791                                                   args->bytes_recv,
1792                                                   sess->sess_params.first_burst_length);
1793                                         args->status = 0x02;
1794                                         TTD_CLEANUP;
1795                                         return -1;
1796                               }
1797                               if ((desired_xfer_len != 0) && data.final) {
1798                                         iscsi_err(__FILE__, __LINE__,
1799                                                   "Expecting more data (%d) "
1800                                                   "from initiator for this sequence\n",
1801                                                   desired_xfer_len);
1802                                         args->status = 0x02;
1803                                         TTD_CLEANUP;
1804                                         return -1;
1805                               }
1806                               if ((desired_xfer_len == 0) && !data.final) {
1807                                         iscsi_err(__FILE__, __LINE__,
1808                                                   "Final bit not set on the last "
1809                                                   "data PDU of this sequence\n");
1810                                         args->status = 0x02;
1811                                         TTD_CLEANUP;
1812                                         return -1;
1813                               }
1814                               if ((desired_xfer_len == 0) &&
1815                                   (args->bytes_recv < args->trans_len)) {
1816                                         r2t_flag = 0;
1817                               }
1818                     } while (args->bytes_recv < args->trans_len);
1819 #if 0
1820                     RETURN_NOT_EQUAL("Final bit", data.final, 1, TTD_CLEANUP, -1);
1821 #else
1822                     if (data.final != 1) {
1823                               iscsi_err(__FILE__, __LINE__, "Final bit\n");
1824                               TTD_CLEANUP;
1825                               return -1;
1826                     }
1827 #endif
1828           } else {
1829 #if 0
1830                     RETURN_NOT_EQUAL("Final bit", args->final, 1, TTD_CLEANUP, -1);
1831 #else
1832                     if (args->final != 1) {
1833                               iscsi_err(__FILE__, __LINE__, "Final bit\n");
1834                               TTD_CLEANUP;
1835                               return -1;
1836                     }
1837 #endif
1838           }
1839           iscsi_trace(TRACE_ISCSI_DEBUG,
1840                     "successfully transferred %u bytes write data\n",
1841                     args->trans_len);
1842           TTD_CLEANUP;
1843           return 0;
1844 }
1845 
1846 /* check there's enough space in the arrays */
1847 static void
size_arrays(iscsi_target_t * tgt,unsigned needed)1848 size_arrays(iscsi_target_t *tgt, unsigned needed)
1849 {
1850           if (tgt->size == 0) {
1851                     /* only get here first time around */
1852                     tgt->size = needed;
1853                     tgt->name = calloc(sizeof(char *), needed);
1854                     tgt->value = calloc(sizeof(char *), needed);
1855           } else if (tgt->c == tgt->size) {
1856                     /* only uses 'needed' when filled array */
1857                     tgt->size += needed;
1858                     tgt->name = realloc(tgt->name, sizeof(char *) * needed);
1859                     tgt->value = realloc(tgt->value, sizeof(char *) * needed);
1860           }
1861 }
1862 
1863 /* find the name in the array */
1864 static int
findvar(iscsi_target_t * tgt,const char * name)1865 findvar(iscsi_target_t *tgt, const char *name)
1866 {
1867           unsigned  i;
1868 
1869           for (i = 0 ; i < tgt->c && strcmp(tgt->name[i], name) != 0; i++) {
1870           }
1871           return (i == tgt->c) ? -1 : (int)i;
1872 }
1873 
1874 /********************
1875  * Public Functions *
1876  ********************/
1877 
1878 int
iscsi_target_set_defaults(iscsi_target_t * tgt)1879 iscsi_target_set_defaults(iscsi_target_t *tgt)
1880 {
1881           char      buf[32];
1882 
1883           /* set defaults */
1884           (void) memset(tgt, 0x0, sizeof(*tgt));
1885           iscsi_target_setvar(tgt, "iqn", DEFAULT_TARGET_NAME);
1886           (void) snprintf(buf, sizeof(buf), "%d", ISCSI_PORT);
1887           iscsi_target_setvar(tgt, "target port", buf);
1888           iscsi_target_setvar(tgt, "address family", "unspec");
1889           (void) snprintf(buf, sizeof(buf), "%d", DEFAULT_TARGET_MAX_SESSIONS);
1890           iscsi_target_setvar(tgt, "max sessions", buf);
1891           iscsi_target_setvar(tgt, "configfile", _PATH_ISCSI_TARGETS);
1892           iscsi_target_setvar(tgt, "blocklen", "512");
1893           return 1;
1894 }
1895 
1896 /* re-read the configuration file */
1897 int
iscsi_target_reconfigure(iscsi_target_t * tgt)1898 iscsi_target_reconfigure(iscsi_target_t *tgt)
1899 {
1900           targv_t   *oldluns;
1901           devv_t    *olddevices;
1902           extv_t    *oldextents;
1903           targv_t   *luns;
1904           devv_t    *devices;
1905           extv_t    *extents;
1906           char      *config;
1907 
1908           NEW(targv_t, luns, "iscsi_target_reconf 1", return -1);
1909           NEW(devv_t, devices, "iscsi_target_reconf 2", return -1);
1910           NEW(extv_t, extents, "iscsi_target_reconf 3", return -1);
1911           config = iscsi_target_getvar(tgt, "configfile");
1912           if (!read_conf_file(config, tgt->lunv, tgt->devv, tgt->extentv)) {
1913                     (void) fprintf(stderr, "Error: can't open `%s'\n", config);
1914                     return 0;
1915           }
1916           /* it worked - let's reassign things */
1917           /* XXX - agc - lock */
1918           oldluns = tgt->lunv;
1919           olddevices = tgt->devv;
1920           oldextents = tgt->extentv;
1921           tgt->lunv = luns;
1922           tgt->devv = devices;
1923           tgt->extentv = extents;
1924           /* XXX - agc - unlock */
1925           /* free up storage */
1926           (void) free(oldluns);
1927           (void) free(olddevices);
1928           (void) free(oldextents);
1929           return 1;
1930 }
1931 
1932 int
iscsi_target_start(iscsi_target_t * tgt)1933 iscsi_target_start(iscsi_target_t *tgt)
1934 {
1935           uint32_t   j;
1936           targv_t             *lunv;
1937           char                *config;
1938           char                *dbg;
1939           int                  maxsessions;
1940           int              i;
1941 
1942           if ((dbg = iscsi_target_getvar(tgt, "debug")) != NULL) {
1943                     set_debug(dbg);
1944           }
1945           /* allocate space for disks, extents and targets */
1946           NEW(targv_t, tgt->lunv, "iscsi_target_start 1", return -1);
1947           NEW(devv_t, tgt->devv, "iscsi_target_start 2", return -1);
1948           NEW(extv_t, tgt->extentv, "iscsi_target_start 3", return -1);
1949           /* read the configuration file */
1950           config = iscsi_target_getvar(tgt, "configfile");
1951           if (!read_conf_file(config, tgt->lunv, tgt->devv, tgt->extentv)) {
1952                     (void) fprintf(stderr, "Error: can't open `%s'\n", config);
1953                     return 0;
1954           }
1955           lunv = tgt->lunv;
1956           if (lunv->c == 0) {
1957                     (void) fprintf(stderr, "No targets to initialise\n");
1958                     return -1;
1959           }
1960           maxsessions = atoi(iscsi_target_getvar(tgt, "max sessions"));
1961           NEWARRAY(target_session_t, g_session, maxsessions, "iscsi_target_start",
1962                               return -1);
1963           device_set_var("blocklen", iscsi_target_getvar(tgt, "blocklen"));
1964           if (tgt->state == TARGET_INITIALIZING ||
1965               tgt->state == TARGET_INITIALIZED) {
1966                     iscsi_err(__FILE__, __LINE__,
1967                               "duplicate target initialization attempted\n");
1968                     return -1;
1969           }
1970           tgt->state = TARGET_INITIALIZING;
1971           if (iscsi_queue_init(&g_session_q, maxsessions) != 0) {
1972                     iscsi_err(__FILE__, __LINE__,
1973                               "iscsi_queue_init() failed\n");
1974                     return -1;
1975           }
1976           tgt->main_pid = getpid();
1977           for (i = 0; i < maxsessions; i++) {
1978                     g_session[i].id = i;
1979                     g_session[i].d = -1;
1980                     if (iscsi_queue_insert(&g_session_q, &g_session[i]) != 0) {
1981                               iscsi_err(__FILE__, __LINE__,
1982                                         "iscsi_queue_insert() failed\n");
1983                               return -1;
1984                     }
1985           }
1986           for (j = 0 ; j < lunv->c ; j++) {
1987                     int d = device_init(tgt, lunv, &lunv->v[j]);
1988 
1989                     if (d < 0) {
1990                               iscsi_err(__FILE__, __LINE__,
1991                                         "device_init() failed\n");
1992                               return -1;
1993                     }
1994           }
1995           ISCSI_MUTEX_INIT(&g_session_q_mutex, return -1);
1996           tgt->listener_listening = 0;
1997           tgt->listener_pid = -1;
1998           tgt->state = TARGET_INITIALIZED;
1999           printf("TARGET: iSCSI Qualified Name (IQN) is %s\n",
2000                               iscsi_target_getvar(tgt, "iqn"));
2001           for (i = 0 ; i < tgt->sockc ; i++) {
2002                     printf("\tsocket %d listening on port %s\n", tgt->sockv[i],
2003                               iscsi_target_getvar(tgt, "target port"));
2004           }
2005           return 0;
2006 }
2007 
2008 int
iscsi_target_shutdown(iscsi_target_t * tgt)2009 iscsi_target_shutdown(iscsi_target_t *tgt)
2010 {
2011           target_session_t    *sess;
2012           int                            maxsessions;
2013           int                            i;
2014 
2015           if ((tgt->state == TARGET_SHUTTING_DOWN) ||
2016               (tgt->state == TARGET_SHUT_DOWN)) {
2017                     iscsi_err(__FILE__, __LINE__,
2018                               "duplicate target shutdown attempted\n");
2019                     return -1;
2020           }
2021           tgt->state = TARGET_SHUTTING_DOWN;
2022           iscsi_trace(TRACE_ISCSI_DEBUG, "shutting down target\n");
2023           maxsessions = atoi(iscsi_target_getvar(tgt, "max sessions"));
2024           for (i = 0; i < maxsessions; i++) {
2025                     sess = &g_session[i];
2026 
2027                     /* Need to replace with a call to session_destroy() */
2028 
2029                     if (sess->IsLoggedIn) {
2030                               printf("shutting down socket on sess %d\n", i);
2031                               iscsi_trace(TRACE_ISCSI_DEBUG,
2032                                         "shutting down socket on sess %d\n", i);
2033                               if (iscsi_sock_shutdown(sess->sock, 2) != 0) {
2034                                         iscsi_err(__FILE__, __LINE__,
2035                                                   "iscsi_sock_shutdown() failed\n");
2036                                         return -1;
2037                               }
2038                               printf("waiting for worker %d (pid %d, state %d)\n",
2039                                         i, sess->worker.pid, sess->worker.state);
2040                               iscsi_trace(TRACE_ISCSI_DEBUG,
2041                                         "waiting for worker %d (pid %d, state %d)\n",
2042                                         i, sess->worker.pid, sess->worker.state);
2043                               while (sess->worker.state &
2044                                                   ISCSI_WORKER_STATE_STARTED) {
2045                                         ISCSI_SPIN;
2046                               }
2047                               iscsi_trace(TRACE_ISCSI_DEBUG,
2048                                                   "worker %d has exited\n", i);
2049                     }
2050                     if (device_shutdown(sess) != 0) {
2051                               iscsi_err(__FILE__, __LINE__,
2052                                                   "device_shutdown() failed\n");
2053                               return -1;
2054                     }
2055           }
2056           iscsi_trace(TRACE_ISCSI_DEBUG, "shutting down accept socket\n");
2057           if (iscsi_sock_shutdown(tgt->sockv[0], 2) != 0) {
2058                     iscsi_err(__FILE__, __LINE__,
2059                               "iscsi_sock_shutdown() failed\n");
2060                     return -1;
2061           }
2062           if (tgt->listener_pid != getpid()) {
2063                     iscsi_trace(TRACE_ISCSI_DEBUG, "waiting for listener thread\n");
2064                     while (tgt->listener_listening) {
2065                               ISCSI_SPIN;
2066                     }
2067                     iscsi_trace(TRACE_ISCSI_DEBUG, "listener thread has exited\n");
2068           }
2069           iscsi_trace(TRACE_ISCSI_DEBUG, "closing accept socket\n");
2070           if (iscsi_sock_close(tgt->sockv[0]) != 0) {
2071                     iscsi_err(__FILE__, __LINE__,
2072                               "iscsi_sock_close() failed\n");
2073                     return -1;
2074           }
2075           ISCSI_MUTEX_DESTROY(&g_session_q_mutex, return -1);
2076           iscsi_trace(TRACE_ISCSI_DEBUG, "target shutdown complete\n");
2077           tgt->state = TARGET_SHUT_DOWN;
2078 
2079           return 0;
2080 }
2081 
2082 int
iscsi_target_listen(iscsi_target_t * tgt)2083 iscsi_target_listen(iscsi_target_t *tgt)
2084 {
2085           struct sockaddr_in6 remoteAddrStorage6;
2086           struct sockaddr_in6 localAddrStorage6;
2087           struct sockaddr_in  remoteAddrStorage;
2088           struct sockaddr_in  localAddrStorage;
2089           target_session_t    *sess;
2090           socklen_t           remoteAddrLen;
2091           socklen_t           localAddrLen;
2092           char                          targetaddress[2 * 1024];
2093           char                          remote[1024];
2094           char                          local[1024];
2095           char                          *config;
2096           int                           newconn;
2097           int                           i;
2098 
2099           ISCSI_THREAD_START("listen_thread");
2100           tgt->listener_pid = getpid();
2101           tgt->listener_listening++;
2102           iscsi_trace(TRACE_ISCSI_DEBUG, "listener thread started\n");
2103 
2104           if (!iscsi_socks_establish(tgt->sockv, tgt->famv, &tgt->sockc,
2105                               iscsi_target_getvar(tgt, "address family"),
2106                               atoi(iscsi_target_getvar(tgt, "target port")))) {
2107                     iscsi_err(__FILE__, __LINE__,
2108                                         "iscsi_sock_establish() failed\n");
2109                     goto done;
2110           }
2111 
2112           iscsi_trace(TRACE_NET_DEBUG, "create, bind, listen OK\n");
2113 
2114           /* Loop for connections: FIX ME with queue */
2115 
2116           while (tgt->state != TARGET_SHUT_DOWN) {
2117                     ISCSI_LOCK(&g_session_q_mutex, return -1);
2118                     if ((sess = iscsi_queue_remove(&g_session_q)) == NULL) {
2119                               iscsi_err(__FILE__, __LINE__,
2120                               "no free sessions: iscsi_queue_remove() failed\n");
2121                               goto done;
2122                     }
2123                     ISCSI_UNLOCK(&g_session_q_mutex, return -1);
2124                     assert(sess->d == -1);
2125 #if 0
2126                     (void) memset(sess, 0x0, sizeof(*sess));
2127 #endif
2128 
2129                     sess->target = tgt;
2130 
2131                     /* Accept connection, spawn session thread, and */
2132                     /* clean up old threads */
2133 
2134                     config = iscsi_target_getvar(tgt, "configfile");
2135                     i = iscsi_waitfor_connection(tgt->sockv, tgt->sockc, config,
2136                                         &newconn);
2137 
2138                     iscsi_trace(TRACE_NET_DEBUG,
2139                                         "waiting for %s connection on port %s\n",
2140                                         iscsi_address_family(tgt->famv[i]),
2141                                         iscsi_target_getvar(tgt, "target port"));
2142 
2143                     if (!iscsi_sock_accept(newconn, &sess->sock)) {
2144                               iscsi_trace(TRACE_ISCSI_DEBUG,
2145                                                   "iscsi_sock_accept() failed\n");
2146                               goto done;
2147                     }
2148 
2149                     switch (tgt->famv[i]) {
2150                     case AF_INET:
2151                               sess->address_family = 4;
2152                               (void) memset(&localAddrStorage, 0x0,
2153                                         localAddrLen = sizeof(localAddrStorage));
2154                               if (getsockname(sess->sock,
2155                                         (struct sockaddr *)(void *)&localAddrStorage,
2156                                         &localAddrLen) < 0) {
2157                                         iscsi_err(__FILE__, __LINE__,
2158                                                   "iscsi_sock_getsockname() failed\n");
2159                                         goto done;
2160                               }
2161                               (void) memset(&remoteAddrStorage, 0x0,
2162                                         remoteAddrLen = sizeof(remoteAddrStorage));
2163                               if (getpeername(sess->sock,
2164                                         (struct sockaddr *)(void *) &remoteAddrStorage,
2165                                         &remoteAddrLen) < 0) {
2166                                         iscsi_err(__FILE__, __LINE__,
2167                                                   "iscsi_sock_getpeername() failed\n");
2168                                         goto done;
2169                               }
2170 
2171 #ifdef HAVE_GETNAMEINFO
2172                               if (getnameinfo((struct sockaddr *)(void *)
2173                                         &localAddrStorage,
2174                                         sizeof(localAddrStorage), local,
2175                                         sizeof(local), NULL, 0, NI_NUMERICHOST) < 0) {
2176                                         iscsi_err(__FILE__, __LINE__,
2177                                                   "getnameinfo local failed\n");
2178                               }
2179                               if (getnameinfo((struct sockaddr *)(void *)
2180                                         &remoteAddrStorage,
2181                                         sizeof(remoteAddrStorage), remote,
2182                                         sizeof(remote), NULL, 0, NI_NUMERICHOST) < 0) {
2183                                         iscsi_err(__FILE__, __LINE__,
2184                                                   "getnameinfo remote failed\n");
2185                               }
2186                               (void) strlcpy(sess->initiator, remote,
2187                                                   sizeof(sess->initiator));
2188 #else
2189                               (void) strlcpy(local,
2190                                         inet_ntoa(localAddrStorage.sin_addr),
2191                                         sizeof(local));
2192                               (void) strlcpy(sess->initiator,
2193                                         inet_ntoa(remoteAddrStorage.sin_addr),
2194                                         sizeof(sess->initiator));
2195 #endif
2196 
2197                               (void) snprintf(targetaddress, sizeof(targetaddress),
2198                                         "%s:%s,1", local,
2199                                         iscsi_target_getvar(tgt, "target port"));
2200                               iscsi_target_setvar(tgt, "target address",
2201                                         targetaddress);
2202                               iscsi_trace(TRACE_ISCSI_DEBUG,
2203                                         "IPv4 connection accepted on port %s "
2204                                         "(local IP %s, remote IP %s)\n",
2205                                         iscsi_target_getvar(tgt, "target port"),
2206                                         local, sess->initiator);
2207                               iscsi_trace(TRACE_ISCSI_DEBUG,
2208                                         "TargetAddress = \"%s\"\n", targetaddress);
2209                               break;
2210 
2211                     case AF_INET6:
2212                               sess->address_family = 6;
2213                               (void) memset(&localAddrStorage6, 0x0,
2214                                         localAddrLen = sizeof(localAddrStorage6));
2215                               if (getsockname(sess->sock, (struct sockaddr *)(void *)
2216                                         &localAddrStorage6, &localAddrLen) < 0) {
2217                                         iscsi_err(__FILE__, __LINE__,
2218                                                   "getsockname() failed\n");
2219                                         goto done;
2220                               }
2221 
2222                               (void) memset(&remoteAddrStorage6, 0x0,
2223                                         remoteAddrLen = sizeof(remoteAddrStorage6));
2224                               if (getpeername(sess->sock, (struct sockaddr *)(void *)
2225                                         &remoteAddrStorage6, &remoteAddrLen) < 0) {
2226                                         iscsi_err(__FILE__, __LINE__,
2227                                                   "iscsi_sock_getpeername() failed\n");
2228                                         goto done;
2229                               }
2230 
2231                               if (getnameinfo((struct sockaddr *)(void *)
2232                                         &localAddrStorage6, sizeof(localAddrStorage6),
2233                                         local, sizeof(local), NULL, 0,
2234                                         NI_NUMERICHOST) < 0) {
2235                                         iscsi_err(__FILE__, __LINE__,
2236                                                   "getnameinfo local failed\n");
2237                               }
2238                               if (getnameinfo((struct sockaddr *)(void *)
2239                                         &remoteAddrStorage6,
2240                                         sizeof(remoteAddrStorage6), remote,
2241                                         sizeof(remote), NULL, 0, NI_NUMERICHOST) < 0) {
2242                                         iscsi_err(__FILE__, __LINE__,
2243                                                   "getnameinfo remote failed\n");
2244                               }
2245                               (void) strlcpy(sess->initiator, remote,
2246                                         sizeof(sess->initiator));
2247                               (void) snprintf(targetaddress, sizeof(targetaddress),
2248                                         "%s:%s,1", local,
2249                                         iscsi_target_getvar(tgt, "target port"));
2250                               iscsi_target_setvar(tgt, "target address",
2251                                         targetaddress);
2252                               iscsi_trace(TRACE_ISCSI_DEBUG,
2253                                         "IPv6 connection accepted on port %s "
2254                                         "(local IP %s, remote IP %s)\n",
2255                                         iscsi_target_getvar(tgt, "target port"),
2256                                         local, sess->initiator);
2257                               iscsi_trace(TRACE_ISCSI_DEBUG,
2258                                         "TargetAddress = \"%s\"\n", targetaddress);
2259                               break;
2260                     }
2261                     if (iscsi_thread_create(&sess->worker.thread,
2262                               (void *) worker_proc_t, sess) != 0) {
2263                               iscsi_err(__FILE__, __LINE__,
2264                                         "iscsi_thread_create() failed\n");
2265                               goto done;
2266                     }
2267           }
2268 done:
2269           tgt->listener_listening--;
2270           return 0;
2271 }
2272 
2273 /* write the pid to the pid file */
2274 void
iscsi_target_write_pidfile(const char * f)2275 iscsi_target_write_pidfile(const char *f)
2276 {
2277           FILE      *fp;
2278 
2279           if (f == NULL) {
2280                     f = _PATH_ISCSI_PID_FILE;
2281           }
2282           if ((fp = fopen(f, "w")) == NULL) {
2283                     (void) fprintf(stderr, "Couldn't create pid file \"%s\": %s",
2284                                         f, strerror(errno));
2285           } else {
2286                     (void) fprintf(fp, "%ld\n", (long) getpid());
2287                     (void) fclose(fp);
2288           }
2289 }
2290 
2291 /* set a variable */
2292 int
iscsi_target_setvar(iscsi_target_t * tgt,const char * name,const char * value)2293 iscsi_target_setvar(iscsi_target_t *tgt, const char *name, const char *value)
2294 {
2295           int       i;
2296 
2297           if ((i = findvar(tgt, name)) < 0) {
2298                     /* add the element to the array */
2299                     size_arrays(tgt, tgt->size + 15);
2300                     tgt->name[i = tgt->c++] = strdup(name);
2301           } else {
2302                     /* replace the element in the array */
2303                     if (tgt->value[i]) {
2304                               (void) free(tgt->value[i]);
2305                               tgt->value[i] = NULL;
2306                     }
2307           }
2308           /* sanity checks for range of values would go here */
2309           tgt->value[i] = strdup(value);
2310           return 1;
2311 }
2312 
2313 /* get a variable's value (NULL if not set) */
2314 char *
iscsi_target_getvar(iscsi_target_t * tgt,const char * name)2315 iscsi_target_getvar(iscsi_target_t *tgt, const char *name)
2316 {
2317           int       i;
2318 
2319           return ((i = findvar(tgt, name)) < 0) ? NULL : tgt->value[i];
2320 }
2321