2 * Common code for setting up discovery and normal sessions.
4 * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
5 * Copyright (C) 2006 - 2009 Mike Christie
6 * Copyright (C) 2006 - 2009 Red Hat, Inc. All rights reserved.
7 * maintained by open-iscsi@googlegroups.com
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * See the file COPYING included with this distribution for more details.
27 #include "initiator.h"
28 #include "transport.h"
30 #include "iscsi_ipc.h"
32 #include "iscsi_sysfs.h"
33 #include "iscsi_settings.h"
37 #include "iscsi_err.h"
39 struct iscsi_session
*session_find_by_sid(uint32_t sid
)
41 struct iscsi_transport
*t
;
42 struct iscsi_session
*session
;
44 list_for_each_entry(t
, &transports
, list
) {
45 list_for_each_entry(session
, &t
->sessions
, list
) {
46 if (session
->id
== sid
)
54 * calculate parameter's padding
57 __padding(unsigned int param
)
64 log_debug(1, "parameter's value %d padded to %d bytes\n",
70 int iscsi_setup_authentication(struct iscsi_session
*session
,
71 struct iscsi_auth_config
*auth_cfg
)
73 /* if we have any incoming credentials, we insist on authenticating
74 * the target or not logging in at all
76 if (auth_cfg
->username_in
[0] || auth_cfg
->password_in_length
) {
77 /* sanity check the config */
78 if (auth_cfg
->password_length
== 0) {
79 log_warning("CHAP configuratoin has incoming "
80 "authentication credentials but has no "
81 "outgoing credentials configured.");
84 session
->bidirectional_auth
= 1;
86 /* no or 1-way authentication */
87 session
->bidirectional_auth
= 0;
90 /* copy in whatever credentials we have */
91 strlcpy(session
->username
, auth_cfg
->username
,
92 sizeof (session
->username
));
93 session
->username
[sizeof (session
->username
) - 1] = '\0';
94 if ((session
->password_length
= auth_cfg
->password_length
))
95 memcpy(session
->password
, auth_cfg
->password
,
96 session
->password_length
);
98 strlcpy(session
->username_in
, auth_cfg
->username_in
,
99 sizeof (session
->username_in
));
100 session
->username_in
[sizeof (session
->username_in
) - 1] = '\0';
101 if ((session
->password_in_length
=
102 auth_cfg
->password_in_length
))
103 memcpy(session
->password_in
, auth_cfg
->password_in
,
104 session
->password_in_length
);
106 if (session
->password_length
|| session
->password_in_length
) {
107 /* setup the auth buffers */
108 session
->auth_buffers
[0].address
= &session
->auth_client_block
;
109 session
->auth_buffers
[0].length
=
110 sizeof (session
->auth_client_block
);
111 session
->auth_buffers
[1].address
=
112 &session
->auth_recv_string_block
;
113 session
->auth_buffers
[1].length
=
114 sizeof (session
->auth_recv_string_block
);
116 session
->auth_buffers
[2].address
=
117 &session
->auth_send_string_block
;
118 session
->auth_buffers
[2].length
=
119 sizeof (session
->auth_send_string_block
);
121 session
->auth_buffers
[3].address
=
122 &session
->auth_recv_binary_block
;
123 session
->auth_buffers
[3].length
=
124 sizeof (session
->auth_recv_binary_block
);
126 session
->auth_buffers
[4].address
=
127 &session
->auth_send_binary_block
;
128 session
->auth_buffers
[4].length
=
129 sizeof (session
->auth_send_binary_block
);
131 session
->num_auth_buffers
= 5;
132 log_debug(6, "authentication setup complete...");
134 session
->num_auth_buffers
= 0;
135 log_debug(6, "no authentication configured...");
142 iscsi_copy_operational_params(struct iscsi_conn
*conn
,
143 struct iscsi_session_operational_config
*session_conf
,
144 struct iscsi_conn_operational_config
*conn_conf
)
146 struct iscsi_session
*session
= conn
->session
;
147 struct iscsi_transport
*t
= session
->t
;
149 conn
->hdrdgst_en
= conn_conf
->HeaderDigest
;
150 conn
->datadgst_en
= conn_conf
->DataDigest
;
152 conn
->max_recv_dlength
=
153 __padding(conn_conf
->MaxRecvDataSegmentLength
);
154 if (conn
->max_recv_dlength
< ISCSI_MIN_MAX_RECV_SEG_LEN
||
155 conn
->max_recv_dlength
> ISCSI_MAX_MAX_RECV_SEG_LEN
) {
156 log_error("Invalid iscsi.MaxRecvDataSegmentLength. Must be "
157 "within %u and %u. Setting to %u\n",
158 ISCSI_MIN_MAX_RECV_SEG_LEN
,
159 ISCSI_MAX_MAX_RECV_SEG_LEN
,
160 DEF_INI_MAX_RECV_SEG_LEN
);
161 conn_conf
->MaxRecvDataSegmentLength
=
162 DEF_INI_MAX_RECV_SEG_LEN
;
163 conn
->max_recv_dlength
= DEF_INI_MAX_RECV_SEG_LEN
;
166 /* zero indicates to use the target's value */
167 conn
->max_xmit_dlength
=
168 __padding(conn_conf
->MaxXmitDataSegmentLength
);
169 if (conn
->max_xmit_dlength
== 0)
170 conn
->max_xmit_dlength
= ISCSI_DEF_MAX_RECV_SEG_LEN
;
171 if (conn
->max_xmit_dlength
< ISCSI_MIN_MAX_RECV_SEG_LEN
||
172 conn
->max_xmit_dlength
> ISCSI_MAX_MAX_RECV_SEG_LEN
) {
173 log_error("Invalid iscsi.MaxXmitDataSegmentLength. Must be "
174 "within %u and %u. Setting to %u\n",
175 ISCSI_MIN_MAX_RECV_SEG_LEN
,
176 ISCSI_MAX_MAX_RECV_SEG_LEN
,
177 DEF_INI_MAX_RECV_SEG_LEN
);
178 conn_conf
->MaxXmitDataSegmentLength
=
179 DEF_INI_MAX_RECV_SEG_LEN
;
180 conn
->max_xmit_dlength
= DEF_INI_MAX_RECV_SEG_LEN
;
183 /* session's operational parameters */
184 session
->initial_r2t_en
= session_conf
->InitialR2T
;
185 session
->imm_data_en
= session_conf
->ImmediateData
;
186 session
->first_burst
= __padding(session_conf
->FirstBurstLength
);
188 * some targets like netapp fail the login if sent bad first_burst
189 * and max_burst lens, even when immediate data=no and
190 * initial r2t = Yes, so we always check the user values.
192 if (session
->first_burst
< ISCSI_MIN_FIRST_BURST_LEN
||
193 session
->first_burst
> ISCSI_MAX_FIRST_BURST_LEN
) {
194 log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
195 "within %u and %u. Setting to %u\n",
196 session
->first_burst
,
197 ISCSI_MIN_FIRST_BURST_LEN
,
198 ISCSI_MAX_FIRST_BURST_LEN
,
199 DEF_INI_FIRST_BURST_LEN
);
200 session_conf
->FirstBurstLength
= DEF_INI_FIRST_BURST_LEN
;
201 session
->first_burst
= DEF_INI_FIRST_BURST_LEN
;
204 session
->max_burst
= __padding(session_conf
->MaxBurstLength
);
205 if (session
->max_burst
< ISCSI_MIN_MAX_BURST_LEN
||
206 session
->max_burst
> ISCSI_MAX_MAX_BURST_LEN
) {
207 log_error("Invalid iscsi.MaxBurstLength of %u. Must be "
208 "within %u and %u. Setting to %u\n",
209 session
->max_burst
, ISCSI_MIN_MAX_BURST_LEN
,
210 ISCSI_MAX_MAX_BURST_LEN
, DEF_INI_MAX_BURST_LEN
);
211 session_conf
->MaxBurstLength
= DEF_INI_MAX_BURST_LEN
;
212 session
->max_burst
= DEF_INI_MAX_BURST_LEN
;
215 if (session
->first_burst
> session
->max_burst
) {
216 log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
217 "less than iscsi.MaxBurstLength. Setting to %u\n",
218 session
->first_burst
, session
->max_burst
);
219 session_conf
->FirstBurstLength
= session
->max_burst
;
220 session
->first_burst
= session
->max_burst
;
223 session
->def_time2wait
= session_conf
->DefaultTime2Wait
;
224 session
->def_time2retain
= session_conf
->DefaultTime2Retain
;
225 session
->erl
= session_conf
->ERL
;
227 if (session
->type
== ISCSI_SESSION_TYPE_DISCOVERY
) {
229 * Right now, we only support 8K max for kernel based
230 * sendtargets discovery, because the recv pdu buffers are
231 * limited to this size.
233 if ((t
->caps
& CAP_TEXT_NEGO
) &&
234 conn
->max_recv_dlength
> ISCSI_DEF_MAX_RECV_SEG_LEN
)
235 conn
->max_recv_dlength
= ISCSI_DEF_MAX_RECV_SEG_LEN
;
237 /* We do not support discovery sessions with digests */
238 conn
->hdrdgst_en
= ISCSI_DIGEST_NONE
;
239 conn
->datadgst_en
= ISCSI_DIGEST_NONE
;
242 if (t
->template->create_conn
)
243 t
->template->create_conn(conn
);
246 int iscsi_setup_portal(struct iscsi_conn
*conn
, char *address
, int port
)
248 char serv
[NI_MAXSERV
];
250 sprintf(serv
, "%d", port
);
251 if (resolve_address(address
, serv
, &conn
->saddr
)) {
252 log_error("cannot resolve host name %s", address
);
253 return ISCSI_ERR_TRANS
;
255 conn
->failback_saddr
= conn
->saddr
;
257 getnameinfo((struct sockaddr
*)&conn
->saddr
, sizeof(conn
->saddr
),
258 conn
->host
, sizeof(conn
->host
), NULL
, 0, NI_NUMERICHOST
);
259 log_debug(4, "resolved %s to %s", address
, conn
->host
);
263 int host_set_param(struct iscsi_transport
*t
,
264 uint32_t host_no
, int param
, char *value
,
269 rc
= ipc
->set_host_param(t
->handle
, host_no
, param
, value
, type
);
270 /* 2.6.20 and below returns EINVAL */
271 if (rc
&& rc
!= -ENOSYS
&& rc
!= -EINVAL
) {
272 log_error("can't set operational parameter %d for "
273 "host %d, retcode %d (%d)", param
, host_no
,
280 static void print_param_value(enum iscsi_param param
, void *value
, int type
)
282 log_debug(3, "set operational parameter %d to:", param
);
284 if (type
== ISCSI_STRING
)
285 log_debug(3, "%s", value
? (char *)value
: "NULL");
287 log_debug(3, "%u", *(uint32_t *)value
);
290 #define MAX_HOST_PARAMS 2
292 int iscsi_host_set_params(struct iscsi_session
*session
)
294 struct iscsi_transport
*t
= session
->t
;
300 } hosttbl
[MAX_HOST_PARAMS
] = {
302 .param
= ISCSI_HOST_PARAM_NETDEV_NAME
,
303 .value
= session
->nrec
.iface
.netdev
,
304 .type
= ISCSI_STRING
,
306 .param
= ISCSI_HOST_PARAM_HWADDRESS
,
307 .value
= session
->nrec
.iface
.hwaddress
,
308 .type
= ISCSI_STRING
,
312 for (i
= 0; i
< MAX_HOST_PARAMS
; i
++) {
313 if (host_set_param(t
, session
->hostno
,
314 hosttbl
[i
].param
, hosttbl
[i
].value
,
319 print_param_value(hosttbl
[i
].param
, hosttbl
[i
].value
,
326 #define MAX_SESSION_PARAMS 32
328 int iscsi_session_set_params(struct iscsi_conn
*conn
)
330 struct iscsi_session
*session
= conn
->session
;
331 struct iscsi_transport
*t
= session
->t
;
333 uint32_t one
= 1, zero
= 0;
339 } conntbl
[MAX_SESSION_PARAMS
] = {
341 .param
= ISCSI_PARAM_MAX_RECV_DLENGTH
,
342 .value
= &conn
->max_recv_dlength
,
346 .param
= ISCSI_PARAM_MAX_XMIT_DLENGTH
,
347 .value
= &conn
->max_xmit_dlength
,
351 .param
= ISCSI_PARAM_HDRDGST_EN
,
352 .value
= &conn
->hdrdgst_en
,
356 .param
= ISCSI_PARAM_DATADGST_EN
,
357 .value
= &conn
->datadgst_en
,
361 .param
= ISCSI_PARAM_INITIAL_R2T_EN
,
362 .value
= &session
->initial_r2t_en
,
366 .param
= ISCSI_PARAM_MAX_R2T
,
367 .value
= &one
, /* FIXME: session->max_r2t */
371 .param
= ISCSI_PARAM_IMM_DATA_EN
,
372 .value
= &session
->imm_data_en
,
376 .param
= ISCSI_PARAM_FIRST_BURST
,
377 .value
= &session
->first_burst
,
381 .param
= ISCSI_PARAM_MAX_BURST
,
382 .value
= &session
->max_burst
,
386 .param
= ISCSI_PARAM_PDU_INORDER_EN
,
387 .value
= &session
->pdu_inorder_en
,
391 .param
=ISCSI_PARAM_DATASEQ_INORDER_EN
,
392 .value
= &session
->dataseq_inorder_en
,
396 .param
= ISCSI_PARAM_ERL
,
397 .value
= &zero
, /* FIXME: session->erl */
401 .param
= ISCSI_PARAM_IFMARKER_EN
,
402 .value
= &zero
,/* FIXME: session->ifmarker_en */
406 .param
= ISCSI_PARAM_OFMARKER_EN
,
407 .value
= &zero
,/* FIXME: session->ofmarker_en */
411 .param
= ISCSI_PARAM_EXP_STATSN
,
412 .value
= &conn
->exp_statsn
,
416 .param
= ISCSI_PARAM_TARGET_NAME
,
418 .type
= ISCSI_STRING
,
419 .value
= session
->target_name
,
421 .param
= ISCSI_PARAM_TPGT
,
422 .value
= &session
->portal_group_tag
,
426 .param
= ISCSI_PARAM_PERSISTENT_ADDRESS
,
427 .value
= session
->nrec
.conn
[conn
->id
].address
,
428 .type
= ISCSI_STRING
,
431 .param
= ISCSI_PARAM_PERSISTENT_PORT
,
432 .value
= &session
->nrec
.conn
[conn
->id
].port
,
436 .param
= ISCSI_PARAM_SESS_RECOVERY_TMO
,
437 .value
= &session
->replacement_timeout
,
441 .param
= ISCSI_PARAM_USERNAME
,
442 .value
= session
->username
,
443 .type
= ISCSI_STRING
,
446 .param
= ISCSI_PARAM_USERNAME_IN
,
447 .value
= session
->username_in
,
448 .type
= ISCSI_STRING
,
451 .param
= ISCSI_PARAM_PASSWORD
,
452 .value
= session
->password
,
453 .type
= ISCSI_STRING
,
456 .param
= ISCSI_PARAM_PASSWORD_IN
,
457 .value
= session
->password_in
,
458 .type
= ISCSI_STRING
,
461 .param
= ISCSI_PARAM_FAST_ABORT
,
462 .value
= &session
->fast_abort
,
466 .param
= ISCSI_PARAM_ABORT_TMO
,
467 .value
= &session
->abort_timeout
,
471 .param
= ISCSI_PARAM_LU_RESET_TMO
,
472 .value
= &session
->lu_reset_timeout
,
476 .param
= ISCSI_PARAM_TGT_RESET_TMO
,
477 .value
= &session
->tgt_reset_timeout
,
481 .param
= ISCSI_PARAM_PING_TMO
,
482 .value
= &conn
->noop_out_timeout
,
486 .param
= ISCSI_PARAM_RECV_TMO
,
487 .value
= &conn
->noop_out_interval
,
491 .param
= ISCSI_PARAM_IFACE_NAME
,
492 .value
= session
->nrec
.iface
.name
,
493 .type
= ISCSI_STRING
,
495 .param
= ISCSI_PARAM_INITIATOR_NAME
,
496 .value
= session
->initiator_name
,
497 .type
= ISCSI_STRING
,
501 session
->param_mask
= ~0ULL;
502 if (!(t
->caps
& CAP_MULTI_R2T
))
503 session
->param_mask
&= ~ISCSI_MAX_R2T
;
504 if (!(t
->caps
& CAP_HDRDGST
))
505 session
->param_mask
&= ~ISCSI_HDRDGST_EN
;
506 if (!(t
->caps
& CAP_DATADGST
))
507 session
->param_mask
&= ~ISCSI_DATADGST_EN
;
508 if (!(t
->caps
& CAP_MARKERS
)) {
509 session
->param_mask
&= ~ISCSI_IFMARKER_EN
;
510 session
->param_mask
&= ~ISCSI_OFMARKER_EN
;
513 /* Entered full-feature phase! */
514 for (i
= 0; i
< MAX_SESSION_PARAMS
; i
++) {
515 if (conn
->id
!= 0 && !conntbl
[i
].conn_only
)
518 if (!(session
->param_mask
& (1ULL << conntbl
[i
].param
)))
521 rc
= ipc
->set_param(session
->t
->handle
, session
->id
,
522 conn
->id
, conntbl
[i
].param
, conntbl
[i
].value
,
524 if (rc
&& rc
!= -ENOSYS
) {
525 log_error("can't set operational parameter %d for "
526 "connection %d:%d, retcode %d (%d)",
527 conntbl
[i
].param
, session
->id
, conn
->id
,
533 switch (conntbl
[i
].param
) {
534 case ISCSI_PARAM_PING_TMO
:
536 * older kernels may not support nops
539 conn
->userspace_nop
= 1;
543 case ISCSI_PARAM_INITIATOR_NAME
:
544 /* use host level one instead */
545 hosttbl
[ISCSI_HOST_PARAM_INITIATOR_NAME
].set
= 1;
551 print_param_value(conntbl
[i
].param
, conntbl
[i
].value
,
558 int iscsi_host_set_net_params(struct iface_rec
*iface
,
559 struct iscsi_session
*session
)
561 struct iscsi_transport
*t
= session
->t
;
564 log_debug(3, "setting iface %s, dev %s, set ip %s, hw %s, "
566 iface
->name
, iface
->netdev
, iface
->ipaddress
,
567 iface
->hwaddress
, iface
->transport_name
);
569 if (!t
->template->set_host_ip
)
572 /* if we need to set the ip addr then set all the iface net settings */
573 if (!iface_is_bound_by_ipaddr(iface
)) {
574 log_warning("Please set the iface.ipaddress for iface %s, "
575 "then retry the login command.\n", iface
->name
);
579 rc
= host_set_param(t
, session
->hostno
,
580 ISCSI_HOST_PARAM_IPADDRESS
,
581 iface
->ipaddress
, ISCSI_STRING
);
585 if (iface_is_bound_by_netdev(iface
)) {
586 rc
= host_set_param(t
, session
->hostno
,
587 ISCSI_HOST_PARAM_NETDEV_NAME
,
588 iface
->netdev
, ISCSI_STRING
);
593 if (iface_is_bound_by_hwaddr(iface
)) {
594 rc
= host_set_param(t
, session
->hostno
,
595 ISCSI_HOST_PARAM_HWADDRESS
,
596 iface
->hwaddress
, ISCSI_STRING
);