summaryrefslogtreecommitdiff
path: root/usr/initiator.h
blob: 02227972f44aa33b5b5f9b8060846b65aefcbf20 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
/*
 * iSCSI Initiator
 *
 * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
 * maintained by open-iscsi@googlegroups.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * See the file COPYING included with this distribution for more details.
 */

#ifndef INITIATOR_H
#define INITIATOR_H

#include <stdint.h>
#include <net/if.h>
#include <sys/time.h>

#include "types.h"
#include "iscsi_proto.h"
#include "iscsi_if.h"
#include "auth.h"
#include "mgmt_ipc.h"
#include "config.h"
#include "actor.h"
#include "list.h"
#include "log.h"

#ifndef ISCSI_CONFIG_ROOT
#define ISCSI_CONFIG_ROOT	"/etc/iscsi/"
#endif

#define CONFIG_FILE		ISCSI_CONFIG_ROOT"/iscsid.conf"
#define INITIATOR_NAME_FILE	ISCSI_CONFIG_ROOT"/initiatorname.iscsi"

#define PID_FILE		"/run/iscsid.pid"

#ifndef LOCK_DIR
#define LOCK_DIR		"/run/lock/iscsi"
#endif

#define LOCK_FILE		LOCK_DIR"/lock"
#define LOCK_WRITE_FILE		LOCK_DIR"/lock.write"

