open-isns: Fix warnings reported by gcc-4.5.2
[open-iscsi.git] / usr / login.c
blobdb76c8052e0ad4405232eeae465be2067b43485e
1 /*
2 * iSCSI Login Library
4 * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
5 * maintained by open-iscsi@googlegroups.com
7 * heavily based on code from iscsi-login.c:
8 * Copyright (C) 2001 Cisco Systems, Inc.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * See the file COPYING included with this distribution for more details.
22 * Formation of iSCSI login pdu, processing the login response and other
23 * functions are defined here
26 #include <netdb.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <poll.h>
31 #include <errno.h>
32 #include <sys/param.h>
34 #include "initiator.h"
35 #include "transport.h"
36 #include "log.h"
37 #include "iscsi_timer.h"
39 /* caller is assumed to be well-behaved and passing NUL terminated strings */
40 int
41 iscsi_add_text(struct iscsi_hdr *pdu, char *data, int max_data_length,
42 char *param, char *value)
44 int param_len = strlen(param);
45 int value_len = strlen(value);
46 int length = param_len + 1 + value_len + 1; /* param, separator,
47 * value, and trailing
48 * NULL
50 int pdu_length = ntoh24(pdu->dlength);
51 char *text = data;
52 char *end = data + max_data_length;
53 char *pdu_text;
55 /* find the end of the current text */
56 text += pdu_length;
57 pdu_text = text;
58 pdu_length += length;
60 if (text + length >= end) {
61 log_warning("Failed to add login text "
62 "'%s=%s'\n", param, value);
63 return 0;
66 /* param */
67 strncpy(text, param, param_len);
68 text += param_len;
70 /* separator */
71 *text++ = ISCSI_TEXT_SEPARATOR;
73 /* value */
74 strncpy(text, value, value_len);
75 text += value_len;
77 /* NUL */
78 *text++ = '\0';
80 /* update the length in the PDU header */
81 hton24(pdu->dlength, pdu_length);
83 return 1;
86 static int
87 iscsi_find_key_value(char *param, char *pdu, char *pdu_end, char **value_start,
88 char **value_end)
90 char *str = param;
91 char *text = pdu;
92 char *value;
94 if (value_start)
95 *value_start = NULL;
96 if (value_end)
97 *value_end = NULL;
99 /* make sure they contain the same bytes */
100 while (*str) {
101 if (text >= pdu_end)
102 return 0;
103 if (*text == '\0')
104 return 0;
105 if (*str != *text)
106 return 0;
107 str++;
108 text++;
111 if ((text >= pdu_end) || (*text == '\0')
112 || (*text != ISCSI_TEXT_SEPARATOR)) {
113 return 0;
116 /* find the value */
117 value = text + 1;
119 /* find the end of the value */
120 while ((text < pdu_end) && (*text))
121 text++;
123 if (value_start)
124 *value_start = value;
125 if (value_end)
126 *value_end = text;
128 return 1;
131 static enum iscsi_login_status
132 get_auth_key_type(struct iscsi_acl *auth_client, char **data, char *end)
134 char *key;
135 char *value = NULL;
136 char *value_end = NULL;
137 char *text = *data;
139 int keytype = AUTH_KEY_TYPE_NONE;
141 while (acl_get_next_key_type(&keytype) == AUTH_STATUS_NO_ERROR) {
142 key = (char *)acl_get_key_name(keytype);
143 if (key && iscsi_find_key_value(key, text, end, &value,
144 &value_end)) {
145 if (acl_recv_key_value(auth_client, keytype, value) !=
146 AUTH_STATUS_NO_ERROR) {
147 log_error("login negotiation failed, can't "
148 "accept %s in security stage", text);
149 return LOGIN_NEGOTIATION_FAILED;
151 text = value_end;
152 *data = text;
153 return LOGIN_OK;
156 log_error("Login negotiation failed, can't accept %s in security "
157 "stage", text);
158 return LOGIN_NEGOTIATION_FAILED;
162 resolve_address(char *host, char *port, struct sockaddr_storage *ss)
164 struct addrinfo hints, *res;
165 int rc;
167 memset(&hints, 0, sizeof(struct addrinfo));
168 hints.ai_family = AF_UNSPEC;
169 hints.ai_socktype = SOCK_STREAM;
171 if ((rc = getaddrinfo(host, port, &hints, &res))) {
172 log_error("Cannot resolve host %s. getaddrinfo error: "
173 "[%s]\n", host, gai_strerror(rc));
174 return rc;
177 memcpy(ss, res->ai_addr, res->ai_addrlen);
179 freeaddrinfo(res);
181 return rc;
185 * try to reset the session's IP address and port, based on the TargetAddress
186 * provided
189 iscsi_update_address(iscsi_conn_t *conn, char *address)
191 char *port, *tag;
192 char default_port[NI_MAXSERV];
193 iscsi_session_t *session = conn->session;
194 struct sockaddr_storage addr;
196 if ((tag = strrchr(address, ','))) {
197 *tag = '\0';
198 tag++;
200 if ((port = strrchr(address, ':'))) {
201 *port = '\0';
202 port++;
205 if (!port) {
206 sprintf(default_port, "%d", ISCSI_LISTEN_PORT);
207 port = default_port;
210 if (*address == '[') {
211 char *end_bracket;
213 if (!(end_bracket = strchr(address, ']'))) {
214 log_error("Invalid IPv6 address with opening bracket, "
215 "but no closing bracket.");
216 return 0;
218 *end_bracket = '\0';
219 address++;
222 if (resolve_address(address, port, &addr)) {
223 log_error("cannot resolve host name %s", address);
224 return 0;
227 conn->saddr = addr;
228 if (tag)
229 session->portal_group_tag = atoi(tag);
230 return 1;
233 static enum iscsi_login_status
234 get_security_text_keys(iscsi_session_t *session, int cid, char **data,
235 struct iscsi_acl *auth_client, char *end)
237 char *text = *data;
238 char *value = NULL;
239 char *value_end = NULL;
240 size_t size;
241 int tag;
242 enum iscsi_login_status ret;
245 * a few keys are possible in Security stage
246 * which the auth code doesn't care about, but
247 * which we might want to see, or at least not
248 * choke on.
250 if (iscsi_find_key_value("TargetAlias", text, end, &value,
251 &value_end)) {
252 size = value_end - value;
253 session->target_alias = malloc(size + 1);
254 if (!session->target_alias) {
255 /* Alias not critical. So just print an error */
256 log_error("Login failed to allocate alias");
257 *data = value_end;
258 return LOGIN_OK;
260 memcpy(session->target_alias, value, size);
261 session->target_alias[size] = '\0';
262 text = value_end;
263 } else if (iscsi_find_key_value("TargetAddress", text, end, &value,
264 &value_end)) {
266 * if possible, change the session's
267 * ip_address and port to the new TargetAddress for
268 * leading connection
270 if (iscsi_update_address(&session->conn[cid], value)) {
271 text = value_end;
272 } else {
273 log_error("Login redirection failed, "
274 "can't handle redirection to %s", value);
275 return LOGIN_REDIRECTION_FAILED;
277 } else if (iscsi_find_key_value("TargetPortalGroupTag", text, end,
278 &value, &value_end)) {
280 * We should have already obtained this
281 * via discovery, but the value could be stale.
282 * If the target was reconfigured it will send us
283 * the updated tpgt.
285 tag = strtoul(value, NULL, 0);
286 if (session->portal_group_tag >= 0) {
287 if (tag != session->portal_group_tag)
288 log_debug(2, "Portal group tag "
289 "mismatch, expected %u, "
290 "received %u. Updating",
291 session->portal_group_tag, tag);
293 /* we now know the tag */
294 session->portal_group_tag = tag;
295 text = value_end;
296 } else {
298 * any key we don't recognize either
299 * goes to the auth code, or we choke
300 * on it
302 ret = get_auth_key_type(auth_client, &text, end);
303 if (ret != LOGIN_OK)
304 return ret;
306 *data = text;
307 return LOGIN_OK;
310 static enum iscsi_login_status
311 get_op_params_text_keys(iscsi_session_t *session, int cid,
312 char **data, char *end)
314 char *text = *data;
315 char *value = NULL;
316 char *value_end = NULL;
317 size_t size;
318 iscsi_conn_t *conn = &session->conn[cid];
320 if (iscsi_find_key_value("TargetAlias", text, end, &value,
321 &value_end)) {
322 size = value_end - value;
323 if (session->target_alias &&
324 strlen(session->target_alias) == size &&
325 memcmp(session->target_alias, value, size) == 0) {
326 *data = value_end;
327 return LOGIN_OK;
329 free(session->target_alias);
330 session->target_alias = malloc(size + 1);
331 if (!session->target_alias) {
332 /* Alias not critical. So just print an error */
333 log_error("Login failed to allocate alias");
334 *data = value_end;
335 return LOGIN_OK;
337 memcpy(session->target_alias, value, size);
338 session->target_alias[size] = '\0';
339 text = value_end;
340 } else if (iscsi_find_key_value("TargetAddress", text, end, &value,
341 &value_end)) {
342 if (iscsi_update_address(conn, value))
343 text = value_end;
344 else {
345 log_error("Login redirection failed, "
346 "can't handle redirection to %s",
347 value);
348 return LOGIN_REDIRECTION_FAILED;
350 } else if (iscsi_find_key_value("TargetPortalGroupTag", text, end,
351 &value, &value_end)) {
352 int tag = strtoul(value, NULL, 0);
354 * We should have already obtained this
355 * via discovery, but the value could be stale.
356 * If the target was reconfigured it will send us
357 * the updated tpgt.
359 if (session->portal_group_tag >= 0) {
360 if (tag != session->portal_group_tag)
361 log_debug(2, "Portal group tag "
362 "mismatch, expected %u, "
363 "received %u. Updating",
364 session->portal_group_tag, tag);
366 /* we now know the tag */
367 session->portal_group_tag = tag;
368 text = value_end;
369 } else if (iscsi_find_key_value("InitialR2T", text, end, &value,
370 &value_end)) {
371 if (session->type == ISCSI_SESSION_TYPE_NORMAL) {
372 if (value && (strcmp(value, "Yes") == 0))
373 session->initial_r2t_en = 1;
374 else
375 session->initial_r2t_en = 0;
376 } else
377 session->irrelevant_keys_bitmap |=
378 IRRELEVANT_INITIALR2T;
379 text = value_end;
380 } else if (iscsi_find_key_value("ImmediateData", text, end, &value,
381 &value_end)) {
382 if (session->type == ISCSI_SESSION_TYPE_NORMAL) {
383 if (value && (strcmp(value, "Yes") == 0))
384 session->imm_data_en = 1;
385 else
386 session->imm_data_en = 0;
387 } else
388 session->irrelevant_keys_bitmap |=
389 IRRELEVANT_IMMEDIATEDATA;
390 text = value_end;
391 } else if (iscsi_find_key_value("MaxRecvDataSegmentLength", text, end,
392 &value, &value_end)) {
393 if (session->type == ISCSI_SESSION_TYPE_DISCOVERY ||
394 !session->t->template->rdma) {
395 int tgt_max_xmit;
396 conn_rec_t *conn_rec = &session->nrec.conn[cid];
398 tgt_max_xmit = strtoul(value, NULL, 0);
400 * if the rec value is zero it means to use
401 * what the target gave us.
403 if (!conn_rec->iscsi.MaxXmitDataSegmentLength ||
404 tgt_max_xmit < conn->max_xmit_dlength)
405 conn->max_xmit_dlength = tgt_max_xmit;
407 text = value_end;
408 } else if (iscsi_find_key_value("FirstBurstLength", text, end, &value,
409 &value_end)) {
410 if (session->type == ISCSI_SESSION_TYPE_NORMAL)
411 session->first_burst = strtoul(value, NULL, 0);
412 else
413 session->irrelevant_keys_bitmap |=
414 IRRELEVANT_FIRSTBURSTLENGTH;
415 text = value_end;
416 } else if (iscsi_find_key_value("MaxBurstLength", text, end, &value,
417 &value_end)) {
419 * we don't really care, since it's a limit on the target's
420 * R2Ts, but record it anwyay
422 if (session->type == ISCSI_SESSION_TYPE_NORMAL)
423 session->max_burst = strtoul(value, NULL, 0);
424 else
425 session->irrelevant_keys_bitmap |=
426 IRRELEVANT_MAXBURSTLENGTH;
427 text = value_end;
428 } else if (iscsi_find_key_value("HeaderDigest", text, end, &value,
429 &value_end)) {
430 if (strcmp(value, "None") == 0) {
431 if (conn->hdrdgst_en != ISCSI_DIGEST_CRC32C)
432 conn->hdrdgst_en = ISCSI_DIGEST_NONE;
433 else {
434 log_error("Login negotiation "
435 "failed, HeaderDigest=CRC32C "
436 "is required, can't accept "
437 "%s", text);
438 return LOGIN_NEGOTIATION_FAILED;
440 } else if (strcmp(value, "CRC32C") == 0) {
441 if (conn->hdrdgst_en != ISCSI_DIGEST_NONE)
442 conn->hdrdgst_en = ISCSI_DIGEST_CRC32C;
443 else {
444 log_error("Login negotiation "
445 "failed, HeaderDigest=None is "
446 "required, can't accept %s", text);
447 return LOGIN_NEGOTIATION_FAILED;
449 } else {
450 log_error("Login negotiation failed, "
451 "can't accept %s", text);
452 return LOGIN_NEGOTIATION_FAILED;
454 text = value_end;
455 } else if (iscsi_find_key_value("DataDigest", text, end, &value,
456 &value_end)) {
457 if (strcmp(value, "None") == 0) {
458 if (conn->datadgst_en != ISCSI_DIGEST_CRC32C)
459 conn->datadgst_en = ISCSI_DIGEST_NONE;
460 else {
461 log_error("Login negotiation "
462 "failed, DataDigest=CRC32C "
463 "is required, can't accept %s", text);
464 return LOGIN_NEGOTIATION_FAILED;
466 } else if (strcmp(value, "CRC32C") == 0) {
467 if (conn->datadgst_en != ISCSI_DIGEST_NONE)
468 conn->datadgst_en = ISCSI_DIGEST_CRC32C;
469 else {
470 log_error("Login negotiation "
471 "failed, DataDigest=None is "
472 "required, can't accept %s", text);
473 return LOGIN_NEGOTIATION_FAILED;
475 } else {
476 log_error("Login negotiation failed, "
477 "can't accept %s", text);
478 return LOGIN_NEGOTIATION_FAILED;
480 text = value_end;
481 } else if (iscsi_find_key_value("DefaultTime2Wait", text, end, &value,
482 &value_end)) {
483 session->def_time2wait = strtoul(value, NULL, 0);
484 text = value_end;
485 } else if (iscsi_find_key_value("DefaultTime2Retain", text, end,
486 &value, &value_end)) {
487 session->def_time2retain = strtoul(value, NULL, 0);
488 text = value_end;
489 } else if (iscsi_find_key_value("OFMarker", text, end, &value,
490 &value_end))
491 /* result function is AND, target must honor our No */
492 text = value_end;
493 else if (iscsi_find_key_value("OFMarkInt", text, end, &value,
494 &value_end))
495 /* we don't do markers, so we don't care */
496 text = value_end;
497 else if (iscsi_find_key_value("IFMarker", text, end, &value,
498 &value_end))
499 /* result function is AND, target must honor our No */
500 text = value_end;
501 else if (iscsi_find_key_value("IFMarkInt", text, end, &value,
502 &value_end))
503 /* we don't do markers, so we don't care */
504 text = value_end;
505 else if (iscsi_find_key_value("DataPDUInOrder", text, end, &value,
506 &value_end)) {
507 if (session->type == ISCSI_SESSION_TYPE_NORMAL) {
508 if (value && strcmp(value, "Yes") == 0)
509 session->pdu_inorder_en = 1;
510 else
511 session->pdu_inorder_en = 0;
512 } else
513 session->irrelevant_keys_bitmap |=
514 IRRELEVANT_DATAPDUINORDER;
515 text = value_end;
516 } else if (iscsi_find_key_value ("DataSequenceInOrder", text, end,
517 &value, &value_end)) {
518 if (session->type == ISCSI_SESSION_TYPE_NORMAL)
519 if (value && strcmp(value, "Yes") == 0)
520 session->dataseq_inorder_en = 1;
521 else
522 session->dataseq_inorder_en = 0;
523 else
524 session->irrelevant_keys_bitmap |=
525 IRRELEVANT_DATASEQUENCEINORDER;
526 text = value_end;
527 } else if (iscsi_find_key_value("MaxOutstandingR2T", text, end, &value,
528 &value_end)) {
529 if (session->type == ISCSI_SESSION_TYPE_NORMAL) {
530 if (strcmp(value, "1")) {
531 log_error("Login negotiation "
532 "failed, can't accept Max"
533 "OutstandingR2T %s", value);
534 return LOGIN_NEGOTIATION_FAILED;
536 } else
537 session->irrelevant_keys_bitmap |=
538 IRRELEVANT_MAXOUTSTANDINGR2T;
539 text = value_end;
540 } else if (iscsi_find_key_value("MaxConnections", text, end, &value,
541 &value_end)) {
542 if (session->type == ISCSI_SESSION_TYPE_NORMAL) {
543 if (strcmp(value, "1")) {
544 log_error("Login negotiation "
545 "failed, can't accept Max"
546 "Connections %s", value);
547 return LOGIN_NEGOTIATION_FAILED;
549 } else
550 session->irrelevant_keys_bitmap |=
551 IRRELEVANT_MAXCONNECTIONS;
552 text = value_end;
553 } else if (iscsi_find_key_value("ErrorRecoveryLevel", text, end,
554 &value, &value_end)) {
555 if (strcmp(value, "0")) {
556 log_error("Login negotiation failed, "
557 "can't accept ErrorRecovery %s", value);
558 return LOGIN_NEGOTIATION_FAILED;
560 text = value_end;
561 } else if (iscsi_find_key_value("RDMAExtensions", text, end,
562 &value, &value_end)) {
563 if (session->t->template->rdma &&
564 strcmp(value, "Yes") != 0) {
565 log_error("Login negotiation failed, "
566 "Target must support RDMAExtensions");
567 return LOGIN_NEGOTIATION_FAILED;
569 text = value_end;
570 } else if (iscsi_find_key_value("InitiatorRecvDataSegmentLength", text,
571 end, &value, &value_end)) {
572 if (session->t->template->rdma) {
573 conn->max_recv_dlength = MIN(conn->max_recv_dlength,
574 strtoul(value, NULL, 0));
576 text = value_end;
577 } else if (iscsi_find_key_value("TargetRecvDataSegmentLength", text,
578 end, &value, &value_end)) {
579 if (session->t->template->rdma) {
580 conn->max_xmit_dlength = MIN(conn->max_xmit_dlength,
581 strtoul(value, NULL, 0));
583 text = value_end;
584 } else if (iscsi_find_key_value ("X-com.cisco.protocol", text, end,
585 &value, &value_end)) {
586 if (strcmp(value, "NotUnderstood") &&
587 strcmp(value, "Reject") &&
588 strcmp(value, "Irrelevant") &&
589 strcmp(value, "draft20")) {
590 /* if we didn't get a compatible protocol, fail */
591 log_error("Login version mismatch, "
592 "can't accept protocol %s", value);
593 return LOGIN_VERSION_MISMATCH;
595 text = value_end;
596 } else if (iscsi_find_key_value("X-com.cisco.PingTimeout", text, end,
597 &value, &value_end))
598 /* we don't really care what the target ends up using */
599 text = value_end;
600 else if (iscsi_find_key_value("X-com.cisco.sendAsyncText", text, end,
601 &value, &value_end))
602 /* we don't bother for the target response */
603 text = value_end;
604 else {
605 log_error("Login negotiation failed, couldn't "
606 "recognize text %s", text);
607 return LOGIN_NEGOTIATION_FAILED;
609 *data = text;
610 return LOGIN_OK;
613 static enum iscsi_login_status
614 check_security_stage_status(iscsi_session_t *session,
615 struct iscsi_acl *auth_client)
617 int debug_status = 0;
619 switch (acl_recv_end(auth_client, session)) {
620 case AUTH_STATUS_CONTINUE:
621 /* continue sending PDUs */
622 break;
624 case AUTH_STATUS_PASS:
625 break;
627 case AUTH_STATUS_NO_ERROR: /* treat this as an error,
628 * since we should get a
629 * different code
631 case AUTH_STATUS_ERROR:
632 case AUTH_STATUS_FAIL:
633 default:
634 if (acl_get_dbg_status(auth_client, &debug_status) !=
635 AUTH_STATUS_NO_ERROR)
636 log_error("Login authentication failed "
637 "with target %s, %s",
638 session->target_name,
639 acl_dbg_status_to_text(debug_status));
640 else
641 log_error("Login authentication failed "
642 "with target %s",
643 session->target_name);
644 return LOGIN_AUTHENTICATION_FAILED;
646 return LOGIN_OK;
650 * this assumes the text data is always NULL terminated. The caller can
651 * always arrange for that by using a slightly larger buffer than the max PDU
652 * size, and then appending a NULL to the PDU.
654 static enum iscsi_login_status
655 iscsi_process_login_response(iscsi_session_t *session, int cid,
656 struct iscsi_login_rsp *login_rsp,
657 char *data, int max_data_length)
659 int transit = login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT;
660 char *text = data;
661 char *end;
662 int pdu_current_stage, pdu_next_stage;
663 enum iscsi_login_status ret;
664 struct iscsi_acl *auth_client;
665 iscsi_conn_t *conn = &session->conn[cid];
667 auth_client = (session->auth_buffers && session->num_auth_buffers) ?
668 (struct iscsi_acl *)session->auth_buffers[0].address : NULL;
670 end = text + ntoh24(login_rsp->dlength) + 1;
671 if (end >= (data + max_data_length)) {
672 log_error("Login failed, process_login_response "
673 "buffer too small to guarantee NULL "
674 "termination");
675 return LOGIN_FAILED;
678 /* guarantee a trailing NUL */
679 *end = '\0';
681 /* if the response status was success, sanity check the response */
682 if (login_rsp->status_class == ISCSI_STATUS_CLS_SUCCESS) {
683 /* check the active version */
684 if (login_rsp->active_version != ISCSI_DRAFT20_VERSION) {
685 log_error("Login version mismatch, "
686 "received incompatible active iSCSI "
687 "version 0x%02x, expected version "
688 "0x%02x",
689 login_rsp->active_version,
690 ISCSI_DRAFT20_VERSION);
691 return LOGIN_VERSION_MISMATCH;
694 /* make sure the current stage matches */
695 pdu_current_stage = (login_rsp->flags &
696 ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
697 if (pdu_current_stage != conn->current_stage) {
698 log_error("Received invalid login PDU, "
699 "current stage mismatch, session %d, "
700 "response %d", conn->current_stage,
701 pdu_current_stage);
702 return LOGIN_INVALID_PDU;
706 * make sure that we're actually advancing if the T-bit is set
708 pdu_next_stage = login_rsp->flags &
709 ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
710 if (transit && (pdu_next_stage <= conn->current_stage))
711 return LOGIN_INVALID_PDU;
714 if (conn->current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {
715 if (acl_recv_begin(auth_client) != AUTH_STATUS_NO_ERROR) {
716 log_error("Login failed because "
717 "acl_recv_begin failed");
718 return LOGIN_FAILED;
721 if (acl_recv_transit_bit(auth_client, transit) !=
722 AUTH_STATUS_NO_ERROR) {
723 log_error("Login failed because "
724 "acl_recv_transit_bit failed");
725 return LOGIN_FAILED;
729 /* scan the text data */
730 while (text && (text < end)) {
731 /* skip any NULs separating each text key=value pair */
732 while ((text < end) && (*text == '\0'))
733 text++;
734 if (text >= end)
735 break;
737 /* handle keys appropriate for each stage */
738 switch (conn->current_stage) {
739 case ISCSI_SECURITY_NEGOTIATION_STAGE:{
740 ret = get_security_text_keys(session, cid,
741 &text, auth_client, end);
742 if (ret != LOGIN_OK)
743 return ret;
744 break;
746 case ISCSI_OP_PARMS_NEGOTIATION_STAGE:{
747 ret = get_op_params_text_keys(session, cid,
748 &text, end);
749 if (ret != LOGIN_OK)
750 return ret;
751 break;
753 default:
754 return LOGIN_FAILED;
758 if (conn->current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {
759 ret = check_security_stage_status(session, auth_client);
760 if (ret != LOGIN_OK)
761 return ret;
763 /* record some of the PDU fields for later use */
764 session->tsih = ntohs(login_rsp->tsih);
765 session->exp_cmdsn = ntohl(login_rsp->exp_cmdsn);
766 session->max_cmdsn = ntohl(login_rsp->max_cmdsn);
767 if (login_rsp->status_class == ISCSI_STATUS_CLS_SUCCESS)
768 conn->exp_statsn = ntohl(login_rsp->statsn) + 1;
770 if (transit) {
771 /* advance to the next stage */
772 conn->partial_response = 0;
773 conn->current_stage = login_rsp->flags &
774 ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
775 session->irrelevant_keys_bitmap = 0;
776 } else
778 * we got a partial response, don't advance,
779 * more negotiation to do
781 conn->partial_response = 1;
783 return LOGIN_OK; /* this PDU is ok, though the login process
784 * may not be done yet
788 static int
789 add_params_normal_session(iscsi_session_t *session, struct iscsi_hdr *pdu,
790 char *data, int max_data_length)
792 char value[AUTH_STR_MAX_LEN];
794 /* these are only relevant for normal sessions */
795 if (!iscsi_add_text(pdu, data, max_data_length, "InitialR2T",
796 session->initial_r2t_en ? "Yes" : "No"))
797 return 0;
799 if (!iscsi_add_text(pdu, data, max_data_length,
800 "ImmediateData",
801 session->imm_data_en ? "Yes" : "No"))
802 return 0;
804 sprintf(value, "%d", session->max_burst);
805 if (!iscsi_add_text(pdu, data, max_data_length,
806 "MaxBurstLength", value))
807 return 0;
809 sprintf(value, "%d",session->first_burst);
810 if (!iscsi_add_text(pdu, data, max_data_length,
811 "FirstBurstLength", value))
812 return 0;
814 /* these we must have */
815 if (!iscsi_add_text(pdu, data, max_data_length,
816 "MaxOutstandingR2T", "1"))
817 return 0;
818 if (!iscsi_add_text(pdu, data, max_data_length,
819 "MaxConnections", "1"))
820 return 0;
821 if (!iscsi_add_text(pdu, data, max_data_length,
822 "DataPDUInOrder", "Yes"))
823 return 0;
824 if (!iscsi_add_text(pdu, data, max_data_length,
825 "DataSequenceInOrder", "Yes"))
826 return 0;
827 return 1;
830 static int
831 add_params_transport_specific(iscsi_session_t *session, int cid,
832 struct iscsi_hdr *pdu, char *data,
833 int max_data_length)
835 char value[AUTH_STR_MAX_LEN];
836 iscsi_conn_t *conn = &session->conn[cid];
838 if (session->type == ISCSI_SESSION_TYPE_DISCOVERY ||
839 !session->t->template->rdma) {
840 sprintf(value, "%d", conn->max_recv_dlength);
841 if (!iscsi_add_text(pdu, data, max_data_length,
842 "MaxRecvDataSegmentLength", value))
843 return 0;
844 } else {
845 sprintf(value, "%d", conn->max_recv_dlength);
846 if (!iscsi_add_text(pdu, data, max_data_length,
847 "InitiatorRecvDataSegmentLength",
848 value))
849 return 0;
851 sprintf(value, "%d", conn->max_xmit_dlength);
852 if (!iscsi_add_text(pdu, data, max_data_length,
853 "TargetRecvDataSegmentLength",
854 value))
855 return 0;
857 if (!iscsi_add_text(pdu, data, max_data_length,
858 "RDMAExtensions", "Yes"))
859 return 0;
861 return 1;
864 static int
865 check_irrelevant_keys(iscsi_session_t *session, struct iscsi_hdr *pdu,
866 char *data, int max_data_length)
868 /* If you receive irrelevant keys, just check them from the irrelevant
869 * keys bitmap and respond with the key=Irrelevant text
872 if (session->irrelevant_keys_bitmap & IRRELEVANT_MAXCONNECTIONS)
873 if (!iscsi_add_text(pdu, data, max_data_length,
874 "MaxConnections", "Irrelevant"))
875 return 0;
877 if (session->irrelevant_keys_bitmap & IRRELEVANT_INITIALR2T)
878 if (!iscsi_add_text(pdu, data, max_data_length,
879 "InitialR2T", "Irrelevant"))
880 return 0;
882 if (session->irrelevant_keys_bitmap & IRRELEVANT_IMMEDIATEDATA)
883 if (!iscsi_add_text(pdu, data, max_data_length,
884 "ImmediateData", "Irrelevant"))
885 return 0;
887 if (session->irrelevant_keys_bitmap & IRRELEVANT_MAXBURSTLENGTH)
888 if (!iscsi_add_text(pdu, data, max_data_length,
889 "MaxBurstLength", "Irrelevant"))
890 return 0;
892 if (session->irrelevant_keys_bitmap & IRRELEVANT_FIRSTBURSTLENGTH)
893 if (!iscsi_add_text(pdu, data, max_data_length,
894 "FirstBurstLength", "Irrelevant"))
895 return 0;
897 if (session->irrelevant_keys_bitmap & IRRELEVANT_MAXOUTSTANDINGR2T)
898 if (!iscsi_add_text(pdu, data, max_data_length,
899 "MaxOutstandingR2T", "Irrelevant"))
900 return 0;
902 if (session->irrelevant_keys_bitmap & IRRELEVANT_DATAPDUINORDER)
903 if (!iscsi_add_text(pdu, data, max_data_length,
904 "DataPDUInOrder", "Irrelevant"))
905 return 0;
907 if (session->irrelevant_keys_bitmap & IRRELEVANT_DATASEQUENCEINORDER )
908 if (!iscsi_add_text(pdu, data, max_data_length,
909 "DataSequenceInOrder", "Irrelevant"))
910 return 0;
912 return 1;
915 static int
916 fill_crc_digest_text(iscsi_conn_t *conn, struct iscsi_hdr *pdu,
917 char *data, int max_data_length)
919 switch (conn->hdrdgst_en) {
920 case ISCSI_DIGEST_NONE:
921 if (!iscsi_add_text(pdu, data, max_data_length,
922 "HeaderDigest", "None"))
923 return 0;
924 break;
925 case ISCSI_DIGEST_CRC32C:
926 if (!iscsi_add_text(pdu, data, max_data_length,
927 "HeaderDigest", "CRC32C"))
928 return 0;
929 break;
930 case ISCSI_DIGEST_CRC32C_NONE:
931 if (!iscsi_add_text(pdu, data, max_data_length,
932 "HeaderDigest", "CRC32C,None"))
933 return 0;
934 break;
935 default:
936 case ISCSI_DIGEST_NONE_CRC32C:
937 if (!iscsi_add_text(pdu, data, max_data_length,
938 "HeaderDigest", "None,CRC32C"))
939 return 0;
940 break;
943 switch (conn->datadgst_en) {
944 case ISCSI_DIGEST_NONE:
945 if (!iscsi_add_text(pdu, data, max_data_length,
946 "DataDigest", "None"))
947 return 0;
948 break;
949 case ISCSI_DIGEST_CRC32C:
950 if (!iscsi_add_text(pdu, data, max_data_length,
951 "DataDigest", "CRC32C"))
952 return 0;
953 break;
954 case ISCSI_DIGEST_CRC32C_NONE:
955 if (!iscsi_add_text(pdu, data, max_data_length,
956 "DataDigest", "CRC32C,None"))
957 return 0;
958 break;
959 default:
960 case ISCSI_DIGEST_NONE_CRC32C:
961 if (!iscsi_add_text(pdu, data, max_data_length,
962 "DataDigest", "None,CRC32C"))
963 return 0;
964 break;
966 return 1;
969 static int
970 fill_op_params_text(iscsi_session_t *session, int cid, struct iscsi_hdr *pdu,
971 char *data, int max_data_length, int *transit)
973 char value[AUTH_STR_MAX_LEN];
974 iscsi_conn_t *conn = &session->conn[cid];
975 int rdma;
977 /* we always try to go from op params to full feature stage */
978 conn->current_stage = ISCSI_OP_PARMS_NEGOTIATION_STAGE;
979 conn->next_stage = ISCSI_FULL_FEATURE_PHASE;
980 *transit = 1;
982 rdma = (session->type == ISCSI_SESSION_TYPE_NORMAL) &&
983 session->t->template->rdma;
986 * If we haven't gotten a partial response, then either we shouldn't be
987 * here, or we just switched to this stage, and need to start offering
988 * keys.
990 if (!conn->partial_response) {
992 * request the desired settings the first time
993 * we are in this stage
995 if (!rdma &&
996 !fill_crc_digest_text(conn, pdu, data, max_data_length))
997 return 0;
999 sprintf(value, "%d", session->def_time2wait);
1000 if (!iscsi_add_text(pdu, data, max_data_length,
1001 "DefaultTime2Wait", value))
1002 return 0;
1004 sprintf(value, "%d", session->def_time2retain);
1005 if (!iscsi_add_text(pdu, data, max_data_length,
1006 "DefaultTime2Retain", value))
1007 return 0;
1009 if (!iscsi_add_text(pdu, data, max_data_length,
1010 "IFMarker", "No"))
1011 return 0;
1013 if (!iscsi_add_text(pdu, data, max_data_length,
1014 "OFMarker", "No"))
1015 return 0;
1017 if (!iscsi_add_text(pdu, data, max_data_length,
1018 "ErrorRecoveryLevel", "0"))
1019 return 0;
1021 if (session->type == ISCSI_SESSION_TYPE_NORMAL) {
1022 if (!add_params_normal_session(session, pdu, data,
1023 max_data_length))
1024 return 0;
1026 if (!add_params_transport_specific(session, cid,
1027 pdu, data,
1028 max_data_length))
1029 return 0;
1030 } else {
1031 sprintf(value, "%d", conn->max_recv_dlength);
1032 if (!iscsi_add_text(pdu, data, max_data_length,
1033 "MaxRecvDataSegmentLength", value))
1034 return 0;
1036 } else {
1037 if (!check_irrelevant_keys(session, pdu, data, max_data_length))
1038 return 0;
1040 if (rdma &&
1041 !fill_crc_digest_text(conn, pdu, data, max_data_length))
1042 return 0;
1045 return 1;
1048 static void
1049 enum_auth_keys(struct iscsi_acl *auth_client, struct iscsi_hdr *pdu,
1050 char *data, int max_data_length, int keytype)
1052 int present = 0, rc;
1053 char *key = (char *)acl_get_key_name(keytype);
1054 int key_length = key ? strlen(key) : 0;
1055 int pdu_length = ntoh24(pdu->dlength);
1056 char *auth_value = data + pdu_length + key_length + 1;
1057 unsigned int max_length = max_data_length - (pdu_length
1058 + key_length + 1);
1061 * add the key/value pairs the auth code wants to send
1062 * directly to the PDU, since they could in theory be large.
1064 rc = acl_send_key_val(auth_client, keytype, &present, auth_value,
1065 max_length);
1066 if ((rc == AUTH_STATUS_NO_ERROR) && present) {
1067 /* actually fill in the key */
1068 strncpy(&data[pdu_length], key, key_length);
1069 pdu_length += key_length;
1070 data[pdu_length] = '=';
1071 pdu_length++;
1073 * adjust the PDU's data segment length
1074 * to include the value and trailing NUL
1076 pdu_length += strlen(auth_value) + 1;
1077 hton24(pdu->dlength, pdu_length);
1081 static int
1082 fill_security_params_text(iscsi_session_t *session, int cid, struct iscsi_hdr *pdu,
1083 struct iscsi_acl *auth_client, char *data,
1084 int max_data_length, int *transit)
1086 int keytype = AUTH_KEY_TYPE_NONE;
1087 int rc = acl_send_transit_bit(auth_client, transit);
1088 iscsi_conn_t *conn = &session->conn[cid];
1090 /* see if we're ready for a stage change */
1091 if (rc != AUTH_STATUS_NO_ERROR)
1092 return 0;
1094 if (*transit) {
1096 * discovery sessions can go right to full-feature phase,
1097 * unless they want to non-standard values for the few relevant
1098 * keys, or want to offer vendor-specific keys
1100 if (session->type == ISCSI_SESSION_TYPE_DISCOVERY)
1101 if ((conn->hdrdgst_en != ISCSI_DIGEST_NONE) ||
1102 (conn->datadgst_en != ISCSI_DIGEST_NONE) ||
1103 (conn->max_recv_dlength !=
1104 ISCSI_DEF_MAX_RECV_SEG_LEN))
1105 conn->next_stage =
1106 ISCSI_OP_PARMS_NEGOTIATION_STAGE;
1107 else
1108 conn->next_stage = ISCSI_FULL_FEATURE_PHASE;
1109 else
1110 conn->next_stage = ISCSI_OP_PARMS_NEGOTIATION_STAGE;
1111 } else
1112 conn->next_stage = ISCSI_SECURITY_NEGOTIATION_STAGE;
1114 /* enumerate all the keys the auth code might want to send */
1115 while (acl_get_next_key_type(&keytype) == AUTH_STATUS_NO_ERROR)
1116 enum_auth_keys(auth_client, pdu, data, max_data_length,
1117 keytype);
1119 return 1;
1123 * iscsi_make_login_pdu - Prepare the login pdu to be sent to iSCSI target.
1124 * @session: session for which login is initiated.
1125 * @pdu: login header
1126 * @data: contains text keys to be negotiated during login
1127 * @max_data_length: data size
1129 * Description:
1130 * Based on whether authentication is enabled or not, corresponding text
1131 * keys are filled up in login pdu.
1134 static int
1135 iscsi_make_login_pdu(iscsi_session_t *session, int cid, struct iscsi_hdr *hdr,
1136 char *data, int max_data_length)
1138 int transit = 0;
1139 int ret;
1140 struct iscsi_login *login_hdr = (struct iscsi_login *)hdr;
1141 struct iscsi_acl *auth_client;
1142 iscsi_conn_t *conn = &session->conn[cid];
1144 auth_client = (session->auth_buffers && session->num_auth_buffers) ?
1145 (struct iscsi_acl *)session->auth_buffers[0].address : NULL;
1147 /* initialize the PDU header */
1148 memset(login_hdr, 0, sizeof(*login_hdr));
1149 login_hdr->opcode = ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE;
1150 login_hdr->cid = 0;
1151 memcpy(login_hdr->isid, session->isid, sizeof(session->isid));
1152 login_hdr->tsih = 0;
1153 login_hdr->cmdsn = htonl(session->cmdsn);
1154 /* don't increment on immediate */
1155 login_hdr->min_version = ISCSI_DRAFT20_VERSION;
1156 login_hdr->max_version = ISCSI_DRAFT20_VERSION;
1157 login_hdr->exp_statsn = htonl(conn->exp_statsn);
1160 * the very first Login PDU has some additional requirements,
1161 * and we need to decide what stage to start in.
1163 if (conn->current_stage == ISCSI_INITIAL_LOGIN_STAGE) {
1164 if (session->initiator_name && session->initiator_name[0]) {
1165 if (!iscsi_add_text(hdr, data, max_data_length,
1166 "InitiatorName", session->initiator_name))
1167 return 0;
1168 } else {
1169 log_error("InitiatorName is required "
1170 "on the first Login PDU");
1171 return 0;
1173 if (session->initiator_alias && session->initiator_alias[0]) {
1174 if (!iscsi_add_text(hdr, data, max_data_length,
1175 "InitiatorAlias", session->initiator_alias))
1176 return 0;
1179 if ((session->target_name && session->target_name[0]) &&
1180 (session->type == ISCSI_SESSION_TYPE_NORMAL)) {
1181 if (!iscsi_add_text(hdr, data, max_data_length,
1182 "TargetName", session->target_name))
1183 return 0;
1186 if (!iscsi_add_text(hdr, data, max_data_length,
1187 "SessionType", (session->type ==
1188 ISCSI_SESSION_TYPE_DISCOVERY) ? "Discovery" : "Normal"))
1189 return 0;
1191 if (auth_client)
1192 /* we're prepared to do authentication */
1193 conn->current_stage = conn->next_stage =
1194 ISCSI_SECURITY_NEGOTIATION_STAGE;
1195 else
1196 /* can't do any authentication, skip that stage */
1197 conn->current_stage = conn->next_stage =
1198 ISCSI_OP_PARMS_NEGOTIATION_STAGE;
1201 /* fill in text based on the stage */
1202 switch (conn->current_stage) {
1203 case ISCSI_OP_PARMS_NEGOTIATION_STAGE:{
1204 ret = fill_op_params_text(session, cid, hdr, data,
1205 max_data_length, &transit);
1206 if (!ret)
1207 return ret;
1208 break;
1210 case ISCSI_SECURITY_NEGOTIATION_STAGE:{
1211 ret = fill_security_params_text(session, cid, hdr,
1212 auth_client, data, max_data_length,
1213 &transit);
1214 if (!ret)
1215 return ret;
1216 break;
1218 case ISCSI_FULL_FEATURE_PHASE:
1219 log_error("Can't send login PDUs in full "
1220 "feature phase");
1221 return 0;
1222 default:
1223 log_error("Can't send login PDUs in unknown "
1224 "stage %d", conn->current_stage);
1225 return 0;
1228 /* fill in the flags */
1229 login_hdr->flags = 0;
1230 login_hdr->flags |= conn->current_stage << 2;
1231 if (transit) {
1232 /* transit to the next stage */
1233 login_hdr->flags |= conn->next_stage;
1234 login_hdr->flags |= ISCSI_FLAG_LOGIN_TRANSIT;
1235 } else
1236 /* next == current */
1237 login_hdr->flags |= conn->current_stage;
1239 return 1;
1242 static enum iscsi_login_status
1243 check_for_authentication(iscsi_session_t *session,
1244 struct iscsi_acl *auth_client)
1246 enum iscsi_login_status ret = LOGIN_FAILED;
1248 auth_client = (struct iscsi_acl *)session->auth_buffers[0].address;
1250 /* prepare for authentication */
1251 if (acl_init(TYPE_INITIATOR, session->num_auth_buffers,
1252 session->auth_buffers) != AUTH_STATUS_NO_ERROR) {
1253 log_error("Couldn't initialize authentication");
1254 return LOGIN_FAILED;
1257 if (session->username &&
1258 (acl_set_user_name(auth_client, session->username) !=
1259 AUTH_STATUS_NO_ERROR)) {
1260 log_error("Couldn't set username");
1261 goto end;
1264 if (session->password && (acl_set_passwd(auth_client,
1265 session->password, session->password_length) !=
1266 AUTH_STATUS_NO_ERROR)) {
1267 log_error("Couldn't set password");
1268 goto end;
1271 if (acl_set_ip_sec(auth_client, 1) != AUTH_STATUS_NO_ERROR) {
1272 log_error("Couldn't set IPSec");
1273 goto end;
1276 if (acl_set_auth_rmt(auth_client, session->bidirectional_auth) !=
1277 AUTH_STATUS_NO_ERROR) {
1278 log_error("Couldn't set remote authentication");
1279 goto end;
1281 return LOGIN_OK;
1283 end:
1284 if (auth_client && acl_finish(auth_client) != AUTH_STATUS_NO_ERROR) {
1285 log_error("Login failed, error finishing auth_client");
1286 if (ret == LOGIN_OK)
1287 ret = LOGIN_FAILED;
1289 return ret;
1292 static enum iscsi_login_status
1293 check_status_login_response(iscsi_session_t *session, int cid,
1294 struct iscsi_login_rsp *login_rsp,
1295 char *data, int max_data_length, int *final)
1297 enum iscsi_login_status ret;
1299 switch (login_rsp->status_class) {
1300 case ISCSI_STATUS_CLS_SUCCESS:
1301 /* process this response and possibly continue sending PDUs */
1302 ret = iscsi_process_login_response(session, cid, login_rsp,
1303 data, max_data_length);
1304 if (ret != LOGIN_OK) /* pass back whatever
1305 * error we discovered
1307 *final = 1;
1308 break;
1309 case ISCSI_STATUS_CLS_REDIRECT:
1311 * we need to process this response to get the
1312 * TargetAddress of the redirect, but we don't care
1313 * about the return code.
1315 iscsi_process_login_response(session, cid, login_rsp,
1316 data, max_data_length);
1317 ret = LOGIN_REDIRECT;
1318 *final = 1;
1319 break;
1320 case ISCSI_STATUS_CLS_INITIATOR_ERR:
1321 if (login_rsp->status_detail ==
1322 ISCSI_LOGIN_STATUS_AUTH_FAILED) {
1323 log_error("Login failed to authenticate "
1324 "with target %s", session->target_name);
1326 ret = LOGIN_OK;
1327 *final = 1;
1328 break;
1329 default:
1331 * some sort of error, login terminated unsuccessfully,
1332 * though this function did it's job.
1333 * the caller must check the status_class and
1334 * status_detail and decide what to do next.
1336 ret = LOGIN_OK;
1337 *final = 1;
1339 return ret;
1343 iscsi_login_begin(iscsi_session_t *session, iscsi_login_context_t *c)
1345 iscsi_conn_t *conn = &session->conn[c->cid];
1347 c->auth_client = NULL;
1348 c->login_rsp = (struct iscsi_login_rsp *)&c->pdu;
1349 c->received_pdu = 0;
1350 c->timeout = 0;
1351 c->final = 0;
1352 c->ret = LOGIN_FAILED;
1354 /* prepare the session of the connection is leading */
1355 if (c->cid ==0) {
1356 session->cmdsn = 1;
1357 session->exp_cmdsn = 1;
1358 session->max_cmdsn = 1;
1361 conn->current_stage = ISCSI_INITIAL_LOGIN_STAGE;
1362 conn->partial_response = 0;
1364 if (session->auth_buffers && session->num_auth_buffers) {
1365 c->ret = check_for_authentication(session, c->auth_client);
1366 if (c->ret != LOGIN_OK)
1367 return 1;
1370 return 0;
1374 iscsi_login_req(iscsi_session_t *session, iscsi_login_context_t *c)
1376 iscsi_conn_t *conn = &session->conn[c->cid];
1378 c->final = 0;
1379 c->timeout = 0;
1380 c->login_rsp = (struct iscsi_login_rsp *)&c->pdu;
1381 c->ret = LOGIN_FAILED;
1383 memset(c->buffer, 0, c->bufsize);
1384 c->data = c->buffer;
1385 c->max_data_length = c->bufsize;
1388 * pick the appropriate timeout. If we know the target has
1389 * responded before, and we're in the security stage, we use a
1390 * longer timeout, since the authentication alogorithms can
1391 * take a while, especially if the target has to go talk to a
1392 * tacacs or RADIUS server (which may or may not be
1393 * responding).
1395 if (c->received_pdu && (conn->current_stage ==
1396 ISCSI_SECURITY_NEGOTIATION_STAGE))
1397 c->timeout = conn->auth_timeout;
1398 else
1399 c->timeout = conn->login_timeout;
1402 * fill in the PDU header and text data based on the login
1403 * stage that we're in
1405 if (!iscsi_make_login_pdu(session, c->cid, &c->pdu, c->data,
1406 c->max_data_length)) {
1407 log_error("login failed, couldn't make a login PDU");
1408 c->ret = LOGIN_FAILED;
1409 goto done;
1412 /* send a PDU to the target */
1413 if (!iscsi_io_send_pdu(conn, &c->pdu, ISCSI_DIGEST_NONE,
1414 c->data, ISCSI_DIGEST_NONE, c->timeout)) {
1416 * FIXME: caller might want us to distinguish I/O
1417 * error and timeout. Might want to switch portals on
1418 * timeouts, but not I/O errors.
1420 log_error("Login I/O error, failed to send a PDU");
1421 c->ret = LOGIN_IO_ERROR;
1422 goto done;
1424 return 0;
1426 done:
1427 if (c->auth_client && acl_finish(c->auth_client) !=
1428 AUTH_STATUS_NO_ERROR) {
1429 log_error("Login failed, error finishing c->auth_client");
1430 if (c->ret == LOGIN_OK)
1431 c->ret = LOGIN_FAILED;
1433 return 1;
1437 iscsi_login_rsp(iscsi_session_t *session, iscsi_login_context_t *c)
1439 iscsi_conn_t *conn = &session->conn[c->cid];
1440 int err;
1442 /* read the target's response into the same buffer */
1443 err = iscsi_io_recv_pdu(conn, &c->pdu, ISCSI_DIGEST_NONE, c->data,
1444 c->max_data_length, ISCSI_DIGEST_NONE,
1445 c->timeout);
1446 if (err == -EAGAIN) {
1447 goto done;
1448 } else if (err < 0) {
1450 * FIXME: caller might want us to distinguish I/O
1451 * error and timeout. Might want to switch portals on
1452 * timeouts, but not I/O errors.
1454 log_error("Login I/O error, failed to receive a PDU");
1455 c->ret = LOGIN_IO_ERROR;
1456 goto done;
1459 err = -EIO;
1460 c->received_pdu = 1;
1462 /* check the PDU response type */
1463 if (c->pdu.opcode == (ISCSI_OP_LOGIN_RSP | 0xC0)) {
1465 * it's probably a draft 8 login response,
1466 * which we can't deal with
1468 log_error("Received iSCSI draft 8 login "
1469 "response opcode 0x%x, expected draft "
1470 "20 login response 0x%2x",
1471 c->pdu.opcode, ISCSI_OP_LOGIN_RSP);
1472 c->ret = LOGIN_VERSION_MISMATCH;
1473 goto done;
1474 } else if (c->pdu.opcode != ISCSI_OP_LOGIN_RSP) {
1475 c->ret = LOGIN_INVALID_PDU;
1476 goto done;
1480 * give the caller the status class and detail from the last
1481 * login response PDU received
1483 c->status_class = c->login_rsp->status_class;
1484 c->status_detail = c->login_rsp->status_detail;
1485 log_debug(1, "login response status %02d%02d",
1486 c->status_class, c->status_detail);
1487 c->ret = check_status_login_response(session, c->cid,
1488 c->login_rsp, c->data, c->max_data_length,
1489 &c->final);
1490 if (c->final)
1491 goto done;
1492 return 0;
1494 done:
1495 if (c->auth_client && acl_finish(c->auth_client) !=
1496 AUTH_STATUS_NO_ERROR) {
1497 log_error("Login failed, error finishing c->auth_client");
1498 if (c->ret == LOGIN_OK)
1499 c->ret = LOGIN_FAILED;
1501 return err;
1505 * iscsi_login - attempt to login to the target.
1506 * @session: login is initiated over this session
1507 * @buffer: holds login pdu
1508 * @bufsize: size of login pdu
1509 * @status_class: holds either success or failure as status of login
1510 * @status_detail: contains details based on the login status
1512 * Description:
1513 * The caller must check the status class to determine if the login
1514 * succeeded. A return of 1 does not mean the login succeeded, it just
1515 * means this function worked, and the status class is valid info.
1516 * This allows the caller to decide whether or not to retry logins, so
1517 * that we don't have any policy logic here.
1519 enum iscsi_login_status
1520 iscsi_login(iscsi_session_t *session, int cid, char *buffer, size_t bufsize,
1521 uint8_t *status_class, uint8_t *status_detail)
1523 iscsi_conn_t *conn = &session->conn[cid];
1524 iscsi_login_context_t *c = &conn->login_context;
1525 struct timeval connection_timer;
1526 struct pollfd pfd;
1527 int ret, timeout;
1530 * assume iscsi_login is only called from discovery, so it is
1531 * safe to always set to zero
1533 conn->exp_statsn = 0;
1535 c->cid = cid;
1536 c->buffer = buffer;
1537 c->bufsize = bufsize;
1539 if (iscsi_login_begin(session, c))
1540 return c->ret;
1542 do {
1543 if (iscsi_login_req(session, c))
1544 return c->ret;
1547 * TODO: merge the poll and req/rsp code with the discovery
1548 * poll and text req/rsp.
1550 iscsi_timer_set(&connection_timer,
1551 session->conn[0].active_timeout);
1552 timeout = iscsi_timer_msecs_until(&connection_timer);
1554 memset(&pfd, 0, sizeof (pfd));
1555 pfd.fd = conn->socket_fd;
1556 pfd.events = POLLIN | POLLPRI;
1558 repoll:
1559 pfd.revents = 0;
1560 ret = poll(&pfd, 1, timeout);
1561 log_debug(7, "%s: Poll return %d\n", __FUNCTION__, ret);
1562 if (iscsi_timer_expired(&connection_timer)) {
1563 log_warning("Login response timeout. Waited %d "
1564 "seconds and did not get reponse PDU.\n",
1565 session->conn[0].active_timeout);
1566 c->ret = LOGIN_FAILED;
1567 return c->ret;
1570 if (ret > 0) {
1571 if (pfd.revents & (POLLIN | POLLPRI)) {
1572 ret = iscsi_login_rsp(session, c);
1573 if (ret == -EAGAIN)
1574 goto repoll;
1576 if (status_class)
1577 *status_class = c->status_class;
1578 if (status_detail)
1579 *status_detail = c->status_detail;
1581 if (ret)
1582 return c->ret;
1583 } else if (pfd.revents & POLLHUP) {
1584 log_warning("Login POLLHUP");
1585 c->ret = LOGIN_FAILED;
1586 return c->ret;
1587 } else if (pfd.revents & POLLNVAL) {
1588 log_warning("Login POLLNVAL");
1589 c->ret = LOGIN_IO_ERROR;
1590 return c->ret;
1591 } else if (pfd.revents & POLLERR) {
1592 log_warning("Login POLLERR");
1593 c->ret = LOGIN_IO_ERROR;
1594 return c->ret;
1597 } else if (ret < 0) {
1598 log_error("Login poll error.\n");
1599 c->ret = LOGIN_FAILED;
1600 return c->ret;
1602 } while (conn->current_stage != ISCSI_FULL_FEATURE_PHASE);
1604 c->ret = LOGIN_OK;
1605 if (c->auth_client && acl_finish(c->auth_client) !=
1606 AUTH_STATUS_NO_ERROR) {
1607 log_error("Login failed, error finishing c->auth_client");
1608 if (c->ret == LOGIN_OK)
1609 c->ret = LOGIN_FAILED;
1612 return c->ret;