Sysfs interface for targets made uniform. ISCSI-SCST made confirming the uniformity...
[mirror/scst/.git] / iscsi-scst / usr / iscsid.c
1 /*
2  *  Copyright (C) 2002 - 2003 Ardis Technolgies <roman@ardistech.com>
3  *  Copyright (C) 2007 - 2009 Vladislav Bolkhovitin
4  *  Copyright (C) 2007 - 2009 ID7 Ltd.
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  as published by the Free Software Foundation, version 2
9  *  of the License.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  *  GNU General Public License for more details.
15  */
16
17 #include <ctype.h>
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <netdb.h>
26
27 #include "iscsid.h"
28
29 int iscsi_enabled;
30
31 static u32 ttt;
32
33 static u32 get_next_ttt(struct connection *conn __attribute__((unused)))
34 {
35         ttt += 1;
36         return (ttt == ISCSI_RESERVED_TAG) ? ++ttt : ttt;
37 }
38
39 static struct iscsi_key login_keys[] = {
40         {"InitiatorName",},
41         {"InitiatorAlias",},
42         {"SessionType",},
43         {"TargetName",},
44         {NULL,},
45 };
46
47 char *text_key_find(struct connection *conn, char *searchKey)
48 {
49         char *data, *key, *value;
50         int keylen, datasize;
51
52         keylen = strlen(searchKey);
53         data = conn->req.data;
54         datasize = conn->req.datasize;
55
56         while (1) {
57                 for (key = data; datasize > 0 && *data != '='; data++, datasize--)
58                         ;
59                 if (!datasize)
60                         return NULL;
61                 data++;
62                 datasize--;
63
64                 for (value = data; datasize > 0 && *data != 0; data++, datasize--)
65                         ;
66                 if (!datasize)
67                         return NULL;
68                 data++;
69                 datasize--;
70
71                 if (keylen == value - key - 1
72                      && !strncasecmp(key, searchKey, keylen))
73                         return value;
74         }
75 }
76
77 static char *next_key(char **data, int *datasize, char **value)
78 {
79         char *key, *p, *q;
80         int size = *datasize;
81
82         key = p = *data;
83         for (; size > 0 && *p != '='; p++, size--)
84                 ;
85         if (!size)
86                 return NULL;
87         *p++ = 0;
88         size--;
89
90         for (q = p; size > 0 && *p != 0; p++, size--)
91                 ;
92         if (!size)
93                 return NULL;
94         p++;
95         size--;
96
97         *data = p;
98         *value = q;
99         *datasize = size;
100
101         return key;
102 }
103
104 static struct buf_segment *conn_alloc_buf_segment(struct connection *conn,
105                                                    size_t sz)
106 {
107         struct buf_segment *seg = malloc(sizeof *seg + sz);
108
109         if (seg) {
110                 seg->len = 0;
111                 memset(seg->data, 0x0, sz);
112                 list_add_tail(&seg->entry, &conn->rsp_buf_list);
113                 log_debug(2, "alloc'ed new buf_segment");
114         }
115
116         return seg;
117 }
118
119 void text_key_add(struct connection *conn, char *key, const char *value)
120 {
121         struct buf_segment *seg;
122         int keylen = strlen(key);
123         int valuelen = strlen(value);
124         int len = keylen + valuelen + 2;
125         int off = 0;
126         int sz = 0;
127         int stage = 0;
128         size_t data_sz;
129
130         data_sz = (conn->state == STATE_FULL) ?
131                 conn->session_params[key_max_xmit_data_length].val :
132                 INCOMING_BUFSIZE;
133
134         seg = list_empty(&conn->rsp_buf_list) ? NULL :
135                 list_entry(conn->rsp_buf_list.q_back, struct buf_segment,
136                            entry);
137
138         while (len) {
139                 if (!seg || seg->len == data_sz) {
140                         seg = conn_alloc_buf_segment(conn, data_sz);
141                         if (!seg) {
142                                 log_error("Failed to alloc text buf segment\n");
143                                 conn_free_rsp_buf_list(conn);
144                                 break;
145                         }
146                 }
147                 switch (stage) {
148                 case 0:
149                         sz = min_t(int, data_sz - seg->len, keylen - off);
150                         strncpy(seg->data + seg->len, key + off, sz);
151                         if (sz == data_sz - seg->len) {
152                                 off += sz;
153                                 if (keylen - off == 0) {
154                                         off = 0;
155                                         stage++;
156                                 }
157                         } else {
158                                 off = 0;
159                                 stage++;
160                         }
161                         break;
162                 case 1:
163                         seg->data[seg->len] = '=';
164                         off = 0;
165                         sz = 1;
166                         stage++;
167                         break;
168                 case 2:
169                         sz = min_t(int, data_sz - seg->len, valuelen - off);
170                         strncpy(seg->data + seg->len, value + off, sz);
171                         off += sz;
172                         if (valuelen - off == 0) {
173                                 off = 0;
174                                 stage++;
175                         }
176                         break;
177                 case 3:
178                         seg->data[seg->len] = 0;
179                         sz = 1;
180                         break;
181                 }
182
183                 log_debug(2, "wrote: %s", seg->data + seg->len);
184
185                 seg->len += sz;
186                 len -= sz;
187         }
188 }
189
190 static void text_key_add_reject(struct connection *conn, char *key)
191 {
192         text_key_add(conn, key, "Reject");
193 }
194
195 static void text_scan_security(struct connection *conn)
196 {
197         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
198         char *key, *value, *data, *nextValue;
199         int datasize;
200
201         data = conn->req.data;
202         datasize = conn->req.datasize;
203
204         while ((key = next_key(&data, &datasize, &value))) {
205                 if (!(params_index_by_name(key, login_keys) < 0))
206                         ;
207                 else if (!strcmp(key, "AuthMethod")) {
208                         do {
209                                 nextValue = strchr(value, ',');
210                                 if (nextValue)
211                                         *nextValue++ = 0;
212
213                                 if (!strcmp(value, "None")) {
214                                         if (!accounts_empty(conn->tid, ISCSI_USER_DIR_INCOMING))
215                                                 continue;
216                                         conn->auth_method = AUTH_NONE;
217                                         text_key_add(conn, key, "None");
218                                         break;
219                                 } else if (!strcmp(value, "CHAP")) {
220                                         if (accounts_empty(conn->tid, ISCSI_USER_DIR_INCOMING))
221                                                 continue;
222                                         conn->auth_method = AUTH_CHAP;
223                                         text_key_add(conn, key, "CHAP");
224                                         break;
225                                 }
226                         } while ((value = nextValue));
227
228                         if (conn->auth_method == AUTH_UNKNOWN)
229                                 text_key_add_reject(conn, key);
230                 } else
231                         text_key_add(conn, key, "NotUnderstood");
232         }
233         if (conn->auth_method == AUTH_UNKNOWN) {
234                 rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
235                 rsp->status_detail = ISCSI_STATUS_AUTH_FAILED;
236                 conn->state = STATE_EXIT;
237         }
238         return;
239 }
240
241 static int login_check_reinstatement(struct connection *conn)
242 {
243         struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
244         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
245         struct session *session;
246         int res = 0;
247
248         /*
249          * We only check here to catch errors earlier. Actual session/connection
250          * reinstatement, if necessary, will be done in the kernel.
251          */
252
253         sBUG_ON(conn->sess != NULL);
254
255         session = session_find_name(conn->tid, conn->initiator, req->sid);
256         if (session != NULL) {
257                 if (req->sid.id.tsih == 0) {
258                         /* Kernel will do session reinstatement */
259                         log_debug(1, "Session sid %#" PRIx64 " reinstatement "
260                                 "detected (tid %d, initiator %s)", req->sid.id64,
261                                 conn->tid, conn->initiator);
262                 } else if (req->sid.id.tsih != session->sid.id.tsih) {
263                         log_error("TSIH for existing session sid %#" PRIx64
264                                 ") doesn't match (tid %d, initiator %s, sid requested "
265                                 "%#" PRIx64, session->sid.id64, conn->tid,
266                                 conn->initiator, req->sid.id64);
267                         /* Fail the login */
268                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
269                         rsp->status_detail = ISCSI_STATUS_SESSION_NOT_FOUND;
270                         conn->state = STATE_EXIT;
271                         res = -1;
272                         goto out;
273                 } else {
274                         struct connection *c = conn_find(session, conn->cid);
275                         if (c != NULL) {
276                                 /* Kernel will do connection reinstatement */
277                                 log_debug(1, "Conn %x reinstatement "
278                                         "detected (tid %d, sid %#" PRIx64
279                                         "initiator %s)", conn->cid, conn->tid,
280                                         req->sid.id64, conn->initiator);
281                                 conn->sess = session;
282                                 list_add_tail(&conn->clist, &session->conn_list);
283                         } else {
284                                 log_error("Only a single connection supported "
285                                         "(initiator %s)", conn->initiator);
286                                 /* Fail the login */
287                                 rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
288                                 rsp->status_detail = ISCSI_STATUS_TOO_MANY_CONN;
289                                 conn->state = STATE_EXIT;
290                                 res = -1;
291                                 goto out;
292                         }
293                 }
294         } else {
295                 if (req->sid.id.tsih != 0) {
296                         log_error("Requested TSIH not 0 (TSIH %d, tid %d, "
297                                 "initiator %s, sid requisted %#" PRIx64 ")",
298                                 req->sid.id.tsih, conn->tid, conn->initiator,
299                                 req->sid.id64);
300                         /* Fail the login */
301                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
302                         rsp->status_detail = ISCSI_STATUS_SESSION_NOT_FOUND;
303                         conn->state = STATE_EXIT;
304                         res = -1;
305                         goto out;
306                 } else
307                         log_debug(1, "New session sid %#" PRIx64 "(tid %d, "
308                                 "initiator %s)", req->sid.id64,
309                                 conn->tid, conn->initiator);
310         }
311
312 out:
313         return res;
314 }
315
316 static void text_scan_login(struct connection *conn)
317 {
318         char *key, *value, *data;
319         int datasize, idx;
320         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
321
322         data = conn->req.data;
323         datasize = conn->req.datasize;
324
325         while ((key = next_key(&data, &datasize, &value))) {
326                 if (!(params_index_by_name(key, login_keys) < 0))
327                         ;
328                 else if (!strcmp(key, "AuthMethod"))
329                         ;
330                 else if (!((idx = params_index_by_name(key, session_keys)) < 0)) {
331                         unsigned int val;
332                         char buf[32];
333
334                         if (idx == key_max_xmit_data_length) {
335                                 text_key_add(conn, key, "NotUnderstood");
336                                 continue;
337                         }
338                         if (idx == key_max_recv_data_length) {
339                                 conn->session_params[idx].key_state = KEY_STATE_DONE;
340                                 idx = key_max_xmit_data_length;
341                         };
342
343                         if (params_str_to_val(session_keys, idx, value, &val) < 0) {
344                                 if (conn->session_params[idx].key_state == KEY_STATE_START) {
345                                         text_key_add_reject(conn, key);
346                                         continue;
347                                 } else {
348                                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
349                                         rsp->status_detail = ISCSI_STATUS_INIT_ERR;
350                                         conn->state = STATE_EXIT;
351                                         goto out;
352                                 }
353                         }
354
355                         params_check_val(session_keys, idx, &val);
356                         params_set_val(session_keys, conn->session_params, idx, &val);
357
358                         switch (conn->session_params[idx].key_state) {
359                         case KEY_STATE_START:
360                                 if (iscsi_is_key_internal(idx)) {
361                                         conn->session_params[idx].key_state = KEY_STATE_DONE;
362                                         break;
363                                 }
364                                 memset(buf, 0, sizeof(buf));
365                                 params_val_to_str(session_keys, idx, val, buf, sizeof(buf));
366                                 text_key_add(conn, key, buf);
367                                 conn->session_params[idx].key_state = KEY_STATE_DONE_ADDED;
368                                 break;
369                         case KEY_STATE_REQUEST:
370                                 if (val != conn->session_params[idx].val) {
371                                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
372                                         rsp->status_detail = ISCSI_STATUS_INIT_ERR;
373                                         conn->state = STATE_EXIT;
374                                         log_warning("%s %u %u\n", key,
375                                                 val, conn->session_params[idx].val);
376                                         goto out;
377                                 }
378                                 conn->session_params[idx].key_state = KEY_STATE_DONE;
379                                 break;
380                         case KEY_STATE_DONE_ADDED:
381                         case KEY_STATE_DONE:
382                                 break;
383                         }
384                 } else
385                         text_key_add(conn, key, "NotUnderstood");
386         }
387
388 out:
389         return;
390 }
391
392 static int text_check_params(struct connection *conn)
393 {
394         struct iscsi_param *p = conn->session_params;
395         char buf[32];
396         int i, cnt;
397
398         for (i = 0, cnt = 0; session_keys[i].name; i++) {
399                 if (p[i].val != session_keys[i].rfc_def) {
400                         if (p[i].key_state == KEY_STATE_START) {
401                                 log_debug(1, "Key %s was not negotiated, use RFC "
402                                         "defined default %d",  session_keys[i].name,
403                                         session_keys[i].rfc_def);
404                                 p[i].val = session_keys[i].rfc_def;
405                                 continue;
406                         } else if (p[i].key_state == KEY_STATE_DONE_ADDED) {
407                                 log_debug(1, "Key %s was already added, val %d",
408                                         session_keys[i].name, p[i].val);
409                                 continue;
410                         }
411                         switch (conn->state) {
412                         case STATE_LOGIN_FULL:
413                         case STATE_SECURITY_FULL:
414                                 if (iscsi_is_key_internal(i)) {
415                                         p[i].key_state = KEY_STATE_DONE;
416                                         continue;
417                                 }
418                                 break;
419                         case STATE_LOGIN:
420                                 if (iscsi_is_key_internal(i))
421                                         continue;
422                                 memset(buf, 0, sizeof(buf));
423                                 params_val_to_str(session_keys, i, p[i].val, buf, sizeof(buf));
424                                 text_key_add(conn, session_keys[i].name, buf);
425                                 if (i == key_max_recv_data_length) {
426                                         p[i].key_state = KEY_STATE_DONE;
427                                         continue;
428                                 }
429                                 p[i].key_state = KEY_STATE_REQUEST;
430                                 break;
431                         default:
432                                 if (iscsi_is_key_internal(i))
433                                         continue;
434                         }
435                         cnt++;
436                 }
437         }
438
439         return cnt;
440 }
441
442 static int init_conn_session_params(struct connection *conn)
443 {
444         int res = 0, i;
445         struct target *target;
446
447         target = target_find_by_id(conn->tid);
448         if (target == NULL) {
449                 log_error("target %d not found", conn->tid);
450                 res = -EINVAL;
451                 goto out;
452         }
453
454         for (i = 0; i < session_key_last; i++)
455                 conn->session_params[i].val = target->session_params[i];
456
457 out:
458         return res;
459 }
460
461 static void login_start(struct connection *conn)
462 {
463         struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
464         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
465         char *name, *alias, *session_type, *target_name;
466
467         conn->cid = be16_to_cpu(req->cid);
468         conn->sid.id64 = req->sid.id64;
469
470         name = text_key_find(conn, "InitiatorName");
471         if (!name) {
472                 rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
473                 rsp->status_detail = ISCSI_STATUS_MISSING_FIELDS;
474                 conn->state = STATE_EXIT;
475                 return;
476         }
477
478         conn->initiator = strdup(name);
479         if (conn->initiator == NULL) {
480                 log_error("Unable to duplicate initiator's name %s", name);
481                 rsp->status_class = ISCSI_STATUS_TARGET_ERR;
482                 rsp->status_detail = ISCSI_STATUS_NO_RESOURCES;
483                 conn->state = STATE_EXIT;
484                 return;
485         }
486
487         alias = text_key_find(conn, "InitiatorAlias");
488         session_type = text_key_find(conn, "SessionType");
489         target_name = text_key_find(conn, "TargetName");
490
491         conn->auth_method = -1;
492         conn->session_type = SESSION_NORMAL;
493
494         if (session_type) {
495                 if (!strcmp(session_type, "Discovery")) {
496                         conn->session_type = SESSION_DISCOVERY;
497                 } else if (strcmp(session_type, "Normal")) {
498                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
499                         rsp->status_detail = ISCSI_STATUS_INV_SESSION_TYPE;
500                         conn->state = STATE_EXIT;
501                         return;
502                 }
503         }
504
505         if (conn->session_type == SESSION_NORMAL) {
506                 struct target *target;
507                 int err;
508
509                 if (!target_name) {
510                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
511                         rsp->status_detail = ISCSI_STATUS_MISSING_FIELDS;
512                         conn->state = STATE_EXIT;
513                         return;
514                 }
515
516                 target = target_find_by_name(target_name);
517                 if (target == NULL) {
518                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
519                         rsp->status_detail = ISCSI_STATUS_TGT_NOT_FOUND;
520                         conn->state = STATE_EXIT;
521                         return;
522                 }
523
524                 if (!target->tgt_enabled) {
525                         log_info("Connect from %s to disabled target %s refused",
526                                 name, target_name);
527                         rsp->status_class = ISCSI_STATUS_TARGET_ERR;
528                         conn->state = STATE_CLOSE;
529                         return;
530                 }
531
532                 conn->tid = target->tid;
533                 if (config_initiator_access(conn->tid, conn->fd) ||
534                     isns_scn_access(conn->tid, conn->fd, name)) {
535                         log_info("Initiator %s not allowed to connect to "
536                                 "target %s", name, target_name);
537                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
538                         rsp->status_detail = ISCSI_STATUS_TGT_NOT_FOUND;
539                         conn->state = STATE_EXIT;
540                         return;
541                 }
542
543                 err = init_conn_session_params(conn);
544                 if (err != 0) {
545                         log_error("Can't get session params for session 0x%" PRIu64 
546                                 " (err %d): %s\n", conn->sid.id64, err,
547                                 strerror(-err));
548                         rsp->status_class = ISCSI_STATUS_TARGET_ERR;
549                         rsp->status_detail = ISCSI_STATUS_TARGET_ERROR;
550                         conn->state = STATE_EXIT;
551                         return;
552                 }
553
554                 if (login_check_reinstatement(conn) != 0)
555                         return;
556         }
557
558         conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn);
559         log_debug(1, "exp_cmd_sn %u, cmd_sn %u", conn->exp_cmd_sn, req->cmd_sn);
560         text_key_add(conn, "TargetPortalGroupTag", "1");
561         return;
562 }
563
564 static int login_finish(struct connection *conn)
565 {
566         int res = 0;
567
568         switch (conn->session_type) {
569         case SESSION_NORMAL:
570                 if (!conn->sess)
571                         res = session_create(conn);
572                 if (res == 0)
573                         conn->sid = conn->sess->sid;
574                 break;
575         case SESSION_DISCOVERY:
576                 /* set a dummy tsih value */
577                 conn->sid.id.tsih = 1;
578                 break;
579         }
580
581         return res;
582 }
583
584 static void cmnd_reject(struct connection *conn, u8 reason)
585 {
586         struct iscsi_reject_hdr *rej =
587                 (struct iscsi_reject_hdr *)&conn->rsp.bhs;
588         size_t data_sz = sizeof(struct iscsi_hdr);
589         struct buf_segment *seg;
590
591         conn_free_rsp_buf_list(conn);
592         seg = conn_alloc_buf_segment(conn, data_sz);
593
594         memset(rej, 0x0, sizeof *rej);
595         rej->opcode = ISCSI_OP_REJECT_MSG;
596         rej->reason = reason;
597         rej->ffffffff = ISCSI_RESERVED_TAG;
598         rej->flags |= ISCSI_FLG_FINAL;
599
600         rej->stat_sn = cpu_to_be32(conn->stat_sn++);
601         rej->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
602         rej->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
603
604         if (!seg) {
605                 log_error("Failed to alloc data segment for Reject PDU\n");
606                 return;
607         }
608
609         memcpy(seg->data, &conn->req.bhs, data_sz);
610         seg->len = data_sz;
611 }
612
613 static int cmnd_exec_auth(struct connection *conn)
614 {
615        int res;
616
617         switch (conn->auth_method) {
618         case AUTH_CHAP:
619                 res = cmnd_exec_auth_chap(conn);
620                 break;
621         case AUTH_NONE:
622                 res = 0;
623                 break;
624         default:
625                 log_error("Unknown auth. method %d", conn->auth_method);
626                 res = -3;
627         }
628
629         return res;
630 }
631
632 static void cmnd_exec_login(struct connection *conn)
633 {
634         struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
635         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
636         int stay = 0, nsg_disagree = 0;
637
638         memset(rsp, 0, BHS_SIZE);
639         if ((req->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_LOGIN_CMD ||
640             !(req->opcode & ISCSI_OP_IMMEDIATE)) {
641                 cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
642                 return;
643         }
644
645         rsp->opcode = ISCSI_OP_LOGIN_RSP;
646         rsp->max_version = ISCSI_VERSION;
647         rsp->active_version = ISCSI_VERSION;
648         rsp->itt = req->itt;
649
650         if (/*req->max_version < ISCSI_VERSION ||*/
651             req->min_version > ISCSI_VERSION) {
652                 rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
653                 rsp->status_detail = ISCSI_STATUS_NO_VERSION;
654                 conn->state = STATE_EXIT;
655                 return;
656         }
657
658         switch (req->flags & ISCSI_FLG_CSG_MASK) {
659         case ISCSI_FLG_CSG_SECURITY:
660                 log_debug(1, "Login request (security negotiation): %d", conn->state);
661                 rsp->flags = ISCSI_FLG_CSG_SECURITY;
662
663                 switch (conn->state) {
664                 case STATE_FREE:
665                         conn->state = STATE_SECURITY;
666                         login_start(conn);
667                         if (rsp->status_class)
668                                 return;
669                         //else fall through
670                 case STATE_SECURITY:
671                         text_scan_security(conn);
672                         if (rsp->status_class)
673                                 return;
674                         if (conn->auth_method != AUTH_NONE) {
675                                 conn->state = STATE_SECURITY_AUTH;
676                                 conn->auth_state = AUTH_STATE_START;
677                         }
678                         break;
679                 case STATE_SECURITY_AUTH:
680                         switch (cmnd_exec_auth(conn)) {
681                         case 0:
682                                 break;
683                         default:
684                         case -1:
685                                 goto init_err;
686                         case -2:
687                                 goto auth_err;
688                         }
689                         break;
690                 default:
691                         goto init_err;
692                 }
693
694                 break;
695         case ISCSI_FLG_CSG_LOGIN:
696                 log_debug(1, "Login request (operational negotiation): %d", conn->state);
697                 rsp->flags = ISCSI_FLG_CSG_LOGIN;
698
699                 switch (conn->state) {
700                 case STATE_FREE:
701                         conn->state = STATE_LOGIN;
702
703                         login_start(conn);
704                         if (!accounts_empty(conn->tid, ISCSI_USER_DIR_INCOMING))
705                                 goto auth_err;
706                         if (rsp->status_class)
707                                 return;
708                         text_scan_login(conn);
709                         if (rsp->status_class)
710                                 return;
711                         stay = text_check_params(conn);
712                         break;
713                 case STATE_LOGIN:
714                         text_scan_login(conn);
715                         if (rsp->status_class)
716                                 return;
717                         stay = text_check_params(conn);
718                         break;
719                 default:
720                         goto init_err;
721                 }
722                 break;
723         default:
724                 goto init_err;
725         }
726
727         if (rsp->status_class)
728                 return;
729         if (conn->state != STATE_SECURITY_AUTH && req->flags & ISCSI_FLG_TRANSIT) {
730                 int nsg = req->flags & ISCSI_FLG_NSG_MASK;
731
732                 switch (nsg) {
733                 case ISCSI_FLG_NSG_LOGIN:
734                         switch (conn->state) {
735                         case STATE_SECURITY:
736                         case STATE_SECURITY_DONE:
737                                 conn->state = STATE_SECURITY_LOGIN;
738                                 break;
739                         default:
740                                 goto init_err;
741                         }
742                         break;
743                 case ISCSI_FLG_NSG_FULL_FEATURE:
744                         switch (conn->state) {
745                         case STATE_SECURITY:
746                         case STATE_SECURITY_DONE:
747                                 if ((nsg_disagree = text_check_params(conn))) {
748                                         conn->state = STATE_LOGIN;
749                                         nsg = ISCSI_FLG_NSG_LOGIN;
750                                         break;
751                                 }
752                                 conn->state = STATE_SECURITY_FULL;
753                                 break;
754                         case STATE_LOGIN:
755                                 if (stay)
756                                         nsg = ISCSI_FLG_NSG_LOGIN;
757                                 else
758                                         conn->state = STATE_LOGIN_FULL;
759                                 break;
760                         default:
761                                 goto init_err;
762                         }
763                         if (!stay && !nsg_disagree) {
764                                 int err;
765                                 text_check_params(conn);
766                                 err = login_finish(conn);
767                                 if (err != 0) {
768                                         log_debug(1, "login_finish() failed: %d", err);
769                                         /* Make initiator retry later */
770                                         goto tgt_no_mem;
771                                 }
772                         }
773                         break;
774                 default:
775                         goto init_err;
776                 }
777                 rsp->flags |= nsg | (stay ? 0 : ISCSI_FLG_TRANSIT);
778         }
779
780         /*
781          * TODO: support Logical Text Data Segments > INCOMING_BUFSIZE (i.e.
782          * key=value pairs spanning several PDUs) during login phase
783          */
784         if (!list_empty(&conn->rsp_buf_list) &&
785             !list_length_is_one(&conn->rsp_buf_list)) {
786                 log_error("Target error: \'key=value\' pairs spanning several "
787                           "Login PDUs are not implemented, yet\n");
788                 goto target_err;
789         }
790
791         rsp->sid = conn->sid;
792         rsp->stat_sn = cpu_to_be32(conn->stat_sn++);
793         rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
794         rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
795         return;
796
797 init_err:
798         log_error("Initiator %s error", conn->initiator);
799         rsp->flags = 0;
800         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
801         rsp->status_detail = ISCSI_STATUS_INIT_ERR;
802         conn->state = STATE_EXIT;
803         return;
804
805 auth_err:
806         log_error("Authentication of initiator %s failed", conn->initiator);
807         rsp->flags = 0;
808         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
809         rsp->status_detail = ISCSI_STATUS_AUTH_FAILED;
810         conn->state = STATE_EXIT;
811         return;
812
813 target_err:
814         rsp->flags = 0;
815         rsp->status_class = ISCSI_STATUS_TARGET_ERR;
816         rsp->status_detail = ISCSI_STATUS_TARGET_ERROR;
817         conn->state = STATE_EXIT;
818         return;
819
820 tgt_no_mem:
821         rsp->flags = 0;
822         rsp->status_class = ISCSI_STATUS_TARGET_ERR;
823         rsp->status_detail = ISCSI_STATUS_NO_RESOURCES;
824         conn->state = STATE_EXIT;
825         return;
826 }
827
828 static void text_scan_text(struct connection *conn)
829 {
830         char *key, *value, *data;
831         int datasize;
832
833         data = conn->req.data;
834         datasize = conn->req.datasize;
835
836         while ((key = next_key(&data, &datasize, &value))) {
837                 if (!strcmp(key, "SendTargets")) {
838                         struct sockaddr_storage ss;
839                         socklen_t slen, blen;
840                         char *p, *addr, buf[NI_MAXHOST + 128];
841                         int suppress_ip6 = 0;
842
843                         if (value[0] == 0)
844                                 continue;
845
846                         p = addr = buf + 1;
847                         buf[0] = '[';
848                         blen = sizeof(buf) - 1;
849
850                         slen = sizeof(ss);
851
852                         getpeername(conn->fd, (struct sockaddr *) &ss, &slen);
853                         if (ss.ss_family == AF_INET)
854                                 suppress_ip6 = 1;
855                         else {
856                                 getnameinfo((struct sockaddr *) &ss, slen, p,
857                                             blen, NULL, 0, NI_NUMERICHOST);
858
859                                 if (strstr(p, "::ffff:") == p)
860                                         suppress_ip6 = 1;       // ipv4-mapped ipv6 ?
861                         }
862
863                         getsockname(conn->fd, (struct sockaddr *) &ss, &slen);
864                         slen = sizeof(ss);
865
866                         getnameinfo((struct sockaddr *) &ss, slen, p, blen,
867                                     NULL, 0, NI_NUMERICHOST);
868
869                         if (ss.ss_family == AF_INET6 && suppress_ip6) {
870                                 if (strstr(p, "::ffff:") != p) {
871                                         log_error("%s, %s:%d.", __FILE__,
872                                                   __func__, __LINE__);
873                                         suppress_ip6 = 0;
874                                 } else
875                                         addr += 7;
876                         }
877
878                         p += strlen(p);
879
880                         if (ss.ss_family == AF_INET6 && !suppress_ip6) {
881                                 *p++ = ']';
882                                 addr = buf;
883                         }
884
885                         sprintf(p, ":%d,1", server_port);
886                         target_list_build(conn, addr,
887                                           strcmp(value, "All") ? value : NULL);
888                 } else
889                         text_key_add(conn, key, "NotUnderstood");
890         }
891 }
892
893 static void cmnd_exec_text(struct connection *conn)
894 {
895         struct iscsi_text_req_hdr *req = (struct iscsi_text_req_hdr *)&conn->req.bhs;
896         struct iscsi_text_rsp_hdr *rsp = (struct iscsi_text_rsp_hdr *)&conn->rsp.bhs;
897
898         memset(rsp, 0, BHS_SIZE);
899
900         rsp->opcode = ISCSI_OP_TEXT_RSP;
901         rsp->itt = req->itt;
902         conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn);
903         if (!(req->opcode & ISCSI_OP_IMMEDIATE))
904                 conn->exp_cmd_sn++;
905
906         log_debug(1, "Text request: %d", conn->state);
907
908         if (req->ttt == ISCSI_RESERVED_TAG) {
909                 conn_free_rsp_buf_list(conn);
910                 text_scan_text(conn);
911                 if (!list_empty(&conn->rsp_buf_list) &&
912                     !list_length_is_one(&conn->rsp_buf_list))
913                         conn->ttt = get_next_ttt(conn);
914                 else
915                         conn->ttt = ISCSI_RESERVED_TAG;
916         } else if (list_empty(&conn->rsp_buf_list) || conn->ttt != req->ttt) {
917                 log_error("Rejecting unexpected text request. TTT recv %#x, "
918                           "expected %#x; %stext segments queued\n",
919                           req->ttt, conn->ttt, list_empty(&conn->rsp_buf_list) ?
920                           "no " : "");
921                 cmnd_reject(conn, ISCSI_REASON_INVALID_PDU_FIELD);
922                 return;
923         }
924
925         if (list_length_is_one(&conn->rsp_buf_list))
926                 rsp->flags = ISCSI_FLG_FINAL;
927         rsp->ttt = conn->ttt;
928
929         rsp->stat_sn = cpu_to_be32(conn->stat_sn++);
930         rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
931         rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
932 }
933
934 static void cmnd_exec_logout(struct connection *conn)
935 {
936         struct iscsi_logout_req_hdr *req = (struct iscsi_logout_req_hdr *)&conn->req.bhs;
937         struct iscsi_logout_rsp_hdr *rsp = (struct iscsi_logout_rsp_hdr *)&conn->rsp.bhs;
938
939         memset(rsp, 0, BHS_SIZE);
940         rsp->opcode = ISCSI_OP_LOGOUT_RSP;
941         rsp->flags = ISCSI_FLG_FINAL;
942         rsp->itt = req->itt;
943         conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn);
944         if (!(req->opcode & ISCSI_OP_IMMEDIATE))
945                 conn->exp_cmd_sn++;
946
947         rsp->stat_sn = cpu_to_be32(conn->stat_sn++);
948         rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
949         rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
950 }
951
952 int cmnd_execute(struct connection *conn)
953 {
954         int res = 1;
955         struct buf_segment *seg;
956         struct iscsi_login_rsp_hdr *login_rsp;
957
958         switch (conn->req.bhs.opcode & ISCSI_OPCODE_MASK) {
959         case ISCSI_OP_LOGIN_CMD:
960                 if (conn->state == STATE_FULL) {
961                         cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
962                         break;
963                 }
964                 cmnd_exec_login(conn);
965                 login_rsp = (struct iscsi_login_rsp_hdr *) &conn->rsp.bhs;
966                 if (login_rsp->status_class)
967                         conn_free_rsp_buf_list(conn);
968                 break;
969         case ISCSI_OP_TEXT_CMD:
970                 if (conn->state != STATE_FULL)
971                         cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
972                 else
973                         cmnd_exec_text(conn);
974                 break;
975         case ISCSI_OP_LOGOUT_CMD:
976                 if (conn->state != STATE_FULL)
977                         cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
978                 else
979                         cmnd_exec_logout(conn);
980                 cmnd_exec_logout(conn);
981                 break;
982         default:
983                 cmnd_reject(conn, ISCSI_REASON_UNSUPPORTED_COMMAND);
984                 res = 0;
985                 goto out;
986         }
987
988         if (!list_empty(&conn->rsp_buf_list)) {
989                 seg = list_entry(conn->rsp_buf_list.q_forw,
990                                  struct buf_segment, entry);
991                 list_del_init(&seg->entry);
992                 conn->rsp.datasize = seg->len;
993                 conn->rsp.data = seg->data;
994         } else {
995                 conn->rsp.datasize = 0;
996                 conn->rsp.data = NULL;
997         }
998
999         conn->rsp.bhs.ahslength = conn->rsp.ahssize / 4;
1000         conn->rsp.bhs.datalength[0] = conn->rsp.datasize >> 16;
1001         conn->rsp.bhs.datalength[1] = conn->rsp.datasize >> 8;
1002         conn->rsp.bhs.datalength[2] = conn->rsp.datasize;
1003         log_pdu(2, &conn->rsp);
1004
1005 out:
1006         return res;
1007 }
1008
1009 void cmnd_finish(struct connection *conn)
1010 {
1011         struct buf_segment *seg;
1012
1013         if (conn->rsp.data) {
1014                 seg = container_of(conn->rsp.data, struct buf_segment, data);
1015                 list_del(&seg->entry);
1016                 free(seg);
1017                 conn->rsp.data = NULL;
1018         }
1019
1020         switch (conn->state) {
1021         case STATE_EXIT:
1022                 conn->state = STATE_CLOSE;
1023                 break;
1024         case STATE_SECURITY_LOGIN:
1025                 conn->state = STATE_LOGIN;
1026                 break;
1027         case STATE_SECURITY_FULL:
1028                 //fall through
1029         case STATE_LOGIN_FULL:
1030                 if (conn->session_type == SESSION_NORMAL)
1031                         conn->state = STATE_KERNEL;
1032                 else
1033                         conn->state = STATE_FULL;
1034                 break;
1035         }
1036 }