#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
#include <gpxe/vsprintf.h>
#include <gpxe/socket.h>
#include <gpxe/xfer.h>
#include <gpxe/open.h>
#include <gpxe/scsi.h>
#include <gpxe/process.h>
#include <gpxe/uaccess.h>
#include <gpxe/tcpip.h>
#include <gpxe/settings.h>
#include <gpxe/features.h>
#include <gpxe/iscsi.h>
Go to the source code of this file.
Data Structures | |
| struct | iscsi_string_type |
| An iSCSI text string that we want to handle. More... | |
| struct | iscsi_string_setting |
| An iSCSI string setting. More... | |
Defines | |
| #define | EACCES_INCORRECT_TARGET_USERNAME ( EACCES | EUNIQ_01 ) |
| #define | EACCES_INCORRECT_TARGET_PASSWORD ( EACCES | EUNIQ_02 ) |
| #define | ENOTSUP_INITIATOR_STATUS ( ENOTSUP | EUNIQ_01 ) |
| #define | ENOTSUP_OPCODE ( ENOTSUP | EUNIQ_02 ) |
| #define | ENOTSUP_DISCOVERY ( ENOTSUP | EUNIQ_03 ) |
| #define | EPERM_INITIATOR_AUTHENTICATION ( EPERM | EUNIQ_01 ) |
| #define | EPERM_INITIATOR_AUTHORISATION ( EPERM | EUNIQ_02 ) |
| #define | EPROTO_INVALID_CHAP_ALGORITHM ( EPROTO | EUNIQ_01 ) |
| #define | EPROTO_INVALID_CHAP_IDENTIFIER ( EPROTO | EUNIQ_02 ) |
| #define | EPROTO_INVALID_CHAP_CHALLENGE ( EPROTO | EUNIQ_03 ) |
| #define | EPROTO_INVALID_CHAP_RESPONSE ( EPROTO | EUNIQ_04 ) |
Enumerations | |
| enum | iscsi_root_path_component { RP_LITERAL = 0, RP_SERVERNAME, RP_PROTOCOL, RP_PORT, RP_LUN, RP_TARGETNAME, NUM_RP_COMPONENTS } |
| iSCSI root path components (as per RFC4173) More... | |
Functions | |
| FILE_LICENCE (GPL2_OR_LATER) | |
| FEATURE (FEATURE_PROTOCOL,"iSCSI", DHCP_EB_FEATURE_ISCSI, 1) | |
| static void | iscsi_start_tx (struct iscsi_session *iscsi) |
| Start up a new TX PDU. | |
| static void | iscsi_start_login (struct iscsi_session *iscsi) |
| Build iSCSI login request BHS. | |
| static void | iscsi_start_data_out (struct iscsi_session *iscsi, unsigned int datasn) |
| Build iSCSI data-out BHS. | |
| static void | iscsi_rx_buffered_data_done (struct iscsi_session *iscsi) |
| Finish receiving PDU data into buffer. | |
| static void | iscsi_free (struct refcnt *refcnt) |
| Free iSCSI session. | |
| static int | iscsi_open_connection (struct iscsi_session *iscsi) |
| Open iSCSI transport-layer connection. | |
| static void | iscsi_close_connection (struct iscsi_session *iscsi, int rc) |
| Close iSCSI transport-layer connection. | |
| static void | iscsi_scsi_done (struct iscsi_session *iscsi, int rc) |
| Mark iSCSI SCSI operation as complete. | |
| static void | iscsi_start_command (struct iscsi_session *iscsi) |
| Build iSCSI SCSI command BHS. | |
| static int | iscsi_rx_scsi_response (struct iscsi_session *iscsi, const void *data, size_t len, size_t remaining) |
| Receive data segment of an iSCSI SCSI response PDU. | |
| static int | iscsi_rx_data_in (struct iscsi_session *iscsi, const void *data, size_t len, size_t remaining) |
| Receive data segment of an iSCSI data-in PDU. | |
| static int | iscsi_rx_r2t (struct iscsi_session *iscsi, const void *data __unused, size_t len __unused, size_t remaining __unused) |
| Receive data segment of an iSCSI R2T PDU. | |
| static void | iscsi_data_out_done (struct iscsi_session *iscsi) |
| Complete iSCSI data-out PDU transmission. | |
| static int | iscsi_tx_data_out (struct iscsi_session *iscsi) |
| Send iSCSI data-out data segment. | |
| static int | iscsi_build_login_request_strings (struct iscsi_session *iscsi, void *data, size_t len) |
| Build iSCSI login request strings. | |
| static void | iscsi_login_request_done (struct iscsi_session *iscsi) |
| Complete iSCSI login request PDU transmission. | |
| static int | iscsi_tx_login_request (struct iscsi_session *iscsi) |
| Transmit data segment of an iSCSI login request PDU. | |
| static int | iscsi_handle_targetaddress_value (struct iscsi_session *iscsi, const char *value) |
| Handle iSCSI TargetAddress text value. | |
| static int | iscsi_handle_authmethod_value (struct iscsi_session *iscsi, const char *value) |
| Handle iSCSI AuthMethod text value. | |
| static int | iscsi_handle_chap_a_value (struct iscsi_session *iscsi, const char *value) |
| Handle iSCSI CHAP_A text value. | |
| static int | iscsi_handle_chap_i_value (struct iscsi_session *iscsi, const char *value) |
| Handle iSCSI CHAP_I text value. | |
| static int | iscsi_handle_chap_c_value (struct iscsi_session *iscsi, const char *value) |
| Handle iSCSI CHAP_C text value. | |
| static int | iscsi_handle_chap_n_value (struct iscsi_session *iscsi, const char *value) |
| Handle iSCSI CHAP_N text value. | |
| static int | iscsi_handle_chap_r_value (struct iscsi_session *iscsi, const char *value) |
| Handle iSCSI CHAP_R text value. | |
| static int | iscsi_handle_string (struct iscsi_session *iscsi, const char *string) |
| Handle iSCSI string. | |
| static int | iscsi_handle_strings (struct iscsi_session *iscsi, const char *strings, size_t len) |
| Handle iSCSI strings. | |
| static int | iscsi_rx_buffered_data (struct iscsi_session *iscsi, const void *data, size_t len) |
| Receive PDU data into buffer. | |
| static int | iscsi_status_to_rc (unsigned int status_class, unsigned int status_detail) |
| Convert iSCSI response status to return status code. | |
| static int | iscsi_rx_login_response (struct iscsi_session *iscsi, const void *data, size_t len, size_t remaining) |
| Receive data segment of an iSCSI login response PDU. | |
| static int | iscsi_tx_nothing (struct iscsi_session *iscsi __unused) |
| Transmit nothing. | |
| static int | iscsi_tx_bhs (struct iscsi_session *iscsi) |
| Transmit basic header segment of an iSCSI PDU. | |
| static int | iscsi_tx_data (struct iscsi_session *iscsi) |
| Transmit data segment of an iSCSI PDU. | |
| static int | iscsi_tx_data_padding (struct iscsi_session *iscsi) |
| Transmit data padding of an iSCSI PDU. | |
| static void | iscsi_tx_done (struct iscsi_session *iscsi) |
| Complete iSCSI PDU transmission. | |
| static void | iscsi_tx_step (struct process *process) |
| Transmit iSCSI PDU. | |
| static int | iscsi_rx_bhs (struct iscsi_session *iscsi, const void *data, size_t len, size_t remaining __unused) |
| Receive basic header segment of an iSCSI PDU. | |
| static int | iscsi_rx_discard (struct iscsi_session *iscsi __unused, const void *data __unused, size_t len __unused, size_t remaining __unused) |
| Discard portion of an iSCSI PDU. | |
| static int | iscsi_rx_data (struct iscsi_session *iscsi, const void *data, size_t len, size_t remaining) |
| Receive data segment of an iSCSI PDU. | |
| static int | iscsi_socket_deliver_raw (struct xfer_interface *socket, const void *data, size_t len) |
| Receive new data. | |
| static void | iscsi_socket_close (struct xfer_interface *socket, int rc) |
| Handle stream connection closure. | |
| static int | iscsi_vredirect (struct xfer_interface *socket, int type, va_list args) |
| Handle redirection event. | |
| static int | iscsi_command (struct scsi_device *scsi, struct scsi_command *command) |
| Issue SCSI command. | |
| void | iscsi_detach (struct scsi_device *scsi) |
| Shut down iSCSI interface. | |
| static int | iscsi_parse_root_path (struct iscsi_session *iscsi, const char *root_path) |
| Parse iSCSI root path. | |
| static int | iscsi_set_auth (struct iscsi_session *iscsi, const char *initiator_username, const char *initiator_password, const char *target_username, const char *target_password) |
| Set iSCSI authentication details. | |
| int | iscsi_attach (struct scsi_device *scsi, const char *root_path) |
| Attach iSCSI interface. | |
| static int | apply_iscsi_string_setting (struct iscsi_string_setting *setting) |
| Apply iSCSI setting. | |
| static int | apply_iscsi_settings (void) |
| Apply iSCSI settings. | |
| const char * | iscsi_initiator_iqn (void) |
| Get iSCSI initiator IQN. | |
Variables | |
| static char * | iscsi_explicit_initiator_iqn |
| iSCSI initiator name (explicitly specified) | |
| static char * | iscsi_default_initiator_iqn |
| Default iSCSI initiator name (constructed from hostname). | |
| static char * | iscsi_initiator_username |
| iSCSI initiator username | |
| static char * | iscsi_initiator_password |
| iSCSI initiator password | |
| static char * | iscsi_target_username |
| iSCSI target username | |
| static char * | iscsi_target_password |
| iSCSI target password | |
| static struct iscsi_string_type | iscsi_string_types [] |
| iSCSI text strings that we want to handle | |
| static struct xfer_interface_operations | iscsi_socket_operations |
| iSCSI socket operations | |
| struct setting initiator_iqn_setting | __setting |
| iSCSI initiator IQN setting | |
| static struct iscsi_string_setting | iscsi_string_settings [] |
| iSCSI string settings | |
| struct settings_applicator iscsi_settings_applicator | __settings_applicator |
| iSCSI settings applicator | |
Definition in file iscsi.c.
| #define EACCES_INCORRECT_TARGET_USERNAME ( EACCES | EUNIQ_01 ) |
| #define EACCES_INCORRECT_TARGET_PASSWORD ( EACCES | EUNIQ_02 ) |
| #define ENOTSUP_INITIATOR_STATUS ( ENOTSUP | EUNIQ_01 ) |
| #define ENOTSUP_OPCODE ( ENOTSUP | EUNIQ_02 ) |
| #define ENOTSUP_DISCOVERY ( ENOTSUP | EUNIQ_03 ) |
| #define EPERM_INITIATOR_AUTHENTICATION ( EPERM | EUNIQ_01 ) |
| #define EPERM_INITIATOR_AUTHORISATION ( EPERM | EUNIQ_02 ) |
| #define EPROTO_INVALID_CHAP_ALGORITHM ( EPROTO | EUNIQ_01 ) |
| #define EPROTO_INVALID_CHAP_IDENTIFIER ( EPROTO | EUNIQ_02 ) |
| #define EPROTO_INVALID_CHAP_CHALLENGE ( EPROTO | EUNIQ_03 ) |
| #define EPROTO_INVALID_CHAP_RESPONSE ( EPROTO | EUNIQ_04 ) |
iSCSI root path components (as per RFC4173)
Definition at line 1618 of file iscsi.c.
01618 { 01619 RP_LITERAL = 0, 01620 RP_SERVERNAME, 01621 RP_PROTOCOL, 01622 RP_PORT, 01623 RP_LUN, 01624 RP_TARGETNAME, 01625 NUM_RP_COMPONENTS 01626 };
| FILE_LICENCE | ( | GPL2_OR_LATER | ) |
| FEATURE | ( | FEATURE_PROTOCOL | , | |
| "iSCSI" | , | |||
| DHCP_EB_FEATURE_ISCSI | , | |||
| 1 | ||||
| ) |
| static void iscsi_start_tx | ( | struct iscsi_session * | iscsi | ) | [static] |
Start up a new TX PDU.
| iscsi | iSCSI session |
Definition at line 1147 of file iscsi.c.
References assert, ISCSI_TX_BHS, ISCSI_TX_IDLE, memset(), iscsi_session::tx_bhs, and iscsi_session::tx_state.
Referenced by iscsi_start_command(), iscsi_start_data_out(), and iscsi_start_login().
01147 { 01148 assert ( iscsi->tx_state == ISCSI_TX_IDLE ); 01149 01150 /* Initialise TX BHS */ 01151 memset ( &iscsi->tx_bhs, 0, sizeof ( iscsi->tx_bhs ) ); 01152 01153 /* Flag TX engine to start transmitting */ 01154 iscsi->tx_state = ISCSI_TX_BHS; 01155 }
| static void iscsi_start_login | ( | struct iscsi_session * | iscsi | ) | [static] |
Build iSCSI login request BHS.
| iscsi | iSCSI session |
Definition at line 559 of file iscsi.c.
References iscsi_session::cmdsn, iscsi_bhs_login_request::cmdsn, iscsi_bhs_login_request::expstatsn, iscsi_bhs_login_request::flags, htonl, htons, IANA_EN_FEN_SYSTEMS, iscsi_build_login_request_strings(), ISCSI_FLAG_IMMEDIATE, ISCSI_ISID_IANA, ISCSI_LOGIN_FLAG_TRANSITION, ISCSI_OPCODE_LOGIN_REQUEST, ISCSI_SET_LENGTHS, iscsi_start_tx(), ISCSI_STATUS_PHASE_MASK, iscsi_bhs_login_request::isid_iana_en, iscsi_session::itt, iscsi_bhs_login_request::itt, iscsi_bhs_login_request::lengths, iscsi_bhs::login_request, NULL, iscsi_bhs_login_request::opcode, iscsi_session::statsn, iscsi_session::status, iscsi_session::tsih, iscsi_bhs_login_request::tsih, and iscsi_session::tx_bhs.
Referenced by iscsi_open_connection(), and iscsi_rx_login_response().
00559 { 00560 struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request; 00561 int len; 00562 00563 /* Construct BHS and initiate transmission */ 00564 iscsi_start_tx ( iscsi ); 00565 request->opcode = ( ISCSI_OPCODE_LOGIN_REQUEST | 00566 ISCSI_FLAG_IMMEDIATE ); 00567 request->flags = ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) | 00568 ISCSI_LOGIN_FLAG_TRANSITION ); 00569 /* version_max and version_min left as zero */ 00570 len = iscsi_build_login_request_strings ( iscsi, NULL, 0 ); 00571 ISCSI_SET_LENGTHS ( request->lengths, 0, len ); 00572 request->isid_iana_en = htonl ( ISCSI_ISID_IANA | 00573 IANA_EN_FEN_SYSTEMS ); 00574 /* isid_iana_qual left as zero */ 00575 request->tsih = htons ( iscsi->tsih ); 00576 request->itt = htonl ( iscsi->itt ); 00577 /* cid left as zero */ 00578 request->cmdsn = htonl ( iscsi->cmdsn ); 00579 request->expstatsn = htonl ( iscsi->statsn + 1 ); 00580 }
| static void iscsi_start_data_out | ( | struct iscsi_session * | iscsi, | |
| unsigned int | datasn | |||
| ) | [static] |
Build iSCSI data-out BHS.
| iscsi | iSCSI session | |
| datasn | Data sequence number within the transfer |
Definition at line 357 of file iscsi.c.
References iscsi_bhs::data_out, iscsi_bhs_data_out::datasn, DBGC, iscsi_bhs_data_out::expstatsn, iscsi_bhs_data_out::flags, htonl, ISCSI_FLAG_FINAL, ISCSI_OPCODE_DATA_OUT, ISCSI_SET_LENGTHS, iscsi_start_tx(), iscsi_session::itt, iscsi_bhs_data_out::itt, iscsi_bhs_data_out::lengths, iscsi_session::lun, iscsi_bhs_data_out::lun, iscsi_bhs_data_out::offset, offset, iscsi_bhs_data_out::opcode, iscsi_session::statsn, iscsi_session::transfer_len, iscsi_session::transfer_offset, iscsi_session::ttt, iscsi_bhs_data_out::ttt, and iscsi_session::tx_bhs.
Referenced by iscsi_data_out_done(), and iscsi_rx_r2t().
00358 { 00359 struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out; 00360 unsigned long offset; 00361 unsigned long remaining; 00362 unsigned long len; 00363 00364 /* We always send 512-byte Data-Out PDUs; this removes the 00365 * need to worry about the target's MaxRecvDataSegmentLength. 00366 */ 00367 offset = datasn * 512; 00368 remaining = iscsi->transfer_len - offset; 00369 len = remaining; 00370 if ( len > 512 ) 00371 len = 512; 00372 00373 /* Construct BHS and initiate transmission */ 00374 iscsi_start_tx ( iscsi ); 00375 data_out->opcode = ISCSI_OPCODE_DATA_OUT; 00376 if ( len == remaining ) 00377 data_out->flags = ( ISCSI_FLAG_FINAL ); 00378 ISCSI_SET_LENGTHS ( data_out->lengths, 0, len ); 00379 data_out->lun = iscsi->lun; 00380 data_out->itt = htonl ( iscsi->itt ); 00381 data_out->ttt = htonl ( iscsi->ttt ); 00382 data_out->expstatsn = htonl ( iscsi->statsn + 1 ); 00383 data_out->datasn = htonl ( datasn ); 00384 data_out->offset = htonl ( iscsi->transfer_offset + offset ); 00385 DBGC ( iscsi, "iSCSI %p start data out DataSN %#x len %#lx\n", 00386 iscsi, datasn, len ); 00387 }
| static void iscsi_rx_buffered_data_done | ( | struct iscsi_session * | iscsi | ) | [static] |
Finish receiving PDU data into buffer.
| iscsi | iSCSI session |
Definition at line 89 of file iscsi.c.
References free(), NULL, and iscsi_session::rx_buffer.
Referenced by iscsi_close_connection(), iscsi_free(), and iscsi_rx_login_response().
| static void iscsi_free | ( | struct refcnt * | refcnt | ) | [static] |
Free iSCSI session.
| refcnt | Reference counter |
Definition at line 99 of file iscsi.c.
References iscsi_session::chap, chap_finish(), container_of, free(), iscsi_session::initiator_password, iscsi_session::initiator_username, iscsi_rx_buffered_data_done(), iscsi_session::target_address, iscsi_session::target_iqn, iscsi_session::target_password, and iscsi_session::target_username.
Referenced by iscsi_attach().
00099 { 00100 struct iscsi_session *iscsi = 00101 container_of ( refcnt, struct iscsi_session, refcnt ); 00102 00103 free ( iscsi->target_address ); 00104 free ( iscsi->target_iqn ); 00105 free ( iscsi->initiator_username ); 00106 free ( iscsi->initiator_password ); 00107 free ( iscsi->target_username ); 00108 free ( iscsi->target_password ); 00109 chap_finish ( &iscsi->chap ); 00110 iscsi_rx_buffered_data_done ( iscsi ); 00111 free ( iscsi ); 00112 }
| static int iscsi_open_connection | ( | struct iscsi_session * | iscsi | ) | [static] |
Open iSCSI transport-layer connection.
| iscsi | iSCSI session |
| rc | Return status code |
Definition at line 120 of file iscsi.c.
References assert, DBGC, htons, ISCSI_RX_BHS, iscsi_start_login(), ISCSI_STATUS_AUTH_REVERSE_REQUIRED, ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE, ISCSI_STATUS_STRINGS_SECURITY, ISCSI_TX_IDLE, iscsi_session::itt, memset(), NULL, iscsi_session::rx_offset, iscsi_session::rx_state, SOCK_STREAM, iscsi_session::socket, sockaddr_tcpip::st_port, iscsi_session::status, strerror(), iscsi_session::target_address, iscsi_session::target_port, iscsi_session::target_username, iscsi_session::tx_state, and xfer_open_named_socket().
Referenced by iscsi_command(), iscsi_rx_login_response(), and iscsi_socket_close().
00120 { 00121 struct sockaddr_tcpip target; 00122 int rc; 00123 00124 assert ( iscsi->tx_state == ISCSI_TX_IDLE ); 00125 assert ( iscsi->rx_state == ISCSI_RX_BHS ); 00126 assert ( iscsi->rx_offset == 0 ); 00127 00128 /* Open socket */ 00129 memset ( &target, 0, sizeof ( target ) ); 00130 target.st_port = htons ( iscsi->target_port ); 00131 if ( ( rc = xfer_open_named_socket ( &iscsi->socket, SOCK_STREAM, 00132 ( struct sockaddr * ) &target, 00133 iscsi->target_address, 00134 NULL ) ) != 0 ) { 00135 DBGC ( iscsi, "iSCSI %p could not open socket: %s\n", 00136 iscsi, strerror ( rc ) ); 00137 return rc; 00138 } 00139 00140 /* Enter security negotiation phase */ 00141 iscsi->status = ( ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE | 00142 ISCSI_STATUS_STRINGS_SECURITY ); 00143 if ( iscsi->target_username ) 00144 iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_REQUIRED; 00145 00146 /* Assign fresh initiator task tag */ 00147 iscsi->itt++; 00148 00149 /* Initiate login */ 00150 iscsi_start_login ( iscsi ); 00151 00152 return 0; 00153 }
| static void iscsi_close_connection | ( | struct iscsi_session * | iscsi, | |
| int | rc | |||
| ) | [static] |
Close iSCSI transport-layer connection.
| iscsi | iSCSI session | |
| rc | Reason for close |
Definition at line 164 of file iscsi.c.
References iscsi_session::chap, chap_finish(), ISCSI_RX_BHS, iscsi_rx_buffered_data_done(), ISCSI_TX_IDLE, iscsi_session::rx_offset, iscsi_session::rx_state, iscsi_session::socket, iscsi_session::status, iscsi_session::tx_state, and xfer_close().
Referenced by iscsi_detach(), iscsi_rx_login_response(), iscsi_socket_close(), and iscsi_socket_deliver_raw().
00164 { 00165 00166 /* Close all data transfer interfaces */ 00167 xfer_close ( &iscsi->socket, rc ); 00168 00169 /* Clear connection status */ 00170 iscsi->status = 0; 00171 00172 /* Reset TX and RX state machines */ 00173 iscsi->tx_state = ISCSI_TX_IDLE; 00174 iscsi->rx_state = ISCSI_RX_BHS; 00175 iscsi->rx_offset = 0; 00176 00177 /* Free any temporary dynamically allocated memory */ 00178 chap_finish ( &iscsi->chap ); 00179 iscsi_rx_buffered_data_done ( iscsi ); 00180 }
| static void iscsi_scsi_done | ( | struct iscsi_session * | iscsi, | |
| int | rc | |||
| ) | [static] |
Mark iSCSI SCSI operation as complete.
| iscsi | iSCSI session | |
| rc | Return status code |
Definition at line 195 of file iscsi.c.
References assert, iscsi_session::command, ISCSI_TX_IDLE, NULL, scsi_command::rc, and iscsi_session::tx_state.
Referenced by iscsi_rx_data_in(), iscsi_rx_scsi_response(), iscsi_socket_close(), and iscsi_socket_deliver_raw().
00195 { 00196 00197 assert ( iscsi->tx_state == ISCSI_TX_IDLE ); 00198 assert ( iscsi->command != NULL ); 00199 00200 iscsi->command->rc = rc; 00201 iscsi->command = NULL; 00202 }
| static void iscsi_start_command | ( | struct iscsi_session * | iscsi | ) | [static] |
Build iSCSI SCSI command BHS.
| iscsi | iSCSI session |
Definition at line 220 of file iscsi.c.
References assert, scsi_command::cdb, iscsi_bhs_scsi_command::cdb, iscsi_session::cmdsn, iscsi_bhs_scsi_command::cmdsn, iscsi_session::command, scsi_command::data_in, scsi_command::data_in_len, scsi_command::data_out, scsi_command::data_out_len, DBGC2, iscsi_bhs_scsi_command::exp_len, iscsi_bhs_scsi_command::expstatsn, iscsi_bhs_scsi_command::flags, htonl, ISCSI_COMMAND_ATTR_SIMPLE, ISCSI_COMMAND_FLAG_READ, ISCSI_COMMAND_FLAG_WRITE, ISCSI_FLAG_FINAL, ISCSI_OPCODE_SCSI_COMMAND, iscsi_start_tx(), iscsi_session::itt, iscsi_bhs_scsi_command::itt, iscsi_session::lun, iscsi_bhs_scsi_command::lun, memcpy, iscsi_bhs_scsi_command::opcode, SCSI_CDB_DATA, SCSI_CDB_FORMAT, iscsi_bhs::scsi_command, iscsi_session::statsn, and iscsi_session::tx_bhs.
Referenced by iscsi_command(), and iscsi_rx_login_response().
00220 { 00221 struct iscsi_bhs_scsi_command *command = &iscsi->tx_bhs.scsi_command; 00222 00223 assert ( ! ( iscsi->command->data_in && iscsi->command->data_out ) ); 00224 00225 /* Construct BHS and initiate transmission */ 00226 iscsi_start_tx ( iscsi ); 00227 command->opcode = ISCSI_OPCODE_SCSI_COMMAND; 00228 command->flags = ( ISCSI_FLAG_FINAL | 00229 ISCSI_COMMAND_ATTR_SIMPLE ); 00230 if ( iscsi->command->data_in ) 00231 command->flags |= ISCSI_COMMAND_FLAG_READ; 00232 if ( iscsi->command->data_out ) 00233 command->flags |= ISCSI_COMMAND_FLAG_WRITE; 00234 /* lengths left as zero */ 00235 command->lun = iscsi->lun; 00236 command->itt = htonl ( ++iscsi->itt ); 00237 command->exp_len = htonl ( iscsi->command->data_in_len | 00238 iscsi->command->data_out_len ); 00239 command->cmdsn = htonl ( iscsi->cmdsn ); 00240 command->expstatsn = htonl ( iscsi->statsn + 1 ); 00241 memcpy ( &command->cdb, &iscsi->command->cdb, sizeof ( command->cdb )); 00242 DBGC2 ( iscsi, "iSCSI %p start " SCSI_CDB_FORMAT " %s %#zx\n", 00243 iscsi, SCSI_CDB_DATA ( command->cdb ), 00244 ( iscsi->command->data_in ? "in" : "out" ), 00245 ( iscsi->command->data_in ? 00246 iscsi->command->data_in_len : 00247 iscsi->command->data_out_len ) ); 00248 }
| static int iscsi_rx_scsi_response | ( | struct iscsi_session * | iscsi, | |
| const void * | data, | |||
| size_t | len, | |||
| size_t | remaining | |||
| ) | [static] |
Receive data segment of an iSCSI SCSI response PDU.
| iscsi | iSCSI session | |
| data | Received data | |
| len | Length of received data | |
| remaining | Data remaining after this data |
| rc | Return status code |
Definition at line 259 of file iscsi.c.
References iscsi_session::command, EIO, ISCSI_RESPONSE_COMMAND_COMPLETE, iscsi_scsi_done(), ISCSI_SENSE_RESPONSE_CODE_OFFSET, iscsi_bhs_scsi_response::response, iscsi_session::rx_bhs, iscsi_session::rx_offset, iscsi_bhs::scsi_response, scsi_command::sense_response, iscsi_bhs_scsi_response::status, and scsi_command::status.
Referenced by iscsi_rx_data().
00261 { 00262 struct iscsi_bhs_scsi_response *response 00263 = &iscsi->rx_bhs.scsi_response; 00264 int sense_offset; 00265 00266 /* Capture the sense response code as it floats past, if present */ 00267 sense_offset = ISCSI_SENSE_RESPONSE_CODE_OFFSET - iscsi->rx_offset; 00268 if ( ( sense_offset >= 0 ) && len ) { 00269 iscsi->command->sense_response = 00270 * ( ( char * ) data + sense_offset ); 00271 } 00272 00273 /* Wait for whole SCSI response to arrive */ 00274 if ( remaining ) 00275 return 0; 00276 00277 /* Record SCSI status code */ 00278 iscsi->command->status = response->status; 00279 00280 /* Check for errors */ 00281 if ( response->response != ISCSI_RESPONSE_COMMAND_COMPLETE ) 00282 return -EIO; 00283 00284 /* Mark as completed */ 00285 iscsi_scsi_done ( iscsi, 0 ); 00286 return 0; 00287 }
| static int iscsi_rx_data_in | ( | struct iscsi_session * | iscsi, | |
| const void * | data, | |||
| size_t | len, | |||
| size_t | remaining | |||
| ) | [static] |
Receive data segment of an iSCSI data-in PDU.
| iscsi | iSCSI session | |
| data | Received data | |
| len | Length of received data | |
| remaining | Data remaining after this data |
| rc | Return status code |
Definition at line 298 of file iscsi.c.
References assert, iscsi_session::command, copy_to_user(), scsi_command::data_in, iscsi_bhs::data_in, scsi_command::data_in_len, iscsi_bhs_data_in::flags, ISCSI_DATA_FLAG_STATUS, ISCSI_FLAG_FINAL, iscsi_scsi_done(), ntohl, NULL, iscsi_bhs_data_in::offset, offset, iscsi_session::rx_bhs, iscsi_session::rx_offset, iscsi_bhs_data_in::status, and scsi_command::status.
Referenced by iscsi_rx_data().
00300 { 00301 struct iscsi_bhs_data_in *data_in = &iscsi->rx_bhs.data_in; 00302 unsigned long offset; 00303 00304 /* Copy data to data-in buffer */ 00305 offset = ntohl ( data_in->offset ) + iscsi->rx_offset; 00306 assert ( iscsi->command != NULL ); 00307 assert ( iscsi->command->data_in ); 00308 assert ( ( offset + len ) <= iscsi->command->data_in_len ); 00309 copy_to_user ( iscsi->command->data_in, offset, data, len ); 00310 00311 /* Wait for whole SCSI response to arrive */ 00312 if ( remaining ) 00313 return 0; 00314 00315 /* Mark as completed if status is present */ 00316 if ( data_in->flags & ISCSI_DATA_FLAG_STATUS ) { 00317 assert ( ( offset + len ) == iscsi->command->data_in_len ); 00318 assert ( data_in->flags & ISCSI_FLAG_FINAL ); 00319 iscsi->command->status = data_in->status; 00320 /* iSCSI cannot return an error status via a data-in */ 00321 iscsi_scsi_done ( iscsi, 0 ); 00322 } 00323 00324 return 0; 00325 }
| static int iscsi_rx_r2t | ( | struct iscsi_session * | iscsi, | |
| const void *data | __unused, | |||
| size_t len | __unused, | |||
| size_t remaining | __unused | |||
| ) | [static] |
Receive data segment of an iSCSI R2T PDU.
| iscsi | iSCSI session | |
| data | Received data | |
| len | Length of received data | |
| remaining | Data remaining after this data |
| rc | Return status code |
Definition at line 336 of file iscsi.c.
References iscsi_start_data_out(), iscsi_bhs_r2t::len, ntohl, iscsi_bhs_r2t::offset, iscsi_bhs::r2t, iscsi_session::rx_bhs, iscsi_session::transfer_len, iscsi_session::transfer_offset, iscsi_bhs_r2t::ttt, and iscsi_session::ttt.
Referenced by iscsi_rx_data().
00338 { 00339 struct iscsi_bhs_r2t *r2t = &iscsi->rx_bhs.r2t; 00340 00341 /* Record transfer parameters and trigger first data-out */ 00342 iscsi->ttt = ntohl ( r2t->ttt ); 00343 iscsi->transfer_offset = ntohl ( r2t->offset ); 00344 iscsi->transfer_len = ntohl ( r2t->len ); 00345 iscsi_start_data_out ( iscsi, 0 ); 00346 00347 return 0; 00348 }
| static void iscsi_data_out_done | ( | struct iscsi_session * | iscsi | ) | [static] |
Complete iSCSI data-out PDU transmission.
| iscsi | iSCSI session |
Definition at line 395 of file iscsi.c.
References iscsi_bhs::data_out, iscsi_bhs_data_out::datasn, iscsi_bhs_data_out::flags, ISCSI_FLAG_FINAL, iscsi_start_data_out(), ntohl, and iscsi_session::tx_bhs.
Referenced by iscsi_tx_done().
00395 { 00396 struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out; 00397 00398 /* If we haven't reached the end of the sequence, start 00399 * sending the next data-out PDU. 00400 */ 00401 if ( ! ( data_out->flags & ISCSI_FLAG_FINAL ) ) 00402 iscsi_start_data_out ( iscsi, ntohl ( data_out->datasn ) + 1 ); 00403 }
| static int iscsi_tx_data_out | ( | struct iscsi_session * | iscsi | ) | [static] |
Send iSCSI data-out data segment.
| iscsi | iSCSI session |
| rc | Return status code |
Definition at line 411 of file iscsi.c.
References assert, iscsi_session::command, copy_from_user(), scsi_command::data_out, iscsi_bhs::data_out, scsi_command::data_out_len, ENOMEM, iob_put, ISCSI_DATA_LEN, iscsi_bhs_data_out::lengths, ntohl, NULL, iscsi_bhs_data_out::offset, offset, iscsi_session::socket, iscsi_session::tx_bhs, xfer_alloc_iob(), and xfer_deliver_iob().
Referenced by iscsi_tx_data().
00411 { 00412 struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out; 00413 struct io_buffer *iobuf; 00414 unsigned long offset; 00415 size_t len; 00416 00417 offset = ntohl ( data_out->offset ); 00418 len = ISCSI_DATA_LEN ( data_out->lengths ); 00419 00420 assert ( iscsi->command != NULL ); 00421 assert ( iscsi->command->data_out ); 00422 assert ( ( offset + len ) <= iscsi->command->data_out_len ); 00423 00424 iobuf = xfer_alloc_iob ( &iscsi->socket, len ); 00425 if ( ! iobuf ) 00426 return -ENOMEM; 00427 00428 copy_from_user ( iob_put ( iobuf, len ), 00429 iscsi->command->data_out, offset, len ); 00430 00431 return xfer_deliver_iob ( &iscsi->socket, iobuf ); 00432 }
| static int iscsi_build_login_request_strings | ( | struct iscsi_session * | iscsi, | |
| void * | data, | |||
| size_t | len | |||
| ) | [static] |
Build iSCSI login request strings.
| iscsi | iSCSI session |
HeaderDigest=None DataDigest=None MaxConnections is irrelevant; we make only one connection anyway [4] InitialR2T=Yes [1] ImmediateData is irrelevant; we never send immediate data [4] MaxRecvDataSegmentLength=8192 (default; we don't care) [3] MaxBurstLength=262144 (default; we don't care) [3] FirstBurstLength=262144 (default; we don't care) DefaultTime2Wait=0 [2] DefaultTime2Retain=0 [2] MaxOutstandingR2T=1 DataPDUInOrder=Yes DataSequenceInOrder=Yes ErrorRecoveryLevel=0
[1] InitialR2T has an OR resolution function, so the target may force us to use it. We therefore simplify our logic by always using it.
[2] These ensure that we can safely start a new task once we have reconnected after a failure, without having to manually tidy up after the old one.
[3] We are quite happy to use the RFC-defined default values for these parameters, but some targets (notably OpenSolaris) incorrectly assume a default value of zero, so we explicitly specify the default values.
[4] We are quite happy to use the RFC-defined default values for these parameters, but some targets (notably a QNAP TS-639Pro) fail unless they are supplied, so we explicitly specify the default values.
Definition at line 481 of file iscsi.c.
References assert, iscsi_session::chap, iscsi_session::chap_challenge, iscsi_session::initiator_username, iscsi_initiator_iqn(), ISCSI_STATUS_STRINGS_CHAP_ALGORITHM, ISCSI_STATUS_STRINGS_CHAP_CHALLENGE, ISCSI_STATUS_STRINGS_CHAP_RESPONSE, ISCSI_STATUS_STRINGS_OPERATIONAL, ISCSI_STATUS_STRINGS_SECURITY, NULL, chap_response::response, chap_response::response_len, ssnprintf(), iscsi_session::status, iscsi_session::target_iqn, and iscsi_session::target_username.
Referenced by iscsi_start_login(), and iscsi_tx_login_request().
00482 { 00483 unsigned int used = 0; 00484 unsigned int i; 00485 const char *auth_method; 00486 00487 if ( iscsi->status & ISCSI_STATUS_STRINGS_SECURITY ) { 00488 /* Default to allowing no authentication */ 00489 auth_method = "None"; 00490 /* If we have a credential to supply, permit CHAP */ 00491 if ( iscsi->initiator_username ) 00492 auth_method = "CHAP,None"; 00493 /* If we have a credential to check, force CHAP */ 00494 if ( iscsi->target_username ) 00495 auth_method = "CHAP"; 00496 used += ssnprintf ( data + used, len - used, 00497 "InitiatorName=%s%c" 00498 "TargetName=%s%c" 00499 "SessionType=Normal%c" 00500 "AuthMethod=%s%c", 00501 iscsi_initiator_iqn(), 0, 00502 iscsi->target_iqn, 0, 0, 00503 auth_method, 0 ); 00504 } 00505 00506 if ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_ALGORITHM ) { 00507 used += ssnprintf ( data + used, len - used, "CHAP_A=5%c", 0 ); 00508 } 00509 00510 if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_RESPONSE ) ) { 00511 assert ( iscsi->initiator_username != NULL ); 00512 used += ssnprintf ( data + used, len - used, 00513 "CHAP_N=%s%cCHAP_R=0x", 00514 iscsi->initiator_username, 0 ); 00515 for ( i = 0 ; i < iscsi->chap.response_len ; i++ ) { 00516 used += ssnprintf ( data + used, len - used, "%02x", 00517 iscsi->chap.response[i] ); 00518 } 00519 used += ssnprintf ( data + used, len - used, "%c", 0 ); 00520 } 00521 00522 if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_CHALLENGE ) ) { 00523 used += ssnprintf ( data + used, len - used, 00524 "CHAP_I=%d%cCHAP_C=0x", 00525 iscsi->chap_challenge[0], 0 ); 00526 for ( i = 1 ; i < sizeof ( iscsi->chap_challenge ) ; i++ ) { 00527 used += ssnprintf ( data + used, len - used, "%02x", 00528 iscsi->chap_challenge[i] ); 00529 } 00530 used += ssnprintf ( data + used, len - used, "%c", 0 ); 00531 } 00532 00533 if ( iscsi->status & ISCSI_STATUS_STRINGS_OPERATIONAL ) { 00534 used += ssnprintf ( data + used, len - used, 00535 "HeaderDigest=None%c" 00536 "DataDigest=None%c" 00537 "MaxConnections=1%c" 00538 "InitialR2T=Yes%c" 00539 "ImmediateData=No%c" 00540 "MaxRecvDataSegmentLength=8192%c" 00541 "MaxBurstLength=262144%c" 00542 "DefaultTime2Wait=0%c" 00543 "DefaultTime2Retain=0%c" 00544 "MaxOutstandingR2T=1%c" 00545 "DataPDUInOrder=Yes%c" 00546 "DataSequenceInOrder=Yes%c" 00547 "ErrorRecoveryLevel=0%c", 00548 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 00549 } 00550 00551 return used; 00552 }
| static void iscsi_login_request_done | ( | struct iscsi_session * | iscsi | ) | [static] |
Complete iSCSI login request PDU transmission.
| iscsi | iSCSI session |
Definition at line 588 of file iscsi.c.
References iscsi_session::chap, chap_finish(), ISCSI_STATUS_STRINGS_MASK, and iscsi_session::status.
Referenced by iscsi_tx_done().
00588 { 00589 00590 /* Clear any "strings to send" flags */ 00591 iscsi->status &= ~ISCSI_STATUS_STRINGS_MASK; 00592 00593 /* Free any dynamically allocated storage used for login */ 00594 chap_finish ( &iscsi->chap ); 00595 }
| static int iscsi_tx_login_request | ( | struct iscsi_session * | iscsi | ) | [static] |
Transmit data segment of an iSCSI login request PDU.
| iscsi | iSCSI session |
| rc | Return status code |
Definition at line 605 of file iscsi.c.
References io_buffer::data, ENOMEM, iob_put, iscsi_build_login_request_strings(), ISCSI_DATA_LEN, iscsi_bhs_login_request::lengths, iscsi_bhs::login_request, iscsi_session::socket, iscsi_session::tx_bhs, xfer_alloc_iob(), and xfer_deliver_iob().
Referenced by iscsi_tx_data().
00605 { 00606 struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request; 00607 struct io_buffer *iobuf; 00608 size_t len; 00609 00610 len = ISCSI_DATA_LEN ( request->lengths ); 00611 iobuf = xfer_alloc_iob ( &iscsi->socket, len ); 00612 if ( ! iobuf ) 00613 return -ENOMEM; 00614 iob_put ( iobuf, len ); 00615 iscsi_build_login_request_strings ( iscsi, iobuf->data, len ); 00616 return xfer_deliver_iob ( &iscsi->socket, iobuf ); 00617 }
| static int iscsi_handle_targetaddress_value | ( | struct iscsi_session * | iscsi, | |
| const char * | value | |||
| ) | [static] |
Handle iSCSI TargetAddress text value.
| iscsi | iSCSI session | |
| value | TargetAddress value |
| rc | Return status code |
Definition at line 626 of file iscsi.c.
References DBGC, ENOMEM, free(), htons, ISCSI_PORT, NULL, strchr(), strdup(), strtoul(), iscsi_session::target_address, and iscsi_session::target_port.
00627 { 00628 char *separator; 00629 00630 DBGC ( iscsi, "iSCSI %p will redirect to %s\n", iscsi, value ); 00631 00632 /* Replace target address */ 00633 free ( iscsi->target_address ); 00634 iscsi->target_address = strdup ( value ); 00635 if ( ! iscsi->target_address ) 00636 return -ENOMEM; 00637 00638 /* Replace target port */ 00639 iscsi->target_port = htons ( ISCSI_PORT ); 00640 separator = strchr ( iscsi->target_address, ':' ); 00641 if ( separator ) { 00642 *separator = '\0'; 00643 iscsi->target_port = strtoul ( ( separator + 1 ), NULL, 0 ); 00644 } 00645 00646 return 0; 00647 }
| static int iscsi_handle_authmethod_value | ( | struct iscsi_session * | iscsi, | |
| const char * | value | |||
| ) | [static] |
Handle iSCSI AuthMethod text value.
| iscsi | iSCSI session | |
| value | AuthMethod value |
| rc | Return status code |
Definition at line 656 of file iscsi.c.
References DBGC, ISCSI_STATUS_AUTH_FORWARD_REQUIRED, ISCSI_STATUS_STRINGS_CHAP_ALGORITHM, iscsi_session::status, and strcmp().
00657 { 00658 00659 /* If server requests CHAP, send the CHAP_A string */ 00660 if ( strcmp ( value, "CHAP" ) == 0 ) { 00661 DBGC ( iscsi, "iSCSI %p initiating CHAP authentication\n", 00662 iscsi ); 00663 iscsi->status |= ( ISCSI_STATUS_STRINGS_CHAP_ALGORITHM | 00664 ISCSI_STATUS_AUTH_FORWARD_REQUIRED ); 00665 } 00666 00667 return 0; 00668 }
| static int iscsi_handle_chap_a_value | ( | struct iscsi_session * | iscsi, | |
| const char * | value | |||
| ) | [static] |
Handle iSCSI CHAP_A text value.
| iscsi | iSCSI session | |
| value | CHAP_A value |
| rc | Return status code |
Definition at line 677 of file iscsi.c.
References DBGC, EPROTO_INVALID_CHAP_ALGORITHM, and strcmp().
00678 { 00679 00680 /* We only ever offer "5" (i.e. MD5) as an algorithm, so if 00681 * the server responds with anything else it is a protocol 00682 * violation. 00683 */ 00684 if ( strcmp ( value, "5" ) != 0 ) { 00685 DBGC ( iscsi, "iSCSI %p got invalid CHAP algorithm \"%s\"\n", 00686 iscsi, value ); 00687 return -EPROTO_INVALID_CHAP_ALGORITHM; 00688 } 00689 00690 return 0; 00691 }
| static int iscsi_handle_chap_i_value | ( | struct iscsi_session * | iscsi, | |
| const char * | value | |||
| ) | [static] |
Handle iSCSI CHAP_I text value.
| iscsi | iSCSI session | |
| value | CHAP_I value |
| rc | Return status code |
Definition at line 700 of file iscsi.c.
References iscsi_session::chap, chap_finish(), chap_init(), chap_set_identifier(), chap_update(), DBGC, EPROTO_INVALID_CHAP_IDENTIFIER, iscsi_session::initiator_password, md5_algorithm, strerror(), strlen(), and strtoul().
00701 { 00702 unsigned int identifier; 00703 char *endp; 00704 int rc; 00705 00706 /* The CHAP identifier is an integer value */ 00707 identifier = strtoul ( value, &endp, 0 ); 00708 if ( *endp != '\0' ) { 00709 DBGC ( iscsi, "iSCSI %p saw invalid CHAP identifier \"%s\"\n", 00710 iscsi, value ); 00711 return -EPROTO_INVALID_CHAP_IDENTIFIER; 00712 } 00713 00714 /* Prepare for CHAP with MD5 */ 00715 chap_finish ( &iscsi->chap ); 00716 if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) { 00717 DBGC ( iscsi, "iSCSI %p could not initialise CHAP: %s\n", 00718 iscsi, strerror ( rc ) ); 00719 return rc; 00720 } 00721 00722 /* Identifier and secret are the first two components of the 00723 * challenge. 00724 */ 00725 chap_set_identifier ( &iscsi->chap, identifier ); 00726 if ( iscsi->initiator_password ) { 00727 chap_update ( &iscsi->chap, iscsi->initiator_password, 00728 strlen ( iscsi->initiator_password ) ); 00729 } 00730 00731 return 0; 00732 }
| static int iscsi_handle_chap_c_value | ( | struct iscsi_session * | iscsi, | |
| const char * | value | |||
| ) | [static] |
Handle iSCSI CHAP_C text value.
| iscsi | iSCSI session | |
| value | CHAP_C value |
| rc | Return status code |
Definition at line 741 of file iscsi.c.
References iscsi_session::chap, iscsi_session::chap_challenge, chap_respond(), chap_update(), DBGC, EPROTO_INVALID_CHAP_CHALLENGE, ISCSI_STATUS_STRINGS_CHAP_CHALLENGE, ISCSI_STATUS_STRINGS_CHAP_RESPONSE, memcpy, random(), iscsi_session::status, strtoul(), and iscsi_session::target_username.
00742 { 00743 char buf[3]; 00744 char *endp; 00745 uint8_t byte; 00746 unsigned int i; 00747 00748 /* Check and strip leading "0x" */ 00749 if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) { 00750 DBGC ( iscsi, "iSCSI %p saw invalid CHAP challenge \"%s\"\n", 00751 iscsi, value ); 00752 return -EPROTO_INVALID_CHAP_CHALLENGE; 00753 } 00754 value += 2; 00755 00756 /* Process challenge an octet at a time */ 00757 for ( ; ( value[0] && value[1] ) ; value += 2 ) { 00758 memcpy ( buf, value, 2 ); 00759 buf[2] = 0; 00760 byte = strtoul ( buf, &endp, 16 ); 00761 if ( *endp != '\0' ) { 00762 DBGC ( iscsi, "iSCSI %p saw invalid CHAP challenge " 00763 "byte \"%s\"\n", iscsi, buf ); 00764 return -EPROTO_INVALID_CHAP_CHALLENGE; 00765 } 00766 chap_update ( &iscsi->chap, &byte, sizeof ( byte ) ); 00767 } 00768 00769 /* Build CHAP response */ 00770 DBGC ( iscsi, "iSCSI %p sending CHAP response\n", iscsi ); 00771 chap_respond ( &iscsi->chap ); 00772 iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_RESPONSE; 00773 00774 /* Send CHAP challenge, if applicable */ 00775 if ( iscsi->target_username ) { 00776 iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_CHALLENGE; 00777 /* Generate CHAP challenge data */ 00778 for ( i = 0 ; i < sizeof ( iscsi->chap_challenge ) ; i++ ) { 00779 iscsi->chap_challenge[i] = random(); 00780 } 00781 } 00782 00783 return 0; 00784 }
| static int iscsi_handle_chap_n_value | ( | struct iscsi_session * | iscsi, | |
| const char * | value | |||
| ) | [static] |
Handle iSCSI CHAP_N text value.
| iscsi | iSCSI session | |
| value | CHAP_N value |
| rc | Return status code |
Definition at line 793 of file iscsi.c.
References DBGC, EACCES_INCORRECT_TARGET_USERNAME, strcmp(), and iscsi_session::target_username.
00794 { 00795 00796 /* The target username isn't actually involved at any point in 00797 * the authentication process; it merely serves to identify 00798 * which password the target is using to generate the CHAP 00799 * response. We unnecessarily verify that the username is as 00800 * expected, in order to provide mildly helpful diagnostics if 00801 * the target is supplying the wrong username/password 00802 * combination. 00803 */ 00804 if ( iscsi->target_username && 00805 ( strcmp ( iscsi->target_username, value ) != 0 ) ) { 00806 DBGC ( iscsi, "iSCSI %p target username \"%s\" incorrect " 00807 "(wanted \"%s\")\n", 00808 iscsi, value, iscsi->target_username ); 00809 return -EACCES_INCORRECT_TARGET_USERNAME; 00810 } 00811 00812 return 0; 00813 }
| static int iscsi_handle_chap_r_value | ( | struct iscsi_session * | iscsi, | |
| const char * | value | |||
| ) | [static] |
Handle iSCSI CHAP_R text value.
| iscsi | iSCSI session | |
| value | CHAP_R value |
| rc | Return status code |
Definition at line 822 of file iscsi.c.
References assert, iscsi_session::chap, iscsi_session::chap_challenge, chap_finish(), chap_init(), chap_respond(), chap_set_identifier(), chap_update(), DBGC, EACCES_INCORRECT_TARGET_PASSWORD, EPROTO_INVALID_CHAP_RESPONSE, ISCSI_STATUS_AUTH_REVERSE_OK, md5_algorithm, memcpy, chap_response::response, chap_response::response_len, iscsi_session::status, strerror(), strlen(), strtoul(), and iscsi_session::target_password.
00823 { 00824 char buf[3]; 00825 char *endp; 00826 uint8_t byte; 00827 unsigned int i; 00828 int rc; 00829 00830 /* Generate CHAP response for verification */ 00831 chap_finish ( &iscsi->chap ); 00832 if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) { 00833 DBGC ( iscsi, "iSCSI %p could not initialise CHAP: %s\n", 00834 iscsi, strerror ( rc ) ); 00835 return rc; 00836 } 00837 chap_set_identifier ( &iscsi->chap, iscsi->chap_challenge[0] ); 00838 if ( iscsi->target_password ) { 00839 chap_update ( &iscsi->chap, iscsi->target_password, 00840 strlen ( iscsi->target_password ) ); 00841 } 00842 chap_update ( &iscsi->chap, &iscsi->chap_challenge[1], 00843 ( sizeof ( iscsi->chap_challenge ) - 1 ) ); 00844 chap_respond ( &iscsi->chap ); 00845 00846 /* Check and strip leading "0x" */ 00847 if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) { 00848 DBGC ( iscsi, "iSCSI %p saw invalid CHAP response \"%s\"\n", 00849 iscsi, value ); 00850 return -EPROTO_INVALID_CHAP_RESPONSE; 00851 } 00852 value += 2; 00853 00854 /* Check CHAP response length */ 00855 if ( strlen ( value ) != ( 2 * iscsi->chap.response_len ) ) { 00856 DBGC ( iscsi, "iSCSI %p invalid CHAP response length\n", 00857 iscsi ); 00858 return -EPROTO_INVALID_CHAP_RESPONSE; 00859 } 00860 00861 /* Process response an octet at a time */ 00862 for ( i = 0 ; ( value[0] && value[1] ) ; value += 2, i++ ) { 00863 memcpy ( buf, value, 2 ); 00864 buf[2] = 0; 00865 byte = strtoul ( buf, &endp, 16 ); 00866 if ( *endp != '\0' ) { 00867 DBGC ( iscsi, "iSCSI %p saw invalid CHAP response " 00868 "byte \"%s\"\n", iscsi, buf ); 00869 return -EPROTO_INVALID_CHAP_RESPONSE; 00870 } 00871 if ( byte != iscsi->chap.response[i] ) { 00872 DBGC ( iscsi, "iSCSI %p saw incorrect CHAP " 00873 "response\n", iscsi ); 00874 return -EACCES_INCORRECT_TARGET_PASSWORD; 00875 } 00876 } 00877 assert ( i == iscsi->chap.response_len ); 00878 00879 /* Mark session as authenticated */ 00880 iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_OK; 00881 00882 return 0; 00883 }
| static int iscsi_handle_string | ( | struct iscsi_session * | iscsi, | |
| const char * | string | |||
| ) | [static] |
Handle iSCSI string.
| iscsi | iSCSI session | |
| string | iSCSI string (in "key=value" format) |
| rc | Return status code |
Definition at line 921 of file iscsi.c.
References DBGC, iscsi_string_type::handle, iscsi_string_type::key, strerror(), strlen(), and strncmp().
Referenced by iscsi_handle_strings().
00922 { 00923 struct iscsi_string_type *type; 00924 size_t key_len; 00925 int rc; 00926 00927 for ( type = iscsi_string_types ; type->key ; type++ ) { 00928 key_len = strlen ( type->key ); 00929 if ( strncmp ( string, type->key, key_len ) != 0 ) 00930 continue; 00931 DBGC ( iscsi, "iSCSI %p handling %s\n", iscsi, string ); 00932 if ( ( rc = type->handle ( iscsi, 00933 ( string + key_len ) ) ) != 0 ) { 00934 DBGC ( iscsi, "iSCSI %p could not handle %s: %s\n", 00935 iscsi, string, strerror ( rc ) ); 00936 return rc; 00937 } 00938 return 0; 00939 } 00940 DBGC ( iscsi, "iSCSI %p ignoring %s\n", iscsi, string ); 00941 return 0; 00942 }
| static int iscsi_handle_strings | ( | struct iscsi_session * | iscsi, | |
| const char * | strings, | |||
| size_t | len | |||
| ) | [static] |
Handle iSCSI strings.
| iscsi | iSCSI session | |
| string | iSCSI string buffer | |
| len | Length of string buffer |
| rc | Return status code |
Definition at line 952 of file iscsi.c.
References iscsi_handle_string(), and strnlen().
Referenced by iscsi_rx_login_response().
00953 { 00954 size_t string_len; 00955 int rc; 00956 00957 /* Handle each string in turn, taking care not to overrun the 00958 * data buffer in case of badly-terminated data. 00959 */ 00960 while ( 1 ) { 00961 string_len = ( strnlen ( strings, len ) + 1 ); 00962 if ( string_len > len ) 00963 break; 00964 if ( ( rc = iscsi_handle_string ( iscsi, strings ) ) != 0 ) 00965 return rc; 00966 strings += string_len; 00967 len -= string_len; 00968 } 00969 return 0; 00970 }
| static int iscsi_rx_buffered_data | ( | struct iscsi_session * | iscsi, | |
| const void * | data, | |||
| size_t | len | |||
| ) | [static] |
Receive PDU data into buffer.
| iscsi | iSCSI session | |
| data | Data to receive | |
| len | Length of data |
| rc | Return status code |
Definition at line 985 of file iscsi.c.
References assert, ENOMEM, malloc(), memcpy, iscsi_session::rx_buffer, iscsi_session::rx_len, and iscsi_session::rx_offset.
Referenced by iscsi_rx_login_response().
00986 { 00987 00988 /* Allocate buffer on first call */ 00989 if ( ! iscsi->rx_buffer ) { 00990 iscsi->rx_buffer = malloc ( iscsi->rx_len ); 00991 if ( ! iscsi->rx_buffer ) 00992 return -ENOMEM; 00993 } 00994 00995 /* Copy data to buffer */ 00996 assert ( ( iscsi->rx_offset + len ) <= iscsi->rx_len ); 00997 memcpy ( ( iscsi->rx_buffer + iscsi->rx_offset ), data, len ); 00998 00999 return 0; 01000 }
| static int iscsi_status_to_rc | ( | unsigned int | status_class, | |
| unsigned int | status_detail | |||
| ) | [static] |
Convert iSCSI response status to return status code.
| status_class | iSCSI status class | |
| status_detail | iSCSI status detail |
| rc | Return status code |
Definition at line 1009 of file iscsi.c.
References EINVAL, EIO, ENODEV, ENOTSUP_INITIATOR_STATUS, EPERM_INITIATOR_AUTHENTICATION, EPERM_INITIATOR_AUTHORISATION, ISCSI_STATUS_INITIATOR_ERROR, ISCSI_STATUS_INITIATOR_ERROR_AUTHENTICATION, ISCSI_STATUS_INITIATOR_ERROR_AUTHORISATION, ISCSI_STATUS_INITIATOR_ERROR_NOT_FOUND, ISCSI_STATUS_INITIATOR_ERROR_REMOVED, and ISCSI_STATUS_TARGET_ERROR.
Referenced by iscsi_rx_login_response().
01010 { 01011 switch ( status_class ) { 01012 case ISCSI_STATUS_INITIATOR_ERROR : 01013 switch ( status_detail ) { 01014 case ISCSI_STATUS_INITIATOR_ERROR_AUTHENTICATION : 01015 return -EPERM_INITIATOR_AUTHENTICATION; 01016 case ISCSI_STATUS_INITIATOR_ERROR_AUTHORISATION : 01017 return -EPERM_INITIATOR_AUTHORISATION; 01018 case ISCSI_STATUS_INITIATOR_ERROR_NOT_FOUND : 01019 case ISCSI_STATUS_INITIATOR_ERROR_REMOVED : 01020 return -ENODEV; 01021 default : 01022 return -ENOTSUP_INITIATOR_STATUS; 01023 } 01024 case ISCSI_STATUS_TARGET_ERROR : 01025 return -EIO; 01026 default : 01027 return -EINVAL; 01028 } 01029 }
| static int iscsi_rx_login_response | ( | struct iscsi_session * | iscsi, | |
| const void * | data, | |||
| size_t | len, | |||
| size_t | remaining | |||
| ) | [static] |
Receive data segment of an iSCSI login response PDU.
| iscsi | iSCSI session | |
| data | Received data | |
| len | Length of received data | |
| remaining | Data remaining after this data |
| rc | Return status code |
Definition at line 1040 of file iscsi.c.
References DBGC, EIO, EPROTO, iscsi_bhs_login_response::flags, iscsi_session::instant_rc, iscsi_close_connection(), iscsi_handle_strings(), ISCSI_LOGIN_FLAG_TRANSITION, ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE, ISCSI_LOGIN_NSG_MASK, ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION, iscsi_open_connection(), iscsi_rx_buffered_data(), iscsi_rx_buffered_data_done(), iscsi_start_command(), iscsi_start_login(), ISCSI_STATUS_AUTH_REVERSE_OK, ISCSI_STATUS_AUTH_REVERSE_REQUIRED, ISCSI_STATUS_FULL_FEATURE_PHASE, ISCSI_STATUS_OPERATIONAL_NEGOTIATION_PHASE, ISCSI_STATUS_PHASE_MASK, ISCSI_STATUS_REDIRECT, ISCSI_STATUS_STRINGS_MASK, ISCSI_STATUS_STRINGS_OPERATIONAL, iscsi_status_to_rc(), iscsi_bhs::login_response, ntohl, iscsi_session::retry_count, iscsi_session::rx_bhs, iscsi_session::rx_buffer, iscsi_session::rx_len, iscsi_session::status, iscsi_bhs_login_response::status_class, iscsi_bhs_login_response::status_detail, strerror(), iscsi_bhs_login_response::tsih, and iscsi_session::tsih.
Referenced by iscsi_rx_data().
01042 { 01043 struct iscsi_bhs_login_response *response 01044 = &iscsi->rx_bhs.login_response; 01045 int rc; 01046 01047 /* Buffer up the PDU data */ 01048 if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) { 01049 DBGC ( iscsi, "iSCSI %p could not buffer login response: %s\n", 01050 iscsi, strerror ( rc ) ); 01051 return rc; 01052 } 01053 if ( remaining ) 01054 return 0; 01055 01056 /* Process string data and discard string buffer */ 01057 if ( ( rc = iscsi_handle_strings ( iscsi, iscsi->rx_buffer, 01058 iscsi->rx_len ) ) != 0 ) 01059 return rc; 01060 iscsi_rx_buffered_data_done ( iscsi ); 01061 01062 /* Check for login redirection */ 01063 if ( response->status_class == ISCSI_STATUS_REDIRECT ) { 01064 DBGC ( iscsi, "iSCSI %p redirecting to new server\n", iscsi ); 01065 iscsi_close_connection ( iscsi, 0 ); 01066 if ( ( rc = iscsi_open_connection ( iscsi ) ) != 0 ) { 01067 DBGC ( iscsi, "iSCSI %p could not redirect: %s\n ", 01068 iscsi, strerror ( rc ) ); 01069 return rc; 01070 } 01071 return 0; 01072 } 01073 01074 /* Check for fatal errors */ 01075 if ( response->status_class != 0 ) { 01076 DBGC ( iscsi, "iSCSI login failure: class %02x detail %02x\n", 01077 response->status_class, response->status_detail ); 01078 rc = iscsi_status_to_rc ( response->status_class, 01079 response->status_detail ); 01080 iscsi->instant_rc = rc; 01081 return rc; 01082 } 01083 01084 /* Handle login transitions */ 01085 if ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) { 01086 iscsi->status &= ~( ISCSI_STATUS_PHASE_MASK | 01087 ISCSI_STATUS_STRINGS_MASK ); 01088 switch ( response->flags & ISCSI_LOGIN_NSG_MASK ) { 01089 case ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION: 01090 iscsi->status |= 01091 ( ISCSI_STATUS_OPERATIONAL_NEGOTIATION_PHASE | 01092 ISCSI_STATUS_STRINGS_OPERATIONAL ); 01093 break; 01094 case ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE: 01095 iscsi->status |= ISCSI_STATUS_FULL_FEATURE_PHASE; 01096 break; 01097 default: 01098 DBGC ( iscsi, "iSCSI %p got invalid response flags " 01099 "%02x\n", iscsi, response->flags ); 01100 return -EIO; 01101 } 01102 } 01103 01104 /* Send next login request PDU if we haven't reached the full 01105 * feature phase yet. 01106 */ 01107 if ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) != 01108 ISCSI_STATUS_FULL_FEATURE_PHASE ) { 01109 iscsi_start_login ( iscsi ); 01110 return 0; 01111 } 01112 01113 /* Check that target authentication was successful (if required) */ 01114 if ( ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) && 01115 ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_OK ) ) { 01116 DBGC ( iscsi, "iSCSI %p nefarious target tried to bypass " 01117 "authentication\n", iscsi ); 01118 return -EPROTO; 01119 } 01120 01121 /* Reset retry count */ 01122 iscsi->retry_count = 0; 01123 01124 /* Record TSIH for future reference */ 01125 iscsi->tsih = ntohl ( response->tsih ); 01126 01127 /* Send the actual SCSI command */ 01128 iscsi_start_command ( iscsi ); 01129 01130 return 0; 01131 }
| static int iscsi_tx_nothing | ( | struct iscsi_session *iscsi | __unused | ) | [static] |
Transmit nothing.
| iscsi | iSCSI session |
| rc | Return status code |
Definition at line 1163 of file iscsi.c.
Referenced by iscsi_tx_step().
| static int iscsi_tx_bhs | ( | struct iscsi_session * | iscsi | ) | [static] |
Transmit basic header segment of an iSCSI PDU.
| iscsi | iSCSI session |
| rc | Return status code |
Definition at line 1173 of file iscsi.c.
References iscsi_session::socket, iscsi_session::tx_bhs, and xfer_deliver_raw().
Referenced by iscsi_tx_step().
01173 { 01174 return xfer_deliver_raw ( &iscsi->socket, &iscsi->tx_bhs, 01175 sizeof ( iscsi->tx_bhs ) ); 01176 }
| static int iscsi_tx_data | ( | struct iscsi_session * | iscsi | ) | [static] |
Transmit data segment of an iSCSI PDU.
| iscsi | iSCSI session |
| rc | Return status code |
Definition at line 1187 of file iscsi.c.
References iscsi_bhs::common, ISCSI_OPCODE_DATA_OUT, ISCSI_OPCODE_LOGIN_REQUEST, ISCSI_OPCODE_MASK, iscsi_tx_data_out(), iscsi_tx_login_request(), iscsi_bhs_common::opcode, and iscsi_session::tx_bhs.
Referenced by iscsi_tx_step().
01187 { 01188 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common; 01189 01190 switch ( common->opcode & ISCSI_OPCODE_MASK ) { 01191 case ISCSI_OPCODE_DATA_OUT: 01192 return iscsi_tx_data_out ( iscsi ); 01193 case ISCSI_OPCODE_LOGIN_REQUEST: 01194 return iscsi_tx_login_request ( iscsi ); 01195 default: 01196 /* Nothing to send in other states */ 01197 return 0; 01198 } 01199 }
| static int iscsi_tx_data_padding | ( | struct iscsi_session * | iscsi | ) | [static] |
Transmit data padding of an iSCSI PDU.
| iscsi | iSCSI session |
| rc | Return status code |
Definition at line 1210 of file iscsi.c.
References iscsi_bhs::common, ISCSI_DATA_PAD_LEN, iscsi_bhs_common::lengths, iscsi_session::socket, iscsi_session::tx_bhs, and xfer_deliver_raw().
Referenced by iscsi_tx_step().
01210 { 01211 static const char pad[] = { '\0', '\0', '\0' }; 01212 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common; 01213 size_t pad_len; 01214 01215 pad_len = ISCSI_DATA_PAD_LEN ( common->lengths ); 01216 if ( ! pad_len ) 01217 return 0; 01218 01219 return xfer_deliver_raw ( &iscsi->socket, pad, pad_len ); 01220 }
| static void iscsi_tx_done | ( | struct iscsi_session * | iscsi | ) | [static] |
Complete iSCSI PDU transmission.
| iscsi | iSCSI session |
Definition at line 1231 of file iscsi.c.
References iscsi_bhs::common, iscsi_data_out_done(), iscsi_login_request_done(), ISCSI_OPCODE_DATA_OUT, ISCSI_OPCODE_LOGIN_REQUEST, ISCSI_OPCODE_MASK, iscsi_bhs_common::opcode, and iscsi_session::tx_bhs.
Referenced by iscsi_tx_step().
01231 { 01232 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common; 01233 01234 switch ( common->opcode & ISCSI_OPCODE_MASK ) { 01235 case ISCSI_OPCODE_DATA_OUT: 01236 iscsi_data_out_done ( iscsi ); 01237 case ISCSI_OPCODE_LOGIN_REQUEST: 01238 iscsi_login_request_done ( iscsi ); 01239 default: 01240 /* No action */ 01241 break; 01242 } 01243 }
| static void iscsi_tx_step | ( | struct process * | process | ) | [static] |
Transmit iSCSI PDU.
| iscsi | iSCSI session | |
| buf | Temporary data buffer | |
| len | Length of temporary data buffer |
Definition at line 1254 of file iscsi.c.
References assert, iscsi_bhs::common, container_of, DBGC, ISCSI_DATA_LEN, ISCSI_DATA_PAD_LEN, ISCSI_TX_AHS, iscsi_tx_bhs(), ISCSI_TX_BHS, iscsi_tx_data(), ISCSI_TX_DATA, iscsi_tx_data_padding(), ISCSI_TX_DATA_PADDING, iscsi_tx_done(), ISCSI_TX_IDLE, iscsi_tx_nothing(), iscsi_bhs_common::lengths, iscsi_session::socket, strerror(), iscsi_session::tx_bhs, iscsi_session::tx_state, and xfer_window().
Referenced by iscsi_attach().
01254 { 01255 struct iscsi_session *iscsi = 01256 container_of ( process, struct iscsi_session, process ); 01257 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common; 01258 int ( * tx ) ( struct iscsi_session *iscsi ); 01259 enum iscsi_tx_state next_state; 01260 size_t tx_len; 01261 int rc; 01262 01263 /* Select fragment to transmit */ 01264 while ( 1 ) { 01265 switch ( iscsi->tx_state ) { 01266 case ISCSI_TX_IDLE: 01267 /* Stop processing */ 01268 return; 01269 case ISCSI_TX_BHS: 01270 tx = iscsi_tx_bhs; 01271 tx_len = sizeof ( iscsi->tx_bhs ); 01272 next_state = ISCSI_TX_AHS; 01273 break; 01274 case ISCSI_TX_AHS: 01275 tx = iscsi_tx_nothing; 01276 tx_len = 0; 01277 next_state = ISCSI_TX_DATA; 01278 break; 01279 case ISCSI_TX_DATA: 01280 tx = iscsi_tx_data; 01281 tx_len = ISCSI_DATA_LEN ( common->lengths ); 01282 next_state = ISCSI_TX_DATA_PADDING; 01283 break; 01284 case ISCSI_TX_DATA_PADDING: 01285 tx = iscsi_tx_data_padding; 01286 tx_len = ISCSI_DATA_PAD_LEN ( common->lengths ); 01287 next_state = ISCSI_TX_IDLE; 01288 break; 01289 default: 01290 assert ( 0 ); 01291 return; 01292 } 01293 01294 /* Check for window availability, if needed */ 01295 if ( tx_len && ( xfer_window ( &iscsi->socket ) == 0 ) ) { 01296 /* Cannot transmit at this point; stop processing */ 01297 return; 01298 } 01299 01300 /* Transmit data */ 01301 if ( ( rc = tx ( iscsi ) ) != 0 ) { 01302 DBGC ( iscsi, "iSCSI %p could not transmit: %s\n", 01303 iscsi, strerror ( rc ) ); 01304 return; 01305 } 01306 01307 /* Move to next state */ 01308 iscsi->tx_state = next_state; 01309 if ( next_state == ISCSI_TX_IDLE ) 01310 iscsi_tx_done ( iscsi ); 01311 } 01312 }
| static int iscsi_rx_bhs | ( | struct iscsi_session * | iscsi, | |
| const void * | data, | |||
| size_t | len, | |||
| size_t remaining | __unused | |||
| ) | [static] |
Receive basic header segment of an iSCSI PDU.
| iscsi | iSCSI session | |
| data | Received data | |
| len | Length of received data | |
| remaining | Data remaining after this data |
| rc | Return status code |
Definition at line 1326 of file iscsi.c.
References iscsi_bhs::bytes, iscsi_bhs::common, DBGC2, ISCSI_DATA_LEN, iscsi_bhs_common::lengths, memcpy, iscsi_bhs_common::opcode, iscsi_session::rx_bhs, and iscsi_session::rx_offset.
Referenced by iscsi_socket_deliver_raw().
01327 { 01328 memcpy ( &iscsi->rx_bhs.bytes[iscsi->rx_offset], data, len ); 01329 if ( ( iscsi->rx_offset + len ) >= sizeof ( iscsi->rx_bhs ) ) { 01330 DBGC2 ( iscsi, "iSCSI %p received PDU opcode %#x len %#x\n", 01331 iscsi, iscsi->rx_bhs.common.opcode, 01332 ISCSI_DATA_LEN ( iscsi->rx_bhs.common.lengths ) ); 01333 } 01334 return 0; 01335 }
| static int iscsi_rx_discard | ( | struct iscsi_session *iscsi | __unused, | |
| const void *data | __unused, | |||
| size_t len | __unused, | |||
| size_t remaining | __unused | |||
| ) | [static] |
Discard portion of an iSCSI PDU.
| iscsi | iSCSI session | |
| data | Received data | |
| len | Length of received data | |
| remaining | Data remaining after this data |
| rc | Return status code |
Definition at line 1348 of file iscsi.c.
Referenced by iscsi_socket_deliver_raw().
| static int iscsi_rx_data | ( | struct iscsi_session * | iscsi, | |
| const void * | data, | |||
| size_t | len, | |||
| size_t | remaining | |||
| ) | [static] |
Receive data segment of an iSCSI PDU.
| iscsi | iSCSI session | |
| data | Received data | |
| len | Length of received data | |
| remaining | Data remaining after this data |
| rc | Return status code |
Definition at line 1367 of file iscsi.c.
References iscsi_session::cmdsn, iscsi_bhs::common_response, DBGC, ENOTSUP_OPCODE, iscsi_bhs_common_response::expcmdsn, ISCSI_OPCODE_DATA_IN, ISCSI_OPCODE_LOGIN_RESPONSE, ISCSI_OPCODE_MASK, ISCSI_OPCODE_R2T, ISCSI_OPCODE_SCSI_RESPONSE, iscsi_rx_data_in(), iscsi_rx_login_response(), iscsi_rx_r2t(), iscsi_rx_scsi_response(), ntohl, iscsi_bhs_common_response::opcode, iscsi_session::rx_bhs, iscsi_bhs_common_response::statsn, and iscsi_session::statsn.
Referenced by iscsi_socket_deliver_raw().
01368 { 01369 struct iscsi_bhs_common_response *response 01370 = &iscsi->rx_bhs.common_response; 01371 01372 /* Update cmdsn and statsn */ 01373 iscsi->cmdsn = ntohl ( response->expcmdsn ); 01374 iscsi->statsn = ntohl ( response->statsn ); 01375 01376 switch ( response->opcode & ISCSI_OPCODE_MASK ) { 01377 case ISCSI_OPCODE_LOGIN_RESPONSE: 01378 return iscsi_rx_login_response ( iscsi, data, len, remaining ); 01379 case ISCSI_OPCODE_SCSI_RESPONSE: 01380 return iscsi_rx_scsi_response ( iscsi, data, len, remaining ); 01381 case ISCSI_OPCODE_DATA_IN: 01382 return iscsi_rx_data_in ( iscsi, data, len, remaining ); 01383 case ISCSI_OPCODE_R2T: 01384 return iscsi_rx_r2t ( iscsi, data, len, remaining ); 01385 default: 01386 if ( remaining ) 01387 return 0; 01388 DBGC ( iscsi, "iSCSI %p unknown opcode %02x\n", iscsi, 01389 response->opcode ); 01390 return -ENOTSUP_OPCODE; 01391 } 01392 }
| static int iscsi_socket_deliver_raw | ( | struct xfer_interface * | socket, | |
| const void * | data, | |||
| size_t | len | |||
| ) | [static] |
Receive new data.
| socket | Transport layer interface | |
| data | Received data | |
| len | Length of received data |
| rc | Return status code |
Definition at line 1409 of file iscsi.c.
References assert, iscsi_bhs::common, container_of, DBGC, EINVAL, ISCSI_AHS_LEN, iscsi_close_connection(), ISCSI_DATA_LEN, ISCSI_DATA_PAD_LEN, ISCSI_RX_AHS, iscsi_rx_bhs(), ISCSI_RX_BHS, iscsi_rx_data(), ISCSI_RX_DATA, ISCSI_RX_DATA_PADDING, iscsi_rx_discard(), iscsi_scsi_done(), iscsi_bhs_common::lengths, iscsi_session::rx_bhs, iscsi_session::rx_len, iscsi_session::rx_offset, iscsi_session::rx_state, and strerror().
01410 { 01411 struct iscsi_session *iscsi = 01412 container_of ( socket, struct iscsi_session, socket ); 01413 struct iscsi_bhs_common *common = &iscsi->rx_bhs.common; 01414 int ( * rx ) ( struct iscsi_session *iscsi, const void *data, 01415 size_t len, size_t remaining ); 01416 enum iscsi_rx_state next_state; 01417 size_t frag_len; 01418 size_t remaining; 01419 int rc; 01420 01421 while ( 1 ) { 01422 switch ( iscsi->rx_state ) { 01423 case ISCSI_RX_BHS: 01424 rx = iscsi_rx_bhs; 01425 iscsi->rx_len = sizeof ( iscsi->rx_bhs ); 01426 next_state = ISCSI_RX_AHS; 01427 break; 01428 case ISCSI_RX_AHS: 01429 rx = iscsi_rx_discard; 01430 iscsi->rx_len = 4 * ISCSI_AHS_LEN ( common->lengths ); 01431 next_state = ISCSI_RX_DATA; 01432 break; 01433 case ISCSI_RX_DATA: 01434 rx = iscsi_rx_data; 01435 iscsi->rx_len = ISCSI_DATA_LEN ( common->lengths ); 01436 next_state = ISCSI_RX_DATA_PADDING; 01437 break; 01438 case ISCSI_RX_DATA_PADDING: 01439 rx = iscsi_rx_discard; 01440 iscsi->rx_len = ISCSI_DATA_PAD_LEN ( common->lengths ); 01441 next_state = ISCSI_RX_BHS; 01442 break; 01443 default: 01444 assert ( 0 ); 01445 return -EINVAL; 01446 } 01447 01448 frag_len = iscsi->rx_len - iscsi->rx_offset; 01449 if ( frag_len > len ) 01450 frag_len = len; 01451 remaining = iscsi->rx_len - iscsi->rx_offset - frag_len; 01452 if ( ( rc = rx ( iscsi, data, frag_len, remaining ) ) != 0 ) { 01453 DBGC ( iscsi, "iSCSI %p could not process received " 01454 "data: %s\n", iscsi, strerror ( rc ) ); 01455 iscsi_close_connection ( iscsi, rc ); 01456 iscsi_scsi_done ( iscsi, rc ); 01457 return rc; 01458 } 01459 01460 iscsi->rx_offset += frag_len; 01461 data += frag_len; 01462 len -= frag_len; 01463 01464 /* If all the data for this state has not yet been 01465 * received, stay in this state for now. 01466 */ 01467 if ( iscsi->rx_offset != iscsi->rx_len ) 01468 return 0; 01469 01470 iscsi->rx_state = next_state; 01471 iscsi->rx_offset = 0; 01472 } 01473 01474 return 0; 01475 }
| static void iscsi_socket_close | ( | struct xfer_interface * | socket, | |
| int | rc | |||
| ) | [static] |
Handle stream connection closure.
| socket | Transport layer interface | |
| rc | Reason for close |
Definition at line 1484 of file iscsi.c.
References container_of, DBGC, ECONNRESET, iscsi_session::instant_rc, iscsi_close_connection(), ISCSI_MAX_RETRIES, iscsi_open_connection(), iscsi_scsi_done(), iscsi_session::retry_count, and strerror().
01484 { 01485 struct iscsi_session *iscsi = 01486 container_of ( socket, struct iscsi_session, socket ); 01487 01488 /* Even a graceful close counts as an error for iSCSI */ 01489 if ( ! rc ) 01490 rc = -ECONNRESET; 01491 01492 /* Close session cleanly */ 01493 iscsi_close_connection ( iscsi, rc ); 01494 01495 /* Retry connection if within the retry limit, otherwise fail */ 01496 if ( ++iscsi->retry_count <= ISCSI_MAX_RETRIES ) { 01497 DBGC ( iscsi, "iSCSI %p retrying connection (retry #%d)\n", 01498 iscsi, iscsi->retry_count ); 01499 if ( ( rc = iscsi_open_connection ( iscsi ) ) != 0 ) { 01500 DBGC ( iscsi, "iSCSI %p could not reconnect: %s\n", 01501 iscsi, strerror ( rc ) ); 01502 iscsi_scsi_done ( iscsi, rc ); 01503 } 01504 } else { 01505 DBGC ( iscsi, "iSCSI %p retry count exceeded\n", iscsi ); 01506 iscsi->instant_rc = rc; 01507 iscsi_scsi_done ( iscsi, rc ); 01508 } 01509 }
| static int iscsi_vredirect | ( | struct xfer_interface * | socket, | |
| int | type, | |||
| va_list | args | |||
| ) | [static] |
Handle redirection event.
| socket | Transport layer interface | |
| type | Location type | |
| args | Remaining arguments depend upon location type |
| rc | Return status code |
Definition at line 1519 of file iscsi.c.
References container_of, LOCATION_SOCKET, memcpy, iscsi_session::target_sockaddr, va_arg, va_copy, va_end, and xfer_vreopen().
01520 { 01521 struct iscsi_session *iscsi = 01522 container_of ( socket, struct iscsi_session, socket ); 01523 va_list tmp; 01524 struct sockaddr *peer; 01525 01526 /* Intercept redirects to a LOCATION_SOCKET and record the IP 01527 * address for the iBFT. This is a bit of a hack, but avoids 01528 * inventing an ioctl()-style call to retrieve the socket 01529 * address from a data-xfer interface. 01530 */ 01531 if ( type == LOCATION_SOCKET ) { 01532 va_copy ( tmp, args ); 01533 ( void ) va_arg ( tmp, int ); /* Discard "semantics" */ 01534 peer = va_arg ( tmp, struct sockaddr * ); 01535 memcpy ( &iscsi->target_sockaddr, peer, 01536 sizeof ( iscsi->target_sockaddr ) ); 01537 va_end ( tmp ); 01538 } 01539 01540 return xfer_vreopen ( socket, type, args ); 01541 }
| static int iscsi_command | ( | struct scsi_device * | scsi, | |
| struct scsi_command * | command | |||
| ) | [static] |
Issue SCSI command.
| rc | Return status code |
Definition at line 1568 of file iscsi.c.
References scsi_device::backend, iscsi_session::command, container_of, iscsi_session::instant_rc, iscsi_open_connection(), iscsi_start_command(), NULL, and iscsi_session::status.
Referenced by iscsi_attach().
01569 { 01570 struct iscsi_session *iscsi = 01571 container_of ( scsi->backend, struct iscsi_session, refcnt ); 01572 int rc; 01573 01574 /* Abort immediately if we have a recorded permanent failure */ 01575 if ( iscsi->instant_rc ) 01576 return iscsi->instant_rc; 01577 01578 /* Record SCSI command */ 01579 iscsi->command = command; 01580 01581 /* Issue command or open connection as appropriate */ 01582 if ( iscsi->status ) { 01583 iscsi_start_command ( iscsi ); 01584 } else { 01585 if ( ( rc = iscsi_open_connection ( iscsi ) ) != 0 ) { 01586 iscsi->command = NULL; 01587 return rc; 01588 } 01589 } 01590 01591 return 0; 01592 }
| void iscsi_detach | ( | struct scsi_device * | scsi | ) |
Shut down iSCSI interface.
| scsi | SCSI device |
Definition at line 1599 of file iscsi.c.
References scsi_device::backend, scsi_device::command, container_of, iscsi_close_connection(), NULL, iscsi_session::process, process_del(), ref_put(), scsi_detached_command(), and iscsi_session::socket.
Referenced by iscsiboot().
01599 { 01600 struct iscsi_session *iscsi = 01601 container_of ( scsi->backend, struct iscsi_session, refcnt ); 01602 01603 xfer_nullify ( &iscsi->socket ); 01604 iscsi_close_connection ( iscsi, 0 ); 01605 process_del ( &iscsi->process ); 01606 scsi->command = scsi_detached_command; 01607 ref_put ( scsi->backend ); 01608 scsi->backend = NULL; 01609 }
| static int iscsi_parse_root_path | ( | struct iscsi_session * | iscsi, | |
| const char * | root_path | |||
| ) | [static] |
Parse iSCSI root path.
| iscsi | iSCSI session | |
| root_path | iSCSI root path (as per RFC4173) |
| rc | Return status code |
Definition at line 1635 of file iscsi.c.
References DBGC, EINVAL, ENOMEM, ISCSI_PORT, iscsi_session::lun, NULL, NUM_RP_COMPONENTS, RP_LUN, RP_PORT, RP_SERVERNAME, RP_TARGETNAME, scsi_parse_lun(), strcpy(), strdup(), strlen(), strtoul(), iscsi_session::target_address, iscsi_session::target_iqn, and iscsi_session::target_port.
Referenced by iscsi_attach().
01636 { 01637 char rp_copy[ strlen ( root_path ) + 1 ]; 01638 char *rp_comp[NUM_RP_COMPONENTS]; 01639 char *rp = rp_copy; 01640 int i = 0; 01641 int rc; 01642 01643 /* Split root path into component parts */ 01644 strcpy ( rp_copy, root_path ); 01645 while ( 1 ) { 01646 rp_comp[i++] = rp; 01647 if ( i == NUM_RP_COMPONENTS ) 01648 break; 01649 for ( ; *rp != ':' ; rp++ ) { 01650 if ( ! *rp ) { 01651 DBGC ( iscsi, "iSCSI %p root path \"%s\" " 01652 "too short\n", iscsi, root_path ); 01653 return -EINVAL; 01654 } 01655 } 01656 *(rp++) = '\0'; 01657 } 01658 01659 /* Use root path components to configure iSCSI session */ 01660 iscsi->target_address = strdup ( rp_comp[RP_SERVERNAME] ); 01661 if ( ! iscsi->target_address ) 01662 return -ENOMEM; 01663 iscsi->target_port = strtoul ( rp_comp[RP_PORT], NULL, 10 ); 01664 if ( ! iscsi->target_port ) 01665 iscsi->target_port = ISCSI_PORT; 01666 if ( ( rc = scsi_parse_lun ( rp_comp[RP_LUN], &iscsi->lun ) ) != 0 ) { 01667 DBGC ( iscsi, "iSCSI %p invalid LUN \"%s\"\n", 01668 iscsi, rp_comp[RP_LUN] ); 01669 return rc; 01670 } 01671 iscsi->target_iqn = strdup ( rp_comp[RP_TARGETNAME] ); 01672 if ( ! iscsi->target_iqn ) 01673 return -ENOMEM; 01674 01675 return 0; 01676 }
| static int iscsi_set_auth | ( | struct iscsi_session * | iscsi, | |
| const char * | initiator_username, | |||
| const char * | initiator_password, | |||
| const char * | target_username, | |||
| const char * | target_password | |||
| ) | [static] |
Set iSCSI authentication details.
| iscsi | iSCSI session | |
| initiator_username | Initiator username, if any | |
| initiator_password | Initiator password, if any | |
| target_username | Target username, if any | |
| target_password | Target password, if any |
| rc | Return status code |
Definition at line 1688 of file iscsi.c.
References DBGC, EINVAL, ENOMEM, iscsi_session::initiator_password, iscsi_session::initiator_username, strdup(), iscsi_session::target_password, and iscsi_session::target_username.
Referenced by iscsi_attach().
01692 { 01693 01694 /* Check for initiator or target credentials */ 01695 if ( initiator_username || initiator_password || 01696 target_username || target_password ) { 01697 01698 /* We must have at least an initiator username+password */ 01699 if ( ! ( initiator_username && initiator_password ) ) 01700 goto invalid_auth; 01701 01702 /* Store initiator credentials */ 01703 iscsi->initiator_username = strdup ( initiator_username ); 01704 if ( ! iscsi->initiator_username ) 01705 return -ENOMEM; 01706 iscsi->initiator_password = strdup ( initiator_password ); 01707 if ( ! iscsi->initiator_password ) 01708 return -ENOMEM; 01709 01710 /* Check for target credentials */ 01711 if ( target_username || target_password ) { 01712 01713 /* We must have target username+password */ 01714 if ( ! ( target_username && target_password ) ) 01715 goto invalid_auth; 01716 01717 /* Store target credentials */ 01718 iscsi->target_username = strdup ( target_username ); 01719 if ( ! iscsi->target_username ) 01720 return -ENOMEM; 01721 iscsi->target_password = strdup ( target_password ); 01722 if ( ! iscsi->target_password ) 01723 return -ENOMEM; 01724 } 01725 } 01726 01727 return 0; 01728 01729 invalid_auth: 01730 DBGC ( iscsi, "iSCSI %p invalid credentials: initiator " 01731 "%sname,%spw, target %sname,%spw\n", iscsi, 01732 ( initiator_username ? "" : "no " ), 01733 ( initiator_password ? "" : "no " ), 01734 ( target_username ? "" : "no " ), 01735 ( target_password ? "" : "no " ) ); 01736 return -EINVAL; 01737 }
| int iscsi_attach | ( | struct scsi_device * | scsi, | |
| const char * | root_path | |||
| ) |
Attach iSCSI interface.
| scsi | SCSI device | |
| root_path | iSCSI root path (as per RFC4173) |
| rc | Return status code |
Definition at line 1746 of file iscsi.c.
References scsi_device::backend, scsi_device::command, DBGC, EINVAL, ENOMEM, ENOTSUP_DISCOVERY, refcnt::free, iscsi_command(), iscsi_free(), iscsi_initiator_password, iscsi_initiator_username, iscsi_parse_root_path(), iscsi_set_auth(), iscsi_target_password, iscsi_target_username, iscsi_tx_step(), iscsi_session::process, process_init(), ref_get(), ref_put(), iscsi_session::refcnt, iscsi_session::socket, iscsi_session::target_address, iscsi_session::target_iqn, xfer_init(), and zalloc().
Referenced by iscsiboot().
01746 { 01747 struct iscsi_session *iscsi; 01748 int rc; 01749 01750 /* Allocate and initialise structure */ 01751 iscsi = zalloc ( sizeof ( *iscsi ) ); 01752 if ( ! iscsi ) 01753 return -ENOMEM; 01754 iscsi->refcnt.free = iscsi_free; 01755 xfer_init ( &iscsi->socket, &iscsi_socket_operations, &iscsi->refcnt ); 01756 process_init ( &iscsi->process, iscsi_tx_step, &iscsi->refcnt ); 01757 01758 /* Parse root path */ 01759 if ( ( rc = iscsi_parse_root_path ( iscsi, root_path ) ) != 0 ) 01760 goto err; 01761 /* Set fields not specified by root path */ 01762 if ( ( rc = iscsi_set_auth ( iscsi, 01763 iscsi_initiator_username, 01764 iscsi_initiator_password, 01765 iscsi_target_username, 01766 iscsi_target_password ) ) != 0 ) 01767 goto err; 01768 01769 /* Sanity checks */ 01770 if ( ! iscsi->target_address ) { 01771 DBGC ( iscsi, "iSCSI %p does not yet support discovery\n", 01772 iscsi ); 01773 rc = -ENOTSUP_DISCOVERY; 01774 goto err; 01775 } 01776 if ( ! iscsi->target_iqn ) { 01777 DBGC ( iscsi, "iSCSI %p no target address supplied in %s\n", 01778 iscsi, root_path ); 01779 rc = -EINVAL; 01780 goto err; 01781 } 01782 01783 /* Attach parent interface, mortalise self, and return */ 01784 scsi->backend = ref_get ( &iscsi->refcnt ); 01785 scsi->command = iscsi_command; 01786 ref_put ( &iscsi->refcnt ); 01787 return 0; 01788 01789 err: 01790 ref_put ( &iscsi->refcnt ); 01791 return rc; 01792 }
| static int apply_iscsi_string_setting | ( | struct iscsi_string_setting * | setting | ) | [static] |
Apply iSCSI setting.
| rc | Return status code |
Definition at line 1874 of file iscsi.c.
References assert, ENOMEM, fetch_setting_len(), fetch_string_setting(), free(), malloc(), NULL, iscsi_string_setting::prefix, iscsi_string_setting::setting, strcpy(), iscsi_string_setting::string, and strlen().
Referenced by apply_iscsi_settings().
01874 { 01875 size_t prefix_len; 01876 int setting_len; 01877 size_t len; 01878 int check_len; 01879 char *p; 01880 01881 /* Free old string */ 01882 free ( *setting->string ); 01883 *setting->string = NULL; 01884 01885 /* Allocate new string */ 01886 prefix_len = strlen ( setting->prefix ); 01887 setting_len = fetch_setting_len ( NULL, setting->setting ); 01888 if ( setting_len < 0 ) { 01889 /* Missing settings are not errors; leave strings as NULL */ 01890 return 0; 01891 } 01892 len = ( prefix_len + setting_len + 1 ); 01893 p = *setting->string = malloc ( len ); 01894 if ( ! p ) 01895 return -ENOMEM; 01896 01897 /* Fill new string */ 01898 strcpy ( p, setting->prefix ); 01899 check_len = fetch_string_setting ( NULL, setting->setting, 01900 ( p + prefix_len ), 01901 ( len - prefix_len ) ); 01902 assert ( check_len == setting_len ); 01903 01904 return 0; 01905 }
| static int apply_iscsi_settings | ( | void | ) | [static] |
Apply iSCSI settings.
| rc | Return status code |
Definition at line 1912 of file iscsi.c.
References apply_iscsi_string_setting(), DBG, setting::name, and iscsi_string_setting::setting.
01912 { 01913 struct iscsi_string_setting *setting; 01914 unsigned int i; 01915 int rc; 01916 01917 for ( i = 0 ; i < ( sizeof ( iscsi_string_settings ) / 01918 sizeof ( iscsi_string_settings[0] ) ) ; i++ ) { 01919 setting = &iscsi_string_settings[i]; 01920 if ( ( rc = apply_iscsi_string_setting ( setting ) ) != 0 ) { 01921 DBG ( "iSCSI could not apply setting %s\n", 01922 setting->setting->name ); 01923 return rc; 01924 } 01925 } 01926 01927 return 0; 01928 }
| const char* iscsi_initiator_iqn | ( | void | ) |
Get iSCSI initiator IQN.
| iscsi | iSCSI session |
| rc | Return status code |
Definition at line 1947 of file iscsi.c.
References iscsi_default_initiator_iqn, and iscsi_explicit_initiator_iqn.
Referenced by ibft_fill_initiator(), and iscsi_build_login_request_strings().
01947 { 01948 01949 if ( iscsi_explicit_initiator_iqn ) 01950 return iscsi_explicit_initiator_iqn; 01951 if ( iscsi_default_initiator_iqn ) 01952 return iscsi_default_initiator_iqn; 01953 return "iqn.2000-09.org.etherboot:UNKNOWN"; 01954 }
char* iscsi_explicit_initiator_iqn [static] |
iSCSI initiator name (explicitly specified)
Definition at line 62 of file iscsi.c.
Referenced by iscsi_initiator_iqn().
char* iscsi_default_initiator_iqn [static] |
Default iSCSI initiator name (constructed from hostname).
Definition at line 65 of file iscsi.c.
Referenced by iscsi_initiator_iqn().
char* iscsi_initiator_username [static] |
char* iscsi_initiator_password [static] |
char* iscsi_target_username [static] |
char* iscsi_target_password [static] |
struct iscsi_string_type iscsi_string_types[] [static] |
Initial value:
{
{ "TargetAddress=", iscsi_handle_targetaddress_value },
{ "AuthMethod=", iscsi_handle_authmethod_value },
{ "CHAP_A=", iscsi_handle_chap_a_value },
{ "CHAP_I=", iscsi_handle_chap_i_value },
{ "CHAP_C=", iscsi_handle_chap_c_value },
{ "CHAP_N=", iscsi_handle_chap_n_value },
{ "CHAP_R=", iscsi_handle_chap_r_value },
{ NULL, NULL }
}
struct xfer_interface_operations iscsi_socket_operations [static] |
Initial value:
{
.close = iscsi_socket_close,
.vredirect = iscsi_vredirect,
.window = unlimited_xfer_window,
.alloc_iob = default_xfer_alloc_iob,
.deliver_iob = xfer_deliver_as_raw,
.deliver_raw = iscsi_socket_deliver_raw,
}
struct iscsi_string_setting iscsi_string_settings[] [static] |
| struct settings_applicator iscsi_settings_applicator __settings_applicator |
1.5.7.1