#define conn_info(conn, fmt, ...)				\
do {								\
	if (conn->session == NULL) { 				\
		log_info(fmt, ##__VA_ARGS__);			\
		break;						\
	}							\
	log_info("connection%d:%d " fmt,			\
		   conn->session->id, conn->id, ##__VA_ARGS__);	\
} while(0)

#define conn_warn(conn, fmt, ...)				\
do {								\
	if (conn->session == NULL) { 				\
		log_warning(fmt, ##__VA_ARGS__);		\
		break;						\
	}							\
	log_warning("connection%d:%d " fmt,			\
		   conn->session->id, conn->id, ##__VA_ARGS__);	\
} while(0)

#define conn_error(conn, fmt, ...)				\
do {								\
	if (conn->session == NULL) { 				\
		log_error(fmt, ##__VA_ARGS__);			\
		break;						\
	}							\
	log_error("connection%d:%d " fmt,			\
		   conn->session->id, conn->id, ##__VA_ARGS__);	\
} while(0)

#define conn_debug(level, conn, fmt, ...)			\
do {								\
	if (conn->session == NULL) { 				\
		log_debug(level, fmt, ##__VA_ARGS__);		\
		break;						\
	}							\
	log_debug(level, "connection%d:%d " fmt,		\
		   conn->session->id, conn->id, ##__VA_ARGS__);	\
} while(0)

typedef enum iscsi_session_r_stage_e {
	R_STAGE_NO_CHANGE,
	R_STAGE_SESSION_CLEANUP,
	R_STAGE_SESSION_REOPEN,
	R_STAGE_SESSION_REDIRECT,
	R_STAGE_SESSION_DESTOYED,
} iscsi_session_r_stage_e;

typedef enum conn_login_status_e {
	CONN_LOGIN_SUCCESS		= 0,
	CONN_LOGIN_FAILED		= 1,
	CONN_LOGIN_IO_ERR		= 2,
	CONN_LOGIN_RETRY		= 3,
	CONN_LOGIN_IMM_RETRY		= 4,
	CONN_LOGIN_IMM_REDIRECT_RETRY	= 5,
	CONN_LOGIN_AUTH_FAILED		= 6,
} conn_login_status_e;

enum iscsi_login_status {
	LOGIN_OK			= 0,
	LOGIN_IO_ERROR			= 1,
	LOGIN_FAILED			= 2,
	LOGIN_VERSION_MISMATCH		= 3,
	LOGIN_NEGOTIATION_FAILED	= 4,
	LOGIN_AUTHENTICATION_FAILED	= 5,
	LOGIN_REDIRECTION_FAILED	= 6,
	LOGIN_INVALID_PDU		= 7,
	LOGIN_REDIRECT			= 8,
};

typedef enum iscsi_event_e {
	EV_UNKNOWN,
	EV_CONN_RECV_PDU,
	EV_CONN_POLL,
	EV_CONN_ERROR,
	EV_CONN_LOGOUT_TIMER,
	EV_CONN_STOP,
	EV_CONN_LOGIN,
} iscsi_event_e;

struct queue_task;

typedef struct iscsi_login_context {
	int cid;
	char *buffer;
	size_t bufsize;
	uint8_t status_class;
	uint8_t status_detail;
	struct iscsi_acl *auth_client;
	struct iscsi_hdr pdu;
	struct iscsi_login_rsp *login_rsp;
	char *data;
	int received_pdu;
	int max_data_length;
	int timeout;
	int final;
	enum iscsi_login_status ret;
	struct queue_task *qtask;
} iscsi_login_context_t;

struct iscsi_session;
struct iscsi_conn;
struct iscsi_ev_context;

/* daemon's connection structure */
typedef struct iscsi_conn {
	uint32_t id;
	struct iscsi_session *session;
	iscsi_login_context_t login_context;
	struct iscsi_ev_context *recv_context;
	struct queue_task *logout_qtask;
	char data[ISCSI_DEF_MAX_RECV_SEG_LEN];
	char host[NI_MAXHOST];	/* scratch */
	enum iscsi_conn_state state;
	int userspace_nop;

	struct timeval initial_connect_time;
	actor_t login_timer;
	actor_t nop_out_timer;

#define CONTEXT_POOL_MAX 32
	struct iscsi_ev_context *context_pool[CONTEXT_POOL_MAX];

	/* login state machine */
	int current_stage;
	int next_stage;
	int partial_response;
	conn_login_status_e status;

	/* tcp/socket settings */

	/*
	 * Either a tcp/ip or a netlink socket to do
	 * IO through.
	 */
	int socket_fd;
	/* address being used for normal session connection */
	struct sockaddr_storage saddr;
	/* address received during login */
	struct sockaddr_storage failback_saddr;
	int tcp_window_size;
	int type_of_service;

	/* used for the IPC of bind and for connect/poll/disconnect by
         * transports (eg iser) which does these ops from the kernel.
         * In the case of TCP, it is just the transport_fd casted to u64. */
	uint64_t transport_ep_handle;
	int bind_ep;

	/* timeouts */
	int login_timeout;
	int logout_timeout;
	int auth_timeout;
	int active_timeout;

	int noop_out_interval;
	int noop_out_timeout;

	/* sequencing */
	uint32_t exp_statsn;

	/* negotiated parameters */
	uint32_t hdrdgst_en;
	uint32_t datadgst_en;
	uint32_t max_recv_dlength;	/* the value we declare */
	uint32_t max_xmit_dlength;	/* the value declared by the target */
} iscsi_conn_t;

struct iscsi_ev_context {
	struct actor actor;
	struct iscsi_conn *conn;
	int allocated;
	void *data;
};

typedef struct queue_task {
	iscsi_conn_t *conn;
	iscsiadm_req_t req;
	iscsiadm_rsp_t rsp;
	int mgmt_ipc_fd;
	int allocated : 1;
	/* Newer request types include a
	 * variable-length payload */
	void *payload;
} queue_task_t;

struct iscsi_transport_template;
struct iscsi_transport;

/* daemon's session structure */
typedef struct iscsi_session {
	struct list_head list;
	uint32_t id;
	uint32_t hostno;
	char netdev[IFNAMSIZ];
	struct iscsi_transport *t;
	uint8_t use_ipc;
	node_rec_t nrec; /* copy of original Node record in database */
	unsigned int irrelevant_keys_bitmap;
	int send_async_text;
	uint32_t itt;
	uint32_t cmdsn;
	uint32_t exp_cmdsn;
	uint32_t max_cmdsn;
	int erl;
	uint32_t imm_data_en;
	uint32_t initial_r2t_en;
	uint32_t max_r2t;
	uint32_t fast_abort;
	uint32_t first_burst;
	uint32_t max_burst;
	uint32_t pdu_inorder_en;
	uint32_t dataseq_inorder_en;
	uint32_t def_time2wait;
	uint32_t def_time2retain;
	int type;
	int portal_group_tag;
	uint8_t isid[6];
	uint16_t tsih;
	char target_name[TARGET_NAME_MAXLEN + 1];
	char *target_alias;
	char *initiator_name;
	char *initiator_alias;
	struct auth_str_block auth_recv_string_block;
	struct auth_str_block auth_send_string_block;
	struct auth_large_binary auth_recv_binary_block;
	struct auth_large_binary auth_send_binary_block;
	struct iscsi_acl auth_client_block;
	struct iscsi_acl *auth_client;
	int num_auth_buffers;
	struct auth_buffer_desc auth_buffers[5];
	int bidirectional_auth;
	char username[AUTH_STR_MAX_LEN];
	uint8_t password[AUTH_STR_MAX_LEN];
	int password_length;
	char username_in[AUTH_STR_MAX_LEN];
	uint8_t password_in[AUTH_STR_MAX_LEN];
	int password_in_length;
	unsigned int chap_algs[AUTH_CHAP_ALG_MAX_COUNT];
	iscsi_conn_t conn[ISCSI_CONN_MAX];
	uint64_t param_mask;

	/* connection reopens during recovery */
	int reopen_cnt;
	int reopen_max;
	queue_task_t reopen_qtask;
	iscsi_session_r_stage_e r_stage;
	uint32_t replacement_timeout;

	int host_reset_timeout;
	int tgt_reset_timeout;
	int lu_reset_timeout;
	int abort_timeout;

	/*
	 * used for hw and sync up to notify caller that the operation
	 * is complete
	 */
	queue_task_t *notify_qtask;
} iscsi_session_t;

#define	INVALID_SESSION_ID	(uint32_t)-1

/* login.c */

#define ISCSI_SESSION_TYPE_NORMAL 0
#define ISCSI_SESSION_TYPE_DISCOVERY 1

/* not defined by iSCSI, but used in the login code to determine
 * when to send the initial Login PDU
 */
#define ISCSI_INITIAL_LOGIN_STAGE -1

#define ISCSI_TEXT_SEPARATOR     '='

/* implemented in iscsi-login.c for use on all platforms */
extern int iscsi_add_text(struct iscsi_hdr *hdr, char *data, int max_data_length,
			char *param, char *value);
extern enum iscsi_login_status iscsi_login(iscsi_session_t *session, int cid,
		   char *buffer, size_t bufsize, uint8_t * status_class,
		   uint8_t * status_detail);
extern int iscsi_update_address(iscsi_conn_t *conn, char *address);
extern int iscsi_login_begin(iscsi_session_t *session,
			     iscsi_login_context_t *c);
extern int iscsi_login_req(iscsi_session_t *session, iscsi_login_context_t *c);
extern int iscsi_login_rsp(iscsi_session_t *session, iscsi_login_context_t *c);
extern int resolve_address(char *host, char *port, struct sockaddr_storage *ss);

/* Digest types */
#define ISCSI_DIGEST_NONE  0
#define ISCSI_DIGEST_CRC32C 1
#define ISCSI_DIGEST_CRC32C_NONE 2	/* offer both, prefer CRC32C */
#define ISCSI_DIGEST_NONE_CRC32C 3	/* offer both, prefer None */

#define IRRELEVANT_MAXCONNECTIONS	0x01
#define IRRELEVANT_INITIALR2T		0x02
#define IRRELEVANT_IMMEDIATEDATA	0x04
#define IRRELEVANT_MAXBURSTLENGTH	0x08
#define IRRELEVANT_FIRSTBURSTLENGTH	0x10
#define IRRELEVANT_MAXOUTSTANDINGR2T	0x20
#define IRRELEVANT_DATAPDUINORDER	0x40
#define IRRELEVANT_DATASEQUENCEINORDER	0x80


/*
 * These user/kernel IPC calls are used by transports (eg iSER) that have their
 * native connection managed from the kernel. The IPC for having the user space
 * code being able to do it, is implemented as an enhancement of the open iscsi
 * netlink IPC scheme, currently with the ability to connect/poll-for-establish
 * ment/disconnect an opaque transport dependent 64 bit ep (endpoint) handle.
 * The exact IPC ABI for that matter is defined in iscsi_if.h
 */
/* netlink.c */
extern int ktransport_ep_connect(iscsi_conn_t *conn, int non_blocking);
extern int ktransport_ep_poll(iscsi_conn_t *conn, int timeout_ms);
extern void ktransport_ep_disconnect(iscsi_conn_t *conn);

/* io.c */
extern int iscsi_io_tcp_poll(iscsi_conn_t *conn, int timeout_ms);
extern int iscsi_io_tcp_connect(iscsi_conn_t *conn, int non_blocking);
extern void iscsi_io_tcp_disconnect(iscsi_conn_t *conn);

extern int iscsi_io_connect(iscsi_conn_t *conn);
extern void iscsi_io_disconnect(iscsi_conn_t *conn);
extern int iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
	       int hdr_digest, char *data, int data_digest, int timeout);
extern int iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr,
	int hdr_digest, char *data, int max_data_length, int data_digest,
	int timeout);

/* initiator.c */
extern int session_login_task(node_rec_t *rec, queue_task_t *qtask);
extern int session_logout_task(int sid, queue_task_t *qtask);
extern iscsi_session_t *session_find_by_sid(uint32_t sid);
extern int iscsi_sync_session(node_rec_t *rec, queue_task_t
					 *tsk, uint32_t sid);
extern int iscsi_host_send_targets(queue_task_t *qtask,
			int host_no, int do_login, struct sockaddr_storage *ss);

extern void free_initiator(void);
extern void iscsi_initiator_init(void);

/* initiator code common to discovery and normal sessions */
extern int iscsi_session_set_neg_params(struct iscsi_conn *conn);
extern int iscsi_session_set_params(struct iscsi_conn *conn);
extern int iscsi_host_set_params(struct iscsi_session *session);
extern int iscsi_host_set_net_params(struct iface_rec *iface,
				     struct iscsi_session *session);
extern void iscsi_copy_operational_params(struct iscsi_conn *conn,
			struct iscsi_session_operational_config *session_conf,
			struct iscsi_conn_operational_config *conn_conf);
extern int iscsi_setup_authentication(struct iscsi_session *session,
				      struct iscsi_auth_config *auth_cfg);
extern int iscsi_setup_portal(struct iscsi_conn *conn, char *address, int port);
extern int iscsi_set_net_config(struct iscsi_transport *t,
				iscsi_session_t *session,
				struct iface_rec *iface);
extern void iscsi_session_init_params(struct iscsi_session *session);

extern int session_in_use(int sid);
#endif /* INITIATOR_H */