From 711f54498a2deb7a28f8a1f52af8fea4831e9b7d Mon Sep 17 00:00:00 2001 From: Sebastian Vater Date: Tue, 8 Jul 2025 16:37:35 +0200 Subject: Removed accidental else if clause in server/net.c causing compile failure. Also Added login and other stuff to iscsi.h. --- src/server/iscsi.h | 513 ++++++++++++++++++++++++++++++++++++++++++++++++++--- src/server/net.c | 2 +- 2 files changed, 491 insertions(+), 24 deletions(-) diff --git a/src/server/iscsi.h b/src/server/iscsi.h index b94f9ec..5241728 100644 --- a/src/server/iscsi.h +++ b/src/server/iscsi.h @@ -512,7 +512,7 @@ typedef struct __attribute__((packed)) iscsi_task_mgmt_func_response_packet { // c) if the Referenced Task Tag does not identify an existing task // and the CmdSN indicated by the RefCmdSN field in the Task // Management Function Request is outside the valid CmdSN window, - // then targets must return the "Task does not exist" response. + // then targets must return the "Task does not exist" response uint8_t reserved2; // Reserved for future usage uint8_t total_ahs_len; // TotalAHSLength (MUST be 0 for this PDU) uint8_t ds_len[3]; // DataSegmentLength (MUST be 0 for this PDU) @@ -520,7 +520,7 @@ typedef struct __attribute__((packed)) iscsi_task_mgmt_func_response_packet { uint32_t init_task_tag; // Initiator task tag uint32_t reserved4; // Reserved for future usage uint32_t stat_sn; // StatSN - uint32_t exp_cmnd_sn; // ExpCmdSN + uint32_t exp_cmd_sn; // ExpCmdSN uint32_t max_cmd_sn; // MaxCmdSN uint32_t reserved5[3]; // Reserved for future usage struct iscsi_header_digest hdr_digest; // Optional header digest @@ -626,7 +626,7 @@ typedef struct __attribute__((packed)) iscsi_scsi_data_in_response_packet { // status (and of a residual count) is signaled via the S flag bit. // Although targets MAY choose to send even non-exception status in // separate responses, initiators MUST support non-exception status in - // Data-In PDUs. + // Data-In PDUs uint8_t total_ahs_len; // TotalAHSLength uint8_t ds_len[3]; // DataSegmentLength // This is the data payload length of a SCSI Data-In or SCSI Data-Out @@ -635,11 +635,11 @@ typedef struct __attribute__((packed)) iscsi_scsi_data_in_response_packet { // segments. // The data segments of Data-In and Data-Out PDUs SHOULD be filled to // the integer number of 4-byte words (real payload), unless the F bit - // is set to 1. - uint64_t lun; // Logical Unit Number (LUN) or Reserved. + // is set to 1 + uint64_t lun; // Logical Unit Number (LUN) or Reserved // If the Target Transfer Tag isprovided, then the LUN field MUST hold a // valid value and be consistent with whatever was specified with the command; - // otherwise, the LUN field is reserved. + // otherwise, the LUN field is reserved uint32_t init_task_tag; // Initiator task tag uint32_t target_xfer_tag; // On outgoing data, the Target Transfer Tag is provided to the target // if the transfer is honoring an R2T. In this case, the Target @@ -652,9 +652,9 @@ typedef struct __attribute__((packed)) iscsi_scsi_data_in_response_packet { // Data-In PDU with the A bit set to 1. // The Target Transfer Tag values are not specified by this protocol, // except that the value 0xFFFFFFFF is reserved and means that the - // Target Transfer Tag is not supplied. + // Target Transfer Tag is not supplied uint32_t stat_sn; // StatSN - uint32_t exp_cmnd_sn; // ExpCmdSN + uint32_t exp_cmd_sn; // ExpCmdSN uint32_t max_cmd_sn; // MaxCmdSN uint32_t data_sn; // DataSN // For input (read) or bidirectional Data-In PDUs, the DataSN is the @@ -666,7 +666,7 @@ typedef struct __attribute__((packed)) iscsi_scsi_data_in_response_packet { // within the current output sequence. Either the current output // sequence is identified by the Initiator Task Tag (for unsolicited // data) or it is a data sequence generated for one R2T (for data - // solicited through R2T). + // solicited through R2T) uint32_t buf_offset; // Buffer Offset // The Buffer Offset field contains the offset of this PDU payload data // within the complete data transfer. The sum of the buffer offset and @@ -677,7 +677,7 @@ typedef struct __attribute__((packed)) iscsi_scsi_data_in_response_packet { // increasing buffer offset order and overlays are forbidden. // The ordering between sequences is determined by DataSequenceInOrder. // When set to Yes, it means that sequences have to be in increasing - // buffer offset order and overlays are forbidden. + // buffer offset order and overlays are forbidden uint32_t res_cnt; // Residual Count or Reserved struct iscsi_header_digest hdr_digest; // Optional header digest struct iscsi_ds_cmd_data ds_cmd_data; // Data segment @@ -741,12 +741,12 @@ typedef struct __attribute__((packed)) iscsi_r2t_packet { uint8_t reserved[3]; // Reserved for future usage uint8_t total_ahs_len; // TotalAHSLength, MUST be 0 for this PDU uint8_t ds_len[3]; // DataSegmentLength, MUST be 0 0 for this PDU - uint64_t lun; // Logical Unit Number (LUN) or Reserved. + uint64_t lun; // Logical Unit Number (LUN) or Reserved uint32_t init_task_tag; // Initiator task tag uint32_t target_xfer_tag; // Target transfer tag uint32_t stat_sn; // The StatSN field will contain the next StatSN. The StatSN for this - // connection is not advanced after this PDU is sent. - uint32_t exp_cmnd_sn; // ExpCmdSN + // connection is not advanced after this PDU is sent + uint32_t exp_cmd_sn; // ExpCmdSN uint32_t max_cmd_sn; // MaxCmdSN uint32_t data_sn; // DataSN uint32_t r2t_sn; // R2TSN is the R2T PDU input PDU number within the command identified @@ -756,13 +756,13 @@ typedef struct __attribute__((packed)) iscsi_r2t_packet { uint32_t buf_offset; // Buffer Offset // The target therefore also specifies a buffer offset that // indicates the point at which the data transfer should begin, relative - // to the beginning of the total data transfer. + // to the beginning of the total data transfer uint32_t des_data_xfer_len; // Desired Data Transfer Length // The target specifies how many bytes it wants the initiator to send // because of this R2T PDU. The target may request the data from the // initiator in several chunks, not necessarily in the original order of // the data. The Desired Data Transfer Length MUST NOT be 0 and MUST NOT - // exceed MaxBurstLength. + // exceed MaxBurstLength struct iscsi_header_digest hdr_digest; // Optional header digest } iscsi_r2t_packet; @@ -788,7 +788,7 @@ typedef struct __attribute__((packed)) iscsi_r2t_packet { // log out in Parameter3 seconds, the target should send an Async // PDU with iSCSI event code "Dropped the connection" if possible // or simply terminate the transport connection. Parameter1 and - // Parameter2 are reserved. + // Parameter2 are reserved #define ISCSI_ASYNC_MSG_EVENT_CONNECT_DROP_NOTIFY 0x02 // (Connection Drop Notification) - the target indicates that it // will drop the connection. // The Parameter1 field indicates the CID of the connection that @@ -806,7 +806,7 @@ typedef struct __attribute__((packed)) iscsi_r2t_packet { // other responses should be expected from the target for the // outstanding commands on this connection. // A value of 0 for Parameter2 indicates that reconnect can be - // attempted immediately. + // attempted immediately #define ISCSI_ASYNC_MSG_EVENT_SESSION_DROP_NOTIFY 0x03 // (Session Drop Notification) - the target indicates that it // will drop all the connections of this session. // The Parameter1 field is reserved. @@ -822,7 +822,7 @@ typedef struct __attribute__((packed)) iscsi_r2t_packet { // commands in this session; no other responses should be // expected from the target for the outstanding commands in this // session. A value of 0 for Parameter2 indicates that reconnect - // can be attempted immediately. + // can be attempted immediately #define ISCSI_ASYNC_MSG_EVENT_NEGOTIATION_REQUEST 0x04 // (Negotiation Request) - the target requests parameter // negotiation on this connection. The initiator MUST honor this // request by issuing a Text Request (that can be empty) on the @@ -831,7 +831,7 @@ typedef struct __attribute__((packed)) iscsi_r2t_packet { // on the connection, or by issuing a Logout Request. If the // initiator does not issue a Text Request, the target may // reissue the Asynchronous Message requesting parameter - // negotiation. + // negotiation #define ISCSI_ASYNC_MSG_EVENT_TASK_TERMINATION 0x05 // (Task Termination) - all active tasks for a LU with a matching // LUN field in the Async Message PDU are being terminated. The // receiving initiator iSCSI layer MUST respond to this message @@ -844,7 +844,7 @@ typedef struct __attribute__((packed)) iscsi_r2t_packet { // NOP-Out. // This value of AsyncEvent, however, MUST NOT be used on an // iSCSI session unless the new TaskReporting text key was - // negotiated to FastAbort on the session. + // negotiated to FastAbort on the session #define ISCSI_ASYNC_MSG_EVENT_VENDOR_FIRST 0xF8 // First vendor-specific iSCSI event. The AsyncVCode details the // vendor code, and data MAY accompany the report #define ISCSI_ASYNC_MSG_EVENT_VENDOR_LAST 0xFF // Last vendor-specific iSCSI event. The AsyncVCode details the @@ -862,18 +862,18 @@ typedef struct __attribute__((packed)) iscsi_async_msg_packet { uint8_t total_ahs_len; // TotalAHSLength, MUST be 0 for this PDU uint8_t ds_len[3]; // DataSegmentLength, MUST be 0 0 for this PDU uint64_t lun; // The LUN field MUST be valid if AsyncEvent is 0. Otherwise, this - // field is reserved. + // field is reserved uint32_t tag; // Tag (always 0xFFFFFFFF for now) uint32_t reserved2; // Reserved for future usage uint32_t stat_sn; // StatSN // The StatSN counts this PDU as an acknowledgeable event (the StatSN is // advanced), which allows for initiator and target state synchronization. - uint32_t exp_cmnd_sn; // ExpCmdSN + uint32_t exp_cmd_sn; // ExpCmdSN uint32_t max_cmd_sn; // MaxCmdSN uint8_t async_event; // AsyncEvent uint8_t async_vcode; // AsyncVCode is a vendor-specific detail code that is only valid if the // AsyncEvent field indicates a vendor-specific event. Otherwise, it is - // reserved. + // reserved uint16_t param_1; // Parameter1 or Reserved uint16_t param_2; // Parameter2 or Reserved uint16_t param_3; // Parameter3 or Reserved @@ -883,4 +883,471 @@ typedef struct __attribute__((packed)) iscsi_async_msg_packet { struct iscsi_data_digest data_digest; // Optional data digest } iscsi_async_msg_packet; +/* For a SCSI event, this data accompanies the report in the data + segment and identifies the condition. + + For an iSCSI event, additional vendor-unique data MAY accompany the + Async event. Initiators MAY ignore the data when not understood, + while processing the rest of the PDU. + + If the DataSegmentLength is not 0, the format of the DataSegment is + as follows: +*/ +typedef struct __attribute__((packed)) iscsi_sense_event_data_packet { + uint16_t sense_len; // SenseLength + // This is the length of Sense Data. When the Sense Data field is empty + // (e.g., the event is not a SCSI event), SenseLength is 0 + uint16_t sense_data[0]; // Sense Data + uint16_t event_data[0]; // iSCSI Event Data +} iscsi_sense_event_data_packet; + +#define ISCSI_TEXT_REQ_FLAGS_CONTINUE (1 << 6) // (C) When set to 1, this bit indicates that the text (set of key=value + // pairs) in this Text Request is not complete (it will be continued on + // subsequent Text Requests); otherwise, it indicates that this Text + // Request ends a set of key=value pairs. A Text Request with the C bit + // set to 1 MUST have the F bit set to 0. +#define ISCSI_TEXT_REQ_FLAGS_FINAL (1 << 7) // (F) When set to 1, this bit indicates that this is the last or only Text + // Request in a sequence of Text Requests; otherwise, it indicates that + // more Text Requests will follow. + +/* The Text Request is provided to allow for the exchange of information + and for future extensions. It permits the initiator to inform a + target of its capabilities or request some special operations. + + An initiator MUST NOT have more than one outstanding Text Request on + a connection at any given time. + + On a connection failure, an initiator must either explicitly abort + any active allegiant text negotiation task or cause such a task to be + implicitly terminated by the target. +*/ +typedef struct __attribute__((packed)) iscsi_text_req_packet { + uint8_t opcode; // Always 0x04 according to specification (see above) + int8_t flags; // Text request flags (see above) + uint8_t reserved[2]; // Reserved for future usage + uint8_t total_ahs_len; // TotalAHSLength + uint8_t ds_len[3]; // DataSegmentLength + uint64_t lun; // Logical Unit Number (LUN) or Reserved + uint32_t init_task_tag; // This is the initiator-assigned identifier for this Text Request. If + // the command is sent as part of a sequence of Text Requests and + // responses, the Initiator Task Tag MUST be the same for all the + // requests within the sequence (similar to linked SCSI commands). The + // I bit for all requests in a sequence also MUST be the same + uint32_t target_xfer_tag; // When the Target Transfer Tag is set to the reserved value 0xFFFFFFFF, + // it tells the target that this is a new request, and the target resets + // any internal state associated with the Initiator Task Tag (resets the + // current negotiation state). + // The target sets the Target Transfer Tag in a Text Response to a value + // other than the reserved value 0xFFFFFFFF whenever it indicates that + // it has more data to send or more operations to perform that are + // associated with the specified Initiator Task Tag. It MUST do so + // whenever it sets the F bit to 0 in the response. By copying the + // Target Transfer Tag from the response to the next Text Request, the + // initiator tells the target to continue the operation for the specific + // Initiator Task Tag. The initiator MUST ignore the Target Transfer + // Tag in the Text Response when the F bit is set to 1. + // This mechanism allows the initiator and target to transfer a large + // amount of textual data over a sequence of text-command/text-response + // exchanges or to perform extended negotiation sequences. + // If the Target Transfer Tag is not 0xFFFFFFFF, the LUN field MUST be + // sent by the target in the Text Response. + // A target MAY reset its internal negotiation state if an exchange is + // stalled by the initiator for a long time or if it is running out of + // resources. + // Long Text Responses are handled as shown in the following example: + // I->T Text SendTargets=All (F = 1, TTT = 0xFFFFFFFF) + // T->I Text (F = 0, TTT = 0x12345678) + // I->T Text (F = 1, TTT = 0x12345678) + // T->I Text (F = 0, TTT = 0x12345678) + // I->T Text (F = 1, TTT = 0x12345678) + // ... + // T->I Text (F = 1, TTT = 0xFFFFFFFF) + uint32_t cmd_sn; // CmdSN + uint32_t exp_stat_sn; // ExpStatSN + uint64_t reserved2[2]; // Reserved for future usage + struct iscsi_header_digest hdr_digest; // Optional header digest + struct iscsi_ds_cmd_data ds_cmd_data; // Data segment + // The data lengths of a Text Request MUST NOT exceed the iSCSI target + // MaxRecvDataSegmentLength (a parameter that is negotiated per + // connection and per direction). + // A key=value pair can span Text Request or Text Response boundaries. + // A key=value pair can start in one PDU and continue on the next. In + // other words, the end of a PDU does not necessarily signal the end of + // a key=value pair. + // The target responds by sending its response back to the initiator. + // The response text format is similar to the request text format. The + // Text Response MAY refer to key=value pairs presented in an earlier + // Text Request, and the text in the request may refer to earlier + // responses. + // Text operations are usually meant for parameter setting/negotiations + // but can also be used to perform some long-lasting operations + struct iscsi_data_digest data_digest; // Optional data digest +} iscsi_text_req_packet; + +#define ISCSI_TEXT_RESPONSE_FLAGS_CONTINUE (1 << 6) // (C) When set to 1, this bit indicates that the text (set of key=value + // pairs) in this Text Response is not complete (it will be continued on + // subsequent Text Responses); otherwise, it indicates that this Text + // Response ends a set of key=value pairs. A Text Response with the + // C bit set to 1 MUST have the F bit set to 0 +#define ISCSI_TEXT_RESPONSE_FLAGS_FINAL (1 << 7) // (F) When set to 1, in response to a Text Request with the Final bit set + // to 1, the F bit indicates that the target has finished the whole + // operation. Otherwise, if set to 0 in response to a Text Request with + // the Final Bit set to 1, it indicates that the target has more work to + // do (invites a follow-on Text Request). A Text Response with the + // F bit set to 1 in response to a Text Request with the F bit set to 0 + // is a protocol error. + // A Text Response with the F bit set to 1 MUST NOT contain key=value + // pairs that may require additional answers from the initiator. + // A Text Response with the F bit set to 1 MUST have a Target Transfer + // Tag field set to the reserved value 0xFFFFFFFF. + // A Text Response with the F bit set to 0 MUST have a Target Transfer + // Tag field set to a value other than the reserved value 0xFFFFFFFF + +/* The Text Response PDU contains the target's responses to the + initiator's Text Request. The format of the Text field matches that + of the Text Request. +*/ +typedef struct __attribute__((packed)) iscsi_text_response_packet { + uint8_t opcode; // Always 0x24 according to specification (see above) + int8_t flags; // Text response flags (see above) + uint8_t reserved[2]; // Reserved for future usage + uint8_t total_ahs_len; // TotalAHSLength + uint8_t ds_len[3]; // DataSegmentLength + uint64_t lun; // Logical Unit Number (LUN) or Reserved + uint32_t init_task_tag; // The Initiator Task Tag matches the tag used in the initial Text Request + uint32_t target_xfer_tag; // When a target has more work to do (e.g., cannot transfer all the + // remaining text data in a single Text Response or has to continue the + // negotiation) and has enough resources to proceed, it MUST set the + // Target Transfer Tag to a value other than the reserved value + // 0xFFFFFFFF. Otherwise, the Target Transfer Tag MUST be set to + // 0xFFFFFFFF. + // When the Target Transfer Tag is not 0xFFFFFFFF, the LUN field may be + // significant. + // The initiator MUST copy the Target Transfer Tag and LUN in its next + // request to indicate that it wants the rest of the data. + // When the target receives a Text Request with the Target Transfer Tag + // set to the reserved value 0xFFFFFFFF, it resets its internal + // information (resets state) associated with the given Initiator Task + // Tag (restarts the negotiation). + // When a target cannot finish the operation in a single Text Response + // and does not have enough resources to continue, it rejects the Text + // Request with the appropriate Reject code. + // A target may reset its internal state associated with an Initiator + // Task Tag (the current negotiation state) as expressed through the + // Target Transfer Tag if the initiator fails to continue the exchange + // for some time. The target may reject subsequent Text Requests with + // the Target Transfer Tag set to the "stale" value + uint32_t stat_sn; // StatSN. The target StatSN variable is advanced by each Text Response sent + uint32_t exp_cmd_sn; // ExpCmdSN + uint32_t max_cmd_sn; // MaxCmdSN + uint64_t reserved2[2]; // Reserved for future usage + struct iscsi_header_digest hdr_digest; // Optional header digest + struct iscsi_ds_cmd_data ds_cmd_data; // Data segment + // The data lengths of a Text Response MUST NOT exceed the iSCSI + // initiator MaxRecvDataSegmentLength (a parameter that is negotiated + // per connection and per direction). + // The text in the Text Response Data is governed by the same rules as + // the text in the Text Request Data. + // Although the initiator is the requesting party and controls the + // request-response initiation and termination, the target can offer + // key=value pairs of its own as part of a sequence and not only in + // response to the initiator + struct iscsi_data_digest data_digest; // Optional data digest +} iscsi_text_response_packet; + +#define ISCSI_ISID_TYPE_BITS (1 << 6) // Two bits - The T field identifies the format and usage of A, B, C, and D as + // indicated below: +#define ISCSI_ISID_TYPE_FORMAT_OUI 0x0 // OUI-Format + // A and B: 22-bit OUI + // (the I/G and U/L bits are omitted) + // C and D: 24-bit Qualifier +#define ISCSI_ISID_TYPE_FORMAT_EN 0x1 // EN: Format (IANA Enterprise Number) + // A: Reserved + // B and C: EN (IANA Enterprise Number) + // D: Qualifier +#define ISCSI_ISID_TYPE_FORMAT_RANDOM 0x2 // Random + // A: Reserved + // B and C: Random + // D: Qualifier + +/* This is an initiator-defined component of the session identifier and + is structured as follows: + + For the T field values 00b and 01b, a combination of A and B (for + 00b) or B and C (for 01b) identifies the vendor or organization whose + component (software or hardware) generates this ISID. A vendor or + organization with one or more OUIs, or one or more Enterprise + Numbers, MUST use at least one of these numbers and select the + appropriate value for the T field when its components generate ISIDs. + An OUI or EN MUST be set in the corresponding fields in network byte + order (byte big-endian). + + If the T field is 10b, B and C are set to a random 24-bit unsigned + integer value in network byte order (byte big-endian). + + The Qualifier field is a 16-bit or 24-bit unsigned integer value that + provides a range of possible values for the ISID within the selected + namespace. It may be set to any value within the constraints + specified in the iSCSI protocol. + + If the ISID is derived from something assigned to a hardware adapter + or interface by a vendor as a preset default value, it MUST be + configurable to a value assigned according to the SCSI port behavior + desired by the system in which it is installed. The resultant ISID + MUST also be persistent over power cycles, reboot, card swap, etc. +*/ +typedef struct __attribute__((packed)) iscsi_isid { + uint8_t a; // Meaning depends on T bit (see above) + uint16_t b; // Meaning depends on T bit (see above) + uint8_t c; // Meaning depends on T bit (see above) + uint16_t d; // Meaning depends on T bit (see above) +} + +#define ISCSI_LOGIN_REQ_FLAGS_NEXT_STAGE_SECURITY_NEGOTIATION 0x0 // SecurityNegotiation +#define ISCSI_LOGIN_REQ_FLAGS_NEXT_STAGE_LOGIN_OPERATIONAL_NEGOTIATION 0x1 // LoginOperationalNegotiation +#define ISCSI_LOGIN_REQ_FLAGS_NEXT_STAGE_FULL_FEATURE_PHASE 0x3 // FullFeaturePhase +#define ISCSI_LOGIN_REQ_FLAGS_NEXT_STAGE (1 << 0) // (NSG) - Two bits - the Login negotiation requests and responses are + // associated with a specific stage in the session (SecurityNegotiation, + // LoginOperationalNegotiation, FullFeaturePhase) and may indicate the + // next stage to which they want to move. The Next Stage value is only + // valid when the T bit is 1; otherwise, it is reserved +#define ISCSI_LOGIN_REQS_FLAGS_GET_NEXT_STAGE(x) ((x) & 3) + +#define ISCSI_LOGIN_REQ_FLAGS_CURRENT_STAGE_SECURITY_NEGOTIATION 0x0 // SecurityNegotiation +#define ISCSI_LOGIN_REQ_FLAGS_CURRENT_STAGE_LOGIN_OPERATIONAL_NEGOTIATION 0x1 // LoginOperationalNegotiation +#define ISCSI_LOGIN_REQ_FLAGS_CURRENT_STAGE_FULL_FEATURE_PHASE 0x3 // FullFeaturePhase +#define ISCSI_LOGIN_REQ_FLAGS_CURRENT_STAGE (1 << 2) // (CSG) - Two bits - the Login negotiation requests and responses are + // associated with aspecific stage in the session (SecurityNegotiation, + // LoginOperationalNegotiation, FullFeaturePhase) and may indicate the + // next stage to which they want to move +#define ISCSI_LOGIN_REQS_FLAGS_GET_CURRENT_STAGE(x) (((x) >> 2) & 3) + +#define ISCSI_LOGIN_REQ_FLAGS_CONTINUE (1 << 6) // (C) When set to 1, this bit indicates that the text (set of key=value + // pairs) in this Login Request is not complete (it will be continued on + // subsequent Login Requests); otherwise, it indicates that this Login + // Request ends a set of key=value pairs. A Login Request with the + // C bit set to 1 MUST have the T bit set to 0. +#define ISCSI_LOGIN_REQ_FLAGS_TRANSMIT (1 << 7) // (T) When set to 1, this bit indicates that the initiator is ready to + // transit to the next stage. + // If the T bit is set to 1 and the NSG is set to FullFeaturePhase, then + // this also indicates that the initiator is ready for the Login + // Final-Response. + +/* After establishing a TCP connection between an initiator and a + target, the initiator MUST start a Login Phase to gain further access + to the target's resources. + + The Login Phase consists of a sequence of Login Requests and Login + Responses that carry the same Initiator Task Tag. + + Login Requests are always considered as immediate. +*/ +typedef struct __attribute__((packed)) iscsi_login_req_packet { + uint8_t opcode; // Always 0x03 according to specification (see above) + int8_t flags; // Login request flags (see above) + uint8_t version_max; // Version-max indicates the maximum version number supported. + // All Login Requests within the Login Phase MUST carry the same + // Version-max. Currently, this is always 0 + // The target MUST use the value presented with the first Login Request. + uint8_t version_min; // All Login Requests within the Login Phase MUST carry the same + // Version-min. The target MUST use the value presented with the first + // Login Request. Always 0 for now + uint8_t total_ahs_len; // TotalAHSLength + uint8_t ds_len[3]; // DataSegmentLength + struct iscsi_isid isid; // ISID (see above for declaration) + uint16_t tsih; // The TSIH must be set in the first Login Request. The reserved value + // 0 MUST be used on the first connection for a new session. Otherwise, + // the TSIH sent by the target at the conclusion of the successful login + // of the first connection for this session MUST be used. The TSIH + // identifies to the target the associated existing session for this new + // connection. + // All Login Requests within a Login Phase MUST carry the same TSIH. + // The target MUST check the value presented with the first Login + // Request + uint32_t init_task_tag; // Initiator task tag + uint16_t cid; // Connection ID. The CID provides a unique ID for this connection within the session. + // All Login Requests within the Login Phase MUST carry the same CID. + // The target MUST use the value presented with the first Login Request. + // A Login Request with a non-zero TSIH and a CID equal to that of an + // existing connection implies a logout of the connection followed by a + // login + uint32_t cmd_sn; // The CmdSN is either the initial command sequence number of a session + // (for the first Login Request of a session - the "leading" login) or + // the command sequence number in the command stream if the login is for + // a new connection in an existing session. + // Examples: + // - Login on a leading connection: If the leading login carries the + // CmdSN 123, all other Login Requests in the same Login Phase carry + // the CmdSN 123, and the first non-immediate command in the Full + // Feature Phase also carries the CmdSN 123. + // - Login on other than a leading connection: If the current CmdSN at + // the time the first login on the connection is issued is 500, then + // that PDU carries CmdSN=500. Subsequent Login Requests that are + // needed to complete this Login Phase may carry a CmdSN higher than + // 500 if non-immediate requests that were issued on other connections + // in the same session advance the CmdSN. + // If the Login Request is a leading Login Request, the target MUST use + // the value presented in the CmdSN as the target value for the + // ExpCmdSN + uint32_t exp_stat_sn; // For the first Login Request on a connection, this is the ExpStatSN + // for the old connection, and this field is only valid if the Login + // Request restarts a connection + // For subsequent Login Requests, it is used to acknowledge the Login + // Responses with their increasing StatSN values + uint64_t reserved[2]; // Reserved for future usage + struct iscsi_ds_cmd_data ds_cmd_data; // Data segment - Login Parameters in Text Request Format + // The initiator MUST provide some basic parameters in order + // to enable the target to determine if the initiator may use + // the target's resources and the initial text parameters for the security exchange. +} iscsi_login_req_packet; + +#define ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_SECURITY_NEGOTIATION 0x0 // SecurityNegotiation +#define ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_LOGIN_OPERATIONAL_NEGOTIATION 0x1 // LoginOperationalNegotiation +#define ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_FULL_FEATURE_PHASE 0x3 // FullFeaturePhase +#define ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE (1 << 0) // (NSG) - Two bits - the Login negotiation requests and responses are + // associated with a specific stage in the session (SecurityNegotiation, + // LoginOperationalNegotiation, FullFeaturePhase) and may indicate the + // next stage to which they want to move The Next Stage value is only + // valid when the T bit is 1; otherwise, it is reserved +#define ISCSI_LOGIN_RESPONSE_FLAGS_GET_NEXT_STAGE(x) ((x) & 3) + +#define ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_SECURITY_NEGOTIATION 0x0 // SecurityNegotiation +#define ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_LOGIN_OPERATIONAL_NEGOTIATION 0x1 // LoginOperationalNegotiation +#define ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_FULL_FEATURE_PHASE 0x3 // FullFeaturePhase +#define ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE (1 << 2) // (CSG) - Two bits - the Login negotiation requests and responses are + // associated with aspecific stage in the session (SecurityNegotiation, + // LoginOperationalNegotiation, FullFeaturePhase) and may indicate the + // next stage to which they want to move +#define ISCSI_LOGIN_RESPONSE_FLAGS_GET_CURRENT_STAGE(x) (((x) >> 2) & 3) + +#define ISCSI_LOGIN_RESPONSE_FLAGS_CONTINUE (1 << 6) // (C) When set to 1, this bit indicates that the text (set of key=value + // pairs) in this Login Response is not complete (it will be continued + // on subsequent Login Responses); otherwise, it indicates that this + // Login Response ends a set of key=value pairs. A Login Response with + // the C bit set to 1 MUST have the T bit set to 0 +#define ISCSI_LOGIN_RESPONSE_FLAGS_TRANSMIT (1 << 7) // (T) The T bit is set to 1 as an indicator of the end of the stage. If + // the T bit is set to 1 and the NSG is set to FullFeaturePhase, then + // this is also the Login Final-Response. A T bit of 0 indicates a + // "partial" response, which means "more negotiation needed". + // A Login Response with the T bit set to 1 MUST NOT contain key=value + // pairs that may require additional answers from the initiator within + // the same stage. + // If the Status-Class is 0, the T bit MUST NOT be set to 1 if the T bit + // in the request was set to 0 + +#define ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SUCCESS 0x00 // Success - indicates that the iSCSI target successfully + // received, understood, and accepted the request. The numbering + // fields (StatSN, ExpCmdSN, MaxCmdSN) are only valid if Status- + // Class is 0 +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SUCCESS 0x00 // Login is proceeding OK. If the response T bit is set to 1 in both the + // request and the matching response, and the NSG is set to + // FullFeaturePhase in both the request and the matching response, the + // Login Phase is finished, and the initiator may proceed to issue SCSI + // commands. + +#define ISCSI_LOGIN_RESPONSE_STATUS_CLASS_REDIRECT 0x01 // Redirection - indicates that the initiator must take further + // action to complete the request. This is usually due to the + // target moving to a different address. All of the redirection + // Status-Class responses MUST return one or more text key + // parameters of the type "TargetAddress", which indicates the + // target's new address. A redirection response MAY be issued by + // a target prior to or after completing a security negotiation if + // a security negotiation is required. A redirection SHOULD be + // accepted by an initiator, even without having the target + // complete a security negotiation if any security negotiation is + // required, and MUST be accepted by the initiator after the + // completion of the security negotiation if any security + // negotiation is required +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_REDIRECT_TEMP 0x01 // The requested iSCSI Target Name (ITN) has temporarily moved + // to the address provided +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_REDIRECT_PERM 0x02 // The requested ITN has permanently moved to the address provided + +#define ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR 0x02 // Initiator Error (not a format error) - indicates that the + // initiator most likely caused the error. This MAY be due to a + // request for a resource for which the initiator does not have + // permission. The request should not be tried again +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISC 0x00 // Miscellaneous iSCSI initiator errors +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_AUTH_ERR 0x01 // The initiator could not be successfully + // authenticated or target authentication is + // not supported +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_AUTH_FAIL 0x02 // The initiator is not allowed access to the + // given target +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_NOT_FOUND 0x03 // The requested ITN does not exist at this + // address +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_TARGET_REMOVED 0x04 // The requested ITN has been removed, and + // no forwarding address is provided +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_WRONG_VERSION 0x05 // The requested iSCSI version range is not + // supported by the target +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_TOO_MANY_CONNECTIONS 0x06 // Too many connections on this SSID +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISSING_PARAMETER 0x07 // Missing parameters (e.g. iSCSI Initiator + // Name and/or Target Name) +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_NO_SESSION_SPANNING 0x08 // arget does not support session spanning + // to this connection (address) +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_SESSION_NO_SUPPORT 0x09 // Target does not support this type of + // session or not from this initiator +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_SESSION_NO_EXIST 0x0A // Attempt to add a connection to a non- + // existent session +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_INVALID_LOGIN_REQ_TYPE 0x0B // Invalid request type during login + +#define ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SERVER_ERR 0x03 // Target Error - indicates that the target sees no errors in the + // initiator's Login Request but is currently incapable of + // fulfilling the request. The initiator may retry the same Login + // Request later +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_TARGET_ERROR 0x00 // Target hardware or software error +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_SERVICE_UNAVAILABLE 0x01 // The iSCSI service or target is not + // currently operational +#define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_OUT_OF_RESOURCES 0x02 // The target has insufficient session, + // connection, or other resources + +/* The Login Response indicates the progress and/or end of the Login + Phase. +*/ +typedef struct __attribute__((packed)) iscsi_login_response_packet { + uint8_t opcode; // Always 0x23 according to specification (see above) + int8_t flags; // Login response flags (see above) + uint8_t version_max; // This is the highest version number supported by the target. + // All Login Responses within the Login Phase MUST carry the same + // Version-max + uint8_t version_active; // Version-active indicates the highest version supported by the target + // and initiator. If the target does not support a version within the + // range specified by the initiator, the target rejects the login and + // this field indicates the lowest version supported by the target. + // All Login Responses within the Login Phase MUST carry the same + // Version-active. + // The initiator MUST use the value presented as a response to the first + // Login Request + uint8_t total_ahs_len; // TotalAHSLength + uint8_t ds_len[3]; // DataSegmentLength + struct iscsi_isid isid; // ISID (see above for declaration) + uint16_t tsih; // The TSIH is the target-assigned session-identifying handle. Its + // internal format and content are not defined by this protocol, except + // for the value 0, which is reserved. With the exception of the Login + // Final-Response in a new session, this field should be set to the TSIH + // provided by the initiator in the Login Request. For a new session, + // the target MUST generate a non-zero TSIH and ONLY return it in the + // Login Final-Response + uint32_t init_task_tag; // Initiator task tag + uint32_t reserved; // Reserved for future usage + uint32_t stat_sn; // For the first Login Response (the response to the first Login + // Request), this is the starting status sequence number for the + // connection. The next response of any kind - including the next + // Login Response, if any, in the same Login Phase - will carry this + // number + 1. This field is only valid if the Status-Class is 0 + uint32_t exp_cmd_sn; // ExpCmdSN + uint32_t max_cmd_sn; // MaxCmdSN + uint8_t status_class; // Status-class (see above for details). If the Status-Class is + // not 0, the initiator and target MUST close the TCP connection + // If the target wishes to reject the Login Request for more than one + // reason, it should return the primary reason for the rejection + uint8_t status_detail; // Status-detail (see above for details) + uint16_t reserved2; // Reserved for future usage + uint64_t reserved3; // Reserved for future usage + struct iscsi_ds_cmd_data ds_cmd_data; // Data segment - Login Parameters in Text Request Format + // The target MUST provide some basic parameters in order to enable the + // initiator to determine if it is connected to the correct port and the + // initial text parameters for the security exchange. + // All the rules specified for Text Responses also hold for Login + // Responses. +} iscsi_login_response_packet; + #endif /* DNBD3_ISCSI_H_ */ diff --git a/src/server/net.c b/src/server/net.c index 3e5f3aa..629c491 100644 --- a/src/server/net.c +++ b/src/server/net.c @@ -181,7 +181,7 @@ void* net_handleNewConnection(void *clientPtr) logadd( LOG_DEBUG1, "Magic in client handshake incorrect" ); } goto fail_preadd; - } else if ( + } // Magic OK, untangle byte order if required fixup_request( request ); if ( request.cmd != CMD_SELECT_IMAGE ) { -- cgit v1.2.3-55-g7522