iscsi tools: manage qla4xxx iscsi sessions with iscsiadm
[open-iscsi.git] / usr / initiator_common.c
blobfa8846d618c8e699748e84e163574a60c9f644fe
1 /*
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.
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <errno.h>
27 #include "initiator.h"
28 #include "transport.h"
29 #include "iscsid.h"
30 #include "iscsi_ipc.h"
31 #include "log.h"
32 #include "iscsi_sysfs.h"
33 #include "iscsi_settings.h"
34 #include "iface.h"
35 #include "host.h"
36 #include "sysdeps.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)
47 return session;
50 return NULL;
54 * calculate parameter's padding
56 static unsigned int
57 __padding(unsigned int param)
59 int pad;
61 pad = param & 3;
62 if (pad) {
63 pad = 4 - pad;
64 log_debug(1, "parameter's value %d padded to %d bytes\n",
65 param, param + pad);
67 return param + pad;
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.");
82 return EINVAL;
84 session->bidirectional_auth = 1;
85 } else {
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...");
133 } else {
134 session->num_auth_buffers = 0;
135 log_debug(6, "no authentication configured...");
138 return 0;
141 void
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);
260 return 0;
263 int host_set_param(struct iscsi_transport *t,
264 uint32_t host_no, int param, char *value,
265 int type)
267 int rc;
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,
274 rc, errno);
275 return rc;
277 return 0;
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");
286 else
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;
295 int i;
296 struct hostparam {
297 int param;
298 int type;
299 void *value;
300 } hosttbl[MAX_HOST_PARAMS] = {
302 .param = ISCSI_HOST_PARAM_NETDEV_NAME,
303 .value = session->nrec.iface.netdev,
304 .type = ISCSI_STRING,
305 }, {
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,
315 hosttbl[i].type)) {
316 return EPERM;
319 print_param_value(hosttbl[i].param, hosttbl[i].value,
320 hosttbl[i].type);
323 return 0;
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;
332 int i, rc;
333 uint32_t one = 1, zero = 0;
334 struct connparam {
335 int param;
336 int type;
337 void *value;
338 int conn_only;
339 } conntbl[MAX_SESSION_PARAMS] = {
341 .param = ISCSI_PARAM_MAX_RECV_DLENGTH,
342 .value = &conn->max_recv_dlength,
343 .type = ISCSI_INT,
344 .conn_only = 0,
345 }, {
346 .param = ISCSI_PARAM_MAX_XMIT_DLENGTH,
347 .value = &conn->max_xmit_dlength,
348 .type = ISCSI_INT,
349 .conn_only = 0,
350 }, {
351 .param = ISCSI_PARAM_HDRDGST_EN,
352 .value = &conn->hdrdgst_en,
353 .type = ISCSI_INT,
354 .conn_only = 0,
355 }, {
356 .param = ISCSI_PARAM_DATADGST_EN,
357 .value = &conn->datadgst_en,
358 .type = ISCSI_INT,
359 .conn_only = 1,
360 }, {
361 .param = ISCSI_PARAM_INITIAL_R2T_EN,
362 .value = &session->initial_r2t_en,
363 .type = ISCSI_INT,
364 .conn_only = 0,
365 }, {
366 .param = ISCSI_PARAM_MAX_R2T,
367 .value = &one, /* FIXME: session->max_r2t */
368 .type = ISCSI_INT,
369 .conn_only = 0,
370 }, {
371 .param = ISCSI_PARAM_IMM_DATA_EN,
372 .value = &session->imm_data_en,
373 .type = ISCSI_INT,
374 .conn_only = 0,
375 }, {
376 .param = ISCSI_PARAM_FIRST_BURST,
377 .value = &session->first_burst,
378 .type = ISCSI_INT,
379 .conn_only = 0,
380 }, {
381 .param = ISCSI_PARAM_MAX_BURST,
382 .value = &session->max_burst,
383 .type = ISCSI_INT,
384 .conn_only = 0,
385 }, {
386 .param = ISCSI_PARAM_PDU_INORDER_EN,
387 .value = &session->pdu_inorder_en,
388 .type = ISCSI_INT,
389 .conn_only = 0,
390 }, {
391 .param =ISCSI_PARAM_DATASEQ_INORDER_EN,
392 .value = &session->dataseq_inorder_en,
393 .type = ISCSI_INT,
394 .conn_only = 0,
395 }, {
396 .param = ISCSI_PARAM_ERL,
397 .value = &zero, /* FIXME: session->erl */
398 .type = ISCSI_INT,
399 .conn_only = 0,
400 }, {
401 .param = ISCSI_PARAM_IFMARKER_EN,
402 .value = &zero,/* FIXME: session->ifmarker_en */
403 .type = ISCSI_INT,
404 .conn_only = 0,
405 }, {
406 .param = ISCSI_PARAM_OFMARKER_EN,
407 .value = &zero,/* FIXME: session->ofmarker_en */
408 .type = ISCSI_INT,
409 .conn_only = 0,
410 }, {
411 .param = ISCSI_PARAM_EXP_STATSN,
412 .value = &conn->exp_statsn,
413 .type = ISCSI_INT,
414 .conn_only = 1,
415 }, {
416 .param = ISCSI_PARAM_TARGET_NAME,
417 .conn_only = 0,
418 .type = ISCSI_STRING,
419 .value = session->target_name,
420 }, {
421 .param = ISCSI_PARAM_TPGT,
422 .value = &session->portal_group_tag,
423 .type = ISCSI_INT,
424 .conn_only = 0,
425 }, {
426 .param = ISCSI_PARAM_PERSISTENT_ADDRESS,
427 .value = session->nrec.conn[conn->id].address,
428 .type = ISCSI_STRING,
429 .conn_only = 1,
430 }, {
431 .param = ISCSI_PARAM_PERSISTENT_PORT,
432 .value = &session->nrec.conn[conn->id].port,
433 .type = ISCSI_INT,
434 .conn_only = 1,
435 }, {
436 .param = ISCSI_PARAM_SESS_RECOVERY_TMO,
437 .value = &session->replacement_timeout,
438 .type = ISCSI_INT,
439 .conn_only = 0,
440 }, {
441 .param = ISCSI_PARAM_USERNAME,
442 .value = session->username,
443 .type = ISCSI_STRING,
444 .conn_only = 0,
445 }, {
446 .param = ISCSI_PARAM_USERNAME_IN,
447 .value = session->username_in,
448 .type = ISCSI_STRING,
449 .conn_only = 0,
450 }, {
451 .param = ISCSI_PARAM_PASSWORD,
452 .value = session->password,
453 .type = ISCSI_STRING,
454 .conn_only = 0,
455 }, {
456 .param = ISCSI_PARAM_PASSWORD_IN,
457 .value = session->password_in,
458 .type = ISCSI_STRING,
459 .conn_only = 0,
460 }, {
461 .param = ISCSI_PARAM_FAST_ABORT,
462 .value = &session->fast_abort,
463 .type = ISCSI_INT,
464 .conn_only = 0,
465 }, {
466 .param = ISCSI_PARAM_ABORT_TMO,
467 .value = &session->abort_timeout,
468 .type = ISCSI_INT,
469 .conn_only = 0,
470 }, {
471 .param = ISCSI_PARAM_LU_RESET_TMO,
472 .value = &session->lu_reset_timeout,
473 .type = ISCSI_INT,
474 .conn_only = 0,
475 }, {
476 .param = ISCSI_PARAM_TGT_RESET_TMO,
477 .value = &session->tgt_reset_timeout,
478 .type = ISCSI_INT,
479 .conn_only = 0,
480 }, {
481 .param = ISCSI_PARAM_PING_TMO,
482 .value = &conn->noop_out_timeout,
483 .type = ISCSI_INT,
484 .conn_only = 1,
485 }, {
486 .param = ISCSI_PARAM_RECV_TMO,
487 .value = &conn->noop_out_interval,
488 .type = ISCSI_INT,
489 .conn_only = 1,
490 }, {
491 .param = ISCSI_PARAM_IFACE_NAME,
492 .value = session->nrec.iface.name,
493 .type = ISCSI_STRING,
494 }, {
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 /* some llds will send nops internally */
514 if (!iscsi_sysfs_session_supports_nop(session->id)) {
515 session->param_mask &= ~ISCSI_PING_TMO;
516 session->param_mask &= ~ISCSI_RECV_TMO;
519 /* Entered full-feature phase! */
520 for (i = 0; i < MAX_SESSION_PARAMS; i++) {
521 if (conn->id != 0 && !conntbl[i].conn_only)
522 continue;
524 if (!(session->param_mask & (1ULL << conntbl[i].param)))
525 continue;
527 rc = ipc->set_param(session->t->handle, session->id,
528 conn->id, conntbl[i].param, conntbl[i].value,
529 conntbl[i].type);
530 if (rc && rc != -ENOSYS) {
531 log_error("can't set operational parameter %d for "
532 "connection %d:%d, retcode %d (%d)",
533 conntbl[i].param, session->id, conn->id,
534 rc, errno);
535 return EPERM;
538 if (rc == -ENOSYS) {
539 switch (conntbl[i].param) {
540 case ISCSI_PARAM_PING_TMO:
542 * older kernels may not support nops
543 * in kernel
545 conn->userspace_nop = 1;
546 break;
547 #if 0
548 TODO handle this
549 case ISCSI_PARAM_INITIATOR_NAME:
550 /* use host level one instead */
551 hosttbl[ISCSI_HOST_PARAM_INITIATOR_NAME].set = 1;
552 break;
553 #endif
557 print_param_value(conntbl[i].param, conntbl[i].value,
558 conntbl[i].type);
561 return 0;
564 int iscsi_host_set_net_params(struct iface_rec *iface,
565 struct iscsi_session *session)
567 struct iscsi_transport *t = session->t;
568 int rc = 0;
570 log_debug(3, "setting iface %s, dev %s, set ip %s, hw %s, "
571 "transport %s.\n",
572 iface->name, iface->netdev, iface->ipaddress,
573 iface->hwaddress, iface->transport_name);
575 if (!t->template->set_host_ip)
576 return 0;
578 /* if we need to set the ip addr then set all the iface net settings */
579 if (!iface_is_bound_by_ipaddr(iface)) {
580 log_warning("Please set the iface.ipaddress for iface %s, "
581 "then retry the login command.\n", iface->name);
582 return EINVAL;
585 rc = host_set_param(t, session->hostno,
586 ISCSI_HOST_PARAM_IPADDRESS,
587 iface->ipaddress, ISCSI_STRING);
588 if (rc)
589 return rc;
591 if (iface_is_bound_by_netdev(iface)) {
592 rc = host_set_param(t, session->hostno,
593 ISCSI_HOST_PARAM_NETDEV_NAME,
594 iface->netdev, ISCSI_STRING);
595 if (rc)
596 return rc;
599 if (iface_is_bound_by_hwaddr(iface)) {
600 rc = host_set_param(t, session->hostno,
601 ISCSI_HOST_PARAM_HWADDRESS,
602 iface->hwaddress, ISCSI_STRING);
603 if (rc)
604 return rc;
606 return 0;