From a3328a85ef3806ada78dce5d46216370894ccb8c Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sat, 1 Jan 2011 09:51:16 +1100 Subject: [PATCH] Negotiation of MaxBurstLength, FirstBurstLength, MaxRecvDataSegmentLength Add these settings to the iscsi context structure and initialize them to sane valued. When sending login commands to the target, use these values instead of hardcoded values. Parse when the target sends a login reply back to us and update these variables if the target asks us to. This allows us to detect when our defaults are too big for the target and adjust the settings we use so we match the target. Some targets have a very small accepted default for some settings. During login, we will initially send these keys with our dafult values. These targets will then respond back by refusing to transition to the next login phase, and by telling us back what the maximum of these values should be. In this case we have to try the login again but use the smaller values we got from the target. Othervise, if we try again, ignoring the value from the target, and just repeat using our defaults the target will abort the login with a "initiator error". --- include/iscsi-private.h | 4 ++++ lib/init.c | 4 ++++ lib/login.c | 27 +++++++++++++++++++++------ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 496d1e3..ddcffd3 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -82,6 +82,10 @@ struct iscsi_context { struct iscsi_in_pdu *incoming; struct iscsi_in_pdu *inqueue; + + uint32_t max_burst_length; + uint32_t first_burst_length; + uint32_t max_recv_data_segment_length; }; #define ISCSI_PDU_IMMEDIATE 0x40 diff --git a/lib/init.c b/lib/init.c index cc79b1b..c0dfb5f 100644 --- a/lib/init.c +++ b/lib/init.c @@ -58,6 +58,10 @@ iscsi_create_context(const char *initiator_name) iscsi->next_phase = ISCSI_PDU_LOGIN_NSG_OPNEG; iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP; + iscsi->max_burst_length = 262144; + iscsi->first_burst_length = 262144; + iscsi->max_recv_data_segment_length = 262144; + return iscsi; } diff --git a/lib/login.c b/lib/login.c index f143266..8ff7494 100644 --- a/lib/login.c +++ b/lib/login.c @@ -249,13 +249,14 @@ iscsi_login_add_maxburstlength(struct iscsi_context *iscsi, struct iscsi_pdu *pd return 0; } - str = (char *)"MaxBurstLength=262144"; + asprintf(&str, "MaxBurstLength=%d", iscsi->max_burst_length); if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); + free(str); return -1; } - + free(str); return 0; } @@ -269,13 +270,14 @@ iscsi_login_add_firstburstlength(struct iscsi_context *iscsi, struct iscsi_pdu * return 0; } - str = (char *)"FirstBurstLength=262144"; + asprintf(&str, "FirstBurstLength=%d", iscsi->first_burst_length); if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); + free(str); return -1; } - + free(str); return 0; } @@ -289,13 +291,14 @@ iscsi_login_add_maxrecvdatasegmentlength(struct iscsi_context *iscsi, struct isc return 0; } - str = (char *)"MaxRecvDataSegmentLength=262144"; + asprintf(&str, "MaxRecvDataSegmentLength=%d", iscsi->max_recv_data_segment_length); if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); + free(str); return -1; } - + free(str); return 0; } @@ -752,6 +755,18 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, } } + if (!strncmp((char *)ptr, "FirstBurstLength=", 17)) { + iscsi->first_burst_length = strtol((char *)ptr + 17, NULL, 10); + } + + if (!strncmp((char *)ptr, "MaxBurstLength=", 15)) { + iscsi->max_burst_length = strtol((char *)ptr + 15, NULL, 10); + } + + if (!strncmp((char *)ptr, "MaxRecvDataSegmentLength=", 25)) { + iscsi->max_recv_data_segment_length = strtol((char *)ptr + 25, NULL, 10); + } + if (!strncmp((char *)ptr, "AuthMethod=", 11)) { if (!strcmp((char *)ptr + 11, "CHAP")) { iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SELECT_ALGORITHM;