- Update to the latest IET r145
[mirror/scst/.git] / iscsi-scst / usr / iscsid.c
1 /*
2  *  Copyright (C) 2002-2003 Ardis Technolgies <roman@ardistech.com>
3  *  Copyright (C) 2007 Vladislav Bolkhovitin
4  *  Copyright (C) 2007 CMS Distribution Limited
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 static struct iscsi_key login_keys[] = {
30         {"InitiatorName",},
31         {"InitiatorAlias",},
32         {"SessionType",},
33         {"TargetName",},
34         {NULL, 0, 0, 0, 0, NULL},
35 };
36
37 char *text_key_find(struct connection *conn, char *searchKey)
38 {
39         char *data, *key, *value;
40         int keylen, datasize;
41
42         keylen = strlen(searchKey);
43         data = conn->req.data;
44         datasize = conn->req.datasize;
45
46         while (1) {
47                 for (key = data; datasize > 0 && *data != '='; data++, datasize--)
48                         ;
49                 if (!datasize)
50                         return NULL;
51                 data++;
52                 datasize--;
53
54                 for (value = data; datasize > 0 && *data != 0; data++, datasize--)
55                         ;
56                 if (!datasize)
57                         return NULL;
58                 data++;
59                 datasize--;
60
61                 if (keylen == value - key - 1
62                      && !strncmp(key, searchKey, keylen))
63                         return value;
64         }
65 }
66
67 static char *next_key(char **data, int *datasize, char **value)
68 {
69         char *key, *p, *q;
70         int size = *datasize;
71
72         key = p = *data;
73         for (; size > 0 && *p != '='; p++, size--)
74                 ;
75         if (!size)
76                 return NULL;
77         *p++ = 0;
78         size--;
79
80         for (q = p; size > 0 && *p != 0; p++, size--)
81                 ;
82         if (!size)
83                 return NULL;
84         p++;
85         size--;
86
87         *data = p;
88         *value = q;
89         *datasize = size;
90
91         return key;
92 }
93
94 void text_key_add(struct connection *conn, char *key, char *value)
95 {
96         int keylen = strlen(key);
97         int valuelen = strlen(value);
98         int len = keylen + valuelen + 2;
99         char *buffer;
100
101         if (!conn->rsp.datasize) {
102                 if (!conn->rsp_buffer) {
103                         conn->rsp_buffer = malloc(INCOMING_BUFSIZE);
104                         if (!conn->rsp_buffer) {
105                                 log_error("Failed to alloc send buffer");
106                                 return;
107                         }
108                 }
109                 conn->rsp.data = conn->rsp_buffer;
110         }
111         if (conn->rsp.datasize + len > INCOMING_BUFSIZE) {
112                 log_warning("Dropping key (%s=%s)", key, value);
113                 return;
114         }
115
116         buffer = conn->rsp_buffer;
117         buffer += conn->rsp.datasize;
118         conn->rsp.datasize += len;
119
120         strcpy(buffer, key);
121         buffer += keylen;
122         *buffer++ = '=';
123         strcpy(buffer, value);
124 }
125
126 static void text_key_add_reject(struct connection *conn, char *key)
127 {
128         text_key_add(conn, key, "Reject");
129 }
130
131 static int account_empty(u32 tid, int dir)
132 {
133         char pass[ISCSI_NAME_LEN];
134
135         memset(pass, 0, sizeof(pass));
136         return cops->account_query(tid, dir, pass, pass) < 0 ? 1 : 0;
137 }
138
139 static void text_scan_security(struct connection *conn)
140 {
141         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
142         char *key, *value, *data, *nextValue;
143         int datasize;
144
145         data = conn->req.data;
146         datasize = conn->req.datasize;
147
148         while ((key = next_key(&data, &datasize, &value))) {
149                 if (!(param_index_by_name(key, login_keys) < 0))
150                         ;
151                 else if (!strcmp(key, "AuthMethod")) {
152                         do {
153                                 nextValue = strchr(value, ',');
154                                 if (nextValue)
155                                         *nextValue++ = 0;
156
157                                 if (!strcmp(value, "None")) {
158                                         if (!account_empty(conn->tid, AUTH_DIR_INCOMING))
159                                                 continue;
160                                         conn->auth_method = AUTH_NONE;
161                                         text_key_add(conn, key, "None");
162                                         break;
163                                 } else if (!strcmp(value, "CHAP")) {
164                                         if (account_empty(conn->tid, AUTH_DIR_INCOMING))
165                                                 continue;
166                                         conn->auth_method = AUTH_CHAP;
167                                         text_key_add(conn, key, "CHAP");
168                                         break;
169                                 }
170                         } while ((value = nextValue));
171
172                         if (conn->auth_method == AUTH_UNKNOWN)
173                                 text_key_add_reject(conn, key);
174                 } else
175                         text_key_add(conn, key, "NotUnderstood");
176         }
177         if (conn->auth_method == AUTH_UNKNOWN) {
178                 rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
179                 rsp->status_detail = ISCSI_STATUS_AUTH_FAILED;
180                 conn->state = STATE_EXIT;
181         }
182 }
183
184 static void login_security_done(struct connection *conn)
185 {
186         int err;
187         struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
188         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
189         struct session *session;
190
191         if (!conn->tid)
192                 return;
193
194         if ((session = session_find_name(conn->tid, conn->initiator, req->sid))) {
195                 if (!req->sid.id.tsih) {
196                         /* do session reinstatement */
197                         session_conns_close(conn->tid, session->sid.id64);
198                         session = NULL;
199                 } else if (req->sid.id.tsih != session->sid.id.tsih) {
200                         /* fail the login */
201                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
202                         rsp->status_detail = ISCSI_STATUS_SESSION_NOT_FOUND;
203                         conn->state = STATE_EXIT;
204                         return;
205                 } else if ((err = conn_test(conn)) == -ENOENT) {
206                         /* do connection reinstatement */
207                 }
208                 /* add a new connection to the session */
209                 conn->session = session;
210         } else {
211                 if (req->sid.id.tsih) {
212                         /* fail the login */
213                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
214                         rsp->status_detail = ISCSI_STATUS_SESSION_NOT_FOUND;
215                         conn->state = STATE_EXIT;
216                         return;
217                 }
218                 /* instantiate a new session */
219         }
220 }
221
222 static void text_scan_login(struct connection *conn)
223 {
224         char *key, *value, *data;
225         int datasize, idx;
226         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
227
228         data = conn->req.data;
229         datasize = conn->req.datasize;
230
231         while ((key = next_key(&data, &datasize, &value))) {
232                 if (!(param_index_by_name(key, login_keys) < 0))
233                         ;
234                 else if (!strcmp(key, "AuthMethod"))
235                         ;
236                 else if (!((idx = param_index_by_name(key, session_keys)) < 0)) {
237                         unsigned int val;
238                         char buf[32];
239
240                         if (idx == key_max_xmit_data_length) {
241                                 text_key_add(conn, key, "NotUnderstood");
242                                 continue;
243                         }
244                         if (idx == key_max_recv_data_length)
245                                 idx = key_max_xmit_data_length;
246
247                         if (param_str_to_val(session_keys, idx, value, &val) < 0) {
248                                 if (conn->session_param[idx].state
249                                     == KEY_STATE_START) {
250                                         text_key_add_reject(conn, key);
251                                         continue;
252                                 } else {
253                                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
254                                         rsp->status_detail = ISCSI_STATUS_INIT_ERR;
255                                         conn->state = STATE_EXIT;
256                                         goto out;
257                                 }
258                         }
259
260                         param_check_val(session_keys, idx, &val);
261                         param_set_val(session_keys, conn->session_param, idx, &val);
262
263                         switch (conn->session_param[idx].state) {
264                         case KEY_STATE_START:
265                                 if (iscsi_is_key_declarative(idx))
266                                         break;
267                                 memset(buf, 0, sizeof(buf));
268                                 param_val_to_str(session_keys, idx, val, buf);
269                                 text_key_add(conn, key, buf);
270                                 break;
271                         case KEY_STATE_REQUEST:
272                                 if (val != conn->session_param[idx].exec_val) {
273                                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
274                                         rsp->status_detail = ISCSI_STATUS_INIT_ERR;
275                                         conn->state = STATE_EXIT;
276                                         log_warning("%s %u %u\n", key,
277                                                 val, conn->session_param[idx].exec_val);
278                                         goto out;
279                                 }
280                                 break;
281                         case KEY_STATE_DONE:
282                                 break;
283                         }
284                         conn->session_param[idx].state = KEY_STATE_DONE;
285                 } else
286                         text_key_add(conn, key, "NotUnderstood");
287         }
288
289 out:
290         return;
291 }
292
293 static int text_check_param(struct connection *conn)
294 {
295         struct iscsi_param *p = conn->session_param;
296         char buf[32];
297         int i, cnt;
298
299         for (i = 0, cnt = 0; session_keys[i].name; i++) {
300                 if (p[i].state == KEY_STATE_START && p[i].exec_val != session_keys[i].rfc_def) {
301                         switch (conn->state) {
302                         case STATE_LOGIN_FULL:
303                         case STATE_SECURITY_FULL:
304                                 if (iscsi_is_key_declarative(i)) {
305                                         p[i].state = KEY_STATE_DONE;
306                                         continue;
307                                 }
308                                 break;
309                         case STATE_LOGIN:
310                                 if (iscsi_is_key_declarative(i))
311                                         continue;
312                                 memset(buf, 0, sizeof(buf));
313                                 param_val_to_str(session_keys, i, p[i].exec_val,
314                                                  buf);
315                                 text_key_add(conn, session_keys[i].name, buf);
316                                 if (i == key_max_recv_data_length) {
317                                         p[i].state = KEY_STATE_DONE;
318                                         continue;
319                                 }
320                                 p[i].state = KEY_STATE_REQUEST;
321                                 break;
322                         default:
323                                 if (iscsi_is_key_declarative(i))
324                                         continue;
325                         }
326                         cnt++;
327                 }
328         }
329
330         return cnt;
331 }
332
333 static void login_start(struct connection *conn)
334 {
335         struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
336         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
337         char *name, *alias, *session_type, *target_name;
338
339         conn->cid = be16_to_cpu(req->cid);
340         conn->sid.id64 = req->sid.id64;
341         if (!conn->sid.id64) {
342                 rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
343                 rsp->status_detail = ISCSI_STATUS_MISSING_FIELDS;
344                 conn->state = STATE_EXIT;
345                 return;
346         }
347
348         name = text_key_find(conn, "InitiatorName");
349         if (!name) {
350                 rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
351                 rsp->status_detail = ISCSI_STATUS_MISSING_FIELDS;
352                 conn->state = STATE_EXIT;
353                 return;
354         }
355         conn->initiator = strdup(name);
356         alias = text_key_find(conn, "InitiatorAlias");
357         session_type = text_key_find(conn, "SessionType");
358         target_name = text_key_find(conn, "TargetName");
359
360         conn->auth_method = -1;
361         conn->session_type = SESSION_NORMAL;
362
363         if (session_type) {
364                 if (!strcmp(session_type, "Discovery"))
365                         conn->session_type = SESSION_DISCOVERY;
366                 else if (strcmp(session_type, "Normal")) {
367                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
368                         rsp->status_detail = ISCSI_STATUS_INV_SESSION_TYPE;
369                         conn->state = STATE_EXIT;
370                         return;
371                 }
372         }
373
374         if (conn->session_type == SESSION_NORMAL) {
375                 if (!target_name) {
376                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
377                         rsp->status_detail = ISCSI_STATUS_MISSING_FIELDS;
378                         conn->state = STATE_EXIT;
379                         return;
380                 }
381
382                 if (!(conn->tid = target_find_by_name(target_name)) ||
383                     cops->initiator_access(conn->tid, conn->fd) ||
384                     isns_scn_access(conn->tid, conn->fd, name)) {
385                         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
386                         rsp->status_detail = ISCSI_STATUS_TGT_NOT_FOUND;
387                         conn->state = STATE_EXIT;
388                         return;
389                 }
390
391                 if (ki->param_get(conn->tid, 0, key_session,
392                                 conn->session_param, 1))  {
393                         rsp->status_class = ISCSI_STATUS_TARGET_ERROR;
394                         rsp->status_detail = ISCSI_STATUS_SVC_UNAVAILABLE;
395                         conn->state = STATE_EXIT;
396                 }
397                 conn->session_param[key_max_recv_data_length].exec_val = 
398                         conn->session_param[key_max_recv_data_length].local_val;
399         }
400         conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn);
401         log_debug(1, "exp_cmd_sn: %d,%d", conn->exp_cmd_sn, req->cmd_sn);
402         text_key_add(conn, "TargetPortalGroupTag", "1");
403 }
404
405 static void login_finish(struct connection *conn)
406 {
407         switch (conn->session_type) {
408         case SESSION_NORMAL:
409                 if (!conn->session)
410                         session_create(conn);
411                 conn->sid = conn->session->sid;
412                 break;
413         case SESSION_DISCOVERY:
414                 /* set a dummy tsih value */
415                 conn->sid.id.tsih = 1;
416                 break;
417         }
418 }
419
420 static int cmnd_exec_auth(struct connection *conn)
421 {
422        int res;
423
424         switch (conn->auth_method) {
425         case AUTH_CHAP:
426                 res = cmnd_exec_auth_chap(conn);
427                 break;
428         case AUTH_NONE:
429                 res = 0;
430                 break;
431         default:
432                 log_error("Unknown auth. method %d", conn->auth_method);
433                 res = -3;
434         }
435
436         return res;
437 }
438
439 static void cmnd_exec_login(struct connection *conn)
440 {
441         struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
442         struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
443         int stay = 0, nsg_disagree = 0;
444
445         memset(rsp, 0, BHS_SIZE);
446         if ((req->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_LOGIN_CMD ||
447             !(req->opcode & ISCSI_OP_IMMEDIATE)) {
448                 //reject
449         }
450
451         rsp->opcode = ISCSI_OP_LOGIN_RSP;
452         rsp->max_version = ISCSI_VERSION;
453         rsp->active_version = ISCSI_VERSION;
454         rsp->itt = req->itt;
455
456         if (/*req->max_version < ISCSI_VERSION ||*/
457             req->min_version > ISCSI_VERSION) {
458                 rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
459                 rsp->status_detail = ISCSI_STATUS_NO_VERSION;
460                 conn->state = STATE_EXIT;
461                 return;
462         }
463
464         switch (req->flags & ISCSI_FLG_CSG_MASK) {
465         case ISCSI_FLG_CSG_SECURITY:
466                 log_debug(1, "Login request (security negotiation): %d", conn->state);
467                 rsp->flags = ISCSI_FLG_CSG_SECURITY;
468
469                 switch (conn->state) {
470                 case STATE_FREE:
471                         conn->state = STATE_SECURITY;
472                         login_start(conn);
473                         if (rsp->status_class)
474                                 return;
475                         //else fall through
476                 case STATE_SECURITY:
477                         text_scan_security(conn);
478                         if (rsp->status_class)
479                                 return;
480                         if (conn->auth_method != AUTH_NONE) {
481                                 conn->state = STATE_SECURITY_AUTH;
482                                 conn->auth_state = AUTH_STATE_START;
483                         }
484                         break;
485                 case STATE_SECURITY_AUTH:
486                         switch (cmnd_exec_auth(conn)) {
487                         case 0:
488                                 break;
489                         default:
490                         case -1:
491                                 goto init_err;
492                         case -2:
493                                 goto auth_err;
494                         }
495                         break;
496                 default:
497                         goto init_err;
498                 }
499
500                 break;
501         case ISCSI_FLG_CSG_LOGIN:
502                 log_debug(1, "Login request (operational negotiation): %d", conn->state);
503                 rsp->flags = ISCSI_FLG_CSG_LOGIN;
504
505                 switch (conn->state) {
506                 case STATE_FREE:
507                         conn->state = STATE_LOGIN;
508
509                         login_start(conn);
510                         if (!account_empty(conn->tid, AUTH_DIR_INCOMING))
511                                 goto auth_err;
512                         if (rsp->status_class)
513                                 return;
514                         text_scan_login(conn);
515                         if (rsp->status_class)
516                                 return;
517                         stay = text_check_param(conn);
518                         break;
519                 case STATE_LOGIN:
520                         text_scan_login(conn);
521                         if (rsp->status_class)
522                                 return;
523                         stay = text_check_param(conn);
524                         break;
525                 default:
526                         goto init_err;
527                 }
528                 break;
529         default:
530                 goto init_err;
531         }
532
533         if (rsp->status_class)
534                 return;
535         if (conn->state != STATE_SECURITY_AUTH && req->flags & ISCSI_FLG_TRANSIT) {
536                 int nsg = req->flags & ISCSI_FLG_NSG_MASK;
537
538                 switch (nsg) {
539                 case ISCSI_FLG_NSG_LOGIN:
540                         switch (conn->state) {
541                         case STATE_SECURITY:
542                         case STATE_SECURITY_DONE:
543                                 conn->state = STATE_SECURITY_LOGIN;
544                                 login_security_done(conn);
545                                 break;
546                         default:
547                                 goto init_err;
548                         }
549                         break;
550                 case ISCSI_FLG_NSG_FULL_FEATURE:
551                         switch (conn->state) {
552                         case STATE_SECURITY:
553                         case STATE_SECURITY_DONE:
554                                 if ((nsg_disagree = text_check_param(conn))) {
555                                         conn->state = STATE_LOGIN;
556                                         nsg = ISCSI_FLG_NSG_LOGIN;
557                                         break;
558                                 }
559                                 conn->state = STATE_SECURITY_FULL;
560                                 login_security_done(conn);
561                                 break;
562                         case STATE_LOGIN:
563                                 if (stay)
564                                         nsg = ISCSI_FLG_NSG_LOGIN;
565                                 else
566                                         conn->state = STATE_LOGIN_FULL;
567                                 break;
568                         default:
569                                 goto init_err;
570                         }
571                         if (!stay && !nsg_disagree) {
572                                 text_check_param(conn);
573                                 login_finish(conn);
574                         }
575                         break;
576                 default:
577                         goto init_err;
578                 }
579                 rsp->flags |= nsg | (stay ? 0 : ISCSI_FLG_TRANSIT);
580         }
581
582         rsp->sid = conn->sid;
583         rsp->stat_sn = cpu_to_be32(conn->stat_sn++);
584         rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
585         rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
586         return;
587 init_err:
588         rsp->flags = 0;
589         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
590         rsp->status_detail = ISCSI_STATUS_INIT_ERR;
591         conn->state = STATE_EXIT;
592         return;
593 auth_err:
594         rsp->flags = 0;
595         rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
596         rsp->status_detail = ISCSI_STATUS_AUTH_FAILED;
597         conn->state = STATE_EXIT;
598         return;
599 }
600
601 static void text_scan_text(struct connection *conn)
602 {
603         char *key, *value, *data;
604         int datasize;
605
606         data = conn->req.data;
607         datasize = conn->req.datasize;
608
609         while ((key = next_key(&data, &datasize, &value))) {
610                 if (!strcmp(key, "SendTargets")) {
611                         struct sockaddr_storage ss;
612                         socklen_t slen, blen;
613                         char *p, *addr, buf[NI_MAXHOST + 128];
614                         int suppress_ip6 = 0;
615
616                         if (value[0] == 0)
617                                 continue;
618
619                         p = addr = buf + 1;
620                         buf[0] = '[';
621                         blen = sizeof(buf) - 1;
622
623                         slen = sizeof(ss);
624
625                         getpeername(conn->fd, (struct sockaddr *) &ss, &slen);
626                         if (ss.ss_family == AF_INET)
627                                 suppress_ip6 = 1;
628                         else {
629                                 getnameinfo((struct sockaddr *) &ss, slen, p,
630                                             blen, NULL, 0, NI_NUMERICHOST);
631
632                                 if (strstr(p, "::ffff:") == p)
633                                         suppress_ip6 = 1;       // ipv4-mapped ipv6 ?
634                         }
635
636                         getsockname(conn->fd, (struct sockaddr *) &ss, &slen);
637                         slen = sizeof(ss);
638
639                         getnameinfo((struct sockaddr *) &ss, slen, p, blen,
640                                     NULL, 0, NI_NUMERICHOST);
641
642                         if (ss.ss_family == AF_INET6 && suppress_ip6) {
643                                 if (strstr(p, "::ffff:") != p) {
644                                         log_error("%s, %s:%d.", __FILE__,
645                                                   __FUNCTION__, __LINE__);
646                                         suppress_ip6 = 0;
647                                 } else
648                                         addr += 7;
649                         }
650
651                         p += strlen(p);
652
653                         if (ss.ss_family == AF_INET6 && !suppress_ip6) {
654                                 *p++ = ']';
655                                 addr = buf;
656                         }
657
658                         sprintf(p, ":%d,1", server_port);
659                         target_list_build(conn, addr,
660                                           strcmp(value, "All") ? value : NULL);
661                 } else
662                         text_key_add(conn, key, "NotUnderstood");
663         }
664 }
665
666 static void cmnd_exec_text(struct connection *conn)
667 {
668         struct iscsi_text_req_hdr *req = (struct iscsi_text_req_hdr *)&conn->req.bhs;
669         struct iscsi_text_rsp_hdr *rsp = (struct iscsi_text_rsp_hdr *)&conn->rsp.bhs;
670
671         memset(rsp, 0, BHS_SIZE);
672
673         if (be32_to_cpu(req->ttt) != 0xffffffff) {
674                 /* reject */;
675         }
676         rsp->opcode = ISCSI_OP_TEXT_RSP;
677         rsp->itt = req->itt;
678         //rsp->ttt = rsp->ttt;
679         rsp->ttt = 0xffffffff;
680         conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn);
681         if (!(req->opcode & ISCSI_OP_IMMEDIATE))
682                 conn->exp_cmd_sn++;
683
684         log_debug(1, "Text request: %d", conn->state);
685         text_scan_text(conn);
686
687         if (req->flags & ISCSI_FLG_FINAL)
688                 rsp->flags = ISCSI_FLG_FINAL;
689
690         rsp->stat_sn = cpu_to_be32(conn->stat_sn++);
691         rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
692         rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
693 }
694
695 static void cmnd_exec_logout(struct connection *conn)
696 {
697         struct iscsi_logout_req_hdr *req = (struct iscsi_logout_req_hdr *)&conn->req.bhs;
698         struct iscsi_logout_rsp_hdr *rsp = (struct iscsi_logout_rsp_hdr *)&conn->rsp.bhs;
699
700         memset(rsp, 0, BHS_SIZE);
701         rsp->opcode = ISCSI_OP_LOGOUT_RSP;
702         rsp->flags = ISCSI_FLG_FINAL;
703         rsp->itt = req->itt;
704         conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn);
705         if (!(req->opcode & ISCSI_OP_IMMEDIATE))
706                 conn->exp_cmd_sn++;
707
708         rsp->stat_sn = cpu_to_be32(conn->stat_sn++);
709         rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
710         rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
711 }
712
713 int cmnd_execute(struct connection *conn)
714 {
715         int res = 1;
716
717         switch (conn->req.bhs.opcode & ISCSI_OPCODE_MASK) {
718         case ISCSI_OP_LOGIN_CMD:
719                 //if conn->state == STATE_FULL -> reject
720                 cmnd_exec_login(conn);
721                 conn->rsp.bhs.ahslength = conn->rsp.ahssize / 4;
722                 conn->rsp.bhs.datalength[0] = conn->rsp.datasize >> 16;
723                 conn->rsp.bhs.datalength[1] = conn->rsp.datasize >> 8;
724                 conn->rsp.bhs.datalength[2] = conn->rsp.datasize;
725                 log_pdu(2, &conn->rsp);
726                 break;
727         case ISCSI_OP_TEXT_CMD:
728                 //if conn->state != STATE_FULL -> reject
729                 cmnd_exec_text(conn);
730                 conn->rsp.bhs.ahslength = conn->rsp.ahssize / 4;
731                 conn->rsp.bhs.datalength[0] = conn->rsp.datasize >> 16;
732                 conn->rsp.bhs.datalength[1] = conn->rsp.datasize >> 8;
733                 conn->rsp.bhs.datalength[2] = conn->rsp.datasize;
734                 log_pdu(2, &conn->rsp);
735                 break;
736         case ISCSI_OP_LOGOUT_CMD:
737                 //if conn->state != STATE_FULL -> reject
738                 cmnd_exec_logout(conn);
739                 conn->rsp.bhs.ahslength = conn->rsp.ahssize / 4;
740                 conn->rsp.bhs.datalength[0] = conn->rsp.datasize >> 16;
741                 conn->rsp.bhs.datalength[1] = conn->rsp.datasize >> 8;
742                 conn->rsp.bhs.datalength[2] = conn->rsp.datasize;
743                 log_pdu(2, &conn->rsp);
744                 break;
745         default:
746                 //reject
747                 res = 0;
748                 break;
749         }
750
751         return res;
752 }
753
754 void cmnd_finish(struct connection *conn)
755 {
756         switch (conn->state) {
757         case STATE_EXIT:
758                 conn->state = STATE_CLOSE;
759                 break;
760         case STATE_SECURITY_LOGIN:
761                 conn->state = STATE_LOGIN;
762                 break;
763         case STATE_SECURITY_FULL:
764                 //fall through
765         case STATE_LOGIN_FULL:
766                 if (conn->session_type == SESSION_NORMAL)
767                         conn->state = STATE_KERNEL;
768                 else
769                         conn->state = STATE_FULL;
770                 break;
771         }
772 }