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
32 #include <sys/param.h>
34 #include "initiator.h"
35 #include "transport.h"
37 #include "iscsi_timer.h"
39 /* caller is assumed to be well-behaved and passing NUL terminated strings */
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,
50 int pdu_length
= ntoh24(pdu
->dlength
);
52 char *end
= data
+ max_data_length
;
55 /* find the end of the current text */
60 if (text
+ length
>= end
) {
61 log_warning("Failed to add login text "
62 "'%s=%s'\n", param
, value
);
67 strncpy(text
, param
, param_len
);
71 *text
++ = ISCSI_TEXT_SEPARATOR
;
74 strncpy(text
, value
, value_len
);
80 /* update the length in the PDU header */
81 hton24(pdu
->dlength
, pdu_length
);
87 iscsi_find_key_value(char *param
, char *pdu
, char *pdu_end
, char **value_start
,
99 /* make sure they contain the same bytes */
111 if ((text
>= pdu_end
) || (*text
== '\0')
112 || (*text
!= ISCSI_TEXT_SEPARATOR
)) {
119 /* find the end of the value */
120 while ((text
< pdu_end
) && (*text
))
124 *value_start
= value
;
131 static enum iscsi_login_status
132 get_auth_key_type(struct iscsi_acl
*auth_client
, char **data
, char *end
)
136 char *value_end
= NULL
;
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
,
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
;
156 log_error("Login negotiation failed, can't accept %s in security "
158 return LOGIN_NEGOTIATION_FAILED
;
162 resolve_address(char *host
, char *port
, struct sockaddr_storage
*ss
)
164 struct addrinfo hints
, *res
;
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
));
177 memcpy(ss
, res
->ai_addr
, res
->ai_addrlen
);
185 * try to reset the session's IP address and port, based on the TargetAddress
189 iscsi_update_address(iscsi_conn_t
*conn
, char *address
)
192 char default_port
[NI_MAXSERV
];
193 iscsi_session_t
*session
= conn
->session
;
194 struct sockaddr_storage addr
;
196 if ((tag
= strrchr(address
, ','))) {
200 if ((port
= strrchr(address
, ':'))) {
206 sprintf(default_port
, "%d", ISCSI_LISTEN_PORT
);
210 if (*address
== '[') {
213 if (!(end_bracket
= strchr(address
, ']'))) {
214 log_error("Invalid IPv6 address with opening bracket, "
215 "but no closing bracket.");
222 if (resolve_address(address
, port
, &addr
)) {
223 log_error("cannot resolve host name %s", address
);
229 session
->portal_group_tag
= atoi(tag
);
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
)
239 char *value_end
= NULL
;
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
250 if (iscsi_find_key_value("TargetAlias", text
, end
, &value
,
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");
260 memcpy(session
->target_alias
, value
, size
);
261 session
->target_alias
[size
] = '\0';
263 } else if (iscsi_find_key_value("TargetAddress", text
, end
, &value
,
266 * if possible, change the session's
267 * ip_address and port to the new TargetAddress for
270 if (iscsi_update_address(&session
->conn
[cid
], value
)) {
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
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
;
298 * any key we don't recognize either
299 * goes to the auth code, or we choke
302 ret
= get_auth_key_type(auth_client
, &text
, end
);
310 static enum iscsi_login_status
311 get_op_params_text_keys(iscsi_session_t
*session
, int cid
,
312 char **data
, char *end
)
316 char *value_end
= NULL
;
318 iscsi_conn_t
*conn
= &session
->conn
[cid
];
320 if (iscsi_find_key_value("TargetAlias", text
, end
, &value
,
322 size
= value_end
- value
;
323 if (session
->target_alias
&&
324 strlen(session
->target_alias
) == size
&&
325 memcmp(session
->target_alias
, value
, size
) == 0) {
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");
337 memcpy(session
->target_alias
, value
, size
);
338 session
->target_alias
[size
] = '\0';
340 } else if (iscsi_find_key_value("TargetAddress", text
, end
, &value
,
342 if (iscsi_update_address(conn
, value
))
345 log_error("Login redirection failed, "
346 "can't handle redirection to %s",
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
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
;
369 } else if (iscsi_find_key_value("InitialR2T", text
, end
, &value
,
371 if (session
->type
== ISCSI_SESSION_TYPE_NORMAL
) {
372 if (value
&& (strcmp(value
, "Yes") == 0))
373 session
->initial_r2t_en
= 1;
375 session
->initial_r2t_en
= 0;
377 session
->irrelevant_keys_bitmap
|=
378 IRRELEVANT_INITIALR2T
;
380 } else if (iscsi_find_key_value("ImmediateData", text
, end
, &value
,
382 if (session
->type
== ISCSI_SESSION_TYPE_NORMAL
) {
383 if (value
&& (strcmp(value
, "Yes") == 0))
384 session
->imm_data_en
= 1;
386 session
->imm_data_en
= 0;
388 session
->irrelevant_keys_bitmap
|=
389 IRRELEVANT_IMMEDIATEDATA
;
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
) {
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
;
408 } else if (iscsi_find_key_value("FirstBurstLength", text
, end
, &value
,
410 if (session
->type
== ISCSI_SESSION_TYPE_NORMAL
)
411 session
->first_burst
= strtoul(value
, NULL
, 0);
413 session
->irrelevant_keys_bitmap
|=
414 IRRELEVANT_FIRSTBURSTLENGTH
;
416 } else if (iscsi_find_key_value("MaxBurstLength", text
, end
, &value
,
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);
425 session
->irrelevant_keys_bitmap
|=
426 IRRELEVANT_MAXBURSTLENGTH
;
428 } else if (iscsi_find_key_value("HeaderDigest", text
, end
, &value
,
430 if (strcmp(value
, "None") == 0) {
431 if (conn
->hdrdgst_en
!= ISCSI_DIGEST_CRC32C
)
432 conn
->hdrdgst_en
= ISCSI_DIGEST_NONE
;
434 log_error("Login negotiation "
435 "failed, HeaderDigest=CRC32C "
436 "is required, can't accept "
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
;
444 log_error("Login negotiation "
445 "failed, HeaderDigest=None is "
446 "required, can't accept %s", text
);
447 return LOGIN_NEGOTIATION_FAILED
;
450 log_error("Login negotiation failed, "
451 "can't accept %s", text
);
452 return LOGIN_NEGOTIATION_FAILED
;
455 } else if (iscsi_find_key_value("DataDigest", text
, end
, &value
,
457 if (strcmp(value
, "None") == 0) {
458 if (conn
->datadgst_en
!= ISCSI_DIGEST_CRC32C
)
459 conn
->datadgst_en
= ISCSI_DIGEST_NONE
;
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
;
470 log_error("Login negotiation "
471 "failed, DataDigest=None is "
472 "required, can't accept %s", text
);
473 return LOGIN_NEGOTIATION_FAILED
;
476 log_error("Login negotiation failed, "
477 "can't accept %s", text
);
478 return LOGIN_NEGOTIATION_FAILED
;
481 } else if (iscsi_find_key_value("DefaultTime2Wait", text
, end
, &value
,
483 session
->def_time2wait
= strtoul(value
, NULL
, 0);
485 } else if (iscsi_find_key_value("DefaultTime2Retain", text
, end
,
486 &value
, &value_end
)) {
487 session
->def_time2retain
= strtoul(value
, NULL
, 0);
489 } else if (iscsi_find_key_value("OFMarker", text
, end
, &value
,
491 /* result function is AND, target must honor our No */
493 else if (iscsi_find_key_value("OFMarkInt", text
, end
, &value
,
495 /* we don't do markers, so we don't care */
497 else if (iscsi_find_key_value("IFMarker", text
, end
, &value
,
499 /* result function is AND, target must honor our No */
501 else if (iscsi_find_key_value("IFMarkInt", text
, end
, &value
,
503 /* we don't do markers, so we don't care */
505 else if (iscsi_find_key_value("DataPDUInOrder", text
, end
, &value
,
507 if (session
->type
== ISCSI_SESSION_TYPE_NORMAL
) {
508 if (value
&& strcmp(value
, "Yes") == 0)
509 session
->pdu_inorder_en
= 1;
511 session
->pdu_inorder_en
= 0;
513 session
->irrelevant_keys_bitmap
|=
514 IRRELEVANT_DATAPDUINORDER
;
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;
522 session
->dataseq_inorder_en
= 0;
524 session
->irrelevant_keys_bitmap
|=
525 IRRELEVANT_DATASEQUENCEINORDER
;
527 } else if (iscsi_find_key_value("MaxOutstandingR2T", text
, end
, &value
,
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
;
537 session
->irrelevant_keys_bitmap
|=
538 IRRELEVANT_MAXOUTSTANDINGR2T
;
540 } else if (iscsi_find_key_value("MaxConnections", text
, end
, &value
,
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
;
550 session
->irrelevant_keys_bitmap
|=
551 IRRELEVANT_MAXCONNECTIONS
;
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
;
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
;
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));
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));
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
;
596 } else if (iscsi_find_key_value("X-com.cisco.PingTimeout", text
, end
,
598 /* we don't really care what the target ends up using */
600 else if (iscsi_find_key_value("X-com.cisco.sendAsyncText", text
, end
,
602 /* we don't bother for the target response */
605 log_error("Login negotiation failed, couldn't "
606 "recognize text %s", text
);
607 return LOGIN_NEGOTIATION_FAILED
;
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 */
624 case AUTH_STATUS_PASS
:
627 case AUTH_STATUS_NO_ERROR
: /* treat this as an error,
628 * since we should get a
631 case AUTH_STATUS_ERROR
:
632 case AUTH_STATUS_FAIL
:
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
));
641 log_error("Login authentication failed "
643 session
->target_name
);
644 return LOGIN_AUTHENTICATION_FAILED
;
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
;
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 "
678 /* guarantee a trailing NUL */
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 "
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
,
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");
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");
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'))
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
);
746 case ISCSI_OP_PARMS_NEGOTIATION_STAGE
:{
747 ret
= get_op_params_text_keys(session
, cid
,
758 if (conn
->current_stage
== ISCSI_SECURITY_NEGOTIATION_STAGE
) {
759 ret
= check_security_stage_status(session
, auth_client
);
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;
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;
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
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"))
799 if (!iscsi_add_text(pdu
, data
, max_data_length
,
801 session
->imm_data_en
? "Yes" : "No"))
804 sprintf(value
, "%d", session
->max_burst
);
805 if (!iscsi_add_text(pdu
, data
, max_data_length
,
806 "MaxBurstLength", value
))
809 sprintf(value
, "%d",session
->first_burst
);
810 if (!iscsi_add_text(pdu
, data
, max_data_length
,
811 "FirstBurstLength", value
))
814 /* these we must have */
815 if (!iscsi_add_text(pdu
, data
, max_data_length
,
816 "MaxOutstandingR2T", "1"))
818 if (!iscsi_add_text(pdu
, data
, max_data_length
,
819 "MaxConnections", "1"))
821 if (!iscsi_add_text(pdu
, data
, max_data_length
,
822 "DataPDUInOrder", "Yes"))
824 if (!iscsi_add_text(pdu
, data
, max_data_length
,
825 "DataSequenceInOrder", "Yes"))
831 add_params_transport_specific(iscsi_session_t
*session
, int cid
,
832 struct iscsi_hdr
*pdu
, char *data
,
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
))
845 sprintf(value
, "%d", conn
->max_recv_dlength
);
846 if (!iscsi_add_text(pdu
, data
, max_data_length
,
847 "InitiatorRecvDataSegmentLength",
851 sprintf(value
, "%d", conn
->max_xmit_dlength
);
852 if (!iscsi_add_text(pdu
, data
, max_data_length
,
853 "TargetRecvDataSegmentLength",
857 if (!iscsi_add_text(pdu
, data
, max_data_length
,
858 "RDMAExtensions", "Yes"))
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"))
877 if (session
->irrelevant_keys_bitmap
& IRRELEVANT_INITIALR2T
)
878 if (!iscsi_add_text(pdu
, data
, max_data_length
,
879 "InitialR2T", "Irrelevant"))
882 if (session
->irrelevant_keys_bitmap
& IRRELEVANT_IMMEDIATEDATA
)
883 if (!iscsi_add_text(pdu
, data
, max_data_length
,
884 "ImmediateData", "Irrelevant"))
887 if (session
->irrelevant_keys_bitmap
& IRRELEVANT_MAXBURSTLENGTH
)
888 if (!iscsi_add_text(pdu
, data
, max_data_length
,
889 "MaxBurstLength", "Irrelevant"))
892 if (session
->irrelevant_keys_bitmap
& IRRELEVANT_FIRSTBURSTLENGTH
)
893 if (!iscsi_add_text(pdu
, data
, max_data_length
,
894 "FirstBurstLength", "Irrelevant"))
897 if (session
->irrelevant_keys_bitmap
& IRRELEVANT_MAXOUTSTANDINGR2T
)
898 if (!iscsi_add_text(pdu
, data
, max_data_length
,
899 "MaxOutstandingR2T", "Irrelevant"))
902 if (session
->irrelevant_keys_bitmap
& IRRELEVANT_DATAPDUINORDER
)
903 if (!iscsi_add_text(pdu
, data
, max_data_length
,
904 "DataPDUInOrder", "Irrelevant"))
907 if (session
->irrelevant_keys_bitmap
& IRRELEVANT_DATASEQUENCEINORDER
)
908 if (!iscsi_add_text(pdu
, data
, max_data_length
,
909 "DataSequenceInOrder", "Irrelevant"))
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"))
925 case ISCSI_DIGEST_CRC32C
:
926 if (!iscsi_add_text(pdu
, data
, max_data_length
,
927 "HeaderDigest", "CRC32C"))
930 case ISCSI_DIGEST_CRC32C_NONE
:
931 if (!iscsi_add_text(pdu
, data
, max_data_length
,
932 "HeaderDigest", "CRC32C,None"))
936 case ISCSI_DIGEST_NONE_CRC32C
:
937 if (!iscsi_add_text(pdu
, data
, max_data_length
,
938 "HeaderDigest", "None,CRC32C"))
943 switch (conn
->datadgst_en
) {
944 case ISCSI_DIGEST_NONE
:
945 if (!iscsi_add_text(pdu
, data
, max_data_length
,
946 "DataDigest", "None"))
949 case ISCSI_DIGEST_CRC32C
:
950 if (!iscsi_add_text(pdu
, data
, max_data_length
,
951 "DataDigest", "CRC32C"))
954 case ISCSI_DIGEST_CRC32C_NONE
:
955 if (!iscsi_add_text(pdu
, data
, max_data_length
,
956 "DataDigest", "CRC32C,None"))
960 case ISCSI_DIGEST_NONE_CRC32C
:
961 if (!iscsi_add_text(pdu
, data
, max_data_length
,
962 "DataDigest", "None,CRC32C"))
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
];
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
;
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
990 if (!conn
->partial_response
) {
992 * request the desired settings the first time
993 * we are in this stage
996 !fill_crc_digest_text(conn
, pdu
, data
, max_data_length
))
999 sprintf(value
, "%d", session
->def_time2wait
);
1000 if (!iscsi_add_text(pdu
, data
, max_data_length
,
1001 "DefaultTime2Wait", value
))
1004 sprintf(value
, "%d", session
->def_time2retain
);
1005 if (!iscsi_add_text(pdu
, data
, max_data_length
,
1006 "DefaultTime2Retain", value
))
1009 if (!iscsi_add_text(pdu
, data
, max_data_length
,
1013 if (!iscsi_add_text(pdu
, data
, max_data_length
,
1017 if (!iscsi_add_text(pdu
, data
, max_data_length
,
1018 "ErrorRecoveryLevel", "0"))
1021 if (session
->type
== ISCSI_SESSION_TYPE_NORMAL
) {
1022 if (!add_params_normal_session(session
, pdu
, data
,
1026 if (!add_params_transport_specific(session
, cid
,
1031 sprintf(value
, "%d", conn
->max_recv_dlength
);
1032 if (!iscsi_add_text(pdu
, data
, max_data_length
,
1033 "MaxRecvDataSegmentLength", value
))
1037 if (!check_irrelevant_keys(session
, pdu
, data
, max_data_length
))
1041 !fill_crc_digest_text(conn
, pdu
, data
, max_data_length
))
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
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
,
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
] = '=';
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
);
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
)
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
))
1106 ISCSI_OP_PARMS_NEGOTIATION_STAGE
;
1108 conn
->next_stage
= ISCSI_FULL_FEATURE_PHASE
;
1110 conn
->next_stage
= ISCSI_OP_PARMS_NEGOTIATION_STAGE
;
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
,
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
1130 * Based on whether authentication is enabled or not, corresponding text
1131 * keys are filled up in login pdu.
1135 iscsi_make_login_pdu(iscsi_session_t
*session
, int cid
, struct iscsi_hdr
*hdr
,
1136 char *data
, int max_data_length
)
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
;
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
))
1169 log_error("InitiatorName is required "
1170 "on the first Login PDU");
1173 if (session
->initiator_alias
&& session
->initiator_alias
[0]) {
1174 if (!iscsi_add_text(hdr
, data
, max_data_length
,
1175 "InitiatorAlias", session
->initiator_alias
))
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
))
1186 if (!iscsi_add_text(hdr
, data
, max_data_length
,
1187 "SessionType", (session
->type
==
1188 ISCSI_SESSION_TYPE_DISCOVERY
) ? "Discovery" : "Normal"))
1192 /* we're prepared to do authentication */
1193 conn
->current_stage
= conn
->next_stage
=
1194 ISCSI_SECURITY_NEGOTIATION_STAGE
;
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
);
1210 case ISCSI_SECURITY_NEGOTIATION_STAGE
:{
1211 ret
= fill_security_params_text(session
, cid
, hdr
,
1212 auth_client
, data
, max_data_length
,
1218 case ISCSI_FULL_FEATURE_PHASE
:
1219 log_error("Can't send login PDUs in full "
1223 log_error("Can't send login PDUs in unknown "
1224 "stage %d", conn
->current_stage
);
1228 /* fill in the flags */
1229 login_hdr
->flags
= 0;
1230 login_hdr
->flags
|= conn
->current_stage
<< 2;
1232 /* transit to the next stage */
1233 login_hdr
->flags
|= conn
->next_stage
;
1234 login_hdr
->flags
|= ISCSI_FLAG_LOGIN_TRANSIT
;
1236 /* next == current */
1237 login_hdr
->flags
|= conn
->current_stage
;
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");
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");
1271 if (acl_set_ip_sec(auth_client
, 1) != AUTH_STATUS_NO_ERROR
) {
1272 log_error("Couldn't set IPSec");
1276 if (acl_set_auth_rmt(auth_client
, session
->bidirectional_auth
) !=
1277 AUTH_STATUS_NO_ERROR
) {
1278 log_error("Couldn't set remote authentication");
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
)
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
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
;
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
);
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.
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;
1352 c
->ret
= LOGIN_FAILED
;
1354 /* prepare the session of the connection is leading */
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
)
1374 iscsi_login_req(iscsi_session_t
*session
, iscsi_login_context_t
*c
)
1376 iscsi_conn_t
*conn
= &session
->conn
[c
->cid
];
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
1395 if (c
->received_pdu
&& (conn
->current_stage
==
1396 ISCSI_SECURITY_NEGOTIATION_STAGE
))
1397 c
->timeout
= conn
->auth_timeout
;
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
;
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
;
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
;
1437 iscsi_login_rsp(iscsi_session_t
*session
, iscsi_login_context_t
*c
)
1439 iscsi_conn_t
*conn
= &session
->conn
[c
->cid
];
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
,
1446 if (err
== -EAGAIN
) {
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
;
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
;
1474 } else if (c
->pdu
.opcode
!= ISCSI_OP_LOGIN_RSP
) {
1475 c
->ret
= LOGIN_INVALID_PDU
;
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
,
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
;
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
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
;
1530 * assume iscsi_login is only called from discovery, so it is
1531 * safe to always set to zero
1533 conn
->exp_statsn
= 0;
1537 c
->bufsize
= bufsize
;
1539 if (iscsi_login_begin(session
, c
))
1543 if (iscsi_login_req(session
, c
))
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
;
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
;
1571 if (pfd
.revents
& (POLLIN
| POLLPRI
)) {
1572 ret
= iscsi_login_rsp(session
, c
);
1577 *status_class
= c
->status_class
;
1579 *status_detail
= c
->status_detail
;
1583 } else if (pfd
.revents
& POLLHUP
) {
1584 log_warning("Login POLLHUP");
1585 c
->ret
= LOGIN_FAILED
;
1587 } else if (pfd
.revents
& POLLNVAL
) {
1588 log_warning("Login POLLNVAL");
1589 c
->ret
= LOGIN_IO_ERROR
;
1591 } else if (pfd
.revents
& POLLERR
) {
1592 log_warning("Login POLLERR");
1593 c
->ret
= LOGIN_IO_ERROR
;
1597 } else if (ret
< 0) {
1598 log_error("Login poll error.\n");
1599 c
->ret
= LOGIN_FAILED
;
1602 } while (conn
->current_stage
!= ISCSI_FULL_FEATURE_PHASE
);
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
;