4 * Copyright (C) 2002 Cisco Systems, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * See the file COPYING included with this distribution for more details.
30 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
37 #include "iscsi_proto.h"
38 #include "initiator.h"
41 #include "iscsi_settings.h"
43 #include "fw_context.h"
44 #include "iscsid_req.h"
45 #include "iscsi_util.h"
46 /* libisns includes */
52 #include "iscsi-slp-discovery.h"
55 #define DISCOVERY_NEED_RECONNECT 0xdead0001
57 static int rediscover
= 0;
59 static char initiator_name
[TARGET_NAME_MAXLEN
+ 1];
60 static char initiator_alias
[TARGET_NAME_MAXLEN
+ 1];
62 static int request_initiator_name(void)
68 memset(initiator_name
, 0, sizeof(initiator_name
));
69 initiator_name
[0] = '\0';
70 memset(initiator_alias
, 0, sizeof(initiator_alias
));
71 initiator_alias
[0] = '\0';
73 memset(&req
, 0, sizeof(req
));
74 req
.command
= MGMT_IPC_CONFIG_INAME
;
76 rc
= iscsid_exec_req(&req
, &rsp
, 1);
80 if (rsp
.u
.config
.var
[0] != '\0')
81 strcpy(initiator_name
, rsp
.u
.config
.var
);
83 memset(&req
, 0, sizeof(req
));
84 req
.command
= MGMT_IPC_CONFIG_IALIAS
;
86 rc
= iscsid_exec_req(&req
, &rsp
, 0);
88 /* alias is optional so return ok */
91 if (rsp
.u
.config
.var
[0] != '\0')
92 strcpy(initiator_alias
, rsp
.u
.config
.var
);
96 void discovery_isns_free_servername(void)
98 if (isns_config
.ic_server_name
)
99 free(isns_config
.ic_server_name
);
100 isns_config
.ic_server_name
= NULL
;
103 int discovery_isns_set_servername(char *address
, int port
)
108 if (port
> USHRT_MAX
) {
109 log_error("Invalid port %d\n", port
);
113 /* 5 for port and 1 for colon and 1 for null */
114 len
= strlen(address
) + 7;
115 server
= calloc(1, len
);
119 snprintf(server
, len
, "%s:%d", address
, port
);
120 isns_assign_string(&isns_config
.ic_server_name
, server
);
125 int discovery_isns_query(struct discovery_rec
*drec
, const char *iname
,
126 const char *targetname
, struct list_head
*rec_list
)
128 isns_attr_list_t key_attrs
= ISNS_ATTR_LIST_INIT
;
129 isns_object_list_t objects
= ISNS_OBJECT_LIST_INIT
;
130 isns_source_t
*source
;
136 isns_config
.ic_security
= 0;
137 source
= isns_source_create_iscsi(iname
);
141 clnt
= isns_create_client(NULL
, iname
);
147 /* do not retry forever */
148 isns_socket_set_disconnect_fatal(clnt
->ic_socket
);
151 isns_attr_list_append_string(&key_attrs
, ISNS_TAG_ISCSI_NAME
,
154 /* Query for all visible targets */
155 isns_attr_list_append_uint32(&key_attrs
,
156 ISNS_TAG_ISCSI_NODE_TYPE
,
157 ISNS_ISCSI_TARGET_MASK
);
159 qry
= isns_create_query2(clnt
, &key_attrs
, source
);
165 isns_query_request_attr_tag(qry
, ISNS_TAG_ISCSI_NAME
);
166 isns_query_request_attr_tag(qry
, ISNS_TAG_ISCSI_NODE_TYPE
);
167 isns_query_request_attr_tag(qry
, ISNS_TAG_PORTAL_IP_ADDRESS
);
168 isns_query_request_attr_tag(qry
, ISNS_TAG_PORTAL_TCP_UDP_PORT
);
169 isns_query_request_attr_tag(qry
, ISNS_TAG_PG_ISCSI_NAME
);
170 isns_query_request_attr_tag(qry
, ISNS_TAG_PG_PORTAL_IP_ADDR
);
171 isns_query_request_attr_tag(qry
, ISNS_TAG_PG_PORTAL_TCP_UDP_PORT
);
172 isns_query_request_attr_tag(qry
, ISNS_TAG_PG_TAG
);
174 status
= isns_client_call(clnt
, &qry
);
178 case ISNS_SOURCE_UNKNOWN
:
179 /* server requires that we are registered but we are not */
183 log_error("iSNS discovery failed: %s", isns_strerror(status
));
188 status
= isns_query_response_get_objects(qry
, &objects
);
190 log_error("Unable to extract object list from query "
191 "response: %s\n", isns_strerror(status
));
196 for (i
= 0; i
< objects
.iol_count
; ++i
) {
197 isns_object_t
*obj
= objects
.iol_data
[i
];
198 const char *pg_tgt
= NULL
;
199 struct in6_addr in_addr
;
200 uint32_t pg_port
= ISCSI_LISTEN_PORT
;
201 uint32_t pg_tag
= PORTAL_GROUP_TAG_UNKNOWN
;
202 char pg_addr
[INET6_ADDRSTRLEN
+ 1];
203 struct node_rec
*rec
;
205 if (!isns_object_is_pg(obj
))
208 if (!isns_object_get_string(obj
, ISNS_TAG_PG_ISCSI_NAME
,
210 log_debug(1, "Missing target name");
214 if (!isns_object_get_ipaddr(obj
, ISNS_TAG_PG_PORTAL_IP_ADDR
,
216 log_debug(1, "Missing addr");
219 if (IN6_IS_ADDR_V4MAPPED(&in_addr
) ||
220 IN6_IS_ADDR_V4COMPAT(&in_addr
)) {
223 ipv4
.s_addr
= in_addr
.s6_addr32
[3];
224 inet_ntop(AF_INET
, &ipv4
, pg_addr
, sizeof(pg_addr
));
226 inet_ntop(AF_INET6
, &in_addr
, pg_addr
, sizeof(pg_addr
));
228 if (!isns_object_get_uint32(obj
,
229 ISNS_TAG_PG_PORTAL_TCP_UDP_PORT
,
231 log_debug(1, "Missing port");
235 if (!isns_object_get_uint32(obj
, ISNS_TAG_PG_TAG
, &pg_tag
)) {
236 log_debug(1, "Missing tag");
240 rec
= calloc(1, sizeof(*rec
));
246 idbm_node_setup_from_conf(rec
);
248 rec
->disc_type
= drec
->type
;
249 rec
->disc_port
= drec
->port
;
250 strcpy(rec
->disc_address
, drec
->address
);
253 strlcpy(rec
->name
, pg_tgt
, TARGET_NAME_MAXLEN
);
255 rec
->conn
[0].port
= pg_port
;
256 strlcpy(rec
->conn
[0].address
, pg_addr
, NI_MAXHOST
);
257 list_add_tail(&rec
->list
, rec_list
);
263 isns_object_list_destroy(&objects
);
265 isns_simple_free(qry
);
267 isns_client_destroy(clnt
);
269 isns_source_release(source
);
274 * discovery_isns_reg_node - register/deregister node
275 * @iname: initiator name
276 * @reg: bool indicating if we are supposed to register or deregister node.
278 * We do a very simple registration just so we can query.
280 static int discovery_isns_reg_node(const char *iname
, int op_reg
)
284 isns_source_t
*source
;
287 isns_config
.ic_security
= 0;
289 log_debug(1, "trying to %s %s with iSNS server.",
290 op_reg
? "register" : "deregister", iname
);
292 source
= isns_source_create_iscsi(iname
);
296 clnt
= isns_create_client(NULL
, iname
);
302 reg
= isns_simple_create(op_reg
? ISNS_DEVICE_ATTRIBUTE_REGISTER
:
303 ISNS_DEVICE_DEREGISTER
,
310 isns_attr_list_append_string(®
->is_operating_attrs
,
311 ISNS_TAG_ISCSI_NAME
, iname
);
313 isns_attr_list_append_uint32(®
->is_operating_attrs
,
314 ISNS_TAG_ISCSI_NODE_TYPE
,
315 ISNS_ISCSI_INITIATOR_MASK
);
316 status
= isns_client_call(clnt
, ®
);
317 if (status
!= ISNS_SUCCESS
) {
318 log_error("Could not %s %s with iSNS server: %s.",
319 reg
? "register" : "deregister", iname
,
320 isns_strerror(status
));
323 log_debug(1, "%s %s with iSNS server successful.",
324 op_reg
? "register" : "deregister", iname
);
326 isns_client_destroy(clnt
);
328 isns_source_release(source
);
332 int discovery_isns(void *data
, struct iface_rec
*iface
,
333 struct list_head
*rec_list
)
335 struct discovery_rec
*drec
= data
;
337 int rc
, registered
= 0;
339 if (iface
&& strlen(iface
->iname
))
340 iname
= iface
->iname
;
342 if (request_initiator_name() || initiator_name
[0] == '\0') {
343 log_error("Cannot perform discovery. Initiatorname "
347 iname
= initiator_name
;
350 rc
= discovery_isns_set_servername(drec
->address
, drec
->port
);
354 rc
= discovery_isns_query(drec
, iname
, NULL
, rec_list
);
355 if (!registered
&& rc
== ENOENT
) {
356 rc
= discovery_isns_reg_node(iname
, 1);
364 discovery_isns_reg_node(iname
, 0);
366 discovery_isns_free_servername();
370 int discovery_fw(void *data
, struct iface_rec
*iface
,
371 struct list_head
*rec_list
)
373 struct discovery_rec
*drec
= data
;
374 struct boot_context
*bcontext
;
375 struct list_head targets
;
376 struct node_rec
*rec
;
379 INIT_LIST_HEAD(&targets
);
380 rc
= fw_get_targets(&targets
);
382 log_error("Could not get list of targets from firmware. "
386 if (list_empty(&targets
))
389 * TODO: Do we want to match the iface MAC/netdev with what is in
390 * the firmware or could the user want to bind based on what is
391 * in passed in or in the default ifaces?
394 list_for_each_entry(bcontext
, &targets
, list
) {
395 rec
= idbm_create_rec_from_boot_context(bcontext
);
397 log_error("Could not convert firmware info to "
402 rec
->disc_type
= drec
->type
;
404 list_add_tail(&rec
->list
, rec_list
);
408 fw_free_targets(&targets
);
412 int discovery_offload_sendtargets(int host_no
, int do_login
,
413 discovery_rec_t
*drec
)
415 struct sockaddr_storage ss
;
416 char default_port
[NI_MAXSERV
];
421 log_debug(4, "offload st though host %d to %s", host_no
,
424 memset(&req
, 0, sizeof(req
));
425 req
.command
= MGMT_IPC_SEND_TARGETS
;
426 req
.u
.st
.host_no
= host_no
;
427 req
.u
.st
.do_login
= do_login
;
429 /* resolve the DiscoveryAddress to an IP address */
430 sprintf(default_port
, "%d", drec
->port
);
431 if (resolve_address(drec
->address
, default_port
, &ss
)) {
432 log_error("Cannot resolve host name %s.", drec
->address
);
438 * We only know how ask qla4xxx to do discovery and login
439 * to what it finds. We are not able to get what it finds or
440 * is able to log into so we just send the command and proceed.
442 * There is a way to just use the hw to send a sendtargets command
443 * and get back the results. We should do this since it would
444 * allows us to then process the results like software iscsi.
446 rc
= iscsid_exec_req(&req
, &rsp
, 1);
448 log_error("Could not offload sendtargets to %s.\n",
450 iscsid_handle_error(rc
);
458 iscsi_make_text_pdu(iscsi_session_t
*session
, struct iscsi_hdr
*hdr
,
459 char *data
, int max_data_length
)
461 struct iscsi_text
*text_pdu
= (struct iscsi_text
*)hdr
;
463 /* initialize the PDU header */
464 memset(text_pdu
, 0, sizeof (*text_pdu
));
466 text_pdu
->opcode
= ISCSI_OP_TEXT
;
467 text_pdu
->itt
= htonl(session
->itt
);
468 text_pdu
->ttt
= ISCSI_RESERVED_TAG
;
469 text_pdu
->cmdsn
= htonl(session
->cmdsn
++);
470 text_pdu
->exp_statsn
= htonl(session
->conn
[0].exp_statsn
);
476 request_targets(iscsi_session_t
*session
)
479 struct iscsi_text text
;
480 struct iscsi_hdr
*hdr
= (struct iscsi_hdr
*) &text
;
482 memset(&text
, 0, sizeof (text
));
483 memset(data
, 0, sizeof (data
));
485 /* make a text PDU with SendTargets=All */
486 if (!iscsi_make_text_pdu(session
, hdr
, data
, sizeof (data
))) {
487 log_error("failed to make a SendTargets PDU");
491 if (!iscsi_add_text(hdr
, data
, sizeof (data
), "SendTargets", "All")) {
492 log_error("failed to add SendTargets text key");
496 text
.ttt
= ISCSI_RESERVED_TAG
;
497 text
.flags
= ISCSI_FLAG_CMD_FINAL
;
499 if (++session
->itt
== ISCSI_RESERVED_TAG
)
502 if (!iscsi_io_send_pdu(&session
->conn
[0], hdr
, ISCSI_DIGEST_NONE
, data
,
503 ISCSI_DIGEST_NONE
, session
->conn
[0].active_timeout
)) {
504 log_error("failed to send SendTargets PDU");
512 iterate_targets(iscsi_session_t
*session
, uint32_t ttt
)
515 struct iscsi_text text
;
516 struct iscsi_hdr
*pdu
= (struct iscsi_hdr
*) &text
;
518 memset(&text
, 0, sizeof (text
));
519 memset(data
, 0, sizeof (data
));
521 /* make an empty text PDU */
522 if (!iscsi_make_text_pdu(session
, pdu
, data
, sizeof (data
))) {
523 log_error("failed to make an empty text PDU");
528 text
.flags
= ISCSI_FLAG_CMD_FINAL
;
530 if (++session
->itt
== ISCSI_RESERVED_TAG
)
533 if (!iscsi_io_send_pdu(&session
->conn
[0], pdu
, ISCSI_DIGEST_NONE
, data
,
534 ISCSI_DIGEST_NONE
, session
->conn
[0].active_timeout
)) {
535 log_error("failed to send empty text PDU");
542 static int add_portal(struct list_head
*rec_list
, discovery_rec_t
*drec
,
543 char *targetname
, char *address
, char *port
, char *tag
)
545 struct sockaddr_storage ss
;
546 char host
[NI_MAXHOST
];
547 struct node_rec
*rec
;
549 /* resolve the address, in case it was a DNS name */
550 if (resolve_address(address
, port
, &ss
)) {
551 log_error("cannot resolve %s", address
);
555 /* convert the resolved name to text */
556 getnameinfo((struct sockaddr
*) &ss
, sizeof(ss
),
557 host
, sizeof(host
), NULL
, 0, NI_NUMERICHOST
);
559 rec
= calloc(1, sizeof(*rec
));
563 idbm_node_setup_from_conf(rec
);
564 rec
->disc_type
= drec
->type
;
565 rec
->disc_port
= drec
->port
;
566 strcpy(rec
->disc_address
, drec
->address
);
568 strlcpy(rec
->name
, targetname
, TARGET_NAME_MAXLEN
);
570 rec
->tpgt
= atoi(tag
);
572 rec
->tpgt
= PORTAL_GROUP_TAG_UNKNOWN
;
574 rec
->conn
[0].port
= atoi(port
);
576 rec
->conn
[0].port
= ISCSI_LISTEN_PORT
;
577 strlcpy(rec
->conn
[0].address
, address
, NI_MAXHOST
);
579 list_add_tail(&rec
->list
, rec_list
);
584 add_target_record(char *name
, char *end
, discovery_rec_t
*drec
,
585 struct list_head
*rec_list
, char *default_port
)
594 * address = IPv4:port
595 * address = [IPv6]:port
596 * address = DNSname:port
598 * address = [IPv6],tag
599 * address = DNSname,tag
600 * address = IPv4:port,tag
601 * address = [IPv6]:port,tag
602 * address = DNSname:port,tag
605 log_debug(7, "adding target record %p, end %p", name
, end
);
607 /* find the end of the name */
608 while ((nul
< end
) && (*nul
!= '\0'))
612 if (length
> TARGET_NAME_MAXLEN
) {
613 log_error("TargetName %s too long, ignoring", name
);
616 text
= name
+ length
;
618 /* skip NULs after the name */
619 while ((text
< end
) && (*text
== '\0'))
622 /* if no address is provided, use the default */
624 if (drec
->address
== NULL
) {
625 log_error("no default address known for target %s",
628 } else if (!add_portal(rec_list
, drec
, name
, drec
->address
,
629 default_port
, NULL
)) {
630 log_error("failed to add default portal, ignoring "
634 /* finished adding the default */
638 /* process TargetAddresses */
640 char *next
= text
+ strlen(text
) + 1;
642 log_debug(7, "text %p, next %p, end %p, %s", text
, next
, end
,
645 if (strncmp(text
, "TargetAddress=", 14) == 0) {
648 char *address
= text
+ 14;
651 if ((tag
= strrchr(text
, ','))) {
655 if ((port
= strrchr(text
, ':'))) {
660 if (*address
== '[') {
662 if ((temp
= strrchr(text
, ']')))
666 if (!add_portal(rec_list
, drec
, name
, address
, port
,
668 log_error("failed to add default portal, "
669 "ignoring target %s", name
);
673 log_error("unexpected SendTargets data: %s",
682 process_sendtargets_response(struct str_buffer
*sendtargets
,
683 int final
, discovery_rec_t
*drec
,
684 struct list_head
*rec_list
,
687 char *start
= str_buffer_data(sendtargets
);
689 char *end
= text
+ str_data_length(sendtargets
);
695 /* no SendTargets data */
699 /* scan backwards to find the last NUL in the data, to ensure we
700 * don't walk off the end. Since key=value pairs can span PDU
701 * boundaries, we're not guaranteed that the end of the data has a
704 while ((nul
> start
) && *nul
)
708 /* couldn't find anything we can process now,
709 * it's one big partial string
714 /* find the boundaries between target records (TargetName or final PDU)
718 while ((text
< nul
) && (*text
== '\0'))
725 "processing sendtargets record %p, text %p, line %s",
728 /* look for the start of a new target record */
729 if (strncmp(text
, "TargetName=", 11) == 0) {
731 /* send the last record, which we just found
732 * the end of. don't bother passing the
733 * "TargetName=" prefix.
735 if (!add_target_record(record
+ 11, text
,
739 "failed to add target record");
740 str_truncate_buffer(sendtargets
, 0);
748 /* everything up til the next NUL must be part of the
749 * current target record
751 while ((text
< nul
) && (*text
!= '\0'))
757 /* if this is the last PDU of the text sequence,
758 * it also ends a target record
761 "processing final sendtargets record %p, "
764 if (add_target_record (record
+ 11, text
,
765 drec
, rec_list
, default_port
)) {
768 str_truncate_buffer(sendtargets
, 0);
770 log_error("failed to add target record");
771 str_truncate_buffer(sendtargets
, 0);
775 /* remove the parts of the sendtargets buffer we've
776 * processed, and move the parts we haven't to the
777 * beginning of the buffer.
780 "processed %d bytes of sendtargets data, "
782 (int)(record
- str_buffer_data(sendtargets
)),
783 (int)(str_buffer_data(sendtargets
) +
784 str_data_length(sendtargets
) - record
));
785 str_remove_initial(sendtargets
,
786 record
- str_buffer_data(sendtargets
));
796 clear_timer(struct timeval
*timer
)
798 memset(timer
, 0, sizeof (*timer
));
801 /* set timer to now + seconds */
803 set_timer(struct timeval
*timer
, int seconds
)
806 memset(timer
, 0, sizeof (*timer
));
807 gettimeofday(timer
, NULL
);
809 timer
->tv_sec
+= seconds
;
814 timer_expired(struct timeval
*timer
)
818 /* no timer, can't have expired */
819 if ((timer
== NULL
) || ((timer
->tv_sec
== 0) && (timer
->tv_usec
== 0)))
822 memset(&now
, 0, sizeof (now
));
823 gettimeofday(&now
, NULL
);
825 if (now
.tv_sec
> timer
->tv_sec
)
827 if ((now
.tv_sec
== timer
->tv_sec
) && (now
.tv_usec
>= timer
->tv_usec
))
833 msecs_until(struct timeval
*timer
)
839 /* no timer, can't have expired, infinite time til it expires */
840 if ((timer
== NULL
) || ((timer
->tv_sec
== 0) && (timer
->tv_usec
== 0)))
843 memset(&now
, 0, sizeof (now
));
844 gettimeofday(&now
, NULL
);
846 /* already expired? */
847 if (now
.tv_sec
> timer
->tv_sec
)
849 if ((now
.tv_sec
== timer
->tv_sec
) && (now
.tv_usec
>= timer
->tv_usec
))
852 /* not expired yet, do the math */
853 partial
= timer
->tv_usec
- now
.tv_usec
;
855 partial
+= 1000 * 1000;
856 msecs
= (partial
+ 500) / 1000;
857 msecs
+= (timer
->tv_sec
- now
.tv_sec
- 1) * 1000;
859 msecs
= (partial
+ 500) / 1000;
860 msecs
+= (timer
->tv_sec
- now
.tv_sec
) * 1000;
866 static iscsi_session_t
*
867 init_new_session(struct iscsi_sendtargets_config
*config
,
868 struct iface_rec
*iface
)
870 iscsi_session_t
*session
;
872 session
= calloc(1, sizeof (*session
));
876 /* initialize the session's leading connection */
877 session
->conn
[0].socket_fd
= -1;
878 session
->conn
[0].login_timeout
= config
->conn_timeo
.login_timeout
;
879 session
->conn
[0].auth_timeout
= config
->conn_timeo
.auth_timeout
;
880 session
->conn
[0].active_timeout
= config
->conn_timeo
.active_timeout
;
881 session
->conn
[0].hdrdgst_en
= ISCSI_DIGEST_NONE
;
882 session
->conn
[0].datadgst_en
= ISCSI_DIGEST_NONE
;
884 session
->conn
[0].max_recv_dlength
=
885 config
->iscsi
.MaxRecvDataSegmentLength
;
886 if (session
->conn
[0].max_recv_dlength
< ISCSI_MIN_MAX_RECV_SEG_LEN
||
887 session
->conn
[0].max_recv_dlength
> ISCSI_MAX_MAX_RECV_SEG_LEN
) {
888 log_error("Invalid iscsi.MaxRecvDataSegmentLength. Must be "
889 "within %u and %u. Setting to %u.",
890 ISCSI_MIN_MAX_RECV_SEG_LEN
,
891 ISCSI_MAX_MAX_RECV_SEG_LEN
,
892 DEF_INI_DISC_MAX_RECV_SEG_LEN
);
893 session
->conn
[0].max_recv_dlength
=
894 DEF_INI_DISC_MAX_RECV_SEG_LEN
;
896 session
->conn
[0].max_xmit_dlength
= ISCSI_DEF_MAX_RECV_SEG_LEN
;
898 session
->reopen_cnt
= config
->reopen_max
+ 1;
900 /* OUI and uniqifying number */
901 session
->isid
[0] = DRIVER_ISID_0
;
902 session
->isid
[1] = DRIVER_ISID_1
;
903 session
->isid
[2] = DRIVER_ISID_2
;
904 session
->isid
[3] = 0;
905 session
->isid
[4] = 0;
906 session
->isid
[5] = 0;
908 request_initiator_name();
910 if (iface
&& strlen(iface
->iname
)) {
911 strcpy(initiator_name
, iface
->iname
);
912 /* MNC TODO add iface alias */
914 if (initiator_name
[0] == '\0') {
915 log_error("Cannot perform discovery. Initiatorname "
922 session
->initiator_name
= initiator_name
;
923 session
->initiator_alias
= initiator_alias
;
924 session
->portal_group_tag
= PORTAL_GROUP_TAG_UNKNOWN
;
925 session
->type
= ISCSI_SESSION_TYPE_DISCOVERY
;
932 setup_authentication(iscsi_session_t
*session
,
933 discovery_rec_t
*drec
,
934 struct iscsi_sendtargets_config
*config
)
940 /* if we have any incoming credentials, we insist on authenticating
941 * the target or not logging in at all
943 if (config
->auth
.username_in
[0]
944 || config
->auth
.password_in_length
) {
945 session
->bidirectional_auth
= 1;
947 /* sanity check the config */
948 if (config
->auth
.password_length
== 0) {
950 "discovery process to %s:%d has incoming "
951 "authentication credentials but has no outgoing "
952 "credentials configured",
953 drec
->address
, drec
->port
);
955 "discovery process to %s:%d exiting, bad "
957 drec
->address
, drec
->port
);
962 /* no or 1-way authentication */
963 session
->bidirectional_auth
= 0;
966 /* copy in whatever credentials we have */
967 strlcpy(session
->username
, config
->auth
.username
,
968 sizeof (session
->username
));
969 session
->username
[sizeof (session
->username
) - 1] = '\0';
970 if ((session
->password_length
= config
->auth
.password_length
))
971 memcpy(session
->password
, config
->auth
.password
,
972 session
->password_length
);
974 strlcpy(session
->username_in
, config
->auth
.username_in
,
975 sizeof (session
->username_in
));
976 session
->username_in
[sizeof (session
->username_in
) - 1] = '\0';
977 if ((session
->password_in_length
=
978 config
->auth
.password_in_length
))
979 memcpy(session
->password_in
, config
->auth
.password_in
,
980 session
->password_in_length
);
982 if (session
->password_length
|| session
->password_in_length
) {
983 /* setup the auth buffers */
984 session
->auth_buffers
[0].address
= &session
->auth_client_block
;
985 session
->auth_buffers
[0].length
=
986 sizeof (session
->auth_client_block
);
987 session
->auth_buffers
[1].address
=
988 &session
->auth_recv_string_block
;
989 session
->auth_buffers
[1].length
=
990 sizeof (session
->auth_recv_string_block
);
992 session
->auth_buffers
[2].address
=
993 &session
->auth_send_string_block
;
994 session
->auth_buffers
[2].length
=
995 sizeof (session
->auth_send_string_block
);
997 session
->auth_buffers
[3].address
=
998 &session
->auth_recv_binary_block
;
999 session
->auth_buffers
[3].length
=
1000 sizeof (session
->auth_recv_binary_block
);
1002 session
->auth_buffers
[4].address
=
1003 &session
->auth_send_binary_block
;
1004 session
->auth_buffers
[4].length
=
1005 sizeof (session
->auth_send_binary_block
);
1007 session
->num_auth_buffers
= 5;
1009 session
->num_auth_buffers
= 0;
1016 process_recvd_pdu(struct iscsi_hdr
*pdu
,
1017 discovery_rec_t
*drec
,
1018 struct list_head
*rec_list
,
1019 iscsi_session_t
*session
,
1020 struct str_buffer
*sendtargets
,
1028 switch (pdu
->opcode
) {
1029 case ISCSI_OP_TEXT_RSP
:{
1030 struct iscsi_text_rsp
*text_response
=
1031 (struct iscsi_text_rsp
*) pdu
;
1032 int dlength
= ntoh24(pdu
->dlength
);
1034 (text_response
->flags
& ISCSI_FLAG_CMD_FINAL
) ||
1035 (text_response
-> ttt
== ISCSI_RESERVED_TAG
);
1036 size_t curr_data_length
;
1038 log_debug(4, "discovery session to %s:%d received text"
1039 " response, %d data bytes, ttt 0x%x, "
1044 ntohl(text_response
->ttt
),
1045 text_response
->flags
& ISCSI_FLAG_CMD_FINAL
);
1047 /* mark how much more data in the sendtargets
1048 * buffer is now valid
1050 curr_data_length
= str_data_length(sendtargets
);
1051 if (str_enlarge_data(sendtargets
, dlength
)) {
1052 log_error("Could not allocate memory to "
1053 "process SendTargets response.");
1058 memcpy(str_buffer_data(sendtargets
) + curr_data_length
,
1062 /* process as much as we can right now */
1063 process_sendtargets_response(sendtargets
,
1070 /* SendTargets exchange is now complete
1073 /* from now on, after any reconnect,
1074 * assume LUNs may have changed
1077 /* ask for more targets */
1078 if (!iterate_targets(session
,
1079 text_response
->ttt
)) {
1080 rc
= DISCOVERY_NEED_RECONNECT
;
1088 "discovery session to %s:%d received "
1089 "unexpected opcode 0x%x",
1090 drec
->address
, drec
->port
, pdu
->opcode
);
1091 rc
= DISCOVERY_NEED_RECONNECT
;
1099 * Make a best effort to logout the session, then disconnect the
1103 iscsi_logout_and_disconnect(iscsi_session_t
* session
)
1105 struct iscsi_logout logout_req
;
1106 struct iscsi_logout_rsp logout_resp
;
1110 * Build logout request header
1112 memset(&logout_req
, 0, sizeof (logout_req
));
1113 logout_req
.opcode
= ISCSI_OP_LOGOUT
| ISCSI_OP_IMMEDIATE
;
1114 logout_req
.flags
= ISCSI_FLAG_CMD_FINAL
|
1115 (ISCSI_LOGOUT_REASON_CLOSE_SESSION
&
1116 ISCSI_FLAG_LOGOUT_REASON_MASK
);
1117 logout_req
.itt
= htonl(session
->itt
);
1118 if (++session
->itt
== ISCSI_RESERVED_TAG
)
1120 logout_req
.cmdsn
= htonl(session
->cmdsn
);
1121 logout_req
.exp_statsn
= htonl(++session
->conn
[0].exp_statsn
);
1124 * Send the logout request
1126 rc
= iscsi_io_send_pdu(&session
->conn
[0],(struct iscsi_hdr
*)&logout_req
,
1127 ISCSI_DIGEST_NONE
, NULL
, ISCSI_DIGEST_NONE
, 3);
1130 "iscsid: iscsi_logout - failed to send logout PDU.");
1135 * Read the logout response
1137 memset(&logout_resp
, 0, sizeof(logout_resp
));
1138 rc
= iscsi_io_recv_pdu(&session
->conn
[0],
1139 (struct iscsi_hdr
*)&logout_resp
, ISCSI_DIGEST_NONE
, NULL
,
1140 0, ISCSI_DIGEST_NONE
, 1);
1142 log_error("iscsid: logout - failed to receive logout resp");
1145 if (logout_resp
.response
!= ISCSI_LOGOUT_SUCCESS
) {
1146 log_error("iscsid: logout failed - response = 0x%x",
1147 logout_resp
.response
);
1154 iscsi_io_disconnect(&session
->conn
[0]);
1157 int discovery_sendtargets(void *fndata
, struct iface_rec
*iface
,
1158 struct list_head
*rec_list
)
1160 discovery_rec_t
*drec
= fndata
;
1161 iscsi_session_t
*session
;
1163 struct iscsi_hdr pdu_buffer
;
1164 struct iscsi_hdr
*pdu
= &pdu_buffer
;
1166 int active
= 0, valid_text
= 0;
1167 struct timeval connection_timer
;
1170 struct str_buffer sendtargets
;
1171 uint8_t status_class
= 0, status_detail
= 0;
1172 unsigned int login_failures
= 0, data_len
;
1173 int login_delay
= 0;
1174 struct sockaddr_storage ss
;
1175 char host
[NI_MAXHOST
], serv
[NI_MAXSERV
], default_port
[NI_MAXSERV
];
1176 struct iscsi_sendtargets_config
*config
= &drec
->u
.sendtargets
;
1179 log_debug(1, "starting sendtargets discovery, address %s:%d, ",
1180 drec
->address
, drec
->port
);
1181 memset(&pdu_buffer
, 0, sizeof (pdu_buffer
));
1182 clear_timer(&connection_timer
);
1184 /* allocate a new session, and initialize default values */
1185 session
= init_new_session(config
, iface
);
1186 if (session
== NULL
) {
1187 log_error("Discovery process to %s:%d failed to "
1188 "create a discovery session.",
1189 drec
->address
, drec
->port
);
1193 log_debug(4, "sendtargets discovery to %s:%d using "
1194 "isid 0x%02x%02x%02x%02x%02x%02x",
1195 drec
->address
, drec
->port
, session
->isid
[0],
1196 session
->isid
[1], session
->isid
[2], session
->isid
[3],
1197 session
->isid
[4], session
->isid
[5]);
1199 /* allocate data buffers for SendTargets data */
1200 data
= malloc(session
->conn
[0].max_recv_dlength
);
1205 data_len
= session
->conn
[0].max_recv_dlength
;
1207 str_init_buffer(&sendtargets
, 0);
1209 sprintf(default_port
, "%d", drec
->port
);
1210 /* resolve the DiscoveryAddress to an IP address */
1211 if (resolve_address(drec
->address
, default_port
, &ss
)) {
1212 log_error("cannot resolve host name %s", drec
->address
);
1214 goto free_sendtargets
;
1217 log_debug(4, "discovery timeouts: login %d, reopen_cnt %d, auth %d.",
1218 session
->conn
[0].login_timeout
, session
->reopen_cnt
,
1219 session
->conn
[0].auth_timeout
);
1221 /* setup authentication variables for the session*/
1222 rc
= setup_authentication(session
, drec
, config
);
1225 goto free_sendtargets
;
1230 * copy the saved address to the session,
1231 * undoing any temporary redirect
1233 session
->conn
[0].saddr
= ss
;
1237 if (--session
->reopen_cnt
< 0) {
1238 log_error("connection login retries (reopen_max %d) exceeded",
1239 config
->reopen_max
);
1241 goto free_sendtargets
;
1246 iscsi_io_disconnect(&session
->conn
[0]);
1250 session
->portal_group_tag
= PORTAL_GROUP_TAG_UNKNOWN
;
1252 /* slowly back off the frequency of login attempts */
1253 if (login_failures
== 0)
1255 else if (login_failures
< 10)
1256 login_delay
= 1; /* 10 seconds at 1 sec each */
1257 else if (login_failures
< 20)
1258 login_delay
= 2; /* 20 seconds at 2 sec each */
1259 else if (login_failures
< 26)
1260 login_delay
= 5; /* 30 seconds at 5 sec each */
1261 else if (login_failures
< 34)
1262 login_delay
= 15; /* 60 seconds at 15 sec each */
1264 login_delay
= 60; /* after 2 minutes, try once a minute */
1267 log_debug(4, "discovery session to %s:%d sleeping for %d "
1268 "seconds before next login attempt",
1269 drec
->address
, drec
->port
, login_delay
);
1273 getnameinfo((struct sockaddr
*) &session
->conn
[0].saddr
,
1274 sizeof(session
->conn
[0].saddr
), host
,
1275 sizeof(host
), serv
, sizeof(serv
),
1276 NI_NUMERICHOST
|NI_NUMERICSERV
);
1278 if (!iscsi_io_connect(&session
->conn
[0])) {
1279 log_error("connection to discovery address %s "
1283 /* If a temporary redirect sent us to something unreachable,
1284 * we want to go back to the original IP address, so make sure
1285 * we reset the session's IP.
1290 log_debug(1, "connected to discovery address %s", host
);
1292 log_debug(4, "discovery session to %s:%d starting iSCSI login on fd %d",
1293 drec
->address
, drec
->port
, session
->conn
[0].socket_fd
);
1295 /* In case of discovery, we using socket's descriptor as ctrl. */
1296 session
->ctrl_fd
= session
->conn
[0].socket_fd
;
1297 session
->conn
[0].session
= session
;
1302 memset(data
, 0, data_len
);
1303 rc
= iscsi_login(session
, 0, data
, data_len
,
1304 &status_class
, &status_detail
);
1308 case LOGIN_REDIRECT
:
1311 case LOGIN_IO_ERROR
:
1312 case LOGIN_REDIRECTION_FAILED
:
1314 log_warning("retrying discovery login to %s", host
);
1315 iscsi_io_disconnect(&session
->conn
[0]);
1321 case LOGIN_NEGOTIATION_FAILED
:
1322 case LOGIN_AUTHENTICATION_FAILED
:
1323 case LOGIN_VERSION_MISMATCH
:
1324 case LOGIN_INVALID_PDU
:
1325 log_error("discovery login to %s failed, giving up", host
);
1326 iscsi_io_disconnect(&session
->conn
[0]);
1328 goto free_sendtargets
;
1331 /* check the login status */
1332 switch (status_class
) {
1333 case ISCSI_STATUS_CLS_SUCCESS
:
1334 log_debug(4, "discovery login success to %s", host
);
1337 case ISCSI_STATUS_CLS_REDIRECT
:
1338 switch (status_detail
) {
1339 /* the session IP address was changed by the login
1340 * library, so just try again with this portal
1341 * config but the new address.
1343 case ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP
:
1345 "discovery login temporarily redirected to "
1346 "%s port %s", host
, serv
);
1347 goto redirect_reconnect
;
1348 case ISCSI_LOGIN_STATUS_TGT_MOVED_PERM
:
1350 "discovery login permanently redirected to "
1351 "%s port %s", host
, serv
);
1352 /* make the new address permanent */
1353 ss
= session
->conn
[0].saddr
;
1354 goto redirect_reconnect
;
1357 "discovery login rejected: redirection type "
1358 "0x%x not supported",
1363 case ISCSI_STATUS_CLS_INITIATOR_ERR
:
1365 "discovery login to %s rejected: "
1366 "initiator error (%02x/%02x), non-retryable, giving up",
1367 host
, status_class
, status_detail
);
1368 iscsi_io_disconnect(&session
->conn
[0]);
1370 goto free_sendtargets
;
1371 case ISCSI_STATUS_CLS_TARGET_ERR
:
1373 "discovery login to %s rejected: "
1374 "target error (%02x/%02x)",
1375 host
, status_class
, status_detail
);
1376 iscsi_io_disconnect(&session
->conn
[0]);
1381 "discovery login to %s failed, response "
1382 "with unknown status class 0x%x, detail 0x%x",
1384 status_class
, status_detail
);
1385 iscsi_io_disconnect(&session
->conn
[0]);
1391 str_truncate_buffer(&sendtargets
, 0);
1393 /* ask for targets */
1394 if (!request_targets(session
)) {
1400 set_timer(&connection_timer
, session
->conn
[0].active_timeout
);
1402 /* prepare to poll */
1403 memset(&pfd
, 0, sizeof (pfd
));
1404 pfd
.fd
= session
->conn
[0].socket_fd
;
1405 pfd
.events
= POLLIN
| POLLPRI
;
1408 timeout
= msecs_until(&connection_timer
);
1409 /* block until we receive a PDU, a TCP FIN, a TCP RST,
1413 "discovery process %s:%d polling fd %d, "
1414 "timeout in %f seconds",
1415 drec
->address
, drec
->port
, pfd
.fd
,
1419 rc
= poll(&pfd
, 1, timeout
);
1422 "discovery process to %s:%d returned from poll, rc %d",
1423 drec
->address
, drec
->port
, rc
);
1425 if (timer_expired(&connection_timer
)) {
1426 log_warning("discovery session to %s:%d session "
1427 "logout, connection timer expired",
1428 drec
->address
, drec
->port
);
1429 iscsi_logout_and_disconnect(session
);
1431 goto free_sendtargets
;
1435 if (pfd
.revents
& (POLLIN
| POLLPRI
)) {
1436 timeout
= msecs_until(&connection_timer
);
1438 memset(data
, 0, data_len
);
1439 if (!iscsi_io_recv_pdu(&session
->conn
[0],
1440 pdu
, ISCSI_DIGEST_NONE
, data
,
1441 data_len
, ISCSI_DIGEST_NONE
,
1443 log_debug(1, "discovery session to "
1444 "%s:%d failed to recv a PDU "
1445 "response, terminating",
1448 iscsi_io_disconnect(&session
->conn
[0]);
1450 goto free_sendtargets
;
1454 * process iSCSI PDU received
1456 rc
= process_recvd_pdu(pdu
, drec
, rec_list
,
1457 session
, &sendtargets
,
1459 &active
, &valid_text
, data
);
1460 if (rc
== DISCOVERY_NEED_RECONNECT
)
1463 /* reset timers after receiving a PDU */
1465 set_timer(&connection_timer
,
1466 session
->conn
[0].active_timeout
);
1471 if (pfd
.revents
& POLLHUP
) {
1472 log_warning("discovery session to %s:%d "
1473 "terminating after hangup",
1474 drec
->address
, drec
->port
);
1475 iscsi_io_disconnect(&session
->conn
[0]);
1477 goto free_sendtargets
;
1480 if (pfd
.revents
& POLLNVAL
) {
1481 log_warning("discovery POLLNVAL");
1486 if (pfd
.revents
& POLLERR
) {
1487 log_warning("discovery POLLERR");
1491 } else if (rc
< 0) {
1492 if (errno
== EINTR
) {
1493 /* if we got SIGHUP, reconnect and rediscover */
1496 log_debug(1, "rediscovery requested");
1500 log_error("poll error");
1502 goto free_sendtargets
;
1506 log_debug(1, "discovery process to %s:%d exiting",
1507 drec
->address
, drec
->port
);
1511 str_free_buffer(&sendtargets
);
1520 slp_discovery(struct iscsi_slp_config
*config
)
1522 struct sigaction action
;
1524 unsigned short flag
= 0;
1526 memset(&action
, 0, sizeof (struct sigaction
));
1527 action
.sa_sigaction
= NULL
;
1528 action
.sa_flags
= 0;
1529 action
.sa_handler
= SIG_DFL
;
1530 sigaction(SIGTERM
, &action
, NULL
);
1531 sigaction(SIGINT
, &action
, NULL
);
1532 sigaction(SIGPIPE
, &action
, NULL
);
1534 action
.sa_handler
= sighup_handler
;
1535 sigaction(SIGHUP
, &action
, NULL
);
1537 if (iscsi_process_should_exit()) {
1538 log_debug(1, "slp discovery process %p exiting", discovery
);
1542 discovery
->pid
= getpid();
1544 pl
= generate_predicate_list(discovery
, &flag
);
1547 if (flag
== SLP_MULTICAST_ENABLED
) {
1548 discovery
->flag
= SLP_MULTICAST_ENABLED
;
1549 slp_multicast_srv_query(discovery
, pl
, GENERIC_QUERY
);
1552 if (flag
== SLP_UNICAST_ENABLED
) {
1553 discovery
->flag
= SLP_UNICAST_ENABLED
;
1554 slp_unicast_srv_query(discovery
, pl
, GENERIC_QUERY
);
1557 sleep(config
->poll_interval
);