iscsid(8) cannot connect to newer Linux targets

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

iscsid(8) cannot connect to newer Linux targets

Bruno Flueckiger
>Synopsis: iscsid(8) cannot connect to newer Linux targets
>Category: system
>Environment:
        System      : OpenBSD 6.1
        Details     : OpenBSD 6.1-beta (GENERIC.MP) #26: Wed Mar 15 22:22:37 MDT 2017
                         [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP

        Architecture: OpenBSD.amd64
        Machine     : amd64
>Description:
        The iSCSI targets of CentOS 7 and Synology DSM 6.0.2-8451 refuse to
        establish a connection with iscsid(8). Both systems complain about
        missing parameters during the security negotiation phase (CentOS)
        or the operational parameter negotiation phase (DSM).
        Besides Synology DSM and CentOS I've tested the connection to the
        iSCSI targets of the following operating systems: FreeBSD 11,
        NetBSD 7 and Debian 8 (has an old iSCSI implementation for Linux).
        The connection to these three systems is established without pro-
        blems.
>How-To-Repeat:
        Way 1: Install any Linux-based OS with a kernel that uses the LIO
        iSCSI fabric module (http://linux-iscsi.org/wiki/ISCSI), configure
        a LUN accroding to the instructions in the link and try to connect
        to it using iscsid(8).
        Way 2: Create a LUN on a Synology product running a recent version
        of DSM and try to connect to it.
>Fix:
        The following four diffs modify iscsid(8) in a way that the mis-
        sing parameters are advertised during the security negotiation
        phase and the operational parameter negotiation phase.

Index: usr.sbin/iscsid/iscsid.c
===================================================================
RCS file: /cvs/src/usr.sbin/iscsid/iscsid.c,v
retrieving revision 1.20
diff -u -p -r1.20 iscsid.c
--- usr.sbin/iscsid/iscsid.c 23 Jan 2017 08:40:07 -0000 1.20
+++ usr.sbin/iscsid/iscsid.c 2 Mar 2017 14:40:44 -0000
@@ -254,6 +254,8 @@ iscsid_ctrl_dispatch(void *ch, struct pd
  control_compose(ch, CTRL_FAILURE, NULL, 0);
  goto done;
  }
+ s->config.HeaderDigest = SESSION_DIGEST_NONE;
+ s->config.DataDigest = SESSION_DIGEST_NONE;
  }
 
  session_config(s, sc);

Index: usr.sbin/iscsid/iscsid.h
===================================================================
RCS file: /cvs/src/usr.sbin/iscsid/iscsid.h,v
retrieving revision 1.16
diff -u -p -r1.16 iscsid.h
--- usr.sbin/iscsid/iscsid.h 2 Sep 2016 16:22:31 -0000 1.16
+++ usr.sbin/iscsid/iscsid.h 2 Mar 2017 14:40:54 -0000
@@ -181,6 +181,9 @@ struct session_config {
  u_int8_t disabled;
 };
 
+#define SESSION_DIGEST_NONE 0
+#define SESSION_DIGEST_CRC32 1
+
 #define SESSION_TYPE_NORMAL 0
 #define SESSION_TYPE_DISCOVERY 1

Index: usr.sbin/iscsid/initiator.c
===================================================================
RCS file: /cvs/src/usr.sbin/iscsid/initiator.c,v
retrieving revision 1.15
diff -u -p -r1.15 initiator.c
--- usr.sbin/iscsid/initiator.c 16 Jan 2015 15:57:06 -0000 1.15
+++ usr.sbin/iscsid/initiator.c 3 Mar 2017 10:08:46 -0000
@@ -250,39 +250,106 @@ initiator_nop_in_imm(struct connection *
  conn_task_issue(c, t);
 }
 
+#define WRITE_BOOL(k, v) \
+do { \
+ if (v) \
+ k = "Yes"; \
+ else \
+ k = "No"; \
+} while (0)
+
+#define WRITE_NUM(k, v) \
+do { \
+ if (asprintf(&k, "%hu", v) == -1) \
+ return NULL; \
+} while (0)
+
+#define WRITE_INT(k, v) \
+do { \
+ if (asprintf(&k, "%u", v) == -1) \
+ return NULL; \
+} while (0)
+
+#define WRITE_DIGEST(k, v) \
+do { \
+ if (v) \
+ k = "CRC32"; \
+ else \
+ k = "None"; \
+} while (0) \
+
 struct kvp *
 initiator_login_kvp(struct connection *c, u_int8_t stage)
 {
  struct kvp *kvp;
- size_t nkvp;
+ struct session *s;
 
  switch (stage) {
  case ISCSI_LOGIN_STG_SECNEG:
- if (!(kvp = calloc(4, sizeof(*kvp))))
+ if (!(kvp = calloc(5, sizeof(*kvp))))
  return NULL;
  kvp[0].key = "AuthMethod";
  kvp[0].value = "None";
  kvp[1].key = "InitiatorName";
  kvp[1].value = c->session->config.InitiatorName;
+ kvp[2].key = "SessionType";
 
  if (c->session->config.SessionType == SESSION_TYPE_DISCOVERY) {
- kvp[2].key = "SessionType";
  kvp[2].value = "Discovery";
  } else {
- kvp[2].key = "TargetName";
- kvp[2].value = c->session->config.TargetName;
+ kvp[2].value = "Normal";
+ kvp[3].key = "TargetName";
+ kvp[3].value = c->session->config.TargetName;
  }
  break;
  case ISCSI_LOGIN_STG_OPNEG:
- if (conn_gen_kvp(c, NULL, &nkvp) == -1)
- return NULL;
- nkvp += 1; /* add slot for terminator */
- if (!(kvp = calloc(nkvp, sizeof(*kvp))))
- return NULL;
- if (conn_gen_kvp(c, kvp, &nkvp) == -1) {
- free(kvp);
+ if (!(kvp = calloc(15, sizeof(*kvp))))
  return NULL;
- }
+
+ s = c->session;
+
+ kvp[0].key = "MaxConnections";
+ WRITE_NUM(kvp[0].value, s->mine.MaxConnections);
+
+ kvp[1].key = "InitialR2T";
+ WRITE_BOOL(kvp[1].value, s->mine.InitialR2T);
+
+ kvp[2].key = "ImmediateData";
+ WRITE_BOOL(kvp[2].value, s->mine.ImmediateData);
+
+ kvp[3].key = "MaxRecvDataSegmentLength";
+ WRITE_INT(kvp[3].value, c->mine.MaxRecvDataSegmentLength);
+
+ kvp[4].key = "MaxBurstLength";
+ WRITE_INT(kvp[4].value, s->mine.MaxBurstLength);
+
+ kvp[5].key = "FirstBurstLength";
+ WRITE_INT(kvp[5].value, s->mine.FirstBurstLength);
+
+ kvp[6].key = "HeaderDigest";
+ WRITE_DIGEST(kvp[6].value, s->config.HeaderDigest);
+
+ kvp[7].key = "DataDigest";
+ WRITE_DIGEST(kvp[7].value, s->config.DataDigest);
+
+ kvp[8].key = "MaxOutstandingR2T";
+ WRITE_NUM(kvp[8].value, s->mine.MaxOutstandingR2T);
+
+ kvp[9].key = "DataPDUInOrder";
+ WRITE_BOOL(kvp[9].value, s->mine.DataPDUInOrder);
+
+ kvp[10].key = "DataSequenceInOrder";
+ WRITE_BOOL(kvp[10].value, s->mine.DataSequenceInOrder);
+
+ kvp[11].key = "ErrorRecoveryLevel";
+ WRITE_NUM(kvp[11].value, s->mine.ErrorRecoveryLevel);
+
+ kvp[12].key = "DefaultTime2Wait";
+ WRITE_NUM(kvp[12].value, s->mine.DefaultTime2Wait);
+
+ kvp[13].key = "DefaultTime2Retain";
+ WRITE_NUM(kvp[13].value, s->mine.DefaultTime2Retain);
+
  break;
  default:
  log_warnx("initiator_login_kvp: exit stage left");
@@ -290,6 +357,11 @@ initiator_login_kvp(struct connection *c
  }
  return kvp;
 }
+
+#undef WRITE_DIGEST
+#undef WRITE_INT
+#undef WRITE_NUM
+#undef WRITE_BOOL
 
 struct pdu *
 initiator_login_build(struct connection *c, struct task_login *tl)

Index: usr.sbin/iscsid/connection.c
===================================================================
RCS file: /cvs/src/usr.sbin/iscsid/connection.c,v
retrieving revision 1.21
diff -u -p -r1.21 connection.c
--- usr.sbin/iscsid/connection.c 5 Dec 2015 06:38:18 -0000 1.21
+++ usr.sbin/iscsid/connection.c 2 Mar 2017 10:17:13 -0000
@@ -316,44 +316,6 @@ log_debug("conn_parse_kvp: %s = %s", k->
 #undef SET_NUM
 #undef SET_BOOL
 
-int
-conn_gen_kvp(struct connection *c, struct kvp *kvp, size_t *nkvp)
-{
- struct session *s = c->session;
- size_t i = 0;
-
- if (s->mine.MaxConnections != iscsi_sess_defaults.MaxConnections) {
- if (kvp && i < *nkvp) {
- kvp[i].key = strdup("MaxConnections");
- if (kvp[i].key == NULL)
- return -1;
- if (asprintf(&kvp[i].value, "%hu",
-    s->mine.MaxConnections) == -1) {
- kvp[i].value = NULL;
- return -1;
- }
- }
- i++;
- }
- if (c->mine.MaxRecvDataSegmentLength !=
-    iscsi_conn_defaults.MaxRecvDataSegmentLength) {
- if (kvp && i < *nkvp) {
- kvp[i].key = strdup("MaxRecvDataSegmentLength");
- if (kvp[i].key == NULL)
- return -1;
- if (asprintf(&kvp[i].value, "%u",
-    c->mine.MaxRecvDataSegmentLength) == -1) {
- kvp[i].value = NULL;
- return -1;
- }
- }
- i++;
- }
-
- *nkvp = i;
- return 0;
-}
-
 void
 conn_pdu_write(struct connection *c, struct pdu *p)
 {


dmesg:
OpenBSD 6.1-beta (GENERIC.MP) #26: Wed Mar 15 22:22:37 MDT 2017
    [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
real mem = 3881746432 (3701MB)
avail mem = 3759423488 (3585MB)
mpath0 at root
scsibus0 at mpath0: 256 targets
mainbus0 at root
bios0 at mainbus0: SMBIOS rev. 2.7 @ 0xe0970 (63 entries)
bios0: vendor Phoenix Technologies Ltd. version "P11ABK" date 07/15/2015
bios0: SAMSUNG ELECTRONICS CO., LTD. 900X3C/900X3D/900X3E/900X4C/900X4D
acpi0 at bios0: rev 2
acpi0: sleep states S0 S3 S4 S5
acpi0: tables DSDT FACP SLIC SSDT ASF! HPET APIC MCFG FPDT SSDT SSDT UEFI MSDM UEFI UEFI
acpi0: wakeup devices P0P1(S4) GLAN(S4) XHC_(S4) HDEF(S4) PXSX(S4) RP01(S4) PXSX(S4) RP02(S4) PXSX(S4) RP03(S4) PXSX(S4) RP04(S4) PXSX(S4) RP06(S4) PXSX(S4) RP07(S4) [...]
acpitimer0 at acpi0: 3579545 Hz, 24 bits
acpihpet0 at acpi0: 14318179 Hz
acpimadt0 at acpi0 addr 0xfee00000: PC-AT compat
cpu0 at mainbus0: apid 0 (boot processor)
cpu0: Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz, 1696.42 MHz
cpu0: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,POPCNT,DEADLINE,XSAVE,AVX,F16C,RDRAND,NXE,LONG,LAHF,PERF,ITSC,FSGSBASE,SMEP,ERMS,SENSOR,ARAT
cpu0: 256KB 64b/line 8-way L2 cache
cpu0: TSC frequency 1696423920 Hz
cpu0: smt 0, core 0, package 0
mtrr: Pentium Pro MTRR support, 10 var ranges, 88 fixed ranges
cpu0: apic clock running at 99MHz
cpu0: mwait min=64, max=64, C-substates=0.2.1.1.2, IBE
cpu1 at mainbus0: apid 1 (application processor)
cpu1: Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz, 1696.15 MHz
cpu1: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,POPCNT,DEADLINE,XSAVE,AVX,F16C,RDRAND,NXE,LONG,LAHF,PERF,ITSC,FSGSBASE,SMEP,ERMS,SENSOR,ARAT
cpu1: 256KB 64b/line 8-way L2 cache
cpu1: smt 1, core 0, package 0
cpu2 at mainbus0: apid 2 (application processor)
cpu2: Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz, 1696.15 MHz
cpu2: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,POPCNT,DEADLINE,XSAVE,AVX,F16C,RDRAND,NXE,LONG,LAHF,PERF,ITSC,FSGSBASE,SMEP,ERMS,SENSOR,ARAT
cpu2: 256KB 64b/line 8-way L2 cache
cpu2: smt 0, core 1, package 0
cpu3 at mainbus0: apid 3 (application processor)
cpu3: Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz, 1696.15 MHz
cpu3: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,POPCNT,DEADLINE,XSAVE,AVX,F16C,RDRAND,NXE,LONG,LAHF,PERF,ITSC,FSGSBASE,SMEP,ERMS,SENSOR,ARAT
cpu3: 256KB 64b/line 8-way L2 cache
cpu3: smt 1, core 1, package 0
ioapic0 at mainbus0: apid 2 pa 0xfec00000, version 20, 24 pins
acpimcfg0 at acpi0 addr 0xf8000000, bus 0-63
acpiprt0 at acpi0: bus 0 (PCI0)
acpiprt1 at acpi0: bus -1 (P0P1)
acpiprt2 at acpi0: bus 1 (RP01)
acpiprt3 at acpi0: bus -1 (RP02)
acpiprt4 at acpi0: bus -1 (RP03)
acpiprt5 at acpi0: bus 2 (RP04)
acpiprt6 at acpi0: bus 3 (RP05)
acpiprt7 at acpi0: bus -1 (RP06)
acpiprt8 at acpi0: bus -1 (RP07)
acpiprt9 at acpi0: bus -1 (RP08)
acpiprt10 at acpi0: bus -1 (PEG0)
acpiprt11 at acpi0: bus -1 (PEG1)
acpiprt12 at acpi0: bus -1 (PEG2)
acpiprt13 at acpi0: bus -1 (PEG3)
acpiec0 at acpi0
acpicpu0 at acpi0: C3(200@87 mwait.1@0x30), C2(500@59 mwait.1@0x10), C1(1000@1 mwait.1), PSS
acpicpu1 at acpi0: C3(200@87 mwait.1@0x30), C2(500@59 mwait.1@0x10), C1(1000@1 mwait.1), PSS
acpicpu2 at acpi0: C3(200@87 mwait.1@0x30), C2(500@59 mwait.1@0x10), C1(1000@1 mwait.1), PSS
acpicpu3 at acpi0: C3(200@87 mwait.1@0x30), C2(500@59 mwait.1@0x10), C1(1000@1 mwait.1), PSS
acpipwrres0 at acpi0: FN00, resource for FAN0
acpipwrres1 at acpi0: FN01, resource for FAN1
acpipwrres2 at acpi0: FN02, resource for FAN2
acpipwrres3 at acpi0: FN03, resource for FAN3
acpipwrres4 at acpi0: FN04, resource for FAN4
acpitz0 at acpi0: critical temperature is 106 degC
acpitz1 at acpi0: critical temperature is 106 degC
acpibat0 at acpi0: BAT1 type LION oem "SAMSUNG Electronics"
acpials0 at acpi0: ALSD
"INT3F0D" at acpi0 not configured
"MSFT0001" at acpi0 not configured
"ETD0B00" at acpi0 not configured
"PNP0C14" at acpi0 not configured
acpiac0 at acpi0: AC unit online
acpibtn0 at acpi0: LID0
acpibtn1 at acpi0: PWRB
"SAM0714" at acpi0 not configured
"INT340E" at acpi0 not configured
"PNP0C0B" at acpi0 not configured
"PNP0C0B" at acpi0 not configured
"PNP0C0B" at acpi0 not configured
"PNP0C0B" at acpi0 not configured
"PNP0C0B" at acpi0 not configured
acpivideo0 at acpi0: GFX0
acpivout0 at acpivideo0: DD02
cpu0: Enhanced SpeedStep 1696 MHz: speeds: 1701, 1700, 1600, 1500, 1400, 1300, 1200, 1100, 1000, 900, 800, 782 MHz
pci0 at mainbus0 bus 0
pchb0 at pci0 dev 0 function 0 "Intel Core 3G Host" rev 0x09
inteldrm0 at pci0 dev 2 function 0 "Intel HD Graphics 4000" rev 0x09
drm0 at inteldrm0
inteldrm0: msi
inteldrm0: 1600x900, 32bpp
wsdisplay0 at inteldrm0 mux 1: console (std, vt100 emulation)
wsdisplay0: screen 1-5 added (std, vt100 emulation)
"Intel 7 Series MEI" rev 0x04 at pci0 dev 22 function 0 not configured
azalia0 at pci0 dev 27 function 0 "Intel 7 Series HD Audio" rev 0x04: msi
azalia0: codecs: Realtek ALC269, Intel/0x2806, using Realtek ALC269
audio0 at azalia0
ppb0 at pci0 dev 28 function 0 "Intel 7 Series PCIE" rev 0xc4: msi
pci1 at ppb0 bus 1
iwn0 at pci1 dev 0 function 0 "Intel Centrino Advanced-N 6235" rev 0x24: msi, MIMO 2T2R, AGN, address c4:85:08:e5:64:79
ppb1 at pci0 dev 28 function 3 "Intel 7 Series PCIE" rev 0xc4: msi
pci2 at ppb1 bus 2
re0 at pci2 dev 0 function 0 "Realtek 8168" rev 0x06: RTL8168E/8111E-VL (0x2c80), msi, address 50:b7:c3:89:e5:ef
rgephy0 at re0 phy 7: RTL8169S/8110S/8211 PHY, rev. 5
ppb2 at pci0 dev 28 function 4 "Intel 7 Series PCIE" rev 0xc4: msi
pci3 at ppb2 bus 3
xhci0 at pci3 dev 0 function 0 "Renesas uPD720202 xHCI" rev 0x02: msi
usb0 at xhci0: USB revision 3.0
uhub0 at usb0 configuration 1 interface 0 "Renesas xHCI root hub" rev 3.00/1.00 addr 1
ehci0 at pci0 dev 29 function 0 "Intel 7 Series USB" rev 0x04: apic 2 int 23
usb1 at ehci0: USB revision 2.0
uhub1 at usb1 configuration 1 interface 0 "Intel EHCI root hub" rev 2.00/1.00 addr 1
pcib0 at pci0 dev 31 function 0 "Intel HM75 LPC" rev 0x04
ahci0 at pci0 dev 31 function 2 "Intel 7 Series AHCI" rev 0x04: msi, AHCI 1.3
ahci0: port 0: 6.0Gb/s
scsibus1 at ahci0: 32 targets
sd0 at scsibus1 targ 0 lun 0: <ATA, SAMSUNG MZMPC128, CXM1> SCSI3 0/direct fixed naa.5002538043584d30
sd0: 122104MB, 512 bytes/sector, 250069680 sectors, thin
ichiic0 at pci0 dev 31 function 3 "Intel 7 Series SMBus" rev 0x04: apic 2 int 18
iic0 at ichiic0
isa0 at pcib0
isadma0 at isa0
pckbc0 at isa0 port 0x60/5 irq 1 irq 12
pckbd0 at pckbc0 (kbd slot)
wskbd0 at pckbd0: console keyboard, using wsdisplay0
pms0 at pckbc0 (aux slot)
wsmouse0 at pms0 mux 0
pms0: Elantech Clickpad, version 4, firmware 0x461f00
pcppi0 at isa0 port 0x61
spkr0 at pcppi0
vmm0 at mainbus0: VMX/EPT
uftdi0 at uhub0 port 3 configuration 1 interface 0 "FTDI USB HIGH SPEED SERIAL CONVERTER" rev 1.10/2.00 addr 2
ucom0 at uftdi0 portno 1
uhub2 at uhub1 port 1 configuration 1 interface 0 "Intel Rate Matching Hub" rev 2.00/0.00 addr 2
uhidev0 at uhub2 port 2 configuration 1 interface 0 "HP HP Wireless Keyboard Mouse Kit" rev 2.00/1.05 addr 3
uhidev0: iclass 3/1
ukbd0 at uhidev0: 8 variable keys, 6 key codes
wskbd1 at ukbd0 mux 1
wskbd1: connecting to wsdisplay0
uhidev1 at uhub2 port 2 configuration 1 interface 1 "HP HP Wireless Keyboard Mouse Kit" rev 2.00/1.05 addr 3
uhidev1: iclass 3/1, 8 report ids
ums0 at uhidev1 reportid 1: 3 buttons, Z dir
wsmouse1 at ums0 mux 0
uhid0 at uhidev1 reportid 2: input=2, output=0, feature=0
uhid1 at uhidev1 reportid 3: input=1, output=0, feature=0
uhid2 at uhidev1 reportid 4: input=2, output=0, feature=0
uhid3 at uhidev1 reportid 5: input=0, output=0, feature=7
uhid4 at uhidev1 reportid 6: input=0, output=0, feature=7
uhid5 at uhidev1 reportid 7: input=0, output=0, feature=7
uhid6 at uhidev1 reportid 8: input=2, output=0, feature=0
ugen0 at uhub2 port 5 "Intel product 0x07da" rev 2.00/78.69 addr 4
uvideo0 at uhub2 port 6 configuration 1 interface 0 "Namuga\M^? Webcam SC-13HDL11624N" rev 2.00/0.21 addr 5
video0 at uvideo0
vscsi0 at root
scsibus2 at vscsi0: 256 targets
softraid0 at root
scsibus3 at softraid0: 256 targets
root on sd0a (49bf0f84e9238c58.a) swap on sd0b dump on sd0b

usbdevs:
Controller /dev/usb0:
addr 1: super speed, self powered, config 1, xHCI root hub(0x0000), Renesas(0x1912), rev 1.00
 port 1 disabled
 port 2 disabled
 port 3 addr 2: full speed, power 44 mA, config 1, USB HIGH SPEED SERIAL CONVERTER(0x6001), FTDI(0x0403), rev 2.00, iSerialNumber FTAOICNC
 port 4 disabled
Controller /dev/usb1:
addr 1: high speed, self powered, config 1, EHCI root hub(0x0000), Intel(0x8086), rev 1.00
 port 1 addr 2: high speed, self powered, config 1, Rate Matching Hub(0x0024), Intel(0x8087), rev 0.00
  port 1 powered
  port 2 addr 3: low speed, power 98 mA, config 1, HP Wireless Keyboard Mouse Kit(0x0862), HP(0x03f0), rev 1.05
  port 3 powered
  port 4 powered
  port 5 addr 4: full speed, self powered, config 1, product 0x07da(0x07da), Intel(0x8087), rev 78.69
  port 6 addr 5: high speed, power 500 mA, config 1, Webcam SC-13HDL11624N(0x1024), Namuga├┐(0x2232), rev 0.21
 port 2 powered
 port 3 powered

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: iscsid(8) cannot connect to newer Linux targets

Claudio Jeker-3
On Thu, Mar 16, 2017 at 08:32:42PM +0100, Bruno Flueckiger wrote:

> >Synopsis: iscsid(8) cannot connect to newer Linux targets
> >Category: system
> >Environment:
> System      : OpenBSD 6.1
> Details     : OpenBSD 6.1-beta (GENERIC.MP) #26: Wed Mar 15 22:22:37 MDT 2017
> [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
>
> Architecture: OpenBSD.amd64
> Machine     : amd64
> >Description:
> The iSCSI targets of CentOS 7 and Synology DSM 6.0.2-8451 refuse to
> establish a connection with iscsid(8). Both systems complain about
> missing parameters during the security negotiation phase (CentOS)
> or the operational parameter negotiation phase (DSM).
> Besides Synology DSM and CentOS I've tested the connection to the
> iSCSI targets of the following operating systems: FreeBSD 11,
> NetBSD 7 and Debian 8 (has an old iSCSI implementation for Linux).
> The connection to these three systems is established without pro-
> blems.

Thanks for the report and the diff. I will rework your diff a bit and see
how to fix the kvp memory leaks correctly. Guess I need to setup a centos
7 box for testing.

> >How-To-Repeat:
> Way 1: Install any Linux-based OS with a kernel that uses the LIO
> iSCSI fabric module (http://linux-iscsi.org/wiki/ISCSI), configure
> a LUN accroding to the instructions in the link and try to connect
> to it using iscsid(8).
> Way 2: Create a LUN on a Synology product running a recent version
> of DSM and try to connect to it.
> >Fix:
> The following four diffs modify iscsid(8) in a way that the mis-
> sing parameters are advertised during the security negotiation
> phase and the operational parameter negotiation phase.
>
> Index: usr.sbin/iscsid/iscsid.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/iscsid/iscsid.c,v
> retrieving revision 1.20
> diff -u -p -r1.20 iscsid.c
> --- usr.sbin/iscsid/iscsid.c 23 Jan 2017 08:40:07 -0000 1.20
> +++ usr.sbin/iscsid/iscsid.c 2 Mar 2017 14:40:44 -0000
> @@ -254,6 +254,8 @@ iscsid_ctrl_dispatch(void *ch, struct pd
>   control_compose(ch, CTRL_FAILURE, NULL, 0);
>   goto done;
>   }
> + s->config.HeaderDigest = SESSION_DIGEST_NONE;
> + s->config.DataDigest = SESSION_DIGEST_NONE;
>   }
>  
>   session_config(s, sc);
>
> Index: usr.sbin/iscsid/iscsid.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/iscsid/iscsid.h,v
> retrieving revision 1.16
> diff -u -p -r1.16 iscsid.h
> --- usr.sbin/iscsid/iscsid.h 2 Sep 2016 16:22:31 -0000 1.16
> +++ usr.sbin/iscsid/iscsid.h 2 Mar 2017 14:40:54 -0000
> @@ -181,6 +181,9 @@ struct session_config {
>   u_int8_t disabled;
>  };
>  
> +#define SESSION_DIGEST_NONE 0
> +#define SESSION_DIGEST_CRC32 1
> +
>  #define SESSION_TYPE_NORMAL 0
>  #define SESSION_TYPE_DISCOVERY 1
>
> Index: usr.sbin/iscsid/initiator.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/iscsid/initiator.c,v
> retrieving revision 1.15
> diff -u -p -r1.15 initiator.c
> --- usr.sbin/iscsid/initiator.c 16 Jan 2015 15:57:06 -0000 1.15
> +++ usr.sbin/iscsid/initiator.c 3 Mar 2017 10:08:46 -0000
> @@ -250,39 +250,106 @@ initiator_nop_in_imm(struct connection *
>   conn_task_issue(c, t);
>  }
>  
> +#define WRITE_BOOL(k, v) \
> +do { \
> + if (v) \
> + k = "Yes"; \
> + else \
> + k = "No"; \
> +} while (0)
> +
> +#define WRITE_NUM(k, v) \
> +do { \
> + if (asprintf(&k, "%hu", v) == -1) \
> + return NULL; \
> +} while (0)
> +
> +#define WRITE_INT(k, v) \
> +do { \
> + if (asprintf(&k, "%u", v) == -1) \
> + return NULL; \
> +} while (0)
> +
> +#define WRITE_DIGEST(k, v) \
> +do { \
> + if (v) \
> + k = "CRC32"; \
> + else \
> + k = "None"; \
> +} while (0) \
> +

There are some memory leaks hiding here. At least the asprinf() version
leak memory. Just realized that the current code does more or less the
same :(

>  struct kvp *
>  initiator_login_kvp(struct connection *c, u_int8_t stage)
>  {
>   struct kvp *kvp;
> - size_t nkvp;
> + struct session *s;
>  
>   switch (stage) {
>   case ISCSI_LOGIN_STG_SECNEG:
> - if (!(kvp = calloc(4, sizeof(*kvp))))
> + if (!(kvp = calloc(5, sizeof(*kvp))))
>   return NULL;
>   kvp[0].key = "AuthMethod";
>   kvp[0].value = "None";
>   kvp[1].key = "InitiatorName";
>   kvp[1].value = c->session->config.InitiatorName;
> + kvp[2].key = "SessionType";
>  
>   if (c->session->config.SessionType == SESSION_TYPE_DISCOVERY) {
> - kvp[2].key = "SessionType";
>   kvp[2].value = "Discovery";
>   } else {
> - kvp[2].key = "TargetName";
> - kvp[2].value = c->session->config.TargetName;
> + kvp[2].value = "Normal";
> + kvp[3].key = "TargetName";
> + kvp[3].value = c->session->config.TargetName;
>   }
>   break;
>   case ISCSI_LOGIN_STG_OPNEG:
> - if (conn_gen_kvp(c, NULL, &nkvp) == -1)
> - return NULL;
> - nkvp += 1; /* add slot for terminator */
> - if (!(kvp = calloc(nkvp, sizeof(*kvp))))
> - return NULL;
> - if (conn_gen_kvp(c, kvp, &nkvp) == -1) {
> - free(kvp);
> + if (!(kvp = calloc(15, sizeof(*kvp))))
>   return NULL;
> - }
> +
> + s = c->session;
> +
> + kvp[0].key = "MaxConnections";
> + WRITE_NUM(kvp[0].value, s->mine.MaxConnections);
> +
> + kvp[1].key = "InitialR2T";
> + WRITE_BOOL(kvp[1].value, s->mine.InitialR2T);
> +
> + kvp[2].key = "ImmediateData";
> + WRITE_BOOL(kvp[2].value, s->mine.ImmediateData);
> +
> + kvp[3].key = "MaxRecvDataSegmentLength";
> + WRITE_INT(kvp[3].value, c->mine.MaxRecvDataSegmentLength);
> +
> + kvp[4].key = "MaxBurstLength";
> + WRITE_INT(kvp[4].value, s->mine.MaxBurstLength);
> +
> + kvp[5].key = "FirstBurstLength";
> + WRITE_INT(kvp[5].value, s->mine.FirstBurstLength);
> +
> + kvp[6].key = "HeaderDigest";
> + WRITE_DIGEST(kvp[6].value, s->config.HeaderDigest);
> +
> + kvp[7].key = "DataDigest";
> + WRITE_DIGEST(kvp[7].value, s->config.DataDigest);
> +
> + kvp[8].key = "MaxOutstandingR2T";
> + WRITE_NUM(kvp[8].value, s->mine.MaxOutstandingR2T);
> +
> + kvp[9].key = "DataPDUInOrder";
> + WRITE_BOOL(kvp[9].value, s->mine.DataPDUInOrder);
> +
> + kvp[10].key = "DataSequenceInOrder";
> + WRITE_BOOL(kvp[10].value, s->mine.DataSequenceInOrder);
> +
> + kvp[11].key = "ErrorRecoveryLevel";
> + WRITE_NUM(kvp[11].value, s->mine.ErrorRecoveryLevel);
> +
> + kvp[12].key = "DefaultTime2Wait";
> + WRITE_NUM(kvp[12].value, s->mine.DefaultTime2Wait);
> +
> + kvp[13].key = "DefaultTime2Retain";
> + WRITE_NUM(kvp[13].value, s->mine.DefaultTime2Retain);
> +

Hmm. If I remember the iscsi RFC correctly there is no need to send
default values to the target. So either I missed something in the RFC or
those targets are not behaving right. Do you know which params Linux is
complaining about (or is it realy all of them...).

>   break;
>   default:
>   log_warnx("initiator_login_kvp: exit stage left");
> @@ -290,6 +357,11 @@ initiator_login_kvp(struct connection *c
>   }
>   return kvp;
>  }
> +
> +#undef WRITE_DIGEST
> +#undef WRITE_INT
> +#undef WRITE_NUM
> +#undef WRITE_BOOL
>  
>  struct pdu *
>  initiator_login_build(struct connection *c, struct task_login *tl)
>
> Index: usr.sbin/iscsid/connection.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/iscsid/connection.c,v
> retrieving revision 1.21
> diff -u -p -r1.21 connection.c
> --- usr.sbin/iscsid/connection.c 5 Dec 2015 06:38:18 -0000 1.21
> +++ usr.sbin/iscsid/connection.c 2 Mar 2017 10:17:13 -0000
> @@ -316,44 +316,6 @@ log_debug("conn_parse_kvp: %s = %s", k->
>  #undef SET_NUM
>  #undef SET_BOOL
>  
> -int
> -conn_gen_kvp(struct connection *c, struct kvp *kvp, size_t *nkvp)
> -{
> - struct session *s = c->session;
> - size_t i = 0;
> -
> - if (s->mine.MaxConnections != iscsi_sess_defaults.MaxConnections) {
> - if (kvp && i < *nkvp) {
> - kvp[i].key = strdup("MaxConnections");
> - if (kvp[i].key == NULL)
> - return -1;
> - if (asprintf(&kvp[i].value, "%hu",
> -    s->mine.MaxConnections) == -1) {
> - kvp[i].value = NULL;
> - return -1;
> - }
> - }
> - i++;
> - }
> - if (c->mine.MaxRecvDataSegmentLength !=
> -    iscsi_conn_defaults.MaxRecvDataSegmentLength) {
> - if (kvp && i < *nkvp) {
> - kvp[i].key = strdup("MaxRecvDataSegmentLength");
> - if (kvp[i].key == NULL)
> - return -1;
> - if (asprintf(&kvp[i].value, "%u",
> -    c->mine.MaxRecvDataSegmentLength) == -1) {
> - kvp[i].value = NULL;
> - return -1;
> - }
> - }
> - i++;
> - }
> -
> - *nkvp = i;
> - return 0;
> -}
> -
>  void
>  conn_pdu_write(struct connection *c, struct pdu *p)
>  {
>

--
:wq Claudio

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: iscsid(8) cannot connect to newer Linux targets

Bruno Flueckiger
On Mon, Mar 20, 2017 at 10:46:19PM +0100, Claudio Jeker wrote:

> On Thu, Mar 16, 2017 at 08:32:42PM +0100, Bruno Flueckiger wrote:
> > >Synopsis: iscsid(8) cannot connect to newer Linux targets
> > >Category: system
> > >Environment:
> > System      : OpenBSD 6.1
> > Details     : OpenBSD 6.1-beta (GENERIC.MP) #26: Wed Mar 15 22:22:37 MDT 2017
> > [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> >
> > Architecture: OpenBSD.amd64
> > Machine     : amd64
> > >Description:
> > The iSCSI targets of CentOS 7 and Synology DSM 6.0.2-8451 refuse to
> > establish a connection with iscsid(8). Both systems complain about
> > missing parameters during the security negotiation phase (CentOS)
> > or the operational parameter negotiation phase (DSM).
> > Besides Synology DSM and CentOS I've tested the connection to the
> > iSCSI targets of the following operating systems: FreeBSD 11,
> > NetBSD 7 and Debian 8 (has an old iSCSI implementation for Linux).
> > The connection to these three systems is established without pro-
> > blems.
>
> Thanks for the report and the diff. I will rework your diff a bit and see
> how to fix the kvp memory leaks correctly. Guess I need to setup a centos
> 7 box for testing.
>

I still have my test VMs around, so if I can help out with additional
testing I'd happy to do so.

> > >How-To-Repeat:
> > Way 1: Install any Linux-based OS with a kernel that uses the LIO
> > iSCSI fabric module (http://linux-iscsi.org/wiki/ISCSI), configure
> > a LUN accroding to the instructions in the link and try to connect
> > to it using iscsid(8).
> > Way 2: Create a LUN on a Synology product running a recent version
> > of DSM and try to connect to it.
> > >Fix:
> > The following four diffs modify iscsid(8) in a way that the mis-
> > sing parameters are advertised during the security negotiation
> > phase and the operational parameter negotiation phase.
> >
> > Index: usr.sbin/iscsid/iscsid.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/iscsid/iscsid.c,v
> > retrieving revision 1.20
> > diff -u -p -r1.20 iscsid.c
> > --- usr.sbin/iscsid/iscsid.c 23 Jan 2017 08:40:07 -0000 1.20
> > +++ usr.sbin/iscsid/iscsid.c 2 Mar 2017 14:40:44 -0000
> > @@ -254,6 +254,8 @@ iscsid_ctrl_dispatch(void *ch, struct pd
> >   control_compose(ch, CTRL_FAILURE, NULL, 0);
> >   goto done;
> >   }
> > + s->config.HeaderDigest = SESSION_DIGEST_NONE;
> > + s->config.DataDigest = SESSION_DIGEST_NONE;
> >   }
> >  
> >   session_config(s, sc);
> >
> > Index: usr.sbin/iscsid/iscsid.h
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/iscsid/iscsid.h,v
> > retrieving revision 1.16
> > diff -u -p -r1.16 iscsid.h
> > --- usr.sbin/iscsid/iscsid.h 2 Sep 2016 16:22:31 -0000 1.16
> > +++ usr.sbin/iscsid/iscsid.h 2 Mar 2017 14:40:54 -0000
> > @@ -181,6 +181,9 @@ struct session_config {
> >   u_int8_t disabled;
> >  };
> >  
> > +#define SESSION_DIGEST_NONE 0
> > +#define SESSION_DIGEST_CRC32 1
> > +
> >  #define SESSION_TYPE_NORMAL 0
> >  #define SESSION_TYPE_DISCOVERY 1
> >
> > Index: usr.sbin/iscsid/initiator.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/iscsid/initiator.c,v
> > retrieving revision 1.15
> > diff -u -p -r1.15 initiator.c
> > --- usr.sbin/iscsid/initiator.c 16 Jan 2015 15:57:06 -0000 1.15
> > +++ usr.sbin/iscsid/initiator.c 3 Mar 2017 10:08:46 -0000
> > @@ -250,39 +250,106 @@ initiator_nop_in_imm(struct connection *
> >   conn_task_issue(c, t);
> >  }
> >  
> > +#define WRITE_BOOL(k, v) \
> > +do { \
> > + if (v) \
> > + k = "Yes"; \
> > + else \
> > + k = "No"; \
> > +} while (0)
> > +
> > +#define WRITE_NUM(k, v) \
> > +do { \
> > + if (asprintf(&k, "%hu", v) == -1) \
> > + return NULL; \
> > +} while (0)
> > +
> > +#define WRITE_INT(k, v) \
> > +do { \
> > + if (asprintf(&k, "%u", v) == -1) \
> > + return NULL; \
> > +} while (0)
> > +
> > +#define WRITE_DIGEST(k, v) \
> > +do { \
> > + if (v) \
> > + k = "CRC32"; \
> > + else \
> > + k = "None"; \
> > +} while (0) \
> > +
>
> There are some memory leaks hiding here. At least the asprinf() version
> leak memory. Just realized that the current code does more or less the
> same :(
>

I've taken the existing code as a template for my diff and I wasn't
aware of the memory leaks.

> >  struct kvp *
> >  initiator_login_kvp(struct connection *c, u_int8_t stage)
> >  {
> >   struct kvp *kvp;
> > - size_t nkvp;
> > + struct session *s;
> >  
> >   switch (stage) {
> >   case ISCSI_LOGIN_STG_SECNEG:
> > - if (!(kvp = calloc(4, sizeof(*kvp))))
> > + if (!(kvp = calloc(5, sizeof(*kvp))))
> >   return NULL;
> >   kvp[0].key = "AuthMethod";
> >   kvp[0].value = "None";
> >   kvp[1].key = "InitiatorName";
> >   kvp[1].value = c->session->config.InitiatorName;
> > + kvp[2].key = "SessionType";
> >  
> >   if (c->session->config.SessionType == SESSION_TYPE_DISCOVERY) {
> > - kvp[2].key = "SessionType";
> >   kvp[2].value = "Discovery";
> >   } else {
> > - kvp[2].key = "TargetName";
> > - kvp[2].value = c->session->config.TargetName;
> > + kvp[2].value = "Normal";
> > + kvp[3].key = "TargetName";
> > + kvp[3].value = c->session->config.TargetName;
> >   }
> >   break;
> >   case ISCSI_LOGIN_STG_OPNEG:
> > - if (conn_gen_kvp(c, NULL, &nkvp) == -1)
> > - return NULL;
> > - nkvp += 1; /* add slot for terminator */
> > - if (!(kvp = calloc(nkvp, sizeof(*kvp))))
> > - return NULL;
> > - if (conn_gen_kvp(c, kvp, &nkvp) == -1) {
> > - free(kvp);
> > + if (!(kvp = calloc(15, sizeof(*kvp))))
> >   return NULL;
> > - }
> > +
> > + s = c->session;
> > +
> > + kvp[0].key = "MaxConnections";
> > + WRITE_NUM(kvp[0].value, s->mine.MaxConnections);
> > +
> > + kvp[1].key = "InitialR2T";
> > + WRITE_BOOL(kvp[1].value, s->mine.InitialR2T);
> > +
> > + kvp[2].key = "ImmediateData";
> > + WRITE_BOOL(kvp[2].value, s->mine.ImmediateData);
> > +
> > + kvp[3].key = "MaxRecvDataSegmentLength";
> > + WRITE_INT(kvp[3].value, c->mine.MaxRecvDataSegmentLength);
> > +
> > + kvp[4].key = "MaxBurstLength";
> > + WRITE_INT(kvp[4].value, s->mine.MaxBurstLength);
> > +
> > + kvp[5].key = "FirstBurstLength";
> > + WRITE_INT(kvp[5].value, s->mine.FirstBurstLength);
> > +
> > + kvp[6].key = "HeaderDigest";
> > + WRITE_DIGEST(kvp[6].value, s->config.HeaderDigest);
> > +
> > + kvp[7].key = "DataDigest";
> > + WRITE_DIGEST(kvp[7].value, s->config.DataDigest);
> > +
> > + kvp[8].key = "MaxOutstandingR2T";
> > + WRITE_NUM(kvp[8].value, s->mine.MaxOutstandingR2T);
> > +
> > + kvp[9].key = "DataPDUInOrder";
> > + WRITE_BOOL(kvp[9].value, s->mine.DataPDUInOrder);
> > +
> > + kvp[10].key = "DataSequenceInOrder";
> > + WRITE_BOOL(kvp[10].value, s->mine.DataSequenceInOrder);
> > +
> > + kvp[11].key = "ErrorRecoveryLevel";
> > + WRITE_NUM(kvp[11].value, s->mine.ErrorRecoveryLevel);
> > +
> > + kvp[12].key = "DefaultTime2Wait";
> > + WRITE_NUM(kvp[12].value, s->mine.DefaultTime2Wait);
> > +
> > + kvp[13].key = "DefaultTime2Retain";
> > + WRITE_NUM(kvp[13].value, s->mine.DefaultTime2Retain);
> > +
>
> Hmm. If I remember the iscsi RFC correctly there is no need to send
> default values to the target. So either I missed something in the RFC or
> those targets are not behaving right. Do you know which params Linux is
> complaining about (or is it realy all of them...).
>

Unfortunately the CentOS targets just returns the status code 0x0207 in
the login response (according to RFC 7143 Section 11.13.5.). So I've
checked the source of the Linux kernel 3.10 and found that it requires
the following parameter to be set:

- HeaderDigest
- DataDigest
- MaxOutstandingR2T
- DataPDUInOrder
- DataSequenceInOrder
- ErrorRecoveryLevel

Additionally the CentOs 7 target reuires the parameter Discovery to be
set during the security negotiation phase, else it refuses the
connection with an error message that this parameter is missing.

On the Synology DSM target the situation is different due to
modifications the manufacturer has made to the iSCSI target. In the
tcpdump of the failed login I can see that it seems to require the
following parameters:

- HeaderDigest
- DataDigest
- MaxConnections
- InitialR2T
- ImmediateData
- MaxRecvDataSegmentLength
- MaxBurstLength
- FirstBurstLength
- MaxOutstandingR2T
- DataPDUInOrder
- DataSequenceInOrder
- ErrorRecoveryLevel

This list is based on a packet capture I've taken. You can get the pcap
file from here:

https://www.bsdhowto.ch/wp-content/uploads/2017/03/synology_target.pcap

The RFC 7143 states in Section 6 that most of the parameters can be
proposed by both initiator and target. Each proposal made by one side
must be answered by the other side. The existing code in iscsid repeats
the sending of the initial parameters if the T bit in the response is
clear. So I saw to ways for patching: either modify the code to detect
what parameters the targets wants to see or simply send all available
parameters in the first login request even if they have default values.

> >   break;
> >   default:
> >   log_warnx("initiator_login_kvp: exit stage left");
> > @@ -290,6 +357,11 @@ initiator_login_kvp(struct connection *c
> >   }
> >   return kvp;
> >  }
> > +
> > +#undef WRITE_DIGEST
> > +#undef WRITE_INT
> > +#undef WRITE_NUM
> > +#undef WRITE_BOOL
> >  
> >  struct pdu *
> >  initiator_login_build(struct connection *c, struct task_login *tl)
> >
> > Index: usr.sbin/iscsid/connection.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/iscsid/connection.c,v
> > retrieving revision 1.21
> > diff -u -p -r1.21 connection.c
> > --- usr.sbin/iscsid/connection.c 5 Dec 2015 06:38:18 -0000 1.21
> > +++ usr.sbin/iscsid/connection.c 2 Mar 2017 10:17:13 -0000
> > @@ -316,44 +316,6 @@ log_debug("conn_parse_kvp: %s = %s", k->
> >  #undef SET_NUM
> >  #undef SET_BOOL
> >  
> > -int
> > -conn_gen_kvp(struct connection *c, struct kvp *kvp, size_t *nkvp)
> > -{
> > - struct session *s = c->session;
> > - size_t i = 0;
> > -
> > - if (s->mine.MaxConnections != iscsi_sess_defaults.MaxConnections) {
> > - if (kvp && i < *nkvp) {
> > - kvp[i].key = strdup("MaxConnections");
> > - if (kvp[i].key == NULL)
> > - return -1;
> > - if (asprintf(&kvp[i].value, "%hu",
> > -    s->mine.MaxConnections) == -1) {
> > - kvp[i].value = NULL;
> > - return -1;
> > - }
> > - }
> > - i++;
> > - }
> > - if (c->mine.MaxRecvDataSegmentLength !=
> > -    iscsi_conn_defaults.MaxRecvDataSegmentLength) {
> > - if (kvp && i < *nkvp) {
> > - kvp[i].key = strdup("MaxRecvDataSegmentLength");
> > - if (kvp[i].key == NULL)
> > - return -1;
> > - if (asprintf(&kvp[i].value, "%u",
> > -    c->mine.MaxRecvDataSegmentLength) == -1) {
> > - kvp[i].value = NULL;
> > - return -1;
> > - }
> > - }
> > - i++;
> > - }
> > -
> > - *nkvp = i;
> > - return 0;
> > -}
> > -
> >  void
> >  conn_pdu_write(struct connection *c, struct pdu *p)
> >  {
> >
>
> --
> :wq Claudio

Cheers,
Bruno

Loading...