/* * 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 #include #include #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 */