diff --git a/SOURCES/0143-idmb_rec_write-check-for-tpgt-first.patch b/SOURCES/0143-idmb_rec_write-check-for-tpgt-first.patch new file mode 100644 index 00000000..cdc958aa --- /dev/null +++ b/SOURCES/0143-idmb_rec_write-check-for-tpgt-first.patch @@ -0,0 +1,55 @@ +From 24a4d8156786dfd91dcc17b2472653e963ebd028 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 13 Aug 2013 10:59:44 -0700 +Subject: idmb_rec_write, check for tpgt first + +Factor out the check for a tpgt to a single place, before going crazy on +the rec files. Makes flow of this function easier to follow, and preps +for splitting it up. +--- + usr/idbm.c | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +diff --git a/usr/idbm.c b/usr/idbm.c +index 1e4f8c8..0a88699 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -1849,6 +1849,10 @@ static int idbm_rec_write(node_rec_t *rec) + if (rc) + goto free_portal; + ++ if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) ++ /* drop down to old style portal as config */ ++ goto open_conf; ++ + rc = stat(portal, &statb); + if (rc) { + rc = 0; +@@ -1857,23 +1861,11 @@ static int idbm_rec_write(node_rec_t *rec) + * set the tgpt. In new versions you must pass all the info in + * from the start + */ +- if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) +- /* drop down to old style portal as config */ +- goto open_conf; +- else +- goto mkdir_portal; ++ goto mkdir_portal; + } + + if (!S_ISDIR(statb.st_mode)) { + /* +- * older iscsiadm versions had you create the config then set +- * set the tgpt. In new versions you must pass all the info in +- * from the start +- */ +- if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) +- /* drop down to old style portal as config */ +- goto open_conf; +- /* + * Old style portal as a file, but with tpgt. Let's update it. + */ + if (unlink(portal)) { +-- +1.8.1.4 + diff --git a/SOURCES/0145-idbm_rec_write-seperate-old-and-new-style-writes.patch b/SOURCES/0145-idbm_rec_write-seperate-old-and-new-style-writes.patch new file mode 100644 index 00000000..f8b4dbf5 --- /dev/null +++ b/SOURCES/0145-idbm_rec_write-seperate-old-and-new-style-writes.patch @@ -0,0 +1,180 @@ +From 220f360b81246a45d6246b85f7b6bf4133f3c213 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 13 Aug 2013 11:34:31 -0700 +Subject: [PATCH] idbm_rec_write, seperate old and new style writes + +Duplicates a small bit of code, but easier to understand and extened. +--- + usr/idbm.c | 116 +++++++++++++++++++++++++++++++++++++++++-------------------- + 1 file changed, 79 insertions(+), 37 deletions(-) + +diff --git a/usr/idbm.c b/usr/idbm.c +index caec94f..2b4f0da 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -2000,7 +2000,7 @@ mkdir_portal: + return f; + } + +-static int idbm_rec_write(node_rec_t *rec) ++static int idbm_rec_write_new(node_rec_t *rec) + { + struct stat statb; + FILE *f; +@@ -2012,38 +2012,8 @@ static int idbm_rec_write(node_rec_t *rec) + log_error("Could not alloc portal"); + return ISCSI_ERR_NOMEM; + } +- +- snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR); +- if (access(portal, F_OK) != 0) { +- if (mkdir(portal, 0660) != 0) { +- log_error("Could not make %s: %s", portal, +- strerror(errno)); +- rc = ISCSI_ERR_IDBM; +- goto free_portal; +- } +- } +- +- snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name); +- if (access(portal, F_OK) != 0) { +- if (mkdir(portal, 0660) != 0) { +- log_error("Could not make %s: %s", portal, +- strerror(errno)); +- rc = ISCSI_ERR_IDBM; +- goto free_portal; +- } +- } +- + snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, + rec->name, rec->conn[0].address, rec->conn[0].port); +- log_debug(5, "Looking for config file %s", portal); +- +- rc = idbm_lock(); +- if (rc) +- goto free_portal; +- +- if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) +- /* drop down to old style portal as config */ +- goto open_conf; + + rc = stat(portal, &statb); + if (rc) { +@@ -2064,11 +2034,11 @@ static int idbm_rec_write(node_rec_t *rec) + log_error("Could not convert %s: %s", portal, + strerror(errno)); + rc = ISCSI_ERR_IDBM; +- goto unlock; ++ goto free_portal; + } + } else { + rc = ISCSI_ERR_INVAL; +- goto unlock; ++ goto free_portal; + } + + mkdir_portal: +@@ -2079,24 +2049,96 @@ mkdir_portal: + log_error("Could not make dir %s: %s", + portal, strerror(errno)); + rc = ISCSI_ERR_IDBM; +- goto unlock; ++ goto free_portal; + } + } + + snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR, + rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt, + rec->iface.name); +-open_conf: ++/* open_conf: */ + f = fopen(portal, "w"); + if (!f) { + log_error("Could not open %s: %s", portal, strerror(errno)); + rc = ISCSI_ERR_IDBM; +- goto unlock; ++ goto free_portal; + } + + idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f); + fclose(f); +-unlock: ++free_portal: ++ free(portal); ++ return rc; ++} ++ ++static int idbm_rec_write_old(node_rec_t *rec) ++{ ++ FILE *f; ++ char *portal; ++ int rc = 0; ++ ++ portal = malloc(PATH_MAX); ++ if (!portal) { ++ log_error("Could not alloc portal"); ++ return ISCSI_ERR_NOMEM; ++ } ++ snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, ++ rec->name, rec->conn[0].address, rec->conn[0].port); ++ ++ f = fopen(portal, "w"); ++ if (!f) { ++ log_error("Could not open %s: %s", portal, strerror(errno)); ++ rc = ISCSI_ERR_IDBM; ++ goto free_portal; ++ } ++ idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f); ++ fclose(f); ++free_portal: ++ free(portal); ++ return rc; ++} ++ ++static int idbm_rec_write(node_rec_t *rec) ++{ ++ char *portal; ++ int rc = 0; ++ ++ portal = malloc(PATH_MAX); ++ if (!portal) { ++ log_error("Could not alloc portal"); ++ return ISCSI_ERR_NOMEM; ++ } ++ ++ snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR); ++ if (access(portal, F_OK) != 0) { ++ if (mkdir(portal, 0660) != 0) { ++ log_error("Could not make %s: %s", portal, ++ strerror(errno)); ++ rc = ISCSI_ERR_IDBM; ++ goto free_portal; ++ } ++ } ++ ++ snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name); ++ if (access(portal, F_OK) != 0) { ++ if (mkdir(portal, 0660) != 0) { ++ log_error("Could not make %s: %s", portal, ++ strerror(errno)); ++ rc = ISCSI_ERR_IDBM; ++ goto free_portal; ++ } ++ } ++ ++ rc = idbm_lock(); ++ if (rc) ++ goto free_portal; ++ ++ if (rec->tpgt == PORTAL_GROUP_TAG_UNKNOWN) ++ /* old style portal as config */ ++ rc = idbm_rec_write_old(rec); ++ else ++ rc = idbm_rec_write_new(rec); ++ + idbm_unlock(); + free_portal: + free(portal); +-- +2.5.5 + diff --git a/SOURCES/0146-idbw_rec_write-pick-tpgt-from-existing-record.patch b/SOURCES/0146-idbw_rec_write-pick-tpgt-from-existing-record.patch new file mode 100644 index 00000000..28785da8 --- /dev/null +++ b/SOURCES/0146-idbw_rec_write-pick-tpgt-from-existing-record.patch @@ -0,0 +1,87 @@ +From 69de52494cd8f57762ca9b0b7811929f7f9b4287 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 13 Aug 2013 12:39:07 -0700 +Subject: [PATCH] idbw_rec_write, pick tpgt from existing record + +On a static add (-m node -o new) without a user specified tpgt, looks +for existing new style records with tpgt before creating an old style +record without. If one exists, take the tpgt from it an write an +updated new style record instead. +--- + usr/idbm.c | 40 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/usr/idbm.c b/usr/idbm.c +index 2b4f0da..a2ad57f 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -162,6 +163,8 @@ static struct idbm *db; + _n++; \ + } while(0) + ++static int idbm_remove_disc_to_node_link(node_rec_t *rec, char *portal); ++ + static void + idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri) + { +@@ -2076,12 +2079,49 @@ static int idbm_rec_write_old(node_rec_t *rec) + FILE *f; + char *portal; + int rc = 0; ++ glob_t globbuf; ++ int i; ++ int tpgt = PORTAL_GROUP_TAG_UNKNOWN; + + portal = malloc(PATH_MAX); + if (!portal) { + log_error("Could not alloc portal"); + return ISCSI_ERR_NOMEM; + } ++ ++ /* check for newer portal dir with tpgt */ ++ snprintf(portal, PATH_MAX, "%s/%s/%s,%d,*", NODE_CONFIG_DIR, ++ rec->name, rec->conn[0].address, rec->conn[0].port); ++ rc = glob(portal, GLOB_ONLYDIR, NULL, &globbuf); ++ if (!rc) { ++ if (globbuf.gl_pathc > 1) ++ log_warning("multiple tpg records for portal " ++ "%s/%s:%d found", rec->name, ++ rec->conn[0].address, rec->conn[0].port); ++ /* set pattern for sscanf matching of tpgt */ ++ snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%%u", NODE_CONFIG_DIR, ++ rec->name, rec->conn[0].address, rec->conn[0].port); ++ for (i = 0; i < globbuf.gl_pathc; i++) { ++ rc = sscanf(globbuf.gl_pathv[i], portal, &tpgt); ++ if (rc == 1) ++ break; ++ } ++ if (tpgt == PORTAL_GROUP_TAG_UNKNOWN) ++ log_warning("glob match on existing records, " ++ "but no valid tpgt found"); ++ } ++ globfree(&globbuf); ++ rc = 0; ++ ++ /* if a tpgt was selected from an old record, write entry in new format */ ++ if (tpgt != PORTAL_GROUP_TAG_UNKNOWN) { ++ log_warning("using tpgt %u from existing record", tpgt); ++ rec->tpgt = tpgt; ++ rc = idbm_remove_disc_to_node_link(rec, portal); ++ free(portal); ++ return idbm_rec_write_new(rec); ++ } ++ + snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, + rec->name, rec->conn[0].address, rec->conn[0].port); + +-- +2.5.5 + diff --git a/SOURCES/0149-update-systemd-service-files-add-iscsi.service-for-s.patch b/SOURCES/0149-update-systemd-service-files-add-iscsi.service-for-s.patch new file mode 100644 index 00000000..966bb9fa --- /dev/null +++ b/SOURCES/0149-update-systemd-service-files-add-iscsi.service-for-s.patch @@ -0,0 +1,93 @@ +From 1c3b1d23e0b3f17399ffd4463cafad813b0444d5 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Wed, 19 Dec 2012 15:07:36 -0800 +Subject: update systemd service files, add iscsi.service for starting + sessions on boot + +Signed-off-by: Chris Leech +--- + etc/systemd/iscsi.service | 19 +++++++++++++++++++ + etc/systemd/iscsi_mark_root_nodes | 14 ++++++++++++++ + etc/systemd/iscsid.service | 7 +++++-- + etc/systemd/iscsid.socket | 2 +- + 4 files changed, 39 insertions(+), 3 deletions(-) + create mode 100644 etc/systemd/iscsi.service + create mode 100755 etc/systemd/iscsi_mark_root_nodes + +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +new file mode 100644 +index 0000000..bbd52fd +--- /dev/null ++++ b/etc/systemd/iscsi.service +@@ -0,0 +1,19 @@ ++[Unit] ++Description=Login and scanning of iSCSI devices ++Documentation=man:iscsid(8) man:iscsiadm(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service ++Before=remote-fs-pre.target ++ConditionPathExists=/etc/iscsi/initiatorname.iscsi ++ ++[Service] ++Type=oneshot ++RemainAfterExit=true ++ExecStart=/usr/libexec/iscsi_mark_root_nodes ++ExecStart=/sbin/iscsiadm -m node --loginall=automatic ++ExecStop=/bin/sync ++ExecStop=/sbin/iscsiadm -m node --logoutall=automatic ++ ++[Install] ++WantedBy=sysinit.target +diff --git a/etc/systemd/iscsi_mark_root_nodes b/etc/systemd/iscsi_mark_root_nodes +new file mode 100755 +index 0000000..c68475c +--- /dev/null ++++ b/etc/systemd/iscsi_mark_root_nodes +@@ -0,0 +1,14 @@ ++#!/bin/bash ++ ++ISCSIADM=/sbin/iscsiadm ++SESSION_FILE=/run/initramfs/iscsi.sessions ++ ++if [ ! -f $SESSION_FILE ] ; then ++ exit 0 ++fi ++ ++while read t num i target; do ++ ip=${i%:*} ++ $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot ++done < $SESSION_FILE ++ +diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service +index 028e0b3..653dd08 100644 +--- a/etc/systemd/iscsid.service ++++ b/etc/systemd/iscsid.service +@@ -1,7 +1,10 @@ + [Unit] + Description=Open-iSCSI +-Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) +-After=network.target NetworkManager-wait-online.service iscsiuio.service tgtd.service targetcli.service ++Documentation=man:iscsid(8) man:iscsiadm(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=network.target iscsiuio.service ++Before=remote-fs-pre.target + + [Service] + Type=forking +diff --git a/etc/systemd/iscsid.socket b/etc/systemd/iscsid.socket +index 832451d..58a8d12 100644 +--- a/etc/systemd/iscsid.socket ++++ b/etc/systemd/iscsid.socket +@@ -1,6 +1,6 @@ + [Unit] + Description=Open-iSCSI iscsid Socket +-Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) ++Documentation=man:iscsid(8) man:iscsiadm(8) + + [Socket] + ListenStream=@ISCSIADM_ABSTRACT_NAMESPACE +-- +1.7.11.7 + diff --git a/SOURCES/0150-iscsi-boot-related-service-file-updates.patch b/SOURCES/0150-iscsi-boot-related-service-file-updates.patch new file mode 100644 index 00000000..19450ee4 --- /dev/null +++ b/SOURCES/0150-iscsi-boot-related-service-file-updates.patch @@ -0,0 +1,75 @@ +From 8f79529354b4023c371e00091f11bdd523497639 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Aug 2013 07:18:25 -0700 +Subject: iscsi boot related service file updates + +make sure iscsid gets started if there are any boot sessions running +add reload target to fix double session problem when restarting from NM +don't rely on session list passed from initrd, never got fully implemented +--- + etc/systemd/iscsi-mark-root-nodes | 13 +++++++++++++ + etc/systemd/iscsi.service | 3 ++- + etc/systemd/iscsi_mark_root_nodes | 14 -------------- + 3 files changed, 15 insertions(+), 15 deletions(-) + create mode 100644 etc/systemd/iscsi-mark-root-nodes + delete mode 100644 etc/systemd/iscsi_mark_root_nodes + +diff --git a/etc/systemd/iscsi-mark-root-nodes b/etc/systemd/iscsi-mark-root-nodes +new file mode 100644 +index 0000000..157be62 +--- /dev/null ++++ b/etc/systemd/iscsi-mark-root-nodes +@@ -0,0 +1,13 @@ ++#!/bin/bash ++ ++ISCSIADM=/sbin/iscsiadm ++ ++$ISCSIADM -m session >/dev/null 2>&1 || exit 0 ++ ++$ISCSIADM -m session | while read t num i target; do ++ ip=${i%:*} ++ $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot ++done ++ ++systemctl start iscsid.service ++ +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index 7b4efee..d5712bd 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -10,10 +10,11 @@ ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes + [Service] + Type=oneshot + RemainAfterExit=true +-ExecStart=/usr/libexec/iscsi_mark_root_nodes ++ExecStart=/usr/libexec/iscsi-mark-root-nodes + ExecStart=/sbin/iscsiadm -m node --loginall=automatic + ExecStop=/bin/sync + ExecStop=/sbin/iscsiadm -m node --logoutall=automatic ++ExecReload=/sbin/iscsiadm -m node --loginall=automatic + + [Install] + WantedBy=sysinit.target +diff --git a/etc/systemd/iscsi_mark_root_nodes b/etc/systemd/iscsi_mark_root_nodes +deleted file mode 100644 +index c68475c..0000000 +--- a/etc/systemd/iscsi_mark_root_nodes ++++ /dev/null +@@ -1,14 +0,0 @@ +-#!/bin/bash +- +-ISCSIADM=/sbin/iscsiadm +-SESSION_FILE=/run/initramfs/iscsi.sessions +- +-if [ ! -f $SESSION_FILE ] ; then +- exit 0 +-fi +- +-while read t num i target; do +- ip=${i%:*} +- $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot +-done < $SESSION_FILE +- +-- +1.8.1.4 + diff --git a/SOURCES/0151-update-initscripts-and-docs.patch b/SOURCES/0151-update-initscripts-and-docs.patch new file mode 100644 index 00000000..c7cc8a93 --- /dev/null +++ b/SOURCES/0151-update-initscripts-and-docs.patch @@ -0,0 +1,130 @@ +From 714a9dbed8e4c9d943ce34896a58d48a174f54cb Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:37:13 -0800 +Subject: [PATCH] update initscripts and docs + +--- + README | 9 +++------ + etc/iscsid.conf | 23 +++++++++++------------ + usr/idbm.c | 4 ++++ + 3 files changed, 18 insertions(+), 18 deletions(-) + +diff --git a/README b/README +index cbe8763..8db3013 100644 +--- a/README ++++ b/README +@@ -74,11 +74,6 @@ the cache sync command will fail. + - iscsiadm's -P 3 option will not print out scsi devices. + - iscsid will not automatically online devices. + +-You need to enable "Cryptographic API" under "Cryptographic options" in the +-kernel config. And you must enable "CRC32c CRC algorithm" even if +-you do not use header or data digests. They are the kernel options, +-CONFIG_CRYPTO and CONFIG_CRYPTO_CRC32C, respectively. +- + The userspace components: iscsid, iscsiadm and iscsistart require the + open-isns library which can be found here: + +@@ -1132,7 +1127,7 @@ Red Hat or Fedora: + ----------------- + To start open-iscsi in Red Hat/Fedora you can do: + +- service open-iscsi start ++ service iscsi start + + To get open-iscsi to automatically start at run time you may have to + run: +@@ -1340,6 +1335,8 @@ iscsid will only perform rediscovery when it gets a SCN from the server. + # linux-isns (SLES's iSNS server) where it sometimes does not send SCN + # events in the proper format, so they may not get handled. + ++To set the startup value, so that nodes are not logged into automatically ++use the value "manual". + + Example: + -------- +diff --git a/etc/iscsid.conf b/etc/iscsid.conf +index c30a7dc..cfa6844 100644 +--- a/etc/iscsid.conf ++++ b/etc/iscsid.conf +@@ -17,10 +17,10 @@ + # maintainers. + # + # Default for Fedora and RHEL. (uncomment to activate). +-# iscsid.startup = /etc/rc.d/init.d/iscsid force-start ++iscsid.startup = /etc/rc.d/init.d/iscsid force-start + # + # Default for upstream open-iscsi scripts (uncomment to activate). +-iscsid.startup = /sbin/iscsid ++# iscsid.startup = /sbin/iscsid + + # Check for active mounts on devices reachable through a session + # and refuse to logout if there are any. Defaults to "No". +@@ -39,8 +39,8 @@ iscsid.startup = /sbin/iscsid + # To request that the iscsi initd scripts startup a session set to "automatic". + # node.startup = automatic + # +-# To manually startup the session set to "manual". The default is manual. +-node.startup = manual ++# To manually startup the session set to "manual". The default is automatic. ++node.startup = automatic + + # For "automatic" startup nodes, setting this to "Yes" will try logins on each + # available iface until one succeeds, and then stop. The default "No" will try +@@ -262,28 +262,27 @@ node.conn[0].iscsi.MaxXmitDataSegmentLength = 0 + discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 32768 + + # To allow the targets to control the setting of the digest checking, +-# with the initiator requesting a preference of enabling the checking, uncomment# one or both of the following lines: ++# with the initiator requesting a preference of enabling the checking, uncomment ++# the following lines (Data digests are not supported.): + #node.conn[0].iscsi.HeaderDigest = CRC32C,None +-#node.conn[0].iscsi.DataDigest = CRC32C,None ++ + # + # To allow the targets to control the setting of the digest checking, + # with the initiator requesting a preference of disabling the checking, +-# uncomment one or both of the following lines: ++# uncomment the following line: + #node.conn[0].iscsi.HeaderDigest = None,CRC32C +-#node.conn[0].iscsi.DataDigest = None,CRC32C + # + # To enable CRC32C digest checking for the header and/or data part of +-# iSCSI PDUs, uncomment one or both of the following lines: ++# iSCSI PDUs, uncomment the following line: + #node.conn[0].iscsi.HeaderDigest = CRC32C +-#node.conn[0].iscsi.DataDigest = CRC32C + # + # To disable digest checking for the header and/or data part of +-# iSCSI PDUs, uncomment one or both of the following lines: ++# iSCSI PDUs, uncomment the following line: + #node.conn[0].iscsi.HeaderDigest = None +-#node.conn[0].iscsi.DataDigest = None + # + # The default is to never use DataDigests or HeaderDigests. + # ++node.conn[0].iscsi.HeaderDigest = None + + # For multipath configurations, you may want more than one session to be + # created on each iface record. If node.session.nr_sessions is greater +diff --git a/usr/idbm.c b/usr/idbm.c +index 198a5ef..2d64172 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -509,9 +509,13 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) + IDBM_SHOW, "None", "CRC32C", "CRC32C,None", + "None,CRC32C", num, 1); + sprintf(key, CONN_DATA_DIGEST, i); ++ ++#if 0 ++We do not support data digests + __recinfo_int_o4(key, ri, r, conn[i].iscsi.DataDigest, IDBM_SHOW, + "None", "CRC32C", "CRC32C,None", + "None,CRC32C", num, 1); ++#endif + sprintf(key, CONN_IFMARKER, i); + __recinfo_int_o2(key, ri, r, conn[i].iscsi.IFMarker, IDBM_SHOW, + "No", "Yes", num, 1); +-- +2.5.5 + diff --git a/SOURCES/0152-use-var-for-config.patch b/SOURCES/0152-use-var-for-config.patch new file mode 100644 index 00000000..57baebb6 --- /dev/null +++ b/SOURCES/0152-use-var-for-config.patch @@ -0,0 +1,239 @@ +From c229e7d74a3103814403f7c242abcbaef211e259 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:38:45 -0800 +Subject: use var for config + +--- + README | 33 ++++++++++++++++----------------- + doc/iscsiadm.8 | 8 ++++---- + usr/idbm.c | 6 +++--- + usr/idbm.h | 13 +++++++------ + usr/iface.h | 4 +++- + 5 files changed, 33 insertions(+), 31 deletions(-) + +diff --git a/README b/README +index 3757b2d26d0d..fa38c8c82dcf 100644 +--- a/README ++++ b/README +@@ -170,8 +170,7 @@ Usage: iscsid [OPTION] + + Open-iSCSI persistent configuration is stored in a number of + directories under a configuration root directory, using a flat-file +-format. This configuration root directory is /etc/iscsi by default, +-but may also commonly be in /var/lib/iscsi. ++format. This configuration root directory is /var/lib/iscsi by default. + + Configuration is contained in directories for: + +@@ -489,7 +488,7 @@ a scsi_host per HBA port). + To manage both types of initiator stacks, iscsiadm uses the interface (iface) + structure. For each HBA port or for software iscsi for each network + device (ethX) or NIC, that you wish to bind sessions to you must create +-a iface config /etc/iscsi/ifaces. ++a iface config /var/lib/iscsi/ifaces. + + Prep: + +@@ -523,29 +522,29 @@ Running: + iface0 qla4xxx,00:c0:dd:08:63:e8,20.15.0.7,default,iqn.2005-06.com.redhat:madmax + iface1 qla4xxx,00:c0:dd:08:63:ea,20.15.0.9,default,iqn.2005-06.com.redhat:madmax + +-Will report iface configurations that are setup in /etc/iscsi/ifaces. ++Will report iface configurations that are setup in /var/lib/iscsi/ifaces. + The format is: + + iface_name transport_name,hwaddress,ipaddress,net_ifacename,initiatorname + + For software iscsi, you can create the iface configs by hand, but it is + recommended that you use iscsiadm's iface mode. There is an iface.example in +-/etc/iscsi/ifaces which can be used as a template for the daring. ++/var/lib/iscsi/ifaces which can be used as a template for the daring. + + For each network object you wish to bind a session to you must create +-a separate iface config in /etc/iscsi/ifaces and each iface config file ++a separate iface config in /var/lib/iscsi/ifaces and each iface config file + must have a unique name which is less than or equal to 64 characters. + + Example: + + If you have NIC1 with MAC address 00:0F:1F:92:6B:BF and NIC2 with + MAC address 00:C0:DD:08:63:E7 and you wanted to do software iscsi over +-TCP/IP. Then in /etc/iscsi/ifaces/iface0 you would enter: ++TCP/IP. Then in /var/lib/iscsi/ifaces/iface0 you would enter: + + iface.transport_name = tcp + iface.hwaddress = 00:0F:1F:92:6B:BF + +-and in /etc/iscsi/ifaces/iface1 you would enter: ++and in /var/lib/iscsi/ifaces/iface1 you would enter: + + iface.transport_name = tcp + iface.hwaddress = 00:C0:DD:08:63:E7 +@@ -595,7 +594,7 @@ cxgb3i.00:07:43:05:97:07 cxgb3i,00:07:43:05:97:07,,, + qla4xxx.00:0e:1e:04:8b:2e qla4xxx,00:0e:1e:04:8b:2e,,, + + +-Will report iface configurations that are setup in /etc/iscsi/ifaces. ++Will report iface configurations that are setup in /var/lib/iscsi/ifaces. + The format is: + + iface_name transport_name,hwaddress,ipaddress,net_ifacename,initiatorname +@@ -681,7 +680,7 @@ need a separate network connection to the target for discovery purposes. + *This will be fixed in the next version of open-iscsi* + + For compatibility reasons, when you run iscsiadm to do discovery, it +-will check for interfaces in /etc/iscsi/iscsi/ifaces that are using ++will check for interfaces in /var/lib/iscsi/ifaces that are using + tcp for the iface.transport and it will bind the portals that are discovered + so that they will be logged in through those ifaces. This behavior can also + be overriden by passing in the interfaces you want to use. For the case +@@ -699,7 +698,7 @@ we do not bind a session to an iface, then you can use the special iface + + iscsiadm -m discoverydb -t st -p ip:port -I default --discover -P 1 + +-And if you did not define any interfaces in /etc/iscsi/ifaces and do ++And if you did not define any interfaces in /var/lib/iscsi/ifaces and do + not pass anything into iscsiadm, running iscsiadm will do the default + behavior, where we allow the network subsystem to decide which + device to use. +@@ -741,7 +740,7 @@ To now log into targets it is the same as with software iscsi. See section + + ./iscsiadm -m discoverydb -t st -p 192.168.1.1:3260 --discover + +- This will search /etc/iscsi/send_targets for a record with the ++ This will search /var/lib/iscsi/send_targets for a record with the + ID [portal = 192.168.1.1:3260 and type = sendtargets. If found it + will perform discovery using the settings stored in the record. + If a record does not exist, it will be created using the iscsid.conf +@@ -750,7 +749,7 @@ To now log into targets it is the same as with software iscsi. See section + The argument to -p may also be a hostname instead of an address. + ./iscsiadm -m discoverydb -t st -p smoehost --discover + +- For the ifaces, iscsiadm will first search /etc/iscsi/ifaces for ++ For the ifaces, iscsiadm will first search /var/lib/iscsi/ifaces for + interfaces using software iscsi. If any are found then nodes found + during discovery will be setup so that they can logged in through + those interfaces. To specify a specific iface, pass the +@@ -806,7 +805,7 @@ To now log into targets it is the same as with software iscsi. See section + This command will perform discovery, but not manipulate the node DB. + + - SendTargets iSCSI Discovery with a specific interface. If you +- wish to only use a subset of the interfaces in /etc/iscsi/ifaces ++ wish to only use a subset of the interfaces in /var/lib/iscsi/ifaces + then you can pass them in during discovery: + + ./iscsiadm -m discoverydb -t sendtargets -p 192.168.1.1:3260 \ +@@ -1207,8 +1206,8 @@ where targetname is the name of the target and ip_address:port is the address + and port of the portal. tpgt, is the portal group tag of + the portal, and is not used in iscsiadm commands except for static + record creation. And iface name is the name of the iscsi interface +-defined in /etc/iscsi/ifaces. If no interface was defined in +-/etc/iscsi/ifaces or passed in, the default behavior is used. ++defined in /var/lib/iscsi/ifaces. If no interface was defined in ++/var/lib/iscsi/ifaces or passed in, the default behavior is used. + Default here is iscsi_tcp/tcp to be used over which ever NIC the + network layer decides is best. + +@@ -1323,7 +1322,7 @@ If set, iscsid will perform discovery to the address every + discovery.isns.discoveryd_poll_inval or + discovery.sendtargets.discoveryd_poll_inval seconds, + and it will log into any portals found from the discovery source using +-the ifaces in /etc/iscsi/ifaces. ++the ifaces in /var/lib/iscsi/ifaces. + + Note that for iSNS the poll_interval does not have to be set. If not set, + iscsid will only perform rediscovery when it gets a SCN from the server. +diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8 +index a82805e28fb9..758a47c2d1fe 100644 +--- a/doc/iscsiadm.8 ++++ b/doc/iscsiadm.8 +@@ -241,7 +241,7 @@ This option is only valid for ping submode. + .TP + \fB\-I\fR, \fB\-\-interface=\fI[iface]\fR + The interface argument specifies the iSCSI interface to use for the operation. +-iSCSI interfaces (iface) are defined in /etc/iscsi/ifaces. For hardware ++iSCSI interfaces (iface) are defined in /var/lib/iscsi/ifaces. For hardware + iSCSI (qla4xxx) the iface config must have the hardware address + (iface.hwaddress = port's MAC address) + and the driver/transport_name (iface.transport_name). The iface's name is +@@ -318,7 +318,7 @@ If no other options are specified: for \fIdiscovery\fR, \fIdiscoverydb\fR and + \fInode\fR, all of their respective records are displayed; for \fIsession\fR, + all active sessions and connections are displayed; for \fIfw\fR, all boot + firmware values are displayed; for \fIhost\fR, all iSCSI hosts are displayed; +-and for \fIiface\fR, all ifaces setup in /etc/iscsi/ifaces are displayed. ++and for \fIiface\fR, all ifaces setup in /var/lib/iscsi/ifaces are displayed. + + .TP + \fB\-n\fR, \fB\-\-name=\fIname\fR +@@ -703,10 +703,10 @@ The configuration file read by \fBiscsid\fR and \fBiscsiadm\fR on startup. + The file containing the iSCSI InitiatorName and InitiatorAlias read by + \fBiscsid\fR and \fBiscsiadm\fR on startup. + .TP +-/etc/iscsi/nodes/ ++/var/lib/iscsi/nodes/ + This directory contains the nodes with their targets. + .TP +-/etc/iscsi/send_targets ++/var/lib/iscsi/send_targets + This directory contains the portals. + + .SH "SEE ALSO" +diff --git a/usr/idbm.c b/usr/idbm.c +index 2fe424fb66ba..a749cc8ea3f8 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -2917,9 +2917,9 @@ free_info: + int idbm_init(idbm_get_config_file_fn *fn) + { + /* make sure root db dir is there */ +- if (access(ISCSI_CONFIG_ROOT, F_OK) != 0) { +- if (mkdir(ISCSI_CONFIG_ROOT, 0660) != 0) { +- log_error("Could not make %s %d", ISCSI_CONFIG_ROOT, ++ if (access(ISCSIVAR, F_OK) != 0) { ++ if (mkdir(ISCSIVAR, 0660) != 0) { ++ log_error("Could not make %s %d", ISCSIVAR, + errno); + return errno; + } +diff --git a/usr/idbm.h b/usr/idbm.h +index b9020fe4fd0a..b89ddffe55df 100644 +--- a/usr/idbm.h ++++ b/usr/idbm.h +@@ -29,12 +29,13 @@ + #include "list.h" + #include "flashnode.h" + +-#define NODE_CONFIG_DIR ISCSI_CONFIG_ROOT"nodes" +-#define SLP_CONFIG_DIR ISCSI_CONFIG_ROOT"slp" +-#define ISNS_CONFIG_DIR ISCSI_CONFIG_ROOT"isns" +-#define STATIC_CONFIG_DIR ISCSI_CONFIG_ROOT"static" +-#define FW_CONFIG_DIR ISCSI_CONFIG_ROOT"fw" +-#define ST_CONFIG_DIR ISCSI_CONFIG_ROOT"send_targets" ++#define ISCSIVAR "/var/lib/iscsi/" ++#define NODE_CONFIG_DIR ISCSIVAR"nodes" ++#define SLP_CONFIG_DIR ISCSIVAR"slp" ++#define ISNS_CONFIG_DIR ISCSIVAR"isns" ++#define STATIC_CONFIG_DIR ISCSIVAR"static" ++#define FW_CONFIG_DIR ISCSIVAR"fw" ++#define ST_CONFIG_DIR ISCSIVAR"send_targets" + #define ST_CONFIG_NAME "st_config" + #define ISNS_CONFIG_NAME "isns_config" + +diff --git a/usr/iface.h b/usr/iface.h +index 01f70747dadd..f396918ccc15 100644 +--- a/usr/iface.h ++++ b/usr/iface.h +@@ -20,7 +20,9 @@ + #ifndef ISCSI_IFACE_H + #define ISCSI_IFACE_H + +-#define IFACE_CONFIG_DIR ISCSI_CONFIG_ROOT"ifaces" ++#include "idbm.h" ++ ++#define IFACE_CONFIG_DIR ISCSIVAR"ifaces" + + struct iface_rec; + struct list_head; +-- +2.9.3 + diff --git a/SOURCES/0153-use-red-hat-for-name.patch b/SOURCES/0153-use-red-hat-for-name.patch new file mode 100644 index 00000000..27da7b16 --- /dev/null +++ b/SOURCES/0153-use-red-hat-for-name.patch @@ -0,0 +1,39 @@ +From 7f12a1ca8fe699958903278d010cf22d0a98767b Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:40:04 -0800 +Subject: use red hat for name + +--- + doc/iscsi-iname.8 | 2 +- + utils/iscsi-iname.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/doc/iscsi-iname.8 b/doc/iscsi-iname.8 +index a55d666d1af3..dd77ed9f3165 100644 +--- a/doc/iscsi-iname.8 ++++ b/doc/iscsi-iname.8 +@@ -14,7 +14,7 @@ generates a unique iSCSI node name on every invocation. + Display help + .TP + .BI [-p=]\fIprefix\fP +-Use the prefix passed in instead of the default "iqn.2005-03.org.open-iscsi" ++Use the prefix passed in instead of the default "iqn.1994-05.com.redhat" + + .SH AUTHORS + Open-iSCSI project +diff --git a/utils/iscsi-iname.c b/utils/iscsi-iname.c +index 6347edc46293..cb2f6c8b8651 100644 +--- a/utils/iscsi-iname.c ++++ b/utils/iscsi-iname.c +@@ -73,7 +73,7 @@ main(int argc, char *argv[]) + exit(0); + } + } else { +- prefix = "iqn.2005-03.org.open-iscsi"; ++ prefix = "iqn.1994-05.com.redhat"; + } + + /* try to feed some entropy from the pool to MD5 in order to get +-- +2.9.5 + diff --git a/SOURCES/0154-add-libiscsi.patch b/SOURCES/0154-add-libiscsi.patch new file mode 100644 index 00000000..c8737ec9 --- /dev/null +++ b/SOURCES/0154-add-libiscsi.patch @@ -0,0 +1,3928 @@ +From 2b8ba79bfa079177962465c215d5ea2fccfda400 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 16:43:15 -0800 +Subject: add libiscsi + +--- + Makefile | 2 + + libiscsi/Makefile | 61 ++ + libiscsi/libiscsi.c | 620 +++++++++++ + libiscsi/libiscsi.doxy | 1473 +++++++++++++++++++++++++++ + libiscsi/libiscsi.h | 344 +++++++ + libiscsi/pylibiscsi.c | 638 ++++++++++++ + libiscsi/setup.py | 9 + + libiscsi/tests/test_discovery_firmware.c | 53 + + libiscsi/tests/test_discovery_sendtargets.c | 60 ++ + libiscsi/tests/test_get_auth.c | 70 ++ + libiscsi/tests/test_get_initiator_name.c | 38 + + libiscsi/tests/test_get_network_config.c | 45 + + libiscsi/tests/test_login.c | 52 + + libiscsi/tests/test_logout.c | 51 + + libiscsi/tests/test_params.c | 103 ++ + libiscsi/tests/test_set_auth.c | 58 ++ + usr/Makefile | 2 +- + usr/discovery.c | 5 + + usr/idbm.c | 6 +- + usr/idbm.h | 3 + + usr/iscsi_ipc.h | 2 + + 21 files changed, 3691 insertions(+), 4 deletions(-) + create mode 100644 libiscsi/Makefile + create mode 100644 libiscsi/libiscsi.c + create mode 100644 libiscsi/libiscsi.doxy + create mode 100644 libiscsi/libiscsi.h + create mode 100644 libiscsi/pylibiscsi.c + create mode 100644 libiscsi/setup.py + create mode 100644 libiscsi/tests/test_discovery_firmware.c + create mode 100644 libiscsi/tests/test_discovery_sendtargets.c + create mode 100644 libiscsi/tests/test_get_auth.c + create mode 100644 libiscsi/tests/test_get_initiator_name.c + create mode 100644 libiscsi/tests/test_get_network_config.c + create mode 100644 libiscsi/tests/test_login.c + create mode 100644 libiscsi/tests/test_logout.c + create mode 100644 libiscsi/tests/test_params.c + create mode 100644 libiscsi/tests/test_set_auth.c + +diff --git a/Makefile b/Makefile +index c8cd00e09b00..cf028cfd078a 100644 +--- a/Makefile ++++ b/Makefile +@@ -43,6 +43,7 @@ user: iscsiuio/Makefile + $(MAKE) -C usr + $(MAKE) -C utils + $(MAKE) -C iscsiuio ++ $(MAKE) -C libiscsi + @echo + @echo "Compilation complete Output file" + @echo "----------------------------------- ----------------" +@@ -71,6 +72,7 @@ kernel: force + force: ; + + clean: ++ $(MAKE) -C libiscsi clean + $(MAKE) -C utils/sysdeps clean + $(MAKE) -C utils/fwparam_ibft clean + $(MAKE) -C utils clean +diff --git a/libiscsi/Makefile b/libiscsi/Makefile +new file mode 100644 +index 000000000000..317a7ec4db30 +--- /dev/null ++++ b/libiscsi/Makefile +@@ -0,0 +1,61 @@ ++# This Makefile will work only with GNU make. ++ ++OSNAME=$(shell uname -s) ++OPTFLAGS ?= -O2 -g ++WARNFLAGS ?= -Wall -Wstrict-prototypes ++CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I../include -I../usr \ ++ -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden ++LIB = libiscsi.so.0 ++TESTS = tests/test_discovery_sendtargets tests/test_discovery_firmware ++TESTS += tests/test_login tests/test_logout tests/test_params ++TESTS += tests/test_get_network_config tests/test_get_initiator_name ++TESTS += tests/test_set_auth tests/test_get_auth ++ ++COMMON_SRCS = sysdeps.o ++# sources shared between iscsid, iscsiadm and iscsistart ++ISCSI_LIB_SRCS = netlink.o transport.o cxgbi.o be2iscsi.o iscsi_timer.o initiator_common.o iscsi_err.o session_info.o iscsi_util.o io.o auth.o discovery.o login.o log.o md5.o sha1.o iface.o idbm.o sysfs.o iscsi_sysfs.o iscsi_net_util.o iscsid_req.o iser.o uip_mgmt_ipc.o ++FW_PARAM_SRCS = fw_entry.o prom_lex.o prom_parse.tab.o fwparam_ppc.o fwparam_sysfs.o ++ ++# sources shared with the userspace utils, note we build these separately ++# to get PIC versions. ++COMMON_OBJS = $(patsubst %.o, common-objs/%.o, $(COMMON_SRCS)) ++USR_OBJS = $(patsubst %.o, usr-objs/%.o, $(ISCSI_LIB_SRCS) strings.o) ++FW_OBJS = $(patsubst %.o, fw-objs/%.o, $(FW_PARAM_SRCS)) ++ ++# Flags for the tests ++tests/% : CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I. ++ ++all: lib tests html ++ ++lib: $(LIB) ++tests: $(TESTS) ++ ++common-objs/%.o: ../utils/sysdeps/%.c ++ mkdir -p common-objs ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++usr-objs/%.o: ../usr/%.c ++ mkdir -p usr-objs ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++fw-objs/%.o: ../utils/fwparam_ibft/%.c ++ mkdir -p fw-objs ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++$(LIB): $(COMMON_OBJS) $(FW_OBJS) $(USR_OBJS) libiscsi.o ++ $(CC) $(CFLAGS) -shared -Wl,-soname,$(LIB) $^ -o $@ ++ ln -s -f $(LIB) libiscsi.so ++ ++$(TESTS): $(FW_OBJS) $(COMMON_OBJS) $(USR_OBJS) $(LIB) ++ ++html: libiscsi.h libiscsi.doxy ++ doxygen libiscsi.doxy ++ ++clean: ++ rm -rf *.o common-objs usr-objs fw-objs libuip-objs libiscsi.so* \ ++ .depend *~ html $(TESTS) tests/*~ ++ ++depend: ++ gcc $(CFLAGS) -M `ls *.c` > .depend ++ ++-include .depend ../usr/.depend +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +new file mode 100644 +index 000000000000..6e6846a5162e +--- /dev/null ++++ b/libiscsi/libiscsi.c +@@ -0,0 +1,620 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "libiscsi.h" ++#include "idbm.h" ++#include "discovery.h" ++#include "log.h" ++#include "sysfs.h" ++#include "iscsi_sysfs.h" ++#include "session_info.h" ++#include "iscsi_util.h" ++#include "sysdeps.h" ++#include "iface.h" ++#include "iscsi_proto.h" ++#include "fw_context.h" ++#include "iscsid_req.h" ++#include "iscsi_err.h" ++ ++#define CHECK(a) { context->error_str[0] = 0; rc = a; if (rc) goto leave; } ++ ++/* UGLY, not thread safe :( */ ++static int sysfs_initialized = 0; ++ ++struct libiscsi_context { ++ char error_str[256]; ++ /* For get_parameter_helper() */ ++ const char *parameter; ++ char *value; ++}; ++ ++static void libiscsi_log(int prio, void *priv, const char *fmt, va_list ap) ++{ ++ struct libiscsi_context *context = priv; ++ ++ if (prio > LOG_ERR) /* We are only interested in errors (or worse) */ ++ return; ++ ++ vsnprintf(context->error_str, sizeof(context->error_str), fmt, ap); ++} ++ ++struct libiscsi_context *libiscsi_init(void) ++{ ++ struct libiscsi_context *context; ++ ++ context = calloc(1, sizeof *context); ++ if (!context) ++ return NULL; ++ ++ log_init("libiscsi", 1024, libiscsi_log, context); ++ if (!sysfs_initialized) { ++ sysfs_init(); ++ sysfs_initialized = 1; ++ } ++ increase_max_files(); ++ if (idbm_init(NULL)) { ++ sysfs_cleanup(); ++ free(context); ++ return NULL; ++ } ++ ++ iface_setup_host_bindings(); ++ ++ return context; ++} ++ ++void libiscsi_cleanup(struct libiscsi_context *context) ++{ ++ idbm_terminate(); ++ free_transports(); ++ sysfs_cleanup(); ++ free(context); ++} ++ ++static void free_iface_list(struct list_head *ifaces) ++{ ++ struct iface_rec *iface, *tmp_iface; ++ ++ list_for_each_entry_safe(iface, tmp_iface, ifaces, list) { ++ list_del(&iface->list); ++ free(iface); ++ } ++} ++ ++static void free_rec_list(struct list_head *rec_list) ++{ ++ struct node_rec *rec, *tmp; ++ ++ list_for_each_entry_safe(rec, tmp, rec_list, list) { ++ list_del(&rec->list); ++ free(rec); ++ } ++} ++ ++int libiscsi_discover_sendtargets(struct libiscsi_context *context, ++ const char *address, int port, ++ const struct libiscsi_auth_info *auth_info, ++ int *nr_found, struct libiscsi_node **found_nodes) ++{ ++ struct discovery_rec drec; ++ LIST_HEAD(bound_rec_list); ++ struct node_rec *rec; ++ int rc = 0, found = 0; ++ ++ INIT_LIST_HEAD(&bound_rec_list); ++ ++ if (nr_found) ++ *nr_found = 0; ++ if (found_nodes) ++ *found_nodes = NULL; ++ ++ CHECK(libiscsi_verify_auth_info(context, auth_info)) ++ ++ /* Fill the drec struct with all needed info */ ++ memset(&drec, 0, sizeof drec); ++ idbm_sendtargets_defaults(&drec.u.sendtargets); ++ drec.type = DISCOVERY_TYPE_SENDTARGETS; ++ strlcpy(drec.address, address, sizeof(drec.address)); ++ drec.port = port ? port : ISCSI_LISTEN_PORT; ++ switch(auth_info ? auth_info->method : libiscsi_auth_none) { ++ case libiscsi_auth_chap: ++ drec.u.sendtargets.auth.authmethod = AUTH_METHOD_CHAP; ++ strlcpy(drec.u.sendtargets.auth.username, ++ auth_info->chap.username, AUTH_STR_MAX_LEN); ++ strlcpy((char *)drec.u.sendtargets.auth.password, ++ auth_info->chap.password, AUTH_STR_MAX_LEN); ++ drec.u.sendtargets.auth.password_length = ++ strlen((char *)drec.u.sendtargets.auth.password); ++ strlcpy(drec.u.sendtargets.auth.username_in, ++ auth_info->chap.reverse_username, AUTH_STR_MAX_LEN); ++ strlcpy((char *)drec.u.sendtargets.auth.password_in, ++ auth_info->chap.reverse_password, AUTH_STR_MAX_LEN); ++ drec.u.sendtargets.auth.password_in_length = ++ strlen((char *)drec.u.sendtargets.auth.password_in); ++ break; ++ } ++ ++ CHECK(idbm_add_discovery(&drec)) ++ ++ CHECK(idbm_bind_ifaces_to_nodes(discovery_sendtargets, ++ &drec, NULL, &bound_rec_list)) ++ ++ /* now add/update records */ ++ list_for_each_entry(rec, &bound_rec_list, list) { ++ CHECK(idbm_add_node(rec, &drec, 1 /* overwrite */)) ++ found++; ++ } ++ ++ if (nr_found) ++ *nr_found = found; ++ ++ if (found_nodes && found) { ++ *found_nodes = calloc(found, sizeof **found_nodes); ++ if (*found_nodes == NULL) { ++ snprintf(context->error_str, ++ sizeof(context->error_str), strerror(ENOMEM)); ++ rc = ENOMEM; ++ goto leave; ++ } ++ found = 0; ++ list_for_each_entry(rec, &bound_rec_list, list) { ++ strlcpy((*found_nodes)[found].name, rec->name, ++ LIBISCSI_VALUE_MAXLEN); ++ (*found_nodes)[found].tpgt = rec->tpgt; ++ strlcpy((*found_nodes)[found].address, ++ rec->conn[0].address, NI_MAXHOST); ++ (*found_nodes)[found].port = rec->conn[0].port; ++ strlcpy((*found_nodes)[found].iface, ++ rec->iface.name, LIBISCSI_VALUE_MAXLEN); ++ found++; ++ } ++ } ++ ++leave: ++ free_rec_list(&bound_rec_list); ++ return rc; ++} ++ ++int libiscsi_discover_firmware(struct libiscsi_context *context, ++ int *nr_found, struct libiscsi_node **found_nodes) ++{ ++ struct list_head targets, ifaces, rec_list; ++ discovery_rec_t drec; ++ int rc = 0; ++ ++ INIT_LIST_HEAD(&targets); ++ INIT_LIST_HEAD(&ifaces); ++ INIT_LIST_HEAD(&rec_list); ++ ++ if (nr_found) { ++ *nr_found = 0; ++ } ++ ++ if (found_nodes) { ++ *found_nodes = NULL; ++ } ++ ++ rc = fw_get_targets(&targets); ++ if (rc) { ++ log_error("%s: Could not get list of targets from firmware " ++ "(err %d).\n", __func__, rc); ++ return rc; ++ } ++ ++ CHECK(iface_create_ifaces_from_boot_contexts(&ifaces, &targets)); ++ ++ memset(&drec, 0, sizeof(drec)); ++ drec.type = DISCOVERY_TYPE_FW; ++ rc = idbm_bind_ifaces_to_nodes(discovery_fw, &drec, &ifaces, &rec_list); ++ if (rc) { ++ log_error("%s: Could not determine target nodes from firmware " ++ "(err %d).\n", __func__, rc); ++ goto leave; ++ } ++ ++ int node_count = 0; ++ struct list_head *pos; ++ list_for_each(pos, &rec_list) { ++ ++node_count; ++ } ++ ++ struct libiscsi_node* new_nodes; ++ /* allocate enough space for all the nodes */ ++ new_nodes = calloc(node_count, sizeof *new_nodes); ++ if (new_nodes == NULL) { ++ rc = ENOMEM; ++ log_error("%s: %s.\n", __func__, strerror(ENOMEM)); ++ goto leave; ++ } ++ ++ struct node_rec *rec; ++ struct libiscsi_node *new_node = new_nodes; ++ /* in one loop, add nodes to idbm and create libiscsi_node entries */ ++ list_for_each_entry(rec, &rec_list, list) { ++ CHECK(idbm_add_node(rec, NULL, 1 /* overwrite */)); ++ ++ strlcpy(new_node->name, rec->name, LIBISCSI_VALUE_MAXLEN); ++ new_node->tpgt = rec->tpgt; ++ strlcpy(new_node->address, rec->conn[0].address, NI_MAXHOST); ++ new_node->port = rec->conn[0].port; ++ strlcpy(new_node->iface, rec->iface.name, LIBISCSI_VALUE_MAXLEN); ++ ++ ++new_node; ++ } ++ ++ /* update output parameters */ ++ if (nr_found) { ++ *nr_found = node_count; ++ } ++ if (found_nodes) { ++ *found_nodes = new_nodes; ++ } ++ ++leave: ++ fw_free_targets(&targets); ++ ++ free_iface_list(&ifaces); ++ free_rec_list(&rec_list); ++ ++ return rc; ++} ++ ++int libiscsi_verify_auth_info(struct libiscsi_context *context, ++ const struct libiscsi_auth_info *auth_info) ++{ ++ switch(auth_info ? auth_info->method : libiscsi_auth_none) { ++ case libiscsi_auth_none: ++ break; ++ case libiscsi_auth_chap: ++ if (!auth_info->chap.username[0]) { ++ strcpy(context->error_str, "Empty username"); ++ return EINVAL; ++ } ++ if (!auth_info->chap.password[0]) { ++ strcpy(context->error_str, "Empty password"); ++ return EINVAL; ++ } ++ if (auth_info->chap.reverse_username[0] && ++ !auth_info->chap.reverse_password[0]) { ++ strcpy(context->error_str, "Empty reverse password"); ++ return EINVAL; ++ } ++ break; ++ default: ++ sprintf(context->error_str, ++ "Invalid authentication method: %d", ++ (int)auth_info->method); ++ return EINVAL; ++ } ++ return 0; ++} ++ ++int libiscsi_node_set_auth(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ const struct libiscsi_auth_info *auth_info) ++{ ++ int rc = 0; ++ ++ CHECK(libiscsi_verify_auth_info(context, auth_info)) ++ ++ switch(auth_info ? auth_info->method : libiscsi_auth_none) { ++ case libiscsi_auth_none: ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.authmethod", "None")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.username", "")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.password", "")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.username_in", "")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.password_in", "")) ++ break; ++ ++ case libiscsi_auth_chap: ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.authmethod", "CHAP")) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.username", ++ auth_info->chap.username)) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.password", ++ auth_info->chap.password)) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.username_in", ++ auth_info->chap.reverse_username)) ++ CHECK(libiscsi_node_set_parameter(context, node, ++ "node.session.auth.password_in", ++ auth_info->chap.reverse_password)) ++ break; ++ } ++leave: ++ return rc; ++} ++ ++int libiscsi_node_get_auth(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ struct libiscsi_auth_info *auth_info) ++{ ++ int rc = 0; ++ char value[LIBISCSI_VALUE_MAXLEN]; ++ ++ memset(auth_info, 0, sizeof *auth_info); ++ ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.authmethod", value)) ++ ++ if (!strcmp(value, "None")) { ++ auth_info->method = libiscsi_auth_none; ++ } else if (!strcmp(value, "CHAP")) { ++ auth_info->method = libiscsi_auth_chap; ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.username", ++ auth_info->chap.username)) ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.password", ++ auth_info->chap.password)) ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.username_in", ++ auth_info->chap.reverse_username)) ++ CHECK(libiscsi_node_get_parameter(context, node, ++ "node.session.auth.password_in", ++ auth_info->chap.reverse_password)) ++ } else { ++ snprintf(context->error_str, sizeof(context->error_str), ++ "unknown authentication method: %s", value); ++ rc = EINVAL; ++ } ++leave: ++ return rc; ++} ++ ++static void node_to_rec(const struct libiscsi_node *node, ++ struct node_rec *rec) ++{ ++ memset(rec, 0, sizeof *rec); ++ idbm_node_setup_defaults(rec); ++ strlcpy(rec->name, node->name, TARGET_NAME_MAXLEN); ++ rec->tpgt = node->tpgt; ++ strlcpy(rec->conn[0].address, node->address, NI_MAXHOST); ++ rec->conn[0].port = node->port; ++} ++ ++int login_helper(void *data, node_rec_t *rec) ++{ ++ char *iface = (char*)data; ++ if (strcmp(iface, rec->iface.name)) ++ /* different iface, skip it */ ++ return -1; ++ ++ int rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec); ++ if (rc) { ++ iscsi_err_print_msg(rc); ++ rc = ENOTCONN; ++ } ++ return rc; ++} ++ ++int libiscsi_node_login(struct libiscsi_context *context, ++ const struct libiscsi_node *node) ++{ ++ int nr_found = 0, rc; ++ ++ CHECK(idbm_for_each_iface(&nr_found, (void*)node->iface, login_helper, ++ (char *)node->name, node->tpgt, ++ (char *)node->address, node->port)) ++ if (nr_found == 0) { ++ strcpy(context->error_str, "No such node"); ++ rc = ENODEV; ++ } ++leave: ++ return rc; ++} ++ ++static int logout_helper(void *data, struct session_info *info) ++{ ++ int rc; ++ struct node_rec *rec = data; ++ ++ if (!iscsi_match_session(rec, info)) ++ /* Tell iscsi_sysfs_for_each_session this session was not a ++ match so that it will not increase nr_found. */ ++ return -1; ++ ++ rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid); ++ if (rc) { ++ iscsi_err_print_msg(rc); ++ rc = EIO; ++ } ++ ++ return rc; ++} ++ ++int libiscsi_node_logout(struct libiscsi_context *context, ++ const struct libiscsi_node *node) ++{ ++ int nr_found = 0, rc; ++ struct node_rec rec; ++ ++ node_to_rec(node, &rec); ++ CHECK(iscsi_sysfs_for_each_session(&rec, &nr_found, logout_helper,0)) ++ if (nr_found == 0) { ++ strcpy(context->error_str, "No matching session"); ++ rc = ENODEV; ++ } ++leave: ++ return rc; ++} ++ ++int libiscsi_node_set_parameter(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ const char *parameter, const char *value) ++{ ++ int nr_found = 0, rc; ++ struct user_param *param; ++ struct list_head params; ++ ++ INIT_LIST_HEAD(¶ms); ++ param = idbm_alloc_user_param(parameter, value); ++ if (!param) { ++ rc = ENOMEM; ++ goto leave; ++ } ++ list_add_tail(¶ms, ¶m->list); ++ ++ CHECK(idbm_for_each_iface(&nr_found, ¶ms, idbm_node_set_param, ++ (char *)node->name, node->tpgt, ++ (char *)node->address, node->port)) ++ if (nr_found == 0) { ++ strcpy(context->error_str, "No such node"); ++ rc = ENODEV; ++ } ++ free(param->name); ++ free(param); ++leave: ++ return rc; ++} ++ ++static int get_parameter_helper(void *data, node_rec_t *rec) ++{ ++ struct libiscsi_context *context = data; ++ recinfo_t *info; ++ int i; ++ ++ info = idbm_recinfo_alloc(MAX_KEYS); ++ if (!info) { ++ snprintf(context->error_str, sizeof(context->error_str), ++ strerror(ENOMEM)); ++ return ENOMEM; ++ } ++ ++ idbm_recinfo_node(rec, info); ++ ++ for (i = 0; i < MAX_KEYS; i++) { ++ if (!info[i].visible) ++ continue; ++ ++ if (strcmp(context->parameter, info[i].name)) ++ continue; ++ ++ strlcpy(context->value, info[i].value, LIBISCSI_VALUE_MAXLEN); ++ break; ++ } ++ ++ free(info); ++ ++ if (i == MAX_KEYS) { ++ strcpy(context->error_str, "No such parameter"); ++ return EINVAL; ++ } ++ ++ return 0; ++} ++ ++int libiscsi_node_get_parameter(struct libiscsi_context *context, ++ const struct libiscsi_node *node, const char *parameter, char *value) ++{ ++ int nr_found = 0, rc = 0; ++ ++ context->parameter = parameter; ++ context->value = value; ++ ++ /* Note we assume there is only one interface, if not we will get ++ the value from the last interface iterated over! ++ This (multiple interfaces) can only happen if someone explicitly ++ created ones using iscsiadm. Even then this should not be a problem ++ as most settings should be the same independent of the iface. */ ++ CHECK(idbm_for_each_iface(&nr_found, context, get_parameter_helper, ++ (char *)node->name, node->tpgt, ++ (char *)node->address, node->port)) ++ if (nr_found == 0) { ++ strcpy(context->error_str, "No such node"); ++ rc = ENODEV; ++ } ++leave: ++ return rc; ++} ++ ++const char *libiscsi_get_error_string(struct libiscsi_context *context) ++{ ++ /* Sometimes the core open-iscsi code does not give us an error ++ message */ ++ if (!context->error_str[0]) ++ return "Unknown error"; ++ ++ return context->error_str; ++} ++ ++ ++/************************** Utility functions *******************************/ ++ ++int libiscsi_get_firmware_network_config( ++ struct libiscsi_network_config *config) ++{ ++ struct boot_context fw_entry; ++ ++ if (!sysfs_initialized) { ++ sysfs_init(); ++ sysfs_initialized = 1; ++ } ++ ++ memset(config, 0, sizeof *config); ++ memset(&fw_entry, 0, sizeof fw_entry); ++ if (fw_get_entry(&fw_entry)) ++ return ENODEV; ++ ++ config->dhcp = strlen(fw_entry.dhcp) ? 1 : 0; ++ strncpy(config->iface_name, fw_entry.iface, sizeof fw_entry.iface); ++ strncpy(config->mac_address, fw_entry.mac, sizeof fw_entry.mac); ++ strncpy(config->ip_address, fw_entry.ipaddr, sizeof fw_entry.ipaddr); ++ strncpy(config->netmask, fw_entry.mask, sizeof fw_entry.mask); ++ strncpy(config->gateway, fw_entry.gateway, sizeof fw_entry.gateway); ++ strncpy(config->primary_dns, fw_entry.primary_dns, ++ sizeof fw_entry.primary_dns); ++ strncpy(config->secondary_dns, fw_entry.secondary_dns, ++ sizeof fw_entry.secondary_dns); ++ return 0; ++} ++ ++int libiscsi_get_firmware_initiator_name(char *initiatorname) ++{ ++ struct boot_context fw_entry; ++ ++ if (!sysfs_initialized) { ++ sysfs_init(); ++ sysfs_initialized = 1; ++ } ++ ++ memset(initiatorname, 0, LIBISCSI_VALUE_MAXLEN); ++ memset(&fw_entry, 0, sizeof fw_entry); ++ if (fw_get_entry(&fw_entry)) ++ return ENODEV; ++ ++ strncpy(initiatorname, fw_entry.initiatorname, ++ sizeof fw_entry.initiatorname); ++ ++ return 0; ++} +diff --git a/libiscsi/libiscsi.doxy b/libiscsi/libiscsi.doxy +new file mode 100644 +index 000000000000..663770f3e939 +--- /dev/null ++++ b/libiscsi/libiscsi.doxy +@@ -0,0 +1,1473 @@ ++# Doxyfile 1.5.7.1 ++ ++# This file describes the settings to be used by the documentation system ++# doxygen (www.doxygen.org) for a project ++# ++# All text after a hash (#) is considered a comment and will be ignored ++# The format is: ++# TAG = value [value, ...] ++# For lists items can also be appended using: ++# TAG += value [value, ...] ++# Values that contain spaces should be placed between quotes (" ") ++ ++#--------------------------------------------------------------------------- ++# Project related configuration options ++#--------------------------------------------------------------------------- ++ ++# This tag specifies the encoding used for all characters in the config file ++# that follow. The default is UTF-8 which is also the encoding used for all ++# text before the first occurrence of this tag. Doxygen uses libiconv (or the ++# iconv built into libc) for the transcoding. See ++# http://www.gnu.org/software/libiconv for the list of possible encodings. ++ ++DOXYFILE_ENCODING = UTF-8 ++ ++# The PROJECT_NAME tag is a single word (or a sequence of words surrounded ++# by quotes) that should identify the project. ++ ++PROJECT_NAME = libiscsi ++ ++# The PROJECT_NUMBER tag can be used to enter a project or revision number. ++# This could be handy for archiving the generated documentation or ++# if some version control system is used. ++ ++PROJECT_NUMBER = ++ ++# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) ++# base path where the generated documentation will be put. ++# If a relative path is entered, it will be relative to the location ++# where doxygen was started. If left blank the current directory will be used. ++ ++OUTPUT_DIRECTORY = ++ ++# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create ++# 4096 sub-directories (in 2 levels) under the output directory of each output ++# format and will distribute the generated files over these directories. ++# Enabling this option can be useful when feeding doxygen a huge amount of ++# source files, where putting all generated files in the same directory would ++# otherwise cause performance problems for the file system. ++ ++CREATE_SUBDIRS = NO ++ ++# The OUTPUT_LANGUAGE tag is used to specify the language in which all ++# documentation generated by doxygen is written. Doxygen will use this ++# information to generate all constant output in the proper language. ++# The default language is English, other supported languages are: ++# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, ++# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, ++# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), ++# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, ++# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, ++# Spanish, Swedish, and Ukrainian. ++ ++OUTPUT_LANGUAGE = English ++ ++# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will ++# include brief member descriptions after the members that are listed in ++# the file and class documentation (similar to JavaDoc). ++# Set to NO to disable this. ++ ++BRIEF_MEMBER_DESC = YES ++ ++# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend ++# the brief description of a member or function before the detailed description. ++# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the ++# brief descriptions will be completely suppressed. ++ ++REPEAT_BRIEF = NO ++ ++# This tag implements a quasi-intelligent brief description abbreviator ++# that is used to form the text in various listings. Each string ++# in this list, if found as the leading text of the brief description, will be ++# stripped from the text and the result after processing the whole list, is ++# used as the annotated text. Otherwise, the brief description is used as-is. ++# If left blank, the following values are used ("$name" is automatically ++# replaced with the name of the entity): "The $name class" "The $name widget" ++# "The $name file" "is" "provides" "specifies" "contains" ++# "represents" "a" "an" "the" ++ ++ABBREVIATE_BRIEF = ++ ++# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then ++# Doxygen will generate a detailed section even if there is only a brief ++# description. ++ ++ALWAYS_DETAILED_SEC = YES ++ ++# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all ++# inherited members of a class in the documentation of that class as if those ++# members were ordinary class members. Constructors, destructors and assignment ++# operators of the base classes will not be shown. ++ ++INLINE_INHERITED_MEMB = NO ++ ++# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full ++# path before files name in the file list and in the header files. If set ++# to NO the shortest path that makes the file name unique will be used. ++ ++FULL_PATH_NAMES = YES ++ ++# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag ++# can be used to strip a user-defined part of the path. Stripping is ++# only done if one of the specified strings matches the left-hand part of ++# the path. The tag can be used to show relative paths in the file list. ++# If left blank the directory from which doxygen is run is used as the ++# path to strip. ++ ++STRIP_FROM_PATH = ++ ++# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of ++# the path mentioned in the documentation of a class, which tells ++# the reader which header file to include in order to use a class. ++# If left blank only the name of the header file containing the class ++# definition is used. Otherwise one should specify the include paths that ++# are normally passed to the compiler using the -I flag. ++ ++STRIP_FROM_INC_PATH = ++ ++# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter ++# (but less readable) file names. This can be useful is your file systems ++# doesn't support long names like on DOS, Mac, or CD-ROM. ++ ++SHORT_NAMES = NO ++ ++# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen ++# will interpret the first line (until the first dot) of a JavaDoc-style ++# comment as the brief description. If set to NO, the JavaDoc ++# comments will behave just like regular Qt-style comments ++# (thus requiring an explicit @brief command for a brief description.) ++ ++JAVADOC_AUTOBRIEF = NO ++ ++# If the QT_AUTOBRIEF tag is set to YES then Doxygen will ++# interpret the first line (until the first dot) of a Qt-style ++# comment as the brief description. If set to NO, the comments ++# will behave just like regular Qt-style comments (thus requiring ++# an explicit \brief command for a brief description.) ++ ++QT_AUTOBRIEF = NO ++ ++# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen ++# treat a multi-line C++ special comment block (i.e. a block of //! or /// ++# comments) as a brief description. This used to be the default behaviour. ++# The new default is to treat a multi-line C++ comment block as a detailed ++# description. Set this tag to YES if you prefer the old behaviour instead. ++ ++MULTILINE_CPP_IS_BRIEF = NO ++ ++# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented ++# member inherits the documentation from any documented member that it ++# re-implements. ++ ++INHERIT_DOCS = YES ++ ++# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce ++# a new page for each member. If set to NO, the documentation of a member will ++# be part of the file/class/namespace that contains it. ++ ++SEPARATE_MEMBER_PAGES = NO ++ ++# The TAB_SIZE tag can be used to set the number of spaces in a tab. ++# Doxygen uses this value to replace tabs by spaces in code fragments. ++ ++TAB_SIZE = 8 ++ ++# This tag can be used to specify a number of aliases that acts ++# as commands in the documentation. An alias has the form "name=value". ++# For example adding "sideeffect=\par Side Effects:\n" will allow you to ++# put the command \sideeffect (or @sideeffect) in the documentation, which ++# will result in a user-defined paragraph with heading "Side Effects:". ++# You can put \n's in the value part of an alias to insert newlines. ++ ++ALIASES = ++ ++# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C ++# sources only. Doxygen will then generate output that is more tailored for C. ++# For instance, some of the names that are used will be different. The list ++# of all members will be omitted, etc. ++ ++OPTIMIZE_OUTPUT_FOR_C = YES ++ ++# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java ++# sources only. Doxygen will then generate output that is more tailored for ++# Java. For instance, namespaces will be presented as packages, qualified ++# scopes will look different, etc. ++ ++OPTIMIZE_OUTPUT_JAVA = NO ++ ++# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran ++# sources only. Doxygen will then generate output that is more tailored for ++# Fortran. ++ ++OPTIMIZE_FOR_FORTRAN = NO ++ ++# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL ++# sources. Doxygen will then generate output that is tailored for ++# VHDL. ++ ++OPTIMIZE_OUTPUT_VHDL = NO ++ ++# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want ++# to include (a tag file for) the STL sources as input, then you should ++# set this tag to YES in order to let doxygen match functions declarations and ++# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. ++# func(std::string) {}). This also make the inheritance and collaboration ++# diagrams that involve STL classes more complete and accurate. ++ ++BUILTIN_STL_SUPPORT = NO ++ ++# If you use Microsoft's C++/CLI language, you should set this option to YES to ++# enable parsing support. ++ ++CPP_CLI_SUPPORT = NO ++ ++# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. ++# Doxygen will parse them like normal C++ but will assume all classes use public ++# instead of private inheritance when no explicit protection keyword is present. ++ ++SIP_SUPPORT = NO ++ ++# For Microsoft's IDL there are propget and propput attributes to indicate getter ++# and setter methods for a property. Setting this option to YES (the default) ++# will make doxygen to replace the get and set methods by a property in the ++# documentation. This will only work if the methods are indeed getting or ++# setting a simple type. If this is not the case, or you want to show the ++# methods anyway, you should set this option to NO. ++ ++IDL_PROPERTY_SUPPORT = YES ++ ++# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC ++# tag is set to YES, then doxygen will reuse the documentation of the first ++# member in the group (if any) for the other members of the group. By default ++# all members of a group must be documented explicitly. ++ ++DISTRIBUTE_GROUP_DOC = NO ++ ++# Set the SUBGROUPING tag to YES (the default) to allow class member groups of ++# the same type (for instance a group of public functions) to be put as a ++# subgroup of that type (e.g. under the Public Functions section). Set it to ++# NO to prevent subgrouping. Alternatively, this can be done per class using ++# the \nosubgrouping command. ++ ++SUBGROUPING = YES ++ ++# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum ++# is documented as struct, union, or enum with the name of the typedef. So ++# typedef struct TypeS {} TypeT, will appear in the documentation as a struct ++# with name TypeT. When disabled the typedef will appear as a member of a file, ++# namespace, or class. And the struct will be named TypeS. This can typically ++# be useful for C code in case the coding convention dictates that all compound ++# types are typedef'ed and only the typedef is referenced, never the tag name. ++ ++TYPEDEF_HIDES_STRUCT = NO ++ ++# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to ++# determine which symbols to keep in memory and which to flush to disk. ++# When the cache is full, less often used symbols will be written to disk. ++# For small to medium size projects (<1000 input files) the default value is ++# probably good enough. For larger projects a too small cache size can cause ++# doxygen to be busy swapping symbols to and from disk most of the time ++# causing a significant performance penality. ++# If the system has enough physical memory increasing the cache will improve the ++# performance by keeping more symbols in memory. Note that the value works on ++# a logarithmic scale so increasing the size by one will rougly double the ++# memory usage. The cache size is given by this formula: ++# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, ++# corresponding to a cache size of 2^16 = 65536 symbols ++ ++SYMBOL_CACHE_SIZE = 0 ++ ++#--------------------------------------------------------------------------- ++# Build related configuration options ++#--------------------------------------------------------------------------- ++ ++# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in ++# documentation are documented, even if no documentation was available. ++# Private class members and static file members will be hidden unless ++# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES ++ ++EXTRACT_ALL = YES ++ ++# If the EXTRACT_PRIVATE tag is set to YES all private members of a class ++# will be included in the documentation. ++ ++EXTRACT_PRIVATE = NO ++ ++# If the EXTRACT_STATIC tag is set to YES all static members of a file ++# will be included in the documentation. ++ ++EXTRACT_STATIC = NO ++ ++# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) ++# defined locally in source files will be included in the documentation. ++# If set to NO only classes defined in header files are included. ++ ++EXTRACT_LOCAL_CLASSES = YES ++ ++# This flag is only useful for Objective-C code. When set to YES local ++# methods, which are defined in the implementation section but not in ++# the interface are included in the documentation. ++# If set to NO (the default) only methods in the interface are included. ++ ++EXTRACT_LOCAL_METHODS = NO ++ ++# If this flag is set to YES, the members of anonymous namespaces will be ++# extracted and appear in the documentation as a namespace called ++# 'anonymous_namespace{file}', where file will be replaced with the base ++# name of the file that contains the anonymous namespace. By default ++# anonymous namespace are hidden. ++ ++EXTRACT_ANON_NSPACES = NO ++ ++# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all ++# undocumented members of documented classes, files or namespaces. ++# If set to NO (the default) these members will be included in the ++# various overviews, but no documentation section is generated. ++# This option has no effect if EXTRACT_ALL is enabled. ++ ++HIDE_UNDOC_MEMBERS = NO ++ ++# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all ++# undocumented classes that are normally visible in the class hierarchy. ++# If set to NO (the default) these classes will be included in the various ++# overviews. This option has no effect if EXTRACT_ALL is enabled. ++ ++HIDE_UNDOC_CLASSES = NO ++ ++# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all ++# friend (class|struct|union) declarations. ++# If set to NO (the default) these declarations will be included in the ++# documentation. ++ ++HIDE_FRIEND_COMPOUNDS = NO ++ ++# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any ++# documentation blocks found inside the body of a function. ++# If set to NO (the default) these blocks will be appended to the ++# function's detailed documentation block. ++ ++HIDE_IN_BODY_DOCS = NO ++ ++# The INTERNAL_DOCS tag determines if documentation ++# that is typed after a \internal command is included. If the tag is set ++# to NO (the default) then the documentation will be excluded. ++# Set it to YES to include the internal documentation. ++ ++INTERNAL_DOCS = NO ++ ++# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate ++# file names in lower-case letters. If set to YES upper-case letters are also ++# allowed. This is useful if you have classes or files whose names only differ ++# in case and if your file system supports case sensitive file names. Windows ++# and Mac users are advised to set this option to NO. ++ ++CASE_SENSE_NAMES = YES ++ ++# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen ++# will show members with their full class and namespace scopes in the ++# documentation. If set to YES the scope will be hidden. ++ ++HIDE_SCOPE_NAMES = NO ++ ++# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen ++# will put a list of the files that are included by a file in the documentation ++# of that file. ++ ++SHOW_INCLUDE_FILES = YES ++ ++# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] ++# is inserted in the documentation for inline members. ++ ++INLINE_INFO = YES ++ ++# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen ++# will sort the (detailed) documentation of file and class members ++# alphabetically by member name. If set to NO the members will appear in ++# declaration order. ++ ++SORT_MEMBER_DOCS = YES ++ ++# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the ++# brief documentation of file, namespace and class members alphabetically ++# by member name. If set to NO (the default) the members will appear in ++# declaration order. ++ ++SORT_BRIEF_DOCS = NO ++ ++# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the ++# hierarchy of group names into alphabetical order. If set to NO (the default) ++# the group names will appear in their defined order. ++ ++SORT_GROUP_NAMES = NO ++ ++# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be ++# sorted by fully-qualified names, including namespaces. If set to ++# NO (the default), the class list will be sorted only by class name, ++# not including the namespace part. ++# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. ++# Note: This option applies only to the class list, not to the ++# alphabetical list. ++ ++SORT_BY_SCOPE_NAME = NO ++ ++# The GENERATE_TODOLIST tag can be used to enable (YES) or ++# disable (NO) the todo list. This list is created by putting \todo ++# commands in the documentation. ++ ++GENERATE_TODOLIST = YES ++ ++# The GENERATE_TESTLIST tag can be used to enable (YES) or ++# disable (NO) the test list. This list is created by putting \test ++# commands in the documentation. ++ ++GENERATE_TESTLIST = YES ++ ++# The GENERATE_BUGLIST tag can be used to enable (YES) or ++# disable (NO) the bug list. This list is created by putting \bug ++# commands in the documentation. ++ ++GENERATE_BUGLIST = YES ++ ++# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or ++# disable (NO) the deprecated list. This list is created by putting ++# \deprecated commands in the documentation. ++ ++GENERATE_DEPRECATEDLIST= YES ++ ++# The ENABLED_SECTIONS tag can be used to enable conditional ++# documentation sections, marked by \if sectionname ... \endif. ++ ++ENABLED_SECTIONS = ++ ++# The MAX_INITIALIZER_LINES tag determines the maximum number of lines ++# the initial value of a variable or define consists of for it to appear in ++# the documentation. If the initializer consists of more lines than specified ++# here it will be hidden. Use a value of 0 to hide initializers completely. ++# The appearance of the initializer of individual variables and defines in the ++# documentation can be controlled using \showinitializer or \hideinitializer ++# command in the documentation regardless of this setting. ++ ++MAX_INITIALIZER_LINES = 30 ++ ++# Set the SHOW_USED_FILES tag to NO to disable the list of files generated ++# at the bottom of the documentation of classes and structs. If set to YES the ++# list will mention the files that were used to generate the documentation. ++ ++SHOW_USED_FILES = YES ++ ++# If the sources in your project are distributed over multiple directories ++# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy ++# in the documentation. The default is NO. ++ ++SHOW_DIRECTORIES = NO ++ ++# Set the SHOW_FILES tag to NO to disable the generation of the Files page. ++# This will remove the Files entry from the Quick Index and from the ++# Folder Tree View (if specified). The default is YES. ++ ++SHOW_FILES = YES ++ ++# Set the SHOW_NAMESPACES tag to NO to disable the generation of the ++# Namespaces page. This will remove the Namespaces entry from the Quick Index ++# and from the Folder Tree View (if specified). The default is YES. ++ ++SHOW_NAMESPACES = YES ++ ++# The FILE_VERSION_FILTER tag can be used to specify a program or script that ++# doxygen should invoke to get the current version for each file (typically from ++# the version control system). Doxygen will invoke the program by executing (via ++# popen()) the command , where is the value of ++# the FILE_VERSION_FILTER tag, and is the name of an input file ++# provided by doxygen. Whatever the program writes to standard output ++# is used as the file version. See the manual for examples. ++ ++FILE_VERSION_FILTER = ++ ++# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by ++# doxygen. The layout file controls the global structure of the generated output files ++# in an output format independent way. The create the layout file that represents ++# doxygen's defaults, run doxygen with the -l option. You can optionally specify a ++# file name after the option, if omitted DoxygenLayout.xml will be used as the name ++# of the layout file. ++ ++LAYOUT_FILE = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to warning and progress messages ++#--------------------------------------------------------------------------- ++ ++# The QUIET tag can be used to turn on/off the messages that are generated ++# by doxygen. Possible values are YES and NO. If left blank NO is used. ++ ++QUIET = YES ++ ++# The WARNINGS tag can be used to turn on/off the warning messages that are ++# generated by doxygen. Possible values are YES and NO. If left blank ++# NO is used. ++ ++WARNINGS = YES ++ ++# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings ++# for undocumented members. If EXTRACT_ALL is set to YES then this flag will ++# automatically be disabled. ++ ++WARN_IF_UNDOCUMENTED = YES ++ ++# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for ++# potential errors in the documentation, such as not documenting some ++# parameters in a documented function, or documenting parameters that ++# don't exist or using markup commands wrongly. ++ ++WARN_IF_DOC_ERROR = YES ++ ++# This WARN_NO_PARAMDOC option can be abled to get warnings for ++# functions that are documented, but have no documentation for their parameters ++# or return value. If set to NO (the default) doxygen will only warn about ++# wrong or incomplete parameter documentation, but not about the absence of ++# documentation. ++ ++WARN_NO_PARAMDOC = NO ++ ++# The WARN_FORMAT tag determines the format of the warning messages that ++# doxygen can produce. The string should contain the $file, $line, and $text ++# tags, which will be replaced by the file and line number from which the ++# warning originated and the warning text. Optionally the format may contain ++# $version, which will be replaced by the version of the file (if it could ++# be obtained via FILE_VERSION_FILTER) ++ ++WARN_FORMAT = "$file:$line: $text" ++ ++# The WARN_LOGFILE tag can be used to specify a file to which warning ++# and error messages should be written. If left blank the output is written ++# to stderr. ++ ++WARN_LOGFILE = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the input files ++#--------------------------------------------------------------------------- ++ ++# The INPUT tag can be used to specify the files and/or directories that contain ++# documented source files. You may enter file names like "myfile.cpp" or ++# directories like "/usr/src/myproject". Separate the files or directories ++# with spaces. ++ ++INPUT = ++ ++# This tag can be used to specify the character encoding of the source files ++# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is ++# also the default input encoding. Doxygen uses libiconv (or the iconv built ++# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for ++# the list of possible encodings. ++ ++INPUT_ENCODING = UTF-8 ++ ++# If the value of the INPUT tag contains directories, you can use the ++# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp ++# and *.h) to filter out the source-files in the directories. If left ++# blank the following patterns are tested: ++# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx ++# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 ++ ++FILE_PATTERNS = ++ ++# The RECURSIVE tag can be used to turn specify whether or not subdirectories ++# should be searched for input files as well. Possible values are YES and NO. ++# If left blank NO is used. ++ ++RECURSIVE = NO ++ ++# The EXCLUDE tag can be used to specify files and/or directories that should ++# excluded from the INPUT source files. This way you can easily exclude a ++# subdirectory from a directory tree whose root is specified with the INPUT tag. ++ ++EXCLUDE = ++ ++# The EXCLUDE_SYMLINKS tag can be used select whether or not files or ++# directories that are symbolic links (a Unix filesystem feature) are excluded ++# from the input. ++ ++EXCLUDE_SYMLINKS = NO ++ ++# If the value of the INPUT tag contains directories, you can use the ++# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude ++# certain files from those directories. Note that the wildcards are matched ++# against the file with absolute path, so to exclude all test directories ++# for example use the pattern */test/* ++ ++EXCLUDE_PATTERNS = ++ ++# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names ++# (namespaces, classes, functions, etc.) that should be excluded from the ++# output. The symbol name can be a fully qualified name, a word, or if the ++# wildcard * is used, a substring. Examples: ANamespace, AClass, ++# AClass::ANamespace, ANamespace::*Test ++ ++EXCLUDE_SYMBOLS = ++ ++# The EXAMPLE_PATH tag can be used to specify one or more files or ++# directories that contain example code fragments that are included (see ++# the \include command). ++ ++EXAMPLE_PATH = ++ ++# If the value of the EXAMPLE_PATH tag contains directories, you can use the ++# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp ++# and *.h) to filter out the source-files in the directories. If left ++# blank all files are included. ++ ++EXAMPLE_PATTERNS = ++ ++# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be ++# searched for input files to be used with the \include or \dontinclude ++# commands irrespective of the value of the RECURSIVE tag. ++# Possible values are YES and NO. If left blank NO is used. ++ ++EXAMPLE_RECURSIVE = NO ++ ++# The IMAGE_PATH tag can be used to specify one or more files or ++# directories that contain image that are included in the documentation (see ++# the \image command). ++ ++IMAGE_PATH = ++ ++# The INPUT_FILTER tag can be used to specify a program that doxygen should ++# invoke to filter for each input file. Doxygen will invoke the filter program ++# by executing (via popen()) the command , where ++# is the value of the INPUT_FILTER tag, and is the name of an ++# input file. Doxygen will then use the output that the filter program writes ++# to standard output. If FILTER_PATTERNS is specified, this tag will be ++# ignored. ++ ++INPUT_FILTER = ++ ++# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern ++# basis. Doxygen will compare the file name with each pattern and apply the ++# filter if there is a match. The filters are a list of the form: ++# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further ++# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER ++# is applied to all files. ++ ++FILTER_PATTERNS = ++ ++# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using ++# INPUT_FILTER) will be used to filter the input files when producing source ++# files to browse (i.e. when SOURCE_BROWSER is set to YES). ++ ++FILTER_SOURCE_FILES = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to source browsing ++#--------------------------------------------------------------------------- ++ ++# If the SOURCE_BROWSER tag is set to YES then a list of source files will ++# be generated. Documented entities will be cross-referenced with these sources. ++# Note: To get rid of all source code in the generated output, make sure also ++# VERBATIM_HEADERS is set to NO. ++ ++SOURCE_BROWSER = NO ++ ++# Setting the INLINE_SOURCES tag to YES will include the body ++# of functions and classes directly in the documentation. ++ ++INLINE_SOURCES = NO ++ ++# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct ++# doxygen to hide any special comment blocks from generated source code ++# fragments. Normal C and C++ comments will always remain visible. ++ ++STRIP_CODE_COMMENTS = YES ++ ++# If the REFERENCED_BY_RELATION tag is set to YES ++# then for each documented function all documented ++# functions referencing it will be listed. ++ ++REFERENCED_BY_RELATION = NO ++ ++# If the REFERENCES_RELATION tag is set to YES ++# then for each documented function all documented entities ++# called/used by that function will be listed. ++ ++REFERENCES_RELATION = NO ++ ++# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) ++# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from ++# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will ++# link to the source code. Otherwise they will link to the documentstion. ++ ++REFERENCES_LINK_SOURCE = YES ++ ++# If the USE_HTAGS tag is set to YES then the references to source code ++# will point to the HTML generated by the htags(1) tool instead of doxygen ++# built-in source browser. The htags tool is part of GNU's global source ++# tagging system (see http://www.gnu.org/software/global/global.html). You ++# will need version 4.8.6 or higher. ++ ++USE_HTAGS = NO ++ ++# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen ++# will generate a verbatim copy of the header file for each class for ++# which an include is specified. Set to NO to disable this. ++ ++VERBATIM_HEADERS = YES ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the alphabetical class index ++#--------------------------------------------------------------------------- ++ ++# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index ++# of all compounds will be generated. Enable this if the project ++# contains a lot of classes, structs, unions or interfaces. ++ ++ALPHABETICAL_INDEX = NO ++ ++# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then ++# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns ++# in which this list will be split (can be a number in the range [1..20]) ++ ++COLS_IN_ALPHA_INDEX = 5 ++ ++# In case all classes in a project start with a common prefix, all ++# classes will be put under the same header in the alphabetical index. ++# The IGNORE_PREFIX tag can be used to specify one or more prefixes that ++# should be ignored while generating the index headers. ++ ++IGNORE_PREFIX = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the HTML output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_HTML tag is set to YES (the default) Doxygen will ++# generate HTML output. ++ ++GENERATE_HTML = YES ++ ++# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `html' will be used as the default path. ++ ++HTML_OUTPUT = html ++ ++# The HTML_FILE_EXTENSION tag can be used to specify the file extension for ++# each generated HTML page (for example: .htm,.php,.asp). If it is left blank ++# doxygen will generate files with .html extension. ++ ++HTML_FILE_EXTENSION = .html ++ ++# The HTML_HEADER tag can be used to specify a personal HTML header for ++# each generated HTML page. If it is left blank doxygen will generate a ++# standard header. ++ ++HTML_HEADER = ++ ++# The HTML_FOOTER tag can be used to specify a personal HTML footer for ++# each generated HTML page. If it is left blank doxygen will generate a ++# standard footer. ++ ++HTML_FOOTER = ++ ++# The HTML_STYLESHEET tag can be used to specify a user-defined cascading ++# style sheet that is used by each HTML page. It can be used to ++# fine-tune the look of the HTML output. If the tag is left blank doxygen ++# will generate a default style sheet. Note that doxygen will try to copy ++# the style sheet file to the HTML output directory, so don't put your own ++# stylesheet in the HTML output directory as well, or it will be erased! ++ ++HTML_STYLESHEET = ++ ++# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, ++# files or namespaces will be aligned in HTML using tables. If set to ++# NO a bullet list will be used. ++ ++HTML_ALIGN_MEMBERS = YES ++ ++# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML ++# documentation will contain sections that can be hidden and shown after the ++# page has loaded. For this to work a browser that supports ++# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox ++# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). ++ ++HTML_DYNAMIC_SECTIONS = NO ++ ++# If the GENERATE_DOCSET tag is set to YES, additional index files ++# will be generated that can be used as input for Apple's Xcode 3 ++# integrated development environment, introduced with OSX 10.5 (Leopard). ++# To create a documentation set, doxygen will generate a Makefile in the ++# HTML output directory. Running make will produce the docset in that ++# directory and running "make install" will install the docset in ++# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find ++# it at startup. ++# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. ++ ++GENERATE_DOCSET = NO ++ ++# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the ++# feed. A documentation feed provides an umbrella under which multiple ++# documentation sets from a single provider (such as a company or product suite) ++# can be grouped. ++ ++DOCSET_FEEDNAME = "Doxygen generated docs" ++ ++# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that ++# should uniquely identify the documentation set bundle. This should be a ++# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen ++# will append .docset to the name. ++ ++DOCSET_BUNDLE_ID = org.doxygen.Project ++ ++# If the GENERATE_HTMLHELP tag is set to YES, additional index files ++# will be generated that can be used as input for tools like the ++# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) ++# of the generated HTML documentation. ++ ++GENERATE_HTMLHELP = NO ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can ++# be used to specify the file name of the resulting .chm file. You ++# can add a path in front of the file if the result should not be ++# written to the html output directory. ++ ++CHM_FILE = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can ++# be used to specify the location (absolute path including file name) of ++# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run ++# the HTML help compiler on the generated index.hhp. ++ ++HHC_LOCATION = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag ++# controls if a separate .chi index file is generated (YES) or that ++# it should be included in the master .chm file (NO). ++ ++GENERATE_CHI = NO ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING ++# is used to encode HtmlHelp index (hhk), content (hhc) and project file ++# content. ++ ++CHM_INDEX_ENCODING = ++ ++# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag ++# controls whether a binary table of contents is generated (YES) or a ++# normal table of contents (NO) in the .chm file. ++ ++BINARY_TOC = NO ++ ++# The TOC_EXPAND flag can be set to YES to add extra items for group members ++# to the contents of the HTML help documentation and to the tree view. ++ ++TOC_EXPAND = NO ++ ++# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER ++# are set, an additional index file will be generated that can be used as input for ++# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated ++# HTML documentation. ++ ++GENERATE_QHP = NO ++ ++# If the QHG_LOCATION tag is specified, the QCH_FILE tag can ++# be used to specify the file name of the resulting .qch file. ++# The path specified is relative to the HTML output folder. ++ ++QCH_FILE = ++ ++# The QHP_NAMESPACE tag specifies the namespace to use when generating ++# Qt Help Project output. For more information please see ++# Qt Help Project / Namespace. ++ ++QHP_NAMESPACE = org.doxygen.Project ++ ++# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating ++# Qt Help Project output. For more information please see ++# Qt Help Project / Virtual Folders. ++ ++QHP_VIRTUAL_FOLDER = doc ++ ++# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can ++# be used to specify the location of Qt's qhelpgenerator. ++# If non-empty doxygen will try to run qhelpgenerator on the generated ++# .qhp file . ++ ++QHG_LOCATION = ++ ++# The DISABLE_INDEX tag can be used to turn on/off the condensed index at ++# top of each HTML page. The value NO (the default) enables the index and ++# the value YES disables it. ++ ++DISABLE_INDEX = NO ++ ++# This tag can be used to set the number of enum values (range [1..20]) ++# that doxygen will group on one line in the generated HTML documentation. ++ ++ENUM_VALUES_PER_LINE = 4 ++ ++# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index ++# structure should be generated to display hierarchical information. ++# If the tag value is set to FRAME, a side panel will be generated ++# containing a tree-like index structure (just like the one that ++# is generated for HTML Help). For this to work a browser that supports ++# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, ++# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are ++# probably better off using the HTML help feature. Other possible values ++# for this tag are: HIERARCHIES, which will generate the Groups, Directories, ++# and Class Hierarchy pages using a tree view instead of an ordered list; ++# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which ++# disables this behavior completely. For backwards compatibility with previous ++# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE ++# respectively. ++ ++GENERATE_TREEVIEW = NONE ++ ++# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be ++# used to set the initial width (in pixels) of the frame in which the tree ++# is shown. ++ ++TREEVIEW_WIDTH = 250 ++ ++# Use this tag to change the font size of Latex formulas included ++# as images in the HTML documentation. The default is 10. Note that ++# when you change the font size after a successful doxygen run you need ++# to manually remove any form_*.png images from the HTML output directory ++# to force them to be regenerated. ++ ++FORMULA_FONTSIZE = 10 ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the LaTeX output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will ++# generate Latex output. ++ ++GENERATE_LATEX = NO ++ ++# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `latex' will be used as the default path. ++ ++LATEX_OUTPUT = latex ++ ++# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be ++# invoked. If left blank `latex' will be used as the default command name. ++ ++LATEX_CMD_NAME = latex ++ ++# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to ++# generate index for LaTeX. If left blank `makeindex' will be used as the ++# default command name. ++ ++MAKEINDEX_CMD_NAME = makeindex ++ ++# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact ++# LaTeX documents. This may be useful for small projects and may help to ++# save some trees in general. ++ ++COMPACT_LATEX = NO ++ ++# The PAPER_TYPE tag can be used to set the paper type that is used ++# by the printer. Possible values are: a4, a4wide, letter, legal and ++# executive. If left blank a4wide will be used. ++ ++PAPER_TYPE = a4wide ++ ++# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX ++# packages that should be included in the LaTeX output. ++ ++EXTRA_PACKAGES = ++ ++# The LATEX_HEADER tag can be used to specify a personal LaTeX header for ++# the generated latex document. The header should contain everything until ++# the first chapter. If it is left blank doxygen will generate a ++# standard header. Notice: only use this tag if you know what you are doing! ++ ++LATEX_HEADER = ++ ++# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated ++# is prepared for conversion to pdf (using ps2pdf). The pdf file will ++# contain links (just like the HTML output) instead of page references ++# This makes the output suitable for online browsing using a pdf viewer. ++ ++PDF_HYPERLINKS = YES ++ ++# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of ++# plain latex in the generated Makefile. Set this option to YES to get a ++# higher quality PDF documentation. ++ ++USE_PDFLATEX = YES ++ ++# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. ++# command to the generated LaTeX files. This will instruct LaTeX to keep ++# running if errors occur, instead of asking the user for help. ++# This option is also used when generating formulas in HTML. ++ ++LATEX_BATCHMODE = NO ++ ++# If LATEX_HIDE_INDICES is set to YES then doxygen will not ++# include the index chapters (such as File Index, Compound Index, etc.) ++# in the output. ++ ++LATEX_HIDE_INDICES = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the RTF output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output ++# The RTF output is optimized for Word 97 and may not look very pretty with ++# other RTF readers or editors. ++ ++GENERATE_RTF = NO ++ ++# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `rtf' will be used as the default path. ++ ++RTF_OUTPUT = rtf ++ ++# If the COMPACT_RTF tag is set to YES Doxygen generates more compact ++# RTF documents. This may be useful for small projects and may help to ++# save some trees in general. ++ ++COMPACT_RTF = NO ++ ++# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated ++# will contain hyperlink fields. The RTF file will ++# contain links (just like the HTML output) instead of page references. ++# This makes the output suitable for online browsing using WORD or other ++# programs which support those fields. ++# Note: wordpad (write) and others do not support links. ++ ++RTF_HYPERLINKS = NO ++ ++# Load stylesheet definitions from file. Syntax is similar to doxygen's ++# config file, i.e. a series of assignments. You only have to provide ++# replacements, missing definitions are set to their default value. ++ ++RTF_STYLESHEET_FILE = ++ ++# Set optional variables used in the generation of an rtf document. ++# Syntax is similar to doxygen's config file. ++ ++RTF_EXTENSIONS_FILE = ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the man page output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_MAN tag is set to YES (the default) Doxygen will ++# generate man pages ++ ++GENERATE_MAN = NO ++ ++# The MAN_OUTPUT tag is used to specify where the man pages will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `man' will be used as the default path. ++ ++MAN_OUTPUT = man ++ ++# The MAN_EXTENSION tag determines the extension that is added to ++# the generated man pages (default is the subroutine's section .3) ++ ++MAN_EXTENSION = .3 ++ ++# If the MAN_LINKS tag is set to YES and Doxygen generates man output, ++# then it will generate one additional man file for each entity ++# documented in the real man page(s). These additional files ++# only source the real man page, but without them the man command ++# would be unable to find the correct page. The default is NO. ++ ++MAN_LINKS = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the XML output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_XML tag is set to YES Doxygen will ++# generate an XML file that captures the structure of ++# the code including all documentation. ++ ++GENERATE_XML = NO ++ ++# The XML_OUTPUT tag is used to specify where the XML pages will be put. ++# If a relative path is entered the value of OUTPUT_DIRECTORY will be ++# put in front of it. If left blank `xml' will be used as the default path. ++ ++XML_OUTPUT = xml ++ ++# The XML_SCHEMA tag can be used to specify an XML schema, ++# which can be used by a validating XML parser to check the ++# syntax of the XML files. ++ ++XML_SCHEMA = ++ ++# The XML_DTD tag can be used to specify an XML DTD, ++# which can be used by a validating XML parser to check the ++# syntax of the XML files. ++ ++XML_DTD = ++ ++# If the XML_PROGRAMLISTING tag is set to YES Doxygen will ++# dump the program listings (including syntax highlighting ++# and cross-referencing information) to the XML output. Note that ++# enabling this will significantly increase the size of the XML output. ++ ++XML_PROGRAMLISTING = YES ++ ++#--------------------------------------------------------------------------- ++# configuration options for the AutoGen Definitions output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will ++# generate an AutoGen Definitions (see autogen.sf.net) file ++# that captures the structure of the code including all ++# documentation. Note that this feature is still experimental ++# and incomplete at the moment. ++ ++GENERATE_AUTOGEN_DEF = NO ++ ++#--------------------------------------------------------------------------- ++# configuration options related to the Perl module output ++#--------------------------------------------------------------------------- ++ ++# If the GENERATE_PERLMOD tag is set to YES Doxygen will ++# generate a Perl module file that captures the structure of ++# the code including all documentation. Note that this ++# feature is still experimental and incomplete at the ++# moment. ++ ++GENERATE_PERLMOD = NO ++ ++# If the PERLMOD_LATEX tag is set to YES Doxygen will generate ++# the necessary Makefile rules, Perl scripts and LaTeX code to be able ++# to generate PDF and DVI output from the Perl module output. ++ ++PERLMOD_LATEX = NO ++ ++# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be ++# nicely formatted so it can be parsed by a human reader. This is useful ++# if you want to understand what is going on. On the other hand, if this ++# tag is set to NO the size of the Perl module output will be much smaller ++# and Perl will parse it just the same. ++ ++PERLMOD_PRETTY = YES ++ ++# The names of the make variables in the generated doxyrules.make file ++# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. ++# This is useful so different doxyrules.make files included by the same ++# Makefile don't overwrite each other's variables. ++ ++PERLMOD_MAKEVAR_PREFIX = ++ ++#--------------------------------------------------------------------------- ++# Configuration options related to the preprocessor ++#--------------------------------------------------------------------------- ++ ++# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will ++# evaluate all C-preprocessor directives found in the sources and include ++# files. ++ ++ENABLE_PREPROCESSING = YES ++ ++# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro ++# names in the source code. If set to NO (the default) only conditional ++# compilation will be performed. Macro expansion can be done in a controlled ++# way by setting EXPAND_ONLY_PREDEF to YES. ++ ++MACRO_EXPANSION = NO ++ ++# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES ++# then the macro expansion is limited to the macros specified with the ++# PREDEFINED and EXPAND_AS_DEFINED tags. ++ ++EXPAND_ONLY_PREDEF = NO ++ ++# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files ++# in the INCLUDE_PATH (see below) will be search if a #include is found. ++ ++SEARCH_INCLUDES = YES ++ ++# The INCLUDE_PATH tag can be used to specify one or more directories that ++# contain include files that are not input files but should be processed by ++# the preprocessor. ++ ++INCLUDE_PATH = ++ ++# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard ++# patterns (like *.h and *.hpp) to filter out the header-files in the ++# directories. If left blank, the patterns specified with FILE_PATTERNS will ++# be used. ++ ++INCLUDE_FILE_PATTERNS = ++ ++# The PREDEFINED tag can be used to specify one or more macro names that ++# are defined before the preprocessor is started (similar to the -D option of ++# gcc). The argument of the tag is a list of macros of the form: name ++# or name=definition (no spaces). If the definition and the = are ++# omitted =1 is assumed. To prevent a macro definition from being ++# undefined via #undef or recursively expanded use the := operator ++# instead of the = operator. ++ ++PREDEFINED = ++ ++# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then ++# this tag can be used to specify a list of macro names that should be expanded. ++# The macro definition that is found in the sources will be used. ++# Use the PREDEFINED tag if you want to use a different macro definition. ++ ++EXPAND_AS_DEFINED = ++ ++# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then ++# doxygen's preprocessor will remove all function-like macros that are alone ++# on a line, have an all uppercase name, and do not end with a semicolon. Such ++# function macros are typically used for boiler-plate code, and will confuse ++# the parser if not removed. ++ ++SKIP_FUNCTION_MACROS = YES ++ ++#--------------------------------------------------------------------------- ++# Configuration::additions related to external references ++#--------------------------------------------------------------------------- ++ ++# The TAGFILES option can be used to specify one or more tagfiles. ++# Optionally an initial location of the external documentation ++# can be added for each tagfile. The format of a tag file without ++# this location is as follows: ++# TAGFILES = file1 file2 ... ++# Adding location for the tag files is done as follows: ++# TAGFILES = file1=loc1 "file2 = loc2" ... ++# where "loc1" and "loc2" can be relative or absolute paths or ++# URLs. If a location is present for each tag, the installdox tool ++# does not have to be run to correct the links. ++# Note that each tag file must have a unique name ++# (where the name does NOT include the path) ++# If a tag file is not located in the directory in which doxygen ++# is run, you must also specify the path to the tagfile here. ++ ++TAGFILES = ++ ++# When a file name is specified after GENERATE_TAGFILE, doxygen will create ++# a tag file that is based on the input files it reads. ++ ++GENERATE_TAGFILE = ++ ++# If the ALLEXTERNALS tag is set to YES all external classes will be listed ++# in the class index. If set to NO only the inherited external classes ++# will be listed. ++ ++ALLEXTERNALS = NO ++ ++# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed ++# in the modules index. If set to NO, only the current project's groups will ++# be listed. ++ ++EXTERNAL_GROUPS = YES ++ ++# The PERL_PATH should be the absolute path and name of the perl script ++# interpreter (i.e. the result of `which perl'). ++ ++PERL_PATH = /usr/bin/perl ++ ++#--------------------------------------------------------------------------- ++# Configuration options related to the dot tool ++#--------------------------------------------------------------------------- ++ ++# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will ++# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base ++# or super classes. Setting the tag to NO turns the diagrams off. Note that ++# this option is superseded by the HAVE_DOT option below. This is only a ++# fallback. It is recommended to install and use dot, since it yields more ++# powerful graphs. ++ ++CLASS_DIAGRAMS = YES ++ ++# You can define message sequence charts within doxygen comments using the \msc ++# command. Doxygen will then run the mscgen tool (see ++# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the ++# documentation. The MSCGEN_PATH tag allows you to specify the directory where ++# the mscgen tool resides. If left empty the tool is assumed to be found in the ++# default search path. ++ ++MSCGEN_PATH = ++ ++# If set to YES, the inheritance and collaboration graphs will hide ++# inheritance and usage relations if the target is undocumented ++# or is not a class. ++ ++HIDE_UNDOC_RELATIONS = YES ++ ++# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is ++# available from the path. This tool is part of Graphviz, a graph visualization ++# toolkit from AT&T and Lucent Bell Labs. The other options in this section ++# have no effect if this option is set to NO (the default) ++ ++HAVE_DOT = NO ++ ++# By default doxygen will write a font called FreeSans.ttf to the output ++# directory and reference it in all dot files that doxygen generates. This ++# font does not include all possible unicode characters however, so when you need ++# these (or just want a differently looking font) you can specify the font name ++# using DOT_FONTNAME. You need need to make sure dot is able to find the font, ++# which can be done by putting it in a standard location or by setting the ++# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory ++# containing the font. ++ ++DOT_FONTNAME = FreeSans ++ ++# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. ++# The default size is 10pt. ++ ++DOT_FONTSIZE = 10 ++ ++# By default doxygen will tell dot to use the output directory to look for the ++# FreeSans.ttf font (which doxygen will put there itself). If you specify a ++# different font using DOT_FONTNAME you can set the path where dot ++# can find it using this tag. ++ ++DOT_FONTPATH = ++ ++# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen ++# will generate a graph for each documented class showing the direct and ++# indirect inheritance relations. Setting this tag to YES will force the ++# the CLASS_DIAGRAMS tag to NO. ++ ++CLASS_GRAPH = YES ++ ++# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen ++# will generate a graph for each documented class showing the direct and ++# indirect implementation dependencies (inheritance, containment, and ++# class references variables) of the class with other documented classes. ++ ++COLLABORATION_GRAPH = YES ++ ++# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen ++# will generate a graph for groups, showing the direct groups dependencies ++ ++GROUP_GRAPHS = YES ++ ++# If the UML_LOOK tag is set to YES doxygen will generate inheritance and ++# collaboration diagrams in a style similar to the OMG's Unified Modeling ++# Language. ++ ++UML_LOOK = NO ++ ++# If set to YES, the inheritance and collaboration graphs will show the ++# relations between templates and their instances. ++ ++TEMPLATE_RELATIONS = NO ++ ++# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT ++# tags are set to YES then doxygen will generate a graph for each documented ++# file showing the direct and indirect include dependencies of the file with ++# other documented files. ++ ++INCLUDE_GRAPH = YES ++ ++# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and ++# HAVE_DOT tags are set to YES then doxygen will generate a graph for each ++# documented header file showing the documented files that directly or ++# indirectly include this file. ++ ++INCLUDED_BY_GRAPH = YES ++ ++# If the CALL_GRAPH and HAVE_DOT options are set to YES then ++# doxygen will generate a call dependency graph for every global function ++# or class method. Note that enabling this option will significantly increase ++# the time of a run. So in most cases it will be better to enable call graphs ++# for selected functions only using the \callgraph command. ++ ++CALL_GRAPH = NO ++ ++# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then ++# doxygen will generate a caller dependency graph for every global function ++# or class method. Note that enabling this option will significantly increase ++# the time of a run. So in most cases it will be better to enable caller ++# graphs for selected functions only using the \callergraph command. ++ ++CALLER_GRAPH = NO ++ ++# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen ++# will graphical hierarchy of all classes instead of a textual one. ++ ++GRAPHICAL_HIERARCHY = YES ++ ++# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES ++# then doxygen will show the dependencies a directory has on other directories ++# in a graphical way. The dependency relations are determined by the #include ++# relations between the files in the directories. ++ ++DIRECTORY_GRAPH = YES ++ ++# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images ++# generated by dot. Possible values are png, jpg, or gif ++# If left blank png will be used. ++ ++DOT_IMAGE_FORMAT = png ++ ++# The tag DOT_PATH can be used to specify the path where the dot tool can be ++# found. If left blank, it is assumed the dot tool can be found in the path. ++ ++DOT_PATH = ++ ++# The DOTFILE_DIRS tag can be used to specify one or more directories that ++# contain dot files that are included in the documentation (see the ++# \dotfile command). ++ ++DOTFILE_DIRS = ++ ++# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of ++# nodes that will be shown in the graph. If the number of nodes in a graph ++# becomes larger than this value, doxygen will truncate the graph, which is ++# visualized by representing a node as a red box. Note that doxygen if the ++# number of direct children of the root node in a graph is already larger than ++# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note ++# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. ++ ++DOT_GRAPH_MAX_NODES = 50 ++ ++# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the ++# graphs generated by dot. A depth value of 3 means that only nodes reachable ++# from the root by following a path via at most 3 edges will be shown. Nodes ++# that lay further from the root node will be omitted. Note that setting this ++# option to 1 or 2 may greatly reduce the computation time needed for large ++# code bases. Also note that the size of a graph can be further restricted by ++# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. ++ ++MAX_DOT_GRAPH_DEPTH = 0 ++ ++# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent ++# background. This is disabled by default, because dot on Windows does not ++# seem to support this out of the box. Warning: Depending on the platform used, ++# enabling this option may lead to badly anti-aliased labels on the edges of ++# a graph (i.e. they become hard to read). ++ ++DOT_TRANSPARENT = NO ++ ++# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output ++# files in one run (i.e. multiple -o and -T options on the command line). This ++# makes dot run faster, but since only newer versions of dot (>1.8.10) ++# support this, this feature is disabled by default. ++ ++DOT_MULTI_TARGETS = NO ++ ++# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will ++# generate a legend page explaining the meaning of the various boxes and ++# arrows in the dot generated graphs. ++ ++GENERATE_LEGEND = YES ++ ++# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will ++# remove the intermediate dot files that are used to generate ++# the various graphs. ++ ++DOT_CLEANUP = YES ++ ++#--------------------------------------------------------------------------- ++# Configuration::additions related to the search engine ++#--------------------------------------------------------------------------- ++ ++# The SEARCHENGINE tag specifies whether or not a search engine should be ++# used. If set to NO the values of all tags below this one will be ignored. ++ ++SEARCHENGINE = NO +diff --git a/libiscsi/libiscsi.h b/libiscsi/libiscsi.h +new file mode 100644 +index 000000000000..756590e14d8b +--- /dev/null ++++ b/libiscsi/libiscsi.h +@@ -0,0 +1,344 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#ifndef __LIBISCSI_H ++#define __LIBISCSI_H ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++#if __GNUC__ >= 4 ++#define PUBLIC __attribute__ ((visibility("default"))) ++#else ++#define PUBLIC ++#endif ++ ++/** \brief Maximum length for iSCSI values. ++ * ++ * Maximum length for iSCSI values such as hostnames and parameter values. ++ */ ++#define LIBISCSI_VALUE_MAXLEN 256 ++ ++/** \brief supported authentication methods ++ * ++ * This enum lists all supported authentication methods. ++ */ ++enum libiscsi_auth_t { ++ libiscsi_auth_none /** No authentication */, ++ libiscsi_auth_chap /** CHAP authentication */, ++}; ++ ++/** \brief libiscsi context struct ++ * ++ * Note: even though libiscsi uses a context struct, the underlying open-iscsi ++ * code does not, so libiscsi is not thread safe, not even when using one ++ * context per thread! ++ */ ++struct libiscsi_context; ++ ++/** \brief iSCSI node record ++ * ++ * Struct holding data uniquely identifying an iSCSI node. ++ */ ++struct libiscsi_node { ++ char name[LIBISCSI_VALUE_MAXLEN] /** iSCSI iqn for the node. */; ++ int tpgt /** Portal group number. */; ++ /* Note open-iscsi has some code in place for multiple connections in one ++ node record and thus multiple address / port combi's, but this does not ++ get used anywhere, so we keep things simple and assume one connection */ ++ char address[NI_MAXHOST] /** Portal hostname or IP-address. */; ++ int port /** Portal port number. */; ++ char iface[LIBISCSI_VALUE_MAXLEN] /** Interface to connect through. */; ++}; ++ ++/** \brief libiscsi CHAP authentication information struct ++ * ++ * Struct holding all data needed for CHAP login / authentication. Note that ++ * \e reverse_username may be a 0 length string in which case only forward ++ * authentication will be done. ++ */ ++struct libiscsi_chap_auth_info { ++ char username[LIBISCSI_VALUE_MAXLEN] /** Username */; ++ char password[LIBISCSI_VALUE_MAXLEN] /** Password */; ++ char reverse_username[LIBISCSI_VALUE_MAXLEN] /** Reverse Username */; ++ char reverse_password[LIBISCSI_VALUE_MAXLEN] /** Reverse Password */; ++}; ++ ++/** \brief generic libiscsi authentication information struct ++ * ++ * Struct holding authentication information for discovery and login. ++ */ ++struct libiscsi_auth_info { ++ enum libiscsi_auth_t method /** Authentication method to use */; ++ union { ++ struct libiscsi_chap_auth_info chap /** Chap specific info */; ++ } /** Union holding method depenend info */; ++}; ++ ++/** \brief Initalize libiscsi ++ * ++ * This function creates a libiscsi context and initalizes it. This context ++ * is need to use other libiscsi funtions. ++ * ++ * \return A pointer to the created context, or NULL in case of an error. ++ */ ++PUBLIC struct libiscsi_context *libiscsi_init(void); ++ ++/** \brief Cleanup libiscsi used resource ++ * ++ * This function cleanups any used resources and then destroys the passed ++ * context. After this the passed in context may no longer be used! ++ * ++ * \param context libiscsi context to operate on. ++ */ ++PUBLIC void libiscsi_cleanup(struct libiscsi_context *context); ++ ++/** \brief Discover iSCSI nodes using sendtargets and add them to the node db. ++ * ++ * This function connects to the given address and port and then tries to ++ * discover iSCSI nodes using the sendtargets protocol. Any found nodes are ++ * added to the local iSCSI node database and are returned in a dynamically ++ * allocated array. ++ * ++ * Note that the (optional) authentication info is for authenticating the ++ * discovery, and is not for the found nodes! If the connection(s) to the ++ * node(s) need authentication too, you can set the username / password for ++ * those (which can be different!) using the libiscsi_node_set_auth() function. ++ * ++ * \param context libiscsi context to operate on. ++ * \param address Hostname or IP-address to connect to. ++ * \param port Port to connect to, or 0 for the default port. ++ * \param auth_info Authentication information, or NULL. ++ * \param nr_found The number of found nodes will be returned ++ * through this pointer if not NULL. ++ * \param found_nodes The address of the dynamically allocated array ++ * of found nodes will be returned through this ++ * pointer if not NULL. The caller must free this ++ * array using free(). ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_discover_sendtargets(struct libiscsi_context *context, ++ const char *address, int port, const struct libiscsi_auth_info *auth_info, ++ int *nr_found, struct libiscsi_node **found_nodes); ++ ++/** \brief Read iSCSI node info from firmware and add them to the node db. ++ * ++ * This function discovers iSCSI nodes using firmware (ppc or ibft). Any found ++ * nodes are added to the local iSCSI node database and are returned in a ++ * dynamically allocated array. ++ * ++ * Note that unlike sendtargets discovery, this function will also read ++ * authentication info and store that in the database too. ++ * ++ * Note this function currently is a stub which will always return -EINVAL ++ * (IOW it is not yet implemented) ++ * ++ * \param context libiscsi context to operate on. ++ * \param nr_found The number of found nodes will be returned ++ * through this pointer if not NULL. ++ * \param found_nodes The address of the dynamically allocated array ++ * of found nodes will be returned through this ++ * pointer if not NULL. The caller must free this ++ * array using free(). ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_discover_firmware(struct libiscsi_context *context, ++ int *nr_found, struct libiscsi_node **found_nodes); ++ ++/** \brief Check validity of the given authentication info. ++ * ++ * This function checks the validity of the given authentication info. For ++ * example in case of CHAP, if the username and password are not empty. ++ * ++ * This function is mainly intended for use by language bindings. ++ * ++ * \param context libiscsi context to operate on. ++ * \param auth_info Authentication information to check. ++ * \return 0 on success, otherwise EINVAL. ++ */ ++PUBLIC int libiscsi_verify_auth_info(struct libiscsi_context *context, ++ const struct libiscsi_auth_info *auth_info); ++ ++/** \brief Set the authentication info for the given node. ++ * ++ * This function sets the authentication information for the node described by ++ * the given node record. This will overwrite any existing authentication ++ * information. ++ * ++ * This is the way to specify authentication information for nodes found ++ * through sendtargets discovery. ++ * ++ * Note: ++ * 1) This is a convience wrapper around libiscsi_node_set_parameter(), ++ * setting the node.session.auth.* parameters. ++ * 2) For nodes found through firmware discovery the authentication information ++ * has already been set from the firmware. ++ * 3) \e auth_info may be NULL in which case any existing authinfo will be ++ * cleared. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to set auth information of ++ * \param auth_info Authentication information, or NULL. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_set_auth(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ const struct libiscsi_auth_info *auth_info); ++ ++/** \brief Get the authentication info for the given node. ++ * ++ * This function gets the authentication information for the node described by ++ * the given node record. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to set auth information of ++ * \param auth_info Pointer to a libiscsi_auth_info struct where ++ * the retreived information will be stored. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_get_auth(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ struct libiscsi_auth_info *auth_info); ++ ++/** \brief Login to an iSCSI node. ++ * ++ * Login to the iSCSI node described by the given node record. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to login to. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_login(struct libiscsi_context *context, ++ const struct libiscsi_node *node); ++ ++/** \brief Logout of an iSCSI node. ++ * ++ * Logout of the iSCSI node described by the given node record. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to logout from. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_logout(struct libiscsi_context *context, ++ const struct libiscsi_node *node); ++ ++/** \brief Set an iSCSI parameter for the given node ++ * ++ * Set the given nodes iSCSI parameter named by \e parameter to value \e value. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to change a parameter from. ++ * \param parameter Name of the parameter to set. ++ * \param value Value to set the parameter too. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_set_parameter(struct libiscsi_context *context, ++ const struct libiscsi_node *node, ++ const char *parameter, const char *value); ++ ++/** \brief Get the value of an iSCSI parameter for the given node ++ * ++ * Get the value of the given nodes iSCSI parameter named by \e parameter. ++ * ++ * \param context libiscsi context to operate on. ++ * \param node iSCSI node to change a parameter from. ++ * \param parameter Name of the parameter to get. ++ * \param value The retreived value is stored here, this buffer must be ++ * atleast LIBISCSI_VALUE_MAXLEN bytes large. ++ * \return 0 on success, otherwise a standard error code ++ * (from errno.h). ++ */ ++PUBLIC int libiscsi_node_get_parameter(struct libiscsi_context *context, ++ const struct libiscsi_node *node, const char *parameter, char *value); ++ ++/** \brief Get human readable string describing the last libiscsi error. ++ * ++ * This function can be called to get a human readable error string when a ++ * libiscsi function has returned an error. This function uses a single buffer ++ * per context, thus the result is only valid as long as no other libiscsi ++ * calls are made on the same context after the failing function call. ++ * ++ * \param context libiscsi context to operate on. ++ * ++ * \return human readable string describing the last libiscsi error. ++ */ ++PUBLIC const char *libiscsi_get_error_string(struct libiscsi_context *context); ++ ++ ++/************************** Utility functions *******************************/ ++ ++/** \brief libiscsi network config struct ++ * ++ * libiscsi network config struct. ++ */ ++struct libiscsi_network_config { ++ int dhcp /** Using DHCP? (boolean). */; ++ char iface_name[LIBISCSI_VALUE_MAXLEN] /** Interface name. */; ++ char mac_address[LIBISCSI_VALUE_MAXLEN] /** MAC address. */; ++ char ip_address[LIBISCSI_VALUE_MAXLEN] /** IP address. */; ++ char netmask[LIBISCSI_VALUE_MAXLEN] /** Netmask. */; ++ char gateway[LIBISCSI_VALUE_MAXLEN] /** IP of Default gateway. */; ++ char primary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Primary DNS. */; ++ char secondary_dns[LIBISCSI_VALUE_MAXLEN] /** IP of the Secondary DNS. */; ++}; ++ ++/** \brief Get network configuration information from iscsi firmware ++ * ++ * Function can be called to get the network configuration information ++ * (like dhcp, ip, netmask, default gateway, etc.) from the firmware of a ++ * network adapter with iscsi boot firmware. ++ * ++ * Note that not all fields of the returned struct are necessarilly filled, ++ * unset fields contain a 0 length string. ++ * ++ * \param config pointer to a libiscsi_network_config struct to fill. ++ * ++ * \return 0 on success, ENODEV when no iscsi firmware was found. ++ */ ++PUBLIC int libiscsi_get_firmware_network_config( ++ struct libiscsi_network_config *config); ++ ++/** \brief Get the initiator name (iqn) from the iscsi firmware ++ * ++ * Get the initiator name (iqn) from the iscsi firmware. ++ * ++ * \param initiatorname The initiator name is stored here, this buffer must be ++ * atleast LIBISCSI_VALUE_MAXLEN bytes large. ++ * \return 0 on success, ENODEV when no iscsi firmware was found. ++ */ ++PUBLIC int libiscsi_get_firmware_initiator_name(char *initiatorname); ++ ++#undef PUBLIC ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif +diff --git a/libiscsi/pylibiscsi.c b/libiscsi/pylibiscsi.c +new file mode 100644 +index 000000000000..4b09aa7b956a +--- /dev/null ++++ b/libiscsi/pylibiscsi.c +@@ -0,0 +1,638 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include "libiscsi.h" ++ ++static struct libiscsi_context *context = NULL; ++ ++/****************************** helpers ***********************************/ ++static int check_string(const char *string) ++{ ++ if (strlen(string) >= LIBISCSI_VALUE_MAXLEN) { ++ PyErr_SetString(PyExc_ValueError, "string too long"); ++ return -1; ++ } ++ return 0; ++} ++ ++/********************** PyIscsiChapAuthInfo ***************************/ ++ ++typedef struct { ++ PyObject_HEAD ++ ++ struct libiscsi_auth_info info; ++} PyIscsiChapAuthInfo; ++ ++static int PyIscsiChapAuthInfo_init(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ int i; ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ char *kwlist[] = {"username", "password", "reverse_username", ++ "reverse_password", NULL}; ++ const char *string[4] = { NULL, NULL, NULL, NULL }; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, ++ "zz|zz:chapAuthInfo.__init__", ++ kwlist, &string[0], &string[1], ++ &string[2], &string[3])) ++ return -1; ++ ++ for (i = 0; i < 4; i++) ++ if (string[i] && check_string(string[i])) ++ return -1; ++ ++ memset (&chap->info, 0, sizeof(chap->info)); ++ chap->info.method = libiscsi_auth_chap; ++ if (string[0]) ++ strcpy(chap->info.chap.username, string[0]); ++ if (string[1]) ++ strcpy(chap->info.chap.password, string[1]); ++ if (string[2]) ++ strcpy(chap->info.chap.reverse_username, string[2]); ++ if (string[3]) ++ strcpy(chap->info.chap.reverse_password, string[3]); ++ ++ if (libiscsi_verify_auth_info(context, &chap->info)) { ++ PyErr_SetString(PyExc_ValueError, ++ libiscsi_get_error_string(context)); ++ return -1; ++ } ++ return 0; ++} ++ ++static PyObject *PyIscsiChapAuthInfo_get(PyObject *self, void *data) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ const char *attr = (const char *)data; ++ ++ if (!strcmp(attr, "username")) { ++ return PyString_FromString(chap->info.chap.username); ++ } else if (!strcmp(attr, "password")) { ++ return PyString_FromString(chap->info.chap.password); ++ } else if (!strcmp(attr, "reverse_username")) { ++ return PyString_FromString(chap->info.chap.reverse_username); ++ } else if (!strcmp(attr, "reverse_password")) { ++ return PyString_FromString(chap->info.chap.reverse_password); ++ } ++ return NULL; ++} ++ ++static int PyIscsiChapAuthInfo_set(PyObject *self, PyObject *value, void *data) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ const char *attr = (const char *)data; ++ const char *str; ++ ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ ++ if (!strcmp(attr, "username")) { ++ strcpy(chap->info.chap.username, str); ++ } else if (!strcmp(attr, "password")) { ++ strcpy(chap->info.chap.password, str); ++ } else if (!strcmp(attr, "reverse_username")) { ++ strcpy(chap->info.chap.reverse_username, str); ++ } else if (!strcmp(attr, "reverse_password")) { ++ strcpy(chap->info.chap.reverse_password, str); ++ } ++ ++ return 0; ++} ++ ++static int PyIscsiChapAuthInfo_compare(PyIscsiChapAuthInfo *self, ++ PyIscsiChapAuthInfo *other) ++{ ++ int r; ++ ++ r = strcmp(self->info.chap.username, other->info.chap.username); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.password, other->info.chap.password); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.reverse_username, ++ other->info.chap.reverse_username); ++ if (r) ++ return r; ++ ++ r = strcmp(self->info.chap.reverse_password, ++ other->info.chap.reverse_password); ++ return r; ++} ++ ++static PyObject *PyIscsiChapAuthInfo_str(PyObject *self) ++{ ++ PyIscsiChapAuthInfo *chap = (PyIscsiChapAuthInfo *)self; ++ char s[1024], reverse[512] = ""; ++ ++ if (chap->info.chap.reverse_username[0]) ++ snprintf(reverse, sizeof(reverse), ", %s:%s", ++ chap->info.chap.reverse_username, ++ chap->info.chap.reverse_password); ++ ++ snprintf(s, sizeof(s), "%s:%s%s", chap->info.chap.username, ++ chap->info.chap.password, reverse); ++ ++ return PyString_FromString(s); ++} ++ ++static struct PyGetSetDef PyIscsiChapAuthInfo_getseters[] = { ++ {"username", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "username", "username"}, ++ {"password", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "password", "password"}, ++ {"reverse_username", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "reverse_username", "reverse_username"}, ++ {"reverse_password", (getter)PyIscsiChapAuthInfo_get, ++ (setter)PyIscsiChapAuthInfo_set, ++ "reverse_password", "reverse_password"}, ++ {NULL} ++}; ++ ++PyTypeObject PyIscsiChapAuthInfo_Type = { ++ PyObject_HEAD_INIT(NULL) ++ .tp_name = "libiscsi.chapAuthInfo", ++ .tp_basicsize = sizeof (PyIscsiChapAuthInfo), ++ .tp_getset = PyIscsiChapAuthInfo_getseters, ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | ++ Py_TPFLAGS_BASETYPE, ++ .tp_compare = (cmpfunc)PyIscsiChapAuthInfo_compare, ++ .tp_init = PyIscsiChapAuthInfo_init, ++ .tp_str = PyIscsiChapAuthInfo_str, ++ .tp_new = PyType_GenericNew, ++ .tp_doc = "iscsi chap authentication information.", ++}; ++ ++/***************************** PyIscsiNode ********************************/ ++ ++typedef struct { ++ PyObject_HEAD ++ ++ struct libiscsi_node node; ++} PyIscsiNode; ++ ++static int PyIscsiNode_init(PyObject *self, PyObject *args, PyObject *kwds) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ char *kwlist[] = {"name", "tpgt", "address", "port", "iface", NULL}; ++ const char *name = NULL, *address = NULL, *iface = NULL; ++ int tpgt = -1, port = 3260; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|isis:node.__init__", ++ kwlist, &name, &tpgt, &address, ++ &port, &iface)) ++ return -1; ++ if (address == NULL) { ++ PyErr_SetString(PyExc_ValueError, "address not set"); ++ return -1; ++ } ++ if (check_string(name) || check_string(address) || check_string(iface)) ++ return -1; ++ ++ strcpy(node->node.name, name); ++ node->node.tpgt = tpgt; ++ strcpy(node->node.address, address); ++ node->node.port = port; ++ strcpy(node->node.iface, iface); ++ ++ return 0; ++} ++ ++static PyObject *PyIscsiNode_get(PyObject *self, void *data) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *attr = (const char *)data; ++ ++ if (!strcmp(attr, "name")) { ++ return PyString_FromString(node->node.name); ++ } else if (!strcmp(attr, "tpgt")) { ++ return PyInt_FromLong(node->node.tpgt); ++ } else if (!strcmp(attr, "address")) { ++ return PyString_FromString(node->node.address); ++ } else if (!strcmp(attr, "port")) { ++ return PyInt_FromLong(node->node.port); ++ } else if (!strcmp(attr, "iface")) { ++ return PyString_FromString(node->node.iface); ++ } ++ return NULL; ++} ++ ++static int PyIscsiNode_set(PyObject *self, PyObject *value, void *data) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *attr = (const char *)data; ++ const char *str; ++ int i; ++ ++ if (!strcmp(attr, "name")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.name, str); ++ } else if (!strcmp(attr, "tpgt")) { ++ if (!PyArg_Parse(value, "i", &i)) ++ return -1; ++ node->node.tpgt = i; ++ } else if (!strcmp(attr, "address")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.address, str); ++ } else if (!strcmp(attr, "port")) { ++ if (!PyArg_Parse(value, "i", &i)) ++ return -1; ++ node->node.port = i; ++ } else if (!strcmp(attr, "iface")) { ++ if (!PyArg_Parse(value, "s", &str) || check_string(str)) ++ return -1; ++ strcpy(node->node.iface, str); ++ } ++ ++ return 0; ++} ++ ++static int PyIscsiNode_compare(PyIscsiNode *self, PyIscsiNode *other) ++{ ++ int res; ++ ++ res = strcmp(self->node.name, other->node.name); ++ if (res) ++ return res; ++ ++ if (self->node.tpgt < other->node.tpgt) ++ return -1; ++ if (self->node.tpgt > other->node.tpgt) ++ return -1; ++ ++ res = strcmp(self->node.address, other->node.address); ++ if (res) ++ return res; ++ ++ if (self->node.port < other->node.port) ++ return -1; ++ if (self->node.port > other->node.port) ++ return -1; ++ ++ res = strcmp(self->node.iface, other->node.iface); ++ if (res) ++ return res; ++ ++ return 0; ++} ++ ++static PyObject *PyIscsiNode_str(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ char s[1024], tpgt[16] = ""; ++ ++ if (node->node.tpgt != -1) ++ sprintf(tpgt, ",%d", node->node.tpgt); ++ ++ snprintf(s, sizeof(s), "%s:%d%s %s", node->node.address, ++ node->node.port, tpgt, node->node.name); ++ ++ return PyString_FromString(s); ++} ++ ++static PyObject *PyIscsiNode_login(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ ++ if (libiscsi_node_login(context, &node->node)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_logout(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ ++ if (libiscsi_node_logout(context, &node->node)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_setAuth(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"authinfo", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ PyObject *arg; ++ const struct libiscsi_auth_info *authinfo = NULL; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &arg)) ++ return NULL; ++ ++ if (arg == Py_None) { ++ authinfo = NULL; ++ } else if (PyObject_IsInstance(arg, (PyObject *) ++ &PyIscsiChapAuthInfo_Type)) { ++ PyIscsiChapAuthInfo *pyauthinfo = (PyIscsiChapAuthInfo *)arg; ++ authinfo = &pyauthinfo->info; ++ } else { ++ PyErr_SetString(PyExc_ValueError, "invalid authinfo type"); ++ return NULL; ++ } ++ ++ if (libiscsi_node_set_auth(context, &node->node, authinfo)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_getAuth(PyObject *self) ++{ ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ PyIscsiChapAuthInfo *pyauthinfo; ++ struct libiscsi_auth_info authinfo; ++ ++ if (libiscsi_node_get_auth(context, &node->node, &authinfo)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ switch (authinfo.method) { ++ case libiscsi_auth_chap: ++ pyauthinfo = PyObject_New(PyIscsiChapAuthInfo, ++ &PyIscsiChapAuthInfo_Type); ++ if (!pyauthinfo) ++ return NULL; ++ ++ pyauthinfo->info = authinfo; ++ ++ return (PyObject *)pyauthinfo; ++ ++ case libiscsi_auth_none: ++ default: ++ Py_RETURN_NONE; ++ } ++} ++ ++static PyObject *PyIscsiNode_setParameter(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"parameter", "value", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *parameter, *value; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist, ++ ¶meter, &value)) ++ return NULL; ++ if (check_string(parameter) || check_string(value)) ++ return NULL; ++ ++ if (libiscsi_node_set_parameter(context, &node->node, parameter, ++ value)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static PyObject *PyIscsiNode_getParameter(PyObject *self, PyObject *args, ++ PyObject *kwds) ++{ ++ char *kwlist[] = {"parameter", NULL}; ++ PyIscsiNode *node = (PyIscsiNode *)self; ++ const char *parameter; ++ char value[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, ¶meter)) ++ return NULL; ++ if (check_string(parameter)) ++ return NULL; ++ ++ if (libiscsi_node_get_parameter(context, &node->node, parameter, ++ value)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ return Py_BuildValue("s", value); ++} ++ ++static struct PyGetSetDef PyIscsiNode_getseters[] = { ++ {"name", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "name", "name"}, ++ {"tpgt", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "tpgt", "tpgt"}, ++ {"address", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "address", "address"}, ++ {"port", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "port", "port"}, ++ {"iface", (getter)PyIscsiNode_get, (setter)PyIscsiNode_set, ++ "iface", "iface"}, ++ {NULL} ++}; ++ ++static struct PyMethodDef PyIscsiNode_methods[] = { ++ {"login", (PyCFunction) PyIscsiNode_login, METH_NOARGS, ++ "Log in to the node"}, ++ {"logout", (PyCFunction) PyIscsiNode_logout, METH_NOARGS, ++ "Log out of the node"}, ++ {"setAuth", (PyCFunction) PyIscsiNode_setAuth, ++ METH_VARARGS|METH_KEYWORDS, ++ "Set authentication information"}, ++ {"getAuth", (PyCFunction) PyIscsiNode_getAuth, METH_NOARGS, ++ "Get authentication information"}, ++ {"setParameter", (PyCFunction) PyIscsiNode_setParameter, ++ METH_VARARGS|METH_KEYWORDS, ++ "Set an iscsi node parameter"}, ++ {"getParameter", (PyCFunction) PyIscsiNode_getParameter, ++ METH_VARARGS|METH_KEYWORDS, ++ "Get an iscsi node parameter"}, ++ {NULL} ++}; ++ ++PyTypeObject PyIscsiNode_Type = { ++ PyObject_HEAD_INIT(NULL) ++ .tp_name = "libiscsi.node", ++ .tp_basicsize = sizeof (PyIscsiNode), ++ .tp_getset = PyIscsiNode_getseters, ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | ++ Py_TPFLAGS_BASETYPE, ++ .tp_methods = PyIscsiNode_methods, ++ .tp_compare = (cmpfunc)PyIscsiNode_compare, ++ .tp_init = PyIscsiNode_init, ++ .tp_str = PyIscsiNode_str, ++ .tp_new = PyType_GenericNew, ++ .tp_doc = "The iscsi node contains iscsi node information.", ++}; ++ ++/***************************************************************************/ ++ ++static PyObject *pylibiscsi_discover_sendtargets(PyObject *self, ++ PyObject *args, PyObject *kwds) ++{ ++ char *kwlist[] = {"address", "port", "authinfo", NULL}; ++ const char *address = NULL; ++ int i, nr_found, port = 3260; ++ PyObject *authinfo_arg = NULL; ++ const struct libiscsi_auth_info *authinfo = NULL; ++ struct libiscsi_node *found_nodes; ++ PyObject* found_node_list; ++ ++ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iO", ++ kwlist, &address, &port, ++ &authinfo_arg)) ++ return NULL; ++ ++ if (authinfo_arg) { ++ if (PyObject_IsInstance(authinfo_arg, (PyObject *) ++ &PyIscsiChapAuthInfo_Type)) { ++ PyIscsiChapAuthInfo *pyauthinfo = ++ (PyIscsiChapAuthInfo *)authinfo_arg; ++ authinfo = &pyauthinfo->info; ++ } else if (authinfo_arg != Py_None) { ++ PyErr_SetString(PyExc_ValueError, ++ "invalid authinfo type"); ++ return NULL; ++ } ++ } ++ ++ if (libiscsi_discover_sendtargets(context, address, port, authinfo, ++ &nr_found, &found_nodes)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ if (nr_found == 0) ++ Py_RETURN_NONE; ++ ++ found_node_list = PyList_New(nr_found); ++ if (!found_node_list) ++ return NULL; ++ ++ for(i = 0; i < nr_found; i++) { ++ PyIscsiNode *pynode; ++ ++ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type); ++ if (!pynode) { ++ /* This will deref already added nodes for us */ ++ Py_DECREF(found_node_list); ++ return NULL; ++ } ++ pynode->node = found_nodes[i]; ++ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode); ++ } ++ ++ return found_node_list; ++} ++ ++static PyObject *pylibiscsi_discover_firmware(PyObject *self) ++{ ++ int i, nr_found; ++ struct libiscsi_node *found_nodes; ++ PyObject* found_node_list; ++ ++ if (libiscsi_discover_firmware(context, &nr_found, &found_nodes)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ if (nr_found == 0) ++ Py_RETURN_NONE; ++ ++ found_node_list = PyList_New(nr_found); ++ if (!found_node_list) ++ return NULL; ++ ++ for(i = 0; i < nr_found; i++) { ++ PyIscsiNode *pynode; ++ ++ pynode = PyObject_New(PyIscsiNode, &PyIscsiNode_Type); ++ if (!pynode) { ++ /* This will deref already added nodes for us */ ++ Py_DECREF(found_node_list); ++ return NULL; ++ } ++ pynode->node = found_nodes[i]; ++ PyList_SET_ITEM(found_node_list, i, (PyObject *)pynode); ++ } ++ ++ return found_node_list; ++} ++ ++static PyObject *pylibiscsi_get_firmware_initiator_name(PyObject *self) ++{ ++ char initiatorname[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (libiscsi_get_firmware_initiator_name(initiatorname)) { ++ PyErr_SetString(PyExc_IOError, ++ libiscsi_get_error_string(context)); ++ return NULL; ++ } ++ ++ return PyString_FromString(initiatorname); ++} ++ ++static PyMethodDef pylibiscsi_functions[] = { ++ { "discover_sendtargets", ++ (PyCFunction)pylibiscsi_discover_sendtargets, ++ METH_VARARGS|METH_KEYWORDS, ++ "Do sendtargets discovery and return a list of found nodes)"}, ++ { "discover_firmware", ++ (PyCFunction)pylibiscsi_discover_firmware, METH_NOARGS, ++ "Do firmware discovery and return a list of found nodes)"}, ++ { "get_firmware_initiator_name", ++ (PyCFunction)pylibiscsi_get_firmware_initiator_name, ++ METH_NOARGS, ++ "Get initator name (iqn) from firmware"}, ++ {NULL, NULL} ++}; ++ ++PyMODINIT_FUNC initlibiscsi(void) ++{ ++ PyObject *m; ++ ++ if (!context) /* We may be called more then once */ ++ context = libiscsi_init(); ++ if (!context) ++ return; ++ ++ if (PyType_Ready(&PyIscsiChapAuthInfo_Type) < 0) ++ return; ++ ++ if (PyType_Ready(&PyIscsiNode_Type) < 0) ++ return; ++ ++ m = Py_InitModule("libiscsi", pylibiscsi_functions); ++ Py_INCREF(&PyIscsiChapAuthInfo_Type); ++ PyModule_AddObject(m, "chapAuthInfo", (PyObject *) &PyIscsiChapAuthInfo_Type); ++ Py_INCREF(&PyIscsiNode_Type); ++ PyModule_AddObject(m, "node", (PyObject *) &PyIscsiNode_Type); ++} +diff --git a/libiscsi/setup.py b/libiscsi/setup.py +new file mode 100644 +index 000000000000..bb4329bc2158 +--- /dev/null ++++ b/libiscsi/setup.py +@@ -0,0 +1,9 @@ ++from distutils.core import setup, Extension ++ ++module1 = Extension('libiscsimodule', ++ sources = ['pylibiscsi.c'], ++ libraries = ['iscsi'], ++ library_dirs = ['.']) ++ ++setup (name = 'PyIscsi',version = '1.0', ++ description = 'libiscsi python bindings', ext_modules = [module1]) +diff --git a/libiscsi/tests/test_discovery_firmware.c b/libiscsi/tests/test_discovery_firmware.c +new file mode 100644 +index 000000000000..76e852a37019 +--- /dev/null ++++ b/libiscsi/tests/test_discovery_firmware.c +@@ -0,0 +1,53 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node *found_nodes; ++ struct libiscsi_context *context; ++ int i, found, rc = 0; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_discover_firmware(context, &found, &found_nodes); ++ if (rc) ++ fprintf(stderr, "Error discovering: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ for (i = 0; i < found; i++) { ++ fprintf(stdout, "Found node: %s, tpgt: %d, portal: %s:%d\n", ++ found_nodes[i].name, found_nodes[i].tpgt, ++ found_nodes[i].address, found_nodes[i].port); ++ } ++ ++ libiscsi_cleanup(context); ++ free (found_nodes); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_discovery_sendtargets.c b/libiscsi/tests/test_discovery_sendtargets.c +new file mode 100644 +index 000000000000..1a3c12ef684b +--- /dev/null ++++ b/libiscsi/tests/test_discovery_sendtargets.c +@@ -0,0 +1,60 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node *found_nodes; ++ struct libiscsi_context *context; ++ struct libiscsi_auth_info auth_info; ++ int i, found, rc = 0; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ memset(&auth_info, 0, sizeof(auth_info)); ++ auth_info.method = libiscsi_auth_chap; ++ strcpy(auth_info.chap.username, "joe"); ++ strcpy(auth_info.chap.password, "secret"); ++ ++ rc = libiscsi_discover_sendtargets(context, "127.0.0.1", 3260, ++ &auth_info, &found, &found_nodes); ++ if (rc) ++ fprintf(stderr, "Error discovering: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ for (i = 0; i < found; i++) { ++ fprintf(stdout, "Found node: %s, tpgt: %d, portal: %s:%d\n", ++ found_nodes[i].name, found_nodes[i].tpgt, ++ found_nodes[i].address, found_nodes[i].port); ++ } ++ ++ libiscsi_cleanup(context); ++ free (found_nodes); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_get_auth.c b/libiscsi/tests/test_get_auth.c +new file mode 100644 +index 000000000000..5e234dadd0de +--- /dev/null ++++ b/libiscsi/tests/test_get_auth.c +@@ -0,0 +1,70 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ struct libiscsi_auth_info auth_info; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_get_auth(context, &node, &auth_info); ++ if (rc) { ++ fprintf(stderr, "Error setting authinfo: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ switch (auth_info.method) { ++ case libiscsi_auth_none: ++ printf("Method: \"None\"\n"); ++ break; ++ case libiscsi_auth_chap: ++ printf("Method: \"CHAP\"\n"); ++ printf("User: \"%s\"\n", auth_info.chap.username); ++ printf("Pass: \"%s\"\n", auth_info.chap.password); ++ printf("RevUser: \"%s\"\n", ++ auth_info.chap.reverse_username); ++ printf("RevPass: \"%s\"\n", ++ auth_info.chap.reverse_password); ++ break; ++ } ++leave: ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_get_initiator_name.c b/libiscsi/tests/test_get_initiator_name.c +new file mode 100644 +index 000000000000..997c053e5bf6 +--- /dev/null ++++ b/libiscsi/tests/test_get_initiator_name.c +@@ -0,0 +1,38 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ char initiatorname[LIBISCSI_VALUE_MAXLEN]; ++ ++ if (libiscsi_get_firmware_initiator_name(initiatorname)) { ++ fprintf(stderr, "No iscsi boot firmware found\n"); ++ return 1; ++ } ++ ++ printf("iqn:\t%s\n", initiatorname); ++ ++ return 0; ++} +diff --git a/libiscsi/tests/test_get_network_config.c b/libiscsi/tests/test_get_network_config.c +new file mode 100644 +index 000000000000..2dedd6102858 +--- /dev/null ++++ b/libiscsi/tests/test_get_network_config.c +@@ -0,0 +1,45 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_network_config config; ++ ++ if (libiscsi_get_firmware_network_config(&config)) { ++ fprintf(stderr, "No iscsi boot firmware found\n"); ++ return 1; ++ } ++ ++ printf("dhcp:\t%d\n", config.dhcp); ++ printf("iface:\t%s\n", config.iface_name); ++ printf("mac:\t%s\n", config.mac_address); ++ printf("ipaddr:\t%s\n", config.ip_address); ++ printf("mask:\t%s\n", config.netmask); ++ printf("gate:\t%s\n", config.gateway); ++ printf("dns1:\t%s\n", config.primary_dns); ++ printf("dns2:\t%s\n", config.secondary_dns); ++ ++ return 0; ++} +diff --git a/libiscsi/tests/test_login.c b/libiscsi/tests/test_login.c +new file mode 100644 +index 000000000000..3eb70d63e111 +--- /dev/null ++++ b/libiscsi/tests/test_login.c +@@ -0,0 +1,52 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_login(context, &node); ++ if (rc) ++ fprintf(stderr, "Error logging in: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_logout.c b/libiscsi/tests/test_logout.c +new file mode 100644 +index 000000000000..b734dca58773 +--- /dev/null ++++ b/libiscsi/tests/test_logout.c +@@ -0,0 +1,51 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_logout(context, &node); ++ if (rc) ++ fprintf(stderr, "Error logging out: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_params.c b/libiscsi/tests/test_params.c +new file mode 100644 +index 000000000000..d3223be1e894 +--- /dev/null ++++ b/libiscsi/tests/test_params.c +@@ -0,0 +1,103 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ char orig_value[LIBISCSI_VALUE_MAXLEN], value[LIBISCSI_VALUE_MAXLEN]; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_get_parameter(context, &node, "node.startup", ++ orig_value); ++ if (rc) { ++ fprintf(stderr, "Error getting original value: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ rc = libiscsi_node_set_parameter(context, &node, "node.startup", ++ "automatic"); ++ if (rc) { ++ fprintf(stderr, "Error setting node startup param: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ rc = libiscsi_node_get_parameter(context, &node, "node.startup", ++ value); ++ if (rc) { ++ fprintf(stderr, "Error getting node startup param: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ if (strcmp(value, "automatic")) { ++ fprintf(stderr, "Error set and get values do not match!\n"); ++ rc = EIO; ++ goto leave; ++ } ++ ++ rc = libiscsi_node_set_parameter(context, &node, "node.startup", ++ orig_value); ++ if (rc) { ++ fprintf(stderr, "Error setting original value: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ rc = libiscsi_node_get_parameter(context, &node, "node.startup", ++ value); ++ if (rc) { ++ fprintf(stderr, "Error re-getting original value: %s\n", ++ libiscsi_get_error_string(context)); ++ goto leave; ++ } ++ ++ if (strcmp(value, orig_value)) { ++ fprintf(stderr, ++ "Error set and get original values do not match!\n"); ++ rc = EIO; ++ goto leave; ++ } ++ ++leave: ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/libiscsi/tests/test_set_auth.c b/libiscsi/tests/test_set_auth.c +new file mode 100644 +index 000000000000..a21f88806ab9 +--- /dev/null ++++ b/libiscsi/tests/test_set_auth.c +@@ -0,0 +1,58 @@ ++/* ++ * iSCSI Administration library ++ * ++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2008-2009 Hans de Goede ++ * maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include "libiscsi.h" ++ ++int main(void) ++{ ++ struct libiscsi_node node; ++ struct libiscsi_context *context; ++ struct libiscsi_auth_info auth_info; ++ int rc = 0; ++ ++ snprintf(node.name, LIBISCSI_VALUE_MAXLEN, "%s", ++ "iqn.2009-01.com.example:testdisk"); ++ node.tpgt = 1; ++ snprintf(node.address, NI_MAXHOST, "%s", "127.0.0.1"); ++ node.port = 3260; ++ ++ memset(&auth_info, 0, sizeof(auth_info)); ++ auth_info.method = libiscsi_auth_chap; ++ strcpy(auth_info.chap.username, "joe"); ++ strcpy(auth_info.chap.password, "secret"); ++ ++ context = libiscsi_init(); ++ if (!context) { ++ fprintf(stderr, "Error initializing libiscsi\n"); ++ return 1; ++ } ++ ++ rc = libiscsi_node_set_auth(context, &node, &auth_info); ++ if (rc) ++ fprintf(stderr, "Error setting authinfo: %s\n", ++ libiscsi_get_error_string(context)); ++ ++ libiscsi_cleanup(context); ++ ++ return rc; ++} +diff --git a/usr/Makefile b/usr/Makefile +index c1866b6a4ed8..6d3ce2e8b6ce 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -30,7 +30,7 @@ endif + + CFLAGS ?= -O2 -g + WARNFLAGS ?= -Wall -Wstrict-prototypes +-CFLAGS += $(WARNFLAGS) -I../include -I. -D$(OSNAME) $(IPC_CFLAGS) ++CFLAGS += $(WARNFLAGS) -I../include -I. -D$(OSNAME) $(IPC_CFLAGS) -DISNS_ENABLE + PROGRAMS = iscsid iscsiadm iscsistart + + # libc compat files +diff --git a/usr/discovery.c b/usr/discovery.c +index 593d22650f0d..de8267f08f8a 100644 +--- a/usr/discovery.c ++++ b/usr/discovery.c +@@ -36,6 +36,7 @@ + #include "types.h" + #include "iscsi_proto.h" + #include "initiator.h" ++#include "config.h" + #include "log.h" + #include "idbm.h" + #include "iscsi_settings.h" +@@ -49,10 +50,12 @@ + #include "iface.h" + #include "iscsi_timer.h" + #include "iscsi_err.h" ++#ifdef ISNS_ENABLE + /* libisns includes */ + #include + #include + #include ++#endif + + #ifdef SLP_ENABLE + #include "iscsi-slp-discovery.h" +@@ -98,6 +101,7 @@ static int request_initiator_name(void) + return 0; + } + ++#ifdef ISNS_ENABLE + void discovery_isns_free_servername(void) + { + if (isns_config.ic_server_name) +@@ -377,6 +381,7 @@ retry: + discovery_isns_free_servername(); + return rc; + } ++#endif + + int discovery_fw(void *data, struct iface_rec *iface, + struct list_head *rec_list) +diff --git a/usr/idbm.c b/usr/idbm.c +index a749cc8ea3f8..979fefb7a5d7 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -1709,9 +1709,9 @@ int idbm_print_all_discovery(int info_level) + * fn should return -1 if it skipped the rec, an ISCSI_ERR error code if + * the operation failed or 0 if fn was run successfully. + */ +-static int idbm_for_each_iface(int *found, void *data, +- idbm_iface_op_fn *fn, +- char *targetname, int tpgt, char *ip, int port) ++int idbm_for_each_iface(int *found, void *data, ++ idbm_iface_op_fn *fn, ++ char *targetname, int tpgt, char *ip, int port) + { + DIR *iface_dirfd; + struct dirent *iface_dent; +diff --git a/usr/idbm.h b/usr/idbm.h +index b89ddffe55df..36312621f06c 100644 +--- a/usr/idbm.h ++++ b/usr/idbm.h +@@ -102,6 +102,9 @@ struct rec_op_data { + node_rec_t *match_rec; + idbm_iface_op_fn *fn; + }; ++extern int idbm_for_each_iface(int *found, void *data, ++ idbm_iface_op_fn *fn, ++ char *targetname, int tpgt, char *ip, int port); + extern int idbm_for_each_portal(int *found, void *data, + idbm_portal_op_fn *fn, char *targetname); + extern int idbm_for_each_node(int *found, void *data, +diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h +index 5087b5c6343d..a6dc40a55d78 100644 +--- a/usr/iscsi_ipc.h ++++ b/usr/iscsi_ipc.h +@@ -166,4 +166,6 @@ struct iscsi_ipc { + char *host_stats); + }; + ++struct iscsi_ipc *ipc; ++ + #endif /* ISCSI_IPC_H */ +-- +2.9.3 + diff --git a/SOURCES/0156-remove-the-offload-boot-supported-ifdef.patch b/SOURCES/0156-remove-the-offload-boot-supported-ifdef.patch new file mode 100644 index 00000000..a1ccdc72 --- /dev/null +++ b/SOURCES/0156-remove-the-offload-boot-supported-ifdef.patch @@ -0,0 +1,45 @@ +From aa58a042ec20575143c1a5c813c9552a286aeb0e Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 19 Nov 2012 17:09:24 -0800 +Subject: remove the offload boot supported ifdef + +--- + usr/iface.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/usr/iface.c b/usr/iface.c +index c86892e..f5441c0 100644 +--- a/usr/iface.c ++++ b/usr/iface.c +@@ -895,6 +895,7 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + { + struct iscsi_transport *t = NULL; + uint32_t hostno; ++ int rc; + + if (strlen(context->initiatorname)) + strlcpy(iface->iname, context->initiatorname, +@@ -907,10 +908,7 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + return 0; + } + } else if (strlen(context->iface)) { +-/* this ifdef is only temp until distros and firmwares are updated */ +-#ifdef OFFLOAD_BOOT_SUPPORTED + char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN]; +- int rc; + + memset(transport_name, 0, ISCSI_TRANSPORT_NAME_MAXLEN); + /* make sure offload driver is loaded */ +@@ -936,9 +934,6 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + } + + strlcpy(iface->netdev, context->iface, sizeof(iface->netdev)); +-#else +- return 0; +-#endif + } else + return 0; + +-- +1.7.11.7 + diff --git a/SOURCES/0159-iscsiuio-systemd-unit-files.patch b/SOURCES/0159-iscsiuio-systemd-unit-files.patch new file mode 100644 index 00000000..2d0e213f --- /dev/null +++ b/SOURCES/0159-iscsiuio-systemd-unit-files.patch @@ -0,0 +1,53 @@ +From 822b53e6c9ebb0fe7236ebd3b4c73b009100592d Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 22 Jan 2013 14:27:12 -0800 +Subject: iscsiuio systemd unit files + +--- + etc/systemd/iscsiuio.service | 17 +++++++++++++++++ + etc/systemd/iscsiuio.socket | 9 +++++++++ + 2 files changed, 26 insertions(+) + create mode 100644 etc/systemd/iscsiuio.service + create mode 100644 etc/systemd/iscsiuio.socket + +diff --git a/etc/systemd/iscsiuio.service b/etc/systemd/iscsiuio.service +new file mode 100644 +index 0000000..f0410b7 +--- /dev/null ++++ b/etc/systemd/iscsiuio.service +@@ -0,0 +1,17 @@ ++[Unit] ++Description=iSCSI UserSpace I/O driver ++Documentation=man:iscsiuio(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++Requires=iscsid.service ++BindTo=iscsid.service ++After=network.target ++Before=remote-fs-pre.target iscsid.service ++ ++[Service] ++Type=forking ++PIDFile=/var/run/iscsiuio.pid ++ExecStart=/usr/sbin/iscsiuio ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/etc/systemd/iscsiuio.socket b/etc/systemd/iscsiuio.socket +new file mode 100644 +index 0000000..d42cedc +--- /dev/null ++++ b/etc/systemd/iscsiuio.socket +@@ -0,0 +1,9 @@ ++[Unit] ++Description=Open-iSCSI iscsiuio Socket ++Documentation=man:iscsiuio(8) ++ ++[Socket] ++ListenStream=@ISCSID_UIP_ABSTRACT_NAMESPACE ++ ++[Install] ++WantedBy=sockets.target +-- +1.7.11.7 + diff --git a/SOURCES/0160-use-systemctl-to-start-iscsid.patch b/SOURCES/0160-use-systemctl-to-start-iscsid.patch new file mode 100644 index 00000000..81aa2a37 --- /dev/null +++ b/SOURCES/0160-use-systemctl-to-start-iscsid.patch @@ -0,0 +1,25 @@ +From c3d2b8f3de5b6161845304cf46982d2c5a9918b6 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Thu Feb 21 21:05:39 PST 2013 +Subject: disable iscsid.startup from iscsiadm, prefer systemd socket activation + +--- + etc/iscsid.conf | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/etc/iscsid.conf b/etc/iscsid.conf +index ac1d231..5851fa5 100644 +--- a/etc/iscsid.conf ++++ b/etc/iscsid.conf +@@ -17,7 +17,7 @@ + # maintainers. + # + # Default for Fedora and RHEL. (uncomment to activate). +-iscsid.startup = /etc/rc.d/init.d/iscsid force-start ++#iscsid.startup = /bin/systemctl start iscsid.service + # + # Default for upstream open-iscsi scripts (uncomment to activate). + # iscsid.startup = /sbin/iscsid +-- +1.7.11.7 + diff --git a/SOURCES/0161-resolve-565245-multilib-issues-caused-by-doxygen.patch b/SOURCES/0161-resolve-565245-multilib-issues-caused-by-doxygen.patch new file mode 100644 index 00000000..1f64d9c7 --- /dev/null +++ b/SOURCES/0161-resolve-565245-multilib-issues-caused-by-doxygen.patch @@ -0,0 +1,39 @@ +From bc4cf1487b4d6039de2a082c1786ac83ab148c88 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 22 Jan 2013 15:14:21 -0800 +Subject: resolve 565245: multilib issues caused by doxygen + +--- + libiscsi/libiscsi.doxy | 2 +- + libiscsi/no_date_footer.html | 6 ++++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + create mode 100644 libiscsi/no_date_footer.html + +diff --git a/libiscsi/libiscsi.doxy b/libiscsi/libiscsi.doxy +index 663770f..7a5ff7f 100644 +--- a/libiscsi/libiscsi.doxy ++++ b/libiscsi/libiscsi.doxy +@@ -765,7 +765,7 @@ HTML_HEADER = + # each generated HTML page. If it is left blank doxygen will generate a + # standard footer. + +-HTML_FOOTER = ++HTML_FOOTER = no_date_footer.html + + # The HTML_STYLESHEET tag can be used to specify a user-defined cascading + # style sheet that is used by each HTML page. It can be used to +diff --git a/libiscsi/no_date_footer.html b/libiscsi/no_date_footer.html +new file mode 100644 +index 0000000..1e0c6c4 +--- /dev/null ++++ b/libiscsi/no_date_footer.html +@@ -0,0 +1,6 @@ ++
++Generated for $projectname by doxygen ++$doxygenversion
++ ++ +-- +1.7.11.7 + diff --git a/SOURCES/0162-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch b/SOURCES/0162-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch new file mode 100644 index 00000000..684463f3 --- /dev/null +++ b/SOURCES/0162-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch @@ -0,0 +1,30 @@ +From ab79bdb20e37216ca969e06d63a952acfd023963 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 28 May 2013 13:12:27 -0700 +Subject: [PATCH] Don't check for autostart sessions if iscsi is not used (bug + #951951) + +Change conditional startup in iscsi.service to check for a non-empty +nodes directory, instead of initiator-name. This fits better with what +it's doing, as there's no need to scan for autostart node records if +there are no node records at all. +--- + etc/systemd/iscsi.service | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index bbd52fd..7b4efee 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -5,7 +5,7 @@ DefaultDependencies=no + Conflicts=shutdown.target + After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service + Before=remote-fs-pre.target +-ConditionPathExists=/etc/iscsi/initiatorname.iscsi ++ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes + + [Service] + Type=oneshot +-- +1.8.1.4 + diff --git a/SOURCES/0164-libiscsi-fix-incorrect-strncpy-use.patch b/SOURCES/0164-libiscsi-fix-incorrect-strncpy-use.patch new file mode 100644 index 00000000..55d1166e --- /dev/null +++ b/SOURCES/0164-libiscsi-fix-incorrect-strncpy-use.patch @@ -0,0 +1,52 @@ +From fcad7de1a8c3d140d1d0eb120727966017d3727b Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Sat, 17 Aug 2013 15:50:45 -0700 +Subject: libiscsi: fix incorrect strncpy use + +Changes to internal structures make the src and dst buffers of some +copies (potentially) different sizes. Fix strncpy calls that were using +the size of the src argument as the limit. +--- + libiscsi/libiscsi.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c +index 6e6846a..064e4b5 100644 +--- a/libiscsi/libiscsi.c ++++ b/libiscsi/libiscsi.c +@@ -587,15 +587,13 @@ int libiscsi_get_firmware_network_config( + return ENODEV; + + config->dhcp = strlen(fw_entry.dhcp) ? 1 : 0; +- strncpy(config->iface_name, fw_entry.iface, sizeof fw_entry.iface); +- strncpy(config->mac_address, fw_entry.mac, sizeof fw_entry.mac); +- strncpy(config->ip_address, fw_entry.ipaddr, sizeof fw_entry.ipaddr); +- strncpy(config->netmask, fw_entry.mask, sizeof fw_entry.mask); +- strncpy(config->gateway, fw_entry.gateway, sizeof fw_entry.gateway); +- strncpy(config->primary_dns, fw_entry.primary_dns, +- sizeof fw_entry.primary_dns); +- strncpy(config->secondary_dns, fw_entry.secondary_dns, +- sizeof fw_entry.secondary_dns); ++ strlcpy(config->iface_name, fw_entry.iface, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->mac_address, fw_entry.mac, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->ip_address, fw_entry.ipaddr, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->netmask, fw_entry.mask, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->gateway, fw_entry.gateway, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->primary_dns, fw_entry.primary_dns, LIBISCSI_VALUE_MAXLEN); ++ strlcpy(config->secondary_dns, fw_entry.secondary_dns, LIBISCSI_VALUE_MAXLEN); + return 0; + } + +@@ -613,8 +611,7 @@ int libiscsi_get_firmware_initiator_name(char *initiatorname) + if (fw_get_entry(&fw_entry)) + return ENODEV; + +- strncpy(initiatorname, fw_entry.initiatorname, +- sizeof fw_entry.initiatorname); ++ strlcpy(initiatorname, fw_entry.initiatorname, LIBISCSI_VALUE_MAXLEN); + + return 0; + } +-- +1.8.1.4 + diff --git a/SOURCES/0166-start-socket-listeners-on-iscsiadm-command.patch b/SOURCES/0166-start-socket-listeners-on-iscsiadm-command.patch new file mode 100644 index 00000000..cb363b7f --- /dev/null +++ b/SOURCES/0166-start-socket-listeners-on-iscsiadm-command.patch @@ -0,0 +1,28 @@ +From 89e9c2ff66d069b812fabcd4fefe453bbcea73e4 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 25 Nov 2013 22:28:12 -0800 +Subject: [PATCH] start socket listeners on iscsiadm command + +fix for trying to run iscsiadm commands right after installing the rpm +without manually starting the systemd units +--- + etc/iscsid.conf | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/etc/iscsid.conf b/etc/iscsid.conf +index 1fd3000..412f130 100644 +--- a/etc/iscsid.conf ++++ b/etc/iscsid.conf +@@ -17,7 +17,8 @@ + # maintainers. + # + # Default for Fedora and RHEL. (uncomment to activate). +-#iscsid.startup = /bin/systemctl start iscsid.service ++# Use socket activation, but try to make sure the socket units are listening ++iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket + # + # Default for upstream open-iscsi scripts (uncomment to activate). + # iscsid.startup = /sbin/iscsid +-- +1.8.3.1 + diff --git a/SOURCES/0167-Revert-iscsiadm-return-error-when-login-fails.patch b/SOURCES/0167-Revert-iscsiadm-return-error-when-login-fails.patch new file mode 100644 index 00000000..64c9af85 --- /dev/null +++ b/SOURCES/0167-Revert-iscsiadm-return-error-when-login-fails.patch @@ -0,0 +1,35 @@ +From 1c0f37a8ae48daa3ae1c37cdac7c0789299180eb Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 24 Feb 2014 09:33:33 -0800 +Subject: [PATCH] Revert "iscsiadm: return error when login fails" + +This reverts commit fc2a8e9a2911bc76f961fe3e4a159fab9b8b9691. + +Done to address RHBZ #1015563 + +--- + usr/session_mgmt.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/usr/session_mgmt.c b/usr/session_mgmt.c +index 87b8e00..3815b1d 100644 +--- a/usr/session_mgmt.c ++++ b/usr/session_mgmt.c +@@ -178,12 +178,12 @@ int iscsi_login_portal(void *data, struct list_head *list, struct node_rec *rec) + goto done; + } + if (session_count >= rec->session.nr_sessions) { +- log_warning("%s: %d session%s requested, but %d " ++ log_debug(1, "%s: %d session%s requested, but %d " + "already present.", + rec->iface.name, rec->session.nr_sessions, + rec->session.nr_sessions == 1 ? "" : "s", + session_count); +- rc = ISCSI_ERR_SESS_EXISTS; ++ rc = 0; + goto done; + } + +-- +1.8.3.1 + diff --git a/SOURCES/0168-update-handling-of-boot-sessions.patch b/SOURCES/0168-update-handling-of-boot-sessions.patch new file mode 100644 index 00000000..9c638c16 --- /dev/null +++ b/SOURCES/0168-update-handling-of-boot-sessions.patch @@ -0,0 +1,55 @@ +From 83f291bd475f3d11abaf1f7346732f75af585ed8 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Wed, 26 Feb 2014 16:33:48 -0800 +Subject: update handling of boot sessions + +force start iscsiuio if needed, socket activation does not seem to be +working for recovery +--- + etc/systemd/iscsi-mark-root-nodes | 29 +++++++++++++++++++++++------ + 1 file changed, 23 insertions(+), 6 deletions(-) + +diff --git a/etc/systemd/iscsi-mark-root-nodes b/etc/systemd/iscsi-mark-root-nodes +index 157be62..d106ac6 100644 +--- a/etc/systemd/iscsi-mark-root-nodes ++++ b/etc/systemd/iscsi-mark-root-nodes +@@ -1,13 +1,30 @@ + #!/bin/bash + + ISCSIADM=/sbin/iscsiadm ++start_iscsid=0 ++start_iscsiuio=0 + +-$ISCSIADM -m session >/dev/null 2>&1 || exit 0 ++while read t num p target flash; do ++ # strip tag number from portal, keep "ip:port" ++ portal=${p%,*} ++ transport=${t%:} + +-$ISCSIADM -m session | while read t num i target; do +- ip=${i%:*} +- $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot +-done ++ $ISCSIADM -m node -p $portal -T $target -o update -n node.startup -v onboot + +-systemctl start iscsid.service ++ start_iscsid=1 ++ ++ if [ "$transport" = bnx2i ] || [ "$transport" = qedi ]; then ++ start_iscsiuio=1 ++ fi ++done < <( $ISCSIADM -m session ) ++ ++# force iscsid and iscsiuio to start if needed for ++# recovering sessions created in the initrd ++ ++if [ "$start_iscsid" -eq 1 ]; then ++ systemctl --no-block start iscsid.service ++fi ++if [ "$start_iscsiuio" -eq 1 ]; then ++ systemctl --no-block start iscsiuio.service ++fi + +-- +1.8.3.1 + diff --git a/SOURCES/0169-update-iscsi.service-for-boot-session-recovery.patch b/SOURCES/0169-update-iscsi.service-for-boot-session-recovery.patch new file mode 100644 index 00000000..f7a2f792 --- /dev/null +++ b/SOURCES/0169-update-iscsi.service-for-boot-session-recovery.patch @@ -0,0 +1,34 @@ +From 969e26197c792ec5377d2c261a934a9c907e82f0 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Fri, 14 Mar 2014 09:22:21 -0700 +Subject: [PATCH] update iscsi.service for boot session recovery + +--- + etc/systemd/iscsi.service | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index d5712bd..3de76c5 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -5,14 +5,15 @@ DefaultDependencies=no + Conflicts=shutdown.target + After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service + Before=remote-fs-pre.target +-ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes ++ConditionDirectoryNotEmpty=|/var/lib/iscsi/nodes ++ConditionDirectoryNotEmpty=|/sys/class/iscsi_session + + [Service] + Type=oneshot + RemainAfterExit=true + ExecStart=/usr/libexec/iscsi-mark-root-nodes ++SuccessExitStatus=21 + ExecStart=/sbin/iscsiadm -m node --loginall=automatic +-ExecStop=/bin/sync + ExecStop=/sbin/iscsiadm -m node --logoutall=automatic + ExecReload=/sbin/iscsiadm -m node --loginall=automatic + +-- +1.8.3.1 + diff --git a/SOURCES/0170-fix-systemd-unit-wants.patch b/SOURCES/0170-fix-systemd-unit-wants.patch new file mode 100644 index 00000000..45ce32a5 --- /dev/null +++ b/SOURCES/0170-fix-systemd-unit-wants.patch @@ -0,0 +1,41 @@ +From 347e6120213efda47a45443b4e366ed1400433c1 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Wed, 17 Sep 2014 09:58:39 -0700 +Subject: [PATCH] updates to iscsi.service + +Resolves: #1126524 +Resolves: #1111925 +--- + etc/systemd/iscsi.service | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index 3de76c5..ad7be34 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -5,17 +5,17 @@ DefaultDependencies=no + Conflicts=shutdown.target + After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service + Before=remote-fs-pre.target ++Wants=remote-fs-pre.target + ConditionDirectoryNotEmpty=|/var/lib/iscsi/nodes + ConditionDirectoryNotEmpty=|/sys/class/iscsi_session + + [Service] + Type=oneshot + RemainAfterExit=true +-ExecStart=/usr/libexec/iscsi-mark-root-nodes +-SuccessExitStatus=21 +-ExecStart=/sbin/iscsiadm -m node --loginall=automatic +-ExecStop=/sbin/iscsiadm -m node --logoutall=automatic +-ExecReload=/sbin/iscsiadm -m node --loginall=automatic ++ExecStart=-/usr/libexec/iscsi-mark-root-nodes ++ExecStart=-/sbin/iscsiadm -m node --loginall=automatic ++ExecStop=-/sbin/iscsiadm -m node --logoutall=automatic ++ExecReload=-/sbin/iscsiadm -m node --loginall=automatic + + [Install] + WantedBy=sysinit.target +-- +1.9.3 + diff --git a/SOURCES/0172-move-cleanup-to-seperate-service.patch b/SOURCES/0172-move-cleanup-to-seperate-service.patch new file mode 100644 index 00000000..f54de39b --- /dev/null +++ b/SOURCES/0172-move-cleanup-to-seperate-service.patch @@ -0,0 +1,56 @@ +From 56d9d1c6a02dcad0915c0673f9cd2e653c86302f Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Tue, 13 Jan 2015 16:30:01 -0800 +Subject: [PATCH] 0171-make-session-shutdown-a-seperate-service.patch + +--- + etc/systemd/iscsi-shutdown.service | 14 ++++++++++++++ + etc/systemd/iscsi.service | 3 +-- + 2 files changed, 15 insertions(+), 2 deletions(-) + create mode 100644 etc/systemd/iscsi-shutdown.service + +diff --git a/etc/systemd/iscsi-shutdown.service b/etc/systemd/iscsi-shutdown.service +new file mode 100644 +index 0000000..23758e9 +--- /dev/null ++++ b/etc/systemd/iscsi-shutdown.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Logout off all iSCSI sessions on shutdown ++Documentation=man:iscsid(8) man:iscsiadm(8) ++DefaultDependencies=no ++Conflicts=shutdown.target ++After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service ++Before=remote-fs-pre.target ++Wants=remote-fs-pre.target ++RefuseManualStop=yes ++ ++[Service] ++Type=oneshot ++RemainAfterExit=true ++ExecStart=-/bin/true ++ExecStop=-/sbin/iscsiadm -m node --logoutall=all +diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service +index ad7be34..2736956 100644 +--- a/etc/systemd/iscsi.service ++++ b/etc/systemd/iscsi.service +@@ -5,7 +5,7 @@ DefaultDependencies=no + Conflicts=shutdown.target + After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service + Before=remote-fs-pre.target +-Wants=remote-fs-pre.target ++Wants=remote-fs-pre.target iscsi-shutdown.service + ConditionDirectoryNotEmpty=|/var/lib/iscsi/nodes + ConditionDirectoryNotEmpty=|/sys/class/iscsi_session + +@@ -14,7 +14,6 @@ Type=oneshot + RemainAfterExit=true + ExecStart=-/usr/libexec/iscsi-mark-root-nodes + ExecStart=-/sbin/iscsiadm -m node --loginall=automatic +-ExecStop=-/sbin/iscsiadm -m node --logoutall=automatic + ExecReload=-/sbin/iscsiadm -m node --loginall=automatic + + [Install] +-- +2.1.0 + diff --git a/SOURCES/0199-use-Red-Hat-version-string-to-match-RPM-package-vers.patch b/SOURCES/0199-use-Red-Hat-version-string-to-match-RPM-package-vers.patch new file mode 100644 index 00000000..d45b83e9 --- /dev/null +++ b/SOURCES/0199-use-Red-Hat-version-string-to-match-RPM-package-vers.patch @@ -0,0 +1,25 @@ +From 8f7669c48198989eac5e08664133f56371ad963b Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 21 Jan 2013 15:43:36 -0800 +Subject: use Red Hat version string to match RPM package version + +--- + usr/version.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/usr/version.h b/usr/version.h +index 20f07946be1f..baa8c00c7185 100644 +--- a/usr/version.h ++++ b/usr/version.h +@@ -6,7 +6,7 @@ + * This may not be the same value as the kernel versions because + * some other maintainer could merge a patch without going through us + */ +-#define ISCSI_VERSION_STR "2.0-874" ++#define ISCSI_VERSION_STR "6.2.0.874-7" + #define ISCSI_VERSION_FILE "/sys/module/scsi_transport_iscsi/version" + + #endif +-- +2.9.3 + diff --git a/SOURCES/04-iscsi b/SOURCES/04-iscsi new file mode 100755 index 00000000..864ade79 --- /dev/null +++ b/SOURCES/04-iscsi @@ -0,0 +1,7 @@ +#!/bin/sh + +case "$2" in + up|vpn-up) + /bin/systemctl --no-block reload iscsi.service || : + ;; +esac diff --git a/SOURCES/be2iscsi-vlan.patch b/SOURCES/be2iscsi-vlan.patch new file mode 100644 index 00000000..7a48644f --- /dev/null +++ b/SOURCES/be2iscsi-vlan.patch @@ -0,0 +1,191 @@ +commit ea9c14d9ab10d1070a8d3c032e64bb946a279a02 +Author: Chris Leech +Date: Thu Nov 30 12:05:28 2017 -0800 + + vlan setting sync for be2iscsi + +diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c +index b30518a293db..f269fc406a13 100644 +--- a/usr/iscsiadm.c ++++ b/usr/iscsiadm.c +@@ -2311,6 +2311,89 @@ static int verify_iface_params(struct list_head *params, struct node_rec *rec) + return 0; + } + ++static int iface_param_update(struct iface_rec *iface, struct list_head *params) ++{ ++ struct node_rec *rec; ++ int rc = 0; ++ ++ rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 1); ++ if (!rec) { ++ rc = ISCSI_ERR_INVAL; ++ goto update_fail; ++ } ++ ++ if (iscsi_check_for_running_session(rec)) ++ log_warning("Updating iface while iscsi sessions " ++ "are using it. You must logout the running " ++ "sessions then log back in for the " ++ "new settings to take affect."); ++ ++ rc = verify_iface_params(params, rec); ++ if (rc) ++ goto update_fail; ++ ++ rc = iface_conf_update(params, &rec->iface); ++ if (rc) ++ goto update_fail; ++ ++ rc = __for_each_matched_rec(0, rec, params, idbm_node_set_param); ++ if (rc == ISCSI_ERR_NO_OBJS_FOUND) ++ rc = 0; ++ else if (rc) ++ goto update_fail; ++ ++ printf("%s updated.\n", iface->name); ++ free(rec); ++ return rc; ++ ++update_fail: ++ log_error("Could not update iface %s: %s", ++ iface->name, iscsi_err_to_str(rc)); ++ free(rec); ++ return rc; ++} ++ ++struct iface_param_sync { ++ struct iface_rec *primary; ++ struct list_head *params; ++ int count; ++}; ++ ++static int update_sync_params(void *data, struct iface_rec *iface) ++{ ++ struct iface_param_sync *iface_params = data; ++ struct iface_rec *primary = iface_params->primary; ++ struct list_head *params = iface_params->params; ++ ++ if ((strcmp(primary->transport_name, iface->transport_name)) || ++ (strcmp(primary->hwaddress, iface->hwaddress)) || ++ (primary->iface_num != iface->iface_num)) ++ return 0; ++ ++ return iface_param_update(iface, params); ++} ++ ++static int split_vlan_params(struct list_head *params, struct list_head *vlan_params) ++{ ++ struct user_param *param, *tmp; ++ ++ list_for_each_entry_safe(param, tmp, params, list) { ++ if (!strncmp(param->name, "iface.vlan", 10)) { ++ list_move_tail(¶m->list, vlan_params); ++ } ++ } ++ return 0; ++} ++ ++static inline void list_splice_tail(struct list_head *list, struct list_head *head) ++{ ++ list->prev->next = head; ++ list->next->prev = head->prev; ++ head->prev->next = list->next; ++ head->prev = list->prev; ++ INIT_LIST_HEAD(list); ++} ++ + /* TODO: merge iter helpers and clean them up, so we can use them here */ + static int exec_iface_op(int op, int do_show, int info_level, + struct iface_rec *iface, uint64_t host_no, +@@ -2319,6 +2402,8 @@ static int exec_iface_op(int op, int do_show, int info_level, + struct host_info hinfo; + struct node_rec *rec = NULL; + int rc = 0; ++ LIST_HEAD(vlan_params); ++ struct iscsi_transport *t; + + switch (op) { + case OP_NEW: +@@ -2381,36 +2466,27 @@ delete_fail: + rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 1); + if (!rec) { + rc = ISCSI_ERR_INVAL; +- goto update_fail; ++ break; + } +- +- if (iscsi_check_for_running_session(rec)) +- log_warning("Updating iface while iscsi sessions " +- "are using it. You must logout the running " +- "sessions then log back in for the " +- "new settings to take affect."); +- +- rc = verify_iface_params(params, rec); +- if (rc) ++ t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name); ++ if (!t) { ++ log_error("Cound not locate transport for iface %s", iface->name); ++ rc = ISCSI_ERR_INVAL; + break; +- +- /* pass rec's iface because it has the db values */ +- rc = iface_conf_update(params, &rec->iface); +- if (rc) +- goto update_fail; +- +- rc = __for_each_matched_rec(0, rec, params, +- idbm_node_set_param); +- if (rc == ISCSI_ERR_NO_OBJS_FOUND) +- rc = 0; +- else if (rc) +- goto update_fail; +- +- printf("%s updated.\n", iface->name); +- break; +-update_fail: +- log_error("Could not update iface %s: %s", +- iface->name, iscsi_err_to_str(rc)); ++ } ++ if (t->template->sync_vlan_settings) { ++ /* sync shared vlan settings across ifaces */ ++ int nr_found = 0; ++ struct iface_param_sync sync_params = { ++ .primary = &rec->iface, ++ .params = &vlan_params, ++ .count = 0, ++ }; ++ split_vlan_params(params, &vlan_params); ++ iface_for_each_iface(&sync_params, 1, &nr_found, update_sync_params); ++ } ++ iface_param_update(&rec->iface, params); ++ list_splice_tail(&vlan_params, params); + break; + case OP_APPLY: + if (!iface) { +diff --git a/usr/transport.c b/usr/transport.c +index 3b7a00a2245e..35a8ccd4a400 100644 +--- a/usr/transport.c ++++ b/usr/transport.c +@@ -91,6 +91,7 @@ struct iscsi_transport_template bnx2i = { + struct iscsi_transport_template be2iscsi = { + .name = "be2iscsi", + .bind_ep_required = 1, ++ .sync_vlan_settings = 1, + .create_conn = be2iscsi_create_conn, + .ep_connect = ktransport_ep_connect, + .ep_poll = ktransport_ep_poll, +diff --git a/usr/transport.h b/usr/transport.h +index b67776b47288..07027564e46b 100644 +--- a/usr/transport.h ++++ b/usr/transport.h +@@ -40,6 +40,9 @@ struct iscsi_transport_template { + uint8_t use_boot_info; + uint8_t bind_ep_required; + uint8_t no_netdev; ++ /* be2iscsi has a single host vlan setting, ++ * but uses 2 ifaces for ipv4 and ipv6 settings; keep them in sync */ ++ uint8_t sync_vlan_settings; + int (*ep_connect) (struct iscsi_conn *conn, int non_blocking); + int (*ep_poll) (struct iscsi_conn *conn, int timeout_ms); + void (*ep_disconnect) (struct iscsi_conn *conn); diff --git a/SOURCES/iscsi-tmpfiles.conf b/SOURCES/iscsi-tmpfiles.conf new file mode 100644 index 00000000..eab4fb21 --- /dev/null +++ b/SOURCES/iscsi-tmpfiles.conf @@ -0,0 +1,2 @@ +d /run/lock/iscsi 0700 root root - +f /run/lock/iscsi/lock 0600 root root - diff --git a/SOURCES/keep-open-isns.patch b/SOURCES/keep-open-isns.patch new file mode 100644 index 00000000..b8b700eb --- /dev/null +++ b/SOURCES/keep-open-isns.patch @@ -0,0 +1,45649 @@ +From 791c2f1d7ada4e1eb2215164db3a8343005e30c2 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Mon, 13 Jun 2016 16:11:01 -0700 +Subject: [PATCH] keep-open-isns.patch + +--- + Makefile | 12 +- + README | 14 - + usr/Makefile | 7 +- + usr/discovery.c | 6 +- + usr/discoveryd.c | 8 +- + usr/iscsiadm.c | 2 +- + utils/open-isns/COPYING | 504 ++ + utils/open-isns/ChangeLog | 50 + + utils/open-isns/HACKING | 30 + + utils/open-isns/Makefile.in | 81 + + utils/open-isns/README | 173 + + utils/open-isns/TODO | 100 + + utils/open-isns/aclocal/config.guess | 1499 +++++ + utils/open-isns/aclocal/config.sub | 1570 +++++ + utils/open-isns/aclocal/install-sh | 251 + + utils/open-isns/attrs.c | 1618 +++++ + utils/open-isns/attrs.h | 262 + + utils/open-isns/authblock.c | 62 + + utils/open-isns/bitvector.c | 648 ++ + utils/open-isns/buffer.c | 407 ++ + utils/open-isns/buffer.h | 141 + + utils/open-isns/callback.c | 148 + + utils/open-isns/client.c | 205 + + utils/open-isns/compat/my_getopt.c | 271 + + utils/open-isns/compat/my_getopt.h | 69 + + utils/open-isns/config.c | 278 + + utils/open-isns/config.h.in | 103 + + utils/open-isns/configure | 6727 ++++++++++++++++++++ + utils/open-isns/configure.ac | 118 + + utils/open-isns/db-file.c | 615 ++ + utils/open-isns/db-policy.c | 187 + + utils/open-isns/db.c | 994 +++ + utils/open-isns/db.h | 147 + + utils/open-isns/dd.c | 1306 ++++ + utils/open-isns/deregister.c | 271 + + utils/open-isns/doc/isns_config.5 | 387 ++ + utils/open-isns/doc/isnsadm.8 | 688 ++ + utils/open-isns/doc/isnsd.8 | 93 + + utils/open-isns/doc/isnsdd.8 | 75 + + utils/open-isns/domain.c | 208 + + utils/open-isns/entity.c | 127 + + utils/open-isns/error.c | 65 + + utils/open-isns/esi.c | 576 ++ + utils/open-isns/etc/isnsadm.conf | 73 + + utils/open-isns/etc/isnsd.conf | 129 + + utils/open-isns/etc/isnsdd.conf | 72 + + utils/open-isns/etc/openisns.init | 71 + + utils/open-isns/export.c | 547 ++ + utils/open-isns/getnext.c | 257 + + utils/open-isns/internal.h | 16 + + utils/open-isns/isns-proto.h | 259 + + utils/open-isns/isns.h | 673 ++ + utils/open-isns/isnsadm.c | 1151 ++++ + utils/open-isns/isnsd.c | 299 + + utils/open-isns/isnsdd.c | 1153 ++++ + utils/open-isns/isnssetup | 52 + + utils/open-isns/local.c | 353 + + utils/open-isns/logging.c | 228 + + utils/open-isns/mdebug.c | 295 + + utils/open-isns/message.c | 681 ++ + utils/open-isns/message.h | 196 + + utils/open-isns/objects.c | 1320 ++++ + utils/open-isns/objects.h | 168 + + utils/open-isns/parser.c | 134 + + utils/open-isns/paths.h | 22 + + utils/open-isns/pidfile.c | 98 + + utils/open-isns/pki.c | 536 ++ + utils/open-isns/policy.c | 577 ++ + utils/open-isns/portal-group.c | 307 + + utils/open-isns/query.c | 238 + + utils/open-isns/register.c | 934 +++ + utils/open-isns/relation.c | 281 + + utils/open-isns/scn.c | 926 +++ + utils/open-isns/scope.c | 513 ++ + utils/open-isns/security.c | 437 ++ + utils/open-isns/security.h | 185 + + utils/open-isns/server.c | 236 + + utils/open-isns/simple.c | 727 +++ + utils/open-isns/slp.c | 242 + + utils/open-isns/socket.c | 2304 +++++++ + utils/open-isns/socket.h | 95 + + utils/open-isns/source.h | 32 + + utils/open-isns/storage-node.c | 202 + + utils/open-isns/sysdep-unix.c | 186 + + utils/open-isns/tags.c | 740 +++ + utils/open-isns/tests/.cvsignore | 2 + + utils/open-isns/tests/Makefile | 40 + + utils/open-isns/tests/client.conf | 8 + + utils/open-isns/tests/data/test01/01-enroll | 18 + + utils/open-isns/tests/data/test01/02-registration | 42 + + utils/open-isns/tests/data/test01/03-query | 20 + + utils/open-isns/tests/data/test01/03-registration | 20 + + .../open-isns/tests/data/test01/99-unregistration | 18 + + utils/open-isns/tests/data/test02/01-enroll | 18 + + utils/open-isns/tests/data/test02/02-enroll | 24 + + utils/open-isns/tests/data/test02/03-registration | 72 + + utils/open-isns/tests/data/test02/04-query | 20 + + utils/open-isns/tests/data/test02/05-query | 20 + + .../open-isns/tests/data/test02/06-dd-registration | 81 + + utils/open-isns/tests/data/test02/07-query | 40 + + utils/open-isns/tests/data/test02/08-query | 40 + + utils/open-isns/tests/data/test02/09-query | 20 + + .../open-isns/tests/data/test02/10-dd-registration | 87 + + utils/open-isns/tests/data/test02/11-query | 10 + + .../tests/data/test02/12-dd-deregistration | 85 + + .../tests/data/test02/13-dd-deregistration | 83 + + .../open-isns/tests/data/test02/14-dd-registration | 85 + + .../tests/data/test02/15-dd-deregistration | 76 + + utils/open-isns/tests/data/test03/01-enroll | 18 + + utils/open-isns/tests/data/test03/02-registration | 42 + + .../open-isns/tests/data/test03/03-unregistration | 42 + + .../open-isns/tests/data/test03/04-unregistration | 18 + + .../open-isns/tests/data/test03/99-unregistration | 13 + + utils/open-isns/tests/data/test04/01-enroll | 18 + + utils/open-isns/tests/data/test04/02-registration | 42 + + utils/open-isns/tests/data/test04/03-restart | 42 + + utils/open-isns/tests/data/test04/04-query | 20 + + utils/open-isns/tests/data/test05/01-enroll | 18 + + utils/open-isns/tests/data/test05/02-registration | 42 + + utils/open-isns/tests/data/test05/03-expired | 18 + + utils/open-isns/tests/data/test06/01-enroll | 18 + + utils/open-isns/tests/data/test06/02-registration | 42 + + utils/open-isns/tests/data/test06/03-registration | 42 + + utils/open-isns/tests/data/test06/04-registration | 42 + + .../open-isns/tests/data/test06/05-dd-registration | 49 + + utils/open-isns/tests/data/test06/06-registration | 49 + + .../open-isns/tests/data/test06/07-dd-registration | 52 + + utils/open-isns/tests/data/test06/08-registration | 64 + + utils/open-isns/tests/data/test06/09-registration | 64 + + .../open-isns/tests/data/test06/10-unregistration | 37 + + utils/open-isns/tests/data/test06/11-registration | 52 + + utils/open-isns/tests/data/test07/01-enroll | 19 + + utils/open-isns/tests/data/test07/02-registration | 45 + + utils/open-isns/tests/data/test07/03-expired | 19 + + utils/open-isns/tests/data/test07/04-registration | 57 + + utils/open-isns/tests/data/test07/05-expired | 19 + + utils/open-isns/tests/data/test08/01-pauw1 | 100 + + utils/open-isns/tests/data/test09/01-pauw2 | 31 + + utils/open-isns/tests/data/test10/01-pauw3 | 31 + + utils/open-isns/tests/data/test10/02-expired | 31 + + utils/open-isns/tests/data/test10/03-pauw3 | 31 + + utils/open-isns/tests/data/test10/04-expired | 31 + + utils/open-isns/tests/data/test11/01-pauw4 | 32 + + utils/open-isns/tests/genkey | 175 + + utils/open-isns/tests/harness.pl | 929 +++ + utils/open-isns/tests/pauw1.c | 179 + + utils/open-isns/tests/pauw2.c | 212 + + utils/open-isns/tests/pauw3.c | 139 + + utils/open-isns/tests/pauw4.c | 137 + + utils/open-isns/tests/server.conf | 11 + + utils/open-isns/tests/test01.pl | 30 + + utils/open-isns/tests/test02.pl | 58 + + utils/open-isns/tests/test03.pl | 27 + + utils/open-isns/tests/test04.pl | 30 + + utils/open-isns/tests/test05.pl | 25 + + utils/open-isns/tests/test06.pl | 50 + + utils/open-isns/tests/test07.pl | 37 + + utils/open-isns/tests/test08.pl | 23 + + utils/open-isns/tests/test09.pl | 23 + + utils/open-isns/tests/test10.pl | 33 + + utils/open-isns/tests/test11.pl | 23 + + utils/open-isns/timer.c | 126 + + utils/open-isns/types.h | 57 + + utils/open-isns/util.c | 263 + + utils/open-isns/util.h | 289 + + utils/open-isns/vendor.c | 41 + + utils/open-isns/vendor.h | 56 + + 167 files changed, 44212 insertions(+), 28 deletions(-) + create mode 100644 utils/open-isns/COPYING + create mode 100644 utils/open-isns/ChangeLog + create mode 100644 utils/open-isns/HACKING + create mode 100644 utils/open-isns/Makefile.in + create mode 100644 utils/open-isns/README + create mode 100644 utils/open-isns/TODO + create mode 100644 utils/open-isns/aclocal/config.guess + create mode 100644 utils/open-isns/aclocal/config.sub + create mode 100644 utils/open-isns/aclocal/install-sh + create mode 100644 utils/open-isns/attrs.c + create mode 100644 utils/open-isns/attrs.h + create mode 100644 utils/open-isns/authblock.c + create mode 100644 utils/open-isns/bitvector.c + create mode 100644 utils/open-isns/buffer.c + create mode 100644 utils/open-isns/buffer.h + create mode 100644 utils/open-isns/callback.c + create mode 100644 utils/open-isns/client.c + create mode 100644 utils/open-isns/compat/my_getopt.c + create mode 100644 utils/open-isns/compat/my_getopt.h + create mode 100644 utils/open-isns/config.c + create mode 100644 utils/open-isns/config.h.in + create mode 100755 utils/open-isns/configure + create mode 100644 utils/open-isns/configure.ac + create mode 100644 utils/open-isns/db-file.c + create mode 100644 utils/open-isns/db-policy.c + create mode 100644 utils/open-isns/db.c + create mode 100644 utils/open-isns/db.h + create mode 100644 utils/open-isns/dd.c + create mode 100644 utils/open-isns/deregister.c + create mode 100644 utils/open-isns/doc/isns_config.5 + create mode 100644 utils/open-isns/doc/isnsadm.8 + create mode 100644 utils/open-isns/doc/isnsd.8 + create mode 100644 utils/open-isns/doc/isnsdd.8 + create mode 100644 utils/open-isns/domain.c + create mode 100644 utils/open-isns/entity.c + create mode 100644 utils/open-isns/error.c + create mode 100644 utils/open-isns/esi.c + create mode 100644 utils/open-isns/etc/isnsadm.conf + create mode 100644 utils/open-isns/etc/isnsd.conf + create mode 100644 utils/open-isns/etc/isnsdd.conf + create mode 100644 utils/open-isns/etc/openisns.init + create mode 100644 utils/open-isns/export.c + create mode 100644 utils/open-isns/getnext.c + create mode 100644 utils/open-isns/internal.h + create mode 100644 utils/open-isns/isns-proto.h + create mode 100644 utils/open-isns/isns.h + create mode 100644 utils/open-isns/isnsadm.c + create mode 100644 utils/open-isns/isnsd.c + create mode 100644 utils/open-isns/isnsdd.c + create mode 100644 utils/open-isns/isnssetup + create mode 100644 utils/open-isns/local.c + create mode 100644 utils/open-isns/logging.c + create mode 100644 utils/open-isns/mdebug.c + create mode 100644 utils/open-isns/message.c + create mode 100644 utils/open-isns/message.h + create mode 100644 utils/open-isns/objects.c + create mode 100644 utils/open-isns/objects.h + create mode 100644 utils/open-isns/parser.c + create mode 100644 utils/open-isns/paths.h + create mode 100644 utils/open-isns/pidfile.c + create mode 100644 utils/open-isns/pki.c + create mode 100644 utils/open-isns/policy.c + create mode 100644 utils/open-isns/portal-group.c + create mode 100644 utils/open-isns/query.c + create mode 100644 utils/open-isns/register.c + create mode 100644 utils/open-isns/relation.c + create mode 100644 utils/open-isns/scn.c + create mode 100644 utils/open-isns/scope.c + create mode 100644 utils/open-isns/security.c + create mode 100644 utils/open-isns/security.h + create mode 100644 utils/open-isns/server.c + create mode 100644 utils/open-isns/simple.c + create mode 100644 utils/open-isns/slp.c + create mode 100644 utils/open-isns/socket.c + create mode 100644 utils/open-isns/socket.h + create mode 100644 utils/open-isns/source.h + create mode 100644 utils/open-isns/storage-node.c + create mode 100644 utils/open-isns/sysdep-unix.c + create mode 100644 utils/open-isns/tags.c + create mode 100644 utils/open-isns/tests/.cvsignore + create mode 100644 utils/open-isns/tests/Makefile + create mode 100644 utils/open-isns/tests/client.conf + create mode 100644 utils/open-isns/tests/data/test01/01-enroll + create mode 100644 utils/open-isns/tests/data/test01/02-registration + create mode 100644 utils/open-isns/tests/data/test01/03-query + create mode 100644 utils/open-isns/tests/data/test01/03-registration + create mode 100644 utils/open-isns/tests/data/test01/99-unregistration + create mode 100644 utils/open-isns/tests/data/test02/01-enroll + create mode 100644 utils/open-isns/tests/data/test02/02-enroll + create mode 100644 utils/open-isns/tests/data/test02/03-registration + create mode 100644 utils/open-isns/tests/data/test02/04-query + create mode 100644 utils/open-isns/tests/data/test02/05-query + create mode 100644 utils/open-isns/tests/data/test02/06-dd-registration + create mode 100644 utils/open-isns/tests/data/test02/07-query + create mode 100644 utils/open-isns/tests/data/test02/08-query + create mode 100644 utils/open-isns/tests/data/test02/09-query + create mode 100644 utils/open-isns/tests/data/test02/10-dd-registration + create mode 100644 utils/open-isns/tests/data/test02/11-query + create mode 100644 utils/open-isns/tests/data/test02/12-dd-deregistration + create mode 100644 utils/open-isns/tests/data/test02/13-dd-deregistration + create mode 100644 utils/open-isns/tests/data/test02/14-dd-registration + create mode 100644 utils/open-isns/tests/data/test02/15-dd-deregistration + create mode 100644 utils/open-isns/tests/data/test03/01-enroll + create mode 100644 utils/open-isns/tests/data/test03/02-registration + create mode 100644 utils/open-isns/tests/data/test03/03-unregistration + create mode 100644 utils/open-isns/tests/data/test03/04-unregistration + create mode 100644 utils/open-isns/tests/data/test03/99-unregistration + create mode 100644 utils/open-isns/tests/data/test04/01-enroll + create mode 100644 utils/open-isns/tests/data/test04/02-registration + create mode 100644 utils/open-isns/tests/data/test04/03-restart + create mode 100644 utils/open-isns/tests/data/test04/04-query + create mode 100644 utils/open-isns/tests/data/test05/01-enroll + create mode 100644 utils/open-isns/tests/data/test05/02-registration + create mode 100644 utils/open-isns/tests/data/test05/03-expired + create mode 100644 utils/open-isns/tests/data/test06/01-enroll + create mode 100644 utils/open-isns/tests/data/test06/02-registration + create mode 100644 utils/open-isns/tests/data/test06/03-registration + create mode 100644 utils/open-isns/tests/data/test06/04-registration + create mode 100644 utils/open-isns/tests/data/test06/05-dd-registration + create mode 100644 utils/open-isns/tests/data/test06/06-registration + create mode 100644 utils/open-isns/tests/data/test06/07-dd-registration + create mode 100644 utils/open-isns/tests/data/test06/08-registration + create mode 100644 utils/open-isns/tests/data/test06/09-registration + create mode 100644 utils/open-isns/tests/data/test06/10-unregistration + create mode 100644 utils/open-isns/tests/data/test06/11-registration + create mode 100644 utils/open-isns/tests/data/test07/01-enroll + create mode 100644 utils/open-isns/tests/data/test07/02-registration + create mode 100644 utils/open-isns/tests/data/test07/03-expired + create mode 100644 utils/open-isns/tests/data/test07/04-registration + create mode 100644 utils/open-isns/tests/data/test07/05-expired + create mode 100644 utils/open-isns/tests/data/test08/01-pauw1 + create mode 100644 utils/open-isns/tests/data/test09/01-pauw2 + create mode 100644 utils/open-isns/tests/data/test10/01-pauw3 + create mode 100644 utils/open-isns/tests/data/test10/02-expired + create mode 100644 utils/open-isns/tests/data/test10/03-pauw3 + create mode 100644 utils/open-isns/tests/data/test10/04-expired + create mode 100644 utils/open-isns/tests/data/test11/01-pauw4 + create mode 100644 utils/open-isns/tests/genkey + create mode 100644 utils/open-isns/tests/harness.pl + create mode 100644 utils/open-isns/tests/pauw1.c + create mode 100644 utils/open-isns/tests/pauw2.c + create mode 100644 utils/open-isns/tests/pauw3.c + create mode 100644 utils/open-isns/tests/pauw4.c + create mode 100644 utils/open-isns/tests/server.conf + create mode 100644 utils/open-isns/tests/test01.pl + create mode 100644 utils/open-isns/tests/test02.pl + create mode 100644 utils/open-isns/tests/test03.pl + create mode 100644 utils/open-isns/tests/test04.pl + create mode 100644 utils/open-isns/tests/test05.pl + create mode 100644 utils/open-isns/tests/test06.pl + create mode 100644 utils/open-isns/tests/test07.pl + create mode 100644 utils/open-isns/tests/test08.pl + create mode 100644 utils/open-isns/tests/test09.pl + create mode 100644 utils/open-isns/tests/test10.pl + create mode 100644 utils/open-isns/tests/test11.pl + create mode 100644 utils/open-isns/timer.c + create mode 100644 utils/open-isns/types.h + create mode 100644 utils/open-isns/util.c + create mode 100644 utils/open-isns/util.h + create mode 100644 utils/open-isns/vendor.c + create mode 100644 utils/open-isns/vendor.h + +diff --git a/Makefile b/Makefile +index cf028cf..03175a3 100644 +--- a/Makefile ++++ b/Makefile +@@ -7,7 +7,7 @@ + DESTDIR ?= + + prefix = /usr +-exec_prefix = / ++exec_prefix = /usr + sbindir = $(exec_prefix)/sbin + bindir = $(exec_prefix)/bin + mandir = $(prefix)/share/man +@@ -25,7 +25,7 @@ ifdef OPTFLAGS + CFLAGS = $(OPTFLAGS) + endif + +-# Export it so configure of iscsiuio will ++# Export it so configure of iscsiuio & open-isns will + # pick it up. + ifneq (,$(CFLAGS)) + export CFLAGS +@@ -37,7 +37,8 @@ endif + + all: user + +-user: iscsiuio/Makefile ++user: utils/open-isns/Makefile iscsiuio/Makefile ++ $(MAKE) -C utils/open-isns + $(MAKE) -C utils/sysdeps + $(MAKE) -C utils/fwparam_ibft + $(MAKE) -C usr +@@ -54,6 +55,9 @@ user: iscsiuio/Makefile + @echo + @echo "Read README file for detailed information." + ++utils/open-isns/Makefile: utils/open-isns/configure utils/open-isns/Makefile.in ++ cd utils/open-isns; ./configure --with-security=no ++ + iscsiuio/Makefile: iscsiuio/configure iscsiuio/Makefile.in + cd iscsiuio; ./configure + +@@ -80,6 +84,8 @@ clean: + $(MAKE) -C kernel clean + [ ! -f iscsiuio/Makefile ] || $(MAKE) -C iscsiuio clean + [ ! -f iscsiuio/Makefile ] || $(MAKE) -C iscsiuio distclean ++ [ ! -f utils/open-isns/Makefile ] || $(MAKE) -C utils/open-isns clean ++ [ ! -f utils/open-isns/Makefile ] || $(MAKE) -C utils/open-isns distclean + + # this is for safety + # now -jXXX will still be safe +diff --git a/README b/README +index cfc7f2f..c4fc3cf 100644 +--- a/README ++++ b/README +@@ -74,20 +74,6 @@ the cache sync command will fail. + - iscsiadm's -P 3 option will not print out scsi devices. + - iscsid will not automatically online devices. + +-The userspace components: iscsid, iscsiadm and iscsistart require the +-open-isns library which can be found here: +- +-https://github.com/gonzoleeman/open-isns/releases +- +-To install the open-isns headers and library required for open-iscsi download +-the current release and run: +- +- ./configure +- make +- make install +- make install_hdrs +- make install_lib +- + By default the kernel's iSCSI modules will be used. Running: + + make +diff --git a/usr/Makefile b/usr/Makefile +index 6d3ce2e..865d001 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -30,7 +30,8 @@ endif + + CFLAGS ?= -O2 -g + WARNFLAGS ?= -Wall -Wstrict-prototypes +-CFLAGS += $(WARNFLAGS) -I../include -I. -D$(OSNAME) $(IPC_CFLAGS) -DISNS_ENABLE ++CFLAGS += $(WARNFLAGS) -I../include -I. -I../utils/open-isns \ ++ -D$(OSNAME) $(IPC_CFLAGS) -DISNS_ENABLE + PROGRAMS = iscsid iscsiadm iscsistart + + # libc compat files +@@ -54,10 +55,10 @@ all: $(PROGRAMS) + + iscsid: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(DISCOVERY_SRCS) \ + iscsid.o session_mgmt.o discoveryd.o mntcheck.o +- $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lisns -lcrypto -lrt -lmount ++ $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lrt -lmount + + iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o mntcheck.o +- $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lisns -lcrypto -lmount ++ $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lmount + + iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \ + iscsistart.o statics.o +diff --git a/usr/discovery.c b/usr/discovery.c +index de8267f..de8e81e 100644 +--- a/usr/discovery.c ++++ b/usr/discovery.c +@@ -52,9 +52,9 @@ + #include "iscsi_err.h" + #ifdef ISNS_ENABLE + /* libisns includes */ +-#include +-#include +-#include ++#include "isns.h" ++#include "paths.h" ++#include "message.h" + #endif + + #ifdef SLP_ENABLE +diff --git a/usr/discoveryd.c b/usr/discoveryd.c +index f5359c7..1e14977 100644 +--- a/usr/discoveryd.c ++++ b/usr/discoveryd.c +@@ -40,11 +40,11 @@ + #include "iface.h" + #include "session_mgmt.h" + #include "session_info.h" ++#include "isns-proto.h" ++#include "isns.h" ++#include "paths.h" ++#include "message.h" + #include "iscsi_err.h" +-#include +-#include +-#include +-#include + + #define DISC_DEF_POLL_INVL 30 + +diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c +index fc0c8bc..b916f51 100644 +--- a/usr/iscsiadm.c ++++ b/usr/iscsiadm.c +@@ -49,7 +49,7 @@ + #include "idbm_fields.h" + #include "session_mgmt.h" + #include "iscsid_req.h" +-#include ++#include "isns-proto.h" + #include "iscsi_err.h" + #include "iscsi_ipc.h" + #include "iscsi_timer.h" +diff --git a/utils/open-isns/COPYING b/utils/open-isns/COPYING +new file mode 100644 +index 0000000..b1e3f5a +--- /dev/null ++++ b/utils/open-isns/COPYING +@@ -0,0 +1,504 @@ ++ GNU LESSER GENERAL PUBLIC LICENSE ++ Version 2.1, February 1999 ++ ++ Copyright (C) 1991, 1999 Free Software Foundation, Inc. ++ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++[This is the first released version of the Lesser GPL. It also counts ++ as the successor of the GNU Library Public License, version 2, hence ++ the version number 2.1.] ++ ++ Preamble ++ ++ The licenses for most software are designed to take away your ++freedom to share and change it. By contrast, the GNU General Public ++Licenses are intended to guarantee your freedom to share and change ++free software--to make sure the software is free for all its users. ++ ++ This license, the Lesser General Public License, applies to some ++specially designated software packages--typically libraries--of the ++Free Software Foundation and other authors who decide to use it. You ++can use it too, but we suggest you first think carefully about whether ++this license or the ordinary General Public License is the better ++strategy to use in any particular case, based on the explanations below. ++ ++ When we speak of free software, we are referring to freedom of use, ++not price. Our General Public Licenses are designed to make sure that ++you have the freedom to distribute copies of free software (and charge ++for this service if you wish); that you receive source code or can get ++it if you want it; that you can change the software and use pieces of ++it in new free programs; and that you are informed that you can do ++these things. ++ ++ To protect your rights, we need to make restrictions that forbid ++distributors to deny you these rights or to ask you to surrender these ++rights. These restrictions translate to certain responsibilities for ++you if you distribute copies of the library or if you modify it. ++ ++ For example, if you distribute copies of the library, whether gratis ++or for a fee, you must give the recipients all the rights that we gave ++you. You must make sure that they, too, receive or can get the source ++code. If you link other code with the library, you must provide ++complete object files to the recipients, so that they can relink them ++with the library after making changes to the library and recompiling ++it. And you must show them these terms so they know their rights. ++ ++ We protect your rights with a two-step method: (1) we copyright the ++library, and (2) we offer you this license, which gives you legal ++permission to copy, distribute and/or modify the library. ++ ++ To protect each distributor, we want to make it very clear that ++there is no warranty for the free library. Also, if the library is ++modified by someone else and passed on, the recipients should know ++that what they have is not the original version, so that the original ++author's reputation will not be affected by problems that might be ++introduced by others. ++ ++ Finally, software patents pose a constant threat to the existence of ++any free program. We wish to make sure that a company cannot ++effectively restrict the users of a free program by obtaining a ++restrictive license from a patent holder. Therefore, we insist that ++any patent license obtained for a version of the library must be ++consistent with the full freedom of use specified in this license. ++ ++ Most GNU software, including some libraries, is covered by the ++ordinary GNU General Public License. This license, the GNU Lesser ++General Public License, applies to certain designated libraries, and ++is quite different from the ordinary General Public License. We use ++this license for certain libraries in order to permit linking those ++libraries into non-free programs. ++ ++ When a program is linked with a library, whether statically or using ++a shared library, the combination of the two is legally speaking a ++combined work, a derivative of the original library. The ordinary ++General Public License therefore permits such linking only if the ++entire combination fits its criteria of freedom. The Lesser General ++Public License permits more lax criteria for linking other code with ++the library. ++ ++ We call this license the "Lesser" General Public License because it ++does Less to protect the user's freedom than the ordinary General ++Public License. It also provides other free software developers Less ++of an advantage over competing non-free programs. These disadvantages ++are the reason we use the ordinary General Public License for many ++libraries. However, the Lesser license provides advantages in certain ++special circumstances. ++ ++ For example, on rare occasions, there may be a special need to ++encourage the widest possible use of a certain library, so that it becomes ++a de-facto standard. To achieve this, non-free programs must be ++allowed to use the library. A more frequent case is that a free ++library does the same job as widely used non-free libraries. In this ++case, there is little to gain by limiting the free library to free ++software only, so we use the Lesser General Public License. ++ ++ In other cases, permission to use a particular library in non-free ++programs enables a greater number of people to use a large body of ++free software. For example, permission to use the GNU C Library in ++non-free programs enables many more people to use the whole GNU ++operating system, as well as its variant, the GNU/Linux operating ++system. ++ ++ Although the Lesser General Public License is Less protective of the ++users' freedom, it does ensure that the user of a program that is ++linked with the Library has the freedom and the wherewithal to run ++that program using a modified version of the Library. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. Pay close attention to the difference between a ++"work based on the library" and a "work that uses the library". The ++former contains code derived from the library, whereas the latter must ++be combined with the library in order to run. ++ ++ GNU LESSER GENERAL PUBLIC LICENSE ++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++ 0. This License Agreement applies to any software library or other ++program which contains a notice placed by the copyright holder or ++other authorized party saying it may be distributed under the terms of ++this Lesser General Public License (also called "this License"). ++Each licensee is addressed as "you". ++ ++ A "library" means a collection of software functions and/or data ++prepared so as to be conveniently linked with application programs ++(which use some of those functions and data) to form executables. ++ ++ The "Library", below, refers to any such software library or work ++which has been distributed under these terms. A "work based on the ++Library" means either the Library or any derivative work under ++copyright law: that is to say, a work containing the Library or a ++portion of it, either verbatim or with modifications and/or translated ++straightforwardly into another language. (Hereinafter, translation is ++included without limitation in the term "modification".) ++ ++ "Source code" for a work means the preferred form of the work for ++making modifications to it. For a library, complete source code means ++all the source code for all modules it contains, plus any associated ++interface definition files, plus the scripts used to control compilation ++and installation of the library. ++ ++ Activities other than copying, distribution and modification are not ++covered by this License; they are outside its scope. The act of ++running a program using the Library is not restricted, and output from ++such a program is covered only if its contents constitute a work based ++on the Library (independent of the use of the Library in a tool for ++writing it). Whether that is true depends on what the Library does ++and what the program that uses the Library does. ++ ++ 1. You may copy and distribute verbatim copies of the Library's ++complete source code as you receive it, in any medium, provided that ++you conspicuously and appropriately publish on each copy an ++appropriate copyright notice and disclaimer of warranty; keep intact ++all the notices that refer to this License and to the absence of any ++warranty; and distribute a copy of this License along with the ++Library. ++ ++ You may charge a fee for the physical act of transferring a copy, ++and you may at your option offer warranty protection in exchange for a ++fee. ++ ++ 2. You may modify your copy or copies of the Library or any portion ++of it, thus forming a work based on the Library, and copy and ++distribute such modifications or work under the terms of Section 1 ++above, provided that you also meet all of these conditions: ++ ++ a) The modified work must itself be a software library. ++ ++ b) You must cause the files modified to carry prominent notices ++ stating that you changed the files and the date of any change. ++ ++ c) You must cause the whole of the work to be licensed at no ++ charge to all third parties under the terms of this License. ++ ++ d) If a facility in the modified Library refers to a function or a ++ table of data to be supplied by an application program that uses ++ the facility, other than as an argument passed when the facility ++ is invoked, then you must make a good faith effort to ensure that, ++ in the event an application does not supply such function or ++ table, the facility still operates, and performs whatever part of ++ its purpose remains meaningful. ++ ++ (For example, a function in a library to compute square roots has ++ a purpose that is entirely well-defined independent of the ++ application. Therefore, Subsection 2d requires that any ++ application-supplied function or table used by this function must ++ be optional: if the application does not supply it, the square ++ root function must still compute square roots.) ++ ++These requirements apply to the modified work as a whole. If ++identifiable sections of that work are not derived from the Library, ++and can be reasonably considered independent and separate works in ++themselves, then this License, and its terms, do not apply to those ++sections when you distribute them as separate works. But when you ++distribute the same sections as part of a whole which is a work based ++on the Library, the distribution of the whole must be on the terms of ++this License, whose permissions for other licensees extend to the ++entire whole, and thus to each and every part regardless of who wrote ++it. ++ ++Thus, it is not the intent of this section to claim rights or contest ++your rights to work written entirely by you; rather, the intent is to ++exercise the right to control the distribution of derivative or ++collective works based on the Library. ++ ++In addition, mere aggregation of another work not based on the Library ++with the Library (or with a work based on the Library) on a volume of ++a storage or distribution medium does not bring the other work under ++the scope of this License. ++ ++ 3. You may opt to apply the terms of the ordinary GNU General Public ++License instead of this License to a given copy of the Library. To do ++this, you must alter all the notices that refer to this License, so ++that they refer to the ordinary GNU General Public License, version 2, ++instead of to this License. (If a newer version than version 2 of the ++ordinary GNU General Public License has appeared, then you can specify ++that version instead if you wish.) Do not make any other change in ++these notices. ++ ++ Once this change is made in a given copy, it is irreversible for ++that copy, so the ordinary GNU General Public License applies to all ++subsequent copies and derivative works made from that copy. ++ ++ This option is useful when you wish to copy part of the code of ++the Library into a program that is not a library. ++ ++ 4. You may copy and distribute the Library (or a portion or ++derivative of it, under Section 2) in object code or executable form ++under the terms of Sections 1 and 2 above provided that you accompany ++it with the complete corresponding machine-readable source code, which ++must be distributed under the terms of Sections 1 and 2 above on a ++medium customarily used for software interchange. ++ ++ If distribution of object code is made by offering access to copy ++from a designated place, then offering equivalent access to copy the ++source code from the same place satisfies the requirement to ++distribute the source code, even though third parties are not ++compelled to copy the source along with the object code. ++ ++ 5. A program that contains no derivative of any portion of the ++Library, but is designed to work with the Library by being compiled or ++linked with it, is called a "work that uses the Library". Such a ++work, in isolation, is not a derivative work of the Library, and ++therefore falls outside the scope of this License. ++ ++ However, linking a "work that uses the Library" with the Library ++creates an executable that is a derivative of the Library (because it ++contains portions of the Library), rather than a "work that uses the ++library". The executable is therefore covered by this License. ++Section 6 states terms for distribution of such executables. ++ ++ When a "work that uses the Library" uses material from a header file ++that is part of the Library, the object code for the work may be a ++derivative work of the Library even though the source code is not. ++Whether this is true is especially significant if the work can be ++linked without the Library, or if the work is itself a library. The ++threshold for this to be true is not precisely defined by law. ++ ++ If such an object file uses only numerical parameters, data ++structure layouts and accessors, and small macros and small inline ++functions (ten lines or less in length), then the use of the object ++file is unrestricted, regardless of whether it is legally a derivative ++work. (Executables containing this object code plus portions of the ++Library will still fall under Section 6.) ++ ++ Otherwise, if the work is a derivative of the Library, you may ++distribute the object code for the work under the terms of Section 6. ++Any executables containing that work also fall under Section 6, ++whether or not they are linked directly with the Library itself. ++ ++ 6. As an exception to the Sections above, you may also combine or ++link a "work that uses the Library" with the Library to produce a ++work containing portions of the Library, and distribute that work ++under terms of your choice, provided that the terms permit ++modification of the work for the customer's own use and reverse ++engineering for debugging such modifications. ++ ++ You must give prominent notice with each copy of the work that the ++Library is used in it and that the Library and its use are covered by ++this License. You must supply a copy of this License. If the work ++during execution displays copyright notices, you must include the ++copyright notice for the Library among them, as well as a reference ++directing the user to the copy of this License. Also, you must do one ++of these things: ++ ++ a) Accompany the work with the complete corresponding ++ machine-readable source code for the Library including whatever ++ changes were used in the work (which must be distributed under ++ Sections 1 and 2 above); and, if the work is an executable linked ++ with the Library, with the complete machine-readable "work that ++ uses the Library", as object code and/or source code, so that the ++ user can modify the Library and then relink to produce a modified ++ executable containing the modified Library. (It is understood ++ that the user who changes the contents of definitions files in the ++ Library will not necessarily be able to recompile the application ++ to use the modified definitions.) ++ ++ b) Use a suitable shared library mechanism for linking with the ++ Library. A suitable mechanism is one that (1) uses at run time a ++ copy of the library already present on the user's computer system, ++ rather than copying library functions into the executable, and (2) ++ will operate properly with a modified version of the library, if ++ the user installs one, as long as the modified version is ++ interface-compatible with the version that the work was made with. ++ ++ c) Accompany the work with a written offer, valid for at ++ least three years, to give the same user the materials ++ specified in Subsection 6a, above, for a charge no more ++ than the cost of performing this distribution. ++ ++ d) If distribution of the work is made by offering access to copy ++ from a designated place, offer equivalent access to copy the above ++ specified materials from the same place. ++ ++ e) Verify that the user has already received a copy of these ++ materials or that you have already sent this user a copy. ++ ++ For an executable, the required form of the "work that uses the ++Library" must include any data and utility programs needed for ++reproducing the executable from it. However, as a special exception, ++the materials to be distributed need not include anything that is ++normally distributed (in either source or binary form) with the major ++components (compiler, kernel, and so on) of the operating system on ++which the executable runs, unless that component itself accompanies ++the executable. ++ ++ It may happen that this requirement contradicts the license ++restrictions of other proprietary libraries that do not normally ++accompany the operating system. Such a contradiction means you cannot ++use both them and the Library together in an executable that you ++distribute. ++ ++ 7. You may place library facilities that are a work based on the ++Library side-by-side in a single library together with other library ++facilities not covered by this License, and distribute such a combined ++library, provided that the separate distribution of the work based on ++the Library and of the other library facilities is otherwise ++permitted, and provided that you do these two things: ++ ++ a) Accompany the combined library with a copy of the same work ++ based on the Library, uncombined with any other library ++ facilities. This must be distributed under the terms of the ++ Sections above. ++ ++ b) Give prominent notice with the combined library of the fact ++ that part of it is a work based on the Library, and explaining ++ where to find the accompanying uncombined form of the same work. ++ ++ 8. You may not copy, modify, sublicense, link with, or distribute ++the Library except as expressly provided under this License. Any ++attempt otherwise to copy, modify, sublicense, link with, or ++distribute the Library is void, and will automatically terminate your ++rights under this License. However, parties who have received copies, ++or rights, from you under this License will not have their licenses ++terminated so long as such parties remain in full compliance. ++ ++ 9. You are not required to accept this License, since you have not ++signed it. However, nothing else grants you permission to modify or ++distribute the Library or its derivative works. These actions are ++prohibited by law if you do not accept this License. Therefore, by ++modifying or distributing the Library (or any work based on the ++Library), you indicate your acceptance of this License to do so, and ++all its terms and conditions for copying, distributing or modifying ++the Library or works based on it. ++ ++ 10. Each time you redistribute the Library (or any work based on the ++Library), the recipient automatically receives a license from the ++original licensor to copy, distribute, link with or modify the Library ++subject to these terms and conditions. You may not impose any further ++restrictions on the recipients' exercise of the rights granted herein. ++You are not responsible for enforcing compliance by third parties with ++this License. ++ ++ 11. If, as a consequence of a court judgment or allegation of patent ++infringement or for any other reason (not limited to patent issues), ++conditions are imposed on you (whether by court order, agreement or ++otherwise) that contradict the conditions of this License, they do not ++excuse you from the conditions of this License. If you cannot ++distribute so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you ++may not distribute the Library at all. For example, if a patent ++license would not permit royalty-free redistribution of the Library by ++all those who receive copies directly or indirectly through you, then ++the only way you could satisfy both it and this License would be to ++refrain entirely from distribution of the Library. ++ ++If any portion of this section is held invalid or unenforceable under any ++particular circumstance, the balance of the section is intended to apply, ++and the section as a whole is intended to apply in other circumstances. ++ ++It is not the purpose of this section to induce you to infringe any ++patents or other property right claims or to contest validity of any ++such claims; this section has the sole purpose of protecting the ++integrity of the free software distribution system which is ++implemented by public license practices. Many people have made ++generous contributions to the wide range of software distributed ++through that system in reliance on consistent application of that ++system; it is up to the author/donor to decide if he or she is willing ++to distribute software through any other system and a licensee cannot ++impose that choice. ++ ++This section is intended to make thoroughly clear what is believed to ++be a consequence of the rest of this License. ++ ++ 12. If the distribution and/or use of the Library is restricted in ++certain countries either by patents or by copyrighted interfaces, the ++original copyright holder who places the Library under this License may add ++an explicit geographical distribution limitation excluding those countries, ++so that distribution is permitted only in or among countries not thus ++excluded. In such case, this License incorporates the limitation as if ++written in the body of this License. ++ ++ 13. The Free Software Foundation may publish revised and/or new ++versions of the Lesser General Public License from time to time. ++Such new versions will be similar in spirit to the present version, ++but may differ in detail to address new problems or concerns. ++ ++Each version is given a distinguishing version number. If the Library ++specifies a version number of this License which applies to it and ++"any later version", you have the option of following the terms and ++conditions either of that version or of any later version published by ++the Free Software Foundation. If the Library does not specify a ++license version number, you may choose any version ever published by ++the Free Software Foundation. ++ ++ 14. If you wish to incorporate parts of the Library into other free ++programs whose distribution conditions are incompatible with these, ++write to the author to ask for permission. For software which is ++copyrighted by the Free Software Foundation, write to the Free ++Software Foundation; we sometimes make exceptions for this. Our ++decision will be guided by the two goals of preserving the free status ++of all derivatives of our free software and of promoting the sharing ++and reuse of software generally. ++ ++ NO WARRANTY ++ ++ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO ++WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. ++EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR ++OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY ++KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE ++IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE ++LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME ++THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. ++ ++ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN ++WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY ++AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU ++FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR ++CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE ++LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING ++RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A ++FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF ++SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH ++DAMAGES. ++ ++ END OF TERMS AND CONDITIONS ++ ++ How to Apply These Terms to Your New Libraries ++ ++ If you develop a new library, and you want it to be of the greatest ++possible use to the public, we recommend making it free software that ++everyone can redistribute and change. You can do so by permitting ++redistribution under these terms (or, alternatively, under the terms of the ++ordinary General Public License). ++ ++ To apply these terms, attach the following notices to the library. It is ++safest to attach them to the start of each source file to most effectively ++convey the exclusion of warranty; and each file should have at least the ++"copyright" line and a pointer to where the full notice is found. ++ ++ ++ Copyright (C) ++ ++ This library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ This library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with this library; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the library, if ++necessary. Here is a sample; alter the names: ++ ++ Yoyodyne, Inc., hereby disclaims all copyright interest in the ++ library `Frob' (a library for tweaking knobs) written by James Random Hacker. ++ ++ , 1 April 1990 ++ Ty Coon, President of Vice ++ ++That's all there is to it! ++ ++ +diff --git a/utils/open-isns/ChangeLog b/utils/open-isns/ChangeLog +new file mode 100644 +index 0000000..36d6506 +--- /dev/null ++++ b/utils/open-isns/ChangeLog +@@ -0,0 +1,50 @@ ++Under development: ++ ++2007-09-27: ++ Fixed a serious interoperability bug ++ Added SLP support (using openslp) ++ Init script (courtesy Albert Pauw) ++ ++2007-09-18: ++ Fixed a number of bugs ++ Added more test cases ++ Implemented default DD ++ Support autoconf, and building with/without openssl ++ ++2007-08-24: ++ Improved discovery domain handling ++ Implemented DD deregistration ++ Backward compat fixes for older openssl versions ++ Made SCN more robust, SCN state now persists across server restarts ++ More regression tests ++ ++2007-07-27: ++ Implemented SCN and ESI ++ Created iSNS discovery daemon (isnsdd) ++ Rewrote the policy handling a bit ++ Started to write some regression test code ++ Better manpages ++ ++2007-07-12: ++ DevGetNext support ++ You can now define policies linking authentication ++ to permitted storage node names, permitted ++ entity names, etc. ++ Implemented DDReg ++ Queries and GetNext are now scoped to discovery domains ++ Lots of little bits and pieces for RFC conformance ++ ++2005-07-18: ++ Public snapshot released ++ DSA based authentication ++ Deregistration ++ Simple file backed storage for the iSNS database ++ Entity Registration Period + Timestamp support (server side), ++ and entity expiration ++ isnsd now writes a pid file ++ Improved manual pages ++ DevGetNext support under development ++ ++2007-05-11: ++ First public release, supporting register/query ++ +diff --git a/utils/open-isns/HACKING b/utils/open-isns/HACKING +new file mode 100644 +index 0000000..95b330c +--- /dev/null ++++ b/utils/open-isns/HACKING +@@ -0,0 +1,30 @@ ++ ++When hacking on open-isns, or when trying to locate a problem, ++the following information may be useful: ++ ++ - You can start the daemon using the -f option, which ++ prevents it from backgrounding itself. Crucial if ++ you want to run it in a debugger, or under strace. ++ ++ This option works for isnsd and isnsdd ++ ++ - All tools support the "-d" option to enable debugging. ++ In general, you want to use "-d all" to turn on all ++ debugging options. However, you can select individual ++ debug facilities - check out the manpages and/or ++ the source code in logging.c ++ ++ - If isnsd crashes, and you suspect memory corruption, ++ you can compile open-isns with memory debugging enabled. Re-run ++ the configure script and add the option --enable-memdebug. Then ++ run "make clean all" to rebuild everything. ++ ++ Memory debugging can be chosen at run-time by setting the ++ ISNS_MDEBUG environment variable, and re-starting the application: ++ ++ export ISNS_MDEBUG=1 ++ ./isnsd -f -d all ++ ++ Memory debugging works for all memory allocations done by the ++ Open-iSNS code, but does not affect memory allocations by other ++ libraries (such as glibc or openssl). +diff --git a/utils/open-isns/Makefile.in b/utils/open-isns/Makefile.in +new file mode 100644 +index 0000000..a27199c +--- /dev/null ++++ b/utils/open-isns/Makefile.in +@@ -0,0 +1,81 @@ ++prefix = @prefix@ ++exec_prefix = @exec_prefix@ ++sbindir = @sbindir@ ++mandir = @mandir@ ++etcdir = /etc ++vardir = /var/lib/isns ++ ++SBINDIR = $(INSTALL_ROOT)$(sbindir) ++ETCDIR = $(INSTALL_ROOT)$(etcdir) ++CFGDIR = $(ETCDIR)/isns ++MANDIR = $(INSTALL_ROOT)$(mandir) ++VARDIR = $(INSTALL_ROOT)$(vardir) ++ ++CC = @CC@ ++CPPFLAGS= @CPPFLAGS@ ++CFLAGS = @CFLAGS@ -I. ++LDFLAGS = @LDFLAGS@ ++ ++LIB = libisns.a ++LIBOBJS = server.o \ ++ client.o \ ++ objects.o \ ++ callback.o \ ++ timer.o \ ++ vendor.o \ ++ db.o \ ++ db-file.o \ ++ db-policy.o \ ++ relation.o \ ++ scope.o \ ++ message.o \ ++ security.o \ ++ authblock.o \ ++ policy.o \ ++ register.o \ ++ query.o \ ++ getnext.o \ ++ deregister.o \ ++ esi.o \ ++ scn.o \ ++ dd.o \ ++ entity.o \ ++ portal-group.o \ ++ storage-node.o \ ++ domain.o \ ++ simple.o \ ++ tags.o \ ++ attrs.o \ ++ export.o \ ++ socket.o \ ++ slp.o \ ++ error.o \ ++ logging.o \ ++ config.o \ ++ parser.o \ ++ buffer.o \ ++ pidfile.o \ ++ sysdep-unix.o \ ++ util.o \ ++ bitvector.o \ ++ mdebug.o ++SECLINK = @SECLIBS@ ++SLPLINK = @SLPLIBS@ ++SLPLIN = @SLPLIBS@ ++ ++all: $(LIB) ++ ++clean distclean:: ++ rm -f *.o $(LIB) *~ ++ ++distclean:: ++ rm -f config.h Makefile config.status config.log ++ rm -rf autom4te.cache ++ ++$(LIB): $(LIBOBJS) ++ ar cr $@ $(LIBOBJS) ++ ++depend: ++ gcc $(CFLAGS) -M `ls *.c` > .depend ++ ++-include .depend +diff --git a/utils/open-isns/README b/utils/open-isns/README +new file mode 100644 +index 0000000..acff29b +--- /dev/null ++++ b/utils/open-isns/README +@@ -0,0 +1,173 @@ ++ ++Welcome to Open-iSNS ++==================== ++ ++This is a partial implementation of iSNS, according to RFC4171. ++The implementation is still somewhat incomplete, but I'm releasing ++it for your reading pleasure. ++ ++The distribution comprises ++ ++ isnsd ++ This is the iSNS server, supporting persistent storage ++ of registrations in a file based database. ++ ++ isnsadm ++ A command line utility for querying the iSNS database, ++ and for registering/deregistering nodes and portals ++ ++ isnsdd ++ An iSNS Discovery Daemon, which is still very much work ++ in progress. The daemon is supposed to handle all the ++ bit banging and server communications required to register ++ a node, its portals, and to maintain the registration. ++ It is also supposed to use the iSNS State Change Notification ++ framework to learn of new targets or initiators coming online, ++ and inform local services (such as the iSCSI initiator daemon) ++ about these changes. ++ ++Thanks! ++------- ++ ++Many thanks to Albert Pauw for his fearless testing of snapshots, ++and his copious feedback! ++ ++What works, after a fashion: ++---------------------------- ++ ++ - For now, I've been focusing on getting the iSCSI part to ++ work. There is some very basic support for FC objects, but ++ this will be hardly useful yet. ++ ++ - Registration, deregistration, query, getnext ++ You can use isnsadm to register iSCSI nodes, and portals. ++ isnsadm also illustrates how this is supposed to be used from ++ the client perspective. ++ ++ - Discovery domains are supported mostly. The administrator ++ can create discovery domains using isnsadm, and place storage ++ nodes in domains. Queries by clients are scoped by their ++ discovery domains membership, so that they will be unable to ++ see nodes not part of a shared DD. ++ ++ Open-iSNS currently does not allow clients to place themselves ++ in a DD. ++ ++ Optionally, storage nodes that are not in any discovery domain ++ will be placed in a "default DD" (see the DefaultDiscoveryDomain ++ in isnsd.conf). ++ ++ - ESI, supported both by the server and the discovery daemon ++ ++ - SCN, supported by the server and the discovery daemon ++ ++What is still missing ++--------------------- ++ ++ - Better documentation (esp. a HOWTO on getting started with iSNS) ++ - DD Sets ++ - Various bits and pieces of the protocol ++ - FC support ++ ++ ++Building Open-iSNS ++------------------ ++ ++The Open-iSNS build is now based on autoconf. The distributed tarball ++should include a configure script and a config.h.in file generated ++from configure.ac. If these are missing, you can generate them ++by running ++ ++ autoconf ++ autoheader ++ ++For most people, it should be sufficient to run configure without any ++arguments, or at most with the option --prefix. If run without --prefix, ++program files, manpages etc will be installed below /usr/local. To have ++everything installed /usr/bin, /usr/share/man etc, run it as ++ ++ ./configure --prefix=/usr ++ ++Dependencies: ++ ++ - If you want to build Open-iSNS with support for authentication, ++ you need the OpenSSL libraries and header files installed. ++ ++ The configure script should pick up the presence of these ++ libraries, and enable security support automatically. To disable ++ this explicitly in your build, pass the --without-security option ++ to configure. ++ ++ - If you want to build Open-iSNS with SLP support, you need the ++ OpenSLP library and header file installed. ++ ++ The configure script should pick up the presence of this library, ++ and enable SLP support automatically. To disable this explicitly ++ in your build, pass the --without-slp option to configure. ++ ++When configure is run, it checks for a the presence of a number of ++headers and libraries in your system (the results of most of these checks ++are currently ignored :-). Then, it creates a Makefile and a config.h ++include file. With these in place, you can build the binaries and libraries: ++ ++ make ++ make install ++ ++Getting started ++--------------- ++ ++On the iSNS server, you need to generate a server key and install it. The ++simplest way is probably to use the isnssetup script included in the ++source package. ++ ++For each client you wish to use, you should then ++ ++iSNS Security ++------------- ++ ++This implementation of iSNS supports authentication, as descibed in RFC ++4171. In order to use it, you have to create DSA keys for the server and ++all clients. ++ ++iSNS uses conceptually the same security mechanism as SLP, and identifies ++principals by a "Security Parameter Index", which is essentially a string ++identifying a key. ++ ++Open-iSNS fully supports DSA based security, and offers a flexible ++policy mechanism that ties an SPI to a network entity and the storage ++node names it is allowed to use. For an introduction to the security ++model used by Open-iSNS, refer to the isns_config(5) manual page. An ++overview on setting up the iSNS server for authentication is given in ++the EXAMPLES section of the isnsadm(8) manual page. ++ ++Downloading Open-iSNS ++--------------------- ++ ++Open-iSNS is available for download from ++ ++ http://oss.oracle.com/~okir/open-isns ++ ++You have to grab the latest tarball and compile it; fancy things such ++as RPMs are not available yet. ++ ++------------------------------------------------------------------ ++ ++ ++ COPYRIGHT NOTICE ++ ++ Copyright (C) 2007 Olaf Kirch. ++ ++ This library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ This library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with this library; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ +diff --git a/utils/open-isns/TODO b/utils/open-isns/TODO +new file mode 100644 +index 0000000..2ddf008 +--- /dev/null ++++ b/utils/open-isns/TODO +@@ -0,0 +1,100 @@ ++Documentation: ++ - Add HOWTO ++ ++isnsd: ++ - When registering a node, use the default EID given in its ++ policy (avoid the isns.control trap) ++ - make PGs children of the iSCSI storage node they're associated ++ with? ++ - Implement missing functions ++ ++isnsadm: ++ - support iSNS server discovery through DNS SRV ++ records, and SLP ++ ++isnsdd: ++ - support iSNS server discovery through DNS SRV ++ records, and SLP ++ - At startup, query the server for the list of ++ visible nodes/portals ++ - When receiving an SCN, query for the node's ++ portals, authmethod and such, and compare that ++ to what we have cached ++ - At regular intervals, repeat the query for ++ all visible nodes/portals, and do a diff with ++ our shadow DB ++ - At regular intervals, check whether the portals ++ we registered for ESI are seeing the server's ++ ESI messages. ++ ++DevAttrReg: ++ - Refuse registration of nodes inside the CONTROL ++ entity, unless it's a control node. ++ - If the client uses REPLACE, is it okay for the ++ entity's index to change? ++ - security: optionally validate the IP addresses ++ a client registers (either against a static policy, ++ or using DNS). ++ - relaxed security model: require privilege ++ for registration of targets; anyone can register ++ an initiator? ++ - Gracefully handle registrations where the client ++ specifies an index attribute, as long as it matches ++ the next_index ++ ++DevAttrQuery: ++ - fix --local --query policy-index=iqn.1969-12.brummo ++ and write test case ++ - fix the way we enumerate related objects ++ - ensure DD discovery works (5.6.5.2): ++ DD membership can be discovered through the DevAttrQry message ++ by including either DD member attributes (i.e., DD Member ++ iSCSI Index, DD Member iSCSI Node, DD Member iFCP Node, DD ++ Member Portal Index, DD Member Portal IP Addr, and DD Member ++ Portal TCP/UDP) or the object key of the Storage Node or ++ Portal (i.e., iSCSI Name, iSCSI Index, Portal IP Addr, Portal ++ TCP/UDP Port, and Portal Index) in the Operating Attributes. ++ Using DD member attributes SHALL return both registered and ++ unregistered member Storage Nodes and/or Portals of a DD. ++ DevAttrQry messages using the Storage Node and/or Portal ++ object key SHALL return only member Storage Nodes or Portals ++ that are currently registered in the iSNS database. ++ ++DevAttrDereg: ++ - PG Removal code: ignore nodes/portal that are dead ++ - review security ++ - cancel any SCN/ESI callbacks ++ ++SCN: ++ - Trigger a mgmt reg SCN when accepting a mgmt registration ++ ++SCNEvent: ++ - Implement ++ ++ESI: ++ - Right now the way we re-establish ESI state after database ++ reload is awkward. ++ ++DDReg: ++ - Write test cases ++ ++DDDereg: ++ - Write test cases ++ ++DDSReg/DDSDereg: ++ - Implement ++ ++Heartbeat: ++ - Implement message send ++ - Implement failover? ++ ++Security: ++ - Allow policies without key? ++ - Implement simple default policies linking client IP + ++ hostname (network entity) + storage node names ++ ++Renaming ++ - Add isns_ prefix to all visible functions ++ ++Socket code: ++ - impose upper limit on the reassembly buffer +diff --git a/utils/open-isns/aclocal/config.guess b/utils/open-isns/aclocal/config.guess +new file mode 100644 +index 0000000..6d71f75 +--- /dev/null ++++ b/utils/open-isns/aclocal/config.guess +@@ -0,0 +1,1499 @@ ++#! /bin/sh ++# Attempt to guess a canonical system name. ++# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, ++# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. ++ ++timestamp='2005-05-27' ++ ++# This file is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA ++# 02110-1301, USA. ++# ++# As a special exception to the GNU General Public License, if you ++# distribute this file as part of a program that contains a ++# configuration script generated by Autoconf, you may include it under ++# the same distribution terms that you use for the rest of that program. ++ ++ ++# Originally written by Per Bothner . ++# Please send patches to . Submit a context ++# diff and a properly formatted ChangeLog entry. ++# ++# This script attempts to guess a canonical system name similar to ++# config.sub. If it succeeds, it prints the system name on stdout, and ++# exits with 0. Otherwise, it exits with 1. ++# ++# The plan is that this can be called by configure scripts if you ++# don't specify an explicit build system type. ++ ++me=`echo "$0" | sed -e 's,.*/,,'` ++ ++usage="\ ++Usage: $0 [OPTION] ++ ++Output the configuration name of the system \`$me' is run on. ++ ++Operation modes: ++ -h, --help print this help, then exit ++ -t, --time-stamp print date of last modification, then exit ++ -v, --version print version number, then exit ++ ++Report bugs and patches to ." ++ ++version="\ ++GNU config.guess ($timestamp) ++ ++Originally written by Per Bothner. ++Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 ++Free Software Foundation, Inc. ++ ++This is free software; see the source for copying conditions. There is NO ++warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." ++ ++help=" ++Try \`$me --help' for more information." ++ ++# Parse command line ++while test $# -gt 0 ; do ++ case $1 in ++ --time-stamp | --time* | -t ) ++ echo "$timestamp" ; exit ;; ++ --version | -v ) ++ echo "$version" ; exit ;; ++ --help | --h* | -h ) ++ echo "$usage"; exit ;; ++ -- ) # Stop option processing ++ shift; break ;; ++ - ) # Use stdin as input. ++ break ;; ++ -* ) ++ echo "$me: invalid option $1$help" >&2 ++ exit 1 ;; ++ * ) ++ break ;; ++ esac ++done ++ ++if test $# != 0; then ++ echo "$me: too many arguments$help" >&2 ++ exit 1 ++fi ++ ++trap 'exit 1' 1 2 15 ++ ++# CC_FOR_BUILD -- compiler used by this script. Note that the use of a ++# compiler to aid in system detection is discouraged as it requires ++# temporary files to be created and, as you can see below, it is a ++# headache to deal with in a portable fashion. ++ ++# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still ++# use `HOST_CC' if defined, but it is deprecated. ++ ++# Portable tmp directory creation inspired by the Autoconf team. ++ ++set_cc_for_build=' ++trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; ++trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; ++: ${TMPDIR=/tmp} ; ++ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || ++ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || ++ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || ++ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; ++dummy=$tmp/dummy ; ++tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; ++case $CC_FOR_BUILD,$HOST_CC,$CC in ++ ,,) echo "int x;" > $dummy.c ; ++ for c in cc gcc c89 c99 ; do ++ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then ++ CC_FOR_BUILD="$c"; break ; ++ fi ; ++ done ; ++ if test x"$CC_FOR_BUILD" = x ; then ++ CC_FOR_BUILD=no_compiler_found ; ++ fi ++ ;; ++ ,,*) CC_FOR_BUILD=$CC ;; ++ ,*,*) CC_FOR_BUILD=$HOST_CC ;; ++esac ;' ++ ++# This is needed to find uname on a Pyramid OSx when run in the BSD universe. ++# (ghazi@noc.rutgers.edu 1994-08-24) ++if (test -f /.attbin/uname) >/dev/null 2>&1 ; then ++ PATH=$PATH:/.attbin ; export PATH ++fi ++ ++UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown ++UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown ++UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown ++UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown ++ ++# Note: order is significant - the case branches are not exclusive. ++ ++case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ++ *:NetBSD:*:*) ++ # NetBSD (nbsd) targets should (where applicable) match one or ++ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, ++ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently ++ # switched to ELF, *-*-netbsd* would select the old ++ # object file format. This provides both forward ++ # compatibility and a consistent mechanism for selecting the ++ # object file format. ++ # ++ # Note: NetBSD doesn't particularly care about the vendor ++ # portion of the name. We always set it to "unknown". ++ sysctl="sysctl -n hw.machine_arch" ++ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ ++ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` ++ case "${UNAME_MACHINE_ARCH}" in ++ armeb) machine=armeb-unknown ;; ++ arm*) machine=arm-unknown ;; ++ sh3el) machine=shl-unknown ;; ++ sh3eb) machine=sh-unknown ;; ++ *) machine=${UNAME_MACHINE_ARCH}-unknown ;; ++ esac ++ # The Operating System including object format, if it has switched ++ # to ELF recently, or will in the future. ++ case "${UNAME_MACHINE_ARCH}" in ++ arm*|i386|m68k|ns32k|sh3*|sparc|vax) ++ eval $set_cc_for_build ++ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ ++ | grep __ELF__ >/dev/null ++ then ++ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). ++ # Return netbsd for either. FIX? ++ os=netbsd ++ else ++ os=netbsdelf ++ fi ++ ;; ++ *) ++ os=netbsd ++ ;; ++ esac ++ # The OS release ++ # Debian GNU/NetBSD machines have a different userland, and ++ # thus, need a distinct triplet. However, they do not need ++ # kernel version information, so it can be replaced with a ++ # suitable tag, in the style of linux-gnu. ++ case "${UNAME_VERSION}" in ++ Debian*) ++ release='-gnu' ++ ;; ++ *) ++ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ++ ;; ++ esac ++ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: ++ # contains redundant information, the shorter form: ++ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. ++ echo "${machine}-${os}${release}" ++ exit ;; ++ amd64:OpenBSD:*:*) ++ echo x86_64-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ amiga:OpenBSD:*:*) ++ echo m68k-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ cats:OpenBSD:*:*) ++ echo arm-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ hp300:OpenBSD:*:*) ++ echo m68k-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ luna88k:OpenBSD:*:*) ++ echo m88k-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ mac68k:OpenBSD:*:*) ++ echo m68k-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ macppc:OpenBSD:*:*) ++ echo powerpc-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ mvme68k:OpenBSD:*:*) ++ echo m68k-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ mvme88k:OpenBSD:*:*) ++ echo m88k-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ mvmeppc:OpenBSD:*:*) ++ echo powerpc-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ sgi:OpenBSD:*:*) ++ echo mips64-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ sun3:OpenBSD:*:*) ++ echo m68k-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ *:OpenBSD:*:*) ++ echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} ++ exit ;; ++ *:ekkoBSD:*:*) ++ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} ++ exit ;; ++ macppc:MirBSD:*:*) ++ echo powerppc-unknown-mirbsd${UNAME_RELEASE} ++ exit ;; ++ *:MirBSD:*:*) ++ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} ++ exit ;; ++ alpha:OSF1:*:*) ++ case $UNAME_RELEASE in ++ *4.0) ++ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ++ ;; ++ *5.*) ++ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ++ ;; ++ esac ++ # According to Compaq, /usr/sbin/psrinfo has been available on ++ # OSF/1 and Tru64 systems produced since 1995. I hope that ++ # covers most systems running today. This code pipes the CPU ++ # types through head -n 1, so we only detect the type of CPU 0. ++ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` ++ case "$ALPHA_CPU_TYPE" in ++ "EV4 (21064)") ++ UNAME_MACHINE="alpha" ;; ++ "EV4.5 (21064)") ++ UNAME_MACHINE="alpha" ;; ++ "LCA4 (21066/21068)") ++ UNAME_MACHINE="alpha" ;; ++ "EV5 (21164)") ++ UNAME_MACHINE="alphaev5" ;; ++ "EV5.6 (21164A)") ++ UNAME_MACHINE="alphaev56" ;; ++ "EV5.6 (21164PC)") ++ UNAME_MACHINE="alphapca56" ;; ++ "EV5.7 (21164PC)") ++ UNAME_MACHINE="alphapca57" ;; ++ "EV6 (21264)") ++ UNAME_MACHINE="alphaev6" ;; ++ "EV6.7 (21264A)") ++ UNAME_MACHINE="alphaev67" ;; ++ "EV6.8CB (21264C)") ++ UNAME_MACHINE="alphaev68" ;; ++ "EV6.8AL (21264B)") ++ UNAME_MACHINE="alphaev68" ;; ++ "EV6.8CX (21264D)") ++ UNAME_MACHINE="alphaev68" ;; ++ "EV6.9A (21264/EV69A)") ++ UNAME_MACHINE="alphaev69" ;; ++ "EV7 (21364)") ++ UNAME_MACHINE="alphaev7" ;; ++ "EV7.9 (21364A)") ++ UNAME_MACHINE="alphaev79" ;; ++ esac ++ # A Pn.n version is a patched version. ++ # A Vn.n version is a released version. ++ # A Tn.n version is a released field test version. ++ # A Xn.n version is an unreleased experimental baselevel. ++ # 1.2 uses "1.2" for uname -r. ++ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` ++ exit ;; ++ Alpha\ *:Windows_NT*:*) ++ # How do we know it's Interix rather than the generic POSIX subsystem? ++ # Should we change UNAME_MACHINE based on the output of uname instead ++ # of the specific Alpha model? ++ echo alpha-pc-interix ++ exit ;; ++ 21064:Windows_NT:50:3) ++ echo alpha-dec-winnt3.5 ++ exit ;; ++ Amiga*:UNIX_System_V:4.0:*) ++ echo m68k-unknown-sysv4 ++ exit ;; ++ *:[Aa]miga[Oo][Ss]:*:*) ++ echo ${UNAME_MACHINE}-unknown-amigaos ++ exit ;; ++ *:[Mm]orph[Oo][Ss]:*:*) ++ echo ${UNAME_MACHINE}-unknown-morphos ++ exit ;; ++ *:OS/390:*:*) ++ echo i370-ibm-openedition ++ exit ;; ++ *:z/VM:*:*) ++ echo s390-ibm-zvmoe ++ exit ;; ++ *:OS400:*:*) ++ echo powerpc-ibm-os400 ++ exit ;; ++ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) ++ echo arm-acorn-riscix${UNAME_RELEASE} ++ exit ;; ++ arm:riscos:*:*|arm:RISCOS:*:*) ++ echo arm-unknown-riscos ++ exit ;; ++ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) ++ echo hppa1.1-hitachi-hiuxmpp ++ exit ;; ++ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) ++ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. ++ if test "`(/bin/universe) 2>/dev/null`" = att ; then ++ echo pyramid-pyramid-sysv3 ++ else ++ echo pyramid-pyramid-bsd ++ fi ++ exit ;; ++ NILE*:*:*:dcosx) ++ echo pyramid-pyramid-svr4 ++ exit ;; ++ DRS?6000:unix:4.0:6*) ++ echo sparc-icl-nx6 ++ exit ;; ++ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) ++ case `/usr/bin/uname -p` in ++ sparc) echo sparc-icl-nx7; exit ;; ++ esac ;; ++ sun4H:SunOS:5.*:*) ++ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` ++ exit ;; ++ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) ++ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` ++ exit ;; ++ i86pc:SunOS:5.*:*) ++ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` ++ exit ;; ++ sun4*:SunOS:6*:*) ++ # According to config.sub, this is the proper way to canonicalize ++ # SunOS6. Hard to guess exactly what SunOS6 will be like, but ++ # it's likely to be more like Solaris than SunOS4. ++ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` ++ exit ;; ++ sun4*:SunOS:*:*) ++ case "`/usr/bin/arch -k`" in ++ Series*|S4*) ++ UNAME_RELEASE=`uname -v` ++ ;; ++ esac ++ # Japanese Language versions have a version number like `4.1.3-JL'. ++ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` ++ exit ;; ++ sun3*:SunOS:*:*) ++ echo m68k-sun-sunos${UNAME_RELEASE} ++ exit ;; ++ sun*:*:4.2BSD:*) ++ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` ++ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 ++ case "`/bin/arch`" in ++ sun3) ++ echo m68k-sun-sunos${UNAME_RELEASE} ++ ;; ++ sun4) ++ echo sparc-sun-sunos${UNAME_RELEASE} ++ ;; ++ esac ++ exit ;; ++ aushp:SunOS:*:*) ++ echo sparc-auspex-sunos${UNAME_RELEASE} ++ exit ;; ++ # The situation for MiNT is a little confusing. The machine name ++ # can be virtually everything (everything which is not ++ # "atarist" or "atariste" at least should have a processor ++ # > m68000). The system name ranges from "MiNT" over "FreeMiNT" ++ # to the lowercase version "mint" (or "freemint"). Finally ++ # the system name "TOS" denotes a system which is actually not ++ # MiNT. But MiNT is downward compatible to TOS, so this should ++ # be no problem. ++ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) ++ echo m68k-atari-mint${UNAME_RELEASE} ++ exit ;; ++ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) ++ echo m68k-atari-mint${UNAME_RELEASE} ++ exit ;; ++ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) ++ echo m68k-atari-mint${UNAME_RELEASE} ++ exit ;; ++ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) ++ echo m68k-milan-mint${UNAME_RELEASE} ++ exit ;; ++ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) ++ echo m68k-hades-mint${UNAME_RELEASE} ++ exit ;; ++ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) ++ echo m68k-unknown-mint${UNAME_RELEASE} ++ exit ;; ++ m68k:machten:*:*) ++ echo m68k-apple-machten${UNAME_RELEASE} ++ exit ;; ++ powerpc:machten:*:*) ++ echo powerpc-apple-machten${UNAME_RELEASE} ++ exit ;; ++ RISC*:Mach:*:*) ++ echo mips-dec-mach_bsd4.3 ++ exit ;; ++ RISC*:ULTRIX:*:*) ++ echo mips-dec-ultrix${UNAME_RELEASE} ++ exit ;; ++ VAX*:ULTRIX*:*:*) ++ echo vax-dec-ultrix${UNAME_RELEASE} ++ exit ;; ++ 2020:CLIX:*:* | 2430:CLIX:*:*) ++ echo clipper-intergraph-clix${UNAME_RELEASE} ++ exit ;; ++ mips:*:*:UMIPS | mips:*:*:RISCos) ++ eval $set_cc_for_build ++ sed 's/^ //' << EOF >$dummy.c ++#ifdef __cplusplus ++#include /* for printf() prototype */ ++ int main (int argc, char *argv[]) { ++#else ++ int main (argc, argv) int argc; char *argv[]; { ++#endif ++ #if defined (host_mips) && defined (MIPSEB) ++ #if defined (SYSTYPE_SYSV) ++ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); ++ #endif ++ #if defined (SYSTYPE_SVR4) ++ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); ++ #endif ++ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) ++ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); ++ #endif ++ #endif ++ exit (-1); ++ } ++EOF ++ $CC_FOR_BUILD -o $dummy $dummy.c && ++ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && ++ SYSTEM_NAME=`$dummy $dummyarg` && ++ { echo "$SYSTEM_NAME"; exit; } ++ echo mips-mips-riscos${UNAME_RELEASE} ++ exit ;; ++ Motorola:PowerMAX_OS:*:*) ++ echo powerpc-motorola-powermax ++ exit ;; ++ Motorola:*:4.3:PL8-*) ++ echo powerpc-harris-powermax ++ exit ;; ++ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) ++ echo powerpc-harris-powermax ++ exit ;; ++ Night_Hawk:Power_UNIX:*:*) ++ echo powerpc-harris-powerunix ++ exit ;; ++ m88k:CX/UX:7*:*) ++ echo m88k-harris-cxux7 ++ exit ;; ++ m88k:*:4*:R4*) ++ echo m88k-motorola-sysv4 ++ exit ;; ++ m88k:*:3*:R3*) ++ echo m88k-motorola-sysv3 ++ exit ;; ++ AViiON:dgux:*:*) ++ # DG/UX returns AViiON for all architectures ++ UNAME_PROCESSOR=`/usr/bin/uname -p` ++ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] ++ then ++ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ ++ [ ${TARGET_BINARY_INTERFACE}x = x ] ++ then ++ echo m88k-dg-dgux${UNAME_RELEASE} ++ else ++ echo m88k-dg-dguxbcs${UNAME_RELEASE} ++ fi ++ else ++ echo i586-dg-dgux${UNAME_RELEASE} ++ fi ++ exit ;; ++ M88*:DolphinOS:*:*) # DolphinOS (SVR3) ++ echo m88k-dolphin-sysv3 ++ exit ;; ++ M88*:*:R3*:*) ++ # Delta 88k system running SVR3 ++ echo m88k-motorola-sysv3 ++ exit ;; ++ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) ++ echo m88k-tektronix-sysv3 ++ exit ;; ++ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) ++ echo m68k-tektronix-bsd ++ exit ;; ++ *:IRIX*:*:*) ++ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` ++ exit ;; ++ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. ++ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id ++ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' ++ i*86:AIX:*:*) ++ echo i386-ibm-aix ++ exit ;; ++ ia64:AIX:*:*) ++ if [ -x /usr/bin/oslevel ] ; then ++ IBM_REV=`/usr/bin/oslevel` ++ else ++ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} ++ fi ++ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} ++ exit ;; ++ *:AIX:2:3) ++ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then ++ eval $set_cc_for_build ++ sed 's/^ //' << EOF >$dummy.c ++ #include ++ ++ main() ++ { ++ if (!__power_pc()) ++ exit(1); ++ puts("powerpc-ibm-aix3.2.5"); ++ exit(0); ++ } ++EOF ++ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` ++ then ++ echo "$SYSTEM_NAME" ++ else ++ echo rs6000-ibm-aix3.2.5 ++ fi ++ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then ++ echo rs6000-ibm-aix3.2.4 ++ else ++ echo rs6000-ibm-aix3.2 ++ fi ++ exit ;; ++ *:AIX:*:[45]) ++ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` ++ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then ++ IBM_ARCH=rs6000 ++ else ++ IBM_ARCH=powerpc ++ fi ++ if [ -x /usr/bin/oslevel ] ; then ++ IBM_REV=`/usr/bin/oslevel` ++ else ++ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} ++ fi ++ echo ${IBM_ARCH}-ibm-aix${IBM_REV} ++ exit ;; ++ *:AIX:*:*) ++ echo rs6000-ibm-aix ++ exit ;; ++ ibmrt:4.4BSD:*|romp-ibm:BSD:*) ++ echo romp-ibm-bsd4.4 ++ exit ;; ++ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and ++ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to ++ exit ;; # report: romp-ibm BSD 4.3 ++ *:BOSX:*:*) ++ echo rs6000-bull-bosx ++ exit ;; ++ DPX/2?00:B.O.S.:*:*) ++ echo m68k-bull-sysv3 ++ exit ;; ++ 9000/[34]??:4.3bsd:1.*:*) ++ echo m68k-hp-bsd ++ exit ;; ++ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) ++ echo m68k-hp-bsd4.4 ++ exit ;; ++ 9000/[34678]??:HP-UX:*:*) ++ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` ++ case "${UNAME_MACHINE}" in ++ 9000/31? ) HP_ARCH=m68000 ;; ++ 9000/[34]?? ) HP_ARCH=m68k ;; ++ 9000/[678][0-9][0-9]) ++ if [ -x /usr/bin/getconf ]; then ++ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` ++ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` ++ case "${sc_cpu_version}" in ++ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 ++ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 ++ 532) # CPU_PA_RISC2_0 ++ case "${sc_kernel_bits}" in ++ 32) HP_ARCH="hppa2.0n" ;; ++ 64) HP_ARCH="hppa2.0w" ;; ++ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 ++ esac ;; ++ esac ++ fi ++ if [ "${HP_ARCH}" = "" ]; then ++ eval $set_cc_for_build ++ sed 's/^ //' << EOF >$dummy.c ++ ++ #define _HPUX_SOURCE ++ #include ++ #include ++ ++ int main () ++ { ++ #if defined(_SC_KERNEL_BITS) ++ long bits = sysconf(_SC_KERNEL_BITS); ++ #endif ++ long cpu = sysconf (_SC_CPU_VERSION); ++ ++ switch (cpu) ++ { ++ case CPU_PA_RISC1_0: puts ("hppa1.0"); break; ++ case CPU_PA_RISC1_1: puts ("hppa1.1"); break; ++ case CPU_PA_RISC2_0: ++ #if defined(_SC_KERNEL_BITS) ++ switch (bits) ++ { ++ case 64: puts ("hppa2.0w"); break; ++ case 32: puts ("hppa2.0n"); break; ++ default: puts ("hppa2.0"); break; ++ } break; ++ #else /* !defined(_SC_KERNEL_BITS) */ ++ puts ("hppa2.0"); break; ++ #endif ++ default: puts ("hppa1.0"); break; ++ } ++ exit (0); ++ } ++EOF ++ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` ++ test -z "$HP_ARCH" && HP_ARCH=hppa ++ fi ;; ++ esac ++ if [ ${HP_ARCH} = "hppa2.0w" ] ++ then ++ # avoid double evaluation of $set_cc_for_build ++ test -n "$CC_FOR_BUILD" || eval $set_cc_for_build ++ ++ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating ++ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler ++ # generating 64-bit code. GNU and HP use different nomenclature: ++ # ++ # $ CC_FOR_BUILD=cc ./config.guess ++ # => hppa2.0w-hp-hpux11.23 ++ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess ++ # => hppa64-hp-hpux11.23 ++ ++ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | ++ grep __LP64__ >/dev/null ++ then ++ HP_ARCH="hppa2.0w" ++ else ++ HP_ARCH="hppa64" ++ fi ++ fi ++ echo ${HP_ARCH}-hp-hpux${HPUX_REV} ++ exit ;; ++ ia64:HP-UX:*:*) ++ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` ++ echo ia64-hp-hpux${HPUX_REV} ++ exit ;; ++ 3050*:HI-UX:*:*) ++ eval $set_cc_for_build ++ sed 's/^ //' << EOF >$dummy.c ++ #include ++ int ++ main () ++ { ++ long cpu = sysconf (_SC_CPU_VERSION); ++ /* The order matters, because CPU_IS_HP_MC68K erroneously returns ++ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct ++ results, however. */ ++ if (CPU_IS_PA_RISC (cpu)) ++ { ++ switch (cpu) ++ { ++ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; ++ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; ++ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; ++ default: puts ("hppa-hitachi-hiuxwe2"); break; ++ } ++ } ++ else if (CPU_IS_HP_MC68K (cpu)) ++ puts ("m68k-hitachi-hiuxwe2"); ++ else puts ("unknown-hitachi-hiuxwe2"); ++ exit (0); ++ } ++EOF ++ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && ++ { echo "$SYSTEM_NAME"; exit; } ++ echo unknown-hitachi-hiuxwe2 ++ exit ;; ++ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) ++ echo hppa1.1-hp-bsd ++ exit ;; ++ 9000/8??:4.3bsd:*:*) ++ echo hppa1.0-hp-bsd ++ exit ;; ++ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) ++ echo hppa1.0-hp-mpeix ++ exit ;; ++ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) ++ echo hppa1.1-hp-osf ++ exit ;; ++ hp8??:OSF1:*:*) ++ echo hppa1.0-hp-osf ++ exit ;; ++ i*86:OSF1:*:*) ++ if [ -x /usr/sbin/sysversion ] ; then ++ echo ${UNAME_MACHINE}-unknown-osf1mk ++ else ++ echo ${UNAME_MACHINE}-unknown-osf1 ++ fi ++ exit ;; ++ parisc*:Lites*:*:*) ++ echo hppa1.1-hp-lites ++ exit ;; ++ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) ++ echo c1-convex-bsd ++ exit ;; ++ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) ++ if getsysinfo -f scalar_acc ++ then echo c32-convex-bsd ++ else echo c2-convex-bsd ++ fi ++ exit ;; ++ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) ++ echo c34-convex-bsd ++ exit ;; ++ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) ++ echo c38-convex-bsd ++ exit ;; ++ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) ++ echo c4-convex-bsd ++ exit ;; ++ CRAY*Y-MP:*:*:*) ++ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' ++ exit ;; ++ CRAY*[A-Z]90:*:*:*) ++ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ ++ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ ++ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ ++ -e 's/\.[^.]*$/.X/' ++ exit ;; ++ CRAY*TS:*:*:*) ++ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' ++ exit ;; ++ CRAY*T3E:*:*:*) ++ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' ++ exit ;; ++ CRAY*SV1:*:*:*) ++ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' ++ exit ;; ++ *:UNICOS/mp:*:*) ++ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' ++ exit ;; ++ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) ++ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` ++ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` ++ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` ++ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" ++ exit ;; ++ 5000:UNIX_System_V:4.*:*) ++ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` ++ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` ++ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" ++ exit ;; ++ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) ++ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} ++ exit ;; ++ sparc*:BSD/OS:*:*) ++ echo sparc-unknown-bsdi${UNAME_RELEASE} ++ exit ;; ++ *:BSD/OS:*:*) ++ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} ++ exit ;; ++ *:FreeBSD:*:*) ++ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ++ exit ;; ++ i*:CYGWIN*:*) ++ echo ${UNAME_MACHINE}-pc-cygwin ++ exit ;; ++ i*:MINGW*:*) ++ echo ${UNAME_MACHINE}-pc-mingw32 ++ exit ;; ++ i*:windows32*:*) ++ # uname -m includes "-pc" on this system. ++ echo ${UNAME_MACHINE}-mingw32 ++ exit ;; ++ i*:PW*:*) ++ echo ${UNAME_MACHINE}-pc-pw32 ++ exit ;; ++ x86:Interix*:[34]*) ++ echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' ++ exit ;; ++ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) ++ echo i${UNAME_MACHINE}-pc-mks ++ exit ;; ++ i*:Windows_NT*:* | Pentium*:Windows_NT*:*) ++ # How do we know it's Interix rather than the generic POSIX subsystem? ++ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we ++ # UNAME_MACHINE based on the output of uname instead of i386? ++ echo i586-pc-interix ++ exit ;; ++ i*:UWIN*:*) ++ echo ${UNAME_MACHINE}-pc-uwin ++ exit ;; ++ amd64:CYGWIN*:*:*) ++ echo x86_64-unknown-cygwin ++ exit ;; ++ p*:CYGWIN*:*) ++ echo powerpcle-unknown-cygwin ++ exit ;; ++ prep*:SunOS:5.*:*) ++ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` ++ exit ;; ++ *:GNU:*:*) ++ # the GNU system ++ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` ++ exit ;; ++ *:GNU/*:*:*) ++ # other systems with GNU libc and userland ++ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu ++ exit ;; ++ i*86:Minix:*:*) ++ echo ${UNAME_MACHINE}-pc-minix ++ exit ;; ++ arm*:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; ++ cris:Linux:*:*) ++ echo cris-axis-linux-gnu ++ exit ;; ++ crisv32:Linux:*:*) ++ echo crisv32-axis-linux-gnu ++ exit ;; ++ frv:Linux:*:*) ++ echo frv-unknown-linux-gnu ++ exit ;; ++ ia64:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; ++ m32r*:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; ++ m68*:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; ++ mips:Linux:*:*) ++ eval $set_cc_for_build ++ sed 's/^ //' << EOF >$dummy.c ++ #undef CPU ++ #undef mips ++ #undef mipsel ++ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) ++ CPU=mipsel ++ #else ++ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) ++ CPU=mips ++ #else ++ CPU= ++ #endif ++ #endif ++EOF ++ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` ++ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ++ ;; ++ mips64:Linux:*:*) ++ eval $set_cc_for_build ++ sed 's/^ //' << EOF >$dummy.c ++ #undef CPU ++ #undef mips64 ++ #undef mips64el ++ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) ++ CPU=mips64el ++ #else ++ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) ++ CPU=mips64 ++ #else ++ CPU= ++ #endif ++ #endif ++EOF ++ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` ++ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ++ ;; ++ ppc:Linux:*:*) ++ echo powerpc-unknown-linux-gnu ++ exit ;; ++ ppc64:Linux:*:*) ++ echo powerpc64-unknown-linux-gnu ++ exit ;; ++ alpha:Linux:*:*) ++ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in ++ EV5) UNAME_MACHINE=alphaev5 ;; ++ EV56) UNAME_MACHINE=alphaev56 ;; ++ PCA56) UNAME_MACHINE=alphapca56 ;; ++ PCA57) UNAME_MACHINE=alphapca56 ;; ++ EV6) UNAME_MACHINE=alphaev6 ;; ++ EV67) UNAME_MACHINE=alphaev67 ;; ++ EV68*) UNAME_MACHINE=alphaev68 ;; ++ esac ++ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null ++ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi ++ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ++ exit ;; ++ parisc:Linux:*:* | hppa:Linux:*:*) ++ # Look for CPU level ++ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in ++ PA7*) echo hppa1.1-unknown-linux-gnu ;; ++ PA8*) echo hppa2.0-unknown-linux-gnu ;; ++ *) echo hppa-unknown-linux-gnu ;; ++ esac ++ exit ;; ++ parisc64:Linux:*:* | hppa64:Linux:*:*) ++ echo hppa64-unknown-linux-gnu ++ exit ;; ++ s390:Linux:*:* | s390x:Linux:*:*) ++ echo ${UNAME_MACHINE}-ibm-linux ++ exit ;; ++ sh64*:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; ++ sh*:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; ++ sparc:Linux:*:* | sparc64:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; ++ x86_64:Linux:*:*) ++ echo x86_64-unknown-linux-gnu ++ exit ;; ++ i*86:Linux:*:*) ++ # The BFD linker knows what the default object file format is, so ++ # first see if it will tell us. cd to the root directory to prevent ++ # problems with other programs or directories called `ld' in the path. ++ # Set LC_ALL=C to ensure ld outputs messages in English. ++ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ ++ | sed -ne '/supported targets:/!d ++ s/[ ][ ]*/ /g ++ s/.*supported targets: *// ++ s/ .*// ++ p'` ++ case "$ld_supported_targets" in ++ elf32-i386) ++ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ++ ;; ++ a.out-i386-linux) ++ echo "${UNAME_MACHINE}-pc-linux-gnuaout" ++ exit ;; ++ coff-i386) ++ echo "${UNAME_MACHINE}-pc-linux-gnucoff" ++ exit ;; ++ "") ++ # Either a pre-BFD a.out linker (linux-gnuoldld) or ++ # one that does not give us useful --help. ++ echo "${UNAME_MACHINE}-pc-linux-gnuoldld" ++ exit ;; ++ esac ++ # Determine whether the default compiler is a.out or elf ++ eval $set_cc_for_build ++ sed 's/^ //' << EOF >$dummy.c ++ #include ++ #ifdef __ELF__ ++ # ifdef __GLIBC__ ++ # if __GLIBC__ >= 2 ++ LIBC=gnu ++ # else ++ LIBC=gnulibc1 ++ # endif ++ # else ++ LIBC=gnulibc1 ++ # endif ++ #else ++ #ifdef __INTEL_COMPILER ++ LIBC=gnu ++ #else ++ LIBC=gnuaout ++ #endif ++ #endif ++ #ifdef __dietlibc__ ++ LIBC=dietlibc ++ #endif ++EOF ++ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` ++ test x"${LIBC}" != x && { ++ echo "${UNAME_MACHINE}-pc-linux-${LIBC}" ++ exit ++ } ++ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ++ ;; ++ i*86:DYNIX/ptx:4*:*) ++ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. ++ # earlier versions are messed up and put the nodename in both ++ # sysname and nodename. ++ echo i386-sequent-sysv4 ++ exit ;; ++ i*86:UNIX_SV:4.2MP:2.*) ++ # Unixware is an offshoot of SVR4, but it has its own version ++ # number series starting with 2... ++ # I am not positive that other SVR4 systems won't match this, ++ # I just have to hope. -- rms. ++ # Use sysv4.2uw... so that sysv4* matches it. ++ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} ++ exit ;; ++ i*86:OS/2:*:*) ++ # If we were able to find `uname', then EMX Unix compatibility ++ # is probably installed. ++ echo ${UNAME_MACHINE}-pc-os2-emx ++ exit ;; ++ i*86:XTS-300:*:STOP) ++ echo ${UNAME_MACHINE}-unknown-stop ++ exit ;; ++ i*86:atheos:*:*) ++ echo ${UNAME_MACHINE}-unknown-atheos ++ exit ;; ++ i*86:syllable:*:*) ++ echo ${UNAME_MACHINE}-pc-syllable ++ exit ;; ++ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) ++ echo i386-unknown-lynxos${UNAME_RELEASE} ++ exit ;; ++ i*86:*DOS:*:*) ++ echo ${UNAME_MACHINE}-pc-msdosdjgpp ++ exit ;; ++ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) ++ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` ++ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then ++ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} ++ else ++ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} ++ fi ++ exit ;; ++ i*86:*:5:[678]*) ++ # UnixWare 7.x, OpenUNIX and OpenServer 6. ++ case `/bin/uname -X | grep "^Machine"` in ++ *486*) UNAME_MACHINE=i486 ;; ++ *Pentium) UNAME_MACHINE=i586 ;; ++ *Pent*|*Celeron) UNAME_MACHINE=i686 ;; ++ esac ++ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ++ exit ;; ++ i*86:*:3.2:*) ++ if test -f /usr/options/cb.name; then ++ UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then ++ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` ++ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 ++ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ ++ && UNAME_MACHINE=i586 ++ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ ++ && UNAME_MACHINE=i686 ++ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ ++ && UNAME_MACHINE=i686 ++ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL ++ else ++ echo ${UNAME_MACHINE}-pc-sysv32 ++ fi ++ exit ;; ++ pc:*:*:*) ++ # Left here for compatibility: ++ # uname -m prints for DJGPP always 'pc', but it prints nothing about ++ # the processor, so we play safe by assuming i386. ++ echo i386-pc-msdosdjgpp ++ exit ;; ++ Intel:Mach:3*:*) ++ echo i386-pc-mach3 ++ exit ;; ++ paragon:*:*:*) ++ echo i860-intel-osf1 ++ exit ;; ++ i860:*:4.*:*) # i860-SVR4 ++ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then ++ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 ++ else # Add other i860-SVR4 vendors below as they are discovered. ++ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 ++ fi ++ exit ;; ++ mini*:CTIX:SYS*5:*) ++ # "miniframe" ++ echo m68010-convergent-sysv ++ exit ;; ++ mc68k:UNIX:SYSTEM5:3.51m) ++ echo m68k-convergent-sysv ++ exit ;; ++ M680?0:D-NIX:5.3:*) ++ echo m68k-diab-dnix ++ exit ;; ++ M68*:*:R3V[5678]*:*) ++ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; ++ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) ++ OS_REL='' ++ test -r /etc/.relid \ ++ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` ++ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ ++ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } ++ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ ++ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; ++ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) ++ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ ++ && { echo i486-ncr-sysv4; exit; } ;; ++ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) ++ echo m68k-unknown-lynxos${UNAME_RELEASE} ++ exit ;; ++ mc68030:UNIX_System_V:4.*:*) ++ echo m68k-atari-sysv4 ++ exit ;; ++ TSUNAMI:LynxOS:2.*:*) ++ echo sparc-unknown-lynxos${UNAME_RELEASE} ++ exit ;; ++ rs6000:LynxOS:2.*:*) ++ echo rs6000-unknown-lynxos${UNAME_RELEASE} ++ exit ;; ++ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) ++ echo powerpc-unknown-lynxos${UNAME_RELEASE} ++ exit ;; ++ SM[BE]S:UNIX_SV:*:*) ++ echo mips-dde-sysv${UNAME_RELEASE} ++ exit ;; ++ RM*:ReliantUNIX-*:*:*) ++ echo mips-sni-sysv4 ++ exit ;; ++ RM*:SINIX-*:*:*) ++ echo mips-sni-sysv4 ++ exit ;; ++ *:SINIX-*:*:*) ++ if uname -p 2>/dev/null >/dev/null ; then ++ UNAME_MACHINE=`(uname -p) 2>/dev/null` ++ echo ${UNAME_MACHINE}-sni-sysv4 ++ else ++ echo ns32k-sni-sysv ++ fi ++ exit ;; ++ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort ++ # says ++ echo i586-unisys-sysv4 ++ exit ;; ++ *:UNIX_System_V:4*:FTX*) ++ # From Gerald Hewes . ++ # How about differentiating between stratus architectures? -djm ++ echo hppa1.1-stratus-sysv4 ++ exit ;; ++ *:*:*:FTX*) ++ # From seanf@swdc.stratus.com. ++ echo i860-stratus-sysv4 ++ exit ;; ++ i*86:VOS:*:*) ++ # From Paul.Green@stratus.com. ++ echo ${UNAME_MACHINE}-stratus-vos ++ exit ;; ++ *:VOS:*:*) ++ # From Paul.Green@stratus.com. ++ echo hppa1.1-stratus-vos ++ exit ;; ++ mc68*:A/UX:*:*) ++ echo m68k-apple-aux${UNAME_RELEASE} ++ exit ;; ++ news*:NEWS-OS:6*:*) ++ echo mips-sony-newsos6 ++ exit ;; ++ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) ++ if [ -d /usr/nec ]; then ++ echo mips-nec-sysv${UNAME_RELEASE} ++ else ++ echo mips-unknown-sysv${UNAME_RELEASE} ++ fi ++ exit ;; ++ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. ++ echo powerpc-be-beos ++ exit ;; ++ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. ++ echo powerpc-apple-beos ++ exit ;; ++ BePC:BeOS:*:*) # BeOS running on Intel PC compatible. ++ echo i586-pc-beos ++ exit ;; ++ SX-4:SUPER-UX:*:*) ++ echo sx4-nec-superux${UNAME_RELEASE} ++ exit ;; ++ SX-5:SUPER-UX:*:*) ++ echo sx5-nec-superux${UNAME_RELEASE} ++ exit ;; ++ SX-6:SUPER-UX:*:*) ++ echo sx6-nec-superux${UNAME_RELEASE} ++ exit ;; ++ Power*:Rhapsody:*:*) ++ echo powerpc-apple-rhapsody${UNAME_RELEASE} ++ exit ;; ++ *:Rhapsody:*:*) ++ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} ++ exit ;; ++ *:Darwin:*:*) ++ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown ++ case $UNAME_PROCESSOR in ++ *86) UNAME_PROCESSOR=i686 ;; ++ unknown) UNAME_PROCESSOR=powerpc ;; ++ esac ++ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} ++ exit ;; ++ *:procnto*:*:* | *:QNX:[0123456789]*:*) ++ UNAME_PROCESSOR=`uname -p` ++ if test "$UNAME_PROCESSOR" = "x86"; then ++ UNAME_PROCESSOR=i386 ++ UNAME_MACHINE=pc ++ fi ++ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} ++ exit ;; ++ *:QNX:*:4*) ++ echo i386-pc-qnx ++ exit ;; ++ NSE-?:NONSTOP_KERNEL:*:*) ++ echo nse-tandem-nsk${UNAME_RELEASE} ++ exit ;; ++ NSR-?:NONSTOP_KERNEL:*:*) ++ echo nsr-tandem-nsk${UNAME_RELEASE} ++ exit ;; ++ *:NonStop-UX:*:*) ++ echo mips-compaq-nonstopux ++ exit ;; ++ BS2000:POSIX*:*:*) ++ echo bs2000-siemens-sysv ++ exit ;; ++ DS/*:UNIX_System_V:*:*) ++ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} ++ exit ;; ++ *:Plan9:*:*) ++ # "uname -m" is not consistent, so use $cputype instead. 386 ++ # is converted to i386 for consistency with other x86 ++ # operating systems. ++ if test "$cputype" = "386"; then ++ UNAME_MACHINE=i386 ++ else ++ UNAME_MACHINE="$cputype" ++ fi ++ echo ${UNAME_MACHINE}-unknown-plan9 ++ exit ;; ++ *:TOPS-10:*:*) ++ echo pdp10-unknown-tops10 ++ exit ;; ++ *:TENEX:*:*) ++ echo pdp10-unknown-tenex ++ exit ;; ++ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) ++ echo pdp10-dec-tops20 ++ exit ;; ++ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) ++ echo pdp10-xkl-tops20 ++ exit ;; ++ *:TOPS-20:*:*) ++ echo pdp10-unknown-tops20 ++ exit ;; ++ *:ITS:*:*) ++ echo pdp10-unknown-its ++ exit ;; ++ SEI:*:*:SEIUX) ++ echo mips-sei-seiux${UNAME_RELEASE} ++ exit ;; ++ *:DragonFly:*:*) ++ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ++ exit ;; ++ *:*VMS:*:*) ++ UNAME_MACHINE=`(uname -p) 2>/dev/null` ++ case "${UNAME_MACHINE}" in ++ A*) echo alpha-dec-vms ; exit ;; ++ I*) echo ia64-dec-vms ; exit ;; ++ V*) echo vax-dec-vms ; exit ;; ++ esac ;; ++ *:XENIX:*:SysV) ++ echo i386-pc-xenix ++ exit ;; ++ i*86:skyos:*:*) ++ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' ++ exit ;; ++esac ++ ++#echo '(No uname command or uname output not recognized.)' 1>&2 ++#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 ++ ++eval $set_cc_for_build ++cat >$dummy.c < ++# include ++#endif ++main () ++{ ++#if defined (sony) ++#if defined (MIPSEB) ++ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, ++ I don't know.... */ ++ printf ("mips-sony-bsd\n"); exit (0); ++#else ++#include ++ printf ("m68k-sony-newsos%s\n", ++#ifdef NEWSOS4 ++ "4" ++#else ++ "" ++#endif ++ ); exit (0); ++#endif ++#endif ++ ++#if defined (__arm) && defined (__acorn) && defined (__unix) ++ printf ("arm-acorn-riscix\n"); exit (0); ++#endif ++ ++#if defined (hp300) && !defined (hpux) ++ printf ("m68k-hp-bsd\n"); exit (0); ++#endif ++ ++#if defined (NeXT) ++#if !defined (__ARCHITECTURE__) ++#define __ARCHITECTURE__ "m68k" ++#endif ++ int version; ++ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; ++ if (version < 4) ++ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); ++ else ++ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); ++ exit (0); ++#endif ++ ++#if defined (MULTIMAX) || defined (n16) ++#if defined (UMAXV) ++ printf ("ns32k-encore-sysv\n"); exit (0); ++#else ++#if defined (CMU) ++ printf ("ns32k-encore-mach\n"); exit (0); ++#else ++ printf ("ns32k-encore-bsd\n"); exit (0); ++#endif ++#endif ++#endif ++ ++#if defined (__386BSD__) ++ printf ("i386-pc-bsd\n"); exit (0); ++#endif ++ ++#if defined (sequent) ++#if defined (i386) ++ printf ("i386-sequent-dynix\n"); exit (0); ++#endif ++#if defined (ns32000) ++ printf ("ns32k-sequent-dynix\n"); exit (0); ++#endif ++#endif ++ ++#if defined (_SEQUENT_) ++ struct utsname un; ++ ++ uname(&un); ++ ++ if (strncmp(un.version, "V2", 2) == 0) { ++ printf ("i386-sequent-ptx2\n"); exit (0); ++ } ++ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ ++ printf ("i386-sequent-ptx1\n"); exit (0); ++ } ++ printf ("i386-sequent-ptx\n"); exit (0); ++ ++#endif ++ ++#if defined (vax) ++# if !defined (ultrix) ++# include ++# if defined (BSD) ++# if BSD == 43 ++ printf ("vax-dec-bsd4.3\n"); exit (0); ++# else ++# if BSD == 199006 ++ printf ("vax-dec-bsd4.3reno\n"); exit (0); ++# else ++ printf ("vax-dec-bsd\n"); exit (0); ++# endif ++# endif ++# else ++ printf ("vax-dec-bsd\n"); exit (0); ++# endif ++# else ++ printf ("vax-dec-ultrix\n"); exit (0); ++# endif ++#endif ++ ++#if defined (alliant) && defined (i860) ++ printf ("i860-alliant-bsd\n"); exit (0); ++#endif ++ ++ exit (1); ++} ++EOF ++ ++$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && ++ { echo "$SYSTEM_NAME"; exit; } ++ ++# Apollos put the system type in the environment. ++ ++test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } ++ ++# Convex versions that predate uname can use getsysinfo(1) ++ ++if [ -x /usr/convex/getsysinfo ] ++then ++ case `getsysinfo -f cpu_type` in ++ c1*) ++ echo c1-convex-bsd ++ exit ;; ++ c2*) ++ if getsysinfo -f scalar_acc ++ then echo c32-convex-bsd ++ else echo c2-convex-bsd ++ fi ++ exit ;; ++ c34*) ++ echo c34-convex-bsd ++ exit ;; ++ c38*) ++ echo c38-convex-bsd ++ exit ;; ++ c4*) ++ echo c4-convex-bsd ++ exit ;; ++ esac ++fi ++ ++cat >&2 < in order to provide the needed ++information to handle your system. ++ ++config.guess timestamp = $timestamp ++ ++uname -m = `(uname -m) 2>/dev/null || echo unknown` ++uname -r = `(uname -r) 2>/dev/null || echo unknown` ++uname -s = `(uname -s) 2>/dev/null || echo unknown` ++uname -v = `(uname -v) 2>/dev/null || echo unknown` ++ ++/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` ++/bin/uname -X = `(/bin/uname -X) 2>/dev/null` ++ ++hostinfo = `(hostinfo) 2>/dev/null` ++/bin/universe = `(/bin/universe) 2>/dev/null` ++/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` ++/bin/arch = `(/bin/arch) 2>/dev/null` ++/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` ++/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` ++ ++UNAME_MACHINE = ${UNAME_MACHINE} ++UNAME_RELEASE = ${UNAME_RELEASE} ++UNAME_SYSTEM = ${UNAME_SYSTEM} ++UNAME_VERSION = ${UNAME_VERSION} ++EOF ++ ++exit 1 ++ ++# Local variables: ++# eval: (add-hook 'write-file-hooks 'time-stamp) ++# time-stamp-start: "timestamp='" ++# time-stamp-format: "%:y-%02m-%02d" ++# time-stamp-end: "'" ++# End: +diff --git a/utils/open-isns/aclocal/config.sub b/utils/open-isns/aclocal/config.sub +new file mode 100644 +index 0000000..519f2cd +--- /dev/null ++++ b/utils/open-isns/aclocal/config.sub +@@ -0,0 +1,1570 @@ ++#! /bin/sh ++# Configuration validation subroutine script. ++# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, ++# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. ++ ++timestamp='2005-05-12' ++ ++# This file is (in principle) common to ALL GNU software. ++# The presence of a machine in this file suggests that SOME GNU software ++# can handle that machine. It does not imply ALL GNU software can. ++# ++# This file is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA ++# 02110-1301, USA. ++# ++# As a special exception to the GNU General Public License, if you ++# distribute this file as part of a program that contains a ++# configuration script generated by Autoconf, you may include it under ++# the same distribution terms that you use for the rest of that program. ++ ++ ++# Please send patches to . Submit a context ++# diff and a properly formatted ChangeLog entry. ++# ++# Configuration subroutine to validate and canonicalize a configuration type. ++# Supply the specified configuration type as an argument. ++# If it is invalid, we print an error message on stderr and exit with code 1. ++# Otherwise, we print the canonical config type on stdout and succeed. ++ ++# This file is supposed to be the same for all GNU packages ++# and recognize all the CPU types, system types and aliases ++# that are meaningful with *any* GNU software. ++# Each package is responsible for reporting which valid configurations ++# it does not support. The user should be able to distinguish ++# a failure to support a valid configuration from a meaningless ++# configuration. ++ ++# The goal of this file is to map all the various variations of a given ++# machine specification into a single specification in the form: ++# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM ++# or in some cases, the newer four-part form: ++# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM ++# It is wrong to echo any other type of specification. ++ ++me=`echo "$0" | sed -e 's,.*/,,'` ++ ++usage="\ ++Usage: $0 [OPTION] CPU-MFR-OPSYS ++ $0 [OPTION] ALIAS ++ ++Canonicalize a configuration name. ++ ++Operation modes: ++ -h, --help print this help, then exit ++ -t, --time-stamp print date of last modification, then exit ++ -v, --version print version number, then exit ++ ++Report bugs and patches to ." ++ ++version="\ ++GNU config.sub ($timestamp) ++ ++Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 ++Free Software Foundation, Inc. ++ ++This is free software; see the source for copying conditions. There is NO ++warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." ++ ++help=" ++Try \`$me --help' for more information." ++ ++# Parse command line ++while test $# -gt 0 ; do ++ case $1 in ++ --time-stamp | --time* | -t ) ++ echo "$timestamp" ; exit ;; ++ --version | -v ) ++ echo "$version" ; exit ;; ++ --help | --h* | -h ) ++ echo "$usage"; exit ;; ++ -- ) # Stop option processing ++ shift; break ;; ++ - ) # Use stdin as input. ++ break ;; ++ -* ) ++ echo "$me: invalid option $1$help" ++ exit 1 ;; ++ ++ *local*) ++ # First pass through any local machine types. ++ echo $1 ++ exit ;; ++ ++ * ) ++ break ;; ++ esac ++done ++ ++case $# in ++ 0) echo "$me: missing argument$help" >&2 ++ exit 1;; ++ 1) ;; ++ *) echo "$me: too many arguments$help" >&2 ++ exit 1;; ++esac ++ ++# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). ++# Here we must recognize all the valid KERNEL-OS combinations. ++maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` ++case $maybe_os in ++ nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ ++ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) ++ os=-$maybe_os ++ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ++ ;; ++ *) ++ basic_machine=`echo $1 | sed 's/-[^-]*$//'` ++ if [ $basic_machine != $1 ] ++ then os=`echo $1 | sed 's/.*-/-/'` ++ else os=; fi ++ ;; ++esac ++ ++### Let's recognize common machines as not being operating systems so ++### that things like config.sub decstation-3100 work. We also ++### recognize some manufacturers as not being operating systems, so we ++### can provide default operating systems below. ++case $os in ++ -sun*os*) ++ # Prevent following clause from handling this invalid input. ++ ;; ++ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ ++ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ ++ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ ++ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ ++ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ ++ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ ++ -apple | -axis | -knuth | -cray) ++ os= ++ basic_machine=$1 ++ ;; ++ -sim | -cisco | -oki | -wec | -winbond) ++ os= ++ basic_machine=$1 ++ ;; ++ -scout) ++ ;; ++ -wrs) ++ os=-vxworks ++ basic_machine=$1 ++ ;; ++ -chorusos*) ++ os=-chorusos ++ basic_machine=$1 ++ ;; ++ -chorusrdb) ++ os=-chorusrdb ++ basic_machine=$1 ++ ;; ++ -hiux*) ++ os=-hiuxwe2 ++ ;; ++ -sco5) ++ os=-sco3.2v5 ++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ++ ;; ++ -sco4) ++ os=-sco3.2v4 ++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ++ ;; ++ -sco3.2.[4-9]*) ++ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` ++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ++ ;; ++ -sco3.2v[4-9]*) ++ # Don't forget version if it is 3.2v4 or newer. ++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ++ ;; ++ -sco*) ++ os=-sco3.2v2 ++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ++ ;; ++ -udk*) ++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ++ ;; ++ -isc) ++ os=-isc2.2 ++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ++ ;; ++ -clix*) ++ basic_machine=clipper-intergraph ++ ;; ++ -isc*) ++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ++ ;; ++ -lynx*) ++ os=-lynxos ++ ;; ++ -ptx*) ++ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ++ ;; ++ -windowsnt*) ++ os=`echo $os | sed -e 's/windowsnt/winnt/'` ++ ;; ++ -psos*) ++ os=-psos ++ ;; ++ -mint | -mint[0-9]*) ++ basic_machine=m68k-atari ++ os=-mint ++ ;; ++esac ++ ++# Decode aliases for certain CPU-COMPANY combinations. ++case $basic_machine in ++ # Recognize the basic CPU types without company name. ++ # Some are omitted here because they have special meanings below. ++ 1750a | 580 \ ++ | a29k \ ++ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ ++ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ ++ | am33_2.0 \ ++ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ ++ | bfin \ ++ | c4x | clipper \ ++ | d10v | d30v | dlx | dsp16xx \ ++ | fr30 | frv \ ++ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ ++ | i370 | i860 | i960 | ia64 \ ++ | ip2k | iq2000 \ ++ | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ ++ | mips | mipsbe | mipseb | mipsel | mipsle \ ++ | mips16 \ ++ | mips64 | mips64el \ ++ | mips64vr | mips64vrel \ ++ | mips64orion | mips64orionel \ ++ | mips64vr4100 | mips64vr4100el \ ++ | mips64vr4300 | mips64vr4300el \ ++ | mips64vr5000 | mips64vr5000el \ ++ | mipsisa32 | mipsisa32el \ ++ | mipsisa32r2 | mipsisa32r2el \ ++ | mipsisa64 | mipsisa64el \ ++ | mipsisa64r2 | mipsisa64r2el \ ++ | mipsisa64sb1 | mipsisa64sb1el \ ++ | mipsisa64sr71k | mipsisa64sr71kel \ ++ | mipstx39 | mipstx39el \ ++ | mn10200 | mn10300 \ ++ | msp430 \ ++ | ns16k | ns32k \ ++ | openrisc | or32 \ ++ | pdp10 | pdp11 | pj | pjl \ ++ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ ++ | pyramid \ ++ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ ++ | sh64 | sh64le \ ++ | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ ++ | sparcv8 | sparcv9 | sparcv9b \ ++ | strongarm \ ++ | tahoe | thumb | tic4x | tic80 | tron \ ++ | v850 | v850e \ ++ | we32k \ ++ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ ++ | z8k) ++ basic_machine=$basic_machine-unknown ++ ;; ++ m6811 | m68hc11 | m6812 | m68hc12) ++ # Motorola 68HC11/12. ++ basic_machine=$basic_machine-unknown ++ os=-none ++ ;; ++ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ++ ;; ++ ++ # We use `pc' rather than `unknown' ++ # because (1) that's what they normally are, and ++ # (2) the word "unknown" tends to confuse beginning users. ++ i*86 | x86_64) ++ basic_machine=$basic_machine-pc ++ ;; ++ # Object if more than one company name word. ++ *-*-*) ++ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 ++ exit 1 ++ ;; ++ # Recognize the basic CPU types with company name. ++ 580-* \ ++ | a29k-* \ ++ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ ++ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ ++ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ ++ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ ++ | avr-* \ ++ | bfin-* | bs2000-* \ ++ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ ++ | clipper-* | craynv-* | cydra-* \ ++ | d10v-* | d30v-* | dlx-* \ ++ | elxsi-* \ ++ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ ++ | h8300-* | h8500-* \ ++ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ ++ | i*86-* | i860-* | i960-* | ia64-* \ ++ | ip2k-* | iq2000-* \ ++ | m32r-* | m32rle-* \ ++ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ ++ | m88110-* | m88k-* | maxq-* | mcore-* \ ++ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ ++ | mips16-* \ ++ | mips64-* | mips64el-* \ ++ | mips64vr-* | mips64vrel-* \ ++ | mips64orion-* | mips64orionel-* \ ++ | mips64vr4100-* | mips64vr4100el-* \ ++ | mips64vr4300-* | mips64vr4300el-* \ ++ | mips64vr5000-* | mips64vr5000el-* \ ++ | mipsisa32-* | mipsisa32el-* \ ++ | mipsisa32r2-* | mipsisa32r2el-* \ ++ | mipsisa64-* | mipsisa64el-* \ ++ | mipsisa64r2-* | mipsisa64r2el-* \ ++ | mipsisa64sb1-* | mipsisa64sb1el-* \ ++ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ ++ | mipstx39-* | mipstx39el-* \ ++ | mmix-* \ ++ | msp430-* \ ++ | none-* | np1-* | ns16k-* | ns32k-* \ ++ | orion-* \ ++ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ ++ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ ++ | pyramid-* \ ++ | romp-* | rs6000-* \ ++ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ ++ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ ++ | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ ++ | sparclite-* \ ++ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ ++ | tahoe-* | thumb-* \ ++ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ ++ | tron-* \ ++ | v850-* | v850e-* | vax-* \ ++ | we32k-* \ ++ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ ++ | xstormy16-* | xtensa-* \ ++ | ymp-* \ ++ | z8k-*) ++ ;; ++ # Recognize the various machine names and aliases which stand ++ # for a CPU type and a company and sometimes even an OS. ++ 386bsd) ++ basic_machine=i386-unknown ++ os=-bsd ++ ;; ++ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) ++ basic_machine=m68000-att ++ ;; ++ 3b*) ++ basic_machine=we32k-att ++ ;; ++ a29khif) ++ basic_machine=a29k-amd ++ os=-udi ++ ;; ++ abacus) ++ basic_machine=abacus-unknown ++ ;; ++ adobe68k) ++ basic_machine=m68010-adobe ++ os=-scout ++ ;; ++ alliant | fx80) ++ basic_machine=fx80-alliant ++ ;; ++ altos | altos3068) ++ basic_machine=m68k-altos ++ ;; ++ am29k) ++ basic_machine=a29k-none ++ os=-bsd ++ ;; ++ amd64) ++ basic_machine=x86_64-pc ++ ;; ++ amd64-*) ++ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; ++ amdahl) ++ basic_machine=580-amdahl ++ os=-sysv ++ ;; ++ amiga | amiga-*) ++ basic_machine=m68k-unknown ++ ;; ++ amigaos | amigados) ++ basic_machine=m68k-unknown ++ os=-amigaos ++ ;; ++ amigaunix | amix) ++ basic_machine=m68k-unknown ++ os=-sysv4 ++ ;; ++ apollo68) ++ basic_machine=m68k-apollo ++ os=-sysv ++ ;; ++ apollo68bsd) ++ basic_machine=m68k-apollo ++ os=-bsd ++ ;; ++ aux) ++ basic_machine=m68k-apple ++ os=-aux ++ ;; ++ balance) ++ basic_machine=ns32k-sequent ++ os=-dynix ++ ;; ++ c90) ++ basic_machine=c90-cray ++ os=-unicos ++ ;; ++ convex-c1) ++ basic_machine=c1-convex ++ os=-bsd ++ ;; ++ convex-c2) ++ basic_machine=c2-convex ++ os=-bsd ++ ;; ++ convex-c32) ++ basic_machine=c32-convex ++ os=-bsd ++ ;; ++ convex-c34) ++ basic_machine=c34-convex ++ os=-bsd ++ ;; ++ convex-c38) ++ basic_machine=c38-convex ++ os=-bsd ++ ;; ++ cray | j90) ++ basic_machine=j90-cray ++ os=-unicos ++ ;; ++ craynv) ++ basic_machine=craynv-cray ++ os=-unicosmp ++ ;; ++ cr16c) ++ basic_machine=cr16c-unknown ++ os=-elf ++ ;; ++ crds | unos) ++ basic_machine=m68k-crds ++ ;; ++ crisv32 | crisv32-* | etraxfs*) ++ basic_machine=crisv32-axis ++ ;; ++ cris | cris-* | etrax*) ++ basic_machine=cris-axis ++ ;; ++ crx) ++ basic_machine=crx-unknown ++ os=-elf ++ ;; ++ da30 | da30-*) ++ basic_machine=m68k-da30 ++ ;; ++ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) ++ basic_machine=mips-dec ++ ;; ++ decsystem10* | dec10*) ++ basic_machine=pdp10-dec ++ os=-tops10 ++ ;; ++ decsystem20* | dec20*) ++ basic_machine=pdp10-dec ++ os=-tops20 ++ ;; ++ delta | 3300 | motorola-3300 | motorola-delta \ ++ | 3300-motorola | delta-motorola) ++ basic_machine=m68k-motorola ++ ;; ++ delta88) ++ basic_machine=m88k-motorola ++ os=-sysv3 ++ ;; ++ djgpp) ++ basic_machine=i586-pc ++ os=-msdosdjgpp ++ ;; ++ dpx20 | dpx20-*) ++ basic_machine=rs6000-bull ++ os=-bosx ++ ;; ++ dpx2* | dpx2*-bull) ++ basic_machine=m68k-bull ++ os=-sysv3 ++ ;; ++ ebmon29k) ++ basic_machine=a29k-amd ++ os=-ebmon ++ ;; ++ elxsi) ++ basic_machine=elxsi-elxsi ++ os=-bsd ++ ;; ++ encore | umax | mmax) ++ basic_machine=ns32k-encore ++ ;; ++ es1800 | OSE68k | ose68k | ose | OSE) ++ basic_machine=m68k-ericsson ++ os=-ose ++ ;; ++ fx2800) ++ basic_machine=i860-alliant ++ ;; ++ genix) ++ basic_machine=ns32k-ns ++ ;; ++ gmicro) ++ basic_machine=tron-gmicro ++ os=-sysv ++ ;; ++ go32) ++ basic_machine=i386-pc ++ os=-go32 ++ ;; ++ h3050r* | hiux*) ++ basic_machine=hppa1.1-hitachi ++ os=-hiuxwe2 ++ ;; ++ h8300hms) ++ basic_machine=h8300-hitachi ++ os=-hms ++ ;; ++ h8300xray) ++ basic_machine=h8300-hitachi ++ os=-xray ++ ;; ++ h8500hms) ++ basic_machine=h8500-hitachi ++ os=-hms ++ ;; ++ harris) ++ basic_machine=m88k-harris ++ os=-sysv3 ++ ;; ++ hp300-*) ++ basic_machine=m68k-hp ++ ;; ++ hp300bsd) ++ basic_machine=m68k-hp ++ os=-bsd ++ ;; ++ hp300hpux) ++ basic_machine=m68k-hp ++ os=-hpux ++ ;; ++ hp3k9[0-9][0-9] | hp9[0-9][0-9]) ++ basic_machine=hppa1.0-hp ++ ;; ++ hp9k2[0-9][0-9] | hp9k31[0-9]) ++ basic_machine=m68000-hp ++ ;; ++ hp9k3[2-9][0-9]) ++ basic_machine=m68k-hp ++ ;; ++ hp9k6[0-9][0-9] | hp6[0-9][0-9]) ++ basic_machine=hppa1.0-hp ++ ;; ++ hp9k7[0-79][0-9] | hp7[0-79][0-9]) ++ basic_machine=hppa1.1-hp ++ ;; ++ hp9k78[0-9] | hp78[0-9]) ++ # FIXME: really hppa2.0-hp ++ basic_machine=hppa1.1-hp ++ ;; ++ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) ++ # FIXME: really hppa2.0-hp ++ basic_machine=hppa1.1-hp ++ ;; ++ hp9k8[0-9][13679] | hp8[0-9][13679]) ++ basic_machine=hppa1.1-hp ++ ;; ++ hp9k8[0-9][0-9] | hp8[0-9][0-9]) ++ basic_machine=hppa1.0-hp ++ ;; ++ hppa-next) ++ os=-nextstep3 ++ ;; ++ hppaosf) ++ basic_machine=hppa1.1-hp ++ os=-osf ++ ;; ++ hppro) ++ basic_machine=hppa1.1-hp ++ os=-proelf ++ ;; ++ i370-ibm* | ibm*) ++ basic_machine=i370-ibm ++ ;; ++# I'm not sure what "Sysv32" means. Should this be sysv3.2? ++ i*86v32) ++ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` ++ os=-sysv32 ++ ;; ++ i*86v4*) ++ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` ++ os=-sysv4 ++ ;; ++ i*86v) ++ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` ++ os=-sysv ++ ;; ++ i*86sol2) ++ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` ++ os=-solaris2 ++ ;; ++ i386mach) ++ basic_machine=i386-mach ++ os=-mach ++ ;; ++ i386-vsta | vsta) ++ basic_machine=i386-unknown ++ os=-vsta ++ ;; ++ iris | iris4d) ++ basic_machine=mips-sgi ++ case $os in ++ -irix*) ++ ;; ++ *) ++ os=-irix4 ++ ;; ++ esac ++ ;; ++ isi68 | isi) ++ basic_machine=m68k-isi ++ os=-sysv ++ ;; ++ m88k-omron*) ++ basic_machine=m88k-omron ++ ;; ++ magnum | m3230) ++ basic_machine=mips-mips ++ os=-sysv ++ ;; ++ merlin) ++ basic_machine=ns32k-utek ++ os=-sysv ++ ;; ++ mingw32) ++ basic_machine=i386-pc ++ os=-mingw32 ++ ;; ++ miniframe) ++ basic_machine=m68000-convergent ++ ;; ++ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) ++ basic_machine=m68k-atari ++ os=-mint ++ ;; ++ mips3*-*) ++ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ++ ;; ++ mips3*) ++ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ++ ;; ++ monitor) ++ basic_machine=m68k-rom68k ++ os=-coff ++ ;; ++ morphos) ++ basic_machine=powerpc-unknown ++ os=-morphos ++ ;; ++ msdos) ++ basic_machine=i386-pc ++ os=-msdos ++ ;; ++ mvs) ++ basic_machine=i370-ibm ++ os=-mvs ++ ;; ++ ncr3000) ++ basic_machine=i486-ncr ++ os=-sysv4 ++ ;; ++ netbsd386) ++ basic_machine=i386-unknown ++ os=-netbsd ++ ;; ++ netwinder) ++ basic_machine=armv4l-rebel ++ os=-linux ++ ;; ++ news | news700 | news800 | news900) ++ basic_machine=m68k-sony ++ os=-newsos ++ ;; ++ news1000) ++ basic_machine=m68030-sony ++ os=-newsos ++ ;; ++ news-3600 | risc-news) ++ basic_machine=mips-sony ++ os=-newsos ++ ;; ++ necv70) ++ basic_machine=v70-nec ++ os=-sysv ++ ;; ++ next | m*-next ) ++ basic_machine=m68k-next ++ case $os in ++ -nextstep* ) ++ ;; ++ -ns2*) ++ os=-nextstep2 ++ ;; ++ *) ++ os=-nextstep3 ++ ;; ++ esac ++ ;; ++ nh3000) ++ basic_machine=m68k-harris ++ os=-cxux ++ ;; ++ nh[45]000) ++ basic_machine=m88k-harris ++ os=-cxux ++ ;; ++ nindy960) ++ basic_machine=i960-intel ++ os=-nindy ++ ;; ++ mon960) ++ basic_machine=i960-intel ++ os=-mon960 ++ ;; ++ nonstopux) ++ basic_machine=mips-compaq ++ os=-nonstopux ++ ;; ++ np1) ++ basic_machine=np1-gould ++ ;; ++ nsr-tandem) ++ basic_machine=nsr-tandem ++ ;; ++ op50n-* | op60c-*) ++ basic_machine=hppa1.1-oki ++ os=-proelf ++ ;; ++ or32 | or32-*) ++ basic_machine=or32-unknown ++ os=-coff ++ ;; ++ os400) ++ basic_machine=powerpc-ibm ++ os=-os400 ++ ;; ++ OSE68000 | ose68000) ++ basic_machine=m68000-ericsson ++ os=-ose ++ ;; ++ os68k) ++ basic_machine=m68k-none ++ os=-os68k ++ ;; ++ pa-hitachi) ++ basic_machine=hppa1.1-hitachi ++ os=-hiuxwe2 ++ ;; ++ paragon) ++ basic_machine=i860-intel ++ os=-osf ++ ;; ++ pbd) ++ basic_machine=sparc-tti ++ ;; ++ pbb) ++ basic_machine=m68k-tti ++ ;; ++ pc532 | pc532-*) ++ basic_machine=ns32k-pc532 ++ ;; ++ pentium | p5 | k5 | k6 | nexgen | viac3) ++ basic_machine=i586-pc ++ ;; ++ pentiumpro | p6 | 6x86 | athlon | athlon_*) ++ basic_machine=i686-pc ++ ;; ++ pentiumii | pentium2 | pentiumiii | pentium3) ++ basic_machine=i686-pc ++ ;; ++ pentium4) ++ basic_machine=i786-pc ++ ;; ++ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) ++ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; ++ pentiumpro-* | p6-* | 6x86-* | athlon-*) ++ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; ++ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) ++ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; ++ pentium4-*) ++ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; ++ pn) ++ basic_machine=pn-gould ++ ;; ++ power) basic_machine=power-ibm ++ ;; ++ ppc) basic_machine=powerpc-unknown ++ ;; ++ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; ++ ppcle | powerpclittle | ppc-le | powerpc-little) ++ basic_machine=powerpcle-unknown ++ ;; ++ ppcle-* | powerpclittle-*) ++ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; ++ ppc64) basic_machine=powerpc64-unknown ++ ;; ++ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; ++ ppc64le | powerpc64little | ppc64-le | powerpc64-little) ++ basic_machine=powerpc64le-unknown ++ ;; ++ ppc64le-* | powerpc64little-*) ++ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; ++ ps2) ++ basic_machine=i386-ibm ++ ;; ++ pw32) ++ basic_machine=i586-unknown ++ os=-pw32 ++ ;; ++ rom68k) ++ basic_machine=m68k-rom68k ++ os=-coff ++ ;; ++ rm[46]00) ++ basic_machine=mips-siemens ++ ;; ++ rtpc | rtpc-*) ++ basic_machine=romp-ibm ++ ;; ++ s390 | s390-*) ++ basic_machine=s390-ibm ++ ;; ++ s390x | s390x-*) ++ basic_machine=s390x-ibm ++ ;; ++ sa29200) ++ basic_machine=a29k-amd ++ os=-udi ++ ;; ++ sb1) ++ basic_machine=mipsisa64sb1-unknown ++ ;; ++ sb1el) ++ basic_machine=mipsisa64sb1el-unknown ++ ;; ++ sei) ++ basic_machine=mips-sei ++ os=-seiux ++ ;; ++ sequent) ++ basic_machine=i386-sequent ++ ;; ++ sh) ++ basic_machine=sh-hitachi ++ os=-hms ++ ;; ++ sh64) ++ basic_machine=sh64-unknown ++ ;; ++ sparclite-wrs | simso-wrs) ++ basic_machine=sparclite-wrs ++ os=-vxworks ++ ;; ++ sps7) ++ basic_machine=m68k-bull ++ os=-sysv2 ++ ;; ++ spur) ++ basic_machine=spur-unknown ++ ;; ++ st2000) ++ basic_machine=m68k-tandem ++ ;; ++ stratus) ++ basic_machine=i860-stratus ++ os=-sysv4 ++ ;; ++ sun2) ++ basic_machine=m68000-sun ++ ;; ++ sun2os3) ++ basic_machine=m68000-sun ++ os=-sunos3 ++ ;; ++ sun2os4) ++ basic_machine=m68000-sun ++ os=-sunos4 ++ ;; ++ sun3os3) ++ basic_machine=m68k-sun ++ os=-sunos3 ++ ;; ++ sun3os4) ++ basic_machine=m68k-sun ++ os=-sunos4 ++ ;; ++ sun4os3) ++ basic_machine=sparc-sun ++ os=-sunos3 ++ ;; ++ sun4os4) ++ basic_machine=sparc-sun ++ os=-sunos4 ++ ;; ++ sun4sol2) ++ basic_machine=sparc-sun ++ os=-solaris2 ++ ;; ++ sun3 | sun3-*) ++ basic_machine=m68k-sun ++ ;; ++ sun4) ++ basic_machine=sparc-sun ++ ;; ++ sun386 | sun386i | roadrunner) ++ basic_machine=i386-sun ++ ;; ++ sv1) ++ basic_machine=sv1-cray ++ os=-unicos ++ ;; ++ symmetry) ++ basic_machine=i386-sequent ++ os=-dynix ++ ;; ++ t3e) ++ basic_machine=alphaev5-cray ++ os=-unicos ++ ;; ++ t90) ++ basic_machine=t90-cray ++ os=-unicos ++ ;; ++ tic54x | c54x*) ++ basic_machine=tic54x-unknown ++ os=-coff ++ ;; ++ tic55x | c55x*) ++ basic_machine=tic55x-unknown ++ os=-coff ++ ;; ++ tic6x | c6x*) ++ basic_machine=tic6x-unknown ++ os=-coff ++ ;; ++ tx39) ++ basic_machine=mipstx39-unknown ++ ;; ++ tx39el) ++ basic_machine=mipstx39el-unknown ++ ;; ++ toad1) ++ basic_machine=pdp10-xkl ++ os=-tops20 ++ ;; ++ tower | tower-32) ++ basic_machine=m68k-ncr ++ ;; ++ tpf) ++ basic_machine=s390x-ibm ++ os=-tpf ++ ;; ++ udi29k) ++ basic_machine=a29k-amd ++ os=-udi ++ ;; ++ ultra3) ++ basic_machine=a29k-nyu ++ os=-sym1 ++ ;; ++ v810 | necv810) ++ basic_machine=v810-nec ++ os=-none ++ ;; ++ vaxv) ++ basic_machine=vax-dec ++ os=-sysv ++ ;; ++ vms) ++ basic_machine=vax-dec ++ os=-vms ++ ;; ++ vpp*|vx|vx-*) ++ basic_machine=f301-fujitsu ++ ;; ++ vxworks960) ++ basic_machine=i960-wrs ++ os=-vxworks ++ ;; ++ vxworks68) ++ basic_machine=m68k-wrs ++ os=-vxworks ++ ;; ++ vxworks29k) ++ basic_machine=a29k-wrs ++ os=-vxworks ++ ;; ++ w65*) ++ basic_machine=w65-wdc ++ os=-none ++ ;; ++ w89k-*) ++ basic_machine=hppa1.1-winbond ++ os=-proelf ++ ;; ++ xbox) ++ basic_machine=i686-pc ++ os=-mingw32 ++ ;; ++ xps | xps100) ++ basic_machine=xps100-honeywell ++ ;; ++ ymp) ++ basic_machine=ymp-cray ++ os=-unicos ++ ;; ++ z8k-*-coff) ++ basic_machine=z8k-unknown ++ os=-sim ++ ;; ++ none) ++ basic_machine=none-none ++ os=-none ++ ;; ++ ++# Here we handle the default manufacturer of certain CPU types. It is in ++# some cases the only manufacturer, in others, it is the most popular. ++ w89k) ++ basic_machine=hppa1.1-winbond ++ ;; ++ op50n) ++ basic_machine=hppa1.1-oki ++ ;; ++ op60c) ++ basic_machine=hppa1.1-oki ++ ;; ++ romp) ++ basic_machine=romp-ibm ++ ;; ++ mmix) ++ basic_machine=mmix-knuth ++ ;; ++ rs6000) ++ basic_machine=rs6000-ibm ++ ;; ++ vax) ++ basic_machine=vax-dec ++ ;; ++ pdp10) ++ # there are many clones, so DEC is not a safe bet ++ basic_machine=pdp10-unknown ++ ;; ++ pdp11) ++ basic_machine=pdp11-dec ++ ;; ++ we32k) ++ basic_machine=we32k-att ++ ;; ++ sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) ++ basic_machine=sh-unknown ++ ;; ++ sh64) ++ basic_machine=sh64-unknown ++ ;; ++ sparc | sparcv8 | sparcv9 | sparcv9b) ++ basic_machine=sparc-sun ++ ;; ++ cydra) ++ basic_machine=cydra-cydrome ++ ;; ++ orion) ++ basic_machine=orion-highlevel ++ ;; ++ orion105) ++ basic_machine=clipper-highlevel ++ ;; ++ mac | mpw | mac-mpw) ++ basic_machine=m68k-apple ++ ;; ++ pmac | pmac-mpw) ++ basic_machine=powerpc-apple ++ ;; ++ *-unknown) ++ # Make sure to match an already-canonicalized machine name. ++ ;; ++ *) ++ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 ++ exit 1 ++ ;; ++esac ++ ++# Here we canonicalize certain aliases for manufacturers. ++case $basic_machine in ++ *-digital*) ++ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ++ ;; ++ *-commodore*) ++ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ++ ;; ++ *) ++ ;; ++esac ++ ++# Decode manufacturer-specific aliases for certain operating systems. ++ ++if [ x"$os" != x"" ] ++then ++case $os in ++ # First match some system type aliases ++ # that might get confused with valid system types. ++ # -solaris* is a basic system type, with this one exception. ++ -solaris1 | -solaris1.*) ++ os=`echo $os | sed -e 's|solaris1|sunos4|'` ++ ;; ++ -solaris) ++ os=-solaris2 ++ ;; ++ -svr4*) ++ os=-sysv4 ++ ;; ++ -unixware*) ++ os=-sysv4.2uw ++ ;; ++ -gnu/linux*) ++ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ++ ;; ++ # First accept the basic system types. ++ # The portable systems comes first. ++ # Each alternative MUST END IN A *, to match a version number. ++ # -sysv* is not here because it comes later, after sysvr4. ++ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ ++ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ ++ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ ++ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ ++ | -aos* \ ++ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ ++ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ ++ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ ++ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ ++ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ ++ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ ++ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ ++ | -chorusos* | -chorusrdb* \ ++ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ ++ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ ++ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ ++ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ ++ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ ++ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ ++ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ ++ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* | -skyos*) ++ # Remember, each alternative MUST END IN *, to match a version number. ++ ;; ++ -qnx*) ++ case $basic_machine in ++ x86-* | i*86-*) ++ ;; ++ *) ++ os=-nto$os ++ ;; ++ esac ++ ;; ++ -nto-qnx*) ++ ;; ++ -nto*) ++ os=`echo $os | sed -e 's|nto|nto-qnx|'` ++ ;; ++ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ ++ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ ++ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ++ ;; ++ -mac*) ++ os=`echo $os | sed -e 's|mac|macos|'` ++ ;; ++ -linux-dietlibc) ++ os=-linux-dietlibc ++ ;; ++ -linux*) ++ os=`echo $os | sed -e 's|linux|linux-gnu|'` ++ ;; ++ -sunos5*) ++ os=`echo $os | sed -e 's|sunos5|solaris2|'` ++ ;; ++ -sunos6*) ++ os=`echo $os | sed -e 's|sunos6|solaris3|'` ++ ;; ++ -opened*) ++ os=-openedition ++ ;; ++ -os400*) ++ os=-os400 ++ ;; ++ -wince*) ++ os=-wince ++ ;; ++ -osfrose*) ++ os=-osfrose ++ ;; ++ -osf*) ++ os=-osf ++ ;; ++ -utek*) ++ os=-bsd ++ ;; ++ -dynix*) ++ os=-bsd ++ ;; ++ -acis*) ++ os=-aos ++ ;; ++ -atheos*) ++ os=-atheos ++ ;; ++ -syllable*) ++ os=-syllable ++ ;; ++ -386bsd) ++ os=-bsd ++ ;; ++ -ctix* | -uts*) ++ os=-sysv ++ ;; ++ -nova*) ++ os=-rtmk-nova ++ ;; ++ -ns2 ) ++ os=-nextstep2 ++ ;; ++ -nsk*) ++ os=-nsk ++ ;; ++ # Preserve the version number of sinix5. ++ -sinix5.*) ++ os=`echo $os | sed -e 's|sinix|sysv|'` ++ ;; ++ -sinix*) ++ os=-sysv4 ++ ;; ++ -tpf*) ++ os=-tpf ++ ;; ++ -triton*) ++ os=-sysv3 ++ ;; ++ -oss*) ++ os=-sysv3 ++ ;; ++ -svr4) ++ os=-sysv4 ++ ;; ++ -svr3) ++ os=-sysv3 ++ ;; ++ -sysvr4) ++ os=-sysv4 ++ ;; ++ # This must come after -sysvr4. ++ -sysv*) ++ ;; ++ -ose*) ++ os=-ose ++ ;; ++ -es1800*) ++ os=-ose ++ ;; ++ -xenix) ++ os=-xenix ++ ;; ++ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) ++ os=-mint ++ ;; ++ -aros*) ++ os=-aros ++ ;; ++ -kaos*) ++ os=-kaos ++ ;; ++ -zvmoe) ++ os=-zvmoe ++ ;; ++ -none) ++ ;; ++ *) ++ # Get rid of the `-' at the beginning of $os. ++ os=`echo $os | sed 's/[^-]*-//'` ++ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 ++ exit 1 ++ ;; ++esac ++else ++ ++# Here we handle the default operating systems that come with various machines. ++# The value should be what the vendor currently ships out the door with their ++# machine or put another way, the most popular os provided with the machine. ++ ++# Note that if you're going to try to match "-MANUFACTURER" here (say, ++# "-sun"), then you have to tell the case statement up towards the top ++# that MANUFACTURER isn't an operating system. Otherwise, code above ++# will signal an error saying that MANUFACTURER isn't an operating ++# system, and we'll never get to this point. ++ ++case $basic_machine in ++ *-acorn) ++ os=-riscix1.2 ++ ;; ++ arm*-rebel) ++ os=-linux ++ ;; ++ arm*-semi) ++ os=-aout ++ ;; ++ c4x-* | tic4x-*) ++ os=-coff ++ ;; ++ # This must come before the *-dec entry. ++ pdp10-*) ++ os=-tops20 ++ ;; ++ pdp11-*) ++ os=-none ++ ;; ++ *-dec | vax-*) ++ os=-ultrix4.2 ++ ;; ++ m68*-apollo) ++ os=-domain ++ ;; ++ i386-sun) ++ os=-sunos4.0.2 ++ ;; ++ m68000-sun) ++ os=-sunos3 ++ # This also exists in the configure program, but was not the ++ # default. ++ # os=-sunos4 ++ ;; ++ m68*-cisco) ++ os=-aout ++ ;; ++ mips*-cisco) ++ os=-elf ++ ;; ++ mips*-*) ++ os=-elf ++ ;; ++ or32-*) ++ os=-coff ++ ;; ++ *-tti) # must be before sparc entry or we get the wrong os. ++ os=-sysv3 ++ ;; ++ sparc-* | *-sun) ++ os=-sunos4.1.1 ++ ;; ++ *-be) ++ os=-beos ++ ;; ++ *-ibm) ++ os=-aix ++ ;; ++ *-knuth) ++ os=-mmixware ++ ;; ++ *-wec) ++ os=-proelf ++ ;; ++ *-winbond) ++ os=-proelf ++ ;; ++ *-oki) ++ os=-proelf ++ ;; ++ *-hp) ++ os=-hpux ++ ;; ++ *-hitachi) ++ os=-hiux ++ ;; ++ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) ++ os=-sysv ++ ;; ++ *-cbm) ++ os=-amigaos ++ ;; ++ *-dg) ++ os=-dgux ++ ;; ++ *-dolphin) ++ os=-sysv3 ++ ;; ++ m68k-ccur) ++ os=-rtu ++ ;; ++ m88k-omron*) ++ os=-luna ++ ;; ++ *-next ) ++ os=-nextstep ++ ;; ++ *-sequent) ++ os=-ptx ++ ;; ++ *-crds) ++ os=-unos ++ ;; ++ *-ns) ++ os=-genix ++ ;; ++ i370-*) ++ os=-mvs ++ ;; ++ *-next) ++ os=-nextstep3 ++ ;; ++ *-gould) ++ os=-sysv ++ ;; ++ *-highlevel) ++ os=-bsd ++ ;; ++ *-encore) ++ os=-bsd ++ ;; ++ *-sgi) ++ os=-irix ++ ;; ++ *-siemens) ++ os=-sysv4 ++ ;; ++ *-masscomp) ++ os=-rtu ++ ;; ++ f30[01]-fujitsu | f700-fujitsu) ++ os=-uxpv ++ ;; ++ *-rom68k) ++ os=-coff ++ ;; ++ *-*bug) ++ os=-coff ++ ;; ++ *-apple) ++ os=-macos ++ ;; ++ *-atari*) ++ os=-mint ++ ;; ++ *) ++ os=-none ++ ;; ++esac ++fi ++ ++# Here we handle the case where we know the os, and the CPU type, but not the ++# manufacturer. We pick the logical manufacturer. ++vendor=unknown ++case $basic_machine in ++ *-unknown) ++ case $os in ++ -riscix*) ++ vendor=acorn ++ ;; ++ -sunos*) ++ vendor=sun ++ ;; ++ -aix*) ++ vendor=ibm ++ ;; ++ -beos*) ++ vendor=be ++ ;; ++ -hpux*) ++ vendor=hp ++ ;; ++ -mpeix*) ++ vendor=hp ++ ;; ++ -hiux*) ++ vendor=hitachi ++ ;; ++ -unos*) ++ vendor=crds ++ ;; ++ -dgux*) ++ vendor=dg ++ ;; ++ -luna*) ++ vendor=omron ++ ;; ++ -genix*) ++ vendor=ns ++ ;; ++ -mvs* | -opened*) ++ vendor=ibm ++ ;; ++ -os400*) ++ vendor=ibm ++ ;; ++ -ptx*) ++ vendor=sequent ++ ;; ++ -tpf*) ++ vendor=ibm ++ ;; ++ -vxsim* | -vxworks* | -windiss*) ++ vendor=wrs ++ ;; ++ -aux*) ++ vendor=apple ++ ;; ++ -hms*) ++ vendor=hitachi ++ ;; ++ -mpw* | -macos*) ++ vendor=apple ++ ;; ++ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) ++ vendor=atari ++ ;; ++ -vos*) ++ vendor=stratus ++ ;; ++ esac ++ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ++ ;; ++esac ++ ++echo $basic_machine$os ++exit ++ ++# Local variables: ++# eval: (add-hook 'write-file-hooks 'time-stamp) ++# time-stamp-start: "timestamp='" ++# time-stamp-format: "%:y-%02m-%02d" ++# time-stamp-end: "'" ++# End: +diff --git a/utils/open-isns/aclocal/install-sh b/utils/open-isns/aclocal/install-sh +new file mode 100644 +index 0000000..220abbf +--- /dev/null ++++ b/utils/open-isns/aclocal/install-sh +@@ -0,0 +1,251 @@ ++#!/bin/sh ++# ++# install - install a program, script, or datafile ++# This comes from X11R5 (mit/util/scripts/install.sh). ++# ++# Copyright 1991 by the Massachusetts Institute of Technology ++# ++# Permission to use, copy, modify, distribute, and sell this software and its ++# documentation for any purpose is hereby granted without fee, provided that ++# the above copyright notice appear in all copies and that both that ++# copyright notice and this permission notice appear in supporting ++# documentation, and that the name of M.I.T. not be used in advertising or ++# publicity pertaining to distribution of the software without specific, ++# written prior permission. M.I.T. makes no representations about the ++# suitability of this software for any purpose. It is provided "as is" ++# without express or implied warranty. ++# ++# Calling this script install-sh is preferred over install.sh, to prevent ++# `make' implicit rules from creating a file called install from it ++# when there is no Makefile. ++# ++# This script is compatible with the BSD install script, but was written ++# from scratch. It can only install one file at a time, a restriction ++# shared with many OS's install programs. ++ ++ ++# set DOITPROG to echo to test this script ++ ++# Don't use :- since 4.3BSD and earlier shells don't like it. ++doit="${DOITPROG-}" ++ ++ ++# put in absolute paths if you don't have them in your path; or use env. vars. ++ ++mvprog="${MVPROG-mv}" ++cpprog="${CPPROG-cp}" ++chmodprog="${CHMODPROG-chmod}" ++chownprog="${CHOWNPROG-chown}" ++chgrpprog="${CHGRPPROG-chgrp}" ++stripprog="${STRIPPROG-strip}" ++rmprog="${RMPROG-rm}" ++mkdirprog="${MKDIRPROG-mkdir}" ++ ++transformbasename="" ++transform_arg="" ++instcmd="$mvprog" ++chmodcmd="$chmodprog 0755" ++chowncmd="" ++chgrpcmd="" ++stripcmd="" ++rmcmd="$rmprog -f" ++mvcmd="$mvprog" ++src="" ++dst="" ++dir_arg="" ++ ++while [ x"$1" != x ]; do ++ case $1 in ++ -c) instcmd="$cpprog" ++ shift ++ continue;; ++ ++ -d) dir_arg=true ++ shift ++ continue;; ++ ++ -m) chmodcmd="$chmodprog $2" ++ shift ++ shift ++ continue;; ++ ++ -o) chowncmd="$chownprog $2" ++ shift ++ shift ++ continue;; ++ ++ -g) chgrpcmd="$chgrpprog $2" ++ shift ++ shift ++ continue;; ++ ++ -s) stripcmd="$stripprog" ++ shift ++ continue;; ++ ++ -t=*) transformarg=`echo $1 | sed 's/-t=//'` ++ shift ++ continue;; ++ ++ -b=*) transformbasename=`echo $1 | sed 's/-b=//'` ++ shift ++ continue;; ++ ++ *) if [ x"$src" = x ] ++ then ++ src=$1 ++ else ++ # this colon is to work around a 386BSD /bin/sh bug ++ : ++ dst=$1 ++ fi ++ shift ++ continue;; ++ esac ++done ++ ++if [ x"$src" = x ] ++then ++ echo "install: no input file specified" ++ exit 1 ++else ++ true ++fi ++ ++if [ x"$dir_arg" != x ]; then ++ dst=$src ++ src="" ++ ++ if [ -d $dst ]; then ++ instcmd=: ++ chmodcmd="" ++ else ++ instcmd=mkdir ++ fi ++else ++ ++# Waiting for this to be detected by the "$instcmd $src $dsttmp" command ++# might cause directories to be created, which would be especially bad ++# if $src (and thus $dsttmp) contains '*'. ++ ++ if [ -f $src -o -d $src ] ++ then ++ true ++ else ++ echo "install: $src does not exist" ++ exit 1 ++ fi ++ ++ if [ x"$dst" = x ] ++ then ++ echo "install: no destination specified" ++ exit 1 ++ else ++ true ++ fi ++ ++# If destination is a directory, append the input filename; if your system ++# does not like double slashes in filenames, you may need to add some logic ++ ++ if [ -d $dst ] ++ then ++ dst="$dst"/`basename $src` ++ else ++ true ++ fi ++fi ++ ++## this sed command emulates the dirname command ++dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` ++ ++# Make sure that the destination directory exists. ++# this part is taken from Noah Friedman's mkinstalldirs script ++ ++# Skip lots of stat calls in the usual case. ++if [ ! -d "$dstdir" ]; then ++defaultIFS=' ++' ++IFS="${IFS-${defaultIFS}}" ++ ++oIFS="${IFS}" ++# Some sh's can't handle IFS=/ for some reason. ++IFS='%' ++set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` ++IFS="${oIFS}" ++ ++pathcomp='' ++ ++while [ $# -ne 0 ] ; do ++ pathcomp="${pathcomp}${1}" ++ shift ++ ++ if [ ! -d "${pathcomp}" ] ; ++ then ++ $mkdirprog "${pathcomp}" ++ else ++ true ++ fi ++ ++ pathcomp="${pathcomp}/" ++done ++fi ++ ++if [ x"$dir_arg" != x ] ++then ++ $doit $instcmd $dst && ++ ++ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && ++ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && ++ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && ++ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi ++else ++ ++# If we're going to rename the final executable, determine the name now. ++ ++ if [ x"$transformarg" = x ] ++ then ++ dstfile=`basename $dst` ++ else ++ dstfile=`basename $dst $transformbasename | ++ sed $transformarg`$transformbasename ++ fi ++ ++# don't allow the sed command to completely eliminate the filename ++ ++ if [ x"$dstfile" = x ] ++ then ++ dstfile=`basename $dst` ++ else ++ true ++ fi ++ ++# Make a temp file name in the proper directory. ++ ++ dsttmp=$dstdir/#inst.$$# ++ ++# Move or copy the file name to the temp name ++ ++ $doit $instcmd $src $dsttmp && ++ ++ trap "rm -f ${dsttmp}" 0 && ++ ++# and set any options; do chmod last to preserve setuid bits ++ ++# If any of these fail, we abort the whole thing. If we want to ++# ignore errors from any of these, just make sure not to ignore ++# errors from the above "$doit $instcmd $src $dsttmp" command. ++ ++ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && ++ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && ++ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && ++ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && ++ ++# Now rename the file to the real destination. ++ ++ $doit $rmcmd -f $dstdir/$dstfile && ++ $doit $mvcmd $dsttmp $dstdir/$dstfile ++ ++fi && ++ ++ ++exit 0 +diff --git a/utils/open-isns/attrs.c b/utils/open-isns/attrs.c +new file mode 100644 +index 0000000..12517c1 +--- /dev/null ++++ b/utils/open-isns/attrs.c +@@ -0,0 +1,1618 @@ ++/* ++ * Handle iSNS attributes and attribute lists ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include "util.h" ++#include "vendor.h" ++#include "attrs.h" ++#include "isns.h" ++ ++/* Implementation limit - sanity checking */ ++#define ISNS_ATTR_MAX_LEN 8192 ++ ++static void __isns_attr_set_value(isns_attr_t *, const isns_value_t *); ++ ++/* ++ * Allocate an attribute ++ */ ++isns_attr_t * ++isns_attr_alloc(uint32_t tag, const isns_tag_type_t *tag_type, const isns_value_t *value) ++{ ++ isns_attr_t *attr; ++ ++ if (tag_type == NULL) ++ tag_type = isns_tag_type_by_id(tag); ++ ++ attr = isns_calloc(1, sizeof(*attr)); ++ if (!attr) ++ isns_fatal("Out of memory!\n"); ++ ++ attr->ia_users = 1; ++ attr->ia_tag_id = tag; ++ attr->ia_tag = tag_type; ++ ++ __isns_attr_set_value(attr, value); ++ return attr; ++} ++ ++isns_attr_t * ++isns_attr_get(isns_attr_t *attr) ++{ ++ if (attr) { ++ isns_assert(attr->ia_users); ++ attr->ia_users++; ++ } ++ return attr; ++} ++ ++void ++isns_attr_release(isns_attr_t *attr) ++{ ++ const isns_attr_type_t *type; ++ ++ isns_assert(attr->ia_users); ++ if (--(attr->ia_users)) ++ return; ++ ++ type = attr->ia_value.iv_type; ++ if (type->it_destroy) ++ type->it_destroy(&attr->ia_value); ++ isns_free(attr); ++} ++ ++/* ++ * Assign a value to an attribute ++ */ ++void ++__isns_attr_set_value(isns_attr_t *attr, const isns_value_t *new_value) ++{ ++ const isns_attr_type_t *type, *old_type; ++ isns_value_t *old_value; ++ ++ old_value = &attr->ia_value; ++ if (old_value == new_value) ++ return; ++ ++ old_type = old_value->iv_type; ++ if (old_type && old_type->it_destroy) ++ old_type->it_destroy(old_value); ++ ++ if (!new_value || !(type = new_value->iv_type)) ++ type = attr->ia_tag->it_type; ++ ++ /* When assigning the value to the attr, check ++ * whether it needs special attention. */ ++ if (new_value) { ++ if (type->it_assign) { ++ type->it_assign(&attr->ia_value, new_value); ++ } else { ++ attr->ia_value = *new_value; ++ } ++ } ++ attr->ia_value.iv_type = type; ++} ++ ++/* ++ * Compare two attributes. ++ * Returns non-null when attributes are the same, else 0. ++ */ ++int ++isns_attr_match(const isns_attr_t *a, const isns_attr_t *b) ++{ ++ const isns_attr_type_t *type; ++ ++ if (a->ia_tag_id != b->ia_tag_id) ++ return 0; ++ ++ /* NIL acts as a wildcard */ ++ if (a->ia_value.iv_type == &isns_attr_type_nil ++ || b->ia_value.iv_type == &isns_attr_type_nil) ++ return 1; ++ ++ if (a->ia_value.iv_type != b->ia_value.iv_type) ++ return 0; ++ type = a->ia_value.iv_type; ++ ++ if (type->it_match) ++ return type->it_match(&a->ia_value, &b->ia_value); ++ ++ return !memcmp(&a->ia_value, &b->ia_value, sizeof(isns_value_t)); ++} ++ ++/* ++ * Lexicographical comparison of two attributes. ++ * Returns -1 when a is less than b, +1 when a is greater than ++ * b, and 0 if equal. ++ */ ++int ++isns_attr_compare(const isns_attr_t *a, const isns_attr_t *b) ++{ ++ const isns_attr_type_t *type = a->ia_value.iv_type; ++ ++ isns_assert(a->ia_tag_id == b->ia_tag_id); ++ ++ if (type != b->ia_value.iv_type) { ++ /* One of them must be NIL */ ++ if (type == &isns_attr_type_nil) ++ return -1; ++ return 1; ++ } ++ ++ /* If both are NIL, consider them equal */ ++ if (type == &isns_attr_type_nil) ++ return 0; ++ ++ /* A few types need special comparison functions, but ++ * most don't. The reason is, we don't care whether the ++ * ordering this creates is the "canonical" ordering for ++ * this type, eg for integers. All that matters is that ++ * there is some consistent ordering suitable for ++ * DevGetNext. ++ */ ++ if (type->it_compare) ++ return type->it_compare(&a->ia_value, &b->ia_value); ++ ++ return memcmp(&a->ia_value, &b->ia_value, sizeof(isns_value_t)); ++} ++ ++/* ++ * Convert a string to an attribute ++ */ ++isns_attr_t * ++isns_attr_from_string(uint32_t tag, const char *string) ++{ ++ const isns_tag_type_t *tag_type; ++ int (*parse)(isns_value_t *, const char *); ++ isns_value_t value; ++ ++ memset(&value, 0, sizeof(value)); ++ ++ tag_type = isns_tag_type_by_id(tag); ++ if (!tag_type) ++ return NULL; ++ ++ parse = tag_type->it_parse; ++ if (parse == NULL) ++ parse = tag_type->it_type->it_parse; ++ ++ if (!parse || !parse(&value, string)) ++ return NULL; ++ ++ return isns_attr_alloc(tag, tag_type, &value); ++} ++ ++/* ++ * Initialize an attribute list. ++ */ ++void ++isns_attr_list_init(isns_attr_list_t *list) ++{ ++ memset(list, 0, sizeof(*list)); ++} ++ ++static inline void ++__isns_attr_list_resize(isns_attr_list_t *list, unsigned int count) ++{ ++ unsigned int max; ++ ++ max = (list->ial_count + 15) & ~15; ++ if (count < max) ++ return; ++ ++ count = (count + 15) & ~15; ++ list->ial_data = isns_realloc(list->ial_data, count * sizeof(isns_attr_t *)); ++ if (!list->ial_data) ++ isns_fatal("Out of memory!\n"); ++} ++ ++void ++isns_attr_list_append_list(isns_attr_list_t *dst, ++ const isns_attr_list_t *src) ++{ ++ unsigned int i, j; ++ ++ __isns_attr_list_resize(dst, dst->ial_count + src->ial_count); ++ j = dst->ial_count; ++ for (i = 0; i < src->ial_count; ++i, ++j) { ++ isns_attr_t *attr = src->ial_data[i]; ++ ++ dst->ial_data[j] = attr; ++ attr->ia_users++; ++ } ++ dst->ial_count = j; ++} ++ ++void ++isns_attr_list_copy(isns_attr_list_t *dst, ++ const isns_attr_list_t *src) ++{ ++ isns_attr_list_destroy(dst); ++ isns_attr_list_append_list(dst, src); ++} ++ ++void ++isns_attr_list_destroy(isns_attr_list_t *list) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < list->ial_count; ++i) { ++ isns_attr_t *attr = list->ial_data[i]; ++ ++ isns_attr_release(attr); ++ } ++ ++ if (list->ial_data) ++ isns_free(list->ial_data); ++ memset(list, 0, sizeof(*list)); ++} ++ ++int ++isns_attr_list_remove_tag(isns_attr_list_t *list, uint32_t tag) ++{ ++ unsigned int i = 0, j = 0, removed = 0; ++ ++ for (i = 0; i < list->ial_count; ++i) { ++ isns_attr_t *attr = list->ial_data[i]; ++ ++ if (attr->ia_tag_id == tag) { ++ isns_attr_release(attr); ++ removed++; ++ } else { ++ list->ial_data[j++] = attr; ++ } ++ } ++ list->ial_count = j; ++ return removed; ++} ++ ++/* ++ * Locate the given attribute in the list, remove it ++ * and any following attributes that have a tag from the ++ * @subordinate_tags list. This is used by the DDDereg ++ * code to remove DD members. ++ */ ++int ++isns_attr_list_remove_member(isns_attr_list_t *list, ++ const isns_attr_t *match, ++ const uint32_t *subordinate_tags) ++{ ++ unsigned int i = 0, j = 0, k, removed = 0, purging = 0; ++ ++ while (i < list->ial_count) { ++ isns_attr_t *attr = list->ial_data[i++]; ++ ++ if (purging && subordinate_tags) { ++ for (k = 0; subordinate_tags[k]; ++k) { ++ if (attr->ia_tag_id == subordinate_tags[k]) ++ goto purge_attr; ++ } ++ } ++ purging = 0; ++ ++ if (!isns_attr_match(attr, match)) { ++ list->ial_data[j++] = attr; ++ continue; ++ } ++ ++purge_attr: ++ isns_attr_release(attr); ++ purging = 1; ++ removed++; ++ } ++ list->ial_count = j; ++ return removed; ++} ++ ++/* ++ * Find the first attribute with the given tag ++ */ ++static inline isns_attr_t * ++__isns_attr_list_find(const isns_attr_list_t *list, uint32_t tag) ++{ ++ isns_attr_t *attr; ++ unsigned int i; ++ ++ for (i = 0; i < list->ial_count; ++i) { ++ attr = list->ial_data[i]; ++ ++ if (attr->ia_tag_id == tag) ++ return attr; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Add a new attribute at the end of the list ++ */ ++static inline void ++__isns_attr_list_append_attr(isns_attr_list_t *list, isns_attr_t *attr) ++{ ++ __isns_attr_list_resize(list, list->ial_count + 1); ++ list->ial_data[list->ial_count++] = attr; ++} ++ ++void ++isns_attr_list_append_attr(isns_attr_list_t *list, isns_attr_t *attr) ++{ ++ attr->ia_users++; ++ __isns_attr_list_append_attr(list, attr); ++} ++ ++/* ++ * Append an element to an attribute list ++ */ ++static void ++__isns_attr_list_append(isns_attr_list_t *list, ++ uint32_t tag, const isns_tag_type_t *tag_type, ++ const isns_value_t *value) ++{ ++ isns_attr_t *attr; ++ ++ if (tag_type == NULL) ++ tag_type = isns_tag_type_by_id(tag); ++ if (value->iv_type != &isns_attr_type_nil ++ && value->iv_type != tag_type->it_type) { ++ isns_warning("Using wrong type (%s) " ++ "when encoding attribute %04x (%s) - should be %s\n", ++ value->iv_type->it_name, ++ tag, tag_type->it_name, ++ tag_type->it_type->it_name); ++ } ++ ++ attr = isns_attr_alloc(tag, tag_type, value); ++ __isns_attr_list_append_attr(list, attr); ++} ++ ++/* ++ * Update an element to an attribute list ++ */ ++static void ++__isns_attr_list_update(isns_attr_list_t *list, ++ uint32_t tag, const isns_tag_type_t *tag_type, ++ const isns_value_t *value) ++{ ++ const isns_attr_type_t *type = value->iv_type; ++ isns_attr_t *attr; ++ ++ if (tag_type == NULL) ++ tag_type = isns_tag_type_by_id(tag); ++ if (type != &isns_attr_type_nil ++ && type != tag_type->it_type) { ++ isns_warning("Using wrong type (%s) " ++ "when encoding attribute %04x (%s) - should be %s\n", ++ type->it_name, ++ tag, tag_type->it_name, ++ tag_type->it_type->it_name); ++ } ++ ++ if (tag_type->it_multiple ++ || (attr = __isns_attr_list_find(list, tag)) == NULL) { ++ attr = isns_attr_alloc(tag, tag_type, NULL); ++ __isns_attr_list_append_attr(list, attr); ++ } ++ ++ __isns_attr_set_value(attr, value); ++} ++ ++/* ++ * Append an element to an attribute list - public interface ++ */ ++void ++isns_attr_list_append_value(isns_attr_list_t *list, ++ uint32_t tag, const isns_tag_type_t *tag_type, ++ const isns_value_t *value) ++{ ++ __isns_attr_list_append(list, tag, tag_type, value); ++} ++ ++/* ++ * Update an element of an attribute list - public interface ++ */ ++void ++isns_attr_list_update_value(isns_attr_list_t *list, ++ uint32_t tag, const isns_tag_type_t *tag_type, ++ const isns_value_t *value) ++{ ++ __isns_attr_list_update(list, tag, tag_type, value); ++} ++ ++void ++isns_attr_list_update_attr(isns_attr_list_t *list, ++ const isns_attr_t *attr) ++{ ++ __isns_attr_list_update(list, attr->ia_tag_id, ++ attr->ia_tag, &attr->ia_value); ++} ++ ++/* ++ * Replace an attribute on a list ++ */ ++int ++isns_attr_list_replace_attr(isns_attr_list_t *list, ++ isns_attr_t *attr) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < list->ial_count; ++i) { ++ isns_attr_t *other = list->ial_data[i]; ++ ++ if (other->ia_tag_id == attr->ia_tag_id) { ++ list->ial_data[i] = attr; ++ attr->ia_users++; ++ isns_attr_release(other); ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * Retrieve an element of an attribute list ++ */ ++int ++isns_attr_list_get_attr(const isns_attr_list_t *list, ++ uint32_t tag, isns_attr_t **result) ++{ ++ *result = __isns_attr_list_find(list, tag); ++ return *result != NULL; ++} ++ ++int ++isns_attr_list_get_value(const isns_attr_list_t *list, ++ uint32_t tag, isns_value_t *value) ++{ ++ isns_attr_t *attr; ++ ++ if (!(attr = __isns_attr_list_find(list, tag))) ++ return 0; ++ ++ *value = attr->ia_value; ++ return 1; ++} ++ ++int ++isns_attr_list_get_uint32(const isns_attr_list_t *list, ++ uint32_t tag, uint32_t *value) ++{ ++ isns_attr_t *attr; ++ ++ if (!(attr = __isns_attr_list_find(list, tag)) ++ || !ISNS_ATTR_IS_UINT32(attr)) ++ return 0; ++ ++ *value = attr->ia_value.iv_uint32; ++ return 1; ++} ++ ++int ++isns_attr_list_get_ipaddr(const isns_attr_list_t *list, ++ uint32_t tag, struct in6_addr *value) ++{ ++ isns_attr_t *attr; ++ ++ if (!(attr = __isns_attr_list_find(list, tag)) ++ || !ISNS_ATTR_IS_IPADDR(attr)) ++ return 0; ++ ++ *value = attr->ia_value.iv_ipaddr; ++ return 1; ++} ++ ++int ++isns_attr_list_get_string(const isns_attr_list_t *list, ++ uint32_t tag, const char **value) ++{ ++ isns_attr_t *attr; ++ ++ if (!(attr = __isns_attr_list_find(list, tag)) ++ || !ISNS_ATTR_IS_STRING(attr)) ++ return 0; ++ ++ *value = attr->ia_value.iv_string; ++ return 1; ++} ++ ++int ++isns_attr_list_contains(const isns_attr_list_t *list, ++ uint32_t tag) ++{ ++ return __isns_attr_list_find(list, tag) != NULL; ++} ++ ++/* ++ * Some attribute types have an implied ordering, ++ * which is needed for GetNext. This is used to ++ * compare two lists. ++ */ ++ ++/* ++ * Typed versions of isns_attr_list_append ++ */ ++void ++isns_attr_list_append_nil(isns_attr_list_t *list, uint32_t tag) ++{ ++ isns_value_t var = ISNS_VALUE_INIT(nil, 0); ++ ++ __isns_attr_list_append(list, tag, NULL, &var); ++} ++ ++void ++isns_attr_list_append_string(isns_attr_list_t *list, ++ uint32_t tag, const char *value) ++{ ++ isns_value_t var = ISNS_VALUE_INIT(string, (char *) value); ++ ++ __isns_attr_list_append(list, tag, NULL, &var); ++} ++ ++void ++isns_attr_list_append_uint32(isns_attr_list_t *list, ++ uint32_t tag, uint32_t value) ++{ ++ isns_value_t var = ISNS_VALUE_INIT(uint32, value); ++ ++ __isns_attr_list_append(list, tag, NULL, &var); ++} ++ ++void ++isns_attr_list_append_int32(isns_attr_list_t *list, ++ uint32_t tag, int32_t value) ++{ ++ isns_value_t var = ISNS_VALUE_INIT(int32, value); ++ ++ __isns_attr_list_append(list, tag, NULL, &var); ++} ++ ++void ++isns_attr_list_append_uint64(isns_attr_list_t *list, ++ uint32_t tag, int64_t value) ++{ ++ isns_value_t var = ISNS_VALUE_INIT(uint64, value); ++ ++ __isns_attr_list_append(list, tag, NULL, &var); ++} ++ ++void ++isns_attr_list_append_ipaddr(isns_attr_list_t *list, ++ uint32_t tag, const struct in6_addr *value) ++{ ++ isns_value_t var = ISNS_VALUE_INIT(ipaddr, *value); ++ ++ __isns_attr_list_append(list, tag, NULL, &var); ++} ++ ++/* ++ * Untyped version of isns_attr_list_append and isns_attr_list_update. ++ * The caller must make sure that the type of @data matches the tag's type. ++ */ ++int ++isns_attr_list_append(isns_attr_list_t *list, uint32_t tag, const void *data) ++{ ++ const isns_tag_type_t *tag_type; ++ isns_value_t var; ++ ++ if (!(tag_type = isns_tag_type_by_id(tag))) ++ return 0; ++ ++ var.iv_type = tag_type->it_type; ++ if (!var.iv_type->it_set(&var, data)) ++ return 0; ++ ++ __isns_attr_list_append(list, tag, tag_type, &var); ++ return 1; ++} ++ ++int ++isns_attr_list_update(isns_attr_list_t *list, uint32_t tag, const void *data) ++{ ++ const isns_tag_type_t *tag_type; ++ isns_attr_type_t *type; ++ isns_value_t var; ++ ++ if (!(tag_type = isns_tag_type_by_id(tag))) ++ return 0; ++ ++ type = tag_type->it_type; ++ var.iv_type = type; ++ if (!type->it_set(&var, data)) ++ return 0; ++ ++ __isns_attr_list_update(list, tag, tag_type, &var); ++ return 1; ++} ++ ++/* ++ * Validate the attribute list. ++ */ ++int ++isns_attr_validate(const isns_attr_t *attr, ++ const isns_policy_t *policy) ++{ ++ const isns_tag_type_t *tag_type; ++ ++ tag_type = attr->ia_tag; ++ if (tag_type->it_validate == NULL) ++ return 1; ++ return tag_type->it_validate(&attr->ia_value, policy); ++} ++ ++int ++isns_attr_list_validate(const isns_attr_list_t *list, ++ const isns_policy_t *policy, ++ unsigned int function) ++{ ++ DECLARE_BITMAP(seen, __ISNS_TAG_MAX); ++ unsigned int i; ++ ++ for (i = 0; i < list->ial_count; ++i) { ++ const isns_tag_type_t *tag_type; ++ isns_attr_t *attr = list->ial_data[i]; ++ uint32_t tag = attr->ia_tag_id; ++ unsigned int bit; ++ ++ if (attr == NULL) ++ return ISNS_INTERNAL_ERROR; ++ ++ tag_type = attr->ia_tag; ++ if (tag_type == NULL) ++ return ISNS_INTERNAL_ERROR; ++ ++ bit = tag; ++ if (OPENISNS_IS_PRIVATE_ATTR(tag)) ++ bit -= OPENISNS_VENDOR_PREFIX; ++ if (bit >= __ISNS_TAG_MAX) ++ goto invalid; ++ ++ if (attr->ia_value.iv_type == &isns_attr_type_nil) { ++ if (test_bit(seen, bit)) ++ goto invalid; ++ } else ++ if (attr->ia_value.iv_type == tag_type->it_type) { ++ if (!tag_type->it_multiple && test_bit(seen, bit)) ++ goto invalid; ++ ++ if (!isns_attr_validate(attr, policy)) ++ goto invalid; ++ } else { ++ return ISNS_INTERNAL_ERROR; ++ } ++ ++ if (function == ISNS_DEVICE_ATTRIBUTE_REGISTER ++ && tag_type->it_readonly) ++ goto invalid; ++ ++ set_bit(seen, bit); ++ } ++ ++ return ISNS_SUCCESS; ++ ++invalid: ++ switch (function) { ++ case ISNS_DEVICE_ATTRIBUTE_REGISTER: ++ return ISNS_INVALID_REGISTRATION; ++ ++ case ISNS_DEVICE_DEREGISTER: ++ return ISNS_INVALID_DEREGISTRATION; ++ ++ case ISNS_DEVICE_ATTRIBUTE_QUERY: ++ case ISNS_DEVICE_GET_NEXT: ++ return ISNS_INVALID_QUERY; ++ } ++ return ISNS_ATTRIBUTE_NOT_IMPLEMENTED; ++} ++ ++/* ++ * Debug helper: print attribute list ++ */ ++void ++isns_attr_list_print(const isns_attr_list_t *list, isns_print_fn_t *fn) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < list->ial_count; ++i) ++ isns_attr_print(list->ial_data[i], fn); ++} ++ ++char * ++isns_attr_print_value(const isns_attr_t *attr, char *buffer, size_t size) ++{ ++ const isns_tag_type_t *tag_type = attr->ia_tag; ++ const isns_attr_type_t *type = attr->ia_value.iv_type; ++ ++ if (tag_type->it_print && type == tag_type->it_type) ++ tag_type->it_print(&attr->ia_value, buffer, size); ++ else ++ type->it_print(&attr->ia_value, buffer, size); ++ return buffer; ++} ++ ++void ++isns_attr_print(const isns_attr_t *attr, isns_print_fn_t *fn) ++{ ++ const isns_tag_type_t *tag_type = attr->ia_tag; ++ const isns_attr_type_t *type = attr->ia_value.iv_type; ++ uint32_t tag; ++ char value[512], *vspec = ""; ++ ++ tag = attr->ia_tag_id; ++ if (OPENISNS_IS_PRIVATE_ATTR(tag)) { ++ tag -= OPENISNS_VENDOR_PREFIX; ++ vspec = "v"; ++ } ++ ++ fn(" %04x%1s %-12s: %s = %s\n", ++ tag, vspec, ++ type->it_name, ++ tag_type? tag_type->it_name : "Unknown Attribute", ++ isns_attr_print_value(attr, value, sizeof(value))); ++} ++ ++/* ++ * TLV encode a single attribute ++ */ ++int ++isns_attr_encode(buf_t *bp, const isns_attr_t *attr) ++{ ++ const isns_value_t *value = &attr->ia_value; ++ const isns_attr_type_t *type = value->iv_type; ++ ++ if (!buf_put32(bp, attr->ia_tag_id) ++ || !type->it_encode(bp, value)) ++ return ISNS_INTERNAL_ERROR; ++ ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * TLV decode a single attribute ++ */ ++int ++isns_attr_decode(buf_t *bp, isns_attr_t **result) ++{ ++ isns_attr_t *attr = NULL; ++ isns_value_t *value; ++ uint32_t tag, len; ++ ++ if (!buf_get32(bp, &tag) ++ || !buf_get32(bp, &len)) ++ goto msg_fmt_error; ++ ++ /* Attributes MUST be word aligned */ ++ if (len & 3) ++ goto msg_fmt_error; ++ ++ if (len > ISNS_ATTR_MAX_LEN) ++ goto msg_fmt_error; ++ ++ /* Allocate the attribute */ ++ attr = isns_attr_alloc(tag, NULL, NULL); ++ ++ value = &attr->ia_value; ++ if (len == 0) ++ value->iv_type = &isns_attr_type_nil; ++ ++ if (!value->iv_type->it_decode(bp, len, value)) ++ goto msg_fmt_error; ++ ++ *result = attr; ++ return ISNS_SUCCESS; ++ ++msg_fmt_error: ++ isns_error("Error decoding attribute, tag=0x%04x, len=%u\n", ++ tag, len); ++ if (attr) ++ isns_attr_release(attr); ++ return ISNS_MESSAGE_FORMAT_ERROR; ++} ++ ++ ++/* ++ * Decode the list of TLV encoded attributes inside an ++ * iSNS message. ++ */ ++static int ++__isns_attr_list_decode(buf_t *bp, isns_attr_list_t *list, int delimited) ++{ ++ int status; ++ ++ while (buf_avail(bp)) { ++ isns_attr_t *attr; ++ ++ status = isns_attr_decode(bp, &attr); ++ if (status != ISNS_SUCCESS) ++ return status; ++ ++ if (delimited && attr->ia_tag_id == ISNS_TAG_DELIMITER) { ++ isns_attr_release(attr); ++ break; ++ } ++ ++ __isns_attr_list_append_attr(list, attr); ++ } ++ ++ return ISNS_SUCCESS; ++} ++ ++int ++isns_attr_list_decode(buf_t *bp, isns_attr_list_t *list) ++{ ++ return __isns_attr_list_decode(bp, list, 0); ++} ++ ++int ++isns_attr_list_decode_delimited(buf_t *bp, isns_attr_list_t *list) ++{ ++ return __isns_attr_list_decode(bp, list, 1); ++} ++ ++/* ++ * Remove all attributes from a list save those matching ++ * the given tags. ++ */ ++void ++isns_attr_list_prune(isns_attr_list_t *list, ++ const uint32_t *tags, unsigned int num_tags) ++{ ++ unsigned int i, j, k; ++ ++ for (i = j = 0; i < list->ial_count; ++i) { ++ isns_attr_t *attr = list->ial_data[i]; ++ ++ for (k = 0; k < num_tags; ++k) { ++ if (attr->ia_tag_id == tags[k]) { ++ list->ial_data[j++] = attr; ++ goto next; ++ } ++ } ++ ++ isns_attr_release(attr); ++ ++next: ; ++ } ++ ++ list->ial_count = j; ++} ++ ++/* ++ * TLV ecode the list of attributes to go with ++ * iSNS message. ++ */ ++int ++isns_attr_list_encode(buf_t *bp, const isns_attr_list_t *list) ++{ ++ unsigned int i, status = ISNS_SUCCESS; ++ ++ for (i = 0; i < list->ial_count; ++i) { ++ struct isns_attr *attr = list->ial_data[i]; ++ ++ status = isns_attr_encode(bp, attr); ++ if (status) ++ break; ++ } ++ return status; ++} ++ ++/* ++ * Encode the delimiter attribute ++ */ ++int ++isns_encode_delimiter(buf_t *bp) ++{ ++ uint32_t tag = 0, len = 0; ++ ++ if (!buf_put32(bp, tag) ++ || !buf_put32(bp, len)) ++ return ISNS_INTERNAL_ERROR; ++ ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * Padded encoding ++ */ ++static inline int ++isns_encode_padded(buf_t *bp, const void *ptr, size_t len) ++{ ++ if (!buf_put(bp, ptr, len)) ++ return 0; ++ ++ if ((len & 3) == 0) ++ return 1; ++ ++ return buf_put(bp, "\0\0\0", 4 - (len & 3)); ++} ++ ++/* ++ * Helper functions to deal with portal information ++ */ ++void ++isns_portal_init(isns_portal_info_t *portal, ++ const struct sockaddr *saddr, int proto) ++{ ++ const struct sockaddr_in *sin; ++ ++ memset(portal, 0, sizeof(*portal)); ++ switch (saddr->sa_family) { ++ case AF_INET6: ++ portal->addr = *(const struct sockaddr_in6 *) saddr; ++ break; ++ ++ case AF_INET: ++ sin = (const struct sockaddr_in *) saddr; ++ portal->addr.sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; ++ portal->addr.sin6_port = sin->sin_port; ++ portal->addr.sin6_family = AF_INET6; ++ break; ++ default: ++ isns_warning("Unknown address family in isns_portal_init\n"); ++ return; ++ } ++ ++ portal->proto = proto; ++} ++ ++int ++isns_portal_from_attr_list(isns_portal_info_t *portal, ++ uint32_t addr_tag, uint32_t port_tag, ++ const isns_attr_list_t *list) ++{ ++ const isns_attr_t *addr_attr = NULL, *port_attr = NULL; ++ unsigned int i; ++ ++ for (i = 0; i + 1 < list->ial_count; ++i) { ++ const isns_attr_t *attr = list->ial_data[i]; ++ ++ if (!ISNS_ATTR_IS_IPADDR(attr)) ++ continue; ++ if (addr_tag && attr->ia_tag_id != addr_tag) ++ continue; ++ addr_attr = attr; ++ if (port_tag == 0) { ++ port_attr = list->ial_data[i + 1]; ++ goto extract_portal; ++ } ++ break; ++ } ++ ++ /* We have a specific port tag. */ ++ while (++i < list->ial_count) { ++ const isns_attr_t *attr = list->ial_data[i]; ++ ++ if (attr->ia_tag_id == port_tag) { ++ port_attr = attr; ++ goto extract_portal; ++ } ++ } ++ ++ return 0; ++ ++extract_portal: ++ return isns_portal_from_attr_pair(portal, ++ addr_attr, port_attr); ++} ++ ++int ++isns_portal_from_attr_pair(isns_portal_info_t *portal, ++ const isns_attr_t *addr_attr, ++ const isns_attr_t *port_attr) ++{ ++ uint32_t portspec; ++ ++ memset(portal, 0, sizeof(*portal)); ++ portal->addr.sin6_family = AF_INET6; ++ ++ if (!ISNS_ATTR_IS_IPADDR(addr_attr) ++ || !ISNS_ATTR_IS_UINT32(port_attr)) ++ return 0; ++ ++ portal->addr.sin6_addr = addr_attr->ia_value.iv_ipaddr; ++ ++ portspec = port_attr->ia_value.iv_uint32; ++ portal->addr.sin6_port = htons(portspec & 0xffff); ++ portal->proto = (portspec & ISNS_PORTAL_PORT_UDP_MASK)? IPPROTO_UDP : IPPROTO_TCP; ++ ++ return 1; ++} ++ ++int ++isns_portal_to_attr_list(const isns_portal_info_t *portal, ++ uint32_t addr_tag, uint32_t port_tag, ++ isns_attr_list_t *list) ++{ ++ uint32_t portspec; ++ ++ portspec = htons(portal->addr.sin6_port); ++ if (portal->proto == IPPROTO_UDP) ++ portspec |= ISNS_PORTAL_PORT_UDP_MASK; ++ ++ { ++ isns_value_t addr_value = ISNS_VALUE_INIT(ipaddr, portal->addr.sin6_addr); ++ isns_value_t port_value = ISNS_VALUE_INIT(uint32, portspec); ++ ++ isns_attr_list_update_value(list, addr_tag, NULL, &addr_value); ++ isns_attr_list_update_value(list, port_tag, NULL, &port_value); ++ } ++ ++ return 1; ++} ++ ++const char * ++isns_portal_string(const isns_portal_info_t *portal) ++{ ++ const struct sockaddr_in6 *six = &portal->addr; ++ static char buffer[128]; ++ char abuf[128]; ++ ++ inet_ntop(six->sin6_family, &six->sin6_addr, abuf, sizeof(abuf)); ++ snprintf(buffer, sizeof(buffer), "[%s]:%d/%s", ++ abuf, ntohs(six->sin6_port), ++ (portal->proto == IPPROTO_UDP)? "udp" : "tcp"); ++ return buffer; ++} ++ ++int ++isns_portal_is_wildcard(const isns_portal_info_t *portal) ++{ ++ return !memcmp(&portal->addr.sin6_addr, ++ &in6addr_any, ++ sizeof(struct in6_addr)); ++} ++ ++int ++isns_portal_equal(const isns_portal_info_t *a, ++ const isns_portal_info_t *b) ++{ ++ if (a->proto != b->proto) ++ return 0; ++ return !memcmp(&a->addr, &b->addr, sizeof(a->addr)); ++} ++ ++uint32_t ++isns_portal_tcpudp_port(const isns_portal_info_t *portal) ++{ ++ uint32_t port; ++ ++ port = isns_addr_get_port((const struct sockaddr *) &portal->addr); ++ if (portal->proto == IPPROTO_UDP) ++ port |= ISNS_PORTAL_PORT_UDP_MASK; ++ return port; ++} ++ ++int ++isns_portal_parse(isns_portal_info_t *portal, ++ const char *spec, ++ const char *default_port) ++{ ++ struct sockaddr_storage addr; ++ char *copy, *psp; ++ int alen, proto = IPPROTO_TCP, sock_type = SOCK_STREAM; ++ ++ if (spec[0] == '/') { ++ isns_warning("%s: no AF_LOCAL addresses for portals!\n", ++ __FUNCTION__); ++ return 0; ++ } ++ ++ /* Look at trailing /tcp or /udp */ ++ copy = isns_strdup(spec); ++ if ((psp = strrchr(copy, '/')) != NULL) { ++ if (!strcasecmp(psp, "/udp")) { ++ sock_type = SOCK_DGRAM; ++ proto = IPPROTO_UDP; ++ *psp = '\0'; ++ } else ++ if (!strcasecmp(psp, "/tcp")) { ++ sock_type = SOCK_STREAM; ++ proto = IPPROTO_TCP; ++ *psp = '\0'; ++ } ++ } ++ ++ alen = isns_get_address(&addr, copy, default_port, 0, sock_type, 0); ++ isns_free(copy); ++ ++ if (alen < 0) ++ return 0; ++ ++ isns_portal_init(portal, (struct sockaddr *) &addr, proto); ++ return 1; ++} ++ ++/* ++ * Attribute type NIL ++ */ ++static int ++isns_attr_type_nil_encode(buf_t *bp, const isns_value_t *value) ++{ ++ return buf_put32(bp, 0); ++} ++ ++static int ++isns_attr_type_nil_decode(buf_t *bp, size_t len, isns_value_t *value) ++{ ++ return len == 0; ++} ++ ++static void ++isns_attr_type_nil_print(const isns_value_t *value, char *buf, size_t size) ++{ ++ snprintf(buf, size, ""); ++} ++ ++static int ++isns_attr_type_nil_parse(isns_value_t *value, const char *string) ++{ ++ if (string && *string) ++ return 0; ++ return 1; ++} ++ ++isns_attr_type_t isns_attr_type_nil = { ++ .it_id = ISNS_ATTR_TYPE_NIL, ++ .it_name = "nil", ++ .it_encode = isns_attr_type_nil_encode, ++ .it_decode = isns_attr_type_nil_decode, ++ .it_print = isns_attr_type_nil_print, ++ .it_parse = isns_attr_type_nil_parse, ++}; ++ ++/* ++ * Attribute type UINT32 ++ */ ++static int ++isns_attr_type_uint32_encode(buf_t *bp, const isns_value_t *value) ++{ ++ return buf_put32(bp, 4) && buf_put32(bp, value->iv_uint32); ++} ++ ++static int ++isns_attr_type_uint32_decode(buf_t *bp, size_t len, isns_value_t *value) ++{ ++ if (len != 4) ++ return 0; ++ return buf_get32(bp, &value->iv_uint32); ++} ++ ++static void ++isns_attr_type_uint32_print(const isns_value_t *value, char *buf, size_t size) ++{ ++ snprintf(buf, size, "%u", value->iv_uint32); ++} ++ ++static int ++isns_attr_type_uint32_parse(isns_value_t *value, const char *string) ++{ ++ char *end; ++ ++ value->iv_uint32 = strtoul(string, &end, 0); ++ return *end == '\0'; ++} ++ ++static void ++isns_attr_type_int32_print(const isns_value_t *value, char *buf, size_t size) ++{ ++ snprintf(buf, size, "%d", value->iv_uint32); ++} ++ ++static int ++isns_attr_type_int32_parse(isns_value_t *value, const char *string) ++{ ++ char *end; ++ ++ value->iv_int32 = strtol(string, &end, 0); ++ return *end == '\0'; ++} ++ ++isns_attr_type_t isns_attr_type_uint32 = { ++ .it_id = ISNS_ATTR_TYPE_UINT32, ++ .it_name = "uint32", ++ .it_encode = isns_attr_type_uint32_encode, ++ .it_decode = isns_attr_type_uint32_decode, ++ .it_print = isns_attr_type_uint32_print, ++ .it_parse = isns_attr_type_uint32_parse, ++}; ++ ++isns_attr_type_t isns_attr_type_int32 = { ++ .it_id = ISNS_ATTR_TYPE_INT32, ++ .it_name = "int32", ++ .it_encode = isns_attr_type_uint32_encode, ++ .it_decode = isns_attr_type_uint32_decode, ++ .it_print = isns_attr_type_int32_print, ++ .it_parse = isns_attr_type_int32_parse, ++}; ++ ++/* ++ * 16bit min/max ++ */ ++static int ++isns_attr_type_range16_encode(buf_t *bp, const isns_value_t *value) ++{ ++ uint32_t word; ++ ++ word = (value->iv_range.max << 16) | value->iv_range.min; ++ return buf_put32(bp, 4) && buf_put32(bp, word); ++} ++ ++static int ++isns_attr_type_range16_decode(buf_t *bp, size_t len, isns_value_t *value) ++{ ++ uint32_t word; ++ ++ if (len != 4) ++ return 0; ++ if (!buf_get32(bp, &word)) ++ return 0; ++ value->iv_range.max = word >> 16; ++ value->iv_range.min = word & 0xFFFF; ++ return 1; ++} ++ ++static void ++isns_attr_type_range16_print(const isns_value_t *value, char *buf, size_t size) ++{ ++ snprintf(buf, size, "[%u, %u]", value->iv_range.min, value->iv_range.max); ++} ++ ++isns_attr_type_t isns_attr_type_range16 = { ++ .it_id = ISNS_ATTR_TYPE_RANGE16, ++ .it_name = "range16", ++ .it_encode = isns_attr_type_range16_encode, ++ .it_decode = isns_attr_type_range16_decode, ++ .it_print = isns_attr_type_range16_print, ++// .it_parse = isns_attr_type_range16_parse, ++}; ++ ++ ++/* ++ * 64bit integers ++ */ ++static int ++isns_attr_type_uint64_encode(buf_t *bp, const isns_value_t *value) ++{ ++ return buf_put32(bp, 8) && buf_put64(bp, value->iv_uint64); ++} ++ ++static int ++isns_attr_type_uint64_decode(buf_t *bp, size_t len, isns_value_t *value) ++{ ++ if (len != 8) ++ return 0; ++ return buf_get64(bp, &value->iv_uint64); ++} ++ ++static void ++isns_attr_type_uint64_print(const isns_value_t *value, char *buf, size_t size) ++{ ++ snprintf(buf, size, "%Lu", (unsigned long long) value->iv_uint64); ++} ++ ++static int ++isns_attr_type_uint64_parse(isns_value_t *value, const char *string) ++{ ++ char *end; ++ ++ value->iv_uint64 = strtoull(string, &end, 0); ++ return *end == '\0'; ++} ++ ++isns_attr_type_t isns_attr_type_uint64 = { ++ .it_id = ISNS_ATTR_TYPE_UINT64, ++ .it_name = "uint64", ++ .it_encode = isns_attr_type_uint64_encode, ++ .it_decode = isns_attr_type_uint64_decode, ++ .it_print = isns_attr_type_uint64_print, ++ .it_parse = isns_attr_type_uint64_parse, ++}; ++ ++/* ++ * Attribute type STRING ++ */ ++static void ++isns_attr_type_string_destroy(isns_value_t *value) ++{ ++ isns_free(value->iv_string); ++ value->iv_string = NULL; ++} ++ ++static int ++isns_attr_type_string_match(const isns_value_t *a, const isns_value_t *b) ++{ ++ if (a->iv_string && b->iv_string) ++ return !strcmp(a->iv_string, b->iv_string); ++ ++ return a->iv_string == b->iv_string; ++} ++ ++static int ++isns_attr_type_string_compare(const isns_value_t *a, const isns_value_t *b) ++{ ++ if (a->iv_string && b->iv_string) ++ return strcmp(a->iv_string, b->iv_string); ++ ++ return a->iv_string? 1 : -1; ++} ++ ++static int ++isns_attr_type_string_encode(buf_t *bp, const isns_value_t *value) ++{ ++ uint32_t len; ++ ++ len = value->iv_string? strlen(value->iv_string) + 1 : 0; ++ ++ if (!buf_put32(bp, ISNS_PAD(len))) ++ return 0; ++ ++ if (len && !isns_encode_padded(bp, value->iv_string, len)) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++isns_attr_type_string_decode(buf_t *bp, size_t len, isns_value_t *value) ++{ ++ /* Is this legal? */ ++ if (len == 0) ++ return 1; ++ ++ /* The string should be NUL terminated, but ++ * better be safe than sorry. */ ++ value->iv_string = isns_malloc(len + 1); ++ if (!buf_get(bp, value->iv_string, len)) { ++ isns_free(value->iv_string); ++ return 0; ++ } ++ value->iv_string[len] = '\0'; ++ return 1; ++} ++ ++static void ++isns_attr_type_string_print(const isns_value_t *value, char *buf, size_t size) ++{ ++ if (!value->iv_string) ++ snprintf(buf, size, "(empty)"); ++ else ++ snprintf(buf, size, "\"%s\"", value->iv_string); ++} ++ ++static int ++isns_attr_type_string_parse(isns_value_t *value, const char *string) ++{ ++ value->iv_string = isns_strdup(string); ++ return 1; ++} ++ ++static void ++isns_attr_type_string_assign(isns_value_t *value, const isns_value_t *new_value) ++{ ++ isns_assert(!value->iv_string); ++ if (new_value->iv_string) ++ value->iv_string = isns_strdup(new_value->iv_string); ++} ++ ++isns_attr_type_t isns_attr_type_string = { ++ .it_id = ISNS_ATTR_TYPE_STRING, ++ .it_name = "string", ++ .it_assign = isns_attr_type_string_assign, ++ .it_destroy = isns_attr_type_string_destroy, ++ .it_match = isns_attr_type_string_match, ++ .it_compare = isns_attr_type_string_compare, ++ .it_encode = isns_attr_type_string_encode, ++ .it_decode = isns_attr_type_string_decode, ++ .it_print = isns_attr_type_string_print, ++ .it_parse = isns_attr_type_string_parse, ++}; ++ ++/* ++ * Attribute type IPADDR ++ */ ++static int ++isns_attr_type_ipaddr_encode(buf_t *bp, const isns_value_t *value) ++{ ++ if (!buf_put32(bp, 16) ++ || !buf_put(bp, &value->iv_ipaddr, 16)) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++isns_attr_type_ipaddr_decode(buf_t *bp, size_t len, isns_value_t *value) ++{ ++ if (len != 16) ++ return 0; ++ ++ return buf_get(bp, &value->iv_ipaddr, 16); ++} ++ ++static void ++isns_attr_type_ipaddr_print(const isns_value_t *value, char *buf, size_t size) ++{ ++ const struct in6_addr *addr = &value->iv_ipaddr; ++ char buffer[INET6_ADDRSTRLEN + 1]; ++ ++ /* The standard requires IPv4 mapping, but ++ * some oldish implementations seem to use ++ * IPv4 compatible addresss. */ ++ if (IN6_IS_ADDR_V4MAPPED(addr) || IN6_IS_ADDR_V4COMPAT(addr)) { ++ struct in_addr ipv4; ++ ++ ipv4.s_addr = addr->s6_addr32[3]; ++ inet_ntop(AF_INET, &ipv4, buffer, sizeof(buffer)); ++ } else { ++ inet_ntop(AF_INET6, addr, buffer, sizeof(buffer)); ++ } ++ snprintf(buf, size, "%s", buffer); ++} ++ ++static int ++isns_attr_type_ipaddr_parse(isns_value_t *value, const char *string) ++{ ++ struct in_addr addr4; ++ ++ if (inet_pton(AF_INET, string, &addr4)) { ++ value->iv_ipaddr = in6addr_any; ++ value->iv_ipaddr.s6_addr32[3] = addr4.s_addr; ++ return 1; ++ } ++ ++ return inet_pton(AF_INET6, string, &value->iv_ipaddr); ++} ++ ++isns_attr_type_t isns_attr_type_ipaddr = { ++ .it_id = ISNS_ATTR_TYPE_IPADDR, ++ .it_name = "ipaddr", ++ .it_encode = isns_attr_type_ipaddr_encode, ++ .it_decode = isns_attr_type_ipaddr_decode, ++ .it_print = isns_attr_type_ipaddr_print, ++ .it_parse = isns_attr_type_ipaddr_parse, ++}; ++ ++/* ++ * Attribute type OPAQUE ++ */ ++static void ++isns_attr_type_opaque_assign(isns_value_t *value, const isns_value_t *new_value) ++{ ++ size_t new_len = new_value->iv_opaque.len; ++ isns_assert(value->iv_opaque.len == 0); ++ if (new_len) { ++ value->iv_opaque.ptr = isns_malloc(new_len); ++ value->iv_opaque.len = new_len; ++ memcpy(value->iv_opaque.ptr, ++ new_value->iv_opaque.ptr, ++ new_len); ++ } ++} ++ ++static void ++isns_attr_type_opaque_destroy(isns_value_t *value) ++{ ++ isns_free(value->iv_opaque.ptr); ++ value->iv_opaque.ptr = NULL; ++ value->iv_opaque.len = 0; ++} ++ ++static int ++isns_attr_type_opaque_match(const isns_value_t *a, const isns_value_t *b) ++{ ++ if (a->iv_opaque.len != b->iv_opaque.len) ++ return 0; ++ return !memcmp(a->iv_opaque.ptr, b->iv_opaque.ptr, a->iv_opaque.len); ++} ++ ++static int ++isns_attr_type_opaque_compare(const isns_value_t *a, const isns_value_t *b) ++{ ++ long delta; ++ ++ delta = a->iv_opaque.len - b->iv_opaque.len; ++ if (delta) ++ return delta; ++ ++ return memcmp(a->iv_opaque.ptr, b->iv_opaque.ptr, a->iv_opaque.len); ++} ++ ++static int ++isns_attr_type_opaque_encode(buf_t *bp, const isns_value_t *value) ++{ ++ uint32_t len; ++ ++ len = value->iv_opaque.len; ++ if (len & 3) ++ return 0; ++ ++ if (!buf_put32(bp, len) ++ || !buf_put(bp, value->iv_opaque.ptr, len)) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++isns_attr_type_opaque_decode(buf_t *bp, size_t len, isns_value_t *value) ++{ ++ value->iv_opaque.ptr = isns_malloc(len); ++ if (!buf_get(bp, value->iv_opaque.ptr, len)) { ++ isns_free(value->iv_opaque.ptr); ++ return 0; ++ } ++ ++ value->iv_opaque.len = len; ++ return 1; ++} ++ ++static void ++isns_attr_type_opaque_print(const isns_value_t *value, char *buf, size_t size) ++{ ++ unsigned char *data = value->iv_opaque.ptr; ++ unsigned int i, len; ++ ++ /* There must be room for "<...>\0" */ ++ if (size < 6) ++ return; ++ size -= 6; ++ ++ if ((len = value->iv_opaque.len) > 20) ++ len = 20; ++ if (size < 3 * len) ++ len = size / 3; ++ ++ *buf++ = '<'; ++ for (i = 0; i < len; ++i) { ++ if (i) ++ *buf++ = ' '; ++ sprintf(buf, "%02x", data[i]); ++ buf += 2; ++ } ++ if (len < value->iv_opaque.len) { ++ strcat(buf, "..."); ++ buf += 4; ++ } ++ *buf++ = '>'; ++ *buf++ = '\0'; ++} ++ ++isns_attr_type_t isns_attr_type_opaque = { ++ .it_id = ISNS_ATTR_TYPE_OPAQUE, ++ .it_name = "opaque", ++ .it_assign = isns_attr_type_opaque_assign, ++ .it_destroy = isns_attr_type_opaque_destroy, ++ .it_match = isns_attr_type_opaque_match, ++ .it_compare = isns_attr_type_opaque_compare, ++ .it_encode = isns_attr_type_opaque_encode, ++ .it_decode = isns_attr_type_opaque_decode, ++ .it_print = isns_attr_type_opaque_print, ++}; ++ ++/* ++ * Map attribute type IDs to attribute types ++ */ ++static isns_attr_type_t * ++isns_attr_types_builtin[__ISNS_ATTR_TYPE_BUILTIN_MAX] = { ++[ISNS_ATTR_TYPE_NIL] = &isns_attr_type_nil, ++[ISNS_ATTR_TYPE_OPAQUE] = &isns_attr_type_opaque, ++[ISNS_ATTR_TYPE_STRING] = &isns_attr_type_string, ++[ISNS_ATTR_TYPE_INT32] = &isns_attr_type_int32, ++[ISNS_ATTR_TYPE_UINT32] = &isns_attr_type_uint32, ++[ISNS_ATTR_TYPE_UINT64] = &isns_attr_type_uint64, ++[ISNS_ATTR_TYPE_IPADDR] = &isns_attr_type_ipaddr, ++[ISNS_ATTR_TYPE_RANGE16] = &isns_attr_type_range16, ++}; ++ ++const isns_attr_type_t * ++isns_attr_type_by_id(unsigned int id) ++{ ++ if (id < __ISNS_ATTR_TYPE_BUILTIN_MAX) ++ return isns_attr_types_builtin[id]; ++ ++ /* TODO: handle dynamic registration of attrtypes ++ * for vendor extensions. */ ++ return NULL; ++} +diff --git a/utils/open-isns/attrs.h b/utils/open-isns/attrs.h +new file mode 100644 +index 0000000..1d3667e +--- /dev/null ++++ b/utils/open-isns/attrs.h +@@ -0,0 +1,262 @@ ++/* ++ * iSNS object attributes ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#ifndef ISNS_ATTRS_H ++#define ISNS_ATTRS_H ++ ++#include ++#include "buffer.h" ++#include "isns.h" ++ ++/* ++ * Type identifier ++ */ ++enum { ++ ISNS_ATTR_TYPE_NIL = 0, ++ ISNS_ATTR_TYPE_OPAQUE, ++ ISNS_ATTR_TYPE_STRING, ++ ISNS_ATTR_TYPE_INT32, ++ ISNS_ATTR_TYPE_UINT32, ++ ISNS_ATTR_TYPE_UINT64, ++ ISNS_ATTR_TYPE_IPADDR, ++ ISNS_ATTR_TYPE_RANGE16, ++ ++ __ISNS_ATTR_TYPE_BUILTIN_MAX ++}; ++ ++/* ++ * Union holding an attribute value ++ */ ++typedef struct isns_value { ++ const struct isns_attr_type * iv_type; ++ ++ /* Data is stuffed into an anonymous union */ ++ union { ++ uint32_t iv_nil; ++ struct __isns_opaque { ++ void * ptr; ++ size_t len; ++ } iv_opaque; ++ char * iv_string; ++ int32_t iv_int32; ++ uint32_t iv_uint32; ++ uint64_t iv_uint64; ++ struct in6_addr iv_ipaddr; ++ struct { ++ uint16_t min, max; ++ } iv_range; ++ }; ++} isns_value_t; ++ ++#define __ISNS_ATTRTYPE(type) isns_attr_type_##type ++#define __ISNS_MEMBER(type) iv_##type ++#define ISNS_VALUE_INIT(type, value) \ ++ (isns_value_t) { .iv_type = &__ISNS_ATTRTYPE(type), \ ++ { .__ISNS_MEMBER(type) = (value) } } ++ ++#define isns_attr_initialize(attrp, tag, type, value) do { \ ++ isns_attr_t *__attr = (attrp); \ ++ uint32_t __tag = (tag); \ ++ __attr->ia_users = 1; \ ++ __attr->ia_tag_id = (__tag); \ ++ __attr->ia_tag = isns_tag_type_by_id(__tag); \ ++ __attr->ia_value = ISNS_VALUE_INIT(type, value); \ ++ } while (0) ++#define ISNS_ATTR_INIT(tag, type, value) (isns_attr_t) { \ ++ .ia_users = 1, \ ++ .ia_tag_id = (tag), \ ++ .ia_tag = isns_tag_type_by_id(tag), \ ++ .ia_value = ISNS_VALUE_INIT(type, value) \ ++ } ++ ++/* ++ * Attribute type ++ */ ++typedef struct isns_attr_type { ++ uint32_t it_id; ++ const char * it_name; ++ ++ void (*it_assign)(isns_value_t *, const isns_value_t *); ++ int (*it_set)(isns_value_t *, const void *); ++ int (*it_get)(isns_value_t *, void *); ++ int (*it_match)(const isns_value_t *, const isns_value_t *); ++ int (*it_compare)(const isns_value_t *, const isns_value_t *); ++ int (*it_encode)(buf_t *, const isns_value_t *); ++ int (*it_decode)(buf_t *, size_t, isns_value_t *); ++ void (*it_destroy)(isns_value_t *); ++ void (*it_print)(const isns_value_t *, char *, size_t); ++ int (*it_parse)(isns_value_t *, const char *); ++} isns_attr_type_t; ++ ++/* ++ * Tag info: for each tag, provides a printable name, ++ * and the attribute type associated with it. ++ */ ++struct isns_tag_type { ++ uint32_t it_id; ++ const char * it_name; ++ unsigned int it_multiple : 1, ++ it_readonly : 1; ++ isns_attr_type_t *it_type; ++ ++ int (*it_validate)(const isns_value_t *, ++ const isns_policy_t *); ++ void (*it_print)(const isns_value_t *, char *, size_t); ++ int (*it_parse)(isns_value_t *, const char *); ++ const char * (*it_help)(void); ++}; ++ ++/* ++ * Attribute ++ */ ++struct isns_attr { ++ unsigned int ia_users; ++ uint32_t ia_tag_id; ++ const isns_tag_type_t * ia_tag; ++ isns_value_t ia_value; ++}; ++ ++extern isns_attr_type_t isns_attr_type_nil; ++extern isns_attr_type_t isns_attr_type_opaque; ++extern isns_attr_type_t isns_attr_type_string; ++extern isns_attr_type_t isns_attr_type_int32; ++extern isns_attr_type_t isns_attr_type_uint32; ++extern isns_attr_type_t isns_attr_type_uint64; ++extern isns_attr_type_t isns_attr_type_ipaddr; ++extern isns_attr_type_t isns_attr_type_range16; ++ ++extern isns_attr_t * isns_attr_alloc(uint32_t, const isns_tag_type_t *, ++ const isns_value_t *); ++ ++extern void isns_attr_list_append_value(isns_attr_list_t *, ++ uint32_t tag, const isns_tag_type_t *, ++ const isns_value_t *); ++extern void isns_attr_list_update_value(isns_attr_list_t *, ++ uint32_t tag, const isns_tag_type_t *, ++ const isns_value_t *); ++extern int isns_attr_list_get_value(const isns_attr_list_t *, ++ uint32_t tag, ++ isns_value_t *); ++extern int isns_attr_list_get_uint32(const isns_attr_list_t *, ++ uint32_t tag, ++ uint32_t *); ++extern int isns_attr_list_get_string(const isns_attr_list_t *, ++ uint32_t tag, ++ const char **); ++ ++extern int isns_attr_list_validate(const isns_attr_list_t *, ++ const isns_policy_t *, ++ unsigned int function); ++extern int isns_attr_validate(const isns_attr_t *, ++ const isns_policy_t *); ++ ++extern void isns_attr_list_prune(isns_attr_list_t *, ++ const uint32_t *, ++ unsigned int); ++extern int isns_attr_list_remove_member(isns_attr_list_t *, ++ const isns_attr_t *, ++ const uint32_t *); ++extern void isns_attr_list_update_attr(isns_attr_list_t *, ++ const isns_attr_t *); ++ ++extern int isns_attr_decode(buf_t *, isns_attr_t **); ++extern int isns_attr_encode(buf_t *, const isns_attr_t *); ++ ++extern int isns_attr_list_decode(buf_t *, isns_attr_list_t *); ++extern int isns_attr_list_decode_delimited(buf_t *, isns_attr_list_t *); ++extern int isns_attr_list_encode(buf_t *, const isns_attr_list_t *); ++extern int isns_encode_delimiter(buf_t *); ++ ++extern const isns_tag_type_t *isns_tag_type_by_id(unsigned int); ++extern const isns_attr_type_t *isns_attr_type_by_id(unsigned int); ++ ++typedef struct isns_quick_attr_list isns_quick_attr_list_t; ++struct isns_quick_attr_list { ++ isns_attr_list_t iqa_list; ++ isns_attr_t * iqa_attrs[1]; ++ isns_attr_t iqa_attr; ++}; ++#define ISNS_QUICK_ATTR_LIST_DECLARE(qlist, tag, type, value) \ ++ isns_quick_attr_list_t qlist = { \ ++ .iqa_list = (isns_attr_list_t) { \ ++ .ial_data = qlist.iqa_attrs, \ ++ .ial_count = 1 \ ++ }, \ ++ .iqa_attrs = { &qlist.iqa_attr }, \ ++ .iqa_attr = ISNS_ATTR_INIT(tag, type, value), \ ++ } ++ ++/* ++ * The following is used to chop up an incoming attr list as ++ * given in eg. a DevAttrReg message into separate chunks, ++ * following the ordering constraints laid out in the RFC. ++ * ++ * isns_attr_list_scanner_init initializes the scanner state. ++ * ++ * isns_attr_list_scanner_next advances to the next object in ++ * the list, returning the keys and attrs for one object. ++ * ++ * The isns_attr_list_scanner struct should really be opaque, but ++ * we put it here so you can declare a scanner variable on the ++ * stack. ++ */ ++struct isns_attr_list_scanner { ++ isns_source_t * source; ++ isns_policy_t * policy; ++ isns_object_t * key_obj; ++ isns_attr_list_t orig_attrs; ++ unsigned int pos; ++ ++ isns_attr_list_t keys; ++ isns_attr_list_t attrs; ++ isns_object_template_t *tmpl; ++ unsigned int num_key_attrs; ++ ++ unsigned int entities; ++ ++ uint32_t pgt_next_attr; ++ uint32_t pgt_value; ++ const char * pgt_iscsi_name; ++ isns_portal_info_t pgt_portal_info; ++ isns_object_t * pgt_base_object; ++ ++ unsigned int index_acceptable : 1; ++}; ++ ++extern void isns_attr_list_scanner_init(struct isns_attr_list_scanner *, ++ isns_object_t *key_obj, ++ const isns_attr_list_t *attrs); ++extern int isns_attr_list_scanner_next(struct isns_attr_list_scanner *); ++extern void isns_attr_list_scanner_destroy(struct isns_attr_list_scanner *); ++ ++/* ++ * The following is used to parse attribute lists given as ++ * a bunch of strings. ++ */ ++struct isns_attr_list_parser { ++ struct isns_tag_prefix *prefix; ++ const char * default_port; ++ ++ unsigned int multi_type_permitted : 1, ++ nil_permitted : 1; ++ ++ isns_attr_t * (*load_key)(const char *); ++ isns_attr_t * (*generate_key)(void); ++}; ++ ++extern int isns_attr_list_split(char *line, char **argv, unsigned int argc_max); ++extern void isns_attr_list_parser_init(struct isns_attr_list_parser *, ++ isns_object_template_t *); ++extern int isns_parse_attrs(unsigned int, char **, ++ isns_attr_list_t *, struct isns_attr_list_parser *); ++extern int isns_parse_query_attrs(unsigned int, char **, ++ isns_attr_list_t *, isns_attr_list_t *, ++ struct isns_attr_list_parser *); ++extern void isns_attr_list_parser_help(struct isns_attr_list_parser *); ++extern isns_object_template_t *isns_attr_list_parser_context(const struct isns_attr_list_parser *); ++extern int isns_print_attrs(isns_object_t *, char **, unsigned int); ++ ++#endif /* ISNS_ATTRS_H */ +diff --git a/utils/open-isns/authblock.c b/utils/open-isns/authblock.c +new file mode 100644 +index 0000000..76d35b4 +--- /dev/null ++++ b/utils/open-isns/authblock.c +@@ -0,0 +1,62 @@ ++/* ++ * iSNS authentication functions ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include "isns.h" ++#include "attrs.h" ++#include "message.h" ++#include "util.h" ++ ++/* We impose an artificial limit on the size of ++ * the size of the authenticator ++ */ ++#define ISNS_SPISTR_MAX 512 ++ ++int ++isns_authblock_decode(buf_t *bp, struct isns_authblk *auth) ++{ ++ unsigned int avail = buf_avail(bp); ++ ++ if (!buf_get32(bp, &auth->iab_bsd) ++ || !buf_get32(bp, &auth->iab_length) ++ || !buf_get64(bp, &auth->iab_timestamp) ++ || !buf_get32(bp, &auth->iab_spi_len)) ++ return 0; ++ ++ /* Make sure the length specified by the auth block ++ * is reasonable. */ ++ if (auth->iab_length < ISNS_AUTHBLK_SIZE ++ || auth->iab_length > avail) ++ return 0; ++ ++ /* This chops off any data trailing the auth block. ++ * It also makes sure that we detect if iab_length ++ * exceeds the amount of available data. */ ++ if (!buf_truncate(bp, auth->iab_length - ISNS_AUTHBLK_SIZE)) ++ return 0; ++ ++ auth->iab_spi = buf_head(bp); ++ if (!buf_pull(bp, auth->iab_spi_len)) ++ return 0; ++ ++ auth->iab_sig = buf_head(bp); ++ auth->iab_sig_len = buf_avail(bp); ++ return 1; ++} ++ ++int ++isns_authblock_encode(buf_t *bp, const struct isns_authblk *auth) ++{ ++ if (!buf_put32(bp, auth->iab_bsd) ++ || !buf_put32(bp, auth->iab_length) ++ || !buf_put64(bp, auth->iab_timestamp) ++ || !buf_put32(bp, auth->iab_spi_len) ++ || !buf_put(bp, auth->iab_spi, auth->iab_spi_len) ++ || !buf_put(bp, auth->iab_sig, auth->iab_sig_len)) ++ return 0; ++ return 1; ++} +diff --git a/utils/open-isns/bitvector.c b/utils/open-isns/bitvector.c +new file mode 100644 +index 0000000..9d66276 +--- /dev/null ++++ b/utils/open-isns/bitvector.c +@@ -0,0 +1,648 @@ ++/* ++ * Handle bit vector as a run length encoded array of ++ * 32bit words. ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include "isns.h" ++#include "util.h" ++ ++struct isns_bitvector { ++ unsigned int ib_count; ++ uint32_t * ib_words; ++}; ++ ++void ++isns_bitvector_init(isns_bitvector_t *bv) ++{ ++ memset(bv, 0, sizeof(*bv)); ++} ++ ++void ++isns_bitvector_destroy(isns_bitvector_t *bv) ++{ ++ isns_free(bv->ib_words); ++ memset(bv, 0, sizeof(*bv)); ++} ++ ++isns_bitvector_t * ++isns_bitvector_alloc(void) ++{ ++ return isns_calloc(1, sizeof(isns_bitvector_t)); ++} ++ ++void ++isns_bitvector_free(isns_bitvector_t *bv) ++{ ++ if (bv) { ++ isns_free(bv->ib_words); ++ memset(bv, 0xa5, sizeof(*bv)); ++ isns_free(bv); ++ } ++} ++ ++/* ++ * Helper function to locate bit ++ */ ++uint32_t * ++__isns_bitvector_find_word(const isns_bitvector_t *bv, unsigned int bit) ++{ ++ uint32_t *wp, *end; ++ ++ if (bv->ib_words == NULL) ++ return NULL; ++ ++ wp = bv->ib_words; ++ end = wp + bv->ib_count; ++ while (wp < end) { ++ unsigned int base, rlen; ++ ++ base = wp[0]; ++ rlen = wp[1]; ++ ++ isns_assert(!(base % 32)); ++ if (base <= bit && bit < base + rlen * 32) ++ return wp + 2 + ((bit - base) / 32); ++ ++ wp += 2 + rlen; ++ isns_assert(wp <= end); ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Insert words in the middle of the array ++ */ ++static inline void ++__isns_bitvector_insert_words(isns_bitvector_t *bv, ++ unsigned int offset, unsigned int count) ++{ ++ bv->ib_words = isns_realloc(bv->ib_words, ++ (bv->ib_count + count) * sizeof(uint32_t)); ++ ++ /* If we insert in the middle, shift out the tail ++ * to make room for the new range. */ ++ isns_assert(offset <= bv->ib_count); ++ if (offset < bv->ib_count) { ++ memmove(bv->ib_words + offset + count, ++ bv->ib_words + offset, ++ (bv->ib_count - offset) * sizeof(uint32_t)); ++ } ++ ++ memset(bv->ib_words + offset, 0, count * sizeof(uint32_t)); ++ bv->ib_count += count; ++} ++ ++/* ++ * Insert a new range ++ */ ++static inline uint32_t * ++__isns_bitvector_insert_range(isns_bitvector_t *bv, ++ unsigned int offset, unsigned int base) ++{ ++ uint32_t *pos; ++ ++ __isns_bitvector_insert_words(bv, offset, 3); ++ ++ pos = bv->ib_words + offset; ++ ++ *pos++ = base & ~31; ++ *pos++ = 1; ++ ++ return pos; ++} ++ ++/* ++ * Extend an existing range ++ * @offset marks the beginning of the existing range. ++ */ ++static inline uint32_t * ++__isns_bitvector_extend_range(isns_bitvector_t *bv, ++ unsigned int offset, unsigned int count) ++{ ++ uint32_t *pos, rlen; ++ ++ /* Find the end of the range */ ++ pos = bv->ib_words + offset; ++ rlen = pos[1]; ++ ++ __isns_bitvector_insert_words(bv, offset + 2 + rlen, count); ++ ++ pos = bv->ib_words + offset; ++ pos[1] += count; ++ ++ /* Return pointer to the last word of the new range. */ ++ return pos + 2 + rlen + count - 1; ++} ++ ++/* ++ * Find a suitable range for insertion ++ */ ++static uint32_t * ++__isns_bitvector_find_insert_word(isns_bitvector_t *bv, unsigned int bit) ++{ ++ uint32_t *wp, *end; ++ ++ if (bv->ib_words == NULL) ++ return __isns_bitvector_insert_range(bv, 0, bit); ++ ++ wp = bv->ib_words; ++ end = wp + bv->ib_count; ++ while (wp < end) { ++ unsigned int base, rlen, distance; ++ ++ base = wp[0]; ++ rlen = wp[1]; ++ ++ isns_assert(!(base % 32)); ++ ++ if (bit < base) { ++ return __isns_bitvector_insert_range(bv, ++ wp - bv->ib_words, bit); ++ } ++ ++ distance = (bit - base) / 32; ++ if (distance < rlen) { ++ /* This bit is within range */ ++ return wp + 2 + distance; ++ } ++ ++ /* Is it efficient to extend this range? ++ * The break even point is if we have to add ++ * 3 words to extend the range, because a new ++ * range would be at least that much. ++ */ ++ if (distance + 1 <= rlen + 3) { ++ return __isns_bitvector_extend_range(bv, ++ wp - bv->ib_words, ++ distance + 1 - rlen); ++ } ++ ++ wp += 2 + rlen; ++ isns_assert(wp <= end); ++ } ++ ++ /* No suitable range found. Append one at the end */ ++ return __isns_bitvector_insert_range(bv, ++ bv->ib_count, bit); ++} ++ ++/* ++ * After clearing a bit, check if the bitvector can be ++ * compacted. ++ */ ++static void ++__isns_bitvector_compact(isns_bitvector_t *bv) ++{ ++ uint32_t *src, *dst, *end; ++ unsigned int dst_base = 0, dst_len = 0; ++ ++ if (bv->ib_words == NULL) ++ return; ++ ++ src = dst = bv->ib_words; ++ end = src + bv->ib_count; ++ while (src < end) { ++ unsigned int base, rlen; ++ ++ base = *src++; ++ rlen = *src++; ++ ++ /* Consume leading NUL words */ ++ while (rlen && *src == 0) { ++ base += 32; ++ src++; ++ rlen--; ++ } ++ ++ /* Consume trailing NUL words */ ++ while (rlen && src[rlen-1] == 0) ++ rlen--; ++ ++ if (rlen != 0) { ++ if (dst_len && dst_base + 32 * dst_len == base) { ++ /* We can extend the previous run */ ++ } else { ++ /* New run. Close off the previous one, ++ * if we had one. */ ++ if (dst_len != 0) { ++ dst[0] = dst_base; ++ dst[1] = dst_len; ++ dst += 2 + dst_len; ++ } ++ ++ dst_base = base; ++ dst_len = 0; ++ } ++ ++ while (rlen--) ++ dst[2 + dst_len++] = *src++; ++ } ++ ++ isns_assert(src <= end); ++ } ++ ++ ++ if (dst_len != 0) { ++ dst[0] = dst_base; ++ dst[1] = dst_len; ++ dst += 2 + dst_len; ++ } ++ ++ bv->ib_count = dst - bv->ib_words; ++ if (bv->ib_count == 0) ++ isns_bitvector_destroy(bv); ++} ++ ++/* ++ * Test the value of a single bit ++ */ ++int ++isns_bitvector_test_bit(const isns_bitvector_t *bv, unsigned int bit) ++{ ++ const uint32_t *pos; ++ uint32_t mask; ++ ++ pos = __isns_bitvector_find_word(bv, bit); ++ if (pos == NULL) ++ return 0; ++ ++ mask = 1 << (bit % 32); ++ return !!(*pos & mask); ++} ++ ++int ++isns_bitvector_clear_bit(isns_bitvector_t *bv, unsigned int bit) ++{ ++ uint32_t *pos, oldval, mask; ++ ++ pos = __isns_bitvector_find_word(bv, bit); ++ if (pos == NULL) ++ return 0; ++ ++ mask = 1 << (bit % 32); ++ oldval = *pos; ++ *pos &= ~mask; ++ ++ __isns_bitvector_compact(bv); ++ return !!(oldval & mask); ++} ++ ++int ++isns_bitvector_set_bit(isns_bitvector_t *bv, unsigned int bit) ++{ ++ uint32_t *pos, oldval = 0, mask; ++ ++ mask = 1 << (bit % 32); ++ ++ pos = __isns_bitvector_find_insert_word(bv, bit); ++ if (pos != NULL) { ++ oldval = *pos; ++ *pos |= mask; ++ ++ return !!(oldval & mask); ++ } ++ ++ return 0; ++} ++ ++int ++isns_bitvector_is_empty(const isns_bitvector_t *bv) ++{ ++ uint32_t *wp, *end; ++ ++ if (bv == NULL || bv->ib_count == 0) ++ return 1; ++ ++ /* In theory, we should never have a non-compacted ++ * empty bitvector, as the only way to get one ++ * is through clear_bit. ++ * Better safe than sorry... ++ */ ++ ++ wp = bv->ib_words; ++ end = wp + bv->ib_count; ++ while (wp < end) { ++ unsigned int rlen; ++ ++ rlen = wp[1]; ++ wp += 2; ++ ++ while (rlen--) { ++ if (*wp++) ++ return 0; ++ } ++ isns_assert(wp <= end); ++ } ++ ++ return 1; ++} ++ ++int ++isns_bitvector_intersect(const isns_bitvector_t *a, ++ const isns_bitvector_t *b, ++ isns_bitvector_t *result) ++{ ++ const uint32_t *runa, *runb, *enda, *endb; ++ const uint32_t *wpa = NULL, *wpb = NULL; ++ uint32_t bita = 0, lena = 0, bitb = 0, lenb = 0; ++ int found = -1; ++ ++ if (a == NULL || b == NULL) ++ return -1; ++ ++ /* Returning the intersect is not implemented yet. */ ++ isns_assert(result == NULL); ++ ++ runa = a->ib_words; ++ enda = runa + a->ib_count; ++ runb = b->ib_words; ++ endb = runb + b->ib_count; ++ ++ while (1) { ++ unsigned int skip; ++ ++ if (lena == 0) { ++next_a: ++ if (runa >= enda) ++ break; ++ bita = *runa++; ++ lena = *runa++; ++ wpa = runa; ++ runa += lena; ++ lena *= 32; ++ } ++ ++ if (lenb == 0) { ++next_b: ++ if (runb >= endb) ++ break; ++ bitb = *runb++; ++ lenb = *runb++; ++ wpb = runb; ++ runb += lenb; ++ lenb *= 32; ++ } ++ ++ if (bita < bitb) { ++ skip = bitb - bita; ++ ++ /* range A ends before range B starts. ++ * Proceed to next run in vector A. */ ++ if (skip >= lena) ++ goto next_a; ++ ++ bita += skip; ++ lena -= skip; ++ wpa += skip / 32; ++ } else ++ if (bitb < bita) { ++ skip = bita - bitb; ++ ++ /* range B ends before range A starts. ++ * Proceed to next run in vector B. */ ++ if (skip >= lenb) ++ goto next_b; ++ ++ bitb += skip; ++ lenb -= skip; ++ wpb += skip / 32; ++ } ++ ++ isns_assert(bita == bitb); ++ ++ while (lena && lenb) { ++ uint32_t intersect; ++ ++ intersect = *wpa & *wpb; ++ ++ if (!intersect) ++ goto next_word; ++ ++ /* Find the bit */ ++ if (found < 0) { ++ uint32_t mask = intersect; ++ ++ found = bita; ++ while (!(mask & 1)) { ++ found++; ++ mask >>= 1; ++ } ++ } ++ ++ if (result == NULL) ++ return found; ++ ++ /* Append to result vector */ ++ /* FIXME: TBD */ ++ ++next_word: ++ bita += 32; lena -= 32; wpa++; ++ bitb += 32; lenb -= 32; wpb++; ++ } ++ } ++ ++ return found; ++} ++ ++/* ++ * Iterate over the bit vector ++ */ ++void ++isns_bitvector_foreach(const isns_bitvector_t *bv, ++ int (*cb)(uint32_t, void *), ++ void *user_data) ++{ ++ uint32_t *wp, *end; ++ ++ wp = bv->ib_words; ++ end = wp + bv->ib_count; ++ while (wp < end) { ++ unsigned int base, rlen; ++ ++ base = wp[0]; ++ rlen = wp[1]; ++ wp += 2; ++ ++ while (rlen--) { ++ uint32_t mask, word; ++ ++ word = *wp++; ++ for (mask = 1; mask; mask <<= 1, ++base) { ++ if (word & mask) ++ cb(base, user_data); ++ } ++ } ++ isns_assert(wp <= end); ++ } ++} ++ ++void ++isns_bitvector_dump(const isns_bitvector_t *bv, isns_print_fn_t *fn) ++{ ++ uint32_t *wp, *end; ++ ++ fn("Bit Vector %p (%u words):", bv, bv->ib_count); ++ ++ wp = bv->ib_words; ++ end = wp + bv->ib_count; ++ while (wp < end) { ++ unsigned int base, rlen; ++ ++ base = wp[0]; ++ rlen = wp[1]; ++ wp += 2; ++ ++ fn(" <%u:", base); ++ while (rlen--) ++ fn(" 0x%x", *wp++); ++ fn(">"); ++ ++ isns_assert(wp <= end); ++ } ++ ++ if (bv->ib_count == 0) ++ fn(""); ++ fn("\n"); ++} ++ ++static inline void ++__isns_bitvector_print_next(uint32_t first, uint32_t last, ++ isns_print_fn_t *fn) ++{ ++ switch (last - first) { ++ case 0: ++ return; ++ case 1: ++ fn(", %u", last); ++ break; ++ default: ++ fn("-%u", last); ++ break; ++ } ++} ++ ++void ++isns_bitvector_print(const isns_bitvector_t *bv, ++ isns_print_fn_t *fn) ++{ ++ uint32_t *wp, *end, first = 0, next = 0; ++ const char *sepa = ""; ++ ++ wp = bv->ib_words; ++ end = wp + bv->ib_count; ++ while (wp < end) { ++ unsigned int base, rlen; ++ ++ base = wp[0]; ++ rlen = wp[1]; ++ wp += 2; ++ ++ while (rlen--) { ++ uint32_t mask, word; ++ ++ word = *wp++; ++ for (mask = 1; mask; mask <<= 1, ++base) { ++ if (word & mask) { ++ if (next++) ++ continue; ++ fn("%s%u", sepa, base); ++ sepa = ", "; ++ first = base; ++ next = base + 1; ++ } else { ++ if (next) ++ __isns_bitvector_print_next(first, next - 1, fn); ++ first = next = 0; ++ } ++ } ++ } ++ isns_assert(wp <= end); ++ } ++ ++ if (next) ++ __isns_bitvector_print_next(first, next - 1, fn); ++ ++ if (*sepa == '\0') ++ fn(""); ++ fn("\n"); ++} ++ ++#ifdef TEST ++int ++main(void) ++{ ++ isns_bitvector_t a, b; ++ int i; ++ ++ isns_bitvector_init(&a); ++ isns_bitvector_set_bit(&a, 0); ++ isns_bitvector_dump(&a, isns_print_stdout); ++ isns_bitvector_set_bit(&a, 1); ++ isns_bitvector_set_bit(&a, 16); ++ isns_bitvector_set_bit(&a, 32); ++ isns_bitvector_set_bit(&a, 64); ++ isns_bitvector_dump(&a, isns_print_stdout); ++ isns_bitvector_set_bit(&a, 8192); ++ isns_bitvector_set_bit(&a, 8196); ++ isns_bitvector_set_bit(&a, 8194); ++ isns_bitvector_dump(&a, isns_print_stdout); ++ isns_bitvector_set_bit(&a, 2052); ++ isns_bitvector_set_bit(&a, 2049); ++ isns_bitvector_set_bit(&a, 2051); ++ isns_bitvector_set_bit(&a, 2050); ++ isns_bitvector_dump(&a, isns_print_stdout); ++ isns_bitvector_print(&a, isns_print_stdout); ++ isns_bitvector_destroy(&a); ++ ++ isns_bitvector_init(&a); ++ for (i = 127; i >= 0; --i) ++ isns_bitvector_set_bit(&a, i); ++ isns_bitvector_dump(&a, isns_print_stdout); ++ printf("[Compacting]\n"); ++ __isns_bitvector_compact(&a); ++ isns_bitvector_dump(&a, isns_print_stdout); ++ isns_bitvector_print(&a, isns_print_stdout); ++ isns_bitvector_destroy(&a); ++ ++ isns_bitvector_init(&a); ++ for (i = 0; i < 128; ++i) ++ isns_bitvector_set_bit(&a, i); ++ isns_bitvector_dump(&a, isns_print_stdout); ++ isns_bitvector_print(&a, isns_print_stdout); ++ isns_bitvector_destroy(&a); ++ ++ isns_bitvector_init(&a); ++ isns_bitvector_init(&b); ++ isns_bitvector_set_bit(&a, 0); ++ isns_bitvector_set_bit(&a, 77); ++ isns_bitvector_set_bit(&a, 249); ++ isns_bitvector_set_bit(&a, 102); ++ ++ isns_bitvector_set_bit(&b, 1); ++ isns_bitvector_set_bit(&b, 76); ++ isns_bitvector_set_bit(&b, 250); ++ isns_bitvector_set_bit(&b, 102); ++ i = isns_bitvector_intersect(&a, &b, NULL); ++ if (i != 102) ++ fprintf(stderr, "*** BAD: Intersect should return 102 (got %d)! ***\n", i); ++ else ++ printf("Intersect okay: %d\n", i); ++ isns_bitvector_destroy(&a); ++ isns_bitvector_destroy(&b); ++ ++ isns_bitvector_init(&a); ++ isns_bitvector_set_bit(&a, 0); ++ isns_bitvector_set_bit(&a, 1); ++ isns_bitvector_clear_bit(&a, 1); ++ isns_bitvector_clear_bit(&a, 0); ++ isns_bitvector_dump(&a, isns_print_stdout); ++ isns_bitvector_print(&a, isns_print_stdout); ++ isns_bitvector_destroy(&a); ++ return 0; ++} ++#endif +diff --git a/utils/open-isns/buffer.c b/utils/open-isns/buffer.c +new file mode 100644 +index 0000000..279ab76 +--- /dev/null ++++ b/utils/open-isns/buffer.c +@@ -0,0 +1,407 @@ ++/* ++ * Buffer handling functions ++ * ++ * Copyright (C) 2003-2007, Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* ntohl&htonl */ ++#include "buffer.h" ++#include "util.h" /* htonll */ ++ ++static int buf_drain(buf_t *bp); ++ ++buf_t * ++buf_alloc(size_t size) ++{ ++ buf_t *bp; ++ ++ bp = isns_calloc(1, sizeof(*bp)); ++ buf_init_empty(bp, size); ++ ++ return bp; ++} ++ ++buf_t * ++buf_open(const char *filename, int flags) ++{ ++ static const unsigned int buflen = 4096; ++ buf_t *bp; ++ int oerr; ++ ++ if (!(bp = isns_calloc(1, sizeof(*bp) + buflen))) ++ return NULL; ++ buf_init(bp, (bp + 1), buflen); ++ ++ switch (flags & O_ACCMODE) { ++ case O_RDONLY: ++ bp->write_mode = 0; ++ break; ++ ++ case O_WRONLY: ++ bp->write_mode = 1; ++ break; ++ ++ default: ++ errno = EINVAL; ++ goto failed; ++ } ++ ++ if (!filename || !strcmp(filename, "-")) { ++ bp->fd = dup(bp->write_mode? 1 : 0); ++ } else { ++ bp->fd = open(filename, flags, 0666); ++ } ++ ++ if (bp->fd < 0) ++ goto failed; ++ ++ return bp; ++ ++failed: oerr = errno; ++ isns_free(bp); ++ errno = oerr; ++ return NULL; ++} ++ ++buf_t * ++buf_dup(const buf_t *src) ++{ ++ buf_t *bp; ++ ++ bp = buf_alloc(src->max_size); ++ buf_put(bp, src->base + src->head, src->tail - src->head); ++ ++ bp->addr = src->addr; ++ bp->addrlen = src->addrlen; ++ return bp; ++} ++ ++void ++buf_close(buf_t *bp) ++{ ++ if (bp->write_mode) ++ buf_drain(bp); ++ if (bp->fd >= 0) ++ close(bp->fd); ++ bp->fd = -1; ++ isns_free(bp); ++} ++ ++void ++buf_free(buf_t *bp) ++{ ++ if (!bp) ++ return; ++ if (bp->allocated) ++ isns_free(bp->base); ++ isns_free(bp); ++} ++ ++void ++buf_list_free(buf_t *bp) ++{ ++ buf_t *next; ++ ++ while (bp) { ++ next = bp->next; ++ buf_free(bp); ++ bp = next; ++ } ++} ++ ++void ++buf_init(buf_t *bp, void *mem, size_t len) ++{ ++ memset(bp, 0, sizeof(*bp)); ++ bp->base = (unsigned char *) mem; ++ bp->size = len; ++ bp->max_size = len; ++ bp->fd = -1; ++} ++ ++void ++buf_init_empty(buf_t *bp, size_t len) ++{ ++ memset(bp, 0, sizeof(*bp)); ++ bp->max_size = len; ++ bp->fd = -1; ++} ++ ++void ++buf_set(buf_t *bp, void *mem, size_t len) ++{ ++ buf_init(bp, mem, len); ++ bp->tail = len; ++} ++ ++void ++buf_clear(buf_t *bp) ++{ ++ bp->head = bp->tail = 0; ++} ++ ++int ++buf_fill(buf_t *bp) ++{ ++ int n; ++ ++ if (bp->head || bp->tail) ++ buf_compact(bp); ++ ++ if (bp->write_mode || bp->fd < 0) ++ return 0; ++ ++ n = read(bp->fd, bp->base + bp->tail, buf_tailroom(bp)); ++ if (n < 0) { ++ warn("read error"); ++ return 0; ++ } ++ ++ bp->tail += n; ++ return n; ++} ++ ++int ++buf_drain(buf_t *bp) ++{ ++ int n; ++ ++ if (!bp->write_mode || bp->fd < 0) ++ return 0; ++ ++ n = write(bp->fd, bp->base + bp->head, buf_avail(bp)); ++ if (n < 0) { ++ warn("write error"); ++ return 0; ++ } ++ ++ bp->head += n; ++ return n; ++} ++ ++int ++__buf_resize(buf_t *bp, size_t new_size) ++{ ++ void *new_base; ++ ++ if (new_size > bp->max_size) ++ return 0; ++ isns_assert(bp->allocated || bp->base == NULL); ++ ++ new_size = (new_size + 127) & ~127; ++ if (new_size > bp->max_size) ++ new_size = bp->max_size; ++ ++ new_base = isns_realloc(bp->base, new_size); ++ if (new_base == NULL) ++ return 0; ++ ++ bp->base = new_base; ++ bp->size = new_size; ++ bp->allocated = 1; ++ return new_size; ++} ++ ++buf_t * ++buf_split(buf_t **to_split, size_t size) ++{ ++ buf_t *old = *to_split, *new; ++ size_t avail; ++ ++ avail = buf_avail(old); ++ if (size > avail) ++ return NULL; ++ ++ if (size == avail) { ++ *to_split = NULL; ++ return old; ++ } ++ ++ new = buf_alloc(size); ++ buf_put(new, buf_head(old), size); ++ buf_pull(old, size); ++ ++ return new; ++} ++ ++int ++buf_seek(buf_t *bp, off_t offset) ++{ ++ if (bp->write_mode && !buf_drain(bp)) ++ return 0; ++ if (lseek(bp->fd, offset, SEEK_SET) < 0) { ++ warn("cannot seek to offset %ld", (long) offset); ++ return 0; ++ } ++ return 1; ++} ++ ++int ++buf_get(buf_t *bp, void *mem, size_t len) ++{ ++ caddr_t dst = (caddr_t) mem; ++ unsigned int total = len, copy; ++ ++ while (len) { ++ if ((copy = buf_avail(bp)) > len) ++ copy = len; ++ if (copy == 0) { ++ if (!buf_fill(bp)) ++ return 0; ++ continue; ++ } ++ if (dst) { ++ memcpy(dst, bp->base + bp->head, copy); ++ dst += copy; ++ } ++ bp->head += copy; ++ len -= copy; ++ } ++ return total; ++} ++ ++int ++buf_get32(buf_t *bp, uint32_t *vp) ++{ ++ if (!buf_get(bp, vp, 4)) ++ return 0; ++ *vp = ntohl(*vp); ++ return 1; ++} ++ ++int ++buf_get64(buf_t *bp, uint64_t *vp) ++{ ++ if (!buf_get(bp, vp, 8)) ++ return 0; ++ *vp = ntohll(*vp); ++ return 1; ++} ++ ++int ++buf_gets(buf_t *bp, char *stringbuf, size_t size) ++{ ++ uint32_t len, copy; ++ ++ if (size == 0) ++ return 0; ++ ++ if (!buf_get32(bp, &len)) ++ return 0; ++ ++ if ((copy = len) >= size) ++ copy = size - 1; ++ ++ if (!buf_get(bp, stringbuf, copy)) ++ return 0; ++ stringbuf[copy] = '\0'; ++ ++ /* Pull remaining bytes */ ++ if (copy != len && !buf_pull(bp, len - copy)) ++ return 0; ++ ++ return copy + 1; ++} ++ ++int ++buf_put(buf_t *bp, const void *mem, size_t len) ++{ ++ caddr_t src = (caddr_t) mem; ++ unsigned int total = len, copy; ++ ++ while (len) { ++ if ((copy = bp->size - bp->tail) > len) ++ copy = len; ++ if (copy == 0) { ++ if (buf_drain(bp)) { ++ buf_compact(bp); ++ continue; ++ } ++ if (__buf_resize(bp, bp->tail + len)) { ++ buf_compact(bp); ++ continue; ++ } ++ return 0; ++ } ++ if (src) { ++ memcpy(bp->base + bp->tail, src, copy); ++ src += copy; ++ } ++ bp->tail += copy; ++ len -= copy; ++ } ++ return total; ++} ++ ++int ++buf_putc(buf_t *bp, int byte) ++{ ++ unsigned char c = byte; ++ ++ return buf_put(bp, &c, 1); ++} ++ ++int ++buf_put32(buf_t *bp, uint32_t val) ++{ ++ val = htonl(val); ++ if (!buf_put(bp, &val, 4)) ++ return 0; ++ return 1; ++} ++ ++int ++buf_put64(buf_t *bp, uint64_t val) ++{ ++ val = htonll(val); ++ return buf_put(bp, &val, 8); ++} ++ ++int ++buf_puts(buf_t *bp, const char *sp) ++{ ++ uint32_t len = 0; ++ ++ if (sp) ++ len = strlen(sp); ++ return buf_put32(bp, len) && buf_put(bp, sp, len); ++} ++ ++void ++buf_compact(buf_t *bp) ++{ ++ unsigned int count; ++ ++ if (bp->head == 0) ++ return; ++ ++ count = bp->tail - bp->head; ++ memmove(bp->base, bp->base + bp->head, count); ++ bp->tail -= bp->head; ++ bp->head = 0; ++} ++ ++void ++buf_list_append(buf_t **list, buf_t *bp) ++{ ++ bp->next = NULL; ++ while (*list) ++ list = &(*list)->next; ++ *list = bp; ++} ++ ++int ++buf_truncate(buf_t *bp, size_t len) ++{ ++ if (bp->head + len > bp->tail) ++ return 0; ++ ++ bp->tail = bp->head + len; ++ return 1; ++} +diff --git a/utils/open-isns/buffer.h b/utils/open-isns/buffer.h +new file mode 100644 +index 0000000..75ba910 +--- /dev/null ++++ b/utils/open-isns/buffer.h +@@ -0,0 +1,141 @@ ++/* ++ * Buffer handling functions ++ * ++ * Copyright (C) 2003-2006, Olaf Kirch ++ */ ++ ++#ifndef BUFFER_H ++#define BUFFER_H ++ ++#include ++#include ++#include ++ ++typedef struct isns_buf { ++ struct isns_buf * next; ++ unsigned char * base; ++ unsigned int head, tail, size, max_size; ++ unsigned int write_mode : 1, ++ allocated : 1; ++ int fd; ++ ++ /* Anonymous union for misc stuff */ ++ union { ++ struct { ++ struct sockaddr_storage addr; ++ socklen_t addrlen; ++ }; ++ }; ++} buf_t; ++ ++extern buf_t * buf_open(const char *, int); ++extern buf_t * buf_alloc(size_t); ++extern buf_t * buf_dup(const buf_t *); ++extern void buf_init(buf_t *, void *, size_t); ++extern void buf_init_empty(buf_t *, size_t); ++extern void buf_set(buf_t *, void *, size_t); ++ ++extern void buf_clear(buf_t *); ++extern void buf_close(buf_t *); ++extern void buf_destroy(buf_t *); ++extern void buf_free(buf_t *); ++extern void buf_list_free(buf_t *); ++ ++extern int buf_get(buf_t *, void *, size_t); ++extern int buf_get32(buf_t *, uint32_t *); ++extern int buf_get64(buf_t *, uint64_t *); ++extern int buf_gets(buf_t *, char *, size_t); ++extern int buf_put(buf_t *, const void *, size_t); ++extern int buf_put32(buf_t *, uint32_t); ++extern int buf_put64(buf_t *, uint64_t); ++extern int buf_puts(buf_t *, const char *); ++extern int buf_putc(buf_t *, int); ++extern int buf_read(buf_t *, int); ++extern int buf_seek(buf_t *bp, off_t offset); ++extern int buf_truncate(buf_t *, size_t); ++extern void buf_compact(buf_t *); ++extern buf_t * buf_split(buf_t **to_split, size_t len); ++extern int __buf_resize(buf_t *, size_t); ++ ++extern void buf_list_append(buf_t **, buf_t *); ++ ++static inline size_t ++buf_avail(const buf_t *bp) ++{ ++ return bp->tail - bp->head; ++} ++ ++static inline size_t ++buf_tailroom(const buf_t *bp) ++{ ++ return bp->max_size - bp->tail; ++} ++ ++static inline size_t ++buf_size(const buf_t *bp) ++{ ++ return bp->size; ++} ++ ++static inline void * ++buf_head(const buf_t *bp) ++{ ++ return bp->base + bp->head; ++} ++ ++static inline void * ++buf_tail(const buf_t *bp) ++{ ++ return bp->base + bp->tail; ++} ++ ++static inline int ++buf_reserve(buf_t *bp, size_t len) ++{ ++ if (bp->head != bp->tail) ++ return 0; ++ if (bp->max_size - bp->head < len) ++ return 0; ++ bp->head += len; ++ bp->tail += len; ++ return 1; ++} ++ ++static inline int ++buf_pull(buf_t *bp, size_t len) ++{ ++ if (len > buf_avail(bp)) ++ return 0; ++ bp->head += len; ++ return 1; ++} ++ ++static inline void * ++buf_push(buf_t *bp, size_t len) ++{ ++ if (bp->max_size - bp->tail < len) ++ return NULL; ++ ++ if (bp->tail + len > bp->size ++ && !__buf_resize(bp, bp->tail + len)) ++ return NULL; ++ ++ bp->tail += len; ++ return bp->base + bp->tail - len; ++} ++ ++static inline void * ++buf_push_head(buf_t *bp, size_t len) ++{ ++ if (bp->head < len) ++ return NULL; ++ ++ if (bp->tail > bp->size ++ && !__buf_resize(bp, bp->tail)) ++ return NULL; ++ ++ bp->head -= len; ++ return bp->base + bp->head; ++} ++ ++#endif /* BUFFER_H */ +diff --git a/utils/open-isns/callback.c b/utils/open-isns/callback.c +new file mode 100644 +index 0000000..ecdabd7 +--- /dev/null ++++ b/utils/open-isns/callback.c +@@ -0,0 +1,148 @@ ++/* ++ * iSNS object callbacks for SCN and other stuff ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include "isns.h" ++#include "objects.h" ++#include "vendor.h" ++#include "attrs.h" ++#include "util.h" ++ ++typedef struct isns_object_notifier isns_object_notifier_t; ++struct isns_object_notifier { ++ isns_list_t list; ++ isns_db_callback_t * func; ++ void * data; ++}; ++ ++typedef struct isns_cb_event isns_cb_event_t; ++struct isns_cb_event { ++ isns_list_t list; ++ isns_db_event_t info; ++}; ++ ++static ISNS_LIST_DECLARE(notifiers); ++static ISNS_LIST_DECLARE(events); ++ ++static inline void ++__isns_db_event(isns_object_t *dst, ++ isns_object_t *obj, ++ unsigned int bits, ++ isns_object_t *trigger) ++{ ++ isns_cb_event_t *ev; ++ ++ ev = isns_calloc(1, sizeof(*ev)); ++ ev->info.ie_recipient = isns_object_get(dst); ++ ev->info.ie_object = isns_object_get(obj); ++ ev->info.ie_bits = bits; ++ ev->info.ie_trigger = isns_object_get(trigger); ++ isns_list_append(&events, &ev->list); ++} ++ ++void ++isns_object_event(isns_object_t *obj, ++ unsigned int bits, ++ isns_object_t *trigger) ++{ ++ __isns_db_event(NULL, obj, bits, trigger); ++} ++ ++void ++isns_unicast_event(isns_object_t *dst, ++ isns_object_t *obj, ++ unsigned int bits, ++ isns_object_t *trigger) ++{ ++ __isns_db_event(dst, obj, bits, trigger); ++} ++ ++/* ++ * Given an object pair and an event bitmask, ++ * invoke all callbacks ++ */ ++static inline void ++isns_call_callbacks(isns_db_event_t *ev) ++{ ++ isns_object_t *obj = ev->ie_object; ++ isns_list_t *pos, *next; ++ ++ ev->ie_bits |= obj->ie_scn_bits; ++ if (ev->ie_bits == 0) ++ return; ++ isns_list_foreach(¬ifiers, pos, next) { ++ isns_object_notifier_t *not; ++ ++ not = isns_list_item(isns_object_notifier_t, list, pos); ++ not->func(ev, not->data); ++ } ++ obj->ie_scn_bits = 0; ++} ++ ++void ++isns_flush_events(void) ++{ ++ while (!isns_list_empty(&events)) { ++ isns_cb_event_t *ev = isns_list_item(isns_cb_event_t, list, events.next); ++ ++ isns_call_callbacks(&ev->info); ++ isns_object_release(ev->info.ie_recipient); ++ isns_object_release(ev->info.ie_object); ++ isns_object_release(ev->info.ie_trigger); ++ isns_list_del(&ev->list); ++ isns_free(ev); ++ } ++} ++ ++void ++isns_register_callback(isns_db_callback_t *func, ++ void *user_data) ++{ ++ isns_object_notifier_t *not; ++ ++ not = isns_calloc(1, sizeof(*not)); ++ not->func = func; ++ not->data = user_data; ++ ++ isns_list_append(¬ifiers, ¬->list); ++} ++ ++const char * ++isns_event_string(unsigned int bits) ++{ ++ static const char *names[16] = { ++ [ISNS_SCN_DD_MEMBER_ADDED] = "member added", ++ [ISNS_SCN_DD_MEMBER_REMOVED] = "member removed", ++ [ISNS_SCN_OBJECT_UPDATED] = "updated", ++ [ISNS_SCN_OBJECT_ADDED] = "added", ++ [ISNS_SCN_OBJECT_REMOVED] = "removed", ++ [ISNS_SCN_MANAGEMENT_REGISTRATION]= "mgmt registration", ++ [ISNS_SCN_TARGET_AND_SELF_ONLY] = "target+self", ++ [ISNS_SCN_INITIATOR_AND_SELF_ONLY]= "initiator+self", ++ }; ++ static char buffer[128]; ++ unsigned int pos = 0, i; ++ ++ ++ for (i = 0; i < 16; ++i, bits >>= 1) { ++ if (!(bits & 1)) ++ continue; ++ ++ if (names[i]) { ++ snprintf(buffer + pos, sizeof(buffer) - pos, ++ "%s%s", pos? ", " : "", names[i]); ++ } else { ++ snprintf(buffer + pos, sizeof(buffer) - pos, ++ "%sevent %u", pos? ", " : "", i); ++ } ++ pos = strlen(buffer); ++ } ++ if (pos == 0) ++ return ""; ++ ++ return buffer; ++} +diff --git a/utils/open-isns/client.c b/utils/open-isns/client.c +new file mode 100644 +index 0000000..c470048 +--- /dev/null ++++ b/utils/open-isns/client.c +@@ -0,0 +1,205 @@ ++/* ++ * Client functions ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include "security.h" ++#include "util.h" ++#include "internal.h" ++#include "config.h" ++ ++static isns_client_t * ++__isns_create_default_client(isns_socket_t *sock, isns_security_t *ctx, ++ const char *source_name) ++{ ++ isns_client_t *clnt; ++ ++ clnt = isns_calloc(1, sizeof(*clnt)); ++ ++ if (!source_name) ++ source_name = isns_config.ic_source_name; ++ ++ clnt->ic_source = isns_source_create_iscsi(source_name); ++ clnt->ic_socket = sock; ++ ++ isns_socket_set_security_ctx(clnt->ic_socket, ctx); ++ ++ return clnt; ++} ++ ++isns_client_t * ++isns_create_client(isns_security_t *ctx, const char *source_name) ++{ ++ isns_socket_t *sock; ++ const char *server_name; ++ ++ server_name = isns_config.ic_server_name; ++ if (!strcasecmp(server_name, "SLP:") ++ && !(server_name = isns_slp_find())) { ++ isns_error("Unable to locate iSNS server through SLP\n"); ++ return NULL; ++ } ++ ++ sock = isns_create_bound_client_socket( ++ isns_config.ic_bind_address, ++ server_name, ++ "isns", 0, SOCK_STREAM); ++ if (sock == NULL) { ++ isns_error("Unable to create socket for host \"%s\"\n", ++ isns_config.ic_server_name); ++ return NULL; ++ } ++ ++ return __isns_create_default_client(sock, ++ ctx? : isns_default_security_context(0), ++ source_name); ++} ++ ++isns_client_t * ++isns_create_default_client(isns_security_t *ctx) ++{ ++ return isns_create_client(ctx, isns_config.ic_source_name); ++} ++ ++isns_client_t * ++isns_create_local_client(isns_security_t *ctx, const char *source_name) ++{ ++ isns_socket_t *sock; ++ ++ if (isns_config.ic_control_socket == NULL) ++ isns_fatal("Cannot use local mode: no local control socket\n"); ++ ++ sock = isns_create_client_socket(isns_config.ic_control_socket, ++ NULL, 0, SOCK_STREAM); ++ if (sock == NULL) { ++ isns_error("Unable to create control socket (%s)\n", ++ isns_config.ic_control_socket); ++ return NULL; ++ } ++ ++ return __isns_create_default_client(sock, ctx, source_name); ++} ++ ++int ++isns_client_call(isns_client_t *clnt, ++ isns_simple_t **inout) ++{ ++ return isns_simple_call(clnt->ic_socket, inout); ++} ++ ++void ++isns_client_destroy(isns_client_t *clnt) ++{ ++ if (clnt->ic_socket) ++ isns_socket_free(clnt->ic_socket); ++ if (clnt->ic_source) ++ isns_source_release(clnt->ic_source); ++ isns_free(clnt); ++} ++ ++/* ++ * Get the local address ++ */ ++int ++isns_client_get_local_address(const isns_client_t *clnt, ++ isns_portal_info_t *portal_info) ++{ ++ return isns_socket_get_portal_info(clnt->ic_socket, portal_info); ++} ++ ++/* ++ * Create a security context ++ */ ++static isns_security_t * ++__create_security_context(const char *name, const char *auth_key, ++ const char *server_key) ++{ ++#ifdef WITH_SECURITY ++ isns_security_t *ctx; ++ isns_principal_t *princ; ++#endif /* WITH_SECURITY */ ++ ++ if (!isns_config.ic_security) ++ return NULL; ++ ++#ifndef WITH_SECURITY ++ isns_error("Cannot create security context: security disabled at build time\n"); ++ return NULL; ++#else /* WITH_SECURITY */ ++ ctx = isns_create_dsa_context(); ++ if (ctx == NULL) ++ isns_fatal("Unable to create security context\n"); ++ ++ /* Load my own key */ ++ princ = isns_security_load_privkey(ctx, auth_key); ++ if (!princ) ++ isns_fatal("Unable to load private key from %s\n", ++ auth_key); ++ ++ isns_principal_set_name(princ, name); ++ isns_security_set_identity(ctx, princ); ++ ++ if (server_key) { ++ /* We're a client, and we want to load the ++ * server's public key in order to authenticate ++ * the server's responses. ++ */ ++ princ = isns_security_load_pubkey(ctx, server_key); ++ if (!princ) ++ isns_fatal("Unable to load public key from %s\n", ++ server_key); ++ ++ /* Do *not* set a name for this principal - ++ * this will be the default principal used when ++ * verifying the server's reply, which is a good thing ++ * because we don't know what SPI the server will ++ * be using. */ ++ isns_add_principal(ctx, princ); ++ ++ /* But set a policy for the server which allows it ++ to send ESI and SCN messages */ ++ isns_principal_set_policy(princ, isns_policy_server()); ++ } ++ ++ return ctx; ++#endif /* WITH_SECURITY */ ++} ++ ++/* ++ * Create the default security context ++ */ ++isns_security_t * ++isns_default_security_context(int server_only) ++{ ++ static isns_security_t *ctx; ++ ++ if (ctx == NULL) ++ ctx = __create_security_context(isns_config.ic_auth_name, ++ isns_config.ic_auth_key_file, ++ server_only? NULL : isns_config.ic_server_key_file); ++ return ctx; ++} ++ ++/* ++ * Create the control security context ++ */ ++isns_security_t * ++isns_control_security_context(int server_only) ++{ ++ static isns_security_t *ctx; ++ ++ if (ctx == NULL) ++ ctx = __create_security_context(isns_config.ic_control_name, ++ isns_config.ic_control_key_file, ++ server_only? NULL : isns_config.ic_server_key_file); ++ return ctx; ++} +diff --git a/utils/open-isns/compat/my_getopt.c b/utils/open-isns/compat/my_getopt.c +new file mode 100644 +index 0000000..512b0ae +--- /dev/null ++++ b/utils/open-isns/compat/my_getopt.c +@@ -0,0 +1,271 @@ ++/* ++ * my_getopt.c - my re-implementation of getopt. ++ * Copyright 1997, 2000, 2001, 2002, Benjamin Sittler ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, ++ * modify, merge, publish, distribute, sublicense, and/or sell copies ++ * of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ++ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "my_getopt.h" ++ ++int my_optind=1, my_opterr=1, my_optopt=0; ++char *my_optarg=0; ++ ++/* this is the plain old UNIX getopt, with GNU-style extensions. */ ++/* if you're porting some piece of UNIX software, this is all you need. */ ++/* this supports GNU-style permution and optional arguments */ ++ ++int my_getopt(int argc, char * argv[], const char *opts) ++{ ++ static int charind=0; ++ const char *s; ++ char mode, colon_mode; ++ int off = 0, opt = -1; ++ ++ if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+'; ++ else { ++ if((colon_mode = *opts) == ':') off ++; ++ if(((mode = opts[off]) == '+') || (mode == '-')) { ++ off++; ++ if((colon_mode != ':') && ((colon_mode = opts[off]) == ':')) ++ off ++; ++ } ++ } ++ my_optarg = 0; ++ if(charind) { ++ my_optopt = argv[my_optind][charind]; ++ for(s=opts+off; *s; s++) if(my_optopt == *s) { ++ charind++; ++ if((*(++s) == ':') || ((my_optopt == 'W') && (*s == ';'))) { ++ if(argv[my_optind][charind]) { ++ my_optarg = &(argv[my_optind++][charind]); ++ charind = 0; ++ } else if(*(++s) != ':') { ++ charind = 0; ++ if(++my_optind >= argc) { ++ if(my_opterr) fprintf(stderr, ++ "%s: option requires an argument -- %c\n", ++ argv[0], my_optopt); ++ opt = (colon_mode == ':') ? ':' : '?'; ++ goto my_getopt_ok; ++ } ++ my_optarg = argv[my_optind++]; ++ } ++ } ++ opt = my_optopt; ++ goto my_getopt_ok; ++ } ++ if(my_opterr) fprintf(stderr, ++ "%s: illegal option -- %c\n", ++ argv[0], my_optopt); ++ opt = '?'; ++ if(argv[my_optind][++charind] == '\0') { ++ my_optind++; ++ charind = 0; ++ } ++ my_getopt_ok: ++ if(charind && ! argv[my_optind][charind]) { ++ my_optind++; ++ charind = 0; ++ } ++ } else if((my_optind >= argc) || ++ ((argv[my_optind][0] == '-') && ++ (argv[my_optind][1] == '-') && ++ (argv[my_optind][2] == '\0'))) { ++ my_optind++; ++ opt = -1; ++ } else if((argv[my_optind][0] != '-') || ++ (argv[my_optind][1] == '\0')) { ++ char *tmp; ++ int i, j, k; ++ ++ if(mode == '+') opt = -1; ++ else if(mode == '-') { ++ my_optarg = argv[my_optind++]; ++ charind = 0; ++ opt = 1; ++ } else { ++ for(i=j=my_optind; i j) { ++ tmp=argv[--i]; ++ for(k=i; k+1 argc) my_optind = argc; ++ return opt; ++} ++ ++/* this is the extended getopt_long{,_only}, with some GNU-like ++ * extensions. Implements _getopt_internal in case any programs ++ * expecting GNU libc getopt call it. ++ */ ++ ++int _my_getopt_internal(int argc, char * argv[], const char *shortopts, ++ const struct option *longopts, int *longind, ++ int long_only) ++{ ++ char mode, colon_mode = *shortopts; ++ int shortoff = 0, opt = -1; ++ ++ if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+'; ++ else { ++ if((colon_mode = *shortopts) == ':') shortoff ++; ++ if(((mode = shortopts[shortoff]) == '+') || (mode == '-')) { ++ shortoff++; ++ if((colon_mode != ':') && ((colon_mode = shortopts[shortoff]) == ':')) ++ shortoff ++; ++ } ++ } ++ my_optarg = 0; ++ if((my_optind >= argc) || ++ ((argv[my_optind][0] == '-') && ++ (argv[my_optind][1] == '-') && ++ (argv[my_optind][2] == '\0'))) { ++ my_optind++; ++ opt = -1; ++ } else if((argv[my_optind][0] != '-') || ++ (argv[my_optind][1] == '\0')) { ++ char *tmp; ++ int i, j, k; ++ ++ opt = -1; ++ if(mode == '+') return -1; ++ else if(mode == '-') { ++ my_optarg = argv[my_optind++]; ++ return 1; ++ } ++ for(i=j=my_optind; i j) { ++ tmp=argv[--i]; ++ for(k=i; k+1= argc) { ++ opt = (colon_mode == ':') ? ':' : '?'; ++ if(my_opterr) fprintf(stderr, ++ "%s: option `--%s' requires an argument\n", ++ argv[0], longopts[found].name); ++ } else my_optarg = argv[my_optind]; ++ } ++ if(!opt) { ++ if (longind) *longind = found; ++ if(!longopts[found].flag) opt = longopts[found].val; ++ else *(longopts[found].flag) = longopts[found].val; ++ } ++ my_optind++; ++ } else if(!hits) { ++ if(offset == 1) opt = my_getopt(argc, argv, shortopts); ++ else { ++ opt = '?'; ++ if(my_opterr) fprintf(stderr, ++ "%s: unrecognized option `%s'\n", ++ argv[0], argv[my_optind++]); ++ } ++ } else { ++ opt = '?'; ++ if(my_opterr) fprintf(stderr, ++ "%s: option `%s' is ambiguous\n", ++ argv[0], argv[my_optind++]); ++ } ++ } ++ if (my_optind > argc) my_optind = argc; ++ return opt; ++} ++ ++int my_getopt_long(int argc, char * argv[], const char *shortopts, ++ const struct option *longopts, int *longind) ++{ ++ return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 0); ++} ++ ++int my_getopt_long_only(int argc, char * argv[], const char *shortopts, ++ const struct option *longopts, int *longind) ++{ ++ return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 1); ++} +diff --git a/utils/open-isns/compat/my_getopt.h b/utils/open-isns/compat/my_getopt.h +new file mode 100644 +index 0000000..34fcfe7 +--- /dev/null ++++ b/utils/open-isns/compat/my_getopt.h +@@ -0,0 +1,69 @@ ++/* ++ * my_getopt.h - interface to my re-implementation of getopt. ++ * Copyright 1997, 2000, 2001, 2002, Benjamin Sittler ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, ++ * modify, merge, publish, distribute, sublicense, and/or sell copies ++ * of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ++ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef MY_GETOPT_H_INCLUDED ++#define MY_GETOPT_H_INCLUDED ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* UNIX-style short-argument parser */ ++extern int my_getopt(int argc, char * argv[], const char *opts); ++ ++extern int my_optind, my_opterr, my_optopt; ++extern char *my_optarg; ++ ++struct option { ++ const char *name; ++ int has_arg; ++ int *flag; ++ int val; ++}; ++ ++/* human-readable values for has_arg */ ++#undef no_argument ++#define no_argument 0 ++#undef required_argument ++#define required_argument 1 ++#undef optional_argument ++#define optional_argument 2 ++ ++/* GNU-style long-argument parsers */ ++extern int my_getopt_long(int argc, char * argv[], const char *shortopts, ++ const struct option *longopts, int *longind); ++ ++extern int my_getopt_long_only(int argc, char * argv[], const char *shortopts, ++ const struct option *longopts, int *longind); ++ ++extern int _my_getopt_internal(int argc, char * argv[], const char *shortopts, ++ const struct option *longopts, int *longind, ++ int long_only); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* MY_GETOPT_H_INCLUDED */ +diff --git a/utils/open-isns/config.c b/utils/open-isns/config.c +new file mode 100644 +index 0000000..cc470a4 +--- /dev/null ++++ b/utils/open-isns/config.c +@@ -0,0 +1,278 @@ ++/* ++ * Config file reader ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++#include ++#include ++#include ++#include ++ ++#include "isns.h" ++#include "util.h" ++#include "paths.h" ++ ++/* ++ * iSNS configuration ++ */ ++struct isns_config isns_config = { ++ /* Security parameters */ ++ .ic_security = -1, ++ .ic_auth_key_file = ISNS_ETCDIR "/auth_key", ++ .ic_server_key_file = ISNS_ETCDIR "/server_key.pub", ++ .ic_client_keystore = "DB:", ++ .ic_control_socket = ISNS_RUNDIR "/isnsctl", ++ .ic_pidfile = ISNS_RUNDIR "/isnsd.pid", ++ .ic_local_registry_file = ISNS_DEFAULT_LOCAL_REGISTRY, ++ ++ .ic_control_name = "isns.control", ++ .ic_control_key_file = ISNS_ETCDIR "/control.key", ++ ++ .ic_registration_period = 3600, /* 1 hour */ ++ .ic_scn_timeout = 60, ++ .ic_scn_retries = 3, ++ ++ .ic_esi_max_interval = 600, /* 10 minutes */ ++ .ic_esi_min_interval = 60, /* 1 minute */ ++ .ic_esi_retries = 3, ++ ++ .ic_auth = { ++ .replay_window = 300, /* 5 min clock skew */ ++ .timestamp_jitter = 1, /* 1 sec timestamp jitter */ ++ .allow_unknown_peers = 1, ++ }, ++ .ic_network = { ++ .max_sockets = 1024, ++ .connect_timeout = 5, ++ .reconnect_timeout = 10, ++ .call_timeout = 60, ++ .udp_retrans_timeout = 10, ++ .tcp_retrans_timeout = 60, ++ .idle_timeout = 300, ++ }, ++ .ic_dsa = { ++ .param_file = ISNS_ETCDIR "/dsa.params", ++ }, ++}; ++ ++/* ++ * Default string values need to be dup'ed, ++ * so that later assignment does't try to free ++ * these strings. ++ */ ++static inline void ++__isns_config_defaults(void) ++{ ++ static int defaults_init = 1; ++ ++ if (!defaults_init) ++ return; ++ ++#define DUP(member) \ ++ if (isns_config.member) \ ++ isns_config.member = isns_strdup(isns_config.member) ++ ++ DUP(ic_source_name); ++ DUP(ic_database); ++ DUP(ic_server_name); ++ DUP(ic_bind_address); ++ DUP(ic_auth_key_file); ++ DUP(ic_server_key_file); ++ DUP(ic_client_keystore); ++ DUP(ic_control_socket); ++ DUP(ic_pidfile); ++ DUP(ic_control_name); ++ DUP(ic_control_key_file); ++ DUP(ic_local_registry_file); ++ DUP(ic_dsa.param_file); ++ ++#undef DUP ++ ++ defaults_init = 0; ++} ++ ++/* ++ * Read the iSNS configuration file ++ */ ++int ++isns_read_config(const char *filename) ++{ ++ FILE *fp; ++ char *name, *pos; ++ ++ __isns_config_defaults(); ++ ++ if ((fp = fopen(filename, "r")) == NULL) { ++ perror(filename); ++ return -1; ++ } ++ ++ while ((pos = parser_get_next_line(fp)) != NULL) { ++ pos[strcspn(pos, "#")] = '\0'; ++ ++ if (!(name = parser_get_next_word(&pos))) ++ continue; ++ ++ isns_config_set(name, pos); ++ } ++ ++ fclose(fp); ++ ++ /* Massage the config file */ ++ if (isns_config.ic_security < 0) { ++ /* By default, we will enable authentication ++ * whenever we find our private key, and ++ * the server's public key. */ ++ if (access(isns_config.ic_auth_key_file, R_OK) == 0 ++ && access(isns_config.ic_server_key_file, R_OK) == 0) ++ isns_config.ic_security = 1; ++ else ++ isns_config.ic_security = 0; ++ } ++ ++ isns_init_names(); ++ ++ return 0; ++} ++ ++int ++isns_config_set(const char *name, char *pos) ++{ ++ char *value; ++ ++ value = parser_get_rest_of_line(&pos); ++ if (value) ++ while (isspace(*value) || *value == '=') ++ ++value; ++ if (!strcasecmp(name, "HostName")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_host_name, value); ++ } else if (!strcasecmp(name, "SourceName")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_source_name, value); ++ } else if (!strcasecmp(name, "AuthName")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_auth_name, value); ++ } else if (!strcasecmp(name, "Database")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_database, value); ++ } else if (!strcasecmp(name, "ServerAddress")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_server_name, value); ++ } else if (!strcasecmp(name, "BindAddress")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_bind_address, value); ++ } else if (!strcasecmp(name, "ControlSocket")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_control_socket, value); ++ } else if (!strcasecmp(name, "PIDFile")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_pidfile, value); ++ } else if (!strcasecmp(name, "LocalRegistry")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_local_registry_file, value); ++ } else if (!strcasecmp(name, "RegistrationPeriod")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_registration_period = parse_timeout(value); ++ } else if (!strcasecmp(name, "SCNTimeout")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_scn_timeout = parse_timeout(value); ++ } else if (!strcasecmp(name, "SCNRetries")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_scn_retries = parse_int(value); ++ } else if (!strcasecmp(name, "SCNCallout")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_scn_callout, value); ++ } else if (!strcasecmp(name, "ESIMinInterval")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_esi_min_interval = parse_timeout(value); ++ } else if (!strcasecmp(name, "ESIMaxInterval")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_esi_max_interval = parse_timeout(value); ++ } else if (!strcasecmp(name, "ESIRetries")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_esi_retries = parse_int(value); ++ } else if (!strcasecmp(name, "DefaultDiscoveryDomain")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_use_default_domain = parse_int(value); ++ } else if (!strcasecmp(name, "SLPRegister")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_slp_register = parse_int(value); ++ } else if (!strcasecmp(name, "Security")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_security = parse_int(value); ++ } else if (!strcasecmp(name, "AuthKeyFile")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_auth_key_file, value); ++ } else if (!strcasecmp(name, "ServerKeyFile")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_server_key_file, value); ++ } else if (!strcasecmp(name, "ClientKeyStore") ++ || !strcasecmp(name, "KeyStore")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_client_keystore, value); ++ } else if (!strcasecmp(name, "Control.SourceName")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_control_name, value); ++ } else if (!strcasecmp(name, "Control.AuthKeyFile")) { ++ if (!value) ++ goto no_value; ++ isns_assign_string(&isns_config.ic_control_key_file, value); ++ } else if (!strcasecmp(name, "Auth.ReplayWindow")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_auth.replay_window = parse_timeout(value); ++ } else if (!strcasecmp(name, "Auth.TimestampJitter")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_auth.timestamp_jitter = parse_timeout(value); ++ } else if (!strcasecmp(name, "Network.MaxSockets")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_network.max_sockets = parse_timeout(value); ++ } else if (!strcasecmp(name, "Network.ConnectTimeout")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_network.connect_timeout = parse_timeout(value); ++ } else if (!strcasecmp(name, "Network.ReconnectTimeout")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_network.reconnect_timeout = parse_timeout(value); ++ } else if (!strcasecmp(name, "Network.CallTimeout")) { ++ if (!value) ++ goto no_value; ++ isns_config.ic_network.call_timeout = parse_timeout(value); ++ } else { ++ fprintf(stderr, "Unknown config item %s=%s\n", name, value); ++ } ++ return 0; ++ ++no_value: ++ fprintf(stderr, ++ "*** Missing value in configuration assignment for %s ***\n", ++ name); ++ return -1; ++} +diff --git a/utils/open-isns/config.h.in b/utils/open-isns/config.h.in +new file mode 100644 +index 0000000..b560bb0 +--- /dev/null ++++ b/utils/open-isns/config.h.in +@@ -0,0 +1,103 @@ ++/* config.h.in. Generated from configure.ac by autoheader. */ ++ ++/* Define if building universal (internal helper macro) */ ++#undef AC_APPLE_UNIVERSAL_BUILD ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_ERRNO_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_FCNTL_H ++ ++/* Define if you have the header file. */ ++#undef HAVE_GETOPT_H ++ ++/* Define if you have the `getopt_long' function. */ ++#undef HAVE_GETOPT_LONG ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_INTTYPES_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_LOCALE_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_MALLOC_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_MEMORY_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_OPENSSL_CRYPTO_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SLP_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_STDINT_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_STDLIB_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_STRINGS_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_STRING_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_STAT_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_TIME_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_TYPES_H ++ ++/* Define to 1 if you have that is POSIX.1 compatible. */ ++#undef HAVE_SYS_WAIT_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_UNISTD_H ++ ++/* Define to the address where bug reports for this package should be sent. */ ++#undef PACKAGE_BUGREPORT ++ ++/* Define to the full name of this package. */ ++#undef PACKAGE_NAME ++ ++/* Define to the full name and version of this package. */ ++#undef PACKAGE_STRING ++ ++/* Define to the one symbol short name of this package. */ ++#undef PACKAGE_TARNAME ++ ++/* Define to the version of this package. */ ++#undef PACKAGE_VERSION ++ ++/* Define to 1 if you have the ANSI C header files. */ ++#undef STDC_HEADERS ++ ++/* Define if you want to support iSNS authentication */ ++#undef WITH_SECURITY ++ ++/* Define if you want to support SLP discovery */ ++#undef WITH_SLP ++ ++/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most ++ significant byte first (like Motorola and SPARC, unlike Intel). */ ++#if defined AC_APPLE_UNIVERSAL_BUILD ++# if defined __BIG_ENDIAN__ ++# define WORDS_BIGENDIAN 1 ++# endif ++#else ++# ifndef WORDS_BIGENDIAN ++# undef WORDS_BIGENDIAN ++# endif ++#endif ++ ++/* Define to `__inline__' or `__inline' if that's what the C compiler ++ calls it, or to nothing if 'inline' is not supported under any name. */ ++#ifndef __cplusplus ++#undef inline ++#endif +diff --git a/utils/open-isns/configure b/utils/open-isns/configure +new file mode 100755 +index 0000000..2d1054b +--- /dev/null ++++ b/utils/open-isns/configure +@@ -0,0 +1,6727 @@ ++#! /bin/sh ++# Guess values for system-dependent variables and create Makefiles. ++# Generated by GNU Autoconf 2.63 for open-isns 0.90. ++# ++# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, ++# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. ++# This configure script is free software; the Free Software Foundation ++# gives unlimited permission to copy, distribute and modify it. ++## --------------------- ## ++## M4sh Initialization. ## ++## --------------------- ## ++ ++# Be more Bourne compatible ++DUALCASE=1; export DUALCASE # for MKS sh ++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then ++ emulate sh ++ NULLCMD=: ++ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which ++ # is contrary to our usage. Disable this feature. ++ alias -g '${1+"$@"}'='"$@"' ++ setopt NO_GLOB_SUBST ++else ++ case `(set -o) 2>/dev/null` in ++ *posix*) set -o posix ;; ++esac ++ ++fi ++ ++ ++ ++ ++# PATH needs CR ++# Avoid depending upon Character Ranges. ++as_cr_letters='abcdefghijklmnopqrstuvwxyz' ++as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' ++as_cr_Letters=$as_cr_letters$as_cr_LETTERS ++as_cr_digits='0123456789' ++as_cr_alnum=$as_cr_Letters$as_cr_digits ++ ++as_nl=' ++' ++export as_nl ++# Printing a long string crashes Solaris 7 /usr/bin/printf. ++as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo ++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo ++if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then ++ as_echo='printf %s\n' ++ as_echo_n='printf %s' ++else ++ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then ++ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' ++ as_echo_n='/usr/ucb/echo -n' ++ else ++ as_echo_body='eval expr "X$1" : "X\\(.*\\)"' ++ as_echo_n_body='eval ++ arg=$1; ++ case $arg in ++ *"$as_nl"*) ++ expr "X$arg" : "X\\(.*\\)$as_nl"; ++ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; ++ esac; ++ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ++ ' ++ export as_echo_n_body ++ as_echo_n='sh -c $as_echo_n_body as_echo' ++ fi ++ export as_echo_body ++ as_echo='sh -c $as_echo_body as_echo' ++fi ++ ++# The user is always right. ++if test "${PATH_SEPARATOR+set}" != set; then ++ PATH_SEPARATOR=: ++ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { ++ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || ++ PATH_SEPARATOR=';' ++ } ++fi ++ ++# Support unset when possible. ++if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then ++ as_unset=unset ++else ++ as_unset=false ++fi ++ ++ ++# IFS ++# We need space, tab and new line, in precisely that order. Quoting is ++# there to prevent editors from complaining about space-tab. ++# (If _AS_PATH_WALK were called with IFS unset, it would disable word ++# splitting by setting IFS to empty value.) ++IFS=" "" $as_nl" ++ ++# Find who we are. Look in the path if we contain no directory separator. ++case $0 in ++ *[\\/]* ) as_myself=$0 ;; ++ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break ++done ++IFS=$as_save_IFS ++ ++ ;; ++esac ++# We did not find ourselves, most probably we were run as `sh COMMAND' ++# in which case we are not to be found in the path. ++if test "x$as_myself" = x; then ++ as_myself=$0 ++fi ++if test ! -f "$as_myself"; then ++ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 ++ { (exit 1); exit 1; } ++fi ++ ++# Work around bugs in pre-3.0 UWIN ksh. ++for as_var in ENV MAIL MAILPATH ++do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var ++done ++PS1='$ ' ++PS2='> ' ++PS4='+ ' ++ ++# NLS nuisances. ++LC_ALL=C ++export LC_ALL ++LANGUAGE=C ++export LANGUAGE ++ ++# Required to use basename. ++if expr a : '\(a\)' >/dev/null 2>&1 && ++ test "X`expr 00001 : '.*\(...\)'`" = X001; then ++ as_expr=expr ++else ++ as_expr=false ++fi ++ ++if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then ++ as_basename=basename ++else ++ as_basename=false ++fi ++ ++ ++# Name of the executable. ++as_me=`$as_basename -- "$0" || ++$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ ++ X"$0" : 'X\(//\)$' \| \ ++ X"$0" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X/"$0" | ++ sed '/^.*\/\([^/][^/]*\)\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\/\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\/\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ ++# CDPATH. ++$as_unset CDPATH ++ ++ ++if test "x$CONFIG_SHELL" = x; then ++ if (eval ":") 2>/dev/null; then ++ as_have_required=yes ++else ++ as_have_required=no ++fi ++ ++ if test $as_have_required = yes && (eval ": ++(as_func_return () { ++ (exit \$1) ++} ++as_func_success () { ++ as_func_return 0 ++} ++as_func_failure () { ++ as_func_return 1 ++} ++as_func_ret_success () { ++ return 0 ++} ++as_func_ret_failure () { ++ return 1 ++} ++ ++exitcode=0 ++if as_func_success; then ++ : ++else ++ exitcode=1 ++ echo as_func_success failed. ++fi ++ ++if as_func_failure; then ++ exitcode=1 ++ echo as_func_failure succeeded. ++fi ++ ++if as_func_ret_success; then ++ : ++else ++ exitcode=1 ++ echo as_func_ret_success failed. ++fi ++ ++if as_func_ret_failure; then ++ exitcode=1 ++ echo as_func_ret_failure succeeded. ++fi ++ ++if ( set x; as_func_ret_success y && test x = \"\$1\" ); then ++ : ++else ++ exitcode=1 ++ echo positional parameters were not saved. ++fi ++ ++test \$exitcode = 0) || { (exit 1); exit 1; } ++ ++( ++ as_lineno_1=\$LINENO ++ as_lineno_2=\$LINENO ++ test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && ++ test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } ++") 2> /dev/null; then ++ : ++else ++ as_candidate_shells= ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ case $as_dir in ++ /*) ++ for as_base in sh bash ksh sh5; do ++ as_candidate_shells="$as_candidate_shells $as_dir/$as_base" ++ done;; ++ esac ++done ++IFS=$as_save_IFS ++ ++ ++ for as_shell in $as_candidate_shells $SHELL; do ++ # Try only shells that exist, to save several forks. ++ if { test -f "$as_shell" || test -f "$as_shell.exe"; } && ++ { ("$as_shell") 2> /dev/null <<\_ASEOF ++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then ++ emulate sh ++ NULLCMD=: ++ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which ++ # is contrary to our usage. Disable this feature. ++ alias -g '${1+"$@"}'='"$@"' ++ setopt NO_GLOB_SUBST ++else ++ case `(set -o) 2>/dev/null` in ++ *posix*) set -o posix ;; ++esac ++ ++fi ++ ++ ++: ++_ASEOF ++}; then ++ CONFIG_SHELL=$as_shell ++ as_have_required=yes ++ if { "$as_shell" 2> /dev/null <<\_ASEOF ++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then ++ emulate sh ++ NULLCMD=: ++ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which ++ # is contrary to our usage. Disable this feature. ++ alias -g '${1+"$@"}'='"$@"' ++ setopt NO_GLOB_SUBST ++else ++ case `(set -o) 2>/dev/null` in ++ *posix*) set -o posix ;; ++esac ++ ++fi ++ ++ ++: ++(as_func_return () { ++ (exit $1) ++} ++as_func_success () { ++ as_func_return 0 ++} ++as_func_failure () { ++ as_func_return 1 ++} ++as_func_ret_success () { ++ return 0 ++} ++as_func_ret_failure () { ++ return 1 ++} ++ ++exitcode=0 ++if as_func_success; then ++ : ++else ++ exitcode=1 ++ echo as_func_success failed. ++fi ++ ++if as_func_failure; then ++ exitcode=1 ++ echo as_func_failure succeeded. ++fi ++ ++if as_func_ret_success; then ++ : ++else ++ exitcode=1 ++ echo as_func_ret_success failed. ++fi ++ ++if as_func_ret_failure; then ++ exitcode=1 ++ echo as_func_ret_failure succeeded. ++fi ++ ++if ( set x; as_func_ret_success y && test x = "$1" ); then ++ : ++else ++ exitcode=1 ++ echo positional parameters were not saved. ++fi ++ ++test $exitcode = 0) || { (exit 1); exit 1; } ++ ++( ++ as_lineno_1=$LINENO ++ as_lineno_2=$LINENO ++ test "x$as_lineno_1" != "x$as_lineno_2" && ++ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } ++ ++_ASEOF ++}; then ++ break ++fi ++ ++fi ++ ++ done ++ ++ if test "x$CONFIG_SHELL" != x; then ++ for as_var in BASH_ENV ENV ++ do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var ++ done ++ export CONFIG_SHELL ++ exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} ++fi ++ ++ ++ if test $as_have_required = no; then ++ echo This script requires a shell more modern than all the ++ echo shells that I found on your system. Please install a ++ echo modern shell, or manually run the script under such a ++ echo shell if you do have one. ++ { (exit 1); exit 1; } ++fi ++ ++ ++fi ++ ++fi ++ ++ ++ ++(eval "as_func_return () { ++ (exit \$1) ++} ++as_func_success () { ++ as_func_return 0 ++} ++as_func_failure () { ++ as_func_return 1 ++} ++as_func_ret_success () { ++ return 0 ++} ++as_func_ret_failure () { ++ return 1 ++} ++ ++exitcode=0 ++if as_func_success; then ++ : ++else ++ exitcode=1 ++ echo as_func_success failed. ++fi ++ ++if as_func_failure; then ++ exitcode=1 ++ echo as_func_failure succeeded. ++fi ++ ++if as_func_ret_success; then ++ : ++else ++ exitcode=1 ++ echo as_func_ret_success failed. ++fi ++ ++if as_func_ret_failure; then ++ exitcode=1 ++ echo as_func_ret_failure succeeded. ++fi ++ ++if ( set x; as_func_ret_success y && test x = \"\$1\" ); then ++ : ++else ++ exitcode=1 ++ echo positional parameters were not saved. ++fi ++ ++test \$exitcode = 0") || { ++ echo No shell found that supports shell functions. ++ echo Please tell bug-autoconf@gnu.org about your system, ++ echo including any error possibly output before this message. ++ echo This can help us improve future autoconf versions. ++ echo Configuration will now proceed without shell functions. ++} ++ ++ ++ ++ as_lineno_1=$LINENO ++ as_lineno_2=$LINENO ++ test "x$as_lineno_1" != "x$as_lineno_2" && ++ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { ++ ++ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO ++ # uniformly replaced by the line number. The first 'sed' inserts a ++ # line-number line after each line using $LINENO; the second 'sed' ++ # does the real work. The second script uses 'N' to pair each ++ # line-number line with the line containing $LINENO, and appends ++ # trailing '-' during substitution so that $LINENO is not a special ++ # case at line end. ++ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the ++ # scripts with optimization help from Paolo Bonzini. Blame Lee ++ # E. McMahon (1931-1989) for sed's syntax. :-) ++ sed -n ' ++ p ++ /[$]LINENO/= ++ ' <$as_myself | ++ sed ' ++ s/[$]LINENO.*/&-/ ++ t lineno ++ b ++ :lineno ++ N ++ :loop ++ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ ++ t loop ++ s/-\n.*// ++ ' >$as_me.lineno && ++ chmod +x "$as_me.lineno" || ++ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 ++ { (exit 1); exit 1; }; } ++ ++ # Don't try to exec as it changes $[0], causing all sort of problems ++ # (the dirname of $[0] is not the place where we might find the ++ # original and so on. Autoconf is especially sensitive to this). ++ . "./$as_me.lineno" ++ # Exit status is that of the last command. ++ exit ++} ++ ++ ++if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then ++ as_dirname=dirname ++else ++ as_dirname=false ++fi ++ ++ECHO_C= ECHO_N= ECHO_T= ++case `echo -n x` in ++-n*) ++ case `echo 'x\c'` in ++ *c*) ECHO_T=' ';; # ECHO_T is single tab character. ++ *) ECHO_C='\c';; ++ esac;; ++*) ++ ECHO_N='-n';; ++esac ++if expr a : '\(a\)' >/dev/null 2>&1 && ++ test "X`expr 00001 : '.*\(...\)'`" = X001; then ++ as_expr=expr ++else ++ as_expr=false ++fi ++ ++rm -f conf$$ conf$$.exe conf$$.file ++if test -d conf$$.dir; then ++ rm -f conf$$.dir/conf$$.file ++else ++ rm -f conf$$.dir ++ mkdir conf$$.dir 2>/dev/null ++fi ++if (echo >conf$$.file) 2>/dev/null; then ++ if ln -s conf$$.file conf$$ 2>/dev/null; then ++ as_ln_s='ln -s' ++ # ... but there are two gotchas: ++ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. ++ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. ++ # In both cases, we have to default to `cp -p'. ++ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || ++ as_ln_s='cp -p' ++ elif ln conf$$.file conf$$ 2>/dev/null; then ++ as_ln_s=ln ++ else ++ as_ln_s='cp -p' ++ fi ++else ++ as_ln_s='cp -p' ++fi ++rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file ++rmdir conf$$.dir 2>/dev/null ++ ++if mkdir -p . 2>/dev/null; then ++ as_mkdir_p=: ++else ++ test -d ./-p && rmdir ./-p ++ as_mkdir_p=false ++fi ++ ++if test -x / >/dev/null 2>&1; then ++ as_test_x='test -x' ++else ++ if ls -dL / >/dev/null 2>&1; then ++ as_ls_L_option=L ++ else ++ as_ls_L_option= ++ fi ++ as_test_x=' ++ eval sh -c '\'' ++ if test -d "$1"; then ++ test -d "$1/."; ++ else ++ case $1 in ++ -*)set "./$1";; ++ esac; ++ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ++ ???[sx]*):;;*)false;;esac;fi ++ '\'' sh ++ ' ++fi ++as_executable_p=$as_test_x ++ ++# Sed expression to map a string onto a valid CPP name. ++as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" ++ ++# Sed expression to map a string onto a valid variable name. ++as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" ++ ++ ++ ++exec 7<&0 &1 ++ ++# Name of the host. ++# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, ++# so uname gets run too. ++ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` ++ ++# ++# Initializations. ++# ++ac_default_prefix=/usr/local ++ac_clean_files= ++ac_config_libobj_dir=. ++LIBOBJS= ++cross_compiling=no ++subdirs= ++MFLAGS= ++MAKEFLAGS= ++SHELL=${CONFIG_SHELL-/bin/sh} ++ ++# Identity of this package. ++PACKAGE_NAME='open-isns' ++PACKAGE_TARNAME='open-isns' ++PACKAGE_VERSION='0.90' ++PACKAGE_STRING='open-isns 0.90' ++PACKAGE_BUGREPORT='' ++ ++ac_unique_file="isnsd.c" ++# Factoring default headers for most tests. ++ac_includes_default="\ ++#include ++#ifdef HAVE_SYS_TYPES_H ++# include ++#endif ++#ifdef HAVE_SYS_STAT_H ++# include ++#endif ++#ifdef STDC_HEADERS ++# include ++# include ++#else ++# ifdef HAVE_STDLIB_H ++# include ++# endif ++#endif ++#ifdef HAVE_STRING_H ++# if !defined STDC_HEADERS && defined HAVE_MEMORY_H ++# include ++# endif ++# include ++#endif ++#ifdef HAVE_STRINGS_H ++# include ++#endif ++#ifdef HAVE_INTTYPES_H ++# include ++#endif ++#ifdef HAVE_STDINT_H ++# include ++#endif ++#ifdef HAVE_UNISTD_H ++# include ++#endif" ++ ++ac_subst_vars='LTLIBOBJS ++LIBOBJS ++OPTIMIZE ++SLPLIBS ++SECLIBS ++GETOPTSRC ++SH ++SET_MAKE ++LN_S ++INSTALL_DATA ++INSTALL_SCRIPT ++INSTALL_PROGRAM ++EGREP ++GREP ++CPP ++host_os ++host_vendor ++host_cpu ++host ++build_os ++build_vendor ++build_cpu ++build ++OBJEXT ++EXEEXT ++ac_ct_CC ++CPPFLAGS ++LDFLAGS ++CFLAGS ++CC ++target_alias ++host_alias ++build_alias ++LIBS ++ECHO_T ++ECHO_N ++ECHO_C ++DEFS ++mandir ++localedir ++libdir ++psdir ++pdfdir ++dvidir ++htmldir ++infodir ++docdir ++oldincludedir ++includedir ++localstatedir ++sharedstatedir ++sysconfdir ++datadir ++datarootdir ++libexecdir ++sbindir ++bindir ++program_transform_name ++prefix ++exec_prefix ++PACKAGE_BUGREPORT ++PACKAGE_STRING ++PACKAGE_VERSION ++PACKAGE_TARNAME ++PACKAGE_NAME ++PATH_SEPARATOR ++SHELL' ++ac_subst_files='' ++ac_user_opts=' ++enable_option_checking ++with_security ++with_slp ++enable_memdebug ++' ++ ac_precious_vars='build_alias ++host_alias ++target_alias ++CC ++CFLAGS ++LDFLAGS ++LIBS ++CPPFLAGS ++CPP' ++ ++ ++# Initialize some variables set by options. ++ac_init_help= ++ac_init_version=false ++ac_unrecognized_opts= ++ac_unrecognized_sep= ++# The variables have the same names as the options, with ++# dashes changed to underlines. ++cache_file=/dev/null ++exec_prefix=NONE ++no_create= ++no_recursion= ++prefix=NONE ++program_prefix=NONE ++program_suffix=NONE ++program_transform_name=s,x,x, ++silent= ++site= ++srcdir= ++verbose= ++x_includes=NONE ++x_libraries=NONE ++ ++# Installation directory options. ++# These are left unexpanded so users can "make install exec_prefix=/foo" ++# and all the variables that are supposed to be based on exec_prefix ++# by default will actually change. ++# Use braces instead of parens because sh, perl, etc. also accept them. ++# (The list follows the same order as the GNU Coding Standards.) ++bindir='${exec_prefix}/bin' ++sbindir='${exec_prefix}/sbin' ++libexecdir='${exec_prefix}/libexec' ++datarootdir='${prefix}/share' ++datadir='${datarootdir}' ++sysconfdir='${prefix}/etc' ++sharedstatedir='${prefix}/com' ++localstatedir='${prefix}/var' ++includedir='${prefix}/include' ++oldincludedir='/usr/include' ++docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' ++infodir='${datarootdir}/info' ++htmldir='${docdir}' ++dvidir='${docdir}' ++pdfdir='${docdir}' ++psdir='${docdir}' ++libdir='${exec_prefix}/lib' ++localedir='${datarootdir}/locale' ++mandir='${datarootdir}/man' ++ ++ac_prev= ++ac_dashdash= ++for ac_option ++do ++ # If the previous option needs an argument, assign it. ++ if test -n "$ac_prev"; then ++ eval $ac_prev=\$ac_option ++ ac_prev= ++ continue ++ fi ++ ++ case $ac_option in ++ *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; ++ *) ac_optarg=yes ;; ++ esac ++ ++ # Accept the important Cygnus configure options, so we can diagnose typos. ++ ++ case $ac_dashdash$ac_option in ++ --) ++ ac_dashdash=yes ;; ++ ++ -bindir | --bindir | --bindi | --bind | --bin | --bi) ++ ac_prev=bindir ;; ++ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) ++ bindir=$ac_optarg ;; ++ ++ -build | --build | --buil | --bui | --bu) ++ ac_prev=build_alias ;; ++ -build=* | --build=* | --buil=* | --bui=* | --bu=*) ++ build_alias=$ac_optarg ;; ++ ++ -cache-file | --cache-file | --cache-fil | --cache-fi \ ++ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ++ ac_prev=cache_file ;; ++ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ ++ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) ++ cache_file=$ac_optarg ;; ++ ++ --config-cache | -C) ++ cache_file=config.cache ;; ++ ++ -datadir | --datadir | --datadi | --datad) ++ ac_prev=datadir ;; ++ -datadir=* | --datadir=* | --datadi=* | --datad=*) ++ datadir=$ac_optarg ;; ++ ++ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ ++ | --dataroo | --dataro | --datar) ++ ac_prev=datarootdir ;; ++ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ ++ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) ++ datarootdir=$ac_optarg ;; ++ ++ -disable-* | --disable-*) ++ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` ++ # Reject names that are not valid shell variable names. ++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && ++ { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 ++ { (exit 1); exit 1; }; } ++ ac_useropt_orig=$ac_useropt ++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` ++ case $ac_user_opts in ++ *" ++"enable_$ac_useropt" ++"*) ;; ++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ++ ac_unrecognized_sep=', ';; ++ esac ++ eval enable_$ac_useropt=no ;; ++ ++ -docdir | --docdir | --docdi | --doc | --do) ++ ac_prev=docdir ;; ++ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) ++ docdir=$ac_optarg ;; ++ ++ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ++ ac_prev=dvidir ;; ++ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) ++ dvidir=$ac_optarg ;; ++ ++ -enable-* | --enable-*) ++ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` ++ # Reject names that are not valid shell variable names. ++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && ++ { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 ++ { (exit 1); exit 1; }; } ++ ac_useropt_orig=$ac_useropt ++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` ++ case $ac_user_opts in ++ *" ++"enable_$ac_useropt" ++"*) ;; ++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ++ ac_unrecognized_sep=', ';; ++ esac ++ eval enable_$ac_useropt=\$ac_optarg ;; ++ ++ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ ++ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ ++ | --exec | --exe | --ex) ++ ac_prev=exec_prefix ;; ++ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ ++ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ ++ | --exec=* | --exe=* | --ex=*) ++ exec_prefix=$ac_optarg ;; ++ ++ -gas | --gas | --ga | --g) ++ # Obsolete; use --with-gas. ++ with_gas=yes ;; ++ ++ -help | --help | --hel | --he | -h) ++ ac_init_help=long ;; ++ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ++ ac_init_help=recursive ;; ++ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ++ ac_init_help=short ;; ++ ++ -host | --host | --hos | --ho) ++ ac_prev=host_alias ;; ++ -host=* | --host=* | --hos=* | --ho=*) ++ host_alias=$ac_optarg ;; ++ ++ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ++ ac_prev=htmldir ;; ++ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ ++ | --ht=*) ++ htmldir=$ac_optarg ;; ++ ++ -includedir | --includedir | --includedi | --included | --include \ ++ | --includ | --inclu | --incl | --inc) ++ ac_prev=includedir ;; ++ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ ++ | --includ=* | --inclu=* | --incl=* | --inc=*) ++ includedir=$ac_optarg ;; ++ ++ -infodir | --infodir | --infodi | --infod | --info | --inf) ++ ac_prev=infodir ;; ++ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) ++ infodir=$ac_optarg ;; ++ ++ -libdir | --libdir | --libdi | --libd) ++ ac_prev=libdir ;; ++ -libdir=* | --libdir=* | --libdi=* | --libd=*) ++ libdir=$ac_optarg ;; ++ ++ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ ++ | --libexe | --libex | --libe) ++ ac_prev=libexecdir ;; ++ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ ++ | --libexe=* | --libex=* | --libe=*) ++ libexecdir=$ac_optarg ;; ++ ++ -localedir | --localedir | --localedi | --localed | --locale) ++ ac_prev=localedir ;; ++ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) ++ localedir=$ac_optarg ;; ++ ++ -localstatedir | --localstatedir | --localstatedi | --localstated \ ++ | --localstate | --localstat | --localsta | --localst | --locals) ++ ac_prev=localstatedir ;; ++ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ ++ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) ++ localstatedir=$ac_optarg ;; ++ ++ -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ++ ac_prev=mandir ;; ++ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) ++ mandir=$ac_optarg ;; ++ ++ -nfp | --nfp | --nf) ++ # Obsolete; use --without-fp. ++ with_fp=no ;; ++ ++ -no-create | --no-create | --no-creat | --no-crea | --no-cre \ ++ | --no-cr | --no-c | -n) ++ no_create=yes ;; ++ ++ -no-recursion | --no-recursion | --no-recursio | --no-recursi \ ++ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ++ no_recursion=yes ;; ++ ++ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ ++ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ ++ | --oldin | --oldi | --old | --ol | --o) ++ ac_prev=oldincludedir ;; ++ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ ++ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ ++ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) ++ oldincludedir=$ac_optarg ;; ++ ++ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ++ ac_prev=prefix ;; ++ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) ++ prefix=$ac_optarg ;; ++ ++ -program-prefix | --program-prefix | --program-prefi | --program-pref \ ++ | --program-pre | --program-pr | --program-p) ++ ac_prev=program_prefix ;; ++ -program-prefix=* | --program-prefix=* | --program-prefi=* \ ++ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) ++ program_prefix=$ac_optarg ;; ++ ++ -program-suffix | --program-suffix | --program-suffi | --program-suff \ ++ | --program-suf | --program-su | --program-s) ++ ac_prev=program_suffix ;; ++ -program-suffix=* | --program-suffix=* | --program-suffi=* \ ++ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) ++ program_suffix=$ac_optarg ;; ++ ++ -program-transform-name | --program-transform-name \ ++ | --program-transform-nam | --program-transform-na \ ++ | --program-transform-n | --program-transform- \ ++ | --program-transform | --program-transfor \ ++ | --program-transfo | --program-transf \ ++ | --program-trans | --program-tran \ ++ | --progr-tra | --program-tr | --program-t) ++ ac_prev=program_transform_name ;; ++ -program-transform-name=* | --program-transform-name=* \ ++ | --program-transform-nam=* | --program-transform-na=* \ ++ | --program-transform-n=* | --program-transform-=* \ ++ | --program-transform=* | --program-transfor=* \ ++ | --program-transfo=* | --program-transf=* \ ++ | --program-trans=* | --program-tran=* \ ++ | --progr-tra=* | --program-tr=* | --program-t=*) ++ program_transform_name=$ac_optarg ;; ++ ++ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ++ ac_prev=pdfdir ;; ++ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) ++ pdfdir=$ac_optarg ;; ++ ++ -psdir | --psdir | --psdi | --psd | --ps) ++ ac_prev=psdir ;; ++ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) ++ psdir=$ac_optarg ;; ++ ++ -q | -quiet | --quiet | --quie | --qui | --qu | --q \ ++ | -silent | --silent | --silen | --sile | --sil) ++ silent=yes ;; ++ ++ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ++ ac_prev=sbindir ;; ++ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ ++ | --sbi=* | --sb=*) ++ sbindir=$ac_optarg ;; ++ ++ -sharedstatedir | --sharedstatedir | --sharedstatedi \ ++ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ ++ | --sharedst | --shareds | --shared | --share | --shar \ ++ | --sha | --sh) ++ ac_prev=sharedstatedir ;; ++ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ ++ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ ++ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ ++ | --sha=* | --sh=*) ++ sharedstatedir=$ac_optarg ;; ++ ++ -site | --site | --sit) ++ ac_prev=site ;; ++ -site=* | --site=* | --sit=*) ++ site=$ac_optarg ;; ++ ++ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ++ ac_prev=srcdir ;; ++ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) ++ srcdir=$ac_optarg ;; ++ ++ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ ++ | --syscon | --sysco | --sysc | --sys | --sy) ++ ac_prev=sysconfdir ;; ++ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ ++ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) ++ sysconfdir=$ac_optarg ;; ++ ++ -target | --target | --targe | --targ | --tar | --ta | --t) ++ ac_prev=target_alias ;; ++ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) ++ target_alias=$ac_optarg ;; ++ ++ -v | -verbose | --verbose | --verbos | --verbo | --verb) ++ verbose=yes ;; ++ ++ -version | --version | --versio | --versi | --vers | -V) ++ ac_init_version=: ;; ++ ++ -with-* | --with-*) ++ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` ++ # Reject names that are not valid shell variable names. ++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && ++ { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 ++ { (exit 1); exit 1; }; } ++ ac_useropt_orig=$ac_useropt ++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` ++ case $ac_user_opts in ++ *" ++"with_$ac_useropt" ++"*) ;; ++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ++ ac_unrecognized_sep=', ';; ++ esac ++ eval with_$ac_useropt=\$ac_optarg ;; ++ ++ -without-* | --without-*) ++ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` ++ # Reject names that are not valid shell variable names. ++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && ++ { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 ++ { (exit 1); exit 1; }; } ++ ac_useropt_orig=$ac_useropt ++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` ++ case $ac_user_opts in ++ *" ++"with_$ac_useropt" ++"*) ;; ++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ++ ac_unrecognized_sep=', ';; ++ esac ++ eval with_$ac_useropt=no ;; ++ ++ --x) ++ # Obsolete; use --with-x. ++ with_x=yes ;; ++ ++ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ ++ | --x-incl | --x-inc | --x-in | --x-i) ++ ac_prev=x_includes ;; ++ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ ++ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) ++ x_includes=$ac_optarg ;; ++ ++ -x-libraries | --x-libraries | --x-librarie | --x-librari \ ++ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ++ ac_prev=x_libraries ;; ++ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ ++ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) ++ x_libraries=$ac_optarg ;; ++ ++ -*) { $as_echo "$as_me: error: unrecognized option: $ac_option ++Try \`$0 --help' for more information." >&2 ++ { (exit 1); exit 1; }; } ++ ;; ++ ++ *=*) ++ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` ++ # Reject names that are not valid shell variable names. ++ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && ++ { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2 ++ { (exit 1); exit 1; }; } ++ eval $ac_envvar=\$ac_optarg ++ export $ac_envvar ;; ++ ++ *) ++ # FIXME: should be removed in autoconf 3.0. ++ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 ++ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && ++ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 ++ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ++ ;; ++ ++ esac ++done ++ ++if test -n "$ac_prev"; then ++ ac_option=--`echo $ac_prev | sed 's/_/-/g'` ++ { $as_echo "$as_me: error: missing argument to $ac_option" >&2 ++ { (exit 1); exit 1; }; } ++fi ++ ++if test -n "$ac_unrecognized_opts"; then ++ case $enable_option_checking in ++ no) ;; ++ fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2 ++ { (exit 1); exit 1; }; } ;; ++ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; ++ esac ++fi ++ ++# Check all directory arguments for consistency. ++for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ ++ datadir sysconfdir sharedstatedir localstatedir includedir \ ++ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ ++ libdir localedir mandir ++do ++ eval ac_val=\$$ac_var ++ # Remove trailing slashes. ++ case $ac_val in ++ */ ) ++ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` ++ eval $ac_var=\$ac_val;; ++ esac ++ # Be sure to have absolute directory names. ++ case $ac_val in ++ [\\/$]* | ?:[\\/]* ) continue;; ++ NONE | '' ) case $ac_var in *prefix ) continue;; esac;; ++ esac ++ { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 ++ { (exit 1); exit 1; }; } ++done ++ ++# There might be people who depend on the old broken behavior: `$host' ++# used to hold the argument of --host etc. ++# FIXME: To remove some day. ++build=$build_alias ++host=$host_alias ++target=$target_alias ++ ++# FIXME: To remove some day. ++if test "x$host_alias" != x; then ++ if test "x$build_alias" = x; then ++ cross_compiling=maybe ++ $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. ++ If a cross compiler is detected then cross compile mode will be used." >&2 ++ elif test "x$build_alias" != "x$host_alias"; then ++ cross_compiling=yes ++ fi ++fi ++ ++ac_tool_prefix= ++test -n "$host_alias" && ac_tool_prefix=$host_alias- ++ ++test "$silent" = yes && exec 6>/dev/null ++ ++ ++ac_pwd=`pwd` && test -n "$ac_pwd" && ++ac_ls_di=`ls -di .` && ++ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || ++ { $as_echo "$as_me: error: working directory cannot be determined" >&2 ++ { (exit 1); exit 1; }; } ++test "X$ac_ls_di" = "X$ac_pwd_ls_di" || ++ { $as_echo "$as_me: error: pwd does not report name of working directory" >&2 ++ { (exit 1); exit 1; }; } ++ ++ ++# Find the source files, if location was not specified. ++if test -z "$srcdir"; then ++ ac_srcdir_defaulted=yes ++ # Try the directory containing this script, then the parent directory. ++ ac_confdir=`$as_dirname -- "$as_myself" || ++$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ ++ X"$as_myself" : 'X\(//\)[^/]' \| \ ++ X"$as_myself" : 'X\(//\)$' \| \ ++ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X"$as_myself" | ++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)[^/].*/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ srcdir=$ac_confdir ++ if test ! -r "$srcdir/$ac_unique_file"; then ++ srcdir=.. ++ fi ++else ++ ac_srcdir_defaulted=no ++fi ++if test ! -r "$srcdir/$ac_unique_file"; then ++ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." ++ { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 ++ { (exit 1); exit 1; }; } ++fi ++ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ++ac_abs_confdir=`( ++ cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2 ++ { (exit 1); exit 1; }; } ++ pwd)` ++# When building in place, set srcdir=. ++if test "$ac_abs_confdir" = "$ac_pwd"; then ++ srcdir=. ++fi ++# Remove unnecessary trailing slashes from srcdir. ++# Double slashes in file names in object file debugging info ++# mess up M-x gdb in Emacs. ++case $srcdir in ++*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; ++esac ++for ac_var in $ac_precious_vars; do ++ eval ac_env_${ac_var}_set=\${${ac_var}+set} ++ eval ac_env_${ac_var}_value=\$${ac_var} ++ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} ++ eval ac_cv_env_${ac_var}_value=\$${ac_var} ++done ++ ++# ++# Report the --help message. ++# ++if test "$ac_init_help" = "long"; then ++ # Omit some internal or obsolete options to make the list less imposing. ++ # This message is too long to be a string in the A/UX 3.1 sh. ++ cat <<_ACEOF ++\`configure' configures open-isns 0.90 to adapt to many kinds of systems. ++ ++Usage: $0 [OPTION]... [VAR=VALUE]... ++ ++To assign environment variables (e.g., CC, CFLAGS...), specify them as ++VAR=VALUE. See below for descriptions of some of the useful variables. ++ ++Defaults for the options are specified in brackets. ++ ++Configuration: ++ -h, --help display this help and exit ++ --help=short display options specific to this package ++ --help=recursive display the short help of all the included packages ++ -V, --version display version information and exit ++ -q, --quiet, --silent do not print \`checking...' messages ++ --cache-file=FILE cache test results in FILE [disabled] ++ -C, --config-cache alias for \`--cache-file=config.cache' ++ -n, --no-create do not create output files ++ --srcdir=DIR find the sources in DIR [configure dir or \`..'] ++ ++Installation directories: ++ --prefix=PREFIX install architecture-independent files in PREFIX ++ [$ac_default_prefix] ++ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX ++ [PREFIX] ++ ++By default, \`make install' will install all the files in ++\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify ++an installation prefix other than \`$ac_default_prefix' using \`--prefix', ++for instance \`--prefix=\$HOME'. ++ ++For better control, use the options below. ++ ++Fine tuning of the installation directories: ++ --bindir=DIR user executables [EPREFIX/bin] ++ --sbindir=DIR system admin executables [EPREFIX/sbin] ++ --libexecdir=DIR program executables [EPREFIX/libexec] ++ --sysconfdir=DIR read-only single-machine data [PREFIX/etc] ++ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] ++ --localstatedir=DIR modifiable single-machine data [PREFIX/var] ++ --libdir=DIR object code libraries [EPREFIX/lib] ++ --includedir=DIR C header files [PREFIX/include] ++ --oldincludedir=DIR C header files for non-gcc [/usr/include] ++ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] ++ --datadir=DIR read-only architecture-independent data [DATAROOTDIR] ++ --infodir=DIR info documentation [DATAROOTDIR/info] ++ --localedir=DIR locale-dependent data [DATAROOTDIR/locale] ++ --mandir=DIR man documentation [DATAROOTDIR/man] ++ --docdir=DIR documentation root [DATAROOTDIR/doc/open-isns] ++ --htmldir=DIR html documentation [DOCDIR] ++ --dvidir=DIR dvi documentation [DOCDIR] ++ --pdfdir=DIR pdf documentation [DOCDIR] ++ --psdir=DIR ps documentation [DOCDIR] ++_ACEOF ++ ++ cat <<\_ACEOF ++ ++System types: ++ --build=BUILD configure for building on BUILD [guessed] ++ --host=HOST cross-compile to build programs to run on HOST [BUILD] ++_ACEOF ++fi ++ ++if test -n "$ac_init_help"; then ++ case $ac_init_help in ++ short | recursive ) echo "Configuration of open-isns 0.90:";; ++ esac ++ cat <<\_ACEOF ++ ++Optional Features: ++ --disable-option-checking ignore unrecognized --enable/--with options ++ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) ++ --enable-FEATURE[=ARG] include FEATURE [ARG=yes] ++ --enable-memdebug Enable malloc debugging ++ ++Optional Packages: ++ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] ++ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) ++ --with-security Enable iSNS authentication - requires OpenSSL ++ --with-slp Enable SLP for server discovery - requires OpenSLP ++ ++Some influential environment variables: ++ CC C compiler command ++ CFLAGS C compiler flags ++ LDFLAGS linker flags, e.g. -L if you have libraries in a ++ nonstandard directory ++ LIBS libraries to pass to the linker, e.g. -l ++ CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if ++ you have headers in a nonstandard directory ++ CPP C preprocessor ++ ++Use these variables to override the choices made by `configure' or to help ++it to find libraries and programs with nonstandard names/locations. ++ ++_ACEOF ++ac_status=$? ++fi ++ ++if test "$ac_init_help" = "recursive"; then ++ # If there are subdirs, report their specific --help. ++ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue ++ test -d "$ac_dir" || ++ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || ++ continue ++ ac_builddir=. ++ ++case "$ac_dir" in ++.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; ++*) ++ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` ++ # A ".." for each directory in $ac_dir_suffix. ++ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` ++ case $ac_top_builddir_sub in ++ "") ac_top_builddir_sub=. ac_top_build_prefix= ;; ++ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; ++ esac ;; ++esac ++ac_abs_top_builddir=$ac_pwd ++ac_abs_builddir=$ac_pwd$ac_dir_suffix ++# for backward compatibility: ++ac_top_builddir=$ac_top_build_prefix ++ ++case $srcdir in ++ .) # We are building in place. ++ ac_srcdir=. ++ ac_top_srcdir=$ac_top_builddir_sub ++ ac_abs_top_srcdir=$ac_pwd ;; ++ [\\/]* | ?:[\\/]* ) # Absolute name. ++ ac_srcdir=$srcdir$ac_dir_suffix; ++ ac_top_srcdir=$srcdir ++ ac_abs_top_srcdir=$srcdir ;; ++ *) # Relative name. ++ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ++ ac_top_srcdir=$ac_top_build_prefix$srcdir ++ ac_abs_top_srcdir=$ac_pwd/$srcdir ;; ++esac ++ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix ++ ++ cd "$ac_dir" || { ac_status=$?; continue; } ++ # Check for guested configure. ++ if test -f "$ac_srcdir/configure.gnu"; then ++ echo && ++ $SHELL "$ac_srcdir/configure.gnu" --help=recursive ++ elif test -f "$ac_srcdir/configure"; then ++ echo && ++ $SHELL "$ac_srcdir/configure" --help=recursive ++ else ++ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 ++ fi || ac_status=$? ++ cd "$ac_pwd" || { ac_status=$?; break; } ++ done ++fi ++ ++test -n "$ac_init_help" && exit $ac_status ++if $ac_init_version; then ++ cat <<\_ACEOF ++open-isns configure 0.90 ++generated by GNU Autoconf 2.63 ++ ++Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, ++2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. ++This configure script is free software; the Free Software Foundation ++gives unlimited permission to copy, distribute and modify it. ++_ACEOF ++ exit ++fi ++cat >config.log <<_ACEOF ++This file contains any messages produced by compilers while ++running configure, to aid debugging if configure makes a mistake. ++ ++It was created by open-isns $as_me 0.90, which was ++generated by GNU Autoconf 2.63. Invocation command line was ++ ++ $ $0 $@ ++ ++_ACEOF ++exec 5>>config.log ++{ ++cat <<_ASUNAME ++## --------- ## ++## Platform. ## ++## --------- ## ++ ++hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` ++uname -m = `(uname -m) 2>/dev/null || echo unknown` ++uname -r = `(uname -r) 2>/dev/null || echo unknown` ++uname -s = `(uname -s) 2>/dev/null || echo unknown` ++uname -v = `(uname -v) 2>/dev/null || echo unknown` ++ ++/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` ++/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` ++ ++/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` ++/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` ++/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` ++/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` ++/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` ++/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` ++/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` ++ ++_ASUNAME ++ ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ $as_echo "PATH: $as_dir" ++done ++IFS=$as_save_IFS ++ ++} >&5 ++ ++cat >&5 <<_ACEOF ++ ++ ++## ----------- ## ++## Core tests. ## ++## ----------- ## ++ ++_ACEOF ++ ++ ++# Keep a trace of the command line. ++# Strip out --no-create and --no-recursion so they do not pile up. ++# Strip out --silent because we don't want to record it for future runs. ++# Also quote any args containing shell meta-characters. ++# Make two passes to allow for proper duplicate-argument suppression. ++ac_configure_args= ++ac_configure_args0= ++ac_configure_args1= ++ac_must_keep_next=false ++for ac_pass in 1 2 ++do ++ for ac_arg ++ do ++ case $ac_arg in ++ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; ++ -q | -quiet | --quiet | --quie | --qui | --qu | --q \ ++ | -silent | --silent | --silen | --sile | --sil) ++ continue ;; ++ *\'*) ++ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; ++ esac ++ case $ac_pass in ++ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; ++ 2) ++ ac_configure_args1="$ac_configure_args1 '$ac_arg'" ++ if test $ac_must_keep_next = true; then ++ ac_must_keep_next=false # Got value, back to normal. ++ else ++ case $ac_arg in ++ *=* | --config-cache | -C | -disable-* | --disable-* \ ++ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ ++ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ ++ | -with-* | --with-* | -without-* | --without-* | --x) ++ case "$ac_configure_args0 " in ++ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; ++ esac ++ ;; ++ -* ) ac_must_keep_next=true ;; ++ esac ++ fi ++ ac_configure_args="$ac_configure_args '$ac_arg'" ++ ;; ++ esac ++ done ++done ++$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } ++$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } ++ ++# When interrupted or exit'd, cleanup temporary files, and complete ++# config.log. We remove comments because anyway the quotes in there ++# would cause problems or look ugly. ++# WARNING: Use '\'' to represent an apostrophe within the trap. ++# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. ++trap 'exit_status=$? ++ # Save into config.log some information that might help in debugging. ++ { ++ echo ++ ++ cat <<\_ASBOX ++## ---------------- ## ++## Cache variables. ## ++## ---------------- ## ++_ASBOX ++ echo ++ # The following way of writing the cache mishandles newlines in values, ++( ++ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do ++ eval ac_val=\$$ac_var ++ case $ac_val in #( ++ *${as_nl}*) ++ case $ac_var in #( ++ *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 ++$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ++ esac ++ case $ac_var in #( ++ _ | IFS | as_nl) ;; #( ++ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( ++ *) $as_unset $ac_var ;; ++ esac ;; ++ esac ++ done ++ (set) 2>&1 | ++ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( ++ *${as_nl}ac_space=\ *) ++ sed -n \ ++ "s/'\''/'\''\\\\'\'''\''/g; ++ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ++ ;; #( ++ *) ++ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ++ ;; ++ esac | ++ sort ++) ++ echo ++ ++ cat <<\_ASBOX ++## ----------------- ## ++## Output variables. ## ++## ----------------- ## ++_ASBOX ++ echo ++ for ac_var in $ac_subst_vars ++ do ++ eval ac_val=\$$ac_var ++ case $ac_val in ++ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; ++ esac ++ $as_echo "$ac_var='\''$ac_val'\''" ++ done | sort ++ echo ++ ++ if test -n "$ac_subst_files"; then ++ cat <<\_ASBOX ++## ------------------- ## ++## File substitutions. ## ++## ------------------- ## ++_ASBOX ++ echo ++ for ac_var in $ac_subst_files ++ do ++ eval ac_val=\$$ac_var ++ case $ac_val in ++ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; ++ esac ++ $as_echo "$ac_var='\''$ac_val'\''" ++ done | sort ++ echo ++ fi ++ ++ if test -s confdefs.h; then ++ cat <<\_ASBOX ++## ----------- ## ++## confdefs.h. ## ++## ----------- ## ++_ASBOX ++ echo ++ cat confdefs.h ++ echo ++ fi ++ test "$ac_signal" != 0 && ++ $as_echo "$as_me: caught signal $ac_signal" ++ $as_echo "$as_me: exit $exit_status" ++ } >&5 ++ rm -f core *.core core.conftest.* && ++ rm -f -r conftest* confdefs* conf$$* $ac_clean_files && ++ exit $exit_status ++' 0 ++for ac_signal in 1 2 13 15; do ++ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal ++done ++ac_signal=0 ++ ++# confdefs.h avoids OS command line length limits that DEFS can exceed. ++rm -f -r conftest* confdefs.h ++ ++# Predefined preprocessor variables. ++ ++cat >>confdefs.h <<_ACEOF ++#define PACKAGE_NAME "$PACKAGE_NAME" ++_ACEOF ++ ++ ++cat >>confdefs.h <<_ACEOF ++#define PACKAGE_TARNAME "$PACKAGE_TARNAME" ++_ACEOF ++ ++ ++cat >>confdefs.h <<_ACEOF ++#define PACKAGE_VERSION "$PACKAGE_VERSION" ++_ACEOF ++ ++ ++cat >>confdefs.h <<_ACEOF ++#define PACKAGE_STRING "$PACKAGE_STRING" ++_ACEOF ++ ++ ++cat >>confdefs.h <<_ACEOF ++#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" ++_ACEOF ++ ++ ++# Let the site file select an alternate cache file if it wants to. ++# Prefer an explicitly selected file to automatically selected ones. ++ac_site_file1=NONE ++ac_site_file2=NONE ++if test -n "$CONFIG_SITE"; then ++ ac_site_file1=$CONFIG_SITE ++elif test "x$prefix" != xNONE; then ++ ac_site_file1=$prefix/share/config.site ++ ac_site_file2=$prefix/etc/config.site ++else ++ ac_site_file1=$ac_default_prefix/share/config.site ++ ac_site_file2=$ac_default_prefix/etc/config.site ++fi ++for ac_site_file in "$ac_site_file1" "$ac_site_file2" ++do ++ test "x$ac_site_file" = xNONE && continue ++ if test -r "$ac_site_file"; then ++ { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 ++$as_echo "$as_me: loading site script $ac_site_file" >&6;} ++ sed 's/^/| /' "$ac_site_file" >&5 ++ . "$ac_site_file" ++ fi ++done ++ ++if test -r "$cache_file"; then ++ # Some versions of bash will fail to source /dev/null (special ++ # files actually), so we avoid doing that. ++ if test -f "$cache_file"; then ++ { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5 ++$as_echo "$as_me: loading cache $cache_file" >&6;} ++ case $cache_file in ++ [\\/]* | ?:[\\/]* ) . "$cache_file";; ++ *) . "./$cache_file";; ++ esac ++ fi ++else ++ { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5 ++$as_echo "$as_me: creating cache $cache_file" >&6;} ++ >$cache_file ++fi ++ ++# Check that the precious variables saved in the cache have kept the same ++# value. ++ac_cache_corrupted=false ++for ac_var in $ac_precious_vars; do ++ eval ac_old_set=\$ac_cv_env_${ac_var}_set ++ eval ac_new_set=\$ac_env_${ac_var}_set ++ eval ac_old_val=\$ac_cv_env_${ac_var}_value ++ eval ac_new_val=\$ac_env_${ac_var}_value ++ case $ac_old_set,$ac_new_set in ++ set,) ++ { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 ++$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ++ ac_cache_corrupted=: ;; ++ ,set) ++ { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 ++$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ++ ac_cache_corrupted=: ;; ++ ,);; ++ *) ++ if test "x$ac_old_val" != "x$ac_new_val"; then ++ # differences in whitespace do not lead to failure. ++ ac_old_val_w=`echo x $ac_old_val` ++ ac_new_val_w=`echo x $ac_new_val` ++ if test "$ac_old_val_w" != "$ac_new_val_w"; then ++ { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 ++$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ++ ac_cache_corrupted=: ++ else ++ { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 ++$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} ++ eval $ac_var=\$ac_old_val ++ fi ++ { $as_echo "$as_me:$LINENO: former value: \`$ac_old_val'" >&5 ++$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} ++ { $as_echo "$as_me:$LINENO: current value: \`$ac_new_val'" >&5 ++$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} ++ fi;; ++ esac ++ # Pass precious variables to config.status. ++ if test "$ac_new_set" = set; then ++ case $ac_new_val in ++ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; ++ *) ac_arg=$ac_var=$ac_new_val ;; ++ esac ++ case " $ac_configure_args " in ++ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. ++ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; ++ esac ++ fi ++done ++if $ac_cache_corrupted; then ++ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++ { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 ++$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} ++ { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 ++$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} ++ { (exit 1); exit 1; }; } ++fi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ac_ext=c ++ac_cpp='$CPP $CPPFLAGS' ++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_c_compiler_gnu ++ ++ ++ ++ac_aux_dir= ++for ac_dir in aclocal "$srcdir"/aclocal; do ++ if test -f "$ac_dir/install-sh"; then ++ ac_aux_dir=$ac_dir ++ ac_install_sh="$ac_aux_dir/install-sh -c" ++ break ++ elif test -f "$ac_dir/install.sh"; then ++ ac_aux_dir=$ac_dir ++ ac_install_sh="$ac_aux_dir/install.sh -c" ++ break ++ elif test -f "$ac_dir/shtool"; then ++ ac_aux_dir=$ac_dir ++ ac_install_sh="$ac_aux_dir/shtool install -c" ++ break ++ fi ++done ++if test -z "$ac_aux_dir"; then ++ { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in aclocal \"$srcdir\"/aclocal" >&5 ++$as_echo "$as_me: error: cannot find install-sh or install.sh in aclocal \"$srcdir\"/aclocal" >&2;} ++ { (exit 1); exit 1; }; } ++fi ++ ++# These three variables are undocumented and unsupported, ++# and are intended to be withdrawn in a future Autoconf release. ++# They can cause serious problems if a builder's source tree is in a directory ++# whose full name contains unusual characters. ++ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ++ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ++ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. ++ ++ ++ ++ac_config_headers="$ac_config_headers config.h" ++ ++ ++ac_ext=c ++ac_cpp='$CPP $CPPFLAGS' ++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_c_compiler_gnu ++if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. ++set dummy ${ac_tool_prefix}gcc; ac_word=$2 ++{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if test "${ac_cv_prog_CC+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CC"; then ++ ac_cv_prog_CC="$CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ ac_cv_prog_CC="${ac_tool_prefix}gcc" ++ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++done ++IFS=$as_save_IFS ++ ++fi ++fi ++CC=$ac_cv_prog_CC ++if test -n "$CC"; then ++ { $as_echo "$as_me:$LINENO: result: $CC" >&5 ++$as_echo "$CC" >&6; } ++else ++ { $as_echo "$as_me:$LINENO: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_CC"; then ++ ac_ct_CC=$CC ++ # Extract the first word of "gcc", so it can be a program name with args. ++set dummy gcc; ac_word=$2 ++{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if test "${ac_cv_prog_ac_ct_CC+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_CC"; then ++ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ ac_cv_prog_ac_ct_CC="gcc" ++ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_CC=$ac_cv_prog_ac_ct_CC ++if test -n "$ac_ct_CC"; then ++ { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 ++$as_echo "$ac_ct_CC" >&6; } ++else ++ { $as_echo "$as_me:$LINENO: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_CC" = x; then ++ CC="" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ CC=$ac_ct_CC ++ fi ++else ++ CC="$ac_cv_prog_CC" ++fi ++ ++if test -z "$CC"; then ++ if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. ++set dummy ${ac_tool_prefix}cc; ac_word=$2 ++{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if test "${ac_cv_prog_CC+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CC"; then ++ ac_cv_prog_CC="$CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ ac_cv_prog_CC="${ac_tool_prefix}cc" ++ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++done ++IFS=$as_save_IFS ++ ++fi ++fi ++CC=$ac_cv_prog_CC ++if test -n "$CC"; then ++ { $as_echo "$as_me:$LINENO: result: $CC" >&5 ++$as_echo "$CC" >&6; } ++else ++ { $as_echo "$as_me:$LINENO: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ fi ++fi ++if test -z "$CC"; then ++ # Extract the first word of "cc", so it can be a program name with args. ++set dummy cc; ac_word=$2 ++{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if test "${ac_cv_prog_CC+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CC"; then ++ ac_cv_prog_CC="$CC" # Let the user override the test. ++else ++ ac_prog_rejected=no ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ++ ac_prog_rejected=yes ++ continue ++ fi ++ ac_cv_prog_CC="cc" ++ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++done ++IFS=$as_save_IFS ++ ++if test $ac_prog_rejected = yes; then ++ # We found a bogon in the path, so make sure we never use it. ++ set dummy $ac_cv_prog_CC ++ shift ++ if test $# != 0; then ++ # We chose a different compiler from the bogus one. ++ # However, it has the same basename, so the bogon will be chosen ++ # first if we set CC to just the basename; use the full file name. ++ shift ++ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" ++ fi ++fi ++fi ++fi ++CC=$ac_cv_prog_CC ++if test -n "$CC"; then ++ { $as_echo "$as_me:$LINENO: result: $CC" >&5 ++$as_echo "$CC" >&6; } ++else ++ { $as_echo "$as_me:$LINENO: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$CC"; then ++ if test -n "$ac_tool_prefix"; then ++ for ac_prog in cl.exe ++ do ++ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. ++set dummy $ac_tool_prefix$ac_prog; ac_word=$2 ++{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if test "${ac_cv_prog_CC+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CC"; then ++ ac_cv_prog_CC="$CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ ac_cv_prog_CC="$ac_tool_prefix$ac_prog" ++ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++done ++IFS=$as_save_IFS ++ ++fi ++fi ++CC=$ac_cv_prog_CC ++if test -n "$CC"; then ++ { $as_echo "$as_me:$LINENO: result: $CC" >&5 ++$as_echo "$CC" >&6; } ++else ++ { $as_echo "$as_me:$LINENO: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$CC" && break ++ done ++fi ++if test -z "$CC"; then ++ ac_ct_CC=$CC ++ for ac_prog in cl.exe ++do ++ # Extract the first word of "$ac_prog", so it can be a program name with args. ++set dummy $ac_prog; ac_word=$2 ++{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if test "${ac_cv_prog_ac_ct_CC+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_CC"; then ++ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ ac_cv_prog_ac_ct_CC="$ac_prog" ++ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_CC=$ac_cv_prog_ac_ct_CC ++if test -n "$ac_ct_CC"; then ++ { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 ++$as_echo "$ac_ct_CC" >&6; } ++else ++ { $as_echo "$as_me:$LINENO: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$ac_ct_CC" && break ++done ++ ++ if test "x$ac_ct_CC" = x; then ++ CC="" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ CC=$ac_ct_CC ++ fi ++fi ++ ++fi ++ ++ ++test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++{ { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH ++See \`config.log' for more details." >&5 ++$as_echo "$as_me: error: no acceptable C compiler found in \$PATH ++See \`config.log' for more details." >&2;} ++ { (exit 1); exit 1; }; }; } ++ ++# Provide some information about the compiler. ++$as_echo "$as_me:$LINENO: checking for C compiler version" >&5 ++set X $ac_compile ++ac_compiler=$2 ++{ (ac_try="$ac_compiler --version >&5" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compiler --version >&5") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } ++{ (ac_try="$ac_compiler -v >&5" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compiler -v >&5") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } ++{ (ac_try="$ac_compiler -V >&5" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compiler -V >&5") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } ++ ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++ac_clean_files_save=$ac_clean_files ++ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" ++# Try to create an executable without -o first, disregard a.out. ++# It will help us diagnose broken compilers, and finding out an intuition ++# of exeext. ++{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 ++$as_echo_n "checking for C compiler default output file name... " >&6; } ++ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` ++ ++# The possible output files: ++ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ++ ++ac_rmfiles= ++for ac_file in $ac_files ++do ++ case $ac_file in ++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; ++ * ) ac_rmfiles="$ac_rmfiles $ac_file";; ++ esac ++done ++rm -f $ac_rmfiles ++ ++if { (ac_try="$ac_link_default" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_link_default") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; then ++ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. ++# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' ++# in a Makefile. We should not override ac_cv_exeext if it was cached, ++# so that the user can short-circuit this test for compilers unknown to ++# Autoconf. ++for ac_file in $ac_files '' ++do ++ test -f "$ac_file" || continue ++ case $ac_file in ++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ++ ;; ++ [ab].out ) ++ # We found the default executable, but exeext='' is most ++ # certainly right. ++ break;; ++ *.* ) ++ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; ++ then :; else ++ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` ++ fi ++ # We set ac_cv_exeext here because the later test for it is not ++ # safe: cross compilers may not add the suffix if given an `-o' ++ # argument, so we may need to know it at that point already. ++ # Even if this section looks crufty: it has the advantage of ++ # actually working. ++ break;; ++ * ) ++ break;; ++ esac ++done ++test "$ac_cv_exeext" = no && ac_cv_exeext= ++ ++else ++ ac_file='' ++fi ++ ++{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5 ++$as_echo "$ac_file" >&6; } ++if test -z "$ac_file"; then ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables ++See \`config.log' for more details." >&5 ++$as_echo "$as_me: error: C compiler cannot create executables ++See \`config.log' for more details." >&2;} ++ { (exit 77); exit 77; }; }; } ++fi ++ ++ac_exeext=$ac_cv_exeext ++ ++# Check that the compiler produces executables we can run. If not, either ++# the compiler is broken, or we cross compile. ++{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5 ++$as_echo_n "checking whether the C compiler works... " >&6; } ++# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 ++# If not cross compiling, check that we can run a simple program. ++if test "$cross_compiling" != yes; then ++ if { ac_try='./$ac_file' ++ { (case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_try") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ cross_compiling=no ++ else ++ if test "$cross_compiling" = maybe; then ++ cross_compiling=yes ++ else ++ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++{ { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs. ++If you meant to cross compile, use \`--host'. ++See \`config.log' for more details." >&5 ++$as_echo "$as_me: error: cannot run C compiled programs. ++If you meant to cross compile, use \`--host'. ++See \`config.log' for more details." >&2;} ++ { (exit 1); exit 1; }; }; } ++ fi ++ fi ++fi ++{ $as_echo "$as_me:$LINENO: result: yes" >&5 ++$as_echo "yes" >&6; } ++ ++rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ++ac_clean_files=$ac_clean_files_save ++# Check that the compiler produces executables we can run. If not, either ++# the compiler is broken, or we cross compile. ++{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 ++$as_echo_n "checking whether we are cross compiling... " >&6; } ++{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5 ++$as_echo "$cross_compiling" >&6; } ++ ++{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5 ++$as_echo_n "checking for suffix of executables... " >&6; } ++if { (ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_link") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; then ++ # If both `conftest.exe' and `conftest' are `present' (well, observable) ++# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will ++# work properly (i.e., refer to `conftest.exe'), while it won't with ++# `rm'. ++for ac_file in conftest.exe conftest conftest.*; do ++ test -f "$ac_file" || continue ++ case $ac_file in ++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; ++ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` ++ break;; ++ * ) break;; ++ esac ++done ++else ++ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link ++See \`config.log' for more details." >&5 ++$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link ++See \`config.log' for more details." >&2;} ++ { (exit 1); exit 1; }; }; } ++fi ++ ++rm -f conftest$ac_cv_exeext ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 ++$as_echo "$ac_cv_exeext" >&6; } ++ ++rm -f conftest.$ac_ext ++EXEEXT=$ac_cv_exeext ++ac_exeext=$EXEEXT ++{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5 ++$as_echo_n "checking for suffix of object files... " >&6; } ++if test "${ac_cv_objext+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.o conftest.obj ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; then ++ for ac_file in conftest.o conftest.obj conftest.*; do ++ test -f "$ac_file" || continue; ++ case $ac_file in ++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; ++ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` ++ break;; ++ esac ++done ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile ++See \`config.log' for more details." >&5 ++$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile ++See \`config.log' for more details." >&2;} ++ { (exit 1); exit 1; }; }; } ++fi ++ ++rm -f conftest.$ac_cv_objext conftest.$ac_ext ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 ++$as_echo "$ac_cv_objext" >&6; } ++OBJEXT=$ac_cv_objext ++ac_objext=$OBJEXT ++{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 ++$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } ++if test "${ac_cv_c_compiler_gnu+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++#ifndef __GNUC__ ++ choke me ++#endif ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_compiler_gnu=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_compiler_gnu=no ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ac_cv_c_compiler_gnu=$ac_compiler_gnu ++ ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 ++$as_echo "$ac_cv_c_compiler_gnu" >&6; } ++if test $ac_compiler_gnu = yes; then ++ GCC=yes ++else ++ GCC= ++fi ++ac_test_CFLAGS=${CFLAGS+set} ++ac_save_CFLAGS=$CFLAGS ++{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 ++$as_echo_n "checking whether $CC accepts -g... " >&6; } ++if test "${ac_cv_prog_cc_g+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ ac_save_c_werror_flag=$ac_c_werror_flag ++ ac_c_werror_flag=yes ++ ac_cv_prog_cc_g=no ++ CFLAGS="-g" ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_cv_prog_cc_g=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ CFLAGS="" ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ : ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_c_werror_flag=$ac_save_c_werror_flag ++ CFLAGS="-g" ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_cv_prog_cc_g=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ ac_c_werror_flag=$ac_save_c_werror_flag ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 ++$as_echo "$ac_cv_prog_cc_g" >&6; } ++if test "$ac_test_CFLAGS" = set; then ++ CFLAGS=$ac_save_CFLAGS ++elif test $ac_cv_prog_cc_g = yes; then ++ if test "$GCC" = yes; then ++ CFLAGS="-g -O2" ++ else ++ CFLAGS="-g" ++ fi ++else ++ if test "$GCC" = yes; then ++ CFLAGS="-O2" ++ else ++ CFLAGS= ++ fi ++fi ++{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 ++$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } ++if test "${ac_cv_prog_cc_c89+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ ac_cv_prog_cc_c89=no ++ac_save_CC=$CC ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++#include ++#include ++#include ++/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ ++struct buf { int x; }; ++FILE * (*rcsopen) (struct buf *, struct stat *, int); ++static char *e (p, i) ++ char **p; ++ int i; ++{ ++ return p[i]; ++} ++static char *f (char * (*g) (char **, int), char **p, ...) ++{ ++ char *s; ++ va_list v; ++ va_start (v,p); ++ s = g (p, va_arg (v,int)); ++ va_end (v); ++ return s; ++} ++ ++/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has ++ function prototypes and stuff, but not '\xHH' hex character constants. ++ These don't provoke an error unfortunately, instead are silently treated ++ as 'x'. The following induces an error, until -std is added to get ++ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an ++ array size at least. It's necessary to write '\x00'==0 to get something ++ that's true only with -std. */ ++int osf4_cc_array ['\x00' == 0 ? 1 : -1]; ++ ++/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters ++ inside strings and character constants. */ ++#define FOO(x) 'x' ++int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; ++ ++int test (int i, double x); ++struct s1 {int (*f) (int a);}; ++struct s2 {int (*f) (double a);}; ++int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); ++int argc; ++char **argv; ++int ++main () ++{ ++return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ++ ; ++ return 0; ++} ++_ACEOF ++for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ ++ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" ++do ++ CC="$ac_save_CC $ac_arg" ++ rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_cv_prog_cc_c89=$ac_arg ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ++fi ++ ++rm -f core conftest.err conftest.$ac_objext ++ test "x$ac_cv_prog_cc_c89" != "xno" && break ++done ++rm -f conftest.$ac_ext ++CC=$ac_save_CC ++ ++fi ++# AC_CACHE_VAL ++case "x$ac_cv_prog_cc_c89" in ++ x) ++ { $as_echo "$as_me:$LINENO: result: none needed" >&5 ++$as_echo "none needed" >&6; } ;; ++ xno) ++ { $as_echo "$as_me:$LINENO: result: unsupported" >&5 ++$as_echo "unsupported" >&6; } ;; ++ *) ++ CC="$CC $ac_cv_prog_cc_c89" ++ { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 ++$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; ++esac ++ ++ ++ac_ext=c ++ac_cpp='$CPP $CPPFLAGS' ++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_c_compiler_gnu ++ ++# Make sure we can run config.sub. ++$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || ++ { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 ++$as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} ++ { (exit 1); exit 1; }; } ++ ++{ $as_echo "$as_me:$LINENO: checking build system type" >&5 ++$as_echo_n "checking build system type... " >&6; } ++if test "${ac_cv_build+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ ac_build_alias=$build_alias ++test "x$ac_build_alias" = x && ++ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` ++test "x$ac_build_alias" = x && ++ { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 ++$as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;} ++ { (exit 1); exit 1; }; } ++ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || ++ { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 ++$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} ++ { (exit 1); exit 1; }; } ++ ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5 ++$as_echo "$ac_cv_build" >&6; } ++case $ac_cv_build in ++*-*-*) ;; ++*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 ++$as_echo "$as_me: error: invalid value of canonical build" >&2;} ++ { (exit 1); exit 1; }; };; ++esac ++build=$ac_cv_build ++ac_save_IFS=$IFS; IFS='-' ++set x $ac_cv_build ++shift ++build_cpu=$1 ++build_vendor=$2 ++shift; shift ++# Remember, the first character of IFS is used to create $*, ++# except with old shells: ++build_os=$* ++IFS=$ac_save_IFS ++case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac ++ ++ ++{ $as_echo "$as_me:$LINENO: checking host system type" >&5 ++$as_echo_n "checking host system type... " >&6; } ++if test "${ac_cv_host+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ if test "x$host_alias" = x; then ++ ac_cv_host=$ac_cv_build ++else ++ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || ++ { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 ++$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} ++ { (exit 1); exit 1; }; } ++fi ++ ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5 ++$as_echo "$ac_cv_host" >&6; } ++case $ac_cv_host in ++*-*-*) ;; ++*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 ++$as_echo "$as_me: error: invalid value of canonical host" >&2;} ++ { (exit 1); exit 1; }; };; ++esac ++host=$ac_cv_host ++ac_save_IFS=$IFS; IFS='-' ++set x $ac_cv_host ++shift ++host_cpu=$1 ++host_vendor=$2 ++shift; shift ++# Remember, the first character of IFS is used to create $*, ++# except with old shells: ++host_os=$* ++IFS=$ac_save_IFS ++case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac ++ ++ ++ ++ac_ext=c ++ac_cpp='$CPP $CPPFLAGS' ++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_c_compiler_gnu ++{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 ++$as_echo_n "checking how to run the C preprocessor... " >&6; } ++# On Suns, sometimes $CPP names a directory. ++if test -n "$CPP" && test -d "$CPP"; then ++ CPP= ++fi ++if test -z "$CPP"; then ++ if test "${ac_cv_prog_CPP+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ # Double quotes because CPP needs to be expanded ++ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" ++ do ++ ac_preproc_ok=false ++for ac_c_preproc_warn_flag in '' yes ++do ++ # Use a header file that comes with gcc, so configuring glibc ++ # with a fresh cross-compiler works. ++ # Prefer to if __STDC__ is defined, since ++ # exists even on freestanding compilers. ++ # On the NeXT, cc -E runs the code through the compiler's parser, ++ # not just through cpp. "Syntax error" is here to catch this case. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#ifdef __STDC__ ++# include ++#else ++# include ++#endif ++ Syntax error ++_ACEOF ++if { (ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } >/dev/null && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then ++ : ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ # Broken: fails on valid input. ++continue ++fi ++ ++rm -f conftest.err conftest.$ac_ext ++ ++ # OK, works on sane cases. Now check whether nonexistent headers ++ # can be detected and how. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++_ACEOF ++if { (ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } >/dev/null && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then ++ # Broken: success on invalid input. ++continue ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ # Passes both tests. ++ac_preproc_ok=: ++break ++fi ++ ++rm -f conftest.err conftest.$ac_ext ++ ++done ++# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. ++rm -f conftest.err conftest.$ac_ext ++if $ac_preproc_ok; then ++ break ++fi ++ ++ done ++ ac_cv_prog_CPP=$CPP ++ ++fi ++ CPP=$ac_cv_prog_CPP ++else ++ ac_cv_prog_CPP=$CPP ++fi ++{ $as_echo "$as_me:$LINENO: result: $CPP" >&5 ++$as_echo "$CPP" >&6; } ++ac_preproc_ok=false ++for ac_c_preproc_warn_flag in '' yes ++do ++ # Use a header file that comes with gcc, so configuring glibc ++ # with a fresh cross-compiler works. ++ # Prefer to if __STDC__ is defined, since ++ # exists even on freestanding compilers. ++ # On the NeXT, cc -E runs the code through the compiler's parser, ++ # not just through cpp. "Syntax error" is here to catch this case. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#ifdef __STDC__ ++# include ++#else ++# include ++#endif ++ Syntax error ++_ACEOF ++if { (ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } >/dev/null && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then ++ : ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ # Broken: fails on valid input. ++continue ++fi ++ ++rm -f conftest.err conftest.$ac_ext ++ ++ # OK, works on sane cases. Now check whether nonexistent headers ++ # can be detected and how. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++_ACEOF ++if { (ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } >/dev/null && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then ++ # Broken: success on invalid input. ++continue ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ # Passes both tests. ++ac_preproc_ok=: ++break ++fi ++ ++rm -f conftest.err conftest.$ac_ext ++ ++done ++# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. ++rm -f conftest.err conftest.$ac_ext ++if $ac_preproc_ok; then ++ : ++else ++ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check ++See \`config.log' for more details." >&5 ++$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check ++See \`config.log' for more details." >&2;} ++ { (exit 1); exit 1; }; }; } ++fi ++ ++ac_ext=c ++ac_cpp='$CPP $CPPFLAGS' ++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_c_compiler_gnu ++ ++ ++{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 ++$as_echo_n "checking for grep that handles long lines and -e... " >&6; } ++if test "${ac_cv_path_GREP+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ if test -z "$GREP"; then ++ ac_path_GREP_found=false ++ # Loop through the user's path and test for each of PROGNAME-LIST ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_prog in grep ggrep; do ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" ++ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue ++# Check for GNU ac_path_GREP and select it if it is found. ++ # Check for GNU $ac_path_GREP ++case `"$ac_path_GREP" --version 2>&1` in ++*GNU*) ++ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; ++*) ++ ac_count=0 ++ $as_echo_n 0123456789 >"conftest.in" ++ while : ++ do ++ cat "conftest.in" "conftest.in" >"conftest.tmp" ++ mv "conftest.tmp" "conftest.in" ++ cp "conftest.in" "conftest.nl" ++ $as_echo 'GREP' >> "conftest.nl" ++ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break ++ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break ++ ac_count=`expr $ac_count + 1` ++ if test $ac_count -gt ${ac_path_GREP_max-0}; then ++ # Best one so far, save it but keep looking for a better one ++ ac_cv_path_GREP="$ac_path_GREP" ++ ac_path_GREP_max=$ac_count ++ fi ++ # 10*(2^10) chars as input seems more than enough ++ test $ac_count -gt 10 && break ++ done ++ rm -f conftest.in conftest.tmp conftest.nl conftest.out;; ++esac ++ ++ $ac_path_GREP_found && break 3 ++ done ++ done ++done ++IFS=$as_save_IFS ++ if test -z "$ac_cv_path_GREP"; then ++ { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 ++$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} ++ { (exit 1); exit 1; }; } ++ fi ++else ++ ac_cv_path_GREP=$GREP ++fi ++ ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 ++$as_echo "$ac_cv_path_GREP" >&6; } ++ GREP="$ac_cv_path_GREP" ++ ++ ++{ $as_echo "$as_me:$LINENO: checking for egrep" >&5 ++$as_echo_n "checking for egrep... " >&6; } ++if test "${ac_cv_path_EGREP+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 ++ then ac_cv_path_EGREP="$GREP -E" ++ else ++ if test -z "$EGREP"; then ++ ac_path_EGREP_found=false ++ # Loop through the user's path and test for each of PROGNAME-LIST ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_prog in egrep; do ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" ++ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue ++# Check for GNU ac_path_EGREP and select it if it is found. ++ # Check for GNU $ac_path_EGREP ++case `"$ac_path_EGREP" --version 2>&1` in ++*GNU*) ++ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; ++*) ++ ac_count=0 ++ $as_echo_n 0123456789 >"conftest.in" ++ while : ++ do ++ cat "conftest.in" "conftest.in" >"conftest.tmp" ++ mv "conftest.tmp" "conftest.in" ++ cp "conftest.in" "conftest.nl" ++ $as_echo 'EGREP' >> "conftest.nl" ++ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break ++ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break ++ ac_count=`expr $ac_count + 1` ++ if test $ac_count -gt ${ac_path_EGREP_max-0}; then ++ # Best one so far, save it but keep looking for a better one ++ ac_cv_path_EGREP="$ac_path_EGREP" ++ ac_path_EGREP_max=$ac_count ++ fi ++ # 10*(2^10) chars as input seems more than enough ++ test $ac_count -gt 10 && break ++ done ++ rm -f conftest.in conftest.tmp conftest.nl conftest.out;; ++esac ++ ++ $ac_path_EGREP_found && break 3 ++ done ++ done ++done ++IFS=$as_save_IFS ++ if test -z "$ac_cv_path_EGREP"; then ++ { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 ++$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} ++ { (exit 1); exit 1; }; } ++ fi ++else ++ ac_cv_path_EGREP=$EGREP ++fi ++ ++ fi ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 ++$as_echo "$ac_cv_path_EGREP" >&6; } ++ EGREP="$ac_cv_path_EGREP" ++ ++ ++{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5 ++$as_echo_n "checking for ANSI C header files... " >&6; } ++if test "${ac_cv_header_stdc+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++#include ++#include ++#include ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_cv_header_stdc=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_cv_header_stdc=no ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ ++if test $ac_cv_header_stdc = yes; then ++ # SunOS 4.x string.h does not declare mem*, contrary to ANSI. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ ++_ACEOF ++if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | ++ $EGREP "memchr" >/dev/null 2>&1; then ++ : ++else ++ ac_cv_header_stdc=no ++fi ++rm -f conftest* ++ ++fi ++ ++if test $ac_cv_header_stdc = yes; then ++ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ ++_ACEOF ++if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | ++ $EGREP "free" >/dev/null 2>&1; then ++ : ++else ++ ac_cv_header_stdc=no ++fi ++rm -f conftest* ++ ++fi ++ ++if test $ac_cv_header_stdc = yes; then ++ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. ++ if test "$cross_compiling" = yes; then ++ : ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++#include ++#if ((' ' & 0x0FF) == 0x020) ++# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') ++# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) ++#else ++# define ISLOWER(c) \ ++ (('a' <= (c) && (c) <= 'i') \ ++ || ('j' <= (c) && (c) <= 'r') \ ++ || ('s' <= (c) && (c) <= 'z')) ++# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) ++#endif ++ ++#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) ++int ++main () ++{ ++ int i; ++ for (i = 0; i < 256; i++) ++ if (XOR (islower (i), ISLOWER (i)) ++ || toupper (i) != TOUPPER (i)) ++ return 2; ++ return 0; ++} ++_ACEOF ++rm -f conftest$ac_exeext ++if { (ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_link") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ac_try='./conftest$ac_exeext' ++ { (case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_try") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ : ++else ++ $as_echo "$as_me: program exited with status $ac_status" >&5 ++$as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++( exit $ac_status ) ++ac_cv_header_stdc=no ++fi ++rm -rf conftest.dSYM ++rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext ++fi ++ ++ ++fi ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 ++$as_echo "$ac_cv_header_stdc" >&6; } ++if test $ac_cv_header_stdc = yes; then ++ ++cat >>confdefs.h <<\_ACEOF ++#define STDC_HEADERS 1 ++_ACEOF ++ ++fi ++ ++# On IRIX 5.3, sys/types and inttypes.h are conflicting. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ ++ inttypes.h stdint.h unistd.h ++do ++as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ++{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 ++$as_echo_n "checking for $ac_header... " >&6; } ++if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then ++ $as_echo_n "(cached) " >&6 ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++$ac_includes_default ++ ++#include <$ac_header> ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ eval "$as_ac_Header=yes" ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ eval "$as_ac_Header=no" ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++ac_res=`eval 'as_val=${'$as_ac_Header'} ++ $as_echo "$as_val"'` ++ { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++as_val=`eval 'as_val=${'$as_ac_Header'} ++ $as_echo "$as_val"'` ++ if test "x$as_val" = x""yes; then ++ cat >>confdefs.h <<_ACEOF ++#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 ++_ACEOF ++ ++fi ++ ++done ++ ++ ++ ++ { $as_echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 ++$as_echo_n "checking whether byte ordering is bigendian... " >&6; } ++if test "${ac_cv_c_bigendian+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ ac_cv_c_bigendian=unknown ++ # See if we're dealing with a universal compiler. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#ifndef __APPLE_CC__ ++ not a universal capable compiler ++ #endif ++ typedef int dummy; ++ ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ++ # Check for potential -arch flags. It is not universal unless ++ # there are some -arch flags. Note that *ppc* also matches ++ # ppc64. This check is also rather less than ideal. ++ case "${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS}" in #( ++ *-arch*ppc*|*-arch*i386*|*-arch*x86_64*) ac_cv_c_bigendian=universal;; ++ esac ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ if test $ac_cv_c_bigendian = unknown; then ++ # See if sys/param.h defines the BYTE_ORDER macro. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ #include ++ ++int ++main () ++{ ++#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ ++ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ ++ && LITTLE_ENDIAN) ++ bogus endian macros ++ #endif ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ # It does; now see whether it defined to BIG_ENDIAN or not. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ #include ++ ++int ++main () ++{ ++#if BYTE_ORDER != BIG_ENDIAN ++ not big endian ++ #endif ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_cv_c_bigendian=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_cv_c_bigendian=no ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ fi ++ if test $ac_cv_c_bigendian = unknown; then ++ # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ ++int ++main () ++{ ++#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) ++ bogus endian macros ++ #endif ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ # It does; now see whether it defined to _BIG_ENDIAN or not. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ ++int ++main () ++{ ++#ifndef _BIG_ENDIAN ++ not big endian ++ #endif ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_cv_c_bigendian=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_cv_c_bigendian=no ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ fi ++ if test $ac_cv_c_bigendian = unknown; then ++ # Compile a test program. ++ if test "$cross_compiling" = yes; then ++ # Try to guess by grepping values from an object file. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++short int ascii_mm[] = ++ { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; ++ short int ascii_ii[] = ++ { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; ++ int use_ascii (int i) { ++ return ascii_mm[i] + ascii_ii[i]; ++ } ++ short int ebcdic_ii[] = ++ { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; ++ short int ebcdic_mm[] = ++ { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; ++ int use_ebcdic (int i) { ++ return ebcdic_mm[i] + ebcdic_ii[i]; ++ } ++ extern int foo; ++ ++int ++main () ++{ ++return use_ascii (foo) == use_ebcdic (foo); ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ++ ac_cv_c_bigendian=yes ++ fi ++ if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then ++ if test "$ac_cv_c_bigendian" = unknown; then ++ ac_cv_c_bigendian=no ++ else ++ # finding both strings is unlikely to happen, but who knows? ++ ac_cv_c_bigendian=unknown ++ fi ++ fi ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++$ac_includes_default ++int ++main () ++{ ++ ++ /* Are we little or big endian? From Harbison&Steele. */ ++ union ++ { ++ long int l; ++ char c[sizeof (long int)]; ++ } u; ++ u.l = 1; ++ return u.c[sizeof (long int) - 1] == 1; ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest$ac_exeext ++if { (ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_link") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ac_try='./conftest$ac_exeext' ++ { (case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_try") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ ac_cv_c_bigendian=no ++else ++ $as_echo "$as_me: program exited with status $ac_status" >&5 ++$as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++( exit $ac_status ) ++ac_cv_c_bigendian=yes ++fi ++rm -rf conftest.dSYM ++rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext ++fi ++ ++ ++ fi ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 ++$as_echo "$ac_cv_c_bigendian" >&6; } ++ case $ac_cv_c_bigendian in #( ++ yes) ++ cat >>confdefs.h <<\_ACEOF ++#define WORDS_BIGENDIAN 1 ++_ACEOF ++;; #( ++ no) ++ ;; #( ++ universal) ++ ++cat >>confdefs.h <<\_ACEOF ++#define AC_APPLE_UNIVERSAL_BUILD 1 ++_ACEOF ++ ++ ;; #( ++ *) ++ { { $as_echo "$as_me:$LINENO: error: unknown endianness ++ presetting ac_cv_c_bigendian=no (or yes) will help" >&5 ++$as_echo "$as_me: error: unknown endianness ++ presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} ++ { (exit 1); exit 1; }; } ;; ++ esac ++ ++ ++ac_ext=c ++ac_cpp='$CPP $CPPFLAGS' ++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_c_compiler_gnu ++{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 ++$as_echo_n "checking how to run the C preprocessor... " >&6; } ++# On Suns, sometimes $CPP names a directory. ++if test -n "$CPP" && test -d "$CPP"; then ++ CPP= ++fi ++if test -z "$CPP"; then ++ if test "${ac_cv_prog_CPP+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ # Double quotes because CPP needs to be expanded ++ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" ++ do ++ ac_preproc_ok=false ++for ac_c_preproc_warn_flag in '' yes ++do ++ # Use a header file that comes with gcc, so configuring glibc ++ # with a fresh cross-compiler works. ++ # Prefer to if __STDC__ is defined, since ++ # exists even on freestanding compilers. ++ # On the NeXT, cc -E runs the code through the compiler's parser, ++ # not just through cpp. "Syntax error" is here to catch this case. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#ifdef __STDC__ ++# include ++#else ++# include ++#endif ++ Syntax error ++_ACEOF ++if { (ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } >/dev/null && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then ++ : ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ # Broken: fails on valid input. ++continue ++fi ++ ++rm -f conftest.err conftest.$ac_ext ++ ++ # OK, works on sane cases. Now check whether nonexistent headers ++ # can be detected and how. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++_ACEOF ++if { (ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } >/dev/null && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then ++ # Broken: success on invalid input. ++continue ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ # Passes both tests. ++ac_preproc_ok=: ++break ++fi ++ ++rm -f conftest.err conftest.$ac_ext ++ ++done ++# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. ++rm -f conftest.err conftest.$ac_ext ++if $ac_preproc_ok; then ++ break ++fi ++ ++ done ++ ac_cv_prog_CPP=$CPP ++ ++fi ++ CPP=$ac_cv_prog_CPP ++else ++ ac_cv_prog_CPP=$CPP ++fi ++{ $as_echo "$as_me:$LINENO: result: $CPP" >&5 ++$as_echo "$CPP" >&6; } ++ac_preproc_ok=false ++for ac_c_preproc_warn_flag in '' yes ++do ++ # Use a header file that comes with gcc, so configuring glibc ++ # with a fresh cross-compiler works. ++ # Prefer to if __STDC__ is defined, since ++ # exists even on freestanding compilers. ++ # On the NeXT, cc -E runs the code through the compiler's parser, ++ # not just through cpp. "Syntax error" is here to catch this case. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#ifdef __STDC__ ++# include ++#else ++# include ++#endif ++ Syntax error ++_ACEOF ++if { (ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } >/dev/null && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then ++ : ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ # Broken: fails on valid input. ++continue ++fi ++ ++rm -f conftest.err conftest.$ac_ext ++ ++ # OK, works on sane cases. Now check whether nonexistent headers ++ # can be detected and how. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++_ACEOF ++if { (ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } >/dev/null && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then ++ # Broken: success on invalid input. ++continue ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ # Passes both tests. ++ac_preproc_ok=: ++break ++fi ++ ++rm -f conftest.err conftest.$ac_ext ++ ++done ++# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. ++rm -f conftest.err conftest.$ac_ext ++if $ac_preproc_ok; then ++ : ++else ++ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check ++See \`config.log' for more details." >&5 ++$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check ++See \`config.log' for more details." >&2;} ++ { (exit 1); exit 1; }; }; } ++fi ++ ++ac_ext=c ++ac_cpp='$CPP $CPPFLAGS' ++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_c_compiler_gnu ++ ++# Find a good install program. We prefer a C program (faster), ++# so one script is as good as another. But avoid the broken or ++# incompatible versions: ++# SysV /etc/install, /usr/sbin/install ++# SunOS /usr/etc/install ++# IRIX /sbin/install ++# AIX /bin/install ++# AmigaOS /C/install, which installs bootblocks on floppy discs ++# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag ++# AFS /usr/afsws/bin/install, which mishandles nonexistent args ++# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" ++# OS/2's system install, which has a completely different semantic ++# ./install, which can be erroneously created by make from ./install.sh. ++# Reject install programs that cannot install multiple files. ++{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 ++$as_echo_n "checking for a BSD-compatible install... " >&6; } ++if test -z "$INSTALL"; then ++if test "${ac_cv_path_install+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ # Account for people who put trailing slashes in PATH elements. ++case $as_dir/ in ++ ./ | .// | /cC/* | \ ++ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ++ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ ++ /usr/ucb/* ) ;; ++ *) ++ # OSF1 and SCO ODT 3.0 have their own names for install. ++ # Don't use installbsd from OSF since it installs stuff as root ++ # by default. ++ for ac_prog in ginstall scoinst install; do ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then ++ if test $ac_prog = install && ++ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then ++ # AIX install. It has an incompatible calling convention. ++ : ++ elif test $ac_prog = install && ++ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then ++ # program-specific install script used by HP pwplus--don't use. ++ : ++ else ++ rm -rf conftest.one conftest.two conftest.dir ++ echo one > conftest.one ++ echo two > conftest.two ++ mkdir conftest.dir ++ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && ++ test -s conftest.one && test -s conftest.two && ++ test -s conftest.dir/conftest.one && ++ test -s conftest.dir/conftest.two ++ then ++ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" ++ break 3 ++ fi ++ fi ++ fi ++ done ++ done ++ ;; ++esac ++ ++done ++IFS=$as_save_IFS ++ ++rm -rf conftest.one conftest.two conftest.dir ++ ++fi ++ if test "${ac_cv_path_install+set}" = set; then ++ INSTALL=$ac_cv_path_install ++ else ++ # As a last resort, use the slow shell script. Don't cache a ++ # value for INSTALL within a source directory, because that will ++ # break other packages using the cache if that directory is ++ # removed, or if the value is a relative name. ++ INSTALL=$ac_install_sh ++ fi ++fi ++{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5 ++$as_echo "$INSTALL" >&6; } ++ ++# Use test -z because SunOS4 sh mishandles braces in ${var-val}. ++# It thinks the first close brace ends the variable substitution. ++test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' ++ ++test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' ++ ++test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' ++ ++{ $as_echo "$as_me:$LINENO: checking whether ln -s works" >&5 ++$as_echo_n "checking whether ln -s works... " >&6; } ++LN_S=$as_ln_s ++if test "$LN_S" = "ln -s"; then ++ { $as_echo "$as_me:$LINENO: result: yes" >&5 ++$as_echo "yes" >&6; } ++else ++ { $as_echo "$as_me:$LINENO: result: no, using $LN_S" >&5 ++$as_echo "no, using $LN_S" >&6; } ++fi ++ ++{ $as_echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 ++$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } ++set x ${MAKE-make} ++ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` ++if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then ++ $as_echo_n "(cached) " >&6 ++else ++ cat >conftest.make <<\_ACEOF ++SHELL = /bin/sh ++all: ++ @echo '@@@%%%=$(MAKE)=@@@%%%' ++_ACEOF ++# GNU make sometimes prints "make[1]: Entering...", which would confuse us. ++case `${MAKE-make} -f conftest.make 2>/dev/null` in ++ *@@@%%%=?*=@@@%%%*) ++ eval ac_cv_prog_make_${ac_make}_set=yes;; ++ *) ++ eval ac_cv_prog_make_${ac_make}_set=no;; ++esac ++rm -f conftest.make ++fi ++if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then ++ { $as_echo "$as_me:$LINENO: result: yes" >&5 ++$as_echo "yes" >&6; } ++ SET_MAKE= ++else ++ { $as_echo "$as_me:$LINENO: result: no" >&5 ++$as_echo "no" >&6; } ++ SET_MAKE="MAKE=${MAKE-make}" ++fi ++ ++# Extract the first word of "sh", so it can be a program name with args. ++set dummy sh; ac_word=$2 ++{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if test "${ac_cv_path_SH+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ case $SH in ++ [\\/]* | ?:[\\/]*) ++ ac_cv_path_SH="$SH" # Let the user override the test with a path. ++ ;; ++ *) ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ ac_cv_path_SH="$as_dir/$ac_word$ac_exec_ext" ++ $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++done ++IFS=$as_save_IFS ++ ++ ;; ++esac ++fi ++SH=$ac_cv_path_SH ++if test -n "$SH"; then ++ { $as_echo "$as_me:$LINENO: result: $SH" >&5 ++$as_echo "$SH" >&6; } ++else ++ { $as_echo "$as_me:$LINENO: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ ++{ $as_echo "$as_me:$LINENO: checking for inline" >&5 ++$as_echo_n "checking for inline... " >&6; } ++if test "${ac_cv_c_inline+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ ac_cv_c_inline=no ++for ac_kw in inline __inline__ __inline; do ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#ifndef __cplusplus ++typedef int foo_t; ++static $ac_kw foo_t static_foo () {return 0; } ++$ac_kw foo_t foo () {return 0; } ++#endif ++ ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_cv_c_inline=$ac_kw ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ test "$ac_cv_c_inline" != no && break ++done ++ ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 ++$as_echo "$ac_cv_c_inline" >&6; } ++ ++ ++case $ac_cv_c_inline in ++ inline | yes) ;; ++ *) ++ case $ac_cv_c_inline in ++ no) ac_val=;; ++ *) ac_val=$ac_cv_c_inline;; ++ esac ++ cat >>confdefs.h <<_ACEOF ++#ifndef __cplusplus ++#define inline $ac_val ++#endif ++_ACEOF ++ ;; ++esac ++ ++if test "$GCC" = "yes"; then ++ CFLAGS="-Wall -fno-strict-aliasing $CFLAGS" ++ CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" ++fi ++ ++{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5 ++$as_echo_n "checking for ANSI C header files... " >&6; } ++if test "${ac_cv_header_stdc+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++#include ++#include ++#include ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_cv_header_stdc=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_cv_header_stdc=no ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ ++if test $ac_cv_header_stdc = yes; then ++ # SunOS 4.x string.h does not declare mem*, contrary to ANSI. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ ++_ACEOF ++if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | ++ $EGREP "memchr" >/dev/null 2>&1; then ++ : ++else ++ ac_cv_header_stdc=no ++fi ++rm -f conftest* ++ ++fi ++ ++if test $ac_cv_header_stdc = yes; then ++ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++ ++_ACEOF ++if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | ++ $EGREP "free" >/dev/null 2>&1; then ++ : ++else ++ ac_cv_header_stdc=no ++fi ++rm -f conftest* ++ ++fi ++ ++if test $ac_cv_header_stdc = yes; then ++ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. ++ if test "$cross_compiling" = yes; then ++ : ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++#include ++#if ((' ' & 0x0FF) == 0x020) ++# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') ++# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) ++#else ++# define ISLOWER(c) \ ++ (('a' <= (c) && (c) <= 'i') \ ++ || ('j' <= (c) && (c) <= 'r') \ ++ || ('s' <= (c) && (c) <= 'z')) ++# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) ++#endif ++ ++#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) ++int ++main () ++{ ++ int i; ++ for (i = 0; i < 256; i++) ++ if (XOR (islower (i), ISLOWER (i)) ++ || toupper (i) != TOUPPER (i)) ++ return 2; ++ return 0; ++} ++_ACEOF ++rm -f conftest$ac_exeext ++if { (ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_link") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ac_try='./conftest$ac_exeext' ++ { (case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_try") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); }; }; then ++ : ++else ++ $as_echo "$as_me: program exited with status $ac_status" >&5 ++$as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++( exit $ac_status ) ++ac_cv_header_stdc=no ++fi ++rm -rf conftest.dSYM ++rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext ++fi ++ ++ ++fi ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 ++$as_echo "$ac_cv_header_stdc" >&6; } ++if test $ac_cv_header_stdc = yes; then ++ ++cat >>confdefs.h <<\_ACEOF ++#define STDC_HEADERS 1 ++_ACEOF ++ ++fi ++ ++{ $as_echo "$as_me:$LINENO: checking for sys/wait.h that is POSIX.1 compatible" >&5 ++$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } ++if test "${ac_cv_header_sys_wait_h+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include ++#include ++#ifndef WEXITSTATUS ++# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) ++#endif ++#ifndef WIFEXITED ++# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) ++#endif ++ ++int ++main () ++{ ++ int s; ++ wait (&s); ++ s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_cv_header_sys_wait_h=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_cv_header_sys_wait_h=no ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5 ++$as_echo "$ac_cv_header_sys_wait_h" >&6; } ++if test $ac_cv_header_sys_wait_h = yes; then ++ ++cat >>confdefs.h <<\_ACEOF ++#define HAVE_SYS_WAIT_H 1 ++_ACEOF ++ ++fi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++for ac_header in errno.h fcntl.h malloc.h stdlib.h string.h strings.h sys/time.h unistd.h locale.h getopt.h ++do ++as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ++if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then ++ { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 ++$as_echo_n "checking for $ac_header... " >&6; } ++if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then ++ $as_echo_n "(cached) " >&6 ++fi ++ac_res=`eval 'as_val=${'$as_ac_Header'} ++ $as_echo "$as_val"'` ++ { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++else ++ # Is the header compilable? ++{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 ++$as_echo_n "checking $ac_header usability... " >&6; } ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++$ac_includes_default ++#include <$ac_header> ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_header_compiler=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_header_compiler=no ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 ++$as_echo "$ac_header_compiler" >&6; } ++ ++# Is the header present? ++{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 ++$as_echo_n "checking $ac_header presence... " >&6; } ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include <$ac_header> ++_ACEOF ++if { (ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } >/dev/null && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then ++ ac_header_preproc=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_header_preproc=no ++fi ++ ++rm -f conftest.err conftest.$ac_ext ++{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 ++$as_echo "$ac_header_preproc" >&6; } ++ ++# So? What about this header? ++case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in ++ yes:no: ) ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 ++$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 ++$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ++ ac_header_preproc=yes ++ ;; ++ no:yes:* ) ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 ++$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 ++$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 ++$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 ++$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 ++$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 ++$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ++ ++ ;; ++esac ++{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 ++$as_echo_n "checking for $ac_header... " >&6; } ++if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then ++ $as_echo_n "(cached) " >&6 ++else ++ eval "$as_ac_Header=\$ac_header_preproc" ++fi ++ac_res=`eval 'as_val=${'$as_ac_Header'} ++ $as_echo "$as_val"'` ++ { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++ ++fi ++as_val=`eval 'as_val=${'$as_ac_Header'} ++ $as_echo "$as_val"'` ++ if test "x$as_val" = x""yes; then ++ cat >>confdefs.h <<_ACEOF ++#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 ++_ACEOF ++ ++fi ++ ++done ++ ++ ++# Check if socket() is in libsocket ++{ $as_echo "$as_me:$LINENO: checking for socket in -lsocket" >&5 ++$as_echo_n "checking for socket in -lsocket... " >&6; } ++if test "${ac_cv_lib_socket_socket+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-lsocket $LIBS" ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char socket (); ++int ++main () ++{ ++return socket (); ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext conftest$ac_exeext ++if { (ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_link") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest$ac_exeext && { ++ test "$cross_compiling" = yes || ++ $as_test_x conftest$ac_exeext ++ }; then ++ ac_cv_lib_socket_socket=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_cv_lib_socket_socket=no ++fi ++ ++rm -rf conftest.dSYM ++rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5 ++$as_echo "$ac_cv_lib_socket_socket" >&6; } ++if test "x$ac_cv_lib_socket_socket" = x""yes; then ++ LIBS="$LIBS -lsocket" ++fi ++ ++ ++ ++ ++{ $as_echo "$as_me:$LINENO: checking for getopt_long" >&5 ++$as_echo_n "checking for getopt_long... " >&6; } ++if test "${ac_cv_func_getopt_long+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++/* Define getopt_long to an innocuous variant, in case declares getopt_long. ++ For example, HP-UX 11i declares gettimeofday. */ ++#define getopt_long innocuous_getopt_long ++ ++/* System header to define __stub macros and hopefully few prototypes, ++ which can conflict with char getopt_long (); below. ++ Prefer to if __STDC__ is defined, since ++ exists even on freestanding compilers. */ ++ ++#ifdef __STDC__ ++# include ++#else ++# include ++#endif ++ ++#undef getopt_long ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char getopt_long (); ++/* The GNU C library defines this for functions which it implements ++ to always fail with ENOSYS. Some functions are actually named ++ something starting with __ and the normal name is an alias. */ ++#if defined __stub_getopt_long || defined __stub___getopt_long ++choke me ++#endif ++ ++int ++main () ++{ ++return getopt_long (); ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext conftest$ac_exeext ++if { (ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_link") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest$ac_exeext && { ++ test "$cross_compiling" = yes || ++ $as_test_x conftest$ac_exeext ++ }; then ++ ac_cv_func_getopt_long=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_cv_func_getopt_long=no ++fi ++ ++rm -rf conftest.dSYM ++rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ ++ conftest$ac_exeext conftest.$ac_ext ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_getopt_long" >&5 ++$as_echo "$ac_cv_func_getopt_long" >&6; } ++if test "x$ac_cv_func_getopt_long" = x""yes; then ++ ++cat >>confdefs.h <<\_ACEOF ++#define HAVE_GETOPT_LONG 1 ++_ACEOF ++ ++else ++ GETOPTSRC="$GETOPTSRC \$(top_srcdir)/compat/my_getopt.c" ++ CPPFLAGS="-I\$(top_srcdir)/compat/ $CPPFLAGS" ++ ++cat >>confdefs.h <<\_ACEOF ++#define HAVE_GETOPT_H 1 ++_ACEOF ++ ++fi ++ ++ ++WITH_SECURITY=maybe ++ ++# Check whether --with-security was given. ++if test "${with_security+set}" = set; then ++ withval=$with_security; ++ if test "x$withval" = "xno" -o "x$withval" = "xyes"; then ++ WITH_SECURITY=$withval ++ else ++ WITH_SECURITY=yes ++ CPPFLAGS="$CPPFLAGS -I${withval}" ++ LDFLAGS="$LDFLAGS -L${withval}" ++ fi ++ ++ ++fi ++ ++ ++if test "x$WITH_SECURITY" != "xno" ; then ++ # Check for openssl support - very primitive, we just ++ # check for the presence of crypto.h ++ ++for ac_header in openssl/crypto.h ++do ++as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ++if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then ++ { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 ++$as_echo_n "checking for $ac_header... " >&6; } ++if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then ++ $as_echo_n "(cached) " >&6 ++fi ++ac_res=`eval 'as_val=${'$as_ac_Header'} ++ $as_echo "$as_val"'` ++ { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++else ++ # Is the header compilable? ++{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 ++$as_echo_n "checking $ac_header usability... " >&6; } ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++$ac_includes_default ++#include <$ac_header> ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_header_compiler=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_header_compiler=no ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 ++$as_echo "$ac_header_compiler" >&6; } ++ ++# Is the header present? ++{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 ++$as_echo_n "checking $ac_header presence... " >&6; } ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include <$ac_header> ++_ACEOF ++if { (ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } >/dev/null && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then ++ ac_header_preproc=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_header_preproc=no ++fi ++ ++rm -f conftest.err conftest.$ac_ext ++{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 ++$as_echo "$ac_header_preproc" >&6; } ++ ++# So? What about this header? ++case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in ++ yes:no: ) ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 ++$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 ++$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ++ ac_header_preproc=yes ++ ;; ++ no:yes:* ) ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 ++$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 ++$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 ++$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 ++$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 ++$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 ++$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ++ ++ ;; ++esac ++{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 ++$as_echo_n "checking for $ac_header... " >&6; } ++if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then ++ $as_echo_n "(cached) " >&6 ++else ++ eval "$as_ac_Header=\$ac_header_preproc" ++fi ++ac_res=`eval 'as_val=${'$as_ac_Header'} ++ $as_echo "$as_val"'` ++ { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++ ++fi ++as_val=`eval 'as_val=${'$as_ac_Header'} ++ $as_echo "$as_val"'` ++ if test "x$as_val" = x""yes; then ++ cat >>confdefs.h <<_ACEOF ++#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 ++_ACEOF ++ ++else ++ have_libcrypto=no ++fi ++ ++done ++ ++ { $as_echo "$as_me:$LINENO: checking for EVP_PKEY_new in -lcrypto" >&5 ++$as_echo_n "checking for EVP_PKEY_new in -lcrypto... " >&6; } ++if test "${ac_cv_lib_crypto_EVP_PKEY_new+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-lcrypto $LIBS" ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char EVP_PKEY_new (); ++int ++main () ++{ ++return EVP_PKEY_new (); ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext conftest$ac_exeext ++if { (ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_link") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest$ac_exeext && { ++ test "$cross_compiling" = yes || ++ $as_test_x conftest$ac_exeext ++ }; then ++ ac_cv_lib_crypto_EVP_PKEY_new=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_cv_lib_crypto_EVP_PKEY_new=no ++fi ++ ++rm -rf conftest.dSYM ++rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_EVP_PKEY_new" >&5 ++$as_echo "$ac_cv_lib_crypto_EVP_PKEY_new" >&6; } ++if test "x$ac_cv_lib_crypto_EVP_PKEY_new" = x""yes; then ++ SECLIBS="-lcrypto" ++else ++ have_libcrypto=no ++fi ++ ++ ++ if test "x$have_libcrypto" != "xno" ; then ++ ++cat >>confdefs.h <<\_ACEOF ++#define WITH_SECURITY 1 ++_ACEOF ++ ++ else ++ if test "x$WITH_SECURITY" = "xyes" ; then ++ { { $as_echo "$as_me:$LINENO: error: Security requested, but unable to find libcrypto" >&5 ++$as_echo "$as_me: error: Security requested, but unable to find libcrypto" >&2;} ++ { (exit 1); exit 1; }; } ++ fi ++ fi ++fi ++ ++ ++WITH_SLP=maybe ++ ++# Check whether --with-slp was given. ++if test "${with_slp+set}" = set; then ++ withval=$with_slp; ++ if test "x$withval" = "xno" -o "x$withval" = "xyes"; then ++ WITH_SLP=$withval ++ else ++ WITH_SLP=yes ++ CPPFLAGS="$CPPFLAGS -I${withval}" ++ LDFLAGS="$LDFLAGS -L${withval}" ++ fi ++ ++ ++fi ++ ++ ++if test "x$WITH_SLP" != "xno" ; then ++ # Check for openslp support - very primitive ++ ++for ac_header in slp.h ++do ++as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ++if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then ++ { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 ++$as_echo_n "checking for $ac_header... " >&6; } ++if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then ++ $as_echo_n "(cached) " >&6 ++fi ++ac_res=`eval 'as_val=${'$as_ac_Header'} ++ $as_echo "$as_val"'` ++ { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++else ++ # Is the header compilable? ++{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 ++$as_echo_n "checking $ac_header usability... " >&6; } ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++$ac_includes_default ++#include <$ac_header> ++_ACEOF ++rm -f conftest.$ac_objext ++if { (ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_compile") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then ++ ac_header_compiler=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_header_compiler=no ++fi ++ ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 ++$as_echo "$ac_header_compiler" >&6; } ++ ++# Is the header present? ++{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 ++$as_echo_n "checking $ac_header presence... " >&6; } ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++#include <$ac_header> ++_ACEOF ++if { (ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } >/dev/null && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then ++ ac_header_preproc=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_header_preproc=no ++fi ++ ++rm -f conftest.err conftest.$ac_ext ++{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 ++$as_echo "$ac_header_preproc" >&6; } ++ ++# So? What about this header? ++case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in ++ yes:no: ) ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 ++$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 ++$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ++ ac_header_preproc=yes ++ ;; ++ no:yes:* ) ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 ++$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 ++$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 ++$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 ++$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 ++$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 ++$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ++ ++ ;; ++esac ++{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 ++$as_echo_n "checking for $ac_header... " >&6; } ++if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then ++ $as_echo_n "(cached) " >&6 ++else ++ eval "$as_ac_Header=\$ac_header_preproc" ++fi ++ac_res=`eval 'as_val=${'$as_ac_Header'} ++ $as_echo "$as_val"'` ++ { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++ ++fi ++as_val=`eval 'as_val=${'$as_ac_Header'} ++ $as_echo "$as_val"'` ++ if test "x$as_val" = x""yes; then ++ cat >>confdefs.h <<_ACEOF ++#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 ++_ACEOF ++ ++else ++ have_openslp=no ++fi ++ ++done ++ ++ { $as_echo "$as_me:$LINENO: checking for SLPOpen in -lslp" >&5 ++$as_echo_n "checking for SLPOpen in -lslp... " >&6; } ++if test "${ac_cv_lib_slp_SLPOpen+set}" = set; then ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-lslp $LIBS" ++cat >conftest.$ac_ext <<_ACEOF ++/* confdefs.h. */ ++_ACEOF ++cat confdefs.h >>conftest.$ac_ext ++cat >>conftest.$ac_ext <<_ACEOF ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char SLPOpen (); ++int ++main () ++{ ++return SLPOpen (); ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.$ac_objext conftest$ac_exeext ++if { (ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" ++$as_echo "$ac_try_echo") >&5 ++ (eval "$ac_link") 2>conftest.er1 ++ ac_status=$? ++ grep -v '^ *+' conftest.er1 >conftest.err ++ rm -f conftest.er1 ++ cat conftest.err >&5 ++ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest$ac_exeext && { ++ test "$cross_compiling" = yes || ++ $as_test_x conftest$ac_exeext ++ }; then ++ ac_cv_lib_slp_SLPOpen=yes ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_cv_lib_slp_SLPOpen=no ++fi ++ ++rm -rf conftest.dSYM ++rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_slp_SLPOpen" >&5 ++$as_echo "$ac_cv_lib_slp_SLPOpen" >&6; } ++if test "x$ac_cv_lib_slp_SLPOpen" = x""yes; then ++ SLPLIBS="-lslp" ++else ++ have_openslp=no ++fi ++ ++ ++ if test "x$have_openslp" != "xno" ; then ++ ++cat >>confdefs.h <<\_ACEOF ++#define WITH_SLP 1 ++_ACEOF ++ ++ else ++ if test "x$WITH_SLP" = "xyes" ; then ++ { { $as_echo "$as_me:$LINENO: error: SLP requested, but unable to find openslp" >&5 ++$as_echo "$as_me: error: SLP requested, but unable to find openslp" >&2;} ++ { (exit 1); exit 1; }; } ++ fi ++ fi ++fi ++ ++ ++MEMDEBUG= ++# Check whether --enable-memdebug was given. ++if test "${enable_memdebug+set}" = set; then ++ enableval=$enable_memdebug; ++ if test "x$enableval" = "xyes" ; then ++ CPPFLAGS="$CPPFLAGS -DMEMDEBUG" ++ fi ++ ++ ++fi ++ ++ ++ ++ac_config_files="$ac_config_files Makefile" ++ ++cat >confcache <<\_ACEOF ++# This file is a shell script that caches the results of configure ++# tests run on this system so they can be shared between configure ++# scripts and configure runs, see configure's option --config-cache. ++# It is not useful on other systems. If it contains results you don't ++# want to keep, you may remove or edit it. ++# ++# config.status only pays attention to the cache file if you give it ++# the --recheck option to rerun configure. ++# ++# `ac_cv_env_foo' variables (set or unset) will be overridden when ++# loading this file, other *unset* `ac_cv_foo' will be assigned the ++# following values. ++ ++_ACEOF ++ ++# The following way of writing the cache mishandles newlines in values, ++# but we know of no workaround that is simple, portable, and efficient. ++# So, we kill variables containing newlines. ++# Ultrix sh set writes to stderr and can't be redirected directly, ++# and sets the high bit in the cache file unless we assign to the vars. ++( ++ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do ++ eval ac_val=\$$ac_var ++ case $ac_val in #( ++ *${as_nl}*) ++ case $ac_var in #( ++ *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 ++$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ++ esac ++ case $ac_var in #( ++ _ | IFS | as_nl) ;; #( ++ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( ++ *) $as_unset $ac_var ;; ++ esac ;; ++ esac ++ done ++ ++ (set) 2>&1 | ++ case $as_nl`(ac_space=' '; set) 2>&1` in #( ++ *${as_nl}ac_space=\ *) ++ # `set' does not quote correctly, so add quotes (double-quote ++ # substitution turns \\\\ into \\, and sed turns \\ into \). ++ sed -n \ ++ "s/'/'\\\\''/g; ++ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ++ ;; #( ++ *) ++ # `set' quotes correctly as required by POSIX, so do not add quotes. ++ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ++ ;; ++ esac | ++ sort ++) | ++ sed ' ++ /^ac_cv_env_/b end ++ t clear ++ :clear ++ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ ++ t end ++ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ ++ :end' >>confcache ++if diff "$cache_file" confcache >/dev/null 2>&1; then :; else ++ if test -w "$cache_file"; then ++ test "x$cache_file" != "x/dev/null" && ++ { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5 ++$as_echo "$as_me: updating cache $cache_file" >&6;} ++ cat confcache >$cache_file ++ else ++ { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 ++$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} ++ fi ++fi ++rm -f confcache ++ ++test "x$prefix" = xNONE && prefix=$ac_default_prefix ++# Let make expand exec_prefix. ++test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' ++ ++DEFS=-DHAVE_CONFIG_H ++ ++ac_libobjs= ++ac_ltlibobjs= ++for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue ++ # 1. Remove the extension, and $U if already installed. ++ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ++ ac_i=`$as_echo "$ac_i" | sed "$ac_script"` ++ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR ++ # will be set to the directory where LIBOBJS objects are built. ++ ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" ++ ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' ++done ++LIBOBJS=$ac_libobjs ++ ++LTLIBOBJS=$ac_ltlibobjs ++ ++ ++ ++ ++: ${CONFIG_STATUS=./config.status} ++ac_write_fail=0 ++ac_clean_files_save=$ac_clean_files ++ac_clean_files="$ac_clean_files $CONFIG_STATUS" ++{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 ++$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} ++cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++#! $SHELL ++# Generated by $as_me. ++# Run this file to recreate the current configuration. ++# Compiler output produced by configure, useful for debugging ++# configure, is in config.log if it exists. ++ ++debug=false ++ac_cs_recheck=false ++ac_cs_silent=false ++SHELL=\${CONFIG_SHELL-$SHELL} ++_ACEOF ++ ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++## --------------------- ## ++## M4sh Initialization. ## ++## --------------------- ## ++ ++# Be more Bourne compatible ++DUALCASE=1; export DUALCASE # for MKS sh ++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then ++ emulate sh ++ NULLCMD=: ++ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which ++ # is contrary to our usage. Disable this feature. ++ alias -g '${1+"$@"}'='"$@"' ++ setopt NO_GLOB_SUBST ++else ++ case `(set -o) 2>/dev/null` in ++ *posix*) set -o posix ;; ++esac ++ ++fi ++ ++ ++ ++ ++# PATH needs CR ++# Avoid depending upon Character Ranges. ++as_cr_letters='abcdefghijklmnopqrstuvwxyz' ++as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' ++as_cr_Letters=$as_cr_letters$as_cr_LETTERS ++as_cr_digits='0123456789' ++as_cr_alnum=$as_cr_Letters$as_cr_digits ++ ++as_nl=' ++' ++export as_nl ++# Printing a long string crashes Solaris 7 /usr/bin/printf. ++as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo ++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo ++if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then ++ as_echo='printf %s\n' ++ as_echo_n='printf %s' ++else ++ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then ++ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' ++ as_echo_n='/usr/ucb/echo -n' ++ else ++ as_echo_body='eval expr "X$1" : "X\\(.*\\)"' ++ as_echo_n_body='eval ++ arg=$1; ++ case $arg in ++ *"$as_nl"*) ++ expr "X$arg" : "X\\(.*\\)$as_nl"; ++ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; ++ esac; ++ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ++ ' ++ export as_echo_n_body ++ as_echo_n='sh -c $as_echo_n_body as_echo' ++ fi ++ export as_echo_body ++ as_echo='sh -c $as_echo_body as_echo' ++fi ++ ++# The user is always right. ++if test "${PATH_SEPARATOR+set}" != set; then ++ PATH_SEPARATOR=: ++ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { ++ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || ++ PATH_SEPARATOR=';' ++ } ++fi ++ ++# Support unset when possible. ++if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then ++ as_unset=unset ++else ++ as_unset=false ++fi ++ ++ ++# IFS ++# We need space, tab and new line, in precisely that order. Quoting is ++# there to prevent editors from complaining about space-tab. ++# (If _AS_PATH_WALK were called with IFS unset, it would disable word ++# splitting by setting IFS to empty value.) ++IFS=" "" $as_nl" ++ ++# Find who we are. Look in the path if we contain no directory separator. ++case $0 in ++ *[\\/]* ) as_myself=$0 ;; ++ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break ++done ++IFS=$as_save_IFS ++ ++ ;; ++esac ++# We did not find ourselves, most probably we were run as `sh COMMAND' ++# in which case we are not to be found in the path. ++if test "x$as_myself" = x; then ++ as_myself=$0 ++fi ++if test ! -f "$as_myself"; then ++ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 ++ { (exit 1); exit 1; } ++fi ++ ++# Work around bugs in pre-3.0 UWIN ksh. ++for as_var in ENV MAIL MAILPATH ++do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var ++done ++PS1='$ ' ++PS2='> ' ++PS4='+ ' ++ ++# NLS nuisances. ++LC_ALL=C ++export LC_ALL ++LANGUAGE=C ++export LANGUAGE ++ ++# Required to use basename. ++if expr a : '\(a\)' >/dev/null 2>&1 && ++ test "X`expr 00001 : '.*\(...\)'`" = X001; then ++ as_expr=expr ++else ++ as_expr=false ++fi ++ ++if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then ++ as_basename=basename ++else ++ as_basename=false ++fi ++ ++ ++# Name of the executable. ++as_me=`$as_basename -- "$0" || ++$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ ++ X"$0" : 'X\(//\)$' \| \ ++ X"$0" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X/"$0" | ++ sed '/^.*\/\([^/][^/]*\)\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\/\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\/\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ ++# CDPATH. ++$as_unset CDPATH ++ ++ ++ ++ as_lineno_1=$LINENO ++ as_lineno_2=$LINENO ++ test "x$as_lineno_1" != "x$as_lineno_2" && ++ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { ++ ++ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO ++ # uniformly replaced by the line number. The first 'sed' inserts a ++ # line-number line after each line using $LINENO; the second 'sed' ++ # does the real work. The second script uses 'N' to pair each ++ # line-number line with the line containing $LINENO, and appends ++ # trailing '-' during substitution so that $LINENO is not a special ++ # case at line end. ++ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the ++ # scripts with optimization help from Paolo Bonzini. Blame Lee ++ # E. McMahon (1931-1989) for sed's syntax. :-) ++ sed -n ' ++ p ++ /[$]LINENO/= ++ ' <$as_myself | ++ sed ' ++ s/[$]LINENO.*/&-/ ++ t lineno ++ b ++ :lineno ++ N ++ :loop ++ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ ++ t loop ++ s/-\n.*// ++ ' >$as_me.lineno && ++ chmod +x "$as_me.lineno" || ++ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 ++ { (exit 1); exit 1; }; } ++ ++ # Don't try to exec as it changes $[0], causing all sort of problems ++ # (the dirname of $[0] is not the place where we might find the ++ # original and so on. Autoconf is especially sensitive to this). ++ . "./$as_me.lineno" ++ # Exit status is that of the last command. ++ exit ++} ++ ++ ++if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then ++ as_dirname=dirname ++else ++ as_dirname=false ++fi ++ ++ECHO_C= ECHO_N= ECHO_T= ++case `echo -n x` in ++-n*) ++ case `echo 'x\c'` in ++ *c*) ECHO_T=' ';; # ECHO_T is single tab character. ++ *) ECHO_C='\c';; ++ esac;; ++*) ++ ECHO_N='-n';; ++esac ++if expr a : '\(a\)' >/dev/null 2>&1 && ++ test "X`expr 00001 : '.*\(...\)'`" = X001; then ++ as_expr=expr ++else ++ as_expr=false ++fi ++ ++rm -f conf$$ conf$$.exe conf$$.file ++if test -d conf$$.dir; then ++ rm -f conf$$.dir/conf$$.file ++else ++ rm -f conf$$.dir ++ mkdir conf$$.dir 2>/dev/null ++fi ++if (echo >conf$$.file) 2>/dev/null; then ++ if ln -s conf$$.file conf$$ 2>/dev/null; then ++ as_ln_s='ln -s' ++ # ... but there are two gotchas: ++ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. ++ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. ++ # In both cases, we have to default to `cp -p'. ++ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || ++ as_ln_s='cp -p' ++ elif ln conf$$.file conf$$ 2>/dev/null; then ++ as_ln_s=ln ++ else ++ as_ln_s='cp -p' ++ fi ++else ++ as_ln_s='cp -p' ++fi ++rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file ++rmdir conf$$.dir 2>/dev/null ++ ++if mkdir -p . 2>/dev/null; then ++ as_mkdir_p=: ++else ++ test -d ./-p && rmdir ./-p ++ as_mkdir_p=false ++fi ++ ++if test -x / >/dev/null 2>&1; then ++ as_test_x='test -x' ++else ++ if ls -dL / >/dev/null 2>&1; then ++ as_ls_L_option=L ++ else ++ as_ls_L_option= ++ fi ++ as_test_x=' ++ eval sh -c '\'' ++ if test -d "$1"; then ++ test -d "$1/."; ++ else ++ case $1 in ++ -*)set "./$1";; ++ esac; ++ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ++ ???[sx]*):;;*)false;;esac;fi ++ '\'' sh ++ ' ++fi ++as_executable_p=$as_test_x ++ ++# Sed expression to map a string onto a valid CPP name. ++as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" ++ ++# Sed expression to map a string onto a valid variable name. ++as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" ++ ++ ++exec 6>&1 ++ ++# Save the log message, to keep $[0] and so on meaningful, and to ++# report actual input values of CONFIG_FILES etc. instead of their ++# values after options handling. ++ac_log=" ++This file was extended by open-isns $as_me 0.90, which was ++generated by GNU Autoconf 2.63. Invocation command line was ++ ++ CONFIG_FILES = $CONFIG_FILES ++ CONFIG_HEADERS = $CONFIG_HEADERS ++ CONFIG_LINKS = $CONFIG_LINKS ++ CONFIG_COMMANDS = $CONFIG_COMMANDS ++ $ $0 $@ ++ ++on `(hostname || uname -n) 2>/dev/null | sed 1q` ++" ++ ++_ACEOF ++ ++case $ac_config_files in *" ++"*) set x $ac_config_files; shift; ac_config_files=$*;; ++esac ++ ++case $ac_config_headers in *" ++"*) set x $ac_config_headers; shift; ac_config_headers=$*;; ++esac ++ ++ ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++# Files that config.status was made for. ++config_files="$ac_config_files" ++config_headers="$ac_config_headers" ++ ++_ACEOF ++ ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++ac_cs_usage="\ ++\`$as_me' instantiates files from templates according to the ++current configuration. ++ ++Usage: $0 [OPTION]... [FILE]... ++ ++ -h, --help print this help, then exit ++ -V, --version print version number and configuration settings, then exit ++ -q, --quiet, --silent ++ do not print progress messages ++ -d, --debug don't remove temporary files ++ --recheck update $as_me by reconfiguring in the same conditions ++ --file=FILE[:TEMPLATE] ++ instantiate the configuration file FILE ++ --header=FILE[:TEMPLATE] ++ instantiate the configuration header FILE ++ ++Configuration files: ++$config_files ++ ++Configuration headers: ++$config_headers ++ ++Report bugs to ." ++ ++_ACEOF ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++ac_cs_version="\\ ++open-isns config.status 0.90 ++configured by $0, generated by GNU Autoconf 2.63, ++ with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" ++ ++Copyright (C) 2008 Free Software Foundation, Inc. ++This config.status script is free software; the Free Software Foundation ++gives unlimited permission to copy, distribute and modify it." ++ ++ac_pwd='$ac_pwd' ++srcdir='$srcdir' ++INSTALL='$INSTALL' ++test -n "\$AWK" || AWK=awk ++_ACEOF ++ ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++# The default lists apply if the user does not specify any file. ++ac_need_defaults=: ++while test $# != 0 ++do ++ case $1 in ++ --*=*) ++ ac_option=`expr "X$1" : 'X\([^=]*\)='` ++ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ++ ac_shift=: ++ ;; ++ *) ++ ac_option=$1 ++ ac_optarg=$2 ++ ac_shift=shift ++ ;; ++ esac ++ ++ case $ac_option in ++ # Handling of the options. ++ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ++ ac_cs_recheck=: ;; ++ --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) ++ $as_echo "$ac_cs_version"; exit ;; ++ --debug | --debu | --deb | --de | --d | -d ) ++ debug=: ;; ++ --file | --fil | --fi | --f ) ++ $ac_shift ++ case $ac_optarg in ++ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; ++ esac ++ CONFIG_FILES="$CONFIG_FILES '$ac_optarg'" ++ ac_need_defaults=false;; ++ --header | --heade | --head | --hea ) ++ $ac_shift ++ case $ac_optarg in ++ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; ++ esac ++ CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'" ++ ac_need_defaults=false;; ++ --he | --h) ++ # Conflict between --help and --header ++ { $as_echo "$as_me: error: ambiguous option: $1 ++Try \`$0 --help' for more information." >&2 ++ { (exit 1); exit 1; }; };; ++ --help | --hel | -h ) ++ $as_echo "$ac_cs_usage"; exit ;; ++ -q | -quiet | --quiet | --quie | --qui | --qu | --q \ ++ | -silent | --silent | --silen | --sile | --sil | --si | --s) ++ ac_cs_silent=: ;; ++ ++ # This is an error. ++ -*) { $as_echo "$as_me: error: unrecognized option: $1 ++Try \`$0 --help' for more information." >&2 ++ { (exit 1); exit 1; }; } ;; ++ ++ *) ac_config_targets="$ac_config_targets $1" ++ ac_need_defaults=false ;; ++ ++ esac ++ shift ++done ++ ++ac_configure_extra_args= ++ ++if $ac_cs_silent; then ++ exec 6>/dev/null ++ ac_configure_extra_args="$ac_configure_extra_args --silent" ++fi ++ ++_ACEOF ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++if \$ac_cs_recheck; then ++ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion ++ shift ++ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 ++ CONFIG_SHELL='$SHELL' ++ export CONFIG_SHELL ++ exec "\$@" ++fi ++ ++_ACEOF ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++exec 5>>config.log ++{ ++ echo ++ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ++## Running $as_me. ## ++_ASBOX ++ $as_echo "$ac_log" ++} >&5 ++ ++_ACEOF ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++_ACEOF ++ ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++ ++# Handling of arguments. ++for ac_config_target in $ac_config_targets ++do ++ case $ac_config_target in ++ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; ++ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; ++ ++ *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 ++$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;} ++ { (exit 1); exit 1; }; };; ++ esac ++done ++ ++ ++# If the user did not use the arguments to specify the items to instantiate, ++# then the envvar interface is used. Set only those that are not. ++# We use the long form for the default assignment because of an extremely ++# bizarre bug on SunOS 4.1.3. ++if $ac_need_defaults; then ++ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files ++ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers ++fi ++ ++# Have a temporary directory for convenience. Make it in the build tree ++# simply because there is no reason against having it here, and in addition, ++# creating and moving files from /tmp can sometimes cause problems. ++# Hook for its removal unless debugging. ++# Note that there is a small window in which the directory will not be cleaned: ++# after its creation but before its name has been assigned to `$tmp'. ++$debug || ++{ ++ tmp= ++ trap 'exit_status=$? ++ { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ++' 0 ++ trap '{ (exit 1); exit 1; }' 1 2 13 15 ++} ++# Create a (secure) tmp directory for tmp files. ++ ++{ ++ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && ++ test -n "$tmp" && test -d "$tmp" ++} || ++{ ++ tmp=./conf$$-$RANDOM ++ (umask 077 && mkdir "$tmp") ++} || ++{ ++ $as_echo "$as_me: cannot create a temporary directory in ." >&2 ++ { (exit 1); exit 1; } ++} ++ ++# Set up the scripts for CONFIG_FILES section. ++# No need to generate them if there are no CONFIG_FILES. ++# This happens for instance with `./config.status config.h'. ++if test -n "$CONFIG_FILES"; then ++ ++ ++ac_cr=' ' ++ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` ++if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ++ ac_cs_awk_cr='\\r' ++else ++ ac_cs_awk_cr=$ac_cr ++fi ++ ++echo 'BEGIN {' >"$tmp/subs1.awk" && ++_ACEOF ++ ++ ++{ ++ echo "cat >conf$$subs.awk <<_ACEOF" && ++ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && ++ echo "_ACEOF" ++} >conf$$subs.sh || ++ { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 ++$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} ++ { (exit 1); exit 1; }; } ++ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` ++ac_delim='%!_!# ' ++for ac_last_try in false false false false false :; do ++ . ./conf$$subs.sh || ++ { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 ++$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} ++ { (exit 1); exit 1; }; } ++ ++ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` ++ if test $ac_delim_n = $ac_delim_num; then ++ break ++ elif $ac_last_try; then ++ { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 ++$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} ++ { (exit 1); exit 1; }; } ++ else ++ ac_delim="$ac_delim!$ac_delim _$ac_delim!! " ++ fi ++done ++rm -f conf$$subs.sh ++ ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++cat >>"\$tmp/subs1.awk" <<\\_ACAWK && ++_ACEOF ++sed -n ' ++h ++s/^/S["/; s/!.*/"]=/ ++p ++g ++s/^[^!]*!// ++:repl ++t repl ++s/'"$ac_delim"'$// ++t delim ++:nl ++h ++s/\(.\{148\}\).*/\1/ ++t more1 ++s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ ++p ++n ++b repl ++:more1 ++s/["\\]/\\&/g; s/^/"/; s/$/"\\/ ++p ++g ++s/.\{148\}// ++t nl ++:delim ++h ++s/\(.\{148\}\).*/\1/ ++t more2 ++s/["\\]/\\&/g; s/^/"/; s/$/"/ ++p ++b ++:more2 ++s/["\\]/\\&/g; s/^/"/; s/$/"\\/ ++p ++g ++s/.\{148\}// ++t delim ++' >$CONFIG_STATUS || ac_write_fail=1 ++rm -f conf$$subs.awk ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++_ACAWK ++cat >>"\$tmp/subs1.awk" <<_ACAWK && ++ for (key in S) S_is_set[key] = 1 ++ FS = "" ++ ++} ++{ ++ line = $ 0 ++ nfields = split(line, field, "@") ++ substed = 0 ++ len = length(field[1]) ++ for (i = 2; i < nfields; i++) { ++ key = field[i] ++ keylen = length(key) ++ if (S_is_set[key]) { ++ value = S[key] ++ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) ++ len += length(value) + length(field[++i]) ++ substed = 1 ++ } else ++ len += 1 + keylen ++ } ++ ++ print line ++} ++ ++_ACAWK ++_ACEOF ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then ++ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" ++else ++ cat ++fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ ++ || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5 ++$as_echo "$as_me: error: could not setup config files machinery" >&2;} ++ { (exit 1); exit 1; }; } ++_ACEOF ++ ++# VPATH may cause trouble with some makes, so we remove $(srcdir), ++# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and ++# trailing colons and then remove the whole line if VPATH becomes empty ++# (actually we leave an empty line to preserve line numbers). ++if test "x$srcdir" = x.; then ++ ac_vpsub='/^[ ]*VPATH[ ]*=/{ ++s/:*\$(srcdir):*/:/ ++s/:*\${srcdir}:*/:/ ++s/:*@srcdir@:*/:/ ++s/^\([^=]*=[ ]*\):*/\1/ ++s/:*$// ++s/^[^=]*=[ ]*$// ++}' ++fi ++ ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++fi # test -n "$CONFIG_FILES" ++ ++# Set up the scripts for CONFIG_HEADERS section. ++# No need to generate them if there are no CONFIG_HEADERS. ++# This happens for instance with `./config.status Makefile'. ++if test -n "$CONFIG_HEADERS"; then ++cat >"$tmp/defines.awk" <<\_ACAWK || ++BEGIN { ++_ACEOF ++ ++# Transform confdefs.h into an awk script `defines.awk', embedded as ++# here-document in config.status, that substitutes the proper values into ++# config.h.in to produce config.h. ++ ++# Create a delimiter string that does not exist in confdefs.h, to ease ++# handling of long lines. ++ac_delim='%!_!# ' ++for ac_last_try in false false :; do ++ ac_t=`sed -n "/$ac_delim/p" confdefs.h` ++ if test -z "$ac_t"; then ++ break ++ elif $ac_last_try; then ++ { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5 ++$as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;} ++ { (exit 1); exit 1; }; } ++ else ++ ac_delim="$ac_delim!$ac_delim _$ac_delim!! " ++ fi ++done ++ ++# For the awk script, D is an array of macro values keyed by name, ++# likewise P contains macro parameters if any. Preserve backslash ++# newline sequences. ++ ++ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* ++sed -n ' ++s/.\{148\}/&'"$ac_delim"'/g ++t rset ++:rset ++s/^[ ]*#[ ]*define[ ][ ]*/ / ++t def ++d ++:def ++s/\\$// ++t bsnl ++s/["\\]/\\&/g ++s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ ++D["\1"]=" \3"/p ++s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p ++d ++:bsnl ++s/["\\]/\\&/g ++s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ ++D["\1"]=" \3\\\\\\n"\\/p ++t cont ++s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p ++t cont ++d ++:cont ++n ++s/.\{148\}/&'"$ac_delim"'/g ++t clear ++:clear ++s/\\$// ++t bsnlc ++s/["\\]/\\&/g; s/^/"/; s/$/"/p ++d ++:bsnlc ++s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p ++b cont ++' >$CONFIG_STATUS || ac_write_fail=1 ++ ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++ for (key in D) D_is_set[key] = 1 ++ FS = "" ++} ++/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { ++ line = \$ 0 ++ split(line, arg, " ") ++ if (arg[1] == "#") { ++ defundef = arg[2] ++ mac1 = arg[3] ++ } else { ++ defundef = substr(arg[1], 2) ++ mac1 = arg[2] ++ } ++ split(mac1, mac2, "(") #) ++ macro = mac2[1] ++ prefix = substr(line, 1, index(line, defundef) - 1) ++ if (D_is_set[macro]) { ++ # Preserve the white space surrounding the "#". ++ print prefix "define", macro P[macro] D[macro] ++ next ++ } else { ++ # Replace #undef with comments. This is necessary, for example, ++ # in the case of _POSIX_SOURCE, which is predefined and required ++ # on some systems where configure will not decide to define it. ++ if (defundef == "undef") { ++ print "/*", prefix defundef, macro, "*/" ++ next ++ } ++ } ++} ++{ print } ++_ACAWK ++_ACEOF ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++ { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5 ++$as_echo "$as_me: error: could not setup config headers machinery" >&2;} ++ { (exit 1); exit 1; }; } ++fi # test -n "$CONFIG_HEADERS" ++ ++ ++eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " ++shift ++for ac_tag ++do ++ case $ac_tag in ++ :[FHLC]) ac_mode=$ac_tag; continue;; ++ esac ++ case $ac_mode$ac_tag in ++ :[FHL]*:*);; ++ :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5 ++$as_echo "$as_me: error: invalid tag $ac_tag" >&2;} ++ { (exit 1); exit 1; }; };; ++ :[FH]-) ac_tag=-:-;; ++ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; ++ esac ++ ac_save_IFS=$IFS ++ IFS=: ++ set x $ac_tag ++ IFS=$ac_save_IFS ++ shift ++ ac_file=$1 ++ shift ++ ++ case $ac_mode in ++ :L) ac_source=$1;; ++ :[FH]) ++ ac_file_inputs= ++ for ac_f ++ do ++ case $ac_f in ++ -) ac_f="$tmp/stdin";; ++ *) # Look for the file first in the build tree, then in the source tree ++ # (if the path is not absolute). The absolute path cannot be DOS-style, ++ # because $ac_f cannot contain `:'. ++ test -f "$ac_f" || ++ case $ac_f in ++ [\\/$]*) false;; ++ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; ++ esac || ++ { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 ++$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} ++ { (exit 1); exit 1; }; };; ++ esac ++ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac ++ ac_file_inputs="$ac_file_inputs '$ac_f'" ++ done ++ ++ # Let's still pretend it is `configure' which instantiates (i.e., don't ++ # use $as_me), people would be surprised to read: ++ # /* config.h. Generated by config.status. */ ++ configure_input='Generated from '` ++ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' ++ `' by configure.' ++ if test x"$ac_file" != x-; then ++ configure_input="$ac_file. $configure_input" ++ { $as_echo "$as_me:$LINENO: creating $ac_file" >&5 ++$as_echo "$as_me: creating $ac_file" >&6;} ++ fi ++ # Neutralize special characters interpreted by sed in replacement strings. ++ case $configure_input in #( ++ *\&* | *\|* | *\\* ) ++ ac_sed_conf_input=`$as_echo "$configure_input" | ++ sed 's/[\\\\&|]/\\\\&/g'`;; #( ++ *) ac_sed_conf_input=$configure_input;; ++ esac ++ ++ case $ac_tag in ++ *:-:* | *:-) cat >"$tmp/stdin" \ ++ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 ++$as_echo "$as_me: error: could not create $ac_file" >&2;} ++ { (exit 1); exit 1; }; } ;; ++ esac ++ ;; ++ esac ++ ++ ac_dir=`$as_dirname -- "$ac_file" || ++$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ ++ X"$ac_file" : 'X\(//\)[^/]' \| \ ++ X"$ac_file" : 'X\(//\)$' \| \ ++ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X"$ac_file" | ++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)[^/].*/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ { as_dir="$ac_dir" ++ case $as_dir in #( ++ -*) as_dir=./$as_dir;; ++ esac ++ test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { ++ as_dirs= ++ while :; do ++ case $as_dir in #( ++ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( ++ *) as_qdir=$as_dir;; ++ esac ++ as_dirs="'$as_qdir' $as_dirs" ++ as_dir=`$as_dirname -- "$as_dir" || ++$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ ++ X"$as_dir" : 'X\(//\)[^/]' \| \ ++ X"$as_dir" : 'X\(//\)$' \| \ ++ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X"$as_dir" | ++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)[^/].*/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ test -d "$as_dir" && break ++ done ++ test -z "$as_dirs" || eval "mkdir $as_dirs" ++ } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 ++$as_echo "$as_me: error: cannot create directory $as_dir" >&2;} ++ { (exit 1); exit 1; }; }; } ++ ac_builddir=. ++ ++case "$ac_dir" in ++.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; ++*) ++ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` ++ # A ".." for each directory in $ac_dir_suffix. ++ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` ++ case $ac_top_builddir_sub in ++ "") ac_top_builddir_sub=. ac_top_build_prefix= ;; ++ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; ++ esac ;; ++esac ++ac_abs_top_builddir=$ac_pwd ++ac_abs_builddir=$ac_pwd$ac_dir_suffix ++# for backward compatibility: ++ac_top_builddir=$ac_top_build_prefix ++ ++case $srcdir in ++ .) # We are building in place. ++ ac_srcdir=. ++ ac_top_srcdir=$ac_top_builddir_sub ++ ac_abs_top_srcdir=$ac_pwd ;; ++ [\\/]* | ?:[\\/]* ) # Absolute name. ++ ac_srcdir=$srcdir$ac_dir_suffix; ++ ac_top_srcdir=$srcdir ++ ac_abs_top_srcdir=$srcdir ;; ++ *) # Relative name. ++ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ++ ac_top_srcdir=$ac_top_build_prefix$srcdir ++ ac_abs_top_srcdir=$ac_pwd/$srcdir ;; ++esac ++ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix ++ ++ ++ case $ac_mode in ++ :F) ++ # ++ # CONFIG_FILE ++ # ++ ++ case $INSTALL in ++ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; ++ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; ++ esac ++_ACEOF ++ ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++# If the template does not know about datarootdir, expand it. ++# FIXME: This hack should be removed a few years after 2.60. ++ac_datarootdir_hack=; ac_datarootdir_seen= ++ ++ac_sed_dataroot=' ++/datarootdir/ { ++ p ++ q ++} ++/@datadir@/p ++/@docdir@/p ++/@infodir@/p ++/@localedir@/p ++/@mandir@/p ++' ++case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in ++*datarootdir*) ac_datarootdir_seen=yes;; ++*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 ++$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} ++_ACEOF ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++ ac_datarootdir_hack=' ++ s&@datadir@&$datadir&g ++ s&@docdir@&$docdir&g ++ s&@infodir@&$infodir&g ++ s&@localedir@&$localedir&g ++ s&@mandir@&$mandir&g ++ s&\\\${datarootdir}&$datarootdir&g' ;; ++esac ++_ACEOF ++ ++# Neutralize VPATH when `$srcdir' = `.'. ++# Shell code in configure.ac might set extrasub. ++# FIXME: do we really want to maintain this feature? ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++ac_sed_extra="$ac_vpsub ++$extrasub ++_ACEOF ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++:t ++/@[a-zA-Z_][a-zA-Z_0-9]*@/!b ++s|@configure_input@|$ac_sed_conf_input|;t t ++s&@top_builddir@&$ac_top_builddir_sub&;t t ++s&@top_build_prefix@&$ac_top_build_prefix&;t t ++s&@srcdir@&$ac_srcdir&;t t ++s&@abs_srcdir@&$ac_abs_srcdir&;t t ++s&@top_srcdir@&$ac_top_srcdir&;t t ++s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t ++s&@builddir@&$ac_builddir&;t t ++s&@abs_builddir@&$ac_abs_builddir&;t t ++s&@abs_top_builddir@&$ac_abs_top_builddir&;t t ++s&@INSTALL@&$ac_INSTALL&;t t ++$ac_datarootdir_hack ++" ++eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ ++ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 ++$as_echo "$as_me: error: could not create $ac_file" >&2;} ++ { (exit 1); exit 1; }; } ++ ++test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && ++ { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && ++ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && ++ { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' ++which seems to be undefined. Please make sure it is defined." >&5 ++$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' ++which seems to be undefined. Please make sure it is defined." >&2;} ++ ++ rm -f "$tmp/stdin" ++ case $ac_file in ++ -) cat "$tmp/out" && rm -f "$tmp/out";; ++ *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; ++ esac \ ++ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 ++$as_echo "$as_me: error: could not create $ac_file" >&2;} ++ { (exit 1); exit 1; }; } ++ ;; ++ :H) ++ # ++ # CONFIG_HEADER ++ # ++ if test x"$ac_file" != x-; then ++ { ++ $as_echo "/* $configure_input */" \ ++ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" ++ } >"$tmp/config.h" \ ++ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 ++$as_echo "$as_me: error: could not create $ac_file" >&2;} ++ { (exit 1); exit 1; }; } ++ if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then ++ { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5 ++$as_echo "$as_me: $ac_file is unchanged" >&6;} ++ else ++ rm -f "$ac_file" ++ mv "$tmp/config.h" "$ac_file" \ ++ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 ++$as_echo "$as_me: error: could not create $ac_file" >&2;} ++ { (exit 1); exit 1; }; } ++ fi ++ else ++ $as_echo "/* $configure_input */" \ ++ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ ++ || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5 ++$as_echo "$as_me: error: could not create -" >&2;} ++ { (exit 1); exit 1; }; } ++ fi ++ ;; ++ ++ ++ esac ++ ++done # for ac_tag ++ ++ ++{ (exit 0); exit 0; } ++_ACEOF ++chmod +x $CONFIG_STATUS ++ac_clean_files=$ac_clean_files_save ++ ++test $ac_write_fail = 0 || ++ { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5 ++$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;} ++ { (exit 1); exit 1; }; } ++ ++ ++# configure is writing to config.log, and then calls config.status. ++# config.status does its own redirection, appending to config.log. ++# Unfortunately, on DOS this fails, as config.log is still kept open ++# by configure, so config.status won't be able to write to it; its ++# output is simply discarded. So we exec the FD to /dev/null, ++# effectively closing config.log, so it can be properly (re)opened and ++# appended to by config.status. When coming back to configure, we ++# need to make the FD available again. ++if test "$no_create" != yes; then ++ ac_cs_success=: ++ ac_config_status_args= ++ test "$silent" = yes && ++ ac_config_status_args="$ac_config_status_args --quiet" ++ exec 5>/dev/null ++ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false ++ exec 5>>config.log ++ # Use ||, not &&, to avoid exiting from the if with $? = 1, which ++ # would make configure fail if this is the last instruction. ++ $ac_cs_success || { (exit 1); exit 1; } ++fi ++if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then ++ { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 ++$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} ++fi ++ +diff --git a/utils/open-isns/configure.ac b/utils/open-isns/configure.ac +new file mode 100644 +index 0000000..a02915b +--- /dev/null ++++ b/utils/open-isns/configure.ac +@@ -0,0 +1,118 @@ ++AC_INIT(open-isns, [0.90]) ++AC_CONFIG_SRCDIR([isnsd.c]) ++AC_CONFIG_AUX_DIR([aclocal]) ++ ++AC_CONFIG_HEADER(config.h) ++ ++AC_PROG_CC ++AC_CANONICAL_HOST ++AC_C_BIGENDIAN ++ ++AC_PROG_CPP ++AC_PROG_INSTALL ++AC_PROG_LN_S ++AC_PROG_MAKE_SET ++AC_PATH_PROG(SH, sh) ++ ++dnl C Compiler features ++AC_C_INLINE ++if test "$GCC" = "yes"; then ++ CFLAGS="-Wall -fno-strict-aliasing $CFLAGS" ++ CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" ++fi ++ ++dnl Checks for header files. ++AC_HEADER_STDC ++AC_HEADER_SYS_WAIT ++AC_CHECK_HEADERS([errno.h fcntl.h malloc.h stdlib.h string.h strings.h sys/time.h unistd.h locale.h getopt.h]) ++ ++# Check if socket() is in libsocket ++AC_CHECK_LIB(socket, socket, [LIBS="$LIBS -lsocket"]) ++ ++ ++AC_SUBST(GETOPTSRC) ++AC_CHECK_FUNC(getopt_long, AC_DEFINE(HAVE_GETOPT_LONG, 1, [Define if you have the `getopt_long' function.]), ++ [GETOPTSRC="$GETOPTSRC \$(top_srcdir)/compat/my_getopt.c" ++ CPPFLAGS="-I\$(top_srcdir)/compat/ $CPPFLAGS" ++ AC_DEFINE(HAVE_GETOPT_H, 1, [Define if you have the header file.])]) ++ ++WITH_SECURITY=maybe ++AC_ARG_WITH(security, ++ [ --with-security Enable iSNS authentication - requires OpenSSL], ++ [ ++ if test "x$withval" = "xno" -o "x$withval" = "xyes"; then ++ WITH_SECURITY=$withval ++ else ++ WITH_SECURITY=yes ++ CPPFLAGS="$CPPFLAGS -I${withval}" ++ LDFLAGS="$LDFLAGS -L${withval}" ++ fi ++ ] ++) ++ ++if test "x$WITH_SECURITY" != "xno" ; then ++ # Check for openssl support - very primitive, we just ++ # check for the presence of crypto.h ++ AC_CHECK_HEADERS([openssl/crypto.h], ++ , ++ [have_libcrypto=no]) ++ AC_CHECK_LIB(crypto, EVP_PKEY_new, ++ [SECLIBS="-lcrypto"], ++ [have_libcrypto=no]) ++ ++ if test "x$have_libcrypto" != "xno" ; then ++ AC_DEFINE(WITH_SECURITY, 1, ++ [Define if you want to support iSNS authentication]) ++ else ++ if test "x$WITH_SECURITY" = "xyes" ; then ++ AC_MSG_ERROR([Security requested, but unable to find libcrypto]) ++ fi ++ fi ++fi ++AC_SUBST(SECLIBS) ++ ++WITH_SLP=maybe ++AC_ARG_WITH(slp, ++ [ --with-slp Enable SLP for server discovery - requires OpenSLP], ++ [ ++ if test "x$withval" = "xno" -o "x$withval" = "xyes"; then ++ WITH_SLP=$withval ++ else ++ WITH_SLP=yes ++ CPPFLAGS="$CPPFLAGS -I${withval}" ++ LDFLAGS="$LDFLAGS -L${withval}" ++ fi ++ ] ++) ++ ++if test "x$WITH_SLP" != "xno" ; then ++ # Check for openslp support - very primitive ++ AC_CHECK_HEADERS([slp.h],, ++ [have_openslp=no]) ++ AC_CHECK_LIB(slp, SLPOpen, ++ [SLPLIBS="-lslp"], ++ [have_openslp=no]) ++ ++ if test "x$have_openslp" != "xno" ; then ++ AC_DEFINE(WITH_SLP, 1, ++ [Define if you want to support SLP discovery]) ++ else ++ if test "x$WITH_SLP" = "xyes" ; then ++ AC_MSG_ERROR([SLP requested, but unable to find openslp]) ++ fi ++ fi ++fi ++AC_SUBST(SLPLIBS) ++ ++MEMDEBUG= ++AC_ARG_ENABLE(memdebug, ++ [ --enable-memdebug Enable malloc debugging], ++ [ ++ if test "x$enableval" = "xyes" ; then ++ CPPFLAGS="$CPPFLAGS -DMEMDEBUG" ++ fi ++ ] ++) ++AC_SUBST(OPTIMIZE) ++ ++AC_OUTPUT(Makefile) +diff --git a/utils/open-isns/db-file.c b/utils/open-isns/db-file.c +new file mode 100644 +index 0000000..98c08db +--- /dev/null ++++ b/utils/open-isns/db-file.c +@@ -0,0 +1,615 @@ ++/* ++ * iSNS object database ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isns.h" ++#include "objects.h" ++#include "message.h" ++#include "util.h" ++#include "db.h" ++ ++#define DBE_FILE_VERSION 1 ++ ++struct isns_db_file_info { ++ uint32_t db_version; ++ uint32_t db_last_eid; ++ uint32_t db_last_index; ++}; ++ ++struct isns_db_object_info { ++ uint32_t db_version; ++ char db_type[64]; ++ uint32_t db_parent; ++ uint32_t db_state; ++ uint32_t db_flags; ++ uint32_t db_scn_mask; ++ /* reserved bytes */ ++ uint32_t __db_reserved[15]; ++}; ++ ++static int isns_dbe_file_sync(isns_db_t *); ++static int isns_dbe_file_reload(isns_db_t *); ++static int isns_dbe_file_store(isns_db_t *, ++ const isns_object_t *); ++static int isns_dbe_file_remove(isns_db_t *, ++ const isns_object_t *); ++static int __dbe_file_load_all(const char *, ++ isns_object_list_t *); ++ ++/* ++ * Helper functions ++ */ ++static const char * ++__path_concat(const char *dirname, const char *basename) ++{ ++ static char pathname[PATH_MAX]; ++ ++ snprintf(pathname, sizeof(pathname), "%s/%s", ++ dirname, basename); ++ return pathname; ++} ++ ++static const char * ++__print_index(uint32_t index) ++{ ++ static char namebuf[32]; ++ ++ snprintf(namebuf, sizeof(namebuf), "%08x", index); ++ return namebuf; ++} ++ ++static int ++__get_index(const char *name, uint32_t *result) ++{ ++ char *end; ++ ++ *result = strtoul(name, &end, 16); ++ if (*end) ++ return ISNS_INTERNAL_ERROR; ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * Build path names for an object ++ */ ++static const char * ++__dbe_file_object_path(const char *dirname, const isns_object_t *obj) ++{ ++ return __path_concat(dirname, __print_index(obj->ie_index)); ++} ++ ++/* ++ * Build a path name for a temporary file. ++ * Cannot use __path_concat, because we need both names ++ * when storing objects ++ */ ++static const char * ++__dbe_file_object_temp(const char *dirname, const isns_object_t *obj) ++{ ++ static char pathname[PATH_MAX]; ++ ++ snprintf(pathname, sizeof(pathname), "%s/.%s", ++ dirname, __print_index(obj->ie_index)); ++ return pathname; ++} ++ ++/* ++ * Recursively create a directory ++ */ ++static int ++__dbe_mkdir_path(const char *dirname) ++{ ++ unsigned int true_len = strlen(dirname); ++ char *copy, *s; ++ ++ copy = isns_strdup(dirname); ++ ++ /* Walk up until we find a directory that exists */ ++ while (1) { ++ s = strrchr(copy, '/'); ++ if (s == NULL) ++ break; ++ ++ *s = '\0'; ++ if (access(copy, F_OK) == 0) ++ break; ++ } ++ ++ while (strcmp(dirname, copy)) { ++ unsigned int len = strlen(copy); ++ ++ /* Better safe than sorry */ ++ isns_assert(len < true_len); ++ ++ /* Put the next slash back in */ ++ copy[len] = '/'; ++ ++ /* and try to create the directory */ ++ if (mkdir(copy, 0700) < 0) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Write an object to a file ++ */ ++static int ++__dbe_file_store_object(const char *dirname, const isns_object_t *obj) ++{ ++ struct isns_db_object_info info; ++ const char *path = __dbe_file_object_path(dirname, obj); ++ const char *temp = __dbe_file_object_temp(dirname, obj); ++ buf_t *bp = NULL; ++ int status = ISNS_INTERNAL_ERROR; ++ ++ isns_debug_state("DB: Storing object %u -> %s\n", obj->ie_index, path); ++ if (access(dirname, F_OK) < 0 ++ && (errno != ENOENT || __dbe_mkdir_path(dirname) < 0)) { ++ isns_error("DB: Unable to create %s: %m\n", ++ dirname); ++ goto out; ++ } ++ ++ bp = buf_open(temp, O_CREAT|O_TRUNC|O_WRONLY); ++ if (bp == NULL) { ++ isns_error("Unable to open %s: %m\n", temp); ++ goto out; ++ } ++ ++ /* Encode the header info ... */ ++ memset(&info, 0, sizeof(info)); ++ info.db_version = htonl(DBE_FILE_VERSION); ++ info.db_state = htonl(obj->ie_state); ++ info.db_flags = htonl(obj->ie_flags); ++ info.db_scn_mask = htonl(obj->ie_scn_mask); ++ strcpy(info.db_type, obj->ie_template->iot_name); ++ if (obj->ie_container) ++ info.db_parent = htonl(obj->ie_container->ie_index); ++ ++ if (!buf_put(bp, &info, sizeof(info))) ++ goto out; ++ ++ /* ... and attributes */ ++ status = isns_attr_list_encode(bp, &obj->ie_attrs); ++ if (status != ISNS_SUCCESS) ++ goto out; ++ ++ /* Renaming an open file. NFS will hate this */ ++ if (rename(temp, path) < 0) { ++ isns_error("Cannot rename %s -> %s: %m\n", ++ temp, path); ++ unlink(temp); ++ status = ISNS_INTERNAL_ERROR; ++ } ++ ++out: ++ if (bp) ++ buf_close(bp); ++ return status; ++} ++ ++/* ++ * Store all children of an object ++ */ ++static int ++__dbe_file_store_children(const char *dirname, const isns_object_t *obj) ++{ ++ int status = ISNS_SUCCESS; ++ unsigned int i; ++ ++ for (i = 0; i < obj->ie_children.iol_count; ++i) { ++ isns_object_t *child; ++ ++ child = obj->ie_children.iol_data[i]; ++ status = __dbe_file_store_object(dirname, child); ++ if (status) ++ break; ++ status = __dbe_file_store_children(dirname, child); ++ if (status) ++ break; ++ } ++ ++ return status; ++} ++ ++/* ++ * Remove object and children ++ */ ++static int ++__dbe_file_remove_object(const char *dirname, const isns_object_t *obj) ++{ ++ const char *path = __dbe_file_object_path(dirname, obj); ++ ++ isns_debug_state("DB: Purging object %u (%s)\n", obj->ie_index, path); ++ if (unlink(path) < 0) ++ isns_error("DB: Cannot remove %s: %m\n", path); ++ return ISNS_SUCCESS; ++} ++ ++static int ++__dbe_file_remove_children(const char *dirname, const isns_object_t *obj) ++{ ++ const isns_object_list_t *list = &obj->ie_children; ++ unsigned int i; ++ ++ for (i = 0; i < list->iol_count; ++i) ++ __dbe_file_remove_object(dirname, list->iol_data[i]); ++ ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * Load an object from file ++ */ ++static int ++__dbe_file_load_object(const char *filename, const char *basename, ++ isns_object_list_t *result) ++{ ++ struct isns_db_object_info info; ++ isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; ++ isns_object_template_t *tmpl; ++ isns_object_t *obj = NULL; ++ buf_t *bp = NULL; ++ uint32_t index; ++ int status; ++ ++ bp = buf_open(filename, O_RDONLY); ++ if (bp == NULL) { ++ isns_error("Unable to open %s: %m\n", filename); ++ goto internal_error; ++ } ++ ++ /* Decode the header ... */ ++ if (!buf_get(bp, &info, sizeof(info))) ++ goto internal_error; ++ if (info.db_version != htonl(DBE_FILE_VERSION)) { ++ /* If we ever have to deal with a DB version ++ * upgrade, we could do it here. */ ++ isns_fatal("Found iSNS database version %u; not supported\n", ++ ntohl(info.db_version)); ++ } ++ ++ /* ... and attributes */ ++ status = isns_attr_list_decode(bp, &attrs); ++ if (status != ISNS_SUCCESS) ++ goto out; ++ ++ /* Get the index from the file name */ ++ status = __get_index(basename, &index); ++ if (status != ISNS_SUCCESS) ++ goto out; ++ ++ tmpl = isns_object_template_by_name(info.db_type); ++ if (tmpl == NULL) { ++ isns_error("DB: Bad type name \"%s\" in object file\n", ++ info.db_type); ++ goto internal_error; ++ } ++ ++ obj = isns_create_object(tmpl, &attrs, NULL); ++ if (obj == NULL) ++ goto internal_error; ++ ++ obj->ie_state = ntohl(info.db_state); ++ obj->ie_flags = ntohl(info.db_flags) & ~(ISNS_OBJECT_DIRTY); ++ obj->ie_scn_mask = ntohl(info.db_scn_mask); ++ obj->ie_index = index; ++ ++ /* Stash away the parent's index; we resolve them later on ++ * once we've loaded all objects */ ++ obj->ie_container_idx = ntohl(info.db_parent); ++ ++ isns_object_list_append(result, obj); ++ ++out: ++ if (bp) ++ buf_close(bp); ++ if (obj) ++ isns_object_release(obj); ++ isns_attr_list_destroy(&attrs); ++ return status; ++ ++internal_error: ++ isns_error("Unable to load %s: Internal error\n", ++ filename); ++ status = ISNS_INTERNAL_ERROR; ++ goto out; ++} ++ ++/* ++ * Load contents of directory into our database. ++ * ++ * We take two passes over the directory. In the first pass, we load ++ * all regular files containing objects. The file names correspond to ++ * the DB index. ++ * ++ * In the second pass, we load all directories, containing children of ++ * an object. The directories names are formed by the object's index, ++ * with ".d" appended to it. ++ */ ++static int ++__dbe_file_load_all(const char *dirpath, isns_object_list_t *result) ++{ ++ struct dirent *dp; ++ DIR *dir; ++ int status = ISNS_SUCCESS; ++ ++ if ((dir = opendir(dirpath)) == NULL) { ++ isns_error("DB: cannot open %s: %m\n", dirpath); ++ return ISNS_INTERNAL_ERROR; ++ } ++ ++ while ((dp = readdir(dir)) != NULL) { ++ struct stat stb; ++ const char *path; ++ ++ if (dp->d_name[0] == '.' ++ || !strcmp(dp->d_name, "DB")) ++ continue; ++ ++ path = __path_concat(dirpath, dp->d_name); ++ if (lstat(path, &stb) < 0) { ++ isns_error("DB: cannot stat %s: %m\n", path); ++ status = ISNS_INTERNAL_ERROR; ++ } else ++ if (S_ISREG(stb.st_mode)) { ++ status = __dbe_file_load_object(path, ++ dp->d_name, result); ++ } else { ++ isns_debug_state("DB: ignoring %s\n", path); ++ } ++ ++ if (status != ISNS_SUCCESS) ++ break; ++ } ++ ++ closedir(dir); ++ return status; ++} ++ ++/* ++ * Load and store DB metadata ++ */ ++static int ++__dbe_file_write_info(isns_db_t *db) ++{ ++ isns_db_backend_t *back = db->id_backend; ++ const char *path; ++ buf_t *bp; ++ int status = ISNS_INTERNAL_ERROR; ++ ++ path = __path_concat(back->idb_name, "DB"); ++ if ((bp = buf_open(path, O_CREAT|O_TRUNC|O_WRONLY)) == NULL) { ++ isns_error("Unable to write %s: %m\n", path); ++ goto out; ++ } ++ ++ if (buf_put32(bp, DBE_FILE_VERSION) ++ && buf_put32(bp, db->id_last_eid) ++ && buf_put32(bp, db->id_last_index)) ++ status = ISNS_SUCCESS; ++ ++out: ++ if (bp) ++ buf_close(bp); ++ return status; ++} ++ ++static int ++__dbe_file_load_info(isns_db_t *db) ++{ ++ isns_db_backend_t *back = db->id_backend; ++ struct isns_db_file_info info; ++ const char *path; ++ buf_t *bp = NULL; ++ int status; ++ ++ path = __path_concat(back->idb_name, "DB"); ++ if ((bp = buf_open(path, O_RDONLY)) == NULL) { ++ status = ISNS_NO_SUCH_ENTRY; ++ goto out; ++ } ++ ++ status = ISNS_INTERNAL_ERROR; ++ if (!buf_get32(bp, &info.db_version)) ++ goto out; ++ ++ if (info.db_version != DBE_FILE_VERSION) { ++ isns_error("DB file from unsupported version %04x\n", ++ info.db_version); ++ goto out; ++ } ++ ++ if (buf_get32(bp, &info.db_last_eid) ++ && buf_get32(bp, &info.db_last_index)) { ++ db->id_last_eid = info.db_last_eid; ++ db->id_last_index = info.db_last_index; ++ status = ISNS_SUCCESS; ++ } ++ ++out: ++ if (bp) ++ buf_close(bp); ++ return status; ++} ++ ++/* ++ * Find object with the given index. ++ */ ++static isns_object_t * ++__dbe_find_object(isns_object_list_t *list, uint32_t index) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ ++ if (obj->ie_index == index) ++ return obj; ++ } ++ return NULL; ++} ++ ++int ++isns_dbe_file_reload(isns_db_t *db) ++{ ++ isns_db_backend_t *back = db->id_backend; ++ int status; ++ unsigned int i; ++ ++ isns_debug_state("DB: loading all objects from %s\n", ++ back->idb_name); ++ ++ if (access(back->idb_name, R_OK) < 0) { ++ if (errno == ENOENT) { ++ /* Empty database is okay */ ++ return ISNS_NO_SUCH_ENTRY; ++ } ++ isns_error("Cannot open database %s: %m\n", back->idb_name); ++ return ISNS_INTERNAL_ERROR; ++ } ++ ++ status = __dbe_file_load_info(db); ++ if (status) ++ return status; ++ ++ status = __dbe_file_load_all(back->idb_name, db->id_objects); ++ if (status) ++ return status; ++ ++ /* Resolve parent/child relationship for all nodes */ ++ for (i = 0; i < db->id_objects->iol_count; ++i) { ++ isns_object_t *obj = db->id_objects->iol_data[i]; ++ uint32_t index = obj->ie_container_idx; ++ isns_object_t *parent; ++ ++ if (index == 0) ++ continue; ++ ++ obj->ie_container = NULL; ++ ++ parent = __dbe_find_object(db->id_objects, index); ++ if (parent == NULL) { ++ isns_warning("DB: object %u references " ++ "unknown container %u\n", ++ obj->ie_index, ++ index); ++ } else { ++ isns_object_attach(obj, parent); ++ } ++ } ++ ++ /* Add objects to the appropriate lists */ ++ for (i = 0; i < db->id_objects->iol_count; ++i) { ++ isns_object_template_t *tmpl; ++ isns_object_t *obj = db->id_objects->iol_data[i]; ++ ++ switch (obj->ie_state) { ++ case ISNS_OBJECT_STATE_MATURE: ++ isns_scope_add(db->id_global_scope, obj); ++ obj->ie_references++; ++ ++ tmpl = obj->ie_template; ++ if (tmpl->iot_build_relation ++ && !tmpl->iot_build_relation(db, obj, NULL)) ++ isns_warning("DB: cannot build relation for " ++ "object %u\n", ++ obj->ie_index); ++ ++ if (obj->ie_relation) ++ isns_relation_add(db->id_relations, ++ obj->ie_relation); ++ ++ if (ISNS_IS_ENTITY(obj)) ++ isns_esi_register(obj); ++ break; ++ ++ case ISNS_OBJECT_STATE_LIMBO: ++ isns_object_list_append(&db->id_limbo, obj); ++ break; ++ ++ default: ++ isns_error("Unexpected object state %d in object %u " ++ "loaded from %s\n", ++ obj->ie_state, obj->ie_index, ++ back->idb_name); ++ } ++ ++ /* Clear the dirty flag, which will be set when the ++ object is created. */ ++ obj->ie_flags &= ~ISNS_OBJECT_DIRTY; ++ } ++ ++ return ISNS_SUCCESS; ++} ++ ++int ++isns_dbe_file_sync(isns_db_t *db) ++{ ++ return __dbe_file_write_info(db); ++} ++ ++int ++isns_dbe_file_store(isns_db_t *db, const isns_object_t *obj) ++{ ++ isns_db_backend_t *back = db->id_backend; ++ int status; ++ ++ if (obj->ie_index == 0) { ++ isns_error("DB: Refusing to store object with index 0\n"); ++ return ISNS_INTERNAL_ERROR; ++ } ++ ++ status = __dbe_file_store_object(back->idb_name, obj); ++ if (status == ISNS_SUCCESS) ++ status = __dbe_file_store_children(back->idb_name, obj); ++ ++ return status; ++} ++ ++int ++isns_dbe_file_remove(isns_db_t *db, const isns_object_t *obj) ++{ ++ isns_db_backend_t *back = db->id_backend; ++ int status; ++ ++ status = __dbe_file_remove_object(back->idb_name, obj); ++ if (status == ISNS_SUCCESS) ++ status = __dbe_file_remove_children(back->idb_name, obj); ++ ++ return status; ++} ++ ++/* ++ * Create the file backend ++ */ ++isns_db_backend_t * ++isns_create_file_db_backend(const char *pathname) ++{ ++ isns_db_backend_t *back; ++ ++ isns_debug_state("Creating file DB backend (%s)\n", pathname); ++ ++ back = isns_calloc(1, sizeof(*back)); ++ back->idb_name = isns_strdup(pathname); ++ back->idb_reload = isns_dbe_file_reload; ++ back->idb_sync = isns_dbe_file_sync; ++ back->idb_store = isns_dbe_file_store; ++ back->idb_remove = isns_dbe_file_remove; ++ ++ return back; ++} ++ +diff --git a/utils/open-isns/db-policy.c b/utils/open-isns/db-policy.c +new file mode 100644 +index 0000000..a85a436 +--- /dev/null ++++ b/utils/open-isns/db-policy.c +@@ -0,0 +1,187 @@ ++/* ++ * Use database as policy and keystore ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#ifdef WITH_SECURITY ++#include ++#include ++#endif ++#include "isns.h" ++#include "security.h" ++#include "objects.h" ++#include "vendor.h" ++#include "util.h" ++#include "config.h" ++ ++/* ++ * DB keystore ++ */ ++typedef struct isns_db_keystore isns_db_keystore_t; ++struct isns_db_keystore { ++ isns_keystore_t sd_base; ++ isns_db_t * sd_db; ++ isns_object_t * sd_control; ++}; ++ ++/* ++ * Look up the policy object given its SPI ++ */ ++isns_object_t * ++__isns_db_keystore_lookup(isns_db_keystore_t *store, ++ const char *name, size_t namelen) ++{ ++ isns_attr_list_t keys = ISNS_ATTR_LIST_INIT; ++ char namebuf[256]; ++ ++ if (namelen >= sizeof(namebuf)) ++ return NULL; ++ memcpy(namebuf, name, namelen); ++ namebuf[namelen] = '\0'; ++ ++ isns_attr_list_append_string(&keys, ++ OPENISNS_TAG_POLICY_SPI, ++ namebuf); ++ return isns_db_lookup(store->sd_db, NULL, &keys); ++} ++ ++/* ++ * Load a DSA key from the DB store ++ */ ++static EVP_PKEY * ++__isns_db_keystore_find(isns_keystore_t *store_base, ++ const char *name, size_t namelen) ++{ ++#ifdef WITH_SECURITY ++ isns_db_keystore_t *store = (isns_db_keystore_t *) store_base; ++ isns_object_t *obj; ++ const void *key_data; ++ size_t key_size; ++ ++ obj = __isns_db_keystore_lookup(store, name, namelen); ++ if (obj == NULL) ++ return NULL; ++ ++ if (!isns_object_get_opaque(obj, OPENISNS_TAG_POLICY_KEY, ++ &key_data, &key_size)) ++ return NULL; ++ ++ return isns_dsa_decode_public(key_data, key_size); ++#else ++ return NULL; ++#endif ++} ++ ++/* ++ * Retrieve policy from database ++ */ ++static void ++__isns_db_keystore_copy_policy_string(isns_object_t *obj, ++ uint32_t tag, char **var) ++{ ++ const char *value; ++ ++ if (!isns_object_get_string(obj, tag, &value)) ++ return; ++ isns_assign_string(var, value); ++} ++ ++static void ++__isns_db_keystore_copy_policy_strings(isns_object_t *obj, ++ uint32_t tag, struct string_array *array) ++{ ++ isns_attr_list_t *attrs = &obj->ie_attrs; ++ unsigned int i; ++ ++ for (i = 0; i < attrs->ial_count; ++i) { ++ isns_attr_t *attr = attrs->ial_data[i]; ++ ++ if (attr->ia_tag_id != tag ++ || !ISNS_ATTR_IS_STRING(attr)) ++ continue; ++ isns_string_array_append(array, attr->ia_value.iv_string); ++ } ++} ++ ++static isns_policy_t * ++__isns_db_keystore_get_policy(isns_keystore_t *store_base, ++ const char *name, size_t namelen) ++{ ++ isns_db_keystore_t *store = (isns_db_keystore_t *) store_base; ++ isns_policy_t *policy; ++ isns_object_t *obj; ++ uint32_t intval; ++ ++ obj = __isns_db_keystore_lookup(store, name, namelen); ++ if (obj == NULL) ++ return NULL; ++ ++ policy = __isns_policy_alloc(name, namelen); ++ ++ /* retrieve policy bits from object */ ++#if 0 ++ __isns_db_keystore_copy_policy_string(obj, ++ OPENISNS_TAG_POLICY_SOURCE_NAME, ++ &policy->ip_source); ++#endif ++ __isns_db_keystore_copy_policy_string(obj, ++ OPENISNS_TAG_POLICY_ENTITY, ++ &policy->ip_entity); ++ __isns_db_keystore_copy_policy_string(obj, ++ OPENISNS_TAG_POLICY_DEFAULT_DD, ++ &policy->ip_dd_default); ++ __isns_db_keystore_copy_policy_strings(obj, ++ OPENISNS_TAG_POLICY_NODE_NAME, ++ &policy->ip_node_names); ++ ++ if (isns_object_get_uint32(obj, OPENISNS_TAG_POLICY_OBJECT_TYPE, &intval)) ++ policy->ip_object_types = intval; ++ if (isns_object_get_uint32(obj, OPENISNS_TAG_POLICY_NODE_TYPE, &intval)) ++ policy->ip_node_types = intval; ++ if (isns_object_get_uint32(obj, OPENISNS_TAG_POLICY_FUNCTIONS, &intval)) ++ policy->ip_functions = intval; ++ ++ return policy; ++} ++ ++void ++__isns_db_keystore_change_notify(const isns_db_event_t *ev, void *handle) ++{ ++ isns_db_keystore_t *store = handle; ++ isns_object_t *obj = ev->ie_object; ++ ++ if (isns_object_get_entity(obj) == store->sd_control) { ++ isns_debug_auth("DB keystore: policy data was modified\n"); ++ store->sd_base.ic_generation++; ++ } ++} ++ ++isns_keystore_t * ++isns_create_db_keystore(isns_db_t *db) ++{ ++ isns_db_keystore_t *store; ++ isns_object_t *entity; ++ ++ isns_debug_auth("Creating DB keystore\n"); ++ if (!(entity = isns_db_get_control(db))) { ++ isns_error("Could not create control entity in database\n"); ++ return NULL; ++ } ++ isns_debug_auth("Control entity is 0x%08x\n", entity->ie_index); ++ ++ store = isns_calloc(1, sizeof(*store)); ++ store->sd_base.ic_name = "database key store"; ++ store->sd_base.ic_find = __isns_db_keystore_find; ++ store->sd_base.ic_get_policy = __isns_db_keystore_get_policy; ++ store->sd_control = entity; ++ store->sd_db = db; ++ ++ isns_register_callback(__isns_db_keystore_change_notify, store); ++ ++ return (isns_keystore_t *) store; ++} ++ +diff --git a/utils/open-isns/db.c b/utils/open-isns/db.c +new file mode 100644 +index 0000000..c66dfbb +--- /dev/null ++++ b/utils/open-isns/db.c +@@ -0,0 +1,994 @@ ++/* ++ * iSNS object database ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "isns.h" ++#include "objects.h" ++#include "db.h" ++#include "util.h" ++ ++enum { ++ IDT_INSERT, ++ IDT_REMOVE, ++ IDT_UPDATE ++}; ++struct isns_db_trans { ++ struct isns_db_trans * idt_next; ++ int idt_action; ++ isns_object_t * idt_object; ++}; ++ ++/* Internal helpers */ ++static int isns_db_sanity_check(isns_db_t *); ++static int isns_db_get_key_tags(const isns_attr_list_t *, ++ uint32_t *, unsigned int); ++static int isns_db_keyed_compare(const isns_object_t *, ++ const isns_attr_list_t *, ++ const uint32_t *, unsigned int); ++ ++/* ++ * Open a database ++ */ ++static isns_db_t * ++isns_db_create(isns_db_backend_t *backend) ++{ ++ isns_db_t *db; ++ ++ db = isns_calloc(1, sizeof(*db)); ++ db->id_last_index = 1; ++ db->id_last_eid = 1; ++ db->id_backend = backend; ++ db->id_global_scope = isns_scope_alloc(db); ++ db->id_relations = isns_relation_soup_alloc(); ++ db->id_objects = &db->__id_objects; ++ ++ if (backend && backend->idb_reload) { ++ int status; ++ ++ status = backend->idb_reload(db); ++ /* "No such entry" is returned when the DB ++ * is still empty. */ ++ if (status != ISNS_SUCCESS ++ && status != ISNS_NO_SUCH_ENTRY) { ++ isns_error("Error loading database: %s\n", ++ isns_strerror(status)); ++ /* FIXME: isns_db_free(db); */ ++ return NULL; ++ } ++ ++ isns_db_sanity_check(db); ++ } ++ ++ return db; ++} ++ ++isns_db_t * ++isns_db_open(const char *location) ++{ ++ isns_db_backend_t *backend; ++ ++ if (location == NULL) { ++ isns_debug_state("Using in-memory DB\n"); ++ return isns_db_create(NULL); ++ } ++ ++ if (location[0] == '/') { ++ backend = isns_create_file_db_backend(location); ++ } else ++ if (!strncmp(location, "file:", 5)) { ++ backend = isns_create_file_db_backend(location + 5); ++ } else { ++ isns_error("Unsupported database type \"%s\"\n", ++ location); ++ return NULL; ++ } ++ ++ return isns_db_create(backend); ++} ++ ++isns_db_t * ++isns_db_open_shadow(isns_object_list_t *list) ++{ ++ isns_db_t *db; ++ ++ if ((db = isns_db_create(NULL)) != NULL) ++ db->id_objects = list; ++ return db; ++} ++ ++int ++isns_db_sanity_check(isns_db_t *db) ++{ ++ unsigned int i; ++ ++ i = 0; ++ while (i < db->id_objects->iol_count) { ++ isns_object_t *obj = db->id_objects->iol_data[i]; ++ ++ switch (obj->ie_state) { ++ case ISNS_OBJECT_STATE_MATURE: ++ /* Nothing yet. */ ++ break; ++ ++ case ISNS_OBJECT_STATE_LIMBO: ++ if (!ISNS_IS_ISCSI_NODE(obj) ++ && !ISNS_IS_PORTAL(obj)) { ++ isns_error("Unexpected object %u (%s) in limbo\n", ++ obj->ie_index, ++ obj->ie_template->iot_name); ++ isns_db_remove(db, obj); ++ } ++ break; ++ ++ default: ++ isns_error("Unexpected object state %d in object %u (%s)\n", ++ obj->ie_state, obj->ie_index, ++ obj->ie_template->iot_name); ++ isns_db_remove(db, obj); ++ break; ++ } ++ ++ i += 1; ++ } ++ ++ return 1; ++} ++ ++isns_object_t * ++isns_db_lookup(isns_db_t *db, ++ isns_object_template_t *tmpl, ++ const isns_attr_list_t *keys) ++{ ++ return isns_object_list_lookup(db->id_objects, tmpl, keys); ++} ++ ++int ++isns_db_gang_lookup(isns_db_t *db, ++ isns_object_template_t *tmpl, ++ const isns_attr_list_t *keys, ++ isns_object_list_t *result) ++{ ++ return isns_object_list_gang_lookup(db->id_objects, ++ tmpl, keys, result); ++} ++ ++/* ++ * Look up the storage node for the given source. ++ */ ++isns_object_t * ++isns_db_lookup_source_node(isns_db_t *db, ++ const isns_source_t *source) ++{ ++ isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; ++ isns_object_t *node; ++ ++ isns_attr_list_append_attr(&attrs, isns_source_attr(source)); ++ node = isns_db_lookup(db, NULL, &attrs); ++ isns_attr_list_destroy(&attrs); ++ ++ return node; ++} ++ ++isns_object_t * ++isns_db_vlookup(isns_db_t *db, ++ isns_object_template_t *tmpl, ++ ...) ++{ ++ isns_attr_list_t keys = ISNS_ATTR_LIST_INIT; ++ isns_object_t *obj = NULL; ++ va_list ap; ++ ++ va_start(ap, tmpl); ++ while (1) { ++ const isns_tag_type_t *tag_type; ++ isns_value_t value; ++ uint32_t tag; ++ ++ tag = va_arg(ap, unsigned int); ++ if (tag == 0) ++ break; ++ ++ tag_type = isns_tag_type_by_id(tag); ++ if (tag_type == NULL) { ++ isns_error("isns_db_vlookup: unknown tag %u\n", tag); ++ goto out; ++ } ++ ++ memset(&value, 0, sizeof(value)); ++ value.iv_type = tag_type->it_type; ++ switch (tag_type->it_type->it_id) { ++ case ISNS_ATTR_TYPE_STRING: ++ value.iv_string = va_arg(ap, char *); ++ break; ++ ++ case ISNS_ATTR_TYPE_INT32: ++ value.iv_int32 = va_arg(ap, int32_t); ++ break; ++ ++ case ISNS_ATTR_TYPE_UINT32: ++ value.iv_int32 = va_arg(ap, uint32_t); ++ break; ++ ++ case ISNS_ATTR_TYPE_IPADDR: ++ value.iv_ipaddr = *va_arg(ap, struct in6_addr *); ++ break; ++ ++ default: ++ isns_error("isns_db_vlookup: unsupported tag type %s\n", ++ value.iv_type->it_name); ++ goto out; ++ } ++ ++ isns_attr_list_append_value(&keys, tag, tag_type, &value); ++ } ++ ++ obj = isns_db_lookup(db, tmpl, &keys); ++ ++out: ++ isns_attr_list_destroy(&keys); ++ va_end(ap); ++ return obj; ++} ++ ++/* ++ * Find the next matching object ++ * ++ * This implementation could be a lot simpler if the ++ * RFC didn't make things so awfully complicated. ++ * It could simply have mandated the use of the object ++ * index attribute, period. ++ */ ++isns_object_t * ++__isns_db_get_next(const isns_object_list_t *list, ++ isns_object_template_t *tmpl, ++ const isns_attr_list_t *current, ++ const isns_attr_list_t *scope) ++{ ++ isns_object_t *next = NULL; ++ uint32_t tags[16]; ++ unsigned int i; ++ int num_tags; ++ ++ if (!tmpl) ++ return NULL; ++ ++ /* Get the search attribute tags, and sort them. ++ * Note, these don't have to be the standard key ++ * attributes for a given object type; the RFC ++ * also permits index attributes. ++ */ ++ num_tags = isns_db_get_key_tags(current, tags, 16); ++ if (num_tags < 0) ++ return NULL; ++ ++ /* ++ * 5.6.5.3. ++ * If the TLV length of the Message Key Attribute(s) is zero, ++ * then the first object entry in the iSNS database matching the ++ * Message Key type SHALL be returned in the Message Key of the ++ * corresponding DevGetNextRsp message. ++ */ ++ for (i = 0; i < current->ial_count; ++i) { ++ isns_attr_t *attr = current->ial_data[i]; ++ ++ if (!ISNS_ATTR_IS_NIL(attr)) ++ goto non_nil; ++ } ++ current = NULL; ++non_nil: ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ ++ if (obj->ie_template != tmpl) ++ continue; ++ if (scope && !isns_object_match(obj, scope)) ++ continue; ++ ++ /* compare returns -1 if the first list ++ * is "before" the second list, in terms of ++ * implicit ordering. */ ++ if (current ++ && isns_db_keyed_compare(obj, current, tags, num_tags) <= 0) { ++ /* obj less than or equal to current */ ++ continue; ++ } ++ ++ if (next == NULL ++ || isns_db_keyed_compare(obj, &next->ie_attrs, tags, num_tags) < 0) ++ next = obj; ++ } ++ ++ if (next) ++ isns_object_get(next); ++ return next; ++} ++ ++isns_object_t * ++isns_db_get_next(isns_db_t *db, ++ isns_object_template_t *tmpl, ++ const isns_attr_list_t *current, ++ const isns_attr_list_t *scope, ++ const isns_source_t *source) ++{ ++ return __isns_db_get_next(db->id_objects, ++ tmpl, current, scope); ++} ++ ++/* ++ * Get the search key tags ++ */ ++static int ++isns_db_get_key_tags(const isns_attr_list_t *keys, ++ uint32_t *tags, unsigned int max_tags) ++{ ++ unsigned int i; ++ ++ /* Get the search attribute tags, and sort them */ ++ for (i = 0; i < keys->ial_count; ++i) { ++ if (i >= 16) ++ return -1; ++ tags[i] = keys->ial_data[i]->ia_tag_id; ++ } ++ ++ /* FIXME: qsort the list */ ++ return i; ++} ++ ++/* ++ * Helper function for GetNext ++ */ ++static int ++isns_db_keyed_compare(const isns_object_t *obj, ++ const isns_attr_list_t *attrs, ++ const uint32_t *tags, unsigned int num_tags) ++{ ++ int ind = 0; ++ unsigned int i; ++ ++ for (i = 0; i < num_tags; ++i) { ++ isns_attr_t *attr1, *attr2; ++ uint32_t tag = tags[i]; ++ ++ if (!isns_attr_list_get_attr(&obj->ie_attrs, tag, &attr1)) ++ attr1 = NULL; ++ if (!isns_attr_list_get_attr(attrs, tag, &attr2)) ++ attr2 = NULL; ++ if (attr1 == attr2) { ++ ind = 0; ++ } else if (attr1 && attr2) { ++ ind = isns_attr_compare(attr1, attr2); ++ } else if (attr1 == NULL) { ++ ind = -1; ++ } else { ++ ind = 1; ++ } ++ if (ind) ++ break; ++ } ++ return ind; ++} ++ ++uint32_t ++isns_db_allocate_index(isns_db_t *db) ++{ ++ return db->id_last_index++; ++} ++ ++/* ++ * Insert an object into the database. ++ */ ++void ++__isns_db_insert(isns_db_t *db, isns_object_t *obj, unsigned int state) ++{ ++ uint32_t idx_tag = obj->ie_template->iot_index; ++ ++ switch (obj->ie_state) { ++ case ISNS_OBJECT_STATE_LIMBO: ++ /* The object was in limbo; now it goes ++ * live (again). It should have an index, ++ * and it should be on the global id_objects ++ * list too. ++ */ ++ isns_assert(state == ISNS_OBJECT_STATE_MATURE); ++ isns_assert(obj->ie_index); ++ isns_assert(obj->ie_users > 1); ++ isns_object_list_remove(&db->id_limbo, obj); ++ break; ++ ++ case ISNS_OBJECT_STATE_DEAD: ++ /* A DevAttrReg with the F_REPLACE bit set will cause ++ * the key object to be removed from the DB, which may ++ * kill it for good. ++ * The subsequent call to db_insert will assign a new ++ * index, and re-add it to the database. ++ */ ++ ++ case ISNS_OBJECT_STATE_LARVAL: ++ /* Larval objects can go either to mature or ++ * limbo state. */ ++ obj->ie_index = db->id_last_index++; ++ ++ if (idx_tag) ++ isns_object_set_uint32(obj, ++ idx_tag, ++ obj->ie_index); ++ ++ isns_object_list_append(db->id_objects, obj); ++ break; ++ ++ case ISNS_OBJECT_STATE_MATURE: ++ /* If we call db_insert on a mature object, treat ++ this as a NOP. */ ++ isns_assert(state == ISNS_OBJECT_STATE_MATURE); ++ return; ++ ++ default: ++ isns_error("Internal error: unexpected object %u (%s) " ++ "state %u in db_insert\n", ++ obj->ie_index, ++ obj->ie_template->iot_name, ++ obj->ie_state); ++ return; ++ } ++ ++ obj->ie_state = state; ++ ++ /* Add it to the global scope */ ++ if (state == ISNS_OBJECT_STATE_MATURE) { ++ isns_scope_add(db->id_global_scope, obj); ++ obj->ie_references++; ++ ++ /* See if this object represents a relationship ++ * (eg a portal group). */ ++ if (obj->ie_template->iot_relation_type) { ++ if (!obj->ie_relation) { ++ isns_warning("DB: inserting %s object " ++ "without relation\n", ++ obj->ie_template->iot_name); ++ } else { ++ isns_relation_add(db->id_relations, ++ obj->ie_relation); ++ } ++ } ++ ++ isns_mark_object(obj, ISNS_SCN_OBJECT_ADDED); ++ } ++ ++ isns_debug_state("DB: added object %u (%s) state %u\n", ++ obj->ie_index, ++ obj->ie_template->iot_name, ++ obj->ie_state); ++ ++ if (db->id_backend) { ++ db->id_backend->idb_store(db, obj); ++ db->id_backend->idb_sync(db); ++ } ++} ++ ++void ++isns_db_insert(isns_db_t *db, isns_object_t *obj) ++{ ++ __isns_db_insert(db, obj, ISNS_OBJECT_STATE_MATURE); ++} ++ ++void ++isns_db_insert_limbo(isns_db_t *db, isns_object_t *obj) ++{ ++ isns_assert(obj->ie_state == ISNS_OBJECT_STATE_LARVAL); ++ __isns_db_insert(db, obj, ISNS_OBJECT_STATE_LIMBO); ++} ++ ++/* ++ * Save an object after updating it ++ */ ++void ++isns_db_sync(isns_db_t *db) ++{ ++ isns_object_list_t *list = db->id_objects; ++ unsigned int i, saved = 0; ++ ++ if (!db->id_backend) ++ return; ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ ++ if (obj->ie_flags & ISNS_OBJECT_DIRTY) { ++ db->id_backend->idb_store(db, obj); ++ obj->ie_flags &= ~ISNS_OBJECT_DIRTY; ++ saved++; ++ } ++ } ++ if (saved) ++ db->id_backend->idb_sync(db); ++} ++ ++/* ++ * Remove an object from the database. ++ * This is slow and inefficient, due to the use ++ * of an object array. We should at least use ++ * a linked list, or maybe even a hash one day. ++ */ ++static void ++__isns_db_prepare_removal(isns_db_t *db, isns_object_t *obj) ++{ ++ isns_object_t *child; ++ ++ obj->ie_flags |= ISNS_OBJECT_DEAD; ++ isns_object_get(obj); ++ ++ /* The node is dead; it's no longer interested in SCNs */ ++ obj->ie_scn_mask = 0; ++ ++ /* Trigger an SCN event. */ ++ if (obj->ie_state == ISNS_OBJECT_STATE_MATURE) ++ isns_mark_object(obj, ISNS_SCN_OBJECT_REMOVED); ++ ++ /* If the object represents a relation between ++ * two other objects, sever that relationship. ++ */ ++ if (obj->ie_relation) { ++ isns_relation_remove(db->id_relations, ++ obj->ie_relation); ++ isns_relation_sever(obj->ie_relation); ++ isns_relation_release(obj->ie_relation); ++ obj->ie_relation = NULL; ++ } ++ ++ /* Detach the object from its container */ ++ isns_object_detach(obj); ++ ++ /* Remove it from the database */ ++ if (isns_scope_remove(db->id_global_scope, obj)) { ++ obj->ie_references--; ++ } else { ++ isns_warning("Unable to remove object from scope\n"); ++ } ++ ++ /* Recursively remove all children */ ++ while (obj->ie_children.iol_count) { ++ child = obj->ie_children.iol_data[0]; ++ __isns_db_prepare_removal(db, child); ++ } ++ ++ isns_debug_state("DB: removed object %u (%s)\n", ++ obj->ie_index, ++ obj->ie_template->iot_name); ++ ++ isns_object_list_append(&db->id_deferred, obj); ++ isns_object_release(obj); ++} ++ ++int ++isns_db_remove(isns_db_t *db, isns_object_t *obj) ++{ ++ isns_object_t *entity; ++ unsigned int i; ++ ++ /* Don't even bother if the object was never added */ ++ if (obj->ie_index == 0) ++ goto out; ++ ++ /* Obtain the containing entity before removal */ ++ entity = isns_object_get_entity(obj); ++ ++ /* We don't remove the object for real yet; ++ * this will happen later during db_purge */ ++ __isns_db_prepare_removal(db, obj); ++ ++ /* ++ * 5.6.5.4. ++ * If all Nodes and Portals associated with a Network Entity are ++ * deregistered, then the Network Entity SHALL also be removed. ++ * ++ * If both the Portal and iSCSI Storage Node objects associated ++ * with a Portal Group object are removed, then that Portal Group ++ * object SHALL also be removed. The Portal Group object SHALL ++ * remain registered as long as either of its associated Portal ++ * or iSCSI Storage Node objects remain registered. If a deleted ++ * Storage Node or Portal object is subsequently re-registered, ++ * then a relationship between the re- registered object and ++ * an existing Portal or Storage Node object registration, ++ * indicated by the PG object, SHALL be restored. ++ */ ++ if (ISNS_IS_ENTITY(obj)) ++ goto out; ++ ++ if (entity == NULL || !ISNS_IS_ENTITY(entity)) ++ goto out; ++ ++ /* Don't do this for the CONTROL entity. */ ++ if (entity->ie_flags & ISNS_OBJECT_PRIVATE) ++ goto out; ++ ++ /* Step 1: Purge all relationship objects (read: portal groups) ++ * where both referenced objects are dead. ++ */ ++ for (i = 0; i < entity->ie_children.iol_count; ) { ++ isns_object_t *child = entity->ie_children.iol_data[i]; ++ ++ if (child->ie_relation ++ && isns_relation_is_dead(child->ie_relation)) { ++ __isns_db_prepare_removal(db, child); ++ continue; ++ } ++ ++ i += 1; ++ } ++ ++ /* Step 2: If all portals, nodes and PGs have been unregistered, ++ * the list of children should be empty. */ ++ if (entity->ie_children.iol_count == 0) { ++ isns_debug_state("Last portal/node unregistered, removing entity\n"); ++ __isns_db_prepare_removal(db, entity); ++ } ++ ++out: ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * Purge deregistered objects. ++ * If we find they're still part of some discovery ++ * domain, they're moved to id_limbo; otherwise we'll ++ * destroy them for good. ++ */ ++void ++isns_db_purge(isns_db_t *db) ++{ ++ isns_object_list_t *list = &db->id_deferred; ++ unsigned int i; ++ ++ while (list->iol_count) { ++ isns_object_t *obj = list->iol_data[0]; ++ ++ if (obj->ie_references == 0) { ++ isns_debug_state("DB: destroying object %u (%s)\n", ++ obj->ie_index, ++ obj->ie_template->iot_name); ++ ++ if (db->id_backend) { ++ db->id_backend->idb_remove(db, obj); ++ /* db->id_backend->idb_sync(db); */ ++ } ++ ++ isns_object_list_remove(db->id_objects, obj); ++ obj->ie_state = ISNS_OBJECT_STATE_DEAD; ++ } else if (obj->ie_state != ISNS_OBJECT_STATE_LIMBO) { ++ isns_debug_state("DB: moving object %u (%s) to purgatory - " ++ "%u references left\n", ++ obj->ie_index, ++ obj->ie_template->iot_name, ++ obj->ie_references); ++ ++ isns_object_list_append(&db->id_limbo, obj); ++ obj->ie_state = ISNS_OBJECT_STATE_LIMBO; ++ isns_object_prune_attrs(obj); ++ ++ if (db->id_backend) { ++ db->id_backend->idb_store(db, obj); ++ db->id_backend->idb_sync(db); ++ } ++ } ++ ++ isns_object_list_remove(list, obj); ++ } ++ ++ /* Brute force - look at all objects in limbo and kill those ++ * that went out of scope */ ++ for (i = 0; i < db->id_limbo.iol_count; ) { ++ isns_object_t *obj = db->id_limbo.iol_data[i]; ++ ++ if (obj->ie_references == 0) { ++ isns_debug_state("DB: destroying object %u (%s)\n", ++ obj->ie_index, ++ obj->ie_template->iot_name); ++ ++ if (db->id_backend) { ++ db->id_backend->idb_remove(db, obj); ++ /* db->id_backend->idb_sync(db); */ ++ } ++ ++ obj->ie_state = ISNS_OBJECT_STATE_DEAD; ++ isns_object_list_remove(&db->id_limbo, obj); ++ isns_object_list_remove(db->id_objects, obj); ++ continue; ++ } ++ ++ i += 1; ++ } ++} ++ ++/* ++ * Expire old entities ++ * ++ * This code is still rather simple, but once we start ++ * using ESI things get rather complex quickly. ++ */ ++time_t ++isns_db_expire(isns_db_t *db) ++{ ++ isns_object_list_t *list = db->id_objects; ++ time_t now = time(NULL), next_timeout; ++ unsigned int i = 0; ++ ++ next_timeout = now + 3600; ++ if (isns_config.ic_registration_period == 0) ++ return next_timeout; ++ ++ while (i < list->iol_count) { ++ isns_object_t *obj; ++ uint64_t stamp; ++ uint32_t period; ++ ++ obj = list->iol_data[i]; ++ if (!ISNS_IS_ENTITY(obj)) ++ goto next; ++ ++ if (!isns_object_get_uint32(obj, ++ ISNS_TAG_REGISTRATION_PERIOD, ++ &period)) { ++ isns_debug_state("No registration period for entity %u\n", ++ obj->ie_index); ++ goto next; ++ } ++ ++ if (!isns_object_get_uint64(obj, ++ ISNS_TAG_TIMESTAMP, ++ &stamp)) { ++ isns_debug_state("No timestamp for entity %u\n", ++ obj->ie_index); ++ goto next; ++ } ++ ++ stamp += period; ++ if (stamp <= now) { ++ /* removing the object will move one ++ * object from the tail to the free ++ * slot in the list. So don't increment ++ * the index here. */ ++ isns_debug_state("Expiring entity %u\n", obj->ie_index); ++ isns_db_remove(db, obj); ++ goto next; ++ } else { ++ isns_debug_state("Entity %u will expire in %u sec\n", ++ obj->ie_index, (int) (stamp - now)); ++ if (stamp < next_timeout) ++ next_timeout = stamp; ++ } ++ ++next: ++ i += 1; ++ } ++ ++ /* Send out SCN notifications. ++ * This makes sure we won't have extraneous references ++ * on expired objects when we reach db_purge. */ ++ isns_flush_events(); ++ ++ return next_timeout; ++} ++ ++/* ++ * Very special function to make sure we always have a ++ * CONTROL entity. ++ */ ++isns_object_t * ++isns_db_get_control(isns_db_t *db) ++{ ++ isns_attr_list_t keys = ISNS_ATTR_LIST_INIT; ++ isns_object_list_t *list = db->id_objects; ++ isns_object_t *found = NULL; ++ unsigned int i; ++ ++ isns_attr_list_append_string(&keys, ++ ISNS_TAG_ENTITY_IDENTIFIER, ++ ISNS_ENTITY_CONTROL); ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj; ++ ++ obj = list->iol_data[i]; ++ if (!ISNS_IS_ENTITY(obj)) ++ continue; ++ if (isns_object_match(obj, &keys)) { ++ obj->ie_users++; ++ found = obj; ++ goto done; ++ } ++ } ++ ++ found = isns_create_object(&isns_entity_template, ++ &keys, NULL); ++ found->ie_flags |= ISNS_OBJECT_PRIVATE; ++ isns_db_insert(db, found); ++ isns_db_sync(db); ++ ++done: ++ return found; ++} ++ ++void ++isns_db_get_domainless(isns_db_t *db, ++ isns_object_template_t *tmpl, ++ isns_object_list_t *result) ++{ ++ isns_object_list_t *list = db->id_objects; ++ unsigned int i; ++ ++ if (!tmpl) ++ return; ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ ++ if (obj->ie_template == tmpl ++ && isns_bitvector_is_empty(obj->ie_membership)) ++ isns_object_list_append(result, obj); ++ } ++} ++ ++/* ++ * Create a relationship and store it in the DB ++ */ ++void ++isns_db_create_relation(isns_db_t *db, ++ isns_object_t *relating_object, ++ unsigned int relation_type, ++ isns_object_t *subordinate_object1, ++ isns_object_t *subordinate_object2) ++{ ++ isns_relation_t *rel; ++ ++ rel = isns_create_relation(relating_object, ++ relation_type, ++ subordinate_object1, ++ subordinate_object2); ++ if (rel) { ++ isns_relation_add(db->id_relations, rel); ++ isns_relation_release(rel); ++ } ++} ++ ++/* ++ * Get all objects related to @left through a relation ++ * of type @type. ++ */ ++void ++isns_db_get_relationship_objects(isns_db_t *db, ++ const isns_object_t *left, ++ unsigned int relation_type, ++ isns_object_list_t *result) ++{ ++ isns_relation_get_edge_objects(db->id_relations, ++ left, relation_type, ++ result); ++} ++ ++/* ++ * Get the object relating left and right. ++ * Usually called to find the portal group connecting ++ * a portal and a storage node, or a DD connecting ++ * two storage nodes. ++ */ ++isns_object_t * ++isns_db_get_relationship_object(isns_db_t *db, ++ const isns_object_t *left, ++ const isns_object_t *right, ++ unsigned int relation_type) ++{ ++ isns_relation_t *rel; ++ ++ /* Find a relation of the given type, connecting ++ * the two objects. */ ++ rel = isns_relation_find_edge(db->id_relations, ++ left, right, relation_type); ++ ++ if (rel == NULL) ++ return NULL; ++ ++ return isns_object_get(rel->ir_object); ++} ++ ++/* ++ * See if a relationship exists ++ */ ++int ++isns_db_relation_exists(isns_db_t *db, ++ const isns_object_t *relating_object, ++ const isns_object_t *left, ++ const isns_object_t *right, ++ unsigned int relation_type) ++{ ++ return isns_relation_exists(db->id_relations, ++ relating_object, ++ left, right, relation_type); ++} ++ ++/* ++ * Debug helper ++ */ ++void ++isns_db_print(isns_db_t *db, isns_print_fn_t *fn) ++{ ++ const isns_object_list_t *list = db->id_objects; ++ unsigned int i; ++ ++ fn("Dumping database contents\n" ++ "Backend: %s\n" ++ "Last EID: %u\n" ++ "Last Index: %u\n" ++ , ++ db->id_backend->idb_name, ++ db->id_last_eid, ++ db->id_last_index); ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ ++ fn("--------------\n" ++ "Object: index=%u type=<%s> state=%s", ++ obj->ie_index, ++ obj->ie_template->iot_name, ++ isns_object_state_string(obj->ie_state)); ++ if (obj->ie_container) ++ fn(" parent=%u", obj->ie_container->ie_index); ++ if (obj->ie_flags & ISNS_OBJECT_DIRTY) ++ fn(" DIRTY"); ++ if (obj->ie_flags & ISNS_OBJECT_PRIVATE) ++ fn(" PRIVATE"); ++ fn("\n"); ++ isns_attr_list_print(&obj->ie_attrs, fn); ++ } ++} ++ ++/* ++ * Generate a "random" entity identifier. This is used when ++ * a DevAttrReg request does not specify an entity, and the ++ * client's policy doesn't specify one either. ++ */ ++const char * ++isns_db_generate_eid(isns_db_t *db, char *buf, size_t size) ++{ ++ snprintf(buf, size, "isns.entity.%04d", db->id_last_eid); ++ db->id_last_eid++; ++ return buf; ++} ++ ++/* ++ * Highly primitive transaction handling. ++ * This is really just a hack for the iSNS server code, ++ * which wants to go along creating objects, and back out ++ * if something goes wrong. ++ */ ++void ++isns_db_begin_transaction(isns_db_t *db) ++{ ++ if (db->id_in_transaction) { ++ isns_error("isns_db_begin_transaction: running into pending transaction\n"); ++ isns_db_rollback(db); ++ } ++ db->id_in_transaction = 1; ++} ++ ++void ++isns_db_commit(isns_db_t *db) ++{ ++ /* Nothing yet */ ++ db->id_in_transaction = 0; ++} ++ ++void ++isns_db_rollback(isns_db_t *db) ++{ ++ /* Nothing yet */ ++ db->id_in_transaction = 0; ++} +diff --git a/utils/open-isns/db.h b/utils/open-isns/db.h +new file mode 100644 +index 0000000..148d930 +--- /dev/null ++++ b/utils/open-isns/db.h +@@ -0,0 +1,147 @@ ++/* ++ * iSNS object database ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#ifndef ISNS_DB_H ++#define ISNS_DB_H ++ ++#include "attrs.h" ++ ++typedef struct isns_db_backend isns_db_backend_t; ++ ++/* ++ * In-memory portion of object database. ++ * Stable storage is provided by different ++ * backends. ++ */ ++struct isns_db { ++ isns_object_list_t * id_objects; ++ isns_object_list_t __id_objects; ++ ++ isns_relation_soup_t * id_relations; ++ ++ uint32_t id_last_eid; ++ uint32_t id_last_index; ++ ++ isns_scope_t * id_global_scope; ++ isns_scope_t * id_default_scope; ++ ++ isns_db_backend_t * id_backend; ++ ++ unsigned int id_in_transaction : 1; ++ struct isns_db_trans * id_transact; ++ ++ /* This is for objects in limbo. When a client ++ * calls DevAttrDereg, the object will first be ++ * placed on the id_deferred list. ++ * When we're done processing the message, we ++ * invoke isns_db_purge, which looks at these ++ * objects. ++ * - if the reference count is 1, the object ++ * is deleted. ++ * - otherwise, we assume the object is referenced ++ * by a discovery domain. In this case, we prune ++ * the attribute list down to the key attr(s) ++ * plus the index attribute, and move it to ++ * the id_limbo list. ++ */ ++ isns_object_list_t id_deferred; ++ isns_object_list_t id_limbo; ++}; ++ ++ ++struct isns_db_backend { ++ char * idb_name; ++ ++ int (*idb_reload)(isns_db_t *); ++ int (*idb_sync)(isns_db_t *); ++ int (*idb_store)(isns_db_t *, ++ const isns_object_t *); ++ int (*idb_remove)(isns_db_t *, ++ const isns_object_t *); ++}; ++ ++extern isns_db_backend_t *isns_create_file_db_backend(const char *); ++extern isns_object_t * __isns_db_get_next(const isns_object_list_t *, ++ isns_object_template_t *, ++ const isns_attr_list_t *, ++ const isns_attr_list_t *); ++ ++extern isns_relation_soup_t *isns_relation_soup_alloc(void); ++extern isns_relation_t *isns_create_relation(isns_object_t *relating_object, ++ unsigned int relation_type, ++ isns_object_t *subordinate_object1, ++ isns_object_t *subordinate_object2); ++extern void isns_relation_sever(isns_relation_t *); ++extern void isns_relation_release(isns_relation_t *); ++extern void isns_relation_add(isns_relation_soup_t *, ++ isns_relation_t *); ++extern void isns_relation_remove(isns_relation_soup_t *, ++ isns_relation_t *); ++extern isns_object_t * isns_relation_get_other(const isns_relation_t *, ++ const isns_object_t *); ++extern isns_relation_t *isns_relation_find_edge(isns_relation_soup_t *, ++ const isns_object_t *, ++ const isns_object_t *, ++ unsigned int); ++extern void isns_relation_halfspace(isns_relation_soup_t *, ++ const isns_object_t *, ++ unsigned int, ++ isns_object_list_t *); ++extern void isns_relation_get_edge_objects(isns_relation_soup_t *, ++ const isns_object_t *, ++ unsigned int, ++ isns_object_list_t *); ++extern int isns_relation_exists(isns_relation_soup_t *, ++ const isns_object_t *relating_object, ++ const isns_object_t *left, ++ const isns_object_t *right, ++ unsigned int relation_type); ++extern int isns_relation_is_dead(const isns_relation_t *); ++ ++extern void isns_db_create_relation(isns_db_t *db, ++ isns_object_t *relating_object, ++ unsigned int relation_type, ++ isns_object_t *subordinate_object1, ++ isns_object_t *subordinate_object2); ++extern void isns_db_get_relationship_objects(isns_db_t *, ++ const isns_object_t *, ++ unsigned int relation_type, ++ isns_object_list_t *); ++extern isns_object_t * isns_db_get_relationship_object(isns_db_t *, ++ const isns_object_t *, ++ const isns_object_t *, ++ unsigned int relation_type); ++extern int isns_db_relation_exists(isns_db_t *db, ++ const isns_object_t *relating_object, ++ const isns_object_t *left, ++ const isns_object_t *right, ++ unsigned int relation_type); ++extern int isns_db_create_pg_relation(isns_db_t *, ++ isns_object_t *); ++ ++extern isns_scope_t * isns_scope_for_call(isns_db_t *, const isns_simple_t *); ++extern isns_scope_t * isns_scope_alloc(isns_db_t *); ++extern void isns_scope_release(isns_scope_t *); ++extern void isns_scope_add(isns_scope_t *, ++ isns_object_t *); ++extern int isns_scope_remove(isns_scope_t *, ++ isns_object_t *); ++extern int isns_scope_gang_lookup(isns_scope_t *, ++ isns_object_template_t *, ++ const isns_attr_list_t *, ++ isns_object_list_t *); ++extern isns_object_t * isns_scope_get_next(isns_scope_t *, ++ isns_object_template_t *, ++ const isns_attr_list_t *current, ++ const isns_attr_list_t *scope); ++extern void isns_scope_get_related(isns_scope_t *, ++ const isns_object_t *, ++ unsigned int, ++ isns_object_list_t *); ++extern isns_db_t * isns_scope_get_db(const isns_scope_t *); ++ ++ ++#endif /* ISNS_DB_H */ +diff --git a/utils/open-isns/dd.c b/utils/open-isns/dd.c +new file mode 100644 +index 0000000..c2dcd10 +--- /dev/null ++++ b/utils/open-isns/dd.c +@@ -0,0 +1,1306 @@ ++/* ++ * Handle DD registration/deregistration ++ * ++ * Discovery domains are weird, even in the context of ++ * iSNS. For once thing, all other objects have unique ++ * attributes; DDs attributes can appear several times. ++ * They should really have made each DD member an object ++ * in its own right. ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include "isns.h" ++#include "attrs.h" ++#include "objects.h" ++#include "message.h" ++#include "security.h" ++#include "util.h" ++#include "db.h" ++ ++#define DD_DEBUG ++ ++enum { ++ ISNS_DD_MEMBER_ISCSI_NODE = 1, ++ ISNS_DD_MEMBER_IFCP_NODE, ++ ISNS_DD_MEMBER_PORTAL, ++}; ++/* Must be zero/one: */ ++enum { ++ NOTIFY_MEMBER_ADDED = 0, ++ NOTIFY_MEMBER_REMOVED = 1 ++}; ++ ++typedef struct isns_dd isns_dd_t; ++typedef struct isns_dd_list isns_dd_list_t; ++typedef struct isns_dd_member isns_dd_member_t; ++ ++struct isns_dd { ++ uint32_t dd_id; ++ char * dd_name; ++ uint32_t dd_features; ++ isns_dd_member_t * dd_members; ++ ++ unsigned int dd_inserted : 1; ++ ++ isns_object_t * dd_object; ++}; ++ ++struct isns_dd_member { ++ isns_dd_member_t * ddm_next; ++ unsigned int ddm_type; ++ isns_object_ref_t ddm_object; ++ ++ unsigned int ddm_added : 1; ++ union { ++ uint32_t ddm_index; ++ ++ /* Index must be first in all structs below. ++ * Yeah, I know. Aliasing is bad. */ ++ struct isns_dd_portal { ++ uint32_t index; ++ isns_portal_info_t info; ++ } ddm_portal; ++ struct isns_dd_iscsi_node { ++ uint32_t index; ++ char * name; ++ } ddm_iscsi_node; ++ struct isns_dd_ifcp_node { ++ uint32_t index; ++ char * name; ++ } ddm_ifcp_node; ++ }; ++}; ++ ++struct isns_dd_list { ++ unsigned int ddl_count; ++ isns_dd_t ** ddl_data; ++}; ++ ++/* ++ * List of all discovery domains. ++ * This duplicates the DD information from the database, ++ * but unfortunately this can't be helped - we need to ++ * have fast algorithms to compute the membership of a ++ * node, and the relative visibility of two nodes. ++ */ ++static int isns_dd_list_initialized = 0; ++static isns_dd_list_t isns_dd_list; ++static uint32_t isns_dd_next_id = 1; ++ ++static isns_dd_t * isns_dd_alloc(void); ++static isns_dd_t * isns_dd_clone(const isns_dd_t *); ++static void isns_dd_release(isns_dd_t *); ++static int isns_dd_parse_attrs(isns_dd_t *, ++ isns_db_t *, const isns_attr_list_t *, ++ const isns_dd_t *, int); ++static int isns_dd_remove_members(isns_dd_t *, ++ isns_db_t *, ++ isns_dd_t *); ++static void isns_dd_notify(const isns_dd_t *, ++ isns_dd_member_t *, ++ isns_dd_member_t *, ++ int); ++static void isns_dd_add_members(isns_dd_t *, ++ isns_db_t *, ++ isns_dd_t *); ++static void isns_dd_store(isns_db_t *, const isns_dd_t *, int); ++static void isns_dd_destroy(isns_db_t *, isns_dd_t *); ++static void isns_dd_insert(isns_dd_t *); ++static isns_dd_t * isns_dd_by_id(uint32_t); ++static isns_dd_t * isns_dd_by_name(const char *); ++static isns_dd_member_t * isns_dd_create_member(isns_object_t *); ++static inline void isns_dd_member_free(isns_dd_member_t *); ++static int isns_dd_remove_member(isns_dd_t *, isns_object_t *); ++static void isns_dd_list_resize(isns_dd_list_t *, unsigned int); ++static void isns_dd_list_insert(isns_dd_list_t *, isns_dd_t *); ++static void isns_dd_list_remove(isns_dd_list_t *, isns_dd_t *); ++ ++static isns_object_t * isns_dd_get_member_object(isns_db_t *, ++ const isns_attr_t *, const isns_attr_t *, ++ int); ++ ++/* ++ * Create DDReg messages ++ */ ++isns_simple_t * ++isns_create_dd_registration(isns_client_t *clnt, const isns_attr_list_t *attrs) ++{ ++ isns_simple_t *msg; ++ isns_attr_t *id_attr; ++ ++ msg = isns_simple_create(ISNS_DD_REGISTER, clnt->ic_source, NULL); ++ if (msg == NULL) ++ return NULL; ++ ++ /* If the caller specified a DD_ID, use it in the ++ * message key. */ ++ if (isns_attr_list_get_attr(attrs, ISNS_TAG_DD_ID, &id_attr)) ++ isns_attr_list_append_attr(&msg->is_message_attrs, id_attr); ++ ++ isns_attr_list_copy(&msg->is_operating_attrs, attrs); ++ return msg; ++} ++ ++isns_simple_t * ++isns_create_dd_deregistration(isns_client_t *clnt, ++ uint32_t dd_id, const isns_attr_list_t *attrs) ++{ ++ isns_simple_t *msg; ++ ++ msg = isns_simple_create(ISNS_DD_DEREGISTER, clnt->ic_source, NULL); ++ if (msg == NULL) ++ return NULL; ++ ++ isns_attr_list_append_uint32(&msg->is_message_attrs, ++ ISNS_TAG_DD_ID, dd_id); ++ ++ isns_attr_list_copy(&msg->is_operating_attrs, attrs); ++ return msg; ++} ++ ++/* ++ * Process a DD registration ++ */ ++int ++isns_process_dd_registration(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) ++{ ++ isns_simple_t *reply = NULL; ++ isns_attr_list_t *keys = &call->is_message_attrs; ++ isns_attr_list_t *attrs = &call->is_operating_attrs; ++ isns_db_t *db = srv->is_db; ++ isns_dd_t *dd = NULL, *temp_dd = NULL; ++ isns_attr_t *attr; ++ uint32_t id = 0; ++ int status; ++ ++ /* ++ * 5.6.5.9. ++ * The Message Key, if used, contains the DD_ID of the Discovery ++ * Domain to be registered. If the Message Key contains a DD_ID ++ * of an existing DD entry in the iSNS database, then the DDReg ++ * message SHALL attempt to update the existing entry. If the ++ * DD_ID in the Message Key (if used) does not match an existing ++ * DD entry, then the iSNS server SHALL reject the DDReg message ++ * with a status code of 3 (Invalid Registration). ++ */ ++ switch (keys->ial_count) { ++ case 0: ++ /* Security: check if the client is allowed to ++ * create a discovery domain */ ++ if (!isns_policy_validate_object_creation(call->is_policy, ++ call->is_source, ++ &isns_dd_template, ++ keys, attrs, ++ call->is_function)) ++ goto unauthorized; ++ break; ++ ++ case 1: ++ attr = keys->ial_data[0]; ++ if (attr->ia_tag_id != ISNS_TAG_DD_ID) ++ goto reject; ++ if (ISNS_ATTR_IS_NIL(attr)) ++ break; ++ if (!ISNS_ATTR_IS_UINT32(attr)) ++ goto reject; ++ ++ id = attr->ia_value.iv_uint32; ++ if (id == 0) ++ goto reject; ++ ++ dd = isns_dd_by_id(id); ++ if (dd == NULL) { ++ isns_debug_state("DDReg for unknown ID=%u\n", id); ++ goto reject; ++ } ++ ++ /* Security: check if the client is allowed to ++ * mess with this DD. */ ++ isns_assert(dd->dd_object); ++ if (!isns_policy_validate_object_update(call->is_policy, ++ call->is_source, ++ dd->dd_object, attrs, ++ call->is_function)) ++ goto unauthorized; ++ ++ break; ++ ++ default: ++ goto reject; ++ } ++ ++ temp_dd = isns_dd_alloc(); ++ ++ /* Parse the attributes and build a DD object. */ ++ status = isns_dd_parse_attrs(temp_dd, db, attrs, dd, 1); ++ if (status != ISNS_SUCCESS) ++ goto out; ++ ++ if (dd == NULL) { ++ /* Create the DD, and copy the general information ++ * such asn features and symbolic name from temp_dd */ ++ dd = isns_dd_clone(temp_dd); ++ ++ /* Don't assign the attrs to the DD right away. ++ * First and foremost, they may be unsorted. Second, ++ * we really want to hand-pick through them due to ++ * the weird semantics mandated by the RFC. */ ++ dd->dd_object = isns_create_object(&isns_dd_template, NULL, NULL); ++ if (dd->dd_object == NULL) ++ goto reject; ++ ++ /* Insert new domain into database */ ++ isns_db_insert(db, dd->dd_object); ++ ++ /* Add it to the internal list. Assign DD_ID and ++ * symbolic name if none were given. ++ */ ++ isns_dd_insert(dd); ++ } else { ++ if (!dd->dd_id) ++ dd->dd_id = temp_dd->dd_id; ++ dd->dd_features = temp_dd->dd_features; ++ isns_assign_string(&dd->dd_name, temp_dd->dd_name); ++ } ++ ++ /* Send notifications. This must be done before merging ++ * the list of new members into the DD. ++ */ ++ isns_dd_notify(dd, dd->dd_members, temp_dd->dd_members, ++ NOTIFY_MEMBER_ADDED); ++ ++ /* Update the DD */ ++ isns_dd_add_members(dd, db, temp_dd); ++ ++ /* And add it to the database. */ ++ isns_dd_store(db, dd, 0); ++ ++ reply = isns_simple_create(ISNS_DD_REGISTER, srv->is_source, NULL); ++ isns_object_extract_all(dd->dd_object, &reply->is_operating_attrs); ++ ++ status = ISNS_SUCCESS; ++ ++out: ++ isns_dd_release(temp_dd); ++ isns_dd_release(dd); ++ *result = reply; ++ return status; ++ ++reject: ++ status = ISNS_INVALID_REGISTRATION; ++ goto out; ++ ++unauthorized: ++ status = ISNS_SOURCE_UNAUTHORIZED; ++ goto out; ++} ++ ++/* ++ * Process a DD deregistration ++ */ ++int ++isns_process_dd_deregistration(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) ++{ ++ isns_simple_t *reply = NULL; ++ isns_attr_list_t *keys = &call->is_message_attrs; ++ isns_attr_list_t *attrs = &call->is_operating_attrs; ++ isns_db_t *db = srv->is_db; ++ isns_dd_t *dd = NULL, *temp_dd = NULL; ++ isns_attr_t *attr; ++ uint32_t id = 0; ++ int status; ++ ++ /* ++ * 5.6.5.10. ++ * The Message Key Attribute for a DDDereg message is the DD ++ * ID for the Discovery Domain being removed or having members ++ * removed. ++ */ ++ if (keys->ial_count != 1) ++ goto reject; ++ ++ attr = keys->ial_data[0]; ++ if (attr->ia_tag_id != ISNS_TAG_DD_ID ++ || ISNS_ATTR_IS_NIL(attr) ++ || !ISNS_ATTR_IS_UINT32(attr)) ++ goto reject; ++ ++ id = attr->ia_value.iv_uint32; ++ if (id == 0) ++ goto reject; ++ ++ dd = isns_dd_by_id(id); ++ if (dd == NULL) ++ goto reject; ++ ++ /* Security: check if the client is permitted to ++ * modify the DD object. ++ */ ++ if (!isns_policy_validate_object_update(call->is_policy, ++ call->is_source, ++ dd->dd_object, attrs, ++ call->is_function)) ++ goto unauthorized; ++ ++ /* ++ * 5.6.5.10. ++ * If the DD ID matches an existing DD and there are ++ * no Operating Attributes, then the DD SHALL be removed and a ++ * success Status Code returned. Any existing members of that ++ * DD SHALL remain in the iSNS database without membership in ++ * the just-removed DD. ++ */ ++ if (attrs->ial_count == 0) { ++ isns_dd_member_t *mp; ++ ++ /* Zap the membership bit */ ++ for (mp = dd->dd_members; mp; mp = mp->ddm_next) { ++ isns_object_t *obj = mp->ddm_object.obj; ++ ++ isns_object_clear_membership(obj, dd->dd_id); ++ } ++ ++ /* Notify all DD members that they will lose the other ++ * nodes. */ ++ isns_dd_notify(dd, NULL, dd->dd_members, NOTIFY_MEMBER_REMOVED); ++ ++ isns_dd_destroy(db, dd); ++ } else { ++ /* Parse the attributes and build a temporary DD object. */ ++ temp_dd = isns_dd_alloc(); ++ status = isns_dd_parse_attrs(temp_dd, db, attrs, dd, 0); ++ if (status != ISNS_SUCCESS) ++ goto out; ++ ++ /* Update the DD object */ ++ status = isns_dd_remove_members(dd, db, temp_dd); ++ if (status != ISNS_SUCCESS) ++ goto out; ++ ++ /* Send notifications. This must be done before after ++ * updating the DD. ++ */ ++ isns_dd_notify(dd, dd->dd_members, temp_dd->dd_members, ++ NOTIFY_MEMBER_REMOVED); ++ ++ /* Store it in the database. */ ++ isns_dd_store(db, dd, 1); ++ } ++ ++ reply = isns_simple_create(ISNS_DD_DEREGISTER, srv->is_source, NULL); ++ status = ISNS_SUCCESS; ++ ++out: ++ isns_dd_release(temp_dd); ++ isns_dd_release(dd); ++ *result = reply; ++ return status; ++ ++reject: ++ status = ISNS_INVALID_DEREGISTRATION; ++ goto out; ++ ++unauthorized: ++ status = ISNS_SOURCE_UNAUTHORIZED; ++ goto out; ++} ++ ++static isns_dd_t * ++isns_dd_alloc(void) ++{ ++ return isns_calloc(1, sizeof(isns_dd_t)); ++} ++ ++/* ++ * Allocate a clone of the orig_dd, but without ++ * copying the members. ++ */ ++static isns_dd_t * ++isns_dd_clone(const isns_dd_t *orig_dd) ++{ ++ isns_dd_t *dd; ++ ++ dd = isns_dd_alloc(); ++ ++ dd->dd_id = orig_dd->dd_id; ++ dd->dd_features = orig_dd->dd_features; ++ dd->dd_object = isns_object_get(orig_dd->dd_object); ++ isns_assign_string(&dd->dd_name, orig_dd->dd_name); ++ ++ return dd; ++} ++ ++static void ++isns_dd_release(isns_dd_t *dd) ++{ ++ isns_dd_member_t *member; ++ ++ if (dd == NULL || dd->dd_inserted) ++ return; ++ ++ while ((member = dd->dd_members) != NULL) { ++ dd->dd_members = member->ddm_next; ++ isns_dd_member_free(member); ++ } ++ ++ if (dd->dd_object) ++ isns_object_release(dd->dd_object); ++ ++ isns_free(dd->dd_name); ++ isns_free(dd); ++} ++ ++static isns_dd_member_t * ++isns_dd_create_member(isns_object_t *obj) ++{ ++ isns_dd_member_t *new; ++ ++ new = isns_calloc(1, sizeof(*new)); ++ new->ddm_added = 1; ++ ++ if (ISNS_IS_ISCSI_NODE(obj)) ++ new->ddm_type = ISNS_DD_MEMBER_ISCSI_NODE; ++ else if (ISNS_IS_PORTAL(obj)) ++ new->ddm_type = ISNS_DD_MEMBER_PORTAL; ++ else if (ISNS_IS_FC_NODE(obj)) ++ new->ddm_type = ISNS_DD_MEMBER_IFCP_NODE; ++ else { ++ isns_free(new); ++ return NULL; ++ } ++ ++ isns_object_reference_set(&new->ddm_object, obj); ++ return new; ++} ++ ++static inline void ++isns_dd_member_free(isns_dd_member_t *member) ++{ ++ switch (member->ddm_type) { ++ case ISNS_DD_MEMBER_ISCSI_NODE: ++ isns_free(member->ddm_iscsi_node.name); ++ break; ++ ++ case ISNS_DD_MEMBER_IFCP_NODE: ++ isns_free(member->ddm_ifcp_node.name); ++ break; ++ } ++ ++ isns_object_reference_drop(&member->ddm_object); ++ isns_free(member); ++} ++ ++void ++isns_dd_get_members(uint32_t dd_id, isns_object_list_t *list, int active_only) ++{ ++ isns_dd_t *dd; ++ isns_dd_member_t *mp; ++ ++ dd = isns_dd_by_id(dd_id); ++ if (dd == NULL) ++ return; ++ ++ for (mp = dd->dd_members; mp; mp = mp->ddm_next) { ++ isns_object_t *obj = mp->ddm_object.obj; ++ ++ if (active_only ++ && obj->ie_state != ISNS_OBJECT_STATE_MATURE) ++ continue; ++ ++ isns_object_list_append(list, obj); ++ } ++} ++ ++/* ++ * Helper function to remove a member referencing the given object ++ */ ++static int ++isns_dd_remove_member(isns_dd_t *dd, isns_object_t *obj) ++{ ++ isns_dd_member_t *mp, **pos; ++ ++ pos = &dd->dd_members; ++ while ((mp = *pos) != NULL) { ++ if (mp->ddm_object.obj == obj) { ++ *pos = mp->ddm_next; ++ isns_dd_member_free(mp); ++ return 1; ++ } else { ++ pos = &mp->ddm_next; ++ } ++ } ++ ++ return 0; ++} ++ ++static void ++isns_dd_insert(isns_dd_t *dd) ++{ ++ if (dd->dd_inserted) ++ return; ++ ++ if (dd->dd_id == 0) { ++ uint32_t id = isns_dd_next_id; ++ unsigned int i; ++ ++ for (i = 0; i < isns_dd_list.ddl_count; ++i) { ++ isns_dd_t *cur = isns_dd_list.ddl_data[i]; ++ ++ if (cur->dd_id > id) ++ break; ++ if (cur->dd_id == id) ++ ++id; ++ } ++ isns_debug_state("Allocated new DD_ID %d\n", id); ++ dd->dd_id = id; ++ isns_dd_next_id = id + 1; ++ } ++ ++ /* ++ * When creating a new DD, if the DD_Symbolic_Name is ++ * not included in the Operating Attributes, or if it ++ * is included with a zero-length TLV, then the iSNS ++ * server SHALL provide a unique DD_Symbolic_Name value ++ * for the created DD. The assigned DD_Symbolic_Name ++ * value SHALL be returned in the DDRegRsp message. ++ */ ++ if (dd->dd_name == NULL) { ++ char namebuf[64]; ++ ++ snprintf(namebuf, sizeof(namebuf), "isns.dd%u", dd->dd_id); ++ isns_assign_string(&dd->dd_name, namebuf); ++ } ++ ++ isns_dd_list_insert(&isns_dd_list, dd); ++ dd->dd_inserted = 1; ++ ++#ifdef DD_DEBUG ++ /* Safety first - make sure domains are sorted by DD_ID */ ++ { ++ unsigned int i, prev_id = 0; ++ ++ for (i = 0; i < isns_dd_list.ddl_count; ++i) { ++ isns_dd_t *cur = isns_dd_list.ddl_data[i]; ++ ++ isns_assert(cur->dd_id > prev_id); ++ prev_id = cur->dd_id; ++ } ++ } ++#endif ++} ++ ++/* ++ * Resize the DD list ++ */ ++#define LIST_SIZE(n) (((n) + 15) & ~15) ++void ++isns_dd_list_resize(isns_dd_list_t *list, unsigned int last_index) ++{ ++ unsigned int new_size; ++ isns_dd_t **new_data; ++ ++ new_size = LIST_SIZE(last_index + 1); ++ if (new_size < list->ddl_count) ++ return; ++ ++ /* We don't use realloc here because we need ++ * to zero the new pointers anyway. */ ++ new_data = isns_calloc(new_size, sizeof(void *)); ++ isns_assert(new_data); ++ ++ memcpy(new_data, list->ddl_data, ++ list->ddl_count * sizeof(void *)); ++ isns_free(list->ddl_data); ++ ++ list->ddl_data = new_data; ++ list->ddl_count = last_index + 1; ++} ++ ++/* ++ * Find the insert position for a given DD ID. ++ * returns true iff the DD was found in the list. ++ */ ++static int ++__isns_dd_list_find_pos(isns_dd_list_t *list, unsigned int id, ++ unsigned int *where) ++{ ++ unsigned int hi, lo, md; ++ ++ lo = 0; ++ hi = list->ddl_count; ++ ++ /* binary search */ ++ while (lo < hi) { ++ isns_dd_t *cur; ++ ++ md = (lo + hi) / 2; ++ cur = list->ddl_data[md]; ++ ++ if (id == cur->dd_id) { ++ *where = md; ++ return 1; ++ } ++ ++ if (id < cur->dd_id) { ++ hi = md; ++ } else { ++ lo = md + 1; ++ } ++ } ++ ++ *where = hi; ++ return 0; ++} ++ ++/* ++ * In-order insert ++ */ ++static void ++isns_dd_list_insert(isns_dd_list_t *list, isns_dd_t *dd) ++{ ++ unsigned int pos; ++ ++ if (__isns_dd_list_find_pos(list, dd->dd_id, &pos)) { ++ isns_error("Internal error in %s: DD already listed\n", ++ __FUNCTION__); ++ return; ++ } ++ ++ isns_dd_list_resize(list, list->ddl_count); ++ /* Shift the tail of the list to make room for new entry. */ ++ memmove(list->ddl_data + pos + 1, ++ list->ddl_data + pos, ++ (list->ddl_count - pos - 1) * sizeof(void *)); ++ list->ddl_data[pos] = dd; ++} ++ ++/* ++ * Remove DD from list ++ */ ++void ++isns_dd_list_remove(isns_dd_list_t *list, isns_dd_t *dd) ++{ ++ unsigned int pos; ++ ++ if (!__isns_dd_list_find_pos(list, dd->dd_id, &pos)) ++ return; ++ ++ /* Shift the tail of the list */ ++ memmove(list->ddl_data + pos, ++ list->ddl_data + pos + 1, ++ (list->ddl_count - pos - 1) * sizeof(void *)); ++ list->ddl_count -= 1; ++} ++ ++isns_dd_t * ++isns_dd_by_id(uint32_t id) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < isns_dd_list.ddl_count; ++i) { ++ isns_dd_t *dd = isns_dd_list.ddl_data[i]; ++ ++ if (dd && dd->dd_id == id) ++ return dd; ++ } ++ ++ return NULL; ++} ++ ++static isns_dd_t * ++isns_dd_by_name(const char *name) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < isns_dd_list.ddl_count; ++i) { ++ isns_dd_t *dd = isns_dd_list.ddl_data[i]; ++ ++ if (dd && !strcmp(dd->dd_name, name)) ++ return dd; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Validate the operating attributes, which is surprisingly ++ * tedious for DDs. It appears as if the whole DD/DDset ++ * stuff has been slapped onto iSNS as an afterthought. ++ * ++ * DDReg has some funky rules about how eg iSCSI nodes ++ * can be identified by either name or index, and how they ++ * relate to each other. Unfortunately, the RFC is very vague ++ * in describing how to treat DDReg message that mix these ++ * two types of identification, except by saying they ++ * need to be consistent. ++ */ ++static int ++isns_dd_parse_attrs(isns_dd_t *dd, isns_db_t *db, ++ const isns_attr_list_t *attrs, ++ const isns_dd_t *orig_dd, ++ int is_registration) ++{ ++ isns_dd_member_t **tail; ++ const isns_dd_t *conflict; ++ unsigned int i; ++ int rv = ISNS_SUCCESS; ++ ++ if (orig_dd) { ++ dd->dd_id = orig_dd->dd_id; ++ dd->dd_features = orig_dd->dd_features; ++ isns_assign_string(&dd->dd_name, orig_dd->dd_name); ++ } ++ ++ isns_assert(dd->dd_members == NULL); ++ tail = &dd->dd_members; ++ ++ for (i = 0; i < attrs->ial_count; ++i) { ++ isns_object_t *obj = NULL; ++ isns_attr_t *attr, *next = NULL; ++ const char *name; ++ uint32_t id; ++ ++ attr = attrs->ial_data[i]; ++ ++ if (!isns_object_attr_valid(&isns_dd_template, attr->ia_tag_id)) ++ return ISNS_INVALID_REGISTRATION; ++ ++ switch (attr->ia_tag_id) { ++ case ISNS_TAG_DD_ID: ++ /* Ignore this attribute in DDDereg messages */ ++ if (!is_registration) ++ continue; ++ ++ /* ++ * 5.6.5.9. ++ * A DDReg message with no Message Key SHALL result ++ * in the attempted creation of a new Discovery Domain ++ * (DD). If the DD_ID attribute (with non-zero length) ++ * is included among the Operating Attributes in the ++ * DDReg message, then the new Discovery Domain SHALL be ++ * assigned the value contained in that DD_ID attribute. ++ * ++ * If the DD_ID is included in both the Message ++ * Key and Operating Attributes, then the DD_ID ++ * value in the Message Key MUST be the same as ++ * the DD_ID value in the Operating Attributes. ++ * ++ * Implementer's note: It's not clear why the standard ++ * makes an exception for the DD_ID, while all other ++ * index attributes are read-only. ++ */ ++ if (ISNS_ATTR_IS_NIL(attr)) ++ break; ++ ++ id = attr->ia_value.iv_uint32; ++ if (dd->dd_id != 0) { ++ if (dd->dd_id != id) ++ goto invalid; ++ } else if ((conflict = isns_dd_by_id(id)) != NULL) { ++ isns_debug_state("DDReg: requested ID %d " ++ "clashes with existing DD (%s)\n", ++ id, conflict->dd_name); ++ goto invalid; ++ } ++ dd->dd_id = id; ++ break; ++ ++ case ISNS_TAG_DD_SYMBOLIC_NAME: ++ /* Ignore this attribute in DDDereg messages */ ++ if (!is_registration) ++ continue; ++ ++ /* ++ * If the DD_Symbolic_Name is an operating ++ * attribute and its value is unique (i.e., it ++ * does not match the registered DD_Symbolic_Name ++ * for another DD), then the value SHALL be stored ++ * in the iSNS database as the DD_Symbolic_Name ++ * for the specified Discovery Domain. If the ++ * value for the DD_Symbolic_Name is not unique, ++ * then the iSNS server SHALL reject the attempted ++ * DD registration with a status code of 3 ++ * (Invalid Registration). ++ */ ++ if (ISNS_ATTR_IS_NIL(attr)) ++ break; ++ ++ name = attr->ia_value.iv_string; ++ if (dd->dd_name && strcmp(name, dd->dd_name)) { ++ isns_debug_state("DDReg: symbolic name conflict: " ++ "id=%d name=%s requested=%s\n", ++ dd->dd_id, dd->dd_name, name); ++ goto invalid; ++ } ++ if (dd->dd_name) ++ break; ++ ++ if ((conflict = isns_dd_by_name(name)) != NULL) { ++ isns_debug_state("DDReg: requested symbolic name (%s) " ++ "clashes with existing DD (id=%d)\n", ++ name, conflict->dd_id); ++ goto invalid; ++ } ++ isns_assign_string(&dd->dd_name, name); ++ break; ++ ++ case ISNS_TAG_DD_FEATURES: ++ /* Ignore this attribute in DDDereg messages */ ++ if (!is_registration) ++ continue; ++ ++ /* ++ * When creating a new DD, if the DD_Features ++ * attribute is not included in the Operating ++ * Attributes, then the iSNS server SHALL assign ++ * the default value. The default value for ++ * DD_Features is 0. ++ */ ++ if (ISNS_ATTR_IS_UINT32(attr)) ++ dd->dd_features = attr->ia_value.iv_uint32; ++ break; ++ ++ case ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR: ++ /* portal address must be followed by port */ ++ if (i + 1 >= attrs->ial_count) ++ goto invalid; ++ ++ next = attrs->ial_data[i + 1]; ++ if (next->ia_tag_id != ISNS_TAG_DD_MEMBER_PORTAL_TCP_UDP_PORT) ++ goto invalid; ++ i += 1; ++ /* fallthru to normal case */ ++ ++ case ISNS_TAG_DD_MEMBER_PORTAL_INDEX: ++ case ISNS_TAG_DD_MEMBER_ISCSI_INDEX: ++ case ISNS_TAG_DD_MEMBER_ISCSI_NAME: ++ case ISNS_TAG_DD_MEMBER_FC_PORT_NAME: ++ if (ISNS_ATTR_IS_NIL(attr)) ++ goto invalid; ++ ++ obj = isns_dd_get_member_object(db, ++ attr, next, ++ is_registration); ++ /* For a DD deregistration, it's okay if the ++ * object does not exist. */ ++ if (obj == NULL && is_registration) ++ goto invalid; ++ break; ++ ++ invalid: ++ rv = ISNS_INVALID_REGISTRATION; ++ continue; ++ ++ } ++ ++ if (obj) { ++ if (is_registration ++ && isns_object_test_membership(obj, dd->dd_id)) { ++ /* Duplicates are ignored */ ++ isns_debug_state("Ignoring duplicate DD registration " ++ "for %s %u\n", ++ obj->ie_template->iot_name, ++ obj->ie_index); ++ } else { ++ /* This just adds the member to the temporary DD object, ++ * without changing any state in the database. */ ++ isns_dd_member_t *new; ++ ++ new = isns_dd_create_member(obj); ++ if (new) { ++ *tail = new; ++ tail = &new->ddm_next; ++ } ++ } ++ isns_object_release(obj); ++ } ++ } ++ ++ return rv; ++} ++ ++/* ++ * Helper function: extract live nodes from the DD member list ++ */ ++static inline void ++isns_dd_get_member_nodes(isns_dd_member_t *members, isns_object_list_t *result) ++{ ++ isns_dd_member_t *mp; ++ ++ /* Extract iSCSI nodes from both list. */ ++ for (mp = members; mp; mp = mp->ddm_next) { ++ isns_object_t *obj = mp->ddm_object.obj; ++ ++ if (ISNS_IS_ISCSI_NODE(obj) ++ && obj->ie_state == ISNS_OBJECT_STATE_MATURE) ++ isns_object_list_append(result, obj); ++ } ++} ++ ++void ++isns_dd_notify(const isns_dd_t *dd, isns_dd_member_t *unchanged, ++ isns_dd_member_t *changed, int removed) ++{ ++ isns_object_list_t dd_objects = ISNS_OBJECT_LIST_INIT; ++ isns_object_list_t changed_objects = ISNS_OBJECT_LIST_INIT; ++ unsigned int i, j, event; ++ ++ /* Extract iSCSI nodes from both list. */ ++ isns_dd_get_member_nodes(unchanged, &dd_objects); ++ isns_dd_get_member_nodes(changed, &changed_objects); ++ ++ /* Send a management SCN multicast to all ++ * control nodes that care. */ ++ event = removed? ISNS_SCN_DD_MEMBER_REMOVED_MASK : ISNS_SCN_DD_MEMBER_ADDED_MASK; ++ for (i = 0; i < changed_objects.iol_count; ++i) { ++ isns_object_t *obj = changed_objects.iol_data[i]; ++ ++ isns_object_event(obj, ++ event | ISNS_SCN_MANAGEMENT_REGISTRATION_MASK, ++ dd->dd_object); ++ } ++ ++#ifdef notagoodidea ++ /* Not sure - it may be good to send OBJECT ADDED/REMOVED instead ++ * of the DD membership messages. However, right now the SCN code ++ * will nuke all SCN registrations for a node when it sees a ++ * REMOVE event for it. ++ */ ++ event = removed? ISNS_SCN_OBJECT_REMOVED_MASK : ISNS_SCN_OBJECT_ADDED_MASK; ++#endif ++ ++ /* If we added an iscsi node, loop over all members ++ * and send unicast events to each iscsi node, ++ * informing them that a new member has been added/removed. ++ */ ++ for (j = 0; j < changed_objects.iol_count; ++j) { ++ isns_object_t *changed = changed_objects.iol_data[j]; ++ ++ for (i = 0; i < dd_objects.iol_count; ++i) { ++ isns_object_t *obj = dd_objects.iol_data[i]; ++ ++ /* For member removal, do not send notifications ++ * if the two nodes are still visible to each ++ * other through a different discovery domain */ ++ if (removed && isns_object_test_visibility(obj, changed)) ++ continue; ++ ++ /* Inform the old node that the new node was ++ * added/removed. */ ++ isns_unicast_event(obj, changed, event, NULL); ++ ++ /* Inform the new node that the old node became ++ * (in)accessible to it. */ ++ isns_unicast_event(changed, obj, event, NULL); ++ } ++ ++ /* Finally, inform each changed node of the other ++ * DD members that became (in)accessible to it. */ ++ for (i = 0; i < changed_objects.iol_count; ++i) { ++ isns_object_t *obj = changed_objects.iol_data[i]; ++ ++ if (obj == changed) ++ continue; ++ ++ if (removed && isns_object_test_visibility(obj, changed)) ++ continue; ++ ++ isns_unicast_event(changed, obj, event, NULL); ++ } ++ } ++} ++ ++void ++isns_dd_add_members(isns_dd_t *dd, isns_db_t *db, isns_dd_t *new_dd) ++{ ++ isns_dd_member_t *mp, **tail; ++ ++ for (mp = new_dd->dd_members; mp; mp = mp->ddm_next) { ++ const char *node_name; ++ isns_object_t *obj = mp->ddm_object.obj; ++ ++ /* ++ * If the Operating Attributes contain a DD ++ * Member iSCSI Name value for a Storage Node ++ * that is currently not registered in the iSNS ++ * database, then the iSNS server MUST allocate an ++ * unused iSCSI Node Index for that Storage Node. ++ * The assigned iSCSI Node Index SHALL be returned ++ * in the DDRegRsp message as the DD Member iSCSI ++ * Node Index. The allocated iSCSI Node Index ++ * value SHALL be assigned to the Storage Node ++ * if and when it registers in the iSNS database. ++ * [And likewise for portals] ++ */ ++ if (obj->ie_index == 0) ++ isns_db_insert_limbo(db, obj); ++ mp->ddm_index = obj->ie_index; ++ ++ /* Record the fact that the object is a member of ++ * this DD */ ++ isns_object_mark_membership(obj, dd->dd_id); ++ ++ switch (mp->ddm_type) { ++ case ISNS_DD_MEMBER_ISCSI_NODE: ++ if (isns_object_get_string(obj, ISNS_TAG_ISCSI_NAME, &node_name)) ++ isns_assign_string(&mp->ddm_iscsi_node.name, node_name); ++ ++ break; ++ ++ case ISNS_DD_MEMBER_IFCP_NODE: ++ if (isns_object_get_string(obj, ISNS_TAG_FC_PORT_NAME_WWPN, &node_name)) ++ isns_assign_string(&mp->ddm_ifcp_node.name, node_name); ++ ++ break; ++ ++ case ISNS_DD_MEMBER_PORTAL: ++ isns_portal_from_object(&mp->ddm_portal.info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ obj); ++ break; ++ } ++ } ++ ++ /* Find the tail of the DD member list */ ++ tail = &dd->dd_members; ++ while ((mp = *tail) != NULL) ++ tail = &mp->ddm_next; ++ ++ /* Append the new list of members */ ++ *tail = new_dd->dd_members; ++ new_dd->dd_members = NULL; ++} ++ ++/* ++ * Remove members from a DD ++ */ ++int ++isns_dd_remove_members(isns_dd_t *dd, isns_db_t *db, isns_dd_t *temp_dd) ++{ ++ isns_dd_member_t *mp; ++ ++ for (mp = temp_dd->dd_members; mp; mp = mp->ddm_next) { ++ isns_object_t *obj = mp->ddm_object.obj; ++ ++ /* Clear the membership bit. If the object wasn't in this ++ * DD to begin with, bail out right away. */ ++ if (!isns_object_clear_membership(obj, dd->dd_id)) { ++ isns_debug_state("DD dereg: object %d is not in this DD\n", ++ obj->ie_index); ++ continue; ++ } ++ ++ if (!isns_dd_remove_member(dd, obj)) ++ isns_error("%s: DD member not found in internal list\n", ++ __FUNCTION__); ++ } ++ ++ return ISNS_SUCCESS; ++} ++ ++void ++isns_dd_store(isns_db_t *db, const isns_dd_t *dd, int rewrite) ++{ ++ isns_object_t *obj = dd->dd_object; ++ isns_dd_member_t *member; ++ ++ if (rewrite) ++ isns_object_prune_attrs(obj); ++ ++ isns_object_set_uint32(obj, ISNS_TAG_DD_ID, dd->dd_id); ++ isns_object_set_string(obj, ISNS_TAG_DD_SYMBOLIC_NAME, dd->dd_name); ++ isns_object_set_uint32(obj, ISNS_TAG_DD_FEATURES, dd->dd_features); ++ ++ for (member = dd->dd_members; member; member = member->ddm_next) { ++ struct isns_dd_iscsi_node *node; ++ struct isns_dd_portal *portal; ++ ++ if (!member->ddm_added && !rewrite) ++ continue; ++ ++ switch (member->ddm_type) { ++ case ISNS_DD_MEMBER_ISCSI_NODE: ++ node = &member->ddm_iscsi_node; ++ ++ isns_object_set_uint32(obj, ++ ISNS_TAG_DD_MEMBER_ISCSI_INDEX, ++ node->index); ++ if (node->name) ++ isns_object_set_string(obj, ++ ISNS_TAG_DD_MEMBER_ISCSI_NAME, ++ node->name); ++ break; ++ ++ case ISNS_DD_MEMBER_PORTAL: ++ portal = &member->ddm_portal; ++ ++ isns_object_set_uint32(obj, ++ ISNS_TAG_DD_MEMBER_PORTAL_INDEX, ++ portal->index); ++ if (portal->info.addr.sin6_family != AF_UNSPEC) { ++ isns_portal_to_object(&portal->info, ++ ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR, ++ ISNS_TAG_DD_MEMBER_PORTAL_TCP_UDP_PORT, ++ obj); ++ } ++ break; ++ } ++ ++ member->ddm_added = 0; ++ } ++} ++ ++/* ++ * Destroy a DD ++ * The caller should call isns_dd_release to free the DD object. ++ */ ++void ++isns_dd_destroy(isns_db_t *db, isns_dd_t *dd) ++{ ++ isns_db_remove(db, dd->dd_object); ++ isns_dd_list_remove(&isns_dd_list, dd); ++ dd->dd_inserted = 0; ++} ++ ++int ++isns_dd_load_all(isns_db_t *db) ++{ ++ isns_object_list_t list = ISNS_OBJECT_LIST_INIT; ++ unsigned int i; ++ int rc; ++ ++ if (isns_dd_list_initialized) ++ return ISNS_SUCCESS; ++ ++ rc = isns_db_gang_lookup(db, &isns_dd_template, NULL, &list); ++ if (rc != ISNS_SUCCESS) ++ return rc; ++ ++ for (i = 0; i < list.iol_count; ++i) { ++ isns_object_t *obj = list.iol_data[i]; ++ isns_dd_t *dd = NULL, *temp_dd = NULL; ++ isns_dd_member_t *mp; ++ ++ temp_dd = isns_dd_alloc(); ++ ++ rc = isns_dd_parse_attrs(temp_dd, db, &obj->ie_attrs, NULL, 1); ++ if (rc) { ++ if (temp_dd->dd_id == 0) { ++ isns_error("Problem converting DD object (index 0x%x). No DD_ID\n", ++ obj->ie_index); ++ goto next; ++ } ++ isns_error("Problem converting DD %u. Proceeding anyway.\n", ++ temp_dd->dd_id); ++ } else { ++ isns_debug_state("Loaded DD %d from database\n", temp_dd->dd_id); ++ } ++ ++ dd = isns_dd_clone(temp_dd); ++ ++ dd->dd_object = isns_object_get(obj); ++ ++ isns_dd_insert(dd); ++ isns_dd_add_members(dd, db, temp_dd); ++ ++ /* Clear the ddm_added flag for all members, to ++ * prevent all information from being duplicated ++ * to the DB on the next DD modification. */ ++ for (mp = dd->dd_members; mp; mp = mp->ddm_next) ++ mp->ddm_added = 0; ++ ++next: ++ isns_dd_release(temp_dd); ++ } ++ ++ isns_object_list_destroy(&list); ++ isns_dd_list_initialized = 1; ++ return ISNS_SUCCESS; ++} ++ ++isns_object_t * ++isns_dd_get_member_object(isns_db_t *db, const isns_attr_t *key1, ++ const isns_attr_t *key2, ++ int create) ++{ ++ isns_attr_list_t query = ISNS_ATTR_LIST_INIT; ++ isns_object_template_t *tmpl = NULL; ++ isns_object_t *obj; ++ isns_portal_info_t portal_info; ++ const char *key_string = NULL; ++ uint32_t key_index = 0; ++ ++ switch (key1->ia_tag_id) { ++ case ISNS_TAG_DD_MEMBER_ISCSI_INDEX: ++ key_index = key1->ia_value.iv_uint32; ++ isns_attr_list_append_uint32(&query, ++ ISNS_TAG_ISCSI_NODE_INDEX, ++ key_index); ++ tmpl = &isns_iscsi_node_template; ++ break; ++ ++ case ISNS_TAG_DD_MEMBER_ISCSI_NAME: ++ key_string = key1->ia_value.iv_string; ++ isns_attr_list_append_string(&query, ++ ISNS_TAG_ISCSI_NAME, ++ key_string); ++ tmpl = &isns_iscsi_node_template; ++ break; ++ ++ case ISNS_TAG_DD_MEMBER_FC_PORT_NAME: ++ key_string = key1->ia_value.iv_string; ++ isns_attr_list_append_string(&query, ++ ISNS_TAG_FC_PORT_NAME_WWPN, ++ key_string); ++ tmpl = &isns_fc_port_template; ++ break; ++ ++ case ISNS_TAG_DD_MEMBER_PORTAL_INDEX: ++ key_index = key1->ia_value.iv_uint32; ++ isns_attr_list_append_uint32(&query, ++ ISNS_TAG_PORTAL_INDEX, ++ key_index); ++ tmpl = &isns_portal_template; ++ break; ++ ++ case ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR: ++ if (!isns_portal_from_attr_pair(&portal_info, key1, key2) ++ || !isns_portal_to_attr_list(&portal_info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ &query)) ++ return NULL; ++ ++ key_string = isns_portal_string(&portal_info); ++ tmpl = &isns_portal_template; ++ break; ++ ++ default: ++ return NULL; ++ } ++ ++ obj = isns_db_lookup(db, tmpl, &query); ++ if (!obj && create) { ++ if (!key_string) { ++ isns_debug_state("Attempt to register %s DD member " ++ "with unknown index %u\n", ++ tmpl->iot_name, key_index); ++ goto out; ++ } ++ ++ obj = isns_create_object(tmpl, &query, NULL); ++ if (obj != NULL) ++ isns_debug_state("Created limbo object for " ++ "%s DD member %s\n", ++ tmpl->iot_name, key_string); ++ } ++ ++out: ++ isns_attr_list_destroy(&query); ++ return obj; ++ ++} +diff --git a/utils/open-isns/deregister.c b/utils/open-isns/deregister.c +new file mode 100644 +index 0000000..3a7b7a6 +--- /dev/null ++++ b/utils/open-isns/deregister.c +@@ -0,0 +1,271 @@ ++/* ++ * Handle iSNS Device Deregistration ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include "isns.h" ++#include "attrs.h" ++#include "objects.h" ++#include "message.h" ++#include "security.h" ++#include "util.h" ++#include "db.h" ++ ++extern isns_source_t * isns_server_source; ++ ++ ++/* ++ * Create a registration, and set the source name ++ */ ++static isns_simple_t * ++__isns_create_deregistration(isns_source_t *source, const isns_attr_list_t *attrs) ++{ ++ isns_simple_t *simp; ++ ++ simp = isns_simple_create(ISNS_DEVICE_DEREGISTER, source, NULL); ++ if (simp && attrs) ++ isns_attr_list_copy(&simp->is_operating_attrs, attrs); ++ return simp; ++} ++ ++isns_simple_t * ++isns_create_deregistration(isns_client_t *clnt, const isns_attr_list_t *attrs) ++{ ++ return __isns_create_deregistration(clnt->ic_source, attrs); ++} ++ ++/* ++ * Get the next object identified by the operating attrs. ++ */ ++static int ++isns_deregistration_get_next_object(isns_db_t *db, ++ struct isns_attr_list_scanner *st, ++ isns_object_list_t *result) ++{ ++ isns_object_t *current; ++ int status; ++ ++ status = isns_attr_list_scanner_next(st); ++ if (status) ++ return status; ++ ++ /* ++ * 5.6.5.4. ++ * Valid Operating Attributes for DevDereg ++ * --------------------------------------- ++ * Entity Identifier ++ * Portal IP-Address & Portal TCP/UDP Port ++ * Portal Index ++ * iSCSI Name ++ * iSCSI Index ++ * FC Port Name WWPN ++ * FC Node Name WWNN ++ * ++ * In other words, deregistration is restricted to Entity, ++ * portal, and node ++ */ ++ if (st->tmpl != &isns_entity_template ++ && st->tmpl != &isns_iscsi_node_template ++ && st->tmpl != &isns_portal_template) ++ return ISNS_INVALID_DEREGISTRATION; ++ ++ /* Only key attrs allowed */ ++ if (st->attrs.ial_count) { ++ /* MS Initiators send the Entity protocol along ++ * with the Entity Identifier. */ ++ isns_debug_protocol("Client included invalid operating attrs " ++ "with %s:\n", st->tmpl->iot_name); ++ isns_attr_list_print(&st->attrs, isns_debug_protocol); ++ /* return ISNS_INVALID_DEREGISTRATION; */ ++ } ++ ++ /* ++ * 5.6.5.4 ++ * Attempted deregistration of non-existing entries SHALL not ++ * be considered an isns_error. ++ */ ++ current = isns_db_lookup(db, st->tmpl, &st->keys); ++ if (current != NULL) { ++ isns_object_list_append(result, current); ++ isns_object_release(current); ++ } ++ ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * Extract the list of objects to be deregistered from ++ * the list of operating attributes. ++ */ ++static int ++isns_deregistration_get_objects(isns_simple_t *reg, isns_db_t *db, ++ isns_object_list_t *result) ++{ ++ struct isns_attr_list_scanner state; ++ int status = ISNS_SUCCESS; ++ ++ isns_attr_list_scanner_init(&state, NULL, ®->is_operating_attrs); ++ state.index_acceptable = 1; ++ state.source = reg->is_source; ++ ++ while (state.pos < state.orig_attrs.ial_count) { ++ status = isns_deregistration_get_next_object(db, ++ &state, result); ++ ++ if (status == 0) ++ continue; ++ ++ /* Translate error codes */ ++ if (status == ISNS_NO_SUCH_ENTRY) ++ status = ISNS_SUCCESS; ++ else ++ if (status == ISNS_INVALID_REGISTRATION) ++ status = ISNS_INVALID_DEREGISTRATION; ++ break; ++ } ++ ++ isns_attr_list_scanner_destroy(&state); ++ return status; ++} ++ ++/* ++ * Process a deregistration ++ * ++ * Normally, you would expect that a deregistration removes the ++ * object from the database, and that's the end of the story. ++ * Unfortunately, someone added Discovery Domains to the protocol, ++ * requiring _some_ information to survive as long as an object ++ * is referenced by a discovery domain. Specifically, we need to ++ * retain the relationship between key attributes (eg iscsi node ++ * name) and the object index. ++ * ++ * Thus, deregistration consists of the following steps ++ * - the object is removed from the database's global scope, ++ * so that it's no longer visible to DB lookups. ++ * ++ * - the object is detached from its containing Network ++ * Entity. ++ * ++ * - all attributes except the key attr(s) and the index ++ * attribute are removed. ++ */ ++int ++isns_process_deregistration(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) ++{ ++ isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; ++ isns_simple_t *reply = NULL; ++ isns_db_t *db = srv->is_db; ++ int status, dereg_status; ++ unsigned int i; ++ ++ /* Get the objects to deregister */ ++ status = isns_deregistration_get_objects(call, db, &objects); ++ if (status != ISNS_SUCCESS) ++ goto done; ++ ++ /* ++ * 5.6.5.4 ++ * ++ * For messages that change the contents of the iSNS database, ++ * the iSNS server MUST verify that the Source Attribute ++ * identifies either a Control Node or a Storage Node that is ++ * a part of the Network Entity containing the added, deleted, ++ * or modified objects. ++ */ ++ /* ++ * Implementation note: this can be implemented either by ++ * explicitly checking the object's owner in isns_db_remove ++ * (which is what we do right now), or by matching only ++ * those objects that have the right owner anyway. ++ * ++ * The latter sounds like a better choice if the client ++ * uses NIL attributes, because it limits the scope of ++ * the operation; but then the RFC doesn't say whether ++ * this kind of deregistration would be valid at all. ++ */ ++ ++ /* Success: create a new simple message, and ++ * send it in our reply. */ ++ reply = __isns_create_deregistration(srv->is_source, NULL); ++ if (reply == NULL) { ++ status = ISNS_INTERNAL_ERROR; ++ goto done; ++ } ++ ++ dereg_status = ISNS_SUCCESS; ++ for (i = 0; i < objects.iol_count; ++i) { ++ isns_object_t *obj = objects.iol_data[i]; ++ ++ /* Policy: check that the client is permitted ++ * to deregister this object */ ++ if (!isns_policy_validate_object_access(call->is_policy, ++ call->is_source, obj, ++ call->is_function)) ++ status = ISNS_SOURCE_UNAUTHORIZED; ++ ++ if (status == ISNS_SUCCESS) ++ status = isns_db_remove(db, obj); ++ if (status != ISNS_SUCCESS) { ++ /* ++ * 5.7.5.4 ++ * ++ * In the event of an error, this response message ++ * contains the appropriate status code as well ++ * as a list of objects from the original DevDereg ++ * message that were not successfully deregistered ++ * from the iSNS database. This list of objects ++ * is contained in the Operating Attributes ++ * of the DevDeregRsp message. Note that an ++ * attempted deregistration of a non-existent ++ * object does not constitute an isns_error, and ++ * non-existent entries SHALL not be returned ++ * in the DevDeregRsp message. ++ */ ++ /* ++ * Implementation: right now this doesn't work ++ * at all, because isns_msg_set_error will ++ * discard the entire message except for the ++ * status word. ++ */ ++ isns_debug_message("Failed to deregister object: %s (0x%04x)\n", ++ isns_strerror(status), status); ++ ++ isns_object_extract_all(obj, &reply->is_operating_attrs); ++ dereg_status = status; ++ continue; ++ } ++ ++ /* ++ * 5.7.5.4 ++ * If all Nodes and Portals associated with a Network ++ * Entity are deregistered, then the Network Entity ++ * SHALL also be removed. ++ * [...] ++ * If both the Portal and iSCSI Storage Node objects ++ * associated with a Portal Group object are removed, ++ * then that Portal Group object SHALL also be removed. ++ * The Portal Group object SHALL remain registered ++ * as long as either of its associated Portal or ++ * iSCSI Storage Node objects remain registered. If a ++ * deleted Storage Node or Portal object is subsequently ++ * re-registered, then a relationship between the re- ++ * registered object and an existing Portal or Storage ++ * Node object registration, indicated by the PG object, ++ * SHALL be restored. ++ */ ++ /* isns_db_remove takes care of removing dead entities, ++ * and dead portal groups. ++ */ ++ } ++ ++ if (status == ISNS_SUCCESS) ++ status = dereg_status; ++ ++done: ++ isns_object_list_destroy(&objects); ++ *result = reply; ++ return status; ++} +diff --git a/utils/open-isns/doc/isns_config.5 b/utils/open-isns/doc/isns_config.5 +new file mode 100644 +index 0000000..5fbd26e +--- /dev/null ++++ b/utils/open-isns/doc/isns_config.5 +@@ -0,0 +1,387 @@ ++.TH ISNS_CONFIG 8 "11 May 2007" ++.SH NAME ++isns_config - iSNS configuration file ++.SH SYNOPSIS ++.B /etc/isns/isnsadm.conf ++.br ++.B /etc/isns/isnsd.conf ++.br ++.B /etc/isns/isnsdd.conf ++ ++.SH DESCRIPTION ++All Open-iSNS utilities read their configuration ++from a file in ++.BR /etc/isns . ++There is a separate configuration file for each application, ++.BR isnsd ", " isnsadm ", and " isnsdd . ++The syntax and the set of supported options is identical, ++even though some options are specific to e.g. the server. ++Unless indicated, options are applicable to all utilities. ++.PP ++An Open-iSNS configuration file contains keyword-argument pairs, ++one per line. All keywords are case insensitive. ++.PP ++A ++.B # ++character introduces a comment, which extends until the ++end of the line. Empty lines are ignored. ++.PP ++There are no line continuations, and you cannot use quotes ++around arguments. ++.PP ++Some options specify timeout values, which are given in ++units of seconds by default. You can specify an explicit ++unit, however, such as ++.BR d " (days), ++.BR h " (hours), ++.BR m " (minutes), or ++.BR s " (seconds). ++.\" ------------------------------------------------------------------ ++.SS Generic Options ++.TP ++.BR HostName ++By default, Open-iSNS applications will retrieve the machine's ++hostname using the ++.BR gethostname (3) ++system call, and use a DNS lookup to look up the canonical name. ++Using the ++.BR HostName ++option, you can overried this. This option is rarely needed. ++.TP ++.BR SourceName ++This option is mandatory for all Open-iSNS applications. ++This should be a name which identifies the client uniquely. ++There are two readings of RFC 4171; one requires that this ++is an iSCSI qualified name such as ++.BR iqn.2001-04.com.example.host , ++whereas other language in the RFC suggests that this is ++pretty much a free-format string that just has to be ++unique (using e.g. the client's fully qualified domain name). ++.IP ++When using DSA authentication, Open-iSNS currently requires the source ++name to match the key identifier (SPI) of the client's public ++key. ++.IP ++If left empty, the source name is derived from the client's hostname. ++.TP ++.BR ServerAddress " (client): ++This options specifies the host name or address of ++the iSNS server to talk to. It can optionally be followed ++by a colon, and a port number. ++.IP ++Instead of a hostname, IPv4 or IPv6 addresses can be used. ++In order to avoid ambiguities, literal ++IPv6 addresses must be surrounded by square brackets, ++as in ++.BR [2001:4e5f::1] . ++.IP ++When specifying a port number, you can use either the ++numeric port, or a string name to be looked up in ++.BR /etc/services . ++When the port is omitted, it defaults to 3205, the IANA ++assigned port number of iSNS. ++.IP ++If the special string ++.B SLP: ++is used, the client will try to locate the iSNS server ++through SLP. ++.TP ++.BR SLPRegister " (server): ++If set to 1, the iSNS daemon will register itself will ++the SLP service. This allows clients to contact the ++server without having to configure its address ++statically. ++.TP ++.BR PIDFile " (server): ++This specifies the name of the server's PID file, which is ++.B /var/run/isnsd.pid ++by default. ++.\" ------------------------------------------------------------------ ++.SS Database Related Options ++These options apply to the iSNS server only, and control operation ++of the iSNS database. ++.TP ++.BR Database ++This option is used to specify how the database is stored. ++Setting this to an absolute path name will make ++.B isnsd ++keep its database in the specified directory. ++.IP ++If you leave this empty, ++.B isnsd ++will keep its database in memory. ++This is also the default setting. ++.TP ++.BR DefaultDiscoveryDomain ++iSNS scopes visibility of other nodes using so-called ++Discovery Domains. A storage node A will only "see" ++storage node B, if both are members of the same ++discovery domain. ++.IP ++So if a storage node is registered which is not part of ++any discovery domain, it will not see any other nodes. ++.IP ++By setting ++.BR DefaultDiscoveryDomain=1 , ++you can tell isnsd to create a virtual "default discovery domain", which ++holds all nodes that are not part of any administratively configured ++discovery domain. ++.IP ++By default, there is no default discovery domain. ++.TP ++.BR RegistrationPeriod ++The iSNS server can purge registered entities after a certain period ++of inactivity. This is called the registration period. Clients who ++register objects are supposed to refresh their registration within ++this period. ++.IP ++The default value is 1 hour. Setting it to 0 disables expiry ++of entities from the database. ++.TP ++.BR ESIRetries ++Open-iSNS is able to monitor the reachability of storage nodes ++and their portals by using a protocol feature called ESI ++(Entity status inquiry). Clients request ESI monitoring by ++registering an ESI port along with each portal. The server ++will send ESI messages to these portals at regular intervals. ++If the portal fails to reply several times in a row, it is ++considered dead, and will be removed from the database. ++.IP ++.B ESIRetries ++specifies the maximum number of attempts the server will make ++at contacting the portal before pronouncing it dead. If set ++to 0, the server will disable ESI and reject any registrations ++that specify an ESI port with an error code of "ESI not ++supported". ++.IP ++The default value is 3. ++.TP ++.BR ESIMinInterval ++This timeout value specifies the minimum ESI interval. ++If a client requests an ESI interval less than this value, ++it is silently rounded up. ++.IP ++The default value is 60 seconds. ++.TP ++.BR ESIMaxInterval ++This timeout value specifies the maximum ESI interval. ++If a client requests an ESI interval greater than this value, ++it is silently rounded down. ++.IP ++The default value is 10 minutes. ++.IP ++The maximum ESI interval must not exceed half the value ++of the registration period. ++.TP ++.B SCNRetries ++iSNS clients can register to receive State Change Notification ++(SCN) messages to learn about changes in the iSNS database. ++This value specifies how often the server will try to retransmit ++an SCN message until giving up. ++.IP ++The default value is 3. ++.TP ++.B SCNCallout ++This is the path name of a helper program that ++.B isnsdd ++will invoke whenever it processes a state change notification from the ++server. The helper program will be invoked with an argument indicating ++the type of event, being one of ++.BR add ", " update ", or " remove . ++This is followed by a list of attributes in ++.IB name = value ++notation, using the names and conventions described in ++.BR isnsadm (8). ++.\" ------------------------------------------------------------------ ++.SS Security Related Options ++The iSNS standard defines an authentication method based on ++the DSA algorithm. Participants in a message exchange authenticate ++messages by adding an "authentication block" containing a time stamp, ++a string identifying the key used, and a digital signature of the ++message. The same method is also used by SLP, the Service Location ++Protocol. ++.PP ++The string contained in the authentication block is referred to ++as the ++.IR "Security Policy Index" (SPI). ++This string can be used by the server to look up the client's public ++key by whatever mechanism; so the string could be used as the name of ++a public key file in a directory, or to retrieve an X509 certificate ++from LDAP. ++.PP ++From the perspective of Open-iSNS client applications, there are ++only two keys: the client's own (private) key, used to sign the ++messages it sends to the server, and the server's public key, ++used to verify the signatures of incoming server messages. ++.PP ++The iSNS server needs, in addition to its own private key, access to all ++public keys of clients that will communicate to it. The latter are kept ++in what is called a key store. Key stores and their operation will ++be discussed in section ++.B Key Stores and Policy ++below. ++.PP ++The following configuration options control authentication: ++.TP ++.BR Security ++This enables or disables DSA authentication. ++When set to 1, the client will sign all messages, and expect all server ++messages to be signed. ++.IP ++When enabling security in the server, incoming messages are checked ++for the presence of an auth block. If none is present, or if the server ++cannot find a public key corresponding to the SPI, the message is treated ++as originating from an anonymous source. If the SPI is known but the ++signature is incorrect, the message is dropped silently. ++.IP ++Messages from an anonymous source will be assigned a very restrictive ++policy that allows database queries only. ++.IP ++Setting this option to 0 will turn off authentication. ++.IP ++The default value is -1, which tells iSNS to use authentication ++if the required keys are installed, and use unauthenticated iSNS ++otherwise. ++.TP ++.BR AuthName ++This is the string that will be used as the SPI in all outgoing ++messages that have an auth block. It defaults to the host name ++(please refer to option ++.BR HostName ). ++.TP ++.BR AuthKeyFile ++This is the path name of a file containing a PEM encoded DSA key. ++This key is used to sign outgoing messages. ++The default is ++.BR /etc/isns/auth_key . ++.TP ++.BR ServerKeyFile ++This option is used by client applications only, and specifies ++the path name of a file containing a PEM encoded DSA key. ++This key is used to authenticate the server's replies. ++The default is ++.BR /etc/isns/server_key.pub . ++.TP ++.BR KeyStore ++This server-side option specifies the key store to use, ++described in the next section. ++.PP ++The following two options control how iSNS will verify the ++time stamp contained in the authentication block, which ++is supposed to prevent replay attacks. ++.TP ++.B Auth.ReplayWindow ++In order to compensate for clock drift between two hosts exchanging ++iSNS messages, Open-iSNS will apply a little fuzz when comparing ++the time stamp contained in the message ++to the local system time. If the difference between ++time stamp and local system time is less than the number of seconds ++given by this option, the message is acceptable. Otherwise, it is ++rejected. ++.IP ++The default value is ++.BR 5m . ++.TP ++.B Auth.TimestampJitter ++When verifying incoming messages, Open-iSNS checks that the time ++stamps sent by the peer are increasing monotonically. In order to ++compensate for the reordering of messages by the network (eg when ++using UDP as transport), a certain time stamp jitter is accepted. ++If the time stamp of an incoming messages is no earlier than ++.B TimestampJitter ++seconds before the last time stamp received, then the message is acceptable. ++Otherwise, it is rejected. ++.IP ++The default value is ++.BR 1s . ++.\" ------------------------------------------------------------------ ++.SS Key Stores and Policy ++The current implementation supports two types of key stores. ++.PP ++The simple key store uses a flat directory to store public keys, each ++key in a file of its own. The file is expected to hold the client's ++PEM-encoded public key, and it must use the client's SPI as the name. ++This type of key store is not really recommended, as it does not ++store any policy information. ++.PP ++A simple key store can be configured by setting the ++.B KeyStore ++option to the path name of the directory. ++.PP ++The recommended approach is to use the database as key store. This ++uses vendor-specific policy objects to tie SPI string, public key, ++entity name, source name and other bits of policy together, and ++store them in a persistent way. ++.PP ++The database key store is configured by setting the ++.B KeyStore ++option to the reserved value ++.BR DB: , ++which is also the default. ++.PP ++Currently, Open-iSNS policy objects have the following attributes, ++besides the SPI: ++.TP ++Source: ++This is the source node name the client must use. It defaults to ++the SPI string. ++.TP ++Functions: ++This is a bitmap detailing which functions the client is permitted ++to invoke. The bit names correspond to the shorthand names used in ++RFC 4711, such as ++.BR DevAttrReg , ++.BR DevAttrQry , ++etc. The default is to allow registration, query and deregistration, ++as well as SCNRegister. ++.TP ++Entity name: ++This is the entity name assigned to the client. If set, a registration ++by the client is not permitted to use a different entity name. If ++the client sends a registration without Entity identifier, the ++server will assign the entity name given in the policy. ++The default is to not restrict the entity name. ++.TP ++Object access: ++This is a bitfield describing access permissions for each object type. ++For each object type, you can grant Read and/or Write permissions. ++Read access applies to the Query and GetNext calls; all other operations ++require write permission. ++The default grants read and write access to objects of type Entity, Storage ++Node, Portal and Portal Group; and read access to Discovery Domains. ++.TP ++Node types: ++This bitfield describes which types of storage nodes a client is ++allowed to register; the valid bit names are ++.BR target ", " initiator " and " control . ++The default is to restrict nodes to register initiators only. ++.\" ------------------------------------------------------------------ ++.SS Network Related Options ++.TP ++.BR Network.MaxSockets ++This is the number of incoming connections accepted, and defaults to ++1024. This usually applies to server side only, but is relevant if you ++create a passive TCP socket for ESI or SCN. ++.TP ++.BR Network.ConnectTimeout ++This is a timeout value, which specifies the time to wait for a TCP ++connection to be established. It defaults to ++.BR 60s . ++.TP ++.BR Network.ReconnectTimeout ++When a connection attempt failed, we wait for a short time before we ++try connecting again. This is intended to take the pressure off ++overloaded servers. The default value is ++.BR 10s . ++.TP ++.BR Network.CallTimeout ++Total amount of time to wait before timing out a call to the iSNS server. ++The default value is ++.BR 60s . ++.\" ------------------------------------------------------------------ ++.SH SEE ALSO ++RFC 4171, ++.BR isnsd (8), ++.BR isnsadm (8). ++.SH AUTHORS ++Olaf Kirch +diff --git a/utils/open-isns/doc/isnsadm.8 b/utils/open-isns/doc/isnsadm.8 +new file mode 100644 +index 0000000..88ec4cf +--- /dev/null ++++ b/utils/open-isns/doc/isnsadm.8 +@@ -0,0 +1,688 @@ ++'\" t ++.TH ISNSADM 8 "11 May 2007" ++.SH NAME ++isnsadm \- iSNS client utility ++.SH SYNOPSIS ++.B isnsadm ++.RI [ options... ] ++.RI --register " object... ++.PP ++.B isnsadm ++.RB [ ... ] ++.RI --query " attr" [= value ] ++.PP ++.B isnsadm ++.RB [ ... ] ++.RI --deregister " attr=value ++.PP ++.B isnsadm ++.RB [ ... ] ++.RI --list " type attr=value ++.PP ++.B isnsadm ++.RB [ ... ] ++.RI --dd-register " attr=value ++.PP ++.B isnsadm ++.RB [ ... ] ++.RI --dd-deregister " dd-id attr=value ++.PP ++.B isnsadm ++.RB [ ... ] ++.RI --enroll " client-name attr=value ++.PP ++.B isnsadm ++.RB [ ... ] ++.RI --edit-policy " attr=value ++ ++.SH DESCRIPTION ++.B Isnsadm ++is a command line utility for interacting with an iSNS ++server. It operates in one of several modes, which are ++mutually exclusive. ++Currently, ++.B isnsadm ++supports registration, query, and deregistration. ++.SH OPTIONS ++By default, ++.B isnsadm ++will take most of its settings from the configuration ++file ++.BR /etc/isns/isnsadm.conf , ++with the exception of the following options: ++.TP ++.BI \--config " filename\fR, " \-c " filename ++This option overrides the default configuration file. ++.TP ++.BI \--debug " facility\fR, " \-d " facility ++enables debugging. Valid facilities are ++.PP ++.TS ++tab(,),box,center; ++lb|lr. ++socket,network send/receive ++auth,authentication and security related information ++message,iSNS protocol layer ++state,database state ++scn,SCN (state change notification) messages ++esi,ESI (entity status inquiry) messages ++all,all of the above ++.TE ++.PP ++.TP ++.BI \--local ++makes ++.B isnsadm ++use a Local (aka Unix) socket when talking to the iSNS ++server. This can be used by the administrator to perform ++management tasks, such as enrolling new clients, editing ++access control and so on. Local mode is only available ++to the super user. ++.TP ++.BI \--control ++makes ++.B isnsadm ++assume the identity of a control node. Control nodes are ++special in that they have more rights in accessing and ++modifying the database than normal storage nodes have. ++.PP ++When using this option, ++.B isnsadm ++will use the source name and DSA key specified by the ++.BR Control.SourceName " and " Control.AuthKeyFile ++configuration options, respectively. ++.PP ++.TP ++.BI \--key " attr" = value ++This option is recognized in registration mode only, and ++lets you specify an object key. For a more detailed explanation, ++refer to section ++.BR "Registration mode" . ++.TP ++.BI \--keyfile= filename ++When creating a policy for a new iSNS client, ++.B isnsadm ++is able to generate a DSA key for the client. The public ++part of the key is stored in a policy object in the iSNS ++server's database, whereas the private portion is stored in the ++file specified by the ++.B keyfile ++option. ++.B ++.TP ++.BI \--help ++This will print a help message and exit. ++.\"--------------------------- ++.SS Built-in help ++.B Isnsadm ++has built-in help functions. When invoked with ++.BR \--help , ++it will print a general help message showing all supported ++command modes, and exit. Specific help on an individual ++command mode is available by invoking that mode with a ++single argument of ++.BR help , ++like this: ++.PP ++.B isnsadm --register help ++.PP ++This will print a help message describing how to use this ++command mode, followed by a list of attributes this command supports ++and a help text describing the attribute. ++.\"--------------------------- ++.SS Supported attributes ++Most command modes take a list of attributes as arguments on the ++command line. The naming and syntax of these attributes as ++the same for all commands modes, however certain modes support ++only a limited set of attributes. ++.PP ++Attributes are usually given as ++.IB name = value ++pairs. Where empty (or NIL) attributes are supported, the ++attribute name by itself can be given. ++.PP ++The syntax of attribute ++.I value ++depends on the attribute type. For strings and numeric values, ++no special conventions apply, but bitfields have a special syntax ++described below. ++.PP ++The attribute name is usually preceded by the object ++type it applies to (such as ++.BR entity ), ++followed by a hyphen and the name itself. However, where the ++context clearly determines a specific object type, the prefix ++can be omitted. For instance, when editing a policy object ++using ++.BR \--edit-policy , ++it is acceptable to use ++.B node-type ++as shorthand for ++.BR policy-node-type . ++.PP ++Likewise, in a query command, it is not permitted to mix attributes ++from different object types. Thus, the first attribute of a ++query string establishes a type context, so that the following ++two invocations are equivalent: ++.PP ++.B isnsadm --query pg-name=iqn.com.foo pg-addr=10.1.1.1 pg-port=860/tcp ++.br ++.B isnsadm --query pg-name=iqn.com.foo addr=10.1.1.1 port=860/tcp ++.PP ++.B Isnsadm ++currently supports the following attributes: ++.PP ++.TS ++tab(,),box,center; ++li|lilili ++lt|lbrlb. ++Context,Attribute,iSNS tag,Aliases ++_ ++Network Entity,entity-id,1,eid ++\^,entity-prot,2 ++\^,entity-index,7 ++iSCSI Storage Node,iscsi-name,32 ++\^,iscsi-node-type,33 ++\^,iscsi-alias,34 ++\^,iscsi-idx,36 ++\^,iscsi-authmethod,42 ++Portal,portal-addr,16 ++\^,portal-port,17 ++\^,portal-name,18 ++\^,portal-esi-port,20 ++\^,portal-esi-interval,21 ++\^,portal-idx,22 ++\^,portal-scn-port,23 ++Portal Group,portal-group-index,52 ++\^,pg-name,48 ++\^,pg-addr,49 ++\^,pg-port,50 ++\^,pg-tag,51,pgt ++\^,pg-idx,52 ++Discovery Domain,dd-id,2065 ++\^,dd-name,2066 ++\^,dd-member-iscsi-idx,2067 ++\^,dd-member-name,2068 ++\^,dd-member-fc-name,2069, ++\^,dd-member-portal-idx,2070, ++\^,dd-member-addr,2071, ++\^,dd-member-port,2072, ++\^,dd-features,2078, ++Policy Object,policy-name,-,spi ++\^,policy-key,- ++\^,policy-entity,- ++\^,policy-node-type,- ++\^,policy-object-type,- ++\^,policy-functions,- ++.TE ++.PP ++.\"--------------------------- ++.SS Portal attributes ++Portal information is conveyed by two separate attributes ++in iSNS; an address attribute holding the IP address, and ++a TCP/UDP port attribute holding the port number and an indication ++of the protocol to be used (TCP or UDP). ++.PP ++When parsing a TCP/UDP port, Open-iSNS will expect a port number, ++optionally followed by a slash and the protocol. Port names ++such as "iscsi-target" are not supported. ++.PP ++As a convenience, ++.B isnsadm ++supports a notation representing a portal as one pseudo-attribute. ++Separating address and port by a colon. Thus, the following two ++are equivalent, with the latter being the shorthand representation ++of the former: ++.PP ++.BI addr=
" port=" [/ protocol ] \fR. ++.BI portal= : port [/ protocol ] ++.PP ++This notation can be used in any context where an ++.BR addr / port ++attribute pair can appear, and may be prefixed by a type name, ++as in ++.BR pg-portal=... . ++.PP ++When using literal IPv6 addresses, the address has to be surrounded ++by square brackets, otherwise the embedded colons would create ++ambiguity: ++.BR portal=[2001:5c0:0:2::24]:860/tcp ++.PP ++.\"--------------------------- ++.SS Bitfield attributes ++Some iSNS attributes are words representing a bit field. ++.B Isnsadm ++displays and parses these attributes in human-readable form ++rather than using the numerical value. The names of the bit ++values are displayed by built-in help facilities. When specifying ++a bitfield attribute on the command line, you can combine them ++using the plus (\fB+\fP) or comma (\fB,\fR) character, like this: ++.PP ++.B node-type=control+initiator ++.PP ++.\"--------------------------- ++.SS Registration mode ++Registration mode is selected by using the ++.B --register ++option, followed by a list of one or more objects ++to register with the iSNS server. ++By default, this will create a network entity for the ++client (if none exists), and place the new objects inside ++it. Usually, you register all objects for ++a network entity in one operation, rather than each ++one separately. ++.PP ++Each object is specified as a type, optionally followed ++by a comma-separated list of attributes, such as ++this: ++.PP ++.B target=iqn.2005-01.org.open-iscsi.foo:disk1,alias=disk1 ++.PP ++The following object types are currently supported: ++.TP ++.BI entity= name ++Tells the server to group all objects in the specified ++Network Entity container object. ++Normally, the iSNS server will automatically assign an ++entity name that is in line with its policies, and there is ++no need to specify it explicitly. ++.TP ++.BI initiator[= name ] ++This will register an iSCSI storage node of type initiator. ++By default, the name is set to the iSNS source name. ++.IP ++This can be followed by any number of iSCSI storage node ++attributes. ++.TP ++.BI target[= name ] ++This will register an iSCSI storage node of type target. ++By default, the name is set to the iSNS source name. ++.IP ++This object accepts the same set of attributes as ++.BR initiator . ++.TP ++.BI control[= name ] ++This will register an iSCSI storage node of type control. ++By default, the name is set to the iSNS source name. ++Only management nodes should be registered as control ++nodes, as this gives a node complete control over the ++iSNS database. ++.IP ++This object accepts the same set of attributes as ++.BR initiator . ++.TP ++.BI portal=[ address:port/proto ] ++This will register a portal using the given address, ++port and protocol triple. If the triple is omitted, ++.B isnsadm ++will use the client host's IP address. If the portal ++is preceded by an initiator registration (on the command ++line), the port defaults to 860/tcp; if it is preceded by ++a target registration, the port defaults to 3260/tcp. ++For multi-homed hosts, the choice of address is ++implementation dependant. ++.IP ++This can be followed by any number of portal attributes. ++.TP ++.B pg ++This will register a portal group joining the preceding ++portal and node. Portal groups can be used to describe ++the preferred portals for a given node; please refer ++to RFC 4711 for details. ++.IP ++This can be followed by any number of portal group attributes. ++The attribute list must specify a portal group tag (PGT) ++via the ++.BR pgt ++attribute. ++.PP ++There are two additional command line options of interest, ++which are used exclusively with Registration mode. One is ++.BR \--replace . ++Normally, registration mode will ++.I add ++new objects to the network entity associated with the client ++host. If you specify ++.B \--replace ++on the command line, the server will wipe the network ++entity completely, and remove all portals and storage ++nodes it contained. Then it will create a new network ++entity, and place the portals and storage nodes provided ++by the caller inside. ++.PP ++In addition, it is possible to replace just parts of a ++network entity. This is achieved by using the command line ++option ++.B \--key ++to specify the object that should be replaced. ++.PP ++For instance, assume a network entity ++contains the portal ++.BR 10.1.1.1:860 , ++and the client's network address changed to ++.BR 10.2.7.7 . ++Then the following command will atomically update the ++database, replacing just the portal without touching the ++registered storage nodes: ++.PP ++.B " isnsadm --replace --key portal=10.1.1.1:860 portal=10.2.7.7:860 ++.PP ++The ++.B \--key ++option recognizes only a subset of the usual attributes: ++.RS ++.TS ++tab(,),box; ++li|li ++lb|lb. ++Object type,Syntax ++_ ++Entity,eid=\fIidentifier ++Portal,portal=\fIaddress\fP:\fPport ++iSCSI Node,iscsi-name=\fIname ++.TE ++.RE ++.PP ++To get a list of supported attributes, invoke ++.BR "isnsadm --register help" . ++.\"--------------------------- ++.SS Query mode ++Query mode is selected by using the ++.B --query ++option. A query consists of a list of ++.BR attr = \fI value ++pairs. All attributes must belong to the same object type, ++i.e. queries that mix a Network Entity attribute with e.g. ++a Portal attribute will be rejected. ++.PP ++It is also possible to specify an attribute name without ++value (i.e. just ++.BR attr ), ++which will ++will match any object that has such an attribute, regardless ++of its value. This is useful when you want to query for all ++objects of a given type. ++.PP ++To obtain a list of supported attributes, invoke ++.BR "isnsadm --query help" . ++.\"--------------------------- ++.SS List Mode ++In this mode, ++.B isnsadm ++will display all objects of a given type, optionally ++restricted to those matching certain attribute values. ++.PP ++The arguments to list mode are a ++.IR "type name" , ++optionally followed by one or more ++.IB attr = value ++pairs. Only attributes pertaining to the given ++type are permitted; for instance, if you specify a ++type name of ++.BR portals , ++only portal attributes are permitted. ++.PP ++Possible type names are: ++.BR entities , ++.BR nodes , ++.BR portals , ++.BR dds , ++.BR ddsets , ++.BR portal-groups ", and " ++.BR policies . ++.PP ++Additional information is available via ++.BR "isnsadm --list help" . ++.\"--------------------------- ++.SS Deregistration mode ++In this mode, you can deregister objects previously registered. ++Only the node which registered an entity in the first place is ++permitted to remove it, or any of its child objects. (Control ++nodes are not bound by this restriction). ++.PP ++In deregistration mode, the argument list consists of a list of ++.IB attr = value ++pairs. Deregistration supports the same set of attributes as ++query mode. ++.\"--------------------------- ++.SS Discovery Domain Registration ++This mode, allows to register a discovery domain or to add ++new members to an existing discovery domain. Again, attributes ++are specified as a list of ++.IB attr = value ++pairs. Only discovery domain attributes are recognized. ++.PP ++Note, in order to add members to an existing domain, you must ++specify the domain's numeric ID. The domain's symbolic name ++is not a valid handle when referring to a discovery domain. ++.\"--------------------------- ++.SS Discovery Domain Deregistration mode ++In this mode, you can deregister a discoery domain previously registered. ++Only the node which registered a discovery domain in the first place is ++permitted to remove it, or any of its members. (Control ++nodes are not bound by this restriction). ++.PP ++In Discovery Domain deregistration mode, the argument list consists of ++the Discovery Domain ID, followed by a list of ++.IB attr = value ++pairs. Discovery Domain Deregistration supports the same set of attributes as ++query mode. ++.\"--------------------------- ++.SS Client Enrollment ++This mode only works when the server recognizes the client ++as having control node capabilities, which is possible in ++two ways: ++.TP ++Invoke ++.B isnsadm \--local ++as super user on the host ++.B isnsd ++is running on. The ++.B \--local ++options tells it to communicate with the server through ++the local control socket. ++.TP ++Invoke ++.BR "isnsadm \--control" , ++which tells it to assume the identity of a control node. ++When given this option, ++.B isnsadm ++will use the source name and DSA key specified by the ++.BR Control.SourceName " and " Control.AuthKeyFile ++configuration options, respectively. ++The server must be configured to grant this identity ++control node status. ++.PP ++To enroll a client, use the ++.B \--enroll ++option, followed by the (source) name of the client to enroll. ++This string will be used as the name of the security policy ++the client will use to identify itself. ++.PP ++This is followed by a list of attribute/value pairs, where the ++following set of attributes is supported: ++.PP ++.TS ++tab(,),box,center; ++li|lilili ++lb|lrlb. ++Attribute,Description,Aliases ++_ ++name,Policy Name,spi ++key,Client's DSA public key ++entity,Assigned Entity Identifier ++node-type,Permitted node type(s) ++node-name,Permitted node name(s) ++functions,Bitmap of permitted functions ++object-type,Object access mask ++.TE ++.PP ++The ++.B key ++attribute is used to specify the DSA ++public key that the server should use to authenticate ++messages from this client. You can either provide a ++file name; in which case ++.B isnsadm ++will try to read the PEM encoded public key from that file. ++If no ++.B key ++attribute is given, or when using ++.BR key=gen ", " isnsadm ++will generate a DSA key. The private portion of the newly ++generated key will be stored in the file specified by ++.BI --keyfile= filename \fR. ++.PP ++The ++.B object-type ++attribute is used to specify which object types the client ++is permitted to access. This is a comma separated list of ++.IB type : perm ++pairs, where ++.I type ++can be any of ++.BR entity ", " iscsi-node ", " portal ", " portal-group ", " dd ", " ddset ", and " policy . ++The permissions can be either ++.BR rw ", or " r . ++.PP ++The ++.B functions ++attribute can be used to restrict which functions the client is ++permitted to invoke. This is a bitfield, using the standard function ++names from RFC 4171, such as ++.BR DevAttrReg ", " DevAttrQry ", etc." ++.PP ++For a description of the open-isns security model ++and policies, please refer to the ++.BR isns_config (5) ++manual page. ++.PP ++.BR "Important note" : ++In order to generate a DSA key, you have to have a set of DSA ++parameters installed. By default, ++.B isnsadm ++expects to find them in ++.BR /etc/isns/dsa.params . ++These parameters are created by calling ++.B isnsd \--init ++once on the server machine. Alternatively, you can use ++the following command: ++.PP ++.ti +8 ++openssl dsaparam 1024 -out /etc/isns/dsa.params ++.ti -8 ++.PP ++where 1024 is the chosen DSA key size, in bits. ++.SH EXAMPLES ++If you want to use Open-iSNS in authenticated mode, ++you first need to initialize the server's DSA key and ++DSA parameters. This can be done conveniently by using ++.PP ++.B isnsd --init ++.PP ++This will create the server's private and public key, ++and place them in ++.B /etc/isns/auth_key ++and ++.BR auth_key.pub , ++respectively. ++.PP ++The following command will create a policy object for a ++node named ++.B isns.control , ++and grant it control privileges: ++.PP ++.B isnsadm --local --keyfile=control.key ++.B --enroll isns.control \(rs ++.br ++.B " node-type=ALL functions=ALL object-type=ALL ++.PP ++In the process of entrolling the client, this will generate ++a DSA key pair, and place the private key portion in the ++file ++.BR control.key . ++This file must be installed as ++.BR /etc/isns/control.key ++on the host you wish to use as an iSNS management station. ++.PP ++Next, you need to create a storage node object for the ++management station: ++.PP ++.B isnsadm --local --register control ++.PP ++On the management station, you can then enroll additional ++hosts: ++.PP ++.B isnsadm --control --keyfile=somehost.key ++.B --enroll iqn.2005-01.org.open-iscsi.somehost \(rs ++.br ++.B " node-type=target+initiator ++.PP ++Again, this will generate a DSA key pair and store the private ++key portion in auth_key. Note the use of the ++.B \--control ++option that tells ++.B isnsadm ++to use the identity of the control node instead of the default ++key and source name. ++.PP ++You then need to copy ++.B somehost.key ++to the client host and install it as ++.BR /etc/isns/auth_key . ++Likewise, the server's public key (which resides in ++.BR /etc/isns/auth_key.pub ++on the server) needs to be copied to the client machine, ++and placed in ++.BR /etc/isns/server_key.pub . ++.PP ++By default, when a client registers a storage node (be ++it initiator or target) with iSNS, the client will not be ++able to see any other storage nodes. In order for targets ++to be visible to a given initiator, you need to create ++so-called Discovery Domains (or DDs for short). ++.PP ++Currently, domain membership operations require administrator ++privilege. Future extensions may allow iSNS clients to ++add themselves to one or more DDs upon registration. ++.PP ++To create a discovery domain, and add nodes to it, you can ++use ++.PP ++.B isnsadm --control --dd-register dd-name=mydomain \(rs ++.br ++.B " member-name=iqn.org.bozo.client iqn.org.bozo.jbod ... ++.PP ++In order to add members to an existing DD, you have to ++specify the numeric domain ID - using the DD name is not ++sufficient, unfortunately (this is a requirement of the ++RFC, not an implementation issue): ++.PP ++.B isnsadm --control --dd-register dd-id=42 \(rs ++.br ++.B " member-name=iqn.com.foo member-name=iqn.com.bar ++.PP ++The DD ID can be obtained by doing a query for the DD name: ++.PP ++.B isnsadm --control --query dd-name=mydomain ++.PP ++In management mode, you can also register and deregister ++nodes and portals manually, in case you want to fix up ++an inconsisteny in the database. For instance, this will ++register a node and portal on a host named client.bozo.org: ++.PP ++.B isnsadm --control --register entity=client.bozo.org \(rs ++.br ++.B " initiator=iqn.org.bozo.client portal=191.168.7.1:860 ++.PP ++Note that this registration explicitly specifies the network ++entity in which to place the new objects. If you omit this, ++the new objects will be placed in an entity named ++.BR CONTROL , ++which is decidedly not what you want. ++.SH SEE ALSO ++RFC 4171, ++.BR isnsd (8), ++.BR isns_config (5). ++.SH AUTHORS ++Olaf Kirch +diff --git a/utils/open-isns/doc/isnsd.8 b/utils/open-isns/doc/isnsd.8 +new file mode 100644 +index 0000000..84b3913 +--- /dev/null ++++ b/utils/open-isns/doc/isnsd.8 +@@ -0,0 +1,93 @@ ++.TH ISNSD 8 "11 May 2007" ++.SH NAME ++isnsd \- iSNS server daemon ++.SH SYNOPSIS ++.B isnsd ++.RB [ "\-f" ] ++.RB [ "\-4" ] ++.RB [ "\-6" ] ++.RB [ "\-c \fIfilename" ] ++.RB [ "\-d \fIdebug-facility" ] ++.RB [ \--dump-db ] ++.RB [ \--init ] ++ ++.SH DESCRIPTION ++.B Isnsd ++implements the iSNS protocol as defined in RFC 4171. ++iSNS is a discovery protocol for iSCSI and iFCP. ++.SH OPTIONS ++By default, ++.B isnsd ++will take most of its settings from the configuration ++file ++.BR /etc/isns/isnsd.conf , ++with the exception of the following options: ++.TP ++.BI \--config " filename\fR, " \-c " filename ++This option overrides the default configuration file. ++.TP ++.BR \--foreground , \-f ++By default, ++.B isnsd ++will put itself into the background. By specifying this option, you can ++tell it to run in the foreground. Any error messages or debug output ++will be printed to the console rather than being sent to syslog. ++.TP ++.BI \-4 ++tells ++.B isnsd ++to create an IPv4 socket only. Normally, it defaults ++to IPv6 (which will accept both IPv4 and IPv6 connections). ++.TP ++.BI \-6 ++tells ++.B isnsd ++explicitly ++to create an IPv6 socket only. Since it defaults ++to IPv6 anyway, this is really a no-op. ++.TP ++.BI \--debug " facility\fR, " \-d " facility ++enables debugging. Valid facilities are ++.PP ++.TS ++tab(,),box,center; ++lb|lr. ++socket,network send/receive ++auth,authentication and security related information ++message,iSNS protocol layer ++state,database state ++scn,SCN (state change notification) messages ++esi,ESI (entity status inquiry) messages ++all,all of the above ++.TE ++.PP ++.TP ++.B \--dump-db ++This is a helper function that will read the database from the ++file system, and display it in human readable form. When using ++this option, ++.B isnsd ++will not open any sockets, and terminate immediately after display ++the database. ++.IP ++This option is intended to be used by the administrator when suspecting ++that the database contains bad/inconsistent information. ++.TP ++.B \--init ++This option will create the server's authentication key, and ++the required DSA parameters. The private key is stored in the ++file specified by the ++.B AuthKey ++option (usually ++.BR /etc/isns/auth_key ). ++The public portion of the key is written to same directory, ++with the suffix ++.B .pub ++appended to the key file name. ++.SH SEE ALSO ++RFC 4171, ++.BR isnsadm (8), ++.BR isnsdd (8), ++.BR isns_config (5). ++.SH AUTHORS ++Olaf Kirch +diff --git a/utils/open-isns/doc/isnsdd.8 b/utils/open-isns/doc/isnsdd.8 +new file mode 100644 +index 0000000..6088e28 +--- /dev/null ++++ b/utils/open-isns/doc/isnsdd.8 +@@ -0,0 +1,75 @@ ++.TH ISNSDD 8 "11 May 2007" ++.SH NAME ++isnsdd \- iSNS discovery daemon ++.SH SYNOPSIS ++.B isnsdd ++.RB [ "\-f" ] ++.RB [ "\-c \fIfilename" ] ++.RB [ "\-d \fIdebug-facility" ] ++ ++.SH DESCRIPTION ++.B Isnsdd ++is a client side daemon for iSNS. It registers storage ++nodes and portals with the iSNS service, and refreshes ++these registrations in a timely manner. ++.PP ++The daemon also registers itself to receive SCN notifications, ++and processes these. It can be configured to invoke an ++external helper application for each status notification ++received. The path name of the helper application can be ++specified via the ++.B SCNCallout ++option in the configuration file. ++.SH OPTIONS ++By default, ++.B isnsd ++will take most of its settings from the configuration ++file ++.BR /etc/isns/isnsdd.conf , ++with the addition of the following command line options: ++.TP ++.BI \--config " filename\fR, " \-c " filename ++This option overrides the default configuration file. ++.TP ++.BR \--foreground , \-f ++By default, ++.B isnsd ++will put itself into the background. By specifying this option, you can ++tell it to run in the foreground. Any error messages or debug output ++will be printed to the console rather than being sent to syslog. ++.TP ++.BI \--role " role ++This tells the discovery daemon in which capacity is should register itself ++with the iSNS server. ++.I Role ++can be either ++.BR initiator ", or " control . ++The default is to register as an initiator. ++.IP ++Registering target nodes needs to use a different mechanism, as ++the iSCSI target server needs to inform the discovery daemon ++about each exported target separately. This is not implemented ++yet. ++.TP ++.BI \--debug " facility\fR, " \-d " facility ++enables debugging. Valid facilities are ++.PP ++.TS ++tab(,),box,center; ++lb|lr. ++socket,network send/receive ++auth,authentication and security related information ++message,iSNS protocol layer ++state,database state ++scn,SCN (state change notification) messages ++esi,ESI (entity status inquiry) messages ++all,all of the above ++.TE ++.PP ++.SH SEE ALSO ++RFC 4171, ++.BR isnsd (8), ++.BR isnsadm (8), ++.BR isns_config (5). ++.SH AUTHORS ++Olaf Kirch +diff --git a/utils/open-isns/domain.c b/utils/open-isns/domain.c +new file mode 100644 +index 0000000..3b848ac +--- /dev/null ++++ b/utils/open-isns/domain.c +@@ -0,0 +1,208 @@ ++/* ++ * iSNS object model - discovery domain specific code ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include "isns.h" ++#include "objects.h" ++#include "util.h" ++ ++static int ++__isns_default_dd_rebuild(isns_object_t *obj, isns_db_t *db) ++{ ++ isns_object_list_t list = ISNS_OBJECT_LIST_INIT; ++ unsigned int i; ++ ++ isns_object_prune_attrs(obj); ++ ++ isns_db_get_domainless(db, &isns_iscsi_node_template, &list); ++ for (i = 0; i < list.iol_count; ++i) { ++ isns_object_t *node = list.iol_data[i]; ++ const char *name; ++ uint32_t type; ++ ++ if (!isns_object_get_uint32(node, ++ ISNS_TAG_ISCSI_NODE_TYPE, ++ &type)) ++ continue; ++ if (type & ISNS_ISCSI_CONTROL_MASK) ++ continue; ++ if (!isns_object_get_string(node, ++ ISNS_TAG_ISCSI_NAME, ++ &name)) ++ continue; ++ isns_object_set_string(obj, ++ ISNS_TAG_DD_MEMBER_ISCSI_NAME, ++ name); ++ } ++ ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * Create the default domain ++ */ ++isns_object_t * ++isns_create_default_domain(void) ++{ ++ isns_object_t *obj; ++ ++ obj = isns_create_object(&isns_dd_template, NULL, NULL); ++ if (!obj) ++ return NULL; ++ ++ isns_object_set_uint32(obj, ISNS_TAG_DD_ID, 0); ++ obj->ie_rebuild = __isns_default_dd_rebuild; ++ return obj; ++} ++ ++/* ++ * Check object type ++ */ ++int ++isns_object_is_dd(const isns_object_t *obj) ++{ ++ return ISNS_IS_DD(obj); ++} ++ ++int ++isns_object_is_ddset(const isns_object_t *obj) ++{ ++ return ISNS_IS_DDSET(obj); ++} ++ ++/* ++ * Keep track of DD membership through a bit vector ++ */ ++int ++isns_object_mark_membership(isns_object_t *obj, uint32_t id) ++{ ++ if (!obj->ie_membership) ++ obj->ie_membership = isns_bitvector_alloc(); ++ ++ return isns_bitvector_set_bit(obj->ie_membership, id); ++} ++ ++int ++isns_object_test_membership(const isns_object_t *obj, uint32_t id) ++{ ++ if (!obj->ie_membership) ++ return 0; ++ ++ return isns_bitvector_test_bit(obj->ie_membership, id); ++} ++ ++int ++isns_object_clear_membership(isns_object_t *obj, uint32_t id) ++{ ++ if (!obj->ie_membership) ++ return 0; ++ ++ return isns_bitvector_clear_bit(obj->ie_membership, id); ++} ++ ++/* ++ * Check whether the two objects share a discovery domain, ++ * and if so, return the DD_ID. ++ * Returns -1 otherwise. ++ */ ++int ++isns_object_test_visibility(const isns_object_t *a, const isns_object_t *b) ++{ ++ /* The admin can tell isnsd to put all nodes which are *not* ++ * in any discovery domain, into the so-called default domain */ ++ if (isns_config.ic_use_default_domain ++ && a->ie_template == b->ie_template ++ && isns_bitvector_is_empty(a->ie_membership) ++ && isns_bitvector_is_empty(b->ie_membership)) ++ return 1; ++ ++ return isns_bitvector_intersect(a->ie_membership, b->ie_membership, NULL) >= 0; ++} ++ ++/* ++ * Return all visible nodes and portals ++ */ ++static int ++__isns_object_vis_callback(uint32_t dd_id, void *ptr) ++{ ++ isns_object_list_t *list = ptr; ++ ++ /* Get all active members */ ++ isns_dd_get_members(dd_id, list, 1); ++ return 0; ++} ++ ++void ++isns_object_get_visible(const isns_object_t *obj, ++ isns_db_t *db, ++ isns_object_list_t *result) ++{ ++ if (isns_bitvector_is_empty(obj->ie_membership)) { ++ /* Get all other nodes not in any DD */ ++ if (isns_config.ic_use_default_domain) ++ isns_db_get_domainless(db, ++ obj->ie_template, ++ result); ++ return; ++ } ++ ++ isns_bitvector_foreach(obj->ie_membership, ++ __isns_object_vis_callback, ++ result); ++} ++ ++/* ++ * Object templates ++ */ ++static uint32_t discovery_domain_attrs[] = { ++ ISNS_TAG_DD_ID, ++ ISNS_TAG_DD_SYMBOLIC_NAME, ++ ISNS_TAG_DD_MEMBER_ISCSI_INDEX, ++ ISNS_TAG_DD_MEMBER_ISCSI_NAME, ++ ISNS_TAG_DD_MEMBER_FC_PORT_NAME, ++ ISNS_TAG_DD_MEMBER_PORTAL_INDEX, ++ ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR, ++ ISNS_TAG_DD_MEMBER_PORTAL_TCP_UDP_PORT, ++ ISNS_TAG_DD_FEATURES, ++}; ++ ++static uint32_t discovery_domain_key_attrs[] = { ++ ISNS_TAG_DD_ID, ++}; ++ ++isns_object_template_t isns_dd_template = { ++ .iot_name = "Discovery Domain", ++ .iot_handle = ISNS_OBJECT_TYPE_DD, ++ .iot_attrs = discovery_domain_attrs, ++ .iot_num_attrs = array_num_elements(discovery_domain_attrs), ++ .iot_keys = discovery_domain_key_attrs, ++ .iot_num_keys = array_num_elements(discovery_domain_key_attrs), ++ .iot_index = ISNS_TAG_DD_ID, ++ .iot_next_index = ISNS_TAG_DD_NEXT_ID, ++}; ++ ++static uint32_t dd_set_attrs[] = { ++ ISNS_TAG_DD_SET_ID, ++ ISNS_TAG_DD_SET_SYMBOLIC_NAME, ++ ISNS_TAG_DD_SET_STATUS, ++}; ++ ++static uint32_t dd_set_key_attrs[] = { ++ ISNS_TAG_DD_SET_ID, ++}; ++ ++isns_object_template_t isns_ddset_template = { ++ .iot_name = "Discovery Domain Set", ++ .iot_handle = ISNS_OBJECT_TYPE_DDSET, ++ .iot_attrs = dd_set_attrs, ++ .iot_num_attrs = array_num_elements(dd_set_attrs), ++ .iot_keys = dd_set_key_attrs, ++ .iot_num_keys = array_num_elements(dd_set_key_attrs), ++ .iot_next_index = ISNS_TAG_DD_SET_NEXT_ID, ++}; ++ +diff --git a/utils/open-isns/entity.c b/utils/open-isns/entity.c +new file mode 100644 +index 0000000..cd45e1f +--- /dev/null ++++ b/utils/open-isns/entity.c +@@ -0,0 +1,127 @@ ++/* ++ * iSNS object model - network entity specific code ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include "isns.h" ++#include "objects.h" ++#include "util.h" ++ ++/* ++ * Create a network entity ++ */ ++isns_object_t * ++isns_create_entity(int protocol, const char *name) ++{ ++ isns_object_t *obj; ++ ++ obj = isns_create_object(&isns_entity_template, NULL, NULL); ++ isns_object_set_string(obj, ++ ISNS_TAG_ENTITY_IDENTIFIER, ++ name); ++ isns_object_set_uint32(obj, ++ ISNS_TAG_ENTITY_PROTOCOL, ++ protocol); ++ ++ return obj; ++} ++ ++isns_object_t * ++isns_create_entity_for_source(const isns_source_t *source, ++ const char *eid) ++{ ++ switch (isns_source_type(source)) { ++ case ISNS_TAG_ISCSI_NAME: ++ return isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, eid); ++ ++ case ISNS_TAG_FC_PORT_NAME_WWPN: ++ return isns_create_entity(ISNS_ENTITY_PROTOCOL_IFCP, eid); ++ } ++ ++ return NULL; ++} ++ ++const char * ++isns_entity_name(const isns_object_t *node) ++{ ++ const isns_attr_t *attr; ++ ++ if (node->ie_attrs.ial_count == 0) ++ return NULL; ++ attr = node->ie_attrs.ial_data[0]; ++ if (attr->ia_value.iv_type != &isns_attr_type_string ++ || attr->ia_tag_id != ISNS_TAG_ENTITY_IDENTIFIER) ++ return NULL; ++ ++ return attr->ia_value.iv_string; ++ ++} ++ ++int ++isns_object_is_entity(const isns_object_t *obj) ++{ ++ return ISNS_IS_ENTITY(obj); ++} ++ ++/* ++ * 6.2.4. Entity Registration Timestamp ++ * ++ * This field indicates the most recent time when the Network Entity ++ * registration occurred or when an associated object attribute was ++ * updated or queried by the iSNS client registering the Network Entity. ++ * The time format is, in seconds, the update period since the standard ++ * base time of 00:00:00 GMT on January 1, 1970. This field cannot be ++ * explicitly registered. This timestamp TLV format is also used in ++ * the SCN and ESI messages. ++ * ++ * Implementer's note: we consider any kind of activity from ++ * the client an indication that it is still alive. ++ * Only exception is the pseudo-entity that holds the access control ++ * information; we never assign it a timestamp so it is never subject ++ * to expiry. ++ */ ++void ++isns_entity_touch(isns_object_t *obj) ++{ ++ /* Do not add a timestamp to entity CONTROL */ ++ if (obj == NULL ++ || (obj->ie_flags & ISNS_OBJECT_PRIVATE) ++ || obj->ie_template != &isns_entity_template) ++ return; ++ isns_object_set_uint64(obj, ISNS_TAG_TIMESTAMP, time(NULL)); ++} ++ ++/* ++ * Object template ++ */ ++static uint32_t entity_attrs[] = { ++ ISNS_TAG_ENTITY_IDENTIFIER, ++ ISNS_TAG_ENTITY_PROTOCOL, ++ ISNS_TAG_MGMT_IP_ADDRESS, ++ ISNS_TAG_TIMESTAMP, ++ ISNS_TAG_PROTOCOL_VERSION_RANGE, ++ ISNS_TAG_REGISTRATION_PERIOD, ++ ISNS_TAG_ENTITY_INDEX, ++ ISNS_TAG_ENTITY_ISAKMP_PHASE_1, ++ ISNS_TAG_ENTITY_CERTIFICATE, ++}; ++ ++static uint32_t entity_key_attrs[] = { ++ ISNS_TAG_ENTITY_IDENTIFIER, ++}; ++ ++isns_object_template_t isns_entity_template = { ++ .iot_name = "Network Entity", ++ .iot_handle = ISNS_OBJECT_TYPE_ENTITY, ++ .iot_attrs = entity_attrs, ++ .iot_num_attrs = array_num_elements(entity_attrs), ++ .iot_keys = entity_key_attrs, ++ .iot_num_keys = array_num_elements(entity_key_attrs), ++ .iot_index = ISNS_TAG_ENTITY_INDEX, ++ .iot_next_index = ISNS_TAG_ENTITY_NEXT_INDEX, ++}; ++ +diff --git a/utils/open-isns/error.c b/utils/open-isns/error.c +new file mode 100644 +index 0000000..0d365e8 +--- /dev/null ++++ b/utils/open-isns/error.c +@@ -0,0 +1,65 @@ ++/* ++ * iSNS error strings etc. ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include "isns.h" ++ ++const char * ++isns_strerror(enum isns_status status) ++{ ++ switch (status) { ++ case ISNS_SUCCESS: ++ return "Success"; ++ case ISNS_UNKNOWN_ERROR: ++ return "Unknown error"; ++ case ISNS_MESSAGE_FORMAT_ERROR: ++ return "Message format error"; ++ case ISNS_INVALID_REGISTRATION: ++ return "Invalid registration"; ++ case ISNS_INVALID_QUERY: ++ return "Invalid query"; ++ case ISNS_SOURCE_UNKNOWN: ++ return "Source unknown"; ++ case ISNS_SOURCE_ABSENT: ++ return "Source absent"; ++ case ISNS_SOURCE_UNAUTHORIZED: ++ return "Source unauthorized"; ++ case ISNS_NO_SUCH_ENTRY: ++ return "No such entry"; ++ case ISNS_VERSION_NOT_SUPPORTED: ++ return "Version not supported"; ++ case ISNS_INTERNAL_ERROR: ++ return "Internal error"; ++ case ISNS_BUSY: ++ return "Busy"; ++ case ISNS_OPTION_NOT_UNDERSTOOD: ++ return "Option not understood"; ++ case ISNS_INVALID_UPDATE: ++ return "Invalid update"; ++ case ISNS_MESSAGE_NOT_SUPPORTED: ++ return "Message not supported"; ++ case ISNS_SCN_EVENT_REJECTED: ++ return "SCN event rejected"; ++ case ISNS_SCN_REGISTRATION_REJECTED: ++ return "SCN registration rejected"; ++ case ISNS_ATTRIBUTE_NOT_IMPLEMENTED: ++ return "Attribute not implemented"; ++ case ISNS_FC_DOMAIN_ID_NOT_AVAILABLE: ++ return "FC domain id not available"; ++ case ISNS_FC_DOMAIN_ID_NOT_ALLOCATED: ++ return "FC domain id not allocated"; ++ case ISNS_ESI_NOT_AVAILABLE: ++ return "ESI not available"; ++ case ISNS_INVALID_DEREGISTRATION: ++ return "Invalid deregistration"; ++ case ISNS_REGISTRATION_FEATURE_NOT_SUPPORTED: ++ return "Registration feature not supported"; ++ default: ++ break; ++ } ++ ++ return "Unknown iSNS status code"; ++} ++ +diff --git a/utils/open-isns/esi.c b/utils/open-isns/esi.c +new file mode 100644 +index 0000000..47d52c6 +--- /dev/null ++++ b/utils/open-isns/esi.c +@@ -0,0 +1,576 @@ ++/* ++ * Handle ESI events ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include "isns.h" ++#include "attrs.h" ++#include "objects.h" ++#include "message.h" ++#include "security.h" ++#include "util.h" ++#include "db.h" ++ ++#define ESI_RETRANS_TIMEOUT 60 ++ ++typedef struct isns_esi isns_esi_t; ++typedef struct isns_esi_portal isns_esi_portal_t; ++ ++struct isns_esi { ++ isns_list_t esi_list; ++ isns_object_t * esi_object; ++ isns_list_t esi_portals; ++ ++ unsigned int esi_update : 1; ++}; ++ ++struct isns_esi_portal { ++ isns_list_t esp_list; ++ isns_object_t * esp_object; ++ isns_portal_info_t esp_portal; ++ unsigned int esp_interval; ++ isns_portal_info_t esp_dest; ++ ++ isns_socket_t * esp_socket; ++ unsigned int esp_retries; ++ unsigned int esp_timeout; ++ time_t esp_start; ++ time_t esp_next_xmit; ++ uint32_t esp_xid; ++}; ++ ++int isns_esi_enabled = 0; ++static isns_server_t * isns_esi_server = NULL; ++static ISNS_LIST_DECLARE(isns_esi_list); ++ ++static void isns_esi_transmit(void *); ++static void isns_esi_sendto(isns_esi_t *, isns_esi_portal_t *); ++static void isns_process_esi_response(uint32_t, int, ++ isns_simple_t *); ++static void isns_esi_disconnect(isns_esi_portal_t *); ++static void isns_esi_restart(isns_esi_portal_t *); ++static void isns_esi_drop_portal(isns_esi_portal_t *, isns_db_t *, int); ++static void isns_esi_drop_entity(isns_esi_t *, isns_db_t *, int); ++static int isns_esi_update(isns_esi_t *); ++static void isns_esi_schedule(int); ++static void isns_esi_callback(const isns_db_event_t *, void *); ++ ++void ++isns_esi_init(isns_server_t *srv) ++{ ++ if (isns_config.ic_esi_retries == 0) { ++ isns_debug_esi("ESI disabled by administrator\n"); ++ } else { ++ unsigned int max_interval; ++ ++ isns_register_callback(isns_esi_callback, NULL); ++ isns_esi_schedule(0); ++ ++ max_interval = isns_config.ic_registration_period / 2; ++ if (isns_config.ic_esi_max_interval > max_interval) { ++ isns_warning("Max ESI interval adjusted to %u sec " ++ "to match registration period\n", ++ max_interval); ++ isns_config.ic_esi_max_interval = max_interval; ++ if (isns_config.ic_esi_min_interval > max_interval) ++ isns_config.ic_esi_min_interval = max_interval; ++ } ++ isns_esi_server = srv; ++ isns_esi_enabled = 1; ++ } ++} ++ ++/* ++ * Timer callback to send out ESI messages. ++ */ ++void ++isns_esi_transmit(void *ptr) ++{ ++ isns_db_t *db = isns_esi_server->is_db; ++ isns_list_t *esi_pos, *esi_next; ++ time_t now; ++ isns_object_t *obj; ++ time_t next_timeout; ++ ++ now = time(NULL); ++ next_timeout = now + 3600; ++ ++ isns_list_foreach(&isns_esi_list, esi_pos, esi_next) { ++ isns_list_t *esp_pos, *esp_next; ++ isns_esi_t *esi = isns_list_item(isns_esi_t, esi_list, esi_pos); ++ ++ if (esi->esi_update) { ++ esi->esi_update = 0; ++ if (!isns_esi_update(esi)) ++ continue; ++ } ++ ++ isns_list_foreach(&esi->esi_portals, esp_pos, esp_next) { ++ isns_esi_portal_t *esp = isns_list_item(isns_esi_portal_t, ++ esp_list, esp_pos); ++ ++ /* Check whether the portal object still exist */ ++ obj = esp->esp_object; ++ if (obj->ie_state != ISNS_OBJECT_STATE_MATURE) { ++ isns_esi_drop_portal(esp, db, 0); ++ continue; ++ } ++ ++ if (esp->esp_next_xmit <= now) { ++ if (esp->esp_retries == 0) { ++ isns_debug_esi("No ESI response from %s - dropping\n", ++ isns_portal_string(&esp->esp_dest)); ++ isns_esi_drop_portal(esp, db, 1); ++ continue; ++ } ++ ++ esp->esp_retries -= 1; ++ esp->esp_next_xmit = now + esp->esp_timeout; ++ isns_esi_sendto(esi, esp); ++ } ++ if (esp->esp_next_xmit < next_timeout) ++ next_timeout = esp->esp_next_xmit; ++ } ++ ++ if (isns_list_empty(&esi->esi_portals)) ++ isns_esi_drop_entity(esi, db, 1); ++ } ++ ++ isns_debug_esi("Next ESI message in %d seconds\n", next_timeout - now); ++ isns_esi_schedule(next_timeout - now); ++} ++ ++/* ++ * Send an ESI message ++ */ ++void ++isns_esi_sendto(isns_esi_t *esi, isns_esi_portal_t *esp) ++{ ++ isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; ++ isns_socket_t *sock; ++ isns_simple_t *msg; ++ ++ /* For TCP portals, kill the TCP socket every time. */ ++ if (esp->esp_dest.proto == IPPROTO_TCP) ++ isns_esi_disconnect(esp); ++ ++ if (esp->esp_socket == NULL) { ++ sock = isns_connect_to_portal(&esp->esp_dest); ++ if (sock == NULL) ++ return; ++ ++ isns_socket_set_security_ctx(sock, ++ isns_default_security_context(0)); ++ /* sock->is_disconnect_fatal = 1; */ ++ esp->esp_socket = sock; ++ } ++ ++ isns_attr_list_append_uint64(&attrs, ++ ISNS_TAG_TIMESTAMP, ++ time(NULL)); ++ /* The following will extract the ENTITY IDENTIFIER */ ++ isns_object_extract_keys(esi->esi_object, &attrs); ++ isns_portal_to_attr_list(&esp->esp_portal, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ &attrs); ++ ++ msg = isns_simple_create(ISNS_ENTITY_STATUS_INQUIRY, ++ NULL, &attrs); ++ if (msg == NULL) ++ return; ++ ++ isns_debug_esi("*** Sending ESI message to %s (xid=0x%x); %u retries left\n", ++ isns_portal_string(&esp->esp_dest), ++ msg->is_xid, esp->esp_retries); ++ isns_simple_transmit(esp->esp_socket, msg, ++ NULL, esp->esp_timeout - 1, ++ isns_process_esi_response); ++ esp->esp_xid = msg->is_xid; ++ isns_simple_free(msg); ++} ++ ++/* ++ * A new entity was added. See if it uses ESI, and create ++ * portals and such. ++ */ ++static void ++isns_esi_add_entity(isns_object_t *obj) ++{ ++ isns_esi_t *esi; ++ ++ isns_debug_esi("Enable ESI monitoring for entity %u\n", obj->ie_index); ++ esi = isns_calloc(1, sizeof(*esi)); ++ esi->esi_object = isns_object_get(obj); ++ esi->esi_update = 1; ++ isns_list_init(&esi->esi_list); ++ isns_list_init(&esi->esi_portals); ++ ++ isns_list_append(&isns_esi_list, &esi->esi_list); ++} ++ ++/* ++ * Given an entity, see if we can find ESI state for it. ++ */ ++static isns_esi_t * ++isns_esi_find(isns_object_t *obj) ++{ ++ isns_list_t *pos, *next; ++ ++ isns_list_foreach(&isns_esi_list, pos, next) { ++ isns_esi_t *esi = isns_list_item(isns_esi_t, esi_list, pos); ++ ++ if (esi->esi_object == obj) ++ return esi; ++ } ++ return NULL; ++} ++ ++/* ++ * Update the ESI state after an entity has changed ++ */ ++static int ++isns_esi_update(isns_esi_t *esi) ++{ ++ isns_object_t *entity = esi->esi_object; ++ ISNS_LIST_DECLARE(hold); ++ isns_esi_portal_t *esp; ++ unsigned int i; ++ ++ isns_debug_esi("Updating ESI state for entity %u\n", entity->ie_index); ++ ++ isns_list_move(&hold, &esi->esi_portals); ++ for (i = 0; i < entity->ie_children.iol_count; ++i) { ++ isns_object_t *child = entity->ie_children.iol_data[i]; ++ isns_portal_info_t esi_portal, portal_info; ++ uint32_t esi_interval; ++ isns_list_t *pos, *next; ++ int changed = 0; ++ ++ if (!ISNS_IS_PORTAL(child)) ++ continue; ++ ++ if (!isns_portal_from_object(&portal_info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ child) ++ || !isns_portal_from_object(&esi_portal, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_ESI_PORT, ++ child) ++ || !isns_object_get_uint32(child, ++ ISNS_TAG_ESI_INTERVAL, ++ &esi_interval)) ++ continue; ++ ++ isns_list_foreach(&hold, pos, next) { ++ esp = isns_list_item(isns_esi_portal_t, esp_list, pos); ++ ++ if (esp->esp_object == child) { ++ isns_debug_esi("Updating ESI state for %s\n", ++ isns_portal_string(&portal_info)); ++ isns_list_del(&esp->esp_list); ++ goto update; ++ } ++ } ++ ++ isns_debug_esi("Creating ESI state for %s\n", ++ isns_portal_string(&portal_info)); ++ esp = isns_calloc(1, sizeof(*esp)); ++ esp->esp_object = isns_object_get(child); ++ isns_list_init(&esp->esp_list); ++ changed = 1; ++ ++update: ++ if (!isns_portal_equal(&esp->esp_portal, &portal_info)) { ++ esp->esp_portal = portal_info; ++ changed++; ++ } ++ if (!isns_portal_equal(&esp->esp_dest, &esi_portal)) { ++ isns_esi_disconnect(esp); ++ esp->esp_dest = esi_portal; ++ changed++; ++ } ++ if (esp->esp_interval != esi_interval) { ++ esp->esp_interval = esi_interval; ++ changed++; ++ } ++ ++ isns_esi_restart(esp); ++ ++ isns_list_append(&esi->esi_portals, &esp->esp_list); ++ } ++ ++ /* Destroy any old ESI portals */ ++ while (!isns_list_empty(&hold)) { ++ esp = isns_list_item(isns_esi_portal_t, esp_list, hold.next); ++ ++ isns_esi_drop_portal(esp, NULL, 0); ++ } ++ ++ /* If the client explicitly unregistered all ESI portals, ++ * stop monitoring it but *without* destroying the entity. */ ++ if (isns_list_empty(&esi->esi_portals)) { ++ isns_esi_drop_entity(esi, NULL, 0); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++void ++isns_esi_restart(isns_esi_portal_t *esp) ++{ ++ unsigned int timeo; ++ ++ isns_esi_disconnect(esp); ++ ++ esp->esp_start = time(NULL); ++ esp->esp_retries = isns_config.ic_esi_retries; ++ esp->esp_next_xmit = esp->esp_start + esp->esp_interval; ++ esp->esp_xid = 0; ++ ++ timeo = esp->esp_interval / esp->esp_retries; ++ if (timeo == 0) ++ timeo = 1; ++ else if (timeo > ESI_RETRANS_TIMEOUT) ++ timeo = ESI_RETRANS_TIMEOUT; ++ esp->esp_timeout = timeo; ++} ++ ++void ++isns_esi_disconnect(isns_esi_portal_t *esp) ++{ ++ if (esp->esp_socket) ++ isns_socket_free(esp->esp_socket); ++ esp->esp_socket = NULL; ++} ++ ++/* ++ * Generic wrapper to dropping an object ++ */ ++static inline void ++__isns_esi_drop_object(isns_db_t *db, isns_object_t *obj, unsigned int dead) ++{ ++ if (db && obj && obj->ie_state == ISNS_OBJECT_STATE_MATURE && dead) ++ isns_db_remove(db, obj); ++ isns_object_release(obj); ++} ++ ++/* ++ * Portal did not respond in time. Drop it ++ */ ++void ++isns_esi_drop_portal(isns_esi_portal_t *esp, isns_db_t *db, int dead) ++{ ++ isns_debug_esi("ESI: dropping portal %s\n", ++ isns_portal_string(&esp->esp_portal)); ++ ++ isns_list_del(&esp->esp_list); ++ isns_esi_disconnect(esp); ++ __isns_esi_drop_object(db, esp->esp_object, dead); ++ isns_free(esp); ++} ++ ++/* ++ * We ran out of ESI portals for this entity. ++ */ ++void ++isns_esi_drop_entity(isns_esi_t *esi, isns_db_t *db, int dead) ++{ ++ isns_debug_esi("ESI: dropping entity %u\n", ++ esi->esi_object->ie_index); ++ ++ isns_list_del(&esi->esi_list); ++ __isns_esi_drop_object(db, esi->esi_object, dead); ++ ++ while (!isns_list_empty(&esi->esi_portals)) { ++ isns_esi_portal_t *esp; ++ ++ esp = isns_list_item(isns_esi_portal_t, esp_list, ++ esi->esi_portals.next); ++ isns_esi_drop_portal(esp, db, dead); ++ } ++ isns_free(esi); ++} ++ ++/* ++ * When receiving an ESI response, find the portal we sent the ++ * original message to. ++ */ ++static isns_esi_portal_t * ++isns_esi_get_msg_portal(uint32_t xid, isns_esi_t **esip) ++{ ++ isns_list_t *esi_pos, *esi_next; ++ ++ isns_list_foreach(&isns_esi_list, esi_pos, esi_next) { ++ isns_esi_t *esi = isns_list_item(isns_esi_t, esi_list, esi_pos); ++ isns_list_t *esp_pos, *esp_next; ++ ++ isns_list_foreach(&esi->esi_portals, esp_pos, esp_next) { ++ isns_esi_portal_t *esp = isns_list_item(isns_esi_portal_t, ++ esp_list, esp_pos); ++ ++ if (esp->esp_xid == xid) { ++ *esip = esi; ++ return esp; ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Handle incoming ESI request ++ */ ++int ++isns_process_esi(isns_server_t *srv, isns_simple_t *call, isns_simple_t **reply) ++{ ++ const isns_attr_list_t *attrs = &call->is_message_attrs; ++ isns_object_t *portal = NULL; ++ ++ /* We just echo back the attributes sent to us by the server, ++ * without further checking. */ ++ *reply = isns_simple_create(ISNS_ENTITY_STATUS_INQUIRY, ++ srv->is_source, attrs); ++ ++ /* Look up the portal and update its mtime. ++ * This can help the application find out if a portal has ++ * seen ESIs recently, and react. ++ */ ++ if (srv->is_db && attrs->ial_count == 4) { ++ const isns_attr_t *addr_attr, *port_attr; ++ ++ addr_attr = attrs->ial_data[2]; ++ port_attr = attrs->ial_data[3]; ++ if (addr_attr->ia_tag_id == ISNS_TAG_PORTAL_IP_ADDRESS ++ && port_attr->ia_tag_id == ISNS_TAG_PORTAL_TCP_UDP_PORT) { ++ isns_attr_list_t key; ++ ++ key.ial_count = 2; ++ key.ial_data = attrs->ial_data + 2; ++ portal = isns_db_lookup(srv->is_db, ++ &isns_portal_template, ++ &key); ++ } ++ ++ if (portal) ++ portal->ie_mtime = time(NULL); ++ } ++ return ISNS_SUCCESS; ++} ++ ++void ++isns_process_esi_response(uint32_t xid, int status, isns_simple_t *msg) ++{ ++ isns_portal_info_t portal_info; ++ isns_esi_portal_t *esp; ++ isns_esi_t *esi; ++ ++ if (msg == NULL) { ++ isns_debug_esi("ESI call 0x%x timed out\n", xid); ++ return; ++ } ++ ++ /* FIXME: As a matter of security, we should probably ++ * verify that the ESI response originated from the ++ * portal we sent it to; or at least that it was authenticated ++ * by the client we think we're talking to. */ ++ ++ /* Get the portal */ ++ if (!isns_portal_from_attr_list(&portal_info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ &msg->is_message_attrs)) { ++ isns_debug_esi("Ignoring unintelligible ESI response\n"); ++ return; ++ } ++ ++ if (!(esp = isns_esi_get_msg_portal(xid, &esi))) { ++ isns_debug_esi("Ignoring unmatched ESI reply\n"); ++ return; ++ } ++ ++ if (!isns_portal_equal(&esp->esp_portal, &portal_info)) { ++ isns_warning("Faked ESI response for portal %s\n", ++ isns_portal_string(&portal_info)); ++ return; ++ } ++ ++ isns_debug_esi("Good ESI response from %s\n", ++ isns_portal_string(&portal_info)); ++ isns_esi_restart(esp); ++ ++ /* Refresh the entity's registration timestamp */ ++ isns_object_set_uint64(esi->esi_object, ++ ISNS_TAG_TIMESTAMP, ++ time(NULL)); ++ isns_db_sync(isns_esi_server->is_db); ++} ++ ++/* ++ * Helper function to schedule the next timeout ++ */ ++static void ++isns_esi_schedule(int timeout) ++{ ++ isns_cancel_timer(isns_esi_transmit, NULL); ++ isns_add_oneshot_timer(timeout, isns_esi_transmit, NULL); ++} ++ ++/* ++ * Register an entity for ESI monitoring. ++ * This is called when reloading the database. ++ */ ++void ++isns_esi_register(isns_object_t *obj) ++{ ++ if (!isns_esi_find(obj)) ++ isns_esi_add_entity(obj); ++ /* We do not call esi_schedule(0) here; that happens in ++ * isns_esi_init already. */ ++} ++ ++/* ++ * This callback is invoked whenever an object is added/removed/modified. ++ * We use this to keep track of ESI portals and such. ++ */ ++void ++isns_esi_callback(const isns_db_event_t *ev, void *ptr) ++{ ++ isns_object_t *obj, *entity; ++ isns_esi_t *esi; ++ uint32_t event; ++ ++ obj = ev->ie_object; ++ event = ev->ie_bits; ++ ++ if (obj->ie_flags & ISNS_OBJECT_PRIVATE) ++ return; ++ ++ isns_debug_esi("isns_esi_callback(%p, 0x%x)\n", obj, event); ++ ++ if (ISNS_IS_ENTITY(obj) ++ && (event & ISNS_SCN_OBJECT_ADDED_MASK)) { ++ if (!isns_esi_find(obj)) ++ isns_esi_add_entity(obj); ++ /* Schedule an immediate ESI timer run */ ++ isns_esi_schedule(0); ++ return; ++ } ++ ++ if (!(entity = isns_object_get_entity(obj))) ++ return; ++ ++ esi = isns_esi_find(entity); ++ if (esi != NULL) ++ esi->esi_update = 1; ++ ++ /* Schedule an immediate ESI timer run */ ++ isns_esi_schedule(0); ++} +diff --git a/utils/open-isns/etc/isnsadm.conf b/utils/open-isns/etc/isnsadm.conf +new file mode 100644 +index 0000000..e7ee681 +--- /dev/null ++++ b/utils/open-isns/etc/isnsadm.conf +@@ -0,0 +1,73 @@ ++# ++# Sample iSNS client configuration file ++# ++ ++# The source name. This is an iSCSI qualified name, ++# and identifies the client uniquely. ++# ++# If left empty, the source name is derived from ++# the client's hostname. ++# ++#SourceName = iqn.2006-01.com.example.host1 ++ ++# Name and port of the iSNS server. ++# Possible formats: ++# foo.example.com ++# foo.example.com:3205 ++# 192.168.1.7:isns ++# [2001:4e5f::1]:isns ++# SLP: ++# If the special string "SLP:" is given, Open-iSNS will ++# query the SLP directory service to find the iSNS server. ++#ServerAddress = isns.example.com ++ ++ ++# Authentication enable/disable. ++# When set to 1, the client will sign ++# all messages, and expect all server messages ++# to be signed. ++# ++# Authentication requires a valid private DSA ++# key in AuthKeyFile, and the server's DSA public ++# key in ServerKeyFile. ++# ++# The default is to use authentication if the ++# requires keys are installed, and use unauthenticated ++# iSNS otherwise. ++#Security = 1 ++ ++# Location of the client's private key. ++# The file must contain a PEM encoded DSA key. ++# The default is /etc/isns/auth_key ++#AuthKeyFile = /etc/isns/auth_key ++ ++# Location of the servers's public key. ++# The file must contain a PEM encoded DSA key. ++# The default is /etc/isns/server_key.pub ++#ServerKeyFile = /etc/isns/server_key.pub ++ ++# In order to prevent replay attacks, the ++# authentication blocks carried by iSNS ++# include a time stamp. The following two ++# parameters control how we verify the ++# time stamp ++Auth.ReplayWindow = 2m ++Auth.TimeStampJitter = 1s ++ ++# Maximum number of incoming connections ++# accepted. This usually applies to server ++# side only, but is relevant if you create ++# a passive TCP socket for ESI or SCN. ++# Network.MaxSockets = 1024 ++ ++# Time to wait for a TCP connection to be ++# established. ++# Network.ConnectTimeout = 60 ++ ++# When a connection attempt failed, we wait ++# before we try connecting again. ++# Network.ReonnectTimeout = 10 ++ ++# Total amount of time to wait before timing ++# out a call to the iSNS server. ++# Network.CallTimeout = 60 +diff --git a/utils/open-isns/etc/isnsd.conf b/utils/open-isns/etc/isnsd.conf +new file mode 100644 +index 0000000..bc90f40 +--- /dev/null ++++ b/utils/open-isns/etc/isnsd.conf +@@ -0,0 +1,129 @@ ++# ++# Sample iSNS Server configuration file ++# ++ ++# The source name. This is an iSCSI qualified name, ++# and identifies the client uniquely. ++# ++# If left empty, the source name is derived from ++# the client's hostname. ++# ++#SourceName = iqn.2006-01.com.example.host1 ++ ++# Where to store the database. ++# If you leave this empty, isnsd will keep its ++# database in memory. ++# Setting this to an absolute path name will ++# make isnsd keep its database in a directory ++# hierarchy below that directory. ++Database = /var/lib/isns ++ ++# The iSNS server can purge registered entities ++# after a certain period of inactivity. This is ++# called the registration period. ++# Clients who register objects are supposed to ++# refresh their registration within this period. ++# ++# The default value is 0, which disables this ++# feature. ++RegistrationPeriod = 10m ++ ++# iSNS scopes visibility of other nodes using so-called ++# Discovery Domains. A storage node A will only "see" ++# storage node B, if both are members of the same ++# discovery domain. ++# ++# So if a storage node is registered which is not part of ++# any discovery domain, it will not see any other nodes. ++# ++# By setting DefaultDiscoveryDomain=1, you can tell isnsd to ++# create a virtual "default discovery domain", which ++# holds all nodes that are not part of any administratively ++# configured discovery domain. ++DefaultDiscoveryDomain = 1 ++ ++# Make the iSNS server register itself with SLP. ++# Clients will be able to discover the server by ++# querying for service type "iscsi:sms", and a query ++# of "(protocols=isns)" ++SLPRegister = 1 ++ ++# Authentication enable/disable. ++# When set to 1, the client will sign ++# all messages, and expect all server messages ++# to be signed. ++# ++# Authentication requires a valid private DSA ++# key in AuthKeyFile, and the server's DSA public ++# key in ServerKeyFile. ++# ++# The default is to use authentication if the ++# requires keys are installed, and use unauthenticated ++# iSNS otherwise. ++#Security = 1 ++ ++# Location of the client's private key. ++# The file must contain a PEM encoded DSA key. ++# The default is /etc/isns/auth_key ++#AuthKeyFile = /etc/isns/auth_key ++ ++# Location of the servers's public key. ++# The file must contain a PEM encoded DSA key. ++# The default is /etc/isns/server_key.pub ++#ServerKeyFile = /etc/isns/server_key.pub ++ ++# This describes where the iSNS server stores ++# authentication keys and policy information. ++# Two options are currently supported: a ++# simple key store (flat directory with public ++# keys in PEM encoded files), and the iSNS ++# database itself ++#ClientKeyStore = /etc/isns/keystores ++ClientKeyStore = DB: ++ ++# When transmitting State Change Notification, ++# we expect the client to ack them. If the ++# ACK doesn't arrive in due time, we retransmit ++# for a limited number of attempts, cycling ++# through the available portals. ++SCNTimeout = 60 ++SCNRetries = 3 ++ ++# Configuration of ESI. ++# Defaults are ++# ESIMaxInterval = 1h ++# ESIMinInterval = 60s ++# ESIRetries = 3 ++# Setting ESIRetries to 0 disables ESI support, and makes ++# the server reject any portal registrations that specify ++# an ESI portal. ++ESIMinInterval = 1m ++ESIMaxInterval = 2m ++ESIRetries = 3 ++ ++# In order to prevent replay attacks, the ++# authentication blocks carried by iSNS ++# include a time stamp. The following two ++# parameters control how we verify the ++# time stamp ++Auth.ReplayWindow = 2m ++Auth.TimeStampJitter = 1s ++ ++# Maximum number of incoming connections ++# accepted. ++# Network.MaxSockets = 1024 ++ ++# Time to wait for a TCP connection to be ++# established. ++# (Client only) ++# Network.ConnectTimeout = 60 ++ ++# When a connection attempt failed, we wait ++# before we try connecting again. ++# (Client only) ++# Network.ReonnectTimeout = 10 ++ ++# Total amount of time to wait before timing ++# out a call to the iSNS server. ++# (Client only) ++# Network.CallTimeout = 60 +diff --git a/utils/open-isns/etc/isnsdd.conf b/utils/open-isns/etc/isnsdd.conf +new file mode 100644 +index 0000000..d751c3d +--- /dev/null ++++ b/utils/open-isns/etc/isnsdd.conf +@@ -0,0 +1,72 @@ ++# ++# Sample iSNS Discovery Daemon configuration file ++# ++ ++# The source name. This is an iSCSI qualified name, ++# and identifies the client uniquely. ++# ++# If left empty, the source name is derived from ++# the client's hostname. ++# ++#SourceName = iqn.2006-01.com.example.host1:monitor ++ ++# Name and port of the iSNS server. ++# Possible formats: ++# foo.example.com ++# foo.example.com:3205 ++# 192.168.1.7:isns ++# [2001:4e5f::1]:isns ++# SLP: ++# If the special string "SLP:" is given, Open-iSNS will ++# query the SLP directory service to find the iSNS server. ++#ServerAddress = isns.example.com ++ ++# Authentication enable/disable. ++# When set to 1, the client will sign ++# all messages, and expect all server messages ++# to be signed. ++# ++# Authentication requires a valid private DSA ++# key in AuthKeyFile, and the server's DSA public ++# key in ServerKeyFile. ++# ++# The default is to use authentication if the ++# required keys are installed, and use unauthenticated ++# iSNS otherwise. ++#Security = 1 ++ ++# Location of the client's private key. ++# The file must contain a PEM encoded DSA key. ++# The default is /etc/isns/auth_key ++#AuthKeyFile = /etc/isns/auth_key ++ ++# Location of the servers's public key. ++# The file must contain a PEM encoded DSA key. ++# The default is /etc/isns/server_key.pub ++#ServerKeyFile = /etc/isns/server_key.pub ++ ++# In order to prevent replay attacks, the ++# authentication blocks carried by iSNS ++# include a time stamp. The following two ++# parameters control how we verify the ++# time stamp ++Auth.ReplayWindow = 2m ++Auth.TimeStampJitter = 1s ++ ++# Maximum number of incoming connections ++# accepted. This usually applies to server ++# side only, but is relevant if you create ++# a passive TCP socket for ESI or SCN. ++# Network.MaxSockets = 1024 ++ ++# Time to wait for a TCP connection to be ++# established. ++# Network.ConnectTimeout = 60 ++ ++# When a connection attempt failed, we wait ++# before we try connecting again. ++# Network.ReonnectTimeout = 10 ++ ++# Total amount of time to wait before timing ++# out a call to the iSNS server. ++# Network.CallTimeout = 60 +diff --git a/utils/open-isns/etc/openisns.init b/utils/open-isns/etc/openisns.init +new file mode 100644 +index 0000000..7c03778 +--- /dev/null ++++ b/utils/open-isns/etc/openisns.init +@@ -0,0 +1,71 @@ ++#!/bin/sh ++# ++# Init script for Open-iSNS. ++# ++# Copyright (C) 2007 Albert Pauw ++# ++# chkconfig: 345 13 89 ++# description: Starts and stops the iSCSI isns server ++# ++# processname: isnsd ++# pidfile: /var/run/isnsd.pid ++# config: /etc/isns/isnsd.conf ++ ++# Source function library. ++. /etc/init.d/functions ++ ++PATH=/sbin:/bin:/usr/sbin:/usr/bin ++#OPTIONS="-4 -d all" ++CONFIG="-c /etc/isns/isnsd.conf" ++RETVAL=0 ++ ++start() ++{ ++ echo -n "Starting iSCSI isns service: " ++ daemon isnsd $OPTIONS $CONFIG ++ RETVAL=$? ++ success ++ echo ++ [ $RETVAL -eq 0 ] || return ++ touch /var/lock/subsys/open-isns ++} ++ ++stop() ++{ ++ echo -n "Stopping iSCSI isns service: " ++ killproc isnsd ++ [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/open-isns ++ success ++ echo ++ ++} ++ ++restart() ++{ ++ stop ++ start ++} ++ ++case "$1" in ++start) ++ start ++ ;; ++stop) ++ stop ++ ;; ++restart) ++ restart ++ ;; ++status) ++ status isnsd ++ RETVAL=$? ++ ;; ++condrestart) ++ [ -f /var/lock/subsys/open-isns ] && restart ++ ;; ++*) ++ echo $"Usage: $0 {start|stop|restart|status|condrestart}" ++ exit 1 ++esac ++ ++exit $RETVAL +diff --git a/utils/open-isns/export.c b/utils/open-isns/export.c +new file mode 100644 +index 0000000..fa4c278 +--- /dev/null ++++ b/utils/open-isns/export.c +@@ -0,0 +1,547 @@ ++/* ++ * Helper functions to represent iSNS objects as text, ++ * and/or to parse objects represented in textual form. ++ * These functions can be used by command line utilities ++ * such as isnsadm, as well as applications like iscsid ++ * or stgtd when talking to the iSNS discovery daemon. ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "isns.h" ++#include "util.h" ++#include "vendor.h" ++#include "attrs.h" ++#include "security.h" ++#include "objects.h" ++#include "paths.h" ++ ++#define MAX_ALIASES 4 ++ ++struct isns_tag_prefix { ++ const char * name; ++ unsigned int name_len; ++ isns_object_template_t *context; ++}; ++ ++struct tag_name { ++ const char * name; ++ uint32_t tag; ++ struct isns_tag_prefix *prefix; ++ const char * alias[MAX_ALIASES]; ++}; ++ ++static struct isns_tag_prefix all_prefixes[__ISNS_OBJECT_TYPE_MAX] = { ++[ISNS_OBJECT_TYPE_ENTITY] = { "entity-", 7, &isns_entity_template }, ++[ISNS_OBJECT_TYPE_NODE] = { "iscsi-", 6, &isns_iscsi_node_template }, ++[ISNS_OBJECT_TYPE_PORTAL] = { "portal-", 7, &isns_portal_template }, ++[ISNS_OBJECT_TYPE_PG] = { "pg-", 3, &isns_iscsi_pg_template }, ++[ISNS_OBJECT_TYPE_DD] = { "dd-", 3, &isns_dd_template }, ++[ISNS_OBJECT_TYPE_POLICY] = { "policy-", 7, &isns_policy_template }, ++}; ++ ++static struct tag_name all_attrs[] = { ++{ "id", ISNS_TAG_ENTITY_IDENTIFIER, ++ .alias = { "eid", }, ++}, ++{ "prot", ISNS_TAG_ENTITY_PROTOCOL }, ++{ "idx", ISNS_TAG_ENTITY_INDEX }, ++ ++{ "name", ISNS_TAG_ISCSI_NAME }, ++{ "node-type", ISNS_TAG_ISCSI_NODE_TYPE }, ++{ "alias", ISNS_TAG_ISCSI_ALIAS }, ++{ "authmethod", ISNS_TAG_ISCSI_AUTHMETHOD }, ++{ "idx", ISNS_TAG_ISCSI_NODE_INDEX }, ++ ++{ "addr", ISNS_TAG_PORTAL_IP_ADDRESS }, ++{ "port", ISNS_TAG_PORTAL_TCP_UDP_PORT }, ++{ "name", ISNS_TAG_PORTAL_SYMBOLIC_NAME }, ++{ "esi-port", ISNS_TAG_ESI_PORT }, ++{ "esi-interval", ISNS_TAG_ESI_INTERVAL }, ++{ "scn-port", ISNS_TAG_SCN_PORT }, ++{ "idx", ISNS_TAG_PORTAL_INDEX }, ++ ++{ "name", ISNS_TAG_PG_ISCSI_NAME }, ++{ "addr", ISNS_TAG_PG_PORTAL_IP_ADDR }, ++{ "port", ISNS_TAG_PG_PORTAL_TCP_UDP_PORT }, ++{ "tag", ISNS_TAG_PG_TAG }, ++{ "pgt", ISNS_TAG_PG_TAG }, ++{ "idx", ISNS_TAG_PG_INDEX }, ++ ++{ "id", ISNS_TAG_DD_ID }, ++{ "name", ISNS_TAG_DD_SYMBOLIC_NAME }, ++{ "member-name", ISNS_TAG_DD_MEMBER_ISCSI_NAME }, ++{ "member-iscsi-idx", ISNS_TAG_DD_MEMBER_ISCSI_INDEX }, ++{ "member-fc-name", ISNS_TAG_DD_MEMBER_FC_PORT_NAME }, ++{ "member-portal-idx", ISNS_TAG_DD_MEMBER_PORTAL_INDEX }, ++{ "member-addr", ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR }, ++{ "member-port", ISNS_TAG_DD_MEMBER_PORTAL_TCP_UDP_PORT }, ++{ "features", ISNS_TAG_DD_FEATURES }, ++ ++{ "name", OPENISNS_TAG_POLICY_SPI, ++ .alias = { "spi" }, ++}, ++{ "key", OPENISNS_TAG_POLICY_KEY }, ++{ "entity", OPENISNS_TAG_POLICY_ENTITY }, ++{ "object-type", OPENISNS_TAG_POLICY_OBJECT_TYPE }, ++{ "node-type", OPENISNS_TAG_POLICY_NODE_TYPE }, ++{ "node-name", OPENISNS_TAG_POLICY_NODE_NAME }, ++{ "functions", OPENISNS_TAG_POLICY_FUNCTIONS }, ++ ++{ NULL } ++}; ++ ++/* ++ * Initialize tag array ++ */ ++static void ++init_tags(void) ++{ ++ struct tag_name *t; ++ ++ for (t = all_attrs; t->name; ++t) { ++ isns_object_template_t *tmpl; ++ ++ tmpl = isns_object_template_for_tag(t->tag); ++ if (tmpl == NULL) ++ isns_fatal("Bug: cannot find object type for tag %s\n", ++ t->name); ++ t->prefix = &all_prefixes[tmpl->iot_handle]; ++ } ++} ++ ++/* ++ * Match prefix ++ */ ++static struct isns_tag_prefix * ++find_prefix(const char *name) ++{ ++ struct isns_tag_prefix *p; ++ unsigned int i; ++ ++ for (i = 0, p = all_prefixes; i < __ISNS_OBJECT_TYPE_MAX; ++i, ++p) { ++ if (p->name && !strncmp(name, p->name, p->name_len)) ++ return p; ++ } ++ return NULL; ++} ++ ++/* ++ * Look up the tag for a given attribute name. ++ * By default, attr names come with a disambiguating ++ * prefix that defines the object type the attribute applies ++ * to, such as "entity-" or "portal-". Once a context has ++ * been established (ie we know the object type subsequent ++ * attributes apply to), specifying the prefix is optional. ++ * ++ * For instance, in a portal context, "addr=10.1.1.1 port=616 name=foo" ++ * specifies three portal related attributes. Whereas in a portal ++ * group context, the same string would specify three portal group ++ * related attributes. To disambiguate, the first attribute in ++ * this list should be prefixed by "portal-" or "pg-", respectively. ++ */ ++static uint32_t ++tag_by_name(const char *name, struct isns_attr_list_parser *st) ++{ ++ const char *orig_name = name; ++ unsigned int nmatch = 0, i; ++ struct tag_name *t, *match[8]; ++ struct isns_tag_prefix *specific = NULL; ++ ++ if (all_attrs[0].prefix == NULL) ++ init_tags(); ++ ++ specific = find_prefix(name); ++ if (specific != NULL) { ++ if (st->prefix ++ && st->prefix != specific ++ && !st->multi_type_permitted) { ++ isns_error("Cannot mix attributes of different types\n"); ++ return 0; ++ } ++ name += specific->name_len; ++ st->prefix = specific; ++ } ++ ++ for (t = all_attrs; t->name; ++t) { ++ if (specific && t->prefix != specific) ++ continue; ++ if (!st->multi_type_permitted ++ && st->prefix && t->prefix != st->prefix) ++ continue; ++ if (!strcmp(name, t->name)) ++ goto match; ++ for (i = 0; i < MAX_ALIASES && t->alias[i]; ++i) { ++ if (!strcmp(name, t->alias[i])) ++ goto match; ++ } ++ continue; ++ ++match: ++ if (nmatch < 8) ++ match[nmatch++] = t; ++ } ++ ++ if (nmatch > 1) { ++ char conflict[128]; ++ unsigned int i; ++ ++ conflict[0] = '\0'; ++ for (i = 0; i < nmatch; ++i) { ++ if (i) ++ strcat(conflict, ", "); ++ t = match[i]; ++ strcat(conflict, t->prefix->name); ++ strcat(conflict, t->name); ++ } ++ isns_error("tag name \"%s\" not unique in this context " ++ "(could be one of %s)\n", ++ orig_name, conflict); ++ return 0; ++ } ++ ++ if (nmatch == 0) { ++ isns_error("tag name \"%s\" not known in this context\n", ++ orig_name); ++ return 0; ++ } ++ ++ st->prefix = match[0]->prefix; ++ return match[0]->tag; ++} ++ ++static const char * ++name_by_tag(uint32_t tag, struct isns_attr_list_parser *st) ++{ ++ struct tag_name *t; ++ ++ for (t = all_attrs; t->name; ++t) { ++ if (st->prefix && t->prefix != st->prefix) ++ continue; ++ if (t->tag == tag) ++ return t->name; ++ } ++ return NULL; ++} ++ ++static int ++parse_one_attr(const char *name, const char *value, ++ isns_attr_list_t *attrs, ++ struct isns_attr_list_parser *st) ++{ ++ isns_attr_t *attr; ++ uint32_t tag; ++ ++ /* Special case: "portal=" is translated to ++ * addr=
port= ++ * If no context has been set, assume portal context. ++ */ ++ if (!strcasecmp(name, "portal")) { ++ isns_portal_info_t portal_info; ++ uint32_t addr_tag, port_tag; ++ ++ if (st->prefix == NULL) { ++ addr_tag = tag_by_name("portal-addr", st); ++ port_tag = tag_by_name("portal-port", st); ++ } else { ++ addr_tag = tag_by_name("addr", st); ++ port_tag = tag_by_name("port", st); ++ } ++ ++ if (!addr_tag || !port_tag) { ++ isns_error("portal=... not supported in this context\n"); ++ return 0; ++ } ++ if (value == NULL) { ++ isns_attr_list_append_nil(attrs, addr_tag); ++ isns_attr_list_append_nil(attrs, port_tag); ++ return 1; ++ } ++ if (!isns_portal_parse(&portal_info, value, st->default_port)) ++ return 0; ++ isns_portal_to_attr_list(&portal_info, addr_tag, port_tag, attrs); ++ return 1; ++ } ++ ++ if (!(tag = tag_by_name(name, st))) ++ return 0; ++ ++ /* Special handling for key objects */ ++ if (tag == OPENISNS_TAG_POLICY_KEY) { ++ if (!value || !strcasecmp(value, "gen")) { ++ if (st->generate_key == NULL) { ++ isns_error("Key generation not supported in this context\n"); ++ return 0; ++ } ++ attr = st->generate_key(); ++ } else { ++ if (st->load_key == NULL) { ++ isns_error("Policy-key attribute not supported in this context\n"); ++ return 0; ++ } ++ attr = st->load_key(value); ++ } ++ goto append_attr; ++ } ++ ++ if (value == NULL) { ++ isns_attr_list_append_nil(attrs, tag); ++ return 1; ++ } ++ ++ attr = isns_attr_from_string(tag, value); ++ if (!attr) ++ return 0; ++ ++append_attr: ++ isns_attr_list_append_attr(attrs, attr); ++ return 1; ++} ++ ++void ++isns_attr_list_parser_init(struct isns_attr_list_parser *st, ++ isns_object_template_t *tmpl) ++{ ++ if (all_attrs[0].prefix == NULL) ++ init_tags(); ++ ++ memset(st, 0, sizeof(*st)); ++ if (tmpl) ++ st->prefix = &all_prefixes[tmpl->iot_handle]; ++} ++ ++int ++isns_attr_list_split(char *line, char **argv, unsigned int argc_max) ++{ ++ char *src = line; ++ unsigned int argc = 0, quoted = 0; ++ ++ if (!line) ++ return 0; ++ ++ while (1) { ++ char *dst; ++ ++ while (isspace(*src)) ++ ++src; ++ if (!*src) ++ break; ++ ++ argv[argc] = dst = src; ++ while (*src) { ++ char cc = *src++; ++ ++ if (cc == '"') { ++ quoted = !quoted; ++ continue; ++ } ++ if (!quoted && isspace(cc)) { ++ *dst = '\0'; ++ break; ++ } ++ *dst++ = cc; ++ } ++ ++ if (quoted) { ++ isns_error("%s: Unterminated quoted string: \"%s\"\n", ++ __FUNCTION__, argv[argc]); ++ return -1; ++ } ++ argc++; ++ } ++ ++ return argc; ++} ++ ++int ++isns_parse_attrs(unsigned int argc, char **argv, ++ isns_attr_list_t *attrs, ++ struct isns_attr_list_parser *st) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < argc; ++i) { ++ char *name, *value; ++ ++ name = argv[i]; ++ if ((value = strchr(name, '=')) != NULL) ++ *value++ = '\0'; ++ ++ if (!value && !st->nil_permitted) { ++ isns_error("Missing value for atribute %s\n", name); ++ return 0; ++ } ++ ++ if (!parse_one_attr(name, value, attrs, st)) { ++ isns_error("Unable to parse %s=%s\n", name, value); ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++/* ++ * Query strings may contain a mix of query keys (foo=bar), ++ * and requested attributes (?foo). The former are used by ++ * the server in its object search, whereas the latter instruct ++ * it which attributes to return. ++ */ ++int ++isns_parse_query_attrs(unsigned int argc, char **argv, ++ isns_attr_list_t *keys, ++ isns_attr_list_t *requested_attrs, ++ struct isns_attr_list_parser *st) ++{ ++ struct isns_attr_list_parser query_state; ++ unsigned int i; ++ ++ query_state = *st; ++ query_state.multi_type_permitted = 1; ++ ++ for (i = 0; i < argc; ++i) { ++ char *name, *value; ++ ++ name = argv[i]; ++ if ((value = strchr(name, '=')) != NULL) ++ *value++ = '\0'; ++ ++ if (name[0] == '?') { ++ uint32_t tag; ++ ++ if (value) { ++ isns_error("No value allowed for query attribute %s\n", ++ name); ++ return 0; ++ } ++ ++ if ((tag = tag_by_name(name + 1, &query_state)) != 0) { ++ isns_attr_list_append_nil(requested_attrs, tag); ++ continue; ++ } ++ } else { ++ if (!value && !st->nil_permitted) { ++ isns_error("Missing value for atribute %s\n", name); ++ return 0; ++ } ++ ++ if (parse_one_attr(name, value, keys, st)) ++ continue; ++ } ++ ++ isns_error("Unable to parse %s=%s\n", name, value); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++void ++isns_attr_list_parser_help(struct isns_attr_list_parser *st) ++{ ++ isns_object_template_t *tmpl, *current = NULL; ++ struct tag_name *t; ++ ++ if (all_attrs[0].prefix == NULL) ++ init_tags(); ++ ++ for (t = all_attrs; t->name; ++t) { ++ const isns_tag_type_t *tag_type; ++ char namebuf[64]; ++ const char *help; ++ unsigned int i; ++ ++ if (st && !st->multi_type_permitted ++ && st->prefix && t->prefix != st->prefix) ++ continue; ++ ++ tmpl = t->prefix->context; ++ if (tmpl != current) { ++ printf("\nAttributes for object type %s; using prefix %s\n", ++ tmpl->iot_name, t->prefix->name); ++ current = tmpl; ++ } ++ ++ snprintf(namebuf, sizeof(namebuf), "%s%s", t->prefix->name, t->name); ++ printf(" %-20s ", namebuf); ++ ++ tag_type = isns_tag_type_by_id(t->tag); ++ if (tag_type == NULL) { ++ printf("Unknown\n"); ++ continue; ++ } ++ printf("%s (%s", tag_type->it_name, ++ tag_type->it_type->it_name); ++ ++ if (tag_type->it_readonly) ++ printf("; readonly"); ++ if (tag_type->it_multiple) ++ printf("; multiple instances"); ++ printf(")"); ++ ++ help = NULL; ++ if (t->tag == OPENISNS_TAG_POLICY_KEY) { ++ help = "name of key file, or \"gen\" for key generation"; ++ } else ++ if (tag_type->it_help) ++ help = tag_type->it_help(); ++ ++ if (help) { ++ if (strlen(help) < 20) ++ printf(" [%s]", help); ++ else ++ printf("\n%25s[%s]", "", help); ++ } ++ printf("\n"); ++ ++ if (t->alias[0]) { ++ printf("%25sAliases:", ""); ++ for (i = 0; i < MAX_ALIASES && t->alias[i]; ++i) ++ printf(" %s", t->alias[i]); ++ printf("\n"); ++ } ++ } ++} ++ ++isns_object_template_t * ++isns_attr_list_parser_context(const struct isns_attr_list_parser *st) ++{ ++ if (st->prefix) ++ return st->prefix->context; ++ return NULL; ++} ++ ++int ++isns_print_attrs(isns_object_t *obj, char **argv, unsigned int argsmax) ++{ ++ struct isns_attr_list_parser st; ++ unsigned int i, argc = 0; ++ ++ isns_attr_list_parser_init(&st, obj->ie_template); ++ ++ for (i = 0; i < obj->ie_attrs.ial_count; ++i) { ++ isns_attr_t *attr = obj->ie_attrs.ial_data[i]; ++ char argbuf[512], value[512]; ++ const char *name; ++ ++ name = name_by_tag(attr->ia_tag_id, &st); ++ if (name == NULL) ++ continue; ++ if (argc + 1 >= argsmax) ++ break; ++ ++ snprintf(argbuf, sizeof(argbuf), "%s%s=%s", ++ st.prefix->name, name, ++ isns_attr_print_value(attr, value, sizeof(value))); ++ argv[argc++] = isns_strdup(argbuf); ++ } ++ ++ argv[argc] = NULL; ++ return argc; ++} +diff --git a/utils/open-isns/getnext.c b/utils/open-isns/getnext.c +new file mode 100644 +index 0000000..916ee80 +--- /dev/null ++++ b/utils/open-isns/getnext.c +@@ -0,0 +1,257 @@ ++/* ++ * Handle iSNS DevGetNext ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include "isns.h" ++#include "attrs.h" ++#include "message.h" ++#include "security.h" ++#include "objects.h" ++#include "db.h" ++#include "util.h" ++ ++/* ++ * Create a GetNext query, and set the source name ++ */ ++static isns_simple_t * ++__isns_create_getnext(isns_source_t *source, ++ const isns_attr_list_t *key, ++ const isns_attr_list_t *scope) ++{ ++ isns_simple_t *simp; ++ ++ simp = isns_simple_create(ISNS_DEVICE_GET_NEXT, source, key); ++ if (simp && scope) ++ isns_attr_list_copy(&simp->is_operating_attrs, ++ scope); ++ return simp; ++} ++ ++isns_simple_t * ++isns_create_getnext(isns_client_t *clnt, ++ isns_object_template_t *tmpl, ++ const isns_attr_list_t *scope) ++{ ++ isns_simple_t *simp; ++ unsigned int i; ++ ++ simp = __isns_create_getnext(clnt->ic_source, NULL, scope); ++ if (simp == NULL) ++ return NULL; ++ ++ for (i = 0; i < tmpl->iot_num_keys; ++i) { ++ isns_attr_list_append_nil(&simp->is_message_attrs, ++ tmpl->iot_keys[i]); ++ } ++ return simp; ++} ++ ++isns_simple_t * ++isns_create_getnext_followup(isns_client_t *clnt, ++ const isns_simple_t *resp, ++ const isns_attr_list_t *scope) ++{ ++ return __isns_create_getnext(clnt->ic_source, ++ &resp->is_message_attrs, scope); ++} ++ ++/* ++ * Get the list of objects matching this query ++ */ ++static int ++isns_getnext_get_object(isns_simple_t *qry, isns_db_t *db, ++ isns_object_t **result) ++{ ++ isns_scope_t *scope; ++ isns_attr_list_t *keys = &qry->is_message_attrs, match; ++ isns_object_template_t *tmpl; ++ unsigned int i; ++ ++ /* ++ * 5.6.5.3. ++ * The Message Key Attribute may be an Entity Identifier (EID), ++ * iSCSI Name, iSCSI Index, Portal IP Address and TCP/UDP Port, ++ * Portal Index, PG Index, FC Node Name WWNN, or FC Port Name ++ * WWPN. ++ * ++ * Implementer's comment: In other words, it must be the ++ * key attr(s) of a specific object type, or an index attribute. ++ */ ++ if ((tmpl = isns_object_template_for_key_attrs(keys)) != NULL) { ++ if (keys->ial_count != tmpl->iot_num_keys) ++ return ISNS_INVALID_QUERY; ++ } else if (keys->ial_count == 1) { ++ isns_attr_t *attr = keys->ial_data[0]; ++ ++ tmpl = isns_object_template_for_index_tag(attr->ia_tag_id); ++ } ++ if (tmpl == NULL) ++ return ISNS_INVALID_QUERY; ++ ++ /* Verify whether the client is permitted to retrieve ++ * objects of the given type. */ ++ if (!isns_policy_validate_object_type(qry->is_policy, tmpl, ++ qry->is_function)) ++ return ISNS_SOURCE_UNAUTHORIZED; ++ ++ /* ++ * 5.6.5.3. ++ * The Operating Attributes can be used to specify the scope ++ * of the DevGetNext request, and to specify the attributes of ++ * the next object, which are to be returned in the DevGetNext ++ * response message. All Operating Attributes MUST be attributes ++ * of the object type identified by the Message Key. ++ */ ++ match = qry->is_operating_attrs; ++ for (i = 0; i < match.ial_count; ++i) { ++ isns_attr_t *attr = match.ial_data[i]; ++ ++ if (tmpl != isns_object_template_for_tag(attr->ia_tag_id)) ++ return ISNS_INVALID_QUERY; ++ } ++ ++ /* ++ * 5.6.5.3. ++ * Non-zero-length TLV attributes in the Operating Attributes ++ * are used to scope the DevGetNext message. ++ * [...] ++ * Zero-length TLV attributes MUST be listed after non-zero-length ++ * attributes in the Operating Attributes of the DevGetNext ++ * request message. ++ */ ++ for (i = 0; i < match.ial_count; ++i) { ++ if (ISNS_ATTR_IS_NIL(match.ial_data[i])) { ++ match.ial_count = i; ++ break; ++ } ++ } ++ ++ /* Get the scope for the originating node. */ ++ scope = isns_scope_for_call(db, qry); ++ ++ *result = isns_scope_get_next(scope, tmpl, keys, &match); ++ ++ isns_scope_release(scope); ++ ++ if (*result == NULL) ++ return ISNS_NO_SUCH_ENTRY; ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * Create a Query Response ++ */ ++static isns_simple_t * ++isns_create_getnext_response(isns_source_t *source, ++ const isns_simple_t *qry, isns_object_t *obj) ++{ ++ const isns_attr_list_t *req_attrs = NULL; ++ isns_attr_list_t requested; ++ isns_simple_t *resp; ++ unsigned int i; ++ ++ resp = __isns_create_getnext(source, NULL, NULL); ++ ++ /* ++ * 5.7.5.3. Device Get Next Response (DevGetNextRsp) ++ * The Message Key Attribute field returns the object keys ++ * for the next object after the Message Key Attribute in the ++ * original DevGetNext message. ++ * ++ * Implementer's note: slightly convoluted English here. ++ * I *think* this means the key attributes of the object ++ * we matched. ++ */ ++ if (!isns_object_get_key_attrs(obj, &resp->is_message_attrs)) ++ return NULL; ++ ++ /* ++ * 5.7.5.3. ++ * The Operating Attribute field returns the Operating Attributes ++ * of the next object as requested in the original DevGetNext ++ * message. The values of the Operating Attributes are those ++ * associated with the object identified by the Message Key ++ * Attribute field of the DevGetNextRsp message. ++ * ++ * Implementer's note: the RFC doesn't say clearly what to ++ * do when the list of operating attributes does not ++ * contain any NIL TLVs. Let's default to the same ++ * behavior as elsewhere, and return all attributes ++ * in this case. ++ */ ++ req_attrs = &qry->is_operating_attrs; ++ for (i = 0; i < req_attrs->ial_count; ++i) { ++ if (ISNS_ATTR_IS_NIL(req_attrs->ial_data[i])) ++ break; ++ } ++ requested.ial_count = req_attrs->ial_count - i; ++ requested.ial_data = req_attrs->ial_data + i; ++ if (requested.ial_count) ++ req_attrs = &requested; ++ else ++ req_attrs = NULL; ++ ++ isns_object_get_attrlist(obj, ++ &resp->is_operating_attrs, ++ req_attrs); ++ return resp; ++} ++ ++/* ++ * Process a GetNext request ++ */ ++int ++isns_process_getnext(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) ++{ ++ isns_simple_t *reply = NULL; ++ isns_object_t *obj = NULL; ++ isns_db_t *db = srv->is_db; ++ int status; ++ ++ /* Get the next object */ ++ status = isns_getnext_get_object(call, db, &obj); ++ if (status != ISNS_SUCCESS) ++ goto done; ++ ++ /* If it's a virtual object, rebuild it */ ++ if (obj->ie_rebuild) ++ obj->ie_rebuild(obj, srv->is_db); ++ ++ /* Success: create a new simple message, and ++ * send it in our reply. */ ++ reply = isns_create_getnext_response(srv->is_source, call, obj); ++ if (reply == NULL) ++ status = ISNS_INTERNAL_ERROR; ++ ++done: ++ if (obj) ++ isns_object_release(obj); ++ *result = reply; ++ return status; ++} ++ ++/* ++ * Parse the object in a getnext response ++ */ ++int ++isns_getnext_response_get_object(isns_simple_t *qry, ++ isns_object_t **result) ++{ ++ isns_object_template_t *tmpl; ++ ++ tmpl = isns_object_template_for_key_attrs(&qry->is_operating_attrs); ++ if (tmpl == NULL) { ++ isns_error("Cannot determine object type in GetNext response\n"); ++ return ISNS_ATTRIBUTE_NOT_IMPLEMENTED; ++ } ++ ++ *result = isns_create_object(tmpl, ++ &qry->is_operating_attrs, ++ NULL); ++ return ISNS_SUCCESS; ++} ++ +diff --git a/utils/open-isns/internal.h b/utils/open-isns/internal.h +new file mode 100644 +index 0000000..fb80b48 +--- /dev/null ++++ b/utils/open-isns/internal.h +@@ -0,0 +1,16 @@ ++/* ++ * iSNS implementation - internal functions and types ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#ifndef ISNS_INTERNAL_H ++#define ISNS_INTERNAL_H ++ ++extern char * isns_slp_build_url(uint16_t); ++extern int isns_slp_register(const char *); ++extern int isns_slp_unregister(const char *); ++extern char * isns_slp_find(void); ++ ++#endif /* ISNS_INTERNAL_H */ ++ +diff --git a/utils/open-isns/isns-proto.h b/utils/open-isns/isns-proto.h +new file mode 100644 +index 0000000..fbc3376 +--- /dev/null ++++ b/utils/open-isns/isns-proto.h +@@ -0,0 +1,259 @@ ++/* ++ * iSNS protocol definitions ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#ifndef ISNS_PROTO_H ++#define ISNS_PROTO_H ++ ++#include ++ ++struct isns_hdr { ++ uint16_t i_version; ++ uint16_t i_function; ++ uint16_t i_length; ++ uint16_t i_flags; ++ uint16_t i_xid; ++ uint16_t i_seq; ++}; ++ ++#define ISNS_VERSION 0x0001 ++#define ISNS_MAX_PDU_SIZE 65535 ++#define ISNS_DEFAULT_PORT 3205 ++ ++/* ++ * Values for the i_flags field: ++ */ ++#define ISNS_F_CLIENT 0x8000 ++#define ISNS_F_SERVER 0x4000 ++#define ISNS_F_AUTHBLK_PRESENT 0x2000 ++#define ISNS_F_REPLACE 0x1000 ++#define ISNS_F_LAST_PDU 0x0800 ++#define ISNS_F_FIRST_PDU 0x0400 ++ ++/* ++ * Function values ++ */ ++enum isns_function { ++ ISNS_DEVICE_ATTRIBUTE_REGISTER = 1, ++ ISNS_DEVICE_ATTRIBUTE_QUERY = 2, ++ ISNS_DEVICE_GET_NEXT = 3, ++ ISNS_DEVICE_DEREGISTER = 4, ++ ISNS_SCN_REGISTER = 5, ++ ISNS_SCN_DEREGISTER = 6, ++ ISNS_SCN_EVENT = 7, ++ ISNS_STATE_CHANGE_NOTIFICATION = 8, ++ ISNS_DD_REGISTER = 9, ++ ISNS_DD_DEREGISTER = 10, ++ ISNS_DDS_REGISTER = 11, ++ ISNS_DDS_DEREGISTER = 12, ++ ISNS_ENTITY_STATUS_INQUIRY = 13, ++ ISNS_HEARTBEAT = 14, ++}; ++ ++/* ++ * iSNS status codes: ++ */ ++enum isns_status { ++ ISNS_SUCCESS = 0, ++ ISNS_UNKNOWN_ERROR, ++ ISNS_MESSAGE_FORMAT_ERROR, ++ ISNS_INVALID_REGISTRATION, ++ __ISNS_RESERVED_STATUS, ++ ISNS_INVALID_QUERY, ++ ISNS_SOURCE_UNKNOWN, ++ ISNS_SOURCE_ABSENT, ++ ISNS_SOURCE_UNAUTHORIZED, ++ ISNS_NO_SUCH_ENTRY, ++ ISNS_VERSION_NOT_SUPPORTED, ++ ISNS_INTERNAL_ERROR, ++ ISNS_BUSY, ++ ISNS_OPTION_NOT_UNDERSTOOD, ++ ISNS_INVALID_UPDATE, ++ ISNS_MESSAGE_NOT_SUPPORTED, ++ ISNS_SCN_EVENT_REJECTED, ++ ISNS_SCN_REGISTRATION_REJECTED, ++ ISNS_ATTRIBUTE_NOT_IMPLEMENTED, ++ ISNS_FC_DOMAIN_ID_NOT_AVAILABLE, ++ ISNS_FC_DOMAIN_ID_NOT_ALLOCATED, ++ ISNS_ESI_NOT_AVAILABLE, ++ ISNS_INVALID_DEREGISTRATION, ++ ISNS_REGISTRATION_FEATURE_NOT_SUPPORTED, ++}; ++ ++enum isns_tag { ++ ISNS_TAG_DELIMITER = 0, ++ ISNS_TAG_ENTITY_IDENTIFIER = 1, ++ ISNS_TAG_ENTITY_PROTOCOL = 2, ++ ISNS_TAG_MGMT_IP_ADDRESS = 3, ++ ISNS_TAG_TIMESTAMP = 4, ++ ISNS_TAG_PROTOCOL_VERSION_RANGE = 5, ++ ISNS_TAG_REGISTRATION_PERIOD = 6, ++ ISNS_TAG_ENTITY_INDEX = 7, ++ ISNS_TAG_ENTITY_NEXT_INDEX = 8, ++ ISNS_TAG_ENTITY_ISAKMP_PHASE_1 = 11, ++ ISNS_TAG_ENTITY_CERTIFICATE = 12, ++ ISNS_TAG_PORTAL_IP_ADDRESS = 16, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT = 17, ++ ISNS_TAG_PORTAL_SYMBOLIC_NAME = 18, ++ ISNS_TAG_ESI_INTERVAL = 19, ++ ISNS_TAG_ESI_PORT = 20, ++ ISNS_TAG_PORTAL_INDEX = 22, ++ ISNS_TAG_SCN_PORT = 23, ++ ISNS_TAG_PORTAL_NEXT_INDEX = 24, ++ ISNS_TAG_PORTAL_SECURITY_BITMAP = 27, ++ ISNS_TAG_PORTAL_ISAKMP_PHASE_1 = 28, ++ ISNS_TAG_PORTAL_ISAKMP_PHASE_2 = 29, ++ ISNS_TAG_PORTAL_CERTIFICATE = 31, ++ ISNS_TAG_ISCSI_NAME = 32, ++ ISNS_TAG_ISCSI_NODE_TYPE = 33, ++ ISNS_TAG_ISCSI_ALIAS = 34, ++ ISNS_TAG_ISCSI_SCN_BITMAP = 35, ++ ISNS_TAG_ISCSI_NODE_INDEX = 36, ++ ISNS_TAG_WWNN_TOKEN = 37, ++ ISNS_TAG_ISCSI_NODE_NEXT_INDEX = 38, ++ ISNS_TAG_ISCSI_AUTHMETHOD = 42, ++ ISNS_TAG_PG_ISCSI_NAME = 48, ++ ISNS_TAG_PG_PORTAL_IP_ADDR = 49, ++ ISNS_TAG_PG_PORTAL_TCP_UDP_PORT = 50, ++ ISNS_TAG_PG_TAG = 51, ++ ISNS_TAG_PG_INDEX = 52, ++ ISNS_TAG_PG_NEXT_INDEX = 53, ++ ISNS_TAG_FC_PORT_NAME_WWPN = 64, ++ ISNS_TAG_PORT_ID = 65, ++ ISNS_TAG_FC_PORT_TYPE = 66, ++ ISNS_TAG_SYMBOLIC_PORT_NAME = 67, ++ ISNS_TAG_FABRIC_PORT_NAME = 68, ++ ISNS_TAG_HARD_ADDRESS = 69, ++ ISNS_TAG_PORT_IP_ADDRESS = 70, ++ ISNS_TAG_CLASS_OF_SERVICE = 71, ++ ISNS_TAG_FC4_TYPES = 72, ++ ISNS_TAG_FC4_DESCRIPTOR = 73, ++ ISNS_TAG_FC4_FEATURES = 74, ++ ISNS_TAG_IFCP_SCN_BITMAP = 75, ++ ISNS_TAG_PORT_ROLE = 76, ++ ISNS_TAG_PERMANENT_PORT_NAME = 77, ++ ISNS_TAG_FC4_TYPE_CODE = 95, ++ ISNS_TAG_FC_NODE_NAME_WWNN = 96, ++ ISNS_TAG_SYMBOLIC_NODE_NAME = 97, ++ ISNS_TAG_NODE_IP_ADDRESS = 98, ++ ISNS_TAG_NODE_IPA = 99, ++ ISNS_TAG_PROXY_ISCSI_NAME = 101, ++ ISNS_TAG_SWITCH_NAME = 128, ++ ISNS_TAG_PREFERRED_ID = 129, ++ ISNS_TAG_ASSIGNED_ID = 130, ++ ISNS_TAG_VIRTUAL_FABRIC_ID = 131, ++ ISNS_TAG_SERVER_VENDOR_OUI = 256, ++ ISNS_TAG_DD_SET_ID = 2049, ++ ISNS_TAG_DD_SET_SYMBOLIC_NAME = 2050, ++ ISNS_TAG_DD_SET_STATUS = 2051, ++ ISNS_TAG_DD_SET_NEXT_ID = 2052, ++ ISNS_TAG_DD_ID = 2065, ++ ISNS_TAG_DD_SYMBOLIC_NAME = 2066, ++ ISNS_TAG_DD_MEMBER_ISCSI_INDEX = 2067, ++ ISNS_TAG_DD_MEMBER_ISCSI_NAME = 2068, ++ ISNS_TAG_DD_MEMBER_FC_PORT_NAME = 2069, ++ ISNS_TAG_DD_MEMBER_PORTAL_INDEX = 2070, ++ ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR = 2071, ++ ISNS_TAG_DD_MEMBER_PORTAL_TCP_UDP_PORT = 2072, ++ ISNS_TAG_DD_FEATURES = 2078, ++ ISNS_TAG_DD_NEXT_ID = 2079, ++ ++ __ISNS_TAG_MAX, ++ ++ ISNS_VENDOR_SPECIFIC_SERVER_BASE = 257, /* end 384 */ ++ ISNS_VENDOR_SPECIFIC_ENTITY_BASE = 385, /* end 512 */ ++ ISNS_VENDOR_SPECIFIC_PORTAL_BASE = 513, /* end 640 */ ++ ISNS_VENDOR_SPECIFIC_NODE_BASE = 641, /* end 768 */ ++ ISNS_VENDOR_SPECIFIC_DD_BASE = 1024, /* end 1280 */ ++ ISNS_VENDOR_SPECIFIC_DDSET_BASE = 1281, /* end 1536 */ ++ ISNS_VENDOR_SPECIFIC_OTHER_BASE = 1537, /* end 2048 */ ++}; ++ ++typedef enum isns_entity_protocol { ++ ISNS_ENTITY_PROTOCOL_NONE = 1, ++ ISNS_ENTITY_PROTOCOL_ISCSI = 2, ++ ISNS_ENTITY_PROTOCOL_IFCP = 3, ++} isns_entity_protocol_t; ++ ++enum isns_iscsi_node_type_bits { ++ ISNS_ISCSI_NODE_TYPE_TARGET = 0, ++ ISNS_ISCSI_NODE_TYPE_INITIATOR = 1, ++ ISNS_ISCSI_NODE_TYPE_CONTROL = 2, ++}; ++#define ISNS_ISCSI_INITIATOR_MASK (1 << ISNS_ISCSI_NODE_TYPE_INITIATOR) ++#define ISNS_ISCSI_TARGET_MASK (1 << ISNS_ISCSI_NODE_TYPE_TARGET) ++#define ISNS_ISCSI_CONTROL_MASK (1 << ISNS_ISCSI_NODE_TYPE_CONTROL) ++ ++enum isns_portal_port_bits { ++ ISNS_PORTAL_PORT_UDP = 16, ++}; ++#define ISNS_PORTAL_PORT_UDP_MASK (1 << ISNS_PORTAL_PORT_UDP) ++ ++enum isns_portal_security_bits { ++ ISNS_PORTAL_SEC_BITMAP_VALID = 0, ++ ISNS_PORTAL_SEC_IPSEC_ENABLED = 1, ++ ISNS_PORTAL_SEC_MAIN_MODE_ENABLED = 2, ++ ISNS_PORTAL_SEC_AGGR_MODE_ENABLED = 3, ++ ISNS_PORTAL_SEC_PFS_ENABLED = 4, ++ ISNS_PORTAL_SEC_TRANSPORT_MODE_PREFERRED = 5, ++ ISNS_PORTAL_SEC_TUNNEL_MODE_PREFERRED = 6, ++}; ++#define ISNS_PORTAL_SEC_BITMAP_VALID_MASK (1 << ISNS_PORTAL_SEC_BITMAP_VALID) ++#define ISNS_PORTAL_SEC_IPSEC_ENABLED_MASK (1 << ISNS_PORTAL_SEC_IPSEC_ENABLED) ++#define ISNS_PORTAL_SEC_MAIN_MODE_ENABLED_MASK (1 << ISNS_PORTAL_SEC_MAIN_MODE_ENABLED) ++#define ISNS_PORTAL_SEC_AGGR_MODE_ENABLED_MASK (1 << ISNS_PORTAL_SEC_AGGR_MODE_ENABLED) ++#define ISNS_PORTAL_SEC_PFS_ENABLED_MASK (1 << ISNS_PORTAL_SEC_PFS_ENABLED) ++#define ISNS_PORTAL_SEC_TRANSPORT_MODE_PREFERRED_MASK (1 << ISNS_PORTAL_SEC_TRANSPORT_MODE_PREFERRED) ++#define ISNS_PORTAL_SEC_TUNNEL_MODE_PREFERRED_MASK (1 << ISNS_PORTAL_SEC_TUNNEL_MODE_PREFERRED) ++ ++enum isns_scn_bits { ++ ISNS_SCN_DD_MEMBER_ADDED = 0, ++ ISNS_SCN_DD_MEMBER_REMOVED = 1, ++ ISNS_SCN_OBJECT_UPDATED = 2, ++ ISNS_SCN_OBJECT_ADDED = 3, ++ ISNS_SCN_OBJECT_REMOVED = 4, ++ ISNS_SCN_MANAGEMENT_REGISTRATION = 5, ++ ISNS_SCN_TARGET_AND_SELF_ONLY = 6, ++ ISNS_SCN_INITIATOR_AND_SELF_ONLY = 7, ++}; ++#define ISNS_SCN_DD_MEMBER_ADDED_MASK (1 << ISNS_SCN_DD_MEMBER_ADDED) ++#define ISNS_SCN_DD_MEMBER_REMOVED_MASK (1 << ISNS_SCN_DD_MEMBER_REMOVED) ++#define ISNS_SCN_OBJECT_UPDATED_MASK (1 << ISNS_SCN_OBJECT_UPDATED) ++#define ISNS_SCN_OBJECT_ADDED_MASK (1 << ISNS_SCN_OBJECT_ADDED) ++#define ISNS_SCN_OBJECT_REMOVED_MASK (1 << ISNS_SCN_OBJECT_REMOVED) ++#define ISNS_SCN_MANAGEMENT_REGISTRATION_MASK (1 << ISNS_SCN_MANAGEMENT_REGISTRATION) ++#define ISNS_SCN_TARGET_AND_SELF_ONLY_MASK (1 << ISNS_SCN_TARGET_AND_SELF_ONLY) ++#define ISNS_SCN_INITIATOR_AND_SELF_ONLY_MASK (1 << ISNS_SCN_INITIATOR_AND_SELF_ONLY) ++ ++enum isns_dds_status_bits { ++ ISNS_DDS_ENABLED = 0, ++}; ++#define ISNS_DDS_ENABLED_MASK (1 << ISNS_DDS_ENABLED) ++ ++enum isns_dd_feature_bits { ++ ISNS_DD_BOOT_LIST_ENABLED = 0, ++}; ++#define ISNS_DD_BOOT_LIST_ENABLED_MASK (1 << ISN_BOOT_LIST_DDS_ENABLED) ++ ++#define ISNS_PAD(len) (((len) + 3) & ~3UL) ++ ++/* ++ * iSNS auth block ++ */ ++#define ISNS_AUTHBLK_SIZE 20 ++struct isns_authblk { ++ uint32_t iab_bsd; /* 16bit in SLP */ ++ uint32_t iab_length; /* 16bit in SLP */ ++ uint64_t iab_timestamp; /* 32bit in SLP */ ++ uint32_t iab_spi_len; /* 16bit in SLP */ ++ ++ char * iab_spi; ++ void * iab_sig; ++ uint32_t iab_sig_len; ++} __attribute__((packed)); ++ ++#define ISNS_AUTH_TYPE_SHA1_DSA 0x0002 ++ ++#endif /* ISNS_PROTO_H */ +diff --git a/utils/open-isns/isns.h b/utils/open-isns/isns.h +new file mode 100644 +index 0000000..53c22d5 +--- /dev/null ++++ b/utils/open-isns/isns.h +@@ -0,0 +1,673 @@ ++/* ++ * iSNS implementation - library header file. ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ * ++ * This file contains all declarations and definitions ++ * commonly required by users of libisns. ++ */ ++ ++#ifndef ISNS_H ++#define ISNS_H ++ ++#include ++#include ++#include ++ ++#include ++#include "types.h" ++ ++#define ISNS_MAX_BUFFER 8192 ++#define ISNS_MAX_MESSAGE 8192 ++ ++ ++/* ++ * Client handle ++ */ ++typedef struct isns_client isns_client_t; ++struct isns_client { ++ isns_source_t * ic_source; ++ isns_socket_t * ic_socket; ++}; ++ ++/* ++ * Server operations ++ */ ++typedef int isns_service_fn_t(isns_server_t *, isns_simple_t *, isns_simple_t **); ++typedef void isns_scn_callback_fn_t(isns_db_t *, uint32_t scn_bits, ++ isns_object_template_t *node_type, ++ const char *node_name, ++ const char *recipient); ++struct isns_service_ops { ++ isns_service_fn_t * process_registration; ++ isns_service_fn_t * process_query; ++ isns_service_fn_t * process_getnext; ++ isns_service_fn_t * process_deregistration; ++ isns_service_fn_t * process_scn_registration; ++ isns_service_fn_t * process_scn_deregistration; ++ isns_service_fn_t * process_scn_event; ++ isns_service_fn_t * process_scn; ++ isns_service_fn_t * process_dd_registration; ++ isns_service_fn_t * process_dd_deregistration; ++ isns_service_fn_t * process_esi; ++ isns_service_fn_t * process_heartbeat; ++}; ++ ++extern struct isns_service_ops isns_default_service_ops; ++extern struct isns_service_ops isns_callback_service_ops; ++ ++/* ++ * Output function ++ */ ++void isns_print_stdout(const char *, ...); ++ ++/* ++ * Database events ++ */ ++struct isns_db_event { ++ isns_object_t * ie_recipient; /* Recipient node or NULL */ ++ isns_object_t * ie_object; /* Affected object */ ++ isns_object_t * ie_trigger; /* Triggering object */ ++ unsigned int ie_bits; /* SCN bitmask */ ++}; ++typedef void isns_db_callback_t(const isns_db_event_t *, ++ void *user_data); ++ ++/* ++ * Handling of client objects ++ */ ++extern isns_client_t * isns_create_default_client(isns_security_t *); ++extern isns_client_t * isns_create_client(isns_security_t *, ++ const char *source_name); ++extern isns_client_t * isns_create_local_client(isns_security_t *, ++ const char *source_name); ++extern int isns_client_call(isns_client_t *, ++ isns_simple_t **inout); ++extern void isns_client_destroy(isns_client_t *); ++extern int isns_client_get_local_address(const isns_client_t *, ++ isns_portal_info_t *); ++ ++/* ++ * Handling of server objects ++ */ ++extern isns_server_t * isns_create_server(isns_source_t *, ++ isns_db_t *, ++ struct isns_service_ops *); ++extern void isns_server_set_scn_callback(isns_server_t *, ++ isns_scn_callback_fn_t *); ++ ++ ++/* ++ * Handling of source names ++ */ ++extern int isns_init_names(void); ++extern const char * isns_default_source_name(void); ++extern isns_source_t * isns_source_create(isns_attr_t *); ++extern isns_source_t * isns_source_create_iscsi(const char *name); ++extern isns_source_t * isns_source_create_ifcp(const char *name); ++extern uint32_t isns_source_type(const isns_source_t *); ++extern const char * isns_source_name(const isns_source_t *); ++extern isns_attr_t * isns_source_attr(const isns_source_t *); ++extern isns_source_t * isns_source_get(isns_source_t *); ++extern isns_source_t * isns_source_from_object(const isns_object_t *); ++extern void isns_source_release(isns_source_t *); ++extern int isns_source_match(const isns_source_t *, ++ const isns_source_t *); ++ ++extern void isns_server_set_source(isns_source_t *); ++extern isns_message_t * isns_process_message(isns_server_t *, isns_message_t *); ++ ++extern void isns_simple_print(isns_simple_t *, ++ isns_print_fn_t *); ++extern int isns_simple_call(isns_socket_t *, ++ isns_simple_t **); ++extern int isns_simple_transmit(isns_socket_t *, ++ isns_simple_t *, ++ const isns_portal_info_t *, ++ unsigned int, ++ void (*callback)(uint32_t, int, ++ isns_simple_t *)); ++extern void isns_simple_free(isns_simple_t *); ++extern const isns_attr_list_t *isns_simple_get_attrs(isns_simple_t *); ++ ++extern isns_simple_t * isns_create_query(isns_client_t *clnt, ++ const isns_attr_list_t *query_key); ++extern isns_simple_t * isns_create_query2(isns_client_t *clnt, ++ const isns_attr_list_t *query_key, ++ isns_source_t *source); ++extern int isns_query_request_attr_tag(isns_simple_t *, ++ uint32_t); ++extern int isns_query_request_attr(isns_simple_t *, ++ isns_attr_t *); ++extern int isns_query_response_get_objects(isns_simple_t *qry, ++ isns_object_list_t *result); ++ ++extern isns_simple_t * isns_create_registration(isns_client_t *clnt, ++ isns_object_t *key_object); ++extern isns_simple_t * isns_create_registration2(isns_client_t *clnt, ++ isns_object_t *key_object, ++ isns_source_t *source); ++extern void isns_registration_set_replace(isns_simple_t *, int); ++extern void isns_registration_add_object(isns_simple_t *, ++ isns_object_t *object); ++extern void isns_registration_add_object_list(isns_simple_t *, ++ isns_object_list_t *); ++extern int isns_registration_response_get_objects(isns_simple_t *, ++ isns_object_list_t *); ++ ++extern isns_simple_t * isns_create_getnext(isns_client_t *, ++ isns_object_template_t *, ++ const isns_attr_list_t *); ++extern int isns_getnext_response_get_object(isns_simple_t *, ++ isns_object_t **); ++extern isns_simple_t * isns_create_getnext_followup(isns_client_t *, ++ const isns_simple_t *, ++ const isns_attr_list_t *); ++ ++extern isns_simple_t * isns_create_deregistration(isns_client_t *clnt, ++ const isns_attr_list_t *); ++ ++extern isns_simple_t * isns_create_scn_registration(isns_client_t *clnt, ++ unsigned int); ++extern isns_simple_t * isns_create_scn_registration2(isns_client_t *clnt, ++ unsigned int, ++ isns_source_t *); ++ ++extern int isns_dd_load_all(isns_db_t *); ++extern void isns_dd_get_members(uint32_t, isns_object_list_t *, int); ++extern isns_simple_t * isns_create_dd_registration(isns_client_t *, ++ const isns_attr_list_t *); ++extern isns_simple_t * isns_create_dd_deregistration(isns_client_t *, ++ uint32_t, const isns_attr_list_t *); ++ ++extern isns_object_t * isns_create_object(isns_object_template_t *, ++ const isns_attr_list_t *, ++ isns_object_t *); ++extern isns_object_t * isns_create_entity(int, const char *); ++extern isns_object_t * isns_create_entity_for_source(const isns_source_t *, ++ const char *); ++extern const char * isns_entity_name(const isns_object_t *); ++extern isns_object_t * isns_create_portal(const isns_portal_info_t *, ++ isns_object_t *parent); ++extern isns_object_t * isns_create_storage_node(const char *name, ++ uint32_t type_mask, ++ isns_object_t *parent); ++extern isns_object_t * isns_create_storage_node2(const isns_source_t *, ++ uint32_t type_mask, ++ isns_object_t *parent); ++extern isns_object_t * isns_create_iscsi_initiator(const char *name, ++ isns_object_t *parent); ++extern isns_object_t * isns_create_iscsi_target(const char *name, ++ isns_object_t *parent); ++extern const char * isns_storage_node_name(const isns_object_t *); ++extern isns_attr_t * isns_storage_node_key_attr(const isns_object_t *); ++extern isns_object_t * isns_create_portal_group(isns_object_t *portal, ++ isns_object_t *iscsi_node, uint32_t pg_tag); ++extern isns_object_t * isns_create_default_portal_group(isns_db_t *, ++ isns_object_t *portal, ++ isns_object_t *node); ++extern void isns_get_portal_groups(isns_object_t *portal, ++ isns_object_t *node, ++ isns_object_list_t *result); ++ ++extern const char * isns_object_template_name(isns_object_template_t *); ++extern int isns_object_set_attr(isns_object_t *, isns_attr_t *); ++extern int isns_object_set_attrlist(isns_object_t *, const isns_attr_list_t *); ++extern isns_object_t * isns_object_get(isns_object_t *); ++extern int isns_object_get_attrlist(isns_object_t *obj, ++ isns_attr_list_t *result, ++ const isns_attr_list_t *requested_attrs); ++extern int isns_object_get_key_attrs(isns_object_t *, ++ isns_attr_list_t *); ++extern int isns_object_get_attr(const isns_object_t *, uint32_t, ++ isns_attr_t **); ++extern void isns_object_get_related(isns_db_t *, ++ isns_object_t *, isns_object_list_t *); ++extern void isns_object_get_descendants(const isns_object_t *, ++ isns_object_template_t *, ++ isns_object_list_t *); ++extern void isns_object_release(isns_object_t *); ++extern int isns_object_match(const isns_object_t *, ++ const isns_attr_list_t *); ++extern isns_object_t * isns_object_get_entity(isns_object_t *); ++extern int isns_object_attr_valid(isns_object_template_t *, uint32_t); ++extern int isns_object_contains(const isns_object_t *, const isns_object_t *); ++extern int isns_object_delete_attr(isns_object_t *, uint32_t); ++extern int isns_object_is(const isns_object_t *, ++ isns_object_template_t *); ++extern int isns_object_is_entity(const isns_object_t *); ++extern int isns_object_is_iscsi_node(const isns_object_t *); ++extern int isns_object_is_fc_port(const isns_object_t *); ++extern int isns_object_is_fc_node(const isns_object_t *); ++extern int isns_object_is_portal(const isns_object_t *); ++extern int isns_object_is_pg(const isns_object_t *); ++extern int isns_object_is_policy(const isns_object_t *); ++extern int isns_object_is_dd(const isns_object_t *); ++extern int isns_object_is_ddset(const isns_object_t *); ++extern void isns_object_print(isns_object_t *, ++ isns_print_fn_t *); ++extern time_t isns_object_last_modified(const isns_object_t *); ++extern int isns_object_mark_membership(isns_object_t *, uint32_t); ++extern int isns_object_clear_membership(isns_object_t *, uint32_t); ++extern int isns_object_test_membership(const isns_object_t *, uint32_t); ++extern int isns_object_test_visibility(const isns_object_t *, ++ const isns_object_t *); ++extern void isns_object_get_visible(const isns_object_t *, ++ isns_db_t *, isns_object_list_t *); ++extern void isns_entity_touch(isns_object_t *); ++extern int isns_object_extract_keys(const isns_object_t *, ++ isns_attr_list_t *); ++extern int isns_object_extract_all(const isns_object_t *, ++ isns_attr_list_t *); ++extern int isns_object_extract_writable(const isns_object_t *, ++ isns_attr_list_t *); ++ ++ ++extern int isns_object_set_nil(isns_object_t *obj, ++ uint32_t tag); ++extern int isns_object_set_string(isns_object_t *obj, ++ uint32_t tag, ++ const char *value); ++extern int isns_object_set_uint32(isns_object_t *obj, ++ uint32_t tag, ++ uint32_t value); ++extern int isns_object_set_uint64(isns_object_t *obj, ++ uint32_t tag, ++ uint64_t value); ++extern int isns_object_set_ipaddr(isns_object_t *obj, ++ uint32_t tag, ++ const struct in6_addr *value); ++ ++extern int isns_object_get_string(const isns_object_t *, ++ uint32_t, ++ const char **); ++extern int isns_object_get_ipaddr(const isns_object_t *, ++ uint32_t, ++ struct in6_addr *); ++extern int isns_object_get_uint32(const isns_object_t *, ++ uint32_t, ++ uint32_t *); ++extern int isns_object_get_uint64(const isns_object_t *, ++ uint32_t, ++ uint64_t *); ++extern int isns_object_get_opaque(const isns_object_t *, ++ uint32_t, ++ const void **, size_t *); ++ ++ ++extern int isns_object_find_descendants(isns_object_t *obj, ++ isns_object_template_t *, ++ const isns_attr_list_t *keys, ++ isns_object_list_t *result); ++extern isns_object_t * isns_object_find_descendant(isns_object_t *obj, ++ const isns_attr_list_t *keys); ++extern int isns_object_detach(isns_object_t *); ++extern int isns_object_attach(isns_object_t *, isns_object_t *); ++extern void isns_object_prune_attrs(isns_object_t *); ++extern void isns_mark_object(isns_object_t *, unsigned int); ++ ++extern int isns_get_entity_identifier(isns_object_t *, const char **); ++extern int isns_get_entity_protocol(isns_object_t *, isns_entity_protocol_t *); ++extern int isns_get_entity_index(isns_object_t *, uint32_t *); ++ ++extern int isns_get_portal_ipaddr(isns_object_t *, struct in6_addr *); ++extern int isns_get_portal_tcpudp_port(isns_object_t *, ++ int *ipprotocol, uint16_t *port); ++extern int isns_get_portal_index(isns_object_t *, uint32_t *); ++ ++extern int isns_get_address(struct sockaddr_storage *, ++ const char *, const char *, int, int, int); ++extern char * isns_get_canon_name(const char *); ++ ++extern isns_db_t * isns_db_open(const char *location); ++extern isns_db_t * isns_db_open_shadow(isns_object_list_t *); ++extern isns_object_t * isns_db_lookup(isns_db_t *, ++ isns_object_template_t *, ++ const isns_attr_list_t *); ++extern isns_object_t * isns_db_vlookup(isns_db_t *, ++ isns_object_template_t *, ++ ...); ++extern int isns_db_gang_lookup(isns_db_t *, ++ isns_object_template_t *, ++ const isns_attr_list_t *, ++ isns_object_list_t *); ++extern isns_object_t * isns_db_get_next(isns_db_t *, ++ isns_object_template_t *, ++ const isns_attr_list_t *current, ++ const isns_attr_list_t *scope, ++ const isns_source_t *source); ++extern isns_object_t * isns_db_lookup_source_node(isns_db_t *, ++ const isns_source_t *); ++extern void isns_db_get_domainless(isns_db_t *, ++ isns_object_template_t *, ++ isns_object_list_t *); ++extern uint32_t isns_db_allocate_index(isns_db_t *); ++extern void isns_db_insert(isns_db_t *, isns_object_t *); ++extern void isns_db_insert_limbo(isns_db_t *, isns_object_t *); ++extern int isns_db_remove(isns_db_t *, isns_object_t *); ++extern time_t isns_db_expire(isns_db_t *); ++extern void isns_db_purge(isns_db_t *); ++extern void isns_db_sync(isns_db_t *); ++extern const char * isns_db_generate_eid(isns_db_t *, char *, size_t); ++extern isns_object_t * isns_db_get_control(isns_db_t *); ++extern void isns_db_print(isns_db_t *, ++ isns_print_fn_t *); ++ ++extern void isns_db_begin_transaction(isns_db_t *); ++extern void isns_db_commit(isns_db_t *); ++extern void isns_db_rollback(isns_db_t *); ++ ++extern void isns_object_event(isns_object_t *obj, ++ unsigned int bits, ++ isns_object_t *trigger); ++extern void isns_unicast_event(isns_object_t *dst, ++ isns_object_t *obj, ++ unsigned int bits, ++ isns_object_t *trigger); ++extern void isns_register_callback(isns_db_callback_t *, ++ void *); ++extern void isns_flush_events(void); ++extern const char * isns_event_string(unsigned int); ++ ++extern void isns_add_timer(unsigned int, ++ isns_timer_callback_t *, void *); ++extern void isns_add_oneshot_timer(unsigned int, ++ isns_timer_callback_t *, void *); ++extern void isns_cancel_timer(isns_timer_callback_t *, void *); ++extern time_t isns_run_timers(void); ++ ++extern void isns_object_list_init(isns_object_list_t *); ++extern void isns_object_list_destroy(isns_object_list_t *); ++extern int isns_object_list_contains(const isns_object_list_t *, ++ isns_object_t *); ++extern void isns_object_list_append(isns_object_list_t *, ++ isns_object_t *); ++extern void isns_object_list_append_list(isns_object_list_t *, ++ const isns_object_list_t *); ++extern isns_object_t * isns_object_list_lookup(const isns_object_list_t *, ++ isns_object_template_t *, ++ const isns_attr_list_t *); ++extern int isns_object_list_gang_lookup(const isns_object_list_t *, ++ isns_object_template_t *, ++ const isns_attr_list_t *, ++ isns_object_list_t *); ++extern int isns_object_list_remove(isns_object_list_t *, ++ isns_object_t *); ++extern void isns_object_list_uniq(isns_object_list_t *); ++extern void isns_object_list_print(const isns_object_list_t *, ++ isns_print_fn_t *); ++ ++isns_object_template_t *isns_object_template_for_key_attrs(const isns_attr_list_t *); ++isns_object_template_t *isns_object_template_for_tag(uint32_t); ++isns_object_template_t *isns_object_template_for_index_tag(uint32_t); ++isns_object_template_t *isns_object_template_find(uint32_t); ++ ++extern int isns_attr_set(isns_attr_t *, const void *); ++extern isns_attr_t * isns_attr_get(isns_attr_t *); ++extern void isns_attr_release(isns_attr_t *); ++extern void isns_attr_print(const isns_attr_t *, ++ isns_print_fn_t *); ++extern char * isns_attr_print_value(const isns_attr_t *, ++ char *, size_t); ++extern int isns_attr_match(const isns_attr_t *, ++ const isns_attr_t *); ++extern int isns_attr_compare(const isns_attr_t *, ++ const isns_attr_t *); ++extern isns_attr_t * isns_attr_from_string(uint32_t, const char *); ++ ++extern void isns_attr_list_print(const isns_attr_list_t *, ++ isns_print_fn_t *); ++ ++extern void isns_attr_list_init(isns_attr_list_t *); ++extern void isns_attr_list_copy(isns_attr_list_t *, ++ const isns_attr_list_t *); ++extern void isns_attr_list_destroy(isns_attr_list_t *); ++extern int isns_attr_list_remove_tag(isns_attr_list_t *, ++ uint32_t); ++ ++extern void isns_attr_list_append_attr(isns_attr_list_t *, ++ isns_attr_t *); ++extern void isns_attr_list_append_list(isns_attr_list_t *, ++ const isns_attr_list_t *); ++extern int isns_attr_list_replace_attr(isns_attr_list_t *, ++ isns_attr_t *); ++/* Warning: this does *NOT* return a reference to the attribute */ ++extern int isns_attr_list_get_attr(const isns_attr_list_t *, ++ uint32_t tag, ++ isns_attr_t **); ++ ++extern void isns_attr_list_append_nil(isns_attr_list_t *, ++ uint32_t tag); ++extern void isns_attr_list_append_string(isns_attr_list_t *, ++ uint32_t tag, const char *value); ++extern void isns_attr_list_append_uint32(isns_attr_list_t *, ++ uint32_t tag, uint32_t value); ++extern void isns_attr_list_append_uint64(isns_attr_list_t *, ++ uint32_t, int64_t); ++extern void isns_attr_list_append_int32(isns_attr_list_t *, ++ uint32_t tag, int32_t value); ++extern void isns_attr_list_append_opaque(isns_attr_list_t *, ++ uint32_t tag, const void *ptr, size_t len); ++extern void isns_attr_list_append_ipaddr(isns_attr_list_t *, ++ uint32_t tag, const struct in6_addr *); ++ ++extern int isns_attr_list_append(isns_attr_list_t *, ++ uint32_t tag, const void *); ++extern int isns_attr_list_update(isns_attr_list_t *, ++ uint32_t tag, const void *); ++ ++extern int isns_attr_list_contains(const isns_attr_list_t *, ++ uint32_t tag); ++extern int isns_attr_list_compare(const isns_attr_list_t *, ++ const isns_attr_list_t *); ++ ++/* ++ * Helper macros ++ */ ++#define ISNS_ATTR_TYPE_CHECK(attr, type) \ ++ ((attr)->ia_value.iv_type == &isns_attr_type_##type) ++#define ISNS_ATTR_IS_NIL(attr) \ ++ ISNS_ATTR_TYPE_CHECK(attr, nil) ++#define ISNS_ATTR_IS_STRING(attr) \ ++ ISNS_ATTR_TYPE_CHECK(attr, string) ++#define ISNS_ATTR_IS_IPADDR(attr) \ ++ ISNS_ATTR_TYPE_CHECK(attr, ipaddr) ++#define ISNS_ATTR_IS_UINT32(attr) \ ++ ISNS_ATTR_TYPE_CHECK(attr, uint32) ++#define ISNS_ATTR_IS_UINT64(attr) \ ++ ISNS_ATTR_TYPE_CHECK(attr, uint64) ++#define ISNS_ATTR_IS_OPAQUE(attr) \ ++ ISNS_ATTR_TYPE_CHECK(attr, opaque) ++ ++ ++ ++extern isns_socket_t * isns_create_server_socket(const char *hostname, const char *portname, ++ int af_hint, int sock_type); ++extern isns_socket_t * isns_create_client_socket(const char *hostname, const char *portname, ++ int af_hint, int sock_type); ++extern isns_socket_t * isns_create_bound_client_socket(const char *myaddr, ++ const char *hostname, const char *portname, ++ int af_hint, int sock_type); ++extern isns_socket_t * isns_connect_to_portal(const isns_portal_info_t *); ++extern void isns_socket_set_report_failure(isns_socket_t *); ++extern void isns_socket_set_disconnect_fatal(isns_socket_t *); ++extern int isns_socket_get_local_addr(const isns_socket_t *, ++ struct sockaddr_storage *); ++extern int isns_socket_get_portal_info(const isns_socket_t *, ++ isns_portal_info_t *); ++extern void isns_socket_set_security_ctx(isns_socket_t *, ++ isns_security_t *); ++extern isns_message_t * isns_recv_message(struct timeval *timeout); ++extern isns_message_t * isns_socket_call(isns_socket_t *, isns_message_t *, long); ++extern int isns_socket_send(isns_socket_t *, isns_message_t *); ++extern void isns_socket_free(isns_socket_t *); ++extern int isns_addr_get_port(const struct sockaddr *); ++extern void isns_addr_set_port(struct sockaddr *, unsigned int); ++extern isns_socket_t * isns_socket_find_server(const isns_portal_info_t *); ++ ++extern isns_message_t * isns_create_message(uint16_t function, uint16_t flags); ++extern isns_message_t * isns_create_reply(const isns_message_t *); ++extern int isns_message_init(isns_message_t *, ++ uint16_t, uint16_t, size_t); ++extern int isns_message_status(isns_message_t *); ++extern void isns_message_release(isns_message_t *); ++extern unsigned int isns_message_function(const isns_message_t *); ++extern isns_socket_t * isns_message_socket(const isns_message_t *); ++extern void isns_message_set_error(isns_message_t *, uint32_t); ++ ++extern const char * isns_strerror(enum isns_status); ++extern const char * isns_function_name(unsigned int); ++ ++/* ++ * Security related functions ++ */ ++extern int isns_security_init(void); ++extern isns_principal_t *isns_security_load_privkey(isns_security_t *, ++ const char *filename); ++extern isns_principal_t *isns_security_load_pubkey(isns_security_t *, ++ const char *filename); ++extern isns_security_t *isns_default_security_context(int server_only); ++extern isns_security_t *isns_control_security_context(int server_only); ++extern isns_security_t *isns_create_dsa_context(void); ++extern void isns_security_set_identity(isns_security_t *, isns_principal_t *); ++extern void isns_principal_free(isns_principal_t *); ++extern void isns_add_principal(isns_security_t *, isns_principal_t *); ++extern isns_keystore_t *isns_create_keystore(const char *); ++extern void isns_security_set_keystore(isns_security_t *, ++ isns_keystore_t *); ++extern void isns_principal_set_name(isns_principal_t *, const char *); ++extern const char * isns_principal_name(const isns_principal_t *); ++ ++extern isns_object_template_t isns_entity_template; ++extern isns_object_template_t isns_portal_template; ++extern isns_object_template_t isns_iscsi_node_template; ++extern isns_object_template_t isns_fc_port_template; ++extern isns_object_template_t isns_fc_node_template; ++extern isns_object_template_t isns_iscsi_pg_template; ++extern isns_object_template_t isns_dd_template; ++extern isns_object_template_t isns_ddset_template; ++ ++/* ++ * Config file parser ++ */ ++struct isns_config { ++ char * ic_host_name; ++ char * ic_auth_name; ++ char * ic_source_name; ++ char * ic_source_suffix; ++ char * ic_entity_name; ++ ++ char * ic_server_name; ++ char * ic_bind_address; ++ char * ic_database; ++ char * ic_auth_key_file; ++ char * ic_server_key_file; ++ char * ic_client_keystore; ++ char * ic_control_socket; ++ char * ic_pidfile; ++ char * ic_local_registry_file; ++ int ic_security; ++ int ic_slp_register; ++ ++ char * ic_control_name; ++ char * ic_control_key_file; ++ ++ unsigned int ic_registration_period; ++ unsigned int ic_scn_timeout; ++ unsigned int ic_scn_retries; ++ char * ic_scn_callout; ++ ++ unsigned int ic_esi_max_interval; ++ unsigned int ic_esi_min_interval; ++ unsigned int ic_esi_retries; ++ ++ unsigned int ic_use_default_domain; ++ ++ struct { ++ unsigned int policy; ++ unsigned int replay_window; ++ unsigned int timestamp_jitter; ++ int allow_unknown_peers; ++ } ic_auth; ++ struct { ++ unsigned int max_sockets; ++ unsigned int connect_timeout; ++ unsigned int reconnect_timeout; ++ unsigned int call_timeout; ++ unsigned int udp_retrans_timeout; ++ unsigned int tcp_retrans_timeout; ++ unsigned int idle_timeout; ++ } ic_network; ++ struct { ++ char * param_file; ++ unsigned int key_bits; ++ } ic_dsa; ++ ++}; ++ ++extern struct isns_config isns_config; ++extern int isns_read_config(const char *); ++extern int isns_config_set(const char *, char *); ++ ++/* ++ * Reserved entity name for Policy information ++ */ ++#define ISNS_ENTITY_CONTROL "CONTROL" ++ ++ ++/* ++ * Helpers to deal with portal information ++ */ ++struct isns_portal_info { ++ struct sockaddr_in6 addr; ++ int proto; ++}; ++ ++extern void isns_portal_init(isns_portal_info_t *, ++ const struct sockaddr *, int); ++extern int isns_portal_parse(isns_portal_info_t *portal, ++ const char *addr_spec, ++ const char *default_port); ++extern int isns_portal_from_attr_list(isns_portal_info_t *, ++ uint32_t addr_tag, uint32_t port_tag, ++ const isns_attr_list_t *); ++extern int isns_portal_from_attr_pair(isns_portal_info_t *, ++ const isns_attr_t *, ++ const isns_attr_t *); ++extern int isns_portal_from_object(isns_portal_info_t *, ++ uint32_t addr_tag, uint32_t port_tag, ++ const isns_object_t *); ++extern int isns_portal_from_sockaddr(isns_portal_info_t *, ++ const struct sockaddr_storage *); ++extern int isns_portal_to_sockaddr(const isns_portal_info_t *, ++ struct sockaddr_storage *); ++extern int isns_portal_to_attr_list(const isns_portal_info_t *, ++ uint32_t addr_tag, uint32_t port_tag, ++ isns_attr_list_t *); ++extern int isns_portal_to_object(const isns_portal_info_t *, ++ uint32_t addr_tag, uint32_t port_tag, ++ isns_object_t *); ++extern int isns_portal_is_wildcard(const isns_portal_info_t *); ++extern uint32_t isns_portal_tcpudp_port(const isns_portal_info_t *); ++extern const char * isns_portal_string(const isns_portal_info_t *); ++extern int isns_portal_equal(const isns_portal_info_t *, ++ const isns_portal_info_t *); ++extern int isns_enumerate_portals(isns_portal_info_t *, ++ unsigned int); ++extern int isns_get_nr_portals(void); ++ ++/* Local registry stuff */ ++extern int isns_local_registry_load(const char *, pid_t, isns_object_list_t *); ++extern int isns_local_registry_store(const char *, pid_t, const isns_object_list_t *); ++extern int isns_local_registry_purge(const char *, pid_t); ++ ++/* Should go somwhere else .*/ ++extern int isns_esi_enabled; ++ ++extern void isns_esi_init(isns_server_t *); ++extern void isns_esi_register(isns_object_t *); ++ ++extern void isns_scn_init(isns_server_t *); ++extern time_t isns_scn_transmit_all(void); ++ ++#endif /* ISNS_H */ +diff --git a/utils/open-isns/isnsadm.c b/utils/open-isns/isnsadm.c +new file mode 100644 +index 0000000..db34f8f +--- /dev/null ++++ b/utils/open-isns/isnsadm.c +@@ -0,0 +1,1151 @@ ++/* ++ * isnsadm - helper utility ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isns.h" ++#include "util.h" ++#include "vendor.h" ++#include "attrs.h" ++#include "security.h" ++#include "objects.h" ++#include "paths.h" ++#include "config.h" ++ ++#define ISNS_DEFAULT_PORT_INITIATOR 860 ++#define ISNS_DEFAULT_PORT_TARGET 3260 ++ ++ ++enum { ++ DO_REGISTER = 1024, ++ DO_QUERY, ++ DO_QUERY_EID, ++ DO_LIST, ++ DO_DEREGISTER, ++ DO_DD_REGISTER, ++ DO_DD_DEREGISTER, ++ DO_ENROLL, ++ DO_EDIT_POLICY, ++ DO_DELETE_POLICY, ++}; ++ ++static struct option options[] = { ++ { "help", no_argument, NULL, 'h' }, ++ { "config", required_argument, NULL, 'c' }, ++ { "debug", required_argument, NULL, 'd' }, ++ { "keyfile", required_argument, NULL, 'K', }, ++ { "key", required_argument, NULL, 'k', }, ++ { "local", no_argument, NULL, 'l' }, ++ { "control", no_argument, NULL, 'C' }, ++ { "replace", no_argument, NULL, 'r' }, ++ { "query", no_argument, NULL, DO_QUERY }, ++ { "query-eid", no_argument, NULL, DO_QUERY_EID }, ++ { "list", no_argument, NULL, DO_LIST }, ++ { "register", no_argument, NULL, DO_REGISTER }, ++ { "deregister", no_argument, NULL, DO_DEREGISTER }, ++ { "dd-register", no_argument, NULL, DO_DD_REGISTER }, ++ { "dd-deregister", no_argument, NULL, DO_DD_DEREGISTER}, ++ ++ { "enroll", no_argument, NULL, DO_ENROLL }, ++ { "edit-policy", no_argument, NULL, DO_EDIT_POLICY }, ++ { "delete-policy", no_argument, NULL, DO_DELETE_POLICY }, ++ ++ { "version", no_argument, NULL, 'V' }, ++ { NULL } ++}; ++ ++ ++static const char * opt_configfile = ISNS_DEFAULT_ISNSADM_CONFIG; ++static int opt_af = AF_UNSPEC; ++static int opt_action = 0; ++static int opt_local = 0; ++static int opt_control = 0; ++static int opt_replace = 0; ++static const char * opt_keyfile = NULL; ++static char * opt_key = NULL; ++static struct sockaddr_storage opt_myaddr; ++ ++static void usage(int, const char *); ++ ++static int register_objects(isns_client_t *, int, char **); ++static int query_objects(isns_client_t *, int, char **); ++static int query_entity_id(isns_client_t *, int, char **); ++static int list_objects(isns_client_t *, int, char **); ++static int deregister_objects(isns_client_t *, int, char **); ++static int register_domain(isns_client_t *, int, char **); ++static int deregister_domain(isns_client_t *, int, char **); ++static int enroll_client(isns_client_t *, int, char **); ++static int edit_policy(isns_client_t *, int, char **); ++ ++static isns_attr_t * load_key_callback(const char *); ++static isns_attr_t * generate_key_callback(void); ++ ++int ++main(int argc, char **argv) ++{ ++ isns_client_t *clnt; ++ isns_security_t *security = NULL; ++ int c, status; ++ ++ while ((c = getopt_long(argc, argv, "46Cc:d:hK:k:l", options, NULL)) != -1) { ++ switch (c) { ++ case '4': ++ opt_af = AF_INET; ++ break; ++ ++ case '6': ++ opt_af = AF_INET6; ++ break; ++ ++ case 'C': ++ opt_control = 1; ++ break; ++ ++ case 'c': ++ opt_configfile = optarg; ++ break; ++ ++ case 'd': ++ isns_enable_debugging(optarg); ++ break; ++ ++ case 'h': ++ usage(0, NULL); ++ break; ++ ++ case 'K': ++ opt_keyfile = optarg; ++ break; ++ ++ case 'k': ++ opt_key = optarg; ++ break; ++ ++ case 'l': ++ opt_local = 1; ++ break; ++ ++ case 'r': ++ opt_replace = 1; ++ break; ++ ++ case 'V': ++ printf("Open-iSNS version %s\n" ++ "Copyright (C) 2007, Olaf Kirch \n", ++ OPENISNS_VERSION_STRING); ++ return 0; ++ ++ case DO_REGISTER: ++ case DO_QUERY: ++ case DO_QUERY_EID: ++ case DO_LIST: ++ case DO_DEREGISTER: ++ case DO_DD_REGISTER: ++ case DO_DD_DEREGISTER: ++ case DO_ENROLL: ++ case DO_EDIT_POLICY: ++ case DO_DELETE_POLICY: ++ if (opt_action) ++ usage(1, "You cannot specify more than one mode\n"); ++ opt_action = c; ++ break; ++ ++ default: ++ usage(1, "Unknown option"); ++ } ++ } ++ ++ isns_read_config(opt_configfile); ++ ++ if (!isns_config.ic_source_name) ++ usage(1, "Please specify an iSNS source name"); ++ if (!isns_config.ic_server_name) ++ usage(1, "Please specify an iSNS server name"); ++ if (!opt_action) ++ usage(1, "Please specify an operating mode"); ++ ++ if (opt_control) { ++ if (!isns_config.ic_security) ++ isns_fatal("Cannot use control mode, security disabled\n"); ++ security = isns_control_security_context(0); ++ if (!security) ++ isns_fatal("Unable to create control security context\n"); ++ ++ /* Create a networked client, using isns.control as ++ * the source name */ ++ clnt = isns_create_client(security, isns_config.ic_control_name); ++ } else if (opt_local) { ++ /* Create a local client, using isns.control as ++ * the source name */ ++ clnt = isns_create_local_client(security, ++ isns_config.ic_control_name); ++ } else { ++ /* Create a networked client, using the configured ++ * source name */ ++ clnt = isns_create_default_client(security); ++ } ++ ++ if (clnt == NULL) ++ return 1; ++ ++ /* We're an interactive app, and don't want to retry ++ * forever if the server refuses us. */ ++ isns_socket_set_disconnect_fatal(clnt->ic_socket); ++ ++ /* Get the IP address we use to talk to the iSNS server */ ++ if (opt_myaddr.ss_family == AF_UNSPEC && !opt_local) { ++ if (!isns_socket_get_local_addr(clnt->ic_socket, &opt_myaddr)) ++ isns_fatal("Unable to obtain my IP address\n"); ++ isns_addr_set_port((struct sockaddr *) &opt_myaddr, 860); ++ } ++ ++ argv += optind; argc -= optind; ++ switch (opt_action) { ++ case DO_REGISTER: ++ status = register_objects(clnt, argc, argv); ++ break; ++ ++ case DO_QUERY: ++ status = query_objects(clnt, argc, argv); ++ break; ++ ++ case DO_QUERY_EID: ++ status = query_entity_id(clnt, argc, argv); ++ break; ++ ++ case DO_LIST: ++ status = list_objects(clnt, argc, argv); ++ break; ++ ++ case DO_DEREGISTER: ++ status = deregister_objects(clnt, argc, argv); ++ break; ++ ++ case DO_DD_REGISTER: ++ status = register_domain(clnt, argc, argv); ++ break; ++ ++ case DO_DD_DEREGISTER: ++ status = deregister_domain(clnt, argc, argv); ++ break; ++ ++ ++ case DO_ENROLL: ++ status = enroll_client(clnt, argc, argv); ++ break; ++ ++ case DO_EDIT_POLICY: ++ status = edit_policy(clnt, argc, argv); ++ break; ++ ++ // case DO_DELETE_POLICY: ++ ++ default: ++ isns_fatal("Not yet implemented\n"); ++ status = 1; /* compiler food */ ++ } ++ ++ return status != ISNS_SUCCESS; ++} ++ ++void ++usage(int exval, const char *msg) ++{ ++ if (msg) ++ fprintf(stderr, "Error: %s\n", msg); ++ fprintf(stderr, ++ "Usage: isnsadm [options] --action ...\n" ++ " --config Specify alternative config fille\n" ++ " --debug Enable debugging (list of debug flags)\n" ++ " --keyfile Where to store newly generated private key\n" ++ " --local Use local Unix socket to talk to isnsd\n" ++ " --control Assume control node identity for authentication\n" ++ " --replace Use replace mode (--register only)\n" ++ "\nThe following actions are supported:\n" ++ " --register Register one or more objects\n" ++ " --deregister Deregister an object (and children)\n" ++ " --dd-register Register a Discovery Domain (and members)\n" ++ " --dd-deregister Deregister a Discovery Domain (and members)\n" ++ " --query Query iSNS server for objects\n" ++ " --list List all objects of a given type\n" ++ " --enroll Create a new policy object for a client\n" ++ " --edit-policy Edit a policy object\n" ++ " --delete-policy Edit a policy object\n" ++ " --help Display this message\n" ++ "\nUse \"--query help\" to get help on e.g. the query action\n" ++ ); ++ exit(exval); ++} ++ ++int ++parse_registration(char **argv, int argc, isns_object_list_t *objs, isns_object_t *key_obj) ++{ ++ struct sockaddr_storage def_addr; ++ isns_object_t *entity = NULL, *last_portal = NULL, *last_node = NULL; ++ const char *def_port = NULL; ++ int i; ++ ++ if (argc == 1 && !strcmp(argv[0], "help")) { ++ printf("Object registration:\n" ++ " isnsadm [-key attr=value] --register type,attr=value,... type,attr=value,...\n" ++ "Where type can be one of:\n" ++ " entity create/update network entity\n" ++ " initiator create iSCSI initiator storage node\n" ++ " target create iSCSI target storage node\n" ++ " control create control node\n" ++ " portal create portal\n" ++ " pg create portal group\n" ++ "\nThe following attributes are recognized:\n"); ++ ++ isns_attr_list_parser_help(NULL); ++ exit(0); ++ } ++ ++ if (argc == 0) ++ usage(1, "Missing object list\n"); ++ ++ if (key_obj) { ++ //isns_object_list_append(objs, key_obj); ++ if (isns_object_is_entity(key_obj)) ++ entity = key_obj; ++ } ++ ++ def_addr = opt_myaddr; ++ ++ for (i = 0; i < argc; ++i) { ++ isns_attr_list_t attrlist = ISNS_ATTR_LIST_INIT; ++ struct isns_attr_list_parser state; ++ isns_object_t *obj; ++ char *type, *name, *value, *next_attr; ++ char *attrs[128]; ++ unsigned int nattrs = 0; ++ ++ name = argv[i]; ++ ++ if ((next_attr = strchr(name, ',')) != NULL) ++ *next_attr++ = '\0'; ++ ++ while (next_attr && *next_attr) { ++ if (nattrs > 128) ++ isns_fatal("Too many attributes\n"); ++ ++ /* Show mercy with fat fingered ++ * people,,,,who,cannot,,,type,properly */ ++ if (next_attr[0] != ',') ++ attrs[nattrs++] = next_attr; ++ if ((next_attr = strchr(next_attr, ',')) != NULL) ++ *next_attr++ = '\0'; ++ } ++ ++ if ((value = strchr(name, '=')) != NULL) ++ *value++ = '\0'; ++ ++ type = name; ++ if (!strcmp(name, "entity")) { ++ if (entity == NULL) { ++ isns_error("Cannot create entity object " ++ "within this key object\n"); ++ return 0; ++ } ++ ++ if (value != NULL) ++ isns_object_set_string(entity, ++ ISNS_TAG_ENTITY_IDENTIFIER, ++ value); ++ obj = isns_object_get(entity); ++ goto handle_attributes; ++ } else ++ if (!strcmp(name, "node") ++ || !strcmp(name, "initiator")) { ++ const char *node_name; ++ ++ node_name = isns_config.ic_source_name; ++ if (value) ++ node_name = value; ++ ++ obj = isns_create_storage_node(node_name, ++ ISNS_ISCSI_INITIATOR_MASK, ++ entity); ++ last_node = obj; ++ ++ isns_addr_set_port((struct sockaddr *) &def_addr, ++ ISNS_DEFAULT_PORT_INITIATOR); ++ def_port = "iscsi"; ++ } else ++ if (!strcmp(name, "target")) { ++ const char *node_name; ++ ++ node_name = isns_config.ic_source_name; ++ if (value) ++ node_name = value; ++ obj = isns_create_storage_node(node_name, ++ ISNS_ISCSI_TARGET_MASK, ++ entity); ++ last_node = obj; ++ ++ isns_addr_set_port((struct sockaddr *) &def_addr, ++ ISNS_DEFAULT_PORT_TARGET); ++ def_port = "iscsi-target"; ++ } else ++ if (!strcmp(name, "control")) { ++ const char *node_name; ++ ++ node_name = isns_config.ic_control_name; ++ if (value) ++ node_name = value; ++ obj = isns_create_storage_node(node_name, ++ ISNS_ISCSI_CONTROL_MASK, ++ entity); ++ last_node = obj; ++ ++ def_port = NULL; ++ } else ++ if (!strcmp(name, "portal")) { ++ isns_portal_info_t portal_info; ++ ++ if (value == NULL) { ++ if (def_port == NULL) ++ isns_fatal("portal must follow initiator or target\n"); ++ isns_portal_init(&portal_info, ++ (struct sockaddr *) &def_addr, ++ IPPROTO_TCP); ++ } else ++ if (!isns_portal_parse(&portal_info, value, def_port)) ++ isns_fatal("Unable to parse portal=%s\n", value); ++ obj = isns_create_portal(&portal_info, entity); ++ last_portal = obj; ++ } else ++ if (!strcmp(name, "pg")) { ++ if (value) ++ isns_fatal("Unexpected value for portal group\n"); ++ if (!last_portal || !last_node) ++ isns_fatal("Portal group registration must follow portal and node\n"); ++ obj = isns_create_portal_group(last_portal, last_node, 10); ++ } else { ++ isns_error("Unknown object type \"%s\"\n", name); ++ return 0; ++ } ++ ++ if (obj == NULL) { ++ isns_error("Failure to create %s object\n", name); ++ return 0; ++ } ++ isns_object_list_append(objs, obj); ++ ++handle_attributes: ++ isns_attr_list_parser_init(&state, obj->ie_template); ++ state.default_port = def_port; ++ ++ if (!isns_parse_attrs(nattrs, attrs, &attrlist, &state) ++ || !isns_object_set_attrlist(obj, &attrlist)) { ++ isns_error("Failure to set all %s attributes\n", name); ++ isns_attr_list_destroy(&attrlist); ++ return 0; ++ } ++ ++ isns_attr_list_destroy(&attrlist); ++ isns_object_release(obj); ++ } ++ ++ return 1; ++} ++ ++static int ++__register_objects(isns_client_t *clnt, ++ isns_object_t *key_obj, ++ const isns_object_list_t *objects) ++{ ++ isns_source_t *source = NULL; ++ isns_simple_t *reg; ++ uint32_t status; ++ unsigned int i; ++ ++ for (i = 0; i < objects->iol_count && !source; ++i) { ++ isns_object_t *obj = objects->iol_data[i]; ++ ++ if (!isns_object_is_iscsi_node(obj)) ++ continue; ++ source = isns_source_from_object(obj); ++ } ++ ++ reg = isns_create_registration2(clnt, key_obj, source); ++ isns_registration_set_replace(reg, opt_replace); ++ ++ /* Add all objects to be registered */ ++ for (i = 0; i < objects->iol_count; ++i) ++ isns_registration_add_object(reg, objects->iol_data[i]); ++ ++ status = isns_client_call(clnt, ®); ++ isns_simple_free(reg); ++ ++ if (status == ISNS_SUCCESS) ++ printf("Successfully registered object(s)\n"); ++ else ++ isns_error("Failed to register object(s): %s\n", ++ isns_strerror(status)); ++ ++ if (source) ++ isns_source_release(source); ++ return status; ++} ++ ++int ++register_objects(isns_client_t *clnt, ++ int argc, char **argv) ++{ ++ isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; ++ isns_object_t *key_obj = NULL; ++ uint32_t status; ++ ++ if (opt_key != NULL) { ++ isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; ++ struct isns_attr_list_parser state; ++ ++ isns_attr_list_parser_init(&state, NULL); ++ ++ if (!isns_parse_attrs(1, &opt_key, &key_attrs, &state)) { ++ isns_error("Cannot parse registration key \"%s\"\n", ++ opt_key); ++ return 0; ++ } ++ ++ key_obj = isns_create_object(isns_attr_list_parser_context(&state), ++ &key_attrs, NULL); ++ isns_attr_list_destroy(&key_attrs); ++ ++ if (!key_obj) { ++ isns_error("Cannot create registration key object\n"); ++ return 0; ++ } ++ } else { ++ /* If the user does not provide a key object, ++ * create/update an entity. ++ */ ++ key_obj = isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, NULL); ++ } ++ ++ if (!parse_registration(argv, argc, &objects, key_obj)) ++ isns_fatal("Unable to parse registration\n"); ++ ++ status = __register_objects(clnt, key_obj, &objects); ++ isns_object_list_destroy(&objects); ++ ++ isns_object_release(key_obj); ++ return status; ++} ++ ++/* ++ * Parse the query string given by the user ++ * ++ * 5.6.5.2 ++ * The Message Key may contain key or non-key attributes or no ++ * attributes at all. If multiple attributes are used as the ++ * Message Key, then they MUST all be from the same object type ++ * (e.g., IP address and TCP/UDP Port are attributes of the ++ * Portal object type). ++ */ ++int ++parse_query(char **argv, int argc, isns_attr_list_t *keys, isns_attr_list_t *query) ++{ ++ struct isns_attr_list_parser state; ++ ++ isns_attr_list_parser_init(&state, NULL); ++ state.nil_permitted = 1; ++ ++ if (argc == 1 && !strcmp(argv[0], "help")) { ++ printf("Object query:\n" ++ " isnsadm --query attr=value attr=value ... ?query-attr ?query-attr ...\n" ++ "All key attributes must refer to a common object type.\n" ++ "Query attributes specify the attributes the server should return," ++ "and can refer to any object type.\n" ++ "The following attributes are recognized:\n"); ++ isns_attr_list_parser_help(&state); ++ exit(0); ++ } ++ ++ if (argc == 0) ++ isns_fatal("Missing query attributes\n"); ++ ++ return isns_parse_query_attrs(argc, argv, keys, query, &state); ++} ++ ++int ++query_objects(isns_client_t *clnt, int argc, char **argv) ++{ ++ isns_attr_list_t query_key = ISNS_ATTR_LIST_INIT; ++ isns_attr_list_t oper_attrs = ISNS_ATTR_LIST_INIT; ++ isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; ++ uint32_t status; ++ isns_simple_t *qry; ++ unsigned int i; ++ ++ if (!parse_query(argv, argc, &query_key, &oper_attrs)) ++ isns_fatal("Unable to parse query\n"); ++ ++ qry = isns_create_query(clnt, &query_key); ++ isns_attr_list_destroy(&query_key); ++ ++ /* Add the list of attributes we request */ ++ for (i = 0; i < oper_attrs.ial_count; ++i) ++ isns_query_request_attr(qry, oper_attrs.ial_data[i]); ++ isns_attr_list_destroy(&oper_attrs); ++ ++ status = isns_client_call(clnt, &qry); ++ if (status != ISNS_SUCCESS) { ++ isns_error("Query failed: %s\n", isns_strerror(status)); ++ return status; ++ } ++ ++ status = isns_query_response_get_objects(qry, &objects); ++ if (status) { ++ isns_error("Unable to extract object list from query response: %s\n", ++ isns_strerror(status), status); ++ return status; ++ } ++ ++ isns_object_list_print(&objects, isns_print_stdout); ++ isns_object_list_destroy(&objects); ++ isns_simple_free(qry); ++ ++ return status; ++} ++ ++int ++query_entity_id(isns_client_t *clnt, int argc, char **argv) ++{ ++ isns_attr_list_t query_key = ISNS_ATTR_LIST_INIT; ++ isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; ++ uint32_t status; ++ isns_simple_t *qry; ++ const char *eid; ++ ++ if (argc == 1 && !strcmp(argv[0], "help")) { ++ printf("Query iSNS for own entity ID.\n" ++ "No arguments allowed\n"); ++ exit(0); ++ } ++ if (argc != 0) ++ isns_fatal("EID query - no arguments accepted\n"); ++ ++ isns_attr_list_append_string(&query_key, ++ ISNS_TAG_ISCSI_NAME, ++ isns_config.ic_source_name); ++ qry = isns_create_query(clnt, &query_key); ++ isns_attr_list_destroy(&query_key); ++ ++ isns_query_request_attr_tag(qry, ISNS_TAG_ENTITY_IDENTIFIER); ++ ++ status = isns_client_call(clnt, &qry); ++ if (status != ISNS_SUCCESS) { ++ isns_error("Query failed: %s\n", isns_strerror(status)); ++ return status; ++ } ++ ++ status = isns_query_response_get_objects(qry, &objects); ++ if (status) { ++ isns_error("Unable to extract object list from query response: %s\n", ++ isns_strerror(status), status); ++ return status; ++ } ++ ++ status = ISNS_NO_SUCH_ENTRY; ++ if (objects.iol_count == 0) { ++ isns_error("Node %s not registered with iSNS\n", ++ isns_config.ic_source_name); ++ } else ++ if (!isns_object_get_string(objects.iol_data[0], ++ ISNS_TAG_ENTITY_IDENTIFIER, &eid)) { ++ isns_error("Query for %s returned an object without EID\n", ++ isns_config.ic_source_name); ++ } else { ++ printf("%s\n", eid); ++ status = ISNS_SUCCESS; ++ } ++ ++ isns_object_list_destroy(&objects); ++ isns_simple_free(qry); ++ ++ return status; ++} ++ ++/* ++ * Parse the list query string given by the user ++ */ ++int ++parse_list(int argc, char **argv, isns_object_template_t **type_p, isns_attr_list_t *keys) ++{ ++ struct isns_attr_list_parser state; ++ isns_object_template_t *query_type = NULL; ++ char *type_name; ++ ++ if (argc == 0) ++ usage(1, "Missing object type"); ++ ++ if (argc == 1 && !strcmp(argv[0], "help")) { ++ printf("Object query:\n" ++ " isnsadm --list type attr=value attr=value ...\n" ++ "Possible value for :\n" ++ " entities - list all network entites\n" ++ " nodes - list all storage nodes\n" ++ " portals - list all portals\n" ++ " portal-groups - list all portal groups\n" ++ " dds - list all discovery domains\n" ++ " ddsets - list all discovery domains sets\n" ++ " policies - list all policies (privileged)\n" ++ "Additional attributes can be specified to scope the\n" ++ "search. They must match the specified object type.\n" ++ "\nThe following attributes are recognized:\n"); ++ isns_attr_list_parser_help(NULL); ++ exit(0); ++ } ++ ++ type_name = *argv++; --argc; ++ if (!strcasecmp(type_name, "entities")) ++ query_type = &isns_entity_template; ++ else ++ if (!strcasecmp(type_name, "nodes")) ++ query_type = &isns_iscsi_node_template; ++ else ++ if (!strcasecmp(type_name, "portals")) ++ query_type = &isns_portal_template; ++ else ++ if (!strcasecmp(type_name, "portal-groups")) ++ query_type = &isns_iscsi_pg_template; ++ else ++ if (!strcasecmp(type_name, "dds")) ++ query_type = &isns_dd_template; ++ else ++ if (!strcasecmp(type_name, "ddsets")) ++ query_type = &isns_ddset_template; ++ else ++ if (!strcasecmp(type_name, "policies")) ++ query_type = &isns_policy_template; ++ else { ++ isns_error("Unknown object type \"%s\"\n", ++ type_name); ++ return 0; ++ } ++ ++ *type_p = query_type; ++ ++ isns_attr_list_parser_init(&state, query_type); ++ state.nil_permitted = 1; ++ ++ return isns_parse_attrs(argc, argv, keys, &state); ++} ++ ++int ++list_objects(isns_client_t *clnt, int argc, char **argv) ++{ ++ isns_attr_list_t query_keys = ISNS_ATTR_LIST_INIT; ++ isns_object_template_t *query_type = NULL; ++ isns_simple_t *simp; ++ int status, count = 0; ++ ++ if (!parse_list(argc, argv, &query_type, &query_keys)) ++ isns_fatal("Unable to parse parameters\n"); ++ ++ simp = isns_create_getnext(clnt, query_type, &query_keys); ++ while (1) { ++ isns_object_t *obj = NULL; ++ isns_simple_t *followup; ++ ++ status = isns_client_call(clnt, &simp); ++ if (status) ++ break; ++ ++ status = isns_getnext_response_get_object(simp, &obj); ++ if (status) ++ break; ++ ++ printf("Object %u:\n", count++); ++ isns_object_print(obj, isns_print_stdout); ++ isns_object_release(obj); ++ ++ followup = isns_create_getnext_followup(clnt, ++ simp, &query_keys); ++ isns_simple_free(simp); ++ simp = followup; ++ } ++ ++ if (status == ISNS_SOURCE_UNAUTHORIZED ++ && query_type == &isns_policy_template ++ && !opt_local) ++ isns_warning("Please use --local trying to list policies\n"); ++ ++ if (status != ISNS_NO_SUCH_ENTRY) { ++ isns_error("GetNext call failed: %s\n", ++ isns_strerror(status)); ++ return status; ++ } ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * Parse the deregistration string given by the user ++ * ++ * 5.6.5.2 ++ * The Message Key may contain key or non-key attributes or no ++ * attributes at all. If multiple attributes are used as the ++ * Message Key, then they MUST all be from the same object type ++ * (e.g., IP address and TCP/UDP Port are attributes of the ++ * Portal object type). ++ */ ++int ++parse_deregistration(char **argv, int argc, isns_attr_list_t *keys) ++{ ++ struct isns_attr_list_parser state; ++ ++ isns_attr_list_parser_init(&state, NULL); ++ state.multi_type_permitted = 1; ++ state.nil_permitted = 1; ++ ++ if (argc == 1 && !strcmp(argv[0], "help")) { ++ printf("Object deregistration:\n" ++ " isnsadm --deregister attr=value attr=value ...\n" ++ "All attributes must refer to a common object type.\n" ++ "\nThe following attributes are recognized:\n"); ++ isns_attr_list_parser_help(&state); ++ exit(0); ++ } ++ ++ return isns_parse_attrs(argc, argv, keys, &state); ++} ++ ++int ++deregister_objects(isns_client_t *clnt, int argc, char **argv) ++{ ++ isns_attr_list_t query_key = ISNS_ATTR_LIST_INIT; ++ isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; ++ isns_simple_t *dereg; ++ uint32_t status; ++ ++ if (!parse_deregistration(argv, argc, &query_key)) ++ isns_fatal("Unable to parse unregistration\n"); ++ ++ dereg = isns_create_deregistration(clnt, &query_key); ++ isns_attr_list_destroy(&query_key); ++ ++ status = isns_client_call(clnt, &dereg); ++ if (status != ISNS_SUCCESS) { ++ isns_error("Deregistration failed: %s\n", ++ isns_strerror(status)); ++ return status; ++ } ++ ++#if 0 ++ status = isns_dereg_msg_response_get_objects(dereg, &objects); ++ if (status) { ++ isns_error("Unable to extract object list from deregistration response: %s\n", ++ isns_strerror(status), status); ++ goto done; ++ } ++ isns_object_list_print(&objects, isns_print_stdout); ++#endif ++ ++ isns_object_list_destroy(&objects); ++ isns_simple_free(dereg); ++ ++ return status; ++} ++ ++/* ++ * Handle discovery domain registration/deregistration ++ */ ++int ++parse_dd_registration(char **argv, int argc, isns_attr_list_t *keys) ++{ ++ struct isns_attr_list_parser state; ++ ++ isns_attr_list_parser_init(&state, &isns_dd_template); ++ if (argc == 1 && !strcmp(argv[0], "help")) { ++ printf("Object query:\n" ++ " isnsadm --dd-register attr=value attr=value ...\n" ++ "You cannot specify more than one domain.\n" ++ "If you want to modify an existing domain, you must specify its ID.\n" ++ "The following attributes are recognized:\n"); ++ isns_attr_list_parser_help(&state); ++ exit(0); ++ } ++ ++ return isns_parse_attrs(argc, argv, keys, &state); ++} ++ ++int ++register_domain(isns_client_t *clnt, int argc, char **argv) ++{ ++ isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; ++ isns_simple_t *msg; ++ uint32_t status; ++ ++ if (!parse_dd_registration(argv, argc, &attrs)) ++ isns_fatal("Unable to parse DD registration\n"); ++ ++ msg = isns_create_dd_registration(clnt, &attrs); ++ isns_attr_list_destroy(&attrs); ++ ++ if (msg == NULL) { ++ isns_error("Cannot create message\n"); ++ return ISNS_INTERNAL_ERROR; ++ } ++ ++ status = isns_client_call(clnt, &msg); ++ if (status != ISNS_SUCCESS) { ++ isns_error("Registration failed: %s\n", ++ isns_strerror(status)); ++ return status; ++ } ++ ++ if (status == ISNS_SUCCESS) { ++ printf("Registered DD:\n"); ++ isns_attr_list_print( ++ isns_simple_get_attrs(msg), ++ isns_print_stdout); ++ } ++ isns_simple_free(msg); ++ ++ return status; ++} ++ ++int ++parse_dd_deregistration(char **argv, int argc, ++ uint32_t *dd_id, isns_attr_list_t *keys) ++{ ++ struct isns_attr_list_parser state; ++ ++ isns_attr_list_parser_init(&state, &isns_dd_template); ++ if (argc == 0 || (argc == 1 && !strcmp(argv[0], "help"))) { ++ printf("DD deregistration:\n" ++ " isnsadm --dd-deregister dd-id attr=value attr=value ...\n" ++ "You cannot specify more than one domain.\n" ++ "The following attributes are recognized:\n"); ++ isns_attr_list_parser_help(&state); ++ exit(0); ++ } ++ ++ *dd_id = parse_count(argv[0]); ++ ++ return isns_parse_attrs(argc - 1, argv + 1, keys, &state); ++} ++ ++int ++deregister_domain(isns_client_t *clnt, int argc, char **argv) ++{ ++ isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; ++ isns_simple_t *msg; ++ uint32_t dd_id, status; ++ ++ if (!parse_dd_deregistration(argv, argc, &dd_id, &attrs)) ++ isns_fatal("Unable to parse DD registration\n"); ++ ++ msg = isns_create_dd_deregistration(clnt, dd_id, &attrs); ++ isns_attr_list_destroy(&attrs); ++ ++ if (msg == NULL) { ++ isns_error("Cannot create message\n"); ++ return ISNS_INTERNAL_ERROR; ++ } ++ ++ status = isns_client_call(clnt, &msg); ++ if (status != ISNS_SUCCESS) { ++ isns_error("Deregistration failed: %s\n", ++ isns_strerror(status)); ++ return status; ++ } ++ ++ isns_simple_free(msg); ++ return status; ++} ++ ++/* ++ * Parse a policy ++ */ ++int ++parse_policy(int argc, char **argv, isns_attr_list_t *attrs, ++ const char *help_title, const char *help_action) ++{ ++ struct isns_attr_list_parser state; ++ ++ isns_attr_list_parser_init(&state, &isns_policy_template); ++ state.nil_permitted = 0; ++ state.load_key = load_key_callback; ++ state.generate_key = generate_key_callback; ++ ++ if (argc == 1 && !strcmp(argv[0], "help")) { ++ printf("%s:\n" ++ " isnsadm %s attr=value attr=value ...\n" ++ "Specifying a Security Policy Index is mandatory.\n" ++ "\nThe following attributes are recognized:\n", ++ help_title, help_action); ++ isns_attr_list_parser_help(&state); ++ exit(0); ++ } ++ ++ return isns_parse_attrs(argc, argv, attrs, &state); ++} ++ ++static int ++__create_policy(isns_client_t *clnt, const isns_attr_list_t *attrs) ++{ ++ isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; ++ isns_object_t *obj; ++ int status; ++ ++ obj = isns_create_object(&isns_policy_template, attrs, NULL); ++ if (!obj) ++ isns_fatal("Cannot create policy object\n"); ++ isns_object_list_append(&objects, obj); ++ ++ status = __register_objects(clnt, NULL, &objects); ++ isns_object_list_destroy(&objects); ++ return status; ++} ++ ++/* ++ * Enroll a new client ++ */ ++int ++enroll_client(isns_client_t *clnt, int argc, char **argv) ++{ ++ isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; ++ const char *client_name; ++ int status; ++ ++ if (argc == 0) ++ usage(1, "Missing client name"); ++ ++ client_name = *argv++; --argc; ++ ++ isns_attr_list_append_string(&attrs, ++ OPENISNS_TAG_POLICY_SPI, ++ client_name); ++#if 0 ++ isns_attr_list_append_string(&attrs, ++ OPENISNS_TAG_POLICY_SOURCE_NAME, ++ client_name); ++#endif ++ ++ if (!opt_keyfile) { ++ static char namebuf[PATH_MAX]; ++ ++ snprintf(namebuf, sizeof(namebuf), "%s.key", client_name); ++ opt_keyfile = namebuf; ++ } ++ ++ if (argc && !parse_policy(argc, argv, &attrs, ++ "Enroll an iSNS client", ++ "--enroll hostname")) ++ isns_fatal("Cannot parse policy\n"); ++ ++ /* If no key is given, generate one */ ++ if (!isns_attr_list_contains(&attrs, OPENISNS_TAG_POLICY_KEY)) { ++ printf("No key given, generating one\n"); ++ isns_attr_list_append_attr(&attrs, ++ generate_key_callback()); ++ } ++ ++ status = __create_policy(clnt, &attrs); ++ isns_attr_list_destroy(&attrs); ++ return status; ++} ++ ++ ++/* ++ * Create a new policy ++ */ ++int ++edit_policy(isns_client_t *clnt, int argc, char **argv) ++{ ++ isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; ++ int status; ++ ++ if (!parse_policy(argc, argv, &attrs, ++ "Edit an existing policy", ++ "--edit-policy")) ++ isns_fatal("Cannot parse policy\n"); ++ ++ status = __create_policy(clnt, &attrs); ++ isns_attr_list_destroy(&attrs); ++ ++ return status; ++} ++ ++#ifdef WITH_SECURITY ++static isns_attr_t * ++__key_to_attr(EVP_PKEY *pkey) ++{ ++ struct __isns_opaque key; ++ isns_value_t value; ++ isns_attr_t *attr = NULL; ++ ++ if (!isns_dsa_encode_public(pkey, &key.ptr, &key.len)) ++ goto out; ++ ++ /* Must pad key. This means we may end up encoding a few ++ * bytes of trash. Oh well. */ ++ key.len = ISNS_PAD(key.len); ++ ++ value = ISNS_VALUE_INIT(opaque, key); ++ attr = isns_attr_alloc(OPENISNS_TAG_POLICY_KEY, NULL, &value); ++ ++ isns_free(key.ptr); ++ ++out: ++ EVP_PKEY_free(pkey); ++ return attr; ++} ++ ++isns_attr_t * ++generate_key_callback(void) ++{ ++ EVP_PKEY *pkey; ++ ++ if (opt_keyfile == NULL) ++ isns_fatal("Key generation requires --keyfile option\n"); ++ ++ if (!(pkey = isns_dsa_generate_key())) ++ isns_fatal("Key generation failed\n"); ++ ++ if (!isns_dsa_store_private(opt_keyfile, pkey)) ++ isns_fatal("Unable to write private key to %s\n", ++ opt_keyfile); ++ ++ printf("Stored DSA private key in %s\n", opt_keyfile); ++ return __key_to_attr(pkey); ++} ++ ++isns_attr_t * ++load_key_callback(const char *pathname) ++{ ++ EVP_PKEY *pkey; ++ ++ if (!(pkey = isns_dsa_load_public(pathname))) ++ isns_fatal("Unable to load public key from file %s\n", pathname); ++ ++ return __key_to_attr(pkey); ++} ++ ++#else /* WITH_SECURITY */ ++isns_attr_t * ++generate_key_callback(void) ++{ ++ isns_fatal("Authentication disabled in this build\n"); ++ return NULL; ++} ++ ++isns_attr_t * ++load_key_callback(const char *pathname) ++{ ++ isns_fatal("Authentication disabled in this build\n"); ++ return NULL; ++} ++ ++#endif +diff --git a/utils/open-isns/isnsd.c b/utils/open-isns/isnsd.c +new file mode 100644 +index 0000000..3f983d6 +--- /dev/null ++++ b/utils/open-isns/isnsd.c +@@ -0,0 +1,299 @@ ++/* ++ * isnsd - the iSNS Daemon ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef MTRACE ++# include ++#endif ++ ++#include ++#include "security.h" ++#include "util.h" ++#include "paths.h" ++#include "internal.h" ++ ++enum { ++ MODE_NORMAL, ++ MODE_DUMP_DB, ++ MODE_INIT, ++}; ++ ++static const char * opt_configfile = ISNS_DEFAULT_ISNSD_CONFIG; ++static int opt_af = AF_UNSPEC; ++static int opt_mode = MODE_NORMAL; ++static int opt_foreground = 0; ++ ++static char * slp_url; ++ ++static int init_server(void); ++static void run_server(isns_server_t *, isns_db_t *); ++static void usage(int, const char *); ++static void cleanup(int); ++ ++static struct option options[] = { ++ { "config", required_argument, NULL, 'c' }, ++ { "debug", required_argument, NULL, 'd' }, ++ { "foreground", no_argument, NULL, 'f' }, ++ { "init", no_argument, NULL, MODE_INIT }, ++ { "dump-db", no_argument, NULL, MODE_DUMP_DB }, ++ { "help", no_argument, NULL, 'h' }, ++ { "version", no_argument, NULL, 'V' }, ++ { NULL } ++}; ++ ++int ++main(int argc, char **argv) ++{ ++ isns_server_t *server; ++ isns_source_t *source; ++ isns_db_t *db; ++ int c; ++ ++#ifdef MTRACE ++ mtrace(); ++#endif ++ ++ while ((c = getopt_long(argc, argv, "46c:d:fh", options, NULL)) != -1) { ++ switch (c) { ++ case '4': ++ opt_af = AF_INET; ++ break; ++ ++ case '6': ++ opt_af = AF_INET6; ++ break; ++ ++ case 'c': ++ opt_configfile = optarg; ++ break; ++ ++ case 'd': ++ isns_enable_debugging(optarg); ++ break; ++ ++ case 'f': ++ opt_foreground = 1; ++ break; ++ ++ case MODE_DUMP_DB: ++ case MODE_INIT: ++ opt_mode = c; ++ break; ++ ++ case 'h': ++ usage(0, NULL); ++ ++ case 'V': ++ printf("Open-iSNS version %s\n" ++ "Copyright (C) 2007, Olaf Kirch \n", ++ OPENISNS_VERSION_STRING); ++ return 0; ++ ++ default: ++ usage(1, "Unknown option"); ++ } ++ } ++ ++ if (optind != argc) ++ usage(1, NULL); ++ ++ isns_read_config(opt_configfile); ++ ++ if (!isns_config.ic_source_name) ++ usage(1, "Please specify an iSNS source name"); ++ source = isns_source_create_iscsi(isns_config.ic_source_name); ++ ++ if (opt_mode == MODE_INIT) ++ return !init_server(); ++ ++ if (opt_mode == MODE_NORMAL) ++ isns_write_pidfile(isns_config.ic_pidfile); ++ ++ db = isns_db_open(isns_config.ic_database); ++ if (db == NULL) ++ isns_fatal("Unable to open database\n"); ++ ++ if (opt_mode == MODE_DUMP_DB) { ++ isns_db_print(db, isns_print_stdout); ++ exit(0); ++ } ++ ++ if (!opt_foreground) { ++ if (daemon(0, 0) < 0) ++ isns_fatal("Unable to background server process\n"); ++ isns_log_background(); ++ isns_update_pidfile(isns_config.ic_pidfile); ++ } ++ ++ signal(SIGTERM, cleanup); ++ signal(SIGINT, cleanup); ++ ++ server = isns_create_server(source, db, &isns_default_service_ops); ++ ++ run_server(server, db); ++ return 0; ++} ++ ++void ++usage(int exval, const char *msg) ++{ ++ if (msg) ++ fprintf(stderr, "Error: %s\n", msg); ++ fprintf(stderr, ++ "Usage: isnsd [options]\n\n" ++ " --config Specify alternative config fille\n" ++ " --foreground Do not put daemon in the background\n" ++ " --debug Enable debugging (list of debug flags)\n" ++ " --init Initialize the server (key generation etc)\n" ++ " --dump-db Display the database contents and exit\n" ++ " --help Print this message\n" ++ ); ++ exit(exval); ++} ++ ++void ++cleanup(int sig) ++{ ++ isns_remove_pidfile(isns_config.ic_pidfile); ++ exit(1); ++} ++ ++static void ++slp_cleanup(void) ++{ ++ char *url = slp_url; ++ ++ slp_url = NULL; ++ if (url) { ++ isns_slp_unregister(url); ++ isns_free(url); ++ } ++} ++ ++/* ++ * Initialize server ++ */ ++int ++init_server(void) ++{ ++ if (!isns_security_init()) ++ return 0; ++ ++ /* Anything else? */ ++ ++ return 1; ++} ++ ++/* ++ * Server main loop ++ */ ++void ++run_server(isns_server_t *server, isns_db_t *db) ++{ ++ isns_socket_t *sock; ++ isns_security_t *ctx = NULL; ++ isns_message_t *msg, *resp; ++ int status; ++ ++ if (isns_config.ic_security) { ++ const char *ksname; ++ isns_keystore_t *ks; ++ ++ ctx = isns_default_security_context(1); ++ if (!(ksname = isns_config.ic_client_keystore)) ++ isns_fatal("config problem: no key store specified\n"); ++ if (!strcasecmp(ksname, "db:")) ++ ks = isns_create_db_keystore(db); ++ else ++ ks = isns_create_keystore(ksname); ++ if (ks == NULL) ++ isns_fatal("Unable to create keystore %s\n", ksname); ++ isns_security_set_keystore(ctx, ks); ++ } ++ ++ status = isns_dd_load_all(db); ++ if (status != ISNS_SUCCESS) ++ isns_fatal("Problem loading Discovery Domains from database\n"); ++ ++ if (isns_config.ic_control_socket) { ++ sock = isns_create_server_socket(isns_config.ic_control_socket, ++ NULL, AF_UNSPEC, SOCK_STREAM); ++ if (sock == NULL) ++ isns_fatal("Unable to create control socket\n"); ++ /* ++ isns_socket_set_security_ctx(sock, ctx); ++ */ ++ } ++ ++ sock = isns_create_server_socket(isns_config.ic_bind_address, ++ "isns", opt_af, SOCK_STREAM); ++ if (sock == NULL) ++ isns_fatal("Unable to create server socket\n"); ++ isns_socket_set_security_ctx(sock, ctx); ++ ++ if (isns_config.ic_slp_register) { ++ slp_url = isns_slp_build_url(0); ++ isns_slp_register(slp_url); ++ ++ atexit(slp_cleanup); ++ } ++ ++ isns_esi_init(server); ++ isns_scn_init(server); ++ ++ while (1) { ++ struct timeval timeout = { 0, 0 }; ++ time_t now, then, next_timeout = time(NULL) + 3600; ++ ++ /* Expire entities that haven't seen any activity ++ * for a while. */ ++ if (isns_config.ic_registration_period) { ++ then = isns_db_expire(db); ++ if (then && then < next_timeout) ++ next_timeout = then; ++ } ++ ++ /* Run any timers (eg for ESI) */ ++ then = isns_run_timers(); ++ if (then && then < next_timeout) ++ next_timeout = then; ++ ++ /* There may be pending SCNs, push them out now */ ++ then = isns_scn_transmit_all(); ++ if (then && then < next_timeout) ++ next_timeout = then; ++ ++ /* Purge any objects that have been marked for removal ++ * from the DB (deleting them, or moving them to limbo ++ * state). */ ++ isns_db_purge(db); ++ ++ /* Determine how long we can sleep before working ++ * the ESI queues and DB expiry again. */ ++ now = time(NULL); ++ if (next_timeout <= now) ++ continue; ++ timeout.tv_sec = next_timeout - now; ++ ++ if ((msg = isns_recv_message(&timeout)) == NULL) ++ continue; ++ ++ if ((resp = isns_process_message(server, msg)) != NULL) { ++ isns_socket_t *sock = isns_message_socket(msg); ++ ++ isns_socket_send(sock, resp); ++ isns_message_release(resp); ++ } ++ ++ isns_message_release(msg); ++ } ++} +diff --git a/utils/open-isns/isnsdd.c b/utils/open-isns/isnsdd.c +new file mode 100644 +index 0000000..e4e212d +--- /dev/null ++++ b/utils/open-isns/isnsdd.c +@@ -0,0 +1,1153 @@ ++/* ++ * isnsdd - the iSNS Discovery Daemon ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ * ++ * The way isnsdd communicates with local services (initiator, ++ * target) is via a set of files and signals. That sounds rather ++ * awkward, but it's a lot simpler to add to these services ++ * than another socket based communication mechanism I guess. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef MTRACE ++# include ++#endif ++ ++#include ++#include "security.h" ++#include "util.h" ++#include "isns-proto.h" ++#include "paths.h" ++#include "attrs.h" ++ ++enum { ++ ROLE_INITIATOR = 1, ++ ROLE_MONITOR = 2, ++}; ++ ++#define ISNSDD_REG_NAME "isns" ++#define ISNSDD_PGT_OFFSET 10000 ++#define MAX_RETRY_TIMEOUT 300 ++ ++typedef struct isns_proxy isns_proxy_t; ++struct isns_proxy { ++ isns_list_t ip_list; ++ char * ip_eid; ++ isns_object_t * ip_entity; ++ isns_client_t * ip_client; ++ isns_object_list_t ip_objects; ++ time_t ip_last_registration; ++}; ++ ++static const char * opt_configfile = ISNS_DEFAULT_ISNSDD_CONFIG; ++static int opt_af = AF_INET6; ++static int opt_foreground = 0; ++static int opt_role = ROLE_INITIATOR; ++static int opt_scn_bits = ISNS_SCN_OBJECT_UPDATED_MASK | ++ ISNS_SCN_OBJECT_ADDED_MASK | ++ ISNS_SCN_OBJECT_REMOVED_MASK | ++ ISNS_SCN_TARGET_AND_SELF_ONLY_MASK; ++static unsigned int opt_retry_timeout = 10; ++static int opt_esi = 1; ++ ++static isns_socket_t * server_socket; ++static ISNS_LIST_DECLARE(proxies); ++static isns_object_list_t local_registry = ISNS_OBJECT_LIST_INIT; ++static isns_object_list_t local_portals = ISNS_OBJECT_LIST_INIT; ++static isns_object_list_t visible_nodes = ISNS_OBJECT_LIST_INIT; ++static unsigned int esi_interval; ++static int should_reexport; ++ ++static void run_discovery(isns_server_t *srv); ++static void scn_callback(isns_db_t *, uint32_t, ++ isns_object_template_t *, ++ const char *, const char *); ++static void refresh_registration(void *); ++static void retry_registration(void *); ++static void load_exported_objects(void); ++static void store_imported_objects(void); ++static void usage(int, const char *); ++ ++static void install_sighandler(int, void (*func)(int)); ++static void sig_cleanup(int); ++static void sig_reread(int); ++ ++static struct option options[] = { ++ { "config", required_argument, NULL, 'c' }, ++ { "debug", required_argument, NULL, 'd' }, ++ { "foreground", no_argument, NULL, 'f' }, ++ { "role", required_argument, NULL, 'r' }, ++ { "no-esi", no_argument, NULL, 'E' }, ++ { "help", no_argument, NULL, 'h' }, ++ { "version", no_argument, NULL, 'V' }, ++ { NULL } ++}; ++ ++int ++main(int argc, char **argv) ++{ ++ isns_server_t *server; ++ isns_source_t *source; ++ isns_db_t *db; ++ int c; ++ ++#ifdef MTRACE ++ mtrace(); ++#endif ++ ++ while ((c = getopt_long(argc, argv, "46c:d:Efhr:", options, NULL)) != -1) { ++ switch (c) { ++ case '4': ++ opt_af = AF_INET; ++ break; ++ ++ case '6': ++ opt_af = AF_INET6; ++ break; ++ ++ case 'c': ++ opt_configfile = optarg; ++ break; ++ ++ case 'd': ++ isns_enable_debugging(optarg); ++ break; ++ ++ case 'E': ++ opt_esi = 0; ++ break; ++ ++ case 'f': ++ opt_foreground = 1; ++ break; ++ ++ case 'h': ++ usage(0, NULL); ++ ++ case 'r': ++ if (!strcasecmp(optarg, "initiator")) ++ opt_role = ROLE_INITIATOR; ++ else ++ if (!strcasecmp(optarg, "control") ++ || !strcasecmp(optarg, "monitor")) ++ opt_role = ROLE_MONITOR; ++ else { ++ isns_error("Unknown role \"%s\"\n", optarg); ++ usage(1, NULL); ++ } ++ break; ++ ++ case 'V': ++ printf("Open-iSNS version %s\n" ++ "Copyright (C) 2007, Olaf Kirch \n", ++ OPENISNS_VERSION_STRING); ++ return 0; ++ ++ default: ++ usage(1, "Unknown option"); ++ } ++ } ++ ++ if (optind != argc) ++ usage(1, NULL); ++ ++ /* If the config code derives the source name ++ * automatically, we want it to be distinct from ++ * any other source name (chosen by eg the iSCSI ++ * initiator). Adding a suffix of ":isns" is a ++ * somewhat lame attempt. ++ */ ++ isns_config.ic_source_suffix = "isns"; ++ ++ isns_read_config(opt_configfile); ++ ++ if (!isns_config.ic_source_name) ++ usage(1, "Please specify an iSNS source name"); ++ source = isns_source_create_iscsi(isns_config.ic_source_name); ++ ++ isns_write_pidfile(isns_config.ic_pidfile); ++ ++ if (!opt_foreground) { ++ if (daemon(0, 0) < 0) ++ isns_fatal("Unable to background server process\n"); ++ isns_log_background(); ++ isns_update_pidfile(isns_config.ic_pidfile); ++ } ++ ++ install_sighandler(SIGTERM, sig_cleanup); ++ install_sighandler(SIGINT, sig_cleanup); ++ install_sighandler(SIGUSR2, sig_reread); ++ ++ /* Create a DB object that shadows our portal list. This is for ESI - ++ * when an ESI comes in, the library will look up the portal in this ++ * database, and update its mtime. By checking the mtime at regular ++ * intervals, we can verify whether the server's ESIs actually ++ * reach us. ++ */ ++ db = isns_db_open_shadow(&local_portals); ++ ++ server = isns_create_server(source, db, &isns_callback_service_ops); ++ isns_server_set_scn_callback(server, scn_callback); ++ ++ run_discovery(server); ++ return 0; ++} ++ ++void ++usage(int exval, const char *msg) ++{ ++ if (msg) ++ fprintf(stderr, "Error: %s\n", msg); ++ fprintf(stderr, ++ "Usage: isnsdd [options]\n\n" ++ " --role Specify role (one of initiator, control)\n" ++ " --config Specify alternative config fille\n" ++ " --foreground Do not put daemon in the background\n" ++ " --no-esi Do not try to register an portals for ESI status inquiries\n" ++ " --debug Enable debugging (list of debug flags)\n" ++ " --help Print this message\n" ++ ); ++ exit(exval); ++} ++ ++void ++install_sighandler(int signo, void (*func)(int)) ++{ ++ struct sigaction act; ++ ++ memset(&act, 0, sizeof(act)); ++ act.sa_handler = func; ++ sigaction(signo, &act, NULL); ++} ++ ++void ++sig_reread(int sig) ++{ ++ should_reexport = 1; ++} ++ ++void ++sig_cleanup(int sig) ++{ ++ isns_remove_pidfile(isns_config.ic_pidfile); ++ exit(1); ++} ++ ++/* ++ * Proxy handling functions ++ */ ++static isns_proxy_t * ++isns_create_proxy(const char *eid) ++{ ++ isns_proxy_t *proxy; ++ ++ proxy = calloc(1, sizeof(*proxy)); ++ isns_list_init(&proxy->ip_list); ++ proxy->ip_eid = strdup(eid); ++ return proxy; ++} ++ ++static isns_proxy_t * ++__isns_proxy_find(isns_list_t *head, const char *eid) ++{ ++ isns_list_t *pos, *next; ++ ++ isns_list_foreach(head, pos, next) { ++ isns_proxy_t *proxy = isns_list_item(isns_proxy_t, ip_list, pos); ++ ++ if (!strcmp(proxy->ip_eid, eid)) ++ return proxy; ++ } ++ return NULL; ++} ++ ++static isns_proxy_t * ++isns_proxy_by_entity(const isns_object_t *entity) ++{ ++ isns_list_t *pos, *next; ++ ++ isns_list_foreach(&proxies, pos, next) { ++ isns_proxy_t *proxy = isns_list_item(isns_proxy_t, ip_list, pos); ++ ++ if (proxy->ip_entity == entity) ++ return proxy; ++ } ++ return NULL; ++} ++ ++static void ++isns_proxy_erase(isns_proxy_t *proxy) ++{ ++ isns_object_list_destroy(&proxy->ip_objects); ++ if (proxy->ip_client) { ++ isns_client_destroy(proxy->ip_client); ++ proxy->ip_client = NULL; ++ } ++ if (proxy->ip_entity) { ++ isns_object_release(proxy->ip_entity); ++ proxy->ip_entity = NULL; ++ } ++ isns_cancel_timer(refresh_registration, proxy); ++} ++ ++static void ++isns_proxy_free(isns_proxy_t *proxy) ++{ ++ isns_proxy_erase(proxy); ++ isns_list_del(&proxy->ip_list); ++ free(&proxy->ip_eid); ++ free(proxy); ++} ++ ++/* ++ * Force a re-registration of the whole object set. ++ */ ++static void ++force_reregistration(isns_proxy_t *proxy) ++{ ++ isns_cancel_timer(refresh_registration, proxy); ++ isns_add_oneshot_timer(0, retry_registration, proxy); ++} ++ ++/* ++ * Refresh the registration by calling DevAttrQry ++ */ ++static void ++refresh_registration(void *ptr) ++{ ++ isns_proxy_t *proxy = ptr; ++ isns_client_t *clnt = proxy->ip_client; ++ isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; ++ isns_attr_list_t query_key = ISNS_ATTR_LIST_INIT; ++ isns_simple_t *qry = NULL; ++ uint32_t status; ++ ++ isns_debug_state("Refreshing registration for %s\n", proxy->ip_eid); ++ isns_attr_list_append_string(&query_key, ++ ISNS_TAG_ENTITY_IDENTIFIER, ++ proxy->ip_eid); ++ ++ qry = isns_create_query(clnt, &query_key); ++ isns_attr_list_destroy(&query_key); ++ ++ /* We should have an async call mechanism. If the server ++ * is wedged, we'll block here, unable to service any other ++ * functions. ++ */ ++ status = isns_simple_call(clnt->ic_socket, &qry); ++ if (status != ISNS_SUCCESS) { ++ isns_error("Query failed: %s\n", isns_strerror(status)); ++ goto re_register; ++ } ++ ++ status = isns_query_response_get_objects(qry, &objects); ++ isns_simple_free(qry); ++ ++ if (status == ISNS_SUCCESS) { ++ if (objects.iol_count != 0) ++ return; ++ } else { ++ isns_error("Unable to parse query response\n"); ++ } ++ ++re_register: ++ isns_warning("Lost registration, trying to re-register\n"); ++ force_reregistration(proxy); ++} ++ ++/* ++ * Check if all portals have seen ESI messages from the server ++ */ ++static void ++check_portal_registration(void *ptr) ++{ ++ isns_object_list_t bad_portals = ISNS_OBJECT_LIST_INIT; ++ unsigned int i, need_reregister = 0, good_portals = 0; ++ time_t now; ++ ++ isns_debug_state("%s()\n", __FUNCTION__); ++ now = time(NULL); ++ for (i = 0; i < local_portals.iol_count; ++i) { ++ isns_object_t *obj = local_portals.iol_data[i]; ++ isns_portal_info_t portal_info; ++ isns_proxy_t *proxy; ++ time_t last_modified; ++ uint32_t interval; ++ ++ if (!isns_object_get_uint32(obj, ISNS_TAG_ESI_INTERVAL, &interval)) ++ continue; ++ ++ last_modified = isns_object_last_modified(obj); ++ if (last_modified + 2 * interval > now) { ++ good_portals++; ++ continue; ++ } ++ ++ isns_portal_from_object(&portal_info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ obj); ++ ++ isns_notice("Portal %s did not receive ESIs within %u seconds - " ++ "server may have lost us.\n", ++ isns_portal_string(&portal_info), ++ now - last_modified); ++ ++ proxy = isns_proxy_by_entity(isns_object_get_entity(obj)); ++ if (!proxy) ++ continue; ++ ++ /* If we haven't received ANY ESIs, ever, the portal ++ * may be using a non-routable IP */ ++ if (last_modified <= proxy->ip_last_registration) ++ isns_object_list_append(&bad_portals, obj); ++ ++ force_reregistration(proxy); ++ need_reregister++; ++ } ++ ++ for (i = 0; i < bad_portals.iol_count; ++i) ++ isns_object_list_remove(&local_portals, bad_portals.iol_data[i]); ++ isns_object_list_destroy(&bad_portals); ++ ++ if (need_reregister && local_portals.iol_count == 0) { ++ /* Force a re-registration from scratch. ++ * This time without ESI. ++ */ ++ isns_notice("Suspiciously little ESI traffic - server may be broken\n"); ++ isns_notice("Disabling ESI\n"); ++ opt_esi = 0; ++ } ++} ++ ++static void ++setup_esi_watchdog(void) ++{ ++ unsigned int i; ++ ++ isns_cancel_timer(check_portal_registration, NULL); ++ esi_interval = 0; ++ ++ for (i = 0; i < local_portals.iol_count; ++i) { ++ isns_object_t *obj = local_portals.iol_data[i]; ++ uint32_t interval; ++ ++ /* should always succeed */ ++ if (isns_object_get_uint32(obj, ISNS_TAG_ESI_INTERVAL, &interval)) ++ continue; ++ ++ if (!esi_interval || interval < esi_interval) ++ esi_interval = interval; ++ } ++ ++ if (esi_interval) { ++ isns_debug_state("Setting up timer to check for ESI reachability\n"); ++ isns_add_timer(esi_interval * 4 / 5, ++ check_portal_registration, ++ NULL); ++ } ++} ++ ++static void ++load_exported_objects(void) ++{ ++ isns_debug_state("Reading list of exported objects\n"); ++ isns_object_list_destroy(&local_registry); ++ if (!isns_local_registry_load("!" ISNSDD_REG_NAME, 0, &local_registry)) { ++ isns_warning("Unable to obtain locally registered objects\n"); ++ return; ++ } ++} ++ ++static void ++store_imported_objects(void) ++{ ++ if (!isns_local_registry_store(ISNSDD_REG_NAME, 0, &visible_nodes)) ++ isns_warning("Unable to store discovered objects\n"); ++} ++ ++/* ++ * Given the DevAttrReg response, extract the entity ID we ++ * have been assigned. ++ */ ++static int ++extract_entity_id(isns_proxy_t *proxy, isns_simple_t *resp) ++{ ++ isns_object_list_t resp_objects = ISNS_OBJECT_LIST_INIT; ++ isns_object_t *entity = NULL; ++ int status; ++ unsigned int i; ++ ++ status = isns_query_response_get_objects(resp, &resp_objects); ++ if (status) { ++ isns_error("Unable to extract object list from " ++ "registration response: %s\n", ++ isns_strerror(status), status); ++ goto out; ++ } ++ ++ for (i = 0; i < resp_objects.iol_count; ++i) { ++ isns_object_t *obj = resp_objects.iol_data[i]; ++ uint32_t interval; ++ ++ if (!isns_object_is_entity(obj)) ++ continue; ++ ++ if (entity) { ++ isns_error("Server returns more than one entity " ++ "in registration response. What a weirdo.\n"); ++ continue; ++ } ++ entity = obj; ++ ++ if (!isns_object_get_uint32(obj, ++ ISNS_TAG_REGISTRATION_PERIOD, ++ &interval)) ++ continue; ++ ++ if (interval == 0) { ++ isns_error("Server returns a registration period of 0\n"); ++ continue; ++ } ++ ++ isns_debug_state("Setting up timer for registration refresh\n"); ++ isns_add_timer(interval / 2, ++ refresh_registration, ++ proxy); ++ } ++ ++ for (i = 0; i < resp_objects.iol_count; ++i) { ++ isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; ++ isns_object_t *obj = resp_objects.iol_data[i]; ++ uint32_t interval; ++ ++ if (!isns_object_is_portal(obj) ++ || !isns_object_get_uint32(obj, ISNS_TAG_ESI_INTERVAL, &interval)) ++ continue; ++ ++ if (interval == 0) { ++ isns_error("Server returns an ESI interval of 0\n"); ++ continue; ++ } ++ ++ isns_object_get_key_attrs(obj, &key_attrs); ++ if (!(obj = isns_object_list_lookup(&proxy->ip_objects, NULL, &key_attrs))) { ++ isns_error("Server response includes a portal we never registered\n"); ++ continue; ++ } ++ ++ isns_object_set_uint32(obj, ISNS_TAG_ESI_INTERVAL, interval); ++ ++ /* Server enabled ESI for this portal, so add it to ++ * the list of local portals we regularly check for ++ * incoming ESI messages. */ ++ isns_object_list_append(&local_portals, obj); ++ } ++ ++ proxy->ip_last_registration = time(NULL); ++out: ++ isns_object_list_destroy(&resp_objects); ++ return status; ++} ++ ++static inline void ++__add_release_object(isns_object_list_t *objects, isns_object_t *cur) ++{ ++ if (cur == NULL) ++ return; ++ isns_object_list_append(objects, cur); ++ isns_object_release(cur); ++} ++ ++/* ++ * Rebuild the list of proxies given the set of entities ++ */ ++void ++rebuild_proxy_list(isns_object_list_t *entities, isns_list_t *old_list) ++{ ++ isns_proxy_t *proxy; ++ unsigned int i; ++ ++ isns_list_move(old_list, &proxies); ++ ++ for (i = 0; i < entities->iol_count; ++i) { ++ isns_object_t *entity = entities->iol_data[i]; ++ isns_object_t *node; ++ const char *eid; ++ ++ eid = isns_entity_name(entity); ++ if (eid == NULL) { ++ isns_error("Whoopee, entity without name\n"); ++ continue; ++ } ++ ++ proxy = __isns_proxy_find(old_list, eid); ++ if (proxy == NULL) { ++ proxy = isns_create_proxy(eid); ++ } else { ++ isns_proxy_erase(proxy); ++ } ++ ++ isns_object_list_append(&proxy->ip_objects, entity); ++ isns_object_get_descendants(entity, NULL, &proxy->ip_objects); ++ ++ node = isns_object_list_lookup(&proxy->ip_objects, ++ &isns_iscsi_node_template, ++ NULL); ++ if (node == NULL) { ++ isns_warning("Service %s did not register any " ++ "storage nodes - skipped\n", eid); ++ continue; ++ } ++ ++ proxy->ip_client = isns_create_client(NULL, ++ isns_storage_node_name(node)); ++ proxy->ip_entity = isns_object_get(entity); ++ ++ isns_list_del(&proxy->ip_list); ++ isns_list_append(&proxies, &proxy->ip_list); ++ } ++} ++ ++/* ++ * Unregister old proxies ++ */ ++static void ++unregister_entities(isns_list_t *list) ++{ ++ while (!isns_list_empty(list)) { ++ isns_proxy_t *proxy = isns_list_item(isns_proxy_t, ip_list, list->next); ++ ++ /* XXX send a DevDereg */ ++ isns_proxy_free(proxy); ++ } ++} ++ ++/* ++ * The local registry creates fake entities to group objects ++ * registered by the same service. We use this to perform ++ * several registration calls, each with a different EID ++ */ ++static int ++register_entity(isns_proxy_t *proxy) ++{ ++ isns_client_t *clnt = proxy->ip_client; ++ isns_simple_t *call = NULL; ++ int status; ++ ++ call = isns_create_registration(clnt, proxy->ip_entity); ++ isns_registration_set_replace(call, 1); ++ isns_registration_add_object_list(call, &proxy->ip_objects); ++ ++ status = isns_simple_call(clnt->ic_socket, &call); ++ if (status == ISNS_SUCCESS) { ++ /* Extract the EID and registration period */ ++ extract_entity_id(proxy, call); ++ } ++ ++ isns_simple_free(call); ++ return status; ++} ++ ++static int ++register_exported_entities(void) ++{ ++ int status = ISNS_SUCCESS; ++ isns_list_t *pos, *next; ++ ++ isns_list_foreach(&proxies, pos, next) { ++ isns_proxy_t *proxy = isns_list_item(isns_proxy_t, ip_list, pos); ++ ++ status = register_entity(proxy); ++ if (status != ISNS_SUCCESS) ++ break; ++ } ++ ++ setup_esi_watchdog(); ++ return status; ++} ++ ++static void ++all_objects_set(isns_object_list_t *list, uint32_t tag, uint32_t value) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ ++ isns_object_set_uint32(obj, tag, value); ++ } ++} ++ ++static void ++all_objects_unset(isns_object_list_t *list, uint32_t tag) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ ++ isns_object_delete_attr(obj, tag); ++ } ++} ++ ++static int ++register_exported_objects(isns_client_t *clnt) ++{ ++ isns_portal_info_t portal_info; ++ isns_object_list_t entities = ISNS_OBJECT_LIST_INIT; ++ isns_object_list_t portals = ISNS_OBJECT_LIST_INIT; ++ isns_simple_t *call = NULL; ++ int status, with_esi; ++ unsigned int i, my_port; ++ isns_list_t old_proxies; ++ ++ if (!isns_socket_get_portal_info(server_socket, &portal_info)) ++ isns_fatal("Unable to get portal info\n"); ++ my_port = isns_portal_tcpudp_port(&portal_info); ++ ++ /* Look up all entites and portals */ ++ isns_object_list_gang_lookup(&local_registry, ++ &isns_entity_template, NULL, ++ &entities); ++ isns_object_list_gang_lookup(&local_registry, ++ &isns_portal_template, NULL, ++ &portals); ++ ++ isns_list_init(&old_proxies); ++ rebuild_proxy_list(&entities, &old_proxies); ++ unregister_entities(&old_proxies); ++ ++ /* Enable SCN on all portals we're about to register */ ++ all_objects_set(&portals, ISNS_TAG_SCN_PORT, my_port); ++ ++ /* Try ESI first. If the server doesn't support it, or doesn't ++ * have the resources to serve us, fall back to normal ++ * registration refresh. */ ++ if (opt_esi) { ++ all_objects_set(&portals, ++ ISNS_TAG_ESI_INTERVAL, ++ isns_config.ic_esi_min_interval); ++ all_objects_set(&portals, ++ ISNS_TAG_ESI_PORT, ++ my_port); ++ } ++ ++ for (with_esi = opt_esi; 1; with_esi--) { ++ status = register_exported_entities(); ++ ++ /* At some point, we need to add these portals ++ * to the local_portals list so that ESI works ++ * properly. ++ * Right now, we extract the portals from the response ++ * and add those. The down side of this is that we no ++ * longer use the same object (pointer) to refer to the ++ * same thing. The up side is that the information returned ++ * by the server reflects the correct ESI interval. ++ */ ++ if (status == ISNS_SUCCESS) ++ break; ++ ++ if (status != ISNS_ESI_NOT_AVAILABLE || with_esi == 0) { ++ isns_error("Failed to register object(s): %s\n", ++ isns_strerror(status)); ++ goto out; ++ } ++ ++ /* Continue and retry without ESI */ ++ all_objects_unset(&portals, ISNS_TAG_ESI_INTERVAL); ++ all_objects_unset(&portals, ISNS_TAG_ESI_PORT); ++ } ++ ++ for (i = 0; i < local_registry.iol_count; ++i) { ++ isns_object_t *obj = local_registry.iol_data[i]; ++ isns_source_t *source; ++ int status; ++ ++ if (!isns_object_is_iscsi_node(obj) ++ && !isns_object_is_fc_port(obj)) ++ continue; ++ ++ if (!(source = isns_source_from_object(obj))) ++ continue; ++ call = isns_create_scn_registration2(clnt, opt_scn_bits, source); ++ status = isns_simple_call(clnt->ic_socket, &call); ++ if (status != ISNS_SUCCESS) { ++ isns_error("SCN registration for %s failed: %s\n", ++ isns_storage_node_name(obj), ++ isns_strerror(status)); ++ } ++ isns_source_release(source); ++ } ++ ++out: ++ if (call) ++ isns_simple_free(call); ++ isns_object_list_destroy(&entities); ++ isns_object_list_destroy(&portals); ++ return status; ++} ++ ++static void ++retry_registration(void *ptr) ++{ ++ isns_proxy_t *proxy = ptr; ++ static unsigned int timeout = 0; ++ int status; ++ ++ status = register_exported_objects(proxy->ip_client); ++ if (status) { ++ if (timeout == 0) ++ timeout = opt_retry_timeout; ++ else if (timeout >= MAX_RETRY_TIMEOUT) ++ timeout = MAX_RETRY_TIMEOUT; ++ ++ isns_debug_state("Retrying to register in %u seconds\n", timeout); ++ isns_add_oneshot_timer(timeout, retry_registration, proxy); ++ ++ /* Exponential backoff */ ++ timeout <<= 1; ++ } ++} ++ ++/* ++ * Get a list of all visible storage nodes ++ */ ++static int ++get_objects_from_query(isns_simple_t *resp) ++{ ++ isns_object_list_t resp_objects = ISNS_OBJECT_LIST_INIT; ++ unsigned int i; ++ int status; ++ ++ status = isns_query_response_get_objects(resp, &resp_objects); ++ if (status) { ++ isns_error("Unable to extract object list from " ++ "query response: %s\n", ++ isns_strerror(status)); ++ return status; ++ } ++ ++ isns_debug_state("Initial query returned %u object(s)\n", resp_objects.iol_count); ++ for (i = 0; i < resp_objects.iol_count; ++i) { ++ isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; ++ isns_object_t *obj = resp_objects.iol_data[i]; ++ isns_object_t *found; ++ ++ if (!isns_object_extract_keys(obj, &key_attrs)) ++ continue; ++ ++ /* Don't add an object twice, and don't add objects ++ * that *we* registered. ++ * This still leaves any default PGs created by the server, ++ * but we cannot help that (for now). ++ */ ++ found = isns_object_list_lookup(&visible_nodes, NULL, &key_attrs); ++ if (!found) ++ found = isns_object_list_lookup(&local_registry, NULL, &key_attrs); ++ if (found) { ++ isns_object_release(found); ++ } else { ++ isns_object_list_append(&visible_nodes, obj); ++ } ++ isns_attr_list_destroy(&key_attrs); ++ } ++ ++ isns_object_list_destroy(&resp_objects); ++ return status; ++} ++ ++static int ++query_storage_node(isns_source_t *source, const char *name) ++{ ++ isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; ++ isns_simple_t *call; ++ uint32_t tag; ++ int status; ++ isns_client_t *clnt; ++ ++ if (isns_source_type(source) != ISNS_TAG_ISCSI_NAME) { ++ isns_error("FC source node - doesn't work yet\n"); ++ return ISNS_SUCCESS; ++ } ++ clnt = isns_create_client(NULL, isns_source_name(source)); ++ ++ tag = isns_source_type(source); ++ if (name) { ++ isns_attr_list_append_string(&key_attrs, tag, name); ++ } else { ++ /* Query for visible nodes */ ++ isns_attr_list_append_nil(&key_attrs, tag); ++ } ++ ++ call = isns_create_query2(clnt, &key_attrs, source); ++ isns_attr_list_destroy(&key_attrs); ++ ++ isns_query_request_attr_tag(call, tag); ++ switch (tag) { ++ case ISNS_TAG_ISCSI_NAME: ++ isns_query_request_attr_tag(call, ISNS_TAG_ISCSI_NODE_TYPE); ++ isns_query_request_attr_tag(call, ISNS_TAG_ISCSI_ALIAS); ++ isns_query_request_attr_tag(call, ISNS_TAG_ISCSI_NODE_INDEX); ++ ++ isns_query_request_attr_tag(call, ISNS_TAG_PORTAL_IP_ADDRESS); ++ isns_query_request_attr_tag(call, ISNS_TAG_PORTAL_TCP_UDP_PORT); ++ isns_query_request_attr_tag(call, ISNS_TAG_PORTAL_INDEX); ++ ++ isns_query_request_attr_tag(call, ISNS_TAG_PG_ISCSI_NAME); ++ isns_query_request_attr_tag(call, ISNS_TAG_PG_PORTAL_IP_ADDR); ++ isns_query_request_attr_tag(call, ISNS_TAG_PG_PORTAL_TCP_UDP_PORT); ++ isns_query_request_attr_tag(call, ISNS_TAG_PG_TAG); ++ isns_query_request_attr_tag(call, ISNS_TAG_PG_INDEX); ++ break; ++ ++ default: ; ++ } ++ ++ status = isns_simple_call(clnt->ic_socket, &call); ++ if (status == ISNS_SUCCESS) ++ status = get_objects_from_query(call); ++ ++ isns_simple_free(call); ++ isns_client_destroy(clnt); ++ return status; ++} ++ ++/* ++ * Query for visible iscsi nodes ++ */ ++static int ++query_visible(void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < local_registry.iol_count; ++i) { ++ isns_object_t *obj = local_registry.iol_data[i]; ++ isns_source_t *source; ++ int status; ++ ++ if (!isns_object_is_iscsi_node(obj) ++ && !isns_object_is_fc_port(obj)) ++ continue; ++ ++ if (isns_object_is_fc_port(obj)) { ++ isns_error("FC source node - sorry, won't work yet\n"); ++ continue; ++ } ++ ++ if (!(source = isns_source_from_object(obj))) ++ continue; ++ status = query_storage_node(source, NULL); ++ if (status != ISNS_SUCCESS) { ++ isns_warning("Unable to run query on behalf of %s: %s\n", ++ isns_storage_node_name(obj), ++ isns_strerror(status)); ++ } ++ isns_source_release(source); ++ } ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * Invoke the registered callout program ++ */ ++static void ++callout(const char *how, isns_object_t *obj, unsigned int bitmap) ++{ ++ char *argv[128]; ++ int fargc, argc = 0; ++ pid_t pid; ++ ++ if (!isns_config.ic_scn_callout) ++ return; ++ ++ argv[argc++] = isns_config.ic_scn_callout; ++ argv[argc++] = (char *) how; ++ fargc = argc; ++ ++ argc += isns_print_attrs(obj, argv + argc, 128 - argc); ++ ++ pid = fork(); ++ if (pid == 0) { ++ execv(argv[0], argv); ++ isns_fatal("Cannot execute %s: %m\n", argv[0]); ++ } ++ ++ while (fargc < argc) ++ isns_free(argv[fargc++]); ++ ++ if (pid < 0) { ++ isns_error("fork: %m\n"); ++ return; ++ } ++ ++ while (waitpid(pid, NULL, 0) < 0) ++ ; ++} ++ ++/* ++ * This is called when we receive a State Change Notification ++ */ ++static void ++scn_callback(isns_db_t *db, uint32_t bitmap, ++ isns_object_template_t *node_type, ++ const char *node_name, ++ const char *dst_name) ++{ ++ isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; ++ uint32_t key_tag; ++ isns_object_t *node = NULL, *recipient = NULL; ++ ++ isns_notice("%s \"%s\" %s\n", ++ isns_object_template_name(node_type), ++ node_name, isns_event_string(bitmap)); ++ ++ /* This is either an iSCSI node or a FC node - in ++ both cases the storage node name is the key attr */ ++ if (node_type == &isns_iscsi_node_template) { ++ key_tag = ISNS_TAG_ISCSI_NAME; ++ } else if (node_type == &isns_fc_node_template) { ++ key_tag = ISNS_TAG_FC_PORT_NAME_WWPN; ++ } else ++ return; ++ ++ isns_attr_list_append_string(&key_attrs, key_tag, dst_name); ++ recipient = isns_object_list_lookup(&local_registry, node_type, &key_attrs); ++ if (recipient == NULL) { ++ isns_error("Received SCN for unknown recipient \"%s\"\n", ++ dst_name); ++ goto out; ++ } ++ isns_attr_list_destroy(&key_attrs); ++ ++ isns_attr_list_append_string(&key_attrs, key_tag, node_name); ++ node = isns_object_list_lookup(&visible_nodes, node_type, &key_attrs); ++ ++ if (bitmap & (ISNS_SCN_OBJECT_REMOVED_MASK|ISNS_SCN_DD_MEMBER_REMOVED_MASK)) { ++ if (node) { ++ isns_object_list_remove(&visible_nodes, node); ++ /* FIXME: We also want to remove any PGs associated with ++ * this node. */ ++ } ++ store_imported_objects(); ++ callout("remove", node, bitmap); ++ } else ++ if (bitmap & (ISNS_SCN_OBJECT_ADDED_MASK|ISNS_SCN_OBJECT_UPDATED_MASK|ISNS_SCN_DD_MEMBER_ADDED_MASK)) { ++ const char *how = "add"; ++ isns_source_t *source; ++ ++ if (bitmap & ISNS_SCN_OBJECT_UPDATED_MASK) ++ how = "update"; ++ if (!node) { ++ node = isns_create_object(node_type, &key_attrs, NULL); ++ if (!node) ++ goto out; ++ isns_object_list_append(&visible_nodes, node); ++ } ++ ++ /* Query the server for information on this node */ ++ source = isns_source_from_object(recipient); ++ query_storage_node(source, node_name); ++ isns_source_release(source); ++ ++ store_imported_objects(); ++ callout(how, node, bitmap); ++ ++ } ++ ++out: ++ if (node) ++ isns_object_release(node); ++ if (recipient) ++ isns_object_release(recipient); ++ isns_attr_list_destroy(&key_attrs); ++} ++ ++/* ++ * Server main loop ++ */ ++void ++run_discovery(isns_server_t *server) ++{ ++ isns_client_t *clnt; ++ isns_security_t *ctx = NULL; ++ isns_message_t *msg, *resp; ++ ++ /* Create the server socket */ ++ ctx = isns_default_security_context(0); ++ server_socket = isns_create_server_socket(isns_config.ic_bind_address, ++ NULL, opt_af, SOCK_DGRAM); ++ if (server_socket == NULL) ++ isns_fatal("Unable to create server socket\n"); ++ isns_socket_set_security_ctx(server_socket, ctx); ++ ++ /* Create the client socket */ ++ clnt = isns_create_default_client(NULL); ++ if (clnt == NULL) ++ isns_fatal("Cannot connect to server\n"); ++ ++ /* Load all objects registered by local services */ ++ should_reexport = 1; ++ ++ while (1) { ++ struct timeval timeout = { 0, 0 }; ++ time_t now, then, next_timeout; ++ unsigned int function; ++ ++ next_timeout = time(NULL) + 3600; ++ ++ /* Run timers */ ++ then = isns_run_timers(); ++ if (then && then < next_timeout) ++ next_timeout = then; ++ ++ /* Determine how long we can sleep */ ++ now = time(NULL); ++ if (next_timeout <= now) ++ continue; ++ timeout.tv_sec = next_timeout - now; ++ ++ if (should_reexport) { ++ load_exported_objects(); ++ ++ if (register_exported_objects(clnt)) ++ isns_error("Failed to register exported objects.\n"); ++ ++ /* Prime the list of visible storage nodes */ ++ if (query_visible()) ++ isns_error("Unable to query list of visible nodes.\n"); ++ store_imported_objects(); ++ ++ should_reexport = 0; ++ } ++ ++ if ((msg = isns_recv_message(&timeout)) == NULL) ++ continue; ++ ++ function = isns_message_function(msg); ++ if (function != ISNS_STATE_CHANGE_NOTIFICATION ++ && function != ISNS_ENTITY_STATUS_INQUIRY) { ++ isns_warning("Discarding unexpected %s message\n", ++ isns_function_name(function)); ++ isns_message_release(msg); ++ continue; ++ } ++ ++ if ((resp = isns_process_message(server, msg)) != NULL) { ++ isns_socket_t *sock = isns_message_socket(msg); ++ ++ isns_socket_send(sock, resp); ++ isns_message_release(resp); ++ } ++ ++ isns_message_release(msg); ++ } ++} +diff --git a/utils/open-isns/isnssetup b/utils/open-isns/isnssetup +new file mode 100644 +index 0000000..df0bd00 +--- /dev/null ++++ b/utils/open-isns/isnssetup +@@ -0,0 +1,52 @@ ++#!/bin/sh ++# ++# isnssetup - bootstrap open-isns server ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This is a very simple script to bootstrap an iSNS server. ++# It creates the necessary keys, enrolls a control node, ++# and enrolls the local host as target and initiator. ++ ++hostname=`hostname -f` ++ ++if [ -f isnsd -a -d isnsadm ]; then ++ PATH=.:$PATH ++fi ++ ++# Massage the configuration file ++for f in isnsadm.conf isnsdd.conf; do ++ etcfile=/etc/isns/$f ++ sed -e 's/^#*\(ServerAddress[[:space:]]*=\).*/\1 localhost/' \ ++ -e 's/^#*\(Security[[:space:]]*=\).*/\1 1/' \ ++ $etcfile > $etcfile.tmp ++ mv $etcfile.tmp $etcfile ++done ++ ++echo "*** Initializing server security ***" ++isnsd --init ++cp /etc/isns/auth_key.pub /etc/isns/server_key.pub ++ ++if ps ax|grep isnsd | grep -qv grep; then ++ killall -TERM isnsd ++ sleep 1 ++fi ++isnsd ++sleep 1 ++ ++echo "*** Registering control node policy ***" ++rm -f /etc/isns/control.key ++isnsadm --local \ ++ --keyfile=/etc/isns/control.key \ ++ --enroll isns.control \ ++ node-type=ALL functions=ALL object-type=ALL ++ ++echo "*** Registering control node ***" ++isnsadm --local \ ++ --register control ++ ++echo "*** Registering policy for server ***" ++isnsadm --control \ ++ --enroll $hostname \ ++ key=/etc/isns/auth_key.pub \ ++ node-type=target+initiator +diff --git a/utils/open-isns/local.c b/utils/open-isns/local.c +new file mode 100644 +index 0000000..4bc1cb1 +--- /dev/null ++++ b/utils/open-isns/local.c +@@ -0,0 +1,353 @@ ++/* ++ * Local iSNS registration ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ * ++ * The way isnsdd communicates with local services (initiator, ++ * target) is via a file and signals. That sounds rather ++ * awkward, but it's a lot simpler to add to these services ++ * than another socket based communication mechanism I guess. ++ * ++ * The file format is simple: ++ * owner= ++ * owner= ++ * ... ++ * ++ * identifies the service owning these entries. ++ * This is a service name, such as iscsid, tgtd, isnsdd, ++ * optionally followed by a colon and a PID. This allows ++ * removal of all entries created by one service in one go. ++ * ++ * is the description of one iSNS object, using the ++ * syntax used by all other open-isns apps. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include "security.h" ++#include "util.h" ++#include "isns-proto.h" ++#include "paths.h" ++#include "attrs.h" ++#include "util.h" ++ ++typedef int __isns_local_registry_cb_fn_t(const char *line, ++ int argc, char **argv, ++ void *user_data); ++ ++/* ++ * Build the owner=: tag ++ */ ++static const char * ++__isns_local_registry_make_owner(const char *svcname, pid_t pid) ++{ ++ static char owner[128]; ++ ++ if (pid == 0) { ++ return svcname; ++ } ++ snprintf(owner, sizeof(owner), "%s:%u", svcname, pid); ++ return owner; ++} ++ ++/* ++ * Read the registry file, match each entry against the given owner= tag, ++ * and invoke the callback function. ++ * This is used for both reading the registry, and rewriting it. ++ */ ++static int ++__isns_local_registry_read(const char *match_owner, ++ __isns_local_registry_cb_fn_t handle_matching, ++ __isns_local_registry_cb_fn_t handle_nonmatching, ++ void *user_data) ++{ ++ const char *filename = isns_config.ic_local_registry_file; ++ char *line, *copy = NULL; ++ FILE *fp; ++ int rv = 0, owner_len; ++ ++ if (!(fp = fopen(filename, "r"))) { ++ if (errno == ENOENT) { ++ isns_debug_state("Unable to open %s: %m\n", filename); ++ return 1; ++ } ++ isns_error("Unable to open %s: %m\n", filename); ++ return 0; ++ } ++ ++ owner_len = match_owner? strlen(match_owner) : 0; ++ while ((line = parser_get_next_line(fp)) != NULL) { ++ __isns_local_registry_cb_fn_t *cb; ++ char *argv[256], *owner; ++ int argc = 0; ++ ++ isns_assign_string(©, line); ++ ++ argc = isns_attr_list_split(line, argv, 255); ++ if (argc <= 0) ++ continue; ++ ++ /* Last attr should be owner */ ++ if (strncasecmp(argv[argc-1], "owner=", 6)) { ++ isns_error("%s: syntax error (missing owner field)\n", ++ filename); ++ goto out; ++ } ++ owner = argv[argc-1] + 6; ++ ++ if (!strncasecmp(owner, match_owner, owner_len) ++ && (owner[owner_len] == '\0' || owner[owner_len] == ':')) ++ cb = handle_matching; ++ else ++ cb = handle_nonmatching; ++ ++ if (cb && !cb(copy, argc, argv, user_data)) ++ goto out; ++ ++ } ++ rv = 1; ++ ++out: ++ free(copy); ++ fclose(fp); ++ return rv; ++} ++ ++/* ++ * Open and lock the registry file for writing. Returns an ++ * open stream and the name of the lock file. ++ * Follow up with _finish_write when done. ++ */ ++static FILE * ++__isns_local_registry_open_write(char **lock_name) ++{ ++ char lock_path[PATH_MAX]; ++ FILE *fp; ++ int fd, retry; ++ ++ snprintf(lock_path, sizeof(lock_path), "%s.lock", ++ isns_config.ic_local_registry_file); ++ ++ for (retry = 0; retry < 5; ++retry) { ++ fd = open(lock_path, O_RDWR|O_CREAT|O_EXCL, 0644); ++ if (fd >= 0) ++ break; ++ if (errno != EEXIST) { ++ isns_error("Unable to create %s: %m\n", ++ lock_path); ++ return NULL; ++ } ++ isns_error("Cannot lock %s - retry in 1 sec\n", ++ isns_config.ic_local_registry_file); ++ sleep(1); ++ } ++ ++ if (!(fp = fdopen(fd, "w"))) { ++ isns_error("fdopen failed: %m\n"); ++ close(fd); ++ return NULL; ++ } ++ isns_assign_string(lock_name, lock_path); ++ return fp; ++} ++ ++/* ++ * We're done with (re)writing the registry. Commit the changes, ++ * or discard them. ++ * Also frees the lock_name returned by registry_open_write. ++ */ ++static int ++__isns_local_registry_finish_write(FILE *fp, char *lock_name, int commit) ++{ ++ int rv = 1; ++ ++ fclose(fp); ++ if (!commit) { ++ if (unlink(lock_name)) ++ isns_error("Failed to unlink %s: %m\n", lock_name); ++ } else ++ if (rename(lock_name, isns_config.ic_local_registry_file)) { ++ isns_error("Failed to rename %s to %s: %m\n", ++ lock_name, isns_config.ic_local_registry_file); ++ rv = 0; ++ } ++ ++ free(lock_name); ++ return rv; ++} ++ ++/* ++ * Get the entity name for this service ++ */ ++static char * ++__isns_local_registry_entity_name(const char *owner) ++{ ++ static char namebuf[1024]; ++ ++ snprintf(namebuf, sizeof(namebuf), "%s:%s", ++ isns_config.ic_entity_name, ++ owner); ++ return namebuf; ++} ++ ++/* ++ * Callback function which builds an iSNS object from the ++ * list of attr=tag values. ++ */ ++static int ++__isns_local_registry_load_object(const char *line, ++ int argc, char **argv, void *user_data) ++{ ++ isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; ++ struct isns_attr_list_parser state; ++ isns_object_list_t *list = user_data; ++ isns_object_t *obj, *entity = NULL; ++ ++ for (; argc > 0; --argc) { ++ char *attr = argv[argc-1]; ++ ++ if (!strncasecmp(attr, "owner=", 6)) { ++ char *eid = __isns_local_registry_entity_name(attr + 6); ++ ISNS_QUICK_ATTR_LIST_DECLARE(key_attrs, ++ ISNS_TAG_ENTITY_IDENTIFIER, ++ string, eid); ++ ++ if (entity) { ++ isns_error("Duplicate owner entry in registry\n"); ++ continue; ++ } ++ isns_attr_print(&key_attrs.iqa_attr, isns_print_stdout); ++ entity = isns_object_list_lookup(list, ++ &isns_entity_template, ++ &key_attrs.iqa_list); ++ if (entity != NULL) ++ continue; ++ ++ isns_debug_state("Creating fake entity %s\n", eid); ++ entity = isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, eid); ++ isns_object_list_append(list, entity); ++ } else { ++ break; ++ } ++ } ++ ++ isns_attr_list_parser_init(&state, NULL); ++ if (!isns_parse_attrs(argc, argv, &attrs, &state)) { ++ isns_error("Unable to parse attrs\n"); ++ isns_attr_list_destroy(&attrs); ++ return 0; ++ } ++ ++ obj = isns_create_object(isns_attr_list_parser_context(&state), ++ &attrs, entity); ++ isns_attr_list_destroy(&attrs); ++ ++ if (obj == NULL) { ++ isns_error("Unable to create object\n"); ++ return 0; ++ } ++ ++ isns_object_list_append(list, obj); ++ return 1; ++} ++ ++/* ++ * Callback function that simply writes out the line as-is ++ */ ++static int ++__isns_local_registry_rewrite_object(const char *line, ++ int argc, char **argv, void *user_data) ++{ ++ FILE *ofp = user_data; ++ ++ fprintf(ofp, "%s\n", line); ++ return 1; ++} ++ ++/* ++ * Load all objects owner by a specific service from the local registry. ++ * If the svcname starts with "!", all entries except those matching this ++ * particular service are returned. ++ */ ++int ++isns_local_registry_load(const char *svcname, pid_t pid, isns_object_list_t *objs) ++{ ++ __isns_local_registry_cb_fn_t *if_matching = NULL, *if_nonmatching = NULL; ++ ++ if (svcname == NULL) { ++ isns_error("%s: no svcname given\n", __FUNCTION__); ++ return 0; ++ } ++ if (*svcname == '!') { ++ if_nonmatching = __isns_local_registry_load_object; ++ svcname++; ++ } else { ++ if_matching = __isns_local_registry_load_object; ++ } ++ ++ return __isns_local_registry_read( ++ __isns_local_registry_make_owner(svcname, pid), ++ if_matching, if_nonmatching, objs); ++} ++ ++/* ++ * Store the given list of objects in the registry. ++ * This replaces all objects previously registered by this service. ++ */ ++int ++isns_local_registry_store(const char *svcname, pid_t pid, const isns_object_list_t *objs) ++{ ++ const char *owner = __isns_local_registry_make_owner(svcname, pid); ++ char *lock_name = NULL; ++ FILE *ofp; ++ ++ if (!(ofp = __isns_local_registry_open_write(&lock_name))) { ++ isns_error("%s: could not open registry for writing\n", __FUNCTION__); ++ return 0; ++ } ++ ++ /* First, purge all entries previously belonging to this owner */ ++ if (!__isns_local_registry_read(owner, NULL, __isns_local_registry_rewrite_object, ofp)) ++ goto failed; ++ ++ if (objs) { ++ unsigned int i; ++ ++ for (i = 0; i < objs->iol_count; ++i) { ++ isns_object_t *obj = objs->iol_data[i]; ++ char *argv[256]; ++ int i, argc; ++ ++ argc = isns_print_attrs(obj, argv, 256); ++ for (i = 0; i < argc; ++i) ++ fprintf(ofp, "%s ", argv[i]); ++ fprintf(ofp, "owner=%s\n", owner); ++ } ++ } ++ ++ return __isns_local_registry_finish_write(ofp, lock_name, 1); ++ ++failed: ++ isns_error("%s: error rewriting registry file\n", __FUNCTION__); ++ __isns_local_registry_finish_write(ofp, lock_name, 0); ++ return 0; ++} ++ ++/* ++ * Purge the local registry of all objects owned by the ++ * given service. ++ */ ++int ++isns_local_registry_purge(const char *svcname, pid_t pid) ++{ ++ return isns_local_registry_store(svcname, pid, NULL); ++} +diff --git a/utils/open-isns/logging.c b/utils/open-isns/logging.c +new file mode 100644 +index 0000000..63ebbef +--- /dev/null ++++ b/utils/open-isns/logging.c +@@ -0,0 +1,228 @@ ++/* ++ * Logging related utility functions. ++ * ++ * Copyright (C) 2004-2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "util.h" ++ ++static unsigned int log_stdout = 1; ++static unsigned int debugging = 0; ++ ++/* ++ * When backgrounding, any logging output should ++ * go to syslog instead of stdout ++ */ ++void ++isns_log_background(void) ++{ ++ log_stdout = 0; ++} ++ ++/* ++ * For output to syslog, sanitize the format string ++ * by removing newlines. ++ */ ++static const char * ++sanitize_format(const char *fmt) ++{ ++ static char __fmt[1024]; ++ unsigned int len; ++ ++ /* Don't bother unless there's a newline */ ++ if (!strchr(fmt, '\n')) ++ return fmt; ++ ++ len = strlen(fmt); ++ ++ /* Decline if the buffer would overflow */ ++ if (len >= sizeof(__fmt)) ++ return fmt; ++ ++ strcpy(__fmt, fmt); ++ while (len-- && __fmt[len] == '\n') ++ __fmt[len] = '\0'; ++ ++ while (len) { ++ if (__fmt[len] == '\n') ++ __fmt[len] = ' '; ++ --len; ++ } ++ ++ return __fmt; ++} ++ ++/* ++ * Output to stderr or syslog ++ */ ++static void ++voutput(int severity, const char *fmt, va_list ap) ++{ ++ if (log_stdout) { ++ switch (severity) { ++ case LOG_ERR: ++ fprintf(stderr, "Error: "); ++ break; ++ case LOG_WARNING: ++ fprintf(stderr, "Warning: "); ++ break; ++ case LOG_DEBUG: ++ fprintf(stderr, " "); ++ break; ++ } ++ vfprintf(stderr, fmt, ap); ++ } else { ++ fmt = sanitize_format(fmt); ++ if (!fmt || !*fmt) ++ return; ++ vsyslog(severity, fmt, ap); ++ } ++} ++ ++void ++isns_assert_failed(const char *condition, const char *file, unsigned int line) ++{ ++ isns_error("Assertion failed (%s:%d): %s\n", ++ file, line, condition); ++ abort(); ++} ++ ++void ++isns_fatal(const char *fmt, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, fmt); ++ if (log_stdout) ++ fprintf(stderr, "** FATAL ERROR **\n"); ++ voutput(LOG_ERR, fmt, ap); ++ va_end(ap); ++ exit(1); ++} ++ ++void ++isns_error(const char *fmt, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, fmt); ++ voutput(LOG_WARNING, fmt, ap); ++ va_end(ap); ++} ++ ++void ++isns_warning(const char *fmt, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, fmt); ++ voutput(LOG_NOTICE, fmt, ap); ++ va_end(ap); ++} ++ ++void ++isns_notice(const char *fmt, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, fmt); ++ voutput(LOG_INFO, fmt, ap); ++ va_end(ap); ++} ++ ++void ++isns_enable_debugging(const char *what) ++{ ++ char *copy, *s, *next; ++ ++ if (!strcmp(what, "all")) { ++ debugging = ~0U; ++ return; ++ } ++ ++ copy = isns_strdup(what); ++ ++ for (s = copy; s; s = next) { ++ if ((next = strchr(s, ',')) != NULL) ++ *next++ = '\0'; ++ ++ if (!strcmp(s, "general")) ++ debugging |= (1 << DBG_GENERAL); ++ else if (!strcmp(s, "socket")) ++ debugging |= (1 << DBG_SOCKET); ++ else if (!strcmp(s, "protocol")) ++ debugging |= (1 << DBG_PROTOCOL); ++ else if (!strcmp(s, "state")) ++ debugging |= (1 << DBG_STATE); ++ else if (!strcmp(s, "message")) ++ debugging |= (1 << DBG_MESSAGE); ++ else if (!strcmp(s, "auth")) ++ debugging |= (1 << DBG_AUTH); ++ else if (!strcmp(s, "scn")) ++ debugging |= (1 << DBG_SCN); ++ else if (!strcmp(s, "esi")) ++ debugging |= (1 << DBG_ESI); ++ else { ++ isns_error("Ignoring unknown isns_debug facility <<%s>>\n", ++ s); ++ } ++ } ++ isns_free(copy); ++} ++ ++#define DEFINE_DEBUG_FUNC(name, NAME) \ ++void \ ++isns_debug_##name(const char *fmt, ...) \ ++{ \ ++ va_list ap; \ ++ \ ++ if (!(debugging & (1 << DBG_##NAME))) \ ++ return; \ ++ \ ++ va_start(ap, fmt); \ ++ voutput(LOG_DEBUG, fmt, ap); \ ++ va_end(ap); \ ++} ++DEFINE_DEBUG_FUNC(general, GENERAL) ++DEFINE_DEBUG_FUNC(socket, SOCKET) ++DEFINE_DEBUG_FUNC(protocol, PROTOCOL) ++DEFINE_DEBUG_FUNC(message, MESSAGE) ++DEFINE_DEBUG_FUNC(auth, AUTH) ++DEFINE_DEBUG_FUNC(state, STATE) ++DEFINE_DEBUG_FUNC(scn, SCN) ++DEFINE_DEBUG_FUNC(esi, ESI) ++ ++int ++isns_debug_enabled(int fac) ++{ ++ return (debugging & (1 << fac)) != 0; ++} ++ ++/* ++ * Misc isns_print_fn_t implementations ++ */ ++void ++isns_print_stdout(const char *fmt, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, fmt); ++ vfprintf(stdout, fmt, ap); ++ va_end(ap); ++} ++ ++void ++isns_print_stderr(const char *fmt, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, fmt); ++ vfprintf(stderr, fmt, ap); ++ va_end(ap); ++} +diff --git a/utils/open-isns/mdebug.c b/utils/open-isns/mdebug.c +new file mode 100644 +index 0000000..90dcaf0 +--- /dev/null ++++ b/utils/open-isns/mdebug.c +@@ -0,0 +1,295 @@ ++/* ++ * Stupid malloc debugger. I think I wrote something like ++ * this a couple of times already. Where does all the old ++ * source code go? ++ */ ++ ++#ifdef MDEBUG ++ ++#include ++#include ++#include "util.h" ++ ++static void * isns_malloc_default(size_t, const char *, unsigned int); ++static void * isns_calloc_default(unsigned int, size_t, ++ const char *, unsigned int); ++static void * isns_realloc_default(void *, size_t, ++ const char *, unsigned int); ++static char * isns_strdup_default(const char *, const char *, unsigned int); ++static void isns_free_default(void *, const char *, unsigned int); ++ ++/* ++ * These are the function pointers used to redirect malloc and such. ++ */ ++void * (*isns_malloc_fn)(size_t, const char *, unsigned int) = isns_malloc_default; ++void * (*isns_calloc_fn)(unsigned int, size_t, ++ const char *, unsigned int) = isns_calloc_default; ++void * (*isns_realloc_fn)(void *, size_t, ++ const char *, unsigned int) = isns_realloc_default; ++char * (*isns_strdup_fn)(const char *, const char *, unsigned int) = isns_strdup_default; ++void (*isns_free_fn)(void *, const char *, unsigned int) = isns_free_default; ++ ++#define H_MAGIC 0xfeedbeef ++#define T_MAGIC 0xbadf00d ++#define CHUNK_OVERHEAD (sizeof(struct m_header) + sizeof(struct m_trailer)) ++ ++struct m_header { ++ struct isns_list h_list; ++ uint32_t h_magic; ++ size_t h_size; ++ ++ const char * h_file; ++ unsigned int h_line; ++}; ++ ++struct m_trailer { ++ uint32_t t_magic[8]; ++ size_t t_size; ++}; ++ ++static ISNS_LIST_DECLARE(m_list); ++static void * m_low_addr; ++static void * m_high_addr; ++static int m_init = 0; ++ ++static void ++__isns_check_chunk(const struct m_header *head) ++{ ++ const struct m_trailer *tail; ++ int i; ++ ++ if ((void *) head < m_low_addr ++ || (void *) head > m_high_addr) { ++ isns_error("%s: m_list corrupted!\n", __FUNCTION__); ++ abort(); ++ } ++ ++ if (head->h_magic != H_MAGIC) { ++ isns_error("%s: m_list item %p with bad header magic %08x\n", ++ __FUNCTION__, head, head->h_magic); ++ isns_error(" Allocated from %s:%u\n", ++ head->h_file, head->h_line); ++ abort(); ++ } ++ ++ tail = ((void *) head) + sizeof(*head) + head->h_size; ++ for (i = 0; i < 8; ++i) { ++ if (tail->t_magic[i] == T_MAGIC) ++ continue; ++ ++ isns_error("%s: m_list item %p with bad trailer magic[%d] %08x\n", ++ __FUNCTION__, head, i, tail->t_magic[i]); ++ isns_error(" Allocated from %s:%u\n", ++ head->h_file, head->h_line); ++ abort(); ++ } ++ ++ if (tail->t_size != head->h_size) { ++ isns_error("%s: m_list item %p size mismatch; head=%u tail=%u\n", ++ __FUNCTION__, head, ++ head->h_size, tail->t_size); ++ isns_error(" Allocated from %s:%u\n", ++ head->h_file, head->h_line); ++ abort(); ++ } ++} ++ ++static void ++__isns_verify_all(void) ++{ ++ struct isns_list *pos, *next; ++ ++ isns_list_foreach(&m_list, pos, next) { ++ __isns_check_chunk(isns_list_item(struct m_header, h_list, pos)); ++ } ++} ++ ++void * ++__isns_malloc(size_t size, const char *file, unsigned int line) ++{ ++ struct m_header *head; ++ struct m_trailer *tail; ++ size_t true_size; ++ void *ptr; ++ int i; ++ ++ __isns_verify_all(); ++ ++ true_size = size + sizeof(*head) + sizeof(*tail); ++ isns_assert(size < true_size); ++ ++ ptr = malloc(true_size); ++ if (!ptr) ++ return NULL; ++ ++ if (!m_low_addr) { ++ m_low_addr = m_high_addr = ptr; ++ } else if (ptr < m_low_addr) { ++ m_low_addr = ptr; ++ } else if (ptr > m_high_addr) { ++ m_high_addr = ptr; ++ } ++ ++ head = ptr; ++ head->h_magic = H_MAGIC; ++ head->h_size = size; ++ head->h_file = file; ++ head->h_line = line; ++ isns_list_append(&m_list, &head->h_list); ++ ++ ptr += sizeof(*head); ++ ++ tail = ptr + size; ++ for (i = 0; i < 8; ++i) ++ tail->t_magic[i] = T_MAGIC; ++ tail->t_size = size; ++ ++ return ptr; ++} ++ ++void * ++__isns_calloc(unsigned int nele, size_t size, ++ const char *file, unsigned int line) ++{ ++ void *ptr; ++ ++ ptr = __isns_malloc(nele * size, file, line); ++ if (ptr) ++ memset(ptr, 0, nele * size); ++ return ptr; ++} ++ ++void * ++__isns_realloc(void *old, size_t new_size, ++ const char *file, unsigned int line) ++{ ++ struct m_header *old_head = NULL; ++ void *new; ++ ++ if (old) { ++ old_head = (old - sizeof(struct m_header)); ++ __isns_check_chunk(old_head); ++ } ++ ++ new = __isns_malloc(new_size, file, line); ++ if (new && old) { ++ memcpy(new, old, old_head->h_size); ++ isns_free_fn(old, file, line); ++ } ++ ++ return new; ++} ++ ++ ++char * ++__isns_strdup(const char *s, const char *file, unsigned int line) ++{ ++ size_t len; ++ char *ptr; ++ ++ len = s? strlen(s) : 0; ++ ptr = __isns_malloc(len + 1, file, line); ++ if (ptr) { ++ memcpy(ptr, s, len); ++ ptr[len] = '\0'; ++ } ++ return ptr; ++} ++ ++void ++__isns_free(void *ptr, const char *file, unsigned int line) ++{ ++ struct m_header *head; ++ size_t true_size; ++ ++ if (ptr == NULL) ++ return; ++ ++ head = ptr - sizeof(struct m_header); ++ __isns_check_chunk(head); ++ ++ /* ++ printf("__isns_free(%u from %s:%u): freed by %s:%u\n", ++ head->h_size, head->h_file, head->h_line, ++ file, line); ++ */ ++ true_size = head->h_size + CHUNK_OVERHEAD; ++ isns_list_del(&head->h_list); ++ ++ memset(head, 0xa5, true_size); ++ free(head); ++ ++ __isns_verify_all(); ++} ++ ++/* ++ * Enable memory debugging ++ */ ++static void ++__isns_mdebug_init(void) ++{ ++ const char *tracefile; ++ ++ tracefile = getenv("ISNS_MTRACE"); ++ if (tracefile) ++ isns_error("MTRACE not yet supported\n"); ++ ++ if (getenv("ISNS_MDEBUG")) { ++ isns_malloc_fn = __isns_malloc; ++ isns_calloc_fn = __isns_calloc; ++ isns_realloc_fn = __isns_realloc; ++ isns_strdup_fn = __isns_strdup; ++ isns_free_fn = __isns_free; ++ isns_notice("Enabled memory debugging\n"); ++ } ++ ++ m_init = 1; ++} ++ ++static inline void ++isns_mdebug_init(void) ++{ ++ if (!m_init) ++ __isns_mdebug_init(); ++} ++ ++/* ++ * Default implementations of malloc and friends ++ */ ++static void * ++isns_malloc_default(size_t size, const char *file, unsigned int line) ++{ ++ isns_mdebug_init(); ++ return malloc(size); ++} ++ ++static void * ++isns_calloc_default(unsigned int nele, size_t size, ++ const char *file, unsigned int line) ++{ ++ isns_mdebug_init(); ++ return calloc(nele, size); ++} ++ ++static void * ++isns_realloc_default(void *old, size_t size, ++ const char *file, unsigned int line) ++{ ++ isns_mdebug_init(); ++ return realloc(old, size); ++} ++ ++static char * ++isns_strdup_default(const char *s, const char *file, unsigned int line) ++{ ++ isns_mdebug_init(); ++ return strdup(s); ++} ++ ++static void ++isns_free_default(void *ptr, const char *file, unsigned int line) ++{ ++ isns_mdebug_init(); ++ return free(ptr); ++} ++#endif +diff --git a/utils/open-isns/message.c b/utils/open-isns/message.c +new file mode 100644 +index 0000000..4cd40c3 +--- /dev/null ++++ b/utils/open-isns/message.c +@@ -0,0 +1,681 @@ ++/* ++ * iSNS message handling functions ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ * ++ * ++ */ ++ ++#include ++#include ++#include /* for timercmp */ ++#include /* gethostname */ ++#include ++#include "isns.h" ++#include "attrs.h" ++#include "message.h" ++#include "socket.h" ++#include "util.h" ++ ++/* iSCSI qualified names include the year and ++ * month in which the domain was assigned. ++ * See RFC 3720, section 3.2.6.3.1. ++ * That's one of these wonderful committee ++ * type of ideas that makes it hard for everyone, ++ * from coder to sysadmin. ++ * Since we have no way of finding out here, ++ * we fake it by assigning a date before the ++ * dawn of time. ++ */ ++#define DUMMY_IQN_PREFIX "iqn.1967-12." ++ ++static uint32_t isns_xid = 1; ++ ++/* ++ * Initialize a message object ++ */ ++isns_message_t * ++__isns_alloc_message(uint32_t xid, size_t size, void (*destroy)(isns_message_t *)) ++{ ++ isns_message_t *msg; ++ ++ isns_assert(size >= sizeof(*msg)); ++ msg = isns_calloc(1, size); ++ ++ isns_list_init(&msg->im_list); ++ msg->im_users = 1; ++ msg->im_xid = xid; ++ msg->im_destroy = destroy; ++ ++ return msg; ++} ++ ++static int ++__isns_message_init(isns_message_t *msg, ++ uint16_t function, uint16_t flags, ++ size_t payload_len) ++{ ++ struct isns_hdr *hdr = &msg->im_header; ++ ++ /* Pad to multiple of 4 octets */ ++ payload_len = (payload_len + 3) & ~3UL; ++ ++ /* For now, we don't do segmentation */ ++ if (payload_len > ISNS_MAX_PDU_SIZE) ++ return 0; ++ ++ /* msg->im_header is in host byte order */ ++ hdr->i_version = ISNS_VERSION; ++ hdr->i_function = function; ++ hdr->i_flags = flags; ++ hdr->i_length = payload_len; ++ hdr->i_xid = msg->im_xid; ++ hdr->i_seq = 0; ++ ++ /* Allocate buffer and reserve room for header */ ++ msg->im_payload = buf_alloc(sizeof(*hdr) + payload_len); ++ buf_push(msg->im_payload, sizeof(*hdr)); ++ ++ return 1; ++} ++ ++/* ++ * Allocate a message object. ++ */ ++static isns_message_t * ++__isns_create_message(uint32_t xid, uint16_t function, uint16_t flags) ++{ ++ isns_message_t *msg; ++ ++ msg = __isns_alloc_message(xid, sizeof(*msg), NULL); ++ __isns_message_init(msg, function, flags, ISNS_MAX_MESSAGE); ++ ++ return msg; ++} ++ ++/* ++ * Allocate a request message ++ */ ++isns_message_t * ++isns_create_message(uint16_t function, uint16_t flags) ++{ ++ return __isns_create_message(isns_xid++, function, flags); ++} ++ ++/* ++ * Allocate a response message ++ */ ++isns_message_t * ++isns_create_reply(const isns_message_t *msg) ++{ ++ uint16_t function = msg->im_header.i_function;; ++ isns_message_t *resp; ++ ++ resp = __isns_create_message(msg->im_xid, function | 0x8000, ISNS_F_SERVER); ++ resp->im_addr = msg->im_addr; ++ resp->im_addrlen = msg->im_addrlen; ++ ++ /* Default to ISNS_SUCCESS */ ++ buf_put32(resp->im_payload, ISNS_SUCCESS); ++ ++ return resp; ++} ++ ++/* ++ * Delete a message ++ */ ++void ++isns_message_release(isns_message_t *msg) ++{ ++ if (msg == NULL) ++ return; ++ ++ isns_assert(msg->im_users); ++ if (--(msg->im_users)) ++ return; ++ ++ if (msg->im_destroy) ++ msg->im_destroy(msg); ++ if (msg->im_payload) ++ buf_free(msg->im_payload); ++ isns_principal_free(msg->im_security); ++ ++ isns_list_del(&msg->im_list); ++ isns_free(msg); ++} ++ ++/* ++ * Extract the status from a reply message ++ */ ++int ++isns_message_status(isns_message_t *msg) ++{ ++ uint32_t status; ++ ++ if (!(msg->im_header.i_function & 0x8000) ++ || !buf_get32(msg->im_payload, &status)) ++ return ISNS_MESSAGE_FORMAT_ERROR; ++ return status; ++} ++ ++/* ++ * Obtain the socket on which the message was received. ++ */ ++isns_socket_t * ++isns_message_socket(const isns_message_t *msg) ++{ ++ return msg->im_socket; ++} ++ ++/* ++ * Obtain the message's security context ++ */ ++isns_security_t * ++isns_message_security(const isns_message_t *msg) ++{ ++ if (!msg->im_socket) ++ return NULL; ++ return msg->im_socket->is_security; ++} ++ ++unsigned int ++isns_message_function(const isns_message_t *msg) ++{ ++ return msg->im_header.i_function; ++} ++ ++/* ++ * Reset the response message, and encode isns_error ++ * status ++ */ ++void ++isns_message_set_error(isns_message_t *msg, uint32_t status) ++{ ++ /* Clear the buffer. This just resets head + tail */ ++ buf_clear(msg->im_payload); ++ ++ /* Now move past the header, and overwrite the ++ * status word. */ ++ buf_push(msg->im_payload, sizeof(struct isns_hdr)); ++ buf_put32(msg->im_payload, status); ++} ++ ++/* ++ * Message queue handling. Most related functions are ++ * in message.h ++ */ ++void ++isns_message_queue_move(isns_message_queue_t *dstq, ++ isns_message_t *msg) ++{ ++ unsigned int src_ref = 0; ++ ++ /* If the message was on a different queue, ++ * the source queue will hold a reference ++ * to it. Account for that and fix up the ++ * refcount after we've appended it to the ++ * destination queue. */ ++ if (isns_message_unlink(msg)) ++ src_ref = 1; ++ ++ isns_message_queue_append(dstq, msg); ++ msg->im_users -= src_ref; ++} ++ ++/* ++ * Insert a messsage into a queue sorted by resend timeout ++ */ ++void ++isns_message_queue_insert_sorted(isns_message_queue_t *q, ++ int sort, isns_message_t *msg) ++{ ++ isns_list_t *pos; ++ isns_message_t *__m; ++ ++ isns_assert(msg->im_queue == NULL); ++ if (sort == ISNS_MQ_SORT_RESEND_TIMEOUT) { ++ isns_message_queue_foreach(q, pos, __m) { ++ if (timercmp(&msg->im_resend_timeout, ++ &__m->im_resend_timeout, <)) ++ break; ++ } ++ } else { ++ isns_message_queue_append(q, msg); ++ return; ++ } ++ ++ /* Insert before pos */ ++ __isns_list_insert(pos->prev, &msg->im_list, pos); ++ q->imq_count++; ++ ++ msg->im_queue = q; ++ msg->im_users++; ++} ++ ++/* ++ * Message queue handling ++ */ ++void ++isns_message_queue_destroy(isns_message_queue_t *q) ++{ ++ isns_message_t *msg; ++ ++ while ((msg = isns_message_dequeue(q)) != NULL) ++ isns_message_release(msg); ++} ++ ++/* ++ * Find a message with matching xid and address. ++ * (address, alen) may be NULL. ++ */ ++isns_message_t * ++isns_message_queue_find(isns_message_queue_t *q, uint32_t xid, ++ const struct sockaddr_storage *addr, socklen_t alen) ++{ ++ isns_message_t *msg; ++ isns_list_t *pos; ++ ++ isns_message_queue_foreach(q, pos, msg) { ++ if (msg->im_xid != xid) ++ continue; ++ if (alen == 0) ++ return msg; ++ ++ if (msg->im_addrlen == alen ++ && !memcmp(&msg->im_addr, addr, alen)) ++ return msg; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Convert a hostname into an iSCSI qualified name ++ * We omit the dismbiguating YYYY-MM infix because ++ * we have no way of finding out, short of bothering ++ * whois. ++ */ ++static char * ++__revert_fqdn(const char *prefix, const char *__fqdn, const char *suffix) ++{ ++ static char namebuf[1024] = { '\0' }; ++ char *fqdn, *result = NULL; ++ int pos, count = 0; ++ ++ if (prefix) ++ strcpy(namebuf, prefix); ++ pos = strlen(namebuf); ++ ++ fqdn = isns_strdup(__fqdn); ++ while (1) { ++ char *dot, *comp; ++ int comp_len; ++ ++ if ((dot = strrchr(fqdn, '.')) != NULL) { ++ *dot++ = '\0'; ++ comp = dot; ++ } else { ++ comp = fqdn; ++ } ++ ++ if (*comp == '\0') ++ continue; ++ comp_len = strlen(comp); ++ if (pos + comp_len + 2 > sizeof(namebuf)) { ++ isns_error("%s: FQDN too long\n", __FUNCTION__); ++ goto out; ++ } ++ if (count++) ++ namebuf[pos++] = '.'; ++ strcpy(namebuf + pos, comp); ++ pos += comp_len; ++ ++ if (dot == NULL) ++ break; ++ } ++ ++ if (suffix) { ++ int sfx_len = strlen(suffix); ++ ++ if (pos + sfx_len + 2 > sizeof(namebuf)) { ++ isns_error("%s: name too long\n", __FUNCTION__); ++ goto out; ++ } ++ namebuf[pos++] = ':'; ++ strcpy(namebuf + pos, suffix); ++ pos += sfx_len; ++ } ++ ++ result = isns_strdup(namebuf); ++ ++out: isns_free(fqdn); ++ return result; ++} ++ ++/* ++ * Initialize all names ++ */ ++int ++isns_init_names(void) ++{ ++ if (isns_config.ic_host_name == NULL) { ++ char namebuf[1024], *fqdn; ++ ++ if (gethostname(namebuf, sizeof(namebuf)) < 0) { ++ isns_error("gehostname: %m\n"); ++ return 0; ++ } ++ fqdn = isns_get_canon_name(namebuf); ++ if (fqdn == NULL) { ++ /* FIXME: we could get some unique value here ++ * such as the IP address, and concat that ++ * with iqn.2005-01.org.open-iscsi.ip for the ++ * source name. ++ */ ++ isns_error("Unable to get fully qualified hostname\n"); ++ return 0; ++ } ++ isns_config.ic_host_name = fqdn; ++ } ++ ++ if (isns_config.ic_auth_name == NULL) { ++ isns_config.ic_auth_name = isns_config.ic_host_name; ++ } ++ ++ if (isns_config.ic_entity_name == NULL) { ++ isns_config.ic_entity_name = isns_config.ic_auth_name; ++ } ++ ++ if (isns_config.ic_source_name == NULL) { ++ isns_config.ic_source_name = __revert_fqdn(DUMMY_IQN_PREFIX, ++ isns_config.ic_host_name, ++ isns_config.ic_source_suffix); ++ if (isns_config.ic_source_name == NULL) { ++ isns_error("Unable to build source name\n"); ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++/* ++ * Match a source name to a pattern (which is really just ++ * the entity identifier, usually). ++ * ++ * If the pattern is of the form "match:rev-fqdn", the ++ * source name must match ++ * iqn.[YYYY-MM.] ++ * optionally followed by dot, colon or hyphen and arbitrary ++ * text. ++ * ++ * If the pattern does not start with "match:", the source name ++ * must match the pattern literally (case insensitively). ++ */ ++int ++isns_source_pattern_match(const char *pattern, const char *source) ++{ ++ unsigned int rev_len; ++ ++ isns_debug_message("%s(%s, %s)\n", ++ __FUNCTION__, pattern, source); ++ ++ if (!strcmp(pattern, "*")) ++ return 1; ++ ++ if (strncmp(pattern, "match:", 6)) ++ return !strcasecmp(pattern, source); ++ pattern += 6; ++ ++ if (strncasecmp(source, "iqn.", 4)) ++ return 0; ++ source += 4; ++ ++ rev_len = strlen(pattern); ++ if (strncasecmp(source, pattern, rev_len)) { ++ /* See if the next component is YYYY-MM */ ++ if (!(isdigit(source[0]) ++ && isdigit(source[1]) ++ && isdigit(source[2]) ++ && isdigit(source[3]) ++ && source[4] == '-' ++ && isdigit(source[5]) ++ && isdigit(source[6]) ++ && source[7] == '.')) ++ return 0; ++ source += 8; ++ ++ if (strncasecmp(source, pattern, rev_len)) ++ return 0; ++ } ++ ++ source += rev_len; ++ if (source[0] != '.' ++ && source[0] != ':' ++ && source[0] != '-' ++ && source[0] != '\0') ++ return 0; ++ ++ return 1; ++} ++ ++/* ++ * This really just reverts the FQDN so it can ++ * be used in isns_source_entity_match ++ */ ++char * ++isns_build_source_pattern(const char *fqdn) ++{ ++ return __revert_fqdn("match:", fqdn, NULL); ++} ++ ++/* ++ * Manage source objects ++ */ ++static isns_source_t * ++__isns_source_create(isns_attr_t *name_attr) ++{ ++ isns_source_t *source = isns_calloc(1, sizeof(*source)); ++ ++ source->is_users = 1; ++ source->is_attr = name_attr; ++ return source; ++} ++ ++isns_source_t * ++isns_source_create(isns_attr_t *name_attr) ++{ ++ if (name_attr->ia_tag_id != ISNS_TAG_ISCSI_NAME ++ && name_attr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN) ++ return NULL; ++ ++ name_attr->ia_users++; ++ return __isns_source_create(name_attr); ++} ++ ++isns_source_t * ++isns_source_from_object(const isns_object_t *node) ++{ ++ isns_attr_t *attr; ++ ++ if (!(attr = isns_storage_node_key_attr(node))) ++ return NULL; ++ return isns_source_create(attr); ++} ++ ++isns_source_t * ++isns_source_create_iscsi(const char *name) ++{ ++ isns_value_t var = ISNS_VALUE_INIT(string, (char *) name); ++ isns_attr_t *attr; ++ ++ attr = isns_attr_alloc(ISNS_TAG_ISCSI_NAME, NULL, &var); ++ return __isns_source_create(attr); ++} ++ ++/* ++ * This is used to attach a dummy source to iSNS responses ++ * until I fixed up all the code that relies on msg->is_source ++ * to be valid all the time. ++ */ ++isns_source_t * ++isns_source_dummy(void) ++{ ++ static isns_source_t *dummy = NULL; ++ ++ if (!dummy) ++ dummy = isns_source_create_iscsi(".dummy."); ++ return isns_source_get(dummy); ++} ++ ++uint32_t ++isns_source_type(const isns_source_t *source) ++{ ++ return source->is_attr->ia_tag_id; ++} ++ ++const char * ++isns_source_name(const isns_source_t *source) ++{ ++ return source->is_attr->ia_value.iv_string; ++} ++ ++isns_attr_t * ++isns_source_attr(const isns_source_t *source) ++{ ++ return source->is_attr; ++} ++ ++/* ++ * Obtain an additional reference on the source object ++ */ ++isns_source_t * ++isns_source_get(isns_source_t *source) ++{ ++ if (source) ++ source->is_users++; ++ return source; ++} ++ ++/* ++ * Look up the node corresponding to this source name ++ * When we get here, we have already verified that the ++ * client is permitted (by policy) to use this source node. ++ */ ++int ++isns_source_set_node(isns_source_t *source, isns_db_t *db) ++{ ++ isns_object_t *node, *entity; ++ uint32_t node_type; ++ ++ if (source->is_node) ++ return 1; ++ ++ if (db == NULL) ++ return 0; ++ ++ node = isns_db_lookup_source_node(db, source); ++ if (node == NULL) ++ return 0; ++ ++ if (!isns_object_get_uint32(node, ISNS_TAG_ISCSI_NODE_TYPE, &node_type)) ++ node_type = 0; ++ ++ source->is_node = node; ++ source->is_node_type = node_type; ++ ++ if ((entity = isns_object_get_entity(node)) != NULL) ++ source->is_entity = isns_object_get(entity); ++ return 1; ++} ++ ++void ++isns_source_set_entity(isns_source_t *source, isns_object_t *obj) ++{ ++ if (obj) ++ isns_object_get(obj); ++ isns_object_release(source->is_entity); ++ source->is_entity = obj; ++} ++ ++/* ++ * Release a reference on the source object ++ */ ++void ++isns_source_release(isns_source_t *source) ++{ ++ if (source && --source->is_users == 0) { ++ isns_attr_release(source->is_attr); ++ isns_object_release(source->is_node); ++ isns_object_release(source->is_entity); ++ memset(source, 0xa5, sizeof(*source)); ++ isns_free(source); ++ } ++} ++ ++/* ++ * Compare two source objects ++ */ ++int ++isns_source_match(const isns_source_t *a, ++ const isns_source_t *b) ++{ ++ if (a && b) ++ return isns_attr_match(a->is_attr, b->is_attr); ++ return 0; ++} ++ ++/* ++ * Encode/decode source object ++ */ ++int ++isns_source_encode(buf_t *bp, const isns_source_t *source) ++{ ++ if (source == NULL) { ++ isns_attr_t nil = ISNS_ATTR_INIT(ISNS_TAG_DELIMITER, nil, 0); ++ ++ return isns_attr_encode(bp, &nil); ++ } ++ return isns_attr_encode(bp, source->is_attr); ++} ++ ++int ++isns_source_decode(buf_t *bp, isns_source_t **result) ++{ ++ isns_attr_t *attr; ++ int status; ++ ++ status = isns_attr_decode(bp, &attr); ++ if (status == ISNS_SUCCESS) { ++ /* ++ * 5.6.1 ++ * The Source Attribute uniquely identifies the source of the ++ * message. Valid Source Attribute types are shown below. ++ * ++ * Valid Source Attributes ++ * ----------------------- ++ * iSCSI Name ++ * FC Port Name WWPN ++ */ ++ switch (attr->ia_tag_id) { ++#if 0 ++ case ISNS_TAG_DELIMITER: ++ *result = NULL; ++ break; ++#endif ++ ++ case ISNS_TAG_ISCSI_NAME: ++ *result = __isns_source_create(attr); ++ break; ++ ++ case ISNS_TAG_FC_PORT_NAME_WWPN: ++ *result = __isns_source_create(attr); ++ break; ++ ++ default: ++ isns_attr_release(attr); ++ return ISNS_SOURCE_UNKNOWN; ++ } ++ } ++ return status; ++} +diff --git a/utils/open-isns/message.h b/utils/open-isns/message.h +new file mode 100644 +index 0000000..f1f4ed6 +--- /dev/null ++++ b/utils/open-isns/message.h +@@ -0,0 +1,196 @@ ++/* ++ * iSNS message definitions and functions ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#ifndef ISNS_MESSAGE_H ++#define ISNS_MESSAGE_H ++ ++#include "attrs.h" ++#include "source.h" ++#include "util.h" ++ ++typedef struct isns_message_queue isns_message_queue_t; ++ ++struct isns_simple { ++ uint32_t is_function; ++ isns_source_t * is_source; ++ isns_policy_t * is_policy; ++ uint16_t is_xid; ++ ++ unsigned int is_replace : 1; ++ ++ isns_attr_list_t is_message_attrs; ++ isns_attr_list_t is_operating_attrs; ++}; ++ ++struct isns_message { ++ unsigned int im_users; ++ isns_list_t im_list; ++ struct sockaddr_storage im_addr; ++ socklen_t im_addrlen; ++ uint32_t im_xid; ++ struct isns_hdr im_header; ++ struct isns_buf * im_payload; ++ isns_socket_t * im_socket; ++ isns_principal_t * im_security; ++ struct ucred * im_creds; ++ ++ isns_message_queue_t * im_queue; ++ ++ /* When to retransmit */ ++ struct timeval im_resend_timeout; ++ struct timeval im_timeout; ++ ++ void (*im_destroy)(isns_message_t *); ++ void (*im_callback)(isns_message_t *, ++ isns_message_t *); ++ void * im_calldata; ++}; ++ ++enum { ++ ISNS_MQ_SORT_NONE, ++ ISNS_MQ_SORT_RESEND_TIMEOUT, ++}; ++ ++struct isns_message_queue { ++ isns_list_t imq_list; ++ size_t imq_count; ++}; ++ ++struct isns_server { ++ isns_source_t * is_source; ++ isns_db_t * is_db; ++ ++ isns_scn_callback_fn_t *is_scn_callback; ++ struct isns_service_ops *is_ops; ++}; ++ ++extern isns_message_t * __isns_alloc_message(uint32_t, size_t, void (*)(isns_message_t *)); ++extern isns_security_t *isns_message_security(const isns_message_t *); ++ ++extern isns_message_t * isns_message_queue_find(isns_message_queue_t *, uint32_t, ++ const struct sockaddr_storage *, socklen_t); ++extern void isns_message_queue_insert_sorted(isns_message_queue_t *, ++ int, isns_message_t *); ++extern void isns_message_queue_move(isns_message_queue_t *, ++ isns_message_t *); ++extern void isns_message_queue_destroy(isns_message_queue_t *); ++ ++extern isns_simple_t * isns_simple_create(uint32_t, ++ isns_source_t *, ++ const isns_attr_list_t *); ++extern void isns_simple_free(isns_simple_t *); ++extern int isns_simple_encode(isns_simple_t *, ++ isns_message_t **result); ++extern int isns_simple_decode(isns_message_t *, ++ isns_simple_t **); ++extern int isns_simple_encode_response(isns_simple_t *, ++ const isns_message_t *, isns_message_t **); ++extern int isns_simple_response_get_objects(isns_simple_t *, ++ isns_object_list_t *); ++extern const char * isns_function_name(uint32_t); ++ ++extern isns_source_t * isns_simple_get_source(isns_simple_t *); ++ ++extern int isns_process_registration(isns_server_t *, isns_simple_t *, isns_simple_t **); ++extern int isns_process_query(isns_server_t *, isns_simple_t *, isns_simple_t **); ++extern int isns_process_getnext(isns_server_t *, isns_simple_t *, isns_simple_t **); ++extern int isns_process_deregistration(isns_server_t *, isns_simple_t *, isns_simple_t **); ++extern int isns_process_scn_register(isns_server_t *, isns_simple_t *, isns_simple_t **); ++extern int isns_process_scn_deregistration(isns_server_t *, isns_simple_t *, isns_simple_t **); ++extern int isns_process_dd_registration(isns_server_t *, isns_simple_t *, isns_simple_t **); ++extern int isns_process_dd_deregistration(isns_server_t *, isns_simple_t *, isns_simple_t **); ++extern int isns_process_esi(isns_server_t *, isns_simple_t *, isns_simple_t **); ++extern int isns_process_scn(isns_server_t *, isns_simple_t *, isns_simple_t **); ++ ++/* ++ * Inline functions for message queues. ++ */ ++static inline void ++isns_message_queue_init(isns_message_queue_t *q) ++{ ++ isns_list_init(&q->imq_list); ++ q->imq_count = 0; ++} ++ ++static inline isns_message_t * ++isns_message_queue_head(const isns_message_queue_t *q) ++{ ++ isns_list_t *pos = q->imq_list.next; ++ ++ if (pos == &q->imq_list) ++ return NULL; ++ return isns_list_item(isns_message_t, im_list, pos); ++} ++ ++static inline void ++isns_message_queue_append(isns_message_queue_t *q, isns_message_t *msg) ++{ ++ isns_assert(msg->im_queue == NULL); ++ isns_list_append(&q->imq_list, &msg->im_list); ++ q->imq_count++; ++ ++ msg->im_queue = q; ++ msg->im_users++; ++} ++ ++static inline isns_message_t * ++isns_message_queue_remove(isns_message_queue_t *q, isns_message_t *msg) ++{ ++ isns_assert(msg->im_queue == q); ++ isns_list_del(&msg->im_list); ++ msg->im_queue = NULL; ++ q->imq_count--; ++ ++ return msg; ++} ++ ++static inline isns_message_t * ++isns_message_unlink(isns_message_t *msg) ++{ ++ if (msg->im_queue) ++ return isns_message_queue_remove(msg->im_queue, msg); ++ return NULL; ++} ++ ++static inline isns_message_t * ++isns_message_dequeue(isns_message_queue_t *q) ++{ ++ isns_message_t *msg; ++ ++ if ((msg = isns_message_queue_head(q)) != NULL) { ++ isns_list_del(&msg->im_list); ++ msg->im_queue = NULL; ++ q->imq_count--; ++ } ++ return msg; ++} ++ ++/* ++ * Iterator for looping over all messages in a queue ++ */ ++static inline void ++isns_message_queue_begin(isns_message_queue_t *q, isns_list_t **pos) ++{ ++ *pos = q->imq_list.next; ++} ++ ++static inline isns_message_t * ++isns_message_queue_next(isns_message_queue_t *q, isns_list_t **pos) ++{ ++ isns_list_t *next = *pos; ++ ++ if (next == &q->imq_list) ++ return NULL; ++ *pos = next->next; ++ return isns_list_item(isns_message_t, im_list, next); ++} ++ ++#define isns_message_queue_foreach(q, pos, item) \ ++ for (isns_message_queue_begin(q, &pos); \ ++ (item = isns_message_queue_next(q, &pos)) != NULL; \ ++ ) ++ ++#endif /* ISNS_MESSAGE_H */ +diff --git a/utils/open-isns/objects.c b/utils/open-isns/objects.c +new file mode 100644 +index 0000000..1504026 +--- /dev/null ++++ b/utils/open-isns/objects.c +@@ -0,0 +1,1320 @@ ++/* ++ * iSNS object model ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include "isns.h" ++#include "objects.h" ++#include "source.h" ++#include "vendor.h" ++#include "attrs.h" ++#include "util.h" ++ ++/* For relationship stuff - should go */ ++#include "db.h" ++ ++static isns_object_template_t * isns_object_templates[] = { ++ &isns_entity_template, ++ &isns_portal_template, ++ &isns_iscsi_node_template, ++ &isns_fc_port_template, ++ &isns_fc_node_template, ++ &isns_iscsi_pg_template, ++ &isns_dd_template, ++ &isns_ddset_template, ++ ++ /* vendor-specific templates */ ++ &isns_policy_template, ++ ++ NULL ++}; ++ ++/* ++ * Quick lookup of (key) tag to template ++ */ ++#define MAX_QUICK_TAG 2100 ++static isns_object_template_t * isns_object_template_key_map[MAX_QUICK_TAG]; ++static isns_object_template_t * isns_object_template_any_map[MAX_QUICK_TAG]; ++static isns_object_template_t * isns_object_template_idx_map[MAX_QUICK_TAG]; ++static int isns_object_maps_inizialized = 0; ++ ++ ++static void ++__isns_object_maps_init(void) ++{ ++ isns_object_template_t *tmpl; ++ uint32_t i, j, tag; ++ ++ isns_object_maps_inizialized = 1; ++ ++ for (i = 0; (tmpl = isns_object_templates[i]) != NULL; ++i) { ++ if (tmpl->iot_vendor_specific) ++ continue; ++ ++ tag = tmpl->iot_keys[0]; ++ isns_assert(tag < MAX_QUICK_TAG); ++ isns_object_template_key_map[tag] = tmpl; ++ ++ for (j = 0; j < tmpl->iot_num_attrs; ++j) { ++ tag = tmpl->iot_attrs[j]; ++ isns_assert(tag < MAX_QUICK_TAG); ++ isns_object_template_any_map[tag] = tmpl; ++ } ++ ++ if ((tag = tmpl->iot_index) != 0) ++ isns_object_template_idx_map[tag] = tmpl; ++ } ++} ++ ++static void ++isns_object_maps_init(void) ++{ ++ if (!isns_object_maps_inizialized) ++ __isns_object_maps_init(); ++} ++ ++/* ++ * Based on a given key attribute, find the corresponding ++ * object type. ++ */ ++isns_object_template_t * ++isns_object_template_find(uint32_t key_tag) ++{ ++ isns_object_template_t *tmpl; ++ unsigned int i; ++ ++ isns_object_maps_init(); ++ if (key_tag < MAX_QUICK_TAG) ++ return isns_object_template_key_map[key_tag]; ++ ++ for (i = 0; (tmpl = isns_object_templates[i]) != NULL; ++i) { ++ if (tmpl->iot_keys[0] == key_tag) ++ return tmpl; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Given a set of attributes, find the corresponding ++ * object type. ++ * Any attributes in the list in *addition to* the keys ++ * attributes are ignored. ++ */ ++isns_object_template_t * ++isns_object_template_for_key_attrs(const isns_attr_list_t *attrs) ++{ ++ isns_object_template_t *tmpl; ++ const isns_attr_t *attr; ++ unsigned int i; ++ ++ if (attrs->ial_count == 0) ++ return NULL; ++ attr = attrs->ial_data[0]; ++ ++ tmpl = isns_object_template_find(attr->ia_tag_id); ++ if (tmpl == NULL) ++ return NULL; ++ ++ /* ++ * 5.6.4. ++ * ++ * Some objects are keyed by more than one object key attribute ++ * value. For example, the Portal object is keyed by attribute ++ * tags 16 and 17. When describing an object keyed by more than one ++ * key attribute, every object key attribute of that object MUST be ++ * listed sequentially by tag value in the message before non-key ++ * attributes of that object and key attributes of the next object. ++ * A group of key attributes of this kind is treated as a single ++ * logical key attribute when identifying an object. ++ */ ++ for (i = 1; i < tmpl->iot_num_keys; ++i) { ++ attr = attrs->ial_data[i]; ++ ++ if (attr->ia_tag_id != tmpl->iot_keys[i]) ++ return NULL; ++ } ++ ++ return tmpl; ++} ++ ++isns_object_template_t * ++isns_object_template_for_tag(uint32_t tag) ++{ ++ isns_object_template_t *tmpl; ++ unsigned int i, j; ++ ++ isns_object_maps_init(); ++ if (tag < MAX_QUICK_TAG) ++ return isns_object_template_any_map[tag]; ++ ++ for (i = 0; (tmpl = isns_object_templates[i]) != NULL; ++i) { ++ for (j = 0; j < tmpl->iot_num_attrs; ++j) { ++ if (tmpl->iot_attrs[j] == tag) ++ return tmpl; ++ } ++ } ++ ++ return NULL; ++} ++ ++isns_object_template_t * ++isns_object_template_for_index_tag(uint32_t tag) ++{ ++ isns_object_maps_init(); ++ if (tag >= MAX_QUICK_TAG) ++ return NULL; ++ ++ return isns_object_template_idx_map[tag]; ++} ++ ++isns_object_template_t * ++isns_object_template_by_name(const char *name) ++{ ++ isns_object_template_t **pp, *tmpl; ++ ++ pp = isns_object_templates; ++ while ((tmpl = *pp++) != NULL) { ++ if (!strcasecmp(tmpl->iot_name, name)) ++ return tmpl; ++ } ++ return NULL; ++} ++ ++const char * ++isns_object_template_name(isns_object_template_t *tmpl) ++{ ++ if (!tmpl) ++ return NULL; ++ return tmpl->iot_name; ++} ++ ++/* ++ * Notify any listeners that the object has changed, ++ * and mark it dirty. ++ * dd_or_dds is used for DD_MEMBER_ADDED and ++ * DD_MEMBER_REMOVED events, and refers to the ++ * domain or domain set the object was added to or ++ * removed from. ++ */ ++void ++isns_mark_object(isns_object_t *obj, unsigned int how) ++{ ++ obj->ie_flags |= ISNS_OBJECT_DIRTY; ++ obj->ie_mtime = time(NULL); ++ obj->ie_scn_bits |= (1 << how); ++ isns_object_event(obj, 0, NULL); ++} ++ ++static void ++__isns_mark_object(isns_object_t *obj) ++{ ++ obj->ie_flags |= ISNS_OBJECT_DIRTY; ++ obj->ie_mtime = time(NULL); ++} ++ ++/* ++ * Create an object given its object template ++ */ ++isns_object_t * ++isns_create_object(isns_object_template_t *tmpl, ++ const isns_attr_list_t *attrs, ++ isns_object_t *parent) ++{ ++ isns_object_t *obj; ++ unsigned int i; ++ ++ /* Enforce containment rules. */ ++ if (parent) ++ isns_assert(tmpl->iot_container == parent->ie_template); ++ ++#ifdef notdef ++ /* This check is somewhat costly: */ ++ if (attrs && tmpl != isns_object_template_for_key_attrs(attrs)) ++ return NULL; ++#endif ++ ++ obj = isns_calloc(1, sizeof(*obj)); ++ ++ obj->ie_users = 1; ++ obj->ie_template = tmpl; ++ isns_attr_list_init(&obj->ie_attrs); ++ ++ if (parent) ++ isns_object_attach(obj, parent); ++ ++ if (attrs == NULL) { ++ /* Make sure that all key attrs are instantiated ++ * and in sequence. */ ++ for (i = 0; i < tmpl->iot_num_keys; ++i) ++ isns_attr_list_append_nil(&obj->ie_attrs, ++ tmpl->iot_keys[i]); ++ } else { ++ /* We rely on the caller to ensure that ++ * attributes are in proper sequence. */ ++ isns_attr_list_copy(&obj->ie_attrs, attrs); ++ } ++ ++ /* Just mark it dirty, but do not schedule a ++ * SCN event. */ ++ __isns_mark_object(obj); ++ ++ return obj; ++} ++ ++/* ++ * Obtain an additional reference on the object ++ */ ++isns_object_t * ++isns_object_get(isns_object_t *obj) ++{ ++ if (obj) { ++ isns_assert(obj->ie_users); ++ obj->ie_users++; ++ } ++ return obj; ++} ++ ++/* ++ * Release a reference on the object ++ */ ++void ++isns_object_release(isns_object_t *obj) ++{ ++ unsigned int i; ++ isns_object_t *child; ++ ++ if (!obj) ++ return; ++ ++ isns_assert(obj->ie_users); ++ if (--(obj)->ie_users != 0) ++ return; ++ ++ /* Must not have any live references to it */ ++ isns_assert(obj->ie_references == 0); ++ ++ /* Must be detached from parent */ ++ isns_assert(obj->ie_container == NULL); ++ ++ /* Release all children. We explicitly clear ++ * ie_container because the destructor ++ * checks for this (in order to catch ++ * refcounting bugs) */ ++ for (i = 0; i < obj->ie_children.iol_count; ++i) { ++ child = obj->ie_children.iol_data[i]; ++ child->ie_container = NULL; ++ } ++ isns_object_list_destroy(&obj->ie_children); ++ ++ isns_attr_list_destroy(&obj->ie_attrs); ++ ++ isns_bitvector_free(obj->ie_membership); ++ isns_free(obj); ++} ++ ++/* ++ * Get the topmost container (ie Network Entity) ++ * for the given object ++ */ ++isns_object_t * ++isns_object_get_entity(isns_object_t *obj) ++{ ++ if (obj == NULL) ++ return NULL; ++ while (obj->ie_container) ++ obj = obj->ie_container; ++ if (!ISNS_IS_ENTITY(obj)) ++ return NULL; ++ return obj; ++} ++ ++int ++isns_object_contains(const isns_object_t *ancestor, ++ const isns_object_t *descendant) ++{ ++ while (descendant) { ++ if (descendant == ancestor) ++ return 1; ++ descendant = descendant->ie_container; ++ } ++ return 0; ++} ++ ++/* ++ * Get all children of the specified type ++ */ ++void ++isns_object_get_descendants(const isns_object_t *obj, ++ isns_object_template_t *tmpl, ++ isns_object_list_t *result) ++{ ++ isns_object_t *child; ++ unsigned int i; ++ ++ for (i = 0; i < obj->ie_children.iol_count; ++i) { ++ child = obj->ie_children.iol_data[i]; ++ if (!tmpl || child->ie_template == tmpl) ++ isns_object_list_append(result, child); ++ } ++} ++ ++/* ++ * Attach an object to a new container ++ */ ++int ++isns_object_attach(isns_object_t *obj, isns_object_t *parent) ++{ ++ isns_assert(obj->ie_container == NULL); ++ ++ if (parent) { ++ /* Copy the owner (ie source) from the parent ++ * object. ++ * Make sure the parent object type is a valid ++ * container for this object. ++ */ ++ if (parent->ie_template != obj->ie_template->iot_container) { ++ isns_error("You are not allowed to add a %s object " ++ "to a %s!\n", ++ obj->ie_template->iot_name, ++ parent->ie_template->iot_name); ++ return 0; ++ } ++ obj->ie_flags = parent->ie_flags & ISNS_OBJECT_PRIVATE; ++ isns_object_list_append(&parent->ie_children, obj); ++ } ++ obj->ie_container = parent; ++ return 1; ++} ++ ++int ++isns_object_is_valid_container(const isns_object_t *container, ++ isns_object_template_t *child_type) ++{ ++ return child_type->iot_container == container->ie_template; ++} ++ ++/* ++ * Detach an object from its container ++ */ ++int ++isns_object_detach(isns_object_t *obj) ++{ ++ isns_object_t *parent; ++ ++ /* Detach from parent */ ++ if ((parent = obj->ie_container) != NULL) { ++ int removed; ++ ++ obj->ie_container = NULL; ++ removed = isns_object_list_remove( ++ &parent->ie_children, obj); ++ ++ isns_assert(removed != 0); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Check the type of an object ++ */ ++int ++isns_object_is(const isns_object_t *obj, ++ isns_object_template_t *tmpl) ++{ ++ return obj->ie_template == tmpl; ++} ++ ++int ++isns_object_is_iscsi_node(const isns_object_t *obj) ++{ ++ return ISNS_IS_ISCSI_NODE(obj); ++} ++ ++int ++isns_object_is_fc_port(const isns_object_t *obj) ++{ ++ return ISNS_IS_FC_PORT(obj); ++} ++ ++int ++isns_object_is_fc_node(const isns_object_t *obj) ++{ ++ return ISNS_IS_FC_NODE(obj); ++} ++ ++int ++isns_object_is_portal(const isns_object_t *obj) ++{ ++ return ISNS_IS_PORTAL(obj); ++} ++ ++int ++isns_object_is_pg(const isns_object_t *obj) ++{ ++ return ISNS_IS_PG(obj); ++} ++ ++int ++isns_object_is_policy(const isns_object_t *obj) ++{ ++ return ISNS_IS_POLICY(obj); ++} ++ ++/* ++ * Match an object against a list of attributes. ++ */ ++int ++isns_object_match(const isns_object_t *obj, ++ const isns_attr_list_t *attrs) ++{ ++ isns_object_template_t *tmpl = obj->ie_template; ++ isns_attr_t *self, *match; ++ unsigned int i, j, from = 0; ++ uint32_t tag; ++ ++ /* Fast path: try to compare in-order */ ++ while (from < attrs->ial_count) { ++ match = attrs->ial_data[from]; ++ self = obj->ie_attrs.ial_data[from]; ++ ++ if (match->ia_tag_id != self->ia_tag_id) ++ goto slow_path; ++ ++ if (!isns_attr_match(self, match)) ++ return 0; ++ ++ from++; ++ } ++ ++ return 1; ++ ++slow_path: ++ for (i = from; i < attrs->ial_count; ++i) { ++ isns_attr_t *found = NULL; ++ ++ match = attrs->ial_data[i]; ++ ++ /* ++ * 5.6.5.2 ++ * A Message Key with zero-length TLV(s) is scoped to ++ * every object of the type indicated by the zero-length ++ * TLV(s) ++ */ ++ if (match->ia_value.iv_type == &isns_attr_type_nil) { ++ tag = match->ia_tag_id; ++ if (isns_object_attr_valid(tmpl, tag)) ++ continue; ++ return 0; ++ } ++ ++ for (j = from; j < obj->ie_attrs.ial_count; ++j) { ++ self = obj->ie_attrs.ial_data[j]; ++ ++ if (match->ia_tag_id == self->ia_tag_id) { ++ found = self; ++ break; ++ } ++ } ++ ++ if (found == NULL) ++ return 0; ++ ++ if (!isns_attr_match(self, match)) ++ return 0; ++ } ++ return 1; ++} ++ ++/* ++ * Find descendant object matching the given key ++ */ ++isns_object_t * ++isns_object_find_descendant(isns_object_t *obj, const isns_attr_list_t *keys) ++{ ++ isns_object_list_t list = ISNS_OBJECT_LIST_INIT; ++ isns_object_t *found; ++ ++ if (!isns_object_find_descendants(obj, NULL, keys, &list)) ++ return NULL; ++ ++ found = isns_object_get(list.iol_data[0]); ++ isns_object_list_destroy(&list); ++ ++ return found; ++} ++ ++int ++isns_object_find_descendants(isns_object_t *obj, ++ isns_object_template_t *tmpl, ++ const isns_attr_list_t *keys, ++ isns_object_list_t *result) ++{ ++ isns_object_t *child; ++ unsigned int i; ++ ++ if ((tmpl == NULL || tmpl == obj->ie_template) ++ && (keys == NULL || isns_object_match(obj, keys))) ++ isns_object_list_append(result, obj); ++ ++ for (i = 0; i < obj->ie_children.iol_count; ++i) { ++ child = obj->ie_children.iol_data[i]; ++ isns_object_find_descendants(child, tmpl, keys, result); ++ } ++ ++ return result->iol_count; ++} ++ ++/* ++ * Return the object's modification time stamp ++ */ ++time_t ++isns_object_last_modified(const isns_object_t *obj) ++{ ++ return obj->ie_mtime; ++} ++ ++/* ++ * Set the SCN bitmap ++ */ ++void ++isns_object_set_scn_mask(isns_object_t *obj, uint32_t bitmap) ++{ ++ obj->ie_scn_mask = bitmap; ++ __isns_mark_object(obj); ++} ++ ++/* ++ * Debugging utility: print the object ++ */ ++void ++isns_object_print(isns_object_t *obj, isns_print_fn_t *fn) ++{ ++ isns_attr_list_print(&obj->ie_attrs, fn); ++} ++ ++/* ++ * Return a string representing the object state ++ */ ++const char * ++isns_object_state_string(unsigned int state) ++{ ++ switch (state) { ++ case ISNS_OBJECT_STATE_LARVAL: ++ return "larval"; ++ case ISNS_OBJECT_STATE_MATURE: ++ return "mature"; ++ case ISNS_OBJECT_STATE_LIMBO: ++ return "limbo"; ++ case ISNS_OBJECT_STATE_DEAD: ++ return "dead"; ++ } ++ return "UNKNOWN"; ++} ++ ++/* ++ * This is needed when deregistering an object. ++ * Remove all attributes except the key and index attrs. ++ */ ++void ++isns_object_prune_attrs(isns_object_t *obj) ++{ ++ isns_object_template_t *tmpl = obj->ie_template; ++ uint32_t tags[16]; ++ unsigned int i; ++ ++ isns_assert(tmpl->iot_num_keys + 1 <= 16); ++ for (i = 0; i < tmpl->iot_num_keys; ++i) ++ tags[i] = tmpl->iot_keys[i]; ++ if (tmpl->iot_index) ++ tags[i++] = tmpl->iot_index; ++ isns_attr_list_prune(&obj->ie_attrs, tags, i); ++} ++ ++/* ++ * Convenience functions ++ */ ++ ++/* ++ * Create a portal object. ++ * For now, always assume TCP. ++ */ ++isns_object_t * ++isns_create_portal(const isns_portal_info_t *info, ++ isns_object_t *parent) ++{ ++ isns_object_t *obj; ++ ++ obj = isns_create_object(&isns_portal_template, NULL, parent); ++ isns_portal_to_object(info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ obj); ++ return obj; ++} ++ ++/* ++ * Extract all key attrs and place them ++ * in the attribute list. ++ */ ++int ++isns_object_extract_keys(const isns_object_t *obj, ++ isns_attr_list_t *list) ++{ ++ isns_object_template_t *tmpl = obj->ie_template; ++ const isns_attr_list_t *src = &obj->ie_attrs; ++ unsigned int i; ++ ++ for (i = 0; i < tmpl->iot_num_keys; ++i) { ++ isns_attr_t *attr; ++ ++ if (!isns_attr_list_get_attr(src, tmpl->iot_keys[i], &attr)) ++ return 0; ++ isns_attr_list_append_attr(list, attr); ++ } ++ ++ return 1; ++} ++ ++/* ++ * Extract all attributes we are permitted to overwrite and place them ++ * in the attribute list. ++ */ ++int ++isns_object_extract_writable(const isns_object_t *obj, ++ isns_attr_list_t *list) ++{ ++ const isns_attr_list_t *src = &obj->ie_attrs; ++ unsigned int i; ++ ++ for (i = 0; i < src->ial_count; ++i) { ++ isns_attr_t *attr = src->ial_data[i]; ++ ++ if (attr->ia_tag->it_readonly) ++ continue; ++ isns_attr_list_append_attr(list, attr); ++ } ++ ++ return 1; ++} ++ ++/* ++ * Extract all attrs and place them ++ * in the attribute list. We copy the attributes ++ * as they appear inside the object; which allows ++ * duplicate attributes (eg inside a discovery domain). ++ */ ++int ++isns_object_extract_all(const isns_object_t *obj, isns_attr_list_t *list) ++{ ++ isns_attr_list_append_list(list, &obj->ie_attrs); ++ return 1; ++} ++ ++/* ++ * Check if the given object is valid ++ */ ++int ++isns_object_attr_valid(isns_object_template_t *tmpl, uint32_t tag) ++{ ++ const uint32_t *attr_tags = tmpl->iot_attrs; ++ unsigned int i; ++ ++ for (i = 0; i < tmpl->iot_num_attrs; ++i) { ++ if (*attr_tags == tag) ++ return 1; ++ ++attr_tags; ++ } ++ return 0; ++} ++ ++/* ++ * Set an object attribute ++ */ ++static int ++__isns_object_set_attr(isns_object_t *obj, uint32_t tag, ++ const isns_attr_type_t *type, ++ const isns_value_t *value) ++{ ++ const isns_tag_type_t *tag_type; ++ ++ if (!isns_object_attr_valid(obj->ie_template, tag)) ++ return 0; ++ ++ tag_type = isns_tag_type_by_id(tag); ++ if (type != &isns_attr_type_nil ++ && type != tag_type->it_type) { ++ isns_warning("application bug: cannot set attr %s(id=%u, " ++ "type=%s) to a value of type %s\n", ++ tag_type->it_name, tag, ++ tag_type->it_type->it_name, ++ type->it_name); ++ return 0; ++ } ++ ++ isns_attr_list_update_value(&obj->ie_attrs, ++ tag, tag_type, value); ++ ++ /* Timestamp updates should just be written out, but we ++ * do not want to trigger SCN messages and such. */ ++ if (tag != ISNS_TAG_TIMESTAMP) ++ isns_mark_object(obj, ISNS_SCN_OBJECT_UPDATED); ++ else ++ __isns_mark_object(obj); ++ return 1; ++} ++ ++/* ++ * Copy an attribute to the object ++ */ ++int ++isns_object_set_attr(isns_object_t *obj, isns_attr_t *attr) ++{ ++ isns_attr_list_t *list = &obj->ie_attrs; ++ uint32_t tag = attr->ia_tag_id; ++ ++ /* If this attribute exists within the object, ++ * and it cannot occur multiple times, replace it. */ ++ if (!attr->ia_tag->it_multiple ++ && isns_attr_list_replace_attr(list, attr)) ++ goto done; ++ ++ /* It doesn't exist; make sure it's a valid ++ * attribute. */ ++ if (!isns_object_attr_valid(obj->ie_template, tag)) ++ return 0; ++ ++ isns_attr_list_append_attr(list, attr); ++ ++done: ++ isns_mark_object(obj, ISNS_SCN_OBJECT_UPDATED); ++ return 1; ++} ++ ++int ++isns_object_set_attrlist(isns_object_t *obj, const isns_attr_list_t *attrs) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < attrs->ial_count; ++i) { ++ isns_attr_t *attr = attrs->ial_data[i]; ++ if (!isns_object_set_attr(obj, attr)) ++ return 0; ++ } ++ isns_mark_object(obj, ISNS_SCN_OBJECT_UPDATED); ++ return 1; ++} ++ ++/* ++ * Untyped version of isns_object_set. ++ * Any type checking must be done by the caller; ++ * failure to do so will result in the end of the world. ++ */ ++int ++isns_object_set_value(isns_object_t *obj, uint32_t tag, const void *data) ++{ ++ return isns_attr_list_update(&obj->ie_attrs, tag, data); ++} ++ ++/* ++ * Typed versions of isns_object_set ++ */ ++int ++isns_object_set_nil(isns_object_t *obj, uint32_t tag) ++{ ++ return __isns_object_set_attr(obj, tag, ++ &isns_attr_type_nil, NULL); ++} ++ ++int ++isns_object_set_string(isns_object_t *obj, uint32_t tag, ++ const char *value) ++{ ++ isns_value_t var = ISNS_VALUE_INIT(string, (char *) value); ++ int rc; ++ ++ rc = __isns_object_set_attr(obj, tag, ++ &isns_attr_type_string, &var); ++ return rc; ++} ++ ++int ++isns_object_set_uint32(isns_object_t *obj, uint32_t tag, ++ uint32_t value) ++{ ++ isns_value_t var = ISNS_VALUE_INIT(uint32, value); ++ ++ return __isns_object_set_attr(obj, tag, ++ &isns_attr_type_uint32, &var); ++} ++ ++int ++isns_object_set_uint64(isns_object_t *obj, ++ uint32_t tag, ++ uint64_t value) ++{ ++ isns_value_t var = ISNS_VALUE_INIT(uint64, value); ++ ++ return __isns_object_set_attr(obj, tag, ++ &isns_attr_type_uint64, &var); ++} ++ ++int ++isns_object_set_ipaddr(isns_object_t *obj, uint32_t tag, ++ const struct in6_addr *value) ++{ ++ isns_value_t var = ISNS_VALUE_INIT(ipaddr, *value); ++ ++ return __isns_object_set_attr(obj, tag, ++ &isns_attr_type_ipaddr, &var); ++} ++ ++/* ++ * Query object attributes ++ */ ++int ++isns_object_get_attr(const isns_object_t *obj, uint32_t tag, ++ isns_attr_t **result) ++{ ++ return isns_attr_list_get_attr(&obj->ie_attrs, tag, result); ++} ++ ++int ++isns_object_get_attrlist(isns_object_t *obj, ++ isns_attr_list_t *result, ++ const isns_attr_list_t *req_attrs) ++{ ++ isns_attr_list_t *attrs = &obj->ie_attrs; ++ isns_attr_t *attr; ++ unsigned int i; ++ ++ if (req_attrs == NULL) { ++ /* Retrieve all attributes */ ++ isns_attr_list_append_list(result, attrs); ++ } else { ++ for (i = 0; i < req_attrs->ial_count; ++i) { ++ uint32_t tag = req_attrs->ial_data[i]->ia_tag_id; ++ ++ if (tag == obj->ie_template->iot_next_index) { ++ /* FIXME: for now, we fake this value. ++ * We need the DB object at this point ++ * to find out what the next unused ++ * index is. ++ */ ++ isns_attr_list_append_uint32(result, ++ tag, 0); ++ } else ++ if (isns_attr_list_get_attr(attrs, tag, &attr)) ++ isns_attr_list_append_attr(result, attr); ++ } ++ } ++ return 1; ++} ++ ++int ++isns_object_get_key_attrs(isns_object_t *obj, ++ isns_attr_list_t *result) ++{ ++ isns_object_template_t *tmpl = obj->ie_template; ++ isns_attr_list_t *attrs = &obj->ie_attrs; ++ isns_attr_t *attr; ++ unsigned int i; ++ ++ for (i = 0; i < tmpl->iot_num_keys; ++i) { ++ uint32_t tag = tmpl->iot_keys[i]; ++ ++ if (!isns_attr_list_get_attr(attrs, tag, &attr)) { ++ isns_error("%s: %s object is missing key attr %u\n", ++ __FUNCTION__, ++ tmpl->iot_name, ++ tag); ++ return 0; ++ } ++ isns_attr_list_append_attr(result, attr); ++ } ++ return 1; ++} ++ ++int ++isns_object_get_string(const isns_object_t *obj, uint32_t tag, ++ const char **result) ++{ ++ isns_attr_t *attr; ++ ++ if (!isns_object_get_attr(obj, tag, &attr) ++ || !ISNS_ATTR_IS_STRING(attr)) ++ return 0; ++ ++ *result = attr->ia_value.iv_string; ++ return 1; ++} ++ ++int ++isns_object_get_ipaddr(const isns_object_t *obj, uint32_t tag, ++ struct in6_addr *result) ++{ ++ isns_attr_t *attr; ++ ++ if (!isns_object_get_attr(obj, tag, &attr) ++ || !ISNS_ATTR_IS_IPADDR(attr)) ++ return 0; ++ ++ *result = attr->ia_value.iv_ipaddr; ++ return 1; ++} ++ ++int ++isns_object_get_uint32(const isns_object_t *obj, uint32_t tag, ++ uint32_t *result) ++{ ++ isns_attr_t *attr; ++ ++ if (!isns_object_get_attr(obj, tag, &attr) ++ || !ISNS_ATTR_IS_UINT32(attr)) ++ return 0; ++ ++ *result = attr->ia_value.iv_uint32; ++ return 1; ++} ++ ++int ++isns_object_get_uint64(const isns_object_t *obj, uint32_t tag, ++ uint64_t *result) ++{ ++ isns_attr_t *attr; ++ ++ if (!isns_object_get_attr(obj, tag, &attr) ++ || !ISNS_ATTR_IS_UINT64(attr)) ++ return 0; ++ ++ *result = attr->ia_value.iv_uint64; ++ return 1; ++} ++ ++int ++isns_object_get_opaque(const isns_object_t *obj, uint32_t tag, ++ const void **ptr, size_t *len) ++{ ++ isns_attr_t *attr; ++ ++ if (!isns_object_get_attr(obj, tag, &attr) ++ || !ISNS_ATTR_IS_OPAQUE(attr)) ++ return 0; ++ ++ *ptr = attr->ia_value.iv_opaque.ptr; ++ *len = attr->ia_value.iv_opaque.len; ++ return 1; ++} ++ ++int ++isns_object_delete_attr(isns_object_t *obj, uint32_t tag) ++{ ++ return isns_attr_list_remove_tag(&obj->ie_attrs, tag); ++} ++ ++int ++isns_object_remove_member(isns_object_t *obj, ++ const isns_attr_t *attr, ++ const uint32_t *subordinate_tags) ++{ ++ return isns_attr_list_remove_member(&obj->ie_attrs, ++ attr, subordinate_tags); ++} ++ ++/* ++ * Object list functions ++ */ ++void ++isns_object_list_init(isns_object_list_t *list) ++{ ++ memset(list, 0, sizeof(*list)); ++} ++ ++static inline void ++__isns_object_list_resize(isns_object_list_t *list, unsigned int count) ++{ ++ unsigned int max; ++ ++ max = (list->iol_count + 15) & ~15; ++ if (count < max) ++ return; ++ ++ count = (count + 15) & ~15; ++ list->iol_data = isns_realloc(list->iol_data, count * sizeof(isns_object_t *)); ++ if (!list->iol_data) ++ isns_fatal("Out of memory!\n"); ++} ++ ++void ++isns_object_list_append(isns_object_list_t *list, isns_object_t *obj) ++{ ++ __isns_object_list_resize(list, list->iol_count + 1); ++ list->iol_data[list->iol_count++] = obj; ++ obj->ie_users++; ++} ++ ++void ++isns_object_list_append_list(isns_object_list_t *dst, ++ const isns_object_list_t *src) ++{ ++ unsigned int i, j; ++ ++ __isns_object_list_resize(dst, dst->iol_count + src->iol_count); ++ j = dst->iol_count; ++ for (i = 0; i < src->iol_count; ++i, ++j) { ++ isns_object_t *obj = src->iol_data[i]; ++ ++ dst->iol_data[j] = obj; ++ obj->ie_users++; ++ } ++ dst->iol_count = j; ++} ++ ++int ++isns_object_list_contains(const isns_object_list_t *list, ++ isns_object_t *obj) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ if (obj == list->iol_data[i]) ++ return 1; ++ } ++ return 0; ++} ++ ++isns_object_t * ++isns_object_list_lookup(const isns_object_list_t *list, ++ isns_object_template_t *tmpl, ++ const isns_attr_list_t *keys) ++{ ++ unsigned int i; ++ ++ if (!tmpl && !keys) ++ return NULL; ++ ++ if (!tmpl && !(tmpl = isns_object_template_for_key_attrs(keys))) ++ return NULL; ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ ++ if (obj->ie_template != tmpl) ++ continue; ++ if (keys && !isns_object_match(obj, keys)) ++ continue; ++ ++ obj->ie_users++; ++ return obj; ++ } ++ ++ return NULL; ++} ++ ++ ++int ++isns_object_list_gang_lookup(const isns_object_list_t *list, ++ isns_object_template_t *tmpl, ++ const isns_attr_list_t *keys, ++ isns_object_list_t *result) ++{ ++ unsigned int i; ++ ++ if (!tmpl && !keys) ++ return ISNS_INVALID_QUERY; ++ ++ if (!tmpl && !(tmpl = isns_object_template_for_key_attrs(keys))) ++ return ISNS_INVALID_QUERY; ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ ++ if (obj->ie_template != tmpl) ++ continue; ++ if (keys && !isns_object_match(obj, keys)) ++ continue; ++ ++ isns_object_list_append(result, obj); ++ } ++ ++ return ISNS_SUCCESS; ++} ++ ++ ++void ++isns_object_list_destroy(isns_object_list_t *list) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ ++ isns_object_release(obj); ++ } ++ ++ isns_free(list->iol_data); ++ memset(list, 0, sizeof(*list)); ++} ++ ++int ++isns_object_list_remove(isns_object_list_t *list, isns_object_t *tbr) ++{ ++ unsigned int i, last; ++ ++ last = list->iol_count - 1; ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ ++ if (obj == tbr) { ++ list->iol_data[i] = list->iol_data[last]; ++ list->iol_count--; ++ isns_object_release(tbr); ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static int ++isns_object_compare_id(const void *pa, const void *pb) ++{ ++ const isns_object_t *a = *(const isns_object_t **) pa; ++ const isns_object_t *b = *(const isns_object_t **) pb; ++ ++ return (int) a->ie_index - (int) b->ie_index; ++} ++ ++void ++isns_object_list_sort(isns_object_list_t *list) ++{ ++ if (list->iol_count == 0) ++ return; ++ ++ qsort(list->iol_data, list->iol_count, ++ sizeof(void *), isns_object_compare_id); ++} ++ ++void ++isns_object_list_uniq(isns_object_list_t *list) ++{ ++ isns_object_t *prev = NULL, *this; ++ unsigned int i, j; ++ ++ isns_object_list_sort(list); ++ for (i = j = 0; i < list->iol_count; i++) { ++ this = list->iol_data[i]; ++ if (this != prev) ++ list->iol_data[j++] = this; ++ prev = this; ++ } ++ list->iol_count = j; ++} ++ ++void ++isns_object_list_print(const isns_object_list_t *list, isns_print_fn_t *fn) ++{ ++ unsigned int i; ++ ++ if (list->iol_count == 0) { ++ fn("(Object list empty)\n"); ++ return; ++ } ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj; ++ ++ obj = list->iol_data[i]; ++ fn("object[%u] = <%s>\n", i, ++ obj->ie_template->iot_name); ++ isns_object_print(obj, fn); ++ } ++} ++ ++/* ++ * Handle object references ++ */ ++void ++isns_object_reference_set(isns_object_ref_t *ref, isns_object_t *obj) ++{ ++ isns_object_t *old; ++ ++ if (obj) { ++ isns_assert(obj->ie_users); ++ obj->ie_references++; ++ obj->ie_users++; ++ } ++ if ((old = ref->obj) != NULL) { ++ isns_assert(old->ie_references); ++ old->ie_references--; ++ isns_object_release(old); ++ } ++ ref->obj = obj; ++} ++ ++void ++isns_object_reference_drop(isns_object_ref_t *ref) ++{ ++ isns_object_reference_set(ref, NULL); ++} ++ ++/* ++ * Helper function for portal/object conversion ++ */ ++int ++isns_portal_from_object(isns_portal_info_t *portal, ++ uint32_t addr_tag, uint32_t port_tag, ++ const isns_object_t *obj) ++{ ++ return isns_portal_from_attr_list(portal, ++ addr_tag, port_tag, &obj->ie_attrs); ++} ++ ++int ++isns_portal_to_object(const isns_portal_info_t *portal, ++ uint32_t addr_tag, uint32_t port_tag, ++ isns_object_t *obj) ++{ ++ return isns_portal_to_attr_list(portal, ++ addr_tag, port_tag, ++ &obj->ie_attrs); ++} ++ ++/* ++ * Portal ++ */ ++static uint32_t portal_attrs[] = { ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ ISNS_TAG_PORTAL_SYMBOLIC_NAME, ++ ISNS_TAG_ESI_INTERVAL, ++ ISNS_TAG_ESI_PORT, ++ ISNS_TAG_PORTAL_INDEX, ++ ISNS_TAG_SCN_PORT, ++ ISNS_TAG_PORTAL_NEXT_INDEX, ++ ISNS_TAG_PORTAL_SECURITY_BITMAP, ++ ISNS_TAG_PORTAL_ISAKMP_PHASE_1, ++ ISNS_TAG_PORTAL_ISAKMP_PHASE_2, ++ ISNS_TAG_PORTAL_CERTIFICATE, ++}; ++ ++static uint32_t portal_key_attrs[] = { ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++}; ++ ++isns_object_template_t isns_portal_template = { ++ .iot_name = "Portal", ++ .iot_handle = ISNS_OBJECT_TYPE_PORTAL, ++ .iot_attrs = portal_attrs, ++ .iot_num_attrs = array_num_elements(portal_attrs), ++ .iot_keys = portal_key_attrs, ++ .iot_num_keys = array_num_elements(portal_key_attrs), ++ .iot_index = ISNS_TAG_PORTAL_INDEX, ++ .iot_next_index = ISNS_TAG_PORTAL_NEXT_INDEX, ++ .iot_container = &isns_entity_template, ++}; +diff --git a/utils/open-isns/objects.h b/utils/open-isns/objects.h +new file mode 100644 +index 0000000..8cc40c6 +--- /dev/null ++++ b/utils/open-isns/objects.h +@@ -0,0 +1,168 @@ ++/* ++ * iSNS object model ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#ifndef ISNS_OBJECTS_H ++#define ISNS_OBJECTS_H ++ ++#include "isns.h" ++#include "attrs.h" ++ ++enum isns_object_id { ++ ISNS_OBJECT_TYPE_ENTITY = 1, ++ ISNS_OBJECT_TYPE_NODE, ++ ISNS_OBJECT_TYPE_PORTAL, ++ ISNS_OBJECT_TYPE_PG, ++ ISNS_OBJECT_TYPE_DD, ++ ISNS_OBJECT_TYPE_DDSET, ++ ISNS_OBJECT_TYPE_POLICY, ++ ISNS_OBJECT_TYPE_FC_PORT, ++ ISNS_OBJECT_TYPE_FC_NODE, ++ ++ __ISNS_OBJECT_TYPE_MAX ++}; ++ ++ ++struct isns_object_template { ++ const char * iot_name; ++ unsigned int iot_handle; /* internal handle */ ++ unsigned int iot_num_attrs; ++ unsigned int iot_num_keys; ++ uint32_t * iot_attrs; ++ uint32_t * iot_keys; ++ uint32_t iot_index; ++ uint32_t iot_next_index; ++ ++ isns_object_template_t *iot_container; ++ ++ unsigned int iot_relation_type; ++ isns_relation_t * (*iot_build_relation)(isns_db_t *, ++ isns_object_t *, ++ const isns_object_list_t *); ++ ++ unsigned int iot_vendor_specific : 1; ++}; ++ ++struct isns_object { ++ /* There are two kinds of users of an object ++ * - Temporary references that result from the ++ * object being examined; being on a list, ++ * etc. The main purpose of these references ++ * is to make sure the object doesn't go away ++ * while being used. ++ * ++ * These are accounted for by ie_users. ++ * ++ * - Permanent references that result from the ++ * object being references by other objects ++ * (usually relations) such as a Portal Group, ++ * or a Discovery Domain. ++ * ++ * These are accounted for by ie_references. ++ * ++ * The main purpose of these references is to ++ * model some of the weirder life cycle states ++ * described in RFC 4711. ++ * ++ * Every reference via ie_references implies a ++ * reference via ie_users. ++ */ ++ unsigned int ie_users; ++ unsigned int ie_references; ++ ++ uint32_t ie_index; ++ ++ unsigned int ie_state; ++ unsigned int ie_flags; ++ time_t ie_mtime; ++ ++ uint32_t ie_scn_mask; /* Events this node listens for */ ++ uint32_t ie_scn_bits; /* Current event bits */ ++ ++ isns_attr_list_t ie_attrs; ++ isns_object_t * ie_container; ++ uint32_t ie_container_idx; ++ isns_object_template_t *ie_template; ++ ++ isns_relation_t * ie_relation; ++ isns_object_list_t ie_children; ++ ++ /* Bit vector describing DD membership */ ++ isns_bitvector_t * ie_membership; ++ ++ /* Support for virtual objects */ ++ int (*ie_rebuild)(isns_object_t *, isns_db_t *); ++}; ++ ++typedef struct isns_object_ref { ++ isns_object_t * obj; ++} isns_object_ref_t; ++ ++enum { ++ ISNS_RELATION_NONE = 0, ++ ISNS_RELATION_PORTAL_GROUP, ++}; ++ ++struct isns_relation { ++ unsigned int ir_type; ++ unsigned int ir_users; ++ isns_object_t * ir_object; ++ isns_object_ref_t ir_subordinate[2]; ++}; ++ ++typedef struct isns_relation_soup isns_relation_soup_t; ++ ++typedef struct isns_relation_list isns_relation_list_t; ++struct isns_relation_list { ++ unsigned int irl_count; ++ isns_relation_t ** irl_data; ++}; ++#define ISNS_RELATION_LIST_INIT { .irl_count = 0, .irl_data = NULL } ++ ++#define ISNS_OBJECT_DIRTY 0x0001 ++#define ISNS_OBJECT_PRIVATE 0x0002 ++#define ISNS_OBJECT_DEAD 0x0004 ++ ++enum { ++ ISNS_OBJECT_STATE_LARVAL, ++ ISNS_OBJECT_STATE_MATURE, ++ ISNS_OBJECT_STATE_LIMBO, ++ ISNS_OBJECT_STATE_DEAD, ++}; ++ ++extern int isns_object_remove_member(isns_object_t *obj, ++ const isns_attr_t *attr, ++ const uint32_t *subordinate_tags); ++ ++extern void isns_object_reference_set(isns_object_ref_t *ref, ++ isns_object_t *obj); ++extern void isns_object_reference_drop(isns_object_ref_t *ref); ++ ++extern const char *isns_object_state_string(unsigned int); ++ ++extern isns_object_template_t *isns_object_template_by_name(const char *); ++extern int isns_object_is_valid_container(const isns_object_t *, ++ isns_object_template_t *); ++ ++extern void isns_object_set_scn_mask(isns_object_t *, uint32_t); ++ ++extern isns_object_t *isns_create_default_domain(void); ++ ++/* ++ * Helper macros for object type check ++ */ ++#define __ISNS_OBJECT_TYPE_CHECK(obj, type) \ ++ ((obj)->ie_template == &isns_##type##_template) ++#define ISNS_IS_ENTITY(obj) __ISNS_OBJECT_TYPE_CHECK(obj, entity) ++#define ISNS_IS_ISCSI_NODE(obj) __ISNS_OBJECT_TYPE_CHECK(obj, iscsi_node) ++#define ISNS_IS_FC_PORT(obj) __ISNS_OBJECT_TYPE_CHECK(obj, fc_port) ++#define ISNS_IS_FC_NODE(obj) __ISNS_OBJECT_TYPE_CHECK(obj, fc_node) ++#define ISNS_IS_PORTAL(obj) __ISNS_OBJECT_TYPE_CHECK(obj, portal) ++#define ISNS_IS_PG(obj) __ISNS_OBJECT_TYPE_CHECK(obj, iscsi_pg) ++#define ISNS_IS_POLICY(obj) __ISNS_OBJECT_TYPE_CHECK(obj, policy) ++#define ISNS_IS_DD(obj) __ISNS_OBJECT_TYPE_CHECK(obj, dd) ++#define ISNS_IS_DDSET(obj) __ISNS_OBJECT_TYPE_CHECK(obj, ddset) ++ ++#endif /* ISNS_OBJECTS_H */ +diff --git a/utils/open-isns/parser.c b/utils/open-isns/parser.c +new file mode 100644 +index 0000000..378f2c8 +--- /dev/null ++++ b/utils/open-isns/parser.c +@@ -0,0 +1,134 @@ ++/* ++ * parser.c - simple line based parser ++ * ++ * Copyright (C) 2006, 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "util.h" ++ ++/* ++ * By default, the parser will recognize any white space ++ * as "word" separators. ++ * If you need additional separators, you can put them ++ * here. ++ */ ++const char * parser_separators = NULL; ++const char * parser_punctuation = "="; ++ ++char * ++parser_get_next_line(FILE *fp) ++{ ++ static char buffer[8192]; ++ unsigned int n = 0, count = 0; ++ int c, continuation = 0; ++ ++ while (n < sizeof(buffer) - 1) { ++ c = fgetc(fp); ++ if (c == EOF) ++ break; ++ ++ count++; ++ if (c == '\r') ++ continue; ++ /* Discard all blanks ++ * following a backslash-newline ++ */ ++ if (continuation) { ++ if (c == ' ' || c == '\t') ++ continue; ++ continuation = 0; ++ } ++ ++ if (c == '\n') { ++ if (n && buffer[n-1] == '\\') { ++ buffer[--n] = '\0'; ++ continuation = 1; ++ } ++ while (n && isspace(buffer[n-1])) ++ buffer[--n] = '\0'; ++ if (!continuation) ++ break; ++ buffer[n++] = ' '; ++ continue; ++ } ++ ++ buffer[n++] = c; ++ } ++ ++ if (count == 0) ++ return NULL; ++ ++ buffer[n] = '\0'; ++ return buffer; ++} ++ ++static inline int ++is_separator(char c) ++{ ++ if (isspace(c)) ++ return 1; ++ return parser_separators && c && strchr(parser_separators, c); ++} ++ ++static inline int ++is_punctuation(char c) ++{ ++ return parser_punctuation && c && strchr(parser_punctuation, c); ++} ++ ++char * ++parser_get_next_word(char **sp) ++{ ++ static char buffer[512]; ++ char *s = *sp, *p = buffer; ++ ++ while (is_separator(*s)) ++ ++s; ++ ++ if (*s == '\0') ++ goto done; ++ ++ if (is_punctuation(*s)) { ++ *p++ = *s++; ++ goto done; ++ } ++ ++ while (*s && !is_separator(*s) && !is_punctuation(*s)) ++ *p++ = *s++; ++ ++done: ++ *p++ = '\0'; ++ *sp = s; ++ return buffer[0]? buffer : NULL; ++} ++ ++int ++parser_split_line(char *line, unsigned int argsmax, char **argv) ++{ ++ unsigned int argc = 0; ++ char *s; ++ ++ while (argc < argsmax && (s = parser_get_next_word(&line))) ++ argv[argc++] = strdup(s); ++ return argc; ++} ++ ++char * ++parser_get_rest_of_line(char **sp) ++{ ++ char *s = *sp, *res = NULL; ++ ++ while (is_separator(*s)) ++ ++s; ++ ++ *sp = ""; ++ if (*s != '\0') ++ res = s; ++ return res; ++} +diff --git a/utils/open-isns/paths.h b/utils/open-isns/paths.h +new file mode 100644 +index 0000000..b54612c +--- /dev/null ++++ b/utils/open-isns/paths.h +@@ -0,0 +1,22 @@ ++/* ++ * Compile time configuration. ++ * For now, let's keep it simple and ignore autoconf... ++ * ++ * Copyright (C) 2006, 2007 Olaf Kirch ++ */ ++ ++#ifndef ISNS_CONFIG_H ++#define ISNS_CONFIG_H ++ ++#define __OPENISNS_MKVERSION(maj, min) (((maj) << 8) + (min)) ++#define OPENISNS_VERSION __OPENISNS_MKVERSION(0, 90); ++#define OPENISNS_VERSION_STRING "0.90" ++ ++#define ISNS_ETCDIR "/etc/isns" ++#define ISNS_RUNDIR "/var/run" ++#define ISNS_DEFAULT_ISNSD_CONFIG ISNS_ETCDIR "/isnsd.conf" ++#define ISNS_DEFAULT_ISNSDD_CONFIG ISNS_ETCDIR "/isnsdd.conf" ++#define ISNS_DEFAULT_ISNSADM_CONFIG ISNS_ETCDIR "/isnsadm.conf" ++#define ISNS_DEFAULT_LOCAL_REGISTRY ISNS_RUNDIR "/isns.registry" ++ ++#endif /* ISNS_CONFIG_H */ +diff --git a/utils/open-isns/pidfile.c b/utils/open-isns/pidfile.c +new file mode 100644 +index 0000000..3384373 +--- /dev/null ++++ b/utils/open-isns/pidfile.c +@@ -0,0 +1,98 @@ ++/* ++ * write pidfile ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "util.h" ++ ++static void ++__update_pidfile(int fd) ++{ ++ char pidbuf[32]; ++ ++ snprintf(pidbuf, sizeof(pidbuf), "%u\n", getpid()); ++ if (write(fd, pidbuf, strlen(pidbuf)) < 0) ++ isns_fatal("Error writing pid file: %m\n"); ++ close(fd); ++} ++ ++static pid_t ++__read_pidfile(const char *filename) ++{ ++ char pidbuf[32]; ++ FILE *fp; ++ pid_t pid = -1; ++ ++ fp = fopen(filename, "r"); ++ if (fp != NULL) { ++ if (fgets(pidbuf, sizeof(pidbuf), fp)) ++ pid = strtoul(pidbuf, NULL, 0); ++ fclose(fp); ++ } ++ return pid; ++} ++ ++void ++isns_write_pidfile(const char *filename) ++{ ++ int fd; ++ pid_t pid; ++ ++ fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, 0644); ++ if (fd >= 0) { ++ __update_pidfile(fd); ++ return; ++ } ++ ++ if (errno != EEXIST) ++ isns_fatal("Error creating pid file %s: %m\n", ++ filename); ++ ++ /* If the pid file is stale, remove it. ++ * Not really needed in real life, but ++ * highly convenient for debugging :) */ ++ if ((pid = __read_pidfile(filename)) > 0 ++ && kill(pid, 0) < 0 ++ && errno == ESRCH) { ++ isns_debug_general( ++ "Removing stale PID file %s\n", ++ filename); ++ unlink(filename); ++ } ++ ++ /* Try again */ ++ fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, 0644); ++ if (fd < 0) ++ isns_fatal("PID file exists; another daemon " ++ "seems to be running\n"); ++ ++ __update_pidfile(fd); ++} ++ ++void ++isns_update_pidfile(const char *filename) ++{ ++ int fd; ++ ++ fd = open(filename, O_WRONLY); ++ if (fd < 0) { ++ isns_fatal("Error opening pid file %s: %m\n", ++ filename); ++ } ++ ++ __update_pidfile(fd); ++} ++ ++void ++isns_remove_pidfile(const char *filename) ++{ ++ unlink(filename); ++} +diff --git a/utils/open-isns/pki.c b/utils/open-isns/pki.c +new file mode 100644 +index 0000000..f3af922 +--- /dev/null ++++ b/utils/open-isns/pki.c +@@ -0,0 +1,536 @@ ++/* ++ * PKI related functions ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "isns.h" ++#include "security.h" ++#include "util.h" ++#include "config.h" ++ ++#ifdef WITH_SECURITY ++ ++/* versions prior to 9.6.8 didn't seem to have these */ ++#if OPADDRCONFIGENSSL_VERSION_NUMBER < 0x00906080L ++# define EVP_MD_CTX_init(c) do { } while (0) ++# define EVP_MD_CTX_cleanup(c) do { } while (0) ++#endif ++#if OPADDRCONFIGENSSL_VERSION_NUMBER < 0x00906070L ++# define i2d_DSA_PUBKEY i2d_DSA_PUBKEY_backwards ++ ++static int i2d_DSA_PUBKEY_backwards(DSA *, unsigned char **); ++#endif ++ ++static int isns_openssl_init = 0; ++ ++static int isns_dsasig_verify(isns_security_t *ctx, ++ isns_principal_t *peer, ++ buf_t *pdu, ++ const struct isns_authblk *); ++static int isns_dsasig_sign(isns_security_t *ctx, ++ isns_principal_t *peer, ++ buf_t *pdu, ++ struct isns_authblk *); ++static EVP_PKEY *isns_dsasig_load_private_pem(isns_security_t *ctx, ++ const char *filename); ++static EVP_PKEY *isns_dsasig_load_public_pem(isns_security_t *ctx, ++ const char *filename); ++static DSA * isns_dsa_load_params(const char *); ++ ++ ++/* ++ * Create a DSA security context ++ */ ++isns_security_t * ++isns_create_dsa_context(void) ++{ ++ isns_security_t *ctx; ++ ++ if (!isns_openssl_init) { ++ ERR_load_crypto_strings(); ++ OpenSSL_add_all_algorithms(); ++ OpenSSL_add_all_ciphers(); ++ OpenSSL_add_all_digests(); ++ isns_openssl_init = 1; ++ } ++ ++ ctx = isns_calloc(1, sizeof(*ctx)); ++ ++ ctx->is_name = "DSA"; ++ ctx->is_type = ISNS_AUTH_TYPE_SHA1_DSA; ++ ctx->is_replay_window = isns_config.ic_auth.replay_window; ++ ctx->is_timestamp_jitter = isns_config.ic_auth.timestamp_jitter; ++ ++ ctx->is_verify = isns_dsasig_verify; ++ ctx->is_sign = isns_dsasig_sign; ++ ctx->is_load_private = isns_dsasig_load_private_pem; ++ ctx->is_load_public = isns_dsasig_load_public_pem; ++ ++ isns_debug_auth("Created DSA authentication context\n"); ++ return ctx; ++} ++ ++/* ++ * DSA signature generation and verification ++ */ ++static void ++isns_message_digest(EVP_MD_CTX *md, const buf_t *pdu, ++ const struct isns_authblk *blk) ++{ ++ uint64_t stamp; ++ ++ EVP_DigestUpdate(md, buf_head(pdu), buf_avail(pdu)); ++ ++ /* The RFC doesn't say which pieces of the ++ * message should be hashed. ++ * We make an educated guess. ++ */ ++ stamp = htonll(blk->iab_timestamp); ++ EVP_DigestUpdate(md, &stamp, sizeof(stamp)); ++} ++ ++static void ++isns_dsasig_report_errors(const char *msg, isns_print_fn_t *fn) ++{ ++ unsigned long code; ++ ++ fn("%s - OpenSSL errors follow:\n", msg); ++ while ((code = ERR_get_error()) != 0) ++ fn("> %s: %s\n", ++ ERR_func_error_string(code), ++ ERR_reason_error_string(code)); ++} ++ ++int ++isns_dsasig_sign(isns_security_t *ctx, ++ isns_principal_t *peer, ++ buf_t *pdu, ++ struct isns_authblk *blk) ++{ ++ static unsigned char signature[1024]; ++ unsigned int sig_len = sizeof(signature); ++ EVP_MD_CTX md_ctx; ++ EVP_PKEY *pkey; ++ int err; ++ ++ if ((pkey = peer->is_key) == NULL) ++ return 0; ++ ++ if (pkey->type != EVP_PKEY_DSA) { ++ isns_debug_message( ++ "Incompatible public key (spi=%s)\n", ++ peer->is_name); ++ return 0; ++ } ++ if (EVP_PKEY_size(pkey) > sizeof(signature)) { ++ isns_error("isns_dsasig_sign: signature buffer too small\n"); ++ return 0; ++ } ++ if (pkey->pkey.dsa->priv_key == NULL) { ++ isns_error("isns_dsasig_sign: oops, seems to be a public key\n"); ++ return 0; ++ } ++ ++ isns_debug_auth("Signing messages with spi=%s, DSA/%u\n", ++ peer->is_name, EVP_PKEY_bits(pkey)); ++ ++ EVP_MD_CTX_init(&md_ctx); ++ EVP_SignInit(&md_ctx, EVP_dss1()); ++ isns_message_digest(&md_ctx, pdu, blk); ++ err = EVP_SignFinal(&md_ctx, ++ signature, &sig_len, ++ pkey); ++ EVP_MD_CTX_cleanup(&md_ctx); ++ ++ if (err == 0) { ++ isns_dsasig_report_errors("EVP_SignFinal failed", isns_error); ++ return 0; ++ } ++ ++ blk->iab_sig = signature; ++ blk->iab_sig_len = sig_len; ++ return 1; ++} ++ ++int ++isns_dsasig_verify(isns_security_t *ctx, ++ isns_principal_t *peer, ++ buf_t *pdu, ++ const struct isns_authblk *blk) ++{ ++ EVP_MD_CTX md_ctx; ++ EVP_PKEY *pkey; ++ int err; ++ ++ if ((pkey = peer->is_key) == NULL) ++ return 0; ++ ++ if (pkey->type != EVP_PKEY_DSA) { ++ isns_debug_message( ++ "Incompatible public key (spi=%s)\n", ++ peer->is_name); ++ return 0; ++ } ++ ++ EVP_MD_CTX_init(&md_ctx); ++ EVP_VerifyInit(&md_ctx, EVP_dss1()); ++ isns_message_digest(&md_ctx, pdu, blk); ++ err = EVP_VerifyFinal(&md_ctx, ++ blk->iab_sig, blk->iab_sig_len, ++ pkey); ++ EVP_MD_CTX_cleanup(&md_ctx); ++ ++ if (err == 0) { ++ isns_debug_auth("*** Incorrect signature ***\n"); ++ return 0; ++ } ++ if (err < 0) { ++ isns_dsasig_report_errors("EVP_VerifyFinal failed", isns_error); ++ return 0; ++ } ++ ++ isns_debug_message("Good signature from %s\n", ++ peer->is_name?: ""); ++ return 1; ++} ++ ++EVP_PKEY * ++isns_dsasig_load_private_pem(isns_security_t *ctx, const char *filename) ++{ ++ EVP_PKEY *pkey; ++ FILE *fp; ++ ++ if (!(fp = fopen(filename, "r"))) { ++ isns_error("Unable to open DSA keyfile %s: %m\n", ++ filename); ++ return 0; ++ } ++ ++ pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL); ++ fclose(fp); ++ return pkey; ++} ++ ++EVP_PKEY * ++isns_dsasig_load_public_pem(isns_security_t *ctx, const char *filename) ++{ ++ EVP_PKEY *pkey; ++ FILE *fp; ++ ++ if (!(fp = fopen(filename, "r"))) { ++ isns_error("Unable to open DSA keyfile %s: %m\n", ++ filename); ++ return 0; ++ } ++ ++ pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL); ++ if (pkey == NULL) { ++ isns_dsasig_report_errors("Error loading DSA public key", ++ isns_error); ++ } ++ ++ fclose(fp); ++ return pkey; ++} ++ ++EVP_PKEY * ++isns_dsa_decode_public(const void *ptr, size_t len) ++{ ++ const unsigned char *der = ptr; ++ EVP_PKEY *evp; ++ DSA *dsa; ++ ++ /* Assigning ptr to a temporary variable avoids a silly ++ * compiled warning about type-punning. */ ++ dsa = d2i_DSA_PUBKEY(NULL, &der, len); ++ if (dsa == NULL) ++ return NULL; ++ ++ evp = EVP_PKEY_new(); ++ EVP_PKEY_assign_DSA(evp, dsa); ++ return evp; ++} ++ ++int ++isns_dsa_encode_public(EVP_PKEY *pkey, void **ptr, size_t *len) ++{ ++ int bytes; ++ ++ *ptr = NULL; ++ bytes = i2d_DSA_PUBKEY(pkey->pkey.dsa, (unsigned char **) ptr); ++ if (bytes < 0) ++ return 0; ++ ++ *len = bytes; ++ return 1; ++} ++ ++EVP_PKEY * ++isns_dsa_load_public(const char *name) ++{ ++ return isns_dsasig_load_public_pem(NULL, name); ++} ++ ++int ++isns_dsa_store_private(const char *name, EVP_PKEY *key) ++{ ++ FILE *fp; ++ int rv, fd; ++ ++ if ((fd = open(name, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) { ++ isns_error("Cannot save DSA key to %s: %m\n", name); ++ return 0; ++ } ++ ++ if (!(fp = fdopen(fd, "w"))) { ++ isns_error("fdopen(%s): %m\n", name); ++ close(fd); ++ return 0; ++ } ++ ++ rv = PEM_write_PrivateKey(fp, key, NULL, NULL, 0, 0, NULL); ++ fclose(fp); ++ ++ if (rv == 0) ++ isns_dsasig_report_errors("Failed to store private key", ++ isns_error); ++ ++ return rv; ++} ++ ++int ++isns_dsa_store_public(const char *name, EVP_PKEY *key) ++{ ++ FILE *fp; ++ int rv; ++ ++ if (!(fp = fopen(name, "w"))) { ++ isns_error("Unable to open %s: %m\n", name); ++ return 0; ++ } ++ ++ rv = PEM_write_PUBKEY(fp, key); ++ fclose(fp); ++ ++ if (rv == 0) ++ isns_dsasig_report_errors("Failed to store public key", ++ isns_error); ++ ++ return rv; ++} ++ ++ ++/* ++ * DSA key generation ++ */ ++EVP_PKEY * ++isns_dsa_generate_key(void) ++{ ++ EVP_PKEY *pkey; ++ DSA *dsa = NULL; ++ ++ if (!(dsa = isns_dsa_load_params(isns_config.ic_dsa.param_file))) ++ goto failed; ++ ++ if (!DSA_generate_key(dsa)) { ++ isns_dsasig_report_errors("Failed to generate DSA key", ++ isns_error); ++ goto failed; ++ } ++ ++ pkey = EVP_PKEY_new(); ++ EVP_PKEY_assign_DSA(pkey, dsa); ++ return pkey; ++ ++failed: ++ if (dsa) ++ DSA_free(dsa); ++ return NULL; ++} ++ ++DSA * ++isns_dsa_load_params(const char *filename) ++{ ++ FILE *fp; ++ DSA *dsa; ++ ++ if (!filename) { ++ isns_error("Cannot generate key - no DSA parameter file\n"); ++ return NULL; ++ } ++ if (!(fp = fopen(filename, "r"))) { ++ isns_error("Unable to open %s: %m\n", filename); ++ return NULL; ++ } ++ ++ dsa = PEM_read_DSAparams(fp, NULL, NULL, NULL); ++ fclose(fp); ++ ++ if (dsa == NULL) { ++ isns_dsasig_report_errors("Error loading DSA parameters", ++ isns_error); ++ } ++ ++ return dsa; ++} ++ ++static void ++isns_dsa_param_gen_callback(int stage, int index, void *dummy) ++{ ++ if (stage == 0) ++ write(1, "+", 1); ++ else if (stage == 1) ++ write(1, ".", 1); ++ else if (stage == 2) ++ write(1, "/", 1); ++} ++ ++int ++isns_dsa_init_params(const char *filename) ++{ ++ FILE *fp; ++ DSA *dsa; ++ ++ if (access(filename, R_OK) == 0) ++ return 1; ++ ++ isns_mkdir_recursive(isns_dirname(filename)); ++ if (!(fp = fopen(filename, "w"))) { ++ isns_error("Unable to open %s: %m\n", filename); ++ return 0; ++ } ++ ++ isns_notice("Generating DSA parameters; this may take a while\n"); ++ dsa = DSA_generate_parameters(1024, NULL, 0, ++ NULL, NULL, isns_dsa_param_gen_callback, NULL); ++ write(1, "\n", 1); ++ ++ if (dsa == NULL) { ++ isns_dsasig_report_errors("Error generating DSA parameters", ++ isns_error); ++ fclose(fp); ++ return 0; ++ } ++ ++ if (!PEM_write_DSAparams(fp, dsa)) { ++ isns_dsasig_report_errors("Error writing DSA parameters", ++ isns_error); ++ DSA_free(dsa); ++ fclose(fp); ++ return 0; ++ } ++ DSA_free(dsa); ++ fclose(fp); ++ return 1; ++} ++ ++/* ++ * Make sure the authentication key is present. ++ */ ++int ++isns_dsa_init_key(const char *filename) ++{ ++ char pubkey_path[1024]; ++ EVP_PKEY *pkey; ++ ++ isns_mkdir_recursive(isns_dirname(filename)); ++ snprintf(pubkey_path, sizeof(pubkey_path), ++ "%s.pub", filename); ++ if (access(filename, R_OK) == 0 ++ && access(pubkey_path, R_OK) == 0) ++ return 1; ++ ++ if (!(pkey = isns_dsa_generate_key())) { ++ isns_error("Failed to generate AuthKey\n"); ++ return 0; ++ } ++ ++ if (!isns_dsa_store_private(filename, pkey)) { ++ isns_error("Unable to write private key to %s\n", filename); ++ return 0; ++ } ++ isns_notice("Stored private key in %s\n", filename); ++ ++ if (!isns_dsa_store_public(pubkey_path, pkey)) { ++ isns_error("Unable to write public key to %s\n", pubkey_path); ++ return 0; ++ } ++ isns_notice("Stored private key in %s\n", pubkey_path); ++ ++ return 1; ++} ++ ++/* ++ * Simple keystore - this is a flat directory, with ++ * public key files using the SPI as their name. ++ */ ++typedef struct isns_simple_keystore isns_simple_keystore_t; ++struct isns_simple_keystore { ++ isns_keystore_t sc_base; ++ char * sc_dirpath; ++}; ++ ++/* ++ * Load a DSA key from the cert store ++ * In fact, this will load RSA keys as well. ++ */ ++static EVP_PKEY * ++__isns_simple_keystore_find(isns_keystore_t *store_base, ++ const char *name, size_t namelen) ++{ ++ isns_simple_keystore_t *store = (isns_simple_keystore_t *) store_base; ++ char pathname[PATH_MAX]; ++ ++ /* Refuse to open key files with names ++ * that refer to parent directories */ ++ if (memchr(name, '/', namelen) || name[0] == '.') ++ return NULL; ++ ++ snprintf(pathname, sizeof(pathname), ++ "%s/%.*s", store->sc_dirpath, ++ (int) namelen, name); ++ if (access(pathname, R_OK) < 0) ++ return NULL; ++ return isns_dsasig_load_public_pem(NULL, pathname); ++} ++ ++isns_keystore_t * ++isns_create_simple_keystore(const char *dirname) ++{ ++ isns_simple_keystore_t *store; ++ ++ store = isns_calloc(1, sizeof(*store)); ++ store->sc_base.ic_name = "simple key store"; ++ store->sc_base.ic_find = __isns_simple_keystore_find; ++ store->sc_dirpath = isns_strdup(dirname); ++ ++ return (isns_keystore_t *) store; ++} ++ ++#if OPADDRCONFIGENSSL_VERSION_NUMBER < 0x00906070L ++#undef i2d_DSA_PUBKEY ++ ++int ++i2d_DSA_PUBKEY_backwards(DSA *dsa, unsigned char **ptr) ++{ ++ unsigned char *buf; ++ int len; ++ ++ len = i2d_DSA_PUBKEY(dsa, NULL); ++ if (len < 0) ++ return 0; ++ ++ *ptr = buf = OPENSSL_malloc(len); ++ return i2d_DSA_PUBKEY(dsa, &buf); ++} ++#endif ++ ++#endif /* WITH_SECURITY */ +diff --git a/utils/open-isns/policy.c b/utils/open-isns/policy.c +new file mode 100644 +index 0000000..46de15b +--- /dev/null ++++ b/utils/open-isns/policy.c +@@ -0,0 +1,577 @@ ++/* ++ * Open-iSNS policy engine ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ * ++ * For now, policy is static. We can make it configurable ++ * later. ++ */ ++ ++#include ++#include "isns.h" ++#include "security.h" ++#include "objects.h" ++#include "message.h" ++#include "util.h" ++ ++/* ++ A brief discussion of policy ++ ++ For now, a principal's name (ie its SPI string) *must* match ++ the iSNS source name it uses. ++ ++ Special care needs to be taken to restrict which principals ++ are permitted to act as a control node. For now, we don't ++ implement control node semantics. ++ ++ */ ++ ++static unsigned int isns_policy_gen = 0; ++ ++/* ++ * Administrative policy (everything allowed, ++ * talks to entity "CONTROL" ++ */ ++static isns_policy_t isns_superhero_powers = { ++ .ip_name = "administrator", ++ .ip_users = 1, ++ .ip_gen = 0, ++ ++ .ip_entity = ISNS_ENTITY_CONTROL, ++ .ip_functions = ~0, ++ .ip_object_types = ~0, ++ .ip_node_types = ~0, ++}; ++ ++/* ++ * Policy for anon user ++ */ ++static isns_policy_t isns_dweeb_powers = { ++ .ip_name = "anonymous", ++ .ip_users = 1, ++ .ip_gen = 0, ++ ++ .ip_functions = 1 << ISNS_DEVICE_ATTRIBUTE_QUERY, ++ .ip_object_types = 0, ++ .ip_node_types = 0, ++}; ++ ++#define IS_ANON_POLICY(p) ((p) == &isns_dweeb_powers) ++ ++/* ++ * These are used when security is turned off. ++ * Essentially the same as superhero, except ++ * no eid specified. ++ */ ++static isns_policy_t isns_flyingpigs_powers = { ++ .ip_name = "insecure", ++ .ip_users = 1, ++ .ip_gen = 0, ++ ++ .ip_functions = ~0, ++ .ip_object_types = ~0, ++ .ip_node_types = ~0, ++}; ++ ++ ++isns_policy_t * ++isns_policy_bind(const isns_message_t *msg) ++{ ++ isns_policy_t *policy = NULL; ++ isns_principal_t *princ = NULL; ++ ++ /* When the admin turns off gravity, ++ * pigs can fly, too. */ ++ if (isns_config.ic_security == 0) { ++ policy = &isns_flyingpigs_powers; ++ goto found; ++ } ++ ++ /* If the caller is the local root user, s/he can ++ * do anything. */ ++ if (msg->im_creds && msg->im_creds->uid == 0) { ++ policy = &isns_superhero_powers; ++ goto found; ++ } ++ ++ /* Tie the SPI given in the auth block to a ++ * source name. ++ * For now, the names have to match. Down the road, ++ * there may be more flexible schemes. ++ */ ++ if ((princ = msg->im_security) != NULL) { ++ if ((policy = princ->is_policy) != NULL) ++ goto found; ++ ++ isns_error("Internal error - no policy for " ++ "principal %s!\n", ++ princ->is_name); ++ } ++ ++ policy = &isns_dweeb_powers; ++ ++found: ++ policy->ip_users++; ++ return policy; ++} ++ ++/* ++ * Check whether the call is permitted. ++ * This is particularly useful to prevent rogue ++ * clients from messing with Discovery Domains. ++ */ ++int ++isns_policy_validate_function(const isns_policy_t *policy, ++ const isns_message_t *msg) ++{ ++ uint32_t function = msg->im_header.i_function; ++ int rv = 0; ++ ++ if (function >= 32) { ++ isns_debug_auth("Bad function code %08x\n", function); ++ return 0; ++ } ++ ++ if (!(policy->ip_functions & (1 << function))) ++ goto reject; ++ ++ rv = 1; ++ ++reject: ++ isns_debug_auth(":: policy %s function %s (%04x) %s\n", ++ policy->ip_name, ++ isns_function_name(function), function, ++ rv? "permitted" : "DENIED"); ++ return rv; ++} ++ ++/* ++ * Helper function to validate node names and source names ++ */ ++static int ++__validate_node_name(const isns_policy_t *policy, const char *name) ++{ ++ const struct string_array *ap; ++ unsigned int i; ++ ++ /* Control nodes get to do everything */ ++ if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK) ++ return 1; ++ ++ ap = &policy->ip_node_names; ++ for (i = 0; i < ap->count; ++i) { ++ const char *s; ++ ++ s = ap->list[i]; ++ if (s == NULL) ++ continue; ++ if (isns_source_pattern_match(s, name)) ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ * Validate the source of a message ++ */ ++int ++isns_policy_validate_source(const isns_policy_t *policy, ++ const isns_source_t *source) ++{ ++ const char *src_name = isns_source_name(source); ++ int rv = 0; ++ ++ if (!__validate_node_name(policy, src_name)) ++ goto reject; ++ ++ rv = 1; ++ ++reject: ++ isns_debug_auth(":: policy %s source %s %s\n", ++ policy->ip_name, src_name, ++ rv? "permitted" : "DENIED"); ++ return rv; ++} ++ ++/* ++ * Check whether the entity name specified by the client ++ * is actually his to use. ++ */ ++int ++isns_policy_validate_entity(const isns_policy_t *policy, ++ const char *eid) ++{ ++ int rv = 0, eidlen; ++ ++ /* Control nodes get to do everything */ ++ if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK) ++ goto accept; ++ ++ /* For anonymous clients, refuse any attempt to ++ * create an entity */ ++ if (IS_ANON_POLICY(policy)) ++ goto reject; ++ ++ /* If no entity is assigned, this means the client ++ * is not permitted to specify its own entity name, ++ * and accept what we assign it. ++ */ ++ if (policy->ip_entity == NULL) ++ goto reject; ++ ++ eidlen = strlen(policy->ip_entity); ++ if (strncasecmp(policy->ip_entity, eid, eidlen) ++ && (eid[eidlen] == ':' || eid[eidlen] == '\0')) ++ goto reject; ++ ++accept: rv = 1; ++ ++reject: ++ isns_debug_auth(":: policy %s entity ID %s %s\n", ++ policy->ip_name, eid, ++ rv? "permitted" : "DENIED"); ++ return rv; ++} ++ ++const char * ++isns_policy_default_entity(const isns_policy_t *policy) ++{ ++ return policy->ip_entity; ++} ++ ++int ++isns_policy_validate_node_name(const isns_policy_t *policy, ++ const char *node_name) ++{ ++ int rv = 0; ++ ++ /* Control nodes get to do everything */ ++ if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK) ++ goto accept; ++ ++ if (!__validate_node_name(policy, node_name)) ++ goto reject; ++ ++accept: rv = 1; ++reject: ++ isns_debug_auth(":: policy %s storage node name %s %s\n", ++ policy->ip_name, node_name, ++ rv? "permitted" : "DENIED"); ++ return rv; ++} ++ ++/* ++ * Check whether the client is allowed to access ++ * the given object in a particular way. ++ */ ++static int ++__isns_policy_validate_object_access(const isns_policy_t *policy, ++ const isns_source_t *source, ++ const isns_object_t *obj, ++ isns_object_template_t *tmpl, ++ unsigned int function) ++{ ++ uint32_t mask, perm = ISNS_PERMISSION_WRITE; ++ int rv = 0; ++ ++ /* Control nodes get to do everything */ ++ if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK) ++ goto accept; ++ ++ if (function == ISNS_DEVICE_ATTRIBUTE_QUERY ++ || function == ISNS_DEVICE_GET_NEXT) ++ perm = ISNS_PERMISSION_READ; ++ ++ /* ++ * 5.6.1. Source Attribute ++ * ++ * For messages that change the contents of the iSNS ++ * database, the iSNS server MUST verify that the Source ++ * Attribute identifies either a Control Node or a Storage ++ * Node that is a part of the Network Entity containing ++ * the added, deleted, or modified objects. ++ * ++ * Note: this statement makes sense for nodes, portals ++ * etc, but not for discovery domains, which are not ++ * part of any network entity (but the Control Node clause ++ * above still applies). ++ */ ++ if (perm == ISNS_PERMISSION_WRITE && obj != NULL) { ++ const isns_object_t *entity; ++ ++ entity = obj->ie_container; ++ if (entity && entity != source->is_entity) ++ goto refuse; ++ ++ /* You're not allowed to modify virtual objects */ ++ if (obj->ie_rebuild) ++ goto refuse; ++ } ++ ++ /* Check whether the client is permitted ++ to access such an object */ ++ mask = ISNS_ACCESS(tmpl->iot_handle, perm); ++ if (!(policy->ip_object_types & mask)) ++ goto refuse; ++ ++ if (source->is_untrusted && (obj->ie_flags & ISNS_OBJECT_PRIVATE)) ++ goto refuse; ++ ++accept: ++ rv = 1; ++ ++refuse: ++ if (obj) { ++ isns_debug_auth(":: policy %s operation %s on object %08x (%s) %s\n", ++ policy->ip_name, ++ isns_function_name(function), ++ obj->ie_index, ++ tmpl->iot_name, ++ rv? "permitted" : "DENIED"); ++ } else { ++ isns_debug_auth(":: policy %s operation %s on %s object %s\n", ++ policy->ip_name, ++ isns_function_name(function), ++ tmpl->iot_name, ++ rv? "permitted" : "DENIED"); ++ } ++ return rv; ++} ++ ++/* ++ * Check whether the client is allowed to access ++ * the given object. This is called for read functions. ++ */ ++int ++isns_policy_validate_object_access(const isns_policy_t *policy, ++ const isns_source_t *source, ++ const isns_object_t *obj, ++ unsigned int function) ++{ ++ return __isns_policy_validate_object_access(policy, source, ++ obj, obj->ie_template, ++ function); ++} ++ ++/* ++ * Check whether the client is allowed to update ++ * the given object. ++ */ ++int ++isns_policy_validate_object_update(const isns_policy_t *policy, ++ const isns_source_t *source, ++ const isns_object_t *obj, ++ const isns_attr_list_t *attrs, ++ unsigned int function) ++{ ++ return __isns_policy_validate_object_access(policy, source, ++ obj, obj->ie_template, ++ function); ++} ++ ++/* ++ * Check whether the client is allowed to create an object ++ * with the given attrs. ++ */ ++int ++isns_policy_validate_object_creation(const isns_policy_t *policy, ++ const isns_source_t *source, ++ isns_object_template_t *tmpl, ++ const isns_attr_list_t *keys, ++ const isns_attr_list_t *attrs, ++ unsigned int function) ++{ ++ const char *name = NULL; ++ ++ if (tmpl == &isns_entity_template) { ++ /* DevReg messages may contain an empty EID ++ * string, which means the server should select ++ * one. */ ++ if (isns_attr_list_get_string(keys, ++ ISNS_TAG_ENTITY_IDENTIFIER, &name) ++ && !isns_policy_validate_entity(policy, name)) ++ return 0; ++ } ++ ++ if (tmpl == &isns_iscsi_node_template) { ++ if (isns_attr_list_get_string(keys, ++ ISNS_TAG_ISCSI_NAME, &name) ++ && !isns_policy_validate_node_name(policy, name)) ++ return 0; ++ } ++ ++ /* Should we also include the permitted portals ++ * in the policy? */ ++ ++ return __isns_policy_validate_object_access(policy, source, ++ NULL, tmpl, function); ++} ++ ++/* ++ * Check whether the client is permitted to access ++ * or create an object of this type. ++ * FIXME: Pass R/W permission bit ++ */ ++int ++isns_policy_validate_object_type(const isns_policy_t *policy, ++ isns_object_template_t *tmpl, ++ unsigned int function) ++{ ++ uint32_t mask; ++ int rv = 0; ++ ++ /* Control nodes get to do everything */ ++ if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK) ++ goto accept; ++ ++ mask = ISNS_ACCESS_R(tmpl->iot_handle); ++ if (!(policy->ip_object_types & mask)) ++ goto reject; ++ ++accept: rv = 1; ++ ++reject: ++ isns_debug_auth(":: policy %s operation %s on object type %s %s\n", ++ policy->ip_name, ++ isns_function_name(function), ++ tmpl->iot_name, ++ rv? "permitted" : "DENIED"); ++ return rv; ++} ++ ++int ++isns_policy_validate_node_type(const isns_policy_t *policy, uint32_t type) ++{ ++ int rv = 0; ++ ++ if ((~policy->ip_node_types & type) == 0) ++ rv = 1; ++ ++ isns_debug_auth(":: policy %s registration of node type 0x%x %s\n", ++ policy->ip_name, type, ++ rv? "permitted" : "DENIED"); ++ return rv; ++} ++ ++/* ++ * 6.4.4. ++ * Management SCNs provide information about all changes to the network, ++ * regardless of discovery domain membership. Registration for management ++ * SCNs is indicated by setting bit 26 to 1. Only Control Nodes may ++ * register for management SCNs. Bits 30 and 31 may only be enabled if ++ * bit 26 is set to 1. ++ */ ++int ++isns_policy_validate_scn_bitmap(const isns_policy_t *policy, ++ uint32_t bitmap) ++{ ++ int rv = 1; ++ ++ if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK) ++ goto accept; ++ ++ if (!(bitmap & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK)) { ++ if (bitmap & (ISNS_SCN_DD_MEMBER_ADDED_MASK | ++ ISNS_SCN_DD_MEMBER_REMOVED_MASK)) ++ goto reject; ++ goto accept; ++ } ++ ++reject: ++ rv = 0; ++ ++accept: ++ isns_debug_auth(":: policy %s scn bitmap 0x%x %s\n", ++ policy->ip_name, bitmap, ++ rv? "permitted" : "DENIED"); ++ return rv; ++} ++ ++/* ++ * Create the default policy for a given SPI ++ */ ++isns_policy_t * ++isns_policy_default(const char *spi, size_t len) ++{ ++ return __isns_policy_alloc(spi, len); ++} ++ ++/* ++ * Create the policy object for the server we're ++ * talking to. The server is allowed to send us ++ * ESI and SCN messages, and that's about it. ++ */ ++isns_policy_t * ++isns_policy_server(void) ++{ ++ isns_policy_t *policy; ++ ++ policy = __isns_policy_alloc("", 8); ++ ++ policy->ip_functions = ++ (1 << ISNS_ENTITY_STATUS_INQUIRY) | ++ (1 << ISNS_STATE_CHANGE_NOTIFICATION); ++ policy->ip_node_types = 0; ++ policy->ip_object_types = 0; ++ isns_string_array_append(&policy->ip_node_names, "*"); ++ return policy; ++} ++ ++/* ++ * Allocate an empty policy object ++ */ ++isns_policy_t * ++__isns_policy_alloc(const char *spi, size_t len) ++{ ++ isns_policy_t *policy; ++ ++ policy = isns_calloc(1, sizeof(*policy)); ++ policy->ip_name = isns_malloc(len + 1); ++ policy->ip_users = 1; ++ policy->ip_gen = isns_policy_gen; ++ ++ memcpy(policy->ip_name, spi, len); ++ policy->ip_name[len] = '\0'; ++ ++ /* Only register/query allowed */ ++ policy->ip_functions = ++ (1 << ISNS_DEVICE_ATTRIBUTE_REGISTER) | ++ (1 << ISNS_DEVICE_ATTRIBUTE_QUERY) | ++ (1 << ISNS_DEVICE_GET_NEXT) | ++ (1 << ISNS_DEVICE_DEREGISTER) | ++ (1 << ISNS_SCN_REGISTER); ++ ++ /* Can only register initiator node(s) */ ++ policy->ip_node_types = ++ ISNS_ISCSI_INITIATOR_MASK; ++ ++ /* Can only view/modify standard objects */ ++ policy->ip_object_types = ISNS_DEFAULT_OBJECT_ACCESS; ++ ++ return policy; ++} ++ ++/* ++ * Release a policy object ++ */ ++void ++isns_policy_release(isns_policy_t *policy) ++{ ++ if (!policy) ++ return; ++ ++ isns_assert(policy->ip_users); ++ if (--(policy->ip_users)) ++ return; ++ ++ isns_assert(policy != &isns_superhero_powers); ++ isns_assert(policy != &isns_flyingpigs_powers); ++ isns_assert(policy != &isns_dweeb_powers); ++ ++ isns_free(policy->ip_name); ++ isns_free(policy->ip_entity); ++ isns_free(policy->ip_dd_default); ++ isns_string_array_destroy(&policy->ip_node_names); ++ ++ isns_free(policy); ++} +diff --git a/utils/open-isns/portal-group.c b/utils/open-isns/portal-group.c +new file mode 100644 +index 0000000..647bbde +--- /dev/null ++++ b/utils/open-isns/portal-group.c +@@ -0,0 +1,307 @@ ++/* ++ * iSNS object model - portal group specific code ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include "isns.h" ++#include "objects.h" ++#include "vendor.h" ++#include "attrs.h" ++#include "util.h" ++ ++/* For relationship stuff - should go */ ++#include "db.h" ++ ++ ++/* ++ * Retrieve attribute @old_tag from object @obj, create a copy with ++ * tag @new_tag, and append it to list @dst. ++ * (Helper function for the portal group stuff) ++ */ ++static int ++__isns_object_translate_attr(isns_object_t *obj, ++ uint32_t old_tag, uint32_t new_tag, ++ isns_attr_list_t *dst) ++{ ++ isns_value_t value; ++ ++ if (!isns_attr_list_get_value(&obj->ie_attrs, old_tag, &value)) ++ return 0; ++ isns_attr_list_append_value(dst, new_tag, NULL, &value); ++ return 1; ++} ++ ++ ++/* ++ * Portal Group ++ */ ++static isns_object_t * ++__isns_pg_create(const isns_attr_list_t *attrs, uint32_t pg_tag, ++ isns_object_t *portal, isns_object_t *node) ++{ ++ isns_object_t *obj; ++ ++ obj = isns_create_object(&isns_iscsi_pg_template, attrs, ++ isns_object_get_entity(portal)); ++ ++ /* ++ * 3.4 ++ * ++ * Each Portal and iSCSI Storage Node registered in an Entity can ++ * be associated using a Portal Group (PG) object. The PG Tag ++ * (PGT), if non-NULL, indicates that the associated Portal ++ * provides access to the associated iSCSI Storage Node in ++ * the Entity. All Portals that have the same PGT value for ++ * a specific iSCSI Storage Node allow coordinated access to ++ * that node. ++ * ++ * 5.6.5.2 ++ * ++ * If the PGT of the Portal Group is not NULL, then a relationship ++ * exists between the indicated Storage Node and Portal; if the ++ * PGT is NULL, then no relationship exists. ++ */ ++ if (pg_tag != 0) { ++ isns_object_set_uint32(obj, ++ ISNS_TAG_PG_TAG, pg_tag); ++ } else { ++ /* A NULL PGT indicates that the ++ * storage node cannot be accessed through ++ * this portal. */ ++ isns_object_set_nil(obj, ISNS_TAG_PG_TAG); ++ } ++ ++ /* This object represents a relationship between portal ++ and storage node. Create a relation. */ ++ obj->ie_relation = isns_create_relation(obj, ++ ISNS_RELATION_PORTAL_GROUP, ++ portal, node); ++ ++ return obj; ++} ++ ++/* ++ * Find the portal for a given portal group ++ */ ++static isns_object_t * ++__isns_pg_find_portal(isns_db_t *db, isns_object_t *pg, ++ const isns_object_list_t *extra_objs) ++{ ++ isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; ++ isns_object_t *obj = NULL; ++ ++ /* FIXME: ISNS_TAG_PG_PORTAL_IP_ADDR -> ...ADDRESS */ ++ if (!__isns_object_translate_attr(pg, ++ ISNS_TAG_PG_PORTAL_IP_ADDR, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ &key_attrs)) ++ goto out; ++ if (!__isns_object_translate_attr(pg, ++ ISNS_TAG_PG_PORTAL_TCP_UDP_PORT, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ &key_attrs)) ++ goto out; ++ ++ obj = isns_db_lookup(db, &isns_portal_template, &key_attrs); ++ if (!obj && extra_objs) ++ obj = isns_object_list_lookup(extra_objs, ++ &isns_portal_template, &key_attrs); ++ ++out: ++ isns_attr_list_destroy(&key_attrs); ++ return obj; ++} ++ ++/* ++ * Find the node for a given portal group ++ */ ++static isns_object_t * ++__isns_pg_find_node(isns_db_t *db, isns_object_t *pg, ++ const isns_object_list_t *extra_objs) ++{ ++ isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; ++ isns_object_t *obj = NULL; ++ ++ if (!__isns_object_translate_attr(pg, ++ ISNS_TAG_PG_ISCSI_NAME, ++ ISNS_TAG_ISCSI_NAME, ++ &key_attrs)) ++ goto out; ++ ++ obj = isns_db_lookup(db, &isns_iscsi_node_template, &key_attrs); ++ if (!obj && extra_objs) ++ obj = isns_object_list_lookup(extra_objs, ++ &isns_iscsi_node_template, &key_attrs); ++ ++out: ++ isns_attr_list_destroy(&key_attrs); ++ return obj; ++} ++ ++/* ++ * When creating a portal group, it must not connect nodes and ++ * portals from other entities. However, it is perfectly fine to ++ * link objects in limbo. ++ */ ++static inline int ++__isns_pg_may_relate(isns_object_t *entity, isns_object_t *subordinate) ++{ ++ isns_object_t *other; ++ ++ other = isns_object_get_entity(subordinate); ++ return other == NULL || other == entity; ++} ++ ++/* ++ * Given a portal group object, create the relationship ++ */ ++isns_relation_t * ++isns_db_build_pg_relation(isns_db_t *db, isns_object_t *pg, ++ const isns_object_list_t *extra_objs) ++{ ++ isns_object_t *entity, *node = NULL, *portal = NULL; ++ ++ entity = isns_object_get_entity(pg); ++ ++ node = __isns_pg_find_node(db, pg, extra_objs); ++ if (node == NULL) { ++ isns_error("Trying to register PG for non-existant node\n"); ++ goto failed; ++ } ++ if (!__isns_pg_may_relate(entity, node)) { ++ isns_error("Trying to register PG for node in other entity\n"); ++ goto failed; ++ } ++ ++ portal = __isns_pg_find_portal(db, pg, extra_objs); ++ if (portal == NULL) { ++ isns_error("Trying to register PG for non-existant portal\n"); ++ goto failed; ++ } ++ if (!__isns_pg_may_relate(entity, portal)) { ++ isns_error("Trying to register PG for portal in other entity\n"); ++ goto failed; ++ } ++ ++ pg->ie_relation = isns_create_relation(pg, ++ ISNS_RELATION_PORTAL_GROUP, ++ node, portal); ++ isns_object_release(portal); ++ isns_object_release(node); ++ ++ return pg->ie_relation; ++ ++failed: ++ if (portal) ++ isns_object_release(portal); ++ if (node) ++ isns_object_release(node); ++ return NULL; ++} ++ ++/* ++ * Create a portal group given node, portal and PGT ++ */ ++isns_object_t * ++isns_create_portal_group(isns_object_t *portal, ++ isns_object_t *node, uint32_t pg_tag) ++{ ++ isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; ++ isns_object_t *obj = NULL; ++ ++ if (portal == NULL || node == NULL) ++ return NULL; ++ ++ if (node->ie_container != portal->ie_container) { ++ isns_error("Refusing to create portal group " ++ "linking objects from different entities\n"); ++ return NULL; ++ } ++ ++ if (__isns_object_translate_attr(node, ++ ISNS_TAG_ISCSI_NAME, ++ ISNS_TAG_PG_ISCSI_NAME, ++ &key_attrs) ++ && __isns_object_translate_attr(portal, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PG_PORTAL_IP_ADDR, ++ &key_attrs) ++ && __isns_object_translate_attr(portal, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ ISNS_TAG_PG_PORTAL_TCP_UDP_PORT, ++ &key_attrs)) { ++ obj = __isns_pg_create(&key_attrs, pg_tag, portal, node); ++ } ++ ++ isns_attr_list_destroy(&key_attrs); ++ return obj; ++} ++ ++/* ++ * 5.6.5.1 ++ * New PG objects are registered when an associated Portal or ++ * iSCSI Node object is registered. An explicit PG object ++ * registration MAY follow a Portal or iSCSI Node object ++ * registration in a DevAttrReg message. ++ * [...] ++ * If the PGT value is not included in the Storage Node or ++ * Portal object registration, and if a PGT value was not ++ * previously registered for the relationship, then the PGT for ++ * the corresponding PG object SHALL be registered with a value ++ * of 0x00000001. ++ * ++ * We return non-NULL if the object was created. ++ */ ++isns_object_t * ++isns_create_default_portal_group(isns_db_t *db, ++ isns_object_t *portal, isns_object_t *node) ++{ ++ isns_object_t *obj; ++ ++ if (portal == NULL || node == NULL) ++ return 0; ++ ++ /* See if there is a PG already */ ++ obj = isns_db_get_relationship_object(db, node, portal, ++ ISNS_RELATION_PORTAL_GROUP); ++ if (obj != NULL) { ++ isns_object_release(obj); ++ return NULL; ++ } ++ ++ return isns_create_portal_group(portal, node, 1); ++} ++ ++static uint32_t iscsi_pg_attrs[] = { ++ ISNS_TAG_PG_ISCSI_NAME, ++ ISNS_TAG_PG_PORTAL_IP_ADDR, ++ ISNS_TAG_PG_PORTAL_TCP_UDP_PORT, ++ ISNS_TAG_PG_TAG, ++ ISNS_TAG_PG_INDEX, ++}; ++ ++static uint32_t iscsi_pg_key_attrs[] = { ++ ISNS_TAG_PG_ISCSI_NAME, ++ ISNS_TAG_PG_PORTAL_IP_ADDR, ++ ISNS_TAG_PG_PORTAL_TCP_UDP_PORT, ++}; ++ ++isns_object_template_t isns_iscsi_pg_template = { ++ .iot_name = "iSCSI Portal Group", ++ .iot_handle = ISNS_OBJECT_TYPE_PG, ++ .iot_attrs = iscsi_pg_attrs, ++ .iot_num_attrs = array_num_elements(iscsi_pg_attrs), ++ .iot_keys = iscsi_pg_key_attrs, ++ .iot_num_keys = array_num_elements(iscsi_pg_key_attrs), ++ .iot_attrs = iscsi_pg_attrs, ++ .iot_keys = iscsi_pg_key_attrs, ++ .iot_index = ISNS_TAG_PG_INDEX, ++ .iot_next_index = ISNS_TAG_PG_NEXT_INDEX, ++ .iot_container = &isns_entity_template, ++ .iot_relation_type = ISNS_RELATION_PORTAL_GROUP, ++ .iot_build_relation = isns_db_build_pg_relation, ++}; ++ +diff --git a/utils/open-isns/query.c b/utils/open-isns/query.c +new file mode 100644 +index 0000000..b2cfbc9 +--- /dev/null ++++ b/utils/open-isns/query.c +@@ -0,0 +1,238 @@ ++/* ++ * Handle iSNS Device Attribute Query ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include "isns.h" ++#include "attrs.h" ++#include "message.h" ++#include "security.h" ++#include "objects.h" ++#include "db.h" ++#include "util.h" ++ ++/* ++ * Create a query, and set the source name ++ */ ++static isns_simple_t * ++__isns_create_query(isns_source_t *source, const isns_attr_list_t *key) ++{ ++ return isns_simple_create(ISNS_DEVICE_ATTRIBUTE_QUERY, source, key); ++} ++ ++isns_simple_t * ++isns_create_query(isns_client_t *clnt, const isns_attr_list_t *key) ++{ ++ return __isns_create_query(clnt->ic_source, key); ++} ++ ++isns_simple_t * ++isns_create_query2(isns_client_t *clnt, const isns_attr_list_t *key, isns_source_t *source) ++{ ++ return __isns_create_query(source?: clnt->ic_source, key); ++} ++ ++int ++isns_query_request_attr_tag(isns_simple_t *qry, uint32_t tag) ++{ ++ isns_attr_list_append_nil(&qry->is_operating_attrs, tag); ++ return ISNS_SUCCESS; ++} ++ ++int ++isns_query_request_attr(isns_simple_t *qry, isns_attr_t *attr) ++{ ++ if (!ISNS_ATTR_IS_NIL(attr)) { ++ isns_error("Query operating attribute must be NIL\n"); ++ return ISNS_INVALID_QUERY; ++ } ++ isns_attr_list_append_attr(&qry->is_operating_attrs, attr); ++ return ISNS_SUCCESS; ++} ++ ++static unsigned int ++isns_query_get_requested_types(const isns_attr_list_t *attrs) ++{ ++ unsigned int i, mask = 0; ++ ++ for (i = 0; i < attrs->ial_count; ++i) { ++ uint32_t tag = attrs->ial_data[i]->ia_tag_id; ++ isns_object_template_t *tmpl; ++ ++ tmpl = isns_object_template_find(tag); ++ /* Ignore unknown tags */ ++ if (tmpl == NULL) ++ continue; ++ ++ mask |= 1 << tmpl->iot_handle; ++ } ++ return mask; ++} ++ ++/* ++ * Get the list of objects matching this query ++ */ ++static int ++isns_query_get_objects(isns_simple_t *qry, isns_db_t *db, isns_object_list_t *result) ++{ ++ isns_scope_t *scope = NULL; ++ isns_object_list_t matching = ISNS_OBJECT_LIST_INIT; ++ isns_attr_list_t *keys = &qry->is_message_attrs; ++ isns_object_template_t *query_type = NULL; ++ unsigned int i, qry_mask = 0; ++ int status; ++ ++ /* 5.6.5.2 ++ * If multiple attributes are used as the Message Key, then they ++ * MUST all be from the same object type (e.g., IP address and ++ * TCP/UDP Port are attributes of the Portal object type). ++ */ ++ for (i = 0; i < keys->ial_count; ++i) { ++ isns_object_template_t *tmpl; ++ uint32_t tag = keys->ial_data[i]->ia_tag_id; ++ ++ tmpl = isns_object_template_for_tag(tag); ++ if (tmpl == NULL) ++ return ISNS_ATTRIBUTE_NOT_IMPLEMENTED; ++ if (query_type == NULL) ++ query_type = tmpl; ++ else if (tmpl != query_type) ++ return ISNS_INVALID_QUERY; ++ } ++ ++ /* ++ * 5.6.5.2 ++ * An empty Message Key field indicates the query is scoped to ++ * the entire database accessible by the source Node. ++ */ ++ if (keys->ial_count == 0) { ++ query_type = &isns_entity_template; ++ keys = NULL; ++ } ++ ++ /* Policy: check whether the client is allowed to ++ * query this type of object. */ ++ if (!isns_policy_validate_object_type(qry->is_policy, ++ query_type, qry->is_function)) ++ return ISNS_SOURCE_UNAUTHORIZED; ++ ++ /* No scope means that the source is not part of ++ * any discovery domain, and there's no default DD. ++ * Just return an empty reply. */ ++ scope = isns_scope_for_call(db, qry); ++ if (scope == NULL) ++ return ISNS_SUCCESS; ++ ++ status = isns_scope_gang_lookup(scope, query_type, keys, &matching); ++ if (status != ISNS_SUCCESS) ++ goto out; ++ ++ /* Extract the mask of requested objects */ ++ qry_mask = isns_query_get_requested_types(&qry->is_operating_attrs); ++ ++ /* ++ * 5.6.5.2 ++ * The DevAttrQry response message returns attributes of objects ++ * listed in the Operating Attributes that are related to the ++ * Message Key of the original DevAttrQry message. ++ */ ++ for (i = 0; i < matching.iol_count; ++i) { ++ isns_object_t *obj = matching.iol_data[i]; ++ ++ if (!isns_policy_validate_object_access(qry->is_policy, ++ qry->is_source, obj, ++ qry->is_function)) ++ continue; ++ ++ if (obj->ie_container) ++ isns_object_list_append(result, obj->ie_container); ++ isns_object_list_append(result, obj); ++ isns_scope_get_related(scope, obj, qry_mask, result); ++ } ++ ++out: ++ isns_object_list_destroy(&matching); ++ isns_scope_release(scope); ++ return status; ++} ++ ++/* ++ * Create a Query Response ++ */ ++static isns_simple_t * ++isns_create_query_response(isns_server_t *srv, ++ const isns_simple_t *qry, const isns_object_list_t *objects) ++{ ++ const isns_attr_list_t *req_attrs = NULL; ++ isns_simple_t *resp; ++ unsigned int i; ++ ++ resp = __isns_create_query(srv->is_source, &qry->is_message_attrs); ++ ++ /* ++ * 5.7.5.2. ++ * If no Operating Attributes are included in the original ++ * query, then all Operating Attributes SHALL be returned ++ * in the response. ++ */ ++ if (qry->is_operating_attrs.ial_count != 0) ++ req_attrs = &qry->is_operating_attrs; ++ ++ for (i = 0; i < objects->iol_count; ++i) { ++ isns_object_t *obj = objects->iol_data[i]; ++ ++ if (obj->ie_rebuild) ++ obj->ie_rebuild(obj, srv->is_db); ++ isns_object_get_attrlist(obj, ++ &resp->is_operating_attrs, ++ req_attrs); ++ } ++ return resp; ++} ++ ++int ++isns_process_query(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) ++{ ++ isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; ++ isns_simple_t *reply = NULL; ++ isns_db_t *db = srv->is_db; ++ int status; ++ ++ /* Get the objects matching the query */ ++ status = isns_query_get_objects(call, db, &objects); ++ if (status != ISNS_SUCCESS) ++ goto done; ++ ++ /* Success: build the response */ ++ reply = isns_create_query_response(srv, call, &objects); ++ if (reply == NULL) { ++ status = ISNS_INTERNAL_ERROR; ++ goto done; ++ } ++ ++ /* There's nothing in the spec that tells us what to ++ * return if the query matches no object. ++ */ ++ if (objects.iol_count == 0) { ++ status = ISNS_NO_SUCH_ENTRY; ++ goto done; ++ } ++ ++done: ++ isns_object_list_destroy(&objects); ++ *result = reply; ++ return status; ++} ++ ++/* ++ * Parse the list of objects in a query response ++ */ ++int ++isns_query_response_get_objects(isns_simple_t *qry, ++ isns_object_list_t *result) ++{ ++ return isns_simple_response_get_objects(qry, result); ++} +diff --git a/utils/open-isns/register.c b/utils/open-isns/register.c +new file mode 100644 +index 0000000..120deae +--- /dev/null ++++ b/utils/open-isns/register.c +@@ -0,0 +1,934 @@ ++/* ++ * Handle iSNS Device Attribute Registration ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include "isns.h" ++#include "attrs.h" ++#include "objects.h" ++#include "message.h" ++#include "security.h" ++#include "util.h" ++#include "db.h" ++ ++ ++static int isns_create_default_pgs_for_object(isns_db_t *, isns_object_t *); ++ ++/* ++ * Create a registration, and set the source name ++ */ ++static isns_simple_t * ++__isns_create_registration(isns_source_t *source, isns_object_t *key_obj) ++{ ++ isns_simple_t *reg; ++ ++ reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, source, NULL); ++ if (reg == NULL) ++ return NULL; ++ ++ /* ++ * When sending a registration, you can either specify ++ * the object to be modified in the key attrs, or leave ++ * the key empty. ++ */ ++ if (key_obj == NULL) ++ return reg; ++ ++ /* User gave us a key object. We need to put the key ++ * attributes into the message attrs, and *all* attrs ++ * into the operating attrs. */ ++ if (!isns_object_extract_keys(key_obj, ®->is_message_attrs)) { ++ /* bummer - seems the object is missing some ++ * vital organs. */ ++ isns_warning("%s: object not fully specified, key attrs missing\n", ++ __FUNCTION__); ++ goto failed; ++ } ++ ++ /* ++ * The Message Key identifies the object the DevAttrReg message ++ * acts upon. [...] The key attribute(s) identifying this object ++ * MUST also be included among the Operating Attributes. ++ * ++ * We do not enforce this here, we rely on the caller to get this ++ * right. ++ */ ++#if 0 ++ if (!isns_object_extract_all(key_obj, ®->is_operating_attrs)) { ++ isns_warning("%s: unable to extract attrs from key objects\n", ++ __FUNCTION__); ++ goto failed; ++ } ++#endif ++ ++ return reg; ++ ++failed: ++ isns_simple_free(reg); ++ return NULL; ++} ++ ++isns_simple_t * ++isns_create_registration(isns_client_t *clnt, isns_object_t *key_obj) ++{ ++ return __isns_create_registration(clnt->ic_source, key_obj); ++} ++ ++isns_simple_t * ++isns_create_registration2(isns_client_t *clnt, isns_object_t *key_obj, ++ isns_source_t *source) ++{ ++ return __isns_create_registration(source?: clnt->ic_source, key_obj); ++} ++ ++/* ++ * Set the replace flag ++ */ ++void ++isns_registration_set_replace(isns_simple_t *reg, int replace) ++{ ++ reg->is_replace = !!replace; ++} ++ ++/* ++ * Add an object to the registration ++ */ ++void ++isns_registration_add_object(isns_simple_t *reg, isns_object_t *obj) ++{ ++ isns_object_extract_writable(obj, ®->is_operating_attrs); ++} ++ ++void ++isns_registration_add_object_list(isns_simple_t *reg, isns_object_list_t *list) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_extract_writable(list->iol_data[i], ++ ®->is_operating_attrs); ++ } ++} ++ ++/* ++ * Get the key object given in this message ++ * ++ * It doesn't say anywhere explicitly in the RFC, but ++ * the message key can contain both key and non-key ++ * attributes. For instance, you can search by ++ * Portal Group Index (section 3.4). ++ */ ++static int ++isns_registration_get_key(isns_simple_t *reg, isns_db_t *db, isns_object_t **key_obj) ++{ ++ isns_attr_list_t *keys = ®->is_message_attrs; ++ isns_attr_list_t dummy_keys = ISNS_ATTR_LIST_INIT; ++ isns_attr_t *attr; ++ isns_object_t *obj = NULL; ++ const char *eid = NULL; ++ char eidbuf[128]; ++ int status = ISNS_SUCCESS; ++ int obj_must_exist = 0; ++ ++ /* ++ * 5.6.5.1 ++ * If the Message Key is not present, then the DevAttrReg message ++ * implicitly registers a new Network Entity. In this case, ++ * the replace bit SHALL be ignored; a new Network Entity SHALL ++ * be created. ++ * ++ * Note that some clients seem to leave the message key ++ * empty, but hide the entity identifier in the operating ++ * attrs. ++ */ ++ if (keys->ial_count != 0) { ++ attr = keys->ial_data[0]; ++ ++ /* ++ * 5.6.5.1 ++ * If the Message Key does not contain an EID, and no ++ * pre-existing objects match the Message Key, then the ++ * DevAttrReg message SHALL be rejected with a status ++ * code of 3 (Invalid Registration). ++ */ ++ if (keys->ial_count != 1 ++ || attr->ia_tag_id != ISNS_TAG_ENTITY_IDENTIFIER) ++ obj_must_exist = 1; ++ } else { ++ /* Empty message key. But the client may have hidden ++ * the EID in the operating attrs :-/ ++ */ ++ if (reg->is_operating_attrs.ial_count == 0) ++ goto create_entity; ++ ++ attr = reg->is_operating_attrs.ial_data[0]; ++ if (attr->ia_tag_id != ISNS_TAG_ENTITY_IDENTIFIER) ++ goto create_entity; ++ ++ isns_attr_list_append_attr(&dummy_keys, attr); ++ keys = &dummy_keys; ++ } ++ ++ /* If the caller specifies an EID, extract it while ++ * we know what we're doing :-) */ ++ if (attr->ia_tag_id == ISNS_TAG_ENTITY_IDENTIFIER ++ && ISNS_ATTR_IS_STRING(attr)) ++ eid = attr->ia_value.iv_string; ++ ++ /* Look up the object identified by the keys. ++ * We do not scope the lookup, as the client ++ * may want to add nodes to an entity that's ++ * currently empty - and hence not visible to ++ * any DD. */ ++ if (!ISNS_ATTR_IS_NIL(attr)) ++ obj = isns_db_lookup(db, NULL, keys); ++ ++ if (obj == NULL && obj_must_exist) ++ goto err_invalid; ++ ++ if (obj != NULL) { ++ /* ++ * Policy: verify that the client is permitted ++ * to access this object. ++ * ++ * This includes ++ * - the client node must be the object owner, ++ * or a control node. ++ * - the policy must allow modification of ++ * this object type. ++ */ ++ if (!isns_policy_validate_object_access(reg->is_policy, ++ reg->is_source, ++ obj, reg->is_function)) ++ goto err_unauthorized; ++ ++found_object: ++ if (reg->is_replace) { ++ isns_object_t *container = NULL; ++ ++ if (!ISNS_IS_ENTITY(obj)) { ++ container = isns_object_get_entity(obj); ++ if (container == NULL) { ++ isns_error("Trying to replace %s (id %u) " ++ "which has no container\n", ++ obj->ie_template->iot_name, ++ obj->ie_index); ++ goto err_invalid; ++ } ++ } ++ ++ isns_debug_state("Replacing %s (id %u)\n", ++ obj->ie_template->iot_name, ++ obj->ie_index); ++ isns_db_remove(db, obj); ++ isns_object_release(obj); ++ ++ /* Purge the deleted objects from the database now */ ++ isns_db_purge(db); ++ ++ /* We need to flush pending SCNs because the ++ * objects may be resurrected from limbo, ++ * and we might be looking at stale data. */ ++ isns_scn_transmit_all(); ++ ++ /* It's an entity. Nuke it and create ++ * a new one. */ ++ if (container == NULL) { ++ isns_source_set_entity(reg->is_source, NULL); ++ goto create_entity; ++ } ++ ++ obj = isns_object_get(container); ++ } ++ ++ goto out; ++ } ++ ++ /* ++ * If the Message Key contains an EID and no pre-existing objects ++ * match the Message Key, then the DevAttrReg message SHALL create a ++ * new Entity with the specified EID and any new object(s) specified ++ * by the Operating Attributes. The replace bit SHALL be ignored. ++ * ++ * Implementer's note: the EID attribute may be empty, in which case ++ * we also create a new entity. ++ */ ++ ++create_entity: ++ if (!isns_policy_validate_object_creation(reg->is_policy, ++ reg->is_source, ++ &isns_entity_template, keys, NULL, ++ reg->is_function)) ++ goto err_unauthorized; ++ ++ /* ++ * 5.6.5.1 ++ * A registration message that creates a new Network Entity object ++ * MUST contain at least one Portal or one Storage Node. If the ++ * message does not, then it SHALL be considered invalid and result ++ * in a response with Status Code of 3 (Invalid Registration). ++ */ ++ /* FIXME: Implement this check */ ++ ++ /* We try to play nice with lazy clients and attempt to ++ * look up the network entity given the source name. ++ * But we don't do this if a non-NULL EID was given, ++ * because the client may explicitly want to specify more ++ * than one Network Entity. ++ */ ++ if (eid == NULL) { ++ obj = reg->is_source->is_entity; ++ if (obj != NULL) { ++ isns_object_get(obj); ++ goto found_object; ++ } ++ ++ /* The policy may define a default entity name. ++ * If that is the case, use it. ++ */ ++ eid = isns_policy_default_entity(reg->is_policy); ++ if (eid) { ++ obj = isns_db_vlookup(db, &isns_entity_template, ++ ISNS_TAG_ENTITY_IDENTIFIER, eid, ++ 0); ++ if (obj) { ++ reg->is_source->is_entity = isns_object_get(obj); ++ goto found_object; ++ } ++ } ++ } ++ ++ /* ++ * 5.6.5.1 ++ * If the Message Key and Operating Attributes do not contain ++ * an EID attribute, or if the EID attribute has a length of 0, ++ * then a new Network Entity object SHALL be created and the iSNS ++ * server SHALL supply a unique EID value for it. ++ */ ++ if (eid == NULL) ++ eid = isns_db_generate_eid(db, eidbuf, sizeof(eidbuf)); ++ ++ /* ++ * 6.2.2. Entity Protocol ++ * ++ * This attribute is required during initial registration of ++ * the Network Entity. ++ * ++ * Implementer's note: we don't rely on this. Instead, the ++ * Entity Protocol is selected based on the source type. ++ * If the client specifies the protocol, the auto-selected ++ * value is overwritten. ++ */ ++ obj = isns_create_entity_for_source(reg->is_source, eid); ++ if (obj == NULL) ++ goto err_invalid; ++ ++ isns_source_set_entity(reg->is_source, obj); ++ ++ /* ++ * 6.2.6 ++ * If a Registration Period is not requested by the iSNS ++ * client and Entity Status Inquiry (ESI) messages are not ++ * enabled for that client, then the Registration Period ++ * SHALL be set to a non-zero value by the iSNS server. ++ * This implementation-specific value for the Registration ++ * Period SHALL be returned in the registration response to the ++ * iSNS client. The Registration Period may be set to zero, ++ * indicating its non-use, only if ESI messages are enabled for ++ * that Network Entity. ++ * ++ * Implementer's note: we diverge from this in two ways: ++ * - the admin may choose to disable registration timeout, ++ * by setting RegistrationPeriod=0 in the config file ++ * ++ * - When a new entity is created, we always set the ++ * registration interval because we cannot know yet ++ * whether the client will subsequently enable ESI or ++ * not. ++ * ++ * - The control entity (holding policy objects) will ++ * not expire. ++ */ ++ if (isns_config.ic_registration_period ++ && strcasecmp(eid, ISNS_ENTITY_CONTROL)) { ++ isns_object_set_uint32(obj, ++ ISNS_TAG_REGISTRATION_PERIOD, ++ isns_config.ic_registration_period); ++ isns_object_set_uint64(obj, ++ ISNS_TAG_TIMESTAMP, ++ time(NULL)); ++ } ++ ++ /* Insert into database, and set the object's owner */ ++ isns_db_insert(db, obj); ++ ++ reg->is_replace = 0; ++ ++out: ++ *key_obj = obj; ++ isns_attr_list_destroy(&dummy_keys); ++ return ISNS_SUCCESS; ++ ++error: ++ if (obj) ++ isns_object_release(obj); ++ isns_attr_list_destroy(&dummy_keys); ++ return status; ++ ++err_unauthorized: ++ status = ISNS_SOURCE_UNAUTHORIZED; ++ goto error; ++ ++err_invalid: ++ status = ISNS_INVALID_REGISTRATION; ++ goto error; ++} ++ ++static int ++isns_registration_get_next_object(isns_db_t *db, ++ struct isns_attr_list_scanner *st, ++ isns_object_list_t *result) ++{ ++ isns_object_t *current; ++ int status, esi = 0; ++ ++ status = isns_attr_list_scanner_next(st); ++ /* We get here if the registration has a trailing PGT */ ++ if (status == ISNS_NO_SUCH_ENTRY) ++ return ISNS_SUCCESS; ++ if (status) ++ return status; ++ ++ /* ++ * Validate the attrlist. ++ * This makes sure the client does not include ++ * duplicate attributes, readonly attributes ++ * such as Registration Timestamp, Index and Next Index, ++ * or privileged data (such as marking a storage node as ++ * control node). ++ */ ++ status = isns_attr_list_validate(&st->attrs, ++ st->policy, ++ ISNS_DEVICE_ATTRIBUTE_REGISTER); ++ if (status) { ++ isns_debug_protocol("invalid attr in message\n"); ++ return status; ++ } ++ ++ /* ++ * 6.3.4. Entity Status Inquiry Interval ++ * ++ * If the iSNS server is unable to support ESI messages ++ * or the ESI Interval requested, it SHALL [...] reject ++ * the ESI request by returning an "ESI Not Available" ++ * Status Code [...] ++ * ++ * Implementer's note: In section 5.7.5.1, the RFC talks ++ * about modifying the requested ESI interval; so it seems ++ * it's okay to be liberal about the ESI intervals we accept, ++ * and update them quietly. ++ */ ++ if (isns_attr_list_contains(&st->attrs, ISNS_TAG_ESI_PORT)) { ++ if (!isns_esi_enabled) { ++ isns_debug_esi("Refusing to accept portal " ++ "registration with ESI port\n"); ++ return ISNS_ESI_NOT_AVAILABLE; ++ } ++ esi = 1; ++ } ++ ++ /* ++ * Override any registration period specified by the client. ++ */ ++ if (isns_attr_list_contains(&st->attrs, ISNS_TAG_REGISTRATION_PERIOD)) { ++ isns_value_t value = ISNS_VALUE_INIT(uint32, ++ isns_config.ic_registration_period); ++ ++ isns_attr_list_update_value(&st->attrs, ++ ISNS_TAG_REGISTRATION_PERIOD, NULL, ++ &value); ++ } ++ ++ if (st->tmpl == &isns_entity_template) { ++ /* ++ * 5.6.5.1. ++ * A maximum of one Network Entity object can be ++ * created or updated with a single DevAttrReg ++ * message. Consequently, the Operating Attributes ++ * MUST NOT contain more than one Network Entity ++ * object. ++ */ ++ if (st->entities++) { ++ isns_debug_protocol("More than one entity in DevAttrReg msg\n"); ++ return ISNS_INVALID_REGISTRATION; ++ } ++ ++ /* This should be the key object. ++ * The EID specified by by the client may be ++ * empty, so don't overwrite the value we ++ * assigned with something else. ++ */ ++ if (!isns_object_match(st->key_obj, &st->keys)) { ++ isns_debug_protocol("Entity mismatch in message vs. operating attrs\n"); ++ return ISNS_INVALID_REGISTRATION; ++ } ++ current = isns_object_get(st->key_obj); ++ } else ++ if (st->tmpl == &isns_dd_template || st->tmpl == &isns_ddset_template) { ++ isns_debug_protocol("DevAttrReg of type %s not allowed\n", ++ st->tmpl->iot_name); ++ return ISNS_INVALID_REGISTRATION; ++ } else { ++ /* This will also catch objects in limbo. */ ++ current = isns_db_lookup(db, st->tmpl, &st->keys); ++ } ++ ++ if (current != NULL) { ++ /* ++ * If the replace bit is not set, then the message updates ++ * the attributes of the object identified by the Message Key ++ * and its subordinate objects. Existing object containment ++ * relationships MUST NOT be changed. For existing objects, ++ * key attributes MUST NOT be modified, but new subordinate ++ * objects MAY be added. ++ */ ++ ++ /* ++ * [...] ++ * If the Node identified by the Source Attribute is ++ * not a Control Node, then the objects in the operating ++ * attributes MUST be members of the same Network Entity ++ * as the Source Node. ++ */ ++ if (!isns_policy_validate_object_update(st->policy, ++ st->source, current, &st->attrs, ++ ISNS_DEVICE_ATTRIBUTE_REGISTER)) { ++ isns_object_release(current); ++ return ISNS_SOURCE_UNAUTHORIZED; ++ } ++ ++ /* We shouldn't allow messages affecting one Entity ++ * to modify objects owned by a different Entity. ++ * ++ * However, there may be orphan objects (created ++ * while populating discovery domains). These will ++ * not be associated with any Network Entity, so ++ * they're up for grabs. ++ */ ++ if (st->key_obj == current ++ || st->key_obj == current->ie_container) { ++ /* All is well. The current object is the ++ * key object itself, or a direct descendant of the ++ * key object. */ ++ /* FIXME: with FC we can get deeper nesting; ++ * this needs work. */ ++ } else ++ if (!isns_object_is_valid_container(st->key_obj, st->tmpl)) { ++ isns_error("Client attempts to add %s object to a %s - tsk tsk.\n", ++ st->tmpl->iot_name, ++ st->key_obj->ie_template->iot_name); ++ goto invalid_registration; ++ } else if (current->ie_container) { ++ /* We shouldn't get here in authenticated mode, ++ * but in insecure mode we still may. */ ++ isns_error("Client attempts to move %s %u to a different %s\n", ++ current->ie_template->iot_name, ++ current->ie_index, ++ st->key_obj->ie_template->iot_name); ++ goto invalid_registration; ++ } ++ } else { ++ if (!isns_object_is_valid_container(st->key_obj, st->tmpl)) { ++ isns_error("Client attempts to add %s object to a %s - tsk tsk.\n", ++ st->tmpl->iot_name, ++ st->key_obj->ie_template->iot_name); ++ goto invalid_registration; ++ } ++ ++ if (!isns_policy_validate_object_creation(st->policy, ++ st->source, st->tmpl, ++ &st->keys, &st->attrs, ++ ISNS_DEVICE_ATTRIBUTE_REGISTER)) { ++ return ISNS_SOURCE_UNAUTHORIZED; ++ } ++ current = isns_create_object(st->tmpl, &st->keys, ++ isns_object_get_entity(st->key_obj)); ++ ++ /* We do not insert the new object into the database yet. ++ * That happens after we're done with parsing *all* ++ * objects. */ ++ } ++ ++ if (!isns_object_set_attrlist(current, &st->attrs)) { ++ isns_debug_state("Error updating object's attrlist\n"); ++ isns_object_release(current); ++ return ISNS_INTERNAL_ERROR; ++ } ++ ++ /* If the client specifies an ESI port, make sure the ++ * ESI interval is set and within bounds. */ ++ if (esi) { ++ uint32_t esi_interval; ++ ++ if (!isns_object_get_uint32(current, ++ ISNS_TAG_ESI_INTERVAL, &esi_interval)) { ++ esi_interval = isns_config.ic_esi_min_interval; ++ } else ++ if (esi_interval < isns_config.ic_esi_min_interval) { ++ esi_interval = isns_config.ic_esi_min_interval; ++ } else ++ if (esi_interval > isns_config.ic_esi_max_interval) { ++ esi_interval = isns_config.ic_esi_max_interval; ++ } else { ++ esi_interval = 0; ++ } ++ ++ if (esi_interval) ++ isns_object_set_uint32(current, ++ ISNS_TAG_ESI_INTERVAL, esi_interval); ++ } ++ ++ /* Append it to the result list. ++ * We do not return the key object, otherwise ++ * we end up putting it into the response twice. ++ */ ++ if (current != st->key_obj) ++ isns_object_list_append(result, current); ++ ++ /* ++ * When a Portal is registered, the Portal attributes MAY immediately be ++ * followed by a PGT attribute. ++ * [...] ++ * When an iSCSI Storage Node is registered, the Storage Node attributes ++ * MAY immediately be followed by a PGT attribute. ++ */ ++ if (st->tmpl == &isns_portal_template ++ || st->tmpl == &isns_iscsi_node_template) { ++ st->pgt_next_attr = ISNS_TAG_PG_TAG; ++ st->pgt_base_object = current; ++ } else if (st->tmpl != &isns_iscsi_pg_template) { ++ st->pgt_next_attr = 0; ++ st->pgt_base_object = NULL; ++ } ++ ++ isns_object_release(current); ++ return ISNS_SUCCESS; ++ ++invalid_registration: ++ if (current) ++ isns_object_release(current); ++ return ISNS_INVALID_REGISTRATION; ++} ++ ++/* ++ * Extract the list of objects to be registered from ++ * the list of operating attributes. ++ */ ++static int ++isns_registration_get_objects(isns_simple_t *reg, isns_db_t *db, ++ isns_object_t *key_obj, ++ isns_object_list_t *result) ++{ ++ struct isns_attr_list_scanner state; ++ int status = ISNS_SUCCESS; ++ ++ isns_attr_list_scanner_init(&state, key_obj, ®->is_operating_attrs); ++ state.source = reg->is_source; ++ state.policy = reg->is_policy; ++ ++ /* ++ * 5.6.4. ++ * The ordering of Operating Attributes in the message is ++ * important for determining the relationships among objects ++ * and their ownership of non-key attributes. iSNS protocol ++ * messages that violate these ordering rules SHALL be rejected ++ * with the Status Code of 2 (Message Format Error). ++ */ ++ /* FIXME: Implement this check */ ++ ++ while (state.pos < state.orig_attrs.ial_count) { ++ status = isns_registration_get_next_object(db, ++ &state, result); ++ ++ if (status) ++ break; ++ } ++ ++ isns_attr_list_scanner_destroy(&state); ++ return status; ++} ++ ++/* ++ * 5.6.5.1 ++ * New PG objects are registered when an associated Portal or ++ * iSCSI Node object is registered. An explicit PG object ++ * registration MAY follow a Portal or iSCSI Node object ++ * registration in a DevAttrReg message. ++ * [...] ++ * If the PGT value is not included in the Storage Node or ++ * Portal object registration, and if a PGT value was not ++ * previously registered for the relationship, then the PGT for ++ * the corresponding PG object SHALL be registered with a value ++ * of 0x00000001. ++ */ ++static int ++isns_create_registration_pgs(isns_db_t *db, ++ const isns_object_list_t *list) ++{ ++ unsigned int i, num_created = 0; ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ ++ if (ISNS_IS_ISCSI_NODE(obj) || ISNS_IS_PORTAL(obj)) ++ num_created += isns_create_default_pgs_for_object(db, obj); ++ } ++ return num_created; ++} ++ ++static int ++isns_create_default_pgs_for_object(isns_db_t *db, isns_object_t *this) ++{ ++ isns_object_template_t *match_tmpl; ++ isns_object_t *entity; ++ unsigned int i, num_created = 0; ++ ++ if (ISNS_IS_ISCSI_NODE(this)) ++ match_tmpl = &isns_portal_template; ++ else ++ match_tmpl = &isns_iscsi_node_template; ++ ++ entity = isns_object_get_entity(this); ++ for (i = 0; i < entity->ie_children.iol_count; ++i) { ++ isns_object_t *that = entity->ie_children.iol_data[i], *pg; ++ ++ if (that->ie_template != match_tmpl) ++ continue; ++ ++ /* Create the portal group if it does not ++ * exist. ++ * Note: we do not return these implicitly ++ * created portal groups - that's a matter ++ * of sheer laziness. We would have to ++ * splice these into the list in the ++ * appropriate location, and I guess it's ++ * not really worth the hassle. ++ */ ++ if (ISNS_IS_ISCSI_NODE(this)) ++ pg = isns_create_default_portal_group(db, that, this); ++ else ++ pg = isns_create_default_portal_group(db, this, that); ++ ++ /* There already is a PG linking these two ++ * objects. */ ++ if (pg == NULL) ++ continue; ++ ++ isns_db_insert(db, pg); ++ ++ isns_debug_message("--Created default PG:--\n"); ++ isns_object_print(pg, isns_debug_message); ++ ++ isns_object_release(pg); ++ num_created++; ++ } ++ ++ return num_created; ++} ++ ++/* ++ * Commit all changes to the DB ++ */ ++static int ++isns_commit_registration(isns_db_t *db, isns_object_t *key_obj, isns_object_list_t *list) ++{ ++ unsigned int i; ++ ++ /* ++ * If there are any Portal Groups in this registration, build ++ * the relationship handle: ++ * ++ * 3.4 ++ * A new PG object can only be registered by referencing ++ * its associated iSCSI Storage Node or Portal object. ++ * A pre-existing PG object can be modified or queried ++ * by using its Portal Group Index as message key, or ++ * by referencing its associated iSCSI Storage Node or ++ * Portal object. ++ * ++ * Implementation note: isns_db_create_pg_relation ++ * checks whether the referenced node and portal exist, ++ * and belong to the same entity as the PG. If this is ++ * not the case, NULL is returned, and no relation is ++ * defined. ++ */ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ isns_object_template_t *tmpl; ++ ++ tmpl = obj->ie_template; ++ if (tmpl->iot_build_relation && !obj->ie_relation ++ && !tmpl->iot_build_relation(db, obj, list)) { ++ isns_debug_protocol("Unable to build relation for new %s\n", ++ tmpl->iot_name); ++ return ISNS_INVALID_REGISTRATION; ++ } ++ } ++ ++ for (i = 0; i < list->iol_count; ++i) { ++ isns_object_t *obj = list->iol_data[i]; ++ isns_object_template_t *tmpl; ++ ++ tmpl = obj->ie_template; ++ if (key_obj != obj && !obj->ie_container) { ++ if (!isns_object_attach(obj, key_obj)) { ++ /* This should not fail any longer */ ++ isns_debug_protocol("Unable to attach %s %u to %s\n", ++ tmpl->iot_name, obj->ie_index, ++ key_obj->ie_template->iot_name); ++ return ISNS_INVALID_REGISTRATION; ++ } ++ } ++ ++ if (obj->ie_state != ISNS_OBJECT_STATE_MATURE) ++ isns_db_insert(db, obj); ++ } ++ ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * Process a registration ++ */ ++int ++isns_process_registration(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) ++{ ++ isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; ++ isns_simple_t *reply = NULL; ++ isns_object_t *key_obj = NULL; ++ isns_db_t *db = srv->is_db; ++ int status; ++ unsigned int i; ++ ++ /* ++ * 5.6.1 ++ * For messages that change the contents of the iSNS database, ++ * the iSNS server MUST verify that the Source Attribute ++ * identifies either a Control Node or a Storage Node that is ++ * a part of the Network Entity containing the added, deleted, ++ * or modified objects. ++ * ++ * This check happens in isns_registration_get_key by calling ++ * isns_policy_validate_object_access. ++ */ ++ ++ /* Get the key object (usually a Network Entity) */ ++ status = isns_registration_get_key(call, db, &key_obj); ++ if (status) ++ goto done; ++ ++ /* Get the objects to register */ ++ status = isns_registration_get_objects(call, db, key_obj, &objects); ++ if (status != ISNS_SUCCESS) ++ goto done; ++ ++ /* We parsed the request alright; all semantic checks passed. ++ * Now insert the modified/new objects. ++ * We do this in two passes, by first committing all nodes and ++ * portals, and then committing the portal groups. ++ */ ++ status = isns_commit_registration(db, key_obj, &objects); ++ if (status != ISNS_SUCCESS) ++ goto done; ++ ++ /* The client may have registered a bunch of storage nodes, ++ * and created an entity in the process. However, there's the ++ * odd chance that the source node name it used was not ++ * registered. However, we need to be able to later find ++ * the entity it registered based on its source name. ++ * So we implicitly create a dummy storage node with the given ++ * source name and attach it. ++ */ ++#if 1 ++ if (ISNS_IS_ENTITY(key_obj) ++ && !isns_source_set_node(call->is_source, db)) { ++ isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; ++ isns_source_t *source = call->is_source; ++ isns_object_t *obj; ++ ++ isns_attr_list_append_attr(&attrs, isns_source_attr(source)); ++ isns_attr_list_append_uint32(&attrs, ++ ISNS_TAG_ISCSI_NODE_TYPE, ++ 0); ++ obj = isns_create_object(&isns_iscsi_node_template, ++ &attrs, key_obj); ++ if (obj) { ++ isns_db_insert(db, obj); ++ } else { ++ isns_warning("Unable to create dummy storage node " ++ "for source %s\n", ++ isns_source_name(source)); ++ } ++ isns_attr_list_destroy(&attrs); ++ } ++#endif ++ ++ /* ++ * 5.6.5.1 ++ * New PG objects are registered when an associated Portal or ++ * iSCSI Node object is registered. An explicit PG object ++ * registration MAY follow a Portal or iSCSI Node object ++ * registration in a DevAttrReg message. ++ * [...] ++ * If the PGT value is not included in the Storage Node or ++ * Portal object registration, and if a PGT value was not ++ * previously registered for the relationship, then the PGT for ++ * the corresponding PG object SHALL be registered with a value ++ * of 0x00000001. ++ */ ++ isns_create_registration_pgs(db, &objects); ++ ++ /* Success: create a new registration message, and ++ * send it in our reply. */ ++ reply = __isns_create_registration(srv->is_source, key_obj); ++ if (reply == NULL) { ++ status = ISNS_INTERNAL_ERROR; ++ goto done; ++ } ++ ++ /* If the key object was modified (or created) ++ * include it in the response. ++ * We really ought to restrict ourselves to the ++ * key attrs plus those that were modified by this ++ * registration. But right now have no way of ++ * finding out. ++ */ ++ if (key_obj->ie_flags & ISNS_OBJECT_DIRTY) ++ isns_registration_add_object(reply, key_obj); ++ ++ for (i = 0; i < objects.iol_count; ++i) { ++ isns_registration_add_object(reply, ++ objects.iol_data[i]); ++ } ++ ++ ++done: ++ isns_object_list_destroy(&objects); ++ isns_object_release(key_obj); ++ *result = reply; ++ return status; ++} ++ ++/* ++ * Extract the list of objects from the DevAttrReg response ++ */ ++int ++isns_registration_response_get_objects(isns_simple_t *reg, ++ isns_object_list_t *result) ++{ ++ return isns_simple_response_get_objects(reg, result); ++} +diff --git a/utils/open-isns/relation.c b/utils/open-isns/relation.c +new file mode 100644 +index 0000000..caac38b +--- /dev/null ++++ b/utils/open-isns/relation.c +@@ -0,0 +1,281 @@ ++/* ++ * iSNS object relationships ++ * ++ * Relations are used to express a connection between two ++ * objects. Currently, two relationship types are implemented: ++ * ++ * - portal group: this relates a storage node and a portal ++ * - visibility: this relates a nodes nodes that share a ++ * common discovery domain. ++ * ++ * Relation objects are nice for portals groups, but kind of ++ * awkward for DDs. A better way of expressing DD membership ++ * (which also allows for a fast visibility check) could be ++ * to store a [bit] vector of DD IDs in each storage node. ++ * A visibility check would amount to just doing the bitwise ++ * AND of two vectors, and checking for NULL. The only thing ++ * to take care of would be to make sure a DD object takes a ++ * reference on its members (this is necessary so that objects ++ * maintain their ID/name associations even when removed from ++ * the database). ++ * ++ * Aug 22 2007 - changed DD code to use bit vectors. A lot ++ * of code in this file is now obsolete. ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "isns.h" ++#include "objects.h" ++#include "util.h" ++#include "db.h" ++ ++struct isns_relation_soup { ++ /* For now, use one plain list. For better ++ * scalability, we'll need a hash table or ++ * something similar later. */ ++ isns_relation_list_t irs_data; ++}; ++ ++static void isns_relation_list_append(isns_relation_list_t *, ++ isns_relation_t *); ++static int isns_relation_list_remove(isns_relation_list_t *, ++ isns_relation_t *); ++ ++isns_relation_soup_t * ++isns_relation_soup_alloc(void) ++{ ++ return isns_calloc(1, sizeof(isns_relation_soup_t)); ++} ++ ++void ++isns_relation_add(isns_relation_soup_t *soup, ++ isns_relation_t *rp) ++{ ++ isns_relation_list_append(&soup->irs_data, rp); ++} ++ ++isns_relation_t * ++isns_relation_find_edge(isns_relation_soup_t *soup, ++ const isns_object_t *left, ++ const isns_object_t *right, ++ unsigned int relation_type) ++{ ++ isns_relation_list_t *list = &soup->irs_data; ++ unsigned int i; ++ ++ for (i = 0; i < list->irl_count; ++i) { ++ isns_relation_t *rp = list->irl_data[i]; ++ ++ if (rp->ir_type != relation_type) ++ continue; ++ if (rp->ir_subordinate[0].obj == left ++ && rp->ir_subordinate[1].obj == right) ++ return rp; ++ if (rp->ir_subordinate[0].obj == right ++ && rp->ir_subordinate[1].obj == left) ++ return rp; ++ } ++ return NULL; ++} ++ ++void ++isns_relation_get_edge_objects(isns_relation_soup_t *soup, ++ const isns_object_t *left, ++ unsigned int relation_type, ++ isns_object_list_t *result) ++{ ++ isns_relation_list_t *list = &soup->irs_data; ++ unsigned int i; ++ ++ for (i = 0; i < list->irl_count; ++i) { ++ isns_relation_t *rp = list->irl_data[i]; ++ ++ if (rp->ir_type != relation_type) ++ continue; ++ if (rp->ir_object == NULL) ++ continue; ++ if (rp->ir_subordinate[0].obj == left ++ || rp->ir_subordinate[1].obj == left) { ++ isns_object_list_append(result, ++ rp->ir_object); ++ } ++ } ++} ++ ++ ++ ++void ++isns_relation_halfspace(isns_relation_soup_t *soup, ++ const isns_object_t *left, ++ unsigned int relation_type, ++ isns_object_list_t *result) ++{ ++ isns_relation_list_t *list = &soup->irs_data; ++ unsigned int i; ++ ++ for (i = 0; i < list->irl_count; ++i) { ++ isns_relation_t *rp = list->irl_data[i]; ++ ++ if (rp->ir_type != relation_type) ++ continue; ++ if (rp->ir_subordinate[0].obj == left) { ++ isns_object_list_append(result, ++ rp->ir_subordinate[1].obj); ++ } else ++ if (rp->ir_subordinate[1].obj == left) { ++ isns_object_list_append(result, ++ rp->ir_subordinate[0].obj); ++ } ++ } ++} ++ ++int ++isns_relation_exists(isns_relation_soup_t *soup, ++ const isns_object_t *relating_object, ++ const isns_object_t *left, ++ const isns_object_t *right, ++ unsigned int relation_type) ++{ ++ isns_relation_list_t *list = &soup->irs_data; ++ unsigned int i; ++ ++ for (i = 0; i < list->irl_count; ++i) { ++ isns_relation_t *rp = list->irl_data[i]; ++ ++ if (rp->ir_type != relation_type) ++ continue; ++ if (rp->ir_object != relating_object) ++ continue; ++ if (rp->ir_subordinate[0].obj == left ++ && rp->ir_subordinate[1].obj == right) ++ return 1; ++ if (rp->ir_subordinate[0].obj == right ++ && rp->ir_subordinate[1].obj == left) ++ return 1; ++ } ++ return 0; ++} ++ ++isns_object_t * ++isns_relation_get_other(const isns_relation_t *rp, ++ const isns_object_t *this) ++{ ++ if (rp->ir_subordinate[0].obj == this) ++ return rp->ir_subordinate[1].obj; ++ if (rp->ir_subordinate[1].obj == this) ++ return rp->ir_subordinate[0].obj; ++ return NULL; ++} ++ ++void ++isns_relation_remove(isns_relation_soup_t *soup, ++ isns_relation_t *rp) ++{ ++ isns_object_release(rp->ir_object); ++ rp->ir_object = NULL; ++ ++ isns_relation_list_remove(&soup->irs_data, rp); ++} ++ ++isns_relation_t * ++isns_create_relation(isns_object_t *relating_object, ++ unsigned int relation_type, ++ isns_object_t *subordinate_object1, ++ isns_object_t *subordinate_object2) ++{ ++ isns_relation_t *rp; ++ ++ rp = isns_calloc(1, sizeof(*rp)); ++ rp->ir_type = relation_type; ++ rp->ir_users = 1; ++ rp->ir_object = isns_object_get(relating_object); ++ isns_object_reference_set(&rp->ir_subordinate[0], subordinate_object1); ++ isns_object_reference_set(&rp->ir_subordinate[1], subordinate_object2); ++ ++#if 0 ++ if (relating_object) { ++ relating_object->ie_relation = rp; ++ rp->ir_users++; ++ } ++#endif ++ ++ return rp; ++} ++ ++void ++isns_relation_sever(isns_relation_t *rp) ++{ ++ isns_object_release(rp->ir_object); ++ rp->ir_object = NULL; ++ ++ isns_object_reference_drop(&rp->ir_subordinate[0]); ++ isns_object_reference_drop(&rp->ir_subordinate[1]); ++} ++ ++void ++isns_relation_release(isns_relation_t *rp) ++{ ++ if (--(rp->ir_users)) ++ return; ++ ++ isns_relation_sever(rp); ++ isns_free(rp); ++} ++ ++/* ++ * Check whether the relation references two dead/limbo objects. ++ * This is used for dead PG removal. ++ */ ++int ++isns_relation_is_dead(const isns_relation_t *rel) ++{ ++ isns_object_t *left, *right; ++ ++ left = rel->ir_subordinate[0].obj; ++ right = rel->ir_subordinate[1].obj; ++ if ((left->ie_flags & ISNS_OBJECT_DEAD) ++ && (right->ie_flags & ISNS_OBJECT_DEAD)) ++ return 1; ++ ++ return 0; ++} ++ ++void ++isns_relation_list_append(isns_relation_list_t *list, ++ isns_relation_t *rp) ++{ ++ if ((list->irl_count % 128) == 0) { ++ list->irl_data = isns_realloc(list->irl_data, ++ (list->irl_count + 128) * sizeof(void *)); ++ if (list->irl_data == NULL) ++ isns_fatal("out of memory!\n"); ++ } ++ ++ list->irl_data[list->irl_count++] = rp; ++ rp->ir_users++; ++} ++ ++int ++isns_relation_list_remove(isns_relation_list_t *list, ++ isns_relation_t *rp) ++{ ++ unsigned int i, count = list->irl_count; ++ ++ for (i = 0; i < count; ++i) { ++ if (list->irl_data[i] != rp) ++ continue; ++ if (i < count - 1) ++ list->irl_data[i] = list->irl_data[count-1]; ++ isns_relation_release(rp); ++ list->irl_count -= 1; ++ return 1; ++ } ++ ++ return 0; ++} +diff --git a/utils/open-isns/scn.c b/utils/open-isns/scn.c +new file mode 100644 +index 0000000..51fcba3 +--- /dev/null ++++ b/utils/open-isns/scn.c +@@ -0,0 +1,926 @@ ++/* ++ * Handle SCN registration/deregistration/events ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include "isns.h" ++#include "attrs.h" ++#include "objects.h" ++#include "message.h" ++#include "security.h" ++#include "util.h" ++#include "db.h" ++ ++typedef struct isns_scn isns_scn_t; ++typedef struct isns_scn_funnel isns_scn_funnel_t; ++ ++struct isns_scn { ++ isns_scn_t * scn_next; ++ char * scn_name; ++ isns_object_t * scn_entity; ++ isns_object_t * scn_owner; ++ isns_attr_t * scn_attr; ++ ++ isns_simple_t * scn_message; ++ isns_simple_t * scn_pending; ++ unsigned int scn_retries; ++ time_t scn_timeout; ++ uint16_t scn_xid; ++ ++ time_t scn_last_update; ++ isns_scn_funnel_t * scn_current_funnel; ++ isns_scn_funnel_t * scn_funnels; ++}; ++ ++struct isns_scn_funnel { ++ isns_scn_funnel_t * scn_next; ++ isns_portal_info_t scn_portal; ++ isns_socket_t * scn_socket; ++ unsigned int scn_bad; ++}; ++ ++static isns_server_t * isns_scn_server = NULL; ++static isns_scn_t * isns_scn_list; ++ ++static isns_scn_t * isns_scn_create_scn(isns_object_t *, uint32_t, isns_db_t *); ++static void isns_scn_delete_scn(isns_object_t *); ++static isns_scn_t * isns_scn_setup(isns_scn_t *, isns_object_t *); ++static void isns_scn_callback(const isns_db_event_t *, void *); ++static void isns_scn_free(isns_scn_t *); ++ ++/* ++ * Initialize SCN machinery ++ */ ++void ++isns_scn_init(isns_server_t *srv) ++{ ++ isns_db_t *db = srv->is_db; ++ isns_object_list_t nodes = ISNS_OBJECT_LIST_INIT; ++ isns_scn_t **tail; ++ unsigned int i; ++ ++ isns_scn_server = srv; ++ isns_register_callback(isns_scn_callback, db); ++ ++ /* Recover SCN state. */ ++ isns_db_gang_lookup(db, &isns_iscsi_node_template, NULL, &nodes); ++#ifdef notyet ++ isns_db_gang_lookup(db, &isns_fc_node_template, NULL, &nodes); ++#endif ++ ++ tail = &isns_scn_list; ++ for (i = 0; i < nodes.iol_count; ++i) { ++ isns_object_t *node = nodes.iol_data[i]; ++ isns_scn_t *scn; ++ ++ if (!node->ie_scn_mask) ++ continue; ++ ++ isns_debug_state("Recovering SCN state for %s %u\n", ++ node->ie_template->iot_name, ++ node->ie_index); ++ scn = isns_scn_setup(NULL, node); ++ if (scn) { ++ *tail = scn; ++ tail = &scn->scn_next; ++ } ++ } ++} ++ ++/* ++ * Support for SCNRegister calls ++ */ ++isns_simple_t * ++isns_create_scn_registration2(isns_client_t *clnt, unsigned int bitmap, isns_source_t *source) ++{ ++ isns_simple_t *call; ++ ++ if (!source) ++ source = clnt->ic_source; ++ call = isns_simple_create(ISNS_SCN_REGISTER, source, NULL); ++ if (call) { ++ isns_attr_list_append_attr(&call->is_message_attrs, ++ isns_source_attr(source)); ++ isns_attr_list_append_uint32(&call->is_operating_attrs, ++ ISNS_TAG_ISCSI_SCN_BITMAP, ++ bitmap); ++ } ++ return call; ++} ++ ++isns_simple_t * ++isns_create_scn_registration(isns_client_t *clnt, unsigned int bitmap) ++{ ++ return isns_create_scn_registration2(clnt, bitmap, clnt->ic_source); ++} ++ ++/* ++ * Create an SCN ++ */ ++isns_simple_t * ++isns_create_scn(isns_source_t *source, isns_attr_t *nodeattr, isns_attr_t *tsattr) ++{ ++ isns_simple_t *call; ++ ++ call = isns_simple_create(ISNS_STATE_CHANGE_NOTIFICATION, source, NULL); ++ if (call && nodeattr) ++ isns_attr_list_append_attr(&call->is_message_attrs, nodeattr); ++ if (call && tsattr) ++ isns_attr_list_append_attr(&call->is_message_attrs, tsattr); ++ return call; ++} ++ ++static void ++isns_scn_add_event(isns_simple_t *call, uint32_t scn_bits, ++ const isns_object_t *obj, ++ const isns_object_t *dd) ++{ ++ isns_attr_list_t *attrs = &call->is_message_attrs; ++ ++ isns_attr_list_append_uint32(attrs, ++ ISNS_TAG_ISCSI_SCN_BITMAP, ++ scn_bits); ++ isns_object_extract_keys(obj, attrs); ++ if (dd) ++ isns_object_extract_keys(dd, attrs); ++} ++ ++/* ++ * Process a SCN registration ++ */ ++int ++isns_process_scn_register(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) ++{ ++ isns_attr_list_t *keys = &call->is_message_attrs; ++ isns_attr_list_t *attrs = &call->is_operating_attrs; ++ isns_db_t *db = srv->is_db; ++ isns_attr_t *attr; ++ isns_object_t *node = NULL; ++ uint32_t scn_bitmap; ++ isns_scn_t *scn; ++ int status = ISNS_SUCCESS; ++ ++ /* ++ * 5.6.5.5 ++ * The SCNReg request PDU Payload contains a Source Attribute, a Message ++ * Key Attribute, and an Operating Attribute. Valid Message Key ++ * Attributes for a SCNReg are shown below: ++ * ++ * Valid Message Key Attributes for SCNReg ++ * --------------------------------------- ++ * iSCSI Name ++ * FC Port Name WWPN ++ */ ++ if (keys->ial_count != 1 || attrs->ial_count != 1) ++ return ISNS_SCN_REGISTRATION_REJECTED; ++ ++ attr = keys->ial_data[0]; ++ if (attr->ia_tag_id != ISNS_TAG_ISCSI_NAME && ++ attr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN) ++ return ISNS_SCN_REGISTRATION_REJECTED; ++ ++ /* Look up the storage node for this source. If it does ++ * not exist, reject the message. */ ++ node = isns_db_lookup(db, NULL, keys); ++ if (node == NULL) ++ return ISNS_SOURCE_UNKNOWN; ++ ++ /* ++ * Policy: verify that the client is permitted ++ * to access this entity. ++ * ++ * This includes ++ * - the client node must be the object owner, ++ * or a control node. ++ * - the policy must allow monitoring of ++ * this object type. ++ */ ++ if (!isns_policy_validate_object_access(call->is_policy, ++ call->is_source, ++ node, call->is_function)) ++ goto unauthorized; ++ ++ /* ++ * 5.6.5.5 ++ * The SCN Bitmap is the only operating attribute of this message ++ * [...] ++ * Control Nodes MAY conduct registrations for management SCNs; ++ * iSNS clients that are not supporting Control Nodes MUST NOT ++ * conduct registrations for management SCNs. ++ * ++ * Implementer's note: for iFCP sources, we should check for ++ * ISNS_TAG_IFCP_SCN_BITMAP. ++ */ ++ attr = attrs->ial_data[0]; ++ if (attr->ia_tag_id != ISNS_TAG_ISCSI_SCN_BITMAP ++ || !ISNS_ATTR_IS_UINT32(attr)) ++ goto rejected; ++ ++ scn_bitmap = attr->ia_value.iv_uint32; ++ if (!isns_policy_validate_scn_bitmap(call->is_policy, scn_bitmap)) ++ goto unauthorized; ++ ++ /* ++ * 5.6.5.5 ++ * If no SCN Port fields of any Portals of the Storage Node are ++ * registered to receive SCN messages, then the SCNReg message SHALL ++ * be rejected with Status Code 17 (SCN Registration Rejected). ++ */ ++ if (!(scn = isns_scn_create_scn(node, scn_bitmap, db))) ++ goto rejected; ++ ++ *result = isns_simple_create(ISNS_SCN_REGISTER, srv->is_source, NULL); ++ status = ISNS_SUCCESS; ++ ++out: ++ if (node) ++ isns_object_release(node); ++ ++ return status; ++ ++rejected: ++ status = ISNS_SCN_REGISTRATION_REJECTED; ++ goto out; ++ ++unauthorized: ++ status = ISNS_SOURCE_UNAUTHORIZED; ++ goto out; ++} ++ ++/* ++ * Process a SCNDereg message ++ */ ++int ++isns_process_scn_deregistration(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) ++{ ++ isns_attr_list_t *keys = &call->is_message_attrs; ++ isns_db_t *db = srv->is_db; ++ isns_attr_t *attr; ++ isns_object_t *node = NULL; ++ int status = ISNS_SUCCESS; ++ ++ /* ++ * 5.6.5.6 ++ * The SCNDereg request message PDU Payload contains a Source Attribute ++ * and Message Key Attribute(s). Valid Message Key Attributes for a ++ * SCNDereg are shown below: ++ * ++ * Valid Message Key Attributes for SCNDereg ++ * ----------------------------------------- ++ * iSCSI Name ++ * FC Port Name WWPN ++ * ++ * There are no Operating Attributes in the SCNDereg message. ++ */ ++ ++ if (keys->ial_count != 1) ++ return ISNS_SCN_REGISTRATION_REJECTED; ++ ++ attr = keys->ial_data[0]; ++ if (attr->ia_tag_id != ISNS_TAG_ISCSI_NAME && ++ attr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN) ++ return ISNS_SCN_REGISTRATION_REJECTED; ++ ++ /* Look up the storage node for this source. If it does ++ * not exist, reject the message. */ ++ node = isns_db_lookup(db, NULL, keys); ++ if (node == NULL) ++ return ISNS_SUCCESS; ++ ++ /* ++ * Policy: verify that the client is permitted ++ * to access this entity. ++ * ++ * This includes ++ * - the client node must be the object owner, ++ * or a control node. ++ * - the policy must allow monitoring of ++ * this object type. ++ */ ++ if (!isns_policy_validate_object_access(call->is_policy, ++ call->is_source, ++ node, call->is_function)) ++ goto unauthorized; ++ ++ isns_object_set_scn_mask(node, 0); ++ isns_scn_delete_scn(node); ++ ++ *result = isns_simple_create(ISNS_SCN_DEREGISTER, srv->is_source, NULL); ++ status = ISNS_SUCCESS; ++ ++out: ++ if (node) ++ isns_object_release(node); ++ ++ return status; ++ ++unauthorized: ++ status = ISNS_SOURCE_UNAUTHORIZED; ++ goto out; ++} ++ ++/* ++ * Set up the SCN object. ++ */ ++static isns_scn_t * ++isns_scn_setup(isns_scn_t *scn, isns_object_t *node) ++{ ++ isns_object_list_t portals = ISNS_OBJECT_LIST_INIT; ++ isns_object_t *entity; ++ unsigned int i; ++ ++ entity = isns_object_get_entity(node); ++ if (entity == NULL ++ || !isns_object_find_descendants(entity, ++ &isns_portal_template, NULL, &portals)) ++ return NULL; ++ ++ for (i = 0; i < portals.iol_count; ++i) { ++ isns_object_t *portal = portals.iol_data[i]; ++ isns_portal_info_t info; ++ isns_scn_funnel_t *funnel; ++ ++ /* Extract address and SCN port from portal */ ++ if (!isns_portal_from_object(&info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_SCN_PORT, ++ portal)) ++ continue; ++ ++ /* We know where to send our notifications! */ ++ if (scn == NULL) { ++ isns_attr_t *attr; ++ ++ if (!isns_object_get_attr(node, ISNS_TAG_ISCSI_NAME, &attr) ++ && !isns_object_get_attr(node, ISNS_TAG_FC_PORT_NAME_WWPN, &attr)) { ++ isns_error("Attempt to set up SCN for strange node type\n"); ++ return NULL; ++ } ++ ++ scn = isns_calloc(1, sizeof(*scn)); ++ scn->scn_entity = isns_object_get(entity); ++ scn->scn_owner = isns_object_get(node); ++ scn->scn_attr = isns_attr_get(attr); ++ scn->scn_name = isns_strdup(attr->ia_value.iv_string); ++ } ++ ++ funnel = isns_calloc(1, sizeof(*funnel)); ++ funnel->scn_portal = info; ++ funnel->scn_next = scn->scn_funnels; ++ scn->scn_funnels = funnel; ++ } ++ ++ isns_object_list_destroy(&portals); ++ return scn; ++} ++ ++/* ++ * See if an SCN object exists for the given target; ++ * if it doesn't, then create one. ++ */ ++static isns_scn_t * ++isns_scn_create_scn(isns_object_t *node, uint32_t bitmap, isns_db_t *db) ++{ ++ isns_scn_t *scn; ++ ++ for (scn = isns_scn_list; scn; scn = scn->scn_next) { ++ if (scn->scn_owner == node) ++ goto done; ++ } ++ ++ /* Not found - create it */ ++ scn = isns_scn_setup(NULL, node); ++ if (scn == NULL) ++ return NULL; ++ ++ scn->scn_next = isns_scn_list; ++ isns_scn_list = scn; ++ ++done: ++ /* We're all set - update the bitmap */ ++ isns_object_set_scn_mask(node, bitmap); ++ return scn; ++} ++ ++static void ++isns_scn_delete_scn(isns_object_t *node) ++{ ++ isns_scn_t *scn, **pos; ++ ++ pos = &isns_scn_list; ++ while ((scn = *pos) != NULL) { ++ if (scn->scn_owner == node) { ++ isns_debug_scn("Deregistering SCN for node %u\n", ++ node->ie_index); ++ *pos = scn->scn_next; ++ isns_scn_free(scn); ++ return; ++ } ++ pos = &scn->scn_next; ++ } ++} ++ ++static void ++isns_scn_release_funnels(isns_scn_t *scn) ++{ ++ isns_scn_funnel_t *funnel; ++ ++ while ((funnel = scn->scn_funnels) != NULL) { ++ scn->scn_funnels = funnel->scn_next; ++ if (funnel->scn_socket) ++ isns_socket_free(funnel->scn_socket); ++ isns_free(funnel); ++ } ++} ++ ++static void ++isns_scn_free(isns_scn_t *scn) ++{ ++ isns_scn_release_funnels(scn); ++ isns_object_release(scn->scn_owner); ++ isns_object_release(scn->scn_entity); ++ isns_attr_release(scn->scn_attr); ++ isns_free(scn->scn_name); ++ isns_free(scn); ++} ++ ++/* ++ * Check whether we should send an event to the target ++ */ ++static inline int ++isns_scn_match(isns_scn_t *scn, uint32_t event, ++ const isns_object_t *node, ++ uint32_t node_type) ++{ ++ if (event == 0) ++ return 0; ++ ++ if (node->ie_scn_mask & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK) ++ return event | ISNS_SCN_MANAGEMENT_REGISTRATION_MASK; ++ ++#if 0 ++ /* This is a normal (non-control) node. Check whether the object ++ * is in the scope of this client. */ ++ if (!isns_object_in_scope(scn->scn_owner, node)) ++ return 0; ++#endif ++ ++ if (node->ie_scn_mask & ISNS_SCN_TARGET_AND_SELF_ONLY_MASK) { ++ if (node != scn->scn_owner && !(node_type & ISNS_ISCSI_TARGET_MASK)) ++ return 0; ++ } ++ if (node->ie_scn_mask & ISNS_SCN_INITIATOR_AND_SELF_ONLY_MASK) { ++ if (node != scn->scn_owner && !(node_type & ISNS_ISCSI_INITIATOR_MASK)) ++ return 0; ++ } ++ ++ return event; ++} ++ ++/* ++ * Helper to create time stamp attr ++ */ ++static isns_attr_t * ++isns_create_timestamp_attr(void) ++{ ++ isns_value_t value = ISNS_VALUE_INIT(uint64, time(NULL)); ++ ++ return isns_attr_alloc(ISNS_TAG_TIMESTAMP, NULL, &value); ++} ++ ++/* ++ * This function is invoked whenever someone changes the ++ * database. ++ * ++ * SCNs are another area where the RFC is fabulously wishy washy. ++ * It is not entirely clear when DD/DDS information should be ++ * included in a management SCN - one *reasonable* interpretation ++ * would be that this happens for DDReg/DDDereg/DDSReg/DDSDereg ++ * events only. But some sections make it sound as if DD ++ * information is included for all management SCNs. ++ */ ++void ++isns_scn_callback(const isns_db_event_t *ev, void *ptr) ++{ ++ isns_object_t *obj = ev->ie_object; ++ isns_scn_t *scn, **pos; ++ isns_attr_t *timestamp; ++ uint32_t node_type; ++ ++ /* Never send out notifications for policy objects and the like. */ ++ if (obj->ie_flags & ISNS_OBJECT_PRIVATE) ++ return; ++ ++ /* When an entity is nuked, remove all SCNs to nodes ++ * that registered from there */ ++ if (ISNS_IS_ENTITY(obj) && (ev->ie_bits & ISNS_SCN_OBJECT_REMOVED_MASK)) { ++ pos = &isns_scn_list; ++ while ((scn = *pos) != NULL) { ++ if (scn->scn_entity != obj) { ++ pos = &scn->scn_next; ++ continue; ++ } ++ isns_debug_scn("Deleting SCN registration for %s\n", ++ scn->scn_name); ++ *pos = scn->scn_next; ++ isns_scn_free(scn); ++ } ++ return; ++ } ++ ++ /* For now we handle iSCSI nodes only. Maybe later we'll ++ * do iFC nodes as well. */ ++ if (!ISNS_IS_ISCSI_NODE(obj)) ++ return; ++ if (!isns_object_get_uint32(obj, ISNS_TAG_ISCSI_NODE_TYPE, &node_type)) ++ return; ++ ++ if (ev->ie_recipient) { ++ isns_object_t *dst = ev->ie_recipient; ++ ++ isns_debug_scn("SCN unicast <%s %u, %s> -> %s %u\n", ++ obj->ie_template->iot_name, obj->ie_index, ++ isns_event_string(ev->ie_bits), ++ dst->ie_template->iot_name, dst->ie_index); ++ } else { ++ isns_debug_scn("SCN multicast <%s %u, %s>\n", ++ obj->ie_template->iot_name, obj->ie_index, ++ isns_event_string(ev->ie_bits)); ++ } ++ timestamp = isns_create_timestamp_attr(); ++ ++ pos = &isns_scn_list; ++ while ((scn = *pos) != NULL) { ++ unsigned int scn_bits, management; ++ isns_object_t *recipient, *dd = NULL; ++ isns_simple_t *call; ++ ++ recipient = scn->scn_owner; ++ ++ /* Check if the node has gone away completely. */ ++ if (recipient->ie_scn_mask == 0) { ++ *pos = scn->scn_next; ++ isns_scn_free(scn); ++ continue; ++ } ++ ++ if (recipient->ie_container == NULL) { ++ isns_warning("Internal bug - SCN recipient without container\n"); ++ /* Clear the bitmask and loop over - this will remove it */ ++ recipient->ie_scn_mask = 0; ++ continue; ++ } ++ ++ /* See if portals were added/removed. ++ * This does not catch updates that modified *just* ++ * the SCN port */ ++ if (recipient->ie_container->ie_mtime != scn->scn_last_update) { ++ /* Rebuild the list of SCN portals */ ++ isns_scn_release_funnels(scn); ++ scn->scn_last_update = 0; ++ } ++ pos = &scn->scn_next; ++ ++ /* Check for unicast events (triggered for DD addition/removal). ++ * For unicast events, we do not mask the SCN bits, so that ++ * clients who have registered for non-management events ++ * will see the membership events for their DDs nevertheless. */ ++ if (ev->ie_recipient == NULL) { ++ scn_bits = ev->ie_bits & recipient->ie_scn_mask; ++ if (scn_bits == 0) ++ continue; ++ /* Management SCNs should not be delivered to nodes ++ * that have not registered for them. */ ++ if ((ev->ie_bits & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK) ++ && !(recipient->ie_scn_mask & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK)) ++ continue; ++ } else if (recipient == ev->ie_recipient) { ++ scn_bits = ev->ie_bits; ++ } else { ++ /* No match, skip this recipient */ ++ continue; ++ } ++ ++ if (scn->scn_last_update == 0) { ++ scn->scn_last_update = recipient->ie_container->ie_mtime; ++ isns_scn_setup(scn, recipient); ++ } ++ ++ /* We check for SCN capable portals when processing ++ * the SCN registration. But the portals may go away ++ * in the meantime. */ ++ if (scn->scn_funnels == NULL) ++ continue; ++ ++ /* Check SCN bitmask. This will modify the event bits. */ ++ scn_bits = isns_scn_match(scn, scn_bits, obj, node_type); ++ if (scn_bits == 0) ++ continue; ++ management = !!(scn_bits & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK); ++ ++ /* ++ * 2.2.3 ++ * A regular SCN registration indicates that the ++ * Discovery Domain Service SHALL be used to control the ++ * distribution of SCN messages. Receipt of regular ++ * SCNs is limited to the discovery domains in which ++ * the SCN-triggering event takes place. Regular SCNs ++ * do not contain information about discovery domains. ++ * ++ * Implementer's note: We override check for unicast events. ++ * The reason is that DDDereg will sever the ++ * relationship, and we would never send an SCN for that ++ * event. ++ */ ++ if (!management && !ev->ie_recipient) { ++ if (!isns_object_test_visibility(obj, recipient)) ++ continue; ++ } ++ ++ isns_debug_scn("preparing to send SCN to %s\n", ++ scn->scn_name); ++ ++ if ((call = scn->scn_message) == NULL) { ++ call = isns_create_scn(isns_scn_server->is_source, ++ scn->scn_attr, ++ timestamp); ++ if (call == NULL) ++ continue; ++ scn->scn_message = call; ++ } ++ ++ /* ++ * If the SCN is a Management SCN, then the SCN message ++ * SHALL also list the DD_ID and/or DDS_ID of the ++ * Discovery Domains and Discovery Domain Sets (if any) ++ * that caused the change in state for that Storage Node. ++ * These additional attributes (i.e., DD_ID and/or DDS_ID) ++ * shall immediately follow the iSCSI Name or FC Port ++ * Name and precede the next SCN bitmap for the next ++ * notification message (if any). ++ */ ++ if (management && ev->ie_trigger) ++ dd = ev->ie_trigger; ++ ++ isns_scn_add_event(call, scn_bits, obj, dd); ++ ++ } ++ ++ isns_attr_release(timestamp); ++} ++ ++/* ++ * Obtain a socket to talk to this guy. ++ * Not entirely trivial - this can be both an established ++ * (incoming) connection, or one that we should establish. ++ * ++ * Note, we do not support transmission on the incoming ++ * connection yet. ++ */ ++static isns_socket_t * ++isns_scn_get_socket(isns_scn_t *scn) ++{ ++ isns_scn_funnel_t *f, *best = NULL; ++ isns_socket_t *sock; ++ unsigned int worst = 0, loops = 0, nfunnels; ++ ++ /* Keep it simple for now */ ++ if ((f = scn->scn_current_funnel) != NULL && f->scn_socket) { ++ if (!f->scn_bad) ++ return f->scn_socket; ++ /* Oops, we've seen timeouts on this socket. */ ++ isns_socket_free(f->scn_socket); ++ f->scn_socket = NULL; ++ } ++ ++again: ++ nfunnels = 0; ++ for (f = scn->scn_funnels; f; f = f->scn_next) { ++ unsigned int badness = f->scn_bad; ++ ++ if (!best || badness < best->scn_bad) ++ best = f; ++ if (badness > worst) ++ worst = badness; ++ nfunnels++; ++ } ++ ++ if (!best) ++ return NULL; ++ ++ sock = isns_connect_to_portal(&best->scn_portal); ++ if (sock == NULL) { ++ /* Make sure we try each funnel exactly once */ ++ best->scn_bad = worst + 1; ++ if (++loops < nfunnels) ++ goto again; ++ return NULL; ++ } ++ ++ /* Set the security context */ ++ isns_socket_set_security_ctx(sock, ++ isns_default_security_context(1)); ++ ++ isns_debug_scn("SCN: %s using portal %s\n", ++ scn->scn_name, ++ isns_portal_string(&best->scn_portal)); ++ scn->scn_current_funnel = best; ++ best->scn_socket = sock; ++ return sock; ++} ++ ++/* ++ * This is the callback function invoked when the SCN message reply ++ * comes in, or when the message timed out. ++ */ ++static void ++isns_process_scn_response(uint32_t xid, int status, isns_simple_t *msg) ++{ ++ isns_scn_t *scn; ++ ++ if (msg == NULL) { ++ isns_debug_scn("SCN timed out\n"); ++ return; ++ } ++ ++ isns_debug_scn("Received an SCN response\n"); ++ for (scn = isns_scn_list; scn; scn = scn->scn_next) { ++ if (scn->scn_pending && scn->scn_xid == xid) { ++ isns_debug_scn("SCN: %s acknowledged notification\n", ++ scn->scn_name); ++ isns_simple_free(scn->scn_pending); ++ scn->scn_pending = NULL; ++ ++ if (scn->scn_current_funnel) ++ scn->scn_current_funnel->scn_bad = 0; ++ } ++ } ++} ++/* ++ * Transmit all pending SCN messages ++ * ++ * 2.9.2 ++ * If a Network Entity has multiple Portals with registered SCN UDP Ports, ++ * then SCN messages SHALL be delivered to each Portal registered to ++ * receive such messages. ++ * ++ * FIXME: we should make this timer based just as the ESI code. ++ */ ++time_t ++isns_scn_transmit_all(void) ++{ ++ time_t now = time(NULL), next_timeout; ++ isns_scn_t *scn; ++ ++ for (scn = isns_scn_list; scn; scn = scn->scn_next) { ++ isns_simple_t *call; ++ isns_socket_t *sock; ++ ++ /* We do not allow more than one outstanding ++ * notification for now. */ ++ if ((call = scn->scn_pending) != NULL) { ++ if (scn->scn_timeout > now) ++ continue; ++ scn->scn_current_funnel->scn_bad++; ++ if (--(scn->scn_retries)) ++ goto retry; ++ isns_warning("SCN for %s timed out\n", ++ scn->scn_name); ++ isns_simple_free(call); ++ scn->scn_pending = NULL; ++ } ++ ++ if ((call = scn->scn_message) == NULL) ++ continue; ++ ++ isns_debug_scn("SCN: transmit pending message for %s\n", ++ scn->scn_name); ++ scn->scn_retries = isns_config.ic_scn_retries; ++ scn->scn_pending = call; ++ scn->scn_message = NULL; ++ ++retry: ++ if ((sock = isns_scn_get_socket(scn)) == NULL) { ++ /* Sorry, no can do. */ ++ isns_warning("SCN for %s dropped - no portal\n", ++ scn->scn_name); ++ scn->scn_pending = NULL; ++ isns_simple_free(call); ++ continue; ++ } ++ ++ isns_simple_transmit(sock, call, NULL, ++ isns_config.ic_scn_timeout, ++ isns_process_scn_response); ++ scn->scn_xid = call->is_xid; ++ scn->scn_timeout = now + isns_config.ic_scn_timeout; ++ } ++ ++ next_timeout = now + 3600; ++ for (scn = isns_scn_list; scn; scn = scn->scn_next) { ++ if (scn->scn_pending && scn->scn_timeout < next_timeout) ++ next_timeout = scn->scn_timeout; ++ } ++ ++ return next_timeout; ++} ++ ++/* ++ * Process an incoming State Change Notification ++ */ ++int ++isns_process_scn(isns_server_t *srv, isns_simple_t *call, isns_simple_t **reply) ++{ ++ isns_attr_list_t *list = &call->is_message_attrs; ++ isns_attr_t *dstattr, *tsattr; ++ const char *dst_name; ++ unsigned int i; ++ ++ /* The first attribute is the destination, and should match ++ * our source name. Don't bother checking. The second is the ++ * time stamp. ++ */ ++ if (list->ial_count < 2) ++ goto rejected; ++ ++ dstattr = list->ial_data[0]; ++ if (dstattr->ia_tag_id != ISNS_TAG_ISCSI_NAME ++ && dstattr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN) ++ goto rejected; ++ if (!ISNS_ATTR_IS_STRING(dstattr)) ++ goto rejected; ++ dst_name = dstattr->ia_value.iv_string; ++ ++ tsattr = list->ial_data[1]; ++ if (tsattr->ia_tag_id != ISNS_TAG_TIMESTAMP) ++ return ISNS_SCN_EVENT_REJECTED; ++ ++ for (i = 2; i < list->ial_count; ) { ++ isns_object_template_t *tmpl; ++ isns_attr_t *bmattr, *srcattr; ++ const char *node_name; ++ uint32_t bitmap; ++ ++ if (i + 1 >= list->ial_count) ++ goto rejected; ++ ++ bmattr = list->ial_data[i++]; ++ srcattr = list->ial_data[i++]; ++ ++ /* Validate that bitmap and node type match */ ++ switch (bmattr->ia_tag_id) { ++ case ISNS_TAG_ISCSI_SCN_BITMAP: ++ if (srcattr->ia_tag_id != ISNS_TAG_ISCSI_NAME) ++ goto rejected; ++ tmpl = &isns_iscsi_node_template; ++ break; ++ ++ case ISNS_TAG_IFCP_SCN_BITMAP: ++ if (srcattr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN) ++ goto rejected; ++ tmpl = &isns_fc_port_template; ++ break; ++ ++ default: ++ goto rejected; ++ } ++ ++ /* Skip over and DD_ID or DDS_ID attrs */ ++ while (i < list->ial_count) { ++ isns_attr_t *ddattr = list->ial_data[i]; ++ ++ if (ddattr->ia_tag_id == ISNS_TAG_ISCSI_SCN_BITMAP ++ || ddattr->ia_tag_id == ISNS_TAG_IFCP_SCN_BITMAP) ++ break; ++ ++i; ++ } ++ ++ if (!ISNS_ATTR_IS_UINT32(bmattr)) ++ goto rejected; ++ bitmap = bmattr->ia_value.iv_uint32; ++ ++ if (!ISNS_ATTR_IS_STRING(srcattr)) ++ goto rejected; ++ node_name = srcattr->ia_value.iv_string; ++ ++ if (srv->is_scn_callback) ++ srv->is_scn_callback(srv->is_db, bitmap, tmpl, node_name, dst_name); ++ } ++ ++ /* ++ * 5.7.5.8. SCN Response (SCNRsp) ++ * The SCNRsp response contains the SCN Destination Attribute ++ * representing the Node identifier that received the SCN. ++ */ ++ *reply = isns_create_scn(srv->is_source, ++ list->ial_data[0], ++ NULL); ++ return ISNS_SUCCESS; ++ ++rejected: ++ return ISNS_SCN_EVENT_REJECTED; ++} +diff --git a/utils/open-isns/scope.c b/utils/open-isns/scope.c +new file mode 100644 +index 0000000..9ee7f9a +--- /dev/null ++++ b/utils/open-isns/scope.c +@@ -0,0 +1,513 @@ ++/* ++ * Handle object visibility and scope. ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include "isns.h" ++#include "attrs.h" ++#include "objects.h" ++#include "message.h" ++#include "security.h" ++#include "util.h" ++#include "db.h" ++ ++struct isns_scope { ++ isns_db_t * ic_db; ++ unsigned int ic_users; ++ isns_object_t * ic_source_node; ++ ++ isns_object_template_t * ic_query_class; ++ ++ isns_object_list_t ic_dd_nodes; ++ isns_object_list_t ic_dd_portals; ++ isns_object_list_t ic_objects; ++}; ++ ++static int __isns_scope_collect_dd(uint32_t, void *); ++ ++/* ++ * Allocate an empty scope ++ */ ++isns_scope_t * ++isns_scope_alloc(isns_db_t *db) ++{ ++ isns_scope_t *scope; ++ ++ scope = isns_calloc(1, sizeof(*scope)); ++ ++ scope->ic_db = db; ++ scope->ic_users = 1; ++ return scope; ++} ++ ++isns_scope_t * ++isns_scope_get(isns_scope_t *scope) ++{ ++ if (scope) { ++ isns_assert(scope->ic_users); ++ scope->ic_users++; ++ } ++ return scope; ++} ++ ++void ++isns_scope_release(isns_scope_t *scope) ++{ ++ if (!scope) ++ return; ++ ++ isns_assert(scope->ic_users); ++ if (--(scope->ic_users)) ++ return; ++ ++ isns_object_release(scope->ic_source_node); ++ isns_object_list_destroy(&scope->ic_dd_nodes); ++ isns_object_list_destroy(&scope->ic_dd_portals); ++ isns_object_list_destroy(&scope->ic_objects); ++ isns_free(scope); ++} ++ ++/* ++ * Get the scope for this operation ++ */ ++isns_scope_t * ++isns_scope_for_call(isns_db_t *db, const isns_simple_t *call) ++{ ++ isns_source_t *source = call->is_source; ++ isns_object_t *node; ++ isns_scope_t *scope; ++ uint32_t node_type; ++ ++ /* FIXME use source->is_node and source->is_node_type */ ++ ++ /* When we get here, we already know that the client ++ * represents the specified source node. */ ++ node = isns_db_lookup_source_node(db, source); ++ ++ /* Allow unknown nodes to query the DB */ ++ if (node == NULL) { ++ node = isns_create_storage_node2(source, 0, NULL); ++ if (node == NULL) ++ return NULL; ++ source->is_untrusted = 1; ++ } ++ ++ if (isns_object_get_uint32(node, ISNS_TAG_ISCSI_NODE_TYPE, &node_type) ++ && (node_type & ISNS_ISCSI_CONTROL_MASK)) { ++ isns_object_release(node); ++ return isns_scope_get(db->id_global_scope); ++ } ++ ++ scope = isns_scope_alloc(db); ++ scope->ic_source_node = node; ++ ++ { ++ isns_object_list_t members = ISNS_OBJECT_LIST_INIT; ++ unsigned int i; ++ ++ isns_object_get_visible(node, db, &members); ++ isns_object_list_uniq(&members); ++ ++ /* If the node is not a member of any DD, allow it ++ * to at least talk to itself. */ ++ if (members.iol_count == 0) ++ isns_object_list_append(&members, node); ++ ++ /* Sort DD members into nodes and portals */ ++ for (i = 0; i < members.iol_count; ++i) { ++ isns_object_t *obj = members.iol_data[i]; ++ ++ if (obj->ie_state != ISNS_OBJECT_STATE_MATURE) ++ continue; ++ if (!isns_policy_validate_object_access(call->is_policy, ++ source, obj, ++ call->is_function)) ++ continue; ++ if (ISNS_IS_ISCSI_NODE(obj)) ++ isns_object_list_append(&scope->ic_dd_nodes, obj); ++ else ++ if (ISNS_IS_PORTAL(obj)) ++ isns_object_list_append(&scope->ic_dd_portals, obj); ++ } ++ isns_object_list_destroy(&members); ++ } ++ ++ return scope; ++} ++ ++/* ++ * Add an object to a scope ++ */ ++void ++isns_scope_add(isns_scope_t *scope, isns_object_t *obj) ++{ ++ isns_object_list_append(&scope->ic_objects, obj); ++} ++ ++int ++isns_scope_remove(isns_scope_t *scope, isns_object_t *obj) ++{ ++ return isns_object_list_remove(&scope->ic_objects, obj); ++} ++ ++/* ++ * Get all objects related through a portal group, optionally ++ * including the portal group objects themselves ++ */ ++static void ++__isns_scope_get_pg_related(isns_scope_t *scope, ++ const isns_object_t *obj, ++ isns_object_list_t *result) ++{ ++ isns_object_list_t temp = ISNS_OBJECT_LIST_INIT; ++ unsigned int i; ++ ++ /* Get all portal groups related to this object */ ++ isns_db_get_relationship_objects(scope->ic_db, ++ obj, ISNS_RELATION_PORTAL_GROUP, &temp); ++ ++ /* Include all portals/nodes that we can reach. */ ++ for (i = 0; i < temp.iol_count; ++i) { ++ isns_object_t *pg, *other; ++ uint32_t pgt; ++ ++ pg = temp.iol_data[i]; ++ ++ /* Skip any portal group objects with a PG tag of 0; ++ * these actually deny access. */ ++ if (!isns_object_get_uint32(pg, ISNS_TAG_PG_TAG, &pgt) ++ || pgt == 0) ++ continue; ++ ++ /* Get the other object. ++ * Note that isns_relation_get_other doesn't ++ * bump the reference count, so there's no need ++ * to call isns_object_release(other). */ ++ other = isns_relation_get_other(pg->ie_relation, obj); ++ if (other->ie_state != ISNS_OBJECT_STATE_MATURE) ++ continue; ++ ++ isns_object_list_append(result, other); ++ isns_object_list_append(result, pg); ++ } ++ ++ isns_object_list_destroy(&temp); ++} ++ ++/* ++ * Get all portals related to the given node. ++ * ++ * 2.2.2 ++ * Placing Portals of a Network Entity into Discovery Domains allows ++ * administrators to indicate the preferred IP Portal interface through ++ * which storage traffic should access specific Storage Nodes of that ++ * Network Entity. If no Portals of a Network Entity have been placed ++ * into a DD, then queries scoped to that DD SHALL report all Portals of ++ * that Network Entity. If one or more Portals of a Network Entity have ++ * been placed into a DD, then queries scoped to that DD SHALL report ++ * only those Portals that have been explicitly placed in the DD. ++ */ ++static void ++__isns_scope_get_portals(isns_scope_t *scope, ++ const isns_object_t *node, ++ isns_object_list_t *portals, ++ isns_object_list_t *pgs, ++ int unique) ++{ ++ isns_object_list_t related = ISNS_OBJECT_LIST_INIT; ++ unsigned int i, specific = 0; ++ ++ /* Get all portals and portal groups related to the ++ * given node. This will put pairs of (portal, portal-group) ++ * on the list. ++ */ ++ __isns_scope_get_pg_related(scope, node, &related); ++ ++ /* If we're querying for our own portals, don't limit ++ * visibility. */ ++ if (node == scope->ic_source_node) ++ goto report_all_portals; ++ ++ /* Check if any of the portals is mentioned in the DD ++ * FIXME: There is some ambiguity over what the right ++ * answer is when you have two nodes (initiator, target), ++ * and two discovery domains linking the two. One ++ * DD mentions a specific portal through which target ++ * should be accessed; the other DD does not (allowing ++ * use of any portal in that entity). Which portals ++ * to return here? ++ * We go for the strict interpretation, ie if *any* DD ++ * restricts access to certain portals, we report only ++ * those. ++ */ ++ for (i = 0; i < related.iol_count; i += 2) { ++ isns_object_t *portal = related.iol_data[i]; ++ ++ if (isns_object_list_contains(&scope->ic_dd_portals, portal)) { ++ if (portals ++ && !(unique || isns_object_list_contains(portals, portal))) ++ isns_object_list_append(portals, portal); ++ if (pgs) ++ isns_object_list_append(pgs, ++ related.iol_data[i + 1]); ++ specific++; ++ } ++ } ++ ++ if (specific) ++ goto out; ++ ++report_all_portals: ++ /* No specific portal given for this node. Add them all. */ ++ for (i = 0; i < related.iol_count; i += 2) { ++ isns_object_t *portal = related.iol_data[i]; ++ ++ if (portals ++ && !(unique && isns_object_list_contains(portals, portal))) ++ isns_object_list_append(portals, portal); ++ if (pgs) ++ isns_object_list_append(pgs, ++ related.iol_data[i + 1]); ++ } ++ ++out: ++ isns_object_list_destroy(&related); ++} ++ ++/* ++ * Get all nodes reachable through a given portal ++ * This is really the same as __isns_scope_get_portals ++ * minus the special casing for preferred portals. ++ * Still, let's put this into it's own function - the whole ++ * thing is already complex enough already. ++ */ ++static void ++__isns_scope_get_nodes(isns_scope_t *scope, ++ const isns_object_t *portal, ++ isns_object_list_t *nodes, ++ isns_object_list_t *pgs, ++ int unique) ++{ ++ isns_object_list_t related = ISNS_OBJECT_LIST_INIT; ++ unsigned int i; ++ ++ /* Get all nodes and portal groups related to the ++ * given node. This will put pairs of (nodes, portal-group) ++ * on the list. ++ */ ++ __isns_scope_get_pg_related(scope, portal, &related); ++ ++ for (i = 0; i < related.iol_count; i += 2) { ++ isns_object_t *node = related.iol_data[i]; ++ ++ if (nodes ++ && !(unique && isns_object_list_contains(nodes, node))) ++ isns_object_list_append(nodes, node); ++ if (pgs) ++ isns_object_list_append(pgs, ++ related.iol_data[i + 1]); ++ } ++ ++ isns_object_list_destroy(&related); ++} ++ ++static void ++__isns_scope_get_default_dd(isns_scope_t *scope) ++{ ++ isns_object_t *obj; ++ ++ if (isns_config.ic_use_default_domain) { ++ obj = isns_create_default_domain(); ++ isns_object_list_append(&scope->ic_objects, obj); ++ isns_object_release(obj); ++ } ++} ++ ++ ++/* ++ * Scope the query ++ */ ++static void ++__isns_scope_prepare_query(isns_scope_t *scope, ++ isns_object_template_t *tmpl) ++{ ++ isns_object_list_t *nodes; ++ unsigned int i; ++ ++ /* Global and default scope have no source node; they're just ++ * a list of objects. ++ */ ++ if (scope->ic_source_node == NULL) ++ return; ++ ++ if (scope->ic_query_class) { ++ if (scope->ic_query_class == tmpl) ++ return; ++ isns_object_list_destroy(&scope->ic_objects); ++ } ++ scope->ic_query_class = tmpl; ++ ++ nodes = &scope->ic_dd_nodes; ++ if (tmpl == &isns_entity_template) { ++ for (i = 0; i < nodes->iol_count; ++i) { ++ isns_object_t *obj = nodes->iol_data[i]; ++ ++ if (obj->ie_container) ++ isns_object_list_append(&scope->ic_objects, ++ obj->ie_container); ++ } ++ } else ++ if (tmpl == &isns_iscsi_node_template) { ++ for (i = 0; i < nodes->iol_count; ++i) { ++ isns_object_t *obj = nodes->iol_data[i]; ++ ++ isns_object_list_append(&scope->ic_objects, obj); ++ } ++ } else ++ if (tmpl == &isns_portal_template) { ++ for (i = 0; i < nodes->iol_count; ++i) { ++ isns_object_t *obj = nodes->iol_data[i]; ++ ++ __isns_scope_get_portals(scope, obj, ++ &scope->ic_objects, NULL, 0); ++ } ++ } else ++ if (tmpl == &isns_iscsi_pg_template) { ++ for (i = 0; i < nodes->iol_count; ++i) { ++ isns_object_t *obj = nodes->iol_data[i]; ++ ++ __isns_scope_get_portals(scope, obj, ++ NULL, &scope->ic_objects, 0); ++ } ++ } else ++ if (tmpl == &isns_dd_template) { ++ isns_object_t *node = scope->ic_source_node; ++ ++ if (node && !isns_bitvector_is_empty(node->ie_membership)) ++ isns_bitvector_foreach(node->ie_membership, ++ __isns_scope_collect_dd, ++ scope); ++ else ++ __isns_scope_get_default_dd(scope); ++ } ++ ++ isns_object_list_uniq(&scope->ic_objects); ++} ++ ++static int ++__isns_scope_collect_dd(uint32_t dd_id, void *ptr) ++{ ++ isns_scope_t *scope = ptr; ++ isns_object_t *dd; ++ ++ dd = isns_db_vlookup(scope->ic_db, &isns_dd_template, ++ ISNS_TAG_DD_ID, dd_id, ++ 0); ++ if (dd) { ++ isns_object_list_append(&scope->ic_objects, dd); ++ isns_object_release(dd); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Lookup functions for scope ++ */ ++int ++isns_scope_gang_lookup(isns_scope_t *scope, ++ isns_object_template_t *tmpl, ++ const isns_attr_list_t *match, ++ isns_object_list_t *result) ++{ ++ isns_assert(tmpl); ++ ++ if (!scope) ++ return 0; ++ ++ __isns_scope_prepare_query(scope, tmpl); ++ return isns_object_list_gang_lookup(&scope->ic_objects, ++ tmpl, match, result); ++} ++ ++/* ++ * Get related objects. ++ * This is used by the query code. ++ */ ++void ++isns_scope_get_related(isns_scope_t *scope, ++ const isns_object_t *origin, ++ unsigned int type_mask, ++ isns_object_list_t *result) ++{ ++ isns_object_template_t *tmpl = origin->ie_template; ++ isns_object_list_t nodes_result = ISNS_OBJECT_LIST_INIT; ++ isns_object_list_t portals_result = ISNS_OBJECT_LIST_INIT; ++ isns_object_list_t *members = &scope->ic_dd_nodes; ++ unsigned int i; ++ ++ if (tmpl == &isns_entity_template) { ++ /* Entity: include all storage nodes contained, ++ * the portals through which to reach them, and ++ * the portal groups for those. */ ++ for (i = 0; i < members->iol_count; ++i) { ++ isns_object_t *obj = members->iol_data[i]; ++ ++ if (obj->ie_container != origin) ++ continue; ++ ++ isns_object_list_append(&nodes_result, obj); ++ __isns_scope_get_portals(scope, obj, ++ &portals_result, ++ &portals_result, 1); ++ } ++ } else ++ if (tmpl == &isns_iscsi_node_template) { ++ /* Storage node: include all portals through ++ * which it can be reached, and the portal ++ * groups for those. */ ++ __isns_scope_get_portals(scope, origin, ++ &portals_result, ++ &portals_result, 1); ++ /* FIXME: Include all discovery domains the ++ * node is a member of. */ ++ } else ++ if (tmpl == &isns_portal_template) { ++ /* Portal: include all storage nodes which can ++ * be reached through it, and the portal groups ++ * for those. */ ++ __isns_scope_get_nodes(scope, origin, ++ &portals_result, ++ &portals_result, 1); ++ } else ++ if (tmpl == &isns_iscsi_pg_template) { ++ /* Portal group: PGs *are* a relationship, but ++ * unclear how this should be handled. ++ * Return nothing for now. */ ++ } else ++ if (tmpl == &isns_dd_template) { ++ /* Discovery domain: no related objects. */ ++ } ++ ++ isns_object_list_append_list(result, &nodes_result); ++ isns_object_list_append_list(result, &portals_result); ++ ++ isns_object_list_destroy(&nodes_result); ++ isns_object_list_destroy(&portals_result); ++} ++ ++isns_object_t * ++isns_scope_get_next(isns_scope_t *scope, ++ isns_object_template_t *tmpl, ++ const isns_attr_list_t *current, ++ const isns_attr_list_t *match) ++{ ++ if (!tmpl || !scope) ++ return NULL; ++ ++ __isns_scope_prepare_query(scope, tmpl); ++ return __isns_db_get_next(&scope->ic_objects, tmpl, current, match); ++} +diff --git a/utils/open-isns/security.c b/utils/open-isns/security.c +new file mode 100644 +index 0000000..548ce18 +--- /dev/null ++++ b/utils/open-isns/security.c +@@ -0,0 +1,437 @@ ++/* ++ * Security functions for iSNS ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include "isns.h" ++#include "security.h" ++#include "source.h" ++#include "util.h" ++#include "config.h" ++ ++#ifdef WITH_SECURITY ++ ++/* ++ * Allocate a security peer ++ */ ++static isns_principal_t * ++isns_create_principal(const char *spi, size_t spi_len, EVP_PKEY *pk) ++{ ++ char keydesc[32]; ++ isns_principal_t *peer; ++ ++ peer = isns_calloc(1, sizeof(*peer)); ++ peer->is_users = 1; ++ if (spi) { ++ peer->is_name = isns_malloc(spi_len + 1); ++ memcpy(peer->is_name, spi, spi_len); ++ peer->is_name[spi_len] = '\0'; ++ peer->is_namelen = spi_len; ++ } ++ ++ peer->is_key = pk; ++ if (pk) { ++ const char *algo; ++ ++ switch (pk->type) { ++ case EVP_PKEY_DSA: algo = "DSA"; break; ++ case EVP_PKEY_RSA: algo = "RSA"; break; ++ default: algo = "unknown"; break; ++ } ++ ++ snprintf(keydesc, sizeof(keydesc), " (%s/%u)", ++ algo, EVP_PKEY_bits(pk)); ++ } ++ ++ isns_debug_auth("Created security principal \"%s\"%s\n", ++ peer->is_name, keydesc); ++ return peer; ++} ++ ++static void ++isns_principal_set_key(isns_principal_t *princ, EVP_PKEY *key) ++{ ++ if (princ->is_key == key) ++ return; ++ if (princ->is_key) ++ EVP_PKEY_free(princ->is_key); ++ princ->is_key = key; ++} ++ ++void ++isns_principal_free(isns_principal_t *peer) ++{ ++ if (!peer) ++ return; ++ ++ isns_assert(peer->is_users); ++ if (--(peer->is_users)) ++ return; ++ ++ if (peer->is_name) ++ isns_free(peer->is_name); ++ if (peer->is_key) ++ EVP_PKEY_free(peer->is_key); ++ isns_policy_release(peer->is_policy); ++ isns_free(peer); ++} ++ ++/* ++ * Set the principal's name ++ */ ++void ++isns_principal_set_name(isns_principal_t *princ, const char *spi) ++{ ++ isns_assign_string(&princ->is_name, spi); ++ isns_debug_auth("Setting principal name to \"%s\"\n", spi); ++} ++ ++const char * ++isns_principal_name(const isns_principal_t *princ) ++{ ++ return princ->is_name; ++} ++ ++/* ++ * Cache policy in the principal object. ++ */ ++void ++isns_principal_set_policy(isns_principal_t *princ, ++ isns_policy_t *policy) ++{ ++ if (policy) ++ policy->ip_users++; ++ isns_policy_release(princ->is_policy); ++ princ->is_policy = policy; ++} ++ ++/* ++ * Key management functions for a security context. ++ */ ++isns_principal_t * ++isns_security_load_privkey(isns_security_t *ctx, const char *filename) ++{ ++ EVP_PKEY *pkey; ++ ++ isns_debug_auth("Loading private %s key from %s\n", ++ ctx->is_name, filename); ++ if (!ctx->is_load_private) ++ return NULL; ++ if (!(pkey = ctx->is_load_private(ctx, filename))) { ++ isns_error("Unable to load private %s key from %s\n", ++ ctx->is_name, filename); ++ return NULL; ++ } ++ ++ return isns_create_principal(NULL, 0, pkey); ++} ++ ++isns_principal_t * ++isns_security_load_pubkey(isns_security_t *ctx, const char *filename) ++{ ++ EVP_PKEY *pkey; ++ ++ isns_debug_auth("Loading public %s key from %s\n", ++ ctx->is_name, filename); ++ if (!ctx->is_load_public) ++ return NULL; ++ if (!(pkey = ctx->is_load_public(ctx, filename))) { ++ isns_error("Unable to load public %s key from %s\n", ++ ctx->is_name, filename); ++ return NULL; ++ } ++ ++ return isns_create_principal(NULL, 0, pkey); ++} ++ ++void ++isns_security_set_identity(isns_security_t *ctx, isns_principal_t *princ) ++{ ++ if (princ) ++ princ->is_users++; ++ if (ctx->is_self) ++ isns_principal_free(ctx->is_self); ++ ctx->is_self = princ; ++} ++ ++void ++isns_add_principal(isns_security_t *ctx, isns_principal_t *princ) ++{ ++ if (princ) ++ princ->is_users++; ++ princ->is_next = ctx->is_peers; ++ ctx->is_peers = princ; ++} ++ ++isns_principal_t * ++isns_get_principal(isns_security_t *ctx, const char *spi, size_t spi_len) ++{ ++ isns_principal_t *princ; ++ isns_policy_t *policy; ++ isns_keystore_t *ks; ++ EVP_PKEY *pk; ++ ++ ks = ctx->is_peer_keys; ++ ++ for (princ = ctx->is_peers; princ; princ = princ->is_next) { ++ /* In a client socket, we set the (expected) ++ * public key of the peer through ++ * isns_security_set_peer_key, which will ++ * just put it on the peers list. ++ * This key usually has no name. ++ */ ++ if (princ->is_name == NULL) { ++ princ->is_users++; ++ return princ; ++ } ++ if (spi_len == princ->is_namelen ++ && !memcmp(princ->is_name, spi, spi_len)) { ++ /* Check whether the cached key and policy ++ * might be stale. */ ++ if (ks && ks->ic_generation != princ->is_generation) { ++ pk = ks->ic_find(ks, spi, spi_len); ++ if (pk == NULL) { ++ isns_debug_auth("Unable to refresh key " ++ "for principal %.*s - probably deleted\n", ++ spi_len, spi); ++ return NULL; ++ } ++ isns_debug_auth("Refresh key for principal %.*s\n", ++ spi_len, spi); ++ isns_principal_set_key(princ, pk); ++ princ->is_users++; ++ goto refresh_policy; ++ } ++ princ->is_users++; ++ return princ; ++ } ++ } ++ ++ if ((ks = ctx->is_peer_keys) == NULL) ++ return NULL; ++ ++ if (!(pk = ks->ic_find(ks, spi, spi_len))) ++ return NULL; ++ princ = isns_create_principal(spi, spi_len, pk); ++ ++ /* Add it to the list */ ++ princ->is_next = ctx->is_peers; ++ ctx->is_peers = princ; ++ princ->is_users++; ++ ++ /* Bind the policy for this peer */ ++refresh_policy: ++ if (!ks->ic_get_policy ++ || !(policy = ks->ic_get_policy(ks, spi, spi_len))) ++ policy = isns_policy_default(spi, spi_len); ++ ++ /* If no entity is set, use the SPI */ ++ if (policy->ip_entity == NULL) ++ isns_assign_string(&policy->ip_entity, policy->ip_name); ++ ++ /* If the list of permitted node names is empty, ++ * default to the standard pattern derived from ++ * the reversed entity name */ ++ if (policy->ip_node_names.count == 0) { ++ char *pattern; ++ ++ pattern = isns_build_source_pattern(policy->ip_entity); ++ if (pattern != NULL) ++ isns_string_array_append(&policy->ip_node_names, ++ pattern); ++ isns_free(pattern); ++ } ++ ++ isns_principal_set_policy(princ, policy); ++ isns_policy_release(policy); ++ ++ /* Remember the keystore generation number */ ++ princ->is_generation = ks->ic_generation; ++ ++ return princ; ++} ++ ++/* ++ * Create a keystore for a security context. ++ * Key stores let the server side retrieve the ++ * keys associated with a given SPI. ++ * ++ * For now, we support just simple key stores, ++ * but this could be extended to support ++ * URLs such as ldaps://ldap.example.com ++ */ ++isns_keystore_t * ++isns_create_keystore(const char *spec) ++{ ++ if (*spec != '/') ++ return NULL; ++ ++ return isns_create_simple_keystore(spec); ++} ++ ++/* ++ * Attach the keystore to the security context ++ */ ++void ++isns_security_set_keystore(isns_security_t *ctx, ++ isns_keystore_t *ks) ++{ ++ ctx->is_peer_keys = ks; ++} ++ ++/* ++ * Check that the client supplied time stamp is within a ++ * certain window. ++ */ ++static int ++isns_security_check_timestamp(isns_security_t *ctx, ++ isns_principal_t *peer, ++ uint64_t timestamp) ++{ ++ int64_t delta; ++ ++ /* The time stamp must not be earlier than timestamp_jitter ++ * before the last message received. */ ++ if (peer->is_timestamp) { ++ delta = timestamp - peer->is_timestamp; ++ if (delta < -(int64_t) ctx->is_timestamp_jitter) ++ return 0; ++ } ++ ++ /* We allow the client's clock to diverge from ours, within ++ * certain limits. */ ++ if (ctx->is_replay_window != 0) { ++ time_t now = time(NULL); ++ ++ delta = timestamp - now; ++ if (delta < 0) ++ delta = -delta; ++ if (delta > ctx->is_replay_window) ++ return 0; ++ } ++ ++ peer->is_timestamp = timestamp; ++ return 1; ++} ++ ++int ++isns_security_sign(isns_security_t *ctx, isns_principal_t *peer, ++ buf_t *bp, struct isns_authblk *auth) ++{ ++ if (!ctx->is_sign) { ++ isns_debug_auth("isns_security_sign: auth context without " ++ "sign handler.\n"); ++ return 0; ++ } ++ if (!ctx->is_sign(ctx, peer, bp, auth)) { ++ isns_debug_auth("Failed to sign message, spi=%s\n", ++ peer->is_name); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int ++isns_security_verify(isns_security_t *ctx, isns_principal_t *peer, ++ buf_t *bp, struct isns_authblk *auth) ++{ ++ if (!isns_security_check_timestamp(ctx, peer, auth->iab_timestamp)) { ++ isns_debug_auth("Possible replay attack (bad timestamp) " ++ "from spi=%s\n", peer->is_name); ++ return 0; ++ } ++ ++ if (!ctx->is_verify) { ++ isns_debug_auth("isns_security_verify: auth context without " ++ "verify handler.\n"); ++ return 0; ++ } ++ if (!ctx->is_verify(ctx, peer, bp, auth)) { ++ isns_debug_auth("Failed to authenticate message, spi=%s\n", ++ peer->is_name); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* ++ * Initialize security services. ++ */ ++int ++isns_security_init(void) ++{ ++ if (!isns_config.ic_dsa.param_file) { ++ isns_error("No DSA parameter file - please edit configuration\n"); ++ return 0; ++ } ++ ++ if (!isns_dsa_init_params(isns_config.ic_dsa.param_file)) ++ return 0; ++ ++ if (!isns_config.ic_auth_key_file) { ++ isns_error("No AuthKey specified; please edit configuration\n"); ++ return 0; ++ } ++ ++ if (!isns_dsa_init_key(isns_config.ic_auth_key_file)) ++ return 0; ++ ++ return 1; ++} ++ ++#else /* WITH_SECURITY */ ++ ++static void ++isns_no_security(void) ++{ ++ static int complain = 0; ++ ++ if (complain++ < 5) ++ isns_error("iSNS authentication disabled in this build\n"); ++} ++ ++int ++isns_security_init(void) ++{ ++ isns_no_security(); ++ return 0; ++} ++ ++isns_keystore_t * ++isns_create_keystore(const char *spec) ++{ ++ isns_no_security(); ++ return NULL; ++} ++ ++void ++isns_security_set_keystore(isns_security_t *ctx, ++ isns_keystore_t *ks) ++{ ++ isns_no_security(); ++} ++ ++void ++isns_principal_free(isns_principal_t *peer) ++{ ++} ++ ++isns_principal_t * ++isns_get_principal(isns_security_t *ctx, const char *spi, size_t spi_len) ++{ ++ return NULL; ++} ++ ++const char * ++isns_principal_name(const isns_principal_t *princ) ++{ ++ return NULL; ++} ++ ++#endif /* WITH_SECURITY */ +diff --git a/utils/open-isns/security.h b/utils/open-isns/security.h +new file mode 100644 +index 0000000..4b928ff +--- /dev/null ++++ b/utils/open-isns/security.h +@@ -0,0 +1,185 @@ ++/* ++ * Security functions for iSNS ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#ifndef ISNS_SECURITY_H ++#define ISNS_SECURITY_H ++#include "buffer.h" ++#include "util.h" ++ ++ ++#ifdef WITH_SECURITY ++#include ++#else ++#define EVP_PKEY void ++#endif ++ ++/* ++ * Security context ++ */ ++struct isns_security { ++ const char * is_name; ++ unsigned int is_type; ++ unsigned int is_replay_window; ++ unsigned int is_timestamp_jitter; ++ ++ /* Our own key and identity */ ++ isns_principal_t * is_self; ++ ++ /* Key store for peer keys */ ++ isns_principal_t * is_peers; ++ isns_keystore_t * is_peer_keys; ++ ++ EVP_PKEY * (*is_load_private)(isns_security_t *ctx, ++ const char *filename); ++ EVP_PKEY * (*is_load_public)(isns_security_t *ctx, ++ const char *filename); ++ int (*is_verify)(isns_security_t *ctx, ++ isns_principal_t *peer, ++ buf_t *pdu, ++ const struct isns_authblk *); ++ int (*is_sign)(isns_security_t *ctx, ++ isns_principal_t *peer, ++ buf_t *pdu, ++ struct isns_authblk *); ++}; ++ ++struct isns_principal { ++ unsigned int is_users; ++ isns_principal_t * is_next; ++ char * is_name; ++ unsigned int is_namelen; ++ EVP_PKEY * is_key; ++ unsigned int is_generation; ++ uint64_t is_timestamp; ++ ++ isns_policy_t * is_policy; ++}; ++ ++struct isns_policy { ++ unsigned int ip_users; ++ unsigned int ip_gen; ++ ++ /* SPI */ ++ char * ip_name; ++ ++ /* The client's entity name. This is usually ++ * the FQDN. */ ++ char * ip_entity; ++ ++ /* Bitmap of functions the client is ++ * permitted to call. */ ++ unsigned int ip_functions; ++ ++ /* Bitmap of object types the client is ++ * permitted to register (uses iot_handle) */ ++ unsigned int ip_object_types; ++ ++ /* Names of storage nodes the client is permitted ++ * to register. */ ++ struct string_array ip_node_names; ++ ++ /* Storage node types the client is permitted ++ * to read or modify. */ ++ unsigned int ip_node_types; ++ ++ /* The client's default Discovery Domain */ ++ char * ip_dd_default; ++}; ++ ++#define ISNS_PERMISSION_READ 0x01 ++#define ISNS_PERMISSION_WRITE 0x02 ++#define ISNS_ACCESS(t, p) ((p) << (2 * (t))) ++#define ISNS_ACCESS_W(t) ISNS_ACCESS(t, ISNS_PERMISSION_WRITE) ++#define ISNS_ACCESS_R(t) ISNS_ACCESS(t, ISNS_PERMISSION_READ) ++#define ISNS_ACCESS_RW(t) ISNS_ACCESS(t, ISNS_PERMISSION_READ|ISNS_PERMISSION_WRITE) ++ ++#define ISNS_DEFAULT_OBJECT_ACCESS \ ++ ISNS_ACCESS_RW(ISNS_OBJECT_TYPE_ENTITY) | \ ++ ISNS_ACCESS_RW(ISNS_OBJECT_TYPE_NODE) | \ ++ ISNS_ACCESS_RW(ISNS_OBJECT_TYPE_FC_PORT) | \ ++ ISNS_ACCESS_RW(ISNS_OBJECT_TYPE_FC_NODE) | \ ++ ISNS_ACCESS_RW(ISNS_OBJECT_TYPE_PORTAL) | \ ++ ISNS_ACCESS_RW(ISNS_OBJECT_TYPE_PG) | \ ++ ISNS_ACCESS_R(ISNS_OBJECT_TYPE_DD) ++ ++struct isns_keystore { ++ char * ic_name; ++ unsigned int ic_generation; ++ EVP_PKEY * (*ic_find)(isns_keystore_t *, ++ const char *, size_t); ++ isns_policy_t * (*ic_get_policy)(isns_keystore_t *, ++ const char *, size_t); ++}; ++ ++extern isns_principal_t * isns_get_principal(isns_security_t *, ++ const char *, size_t); ++extern int isns_security_sign(isns_security_t *, ++ isns_principal_t *, buf_t *, ++ struct isns_authblk *); ++extern int isns_security_verify(isns_security_t *, ++ isns_principal_t *, buf_t *, ++ struct isns_authblk *); ++extern int isns_security_protected_entity(isns_security_t *, ++ const char *); ++ ++extern isns_keystore_t * isns_create_keystore(const char *); ++extern isns_keystore_t * isns_create_simple_keystore(const char *); ++extern isns_keystore_t * isns_create_db_keystore(isns_db_t *); ++ ++extern int isns_authblock_encode(buf_t *, ++ const struct isns_authblk *); ++extern int isns_authblock_decode(buf_t *, ++ struct isns_authblk *); ++ ++extern isns_policy_t * __isns_policy_alloc(const char *, size_t); ++extern isns_policy_t * isns_policy_bind(const isns_message_t *); ++extern void isns_principal_set_policy(isns_principal_t *, ++ isns_policy_t *); ++extern void isns_policy_release(isns_policy_t *); ++extern int isns_policy_validate_function(const isns_policy_t *, ++ const isns_message_t *); ++extern int isns_policy_validate_source(const isns_policy_t *, ++ const isns_source_t *); ++extern int isns_policy_validate_object_access(const isns_policy_t *, ++ const isns_source_t *, ++ const isns_object_t *, ++ unsigned int); ++extern int isns_policy_validate_object_update(const isns_policy_t *, ++ const isns_source_t *, ++ const isns_object_t *, ++ const isns_attr_list_t *, ++ unsigned int); ++extern int isns_policy_validate_object_creation(const isns_policy_t *, ++ const isns_source_t *, ++ isns_object_template_t *, ++ const isns_attr_list_t *, ++ const isns_attr_list_t *, ++ unsigned int); ++extern int isns_policy_validate_object_type(const isns_policy_t *, ++ isns_object_template_t *, ++ unsigned int function); ++extern int isns_policy_validate_node_type(const isns_policy_t *, ++ uint32_t type); ++extern int isns_policy_validate_entity(const isns_policy_t *, ++ const char *); ++extern int isns_policy_validate_node_name(const isns_policy_t *, ++ const char *); ++extern int isns_policy_validate_scn_bitmap(const isns_policy_t *, ++ uint32_t); ++extern const char * isns_policy_default_entity(const isns_policy_t *); ++extern isns_policy_t * isns_policy_default(const char *, size_t); ++extern isns_policy_t * isns_policy_server(void); ++ ++extern EVP_PKEY * isns_dsa_decode_public(const void *, size_t); ++extern int isns_dsa_encode_public(EVP_PKEY *, ++ void **, size_t *); ++extern EVP_PKEY * isns_dsa_load_public(const char *); ++extern int isns_dsa_store_private(const char *, EVP_PKEY *); ++extern EVP_PKEY * isns_dsa_generate_key(void); ++extern int isns_dsa_init_params(const char *); ++extern int isns_dsa_init_key(const char *); ++ ++#endif /* ISNS_SECURITY_H */ +diff --git a/utils/open-isns/server.c b/utils/open-isns/server.c +new file mode 100644 +index 0000000..0f1c937 +--- /dev/null ++++ b/utils/open-isns/server.c +@@ -0,0 +1,236 @@ ++/* ++ * iSNS server side functions ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include "isns.h" ++#include "util.h" ++#include "security.h" ++#include "message.h" ++ ++static int isns_not_supported(isns_server_t *, isns_simple_t *, isns_simple_t **); ++ ++struct isns_service_ops isns_default_service_ops = { ++ .process_registration = isns_process_registration, ++ .process_query = isns_process_query, ++ .process_getnext = isns_process_getnext, ++ .process_deregistration = isns_process_deregistration, ++ .process_scn_registration = isns_process_scn_register, ++ .process_scn_deregistration = isns_process_scn_deregistration, ++ .process_scn_event = isns_not_supported, ++ .process_dd_registration = isns_process_dd_registration, ++ .process_dd_deregistration= isns_process_dd_deregistration, ++}; ++ ++struct isns_service_ops isns_callback_service_ops = { ++ .process_esi = isns_process_esi, ++ .process_scn = isns_process_scn, ++}; ++ ++/* ++ * Create a server object ++ */ ++isns_server_t * ++isns_create_server(isns_source_t *source, isns_db_t *db, ++ struct isns_service_ops *ops) ++{ ++ isns_server_t *srv; ++ ++ if (source == NULL) { ++ isns_error("%s: source name not set\n", __FUNCTION__); ++ return NULL; ++ } ++ ++ srv = isns_calloc(1, sizeof(*srv)); ++ srv->is_source = isns_source_get(source); ++ srv->is_db = db; ++ srv->is_ops = ops; ++ ++ return srv; ++} ++ ++void ++isns_server_set_scn_callback(isns_server_t *srv, isns_scn_callback_fn_t *func) ++{ ++ srv->is_scn_callback = func; ++} ++ ++/* ++ * Try to handle transactions safely. ++ * This isn't perfect, because there's state outside the DB (for instance ++ * the DD information) ++ */ ++static int ++isns_begin_write_operation(isns_server_t *srv, isns_simple_t *msg, int *status) ++{ ++ isns_db_begin_transaction(srv->is_db); ++ return 1; ++} ++ ++static void ++isns_end_write_operation(isns_server_t *srv, isns_simple_t *msg, int *status) ++{ ++ if (*status == ISNS_SUCCESS) ++ isns_db_commit(srv->is_db); ++ else ++ isns_db_rollback(srv->is_db); ++} ++ ++static inline int ++isns_begin_read_operation(isns_server_t *srv, isns_simple_t *msg, int *status) ++{ ++ return 1; ++} ++ ++static void ++isns_end_read_operation(isns_server_t *srv, isns_simple_t *msg, int *status) ++{ ++} ++ ++/* ++ * Process an incoming message ++ */ ++isns_message_t * ++isns_process_message(isns_server_t *srv, isns_message_t *msg) ++{ ++ struct isns_service_ops *ops = srv->is_ops; ++ uint16_t function = msg->im_header.i_function; ++ int status = ISNS_SUCCESS; ++ isns_simple_t *call = NULL, *reply = NULL; ++ isns_message_t *res_msg = NULL; ++ isns_db_t *db = srv->is_db; ++ ++ status = isns_simple_decode(msg, &call); ++ if (status) { ++ isns_debug_message("Failed to decode %s request: %s\n", ++ isns_function_name(msg->im_header.i_function), ++ isns_strerror(status)); ++ goto reply; ++ } ++ ++ isns_simple_print(call, isns_debug_message); ++ ++ /* Set policy and privileges based on the ++ * sender's identity. */ ++ if (!(call->is_policy = isns_policy_bind(msg))) ++ goto err_unauthorized; ++ ++ if (!isns_policy_validate_function(call->is_policy, msg)) ++ goto err_unauthorized; ++ ++ /* Checks related to the message source. ++ * Note - some messages do not use a source. ++ */ ++ if (call->is_source) { ++ /* Validate the message source. This checks whether the client ++ * is permitted to use this source node name. ++ * Beware - not all messages include a source. ++ */ ++ if (!isns_policy_validate_source(call->is_policy, call->is_source)) ++ goto err_unauthorized; ++ ++ /* This may fail if the source node isn't in the DB yet. */ ++ isns_source_set_node(call->is_source, db); ++ ++ /* ++ * 6.2.6. Registration Period ++ * ++ * The registration SHALL be removed from the iSNS database ++ * if an iSNS Protocol message is not received from the ++ * iSNS client before the registration period has expired. ++ * Receipt of any iSNS Protocol message from the iSNS client ++ * automatically refreshes the Entity Registration Period and ++ * Entity Registration Timestamp. To prevent a registration ++ * from expiring, the iSNS client should send an iSNS Protocol ++ * message to the iSNS server at intervals shorter than the ++ * registration period. Such a message can be as simple as a ++ * query for one of its own attributes, using its associated ++ * iSCSI Name or FC Port Name WWPN as the Source attribute. ++ */ ++ /* Thusly, we update the timestamps of all entities ++ * registered by this source. */ ++ isns_entity_touch(call->is_source->is_entity); ++ } ++ ++ /* Handle the requested function. If the function vector is ++ * NULL, silently discard the message. */ ++ switch (function) { ++#define DO(rw, FUNCTION, __function) \ ++ case FUNCTION: \ ++ if (!ops->__function) \ ++ goto no_reply; \ ++ \ ++ if (!isns_begin_##rw##_operation(srv, call, &status)) \ ++ break; \ ++ status = ops->__function(srv, call, &reply); \ ++ isns_end_##rw##_operation(srv, call, &status); \ ++ break ++ ++ DO(write, ISNS_DEVICE_ATTRIBUTE_REGISTER, process_registration); ++ DO(read, ISNS_DEVICE_ATTRIBUTE_QUERY, process_query); ++ DO(read, ISNS_DEVICE_GET_NEXT, process_getnext); ++ DO(write, ISNS_DEVICE_DEREGISTER, process_deregistration); ++ DO(write, ISNS_DD_REGISTER, process_dd_registration); ++ DO(write, ISNS_DD_DEREGISTER, process_dd_deregistration); ++ DO(read, ISNS_SCN_REGISTER, process_scn_registration); ++ DO(read, ISNS_SCN_DEREGISTER, process_scn_deregistration); ++ DO(read, ISNS_SCN_EVENT, process_scn_event); ++ DO(read, ISNS_STATE_CHANGE_NOTIFICATION, process_scn); ++ DO(read, ISNS_ENTITY_STATUS_INQUIRY, process_esi); ++ DO(read, ISNS_HEARTBEAT, process_heartbeat); ++#undef DO ++ ++ default: ++ isns_error("Function %s not supported\n", ++ isns_function_name(function)); ++ status = ISNS_MESSAGE_NOT_SUPPORTED; ++ break; ++ } ++ ++reply: ++ /* Commit any changes to the DB before we reply */ ++ if (db) ++ isns_db_sync(db); ++ ++ /* Send out SCN notifications */ ++ isns_flush_events(); ++ ++ if (reply != NULL) { ++ reply->is_function |= 0x8000; ++ isns_simple_print(reply, isns_debug_message); ++ ++ /* Encode the whole thing */ ++ status = isns_simple_encode_response(reply, msg, &res_msg); ++ } ++ ++ /* No reply, or error when encoding it: ++ * just send the error, nothing else. */ ++ if (res_msg == NULL) { ++ res_msg = isns_create_reply(msg); ++ if (status == ISNS_SUCCESS) ++ status = ISNS_INTERNAL_ERROR; ++ } ++ ++ isns_debug_message("response status 0x%04x (%s)\n", ++ status, isns_strerror(status)); ++ ++ if (status != ISNS_SUCCESS) ++ isns_message_set_error(res_msg, status); ++ ++no_reply: ++ isns_simple_free(call); ++ if (reply) ++ isns_simple_free(reply); ++ return res_msg; ++ ++err_unauthorized: ++ status = ISNS_SOURCE_UNAUTHORIZED; ++ goto reply; ++} ++ ++int ++isns_not_supported(isns_server_t *srv, isns_simple_t *call, isns_simple_t **replyp) ++{ ++ return ISNS_MESSAGE_NOT_SUPPORTED; ++} +diff --git a/utils/open-isns/simple.c b/utils/open-isns/simple.c +new file mode 100644 +index 0000000..1af89fd +--- /dev/null ++++ b/utils/open-isns/simple.c +@@ -0,0 +1,727 @@ ++/* ++ * Common handling for iSNS message parsing ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ * ++ */ ++ ++#include ++#include ++#include "isns.h" ++#include "attrs.h" ++#include "message.h" ++#include "objects.h" ++#include "security.h" ++#include "socket.h" ++#include "util.h" ++ ++typedef void isns_simple_callback_fn_t(uint32_t, int status, isns_simple_t *); ++ ++static int isns_attr_list_scanner_get_pg(struct isns_attr_list_scanner *st); ++ ++/* ++ * Allocate an empty simple message ++ */ ++static isns_simple_t * ++__isns_alloc_simple(void) ++{ ++ isns_simple_t *simp; ++ ++ simp = isns_calloc(1, sizeof(*simp)); ++ ++ isns_attr_list_init(&simp->is_message_attrs); ++ isns_attr_list_init(&simp->is_operating_attrs); ++ ++ return simp; ++} ++ ++/* ++ * Create a simple message, and set the source name ++ */ ++isns_simple_t * ++isns_simple_create(uint32_t function, isns_source_t *source, ++ const isns_attr_list_t *key) ++{ ++ isns_simple_t *simp; ++ ++ simp = __isns_alloc_simple(); ++ simp->is_function = function; ++ simp->is_source = source; ++ if (source != NULL) ++ source->is_users++; ++ ++ if (key) ++ isns_attr_list_copy(&simp->is_message_attrs, key); ++ ++ return simp; ++} ++ ++/* ++ * Perform a call to the server, waiting for the response. ++ */ ++int ++isns_simple_call(isns_socket_t *sock, isns_simple_t **inout) ++{ ++ isns_simple_t *simp = *inout; ++ isns_message_t *msg, *resp; ++ int status; ++ ++ isns_simple_print(simp, isns_debug_message); ++ ++ status = isns_simple_encode(simp, &msg); ++ if (status != ISNS_SUCCESS) { ++ isns_error("Unable to encode %s: %s\n", ++ isns_function_name(simp->is_function), ++ isns_strerror(status)); ++ return status; ++ } ++ ++ isns_debug_message("Sending request, len=%d\n", ++ buf_avail(msg->im_payload)); ++ ++ resp = isns_socket_call(sock, msg, ++ isns_config.ic_network.call_timeout); ++ isns_assert(msg->im_users == 1); ++ isns_message_release(msg); ++ ++ if (resp == NULL) { ++ isns_error("Timed out while waiting for reply\n"); ++ return ISNS_INTERNAL_ERROR; ++ } ++ ++ isns_debug_message("Received reply, len=%d\n", ++ buf_avail(resp->im_payload)); ++ isns_assert(resp->im_users == 1); ++ ++ status = isns_message_status(resp); ++ if (status != ISNS_SUCCESS) { ++ isns_message_release(resp); ++ return status; ++ } ++ ++ status = isns_simple_decode(resp, &simp); ++ isns_message_release(resp); ++ ++ if (status) { ++ isns_error("Unable to decode server response: %s (status 0x%04x)\n", ++ isns_strerror(status), status); ++ return status; ++ } ++ ++ isns_simple_print(simp, isns_debug_message); ++ ++ isns_simple_free(*inout); ++ *inout = simp; ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * This callback is invoked from the network layer when ++ * we received a response to an async message ++ */ ++static void ++isns_simple_recv_response(isns_message_t *cmsg, isns_message_t *rmsg) ++{ ++ isns_simple_callback_fn_t *user_callback; ++ isns_simple_t *resp = NULL; ++ int status = ISNS_INTERNAL_ERROR; ++ ++ /* rmsg being NULL means the call timed out. */ ++ if (rmsg == NULL) ++ goto callback; ++ ++ status = isns_message_status(rmsg); ++ if (status != ISNS_SUCCESS) { ++ isns_error("Server flags error: %s (status 0x%04x)\n", ++ isns_strerror(status), status); ++ goto callback; ++ } ++ ++ status = isns_simple_decode(rmsg, &resp); ++ if (status) { ++ isns_error("Unable to decode server response: %s (status 0x%04x)\n", ++ isns_strerror(status), status); ++ resp = NULL; ++ goto callback; ++ } ++ ++ isns_simple_print(resp, isns_debug_message); ++ ++callback: ++ user_callback = cmsg->im_calldata; ++ if (user_callback) ++ user_callback(cmsg->im_xid, status, resp); ++ if (resp) ++ isns_simple_free(resp); ++} ++ ++/* ++ * Transmit a call, without waiting for the response. ++ */ ++int ++isns_simple_transmit(isns_socket_t *sock, isns_simple_t *call, ++ const isns_portal_info_t *dest, ++ unsigned int timeout, ++ isns_simple_callback_fn_t *user_callback) ++{ ++ isns_message_t *msg; ++ int status; ++ ++ isns_simple_print(call, isns_debug_message); ++ ++ status = isns_simple_encode(call, &msg); ++ if (status != ISNS_SUCCESS) { ++ isns_error("Unable to encode %s: %s\n", ++ isns_function_name(call->is_function), ++ isns_strerror(status)); ++ return status; ++ } ++ ++ isns_debug_message("Sending message, len=%d\n", ++ buf_avail(msg->im_payload)); ++ ++ if (user_callback) { ++ msg->im_callback = isns_simple_recv_response; ++ msg->im_calldata = user_callback; ++ } ++ ++ if (!isns_socket_submit(sock, msg, timeout)) ++ status = ISNS_INTERNAL_ERROR; ++ isns_message_release(msg); ++ return status; ++} ++ ++/* ++ * Delete the simple message object ++ */ ++void ++isns_simple_free(isns_simple_t *simp) ++{ ++ if (simp == NULL) ++ return; ++ ++ isns_attr_list_destroy(&simp->is_message_attrs); ++ isns_attr_list_destroy(&simp->is_operating_attrs); ++ isns_source_release(simp->is_source); ++ isns_policy_release(simp->is_policy); ++ isns_free(simp); ++} ++ ++/* ++ * Get the source associated with this simple message ++ */ ++isns_source_t * ++isns_simple_get_source(isns_simple_t *simp) ++{ ++ return simp->is_source; ++} ++ ++const isns_attr_list_t * ++isns_simple_get_attrs(isns_simple_t *simp) ++{ ++ return &simp->is_operating_attrs; ++} ++ ++/* ++ * Determine whether message includes a source attr. ++ */ ++static inline int ++isns_simple_include_source(uint16_t function) ++{ ++ if (function & 0x8000) ++ return 0; ++ switch (function) { ++ case ISNS_STATE_CHANGE_NOTIFICATION: ++ case ISNS_ENTITY_STATUS_INQUIRY: ++ return 0; ++ } ++ return 1; ++} ++ ++/* ++ * Decode a simple message ++ */ ++int ++isns_simple_decode(isns_message_t *msg, isns_simple_t **result) ++{ ++ isns_simple_t *simp = __isns_alloc_simple(); ++ buf_t *bp = msg->im_payload; ++ int status = ISNS_SUCCESS; ++ ++ simp->is_function = msg->im_header.i_function; ++ simp->is_xid = msg->im_xid; ++ ++ if (isns_simple_include_source(simp->is_function)) { ++ status = isns_source_decode(bp, &simp->is_source); ++ if (status != ISNS_SUCCESS) ++ goto out; ++ } ++ ++ switch (simp->is_function & 0x7FFF) { ++ case ISNS_ENTITY_STATUS_INQUIRY: ++ case ISNS_STATE_CHANGE_NOTIFICATION: ++ /* Server messages do not include a source */ ++ status = isns_attr_list_decode(bp, ++ &simp->is_message_attrs); ++ break; ++ ++ default: ++ status = isns_attr_list_decode_delimited(bp, ++ &simp->is_message_attrs); ++ if (status == ISNS_SUCCESS) ++ status = isns_attr_list_decode(bp, ++ &simp->is_operating_attrs); ++ } ++ ++ if (msg->im_header.i_flags & ISNS_F_REPLACE) ++ simp->is_replace = 1; ++ ++out: ++ if (status == ISNS_SUCCESS) { ++ *result = simp; ++ } else { ++ isns_simple_free(simp); ++ *result = NULL; ++ } ++ return status; ++} ++ ++/* ++ * Encode a simple message reply or response ++ */ ++static int ++__isns_simple_encode(isns_simple_t *simp, buf_t *bp) ++{ ++ int status = ISNS_SUCCESS; ++ ++ if (isns_simple_include_source(simp->is_function)) { ++ if (simp->is_source == NULL) { ++ isns_error("Cannot encode %s message - caller forgot to set source\n", ++ isns_function_name(simp->is_function)); ++ return ISNS_SOURCE_UNKNOWN; ++ } ++ status = isns_source_encode(bp, simp->is_source); ++ } ++ ++ if (status == ISNS_SUCCESS) ++ status = isns_attr_list_encode(bp, &simp->is_message_attrs); ++ ++ /* Some functions have just one set of attrs. */ ++ switch (simp->is_function & 0x7fff) { ++ /* It's not entirely clear which calls actually have the delimiter. ++ * The spec is sometimes a little vague on this. */ ++ case ISNS_SCN_DEREGISTER: ++ case ISNS_ENTITY_STATUS_INQUIRY: ++ case ISNS_STATE_CHANGE_NOTIFICATION: ++ break; ++ ++ default: ++ if (status == ISNS_SUCCESS) ++ status = isns_encode_delimiter(bp); ++ if (status == ISNS_SUCCESS) ++ status = isns_attr_list_encode(bp, &simp->is_operating_attrs); ++ break; ++ } ++ ++ return status; ++} ++ ++int ++isns_simple_encode(isns_simple_t *simp, isns_message_t **result) ++{ ++ isns_message_t *msg; ++ int status, flags; ++ ++ flags = ISNS_F_CLIENT; ++ if (simp->is_replace) ++ flags |= ISNS_F_REPLACE; ++ msg = isns_create_message(simp->is_function, flags); ++ ++ /* FIXME: for UDP sockets, isns_simple_t may contain a ++ destination address. */ ++ ++ status = __isns_simple_encode(simp, msg->im_payload); ++ if (status != ISNS_SUCCESS) { ++ isns_message_release(msg); ++ msg = NULL; ++ } ++ ++ /* Report the XID to the caller */ ++ simp->is_xid = msg->im_xid; ++ ++ *result = msg; ++ return status; ++} ++ ++int ++isns_simple_encode_response(isns_simple_t *reg, ++ const isns_message_t *request, isns_message_t **result) ++{ ++ isns_message_t *msg; ++ int status; ++ ++ msg = isns_create_reply(request); ++ ++ status = __isns_simple_encode(reg, msg->im_payload); ++ if (status != ISNS_SUCCESS) { ++ isns_message_release(msg); ++ msg = NULL; ++ } ++ ++ *result = msg; ++ return status; ++} ++ ++int ++isns_simple_decode_response(isns_message_t *resp, isns_simple_t **result) ++{ ++ return isns_simple_decode(resp, result); ++} ++ ++/* ++ * Extract the list of objects from a DevAttrReg/DevAttrQry ++ * response or similar. ++ */ ++int ++isns_simple_response_get_objects(isns_simple_t *resp, ++ isns_object_list_t *result) ++{ ++ struct isns_attr_list_scanner state; ++ int status = ISNS_SUCCESS; ++ ++ isns_attr_list_scanner_init(&state, NULL, &resp->is_operating_attrs); ++ while (1) { ++ isns_object_t *obj; ++ ++ status = isns_attr_list_scanner_next(&state); ++ if (status == ISNS_NO_SUCH_ENTRY) { ++ status = ISNS_SUCCESS; ++ break; ++ } ++ if (status) ++ break; ++ ++ obj = isns_create_object(state.tmpl, &state.keys, NULL); ++ ++ isns_object_set_attrlist(obj, &state.attrs); ++ if (obj != state.key_obj) ++ isns_object_list_append(result, obj); ++ isns_object_release(obj); ++ } ++ ++ isns_attr_list_scanner_destroy(&state); ++ return status; ++} ++ ++/* ++ * Print a simple message object ++ */ ++void ++isns_simple_print(isns_simple_t *simp, isns_print_fn_t *fn) ++{ ++ char buffer[256]; ++ ++ if (fn == isns_debug_message ++ && !isns_debug_enabled(DBG_MESSAGE)) ++ return; ++ ++ fn("---%s%s---\n", ++ isns_function_name(simp->is_function), ++ simp->is_replace? "[REPLACE]" : ""); ++ if (simp->is_source) { ++ fn("Source:\n", buffer); ++ isns_attr_print(simp->is_source->is_attr, fn); ++ } else { ++ fn("Source: \n"); ++ } ++ ++ if (simp->is_message_attrs.ial_count == 0) { ++ fn("Message attributes: \n"); ++ } else { ++ fn("Message attributes:\n"); ++ isns_attr_list_print(&simp->is_message_attrs, fn); ++ } ++ if (simp->is_operating_attrs.ial_count == 0) { ++ fn("Operating attributes: \n"); ++ } else { ++ fn("Operating attributes:\n"); ++ isns_attr_list_print(&simp->is_operating_attrs, fn); ++ } ++} ++ ++/* ++ * This set of functions analyzes the operating attrs of a registration, ++ * or a query response, and chops it up into separate chunks, one ++ * per objects. ++ * ++ * It always returns the keys and attrs for one object, ++ * following the ordering constraints laid out in the RFC. ++ */ ++void ++isns_attr_list_scanner_init(struct isns_attr_list_scanner *st, ++ isns_object_t *key_obj, ++ const isns_attr_list_t *attrs) ++{ ++ memset(st, 0, sizeof(*st)); ++ st->orig_attrs = *attrs; ++ st->key_obj = key_obj; ++} ++ ++void ++isns_attr_list_scanner_destroy(struct isns_attr_list_scanner *st) ++{ ++ isns_attr_list_destroy(&st->keys); ++ isns_attr_list_destroy(&st->attrs); ++ memset(st, 0, sizeof(*st)); ++} ++ ++int ++isns_attr_list_scanner_next(struct isns_attr_list_scanner *st) ++{ ++ isns_attr_t *attr; ++ unsigned int i, pos = st->pos; ++ ++ isns_attr_list_destroy(&st->keys); ++ isns_attr_list_destroy(&st->attrs); ++ ++ if (st->orig_attrs.ial_count <= pos) ++ return ISNS_NO_SUCH_ENTRY; ++ ++ attr = st->orig_attrs.ial_data[pos]; ++ ++ /* handle those funky inlined PGT definitions */ ++ if (st->pgt_next_attr && attr->ia_tag_id == st->pgt_next_attr) ++ return isns_attr_list_scanner_get_pg(st); ++ ++ /* This isn't really structured programming anymore */ ++ if (st->index_acceptable ++ && (st->tmpl = isns_object_template_for_index_tag(attr->ia_tag_id))) ++ goto copy_attrs; ++ ++ /* ++ * Find the object template for the given key attr(s). ++ * This function also enforces restrictions on the ++ * order of key attributes. ++ */ ++ st->tmpl = isns_object_template_find(attr->ia_tag_id); ++ if (st->tmpl == NULL) { ++ isns_debug_protocol("%s: attr %u is not a key attr\n", ++ __FUNCTION__, attr->ia_tag_id); ++ return ISNS_INVALID_REGISTRATION; ++ } ++ ++ /* Copy the key attrs */ ++ for (i = 0; i < st->tmpl->iot_num_keys; ++i, ++pos) { ++ if (pos >= st->orig_attrs.ial_count) { ++ isns_debug_protocol("%s: incomplete %s object " ++ "(key attr %u missing)\n", ++ __FUNCTION__, st->tmpl->iot_name, pos); ++ return ISNS_INVALID_REGISTRATION; ++ } ++ attr = st->orig_attrs.ial_data[pos]; ++ ++ /* Make sure key attrs are complete and in order */ ++ if (attr->ia_tag_id != st->tmpl->iot_keys[i]) { ++ isns_debug_protocol("%s: incomplete %s object " ++ "(key attr %u missing)\n", ++ __FUNCTION__, st->tmpl->iot_name, pos); ++ return ISNS_INVALID_REGISTRATION; ++ } ++ ++ isns_attr_list_append_attr(&st->keys, attr); ++ } ++ ++ /* ++ * Consume all non-key attributes corresponding to the ++ * object class. We stop whenever we hit another ++ * key attribute, or an attribute that does not belong to ++ * the object type (eg when a storage node is followed by ++ * a PGT attribute, as described in section 5.6.5.1). ++ */ ++copy_attrs: ++ while (pos < st->orig_attrs.ial_count) { ++ uint32_t tag; ++ ++ attr = st->orig_attrs.ial_data[pos]; ++ tag = attr->ia_tag_id; ++ ++ if (!isns_object_attr_valid(st->tmpl, tag) ++ || isns_object_template_find(tag) != NULL) ++ break; ++ ++ pos++; ++ isns_attr_list_append_attr(&st->attrs, attr); ++ } ++ st->pos = pos; ++ ++ return ISNS_SUCCESS; ++} ++ ++int ++isns_attr_list_scanner_get_pg(struct isns_attr_list_scanner *st) ++{ ++ isns_attr_t *attr, *next = NULL; ++ unsigned int pos = st->pos; ++ ++ ++ attr = st->orig_attrs.ial_data[st->pos++]; ++ if (st->pgt_next_attr == ISNS_TAG_PG_TAG) { ++ isns_object_t *base = st->pgt_base_object; ++ ++ if (ISNS_ATTR_IS_NIL(attr)) ++ st->pgt_value = 0; ++ else if (ISNS_ATTR_IS_UINT32(attr)) ++ st->pgt_value = attr->ia_value.iv_uint32; ++ else ++ return ISNS_INVALID_REGISTRATION; ++ ++ if (ISNS_IS_PORTAL(base) ++ && isns_portal_from_object(&st->pgt_portal_info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ base)) { ++ st->pgt_next_attr = ISNS_TAG_PG_ISCSI_NAME; ++ } else ++ if (ISNS_IS_ISCSI_NODE(base) ++ && isns_object_get_string(base, ++ ISNS_TAG_ISCSI_NAME, ++ &st->pgt_iscsi_name)) { ++ st->pgt_next_attr = ISNS_TAG_PORTAL_IP_ADDRESS; ++ } else { ++ return ISNS_INTERNAL_ERROR; ++ } ++ ++ /* Trailing PGT at end of list. Shrug. */ ++ if (st->pos >= st->orig_attrs.ial_count) ++ return ISNS_NO_SUCH_ENTRY; ++ ++ attr = st->orig_attrs.ial_data[st->pos++]; ++ if (attr->ia_tag_id != st->pgt_next_attr) { ++ /* Some clients may do this; catch them so ++ * we can fix it. */ ++ isns_error("Oops, client sends PGT followed by <%s>\n", ++ attr->ia_tag->it_name); ++ return ISNS_INVALID_REGISTRATION; ++ } ++ } ++ ++ st->tmpl = &isns_iscsi_pg_template; ++ if (st->pgt_next_attr == ISNS_TAG_PG_ISCSI_NAME) { ++ isns_attr_list_append_attr(&st->keys, attr); ++ isns_portal_to_attr_list(&st->pgt_portal_info, ++ ISNS_TAG_PG_PORTAL_IP_ADDR, ++ ISNS_TAG_PG_PORTAL_TCP_UDP_PORT, ++ &st->keys); ++ } else ++ if (st->pgt_next_attr == ISNS_TAG_PG_PORTAL_IP_ADDR) { ++ if (st->pos >= st->orig_attrs.ial_count) ++ return ISNS_INVALID_REGISTRATION; ++ ++ next = st->orig_attrs.ial_data[st->pos++]; ++ if (next->ia_tag_id != ISNS_TAG_PORTAL_TCP_UDP_PORT) ++ return ISNS_INVALID_REGISTRATION; ++ ++ isns_attr_list_append_string(&st->keys, ++ ISNS_TAG_PG_ISCSI_NAME, ++ st->pgt_iscsi_name); ++ isns_attr_list_append_attr(&st->keys, attr); ++ isns_attr_list_append_attr(&st->keys, next); ++ } else { ++ return ISNS_INTERNAL_ERROR; ++ } ++ ++ isns_attr_list_append_uint32(&st->attrs, ++ ISNS_TAG_PG_TAG, ++ st->pgt_value); ++ ++ /* Copy other PG attributes if present */ ++ for (pos = st->pos; pos < st->orig_attrs.ial_count; ++pos) { ++ uint32_t tag; ++ ++ attr = st->orig_attrs.ial_data[pos]; ++ tag = attr->ia_tag_id; ++ ++ /* ++ * Additional sets of PGTs and PG iSCSI Names to be ++ * associated to the registered Portal MAY follow. ++ */ ++ if (tag == ISNS_TAG_PG_TAG) { ++ st->pgt_next_attr = tag; ++ break; ++ } ++ ++ if (tag == ISNS_TAG_PG_ISCSI_NAME ++ || tag == ISNS_TAG_PG_PORTAL_IP_ADDR ++ || tag == ISNS_TAG_PG_PORTAL_TCP_UDP_PORT ++ || !isns_object_attr_valid(st->tmpl, tag)) ++ break; ++ ++ isns_attr_list_append_attr(&st->attrs, attr); ++ } ++ st->pos = pos; ++ ++ return ISNS_SUCCESS; ++} ++ ++/* ++ * Get the name of a function ++ */ ++#define __ISNS_MAX_FUNCTION 16 ++static const char * isns_req_function_names[__ISNS_MAX_FUNCTION] = { ++[ISNS_DEVICE_ATTRIBUTE_REGISTER]= "DevAttrReg", ++[ISNS_DEVICE_ATTRIBUTE_QUERY] = "DevAttrQry", ++[ISNS_DEVICE_GET_NEXT] = "DevGetNext", ++[ISNS_DEVICE_DEREGISTER] = "DevDereg", ++[ISNS_SCN_REGISTER] = "SCNReg", ++[ISNS_SCN_DEREGISTER] = "SCNDereg", ++[ISNS_SCN_EVENT] = "SCNEvent", ++[ISNS_STATE_CHANGE_NOTIFICATION]= "SCN", ++[ISNS_DD_REGISTER] = "DDReg", ++[ISNS_DD_DEREGISTER] = "DDDereg", ++[ISNS_DDS_REGISTER] = "DDSReg", ++[ISNS_DDS_DEREGISTER] = "DDSDereg", ++[ISNS_ENTITY_STATUS_INQUIRY] = "ESI", ++[ISNS_HEARTBEAT] = "Heartbeat", ++}; ++static const char * isns_resp_function_names[__ISNS_MAX_FUNCTION] = { ++[ISNS_DEVICE_ATTRIBUTE_REGISTER]= "DevAttrRegResp", ++[ISNS_DEVICE_ATTRIBUTE_QUERY] = "DevAttrQryResp", ++[ISNS_DEVICE_GET_NEXT] = "DevGetNextResp", ++[ISNS_DEVICE_DEREGISTER] = "DevDeregResp", ++[ISNS_SCN_REGISTER] = "SCNRegResp", ++[ISNS_SCN_DEREGISTER] = "SCNDeregResp", ++[ISNS_SCN_EVENT] = "SCNEventResp", ++[ISNS_STATE_CHANGE_NOTIFICATION]= "SCNResp", ++[ISNS_DD_REGISTER] = "DDRegResp", ++[ISNS_DD_DEREGISTER] = "DDDeregResp", ++[ISNS_DDS_REGISTER] = "DDSRegResp", ++[ISNS_DDS_DEREGISTER] = "DDSDeregResp", ++[ISNS_ENTITY_STATUS_INQUIRY] = "ESIRsp", ++/* No response code for heartbeat */ ++}; ++ ++const char * ++isns_function_name(uint32_t function) ++{ ++ static char namebuf[32]; ++ const char **names, *name; ++ unsigned int num = function; ++ ++ names = isns_req_function_names; ++ if (num & 0x8000) { ++ names = isns_resp_function_names; ++ num &= 0x7fff; ++ } ++ name = NULL; ++ if (num < __ISNS_MAX_FUNCTION) ++ name = names[num]; ++ if (name == NULL) { ++ snprintf(namebuf, sizeof(namebuf), ++ "", ++ function); ++ name = namebuf; ++ } ++ ++ return name; ++} ++ +diff --git a/utils/open-isns/slp.c b/utils/open-isns/slp.c +new file mode 100644 +index 0000000..43075b3 +--- /dev/null ++++ b/utils/open-isns/slp.c +@@ -0,0 +1,242 @@ ++/* ++ * SLP registration and query of iSNS ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include "config.h" ++#include ++#ifdef HAVE_SLP_H ++# include ++#endif ++ ++#include "isns.h" ++#include "util.h" ++#include "internal.h" ++ ++#define ISNS_SLP_SERVICE_NAME "iscsi:sms" ++/* ++ * RFC 4018 says we would use scope initiator-scope-list. ++ * But don't we want targets to find the iSNS server, too? ++ */ ++#define ISNS_SLP_SCOPE "initiator-scope-list" ++ ++#ifdef WITH_SLP ++ ++struct isns_slp_url_state { ++ SLPError slp_err; ++ char * slp_url; ++}; ++ ++static void ++isns_slp_report(SLPHandle handle, SLPError err, void *cookie) ++{ ++ *(SLPError *) cookie = err; ++} ++ ++/* ++ * Register a service with SLP ++ */ ++int ++isns_slp_register(const char *url) ++{ ++ SLPError err, callbackerr; ++ SLPHandle handle = NULL; ++ ++ err = SLPOpen("en", SLP_FALSE, &handle); ++ if(err != SLP_OK) { ++ isns_error("Unable to obtain SLP handle (err %d)\n", err); ++ return 0; ++ } ++ ++ err = SLPReg(handle, url, SLP_LIFETIME_MAXIMUM, ++ ISNS_SLP_SCOPE, ++ "(description=iSNS Server),(protocols=isns)", ++ SLP_TRUE, ++ isns_slp_report, &callbackerr); ++ ++ SLPClose(handle); ++ ++ if (err == SLP_OK) ++ err = callbackerr; ++ if (err != SLP_OK) { ++ isns_error("Failed to register with SLP (err %d)\n", err); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* ++ * DeRegister a service ++ */ ++int ++isns_slp_unregister(const char *url) ++{ ++ SLPError err, callbackerr; ++ SLPHandle handle = NULL; ++ ++ isns_debug_general("SLP: Unregistering \"%s\"\n", url); ++ ++ err = SLPOpen("en", SLP_FALSE, &handle); ++ if(err != SLP_OK) { ++ isns_error("Unable to obtain SLP handle (err %d)\n", err); ++ return 0; ++ } ++ ++ err = SLPDereg(handle, url, isns_slp_report, &callbackerr); ++ ++ SLPClose(handle); ++ ++ if (err == SLP_OK) ++ err = callbackerr; ++ if (err != SLP_OK) { ++ isns_error("Failed to deregister with SLP (err %d)\n", err); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* ++ * Find an iSNS server through SLP ++ */ ++static SLPBoolean ++isns_slp_url_callback(SLPHandle handle, ++ const char *url, unsigned short lifetime, ++ SLPError err, void *cookie) ++{ ++ struct isns_slp_url_state *sp = cookie; ++ SLPSrvURL *parsed_url = NULL; ++ int want_more = SLP_TRUE; ++ char buffer[1024]; ++ ++ if (err != SLP_OK && err != SLP_LAST_CALL) ++ return SLP_FALSE; ++ ++ if (!url) ++ goto out; ++ ++ isns_debug_general("SLP: Found URL \"%s\"\n", url); ++ err = SLPParseSrvURL(url, &parsed_url); ++ if (err != SLP_OK) { ++ isns_error("Error parsing SLP service URL \"%s\"\n", url); ++ goto out; ++ } ++ ++ if (parsed_url->s_pcNetFamily ++ && parsed_url->s_pcNetFamily[0] ++ && strcasecmp(parsed_url->s_pcNetFamily, "ip")) { ++ isns_error("Ignoring SLP service URL \"%s\"\n", url); ++ goto out; ++ } ++ ++ if (parsed_url->s_iPort) { ++ snprintf(buffer, sizeof(buffer), "%s:%u", ++ parsed_url->s_pcHost, ++ parsed_url->s_iPort); ++ isns_assign_string(&sp->slp_url, buffer); ++ } else { ++ isns_assign_string(&sp->slp_url, ++ parsed_url->s_pcHost); ++ } ++ want_more = SLP_FALSE; ++ ++out: ++ if (parsed_url) ++ SLPFree(parsed_url); ++ sp->slp_err = SLP_OK; ++ ++ return want_more; ++} ++ ++/* ++ * Locate the iSNS server using SLP. ++ * This is not really an instantaneous process. Maybe we could ++ * speed this up by using a cache. ++ */ ++char * ++isns_slp_find(void) ++{ ++ static struct isns_slp_url_state state; ++ SLPHandle handle = NULL; ++ SLPError err; ++ ++ if (state.slp_url) ++ return state.slp_url; ++ ++ isns_debug_general("Using SLP to locate iSNS server\n"); ++ ++ err = SLPOpen("en", SLP_FALSE, &handle); ++ if(err != SLP_OK) { ++ isns_error("Unable to obtain SLP handle (err %d)\n", err); ++ return NULL; ++ } ++ ++ err = SLPFindSrvs(handle, ISNS_SLP_SERVICE_NAME, ++ NULL, "(protocols=isns)", ++ isns_slp_url_callback, &state); ++ ++ SLPClose(handle); ++ ++ if (err == SLP_OK) ++ err = state.slp_err; ++ if (err != SLP_OK) { ++ isns_error("Failed to find service in SLP (err %d)\n", err); ++ return NULL; ++ } ++ ++ if (state.slp_url == NULL) { ++ isns_error("Service %s not registered with SLP\n", ++ ISNS_SLP_SERVICE_NAME); ++ return NULL; ++ ++ } ++ ++ isns_debug_general("Using iSNS server at %s\n", state.slp_url); ++ return state.slp_url; ++} ++ ++#else /* WITH_SLP */ ++ ++int ++isns_slp_register(const char *url) ++{ ++ isns_error("SLP support disabled in this build\n"); ++ return 0; ++} ++ ++int ++isns_slp_unregister(const char *url) ++{ ++ isns_error("SLP support disabled in this build\n"); ++ return 0; ++} ++ ++char * ++isns_slp_find(void) ++{ ++ isns_error("SLP support disabled in this build\n"); ++ return NULL; ++} ++ ++#endif /* WITH_SLP */ ++ ++char * ++isns_slp_build_url(uint16_t port) ++{ ++ char buffer[1024]; ++ ++ if (port) ++ snprintf(buffer, sizeof(buffer), ++ "service:%s://%s:%u", ++ ISNS_SLP_SERVICE_NAME, ++ isns_config.ic_host_name, port); ++ else ++ snprintf(buffer, sizeof(buffer), ++ "service:%s://%s", ++ ISNS_SLP_SERVICE_NAME, ++ isns_config.ic_host_name); ++ return isns_strdup(buffer); ++} ++ +diff --git a/utils/open-isns/socket.c b/utils/open-isns/socket.c +new file mode 100644 +index 0000000..47481c6 +--- /dev/null ++++ b/utils/open-isns/socket.c +@@ -0,0 +1,2304 @@ ++/* ++ * Socket handling code ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "buffer.h" ++#include "isns.h" ++#include "socket.h" ++#include "security.h" ++#include "util.h" ++#include "config.h" ++ ++#define SOCK_DEBUG_VERBOSE 0 ++ ++#ifndef AI_ADDRCONFIG ++# define AI_ADDRCONFIG 0 ++#endif ++#ifndef AI_V4MAPPED ++# define AI_V4MAPPED 0 ++#endif ++ ++enum { ++ ISNS_MSG_DISCARD, ++ ISNS_MSG_DONE, ++ ISNS_MSG_RETURN ++}; ++ ++static isns_socket_t *__isns_create_socket(struct addrinfo *src, ++ struct addrinfo *dst, ++ int sock_type); ++static struct addrinfo *isns_get_address_list(const char *, const char *, ++ int, int, int); ++static void release_addrinfo(struct addrinfo *); ++static void isns_net_dgram_recv(isns_socket_t *); ++static void isns_net_dgram_xmit(isns_socket_t *); ++static void isns_net_stream_accept(isns_socket_t *); ++static void isns_net_stream_recv(isns_socket_t *); ++static void isns_net_stream_xmit(isns_socket_t *); ++static void isns_net_stream_hup(isns_socket_t *); ++static void isns_net_stream_error(isns_socket_t *, int); ++static void isns_net_stream_reconnect(isns_socket_t *); ++static void isns_net_stream_disconnect(isns_socket_t *); ++static isns_socket_t *isns_net_alloc(int); ++static int isns_socket_open(isns_socket_t *); ++static int isns_socket_queue_message(isns_socket_t *, isns_message_t *); ++static int isns_socket_retransmit_queued(isns_socket_t *); ++ ++static ISNS_LIST_DECLARE(all_sockets); ++ ++#define debug_verbose(args ...) do { \ ++ if (SOCK_DEBUG_VERBOSE >= 1) isns_debug_socket(args); \ ++} while (0) ++#define debug_verbose2(args ...) do { \ ++ if (SOCK_DEBUG_VERBOSE >= 2) isns_debug_socket(args); \ ++} while (0) ++ ++/* ++ * Helper function for looking at incoming PDUs ++ */ ++static inline buf_t * ++isns_socket_next_pdu(isns_socket_t *sock) ++{ ++ buf_t *bp = sock->is_recv_buf; ++ unsigned int avail; ++ struct isns_hdr *hdr; ++ uint32_t pdu_len = 0; ++ ++ if (bp == NULL) ++ return NULL; ++ ++ avail = buf_avail(bp); ++ if (avail < sizeof(*hdr)) ++ return NULL; ++ hdr = buf_head(bp); ++ pdu_len = sizeof(*hdr) + ntohs(hdr->i_length); ++ ++ if (avail < pdu_len) ++ return NULL; ++ ++ /* Check for presence of authentication block */ ++ if (hdr->i_flags & htons(ISNS_F_AUTHBLK_PRESENT)) { ++ uint32_t *authblk, authlen; ++ ++ authblk = (uint32_t *) ((char *) hdr + pdu_len); ++ if (avail < pdu_len + ISNS_AUTHBLK_SIZE) ++ return NULL; ++ ++ authlen = ntohl(authblk[1]); ++ if (authlen < 20 || authlen > ISNS_MAX_MESSAGE) { ++ /* The authblock is garbage. ++ * The only reliable way to signal such a problem ++ * is by dropping the connection. ++ */ ++ isns_error("socket error: bad auth block\n"); ++ sock->is_state = ISNS_SOCK_DEAD; ++ return NULL; ++ } ++ ++ pdu_len += authlen; ++ if (avail < pdu_len) ++ return NULL; ++ } ++ ++ return buf_split(&sock->is_recv_buf, pdu_len); ++} ++ ++/* ++ * Try to assemble the message from PDUs ++ */ ++static inline int ++isns_msg_complete(struct isns_partial_msg *msg) ++{ ++ buf_t *msg_buf, **chain, *bp; ++ ++ /* Return if we haven't seen first and last frag */ ++ if (((~msg->imp_flags) & (ISNS_F_FIRST_PDU|ISNS_F_LAST_PDU))) ++ return 0; ++ ++ /* Simple - unfragmented case: just move ++ * the PDU on the chain to the payload */ ++ if (msg->imp_first_seq == msg->imp_last_seq) { ++ msg->imp_payload = msg->imp_chain; ++ buf_pull(msg->imp_payload, sizeof(struct isns_hdr)); ++ msg->imp_chain = NULL; ++ return 1; ++ } ++ ++ /* Do we have all fragments? */ ++ if (msg->imp_last_seq - msg->imp_first_seq + 1 ++ != msg->imp_pdu_count) ++ return 0; ++ ++ msg_buf = buf_alloc(msg->imp_msg_size); ++ ++ chain = &msg->imp_chain; ++ while ((bp = *chain) != NULL) { ++ /* Pull the header off */ ++ buf_pull(bp, sizeof(struct isns_hdr)); ++ buf_put(msg_buf, buf_head(bp), buf_avail(bp)); ++ ++ *chain = bp->next; ++ buf_free(bp); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Clear the "partial" part of the message ++ */ ++static void ++__isns_msg_clear_partial(struct isns_partial_msg *msg) ++{ ++ buf_list_free(msg->imp_chain); ++ msg->imp_chain = NULL; ++} ++ ++/* ++ * Add an authentication block to an outgoing PDU ++ */ ++#ifdef WITH_SECURITY ++static int ++isns_pdu_seal(isns_security_t *ctx, buf_t *pdu) ++{ ++ struct isns_authblk auth; ++ isns_principal_t *self; ++ ++ if (!(self = ctx->is_self)) { ++ isns_error("Cannot sign PDU: no sender identity for socket\n"); ++ return 0; ++ } ++ ++ auth.iab_bsd = ctx->is_type; ++ auth.iab_timestamp = time(NULL); ++ auth.iab_spi = self->is_name; ++ auth.iab_spi_len = strlen(self->is_name); ++ ++ if (!isns_security_sign(ctx, self, pdu, &auth)) { ++ isns_error("Cannot sign PDU: error creating signature\n"); ++ return 0; ++ } ++ ++ auth.iab_length = ISNS_AUTHBLK_SIZE + ++ auth.iab_spi_len + ++ auth.iab_sig_len; ++ if (!isns_authblock_encode(pdu, &auth)) ++ return 0; ++ ++ isns_debug_message("Successfully signed message (authlen=%u, spilen=%u, siglen=%u)\n", ++ auth.iab_length, auth.iab_spi_len, auth.iab_sig_len); ++ ++ return 1; ++} ++ ++/* ++ * Authenticate a PDU ++ * ++ * The RFC is doing a bit of handwaving around the ++ * authentication issue. For example, it never ++ * spells out exactly which parts of the message ++ * are included in the SHA1 hash to be signed. ++ * ++ * It also says that the auth block "is identical in format ++ * to the SLP authentication block", but all fields ++ * are twice as wide. ++ * ++ * There's not even an error code to tell the client ++ * we were unable to authenticate him :-( ++ * ++ * Interoperability problems, here I come... ++ */ ++static int ++isns_pdu_authenticate(isns_security_t *sec, ++ struct isns_partial_msg *msg, buf_t *bp) ++{ ++ struct isns_hdr *hdr = buf_head(bp); ++ unsigned int pdu_len, avail; ++ struct isns_authblk authblk; ++ isns_principal_t * peer = NULL; ++ buf_t auth_buf; ++ ++ isns_debug_auth("Message has authblock; trying to authenticate\n"); ++ ++ /* In the TCP path, we checked this before, but ++ * better safe than sorry. */ ++ avail = buf_avail(bp); ++ pdu_len = sizeof(*hdr) + ntohs(hdr->i_length); ++ if (avail < pdu_len + ISNS_AUTHBLK_SIZE) { ++ isns_debug_auth("authblock truncated\n"); ++ return 0; ++ } ++ ++ /* Get the auth block */ ++ buf_set(&auth_buf, buf_head(bp) + pdu_len, avail - pdu_len); ++ if (!isns_authblock_decode(&auth_buf, &authblk)) { ++ isns_debug_auth("error decoding authblock\n"); ++ return 0; ++ } ++ ++ /* Truncate the buffer (this just sets the ++ * tail pointer, but doesn't free memory */ ++ if (!buf_truncate(bp, pdu_len)) { ++ isns_debug_auth("buf_truncate failed - cosmic particles?\n"); ++ return 0; ++ } ++ ++ /* If the socket doesn't have a security context, ++ * just ignore the auth block. */ ++ if (sec == NULL) { ++ msg->imp_header.i_flags &= ~ISNS_F_AUTHBLK_PRESENT; ++ return 1; ++ } ++ ++ if (authblk.iab_bsd != sec->is_type) ++ goto failed; ++ ++ peer = isns_get_principal(sec, authblk.iab_spi, authblk.iab_spi_len); ++ if (peer == NULL) { ++ /* If the admin allows unknown peers, we must make ++ * sure, however, to not allow an unauthenticated ++ * PDU to be inserted into an authenticated message. ++ */ ++ if (isns_config.ic_auth.allow_unknown_peers ++ && msg->imp_security == NULL) { ++ isns_debug_message( ++ "Accepting unknown peer spi=\"%.*s\" as " ++ "anonymous peer\n", ++ authblk.iab_spi_len, authblk.iab_spi); ++ return 1; ++ } ++ ++ isns_debug_message( ++ "Unable to create security peer for spi=%.*s\n", ++ authblk.iab_spi_len, authblk.iab_spi); ++ ++ goto failed; ++ } ++ ++ if (!isns_security_verify(sec, peer, bp, &authblk)) { ++ /* Authentication failed */ ++ goto failed; ++ } ++ ++ /* The RFC doesn't say how to deal with fragmented ++ * messages with different BSDs or SPIs. ++ * kickban seems the right approach. ++ * We discard this segment rather than failing ++ * the entire message. ++ */ ++ if (msg->imp_chain == NULL) { ++ msg->imp_security = peer; ++ peer->is_users++; ++ } else ++ if (msg->imp_security != peer) { ++ goto failed; ++ } ++ ++ isns_principal_free(peer); ++ return 1; ++ ++failed: ++ isns_principal_free(peer); ++ return 0; ++} ++#else /* WITH_SECURITY */ ++static int ++isns_pdu_authenticate(isns_security_t *sec, ++ struct isns_partial_msg *msg, buf_t *bp) ++{ ++ return 0; ++} ++ ++#endif ++ ++/* ++ * Enqueue an incoming PDU on the socket. ++ * ++ * A single iSNS message may be split up into ++ * several PDUs, so we need to perform ++ * reassembly here. ++ * ++ * This function also verifies the authentication ++ * block, if present. ++ */ ++static void ++isns_pdu_enqueue(isns_socket_t *sock, ++ struct sockaddr_storage *addr, socklen_t alen, ++ buf_t *segment, struct ucred *creds) ++{ ++ isns_message_queue_t *q = &sock->is_partial; ++ struct isns_partial_msg *msg; ++ buf_t **chain, *bp; ++ struct isns_hdr *hdr; ++ uint32_t xid, seq, flags; ++ ++ hdr = (struct isns_hdr *) buf_head(segment); ++ xid = ntohs(hdr->i_xid); ++ seq = ntohs(hdr->i_seq); ++ flags = ntohs(hdr->i_flags); ++ ++ isns_debug_socket("Incoming PDU xid=%04x seq=%u len=%u func=%s%s%s%s%s%s\n", ++ xid, seq, ntohs(hdr->i_length), ++ isns_function_name(ntohs(hdr->i_function)), ++ (flags & ISNS_F_CLIENT)? " client" : "", ++ (flags & ISNS_F_SERVER)? " server" : "", ++ (flags & ISNS_F_AUTHBLK_PRESENT)? " authblk" : "", ++ (flags & ISNS_F_FIRST_PDU)? " first" : "", ++ (flags & ISNS_F_LAST_PDU)? " last" : ""); ++ ++ /* Find the message matching (addr, xid) */ ++ msg = (struct isns_partial_msg *) isns_message_queue_find(q, xid, addr, alen); ++ if (msg != NULL) { ++ if (msg->imp_creds ++ && (!creds || memcmp(msg->imp_creds, creds, sizeof(*creds)))) { ++ isns_warning("socket: credentials mismatch! Dropping PDU\n"); ++ goto drop; ++ } ++ hdr = &msg->imp_header; ++ goto found; ++ } ++ ++ msg = (struct isns_partial_msg *) __isns_alloc_message(xid, sizeof(*msg), ++ (void (*)(isns_message_t *)) __isns_msg_clear_partial); ++ memcpy(&msg->imp_addr, addr, alen); ++ msg->imp_addrlen = alen; ++ ++ msg->imp_header = *hdr; ++ msg->imp_header.i_seq = 0; ++ ++ isns_message_queue_append(q, &msg->imp_base); ++ isns_message_release(&msg->imp_base); ++ /* Message is owned by is_partial now */ ++ ++ /* Fix up the PDU header */ ++ hdr = &msg->imp_header; ++ hdr->i_version = ntohs(hdr->i_version); ++ hdr->i_function = ntohs(hdr->i_function); ++ hdr->i_length = ntohs(hdr->i_length); ++ hdr->i_flags = ntohs(hdr->i_flags); ++ hdr->i_xid = ntohs(hdr->i_xid); ++ hdr->i_seq = ntohs(hdr->i_seq); ++ ++ if (creds) { ++ msg->imp_credbuf = *creds; ++ msg->imp_creds = &msg->imp_credbuf; ++ } ++ ++found: ++ if (flags & ISNS_F_AUTHBLK_PRESENT) { ++ /* When authentication fails - should we drop the ++ * message or treat it as unauthenticated? ++ * For now we drop it, but a more user friendly ++ * approach might be to just treat it as ++ * unauthenticated. ++ */ ++ if (!isns_pdu_authenticate(sock->is_security, msg, segment)) ++ goto drop; ++ } else ++ if (msg->imp_header.i_flags & ISNS_F_AUTHBLK_PRESENT) { ++ /* Oops, unauthenticated fragment in an ++ * authenticated message. */ ++ isns_debug_message( ++ "Oops, unauthenticated fragment in an " ++ "authenticated message!\n"); ++ goto drop; ++ } ++ ++ if ((flags & ISNS_F_FIRST_PDU) ++ && !(msg->imp_flags & ISNS_F_FIRST_PDU)) { ++ /* FIXME: first seq must be zero */ ++ msg->imp_first_seq = seq; ++ msg->imp_flags |= ISNS_F_FIRST_PDU; ++ } ++ if ((flags & ISNS_F_LAST_PDU) ++ && !(msg->imp_flags & ISNS_F_LAST_PDU)) { ++ msg->imp_last_seq = seq; ++ msg->imp_flags |= ISNS_F_LAST_PDU; ++ } ++ ++ chain = &msg->imp_chain; ++ while ((bp = *chain) != NULL) { ++ struct isns_hdr *ohdr = buf_head(bp); ++ ++ /* Duplicate? Drop it! */ ++ if (seq == ohdr->i_seq) ++ goto drop; ++ if (seq < ohdr->i_seq) ++ break; ++ chain = &bp->next; ++ } ++ segment->next = *chain; ++ *chain = segment; ++ ++ msg->imp_msg_size += buf_avail(segment) - sizeof(*hdr); ++ msg->imp_pdu_count++; ++ ++ /* We received first and last PDU - check if the ++ * chain is complete */ ++ if (isns_msg_complete(msg)) { ++ /* Remove from partial queue. ++ * We clean the part of the message that is ++ * not in imp_base, so that we can pass this ++ * to the caller and have him call ++ * isns_message_release on it. ++ */ ++ __isns_msg_clear_partial(msg); ++ ++ /* Move from partial queue to complete queue. */ ++ isns_message_queue_move(&sock->is_complete, ++ &msg->imp_base); ++ msg->imp_base.im_socket = sock; ++ } ++ ++ return; ++ ++drop: ++ buf_free(segment); ++ return; ++} ++ ++/* ++ * Send side handling ++ */ ++static void ++isns_send_update(isns_socket_t *sock) ++{ ++ buf_t *bp = sock->is_xmit_buf; ++ ++ if (bp && buf_avail(bp) == 0) { ++ sock->is_xmit_buf = bp->next; ++ buf_free(bp); ++ } ++ ++ if (sock->is_xmit_buf) ++ sock->is_poll_mask |= POLLOUT; ++ else ++ sock->is_poll_mask &= ~POLLOUT; ++} ++ ++/* ++ * Close the socket ++ */ ++static void ++isns_net_close(isns_socket_t *sock, int next_state) ++{ ++ if (sock->is_desc >= 0) { ++ close(sock->is_desc); ++ sock->is_desc = -1; ++ } ++ sock->is_poll_mask &= ~(POLLIN|POLLOUT); ++ sock->is_state = next_state; ++ ++ buf_list_free(sock->is_xmit_buf); ++ sock->is_xmit_buf = NULL; ++ ++ buf_free(sock->is_recv_buf); ++ sock->is_recv_buf = NULL; ++ ++ isns_message_queue_destroy(&sock->is_partial); ++ isns_message_queue_destroy(&sock->is_complete); ++} ++ ++static void ++isns_net_set_timeout(isns_socket_t *sock, ++ void (*func)(isns_socket_t *), ++ unsigned int timeout) ++{ ++ gettimeofday(&sock->is_deadline, NULL); ++ sock->is_deadline.tv_sec += timeout; ++ sock->is_timeout = func; ++} ++ ++static void ++isns_net_cancel_timeout(isns_socket_t *sock) ++{ ++ timerclear(&sock->is_deadline); ++} ++ ++void ++isns_net_error(isns_socket_t *sock, int err_code) ++{ ++ if (sock->is_error) ++ sock->is_error(sock, err_code); ++} ++ ++/* ++ * Create a passive socket (server side) ++ */ ++isns_socket_t * ++isns_create_server_socket(const char *src_spec, const char *portspec, int af_hint, int sock_type) ++{ ++ struct addrinfo *src; ++ ++ src = isns_get_address_list(src_spec, portspec, ++ af_hint, sock_type, AI_PASSIVE); ++ if (src == NULL) ++ return NULL; ++ ++ return __isns_create_socket(src, NULL, sock_type); ++} ++ ++/* ++ * Accept incoming connections. ++ */ ++void ++isns_net_stream_accept(isns_socket_t *sock) ++{ ++ isns_socket_t *child; ++ socklen_t optlen; ++ int fd, passcred = 0; ++ ++ fd = accept(sock->is_desc, NULL, NULL); ++ if (fd < 0) { ++ if (errno != EINTR) ++ isns_error("Error accepting connection: %m\n"); ++ return; ++ } ++ ++ optlen = sizeof(passcred); ++ if (getsockopt(sock->is_desc, SOL_SOCKET, SO_PASSCRED, ++ &passcred, &optlen) >= 0) { ++ setsockopt(fd, SOL_SOCKET, SO_PASSCRED, ++ &passcred, sizeof(passcred)); ++ } ++ ++ child = isns_net_alloc(fd); ++ child->is_type = SOCK_STREAM; ++ child->is_autoclose = 1; ++ child->is_disconnect_fatal = 1; ++ child->is_poll_in = isns_net_stream_recv; ++ child->is_poll_out = isns_net_stream_xmit; ++ child->is_poll_hup = isns_net_stream_hup; ++ child->is_error = isns_net_stream_error; ++ child->is_poll_mask = POLLIN|POLLHUP; ++ child->is_security = sock->is_security; ++ ++ if (isns_config.ic_network.idle_timeout) ++ isns_net_set_timeout(child, ++ isns_net_stream_disconnect, ++ isns_config.ic_network.idle_timeout); ++ ++ isns_list_append(&all_sockets, &child->is_list); ++} ++ ++/* ++ * This is called from the socket code when it detects ++ * an error condition. ++ */ ++static void ++isns_net_stream_error(isns_socket_t *sock, int err_code) ++{ ++ int timeo = 0, next_state = ISNS_SOCK_DEAD; ++ ++ if (err_code == EAGAIN) ++ return; ++ ++ isns_debug_socket("isns_net_stream_error: %s\n", strerror(err_code)); ++ ++ switch (err_code) { ++ case EINTR: /* ignored */ ++ return; ++ ++ case ECONNREFUSED: ++ case ECONNRESET: ++ case EHOSTUNREACH: ++ case ENETUNREACH: ++ case ENOTCONN: ++ case EPIPE: ++ if (sock->is_disconnect_fatal) { ++ isns_warning("socket disconnect, killing socket\n"); ++ break; ++ } ++ ++ /* fallthrough to disconnect */ ++ timeo = isns_config.ic_network.reconnect_timeout; ++ ++ case ETIMEDOUT: ++ /* Disconnect and try to reconnect */ ++ if (sock->is_client) { ++ /* FIXME: We don't want this warning for ESI and ++ * SCN sockets on the server side. */ ++ isns_warning("socket disconnect, retrying in %u sec\n", ++ timeo); ++ isns_net_set_timeout(sock, ++ isns_net_stream_reconnect, ++ timeo); ++ next_state = ISNS_SOCK_DISCONNECTED; ++ break; ++ } ++ ++ /* fallthru */ ++ ++ default: ++ isns_error("socket error: %s\n", strerror(err_code)); ++ } ++ ++ /* Close the socket right away */ ++ isns_net_close(sock, next_state); ++} ++ ++/* ++ * recvmsg wrapper handling SCM_CREDENTIALS passing ++ */ ++static int ++isns_net_recvmsg(isns_socket_t *sock, ++ void *buffer, size_t count, ++ struct sockaddr *addr, socklen_t *alen, ++ struct ucred **cred) ++{ ++ static struct ucred cred_buf; ++ unsigned int control[128]; ++ struct cmsghdr *cmsg; ++ struct msghdr msg; ++ struct iovec iov; ++ int len; ++ ++ *cred = NULL; ++ ++ iov.iov_base = buffer; ++ iov.iov_len = count; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_name = addr; ++ msg.msg_namelen = *alen; ++ msg.msg_iov = &iov; ++ msg.msg_iovlen = 1; ++ msg.msg_control = control; ++ msg.msg_controllen = sizeof(control); ++ ++ len = recvmsg(sock->is_desc, &msg, MSG_DONTWAIT); ++ ++ if (len < 0) ++ return len; ++ ++ cmsg = CMSG_FIRSTHDR(&msg); ++ while (cmsg) { ++ if (cmsg->cmsg_level == SOL_SOCKET ++ && cmsg->cmsg_type == SCM_CREDENTIALS) { ++ memcpy(&cred_buf, CMSG_DATA(cmsg), sizeof(cred_buf)); ++ *cred = &cred_buf; ++ break; ++ } ++ ++ cmsg = CMSG_NXTHDR(&msg, cmsg); ++ } ++ ++ *alen = msg.msg_namelen; ++ return len; ++} ++ ++void ++isns_net_stream_recv(isns_socket_t *sock) ++{ ++ unsigned char buffer[ISNS_MAX_BUFFER]; ++ struct sockaddr_storage addr; ++ struct ucred *creds = NULL; ++ socklen_t alen = sizeof(addr); ++ buf_t *bp; ++ size_t count, total = 0; ++ int len; ++ ++again: ++ if ((bp = sock->is_recv_buf) == NULL) { ++ bp = buf_alloc(ISNS_MAX_MESSAGE); ++ sock->is_recv_buf = bp; ++ } ++ ++ if ((count = buf_tailroom(bp)) > sizeof(buffer)) ++ count = sizeof(buffer); ++ ++ if (count == 0) { ++ /* Message too large */ ++ isns_net_stream_error(sock, EMSGSIZE); ++ return; ++ } ++ ++#if 0 ++ len = recvfrom(sock->is_desc, buffer, count, MSG_DONTWAIT, ++ (struct sockaddr *) &addr, &alen); ++#else ++ len = isns_net_recvmsg(sock, buffer, count, ++ (struct sockaddr *) &addr, &alen, ++ &creds); ++#endif ++ if (len < 0) { ++ isns_net_stream_error(sock, errno); ++ return; ++ } ++ if (len == 0) { ++ if (total == 0) ++ sock->is_poll_mask &= ~POLLIN; ++ return; ++ } ++ ++ /* We received some data from client, re-arm the ++ * idle disconnect timer */ ++ if (sock->is_autoclose ++ && isns_config.ic_network.idle_timeout) ++ isns_net_set_timeout(sock, ++ isns_net_stream_disconnect, ++ isns_config.ic_network.idle_timeout); ++ ++ buf_put(bp, buffer, len); ++ total += len; ++ ++ /* Chop up the recv buffer into PDUs */ ++ while ((bp = isns_socket_next_pdu(sock)) != NULL) { ++ /* We have a full PDU; enqueue it */ ++ /* We shouldn't have more than one partial message ++ * on a TCP connection; we could check this here. ++ */ ++ isns_pdu_enqueue(sock, &addr, alen, bp, creds); ++ } ++ ++ goto again; ++} ++ ++void ++isns_net_stream_xmit(isns_socket_t *sock) ++{ ++ unsigned int count; ++ buf_t *bp = sock->is_xmit_buf; ++ int len; ++ ++ /* If a connecting socket can send, it has ++ * the TCP three-way handshake. */ ++ if (sock->is_state == ISNS_SOCK_CONNECTING) { ++ sock->is_state = ISNS_SOCK_IDLE; ++ sock->is_poll_mask |= POLLIN; ++ isns_net_cancel_timeout(sock); ++ } ++ ++ if (bp == NULL) ++ return; ++ ++ count = buf_avail(bp); ++ len = send(sock->is_desc, buf_head(bp), count, MSG_DONTWAIT); ++ if (len < 0) { ++ isns_net_stream_error(sock, errno); ++ return; ++ } ++ ++ debug_verbose("isns_net_stream_xmit(%p, count=%u): transmitted %d\n", ++ sock, count, len); ++ buf_pull(bp, len); ++ isns_send_update(sock); ++} ++ ++void ++isns_net_stream_hup(isns_socket_t *sock) ++{ ++ sock->is_poll_mask &= ~(POLLIN|POLLOUT); ++ /* POLLHUP while connecting means we failed */ ++ if (sock->is_state == ISNS_SOCK_CONNECTING) ++ isns_net_stream_error(sock, ECONNREFUSED); ++} ++ ++/* ++ * Clone an addrinfo list ++ */ ++static struct addrinfo * ++clone_addrinfo(const struct addrinfo *ai) ++{ ++ struct addrinfo *res = NULL, **p; ++ ++ p = &res; ++ for (; ai; ai = ai->ai_next) { ++ struct addrinfo *new; ++ ++ if (ai->ai_addrlen > sizeof(struct sockaddr_storage)) ++ continue; ++ ++ new = isns_calloc(1, sizeof(*new) + ai->ai_addrlen); ++ new->ai_family = ai->ai_family; ++ new->ai_socktype = ai->ai_socktype; ++ new->ai_protocol = ai->ai_protocol; ++ new->ai_addrlen = ai->ai_addrlen; ++ new->ai_addr = (struct sockaddr *) (new + 1); ++ memcpy(new->ai_addr, ai->ai_addr, new->ai_addrlen); ++ ++ *p = new; ++ p = &new->ai_next; ++ } ++ ++ return res; ++} ++ ++static struct addrinfo * ++__make_addrinfo(const struct sockaddr *ap, socklen_t alen, int socktype) ++{ ++ struct addrinfo *new; ++ ++ new = isns_calloc(1, sizeof(*new) + alen); ++ new->ai_family = ap->sa_family; ++ new->ai_socktype = socktype; ++ new->ai_protocol = 0; ++ new->ai_addrlen = alen; ++ new->ai_addr = (struct sockaddr *) (new + 1); ++ memcpy(new->ai_addr, ap, alen); ++ ++ return new; ++} ++ ++static struct addrinfo * ++make_addrinfo_unix(const char *pathname, int socktype) ++{ ++ unsigned int len = strlen(pathname); ++ struct sockaddr_un sun; ++ ++ if (len + 1 > sizeof(sun.sun_path)) { ++ isns_error("Can't set AF_LOCAL address: path too long!\n"); ++ return NULL; ++ } ++ ++ sun.sun_family = AF_LOCAL; ++ strcpy(sun.sun_path, pathname); ++ return __make_addrinfo((struct sockaddr *) &sun, SUN_LEN(&sun) + 1, socktype); ++} ++ ++static struct addrinfo * ++make_addrinfo_any(int family, int socktype) ++{ ++ struct sockaddr_storage addr = { .ss_family = AF_UNSPEC }; ++ struct addrinfo *res; ++ ++ if (family != AF_UNSPEC) { ++ addr.ss_family = family; ++ res = __make_addrinfo((struct sockaddr *) &addr, sizeof(addr), socktype); ++ } else { ++ addr.ss_family = AF_INET6; ++ res = __make_addrinfo((struct sockaddr *) &addr, sizeof(addr), socktype); ++ addr.ss_family = AF_INET; ++ res->ai_next = __make_addrinfo((struct sockaddr *) &addr, sizeof(addr), socktype); ++ } ++ ++ return res; ++} ++ ++/* ++ * Release addrinfo created by functions above. ++ * We cannot use freeaddrinfo, as we don't know how it ++ * is implemented. ++ */ ++static void ++release_addrinfo(struct addrinfo *ai) ++{ ++ struct addrinfo *next; ++ ++ for (; ai; ai = next) { ++ next = ai->ai_next; ++ isns_free(ai); ++ } ++} ++ ++static void ++__isns_sockaddr_set_current(struct __isns_socket_addr *info, ++ const struct addrinfo *ai) ++{ ++ if (!ai) ++ return; ++ ++ /* Cannot overflow; we check addrlen in clone_addrinfo */ ++ memcpy(&info->addr, ai->ai_addr, ai->ai_addrlen); ++ info->addrlen = ai->ai_addrlen; ++} ++ ++static void ++isns_sockaddr_init(struct __isns_socket_addr *info, ++ struct addrinfo *ai) ++{ ++ if (ai == NULL) ++ return; ++ ++ __isns_sockaddr_set_current(info, ai); ++ ++ /* keep a copy so that we can loop through ++ * all addrs */ ++ info->list = ai; ++ ++ /* Make the list circular */ ++ while (ai->ai_next) ++ ai = ai->ai_next; ++ ai->ai_next = info->list; ++} ++ ++static void ++isns_sockaddr_destroy(struct __isns_socket_addr *info) ++{ ++ struct addrinfo *ai, *next; ++ ++ if ((ai = info->list) != NULL) { ++ /* Break the circular list */ ++ info->list = NULL; ++ next = ai->ai_next; ++ ai->ai_next = NULL; ++ isns_assert(next); ++ ++ /* Can't use freeaddrinfo on homegrown ++ * addrinfo lists. */ ++ release_addrinfo(next); ++ } ++} ++ ++static int ++isns_sockaddr_set_next(struct __isns_socket_addr *info) ++{ ++ struct addrinfo *ai; ++ ++ if (!(ai = info->list)) ++ return 0; ++ ++ info->list = ai->ai_next; ++ __isns_sockaddr_set_current(info, info->list); ++ return 1; ++} ++ ++/* ++ * This function is used to pick a matching source address ++ * when connecting to some server. ++ */ ++static int ++isns_sockaddr_select(struct __isns_socket_addr *info, ++ const struct sockaddr_storage *hint) ++{ ++ struct addrinfo *head = info->list, *ai; ++ ++ if (info->list == NULL) ++ return 0; ++ ++ if (hint->ss_family == AF_INET6) { ++ struct addrinfo *good = NULL, *best = NULL; ++ ++ ai = head; ++ do { ++ if (ai->ai_family == AF_INET) { ++ /* Possible improvement: when ++ * destination is not a private network, ++ * prefer non-private source. */ ++ good = ai; ++ } else ++ if (ai->ai_family == AF_INET6) { ++ /* Possible improvement: prefer IPv6 addr ++ * with same address scope (local, global) ++ */ ++ best = ai; ++ break; ++ } ++ ++ ai = ai->ai_next; ++ } while (ai != head); ++ ++ if (!best) ++ best = good; ++ if (best) { ++ __isns_sockaddr_set_current(info, best); ++ return 1; ++ } ++ } else ++ if (hint->ss_family == AF_INET || hint->ss_family == AF_LOCAL) { ++ ai = head; ++ do { ++ if (ai->ai_family == hint->ss_family) { ++ __isns_sockaddr_set_current(info, ai); ++ return 1; ++ } ++ ai = ai->ai_next; ++ } while (ai != head); ++ } ++ ++ return 0; ++} ++ ++void ++isns_net_stream_reconnect(isns_socket_t *sock) ++{ ++ struct sockaddr *addr = (struct sockaddr *) &sock->is_dst.addr; ++ ++ debug_verbose("isns_net_stream_reconnect(%p)\n", sock); ++ ++ /* If we timed out while connecting, close the socket ++ * and try again. */ ++ if (sock->is_state == ISNS_SOCK_CONNECTING) { ++ isns_net_close(sock, ISNS_SOCK_DISCONNECTED); ++ isns_sockaddr_set_next(&sock->is_dst); ++ } ++ ++ if (!isns_socket_open(sock)) { ++ isns_error("isns_net_stream_reconnect: cannot create socket\n"); ++ sock->is_state = ISNS_SOCK_DEAD; ++ return; ++ } ++ ++ if (connect(sock->is_desc, addr, sock->is_dst.addrlen) >= 0) { ++ sock->is_state = ISNS_SOCK_IDLE; ++ sock->is_poll_mask |= POLLIN; ++ } else ++ if (errno == EINTR || errno == EINPROGRESS) { ++ sock->is_state = ISNS_SOCK_CONNECTING; ++ isns_net_set_timeout(sock, ++ isns_net_stream_reconnect, ++ isns_config.ic_network.connect_timeout); ++ sock->is_poll_mask |= POLLOUT; ++ } else { ++ isns_net_stream_error(sock, errno); ++ return; ++ } ++ ++ /* We're connected, or in the process of doing so. ++ * Check if there are any pending messages, and ++ * retransmit them. */ ++ isns_socket_retransmit_queued(sock); ++} ++ ++void ++isns_net_stream_disconnect(isns_socket_t *sock) ++{ ++ isns_debug_socket("Disconnecting idle socket\n"); ++ isns_net_close(sock, ISNS_SOCK_DEAD); ++} ++ ++/* ++ * Datagram send/recv ++ */ ++static int ++isns_net_dgram_connect(isns_socket_t *sock) ++{ ++ return connect(sock->is_desc, ++ (struct sockaddr *) &sock->is_dst.addr, ++ sock->is_dst.addrlen); ++} ++ ++void ++isns_net_dgram_recv(isns_socket_t *sock) ++{ ++ unsigned char buffer[ISNS_MAX_BUFFER]; ++ struct sockaddr_storage addr; ++ socklen_t alen = sizeof(addr); ++ buf_t *bp; ++ int len; ++ ++ len = recvfrom(sock->is_desc, buffer, sizeof(buffer), ++ MSG_DONTWAIT, (struct sockaddr *) &addr, &alen); ++ if (len < 0) { ++ isns_error("recv: %m\n"); ++ return; ++ } ++ if (len == 0) ++ return; ++ ++ bp = buf_alloc(len); ++ if (bp == NULL) ++ return; ++ ++ buf_put(bp, buffer, len); ++ isns_pdu_enqueue(sock, &addr, alen, bp, NULL); ++} ++ ++void ++isns_net_dgram_xmit(isns_socket_t *sock) ++{ ++ unsigned int count; ++ buf_t *bp = sock->is_xmit_buf; ++ int len; ++ ++ count = buf_avail(bp); ++ if (bp->addrlen) { ++ len = sendto(sock->is_desc, buf_head(bp), count, MSG_DONTWAIT, ++ (struct sockaddr *) &bp->addr, bp->addrlen); ++ } else { ++ len = sendto(sock->is_desc, buf_head(bp), count, MSG_DONTWAIT, ++ NULL, 0); ++ } ++ ++ /* Even if sendto failed, we will pull the pending buffer ++ * off the send chain. Else we'll loop forever on an ++ * unreachable host. */ ++ if (len < 0) ++ isns_error("send: %m\n"); ++ ++ buf_pull(bp, count); ++ isns_send_update(sock); ++} ++ ++/* ++ * Bind socket to random port ++ */ ++static int ++__isns_socket_bind_random(int fd, ++ const struct sockaddr *orig_addr, ++ socklen_t src_len) ++{ ++ struct sockaddr_storage addr; ++ struct sockaddr *src_addr; ++ uint16_t min = 888, max = 1024; ++ unsigned int loop = 0; ++ ++ /* Copy the address to a writable location */ ++ isns_assert(src_len <= sizeof(addr)); ++ memcpy(&addr, orig_addr, src_len); ++ src_addr = (struct sockaddr *) &addr; ++ ++ /* Bind to a random port */ ++ do { ++ uint16_t port; ++ ++ port = random(); ++ port = min + (port % (max - min)); ++ ++ isns_addr_set_port(src_addr, port); ++ ++ if (bind(fd, src_addr, src_len) == 0) ++ return 1; ++ ++ if (errno == EACCES && min < 1024) { ++ min = 1024; ++ max = 65535; ++ continue; ++ } ++ } while (errno == EADDRINUSE && ++loop < 128); ++ ++ isns_error("Unable to bind socket\n"); ++ return 0; ++} ++ ++/* ++ * Create a socket ++ */ ++isns_socket_t * ++__isns_create_socket(struct addrinfo *src, struct addrinfo *dst, int sock_type) ++{ ++ isns_socket_t *sock; ++ ++ sock = isns_net_alloc(-1); ++ sock->is_type = sock_type; ++ ++ /* Set address lists */ ++ isns_sockaddr_init(&sock->is_dst, dst); ++ isns_sockaddr_init(&sock->is_src, src); ++ ++ if (dst) { ++ /* This is an outgoing connection. */ ++ sock->is_client = 1; ++ ++ if (!isns_socket_open(sock)) ++ goto failed; ++ ++ if (sock_type == SOCK_DGRAM) { ++ sock->is_poll_in = isns_net_dgram_recv; ++ sock->is_poll_out = isns_net_dgram_xmit; ++ sock->is_poll_mask = POLLIN; ++ ++ sock->is_retrans_timeout = isns_config.ic_network.udp_retrans_timeout; ++ ++ while (isns_net_dgram_connect(sock) < 0) { ++ if (isns_sockaddr_set_next(&sock->is_dst) ++ && sock->is_dst.list != dst) ++ continue; ++ isns_error("Unable to connect: %m\n"); ++ goto failed; ++ } ++ } else { ++ /* Stream socket */ ++ sock->is_poll_in = isns_net_stream_recv; ++ sock->is_poll_out = isns_net_stream_xmit; ++ sock->is_poll_hup = isns_net_stream_hup; ++ sock->is_error = isns_net_stream_error; ++ sock->is_poll_mask = POLLHUP; ++ ++ sock->is_retrans_timeout = isns_config.ic_network.tcp_retrans_timeout; ++ ++ isns_net_stream_reconnect(sock); ++ } ++ } else { ++ if (!isns_socket_open(sock)) ++ goto failed; ++ ++ if (sock_type == SOCK_DGRAM) { ++ sock->is_poll_in = isns_net_dgram_recv; ++ sock->is_poll_out = isns_net_dgram_xmit; ++ sock->is_state = ISNS_SOCK_IDLE; ++ } else { ++ sock->is_poll_in = isns_net_stream_accept; ++ sock->is_error = isns_net_stream_error; ++ sock->is_state = ISNS_SOCK_LISTENING; ++ } ++ sock->is_poll_mask = POLLIN; ++ } ++ ++ isns_list_append(&all_sockets, &sock->is_list); ++ return sock; ++ ++failed: ++ isns_socket_free(sock); ++ return NULL; ++} ++ ++/* ++ * Connect to the master process ++ */ ++isns_socket_t * ++isns_create_bound_client_socket(const char *src_spec, const char *dst_spec, ++ const char *portspec, int af_hint, int sock_type) ++{ ++ struct addrinfo *src = NULL, *dst; ++ ++ if (src_spec) { ++ src = isns_get_address_list(src_spec, NULL, af_hint, sock_type, 0); ++ if (src == NULL) ++ return NULL; ++ } ++ ++ dst = isns_get_address_list(dst_spec, portspec, af_hint, sock_type, 0); ++ if (dst == NULL) { ++ release_addrinfo(src); ++ return NULL; ++ } ++ ++ return __isns_create_socket(src, dst, sock_type); ++} ++ ++isns_socket_t * ++isns_create_client_socket(const char *dst_spec, const char *portspec, int af_hint, int sock_type) ++{ ++ return isns_create_bound_client_socket(NULL, dst_spec, portspec, af_hint, sock_type); ++} ++ ++static inline int ++isns_socket_type_from_portal(const isns_portal_info_t *info) ++{ ++ switch (info->proto) { ++ case IPPROTO_TCP: ++ return SOCK_STREAM; ++ case IPPROTO_UDP: ++ return SOCK_DGRAM; ++ default: ++ isns_error("Unknown protocol %d in portal\n", info->proto); ++ } ++ return -1; ++} ++ ++isns_socket_t * ++isns_connect_to_portal(const isns_portal_info_t *info) ++{ ++ struct sockaddr_storage dst_addr; ++ struct addrinfo *ai; ++ int dst_alen, sock_type; ++ ++ if ((sock_type = isns_socket_type_from_portal(info)) < 0) ++ return NULL; ++ ++ dst_alen = isns_portal_to_sockaddr(info, &dst_addr); ++ ai = __make_addrinfo((struct sockaddr *) &dst_addr, dst_alen, sock_type); ++ ++ return __isns_create_socket(NULL, ai, sock_type); ++} ++ ++/* ++ * Make server side disconnects isns_fatal. ++ * Nice for command line apps. ++ */ ++void ++isns_socket_set_disconnect_fatal(isns_socket_t *sock) ++{ ++ sock->is_disconnect_fatal = 1; ++} ++ ++void ++isns_socket_set_report_failure(isns_socket_t *sock) ++{ ++ sock->is_report_failure = 1; ++} ++ ++/* ++ * Set the socket's security context ++ */ ++void ++isns_socket_set_security_ctx(isns_socket_t *sock, ++ isns_security_t *ctx) ++{ ++ sock->is_security = ctx; ++} ++ ++/* ++ * Create a socket ++ */ ++static isns_socket_t * ++isns_net_alloc(int fd) ++{ ++ isns_socket_t *new; ++ ++ new = isns_calloc(1, sizeof(*new)); ++ new->is_desc = fd; ++ if (fd >= 0) ++ new->is_state = ISNS_SOCK_IDLE; ++ else ++ new->is_state = ISNS_SOCK_DISCONNECTED; ++ ++ isns_message_queue_init(&new->is_partial); ++ isns_message_queue_init(&new->is_complete); ++ isns_message_queue_init(&new->is_pending); ++ isns_list_init(&new->is_list); ++ ++ return new; ++} ++ ++/* ++ * Open the socket ++ */ ++static int ++isns_socket_open(isns_socket_t *sock) ++{ ++ int af, fd, state = ISNS_SOCK_IDLE; ++ ++ if (sock->is_desc >= 0) ++ return 1; ++ ++ af = sock->is_dst.addr.ss_family; ++ if (af != AF_UNSPEC) { ++ /* Select a matching source address */ ++ if (sock->is_src.list ++ && !isns_sockaddr_select(&sock->is_src, &sock->is_dst.addr)) { ++ isns_warning("No matching source address for given destination\n"); ++ return 0; ++ } ++ } else { ++ af = sock->is_src.addr.ss_family; ++ if (af == AF_UNSPEC) ++ return 0; ++ } ++ ++ if ((fd = socket(af, sock->is_type, 0)) < 0) { ++ isns_error("Unable to create socket: %m\n"); ++ return 0; ++ } ++ ++ if (sock->is_src.addr.ss_family != AF_UNSPEC) { ++ const struct sockaddr *src_addr; ++ int src_len, on = 1, bound = 0; ++ ++ src_addr = (struct sockaddr *) &sock->is_src.addr; ++ src_len = sock->is_src.addrlen; ++ ++ /* For debugging only! */ ++ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { ++ isns_error("setsockopt(SO_REUSEADDR) failed: %m\n"); ++ goto failed; ++ } ++ ++ switch (af) { ++ case AF_LOCAL: ++ unlink(((struct sockaddr_un *) src_addr)->sun_path); ++ ++ if (sock->is_type == SOCK_STREAM ++ && setsockopt(fd, SOL_SOCKET, SO_PASSCRED, ++ &on, sizeof(on)) < 0) { ++ isns_error("setsockopt(SO_PASSCRED) failed: %m\n"); ++ goto failed; ++ } ++ break; ++ ++ case AF_INET: ++ case AF_INET6: ++ if (isns_addr_get_port(src_addr) == 0) { ++ if (!__isns_socket_bind_random(fd, src_addr, src_len)) ++ goto failed; ++ bound++; ++ } ++ break; ++ } ++ ++ if (!bound && bind(fd, src_addr, src_len) < 0) { ++ isns_error("Unable to bind socket: %m\n"); ++ goto failed; ++ } ++ } ++ ++ if (sock->is_client) { ++ /* Set to nonblocking behavior; makes the connect ++ * call return instantly. */ ++ fcntl(fd, F_SETFL, O_NONBLOCK); ++ } else { ++ if (sock->is_type == SOCK_STREAM) { ++ if (listen(fd, 128) < 0) { ++ isns_error("Unable to listen on socket: %m\n"); ++ goto failed; ++ } ++ state = ISNS_SOCK_LISTENING; ++ } ++ } ++ ++ sock->is_desc = fd; ++ sock->is_state = state; ++ return 1; ++ ++failed: ++ close(fd); ++ return 0; ++} ++ ++/* ++ * Destroy a socket ++ */ ++static inline void ++isns_socket_destroy(isns_socket_t *sock) ++{ ++ isns_sockaddr_destroy(&sock->is_dst); ++ isns_sockaddr_destroy(&sock->is_src); ++ isns_free(sock); ++} ++ ++void ++isns_socket_free(isns_socket_t *sock) ++{ ++ isns_net_close(sock, ISNS_SOCK_DEAD); ++ isns_list_del(&sock->is_list); ++ ++ sock->is_destroy = 1; ++ if (sock->is_users == 0) ++ isns_socket_destroy(sock); ++} ++ ++int ++isns_socket_release(isns_socket_t *sock) ++{ ++ isns_assert(sock->is_users); ++ sock->is_users -= 1; ++ ++ if (sock->is_destroy) { ++ if (!sock->is_users) ++ isns_socket_destroy(sock); ++ return 0; ++ } ++ return 1; ++} ++ ++/* ++ * Display a socket ++ */ ++#if SOCK_DEBUG_VERBOSE > 0 ++static const char * ++isns_socket_state_name(int state) ++{ ++ static char xbuf[16]; ++ ++ switch (state) { ++ case ISNS_SOCK_LISTENING: ++ return "listening"; ++ case ISNS_SOCK_CONNECTING: ++ return "connecting"; ++ case ISNS_SOCK_IDLE: ++ return "idle"; ++ case ISNS_SOCK_FAILED: ++ return "failed"; ++ case ISNS_SOCK_DISCONNECTED: ++ return "disconnected"; ++ case ISNS_SOCK_DEAD: ++ return "dead"; ++ } ++ snprintf(xbuf, sizeof(xbuf), "<%u>", state); ++ return xbuf; ++} ++ ++static void ++isns_print_socket(const isns_socket_t *sock) ++{ ++ isns_message_t *msg = NULL; ++ char buffer[8192]; ++ size_t pos = 0, size = sizeof(buffer); ++ ++ snprintf(buffer + pos, size - pos, ++ "socket %p desc %d state %s", ++ sock, sock->is_desc, ++ isns_socket_state_name(sock->is_state)); ++ pos = strlen(buffer); ++ ++ if (timerisset(&sock->is_deadline)) { ++ snprintf(buffer + pos, size - pos, " deadline=%ldms", ++ __timeout_millisec(NULL, &sock->is_deadline)); ++ pos = strlen(buffer); ++ } ++ ++ if ((msg = isns_message_queue_head(&sock->is_pending)) != NULL) { ++ snprintf(buffer + pos, size - pos, " msg timeout=%ldms", ++ __timeout_millisec(NULL, &msg->im_timeout)); ++ pos = strlen(buffer); ++ } ++ ++ isns_debug_socket("%s\n", buffer); ++} ++#else ++#define isns_print_socket(p) do { } while (0) ++#endif ++ ++/* ++ * Process incoming messages, and timeouts ++ */ ++static int ++isns_net_validate(isns_socket_t *sock, isns_message_t *msg, ++ const isns_message_t *check_msg) ++{ ++ isns_message_t *orig = NULL; ++ int verdict = ISNS_MSG_DISCARD; ++ ++ if (sock->is_security && !msg->im_security) { ++ /* Rude server, or malicious man in the ++ * middle. */ ++ isns_debug_message("Ignoring unauthenticated message\n"); ++ goto out; ++ } ++ ++ /* If this is a request, return it. */ ++ if (!(msg->im_header.i_function & 0x8000)) { ++ if (check_msg == NULL) { ++ verdict = ISNS_MSG_RETURN; ++ } else { ++ /* Else: see if there's a server attached to this ++ * socket. */ ++ } ++ goto out; ++ } ++ ++ orig = isns_message_queue_find(&sock->is_pending, msg->im_xid, NULL, 0); ++ if (orig == NULL) { ++ isns_debug_message("Ignoring spurious response message (xid=%04x)\n", ++ msg->im_xid); ++ goto out; ++ } ++ ++ isns_message_unlink(orig); ++ if (orig->im_header.i_function != (msg->im_header.i_function & 0x7FFF)) { ++ isns_debug_message("Response message doesn't match function\n"); ++ goto out; ++ } ++ ++ if (check_msg == orig) { ++ verdict = ISNS_MSG_RETURN; ++ } else { ++ isns_debug_message("Received response for pending message 0x%x\n", ++ msg->im_xid); ++ if (orig->im_callback) ++ orig->im_callback(orig, msg); ++ verdict = ISNS_MSG_DONE; ++ } ++ ++out: ++ isns_message_release(orig); ++ return verdict; ++} ++ ++static void ++isns_net_timeout(isns_socket_t *sock, isns_message_t *msg) ++{ ++ if (msg->im_callback) ++ msg->im_callback(msg, NULL); ++ isns_message_release(msg); ++} ++ ++/* ++ * Helper function to update timeout ++ */ ++static inline void ++__set_timeout(struct timeval *end, unsigned long timeout) ++{ ++ gettimeofday(end, NULL); ++ end->tv_sec += timeout; ++} ++ ++static inline int ++__timeout_expired(const struct timeval *now, const struct timeval *expires) ++{ ++ /* FIXME: Should ignore sub-millisecond remainder */ ++ return timercmp(now, expires, >=); ++} ++ ++static long ++__timeout_millisec(const struct timeval *now, const struct timeval *expires) ++{ ++ struct timeval __now, delta = { 0, 0 }; ++ ++ if (now == NULL) { ++ gettimeofday(&__now, NULL); ++ now = &__now; ++ } ++ ++ timersub(expires, now, &delta); ++ ++ return delta.tv_sec * 1000 + delta.tv_usec / 1000; ++} ++ ++static inline void ++__update_timeout(struct timeval *end, const struct timeval *timeout) ++{ ++ if (!timerisset(end) || timercmp(timeout, end, <)) ++ *end = *timeout; ++} ++ ++/* ++ * Get the next iSNS message ++ */ ++isns_message_t * ++__isns_recv_message(const struct timeval *end_time, isns_message_t *watch_msg) ++{ ++ isns_socket_t *sock, **sock_list; ++ isns_list_t *pos, *next; ++ struct pollfd *pfd; ++ unsigned int i, count, max_sockets; ++ struct timeval now, this_end; ++ int r; ++ ++ max_sockets = isns_config.ic_network.max_sockets; ++ sock_list = alloca(max_sockets * sizeof(sock_list[0])); ++ pfd = alloca(max_sockets * sizeof(pfd[0])); ++ ++again: ++ timerclear(&this_end); ++ gettimeofday(&now, NULL); ++ ++ if (end_time) { ++ if (__timeout_expired(&now, end_time)) ++ return NULL; ++ this_end = *end_time; ++ } ++ ++ i = 0; ++ isns_list_foreach(&all_sockets, pos, next) { ++ isns_socket_t *sock = isns_list_item(isns_socket_t, is_list, pos); ++ isns_message_t *msg = NULL; ++ ++ /* We need to be a little careful here; callbacks may ++ * mark the socket for destruction. ++ * Bumping is_users while we're busy with the socket ++ * prevents mayhem. */ ++ sock->is_users++; ++ ++ while ((msg = isns_message_dequeue(&sock->is_complete)) != NULL) { ++ switch (isns_net_validate(sock, msg, watch_msg)) { ++ case ISNS_MSG_RETURN: ++ isns_assert(!sock->is_destroy); ++ isns_socket_release(sock); ++ return msg; ++ default: ++ isns_message_release(msg); ++ isns_socket_release(sock); ++ return NULL; ++ } ++ } ++ ++ isns_print_socket(sock); ++ ++ /* This handles reconnect, idle disconnect etc. */ ++ while (timerisset(&sock->is_deadline)) { ++ if (__timeout_expired(&now, &sock->is_deadline)) { ++ timerclear(&sock->is_deadline); ++ sock->is_timeout(sock); ++ isns_print_socket(sock); ++ continue; ++ } ++ __update_timeout(&this_end, &sock->is_deadline); ++ break; ++ } ++ ++ /* No more input and output means closed&dead */ ++ if (sock->is_state == ISNS_SOCK_IDLE ++ && !(sock->is_poll_mask & (POLLIN|POLLOUT))) { ++ isns_debug_socket("connection closed by peer, killing socket\n"); ++ isns_net_close(sock, ISNS_SOCK_FAILED); ++ } ++ ++ /* Check whether pending messages have timed out. */ ++ while ((msg = isns_message_queue_head(&sock->is_pending)) != ++ NULL) { ++ if (__timeout_expired(&now, &msg->im_timeout)) { ++ isns_debug_socket("sock %p message %04x timed out\n", ++ sock, msg->im_xid); ++ isns_message_unlink(msg); ++ if (msg == watch_msg) { ++ isns_message_release(msg); ++ isns_socket_release(sock); ++ return NULL; ++ } ++ ++ isns_net_timeout(sock, msg); ++ continue; ++ } ++ ++ if (!__timeout_expired(&now, &msg->im_resend_timeout)) { ++ __update_timeout(&this_end, ++ &msg->im_resend_timeout); ++ /* In odd configurations, the call_timeout ++ * may be lower than the resend_timeout */ ++ __update_timeout(&this_end, ++ &msg->im_timeout); ++ break; ++ } ++ ++ isns_debug_socket("sock %p message %04x - " ++ "minor timeout, resending.\n", ++ sock, msg->im_xid); ++ ++ /* If a TCP socket times out, something is ++ * fishy. Force a reconnect, which will resend ++ * all pending messages. */ ++ if (sock->is_type == SOCK_STREAM) { ++ isns_net_close(sock, ISNS_SOCK_DISCONNECTED); ++ isns_net_set_timeout(sock, ++ isns_net_stream_reconnect, ++ 0); ++ break; ++ } ++ ++ /* UDP socket - retransmit this one message */ ++ isns_message_queue_remove(&sock->is_pending, msg); ++ isns_socket_queue_message(sock, msg); ++ isns_message_release(msg); ++ } ++ ++ /* ++ * If the socket on which we're waiting right ++ * now got disconnected, or had any other kind of ++ * error, return right away to let the caller know. ++ */ ++ if (sock->is_state == ISNS_SOCK_FAILED) { ++ if (sock->is_disconnect_fatal) ++ goto kill_socket; ++ if (sock->is_report_failure) { ++ isns_socket_release(sock); ++ return NULL; ++ } ++ sock->is_state = ISNS_SOCK_DISCONNECTED; ++ isns_socket_release(sock); ++ continue; ++ } ++ ++ if (sock->is_state == ISNS_SOCK_DEAD) { ++kill_socket: ++ isns_list_del(&sock->is_list); ++ if (sock->is_report_failure) { ++ isns_socket_release(sock); ++ return NULL; ++ } ++ if (!sock->is_client) ++ isns_socket_free(sock); ++ isns_socket_release(sock); ++ continue; ++ } ++ ++ /* This will return 0 if the socket was marked for ++ * destruction. */ ++ if (!isns_socket_release(sock)) ++ continue; ++ ++ /* should not happen */ ++ if (i >= max_sockets) ++ break; ++ ++ pfd[i].fd = sock->is_desc; ++ pfd[i].events = sock->is_poll_mask; ++ sock_list[i] = sock; ++ i++; ++ } ++ count = i; ++ ++ if (timerisset(&this_end)) { ++ long millisec; ++ ++ /* timeval arithmetic can yield sub-millisecond timeouts. ++ * Round up to prevent looping. */ ++ millisec = __timeout_millisec(&now, &this_end); ++ if (millisec == 0) ++ millisec += 1; ++ ++ debug_verbose2("poll(%p, %u, %d)\n", pfd, count, millisec); ++ r = poll(pfd, count, millisec); ++ } else { ++ r = poll(pfd, count, -1); ++ } ++ ++ if (r < 0) { ++ if (errno != EINTR) ++ isns_error("poll returned error: %m\n"); ++ return NULL; ++ } ++ ++ /* Any new incoming connections will be added to the ++ * head of the list. */ ++ for (i = 0; i < count; ++i) { ++ sock = sock_list[i]; ++ if (pfd[i].revents & POLLIN) ++ sock->is_poll_in(sock); ++ if (pfd[i].revents & POLLOUT) ++ sock->is_poll_out(sock); ++ if (pfd[i].revents & POLLHUP) ++ sock->is_poll_hup(sock); ++ } ++ ++ goto again; ++} ++ ++isns_message_t * ++isns_recv_message(struct timeval *timeout) ++{ ++ isns_message_t *msg; ++ struct timeval end; ++ ++ if (timeout == NULL) ++ return __isns_recv_message(NULL, NULL); ++ ++ gettimeofday(&end, NULL); ++ timeradd(&end, timeout, &end); ++ msg = __isns_recv_message(&end, NULL); ++ ++ if (msg == NULL) ++ return msg; ++ isns_debug_socket("Next message xid=%04x\n", msg->im_xid); ++ if (msg->im_security) { ++ isns_debug_message("Received authenticated message from \"%s\"\n", ++ isns_principal_name(msg->im_security)); ++ } else if (isns_config.ic_security) { ++ isns_debug_message("Received unauthenticated message\n"); ++ } else { ++ isns_debug_message("Received message\n"); ++ } ++ return msg; ++} ++ ++int ++isns_socket_send(isns_socket_t *sock, isns_message_t *msg) ++{ ++ struct isns_hdr *hdr; ++ size_t pdu_len; ++ buf_t *bp; ++ ++ /* If the socket is disconnected, and the ++ * reconnect timeout is not set, force a ++ * reconnect right away. */ ++ if (sock->is_state == ISNS_SOCK_DISCONNECTED ++ && !timerisset(&sock->is_deadline)) { ++ isns_net_set_timeout(sock, ++ isns_net_stream_reconnect, 0); ++ } ++ ++ if (!(bp = msg->im_payload)) ++ return 0; ++ ++ pdu_len = buf_avail(bp); ++ if (pdu_len < sizeof(*hdr)) ++ return 0; ++ ++ /* Pad PDU to multiple of 4 bytes, if needed */ ++ if (pdu_len & 3) { ++ unsigned int pad = 4 - (pdu_len & 3); ++ ++ if (!buf_put(bp, "\0\0\0", pad)) ++ return 0; ++ pdu_len += pad; ++ } ++ ++ if (!(bp = buf_dup(bp))) ++ return 0; ++ ++ hdr = buf_head(bp); ++ ++ hdr->i_version = htons(msg->im_header.i_version); ++ hdr->i_function = htons(msg->im_header.i_function); ++ hdr->i_flags = htons(msg->im_header.i_flags); ++ hdr->i_length = htons(pdu_len - sizeof(*hdr)); ++ hdr->i_xid = htons(msg->im_header.i_xid); ++ hdr->i_seq = htons(msg->im_header.i_seq); ++ ++ /* For now, we deal with unfragmented messages only. */ ++ hdr->i_flags |= htons(ISNS_F_FIRST_PDU|ISNS_F_LAST_PDU); ++ ++ if (sock->is_security) { ++#ifdef WITH_SECURITY ++ hdr->i_flags |= htons(ISNS_F_AUTHBLK_PRESENT); ++ if (!isns_pdu_seal(sock->is_security, bp)) { ++ isns_debug_message("Error adding auth block to outgoing PDU\n"); ++ goto error; ++ } ++#else ++ isns_debug_message("%s: Authentication not supported\n", ++ __FUNCTION__); ++ goto error; ++#endif ++ } ++ ++ bp->addr = msg->im_addr; ++ bp->addrlen = msg->im_addrlen; ++ ++ buf_list_append(&sock->is_xmit_buf, bp); ++ sock->is_poll_mask |= POLLOUT; ++ ++ /* Set the retransmit timeout */ ++ __set_timeout(&msg->im_resend_timeout, sock->is_retrans_timeout); ++ return 1; ++ ++error: ++ buf_free(bp); ++ return 0; ++} ++ ++/* ++ * Queue a message to a socket ++ */ ++int ++isns_socket_queue_message(isns_socket_t *sock, isns_message_t *msg) ++{ ++ if (!isns_socket_send(sock, msg)) ++ return 0; ++ ++ /* Insert sorted by timeout. For now, this amounts to ++ * appending at the end of the list, but that may change ++ * if we implement exponential backoff for UDP */ ++ isns_message_queue_insert_sorted(&sock->is_pending, ++ ISNS_MQ_SORT_RESEND_TIMEOUT, msg); ++ msg->im_socket = sock; ++ return 1; ++} ++ ++/* ++ * Retransmit any queued messages ++ */ ++int ++isns_socket_retransmit_queued(isns_socket_t *sock) ++{ ++ isns_message_t *msg; ++ isns_list_t *pos; ++ ++ isns_debug_socket("%s(%p)\n", __FUNCTION__, sock); ++ isns_message_queue_foreach(&sock->is_pending, pos, msg) { ++ if (!isns_socket_send(sock, msg)) ++ isns_warning("Unable to retransmit message\n"); ++ } ++ return 1; ++} ++ ++/* ++ * Submit a message to the socket, for asynchronous calls ++ */ ++int ++isns_socket_submit(isns_socket_t *sock, isns_message_t *msg, long timeout) ++{ ++ if (timeout <= 0) ++ timeout = isns_config.ic_network.call_timeout; ++ ++ __set_timeout(&msg->im_timeout, timeout); ++ return isns_socket_queue_message(sock, msg); ++} ++ ++/* ++ * Transmit a message and wait for a response. ++ */ ++isns_message_t * ++isns_socket_call(isns_socket_t *sock, isns_message_t *msg, long timeout) ++{ ++ isns_message_t *resp; ++ ++ debug_verbose("isns_socket_call(sock=%p, msg=%p, timeout=%ld)\n", ++ sock, msg, timeout); ++ if (timeout <= 0) ++ timeout = isns_config.ic_network.call_timeout; ++ ++ __set_timeout(&msg->im_timeout, timeout); ++ if (!isns_socket_queue_message(sock, msg)) ++ return NULL; ++ ++ sock->is_report_failure = 1; ++ resp = __isns_recv_message(NULL, msg); ++ sock->is_report_failure = 0; ++ ++ if (isns_message_unlink(msg)) { ++ /* We can get here if __isns_recv_message returned ++ * due to a fatal socket error. */ ++ isns_debug_socket("%s: msg not unlinked!\n", __FUNCTION__); ++ isns_message_release(msg); ++ } ++ ++ if (resp == NULL && sock->is_type == SOCK_STREAM) ++ isns_net_close(sock, ISNS_SOCK_DISCONNECTED); ++ ++ return resp; ++} ++ ++/* ++ * Resolve a hostname ++ */ ++struct addrinfo * ++isns_get_address_list(const char *addrspec, const char *port, ++ int af_hint, int sock_type, int flags) ++{ ++ struct addrinfo hints, *found = NULL, *res = NULL; ++ char *copy = NULL, *host = NULL, *s; ++ int rv; ++ ++ memset(&hints, 0, sizeof(hints)); ++ hints.ai_flags = AI_ADDRCONFIG; ++ ++ if (addrspec && addrspec[0] == '/') { ++ if (af_hint != AF_LOCAL && af_hint != AF_UNSPEC) { ++ isns_debug_socket("Path as address, but af_hint=%d\n", ++ af_hint); ++ goto bad_address; ++ } ++ ++ res = make_addrinfo_unix(addrspec, SOCK_STREAM); ++ goto out; ++ } ++ ++ if (addrspec) { ++ copy = host = isns_strdup(addrspec); ++ if (*host == '[') { ++ hints.ai_flags |= AI_NUMERICHOST; ++ if ((s = strchr(host, ']')) == NULL) ++ goto bad_address; ++ ++ *s++ = '\0'; ++ if (*s == ':') ++ port = ++s; ++ else if (*s) ++ goto bad_address; ++ } else if ((s = strchr(host, ':')) != NULL) { ++ *s++ = '\0'; ++ if (!*s) ++ goto bad_address; ++ port = s; ++ } ++ ++ if (*host == '\0') ++ host = NULL; ++ } else if (port == NULL) { ++ /* Just wildcard */ ++ res = make_addrinfo_any(af_hint, sock_type); ++ goto out; ++ } ++ ++ hints.ai_family = af_hint; ++ hints.ai_flags |= flags; ++ hints.ai_socktype = sock_type; ++ if (af_hint == AF_INET6) ++ hints.ai_flags |= AI_V4MAPPED; ++ ++ rv = getaddrinfo(host, port, &hints, &found); ++ if (rv) { ++ isns_error("Cannot resolve address \"%s\": %s\n", ++ addrspec, gai_strerror(rv)); ++ goto out; ++ } ++ ++ if (found == NULL) { ++ isns_error("No useable addresses returned.\n"); ++ goto out; ++ } ++ ++ res = clone_addrinfo(found); ++ ++out: ++ if (found) ++ freeaddrinfo(found); ++ isns_free(copy); ++ return res; ++ ++bad_address: ++ isns_error("Cannot parse address spec \"%s\"\n", ++ addrspec); ++ goto out; ++} ++ ++int ++isns_get_address(struct sockaddr_storage *result, ++ const char *addrspec, ++ const char *port, ++ int af_hint, int sock_type, int flags) ++{ ++ struct addrinfo *ai; ++ int alen; ++ ++ if (!(ai = isns_get_address_list(addrspec, port, af_hint, sock_type, flags))) ++ return -1; ++ ++ alen = ai->ai_addrlen; ++ if (alen > sizeof(*result)) ++ return -1; ++ memcpy(result, ai->ai_addr, alen); ++ release_addrinfo(ai); ++ return alen; ++} ++ ++/* ++ * Get the canonical hostname ++ */ ++char * ++isns_get_canon_name(const char *hostname) ++{ ++ struct addrinfo hints, *res = NULL; ++ char *fqdn = NULL; ++ int rv; ++ ++ memset(&hints, 0, sizeof(hints)); ++ hints.ai_flags = AI_CANONNAME; ++ ++ rv = getaddrinfo(hostname, NULL, &hints, &res); ++ if (rv) { ++ isns_error("Cannot resolve hostname \"%s\": %s\n", ++ hostname, gai_strerror(rv)); ++ goto out; ++ } ++ ++ if (res == NULL) { ++ isns_error("No useable addresses returned.\n"); ++ goto out; ++ } ++ ++ ++ fqdn = isns_strdup(res->ai_canonname); ++ ++out: ++ if (res) ++ freeaddrinfo(res); ++ return fqdn; ++} ++ ++int ++isns_socket_get_local_addr(const isns_socket_t *sock, ++ struct sockaddr_storage *addr) ++{ ++ socklen_t alen; ++ ++ if (sock->is_desc < 0) ++ return 0; ++ if (getsockname(sock->is_desc, ++ (struct sockaddr *) addr, &alen) < 0) { ++ isns_error("getsockname: %m\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int ++isns_socket_get_portal_info(const isns_socket_t *sock, ++ isns_portal_info_t *portal) ++{ ++ struct sockaddr_storage addr; ++ socklen_t alen; ++ int fd, success = 0; ++ ++ memset(portal, 0, sizeof(*portal)); ++ ++ /* If the socket is currently closed (eg because the ++ * server shut down the connection), we cannot get the ++ * local address easily. Create a temporary UDP socket, ++ * connect it, and query that socket. */ ++ if ((fd = sock->is_desc) < 0) { ++ const struct sockaddr *daddr; ++ ++ daddr = (struct sockaddr *) &sock->is_dst.addr; ++ fd = socket(daddr->sa_family, SOCK_DGRAM, 0); ++ if (fd < 0) ++ goto out; ++ if (connect(fd, daddr, sizeof(sock->is_dst.addr)) < 0) ++ goto out; ++ } ++ ++ alen = sizeof(addr); ++ if (getsockname(fd, (struct sockaddr *) &addr, &alen) < 0) { ++ isns_error("getsockname: %m\n"); ++ goto out; ++ } ++ ++ if (!isns_portal_from_sockaddr(portal, &addr)) ++ goto out; ++ if (sock->is_type == SOCK_STREAM) ++ portal->proto = IPPROTO_TCP; ++ else ++ portal->proto = IPPROTO_UDP; ++ ++ debug_verbose("socket_get_portal: %s\n", isns_portal_string(portal)); ++ success = 1; ++ ++out: ++ /* If we used a temp UDP socket, close it */ ++ if (fd >= 0 && fd != sock->is_desc) ++ close(fd); ++ return success; ++} ++ ++isns_socket_t * ++isns_socket_find_server(const isns_portal_info_t *portal) ++{ ++ struct sockaddr_storage bound_addr; ++ int sock_type, addr_len; ++ isns_list_t *pos, *next; ++ ++ addr_len = isns_portal_to_sockaddr(portal, &bound_addr); ++ if ((sock_type = isns_socket_type_from_portal(portal)) < 0) ++ return NULL; ++ ++ isns_list_foreach(&all_sockets, pos, next) { ++ isns_socket_t *sock = isns_list_item(isns_socket_t, is_list, pos); ++ ++ if (!sock->is_client ++ && sock->is_type == sock_type ++ && sock->is_dst.addrlen == addr_len ++ && !memcmp(&sock->is_dst.addr, &bound_addr, addr_len)) { ++ sock->is_users++; ++ return sock; ++ } ++ } ++ ++ return NULL; ++} ++ ++int ++isns_addr_get_port(const struct sockaddr *addr) ++{ ++ const struct sockaddr_in *sin; ++ const struct sockaddr_in6 *six; ++ ++ switch (addr->sa_family) { ++ case AF_INET: ++ sin = (const struct sockaddr_in *) addr; ++ return ntohs(sin->sin_port); ++ ++ case AF_INET6: ++ six = (const struct sockaddr_in6 *) addr; ++ return ntohs(six->sin6_port); ++ } ++ return 0; ++} ++ ++void ++isns_addr_set_port(struct sockaddr *addr, unsigned int port) ++{ ++ struct sockaddr_in *sin; ++ struct sockaddr_in6 *six; ++ ++ switch (addr->sa_family) { ++ case AF_INET: ++ sin = (struct sockaddr_in *) addr; ++ sin->sin_port = htons(port); ++ break; ++ ++ case AF_INET6: ++ six = (struct sockaddr_in6 *) addr; ++ six->sin6_port = htons(port); ++ break; ++ } ++} +diff --git a/utils/open-isns/socket.h b/utils/open-isns/socket.h +new file mode 100644 +index 0000000..cc63d23 +--- /dev/null ++++ b/utils/open-isns/socket.h +@@ -0,0 +1,95 @@ ++/* ++ * iSNS network code ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#ifndef ISNS_SOCKET_H ++#define ISNS_SOCKET_H ++ ++#include "isns.h" ++#include "buffer.h" ++#include "message.h" ++ ++struct isns_partial_msg { ++ isns_message_t imp_base; ++ uint32_t imp_flags; ++ uint32_t imp_first_seq; ++ uint32_t imp_last_seq; ++ unsigned int imp_pdu_count; ++ unsigned int imp_msg_size; ++ buf_t * imp_chain; ++ ++ struct ucred imp_credbuf; ++}; ++ ++#define imp_users imp_base.im_users ++#define imp_list imp_base.im_list ++#define imp_xid imp_base.im_xid ++#define imp_header imp_base.im_header ++#define imp_addr imp_base.im_addr ++#define imp_addrlen imp_base.im_addrlen ++#define imp_header imp_base.im_header ++#define imp_payload imp_base.im_payload ++#define imp_security imp_base.im_security ++#define imp_creds imp_base.im_creds ++ ++enum { ++ ISNS_SOCK_LISTENING, ++ ISNS_SOCK_CONNECTING, ++ ISNS_SOCK_IDLE, ++ ISNS_SOCK_FAILED, ++ ISNS_SOCK_DISCONNECTED, ++ ISNS_SOCK_DEAD, ++}; ++ ++/* Helper class */ ++struct __isns_socket_addr { ++ struct sockaddr_storage addr; ++ socklen_t addrlen; ++ struct addrinfo * list; ++}; ++ ++struct isns_socket { ++ isns_list_t is_list; ++ int is_desc; ++ int is_type; ++ unsigned int is_client : 1, ++ is_autoclose : 1, ++ is_disconnect_fatal : 1, ++ is_report_failure : 1, ++ is_destroy : 1; ++ unsigned int is_users; ++ int is_poll_mask; ++ int is_state; ++ ++ isns_security_t * is_security; ++ ++ struct __isns_socket_addr is_src, is_dst; ++ ++ unsigned int is_retrans_timeout; ++ ++ /* If we're past this time, is_timeout() is called. */ ++ struct timeval is_deadline; ++ ++ buf_t * is_recv_buf; ++ buf_t * is_xmit_buf; ++ ++ size_t is_queue_size; ++ isns_message_queue_t is_partial; ++ isns_message_queue_t is_complete; ++ isns_message_queue_t is_pending; ++ ++ void (*is_poll_in)(isns_socket_t *); ++ void (*is_poll_out)(isns_socket_t *); ++ void (*is_poll_hup)(isns_socket_t *); ++ void (*is_poll_err)(isns_socket_t *); ++ void (*is_timeout)(isns_socket_t *); ++ void (*is_error)(isns_socket_t *, int); ++}; ++ ++extern int isns_socket_submit(isns_socket_t *, ++ isns_message_t *, ++ long); ++ ++#endif /* ISNS_SOCKET_H */ +diff --git a/utils/open-isns/source.h b/utils/open-isns/source.h +new file mode 100644 +index 0000000..59fb662 +--- /dev/null ++++ b/utils/open-isns/source.h +@@ -0,0 +1,32 @@ ++/* ++ * iSNS source attribute handling ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#ifndef ISNS_SOURCE_H ++#define ISNS_SOURCE_H ++ ++#include "attrs.h" ++ ++struct isns_source { ++ unsigned int is_users; ++ isns_attr_t * is_attr; ++ unsigned int is_untrusted : 1; ++ ++ isns_object_t * is_node; ++ unsigned int is_node_type; ++ ++ isns_object_t * is_entity; ++}; ++ ++extern int isns_source_encode(buf_t *, const isns_source_t *); ++extern int isns_source_decode(buf_t *, isns_source_t **); ++extern int isns_source_set_node(isns_source_t *, isns_db_t *); ++extern void isns_source_set_entity(isns_source_t *, isns_object_t *); ++extern isns_source_t * isns_source_dummy(void); ++ ++extern char * isns_build_source_pattern(const char *); ++extern int isns_source_pattern_match(const char *, const char *); ++ ++#endif /* ISNS_SOURCE_H */ +diff --git a/utils/open-isns/storage-node.c b/utils/open-isns/storage-node.c +new file mode 100644 +index 0000000..97e54d1 +--- /dev/null ++++ b/utils/open-isns/storage-node.c +@@ -0,0 +1,202 @@ ++/* ++ * iSNS object model - storage node ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include "isns.h" ++#include "objects.h" ++#include "util.h" ++ ++isns_object_t * ++isns_create_storage_node(const char *name, uint32_t type, ++ isns_object_t *parent) ++{ ++ isns_object_t *obj; ++ ++ if (parent && !ISNS_IS_ENTITY(parent)) { ++ isns_warning("Invalid container type \"%s\" for storage node: " ++ "should be \"%s\"\n", ++ parent->ie_template->iot_name, ++ isns_entity_template.iot_name); ++ return NULL; ++ } ++ ++ obj = isns_create_object(&isns_iscsi_node_template, NULL, parent); ++ isns_object_set_string(obj, ++ ISNS_TAG_ISCSI_NAME, name); ++ isns_object_set_uint32(obj, ++ ISNS_TAG_ISCSI_NODE_TYPE, type); ++ ++ return obj; ++} ++ ++isns_object_t * ++isns_create_storage_node2(const isns_source_t *source, ++ uint32_t type, ++ isns_object_t *parent) ++{ ++ isns_attr_t *name_attr; ++ isns_object_t *obj; ++ ++ if (parent && !ISNS_IS_ENTITY(parent)) { ++ isns_warning("Invalid container type \"%s\" for storage node: " ++ "should be \"%s\"\n", ++ parent->ie_template->iot_name, ++ isns_entity_template.iot_name); ++ return NULL; ++ } ++ if ((name_attr = isns_source_attr(source)) == NULL) { ++ isns_warning("No source attribute\n"); ++ return NULL; ++ } ++ ++ if (name_attr->ia_tag_id == ISNS_TAG_ISCSI_NAME) { ++ obj = isns_create_object(&isns_iscsi_node_template, NULL, parent); ++ isns_attr_list_update_attr(&obj->ie_attrs, name_attr); ++ isns_object_set_uint32(obj, ++ ISNS_TAG_ISCSI_NODE_TYPE, type); ++ } else { ++ /* No iFCP yet, sorry */ ++ isns_warning("%s: source tag type %u not supported\n", ++ __FUNCTION__); ++ return NULL; ++ } ++ ++ return obj; ++} ++ ++isns_object_t * ++isns_create_iscsi_initiator(const char *name, ++ isns_object_t *parent) ++{ ++ return isns_create_storage_node(name, ++ 1 << ISNS_ISCSI_NODE_TYPE_INITIATOR, ++ parent); ++} ++ ++isns_object_t * ++isns_create_iscsi_target(const char *name, ++ isns_object_t *parent) ++{ ++ return isns_create_storage_node(name, ++ 1 << ISNS_ISCSI_NODE_TYPE_TARGET, ++ parent); ++} ++ ++const char * ++isns_storage_node_name(const isns_object_t *node) ++{ ++ const isns_attr_t *attr; ++ ++ if (node->ie_attrs.ial_count == 0) ++ return NULL; ++ attr = node->ie_attrs.ial_data[0]; ++ if (attr->ia_value.iv_type != &isns_attr_type_string) ++ return NULL; ++ ++ switch (attr->ia_tag_id) { ++ case ISNS_TAG_ISCSI_NAME: ++ case ISNS_TAG_FC_PORT_NAME_WWPN: ++ return attr->ia_value.iv_string; ++ } ++ ++ return 0; ++ ++} ++ ++isns_attr_t * ++isns_storage_node_key_attr(const isns_object_t *node) ++{ ++ if (node->ie_attrs.ial_count == 0) ++ return NULL; ++ return node->ie_attrs.ial_data[0]; ++} ++ ++static uint32_t iscsi_node_attrs[] = { ++ ISNS_TAG_ISCSI_NAME, ++ ISNS_TAG_ISCSI_NODE_TYPE, ++ ISNS_TAG_ISCSI_ALIAS, ++ ISNS_TAG_ISCSI_SCN_BITMAP, ++ ISNS_TAG_ISCSI_NODE_INDEX, ++ ISNS_TAG_WWNN_TOKEN, ++ ISNS_TAG_ISCSI_AUTHMETHOD, ++ /* RFC 4171 lists a "iSCSI node certificate" ++ * as an option attribute of an iSCSI ++ * storage node, but doesn't define it anywhere ++ * in the spec. ++ */ ++}; ++ ++static uint32_t iscsi_node_key_attrs[] = { ++ ISNS_TAG_ISCSI_NAME, ++}; ++ ++isns_object_template_t isns_iscsi_node_template = { ++ .iot_name = "iSCSI Storage Node", ++ .iot_handle = ISNS_OBJECT_TYPE_NODE, ++ .iot_attrs = iscsi_node_attrs, ++ .iot_num_attrs = array_num_elements(iscsi_node_attrs), ++ .iot_keys = iscsi_node_key_attrs, ++ .iot_num_keys = array_num_elements(iscsi_node_key_attrs), ++ .iot_index = ISNS_TAG_ISCSI_NODE_INDEX, ++ .iot_next_index = ISNS_TAG_ISCSI_NODE_NEXT_INDEX, ++ .iot_container = &isns_entity_template, ++}; ++ ++static uint32_t fc_port_attrs[] = { ++ ISNS_TAG_FC_PORT_NAME_WWPN, ++ ISNS_TAG_PORT_ID, ++ ISNS_TAG_FC_PORT_TYPE, ++ ISNS_TAG_SYMBOLIC_PORT_NAME, ++ ISNS_TAG_FABRIC_PORT_NAME, ++ ISNS_TAG_HARD_ADDRESS, ++ ISNS_TAG_PORT_IP_ADDRESS, ++ ISNS_TAG_CLASS_OF_SERVICE, ++ ISNS_TAG_FC4_TYPES, ++ ISNS_TAG_FC4_DESCRIPTOR, ++ ISNS_TAG_FC4_FEATURES, ++ ISNS_TAG_IFCP_SCN_BITMAP, ++ ISNS_TAG_PORT_ROLE, ++ ISNS_TAG_PERMANENT_PORT_NAME, ++}; ++ ++static uint32_t fc_port_key_attrs[] = { ++ ISNS_TAG_FC_PORT_NAME_WWPN, ++}; ++ ++isns_object_template_t isns_fc_port_template = { ++ .iot_name = "iFCP Port", ++ .iot_handle = ISNS_OBJECT_TYPE_FC_PORT, ++ .iot_attrs = fc_port_attrs, ++ .iot_num_attrs = array_num_elements(fc_port_attrs), ++ .iot_keys = fc_port_key_attrs, ++ .iot_num_keys = array_num_elements(fc_port_key_attrs), ++ .iot_container = &isns_entity_template, ++}; ++ ++static uint32_t fc_node_attrs[] = { ++ ISNS_TAG_FC_NODE_NAME_WWNN, ++ ISNS_TAG_SYMBOLIC_NODE_NAME, ++ ISNS_TAG_NODE_IP_ADDRESS, ++ ISNS_TAG_NODE_IPA, ++ ISNS_TAG_PROXY_ISCSI_NAME, ++}; ++ ++static uint32_t fc_node_key_attrs[] = { ++ ISNS_TAG_FC_NODE_NAME_WWNN, ++}; ++ ++isns_object_template_t isns_fc_node_template = { ++ .iot_name = "iFCP Device Node", ++ .iot_handle = ISNS_OBJECT_TYPE_FC_NODE, ++ .iot_attrs = fc_node_attrs, ++ .iot_num_attrs = array_num_elements(fc_node_attrs), ++ .iot_keys = fc_node_key_attrs, ++ .iot_num_keys = array_num_elements(fc_node_key_attrs), ++ .iot_container = &isns_fc_port_template, ++}; ++ +diff --git a/utils/open-isns/sysdep-unix.c b/utils/open-isns/sysdep-unix.c +new file mode 100644 +index 0000000..d2a9532 +--- /dev/null ++++ b/utils/open-isns/sysdep-unix.c +@@ -0,0 +1,186 @@ ++/* ++ * System dependent stuff ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include "isns.h" ++#include "util.h" ++ ++int isns_get_nr_portals(void) ++{ ++ char buffer[8192], *end, *ptr; ++ struct ifconf ifc; ++ unsigned int nportals = 0; ++ int fd = -1; ++ ++ if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { ++ isns_error("%s: no socket - %m\n", __FUNCTION__); ++ return 0; ++ } ++ ++ ifc.ifc_buf = buffer; ++ ifc.ifc_len = sizeof(buffer); ++ if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { ++ isns_error("ioctl(SIOCGIFCONF): %m\n"); ++ goto out; ++ } ++ ++ ptr = buffer; ++ end = buffer + ifc.ifc_len; ++ while (ptr < end) { ++ struct ifreq ifr; ++ struct sockaddr_storage ifaddr; ++ int ifflags; ++ ++ memcpy(&ifr, ptr, sizeof(ifr)); ++ ptr += sizeof(ifr); ++ ++ /* Get the interface addr */ ++ memcpy(&ifaddr, &ifr.ifr_addr, sizeof(ifr.ifr_addr)); ++ ++ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { ++ isns_error("ioctl(%s, SIOCGIFFLAGS): %m\n", ++ ifr.ifr_name); ++ continue; ++ } ++ ifflags = ifr.ifr_flags; ++ ++ if ((ifflags & IFF_UP) == 0) ++ continue; ++ if ((ifflags & IFF_LOOPBACK) != 0) ++ continue; ++ ++ if (ifaddr.ss_family == AF_INET6 || ifaddr.ss_family == AF_INET) ++ nportals++; ++ } ++ ++out: ++ if (fd >= 0) ++ close(fd); ++ return nportals; ++} ++ ++int ++isns_enumerate_portals(isns_portal_info_t *result, unsigned int max) ++{ ++ char buffer[8192], *end, *ptr; ++ struct ifconf ifc; ++ unsigned int nportals = 0; ++ int fd = -1; ++ ++ if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { ++ isns_error("%s: no socket - %m\n", __FUNCTION__); ++ return 0; ++ } ++ ++ ifc.ifc_buf = buffer; ++ ifc.ifc_len = sizeof(buffer); ++ if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { ++ isns_error("ioctl(SIOCGIFCONF): %m\n"); ++ goto out; ++ } ++ ++ ptr = buffer; ++ end = buffer + ifc.ifc_len; ++ while (ptr < end) { ++ struct ifreq ifr; ++ struct sockaddr_storage ifaddr; ++ isns_portal_info_t portal; ++ int ifflags; ++ ++ memcpy(&ifr, ptr, sizeof(ifr)); ++ ptr += sizeof(ifr); ++ ++ /* Get the interface addr */ ++ memcpy(&ifaddr, &ifr.ifr_addr, sizeof(ifr.ifr_addr)); ++ ++ if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { ++ isns_error("ioctl(%s, SIOCGIFFLAGS): %m\n", ++ ifr.ifr_name); ++ continue; ++ } ++ ifflags = ifr.ifr_flags; ++ ++ if ((ifflags & IFF_UP) == 0) ++ continue; ++ if ((ifflags & IFF_LOOPBACK) != 0) ++ continue; ++ ++ if (!isns_portal_from_sockaddr(&portal, &ifaddr)) ++ continue; ++ ++ isns_debug_socket("Got interface %u: %s %s\n", ++ nportals, ifr.ifr_name, ++ isns_portal_string(&portal)); ++ if (nportals < max) ++ result[nportals++] = portal; ++ } ++ ++out: ++ if (fd >= 0) ++ close(fd); ++ return nportals; ++} ++ ++int ++isns_portal_from_sockaddr(isns_portal_info_t *portal, ++ const struct sockaddr_storage *addr) ++{ ++ struct sockaddr_in6 *six; ++ struct sockaddr_in *sin; ++ ++ memset(portal, 0, sizeof(*portal)); ++ ++ /* May have to convert AF_INET to AF_INET6 */ ++ six = &portal->addr; ++ switch (addr->ss_family) { ++ case AF_INET6: ++ memcpy(six, addr, sizeof(*six)); ++ break; ++ ++ case AF_INET: ++ sin = (struct sockaddr_in *) addr; ++ six->sin6_family = AF_INET6; ++ six->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; ++ six->sin6_port = sin->sin_port; ++ break; ++ ++ default: ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int ++isns_portal_to_sockaddr(const isns_portal_info_t *portal, ++ struct sockaddr_storage *addr) ++{ ++ const struct sockaddr_in6 *six = &portal->addr; ++ struct sockaddr_in *sin; ++ ++ /* Check if this is really a v4 address is disguise. ++ * If so, explicitly use an AF_INET socket - the ++ * stack may not support IPv6. ++ */ ++ if (IN6_IS_ADDR_V4MAPPED(&six->sin6_addr) ++ || IN6_IS_ADDR_V4COMPAT(&six->sin6_addr)) { ++ sin = (struct sockaddr_in *) addr; ++ ++ memset(sin, 0, sizeof(*sin)); ++ sin->sin_family = AF_INET; ++ sin->sin_addr.s_addr = six->sin6_addr.s6_addr32[3]; ++ sin->sin_port = six->sin6_port; ++ ++ return sizeof(*sin); ++ } ++ ++ /* This is the genuine article */ ++ memcpy(addr, six, sizeof(*six)); ++ return sizeof(*six); ++} +diff --git a/utils/open-isns/tags.c b/utils/open-isns/tags.c +new file mode 100644 +index 0000000..7413cee +--- /dev/null ++++ b/utils/open-isns/tags.c +@@ -0,0 +1,740 @@ ++/* ++ * Define all iSNS tags with their types, etc. ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include "isns-proto.h" ++#include "vendor.h" ++#include "attrs.h" ++#include "security.h" ++#include "objects.h" ++#include "util.h" ++ ++#define ISNS_MAX_BUILTIN_TAG 4096 ++ ++ ++static void print_bitfield(unsigned long, char **, char *, size_t); ++static int parse_bitfield( char **, const char *, uint32_t *); ++static const char *help_bitfield(char **); ++ ++#define DECLARE_VALIDATOR(name) \ ++static int isns_##name##_validate(const isns_value_t *, const isns_policy_t *); ++#define DECLARE_ACCESSORS(name) \ ++static int isns_##name##_parse(isns_value_t *, const char *buf); \ ++static void isns_##name##_print(const isns_value_t *, char *buf, size_t size); \ ++static const char * isns_##name##_help(void) ++#define USE_VALIDATOR(name) \ ++ .it_validate = isns_##name##_validate ++#define USE_ACCESSORS(name) \ ++ .it_parse = isns_##name##_parse, \ ++ .it_print = isns_##name##_print, \ ++ .it_help = isns_##name##_help ++ ++DECLARE_VALIDATOR(entity_protocol); ++DECLARE_ACCESSORS(entity_protocol); ++DECLARE_ACCESSORS(tcpudp_port); ++DECLARE_VALIDATOR(iscsi_node_type); ++DECLARE_ACCESSORS(iscsi_node_type); ++DECLARE_ACCESSORS(timestamp); ++DECLARE_ACCESSORS(portal_secbitmap); ++DECLARE_ACCESSORS(scn_bitmap); ++DECLARE_ACCESSORS(dd_features); ++DECLARE_ACCESSORS(policy_object_type); ++DECLARE_ACCESSORS(policy_function); ++ ++static const char *isns_authmethod_help(void); ++ ++#define TAG(ID, name, type, args...) \ ++[ISNS_TAG_##ID] = { \ ++ .it_id = ISNS_TAG_##ID, \ ++ .it_name = name, \ ++ .it_type = &isns_attr_type_##type, \ ++ args \ ++} ++ ++static isns_tag_type_t isns_tags[ISNS_MAX_BUILTIN_TAG] = { ++TAG(DELIMITER, "Delimiter", nil), ++TAG(ENTITY_IDENTIFIER, "Entity identifier", string), ++TAG(ENTITY_PROTOCOL, "Entity protocol", uint32, ++ USE_VALIDATOR(entity_protocol), ++ USE_ACCESSORS(entity_protocol)), ++TAG(MGMT_IP_ADDRESS, "Mgmt IP address", ipaddr), ++TAG(TIMESTAMP, "Timestamp", uint64, ++ USE_ACCESSORS(timestamp), ++ .it_readonly = 1), ++TAG(PROTOCOL_VERSION_RANGE, "Protocol version range", range16), ++TAG(REGISTRATION_PERIOD, "Registration Period", uint32), ++TAG(ENTITY_INDEX, "Entity index", uint32, ++ .it_readonly = 1), ++TAG(ENTITY_NEXT_INDEX, "Entity next index", uint32, ++ .it_readonly = 1), ++TAG(PORTAL_IP_ADDRESS, "Portal IP address", ipaddr), ++TAG(PORTAL_TCP_UDP_PORT, "Portal TCP/UDP port", uint32, ++ USE_ACCESSORS(tcpudp_port)), ++TAG(ESI_INTERVAL, "ESI interval", uint32), ++TAG(ESI_PORT, "ESI port", uint32, ++ USE_ACCESSORS(tcpudp_port)), ++TAG(PORTAL_SYMBOLIC_NAME, "Portal name", string), ++TAG(PORTAL_INDEX, "Portal index", uint32), ++TAG(SCN_PORT, "SCN port", uint32, ++ USE_ACCESSORS(tcpudp_port)), ++TAG(PORTAL_SECURITY_BITMAP, "Portal security bitmap", uint32, ++ USE_ACCESSORS(portal_secbitmap)), ++TAG(PORTAL_NEXT_INDEX, "Portal next index", uint32, ++ .it_readonly = 1), ++ ++TAG(ISCSI_NAME, "iSCSI name", string), ++TAG(ISCSI_NODE_TYPE, "iSCSI node type", uint32, ++ USE_VALIDATOR(iscsi_node_type), ++ USE_ACCESSORS(iscsi_node_type)), ++TAG(ISCSI_ALIAS, "iSCSI alias", string), ++TAG(ISCSI_SCN_BITMAP, "iSCSI SCN bitmap", uint32, ++ USE_ACCESSORS(scn_bitmap)), ++TAG(ISCSI_NODE_INDEX, "iSCSI node index", uint32, ++ .it_readonly = 1), ++TAG(WWNN_TOKEN, "WWNN token", uint64), ++TAG(ISCSI_NODE_NEXT_INDEX, "iSCSI node next index",uint32, ++ .it_readonly = 1), ++TAG(ISCSI_AUTHMETHOD, "iSCSI auth method", string, ++ .it_help = isns_authmethod_help), ++ ++TAG(PG_ISCSI_NAME, "Portal group name", string), ++TAG(PG_PORTAL_IP_ADDR, "Portal group address", ipaddr), ++TAG(PG_PORTAL_TCP_UDP_PORT, "Portal group port", uint32, ++ USE_ACCESSORS(tcpudp_port)), ++TAG(PG_TAG, "Portal group tag", uint32), ++TAG(PG_INDEX, "Portal group index", uint32, ++ .it_readonly = 1), ++TAG(PG_NEXT_INDEX, "Portal group next index",uint32, ++ .it_readonly = 1), ++ ++/* FC Port */ ++TAG(FC_PORT_NAME_WWPN, "FC port name WWPN", uint64), ++TAG(PORT_ID, "FC port ID", uint32), ++TAG(FC_PORT_TYPE, "FC port type", uint32), ++TAG(SYMBOLIC_PORT_NAME, "FC symbolic port name",string), ++TAG(FABRIC_PORT_NAME, "FC fabric port name", uint64), ++TAG(HARD_ADDRESS, "FC hard", uint32), ++TAG(PORT_IP_ADDRESS, "FC Port IP address", ipaddr), ++TAG(CLASS_OF_SERVICE, "FC service class", uint32), ++TAG(FC4_TYPES, "FC4 types", opaque), ++TAG(FC4_DESCRIPTOR, "FC4 descriptor", string), ++TAG(FC4_FEATURES, "FC4 features", opaque), ++TAG(IFCP_SCN_BITMAP, "iFCP SCN bitmap", uint32, ++ USE_ACCESSORS(scn_bitmap)), ++TAG(PORT_ROLE, "FC port role", uint32), ++TAG(PERMANENT_PORT_NAME, "FC permanent port name",uint64), ++TAG(FC4_TYPE_CODE, "FC4 type code", uint32), ++ ++/* FC Node */ ++TAG(FC_NODE_NAME_WWNN, "FC node name", uint64), ++TAG(SYMBOLIC_NODE_NAME, "FC symbolic node name",string), ++TAG(NODE_IP_ADDRESS, "FC node IP address", ipaddr), ++TAG(NODE_IPA, "FC node IPA", uint64), ++TAG(PROXY_ISCSI_NAME, "FC node proxy iSCSI name",string), ++ ++/* Other FC tags to go here */ ++ ++/* Discovery domain set */ ++TAG(DD_SET_ID, "DD set ID", uint32), ++TAG(DD_SET_SYMBOLIC_NAME, "DD set name", string), ++TAG(DD_SET_STATUS, "DD set status", uint32), ++TAG(DD_SET_NEXT_ID, "DD set next ID", uint32, ++ .it_readonly = 1), ++ ++/* Discovery domain */ ++TAG(DD_ID, "DD ID", uint32), ++TAG(DD_SYMBOLIC_NAME, "DD name", string), ++TAG(DD_MEMBER_ISCSI_INDEX, "DD member iSCSI index",uint32, ++ .it_multiple = 1), ++TAG(DD_MEMBER_ISCSI_NAME, "DD member iSCSI name", string, ++ .it_multiple = 1), ++TAG(DD_MEMBER_FC_PORT_NAME, "DD member FC WWPN", string, ++ .it_multiple = 1), ++TAG(DD_MEMBER_PORTAL_INDEX, "DD member portal index",uint32, ++ .it_multiple = 1), ++TAG(DD_MEMBER_PORTAL_IP_ADDR, "DD member portal addr",ipaddr, ++ .it_multiple = 1), ++TAG(DD_MEMBER_PORTAL_TCP_UDP_PORT,"DD member portal port",uint32, ++ USE_ACCESSORS(tcpudp_port), ++ .it_multiple = 1), ++TAG(DD_FEATURES, "DD features", uint32, ++ USE_ACCESSORS(dd_features)), ++TAG(DD_NEXT_ID, "DD next ID", uint32, ++ .it_readonly = 1), ++}; ++ ++/* ++ * End of RFC defined tags ++ */ ++#undef TAG ++ ++/* ++ * Open-iSNS vendor specific tags ++ */ ++#define TAG(ID, name, type, args...) \ ++{ \ ++ .it_id = OPENISNS_TAG_##ID, \ ++ .it_name = name, \ ++ .it_type = &isns_attr_type_##type, \ ++ args \ ++} ++ ++static isns_tag_type_t isns_vendor_tags[] = { ++TAG(POLICY_SPI, "Security Policy Index", string), ++TAG(POLICY_KEY, "DSA security key", opaque), ++TAG(POLICY_ENTITY, "Policy allowed entity name", string), ++TAG(POLICY_OBJECT_TYPE, "Policy allowed object types", uint32, ++ USE_ACCESSORS(policy_object_type)), ++TAG(POLICY_NODE_NAME, "Policy allowed node name", string, ++ .it_multiple = 1), ++TAG(POLICY_NODE_TYPE, "Policy allowed node type", uint32, ++ USE_VALIDATOR(iscsi_node_type), ++ USE_ACCESSORS(iscsi_node_type)), ++TAG(POLICY_FUNCTIONS, "Policy allowed functions", uint32, ++ USE_ACCESSORS(policy_function)), ++TAG(POLICY_VISIBLE_DD, "Visible Discovery Domain", string, ++ .it_multiple = 1), ++TAG(POLICY_DEFAULT_DD, "Default Discovery Domain", string), ++ ++{ 0 } ++}; ++ ++/* ++ * End of vendor-specific tags ++ */ ++ ++static isns_tag_type_t isns_unknown_tag = { ++ .it_id = 0xffff, ++ .it_name = "unknown", ++ .it_type = &isns_attr_type_opaque, ++}; ++ ++/* ++ * Map iSNS attribute tag to its data type ++ */ ++const isns_tag_type_t * ++isns_tag_type_by_id(uint32_t id) ++{ ++ isns_tag_type_t *tag; ++ ++ if (id < ISNS_MAX_BUILTIN_TAG) { ++ tag = &isns_tags[id]; ++ if (tag->it_type == NULL) { ++ *tag = isns_unknown_tag; ++ tag->it_id = id; ++ } ++ return tag; ++ } ++ ++ for (tag = isns_vendor_tags; tag->it_name; ++tag) { ++ if (tag->it_id == id) ++ return tag; ++ } ++ ++ return &isns_unknown_tag; ++} ++ ++/* ++ * Specific validators/pretty printers ++ */ ++int ++isns_entity_protocol_validate(const isns_value_t *value, const isns_policy_t *policy) ++{ ++ enum isns_entity_protocol protocol = value->iv_uint32; ++ ++ switch (protocol) { ++ case ISNS_ENTITY_PROTOCOL_NONE: ++ case ISNS_ENTITY_PROTOCOL_ISCSI: ++ case ISNS_ENTITY_PROTOCOL_IFCP: ++ return 1; ++ } ++ return 0; ++} ++ ++int ++isns_entity_protocol_parse(isns_value_t *value, const char *string) ++{ ++ uint32_t prot; ++ ++ if (!strcasecmp(string, "none")) ++ prot = ISNS_ENTITY_PROTOCOL_NONE; ++ else if (!strcasecmp(string, "iscsi")) ++ prot = ISNS_ENTITY_PROTOCOL_ISCSI; ++ else if (!strcasecmp(string, "ifcp")) ++ prot = ISNS_ENTITY_PROTOCOL_IFCP; ++ else ++ return 0; ++ value->iv_uint32 = prot; ++ return 1; ++} ++ ++void ++isns_entity_protocol_print(const isns_value_t *value, char *buf, size_t size) ++{ ++ enum isns_entity_protocol protocol = value->iv_uint32; ++ const char *prot_name; ++ ++ switch (protocol) { ++ case ISNS_ENTITY_PROTOCOL_NONE: ++ prot_name = "None"; ++ break; ++ ++ case ISNS_ENTITY_PROTOCOL_ISCSI: ++ prot_name = "iSCSI"; ++ break; ++ ++ case ISNS_ENTITY_PROTOCOL_IFCP: ++ prot_name = "iFCP"; ++ break; ++ ++ default: ++ prot_name = "Unknown"; ++ } ++ snprintf(buf, size, "%s (%u)", prot_name, protocol); ++} ++ ++const char * ++isns_entity_protocol_help(void) ++{ ++ return "one of None, iSCSI, iFCP"; ++} ++ ++/* ++ * TCP/UDP port ++ */ ++int ++isns_tcpudp_port_parse(isns_value_t *value, const char *string) ++{ ++ uint32_t num; ++ const char *ep; ++ ++ num = strtoul(string, (char **) &ep, 0); ++ if (ep && *ep) { ++ if (!strcasecmp(ep, "/udp")) ++ num |= ISNS_PORTAL_PORT_UDP_MASK; ++ else ++ if (!strcasecmp(ep, "/tcp")) ++ /* nothing */; ++ else { ++ isns_error("Cannot parse port spec \"%s\"\n", ++ string); ++ return 0; ++ } ++ } ++ value->iv_uint32 = num; ++ return 1; ++} ++ ++void ++isns_tcpudp_port_print(const isns_value_t *value, char *buf, size_t size) ++{ ++ uint32_t portspec = value->iv_uint32, num; ++ ++ if (portspec == 0) { ++ snprintf(buf, size, "[default]"); ++ } else { ++ num = portspec & 0xffff; ++ if (portspec & ISNS_PORTAL_PORT_UDP_MASK) { ++ snprintf(buf, size, "%u/udp", num); ++ } else { ++ snprintf(buf, size, "%u/tcp", num); ++ } ++ } ++} ++ ++const char * ++isns_tcpudp_port_help(void) ++{ ++ return "/tcp, /udp, or (defaults to TCP)"; ++} ++ ++int ++isns_timestamp_parse(isns_value_t *value, const char *string) ++{ ++ isns_error("Timestamp parsing not implemented\n"); ++ return 0; ++} ++ ++void ++isns_timestamp_print(const isns_value_t *value, char *buf, size_t size) ++{ ++ time_t timestamp = value->iv_uint64; ++ char *str, *s; ++ ++ str = ctime(×tamp); ++ if ((s = strchr(str, '\n')) != NULL) ++ *s = '\0'; ++ ++ snprintf(buf, size, "%s", str); ++} ++ ++const char * ++isns_timestamp_help(void) ++{ ++ return NULL; ++} ++ ++/* ++ * Helper macros to implement the off-the-shelf bitfield ++ * accessors. ++ */ ++#define IMPLEMENT_BITFIELD_ACCESSORS(name) \ ++int isns_##name##_parse(isns_value_t *value, const char *string) \ ++{ \ ++ return parse_bitfield(name##_bit_names, string, \ ++ &value->iv_uint32); \ ++} \ ++ \ ++void \ ++isns_##name##_print(const isns_value_t *value, char *buf, size_t size) \ ++{ \ ++ print_bitfield(value->iv_uint32, name##_bit_names, \ ++ buf, size); \ ++} \ ++ \ ++const char * \ ++isns_##name##_help(void) \ ++{ \ ++ return help_bitfield(name##_bit_names); \ ++} ++ ++ ++static char * iscsi_node_type_bit_names[32] = { ++[ISNS_ISCSI_NODE_TYPE_TARGET] = "Target", ++[ISNS_ISCSI_NODE_TYPE_INITIATOR] = "Initiator", ++[ISNS_ISCSI_NODE_TYPE_CONTROL] = "Control", ++}; ++ ++int ++isns_iscsi_node_type_validate(const isns_value_t *value, const isns_policy_t *policy) ++{ ++ uint32_t bits = value->iv_uint32, permitted; ++ ++ permitted = ISNS_ISCSI_INITIATOR_MASK | ++ ISNS_ISCSI_TARGET_MASK | ++ ISNS_ISCSI_CONTROL_MASK; ++ if (bits & ~permitted) ++ return 0; ++ ++ if (policy && !isns_policy_validate_node_type(policy, bits)) ++ return 0; ++ ++ return 1; ++} ++ ++IMPLEMENT_BITFIELD_ACCESSORS(iscsi_node_type); ++ ++/* ++ * Portal Security Bitmap ++ */ ++static char * portal_secbitmap_bit_names[32] = { ++[ISNS_PORTAL_SEC_BITMAP_VALID] = "bitmap valid", ++[ISNS_PORTAL_SEC_IPSEC_ENABLED] = "ipsec enabled", ++[ISNS_PORTAL_SEC_MAIN_MODE_ENABLED] = "main mode enabled", ++[ISNS_PORTAL_SEC_AGGR_MODE_ENABLED] = "aggressive mode enabled", ++[ISNS_PORTAL_SEC_PFS_ENABLED] = "pfs enabled", ++[ISNS_PORTAL_SEC_TRANSPORT_MODE_PREFERRED] = "transport mode preferred", ++[ISNS_PORTAL_SEC_TUNNEL_MODE_PREFERRED] = "tunnel mode preferred", ++}; ++ ++IMPLEMENT_BITFIELD_ACCESSORS(portal_secbitmap); ++ ++/* ++ * SCN bitmap ++ */ ++static char * scn_bitmap_bit_names[32] = { ++[ISNS_SCN_DD_MEMBER_ADDED] = "DD/DDS member added", ++[ISNS_SCN_DD_MEMBER_REMOVED] = "DD/DDS member removed", ++[ISNS_SCN_OBJECT_UPDATED] = "object updated", ++[ISNS_SCN_OBJECT_ADDED] = "object added", ++[ISNS_SCN_OBJECT_REMOVED] = "object removed", ++[ISNS_SCN_MANAGEMENT_REGISTRATION] = "management registration", ++[ISNS_SCN_TARGET_AND_SELF_ONLY] = "target and self information only", ++[ISNS_SCN_INITIATOR_AND_SELF_ONLY] = "initiator and self information only", ++}; ++ ++IMPLEMENT_BITFIELD_ACCESSORS(scn_bitmap); ++ ++/* ++ * DD features bitmap ++ */ ++static char * dd_features_bit_names[32] = { ++[ISNS_DD_BOOT_LIST_ENABLED] = "Boot list enabled", ++}; ++ ++IMPLEMENT_BITFIELD_ACCESSORS(dd_features); ++ ++/* ++ * Policy: list of allowed functions ++ */ ++static char * policy_function_bit_names[32] = { ++[ISNS_DEVICE_ATTRIBUTE_REGISTER]= "DevAttrReg", ++[ISNS_DEVICE_ATTRIBUTE_QUERY] = "DevAttrQry", ++[ISNS_DEVICE_GET_NEXT] = "DevGetNext", ++[ISNS_DEVICE_DEREGISTER] = "DevDereg", ++[ISNS_SCN_REGISTER] = "SCNReg", ++[ISNS_SCN_DEREGISTER] = "SCNDereg", ++[ISNS_SCN_EVENT] = "SCNEvent", ++[ISNS_STATE_CHANGE_NOTIFICATION]= "SCN", ++[ISNS_DD_REGISTER] = "DDReg", ++[ISNS_DD_DEREGISTER] = "DDDereg", ++[ISNS_DDS_REGISTER] = "DDSReg", ++[ISNS_DDS_DEREGISTER] = "DDSDereg", ++[ISNS_ENTITY_STATUS_INQUIRY] = "ESI", ++[ISNS_HEARTBEAT] = "Heartbeat", ++}; ++ ++IMPLEMENT_BITFIELD_ACCESSORS(policy_function); ++ ++/* ++ * Policy: list of allowed node types ++ */ ++static char * policy_object_type_bit_names[32] = { ++[ISNS_OBJECT_TYPE_ENTITY] = "entity", ++[ISNS_OBJECT_TYPE_NODE] = "iscsi-node", ++[ISNS_OBJECT_TYPE_PORTAL] = "portal", ++[ISNS_OBJECT_TYPE_PG] = "portal-group", ++[ISNS_OBJECT_TYPE_DD] = "dd", ++[ISNS_OBJECT_TYPE_DDSET] = "ddset", ++[ISNS_OBJECT_TYPE_POLICY] = "policy", ++}; ++ ++static int ++isns_policy_object_type_parse(isns_value_t *vp, const char *buf) ++{ ++ char *copy, *s, *next; ++ int rv = 0; ++ ++ if (!strcasecmp(buf, "ALL")) { ++ vp->iv_uint32 = ~0; ++ return 1; ++ } ++ if (!strcasecmp(buf, "DEFAULT")) { ++ vp->iv_uint32 = ISNS_DEFAULT_OBJECT_ACCESS; ++ return 1; ++ } ++ ++ vp->iv_uint32 = 0; ++ copy = isns_strdup(buf); ++ for (s = copy; s; s = next) { ++ char *perm; ++ int bit, mask = 0; ++ ++ while (1) { ++ unsigned int n; ++ ++ n = strcspn(s, ",+;|"); ++ if (n) { ++ next = s + n; ++ if (*next) ++ *next++ = '\0'; ++ break; ++ } ++ ++n; ++ } ++ ++ mask = ISNS_PERMISSION_READ; ++ if ((perm = strchr(s, ':')) != NULL) { ++ *perm++ = '\0'; ++ mask = 0; ++ while (*perm) { ++ switch (*perm++) { ++ case 'R': case 'r': ++ mask = ISNS_PERMISSION_READ; ++ break; ++ case 'W': case 'w': ++ mask = ISNS_PERMISSION_READ; ++ break; ++ default: ++ goto failed; ++ } ++ } ++ } ++ ++ for (bit = 0; bit < 32; ++bit) { ++ if (policy_object_type_bit_names[bit] ++ && !strcasecmp(policy_object_type_bit_names[bit], s)) ++ goto found; ++ } ++ goto failed; ++ ++found: vp->iv_uint32 |= ISNS_ACCESS(bit, mask); ++ } ++ rv = 1; ++ ++failed: ++ isns_free(copy); ++ return rv; ++} ++ ++static void ++isns_policy_object_type_print(const isns_value_t *vp, char *buf, size_t size) ++{ ++ unsigned int i, pos = 0; ++ uint32_t mask; ++ const char *sepa = ""; ++ ++ mask = vp->iv_uint32; ++ if (mask == 0) { ++ snprintf(buf, size, ""); ++ return; ++ } ++ ++ for (i = 0; i < 32; ++i, mask >>= 2) { ++ const char *name; ++ ++ if (!(mask & 3)) ++ continue; ++ ++ name = policy_object_type_bit_names[i]; ++ if (name) ++ snprintf(buf + pos, size - pos, "%s%s:%s%s", sepa, name, ++ (mask & ISNS_PERMISSION_READ)? "r" : "", ++ (mask & ISNS_PERMISSION_WRITE)? "w" : ""); ++ else ++ snprintf(buf + pos, size - pos, "%sbit%u:%s%s",sepa, i, ++ (mask & ISNS_PERMISSION_READ)? "r" : "", ++ (mask & ISNS_PERMISSION_WRITE)? "w" : ""); ++ sepa = ", "; ++ pos = strlen(buf); ++ } ++} ++ ++static const char * ++isns_policy_object_type_help(void) ++{ ++ static char buffer[256]; ++ unsigned int i, n; ++ char *sepa = ""; ++ ++ strcpy(buffer, "bitfield (type:perm): perm=R, W, or RW; type="); ++ n = strlen(buffer); ++ ++ for (i = 0; i < 32; ++i) { ++ if (policy_object_type_bit_names[i]) { ++ snprintf(buffer + n, sizeof(buffer) - n, ++ "%s%s", sepa, ++ policy_object_type_bit_names[i]); ++ sepa = ", "; ++ } ++ } ++ return buffer; ++} ++ ++/* ++ * Help message for AuthMethod ++ */ ++const char * ++isns_authmethod_help(void) ++{ ++ return "comma separated list, including of KRB5, SPKM1, SPKM2, SRP, CHAP, none"; ++} ++ ++/* ++ * Helper functions to deal with bitfields ++ */ ++static void ++print_bitfield(unsigned long value, char **bit_names, ++ char *buf, size_t size) ++{ ++ unsigned int bit, mask; ++ const char *sepa = ""; ++ char *buf_end; ++ ++ if (value == 0) { ++ snprintf(buf, size, ""); ++ return; ++ } ++ ++ buf_end = buf + size; ++ for (bit = 0, mask = 1; mask; ++bit, mask <<= 1) { ++ char namebuf[16], *name; ++ ++ if (!(value & mask)) ++ continue; ++ ++ if ((name = bit_names[bit]) == NULL) { ++ sprintf(namebuf, "bit%u", bit); ++ name = namebuf; ++ } ++ ++ snprintf(buf, buf_end - buf, "%s%s", sepa, name); ++ buf += strlen(buf); ++ sepa = ", "; ++ } ++} ++ ++static int ++parse_bitfield(char **bit_names, ++ const char *string, ++ uint32_t *result) ++{ ++ *result = 0; ++ ++ if (!strcasecmp(string, "ALL")) { ++ unsigned int bit; ++ ++ for (bit = 0; bit < 32; ++bit) { ++ if (bit_names[bit]) ++ *result |= 1 << bit; ++ } ++ return 1; ++ } ++ ++ if (!strcasecmp(string, "NONE")) ++ return 1; ++ ++ while (*string) { ++ unsigned int n, bit, match = 0; ++ ++ n = strcspn(string, ",+;|"); ++ if (n == 0) ++ goto next; ++ ++ for (bit = 0; bit < 32; ++bit) { ++ if (!bit_names[bit]) ++ continue; ++ if (!strncasecmp(bit_names[bit], string, n)) { ++ *result |= 1 << bit; ++ match++; ++ } ++ } ++ if (!match) ++ return 0; ++ ++next: ++ string += n; ++ string += strspn(string, ",+;|"); ++ } ++ ++ return 1; ++} ++ ++static const char * ++help_bitfield(char **bit_names) ++{ ++ static char buffer[1024]; ++ char *pos, sepa = ':'; ++ unsigned int bit; ++ ++ strcpy(buffer, "bitfield"); ++ pos = strchr(buffer, '\0'); ++ ++ for (bit = 0; bit < 32; ++bit) { ++ if (bit_names[bit] == NULL) ++ continue; ++ ++ snprintf(pos, sizeof(buffer) - (pos - buffer), ++ "%c %s", sepa, bit_names[bit]); ++ ++ pos += strlen(pos); ++ sepa = ','; ++ } ++ return buffer; ++} ++ +diff --git a/utils/open-isns/tests/.cvsignore b/utils/open-isns/tests/.cvsignore +new file mode 100644 +index 0000000..fa1eb3c +--- /dev/null ++++ b/utils/open-isns/tests/.cvsignore +@@ -0,0 +1,2 @@ ++*.swp ++pauw[1-9] +diff --git a/utils/open-isns/tests/Makefile b/utils/open-isns/tests/Makefile +new file mode 100644 +index 0000000..778195a +--- /dev/null ++++ b/utils/open-isns/tests/Makefile +@@ -0,0 +1,40 @@ ++# ++# Simple makefile to run regression tests, and to ++# document how to run them. ++ ++# ++# Each test case is a perl script, testXX.pl. Run as ++# perl testXX.pl ++# Optionally followed by ++# -q quiet - just print a header line, and the overall result ++# -v verbose - display more detailed information, including the ++# commands being run ++# -f fast - skip tests that take more than 15 seconds ++# ++# The default is to be slightly verbose, and display a comment ++# about each stage of the test. ++ ++# All test related data is kept in /tmp/isns-test, with a ++# subdirectory for each test. ++# For instance, test01 will create ++# /tmp/isns-test/test01/server0 ++# /tmp/isns-test/test01/client1 ++# /tmp/isns-test/test01/dump ++# ++# The server and client directories will contain configuration ++# data, logfiles, and (for the server) the Unix socket, the ++# PID file, and the database. ++# ++# The dump directory contains snapshots of the on-disk database ++# for each test stage (if the test stage involves a verification ++# of the database). ++ ++tests: ++ @for test in test*.pl; do \ ++ perl $$test -q; \ ++ done ++ ++quick: ++ @for test in test*.pl; do \ ++ perl $$test -q --fast; \ ++ done +diff --git a/utils/open-isns/tests/client.conf b/utils/open-isns/tests/client.conf +new file mode 100644 +index 0000000..034a739 +--- /dev/null ++++ b/utils/open-isns/tests/client.conf +@@ -0,0 +1,8 @@ ++SourceName = @NOT_SET@ ++AuthName = @NOT_SET@ ++ServerAddress = @NOT_SET@ ++BindAddress = @NOT_SET@ ++Security = @NOT_SET@ ++AuthKeyFile = @NOT_SET@ ++ServerKeyFile = @NOT_SET@ ++ControlSocket = @NOT_SET@ +diff --git a/utils/open-isns/tests/data/test01/01-enroll b/utils/open-isns/tests/data/test01/01-enroll +new file mode 100644 +index 0000000..f59329b +--- /dev/null ++++ b/utils/open-isns/tests/data/test01/01-enroll +@@ -0,0 +1,18 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test01/server0/database ++Last EID: 1 ++Last Index: 4 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test01/02-registration b/utils/open-isns/tests/data/test01/02-registration +new file mode 100644 +index 0000000..fd26f3c +--- /dev/null ++++ b/utils/open-isns/tests/data/test01/02-registration +@@ -0,0 +1,42 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test01/server0/database ++Last EID: 1 ++Last Index: 8 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 12:40:58 2007 ++ 0007 uint32 : Entity index = 4 ++-------------- ++Object: index=5 type= state=mature parent=4 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 5 ++-------------- ++Object: index=6 type= state=mature parent=4 ++ 0010 ipaddr : Portal IP address = 127.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 6 ++-------------- ++Object: index=7 type= state=mature parent=4 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.0.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test01/03-query b/utils/open-isns/tests/data/test01/03-query +new file mode 100644 +index 0000000..8208f83 +--- /dev/null ++++ b/utils/open-isns/tests/data/test01/03-query +@@ -0,0 +1,20 @@ ++object[0] = ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 12:41:41 2007 ++ 0007 uint32 : Entity index = 4 ++object[1] = ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 5 ++object[2] = ++ 0010 ipaddr : Portal IP address = 127.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 6 ++object[3] = ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.0.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test01/03-registration b/utils/open-isns/tests/data/test01/03-registration +new file mode 100644 +index 0000000..affd69a +--- /dev/null ++++ b/utils/open-isns/tests/data/test01/03-registration +@@ -0,0 +1,20 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test01/server0/database ++Last EID: 1 ++Last Index: 4 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "isns.client1" ++ 0602v string : Policy allowed source name = "isns.client1" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "isns.client2" ++ 0602v string : Policy allowed source name = "isns.client2" ++ 0607v string : Policy allowed node name = "isns.client2" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +diff --git a/utils/open-isns/tests/data/test01/99-unregistration b/utils/open-isns/tests/data/test01/99-unregistration +new file mode 100644 +index 0000000..c7518ff +--- /dev/null ++++ b/utils/open-isns/tests/data/test01/99-unregistration +@@ -0,0 +1,18 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test01/server0/database ++Last EID: 1 ++Last Index: 8 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test02/01-enroll b/utils/open-isns/tests/data/test02/01-enroll +new file mode 100644 +index 0000000..e91fa0b +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/01-enroll +@@ -0,0 +1,18 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test02/server0/database ++Last EID: 1 ++Last Index: 4 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test02/02-enroll b/utils/open-isns/tests/data/test02/02-enroll +new file mode 100644 +index 0000000..dbcb735 +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/02-enroll +@@ -0,0 +1,24 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test02/server0/database ++Last EID: 1 ++Last Index: 5 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client2.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client2" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++ 0608v uint32 : Policy allowed node type = Target +diff --git a/utils/open-isns/tests/data/test02/03-registration b/utils/open-isns/tests/data/test02/03-registration +new file mode 100644 +index 0000000..ec607e6 +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/03-registration +@@ -0,0 +1,72 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test02/server0/database ++Last EID: 1 ++Last Index: 13 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client2.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client2" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++ 0608v uint32 : Policy allowed node type = Target ++-------------- ++Object: index=5 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:53 2007 ++ 0007 uint32 : Entity index = 5 ++-------------- ++Object: index=6 type= state=mature parent=5 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 6 ++-------------- ++Object: index=7 type= state=mature parent=5 ++ 0010 ipaddr : Portal IP address = 127.1.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 7 ++-------------- ++Object: index=8 type= state=mature parent=5 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.1.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 ++-------------- ++Object: index=9 type= state=mature ++ 0001 string : Entity identifier = "client2.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:53 2007 ++ 0007 uint32 : Entity index = 9 ++-------------- ++Object: index=10 type= state=mature parent=9 ++ 0020 string : iSCSI name = "isns.client2" ++ 0021 uint32 : iSCSI node type = Target ++ 0024 uint32 : iSCSI node index = 10 ++-------------- ++Object: index=11 type= state=mature parent=9 ++ 0010 ipaddr : Portal IP address = 127.1.0.2 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0016 uint32 : Portal index = 11 ++-------------- ++Object: index=12 type= state=mature parent=9 ++ 0030 string : Portal group name = "isns.client2" ++ 0031 ipaddr : Portal group address = 127.1.0.2 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 12 +diff --git a/utils/open-isns/tests/data/test02/04-query b/utils/open-isns/tests/data/test02/04-query +new file mode 100644 +index 0000000..fbdb0c0 +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/04-query +@@ -0,0 +1,20 @@ ++object[0] = ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 ++ 0007 uint32 : Entity index = 5 ++object[1] = ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 6 ++object[2] = ++ 0010 ipaddr : Portal IP address = 127.1.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 7 ++object[3] = ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.1.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 +diff --git a/utils/open-isns/tests/data/test02/05-query b/utils/open-isns/tests/data/test02/05-query +new file mode 100644 +index 0000000..a35db9e +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/05-query +@@ -0,0 +1,20 @@ ++object[0] = ++ 0001 string : Entity identifier = "client2.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 ++ 0007 uint32 : Entity index = 9 ++object[1] = ++ 0020 string : iSCSI name = "isns.client2" ++ 0021 uint32 : iSCSI node type = Target ++ 0024 uint32 : iSCSI node index = 10 ++object[2] = ++ 0010 ipaddr : Portal IP address = 127.1.0.2 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0016 uint32 : Portal index = 11 ++object[3] = ++ 0030 string : Portal group name = "isns.client2" ++ 0031 ipaddr : Portal group address = 127.1.0.2 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 12 +diff --git a/utils/open-isns/tests/data/test02/06-dd-registration b/utils/open-isns/tests/data/test02/06-dd-registration +new file mode 100644 +index 0000000..833f62a +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/06-dd-registration +@@ -0,0 +1,81 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test02/server0/database ++Last EID: 1 ++Last Index: 14 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client2.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client2" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++ 0608v uint32 : Policy allowed node type = Target ++-------------- ++Object: index=5 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 ++ 0007 uint32 : Entity index = 5 ++-------------- ++Object: index=6 type= state=mature parent=5 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 6 ++-------------- ++Object: index=7 type= state=mature parent=5 ++ 0010 ipaddr : Portal IP address = 127.1.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 7 ++-------------- ++Object: index=8 type= state=mature parent=5 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.1.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 ++-------------- ++Object: index=9 type= state=mature ++ 0001 string : Entity identifier = "client2.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 ++ 0007 uint32 : Entity index = 9 ++-------------- ++Object: index=10 type= state=mature parent=9 ++ 0020 string : iSCSI name = "isns.client2" ++ 0021 uint32 : iSCSI node type = Target ++ 0024 uint32 : iSCSI node index = 10 ++-------------- ++Object: index=11 type= state=mature parent=9 ++ 0010 ipaddr : Portal IP address = 127.1.0.2 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0016 uint32 : Portal index = 11 ++-------------- ++Object: index=12 type= state=mature parent=9 ++ 0030 string : Portal group name = "isns.client2" ++ 0031 ipaddr : Portal group address = 127.1.0.2 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 12 ++-------------- ++Object: index=13 type= state=mature ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 6 ++ 0814 string : DD member iSCSI name = "isns.client1" ++ 0813 uint32 : DD member iSCSI index = 10 ++ 0814 string : DD member iSCSI name = "isns.client2" +diff --git a/utils/open-isns/tests/data/test02/07-query b/utils/open-isns/tests/data/test02/07-query +new file mode 100644 +index 0000000..de13226 +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/07-query +@@ -0,0 +1,40 @@ ++object[0] = ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 ++ 0007 uint32 : Entity index = 5 ++object[1] = ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 6 ++object[2] = ++ 0010 ipaddr : Portal IP address = 127.1.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 7 ++object[3] = ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.1.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 ++object[4] = ++ 0001 string : Entity identifier = "client2.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 ++ 0007 uint32 : Entity index = 9 ++object[5] = ++ 0020 string : iSCSI name = "isns.client2" ++ 0021 uint32 : iSCSI node type = Target ++ 0024 uint32 : iSCSI node index = 10 ++object[6] = ++ 0010 ipaddr : Portal IP address = 127.1.0.2 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0016 uint32 : Portal index = 11 ++object[7] = ++ 0030 string : Portal group name = "isns.client2" ++ 0031 ipaddr : Portal group address = 127.1.0.2 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 12 +diff --git a/utils/open-isns/tests/data/test02/08-query b/utils/open-isns/tests/data/test02/08-query +new file mode 100644 +index 0000000..de13226 +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/08-query +@@ -0,0 +1,40 @@ ++object[0] = ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 ++ 0007 uint32 : Entity index = 5 ++object[1] = ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 6 ++object[2] = ++ 0010 ipaddr : Portal IP address = 127.1.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 7 ++object[3] = ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.1.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 ++object[4] = ++ 0001 string : Entity identifier = "client2.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 ++ 0007 uint32 : Entity index = 9 ++object[5] = ++ 0020 string : iSCSI name = "isns.client2" ++ 0021 uint32 : iSCSI node type = Target ++ 0024 uint32 : iSCSI node index = 10 ++object[6] = ++ 0010 ipaddr : Portal IP address = 127.1.0.2 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0016 uint32 : Portal index = 11 ++object[7] = ++ 0030 string : Portal group name = "isns.client2" ++ 0031 ipaddr : Portal group address = 127.1.0.2 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 12 +diff --git a/utils/open-isns/tests/data/test02/09-query b/utils/open-isns/tests/data/test02/09-query +new file mode 100644 +index 0000000..a35db9e +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/09-query +@@ -0,0 +1,20 @@ ++object[0] = ++ 0001 string : Entity identifier = "client2.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 ++ 0007 uint32 : Entity index = 9 ++object[1] = ++ 0020 string : iSCSI name = "isns.client2" ++ 0021 uint32 : iSCSI node type = Target ++ 0024 uint32 : iSCSI node index = 10 ++object[2] = ++ 0010 ipaddr : Portal IP address = 127.1.0.2 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0016 uint32 : Portal index = 11 ++object[3] = ++ 0030 string : Portal group name = "isns.client2" ++ 0031 ipaddr : Portal group address = 127.1.0.2 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 12 +diff --git a/utils/open-isns/tests/data/test02/10-dd-registration b/utils/open-isns/tests/data/test02/10-dd-registration +new file mode 100644 +index 0000000..69bf9f6 +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/10-dd-registration +@@ -0,0 +1,87 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test02/server0/database ++Last EID: 1 ++Last Index: 15 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client2.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client2" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++ 0608v uint32 : Policy allowed node type = Target ++-------------- ++Object: index=5 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 ++ 0007 uint32 : Entity index = 5 ++-------------- ++Object: index=6 type= state=mature parent=5 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 6 ++-------------- ++Object: index=7 type= state=mature parent=5 ++ 0010 ipaddr : Portal IP address = 127.1.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 7 ++-------------- ++Object: index=8 type= state=mature parent=5 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.1.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 ++-------------- ++Object: index=9 type= state=mature ++ 0001 string : Entity identifier = "client2.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 ++ 0007 uint32 : Entity index = 9 ++-------------- ++Object: index=10 type= state=mature parent=9 ++ 0020 string : iSCSI name = "isns.client2" ++ 0021 uint32 : iSCSI node type = Target ++ 0024 uint32 : iSCSI node index = 10 ++-------------- ++Object: index=11 type= state=mature parent=9 ++ 0010 ipaddr : Portal IP address = 127.1.0.2 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0016 uint32 : Portal index = 11 ++-------------- ++Object: index=12 type= state=mature parent=9 ++ 0030 string : Portal group name = "isns.client2" ++ 0031 ipaddr : Portal group address = 127.1.0.2 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 12 ++-------------- ++Object: index=13 type= state=mature ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 6 ++ 0814 string : DD member iSCSI name = "isns.client1" ++ 0813 uint32 : DD member iSCSI index = 10 ++ 0814 string : DD member iSCSI name = "isns.client2" ++ 0813 uint32 : DD member iSCSI index = 14 ++ 0814 string : DD member iSCSI name = "iqn.com.foobar:disk1" ++-------------- ++Object: index=14 type= state=limbo ++ 0020 string : iSCSI name = "iqn.com.foobar:disk1" ++ 0024 uint32 : iSCSI node index = 14 +diff --git a/utils/open-isns/tests/data/test02/11-query b/utils/open-isns/tests/data/test02/11-query +new file mode 100644 +index 0000000..5b4c49d +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/11-query +@@ -0,0 +1,10 @@ ++object[0] = ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 6 ++ 0814 string : DD member iSCSI name = "isns.client1" ++ 0813 uint32 : DD member iSCSI index = 10 ++ 0814 string : DD member iSCSI name = "isns.client2" ++ 0813 uint32 : DD member iSCSI index = 14 ++ 0814 string : DD member iSCSI name = "iqn.com.foobar:disk1" +diff --git a/utils/open-isns/tests/data/test02/12-dd-deregistration b/utils/open-isns/tests/data/test02/12-dd-deregistration +new file mode 100644 +index 0000000..d330b2a +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/12-dd-deregistration +@@ -0,0 +1,85 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test02/server0/database ++Last EID: 1 ++Last Index: 15 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client2.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client2" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++ 0608v uint32 : Policy allowed node type = Target ++-------------- ++Object: index=5 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:20:33 2007 ++ 0007 uint32 : Entity index = 5 ++-------------- ++Object: index=6 type= state=mature parent=5 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 6 ++-------------- ++Object: index=7 type= state=mature parent=5 ++ 0010 ipaddr : Portal IP address = 127.1.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 7 ++-------------- ++Object: index=8 type= state=mature parent=5 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.1.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 ++-------------- ++Object: index=9 type= state=mature ++ 0001 string : Entity identifier = "client2.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:20:33 2007 ++ 0007 uint32 : Entity index = 9 ++-------------- ++Object: index=10 type= state=mature parent=9 ++ 0020 string : iSCSI name = "isns.client2" ++ 0021 uint32 : iSCSI node type = Target ++ 0024 uint32 : iSCSI node index = 10 ++-------------- ++Object: index=11 type= state=mature parent=9 ++ 0010 ipaddr : Portal IP address = 127.1.0.2 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0016 uint32 : Portal index = 11 ++-------------- ++Object: index=12 type= state=mature parent=9 ++ 0030 string : Portal group name = "isns.client2" ++ 0031 ipaddr : Portal group address = 127.1.0.2 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 12 ++-------------- ++Object: index=13 type= state=mature ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 6 ++ 0814 string : DD member iSCSI name = "isns.client1" ++ 0813 uint32 : DD member iSCSI index = 14 ++ 0814 string : DD member iSCSI name = "iqn.com.foobar:disk1" ++-------------- ++Object: index=14 type= state=limbo ++ 0020 string : iSCSI name = "iqn.com.foobar:disk1" ++ 0024 uint32 : iSCSI node index = 14 +diff --git a/utils/open-isns/tests/data/test02/13-dd-deregistration b/utils/open-isns/tests/data/test02/13-dd-deregistration +new file mode 100644 +index 0000000..4175e8e +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/13-dd-deregistration +@@ -0,0 +1,83 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test02/server0/database ++Last EID: 1 ++Last Index: 15 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client2.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client2" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++ 0608v uint32 : Policy allowed node type = Target ++-------------- ++Object: index=5 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:24:04 2007 ++ 0007 uint32 : Entity index = 5 ++-------------- ++Object: index=6 type= state=mature parent=5 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 6 ++-------------- ++Object: index=7 type= state=mature parent=5 ++ 0010 ipaddr : Portal IP address = 127.1.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 7 ++-------------- ++Object: index=8 type= state=mature parent=5 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.1.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 ++-------------- ++Object: index=9 type= state=mature ++ 0001 string : Entity identifier = "client2.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:24:04 2007 ++ 0007 uint32 : Entity index = 9 ++-------------- ++Object: index=10 type= state=mature parent=9 ++ 0020 string : iSCSI name = "isns.client2" ++ 0021 uint32 : iSCSI node type = Target ++ 0024 uint32 : iSCSI node index = 10 ++-------------- ++Object: index=11 type= state=mature parent=9 ++ 0010 ipaddr : Portal IP address = 127.1.0.2 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0016 uint32 : Portal index = 11 ++-------------- ++Object: index=12 type= state=mature parent=9 ++ 0030 string : Portal group name = "isns.client2" ++ 0031 ipaddr : Portal group address = 127.1.0.2 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 12 ++-------------- ++Object: index=13 type= state=mature ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 6 ++ 0814 string : DD member iSCSI name = "isns.client1" ++-------------- ++Object: index=14 type= state=limbo ++ 0020 string : iSCSI name = "iqn.com.foobar:disk1" ++ 0024 uint32 : iSCSI node index = 14 +diff --git a/utils/open-isns/tests/data/test02/14-dd-registration b/utils/open-isns/tests/data/test02/14-dd-registration +new file mode 100644 +index 0000000..56cfac3 +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/14-dd-registration +@@ -0,0 +1,85 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test02/server0/database ++Last EID: 1 ++Last Index: 15 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client2.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client2" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++ 0608v uint32 : Policy allowed node type = Target ++-------------- ++Object: index=5 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:24:04 2007 ++ 0007 uint32 : Entity index = 5 ++-------------- ++Object: index=6 type= state=mature parent=5 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 6 ++-------------- ++Object: index=7 type= state=mature parent=5 ++ 0010 ipaddr : Portal IP address = 127.1.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 7 ++-------------- ++Object: index=8 type= state=mature parent=5 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.1.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 ++-------------- ++Object: index=9 type= state=mature ++ 0001 string : Entity identifier = "client2.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:24:04 2007 ++ 0007 uint32 : Entity index = 9 ++-------------- ++Object: index=10 type= state=mature parent=9 ++ 0020 string : iSCSI name = "isns.client2" ++ 0021 uint32 : iSCSI node type = Target ++ 0024 uint32 : iSCSI node index = 10 ++-------------- ++Object: index=11 type= state=mature parent=9 ++ 0010 ipaddr : Portal IP address = 127.1.0.2 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0016 uint32 : Portal index = 11 ++-------------- ++Object: index=12 type= state=mature parent=9 ++ 0030 string : Portal group name = "isns.client2" ++ 0031 ipaddr : Portal group address = 127.1.0.2 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 12 ++-------------- ++Object: index=13 type= state=mature ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 6 ++ 0814 string : DD member iSCSI name = "isns.client1" ++ 0813 uint32 : DD member iSCSI index = 10 ++ 0814 string : DD member iSCSI name = "isns.client2" ++-------------- ++Object: index=14 type= state=limbo ++ 0020 string : iSCSI name = "iqn.com.foobar:disk1" ++ 0024 uint32 : iSCSI node index = 14 +diff --git a/utils/open-isns/tests/data/test02/15-dd-deregistration b/utils/open-isns/tests/data/test02/15-dd-deregistration +new file mode 100644 +index 0000000..d9b420f +--- /dev/null ++++ b/utils/open-isns/tests/data/test02/15-dd-deregistration +@@ -0,0 +1,76 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test02/server0/database ++Last EID: 1 ++Last Index: 15 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client2.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client2" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++ 0608v uint32 : Policy allowed node type = Target ++-------------- ++Object: index=5 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:24:04 2007 ++ 0007 uint32 : Entity index = 5 ++-------------- ++Object: index=6 type= state=mature parent=5 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 6 ++-------------- ++Object: index=7 type= state=mature parent=5 ++ 0010 ipaddr : Portal IP address = 127.1.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 7 ++-------------- ++Object: index=8 type= state=mature parent=5 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.1.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 ++-------------- ++Object: index=9 type= state=mature ++ 0001 string : Entity identifier = "client2.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:24:04 2007 ++ 0007 uint32 : Entity index = 9 ++-------------- ++Object: index=10 type= state=mature parent=9 ++ 0020 string : iSCSI name = "isns.client2" ++ 0021 uint32 : iSCSI node type = Target ++ 0024 uint32 : iSCSI node index = 10 ++-------------- ++Object: index=11 type= state=mature parent=9 ++ 0010 ipaddr : Portal IP address = 127.1.0.2 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0016 uint32 : Portal index = 11 ++-------------- ++Object: index=12 type= state=mature parent=9 ++ 0030 string : Portal group name = "isns.client2" ++ 0031 ipaddr : Portal group address = 127.1.0.2 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 12 ++-------------- ++Object: index=14 type= state=limbo ++ 0020 string : iSCSI name = "iqn.com.foobar:disk1" ++ 0024 uint32 : iSCSI node index = 14 +diff --git a/utils/open-isns/tests/data/test03/01-enroll b/utils/open-isns/tests/data/test03/01-enroll +new file mode 100644 +index 0000000..0046b41 +--- /dev/null ++++ b/utils/open-isns/tests/data/test03/01-enroll +@@ -0,0 +1,18 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test03/server0/database ++Last EID: 1 ++Last Index: 4 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test03/02-registration b/utils/open-isns/tests/data/test03/02-registration +new file mode 100644 +index 0000000..11062a6 +--- /dev/null ++++ b/utils/open-isns/tests/data/test03/02-registration +@@ -0,0 +1,42 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test03/server0/database ++Last EID: 1 ++Last Index: 8 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:36:35 2007 ++ 0007 uint32 : Entity index = 4 ++-------------- ++Object: index=5 type= state=mature parent=4 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 5 ++-------------- ++Object: index=6 type= state=mature parent=4 ++ 0010 ipaddr : Portal IP address = 127.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 6 ++-------------- ++Object: index=7 type= state=mature parent=4 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.0.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test03/03-unregistration b/utils/open-isns/tests/data/test03/03-unregistration +new file mode 100644 +index 0000000..874235b +--- /dev/null ++++ b/utils/open-isns/tests/data/test03/03-unregistration +@@ -0,0 +1,42 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test03/server0/database ++Last EID: 1 ++Last Index: 8 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:25:47 2007 ++ 0007 uint32 : Entity index = 4 ++-------------- ++Object: index=5 type= state=mature parent=4 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 5 ++-------------- ++Object: index=6 type= state=limbo ++ 0010 ipaddr : Portal IP address = 127.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 6 ++-------------- ++Object: index=7 type= state=mature parent=4 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.0.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test03/04-unregistration b/utils/open-isns/tests/data/test03/04-unregistration +new file mode 100644 +index 0000000..efe63e4 +--- /dev/null ++++ b/utils/open-isns/tests/data/test03/04-unregistration +@@ -0,0 +1,18 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test03/server0/database ++Last EID: 1 ++Last Index: 8 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test03/99-unregistration b/utils/open-isns/tests/data/test03/99-unregistration +new file mode 100644 +index 0000000..9ea63b1 +--- /dev/null ++++ b/utils/open-isns/tests/data/test03/99-unregistration +@@ -0,0 +1,13 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test03/server0/database ++Last EID: 1 ++Last Index: 7 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +diff --git a/utils/open-isns/tests/data/test04/01-enroll b/utils/open-isns/tests/data/test04/01-enroll +new file mode 100644 +index 0000000..3caf7a2 +--- /dev/null ++++ b/utils/open-isns/tests/data/test04/01-enroll +@@ -0,0 +1,18 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test04/server0/database ++Last EID: 1 ++Last Index: 4 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test04/02-registration b/utils/open-isns/tests/data/test04/02-registration +new file mode 100644 +index 0000000..0780d23 +--- /dev/null ++++ b/utils/open-isns/tests/data/test04/02-registration +@@ -0,0 +1,42 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test04/server0/database ++Last EID: 1 ++Last Index: 8 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:38:41 2007 ++ 0007 uint32 : Entity index = 4 ++-------------- ++Object: index=5 type= state=mature parent=4 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 5 ++-------------- ++Object: index=6 type= state=mature parent=4 ++ 0010 ipaddr : Portal IP address = 127.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 6 ++-------------- ++Object: index=7 type= state=mature parent=4 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.0.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test04/03-restart b/utils/open-isns/tests/data/test04/03-restart +new file mode 100644 +index 0000000..0780d23 +--- /dev/null ++++ b/utils/open-isns/tests/data/test04/03-restart +@@ -0,0 +1,42 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test04/server0/database ++Last EID: 1 ++Last Index: 8 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:38:41 2007 ++ 0007 uint32 : Entity index = 4 ++-------------- ++Object: index=5 type= state=mature parent=4 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 5 ++-------------- ++Object: index=6 type= state=mature parent=4 ++ 0010 ipaddr : Portal IP address = 127.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 6 ++-------------- ++Object: index=7 type= state=mature parent=4 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.0.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test04/04-query b/utils/open-isns/tests/data/test04/04-query +new file mode 100644 +index 0000000..3320a8c +--- /dev/null ++++ b/utils/open-isns/tests/data/test04/04-query +@@ -0,0 +1,20 @@ ++object[0] = ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:38:42 2007 ++ 0007 uint32 : Entity index = 4 ++object[1] = ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 5 ++object[2] = ++ 0010 ipaddr : Portal IP address = 127.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 6 ++object[3] = ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.0.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test05/01-enroll b/utils/open-isns/tests/data/test05/01-enroll +new file mode 100644 +index 0000000..421d125 +--- /dev/null ++++ b/utils/open-isns/tests/data/test05/01-enroll +@@ -0,0 +1,18 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test05/server0/database ++Last EID: 1 ++Last Index: 4 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test05/02-registration b/utils/open-isns/tests/data/test05/02-registration +new file mode 100644 +index 0000000..8be9f56 +--- /dev/null ++++ b/utils/open-isns/tests/data/test05/02-registration +@@ -0,0 +1,42 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test05/server0/database ++Last EID: 1 ++Last Index: 8 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 20 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:40:40 2007 ++ 0007 uint32 : Entity index = 4 ++-------------- ++Object: index=5 type= state=mature parent=4 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 5 ++-------------- ++Object: index=6 type= state=mature parent=4 ++ 0010 ipaddr : Portal IP address = 127.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 6 ++-------------- ++Object: index=7 type= state=mature parent=4 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.0.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test05/03-expired b/utils/open-isns/tests/data/test05/03-expired +new file mode 100644 +index 0000000..1c8b6ea +--- /dev/null ++++ b/utils/open-isns/tests/data/test05/03-expired +@@ -0,0 +1,18 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test05/server0/database ++Last EID: 1 ++Last Index: 8 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test06/01-enroll b/utils/open-isns/tests/data/test06/01-enroll +new file mode 100644 +index 0000000..5ededae +--- /dev/null ++++ b/utils/open-isns/tests/data/test06/01-enroll +@@ -0,0 +1,18 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test06/server0/database ++Last EID: 1 ++Last Index: 4 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test06/02-registration b/utils/open-isns/tests/data/test06/02-registration +new file mode 100644 +index 0000000..5b6ab13 +--- /dev/null ++++ b/utils/open-isns/tests/data/test06/02-registration +@@ -0,0 +1,42 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test06/server0/database ++Last EID: 1 ++Last Index: 8 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:41:51 2007 ++ 0007 uint32 : Entity index = 4 ++-------------- ++Object: index=5 type= state=mature parent=4 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 5 ++-------------- ++Object: index=6 type= state=mature parent=4 ++ 0010 ipaddr : Portal IP address = 127.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 6 ++-------------- ++Object: index=7 type= state=mature parent=4 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.0.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test06/03-registration b/utils/open-isns/tests/data/test06/03-registration +new file mode 100644 +index 0000000..ad555dc +--- /dev/null ++++ b/utils/open-isns/tests/data/test06/03-registration +@@ -0,0 +1,42 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test06/server0/database ++Last EID: 1 ++Last Index: 12 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=8 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:41:51 2007 ++ 0007 uint32 : Entity index = 8 ++-------------- ++Object: index=9 type= state=mature parent=8 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 9 ++-------------- ++Object: index=10 type= state=mature parent=8 ++ 0010 ipaddr : Portal IP address = 192.168.1.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 10 ++-------------- ++Object: index=11 type= state=mature parent=8 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 192.168.1.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 11 +diff --git a/utils/open-isns/tests/data/test06/04-registration b/utils/open-isns/tests/data/test06/04-registration +new file mode 100644 +index 0000000..477248d +--- /dev/null ++++ b/utils/open-isns/tests/data/test06/04-registration +@@ -0,0 +1,42 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test06/server0/database ++Last EID: 1 ++Last Index: 16 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=12 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:41:51 2007 ++ 0007 uint32 : Entity index = 12 ++-------------- ++Object: index=13 type= state=mature parent=12 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 13 ++-------------- ++Object: index=14 type= state=mature parent=12 ++ 0010 ipaddr : Portal IP address = 192.168.1.2 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 14 ++-------------- ++Object: index=15 type= state=mature parent=12 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 192.168.1.2 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 15 +diff --git a/utils/open-isns/tests/data/test06/05-dd-registration b/utils/open-isns/tests/data/test06/05-dd-registration +new file mode 100644 +index 0000000..01776db +--- /dev/null ++++ b/utils/open-isns/tests/data/test06/05-dd-registration +@@ -0,0 +1,49 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test06/server0/database ++Last EID: 1 ++Last Index: 17 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=12 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:41:52 2007 ++ 0007 uint32 : Entity index = 12 ++-------------- ++Object: index=13 type= state=mature parent=12 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 13 ++-------------- ++Object: index=14 type= state=mature parent=12 ++ 0010 ipaddr : Portal IP address = 192.168.1.2 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 14 ++-------------- ++Object: index=15 type= state=mature parent=12 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 192.168.1.2 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 15 ++-------------- ++Object: index=16 type= state=mature ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 13 ++ 0814 string : DD member iSCSI name = "isns.client1" +diff --git a/utils/open-isns/tests/data/test06/06-registration b/utils/open-isns/tests/data/test06/06-registration +new file mode 100644 +index 0000000..6da36e2 +--- /dev/null ++++ b/utils/open-isns/tests/data/test06/06-registration +@@ -0,0 +1,49 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test06/server0/database ++Last EID: 1 ++Last Index: 20 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=17 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:41:52 2007 ++ 0007 uint32 : Entity index = 17 ++-------------- ++Object: index=13 type= state=mature parent=17 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 13 ++-------------- ++Object: index=18 type= state=mature parent=17 ++ 0010 ipaddr : Portal IP address = 192.168.1.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 18 ++-------------- ++Object: index=19 type= state=mature parent=17 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 192.168.1.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 19 ++-------------- ++Object: index=16 type= state=mature ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 13 ++ 0814 string : DD member iSCSI name = "isns.client1" +diff --git a/utils/open-isns/tests/data/test06/07-dd-registration b/utils/open-isns/tests/data/test06/07-dd-registration +new file mode 100644 +index 0000000..b3201d2 +--- /dev/null ++++ b/utils/open-isns/tests/data/test06/07-dd-registration +@@ -0,0 +1,52 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test06/server0/database ++Last EID: 1 ++Last Index: 20 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=17 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:41:52 2007 ++ 0007 uint32 : Entity index = 17 ++-------------- ++Object: index=13 type= state=mature parent=17 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 13 ++-------------- ++Object: index=18 type= state=mature parent=17 ++ 0010 ipaddr : Portal IP address = 192.168.1.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 18 ++-------------- ++Object: index=19 type= state=mature parent=17 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 192.168.1.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 19 ++-------------- ++Object: index=16 type= state=mature ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 13 ++ 0814 string : DD member iSCSI name = "isns.client1" ++ 0816 uint32 : DD member portal index = 18 ++ 0817 ipaddr : DD member portal addr = 192.168.1.1 ++ 0818 uint32 : DD member portal port = 860/tcp +diff --git a/utils/open-isns/tests/data/test06/08-registration b/utils/open-isns/tests/data/test06/08-registration +new file mode 100644 +index 0000000..f965777 +--- /dev/null ++++ b/utils/open-isns/tests/data/test06/08-registration +@@ -0,0 +1,64 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test06/server0/database ++Last EID: 1 ++Last Index: 22 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=17 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:41:52 2007 ++ 0007 uint32 : Entity index = 17 ++-------------- ++Object: index=13 type= state=mature parent=17 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 13 ++-------------- ++Object: index=18 type= state=limbo ++ 0010 ipaddr : Portal IP address = 192.168.1.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 18 ++-------------- ++Object: index=19 type= state=mature parent=17 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 192.168.1.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 19 ++-------------- ++Object: index=16 type= state=mature ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 13 ++ 0814 string : DD member iSCSI name = "isns.client1" ++ 0816 uint32 : DD member portal index = 18 ++ 0817 ipaddr : DD member portal addr = 192.168.1.1 ++ 0818 uint32 : DD member portal port = 860/tcp ++-------------- ++Object: index=20 type= state=mature parent=17 ++ 0010 ipaddr : Portal IP address = 192.168.1.2 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 20 ++-------------- ++Object: index=21 type= state=mature parent=17 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 192.168.1.2 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 21 +diff --git a/utils/open-isns/tests/data/test06/09-registration b/utils/open-isns/tests/data/test06/09-registration +new file mode 100644 +index 0000000..1308d3c +--- /dev/null ++++ b/utils/open-isns/tests/data/test06/09-registration +@@ -0,0 +1,64 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test06/server0/database ++Last EID: 1 ++Last Index: 22 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=17 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:41:52 2007 ++ 0007 uint32 : Entity index = 17 ++-------------- ++Object: index=13 type= state=mature parent=17 ++ 0020 string : iSCSI name = "isns.client1" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0024 uint32 : iSCSI node index = 13 ++-------------- ++Object: index=18 type= state=mature parent=17 ++ 0010 ipaddr : Portal IP address = 192.168.1.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 18 ++-------------- ++Object: index=19 type= state=mature parent=17 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 192.168.1.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 19 ++-------------- ++Object: index=16 type= state=mature ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 13 ++ 0814 string : DD member iSCSI name = "isns.client1" ++ 0816 uint32 : DD member portal index = 18 ++ 0817 ipaddr : DD member portal addr = 192.168.1.1 ++ 0818 uint32 : DD member portal port = 860/tcp ++-------------- ++Object: index=20 type= state=limbo ++ 0010 ipaddr : Portal IP address = 192.168.1.2 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 20 ++-------------- ++Object: index=21 type= state=mature parent=17 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 192.168.1.2 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 21 +diff --git a/utils/open-isns/tests/data/test06/10-unregistration b/utils/open-isns/tests/data/test06/10-unregistration +new file mode 100644 +index 0000000..0c42d1c +--- /dev/null ++++ b/utils/open-isns/tests/data/test06/10-unregistration +@@ -0,0 +1,37 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test06/server0/database ++Last EID: 1 ++Last Index: 22 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=13 type= state=limbo ++ 0020 string : iSCSI name = "isns.client1" ++ 0024 uint32 : iSCSI node index = 13 ++-------------- ++Object: index=18 type= state=limbo ++ 0010 ipaddr : Portal IP address = 192.168.1.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 18 ++-------------- ++Object: index=16 type= state=mature ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 13 ++ 0814 string : DD member iSCSI name = "isns.client1" ++ 0816 uint32 : DD member portal index = 18 ++ 0817 ipaddr : DD member portal addr = 192.168.1.1 ++ 0818 uint32 : DD member portal port = 860/tcp +diff --git a/utils/open-isns/tests/data/test06/11-registration b/utils/open-isns/tests/data/test06/11-registration +new file mode 100644 +index 0000000..d8d03f8 +--- /dev/null ++++ b/utils/open-isns/tests/data/test06/11-registration +@@ -0,0 +1,52 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test06/server0/database ++Last EID: 1 ++Last Index: 24 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=22 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 21 11:23:54 2007 ++ 0007 uint32 : Entity index = 22 ++-------------- ++Object: index=13 type= state=mature parent=22 ++ 0020 string : iSCSI name = "isns.client1" ++ 0024 uint32 : iSCSI node index = 13 ++ 0021 uint32 : iSCSI node type = Initiator ++-------------- ++Object: index=18 type= state=mature parent=22 ++ 0010 ipaddr : Portal IP address = 192.168.1.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 18 ++-------------- ++Object: index=23 type= state=mature parent=22 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 192.168.1.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 23 ++-------------- ++Object: index=16 type= state=mature ++ 0811 uint32 : DD ID = 1 ++ 0812 string : DD name = "isns.dd1" ++ 081e uint32 : DD features = ++ 0813 uint32 : DD member iSCSI index = 13 ++ 0814 string : DD member iSCSI name = "isns.client1" ++ 0816 uint32 : DD member portal index = 18 ++ 0817 ipaddr : DD member portal addr = 192.168.1.1 ++ 0818 uint32 : DD member portal port = 860/tcp +diff --git a/utils/open-isns/tests/data/test07/01-enroll b/utils/open-isns/tests/data/test07/01-enroll +new file mode 100644 +index 0000000..ad2eaf4 +--- /dev/null ++++ b/utils/open-isns/tests/data/test07/01-enroll +@@ -0,0 +1,19 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test07/server0/database ++Last EID: 1 ++Last Index: 4 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:42:57 2007 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test07/02-registration b/utils/open-isns/tests/data/test07/02-registration +new file mode 100644 +index 0000000..da8962a +--- /dev/null ++++ b/utils/open-isns/tests/data/test07/02-registration +@@ -0,0 +1,45 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test07/server0/database ++Last EID: 1 ++Last Index: 8 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:42:57 2007 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=4 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:42:57 2007 ++ 0007 uint32 : Entity index = 4 ++-------------- ++Object: index=5 type= state=mature parent=4 ++ 0020 string : iSCSI name = "isns.client1" ++ 0024 uint32 : iSCSI node index = 5 ++ 0021 uint32 : iSCSI node type = Initiator ++-------------- ++Object: index=6 type= state=mature parent=4 ++ 0010 ipaddr : Portal IP address = 127.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 6 ++ 0014 uint32 : ESI port = 65535/tcp ++ 0013 uint32 : ESI interval = 5 ++-------------- ++Object: index=7 type= state=mature parent=4 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.0.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test07/03-expired b/utils/open-isns/tests/data/test07/03-expired +new file mode 100644 +index 0000000..edb9ea4 +--- /dev/null ++++ b/utils/open-isns/tests/data/test07/03-expired +@@ -0,0 +1,19 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test07/server0/database ++Last EID: 1 ++Last Index: 8 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:42:57 2007 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test07/04-registration b/utils/open-isns/tests/data/test07/04-registration +new file mode 100644 +index 0000000..de57cbd +--- /dev/null ++++ b/utils/open-isns/tests/data/test07/04-registration +@@ -0,0 +1,57 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test07/server0/database ++Last EID: 1 ++Last Index: 14 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:43:12 2007 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 ++-------------- ++Object: index=8 type= state=mature ++ 0001 string : Entity identifier = "client1.isns-test.eu" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:43:12 2007 ++ 0007 uint32 : Entity index = 8 ++-------------- ++Object: index=9 type= state=mature parent=8 ++ 0020 string : iSCSI name = "isns.client1" ++ 0024 uint32 : iSCSI node index = 9 ++ 0021 uint32 : iSCSI node type = Initiator ++-------------- ++Object: index=10 type= state=mature parent=8 ++ 0010 ipaddr : Portal IP address = 127.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 860/tcp ++ 0016 uint32 : Portal index = 10 ++ 0014 uint32 : ESI port = 65535/tcp ++ 0013 uint32 : ESI interval = 5 ++-------------- ++Object: index=11 type= state=mature parent=8 ++ 0010 ipaddr : Portal IP address = 127.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 1/tcp ++ 0016 uint32 : Portal index = 11 ++-------------- ++Object: index=12 type= state=mature parent=8 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.0.0.1 ++ 0032 uint32 : Portal group port = 860/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 12 ++-------------- ++Object: index=13 type= state=mature parent=8 ++ 0030 string : Portal group name = "isns.client1" ++ 0031 ipaddr : Portal group address = 127.0.0.1 ++ 0032 uint32 : Portal group port = 1/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 13 +diff --git a/utils/open-isns/tests/data/test07/05-expired b/utils/open-isns/tests/data/test07/05-expired +new file mode 100644 +index 0000000..fd51f78 +--- /dev/null ++++ b/utils/open-isns/tests/data/test07/05-expired +@@ -0,0 +1,19 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test07/server0/database ++Last EID: 1 ++Last Index: 14 ++-------------- ++Object: index=1 type= state=mature PRIVATE ++ 0001 string : Entity identifier = "CONTROL" ++ 0007 uint32 : Entity index = 1 ++ 0004 uint64 : Timestamp = Fri Sep 14 13:43:12 2007 ++-------------- ++Object: index=2 type= state=mature parent=1 PRIVATE ++ 0601v string : Security Policy Index = "client1.isns-test.eu" ++ 0607v string : Policy allowed node name = "isns.client1" ++ 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... ++-------------- ++Object: index=3 type= state=mature parent=1 PRIVATE ++ 0020 string : iSCSI name = "isns.control" ++ 0021 uint32 : iSCSI node type = ++ 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test08/01-pauw1 b/utils/open-isns/tests/data/test08/01-pauw1 +new file mode 100644 +index 0000000..3de54da +--- /dev/null ++++ b/utils/open-isns/tests/data/test08/01-pauw1 +@@ -0,0 +1,100 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test08/server0/database ++Last EID: 1 ++Last Index: 15 ++-------------- ++Object: index=1 type= state=mature ++ 0001 string : Entity identifier = "cyan.pauw.homeunix.net" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Mon Sep 17 15:15:41 2007 ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0" ++ 0024 uint32 : iSCSI node index = 2 ++ 0021 uint32 : iSCSI node type = Target ++ 0022 string : iSCSI alias = "Test (10 GB)" ++ 002a string : iSCSI auth method = "None" ++-------------- ++Object: index=3 type= state=mature parent=1 ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-1" ++ 0024 uint32 : iSCSI node index = 3 ++ 0021 uint32 : iSCSI node type = Target ++ 0022 string : iSCSI alias = "160 GB disk (ntfs)" ++ 002a string : iSCSI auth method = "None" ++-------------- ++Object: index=4 type= state=mature parent=1 ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-2" ++ 0024 uint32 : iSCSI node index = 4 ++ 0021 uint32 : iSCSI node type = Target ++ 0022 string : iSCSI alias = "160 GB disk (ext3)" ++ 002a string : iSCSI auth method = "CHAP" ++-------------- ++Object: index=5 type= state=mature parent=1 ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-3" ++ 0024 uint32 : iSCSI node index = 5 ++ 0021 uint32 : iSCSI node type = Target ++ 0022 string : iSCSI alias = "Test (1 GB)" ++ 002a string : iSCSI auth method = "None" ++-------------- ++Object: index=6 type= state=mature parent=1 ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-4" ++ 0024 uint32 : iSCSI node index = 6 ++ 0021 uint32 : iSCSI node type = Target ++ 0022 string : iSCSI alias = "Test (40 GB)" ++ 002a string : iSCSI auth method = "CHAP" ++-------------- ++Object: index=7 type= state=mature parent=1 ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-5" ++ 0024 uint32 : iSCSI node index = 7 ++ 0021 uint32 : iSCSI node type = Target ++ 0022 string : iSCSI alias = "test" ++ 002a string : iSCSI auth method = "None" ++-------------- ++Object: index=8 type= state=mature parent=1 ++ 0010 ipaddr : Portal IP address = 10.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0016 uint32 : Portal index = 8 ++-------------- ++Object: index=9 type= state=mature parent=1 ++ 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0" ++ 0031 ipaddr : Portal group address = 10.0.0.1 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0034 uint32 : Portal group index = 9 ++ 0033 uint32 : Portal group tag = 1 ++-------------- ++Object: index=10 type= state=mature parent=1 ++ 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-1" ++ 0031 ipaddr : Portal group address = 10.0.0.1 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0034 uint32 : Portal group index = 10 ++ 0033 uint32 : Portal group tag = 1 ++-------------- ++Object: index=11 type= state=mature parent=1 ++ 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-2" ++ 0031 ipaddr : Portal group address = 10.0.0.1 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0034 uint32 : Portal group index = 11 ++ 0033 uint32 : Portal group tag = 1 ++-------------- ++Object: index=12 type= state=mature parent=1 ++ 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-3" ++ 0031 ipaddr : Portal group address = 10.0.0.1 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0034 uint32 : Portal group index = 12 ++ 0033 uint32 : Portal group tag = 1 ++-------------- ++Object: index=13 type= state=mature parent=1 ++ 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-4" ++ 0031 ipaddr : Portal group address = 10.0.0.1 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0034 uint32 : Portal group index = 13 ++ 0033 uint32 : Portal group tag = 1 ++-------------- ++Object: index=14 type= state=mature parent=1 ++ 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-5" ++ 0031 ipaddr : Portal group address = 10.0.0.1 ++ 0032 uint32 : Portal group port = 3260/tcp ++ 0034 uint32 : Portal group index = 14 ++ 0033 uint32 : Portal group tag = 1 +diff --git a/utils/open-isns/tests/data/test09/01-pauw2 b/utils/open-isns/tests/data/test09/01-pauw2 +new file mode 100644 +index 0000000..9b0a814 +--- /dev/null ++++ b/utils/open-isns/tests/data/test09/01-pauw2 +@@ -0,0 +1,31 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test09/server0/database ++Last EID: 1 ++Last Index: 9 ++-------------- ++Object: index=5 type= state=mature ++ 0001 string : Entity identifier = "blue.pauw.homeunix.net" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Mon Sep 17 15:18:04 2007 ++ 0007 uint32 : Entity index = 5 ++-------------- ++Object: index=6 type= state=mature parent=5 ++ 0010 ipaddr : Portal IP address = 192.168.1.2 ++ 0011 uint32 : Portal TCP/UDP port = 33849/tcp ++ 0016 uint32 : Portal index = 6 ++ 0014 uint32 : ESI port = 56288/tcp ++ 0013 uint32 : ESI interval = 300 ++-------------- ++Object: index=7 type= state=mature parent=5 ++ 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" ++ 0024 uint32 : iSCSI node index = 7 ++ 0021 uint32 : iSCSI node type = Initiator ++ 0022 string : iSCSI alias = "blue.pauw.homeunix.net" ++-------------- ++Object: index=8 type= state=mature parent=5 ++ 0030 string : Portal group name = "iqn.2005-03.org.open-iscsi:blue" ++ 0031 ipaddr : Portal group address = 192.168.1.2 ++ 0032 uint32 : Portal group port = 33849/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 +diff --git a/utils/open-isns/tests/data/test10/01-pauw3 b/utils/open-isns/tests/data/test10/01-pauw3 +new file mode 100644 +index 0000000..b7f3b10 +--- /dev/null ++++ b/utils/open-isns/tests/data/test10/01-pauw3 +@@ -0,0 +1,31 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test10/server0/database ++Last EID: 1 ++Last Index: 9 ++-------------- ++Object: index=5 type= state=mature ++ 0001 string : Entity identifier = "blue.pauw.homeunix.net" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Mon Sep 17 16:34:30 2007 ++ 0007 uint32 : Entity index = 5 ++-------------- ++Object: index=6 type= state=mature parent=5 ++ 0010 ipaddr : Portal IP address = 192.168.1.2 ++ 0011 uint32 : Portal TCP/UDP port = 33849/tcp ++ 0016 uint32 : Portal index = 6 ++ 0014 uint32 : ESI port = 56288/tcp ++ 0013 uint32 : ESI interval = 10 ++-------------- ++Object: index=7 type= state=mature parent=5 ++ 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" ++ 0024 uint32 : iSCSI node index = 7 ++ 0021 uint32 : iSCSI node type = Initiator ++ 0022 string : iSCSI alias = "blue.pauw.homeunix.net" ++-------------- ++Object: index=8 type= state=mature parent=5 ++ 0030 string : Portal group name = "iqn.2005-03.org.open-iscsi:blue" ++ 0031 ipaddr : Portal group address = 192.168.1.2 ++ 0032 uint32 : Portal group port = 33849/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 +diff --git a/utils/open-isns/tests/data/test10/02-expired b/utils/open-isns/tests/data/test10/02-expired +new file mode 100644 +index 0000000..b7f3b10 +--- /dev/null ++++ b/utils/open-isns/tests/data/test10/02-expired +@@ -0,0 +1,31 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test10/server0/database ++Last EID: 1 ++Last Index: 9 ++-------------- ++Object: index=5 type= state=mature ++ 0001 string : Entity identifier = "blue.pauw.homeunix.net" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Mon Sep 17 16:34:30 2007 ++ 0007 uint32 : Entity index = 5 ++-------------- ++Object: index=6 type= state=mature parent=5 ++ 0010 ipaddr : Portal IP address = 192.168.1.2 ++ 0011 uint32 : Portal TCP/UDP port = 33849/tcp ++ 0016 uint32 : Portal index = 6 ++ 0014 uint32 : ESI port = 56288/tcp ++ 0013 uint32 : ESI interval = 10 ++-------------- ++Object: index=7 type= state=mature parent=5 ++ 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" ++ 0024 uint32 : iSCSI node index = 7 ++ 0021 uint32 : iSCSI node type = Initiator ++ 0022 string : iSCSI alias = "blue.pauw.homeunix.net" ++-------------- ++Object: index=8 type= state=mature parent=5 ++ 0030 string : Portal group name = "iqn.2005-03.org.open-iscsi:blue" ++ 0031 ipaddr : Portal group address = 192.168.1.2 ++ 0032 uint32 : Portal group port = 33849/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 +diff --git a/utils/open-isns/tests/data/test10/03-pauw3 b/utils/open-isns/tests/data/test10/03-pauw3 +new file mode 100644 +index 0000000..412c5b5 +--- /dev/null ++++ b/utils/open-isns/tests/data/test10/03-pauw3 +@@ -0,0 +1,31 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test10/server0/database ++Last EID: 1 ++Last Index: 9 ++-------------- ++Object: index=5 type= state=mature ++ 0001 string : Entity identifier = "blue.pauw.homeunix.net" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Mon Sep 17 16:34:51 2007 ++ 0007 uint32 : Entity index = 5 ++-------------- ++Object: index=6 type= state=mature parent=5 ++ 0010 ipaddr : Portal IP address = 192.168.1.2 ++ 0011 uint32 : Portal TCP/UDP port = 33849/tcp ++ 0016 uint32 : Portal index = 6 ++ 0014 uint32 : ESI port = 56288/tcp ++ 0013 uint32 : ESI interval = 10 ++-------------- ++Object: index=7 type= state=mature parent=5 ++ 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" ++ 0024 uint32 : iSCSI node index = 7 ++ 0021 uint32 : iSCSI node type = Initiator ++ 0022 string : iSCSI alias = "blue.pauw.homeunix.net" ++-------------- ++Object: index=8 type= state=mature parent=5 ++ 0030 string : Portal group name = "iqn.2005-03.org.open-iscsi:blue" ++ 0031 ipaddr : Portal group address = 192.168.1.2 ++ 0032 uint32 : Portal group port = 33849/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 +diff --git a/utils/open-isns/tests/data/test10/04-expired b/utils/open-isns/tests/data/test10/04-expired +new file mode 100644 +index 0000000..412c5b5 +--- /dev/null ++++ b/utils/open-isns/tests/data/test10/04-expired +@@ -0,0 +1,31 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test10/server0/database ++Last EID: 1 ++Last Index: 9 ++-------------- ++Object: index=5 type= state=mature ++ 0001 string : Entity identifier = "blue.pauw.homeunix.net" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Mon Sep 17 16:34:51 2007 ++ 0007 uint32 : Entity index = 5 ++-------------- ++Object: index=6 type= state=mature parent=5 ++ 0010 ipaddr : Portal IP address = 192.168.1.2 ++ 0011 uint32 : Portal TCP/UDP port = 33849/tcp ++ 0016 uint32 : Portal index = 6 ++ 0014 uint32 : ESI port = 56288/tcp ++ 0013 uint32 : ESI interval = 10 ++-------------- ++Object: index=7 type= state=mature parent=5 ++ 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" ++ 0024 uint32 : iSCSI node index = 7 ++ 0021 uint32 : iSCSI node type = Initiator ++ 0022 string : iSCSI alias = "blue.pauw.homeunix.net" ++-------------- ++Object: index=8 type= state=mature parent=5 ++ 0030 string : Portal group name = "iqn.2005-03.org.open-iscsi:blue" ++ 0031 ipaddr : Portal group address = 192.168.1.2 ++ 0032 uint32 : Portal group port = 33849/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 8 +diff --git a/utils/open-isns/tests/data/test11/01-pauw4 b/utils/open-isns/tests/data/test11/01-pauw4 +new file mode 100644 +index 0000000..50c6b92 +--- /dev/null ++++ b/utils/open-isns/tests/data/test11/01-pauw4 +@@ -0,0 +1,32 @@ ++Dumping database contents ++Backend: /tmp/isns-test/test11/server0/database ++Last EID: 1 ++Last Index: 5 ++-------------- ++Object: index=1 type= state=mature ++ 0001 string : Entity identifier = "troopa.nki.nl" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 7200 ++ 0004 uint64 : Timestamp = Fri Sep 21 09:37:10 2007 ++ 0007 uint32 : Entity index = 1 ++-------------- ++Object: index=2 type= state=mature parent=1 ++ 0010 ipaddr : Portal IP address = 192.168.1.40 ++ 0011 uint32 : Portal TCP/UDP port = 3229/tcp ++ 0017 uint32 : SCN port = 3230/tcp ++ 0014 uint32 : ESI port = 3230/tcp ++ 0013 uint32 : ESI interval = 300 ++ 0016 uint32 : Portal index = 2 ++-------------- ++Object: index=3 type= state=mature parent=1 ++ 0030 string : Portal group name = "iqn.1991-05.com.microsoft:orange" ++ 0031 ipaddr : Portal group address = 192.168.1.40 ++ 0032 uint32 : Portal group port = 3229/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0034 uint32 : Portal group index = 3 ++-------------- ++Object: index=4 type= state=mature parent=1 ++ 0020 string : iSCSI name = "iqn.1991-05.com.microsoft:orange" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0022 string : iSCSI alias = "" ++ 0024 uint32 : iSCSI node index = 4 +diff --git a/utils/open-isns/tests/genkey b/utils/open-isns/tests/genkey +new file mode 100644 +index 0000000..36c5eee +--- /dev/null ++++ b/utils/open-isns/tests/genkey +@@ -0,0 +1,175 @@ ++#!/bin/bash ++# ++# This is a very simple script to generate a DSA ++# key pair for authenticated iSNS. ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This script is supposed to be run on the iSNS server. ++# For the first time, run as ++# isnsgenkey -s 1024 ++# This will generate a DSA params file, and a DSA private ++# and public key for the server. ++# ++# For each client, generate a key using ++# isnsgenkey ++# where is the fully qualified domain name. ++# This script will convert the FQDN to a valid iSNS ++# source name (isns.com.foobar.host) ++ ++myname=`basename $0` ++etcdir=/etc/isns ++keystore=$etcdir/keystore ++dsa_parms=$etcdir/dsa.params ++dsa_bits=1024 ++opt_force=0 ++opt_server=0 ++ ++function usage { ++ cat <<-EOF >&2 ++ $* ++ Usage: ++ $myname -s [-f] bits ++ $myname clientname ++ EOF ++ exit 1 ++} ++ ++function make_isns_name { ++ OFS="$IFS" ++ IFS=. ++ set -- $* ++ ++ __result=$1; shift ++ for part; do ++ __result=$part.$__result ++ done ++ echo "isns.$__result" ++ IFS="$OFS" ++} ++ ++set -- `getopt b:fk:s $*` ++while [ $# -gt 0 ]; do ++ opt=$1; shift ++ case $opt in ++ --) break;; ++ -b) dsa_bits=$1; shift;; ++ -f) opt_force=1;; ++ -k) dsa_priv=$1; shift;; ++ -s) opt_server=1;; ++ *) usage "Unknown option $opt";; ++ esac ++done ++ ++if [ `id -un` != "root" -a $opt_force -eq 0 ]; then ++ echo "$myname: should be run by super user only" >&2 ++ exit 1 ++fi ++ ++# All newly generated files should have restricted ++# access by default. ++umask 077 ++ ++tmpdir=`mktemp -d /tmp/isnsgenkey.XXXXXX` ++trap "rm -rf $tmpdir" 0 1 2 15 ++ ++if [ $opt_server -ne 0 ]; then ++ [ $# -eq 1 ] || usage "Expected DSA key length" ++ dsa_bits=$1 ++ ++ install -m 755 -d $etcdir ++ if [ -z $dsa_priv ]; then ++ dsa_priv=$etcdir/auth_key ++ fi ++ dsa_pub=$dsa_priv.pub ++ dsa_copy= ++else ++ [ $# -eq 1 ] || usage "Expected client name" ++ client=`make_isns_name $1` ++ ++ mkdir -p $tmpdir$etcdir ++ # build_client_conf $client > $tmpdir$etcdir/client.conf ++ ++ if [ -z $dsa_priv ]; then ++ dsa_priv=$tmpdir$etcdir/auth_key ++ fi ++ dsa_pub=$dsa_priv.pub ++ dsa_copy=$keystore/$client ++fi ++ ++if [ -f $dsa_priv -a $opt_force -eq 0 ]; then ++ cat <<-EOF ++ ++ ------------------------------------------------------------------ ++ | There is already a DSA key installed in $dsa_priv. In order to ++ | generate a new key, please specify the -f [force] option. ++ ------------------------------------------------------------------ ++ EOF ++ exit 1 ++fi ++ ++if [ ! -r $dsa_parms ]; then ++ if [ $opt_server -eq 0 ]; then ++ echo "Please run $myname in server-initialization mode first" >&2 ++ exit 1 ++ fi ++ ++ cat <<-EOF ++ ++ ------------------------------------------------------------------ ++ | I will now try to generate a set of DSA parameters. This can be ++ | a slow process, so please be patient. ++ ------------------------------------------------------------------ ++ EOF ++ ++ mkdir -p `dirname $dsa_parms` ++ openssl dsaparam $dsa_bits -out $dsa_parms || ++ exit 1 ++ ++ # DSA parameters are public ++ chmod 644 $dsa_parms ++fi ++ ++cat <&2 ++ exit 1 ++fi ++if ! openssl dgst -dss1 -verify $dsa_pub -signature $tmpdir/test-sig /etc/hosts; then ++ echo "DSA verification failed - aborting!" >&2 ++ exit 1 ++fi ++od -tx1 $tmpdir/test-sig ++ ++if [ $opt_server -eq 0 ]; then ++ echo "Installing DSA public key as $dsa_copy" ++ install -d -m 755 $keystore ++ install -m 644 $dsa_pub $dsa_copy ++ install -m 644 $etcdir/auth_key.pub $tmpdir$etcdir/server.pub ++ ++ tarball=auth-$client.tar.gz ++ tar -C $tmpdir -czf $tarball .$etcdir ++ ++ cat <<-EOF ++ ------------------------------------------------------------------ ++ | Successfully packaged $tarball ++ | Please copy this file to client $client and install ++ ------------------------------------------------------------------ ++ EOF ++fi +diff --git a/utils/open-isns/tests/harness.pl b/utils/open-isns/tests/harness.pl +new file mode 100644 +index 0000000..d7ce025 +--- /dev/null ++++ b/utils/open-isns/tests/harness.pl +@@ -0,0 +1,929 @@ ++#!/usr/bin/perl ++ ++use Getopt::Long; ++ ++$__isns_verbose = 1; ++$__isns_security = 1; ++ ++$__isns_bin = "../"; ++$__isns_seq = 0; ++$__isns_test_base = '/tmp/isns-test'; ++$__isns_test_dir = '/tmp/isns-test/test'; ++$__isns_stage = 1; ++$__isns_test_data = ''; ++$__isns_test_dump = ''; ++$__isns_passed = 0; ++$__isns_failed = 0; ++$__isns_warned = 0; ++@__isns_servers = (); ++ ++%__isns_ignore_tag = ( ++ "0004" => 1, # Timestamp ++ "0603v" => 1, # DSA public key ++); ++ ++sub isns_fail { ++ ++ print "*** FAILURE ***\n"; ++ $__isns_failed++; ++ ++ my $line; ++ foreach $line (@_) { ++ print "*** $line ***\n"; ++ } ++} ++ ++sub isns_pass { ++ ++ print "*** SUCCESS ***\n" if ($__isns_verbose > 1); ++ $__isns_passed++; ++} ++ ++sub isns_warn { ++ ++ printf "*** WARNING: %s ***\n", join(' ', @_); ++ $__isns_warned++; ++} ++ ++sub isns_die { ++ ++ printf "*** TERMINAL FAILURE: %s ***\n", join(' ', @_); ++ $__isns_failed++; ++ ++ &isns_finish; ++ die "Test aborted\n"; ++} ++ ++sub isns_finish { ++ ++ my $pid; ++ foreach $pid (@__isns_servers) { ++ kill 15, $pid or &isns_warn("Cannot kill server process (pid=$pid): $!\n"); ++ } ++ ++ &isns_report; ++} ++ ++sub isns_report { ++ ++ print "*** Test $__isns_test_name complete."; ++ print " PASSED: $__isns_passed" if ($__isns_passed); ++ print " FAILED: $__isns_failed" if ($__isns_failed); ++ print " WARNINGS: $__isns_warned" if ($__isns_warned); ++ print " ***\n"; ++} ++ ++sub isns_info { ++ ++ print @_ if ($__isns_verbose > 1); ++} ++ ++sub isns_notice { ++ ++ print @_ if ($__isns_verbose > 0); ++} ++ ++sub isns_stage { ++ ++ local($name, @msg) = @_; ++ ++ if ($name =~ m/^[0-9]/o) { ++ $__isns_stage_name = $name; ++ } else { ++ $__isns_stage_name = sprintf "%02d-%s", ++ $__isns_stage++, $name; ++ } ++ &isns_notice("*** $__isns_stage_name: ", @msg, " ***\n"); ++} ++ ++sub build_config { ++ ++ local($src_file, $dst_file, *__subst) = @_; ++ my $key; ++ my $okey; ++ my $value; ++ my $sepa; ++ my %subst; ++ ++ &isns_info("*** Building $src_file -> $dst_file\n"); ++ ++ # Translate all keys to lower case. ++ foreach $key (keys(%__subst)) { ++ $value = $__subst{$key}; ++ $key =~ tr/A-Z/a-z/; ++ $subst{$key} = $value; ++ } ++# foreach $key (keys(%subst)) { ++# printf " %s -> %s\n", $key, $subst{$key}; ++# } ++ ++ open IN, "<$src_file" or die "$src_file: $!\n"; ++ open OUT, ">$dst_file" or die "$dst_file: $!\n"; ++ ++ while () { ++ $line = $_; ++ if (m:(\S+)(\s*=\s*)(.*):o) { ++ ($okey, $sepa, $value) = ($1, $2, $3); ++ ++ $key = $okey; ++ $key =~ tr/A-Z/a-z/; ++ ++ if ($subst{$key}) { ++ $line = "$okey$sepa$subst{$key}\n"; ++ } ++ } ++ ++ # Ignore unconfigured lines. ++ next if ($line =~ m/\@[A-Z_]*\@/o); ++ print OUT $line; ++ } ++ close OUT; ++ close IN; ++} ++ ++sub get_config_value { ++ local($cfg_file, $item_name) = @_; ++ my $result; ++ my $name; ++ my $value; ++ ++ $item_name =~ tr/A-Z/a-z/; ++ ++ open IN, "<$cfg_file" or die "$cfg_file: $!\n"; ++ while () { ++ chop; ++ ($name, $value) = split(/\s+=\s+/, $_); ++ ++ $name =~ tr/A-Z/a-z/; ++ if ($name eq $item_name) { ++ $result = $value; ++ last; ++ } ++ } ++ close IN; ++ ++ return $result; ++} ++ ++sub create_key { ++ ++ local($keyfile) = @_; ++ ++ if ($__isns_security) { ++ &isns_info("*** Creating key at $keyfile\n"); ++ system "./genkey -fsk $keyfile 2048 >${keyfile}.log 2>&1"; ++ } ++ return $keyfile; ++} ++ ++sub create_server { ++ ++ local(*override) = @_; ++ my %local_config; ++ my $my_dir; ++ my $handle; ++ my $config; ++ ++ $handle = sprintf "server%d", $__isns_seq++; ++ $my_dir = "$__isns_test_dir/${handle}"; ++ ++ mkdir $my_dir, 0700 or die "Cannot create $my_dir: $!\n"; ++ ++ $server_addr = "127.0.0.1:7770" unless ($server_addr); ++ ++ $config = "$my_dir/config"; ++ ++ $local_config{"SourceName"} = "isns.$handle"; ++ $local_config{"Database"} = "$my_dir/database"; ++ $local_config{"BindAddress"} = "$server_addr"; ++ $local_config{"PIDFile"} = "$my_dir/pid"; ++ $local_config{"ControlSocket"} = "$my_dir/control"; ++ $local_config{"Security"} = $__isns_security; ++ $local_config{"AuthKeyFile"} = &create_key("$my_dir/auth_key"); ++ ++ foreach $key (keys(%override)) { ++ $local_config{$key} = $override{$key}; ++ } ++ ++ &build_config('server.conf', $config, \%local_config); ++ return $config; ++} ++ ++sub create_client { ++ ++ local($server_config, $client_address) = @_; ++ my %local_config; ++ my $server_key; ++ my $control_socket; ++ my $server_addr; ++ my $my_dir; ++ my $handle; ++ my $config; ++ ++ $handle = sprintf "client%d", $__isns_seq++; ++ $my_dir = "$__isns_test_dir/${handle}"; ++ ++ mkdir $my_dir, 0700 or die "Cannot create $my_dir: $!\n"; ++ ++ $control_socket = &get_config_value($server_config, "ControlSocket"); ++ $server_addr = &get_config_value($server_config, "BindAddress"); ++ $server_addr = "127.0.0.1" unless ($server_addr); ++ ++ $config = "$my_dir/config"; ++ ++ $local_config{"SourceName"} = "isns.$handle"; ++ $local_config{"AuthName"} = "$handle.isns-test.eu"; ++ $local_config{"ServerAddress"} = $server_addr; ++ $local_config{"ControlSocket"} = $control_socket; ++ $local_config{"BindAddress"} = $client_address if ($client_address); ++ $local_config{"server_config"} = $server_config; ++ $local_config{"Security"} = $__isns_security; ++ $local_config{"AuthKeyFile"} = &create_key("$my_dir/auth_key"); ++ $local_config{"ServerKeyFile"} = ++ &get_config_value($server_config, "AuthKeyFile") . ".pub"; ++ ++ &build_config('client.conf', $config, \%local_config); ++ ++ $__isns_data{$config,"server_config"} = $server_config; ++ $__isns_data{$config} = %local_config; ++ return $config; ++} ++ ++sub get_logfile { ++ ++ local($config) = @_; ++ my $dir; ++ ++ $dir = $config; ++ $dir =~ s|/+[^/]+$||o; ++ ++ return "$dir/logfile"; ++} ++ ++sub run_command { ++ ++ local(@cmd) = @_; ++ my $status; ++ my $cmd; ++ ++ $cmd = join(' ', @cmd); ++ &isns_info("$cmd\n"); ++ ++ system "$cmd"; ++ ++ $status = $?; ++ if ($status) { ++ &isns_warn("Command failed, exit status $status"); ++ print "*** Command was: $cmd ***\n"; ++ return undef; ++ } ++ ++ return 1; ++} ++ ++sub isns_start_server { ++ ++ local($server_config) = @_; ++ my $logfile; ++ my $pidfile; ++ my $pid; ++ ++ die "restart_server: missing server config argument!\n" ++ unless(-f $server_config); ++ $logfile = &get_logfile($server_config); ++ $pidfile = &get_config_value($server_config, "PIDFile"); ++ ++ &isns_info("*** Starting server (logging to $logfile)\n"); ++ ++ $pid = fork(); ++ if ($pid) { ++ my $retry; ++ ++ if ($pidfile) { ++ for ($retry = 0; $retry < 5; $retry++) { ++ last if (-f $pidfile); ++ sleep 1; ++ } ++ $pid = `cat $pidfile` if ($pidfile); ++ chop($pid); ++ } ++ &isns_info("*** Started server (pid=$pid) ***\n"); ++ push(@__isns_servers, $pid); ++ return $pid; ++ } ++ ++ &isns_info("${__isns_bin}isnsd -c $server_config -f -d all\n"); ++ exec "${__isns_bin}isnsd -c $server_config -f -d all >$logfile 2>&1 &" ++ or die "Unable to run isnsd: $!\n"; ++} ++ ++sub isns_stop_server { ++ ++ local($pid) = @_; ++ my @list; ++ my $p; ++ ++ kill 15, $pid or &isns_warn("Cannot kill server process (pid=$pid): $!\n"); ++ foreach $p (@__isns_servers) { ++ append(@list, $p) unless ($p == $pid); ++ } ++ @__isns_servers = @list; ++} ++ ++sub isns_restart_server { ++ ++ local($pid, $server_config); ++ ++ if ($_[0] =~ m:^\d+$:o) { ++ $pid = shift(@_); ++ } else { ++ if ($#__isns_servers < 0) { ++ &isns_warn("isns_restart_server: no server running\n"); ++ return 0; ++ } ++ $pid = $__isns_servers[0]; ++ } ++ $server_config = shift(@_); ++ ++ &isns_stop_server($pid); ++ return &isns_start_server($server_config); ++} ++ ++sub isns_verify_db { ++ ++ local($stage, $server_config); ++ my $dump_file; ++ my $data_file; ++ ++ if ($_[0] =~ m/^\d/o) { ++ $stage = shift(@_); ++ } else { ++ $stage = $__isns_stage_name; ++ } ++ $server_config = shift(@_); ++ ++ die "Test case forgot to call test_prep" unless($__isns_test_data); ++ ++ $dump_file = "$__isns_test_dump/$stage"; ++ unless (&run_command("${__isns_bin}/isnsd -c $server_config --dump-db > $dump_file")) { ++ &isns_fail; ++ return 0; ++ } ++ ++ # See if the reference data file exists. If it ++ # doesn't, this means we're priming the test case. ++ # Just copy the dump file. ++ $data_file = "$__isns_test_data/$stage"; ++ unless (-f $data_file) { ++ print "*** Saving database dump for stage $stage ***\n"; ++ mkdir $__isns_test_data, 0755; ++ system "cp $dump_file $data_file"; ++ return 1; ++ } ++ ++ &isns_info("*** Verifying database dump for stage $stage ***\n"); ++ if (&verify_dump($stage, $data_file, $dump_file)) { ++ &isns_pass; ++ } else { ++ if ($__isns_verbose > 1) { ++ system("diff -u -ITimestamp -I'DSA security key' $data_file $dump_file"); ++ } ++ &isns_fail; ++ } ++ ++ return 1; ++} ++ ++sub verify_db { ++ ++ &isns_verify_db(@_); ++} ++ ++sub verify_response { ++ ++ local($stage, $client_config) = @_; ++ my $dump_file; ++ my $data_file; ++ ++ die "Test case forgot to call test_prep" unless($__isns_test_data); ++ ++ $dump_file = &get_logfile($client_config); ++ ++ # See if the reference data file exists. If it ++ # doesn't, this means we're priming the test case. ++ # Just copy the dump file. ++ $data_file = "$__isns_test_data/$stage"; ++ unless (-f $data_file) { ++ print "*** Saving data for stage $stage ***\n"; ++ mkdir $__isns_test_data, 0755; ++ system "cp $dump_file $data_file"; ++ return 1; ++ } ++ ++ &isns_info("*** Verifying data for stage $stage ***\n"); ++ if (&verify_query($stage, $data_file, $dump_file)) { ++ &isns_pass; ++ } else { ++ &isns_fail("Query response returns unexpected data"); ++ system "cp $dump_file $__isns_test_dump/$stage"; ++ print "*** Saved dump as $__isns_test_dump/$stage\n"; ++ print "*** Reference data in $data_file\n"; ++ if ($__isns_verbose > 1) { ++ system("diff -u -ITimestamp -I'DSA security key' $data_file $dump_file"); ++ } ++ } ++ ++ return 1; ++} ++ ++sub verify_dump { ++ ++ local($stage, $data_file, $dump_file) = @_; ++ my $line; ++ my @dump; ++ my @data; ++ my @obj1; ++ my @obj2; ++ ++ @dump = &load_dump($dump_file); ++ @data = &load_dump($data_file); ++ ++ &skip_header(\@dump); ++ &skip_header(\@data); ++ ++ while (1) { ++ $line++; ++ ++ @obj1 = &get_next_object(\@dump); ++ @obj2 = &get_next_object(\@data); ++ ++ last unless(@obj1 || @obj2); ++ ++ unless (@obj1 && @obj2) { ++ print STDERR "*** $stage: Excess data at end of dump\n"; ++ return 0; ++ } ++ ++ unless (&compare_objects(\@obj1, \@obj2)) { ++ print STDERR "*** Object mismatch (object $line):\n"; ++ print STDERR "Expected:\n "; ++ print STDERR join("\n ", @obj2), "\n"; ++ print STDERR "Got:\n "; ++ print STDERR join("\n ", @obj1), "\n"; ++ return 0; ++ } ++ } ++ ++ if (@data) { ++ print STDERR "*** $stage: Unexpected end of dump at line $line\n"; ++ return 0; ++ } ++ ++ return 1; ++} ++ ++sub skip_header { ++ ++ local(*list) = @_; ++ local($_); ++ ++ while ($_ = shift(@list)) { ++ last if (/^-/o); ++ } ++} ++ ++sub get_next_object { ++ ++ local(*list) = @_; ++ local($_, $header, @result); ++ my @tags; ++ ++ while ($_ = shift(@list)) { ++ next if (/^-/o); ++ if (/^\s+([0-9a-fv]+)\s+/o) { ++ next if ($__isns_ignore_tag{$1}); ++ push(@tags, $_); ++ } else { ++ if (@result) { ++ unshift(@list, $_); ++ last; ++ } ++ push(@result, $_); ++ } ++ #print "### $_\n"; ++ } ++ ++ if (@tags) { ++ push(@result, sort(@tags)); ++ } ++ return @result; ++} ++ ++sub compare_objects { ++ ++ local(*a, *b) = @_; ++ local($i); ++ ++ return 0 unless ($#a == $#b); ++ for ($i = 0; $i <= $#a; $i++) { ++ return 0 unless ($a[$i] eq $b[$i]); ++ } ++ ++ return 1; ++} ++ ++ ++sub verify_query { ++ ++ local($stage, $data_file, $dump_file) = @_; ++ my $line; ++ my @dump; ++ my @data; ++ ++ @dump = &load_dump($dump_file); ++ @data = &load_dump($data_file); ++ ++ while (@dump) { ++ $line++; ++ unless (@data) { ++ print STDERR "*** $stage: Excess data in dump at line $line\n"; ++ return 0; ++ } ++ ++ $a = shift(@dump); ++ $b = shift(@data); ++ if ($a =~ /^\S/o) { ++ next if ($a eq $b); ++ print STDERR "*** $stage: Mismatch at line $line ***\n"; ++ print STDERR "*** Found: $a\n"; ++ print STDERR "*** Expected: $b\n"; ++ return 0; ++ } ++ ++ ($nix, $a_tag, $a_value) = split(/\s+/, $a, 3); ++ ($nix, $b_tag, $b_value) = split(/\s+/, $b, 3); ++ if ($a_tag ne $b_tag) { ++ print STDERR "*** $stage: Tag mismatch at line $line\n"; ++ print STDERR "*** Found: $a\n"; ++ print STDERR "*** Expected: $b\n"; ++ return 0; ++ } ++ ++ next if ($__isns_ignore_tag{$a_tag}); ++ if ($a_value ne $b_value) { ++ print STDERR "*** $stage: Value mismatch at line $line (tag $a_tag)\n"; ++ print STDERR "*** Found: $a\n"; ++ print STDERR "*** Expected: $b\n"; ++ return 0; ++ } ++ } ++ ++ if (@data) { ++ print STDERR "*** $stage: Unexpected end of dump at line $line\n"; ++ return 0; ++ } ++ ++ return 1; ++} ++ ++sub load_dump { ++ ++ local($filename) = @_; ++ my @result; ++ ++ open IN, $filename or die "Unable to open $filename: $!\n"; ++ while () { ++ chop; ++ push(@result, $_); ++ } ++ close IN; ++ return @result; ++} ++ ++ ++sub run_client { ++ ++ local($config, @args) = @_; ++ my $logfile; ++ my $cmd; ++ ++ $logfile = &get_logfile($config); ++ ++ $cmd = "${__isns_bin}/isnsadm -c $client_config " . join(' ', @args); ++ if (&run_command("$cmd >$logfile")) { ++ return $logfile; ++ } ++ return undef; ++} ++ ++sub __isns_enroll_client { ++ ++ local($client_config, @extra_args) = @_; ++ my $source_name; ++ my $auth_name; ++ my $auth_key; ++ my @args; ++ ++ $source_name = &get_config_value($client_config, "SourceName"); ++ $auth_name = &get_config_value($client_config, "AuthName"); ++ $auth_key = &get_config_value($client_config, "AuthKeyFile"); ++ ++ push(@args, "--local --enroll $auth_name node-name=$source_name"); ++ push(@args, " key=${auth_key}.pub") if ($auth_key); ++ push(@args, @extra_args) if (@extra_args); ++ ++ &run_client($client_config, @args); ++} ++ ++sub isns_enroll_client { ++ ++ local($client, @args) = @_; ++ my $server; ++ ++ $server = $__isns_data{$client,"server_config"}; ++ &isns_stage("enroll", "Enrolling client"); ++ &__isns_enroll_client($client, @args); ++ &verify_db($__isns_stage_name, $server); ++} ++ ++sub enroll_client { ++ ++ print "*** Enrolling client ***\n"; ++ &__isns_enroll_client(@_); ++} ++ ++sub __isns_register_client { ++ ++ local($client_config, @extra_args) = @_; ++ my @args; ++ ++ push(@args, "--register"); ++ push(@args, @extra_args) if (@extra_args); ++ ++ &run_client($client_config, @args); ++} ++ ++sub isns_register_client { ++ ++ local($client, @args) = @_; ++ my $server; ++ ++ $server = $__isns_data{$client,"server_config"}; ++ &isns_stage("registration", "Registering client " . join(' ', @args)); ++ &__isns_register_client($client, @args); ++ &verify_db($__isns_stage_name, $server); ++} ++ ++sub register_client { ++ ++ print "*** Registering client ***\n"; ++ &__isns_register_client(@_); ++} ++ ++sub __isns_query_objects { ++ ++ local($client_config, @extra_args) = @_; ++ my @args; ++ ++ push(@args, "--query"); ++ push(@args, @extra_args) if (@extra_args); ++ ++ return &run_client($client_config, @args); ++} ++ ++sub isns_query_objects { ++ ++ local($client, @args) = @_; ++ ++ &isns_stage("query", "Querying " . join(' ', @args)); ++ &__isns_query_objects($client, @args); ++ &verify_response($__isns_stage_name, $client); ++} ++ ++sub query_objects { ++ ++ print "*** Querying objects ***\n"; ++ __isns_query_objects(@_); ++} ++ ++sub isns_query_eid { ++ ++ local($client_config, @extra_args) = @_; ++ my $logfile; ++ my @args; ++ local($eid); ++ ++ push(@args, "--query-eid"); ++ push(@args, @extra_args) if (@extra_args); ++ ++ &isns_info("*** Querying for EID ***\n"); ++ $logfile = &run_client($client_config, @args); ++ ++ if ($logfile) { ++ $eid = `cat $logfile`; ++ unless ($eid) { ++ &isns_fail("Server reports empty EID"); ++ } ++ chop($eid); ++ } ++ ++ return $eid; ++} ++ ++sub __isns_unregister_client { ++ ++ local($client_config, @extra_args) = @_; ++ my @args; ++ ++ push(@args, "--deregister"); ++ push(@args, @extra_args) if (@extra_args); ++ ++ &run_client($client_config, @args); ++} ++ ++sub isns_unregister_client { ++ ++ my $stage = 0; ++ my $client; ++ my $server; ++ my $eid; ++ ++ if ($_[0] =~ m/^\d/o) { ++ &isns_stage(shift(@_), "Unregister client"); ++ } else { ++ &isns_stage("unregistration", "Unregister client"); ++ } ++ ++ $client = shift(@_); ++ ++ unless (@_) { ++ $eid = &isns_query_eid($client); ++ push(@_, "eid=$eid"); ++ } ++ ++ &__isns_unregister_client($client, @_); ++ ++ $server = $__isns_data{$client,"server_config"}; ++ &verify_db($__isns_stage_name, $server); ++} ++ ++sub unregister_client { ++ ++ &isns_info("*** Unregistering client ***\n"); ++ &__isns_unregister_client(@_); ++} ++ ++sub __isns_register_domain { ++ ++ local($client_config, @extra_args) = @_; ++ my @args; ++ ++ push(@args, "--local --dd-register"); ++ push(@args, @extra_args) if (@extra_args); ++ ++ &run_client($client_config, @args); ++} ++ ++sub isns_register_domain { ++ ++ local($client, @args) = @_; ++ my $server; ++ ++ &isns_stage("dd-registration", "Registering DD " . join(' ', @args)); ++ &__isns_register_domain($client, @args); ++ ++ $server = $__isns_data{$client,"server_config"}; ++ &isns_verify_db($server); ++} ++ ++sub register_domain { ++ ++ &isns_info("*** Registering DD ***\n"); ++ &__isns_register_domain(@_); ++} ++ ++sub __isns_deregister_domain { ++ ++ local($client_config, @extra_args) = @_; ++ my @args; ++ ++ push(@args, "--local --dd-deregister"); ++ push(@args, @extra_args) if (@extra_args); ++ ++ &run_client($client_config, @args); ++} ++ ++sub isns_deregister_domain { ++ ++ local($client, @args) = @_; ++ my $server; ++ ++ &isns_stage("dd-deregistration", "Deregistering DD (members)" . join(' ', @args)); ++ &__isns_deregister_domain($client, @args); ++ ++ $server = $__isns_data{$client,"server_config"}; ++ &isns_verify_db($server); ++} ++ ++sub isns_external_test { ++ ++ local($client, @args) = @_; ++ my $logfile; ++ my $stage; ++ my $cmd; ++ ++ $logfile = &get_logfile($client); ++ ++ $cmd = shift(@args); ++ $stage = $cmd; ++ $stage =~ s:.*/::o; ++ ++ $cmd = "${__isns_bin}/$cmd -c $client " . join(' ', @args); ++ ++ &isns_stage($stage, "Running external $cmd " . join(' ', @args)); ++ unless (&run_command("$cmd >$logfile")) { ++ return undef; ++ } ++ ++ $server = $__isns_data{$client,"server_config"}; ++ &isns_verify_db($server); ++} ++ ++sub __isns_prep_test { ++ ++ local($name, $duration, @ARGV) = @_; ++ ++ GetOptions('verbose+' => \$__isns_verbose, ++ "quiet" => \$__isns_quiet, ++ "fast" => \$__isns_quick, ++ "insecure" => \$__isns_insecure); ++ $__isns_verbose = 0 if ($__isns_quiet); ++ $__isns_security = 0 if ($__isns_insecure); ++ ++ if ($__isns_quick && $duration > 15) { ++ print "*** Skipping $name (duration ~ $duration seconds) ***\n"; ++ exit(0); ++ } ++ ++ print "*** Starting $name ***\n"; ++ printf "*** This test case will take about %u sec ***\n", $duration ++ if ($duration); ++ $__isns_test_name = $name; ++ $__isns_test_dir = "$__isns_test_base/$name"; ++ $__isns_test_dump = "$__isns_test_dir/dump"; ++ $__isns_test_data = "data/$name"; ++ ++ # Be careful when removing test dir ++ system "rm -rf $__isns_test_dir" if ($__isns_test_dir =~ m:/tmp/:o); ++ ++ mkdir $__isns_test_base, 0700; ++ mkdir $__isns_test_dir, 0700; ++ mkdir $__isns_test_dump, 0700; ++} ++ ++sub test_prep { ++ ++ local($name, @args) = @_; ++ ++ __isns_prep_test($name, 0, @args); ++} ++ ++sub isns_prep_slow_test { ++ ++ __isns_prep_test(@_); ++} ++ ++# Sleep for a few seconds, giving the user some dots to keep ++# him occupied. ++sub isns_idle { ++ ++ local($time) = @_; ++ ++ if ($__isns_verbose == 0) { ++ sleep $time; ++ return; ++ } ++ ++ $| = 1; ++ print "Snooze"; ++ while ($time--) { ++ print "."; ++ sleep 1; ++ } ++ print "\n"; ++ $| = 0; ++} ++ ++sub main { ++ ++ my $server_config; ++ my $client_config; ++ ++ &test_prep; ++ ++ $server_config = &create_server; ++ $client_config = &create_client($server_config); ++} ++ ++#&main; ++1; +diff --git a/utils/open-isns/tests/pauw1.c b/utils/open-isns/tests/pauw1.c +new file mode 100644 +index 0000000..c3e66f7 +--- /dev/null ++++ b/utils/open-isns/tests/pauw1.c +@@ -0,0 +1,179 @@ ++/* ++ * Test case, captured from a Wasabi Storage Builder ++ * registering itself. ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++int ++main(int argc, char **argv) ++{ ++ const char *opt_configfile = ISNS_DEFAULT_ISNSADM_CONFIG; ++ isns_client_t *clnt; ++ isns_attr_list_t *attrs; ++ isns_simple_t *reg; ++ isns_portal_info_t portal_info; ++ uint32_t status; ++ int c; ++ ++ while ((c = getopt(argc, argv, "c:d:")) != -1) { ++ switch (c) { ++ case 'c': ++ opt_configfile = optarg; ++ break; ++ ++ case 'd': ++ isns_enable_debugging(optarg); ++ break; ++ ++ default: ++ isns_fatal("Unknown option\n"); ++ } ++ } ++ ++ isns_read_config(opt_configfile); ++ isns_assign_string(&isns_config.ic_source_name, ++ "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0"); ++ ++ clnt = isns_create_default_client(NULL); ++ ++ reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, ++ clnt->ic_source, NULL); ++ ++ attrs = ®->is_operating_attrs; ++ ++#define ADD(type, tag, value) \ ++ isns_attr_list_append_##type(attrs, ISNS_TAG_##tag, value) ++#define STR(tag, value) ADD(string, tag, value) ++#define U32(tag, value) ADD(uint32, tag, value) ++#define NIL(tag) isns_attr_list_append_nil(attrs, ISNS_TAG_##tag) ++#define TARGET(name, alias, auth) \ ++ STR(ISCSI_NAME, name); \ ++ U32(ISCSI_NODE_TYPE, ISNS_ISCSI_TARGET_MASK); \ ++ STR(ISCSI_ALIAS, alias); \ ++ STR(ISCSI_AUTHMETHOD, auth) ++ ++ STR(ENTITY_IDENTIFIER, "cyan.pauw.homeunix.net"); ++ U32(ENTITY_PROTOCOL, 2); ++ U32(REGISTRATION_PERIOD, 31536000); ++ ++ TARGET("iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0", ++ "Test (10 GB)", ++ "None"); ++ TARGET("iqn.2000-05.com.wasabisystems.storagebuilder:cyan-1", ++ "160 GB disk (ntfs)", ++ "None"); ++ TARGET("iqn.2000-05.com.wasabisystems.storagebuilder:cyan-2", ++ "160 GB disk (ext3)", ++ "CHAP"); ++ TARGET("iqn.2000-05.com.wasabisystems.storagebuilder:cyan-3", ++ "Test (1 GB)", ++ "None"); ++ TARGET("iqn.2000-05.com.wasabisystems.storagebuilder:cyan-4", ++ "Test (40 GB)", ++ "CHAP"); ++ TARGET("iqn.2000-05.com.wasabisystems.storagebuilder:cyan-5", ++ "test", ++ "None"); ++ ++ isns_portal_parse(&portal_info, "10.0.0.1:3260/tcp", NULL); ++ isns_portal_to_attr_list(&portal_info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ attrs); ++ ++ /* Mumbo jumbo encoding of portal groups */ ++ U32(PG_TAG, 1); ++ STR(PG_ISCSI_NAME, "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0"); ++ STR(PG_ISCSI_NAME, "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-1"); ++ STR(PG_ISCSI_NAME, "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-2"); ++ STR(PG_ISCSI_NAME, "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-3"); ++ STR(PG_ISCSI_NAME, "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-4"); ++ STR(PG_ISCSI_NAME, "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-5"); ++ ++ /* Strictly speaking, a PGT not followed by any data is invalid. ++ * ++ * 5.6.5.1. ++ * When a Portal is registered, the Portal attributes MAY ++ * immediately be followed by a PGT attribute. The PGT attribute ++ * SHALL be followed by the set of PG iSCSI Names representing ++ * nodes that will be associated to the Portal using the indicated ++ * PGT value. ++ */ ++ NIL(PG_TAG); ++ ++ isns_simple_print(reg, isns_print_stdout); ++ ++ status = isns_client_call(clnt, ®); ++ ++ if (status != ISNS_SUCCESS) ++ isns_fatal("Unable to register object: %s\n", ++ isns_strerror(status)); ++ ++ printf("Successfully registered object(s)\n"); ++ isns_simple_print(reg, isns_print_stdout); ++ ++ return 0; ++} ++ ++/* ++ Creating file DB backend (/var/lib/isns) ++ DB: loading all objects from /var/lib/isns ++ Next ESI message in 3600 seconds ++ Incoming PDU xid=0001 seq=0 len=1208 func=DevAttrReg client first last ++ Next message xid=0001 ++ Received message ++ ---DevAttrReg--- ++ Source: ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0" ++ Message attributes: ++ Operating attributes: ++ 0001 string : Entity identifier = "cyan.pauw.homeunix.net" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0006 uint32 : Registration Period = 31536000 ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0" ++ 0021 uint32 : iSCSI node type = Target ++ 0022 string : iSCSI alias = "Test (10 GB)" ++ 002a string : iSCSI auth method = "None" ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-1" ++ 0021 uint32 : iSCSI node type = Target ++ 0022 string : iSCSI alias = "160 GB disk (ntfs)" ++ 002a string : iSCSI auth method = "None" ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-2" ++ 0021 uint32 : iSCSI node type = Target ++ 0022 string : iSCSI alias = "160 GB disk (ext3)" ++ 002a string : iSCSI auth method = "CHAP" ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-3" ++ 0021 uint32 : iSCSI node type = Target ++ 0022 string : iSCSI alias = "Test (1 GB)" ++ 002a string : iSCSI auth method = "None" ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-4" ++ 0021 uint32 : iSCSI node type = Target ++ 0022 string : iSCSI alias = "Test (40 GB)" ++ 002a string : iSCSI auth method = "CHAP" ++ 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-5" ++ 0021 uint32 : iSCSI node type = Target ++ 0022 string : iSCSI alias = "test" ++ 002a string : iSCSI auth method = "None" ++ 0010 ipaddr : Portal IP address = 10.0.0.1 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0033 uint32 : Portal group tag = 1 ++ 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0" ++ 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-1" ++ 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-2" ++ 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-3" ++ 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-4" ++ 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-5" ++ 0033 nil : Portal group tag = ++ :: policy insecure function DevAttrReg (0001) permitted ++ :: policy insecure source ++iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0 permitted ++ :: policy insecure operation DevAttrReg on Network Entity object ++permitted ++ DB: Storing object 00000001 -> /var/lib/isns/00000001 ++ DB: added object 1 (Network Entity) state 1 ++Segmentation fault ++ */ +diff --git a/utils/open-isns/tests/pauw2.c b/utils/open-isns/tests/pauw2.c +new file mode 100644 +index 0000000..29084b3 +--- /dev/null ++++ b/utils/open-isns/tests/pauw2.c +@@ -0,0 +1,212 @@ ++/* ++ * Test case, captured from iscsi-target ++ * registering itself. ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#define ADD(type, tag, value) \ ++ isns_attr_list_append_##type(attrs, ISNS_TAG_##tag, value) ++#define STR(tag, value) ADD(string, tag, value) ++#define U32(tag, value) ADD(uint32, tag, value) ++#define NIL(tag) isns_attr_list_append_nil(attrs, ISNS_TAG_##tag) ++#define TARGET(name, alias, auth) \ ++ STR(ISCSI_NAME, name); \ ++ U32(ISCSI_NODE_TYPE, ISNS_ISCSI_TARGET_MASK); \ ++ STR(ISCSI_ALIAS, alias); \ ++ STR(ISCSI_AUTHMETHOD, auth) ++ ++int ++main(int argc, char **argv) ++{ ++ const char *opt_configfile = ISNS_DEFAULT_ISNSADM_CONFIG; ++ isns_client_t *clnt; ++ isns_attr_list_t *attrs; ++ isns_simple_t *reg; ++ isns_portal_info_t portal_info; ++ uint32_t status; ++ int c; ++ ++ while ((c = getopt(argc, argv, "c:d:")) != -1) { ++ switch (c) { ++ case 'c': ++ opt_configfile = optarg; ++ break; ++ ++ case 'd': ++ isns_enable_debugging(optarg); ++ break; ++ ++ default: ++ isns_fatal("Unknown option\n"); ++ } ++ } ++ ++ isns_read_config(opt_configfile); ++ ++ /* ++ ---DevAttrReg[REPLACE]--- ++ Source: ++ 0020 string : iSCSI name = "iqn.2007-03.com.example:stgt.disk" ++ Message attributes: ++ 0001 string : Entity identifier = "blue.pauw.homeunix.net" ++ Operating attributes: ++ 0001 string : Entity identifier = "blue.pauw.homeunix.net" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0010 ipaddr : Portal IP address = 192.168.1.2 ++ 0011 uint32 : Portal TCP/UDP port = 3260/tcp ++ 0017 uint32 : SCN port = 42138/tcp ++ 0020 string : iSCSI name = "iqn.2007-03.com.example:stgt.disk" ++ 0021 uint32 : iSCSI node type = Target ++ */ ++ isns_assign_string(&isns_config.ic_source_name, ++ "iqn.2007-03.com.example:stgt.disk"); ++ ++ clnt = isns_create_default_client(NULL); ++ reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, ++ clnt->ic_source, NULL); ++ reg->is_replace = 1; ++ ++ /* Message attributes */ ++ attrs = ®->is_message_attrs; ++ STR(ENTITY_IDENTIFIER, "blue.pauw.homeunix.net"); ++ ++ /* Operating attributes */ ++ attrs = ®->is_operating_attrs; ++ ++ STR(ENTITY_IDENTIFIER, "blue.pauw.homeunix.net"); ++ U32(ENTITY_PROTOCOL, 2); ++ ++ isns_portal_parse(&portal_info, "192.168.1.2:3260/tcp", NULL); ++ isns_portal_to_attr_list(&portal_info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ attrs); ++ ++ U32(SCN_PORT, 42138); ++ STR(ISCSI_NAME, "iqn.2007-03.com.example:stgt.disk"); ++ U32(ISCSI_NODE_TYPE, ISNS_ISCSI_TARGET_MASK); ++ isns_simple_print(reg, isns_print_stdout); ++ ++ status = isns_client_call(clnt, ®); ++ ++ if (status != ISNS_SUCCESS) ++ isns_fatal("Unable to register object: %s\n", ++ isns_strerror(status)); ++ ++ printf("Successfully registered object #1\n"); ++ // isns_simple_print(reg, isns_print_stdout); ++ isns_simple_free(reg); ++ isns_client_destroy(clnt); ++ ++ /* ++ ---DevAttrReg[REPLACE]--- ++ Source: ++ 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" ++ Message attributes: ++ 0001 string : Entity identifier = "blue.pauw.homeunix.net" ++ Operating attributes: ++ 0001 string : Entity identifier = "blue.pauw.homeunix.net" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0010 ipaddr : Portal IP address = 192.168.1.2 ++ 0011 uint32 : Portal TCP/UDP port = 33849/tcp ++ 0014 uint32 : ESI port = 56288/tcp ++ 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0022 string : iSCSI alias = "blue.pauw.homeunix.net" ++ ++ [...] ++ response status 0x0003 (Invalid registration) ++ ++ This would fail because we got confused about EID in ++ the replace case. ++ */ ++ isns_assign_string(&isns_config.ic_source_name, ++ "iqn.2005-03.org.open-iscsi:blue"); ++ ++ clnt = isns_create_default_client(NULL); ++ reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, ++ clnt->ic_source, NULL); ++ reg->is_replace = 1; ++ ++ /* Message attributes */ ++ attrs = ®->is_message_attrs; ++ STR(ENTITY_IDENTIFIER, "blue.pauw.homeunix.net"); ++ ++ /* Operating attributes */ ++ attrs = ®->is_operating_attrs; ++ ++ STR(ENTITY_IDENTIFIER, "blue.pauw.homeunix.net"); ++ U32(ENTITY_PROTOCOL, 2); ++ ++ isns_portal_parse(&portal_info, "192.168.1.2:33849/tcp", NULL); ++ isns_portal_to_attr_list(&portal_info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ attrs); ++ ++ U32(ESI_PORT, 56288); ++ STR(ISCSI_NAME, "iqn.2005-03.org.open-iscsi:blue"); ++ U32(ISCSI_NODE_TYPE, ISNS_ISCSI_INITIATOR_MASK); ++ STR(ISCSI_ALIAS, "blue.pauw.homeunix.net"); ++ isns_simple_print(reg, isns_print_stdout); ++ ++ status = isns_client_call(clnt, ®); ++ ++ if (status != ISNS_SUCCESS) ++ isns_fatal("Unable to register object: %s\n", ++ isns_strerror(status)); ++ ++ printf("Successfully registered object #2\n"); ++ // isns_simple_print(reg, isns_print_stdout); ++ isns_simple_free(reg); ++ isns_client_destroy(clnt); ++ ++ return 0; ++} ++ ++/* ++ Creating file DB backend (/var/lib/isns) ++ DB: loading all objects from /var/lib/isns ++ Next ESI message in 3600 seconds ++ Incoming PDU xid=0001 seq=0 len=232 func=DevAttrReg client first last ++ Next message xid=0001 ++ Received message ++ ++ :: policy insecure function DevAttrReg (0001) permitted ++ :: policy insecure source iqn.2005-03.org.open-iscsi:blue permitted ++ :: policy insecure operation DevAttrReg on object 00000001 (Network ++Entity) permitted ++ Replacing Network Entity (id 1) ++ DB: removed object 2 (Portal) ++ DB: removed object 4 (iSCSI Portal Group) ++ DB: removed object 3 (iSCSI Storage Node) ++ DB: removed object 1 (Network Entity) ++ DB: destroying object 2 (Portal) ++ DB: Purging object 2 (/var/lib/isns/00000002) ++ DB: destroying object 1 (Network Entity) ++ DB: Purging object 1 (/var/lib/isns/00000001) ++ DB: destroying object 3 (iSCSI Storage Node) ++ DB: Purging object 3 (/var/lib/isns/00000003) ++ DB: destroying object 4 (iSCSI Portal Group) ++ DB: Purging object 4 (/var/lib/isns/00000004) ++ :: policy insecure entity ID blue.pauw.homeunix.net permitted ++ :: policy insecure operation DevAttrReg on Network Entity object ++permitted ++ DB: Storing object 5 -> /var/lib/isns/00000005 ++ DB: added object 5 (Network Entity) state 1 ++ DB: Storing object 5 -> /var/lib/isns/00000005 ++ isns_esi_callback(0x9dee788, 0x10) ++ Deleting SCN registration for iqn.2007-03.com.example:stgt.disk ++ isns_esi_callback(0x9deeae0, 0x10) ++ isns_esi_callback(0x9deea30, 0x10) ++ isns_esi_callback(0x9deec80, 0x10) ++ SCN multicast ++ isns_scn_callback(0x9deec80, 0x10) ++ isns_esi_callback(0x9def4b0, 0xc) ++ Enable ESI monitoring for entity 5 ++ ++ */ +diff --git a/utils/open-isns/tests/pauw3.c b/utils/open-isns/tests/pauw3.c +new file mode 100644 +index 0000000..3be0baa +--- /dev/null ++++ b/utils/open-isns/tests/pauw3.c +@@ -0,0 +1,139 @@ ++/* ++ * This tests another problem reported by Albert, where a ++ * re-registration shortly before ESI expiry would fail ++ * to resurrect the registration properly. ++ * ++ * Usage: ++ * pauw3 [options] timeout ++ * ++ * Where timeout is the delay until we try to re-register ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define ADD(type, tag, value) \ ++ isns_attr_list_append_##type(attrs, ISNS_TAG_##tag, value) ++#define STR(tag, value) ADD(string, tag, value) ++#define U32(tag, value) ADD(uint32, tag, value) ++#define NIL(tag) isns_attr_list_append_nil(attrs, ISNS_TAG_##tag) ++#define TARGET(name, alias, auth) \ ++ STR(ISCSI_NAME, name); \ ++ U32(ISCSI_NODE_TYPE, ISNS_ISCSI_TARGET_MASK); \ ++ STR(ISCSI_ALIAS, alias); \ ++ STR(ISCSI_AUTHMETHOD, auth) ++ ++int ++main(int argc, char **argv) ++{ ++ const char *opt_configfile = ISNS_DEFAULT_ISNSADM_CONFIG; ++ isns_client_t *clnt; ++ isns_attr_list_t *attrs; ++ isns_simple_t *reg; ++ isns_portal_info_t portal_info; ++ uint32_t status; ++ int opt_replace = 1; ++ int c, n, timeout; ++ ++ while ((c = getopt(argc, argv, "c:d:n")) != -1) { ++ switch (c) { ++ case 'c': ++ opt_configfile = optarg; ++ break; ++ ++ case 'd': ++ isns_enable_debugging(optarg); ++ break; ++ ++ case 'n': ++ opt_replace = 0; ++ break; ++ ++ default: ++ isns_fatal("Unknown option\n"); ++ } ++ } ++ ++ if (optind != argc - 1) ++ isns_fatal("Need timeout argument\n"); ++ timeout = parse_timeout(argv[optind]); ++ ++ isns_read_config(opt_configfile); ++ ++ /* ++ ---DevAttrReg[REPLACE]--- ++ Source: ++ 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" ++ Message attributes: ++ 0001 string : Entity identifier = "blue.pauw.homeunix.net" ++ Operating attributes: ++ 0001 string : Entity identifier = "blue.pauw.homeunix.net" ++ 0002 uint32 : Entity protocol = iSCSI (2) ++ 0010 ipaddr : Portal IP address = 192.168.1.2 ++ 0011 uint32 : Portal TCP/UDP port = 33849/tcp ++ 0014 uint32 : ESI port = 56288/tcp ++ 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" ++ 0021 uint32 : iSCSI node type = Initiator ++ 0022 string : iSCSI alias = "blue.pauw.homeunix.net" ++ ++ [...] ++ response status 0x0003 (Invalid registration) ++ ++ This would fail because we got confused about EID in ++ the replace case. ++ */ ++ isns_assign_string(&isns_config.ic_source_name, ++ "iqn.2005-03.org.open-iscsi:blue"); ++ ++ for (n = 0; n < 2; ++n) { ++ clnt = isns_create_default_client(NULL); ++ reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, ++ clnt->ic_source, NULL); ++ reg->is_replace = opt_replace; ++ ++ /* Message attributes */ ++ attrs = ®->is_message_attrs; ++ STR(ENTITY_IDENTIFIER, "blue.pauw.homeunix.net"); ++ ++ /* Operating attributes */ ++ attrs = ®->is_operating_attrs; ++ ++ STR(ENTITY_IDENTIFIER, "blue.pauw.homeunix.net"); ++ U32(ENTITY_PROTOCOL, 2); ++ ++ isns_portal_parse(&portal_info, "192.168.1.2:33849/tcp", NULL); ++ isns_portal_to_attr_list(&portal_info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ attrs); ++ ++ U32(ESI_PORT, 56288); ++ STR(ISCSI_NAME, "iqn.2005-03.org.open-iscsi:blue"); ++ U32(ISCSI_NODE_TYPE, ISNS_ISCSI_INITIATOR_MASK); ++ STR(ISCSI_ALIAS, "blue.pauw.homeunix.net"); ++ isns_simple_print(reg, isns_print_stdout); ++ ++ status = isns_client_call(clnt, ®); ++ ++ if (status != ISNS_SUCCESS) ++ isns_fatal("Unable to register object: %s\n", ++ isns_strerror(status)); ++ ++ printf("Successfully registered object\n"); ++ // isns_simple_print(reg, isns_print_stdout); ++ isns_simple_free(reg); ++ isns_client_destroy(clnt); ++ ++ if (n == 0) { ++ printf("Sleeping for %d seconds\n", timeout); ++ sleep(timeout); ++ } ++ } ++ ++ return 0; ++} +diff --git a/utils/open-isns/tests/pauw4.c b/utils/open-isns/tests/pauw4.c +new file mode 100644 +index 0000000..9510ddd +--- /dev/null ++++ b/utils/open-isns/tests/pauw4.c +@@ -0,0 +1,137 @@ ++/* ++ * Test MS initiator registration. ++ * The oddity about this is that the PG object precedes the ++ * initiator object in the message. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define ADD(type, tag, value) \ ++ isns_attr_list_append_##type(attrs, ISNS_TAG_##tag, value) ++#define STR(tag, value) ADD(string, tag, value) ++#define U32(tag, value) ADD(uint32, tag, value) ++#define NIL(tag) isns_attr_list_append_nil(attrs, ISNS_TAG_##tag) ++#define TARGET(name, alias, auth) \ ++ STR(ISCSI_NAME, name); \ ++ U32(ISCSI_NODE_TYPE, ISNS_ISCSI_TARGET_MASK); \ ++ STR(ISCSI_ALIAS, alias); \ ++ STR(ISCSI_AUTHMETHOD, auth) ++ ++int ++main(int argc, char **argv) ++{ ++ const char *opt_configfile = ISNS_DEFAULT_ISNSADM_CONFIG; ++ isns_client_t *clnt; ++ isns_attr_list_t *attrs; ++ isns_simple_t *reg; ++ isns_portal_info_t portal_info; ++ uint32_t status; ++ int opt_replace = 1; ++ int c; ++ ++ while ((c = getopt(argc, argv, "c:d:n")) != -1) { ++ switch (c) { ++ case 'c': ++ opt_configfile = optarg; ++ break; ++ ++ case 'd': ++ isns_enable_debugging(optarg); ++ break; ++ ++ case 'n': ++ opt_replace = 0; ++ break; ++ ++ default: ++ isns_fatal("Unknown option\n"); ++ } ++ } ++ ++ isns_read_config(opt_configfile); ++ ++ isns_assign_string(&isns_config.ic_source_name, ++ "iqn.1991-05.com.microsoft:orange"); ++ ++ clnt = isns_create_default_client(NULL); ++ ++ reg = isns_simple_create(ISNS_SCN_DEREGISTER, clnt->ic_source, NULL); ++ ++ /* Message attributes */ ++ attrs = ®->is_message_attrs; ++ STR(ISCSI_NAME, "iqn.1991-05.com.microsoft:orange"); ++ ++ status = isns_client_call(clnt, ®); ++ if (status != ISNS_SUCCESS) ++ isns_error("SCNDereg failed: %s\n", isns_strerror(status)); ++ isns_simple_free(reg); ++ ++ ++ reg = isns_simple_create(ISNS_DEVICE_DEREGISTER, clnt->ic_source, NULL); ++ ++ attrs = ®->is_operating_attrs; ++ STR(ENTITY_IDENTIFIER, "troopa.nki.nl"); ++ U32(ENTITY_PROTOCOL, 2); ++ ++ isns_portal_parse(&portal_info, "192.168.1.40:3229/tcp", NULL); ++ isns_portal_to_attr_list(&portal_info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ attrs); ++ ++ STR(ISCSI_NAME, "iqn.1991-05.com.microsoft:orange"); ++ ++ status = isns_client_call(clnt, ®); ++ if (status != ISNS_SUCCESS) ++ isns_fatal("DevDereg failed: %s\n", isns_strerror(status)); ++ isns_simple_free(reg); ++ ++ reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, clnt->ic_source, NULL); ++ reg->is_replace = opt_replace; ++ ++ attrs = ®->is_operating_attrs; ++ STR(ENTITY_IDENTIFIER, "troopa.nki.nl"); ++ U32(ENTITY_PROTOCOL, 2); ++ ++ isns_portal_parse(&portal_info, "192.168.1.40:3229/tcp", NULL); ++ isns_portal_to_attr_list(&portal_info, ++ ISNS_TAG_PORTAL_IP_ADDRESS, ++ ISNS_TAG_PORTAL_TCP_UDP_PORT, ++ attrs); ++ ++ U32(SCN_PORT, 3230); ++ U32(ESI_PORT, 3230); ++ ++ U32(PG_TAG, 1); ++ STR(PG_ISCSI_NAME, "iqn.1991-05.com.microsoft:orange"); ++ ++ STR(ISCSI_NAME, "iqn.1991-05.com.microsoft:orange"); ++ U32(ISCSI_NODE_TYPE, ISNS_ISCSI_INITIATOR_MASK); ++ STR(ISCSI_ALIAS, ""); ++ ++ status = isns_client_call(clnt, ®); ++ if (status != ISNS_SUCCESS) ++ isns_fatal("DevAttrReg failed: %s\n", isns_strerror(status)); ++ isns_simple_free(reg); ++ ++ reg = isns_simple_create(ISNS_DEVICE_GET_NEXT, clnt->ic_source, NULL); ++ attrs = ®->is_message_attrs; ++ NIL(ISCSI_NAME); ++ ++ attrs = ®->is_operating_attrs; ++ U32(ISCSI_NODE_TYPE, ISNS_ISCSI_TARGET_MASK); ++ NIL(ISCSI_NODE_TYPE); ++ ++ status = isns_client_call(clnt, ®); ++ if (status != ISNS_SUCCESS) ++ isns_fatal("DevGetNext failed: %s\n", isns_strerror(status)); ++ isns_simple_free(reg); ++ ++ return 0; ++} +diff --git a/utils/open-isns/tests/server.conf b/utils/open-isns/tests/server.conf +new file mode 100644 +index 0000000..fc0bb5a +--- /dev/null ++++ b/utils/open-isns/tests/server.conf +@@ -0,0 +1,11 @@ ++BindAddress = @SERVER_ADDRESS@ ++SourceName = @SOURCE_NAME@ ++Database = @DB_PATH@ ++RegistrationPeriod = 2h ++ESIMinInterval = 1m ++ESIMinInterval = 5m ++Security = @NOT_SET@ ++AuthKeyFile = @AUTH_KEY@ ++ClientKeyStore = DB: ++PIDFile = @MYDIR@/pid ++ControlSocket = @MYDIR@/control +diff --git a/utils/open-isns/tests/test01.pl b/utils/open-isns/tests/test01.pl +new file mode 100644 +index 0000000..258acff +--- /dev/null ++++ b/utils/open-isns/tests/test01.pl +@@ -0,0 +1,30 @@ ++#!/usr/bin/perl ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This test case validates registration and simple query of ++# single client. ++ ++push(@INC, "."); ++require "harness.pl"; ++ ++&test_prep("test01", @ARGV); ++ ++$server = &create_server; ++$client = &create_client($server); ++ ++&isns_start_server($server); ++ ++# 1: Enroll the test client ++&isns_enroll_client($client); ++ ++# 2: Register an initiator with default portal ++&isns_register_client($client, "initiator portal"); ++ ++# 3: Run a simple query ++&isns_query_objects($client, "eid"); ++ ++# 99: Unregister client ++&isns_unregister_client("99-unregistration", $client); ++ ++&isns_finish; +diff --git a/utils/open-isns/tests/test02.pl b/utils/open-isns/tests/test02.pl +new file mode 100644 +index 0000000..208bed5 +--- /dev/null ++++ b/utils/open-isns/tests/test02.pl +@@ -0,0 +1,58 @@ ++#!/usr/bin/perl ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This test case validates registration and simple query of ++# two clients, and simple DD functionality. ++ ++push(@INC, "."); ++require "harness.pl"; ++ ++&test_prep("test02", @ARGV); ++ ++$server = &create_server; ++$client1 = &create_client($server, "127.1.0.1"); ++$client2 = &create_client($server, "127.1.0.2"); ++ ++&isns_start_server($server); ++ ++# 1: Enroll the client1 ++&isns_enroll_client($client1); ++ ++# 2: Enroll the client1 ++&isns_enroll_client($client2, "node-type=target"); ++ ++&isns_stage("registration", "Registering both clients"); ++&__isns_register_client($client1, "initiator portal"); ++&__isns_register_client($client2, "target portal"); ++&isns_verify_db($server); ++ ++# Now each of the two clients should just see ++# itself ++&isns_query_objects($client1, "eid"); ++&isns_query_objects($client2, "eid"); ++ ++# Register a DD linking the two nodes ++&isns_register_domain($client1, "member-name=isns.client1", "member-name=isns.client2"); ++ ++# Now the clients should see each other ++&isns_query_objects($client1, "eid"); ++&isns_query_objects($client2, "eid"); ++ ++# Initiator querying for target: ++&isns_query_objects($client1, "iscsi-node-type=Target"); ++ ++# Add another member to this DD, and re-add client2 (making ++# sure the server doesn't generate dupes) ++&isns_register_domain($client1, "dd-id=1", "member-name=isns.client2", "member-name=iqn.com.foobar:disk1"); ++ ++# Query the list of DDs we're a member of ++&isns_query_objects($client1, "dd-id"); ++ ++# Remove some entries from the DD ++&isns_deregister_domain($client1, "1", "member-iscsi-idx=10"); ++&isns_deregister_domain($client1, "1", "member-name=iqn.com.foobar:disk1"); ++&isns_register_domain($client1, "dd-id=1", "member-name=isns.client2"); ++&isns_deregister_domain($client1, "1"); ++ ++&isns_finish; +diff --git a/utils/open-isns/tests/test03.pl b/utils/open-isns/tests/test03.pl +new file mode 100644 +index 0000000..3cc0d71 +--- /dev/null ++++ b/utils/open-isns/tests/test03.pl +@@ -0,0 +1,27 @@ ++#!/usr/bin/perl ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This test case validates registration and unregistration. ++ ++push(@INC, "."); ++require "harness.pl"; ++ ++&test_prep("test03", @ARGV); ++ ++$server = &create_server; ++$client = &create_client($server); ++ ++&isns_start_server($server); ++ ++&isns_enroll_client($client); ++&isns_register_client($client, "initiator portal"); ++ ++# Unregistering the portal should leave the iscsi node and ++# portal group active, and move the portal to state limbo. ++&isns_unregister_client($client, "portal=127.0.0.1:860"); ++ ++# As the iscsi node goes away, so should the whole entity ++&isns_unregister_client($client, "iscsi-name=isns.client1"); ++ ++&isns_finish; +diff --git a/utils/open-isns/tests/test04.pl b/utils/open-isns/tests/test04.pl +new file mode 100644 +index 0000000..8181a4e +--- /dev/null ++++ b/utils/open-isns/tests/test04.pl +@@ -0,0 +1,30 @@ ++#!/usr/bin/perl ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This test case verifies that the database remains intact ++# across server restarts. ++ ++push(@INC, "."); ++require "harness.pl"; ++ ++&test_prep("test04", @ARGV); ++ ++$server = &create_server; ++$client = &create_client($server); ++ ++&isns_start_server($server); ++ ++&isns_enroll_client($client); ++&isns_register_client($client, "initiator portal"); ++ ++# Restart the server, and make sure it still displays ++# the database properly ++&isns_stage("restart", "Restarting server process"); ++&isns_restart_server($server); ++&isns_verify_db($server); ++ ++# Run a simple query ++&isns_query_objects($client, "iscsi-name"); ++ ++&isns_finish; +diff --git a/utils/open-isns/tests/test05.pl b/utils/open-isns/tests/test05.pl +new file mode 100644 +index 0000000..694d7c3 +--- /dev/null ++++ b/utils/open-isns/tests/test05.pl +@@ -0,0 +1,25 @@ ++#!/usr/bin/perl ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This test case verifies entity expiry ++ ++push(@INC, "."); ++require "harness.pl"; ++ ++&isns_prep_slow_test("test05", 30, @ARGV); ++ ++$server = &create_server({ "RegistrationPeriod" => "20s" }); ++$client = &create_client($server); ++ ++&isns_start_server($server); ++ ++&isns_enroll_client($client); ++&isns_register_client($client, "initiator portal"); ++ ++&isns_stage("expired", "Waiting for registration period to expire (25s)"); ++&isns_idle(25); ++&isns_verify_db($server); ++ ++&isns_finish; ++ +diff --git a/utils/open-isns/tests/test06.pl b/utils/open-isns/tests/test06.pl +new file mode 100644 +index 0000000..6b6aa05 +--- /dev/null ++++ b/utils/open-isns/tests/test06.pl +@@ -0,0 +1,50 @@ ++#!/usr/bin/perl ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This test case validates DevAttrReg replace mode. ++ ++push(@INC, "."); ++require "harness.pl"; ++ ++&test_prep("test06", @ARGV); ++ ++$server = &create_server; ++$client = &create_client($server); ++ ++&isns_start_server($server); ++ ++# 1: Enroll the client ++&isns_enroll_client($client); ++ ++# 2: Register a simple initiator with one portal ++&isns_register_client($client, "initiator portal"); ++ ++$eid = &isns_query_eid($client); ++unless ($eid) { ++ &isns_die("Cannot obtain entity ID"); ++} ++ ++# Now replace the portal with different values ++&isns_register_client($client, "--replace entity=$eid initiator portal=192.168.1.1:iscsi"); ++&isns_register_client($client, "--replace entity=$eid initiator portal=192.168.1.2:iscsi"); ++ ++&isns_register_domain($client, "member-name=isns.client1"); ++ ++# Replace our registration once more. Now the object index of the ++# initiator should not change, since it's a domain member now. ++&isns_register_client($client, "--replace entity=$eid initiator portal=192.168.1.1:iscsi"); ++ ++# Make the portal a domain member too. Now even the portal index should stay ++# the same. Note that we do not replace the whole entity now, but just the ++# portal ++&isns_register_domain($client, "dd-id=1 member-addr=192.168.1.1 member-port=860"); ++&isns_register_client($client, "--replace --key portal=192.168.1.1:iscsi portal=192.168.1.2:iscsi"); ++&isns_register_client($client, "--replace --key portal=192.168.1.2:iscsi portal=192.168.1.1:iscsi"); ++ ++# Now unregister the whole client, and re-register. ++# Portal and client index should remain the same ++&isns_unregister_client($client, "eid=$eid"); ++&isns_register_client($client, "initiator portal=192.168.1.1:iscsi"); ++ ++&isns_finish; +diff --git a/utils/open-isns/tests/test07.pl b/utils/open-isns/tests/test07.pl +new file mode 100644 +index 0000000..c13df11 +--- /dev/null ++++ b/utils/open-isns/tests/test07.pl +@@ -0,0 +1,37 @@ ++#!/usr/bin/perl ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This test case validates that the server discards portals ++# that do not respond to ESI messages ++ ++push(@INC, "."); ++require "harness.pl"; ++ ++&isns_prep_slow_test("test07", 30, @ARGV); ++ ++$server = &create_server({ "ESIMinInterval" => "5s" }); ++$client = &create_client($server); ++ ++&isns_start_server($server); ++ ++# 1: Enroll the client ++&isns_enroll_client($client); ++ ++# 2: Register a simple initiator with one portal ++&isns_register_client($client, "initiator portal,esi-port=65535,esi-interval=5"); ++ ++&isns_stage("expired", "Waiting for ESI to expire (~15 sec)"); ++&isns_idle(15); ++&isns_verify_db($server); ++ ++# 3: Register a simple initiator with two portals, one with ESI and one without. ++# When the ESI monitored portal expires, this should still take down ++# the whole network entity. ++&isns_register_client($client, "initiator portal,esi-port=65535,esi-interval=5 portal=127.0.0.1:1"); ++ ++&isns_stage("expired", "Waiting for ESI to expire (~15 sec)"); ++&isns_idle(15); ++&isns_verify_db($server); ++ ++&isns_finish; +diff --git a/utils/open-isns/tests/test08.pl b/utils/open-isns/tests/test08.pl +new file mode 100644 +index 0000000..1487532 +--- /dev/null ++++ b/utils/open-isns/tests/test08.pl +@@ -0,0 +1,23 @@ ++#!/usr/bin/perl ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This test case validates registration and simple query of ++# single client. ++ ++push(@INC, "."); ++require "harness.pl"; ++ ++# For now, this one will run w/o security only ++push(@ARGV, '-i'); ++ ++&test_prep("test08", @ARGV); ++ ++$server = &create_server; ++$client = &create_client($server); ++ ++&isns_start_server($server); ++ ++&isns_external_test($client, "tests/pauw1"); ++ ++&isns_finish; +diff --git a/utils/open-isns/tests/test09.pl b/utils/open-isns/tests/test09.pl +new file mode 100644 +index 0000000..bd2bd7f +--- /dev/null ++++ b/utils/open-isns/tests/test09.pl +@@ -0,0 +1,23 @@ ++#!/usr/bin/perl ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This test case validates registration and simple query of ++# single client. ++ ++push(@INC, "."); ++require "harness.pl"; ++ ++# For now, this one will run w/o security only ++push(@ARGV, '-i'); ++ ++&test_prep("test09", @ARGV); ++ ++$server = &create_server; ++$client = &create_client($server); ++ ++&isns_start_server($server); ++ ++&isns_external_test($client, "tests/pauw2"); ++ ++&isns_finish; +diff --git a/utils/open-isns/tests/test10.pl b/utils/open-isns/tests/test10.pl +new file mode 100644 +index 0000000..7286521 +--- /dev/null ++++ b/utils/open-isns/tests/test10.pl +@@ -0,0 +1,33 @@ ++#!/usr/bin/perl ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This test case validates registration and simple query of ++# single client. ++ ++push(@INC, "."); ++require "harness.pl"; ++ ++# For now, this one will run w/o security only ++push(@ARGV, '-i'); ++ ++&isns_prep_slow_test("test10", 20, @ARGV); ++ ++$server = &create_server({ "ESIMinInterval" => "10s" }); ++$client = &create_client($server); ++ ++&isns_start_server($server); ++ ++&isns_external_test($client, "tests/pauw3", "16"); ++ ++&isns_stage("expired", "Waiting for ESI to come around"); ++&isns_idle(5); ++&isns_verify_db($server); ++ ++&isns_external_test($client, "tests/pauw3", "-n", "16"); ++ ++&isns_stage("expired", "Waiting for ESI to come around"); ++&isns_idle(5); ++&isns_verify_db($server); ++ ++&isns_finish; +diff --git a/utils/open-isns/tests/test11.pl b/utils/open-isns/tests/test11.pl +new file mode 100644 +index 0000000..2745955 +--- /dev/null ++++ b/utils/open-isns/tests/test11.pl +@@ -0,0 +1,23 @@ ++#!/usr/bin/perl ++# ++# Copyright (C) 2007 Olaf Kirch ++# ++# This test case validates registration and simple query of ++# single client. ++ ++push(@INC, "."); ++require "harness.pl"; ++ ++# For now, this one will run w/o security only ++push(@ARGV, '-i'); ++ ++&test_prep("test11", @ARGV); ++ ++$server = &create_server; ++$client = &create_client($server); ++ ++&isns_start_server($server); ++ ++&isns_external_test($client, "tests/pauw4"); ++ ++&isns_finish; +diff --git a/utils/open-isns/timer.c b/utils/open-isns/timer.c +new file mode 100644 +index 0000000..ed8a23f +--- /dev/null ++++ b/utils/open-isns/timer.c +@@ -0,0 +1,126 @@ ++/* ++ * Timers (one-short and periodic) ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include "isns.h" ++#include "util.h" ++ ++typedef struct isns_timer isns_timer_t; ++struct isns_timer { ++ isns_list_t it_list; ++ time_t it_when; ++ unsigned int it_period; ++ isns_timer_callback_t * it_func; ++ void * it_data; ++}; ++ ++ ++static ISNS_LIST_DECLARE(timers); ++ ++static void ++__isns_arm_timer(isns_timer_t *tm) ++{ ++ isns_list_t *pos, *next; ++ time_t when = tm->it_when; ++ ++ isns_list_foreach(&timers, pos, next) { ++ isns_timer_t *cur = isns_list_item(isns_timer_t, it_list, pos); ++ ++ if (when < cur->it_when) ++ break; ++ } ++ isns_item_insert_before(pos, &tm->it_list); ++} ++ ++static isns_timer_t * ++__isns_create_timer(time_t when, ++ unsigned int period, ++ isns_timer_callback_t *fn, ++ void *data) ++{ ++ isns_timer_t *tm; ++ ++ tm = isns_calloc(1, sizeof(*tm)); ++ tm->it_when = when; ++ tm->it_period = period; ++ tm->it_func = fn; ++ tm->it_data = data; ++ return tm; ++} ++ ++void ++isns_add_timer(unsigned int period, ++ isns_timer_callback_t *fn, ++ void *data) ++{ ++ isns_timer_t *tm; ++ ++ isns_assert(period); ++ tm = __isns_create_timer(time(NULL) + period, period, fn, data); ++ __isns_arm_timer(tm); ++} ++ ++void ++isns_add_oneshot_timer(unsigned int expires, ++ isns_timer_callback_t *fn, ++ void *data) ++{ ++ isns_timer_t *tm; ++ ++ tm = __isns_create_timer(time(NULL) + expires, 0, fn, data); ++ __isns_arm_timer(tm); ++} ++ ++void ++isns_cancel_timer(isns_timer_callback_t *fn, void *data) ++{ ++ isns_list_t *pos, *next; ++ ++ isns_list_foreach(&timers, pos, next) { ++ isns_timer_t *tm = isns_list_item(isns_timer_t, it_list, pos); ++ ++ if (tm->it_func == fn ++ && (data == NULL || tm->it_data == data)) { ++ isns_list_del(pos); ++ isns_free(tm); ++ } ++ } ++} ++ ++time_t ++isns_run_timers(void) ++{ ++ ++ while (!isns_list_empty(&timers)) { ++ isns_timer_t *tm = isns_list_item(isns_timer_t, it_list, timers.next); ++ isns_timer_callback_t *func; ++ time_t expire; ++ void *data; ++ ++ expire = tm->it_when; ++ if (time(NULL) < expire) ++ return expire; ++ ++ isns_list_del(&tm->it_list); ++ func = tm->it_func; ++ data = tm->it_data; ++ expire = 0; ++ ++ /* If it's a periodic timer, rearm it now. This allows ++ * the timer callback to cancel the timer. */ ++ if (tm->it_period) { ++ tm->it_when = time(NULL) + tm->it_period; ++ __isns_arm_timer(tm); ++ } else { ++ isns_free(tm); ++ } ++ ++ func(data); ++ } ++ ++ return 0; ++} +diff --git a/utils/open-isns/types.h b/utils/open-isns/types.h +new file mode 100644 +index 0000000..ddd153f +--- /dev/null ++++ b/utils/open-isns/types.h +@@ -0,0 +1,57 @@ ++/* ++ * Open-iSNS types ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#ifndef ISNS_TYPES_H ++#define ISNS_TYPES_H ++ ++typedef struct isns_simple isns_simple_t; ++typedef struct isns_source isns_source_t; ++typedef struct isns_object isns_object_t; ++typedef struct isns_relation isns_relation_t; ++typedef struct isns_attr isns_attr_t; ++typedef struct isns_attr_list isns_attr_list_t; ++typedef struct isns_message isns_message_t; ++typedef struct isns_socket isns_socket_t; ++typedef struct isns_db isns_db_t; ++typedef struct isns_tag_type isns_tag_type_t; ++typedef const struct isns_object_template isns_object_template_t; ++typedef struct isns_authdata isns_authdata_t; ++typedef struct isns_security isns_security_t; ++typedef struct isns_principal isns_principal_t; ++typedef struct isns_policy isns_policy_t; ++typedef struct isns_keystore isns_keystore_t; ++typedef struct isns_scope isns_scope_t; ++typedef struct isns_portal_info isns_portal_info_t; ++typedef struct isns_server isns_server_t; ++typedef struct isns_db_event isns_db_event_t; ++typedef struct isns_bitvector isns_bitvector_t; ++ ++typedef struct isns_object_list { ++ unsigned int iol_count; ++ isns_object_t ** iol_data; ++} isns_object_list_t; ++ ++#define ISNS_OBJECT_LIST_INIT { .iol_count = 0, .iol_data = NULL } ++ ++/* ++ * An attribute list ++ */ ++struct isns_attr_list { ++ unsigned int ial_count; ++ isns_attr_t ** ial_data; ++}; ++#define ISNS_ATTR_LIST_INIT { .ial_count = 0, .ial_data = NULL } ++ ++/* ++ * Function types. ++ */ ++typedef void isns_print_fn_t(const char *, ...); ++typedef void isns_timer_callback_t(void *); ++ ++ ++#endif /* ISNS_TYPES_H */ ++ ++ +diff --git a/utils/open-isns/util.c b/utils/open-isns/util.c +new file mode 100644 +index 0000000..4c0a7b2 +--- /dev/null ++++ b/utils/open-isns/util.c +@@ -0,0 +1,263 @@ ++/* ++ * util.c ++ * ++ * Misc utility functions ++ * ++ * Copyright (C) 2006, 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "util.h" ++ ++unsigned long ++parse_size(const char *arg) ++{ ++ unsigned long mult = 1, ret; ++ char *s; ++ ++ ret = strtol(arg, &s, 0); ++ ++ switch (*s++) { ++ case 'g': ++ case 'G': ++ mult = 1024 * 1024 * 1024; ++ break; ++ case 'm': ++ case 'M': ++ mult = 1024 * 1024; ++ break; ++ case 'k': ++ case 'K': ++ mult = 1024; ++ break; ++ ++ case '\0': ++ return ret; ++ ++ default: ++ bad: ++ err(1, "parse_size: unknown unit in \"%s\"\n", arg); ++ } ++ ++ if (*s != '\0') ++ goto bad; ++ ++ return mult * ret; ++} ++ ++char * ++print_size(unsigned long size) ++{ ++ static char unit[] = "-kMG"; ++ static char buffer[64]; ++ unsigned int power = 0; ++ ++ while (size && !(size % 1024) && power < sizeof(unit)) { ++ size /= 1024; ++ power++; ++ } ++ ++ if (!power) { ++ snprintf(buffer, sizeof(buffer), "%lu", size); ++ } else { ++ snprintf(buffer, sizeof(buffer), "%lu%c", ++ size, unit[power]); ++ } ++ return buffer; ++} ++ ++unsigned int ++parse_count(const char *arg) ++{ ++ unsigned long ret; ++ char *s; ++ ++ ret = strtoul(arg, &s, 0); ++ if (*s != '\0') ++ err(1, "parse_count: unexpected character in \"%s\"\n", arg); ++ ++ return ret; ++} ++ ++int ++parse_int(const char *arg) ++{ ++ long ret; ++ char *s; ++ ++ ret = strtol(arg, &s, 0); ++ if (*s != '\0') ++ err(1, "parse_count: unexpected character in \"%s\"\n", arg); ++ ++ return ret; ++} ++ ++long long ++parse_longlong(const char *arg) ++{ ++ long long ret; ++ char *s; ++ ++ ret = strtoll(arg, &s, 0); ++ if (*s != '\0') ++ err(1, "parse_count: unexpected character in \"%s\"\n", arg); ++ ++ return ret; ++} ++ ++double ++parse_double(const char *arg) ++{ ++ double ret; ++ char *s; ++ ++ ret = strtod(arg, &s); ++ if (*s != '\0') ++ err(1, "parse_count: unexpected character in \"%s\"\n", arg); ++ ++ return ret; ++} ++ ++unsigned int ++parse_timeout(const char *arg) ++{ ++ unsigned int v, ret = 0; ++ char *s; ++ ++ do { ++ v = strtoul(arg, &s, 10); ++ switch (*s) { ++ case '\0': ++ ret += v; ++ break; ++ case 'd': ++ v *= 24; ++ case 'h': ++ v *= 60; ++ case 'm': ++ v *= 60; ++ case 's': ++ ret += v; ++ ++s; ++ break; ++ ++ default: ++ errx(1, "parse_timeout: unexpected character in \"%s\"\n", ++ arg); ++ } ++ ++ arg = s; ++ } while (*arg); ++ ++ return ret; ++} ++ ++void ++isns_string_array_append(struct string_array *array, const char *val) ++{ ++ if (!(array->count % 32)) { ++ array->list = isns_realloc(array->list, ++ (array->count + 32) * sizeof(val)); ++ } ++ array->list[array->count++] = val? isns_strdup(val) : NULL; ++} ++ ++void ++isns_string_array_destroy(struct string_array *array) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < array->count; ++i) ++ isns_free(array->list[i]); ++ isns_free(array->list); ++ memset(array, 0, sizeof(*array)); ++} ++ ++void ++isns_assign_string(char **var, const char *val) ++{ ++ char *s = NULL; ++ ++ if (val && !(s = isns_strdup(val))) ++ errx(1, "out of memory"); ++ ++ if (*var) ++ isns_free(*var); ++ *var = s; ++} ++ ++/* ++ * Recursively create a directory ++ */ ++int ++isns_mkdir_recursive(const char *pathname) ++{ ++ const char *orig_pathname = pathname; ++ char *squirrel[64]; ++ char *copy = NULL, *s; ++ int ns = 0; ++ ++ if (!pathname || !strcmp(pathname, ".")) ++ return 0; ++ while (1) { ++ if (mkdir(pathname, 0755) >= 0) { ++ if (ns == 0) ++ break; ++ *squirrel[--ns] = '/'; ++ continue; ++ } ++ ++ if (errno == EEXIST) ++ goto good; ++ if (errno != ENOENT) ++ goto bad; ++ ++ if (copy == NULL) { ++ copy = isns_strdup(pathname); ++ pathname = copy; ++ } ++ ++ s = strrchr(copy, '/'); ++ while (s > copy && s[-1] == '/') ++ --s; ++ *s = '\0'; ++ ++ isns_assert(ns < 64); ++ squirrel[ns++] = s; ++ ++ if (s == copy) ++ goto bad; ++ } ++ ++good: if (copy) ++ isns_free(copy); ++ errno = 0; ++ return 0; ++ ++bad: if (copy) ++ isns_free(copy); ++ perror(orig_pathname); ++ return -1; ++} ++ ++/* ++ * This one differs from POSIX dirname; it does not ++ * modify its argument ++ */ ++const char * ++isns_dirname(const char *pathname) ++{ ++ static char buffer[4096]; ++ char *s; ++ ++ strcpy(buffer, pathname); ++ if ((s = strrchr(buffer, '/')) != NULL) { ++ *s = '\0'; ++ return buffer; ++ } ++ return "."; ++} +diff --git a/utils/open-isns/util.h b/utils/open-isns/util.h +new file mode 100644 +index 0000000..deecb24 +--- /dev/null ++++ b/utils/open-isns/util.h +@@ -0,0 +1,289 @@ ++/* ++ * Utility functions ++ * ++ * Copyright (C) 2006, 2007 Olaf Kirch ++ */ ++ ++#ifndef UTIL_H ++#define UTIL_H ++ ++#include ++#include ++#include ++#include ++#include ++#include // for strdup ++#include "types.h" ++ ++#define array_num_elements(a) (sizeof(a) / sizeof((a)[0])) ++ ++const char * isns_dirname(const char *); ++int isns_mkdir_recursive(const char *); ++ ++extern const char *parser_separators; ++char * parser_get_next_line(FILE *); ++char * parser_get_next_word(char **); ++char * parser_get_rest_of_line(char **); ++int parser_split_line(char *, unsigned int, char **); ++ ++unsigned long parse_size(const char *); ++unsigned int parse_count(const char *); ++int parse_int(const char *); ++long long parse_longlong(const char *); ++double parse_double(const char *); ++unsigned int parse_timeout(const char *); ++ ++char * print_size(unsigned long); ++ ++/* ++ * Very simple and stupid string array. ++ */ ++struct string_array { ++ unsigned int count; ++ char ** list; ++}; ++ ++void isns_string_array_append(struct string_array *, const char *); ++void isns_string_array_destroy(struct string_array *); ++ ++void isns_assign_string(char **, const char *); ++ ++void isns_write_pidfile(const char *); ++void isns_update_pidfile(const char *); ++void isns_remove_pidfile(const char *); ++ ++extern void isns_log_background(void); ++extern void isns_assert_failed(const char *, ++ const char *, unsigned int); ++extern void isns_fatal(const char *, ...); ++extern void isns_warning(const char *, ...); ++extern void isns_error(const char *, ...); ++extern void isns_notice(const char *, ...); ++extern void isns_debug_general(const char *, ...); ++extern void isns_debug_socket(const char *, ...); ++extern void isns_debug_protocol(const char *, ...); ++extern void isns_debug_message(const char *, ...); ++extern void isns_debug_state(const char *, ...); ++extern void isns_debug_auth(const char *, ...); ++extern void isns_debug_scn(const char *, ...); ++extern void isns_debug_esi(const char *, ...); ++extern void isns_enable_debugging(const char *); ++extern int isns_debug_enabled(int); ++ ++enum { ++ DBG_GENERAL = 0, ++ DBG_SOCKET, ++ DBG_PROTOCOL, ++ DBG_MESSAGE, ++ DBG_STATE, ++ DBG_AUTH, ++ DBG_SCN, ++ DBG_ESI, ++}; ++ ++/* ++ * There's no htonll yet ++ */ ++#ifndef htonll ++# include ++# include ++# if __BYTE_ORDER == __BIG_ENDIAN ++# define htonll(x) (x) ++# define ntohll(x) (x) ++# elif __BYTE_ORDER == __LITTLE_ENDIAN ++# define htonll(x) __bswap_64(x) ++# define ntohll(x) __bswap_64(x) ++# endif ++#endif ++ ++/* ++ * One of the those eternal staples of C coding: ++ */ ++#ifndef MIN ++# define MIN(a, b) ((a) < (b)? (a) : (b)) ++# define MAX(a, b) ((a) > (b)? (a) : (b)) ++#endif ++ ++#define DECLARE_BITMAP(name, NBITS) \ ++ uint32_t name[(NBITS+31) >> 5] = { 0 } ++ ++#define __BIT_INDEX(nr) (nr >> 5) ++#define __BIT_MASK(nr) (1 << (nr & 31)) ++ ++static inline void ++set_bit(uint32_t *map, unsigned int nr) ++{ ++ map[__BIT_INDEX(nr)] |= __BIT_MASK(nr); ++} ++ ++static inline void ++clear_bit(uint32_t *map, unsigned int nr) ++{ ++ map[__BIT_INDEX(nr)] &= ~__BIT_MASK(nr); ++} ++ ++static inline int ++test_bit(const uint32_t *map, unsigned int nr) ++{ ++ return !!(map[__BIT_INDEX(nr)] & __BIT_MASK(nr)); ++} ++ ++/* ++ * Dynamically sized bit vector ++ */ ++extern isns_bitvector_t *isns_bitvector_alloc(void); ++extern void isns_bitvector_init(isns_bitvector_t *); ++extern void isns_bitvector_destroy(isns_bitvector_t *); ++extern void isns_bitvector_free(isns_bitvector_t *); ++extern int isns_bitvector_test_bit(const isns_bitvector_t *, unsigned int); ++extern int isns_bitvector_set_bit(isns_bitvector_t *, unsigned int); ++extern int isns_bitvector_clear_bit(isns_bitvector_t *, unsigned int); ++extern int isns_bitvector_is_empty(const isns_bitvector_t *); ++extern int isns_bitvector_intersect(const isns_bitvector_t *a, ++ const isns_bitvector_t *b, ++ isns_bitvector_t *result); ++extern void isns_bitvector_print(const isns_bitvector_t *, ++ isns_print_fn_t *); ++extern void isns_bitvector_foreach(const isns_bitvector_t *bv, ++ int (*cb)(uint32_t, void *), ++ void *user_data); ++ ++/* ++ * List manipulation primites ++ */ ++typedef struct isns_list isns_list_t; ++struct isns_list { ++ isns_list_t * next; ++ isns_list_t * prev; ++}; ++ ++#define ISNS_LIST_DECLARE(list) \ ++ isns_list_t list = { &list, &list } ++ ++static inline void ++isns_list_init(isns_list_t *head) ++{ ++ head->next = head->prev = head; ++} ++ ++static inline void ++__isns_list_insert(isns_list_t *prev, isns_list_t *item, isns_list_t *next) ++{ ++ item->next = next; ++ item->prev = prev; ++ next->prev = item; ++ prev->next = item; ++} ++ ++static inline void ++isns_list_append(isns_list_t *head, isns_list_t *item) ++{ ++ __isns_list_insert(head->prev, item, head); ++} ++ ++static inline void ++isns_list_insert(isns_list_t *head, isns_list_t *item) ++{ ++ __isns_list_insert(head, item, head->next); ++} ++ ++static inline void ++isns_item_insert_before(isns_list_t *where, isns_list_t *item) ++{ ++ __isns_list_insert(where->prev, item, where); ++} ++ ++static inline void ++isns_item_insert_after(isns_list_t *where, isns_list_t *item) ++{ ++ __isns_list_insert(where, item, where->next); ++} ++ ++static inline void ++isns_list_del(isns_list_t *item) ++{ ++ isns_list_t *prev = item->prev; ++ isns_list_t *next = item->next; ++ ++ prev->next = next; ++ next->prev = prev; ++ item->next = item->prev = item; ++} ++ ++static inline int ++isns_list_empty(const isns_list_t *head) ++{ ++ return head == head->next; ++} ++ ++static inline void ++isns_list_move(isns_list_t *dst, isns_list_t *src) ++{ ++ isns_list_t *prev, *next; ++ isns_list_t *head, *tail; ++ ++ if (isns_list_empty(src)) ++ return; ++ ++ prev = dst->prev; ++ next = dst; ++ ++ head = src->next; ++ tail = src->prev; ++ ++ next->prev = tail; ++ prev->next = head; ++ head->prev = prev; ++ tail->next = next; ++ ++ src->next = src->prev = src; ++} ++ ++#define isns_list_item(type, member, ptr) \ ++ container_of(type, member, ptr) ++ ++#define isns_list_foreach(list, __pos, __next) \ ++ for (__pos = (list)->next; \ ++ (__pos != list) && (__next = __pos->next, 1); \ ++ __pos = __next) ++ ++#if 0 ++/* This is defined in stddef */ ++#define offsetof(type, member) ((unsigned long) &(((type *) 0)->member)) ++#endif ++#define container_of(type, member, ptr) \ ++ ((type *) (((unsigned char *) ptr) - offsetof(type, member))) ++ ++/* ++ * Use isns_assert instead of libc's assert, so that the ++ * message can be captured and sent to syslog. ++ */ ++#define isns_assert(condition) do { \ ++ if (!(condition)) \ ++ isns_assert_failed(#condition, \ ++ __FILE__, __LINE__); \ ++} while (0) ++ ++#ifndef MDEBUG ++# define isns_malloc(size) malloc(size) ++# define isns_calloc(n, size) calloc(n, size) ++# define isns_realloc(p, size) realloc(p, size) ++# define isns_strdup(s) strdup(s) ++# define isns_free(p) free(p) ++#else ++# define isns_malloc(size) isns_malloc_fn(size, __FILE__, __LINE__) ++# define isns_calloc(n, size) isns_calloc_fn(n, size, __FILE__, __LINE__) ++# define isns_realloc(p, size) isns_realloc_fn(p, size, __FILE__, __LINE__) ++# define isns_strdup(s) isns_strdup_fn(s, __FILE__, __LINE__) ++# define isns_free(p) isns_free_fn(p, __FILE__, __LINE__) ++ ++extern void * (*isns_malloc_fn)(size_t, const char *, unsigned int); ++extern void * (*isns_calloc_fn)(unsigned int, size_t, ++ const char *, unsigned int); ++extern void * (*isns_realloc_fn)(void *, size_t, ++ const char *, unsigned int); ++extern char * (*isns_strdup_fn)(const char *, const char *, unsigned int); ++extern void (*isns_free_fn)(void *, const char *, unsigned int); ++#endif ++ ++#endif /* UTIL_H */ +diff --git a/utils/open-isns/vendor.c b/utils/open-isns/vendor.c +new file mode 100644 +index 0000000..e24164d +--- /dev/null ++++ b/utils/open-isns/vendor.c +@@ -0,0 +1,41 @@ ++/* ++ * iSNS vendor specific objects ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#include ++#include ++#include "isns.h" ++#include "objects.h" ++#include "attrs.h" ++#include "vendor.h" ++#include "util.h" ++ ++static uint32_t policy_attrs[] = { ++ OPENISNS_TAG_POLICY_SPI, ++ OPENISNS_TAG_POLICY_KEY, ++ OPENISNS_TAG_POLICY_ENTITY, ++ OPENISNS_TAG_POLICY_OBJECT_TYPE, ++ OPENISNS_TAG_POLICY_NODE_NAME, ++ OPENISNS_TAG_POLICY_NODE_TYPE, ++ OPENISNS_TAG_POLICY_FUNCTIONS, ++ OPENISNS_TAG_POLICY_VISIBLE_DD, ++ OPENISNS_TAG_POLICY_DEFAULT_DD, ++}; ++ ++static uint32_t policy_key_attrs[] = { ++ OPENISNS_TAG_POLICY_SPI, ++}; ++ ++isns_object_template_t isns_policy_template = { ++ .iot_name = "Policy", ++ .iot_handle = ISNS_OBJECT_TYPE_POLICY, ++ .iot_attrs = policy_attrs, ++ .iot_num_attrs = array_num_elements(policy_attrs), ++ .iot_keys = policy_key_attrs, ++ .iot_num_keys = array_num_elements(policy_key_attrs), ++ .iot_container = &isns_entity_template, ++ .iot_vendor_specific = 1, ++}; ++ +diff --git a/utils/open-isns/vendor.h b/utils/open-isns/vendor.h +new file mode 100644 +index 0000000..49c6132 +--- /dev/null ++++ b/utils/open-isns/vendor.h +@@ -0,0 +1,56 @@ ++/* ++ * iSNS "vendor-specific" protocol definitions ++ * ++ * Copyright (C) 2007 Olaf Kirch ++ */ ++ ++#ifndef ISNS_VENDOR_H ++#define ISNS_VENDOR_H ++ ++#include "isns-proto.h" ++ ++/* ++ * We're poor, we don't own a OUI. Let's fake one. ++ */ ++#define OPENISNS_VENDOR_OUI 0xFFFF00 ++#define OPENISNS_VENDOR_PREFIX (OPENISNS_VENDOR_OUI << 8) ++#define OPENISNS_IS_PRIVATE_ATTR(tag) (((tag) >> 16) == 0xFFFF) ++ ++enum openisns_vendor_tag { ++ /* Security Policy Identifier */ ++ OPENISNS_TAG_POLICY_SPI = OPENISNS_VENDOR_PREFIX + ISNS_VENDOR_SPECIFIC_OTHER_BASE, ++ ++ __OPENISNS_TAG_POLICY_RESERVED, ++ ++ /* DSA signature key (public) */ ++ OPENISNS_TAG_POLICY_KEY, ++ ++ /* Entity name to use */ ++ OPENISNS_TAG_POLICY_ENTITY, ++ ++ /* Functions the client is permitted to invoke */ ++ OPENISNS_TAG_POLICY_FUNCTIONS, ++ ++ /* Object types the client is permitted to see. */ ++ OPENISNS_TAG_POLICY_OBJECT_TYPE, ++ ++ /* iSCSI node name the client is permitted to register. ++ * This attribute may occur multiple times. ++ * If absent, it defaults to POLICY_SOURCE_NAME ++ */ ++ OPENISNS_TAG_POLICY_NODE_NAME, ++ ++ /* Node type bitmap the client is permitted to register */ ++ OPENISNS_TAG_POLICY_NODE_TYPE, ++ ++ /* Default discovery domain the client will be ++ * placed in. ++ * Not used yet. ++ */ ++ OPENISNS_TAG_POLICY_DEFAULT_DD, ++ OPENISNS_TAG_POLICY_VISIBLE_DD, ++}; ++ ++extern const struct isns_object_template isns_policy_template; ++ ++#endif /* ISNS_VENDOR_H */ +-- +2.5.5 + diff --git a/SOURCES/open-iscsi-0001-sync-from-2.0.873.patch b/SOURCES/open-iscsi-0001-sync-from-2.0.873.patch new file mode 100644 index 00000000..05842026 --- /dev/null +++ b/SOURCES/open-iscsi-0001-sync-from-2.0.873.patch @@ -0,0 +1,87156 @@ +From f007a4b35f93a0d59cfed29bfb1e660f7992ac6e Mon Sep 17 00:00:00 2001 +From: Mike Christie +Date: Wed, 5 Sep 2012 16:18:16 -0500 +Subject: [PATCH v2 1/9] sync from 2.0.873 + +4c1f2d9 make use of all 24 bits of ISID qualifier space +0fa43f2 iscsiuio: fixup race condition +1f5e791 iscsiuio: Clear memory after allocation +c1642b9 iscsiuio: Do not memcpy identical locations +5fef431 iscsiuio: Get the library to use based on uio sysfs name +a6ef73a iscsiuio: Wait for iface to be ready before issuing the ping +1592a52 iscsiadm: let ping be tried after iface config is initialized +1e692d5 iscsiuio: Add ping support through iscsiuio +74478b0 iscsid: Changes to support ping through iscsiuio +be1c610 iscsiuio: Add QLogic Vendor ID to support newer NX2 HBAs +4c9d6f9 iscsid: fix iscsi_host_set_net_params return code +c1bb0b2 iscsid/iscsiuio: remove uio poll +cefea9d iscsid: make sure actor is delated before rescheduling +c6d1117 iscsi: remove local copy of open-isns +7683266 Use system-wide open-isns, not internal version. +1dfb88a Merge pull request #9 from xypron/kernel_source_path +a777841 Merge pull request #8 from dscunkel/master +779b31f Merge pull request #11 from deepankar/master +c21542d fix typo +254ad46 iscsiuio: Correct the handling of Multi Function mode +6aa2c9b Reformat man page synopsis sections +df602f0 Spelling and escaping error fixes. +312e904 Remove outdated Debian packaging code. +da2473d buildsys: respect CFLAGS and LDFLAGS from the outside +4a4498b buildsys: make 'make clean' idempotent +3d04497 Fix small typo in iscsid.conf +8da14e6 Fix iBFT target flags check. +a277d31 Remove duplicate newlines in log messages. +006270c iscsid: don't re-read config file for every session logout +63d086c iscsid safe session logout +c02b558 Add some more debug logging to actor.c +9297a47 Prevent spinning over poll() when reconnecting to an inaccessible target +def3161 Fix incorrect list operation leading to out-of-order items on pend_list +d0f380b Kernel include path +32e2349 iscsiuio systemd socket activation support +40616d1 iscsiuio CFLAGS fixes +bc9b5c3 iscsid: fix order of setting uid/gid and drop supplementary groups +7acba59 add discovery as a valid mode in iscsiadm.8 +c7fbcd7 guard against NULL ptr during discovery from unexpected event +892ddaf Allow setting host params to return EAGAIN errors. +51c0b6e Supply strings for newly-added error numbers +2966a92 fix regression in iscsi_tcp iface binding +052fa50 Wake up to reap children +6385e2d Make running actors event-driven +9981b06 Remove actor_init and rename actor_new to actor_init +4b5c01e actor: Simplify actor_poll a little +4190b2d actor: Unobfuscate ACTOR_MAX_LOOPS +86b919e actor: Remove ACTOR_TICKS_10MS() +5e7f696 actor: s/ACTOR_TICKS/actor_jiffies/ +22c5038 actor: simplify actor_check +6c14016 actor: Mark actor_check static +b8bb7ba Allow modifications for iface.gateway and iface.subnet_mask +defd640 fwparam_ibft: Check iBFT target and NIC flags +4959a89 Represent DHCP "origin" as an enum, not a string. +a125761 Code cleanup: no functional changes +0fbf555 iscsiuio: Check return value from nic_queue_tx_packet +957ce0b iscsiuio: Remove set but unused variables +366f2f8 iscsiuio: Change nic_disable to return void +0a253d7 iscsiuio: Use attribute(unused) for *icmpv6_hdr +e2c9c58 iscsiuio: Use attribute(unused) for variables that are unused but needed +cd3d245 iscsiuio: Fix aliasing issue with IPV6_IS_ADDR_UNSPECIFIED +f7d4c02 iscsiuio: Resolve strict aliasing issue in iscsiuio/src/unix/nic.c +d58864c iscsiuio: Fix strict-aliasing warning with struct mac_address +769b480 iscsiuio: Fix warning about non-matching types +6f6f2a0 Fix missing header +e253c9a Fix bad sizeof in memset +9c5be24 Fix warning about possibly-uninitialized variable +06309ad Fix build warnings for unused variables +f6d7d30 iscsid: don't round up when modifying padding len +3654c93 Fix typo in man page. +76a441b Added new util script to aid in CNA setup +147db3c Added new utility script to generate initiator name +c9d830b isns: Add docs for deregistering discovery domains. +78e24f5 Parse 'origin' value from iBFT +21a7923 Remove unused variable 'path' +96eaaac iscsiadm : make iface.ipaddress optional in iface configs for transports that don't have a hard requirement on it. +33cb16e iscsiuio: Rebranding iscsiuio +5762ac0 iscsiadm: Initialize param_count in set_host_chap_info +134f8dc iscsid: Fix double close of mgmt ipc fd +c0e509e iscsid: retry login for ISCSI_ERR_HOST_NOT_FOUND +e696b94 Fix StatSN in Open-iSCSI Stack. +5f28b8b be2iscsi: Fix MaxXmitDataLenght of the driver. +36a8b41 iscsid: Fix handling of iscsi async events. +fabe160 ISCSIUIO: Fixed a pthread resc leak from excessive session recovery +b152630 iscsiadm: Fix the compile time warning +f2ecc22 iscsiadm: Fix the hostno check for stats submode of host mode +ea05be3 iscsi tools: set non negotiated params early. +9ef01a7 Add missing DESTDIR +a877c9d iscsiuio: fix compilation +c8113ad iscsiuio: Add .gitignore files +91cc9c3 iscsiuio: Update automake files +2b4a011 iscsiuio: Remove autogenerated files from tracking +5f2f3d7 ISCSIUIO: Removed the auto-generated COPYING file +bd91b81 Man page correction for host mode options of iscsiadm +505ed9d iscsi tools: Fix the iscsiadm help options for host mode +9bd6fba ISCSIUIO: Updated the configure file to reflect the new version +eb1d275 ISCSIUIO: Updated RELEASE note and version +817a083 ISCSIUIO: Added fix for the ARP cache flush mechanism +df68365 ISCSIUIO: Added fix for the iface.subnet_mask decoding for IPv6 +77245b9 ISCSIUIO: Added tx doorbell override mechanism +4a3076b iscsiadm.8: Updated man page for host statistics. +d1e8e68 README: Updated for host statistics. +fe66238 iscsi_tool: Add offload host statistics support. +072d8b9 iscsiadm: Added document for description of iface attributes +4a5e9e2 iscsi tools: Show iface params based on iface type +75ee9d0 iscsi tools: Let default type of iface be ipv4 +9260457 iscsi tools: iface params should be updated for node_rec as well. +66d9f12 iscsi tools: Additional parameters for network settings +da404f2 iscsi tools: Ignore network parameter if not enabled/disabled +d8991c9 iscsi tools: Use single function to set integer network parameters +2220ee4 iscsi tools: Use single function to enable/disable network parameters +466efaa iscsi tools: Use macro to set IPv4/IPv6 IP addresses +d1e07af iscsi_if.h: Additional parameters for network param settings +026c8d7 iscsi_if.h: Remove numbers used for network parameter settings +0a95bc4 iscsi tools: Setup iface conf file with all iface attrs exported in sysfs +f1ed1f7 README changes for adding support to set CHAP entry +65ce3a2 iscsi tools: Correctly get username_in and password_in flashnode params +062718a iscsiadm: Add support to set CHAP entry using host chap mode +38b2993 README changes to use long option --index instead of --flashnode_idx +0c4022d iscsiadm: Man page changes to use -x option for chap_tbl_idx +b3913c5 iscsiadm: Use '-x' option instead of '-v' to specify chap_tbl_idx +360a40f flashnode: Add support to set ISCSI_FLASHNODE_CHAP_OUT_IDX param +1fa1b51 iscsi tools: Bug fix on IPC address copy (version 2) +3b4b450 ISCSID: Added iface content override fix +487c312 ISCSID: Added the extraction of the session boot info +5992173 [PATCH v5 1/3] ISCSISTART: Saved ibft boot info to the session +82c8533 iscsi tools: sync iscsi_if.h with kernel space +181af9a iscsi tools: Print additional session info for flashnode session +3256b93 iscsiadm: Correctly check for invalid hostno and flashnode index +bf39941 [PATCH] Make rescan run in parallel +3d7df63 iscsiuio: Change socket bind to use the same struct size as iscsid +b0ba4d6 iscsid: Fix strlen parameter +d9e26d3 Fix discovery error return without return value +9a2bc38 ISCSIUIO: Updated iscsiuio to version 0.7.8.1b for perf optimization +83d31c7 iscsid/iscsiadm: add support for emulex one connect storage +ff4b2c1 iscsiadm: Check for mode is not required when creating params list +8b33814 iscsiadm: bind ifaces to portals found using isns +fc2a8e9 iscsiadm: return error when login fails +6674fd4 Allow firmware mode to use debug flag +fdac390 PATCH 1 of 1] correctly check return value of nice() +3584b98 README changes for flashnode submode support for host mode. +d64f50d Manpage changes for flashnode submode support for host mode. +42fa258 From: Adheer Chandravanshi +fcab9b7 ISCSID: Added iscsiuio source to the open-iscsi pkg +b255332 ISCSID: Modified the Makefile for iscsiuio compilation +d571cdf ISCSID: Added socket communication hooks for uip +a7afdf4 iscsi tools: fix get_random_bytes error handling +c34e0bd iscsid: add example unit files for systemd +5d0e19f iscsid: implement systemd-compatible socket activation +2d086a8 iscsid,iscsiadm: fix abstract socket length in bind() call +97db3db Update README for removal of DBM requirement +9dd181d iscsi tools: Convert '-r' argument to an integer before checking if it is a path +13d08e7 ISCSID: Passing more net params from ibft to iface +d81fd49 iscsi tools: fix compile error when OFFLOAD_BOOT_SUPPORT defined +f0a8c95 ISCSISTART: Bring up the corresponding network interface for iboot +71cd021 iscsid: fix iscsid segfault during qla4xxx login +--- + Makefile | 37 +- + README | 158 +- + debian/README.Debian | 44 - + debian/changelog | 6 - + debian/compat | 1 - + debian/control | 27 - + debian/control.modules.in | 20 - + debian/copyright | 12 - + debian/dirs | 3 - + debian/docs | 4 - + debian/postinst.modules.in | 11 - + debian/rules | 152 - + debian/rules.modules | 39 - + doc/iscsi_discovery.8 | 12 +- + doc/iscsiadm.8 | 212 +- + etc/iscsid.conf | 5 +- + etc/systemd/iscsid.service | 13 + + etc/systemd/iscsid.socket | 9 + + include/fw_context.h | 15 + + include/iscsi_err.h | 4 + + include/iscsi_if.h | 468 +- + include/iscsi_proto.h | 1 + + include/list.h | 6 + + iscsiuio/.gitignore | 25 + + iscsiuio/AUTHORS | 0 + iscsiuio/ChangeLog | 7 + + iscsiuio/INSTALL | 290 + + iscsiuio/Makefile.am | 25 + + iscsiuio/NEWS | 0 + iscsiuio/README | 224 + + iscsiuio/RELEASE.TXT | 2032 ++++++ + iscsiuio/configure.ac | 78 + + iscsiuio/docs/iscsiuio.8 | 89 + + iscsiuio/iscsiuiolog | 10 + + iscsiuio/src/Makefile.am | 1 + + iscsiuio/src/README | 13 + + iscsiuio/src/apps/Makefile.am | 1 + + iscsiuio/src/apps/README | 2 + + iscsiuio/src/apps/brcm-iscsi/Makefile.am | 13 + + iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi | 1 + + iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c | 89 + + iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h | 91 + + iscsiuio/src/apps/dhcpc/Makefile.am | 13 + + iscsiuio/src/apps/dhcpc/Makefile.dhcpc | 1 + + iscsiuio/src/apps/dhcpc/dhcpc.c | 417 ++ + iscsiuio/src/apps/dhcpc/dhcpc.h | 86 + + iscsiuio/src/apps/dhcpc/dhcpv6.c | 512 ++ + iscsiuio/src/apps/dhcpc/dhcpv6.h | 253 + + iscsiuio/src/uip-1.0-changelog.txt | 98 + + iscsiuio/src/uip/Makefile.am | 18 + + iscsiuio/src/uip/Makefile.include | 47 + + iscsiuio/src/uip/clock.h | 87 + + iscsiuio/src/uip/debug.h | 13 + + iscsiuio/src/uip/icmpv6.h | 302 + + iscsiuio/src/uip/ipv6.c | 1306 ++++ + iscsiuio/src/uip/ipv6.h | 332 + + iscsiuio/src/uip/ipv6_ndpc.c | 427 ++ + iscsiuio/src/uip/ipv6_ndpc.h | 98 + + iscsiuio/src/uip/ipv6_pkt.h | 50 + + iscsiuio/src/uip/lc-addrlabels.h | 80 + + iscsiuio/src/uip/lc-switch.h | 73 + + iscsiuio/src/uip/lc.h | 130 + + iscsiuio/src/uip/psock.c | 339 + + iscsiuio/src/uip/psock.h | 383 ++ + iscsiuio/src/uip/pt.h | 322 + + iscsiuio/src/uip/timer.c | 127 + + iscsiuio/src/uip/timer.h | 84 + + iscsiuio/src/uip/uip-neighbor.c | 219 + + iscsiuio/src/uip/uip-neighbor.h | 105 + + iscsiuio/src/uip/uip.c | 2416 +++++++ + iscsiuio/src/uip/uip.h | 1574 +++++ + iscsiuio/src/uip/uip_arch.h | 137 + + iscsiuio/src/uip/uip_arp.c | 479 ++ + iscsiuio/src/uip/uip_arp.h | 197 + + iscsiuio/src/uip/uip_eth.c | 50 + + iscsiuio/src/uip/uip_eth.h | 43 + + iscsiuio/src/uip/uipopt.h | 536 ++ + iscsiuio/src/unix/.gitignore | 2 + + iscsiuio/src/unix/Makefile.am | 40 + + iscsiuio/src/unix/clock-arch.c | 54 + + iscsiuio/src/unix/clock-arch.h | 39 + + iscsiuio/src/unix/iscsid_ipc.c | 1210 ++++ + iscsiuio/src/unix/iscsid_ipc.h | 52 + + iscsiuio/src/unix/libs/Makefile.am | 13 + + iscsiuio/src/unix/libs/bnx2.c | 1165 ++++ + iscsiuio/src/unix/libs/bnx2.h | 304 + + iscsiuio/src/unix/libs/bnx2x.c | 1653 +++++ + iscsiuio/src/unix/libs/bnx2x.h | 712 +++ + iscsiuio/src/unix/libs/cnic.c | 666 ++ + iscsiuio/src/unix/libs/cnic.h | 55 + + iscsiuio/src/unix/logger.c | 181 + + iscsiuio/src/unix/logger.h | 129 + + iscsiuio/src/unix/main.c | 399 ++ + iscsiuio/src/unix/nic.c | 1545 +++++ + iscsiuio/src/unix/nic.h | 406 ++ + iscsiuio/src/unix/nic_id.c | 364 ++ + iscsiuio/src/unix/nic_id.h | 47 + + iscsiuio/src/unix/nic_nl.c | 678 ++ + iscsiuio/src/unix/nic_nl.h | 54 + + iscsiuio/src/unix/nic_utils.c | 1661 +++++ + iscsiuio/src/unix/nic_utils.h | 102 + + iscsiuio/src/unix/nic_vlan.c | 337 + + iscsiuio/src/unix/nic_vlan.h | 89 + + iscsiuio/src/unix/options.h | 117 + + iscsiuio/src/unix/packet.c | 145 + + iscsiuio/src/unix/packet.h | 76 + + iscsiuio/src/unix/ping.c | 518 ++ + iscsiuio/src/unix/ping.h | 73 + + iscsiuio/src/unix/uip-conf.h | 160 + + sysfs-documentation | 514 ++ + usr/Makefile | 14 +- + usr/actor.c | 325 +- + usr/actor.h | 15 +- + usr/auth.c | 22 +- + usr/be2iscsi.c | 5 - + usr/config.h | 53 +- + usr/discovery.c | 66 +- + usr/discoveryd.c | 18 +- + usr/event_poll.c | 60 +- + usr/flashnode.c | 615 ++ + usr/flashnode.h | 129 + + usr/host.c | 112 +- + usr/host.h | 4 + + usr/idbm.c | 505 +- + usr/idbm.h | 8 + + usr/idbm_fields.h | 112 + + usr/iface.c | 1275 +++- + usr/initiator.c | 498 +- + usr/initiator.h | 5 + + usr/initiator_common.c | 212 +- + usr/io.c | 10 +- + usr/iscsi_err.c | 2 + + usr/iscsi_ipc.h | 19 + + usr/iscsi_net_util.c | 14 +- + usr/iscsi_sysfs.c | 590 +- + usr/iscsi_sysfs.h | 20 +- + usr/iscsi_util.c | 23 +- + usr/iscsi_util.h | 3 + + usr/iscsiadm.c | 1107 +++- + usr/iscsid.c | 47 +- + usr/iscsid.h | 1 + + usr/iscsid_req.c | 125 +- + usr/iscsid_req.h | 3 + + usr/iscsistart.c | 13 +- + usr/login.c | 12 +- + usr/md5.c | 2 +- + usr/mgmt_ipc.c | 40 +- + usr/mgmt_ipc.h | 1 + + usr/netlink.c | 275 +- + usr/session_info.c | 28 +- + usr/session_mgmt.c | 13 +- + usr/strings.c | 2 +- + usr/sysfs.c | 106 +- + usr/sysfs.h | 4 + + usr/transport.c | 32 +- + usr/transport.h | 14 + + usr/types.h | 1 + + usr/uip_mgmt_ipc.c | 78 + + usr/uip_mgmt_ipc.h | 86 + + utils/Makefile | 5 +- + utils/fwparam_ibft/Makefile | 4 +- + utils/fwparam_ibft/fw_entry.c | 17 +- + utils/fwparam_ibft/fwparam_ibft_sysfs.c | 2 + + utils/fwparam_ibft/fwparam_sysfs.c | 37 +- + utils/iscsi-gen-initiatorname | 73 + + utils/iscsi_offload | 378 ++ + utils/md5.c | 2 +- + utils/open-isns/COPYING | 504 -- + utils/open-isns/ChangeLog | 50 - + utils/open-isns/HACKING | 30 - + utils/open-isns/Makefile.in | 81 - + utils/open-isns/README | 173 - + utils/open-isns/TODO | 100 - + utils/open-isns/aclocal/config.guess | 1499 ----- + utils/open-isns/aclocal/config.sub | 1570 ----- + utils/open-isns/aclocal/install-sh | 251 - + utils/open-isns/attrs.c | 1618 ----- + utils/open-isns/attrs.h | 262 - + utils/open-isns/authblock.c | 62 - + utils/open-isns/bitvector.c | 651 -- + utils/open-isns/buffer.c | 407 -- + utils/open-isns/buffer.h | 141 - + utils/open-isns/callback.c | 148 - + utils/open-isns/client.c | 205 - + utils/open-isns/compat/my_getopt.c | 271 - + utils/open-isns/compat/my_getopt.h | 69 - + utils/open-isns/config.c | 278 - + utils/open-isns/config.h.in | 103 - + utils/open-isns/configure | 6727 -------------------- + utils/open-isns/configure.ac | 118 - + utils/open-isns/db-file.c | 615 -- + utils/open-isns/db-policy.c | 187 - + utils/open-isns/db.c | 994 --- + utils/open-isns/db.h | 147 - + utils/open-isns/dd.c | 1307 ---- + utils/open-isns/deregister.c | 271 - + utils/open-isns/doc/isns_config.5 | 387 -- + utils/open-isns/doc/isnsadm.8 | 672 -- + utils/open-isns/doc/isnsd.8 | 93 - + utils/open-isns/doc/isnsdd.8 | 75 - + utils/open-isns/domain.c | 208 - + utils/open-isns/entity.c | 127 - + utils/open-isns/error.c | 65 - + utils/open-isns/esi.c | 576 -- + utils/open-isns/etc/isnsadm.conf | 73 - + utils/open-isns/etc/isnsd.conf | 129 - + utils/open-isns/etc/isnsdd.conf | 72 - + utils/open-isns/etc/openisns.init | 71 - + utils/open-isns/export.c | 547 -- + utils/open-isns/getnext.c | 257 - + utils/open-isns/internal.h | 16 - + utils/open-isns/isns-proto.h | 259 - + utils/open-isns/isns.h | 673 -- + utils/open-isns/isnsadm.c | 1149 ---- + utils/open-isns/isnsd.c | 299 - + utils/open-isns/isnsdd.c | 1153 ---- + utils/open-isns/isnssetup | 52 - + utils/open-isns/local.c | 353 - + utils/open-isns/logging.c | 228 - + utils/open-isns/mdebug.c | 295 - + utils/open-isns/message.c | 681 -- + utils/open-isns/message.h | 196 - + utils/open-isns/objects.c | 1320 ---- + utils/open-isns/objects.h | 168 - + utils/open-isns/parser.c | 134 - + utils/open-isns/paths.h | 22 - + utils/open-isns/pidfile.c | 98 - + utils/open-isns/pki.c | 536 -- + utils/open-isns/policy.c | 577 -- + utils/open-isns/portal-group.c | 307 - + utils/open-isns/query.c | 238 - + utils/open-isns/register.c | 934 --- + utils/open-isns/relation.c | 281 - + utils/open-isns/scn.c | 926 --- + utils/open-isns/scope.c | 513 -- + utils/open-isns/security.c | 437 -- + utils/open-isns/security.h | 185 - + utils/open-isns/server.c | 236 - + utils/open-isns/simple.c | 727 --- + utils/open-isns/slp.c | 242 - + utils/open-isns/socket.c | 2304 ------- + utils/open-isns/socket.h | 95 - + utils/open-isns/source.h | 32 - + utils/open-isns/storage-node.c | 202 - + utils/open-isns/sysdep-unix.c | 186 - + utils/open-isns/tags.c | 740 --- + utils/open-isns/tests/.cvsignore | 2 - + utils/open-isns/tests/Makefile | 40 - + utils/open-isns/tests/client.conf | 8 - + utils/open-isns/tests/data/test01/01-enroll | 18 - + utils/open-isns/tests/data/test01/02-registration | 42 - + utils/open-isns/tests/data/test01/03-query | 20 - + utils/open-isns/tests/data/test01/03-registration | 20 - + .../open-isns/tests/data/test01/99-unregistration | 18 - + utils/open-isns/tests/data/test02/01-enroll | 18 - + utils/open-isns/tests/data/test02/02-enroll | 24 - + utils/open-isns/tests/data/test02/03-registration | 72 - + utils/open-isns/tests/data/test02/04-query | 20 - + utils/open-isns/tests/data/test02/05-query | 20 - + .../open-isns/tests/data/test02/06-dd-registration | 81 - + utils/open-isns/tests/data/test02/07-query | 40 - + utils/open-isns/tests/data/test02/08-query | 40 - + utils/open-isns/tests/data/test02/09-query | 20 - + .../open-isns/tests/data/test02/10-dd-registration | 87 - + utils/open-isns/tests/data/test02/11-query | 10 - + .../tests/data/test02/12-dd-deregistration | 85 - + .../tests/data/test02/13-dd-deregistration | 83 - + .../open-isns/tests/data/test02/14-dd-registration | 85 - + .../tests/data/test02/15-dd-deregistration | 76 - + utils/open-isns/tests/data/test03/01-enroll | 18 - + utils/open-isns/tests/data/test03/02-registration | 42 - + .../open-isns/tests/data/test03/03-unregistration | 42 - + .../open-isns/tests/data/test03/04-unregistration | 18 - + .../open-isns/tests/data/test03/99-unregistration | 13 - + utils/open-isns/tests/data/test04/01-enroll | 18 - + utils/open-isns/tests/data/test04/02-registration | 42 - + utils/open-isns/tests/data/test04/03-restart | 42 - + utils/open-isns/tests/data/test04/04-query | 20 - + utils/open-isns/tests/data/test05/01-enroll | 18 - + utils/open-isns/tests/data/test05/02-registration | 42 - + utils/open-isns/tests/data/test05/03-expired | 18 - + utils/open-isns/tests/data/test06/01-enroll | 18 - + utils/open-isns/tests/data/test06/02-registration | 42 - + utils/open-isns/tests/data/test06/03-registration | 42 - + utils/open-isns/tests/data/test06/04-registration | 42 - + .../open-isns/tests/data/test06/05-dd-registration | 49 - + utils/open-isns/tests/data/test06/06-registration | 49 - + .../open-isns/tests/data/test06/07-dd-registration | 52 - + utils/open-isns/tests/data/test06/08-registration | 64 - + utils/open-isns/tests/data/test06/09-registration | 64 - + .../open-isns/tests/data/test06/10-unregistration | 37 - + utils/open-isns/tests/data/test06/11-registration | 52 - + utils/open-isns/tests/data/test07/01-enroll | 19 - + utils/open-isns/tests/data/test07/02-registration | 45 - + utils/open-isns/tests/data/test07/03-expired | 19 - + utils/open-isns/tests/data/test07/04-registration | 57 - + utils/open-isns/tests/data/test07/05-expired | 19 - + utils/open-isns/tests/data/test08/01-pauw1 | 100 - + utils/open-isns/tests/data/test09/01-pauw2 | 31 - + utils/open-isns/tests/data/test10/01-pauw3 | 31 - + utils/open-isns/tests/data/test10/02-expired | 31 - + utils/open-isns/tests/data/test10/03-pauw3 | 31 - + utils/open-isns/tests/data/test10/04-expired | 31 - + utils/open-isns/tests/data/test11/01-pauw4 | 32 - + utils/open-isns/tests/genkey | 175 - + utils/open-isns/tests/harness.pl | 929 --- + utils/open-isns/tests/pauw1.c | 179 - + utils/open-isns/tests/pauw2.c | 212 - + utils/open-isns/tests/pauw3.c | 139 - + utils/open-isns/tests/pauw4.c | 137 - + utils/open-isns/tests/server.conf | 11 - + utils/open-isns/tests/test01.pl | 30 - + utils/open-isns/tests/test02.pl | 58 - + utils/open-isns/tests/test03.pl | 27 - + utils/open-isns/tests/test04.pl | 30 - + utils/open-isns/tests/test05.pl | 25 - + utils/open-isns/tests/test06.pl | 50 - + utils/open-isns/tests/test07.pl | 37 - + utils/open-isns/tests/test08.pl | 23 - + utils/open-isns/tests/test09.pl | 23 - + utils/open-isns/tests/test10.pl | 33 - + utils/open-isns/tests/test11.pl | 23 - + utils/open-isns/timer.c | 126 - + utils/open-isns/types.h | 57 - + utils/open-isns/util.c | 263 - + utils/open-isns/util.h | 289 - + utils/open-isns/vendor.c | 41 - + utils/open-isns/vendor.h | 56 - + utils/sysdeps/Makefile | 3 +- + 329 files changed, 34931 insertions(+), 45655 deletions(-) + delete mode 100644 debian/README.Debian + delete mode 100644 debian/changelog + delete mode 100644 debian/compat + delete mode 100644 debian/control + delete mode 100644 debian/control.modules.in + delete mode 100644 debian/copyright + delete mode 100644 debian/dirs + delete mode 100644 debian/docs + delete mode 100644 debian/postinst.modules.in + delete mode 100644 debian/rules + delete mode 100644 debian/rules.modules + create mode 100644 etc/systemd/iscsid.service + create mode 100644 etc/systemd/iscsid.socket + create mode 100644 iscsiuio/.gitignore + create mode 100644 iscsiuio/AUTHORS + create mode 100644 iscsiuio/ChangeLog + create mode 100644 iscsiuio/INSTALL + create mode 100644 iscsiuio/Makefile.am + create mode 100644 iscsiuio/NEWS + create mode 100644 iscsiuio/README + create mode 100644 iscsiuio/RELEASE.TXT + create mode 100644 iscsiuio/configure.ac + create mode 100644 iscsiuio/docs/iscsiuio.8 + create mode 100644 iscsiuio/iscsiuiolog + create mode 100644 iscsiuio/src/Makefile.am + create mode 100644 iscsiuio/src/README + create mode 100644 iscsiuio/src/apps/Makefile.am + create mode 100644 iscsiuio/src/apps/README + create mode 100644 iscsiuio/src/apps/brcm-iscsi/Makefile.am + create mode 100644 iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi + create mode 100644 iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c + create mode 100644 iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h + create mode 100644 iscsiuio/src/apps/dhcpc/Makefile.am + create mode 100644 iscsiuio/src/apps/dhcpc/Makefile.dhcpc + create mode 100644 iscsiuio/src/apps/dhcpc/dhcpc.c + create mode 100644 iscsiuio/src/apps/dhcpc/dhcpc.h + create mode 100644 iscsiuio/src/apps/dhcpc/dhcpv6.c + create mode 100644 iscsiuio/src/apps/dhcpc/dhcpv6.h + create mode 100644 iscsiuio/src/uip-1.0-changelog.txt + create mode 100644 iscsiuio/src/uip/Makefile.am + create mode 100644 iscsiuio/src/uip/Makefile.include + create mode 100644 iscsiuio/src/uip/clock.h + create mode 100644 iscsiuio/src/uip/debug.h + create mode 100644 iscsiuio/src/uip/icmpv6.h + create mode 100644 iscsiuio/src/uip/ipv6.c + create mode 100644 iscsiuio/src/uip/ipv6.h + create mode 100644 iscsiuio/src/uip/ipv6_ndpc.c + create mode 100644 iscsiuio/src/uip/ipv6_ndpc.h + create mode 100644 iscsiuio/src/uip/ipv6_pkt.h + create mode 100644 iscsiuio/src/uip/lc-addrlabels.h + create mode 100644 iscsiuio/src/uip/lc-switch.h + create mode 100644 iscsiuio/src/uip/lc.h + create mode 100644 iscsiuio/src/uip/psock.c + create mode 100644 iscsiuio/src/uip/psock.h + create mode 100644 iscsiuio/src/uip/pt.h + create mode 100644 iscsiuio/src/uip/timer.c + create mode 100644 iscsiuio/src/uip/timer.h + create mode 100644 iscsiuio/src/uip/uip-neighbor.c + create mode 100644 iscsiuio/src/uip/uip-neighbor.h + create mode 100644 iscsiuio/src/uip/uip.c + create mode 100644 iscsiuio/src/uip/uip.h + create mode 100644 iscsiuio/src/uip/uip_arch.h + create mode 100644 iscsiuio/src/uip/uip_arp.c + create mode 100644 iscsiuio/src/uip/uip_arp.h + create mode 100644 iscsiuio/src/uip/uip_eth.c + create mode 100644 iscsiuio/src/uip/uip_eth.h + create mode 100644 iscsiuio/src/uip/uipopt.h + create mode 100644 iscsiuio/src/unix/.gitignore + create mode 100644 iscsiuio/src/unix/Makefile.am + create mode 100644 iscsiuio/src/unix/clock-arch.c + create mode 100644 iscsiuio/src/unix/clock-arch.h + create mode 100644 iscsiuio/src/unix/iscsid_ipc.c + create mode 100644 iscsiuio/src/unix/iscsid_ipc.h + create mode 100644 iscsiuio/src/unix/libs/Makefile.am + create mode 100644 iscsiuio/src/unix/libs/bnx2.c + create mode 100644 iscsiuio/src/unix/libs/bnx2.h + create mode 100644 iscsiuio/src/unix/libs/bnx2x.c + create mode 100644 iscsiuio/src/unix/libs/bnx2x.h + create mode 100644 iscsiuio/src/unix/libs/cnic.c + create mode 100644 iscsiuio/src/unix/libs/cnic.h + create mode 100644 iscsiuio/src/unix/logger.c + create mode 100644 iscsiuio/src/unix/logger.h + create mode 100644 iscsiuio/src/unix/main.c + create mode 100644 iscsiuio/src/unix/nic.c + create mode 100644 iscsiuio/src/unix/nic.h + create mode 100644 iscsiuio/src/unix/nic_id.c + create mode 100644 iscsiuio/src/unix/nic_id.h + create mode 100644 iscsiuio/src/unix/nic_nl.c + create mode 100644 iscsiuio/src/unix/nic_nl.h + create mode 100644 iscsiuio/src/unix/nic_utils.c + create mode 100644 iscsiuio/src/unix/nic_utils.h + create mode 100644 iscsiuio/src/unix/nic_vlan.c + create mode 100644 iscsiuio/src/unix/nic_vlan.h + create mode 100644 iscsiuio/src/unix/options.h + create mode 100644 iscsiuio/src/unix/packet.c + create mode 100644 iscsiuio/src/unix/packet.h + create mode 100644 iscsiuio/src/unix/ping.c + create mode 100644 iscsiuio/src/unix/ping.h + create mode 100644 iscsiuio/src/unix/uip-conf.h + create mode 100644 sysfs-documentation + create mode 100644 usr/flashnode.c + create mode 100644 usr/flashnode.h + create mode 100644 usr/uip_mgmt_ipc.c + create mode 100644 usr/uip_mgmt_ipc.h + create mode 100755 utils/iscsi-gen-initiatorname + create mode 100755 utils/iscsi_offload + delete mode 100644 utils/open-isns/COPYING + delete mode 100644 utils/open-isns/ChangeLog + delete mode 100644 utils/open-isns/HACKING + delete mode 100644 utils/open-isns/Makefile.in + delete mode 100644 utils/open-isns/README + delete mode 100644 utils/open-isns/TODO + delete mode 100644 utils/open-isns/aclocal/config.guess + delete mode 100644 utils/open-isns/aclocal/config.sub + delete mode 100644 utils/open-isns/aclocal/install-sh + delete mode 100644 utils/open-isns/attrs.c + delete mode 100644 utils/open-isns/attrs.h + delete mode 100644 utils/open-isns/authblock.c + delete mode 100644 utils/open-isns/bitvector.c + delete mode 100644 utils/open-isns/buffer.c + delete mode 100644 utils/open-isns/buffer.h + delete mode 100644 utils/open-isns/callback.c + delete mode 100644 utils/open-isns/client.c + delete mode 100644 utils/open-isns/compat/my_getopt.c + delete mode 100644 utils/open-isns/compat/my_getopt.h + delete mode 100644 utils/open-isns/config.c + delete mode 100644 utils/open-isns/config.h.in + delete mode 100755 utils/open-isns/configure + delete mode 100644 utils/open-isns/configure.ac + delete mode 100644 utils/open-isns/db-file.c + delete mode 100644 utils/open-isns/db-policy.c + delete mode 100644 utils/open-isns/db.c + delete mode 100644 utils/open-isns/db.h + delete mode 100644 utils/open-isns/dd.c + delete mode 100644 utils/open-isns/deregister.c + delete mode 100644 utils/open-isns/doc/isns_config.5 + delete mode 100644 utils/open-isns/doc/isnsadm.8 + delete mode 100644 utils/open-isns/doc/isnsd.8 + delete mode 100644 utils/open-isns/doc/isnsdd.8 + delete mode 100644 utils/open-isns/domain.c + delete mode 100644 utils/open-isns/entity.c + delete mode 100644 utils/open-isns/error.c + delete mode 100644 utils/open-isns/esi.c + delete mode 100644 utils/open-isns/etc/isnsadm.conf + delete mode 100644 utils/open-isns/etc/isnsd.conf + delete mode 100644 utils/open-isns/etc/isnsdd.conf + delete mode 100644 utils/open-isns/etc/openisns.init + delete mode 100644 utils/open-isns/export.c + delete mode 100644 utils/open-isns/getnext.c + delete mode 100644 utils/open-isns/internal.h + delete mode 100644 utils/open-isns/isns-proto.h + delete mode 100644 utils/open-isns/isns.h + delete mode 100644 utils/open-isns/isnsadm.c + delete mode 100644 utils/open-isns/isnsd.c + delete mode 100644 utils/open-isns/isnsdd.c + delete mode 100644 utils/open-isns/isnssetup + delete mode 100644 utils/open-isns/local.c + delete mode 100644 utils/open-isns/logging.c + delete mode 100644 utils/open-isns/mdebug.c + delete mode 100644 utils/open-isns/message.c + delete mode 100644 utils/open-isns/message.h + delete mode 100644 utils/open-isns/objects.c + delete mode 100644 utils/open-isns/objects.h + delete mode 100644 utils/open-isns/parser.c + delete mode 100644 utils/open-isns/paths.h + delete mode 100644 utils/open-isns/pidfile.c + delete mode 100644 utils/open-isns/pki.c + delete mode 100644 utils/open-isns/policy.c + delete mode 100644 utils/open-isns/portal-group.c + delete mode 100644 utils/open-isns/query.c + delete mode 100644 utils/open-isns/register.c + delete mode 100644 utils/open-isns/relation.c + delete mode 100644 utils/open-isns/scn.c + delete mode 100644 utils/open-isns/scope.c + delete mode 100644 utils/open-isns/security.c + delete mode 100644 utils/open-isns/security.h + delete mode 100644 utils/open-isns/server.c + delete mode 100644 utils/open-isns/simple.c + delete mode 100644 utils/open-isns/slp.c + delete mode 100644 utils/open-isns/socket.c + delete mode 100644 utils/open-isns/socket.h + delete mode 100644 utils/open-isns/source.h + delete mode 100644 utils/open-isns/storage-node.c + delete mode 100644 utils/open-isns/sysdep-unix.c + delete mode 100644 utils/open-isns/tags.c + delete mode 100644 utils/open-isns/tests/.cvsignore + delete mode 100644 utils/open-isns/tests/Makefile + delete mode 100644 utils/open-isns/tests/client.conf + delete mode 100644 utils/open-isns/tests/data/test01/01-enroll + delete mode 100644 utils/open-isns/tests/data/test01/02-registration + delete mode 100644 utils/open-isns/tests/data/test01/03-query + delete mode 100644 utils/open-isns/tests/data/test01/03-registration + delete mode 100644 utils/open-isns/tests/data/test01/99-unregistration + delete mode 100644 utils/open-isns/tests/data/test02/01-enroll + delete mode 100644 utils/open-isns/tests/data/test02/02-enroll + delete mode 100644 utils/open-isns/tests/data/test02/03-registration + delete mode 100644 utils/open-isns/tests/data/test02/04-query + delete mode 100644 utils/open-isns/tests/data/test02/05-query + delete mode 100644 utils/open-isns/tests/data/test02/06-dd-registration + delete mode 100644 utils/open-isns/tests/data/test02/07-query + delete mode 100644 utils/open-isns/tests/data/test02/08-query + delete mode 100644 utils/open-isns/tests/data/test02/09-query + delete mode 100644 utils/open-isns/tests/data/test02/10-dd-registration + delete mode 100644 utils/open-isns/tests/data/test02/11-query + delete mode 100644 utils/open-isns/tests/data/test02/12-dd-deregistration + delete mode 100644 utils/open-isns/tests/data/test02/13-dd-deregistration + delete mode 100644 utils/open-isns/tests/data/test02/14-dd-registration + delete mode 100644 utils/open-isns/tests/data/test02/15-dd-deregistration + delete mode 100644 utils/open-isns/tests/data/test03/01-enroll + delete mode 100644 utils/open-isns/tests/data/test03/02-registration + delete mode 100644 utils/open-isns/tests/data/test03/03-unregistration + delete mode 100644 utils/open-isns/tests/data/test03/04-unregistration + delete mode 100644 utils/open-isns/tests/data/test03/99-unregistration + delete mode 100644 utils/open-isns/tests/data/test04/01-enroll + delete mode 100644 utils/open-isns/tests/data/test04/02-registration + delete mode 100644 utils/open-isns/tests/data/test04/03-restart + delete mode 100644 utils/open-isns/tests/data/test04/04-query + delete mode 100644 utils/open-isns/tests/data/test05/01-enroll + delete mode 100644 utils/open-isns/tests/data/test05/02-registration + delete mode 100644 utils/open-isns/tests/data/test05/03-expired + delete mode 100644 utils/open-isns/tests/data/test06/01-enroll + delete mode 100644 utils/open-isns/tests/data/test06/02-registration + delete mode 100644 utils/open-isns/tests/data/test06/03-registration + delete mode 100644 utils/open-isns/tests/data/test06/04-registration + delete mode 100644 utils/open-isns/tests/data/test06/05-dd-registration + delete mode 100644 utils/open-isns/tests/data/test06/06-registration + delete mode 100644 utils/open-isns/tests/data/test06/07-dd-registration + delete mode 100644 utils/open-isns/tests/data/test06/08-registration + delete mode 100644 utils/open-isns/tests/data/test06/09-registration + delete mode 100644 utils/open-isns/tests/data/test06/10-unregistration + delete mode 100644 utils/open-isns/tests/data/test06/11-registration + delete mode 100644 utils/open-isns/tests/data/test07/01-enroll + delete mode 100644 utils/open-isns/tests/data/test07/02-registration + delete mode 100644 utils/open-isns/tests/data/test07/03-expired + delete mode 100644 utils/open-isns/tests/data/test07/04-registration + delete mode 100644 utils/open-isns/tests/data/test07/05-expired + delete mode 100644 utils/open-isns/tests/data/test08/01-pauw1 + delete mode 100644 utils/open-isns/tests/data/test09/01-pauw2 + delete mode 100644 utils/open-isns/tests/data/test10/01-pauw3 + delete mode 100644 utils/open-isns/tests/data/test10/02-expired + delete mode 100644 utils/open-isns/tests/data/test10/03-pauw3 + delete mode 100644 utils/open-isns/tests/data/test10/04-expired + delete mode 100644 utils/open-isns/tests/data/test11/01-pauw4 + delete mode 100644 utils/open-isns/tests/genkey + delete mode 100644 utils/open-isns/tests/harness.pl + delete mode 100644 utils/open-isns/tests/pauw1.c + delete mode 100644 utils/open-isns/tests/pauw2.c + delete mode 100644 utils/open-isns/tests/pauw3.c + delete mode 100644 utils/open-isns/tests/pauw4.c + delete mode 100644 utils/open-isns/tests/server.conf + delete mode 100644 utils/open-isns/tests/test01.pl + delete mode 100644 utils/open-isns/tests/test02.pl + delete mode 100644 utils/open-isns/tests/test03.pl + delete mode 100644 utils/open-isns/tests/test04.pl + delete mode 100644 utils/open-isns/tests/test05.pl + delete mode 100644 utils/open-isns/tests/test06.pl + delete mode 100644 utils/open-isns/tests/test07.pl + delete mode 100644 utils/open-isns/tests/test08.pl + delete mode 100644 utils/open-isns/tests/test09.pl + delete mode 100644 utils/open-isns/tests/test10.pl + delete mode 100644 utils/open-isns/tests/test11.pl + delete mode 100644 utils/open-isns/timer.c + delete mode 100644 utils/open-isns/types.h + delete mode 100644 utils/open-isns/util.c + delete mode 100644 utils/open-isns/util.h + delete mode 100644 utils/open-isns/vendor.c + delete mode 100644 utils/open-isns/vendor.h + +diff --git a/Makefile b/Makefile +index c5d9700..c8cd00e 100644 +--- a/Makefile ++++ b/Makefile +@@ -14,35 +14,50 @@ mandir = $(prefix)/share/man + etcdir = /etc + initddir = $(etcdir)/init.d + +-MANPAGES = doc/iscsid.8 doc/iscsiadm.8 doc/iscsi_discovery.8 +-PROGRAMS = usr/iscsid usr/iscsiadm utils/iscsi_discovery utils/iscsi-iname ++MANPAGES = doc/iscsid.8 doc/iscsiadm.8 doc/iscsi_discovery.8 iscsiuio/docs/iscsiuio.8 ++PROGRAMS = usr/iscsid usr/iscsiadm utils/iscsi_discovery utils/iscsi-iname iscsiuio/src/unix/iscsiuio + INSTALL = install + ETCFILES = etc/iscsid.conf + IFACEFILES = etc/iface.example + ++# Compatibility: parse old OPTFLAGS argument ++ifdef OPTFLAGS ++CFLAGS = $(OPTFLAGS) ++endif ++ ++# Export it so configure of iscsiuio will ++# pick it up. ++ifneq (,$(CFLAGS)) ++export CFLAGS ++endif ++ + # Random comments: + # using '$(MAKE)' instead of just 'make' allows make to run in parallel + # over multiple makefile. + + all: user + +-user: utils/open-isns/Makefile +- $(MAKE) -C utils/open-isns ++user: iscsiuio/Makefile + $(MAKE) -C utils/sysdeps + $(MAKE) -C utils/fwparam_ibft + $(MAKE) -C usr + $(MAKE) -C utils ++ $(MAKE) -C iscsiuio + @echo + @echo "Compilation complete Output file" + @echo "----------------------------------- ----------------" + @echo "Built iSCSI daemon: usr/iscsid" + @echo "Built management application: usr/iscsiadm" + @echo "Built boot tool: usr/iscsistart" ++ @echo "Built iscsiuio daemon: iscsiuio/src/unix/iscsiuio" + @echo + @echo "Read README file for detailed information." + +-utils/open-isns/Makefile: utils/open-isns/configure utils/open-isns/Makefile.in +- cd utils/open-isns; ./configure CFLAGS="$(OPTFLAGS)" --with-security=no ++iscsiuio/Makefile: iscsiuio/configure iscsiuio/Makefile.in ++ cd iscsiuio; ./configure ++ ++iscsiuio/configure iscsiuio/Makefile.in: iscsiuio/configure.ac iscsiuio/Makefile.am ++ cd iscsiuio; autoreconf --install + + kernel: force + $(MAKE) -C kernel +@@ -61,8 +76,8 @@ clean: + $(MAKE) -C utils clean + $(MAKE) -C usr clean + $(MAKE) -C kernel clean +- $(MAKE) -C utils/open-isns clean +- $(MAKE) -C utils/open-isns distclean ++ [ ! -f iscsiuio/Makefile ] || $(MAKE) -C iscsiuio clean ++ [ ! -f iscsiuio/Makefile ] || $(MAKE) -C iscsiuio distclean + + # this is for safety + # now -jXXX will still be safe +@@ -115,7 +130,7 @@ install_iface: $(IFACEFILES) + $(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi/ifaces + + install_etc: $(ETCFILES) +- if [ ! -f /etc/iscsi/iscsid.conf ]; then \ ++ if [ ! -f $(DESTDIR)/etc/iscsi/iscsid.conf ]; then \ + $(INSTALL) -d $(DESTDIR)$(etcdir)/iscsi ; \ + $(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi ; \ + fi +@@ -128,11 +143,11 @@ install_kernel: + $(MAKE) -C kernel install_kernel + + install_iname: +- if [ ! -f /etc/iscsi/initiatorname.iscsi ]; then \ ++ if [ ! -f $(DESTDIR)/etc/iscsi/initiatorname.iscsi ]; then \ + echo "InitiatorName=`$(DESTDIR)/sbin/iscsi-iname`" > $(DESTDIR)/etc/iscsi/initiatorname.iscsi ; \ + echo "***************************************************" ; \ + echo "Setting InitiatorName to `cat $(DESTDIR)/etc/iscsi/initiatorname.iscsi`" ; \ +- echo "To override edit /etc/iscsi/initiatorname.iscsi" ; \ ++ echo "To override edit $(DESTDIR)/etc/iscsi/initiatorname.iscsi" ; \ + echo "***************************************************" ; \ + fi + +diff --git a/README b/README +index 7364b2d..cbe8763 100644 +--- a/README ++++ b/README +@@ -79,6 +79,20 @@ kernel config. And you must enable "CRC32c CRC algorithm" even if + you do not use header or data digests. They are the kernel options, + CONFIG_CRYPTO and CONFIG_CRYPTO_CRC32C, respectively. + ++The userspace components: iscsid, iscsiadm and iscsistart require the ++open-isns library which can be found here: ++ ++https://github.com/gonzoleeman/open-isns/releases ++ ++To install the open-isns headers and library required for open-iscsi download ++the current release and run: ++ ++ ./configure ++ make ++ make install ++ make install_hdrs ++ make install_lib ++ + By default the kernel's iSCSI modules will be used. Running: + + make +@@ -92,7 +106,7 @@ by running: + make kernel + + When building those modules the kernel source found at +-/lib/modules/`uname -a`/build ++/lib/modules/`uname -r`/build + will be used to compile the open-iscsi modules. To specify a different + kernel to build against use: + +@@ -159,15 +173,20 @@ Usage: iscsid [OPTION] + 5. Open-iSCSI Configuration Utility + =================================== + +-Open-iSCSI persistent configuration is implemented as a DBM database +-available on all Linux installations. ++Open-iSCSI persistent configuration is stored in a number of ++directories under a configuration root directory, using a flat-file ++format. This configuration root directory is /etc/iscsi by default, ++but may also commonly be in /var/lib/iscsi. + +-The database contains two tables: ++Configuration is contained in directories for: + +-- Discovery table (/etc/iscsi/send_targets); +-- Node table (/etc/iscsi/nodes). +- +-The regular place for iSCSI database files: /etc/iscsi/nodes ++- nodes ++- slp ++- isns ++- static ++- fw ++- send_targets ++- ifaces + + The iscsiadm utility is a command-line tool to manage (update, delete, + insert, query) the persistent database. +@@ -388,7 +407,7 @@ Usage: iscsiadm [OPTION] + See below for examples. + -m iface --interface=iscsi_ifacename -C ping --ip=[ipaddr] --packetsize=[size] + --count=[count] --interval=[interval] +- -m host --host=hostno|MAC --print=level -C chap --op=[op] --value=[chap_tbl_idx] ++ -m host --host=hostno|MAC --print=level -C chap --op=[SHOW] + Display information for a specific host. The host + can be passed in by host number or by MAC address. + If a host is not passed in then info +@@ -401,6 +420,37 @@ Usage: iscsiadm [OPTION] + is connected to. + 3 = Print iscsi params used. + 4 = Print SCSI info like LUNs, device state. ++ -m host --host=hostno|MAC -C chap --op=[DELETE] --index=[chap_tbl_idx] ++ Delete chap entry at the given index from chap table. ++ -m host --host=hostno|MAC -C chap --op=[NEW | UPDATE] --index=[chap_tbl_idx] \ ++ --name=[name] --value=[value] ++ Add new or update existing chap entry at the given ++ index with given username and password pair. If index ++ is not passed then entry is added at the first free ++ index in chap table. ++ -m host --host=hostno|MAC -C flashnode ++ Display list of all the targets in adapter's ++ flash (flash node), for the specified host, ++ with ip, port, tpgt and iqn. ++ -m host --host=hostno|MAC -C flashnode --op=[NEW] --portal_type=[ipv4|ipv6] ++ Create new flash node entry for the given host of the ++ specified portal_type. This returns the index of the ++ newly created entry on success. ++ -m host --host=hostno|MAC -C flashnode --index=[flashnode index] \ ++ --op=[UPDATE] --name=[name] --value=[value] ++ Update the params of the speficied flash node. ++ The [name] and [value] pairs must be provided for the ++ params that need to be updated. Multiple params can ++ be updated using a single command. ++ -m host --host=hostno|MAC -C flashnode --index=[flashnode index] \ ++ --op=[SHOW | DELETE | LOGIN | LOGOUT] ++ op=DELETE|LOGIN|LOGOUT will perform deletion/login/ ++ logout operation on the specified flash node. ++ ++ op=SHOW will list all params with the values for the ++ specified flash node. This is the default operation. ++ ++ See the iscsiadm example section for more info. + -d, --debug debuglevel print debugging information + -V, --version display version and exit + -h, --help display this help and exit +@@ -955,6 +1005,96 @@ To now log into targets it is the same as with sofware iscsi. See section + + ./iscsiadm -m session -P 1 + ++ ++ Host mode with flashnode submode: ++ ++ - Display list of flash nodes for a host ++ ++ ./iscsiadm -m host -H 6 -C flashnode ++ ++ This will print list of all the flash node entries for the given host 6 ++ along with their ip, port, tpgt and iqn values. ++ ++ - Display all parameters of a flash node entry for a host ++ ++ ./iscsiadm -m host -H 6 -C flashnode -x 0 ++ ++ This will list all the parameter name,value pairs for flash node entry at ++ index 0 of host 6. ++ ++ - Add a new flash node entry for a host ++ ++ ./iscsiadm -m host -H 6 -C flashnode -o new -A ipv4 ++ or ++ ./iscsiadm -m host -H 6 -C flashnode -o new -A ipv6 ++ ++ This will add new flash node entry for the given host 6 with portal ++ type of either ipv4 or ipv6. The new operation returns the index of ++ the newly created flash node entry. ++ ++ - Update a flashnode entry ++ ./iscsiadm -m host -H 6 -C flashnode -x 1 -o update \ ++ -n flashnode.conn[0].ipaddress -v 192.168.1.12 \ ++ -n flashnode.session.targetname \ ++ -v iqn.2002-03.com.compellent:5000d310004b0716 ++ ++ This will update the values of ipaddress and targetname params of ++ flash node entry at index 1 of host 6. ++ ++ - Login to a flash node entry ++ ./iscsiadm -m host -H 6 -C flashnode -x 1 -o login ++ ++ - Logout from a flash node entry ++ ./iscsiadm -m host -H 6 -C flashnode -x 1 -o logout ++ or ++ ./iscsiadm -m session -r $sid -u ++ ++ Logout can be performed either using the flash node index or using the ++ corresponding session index. ++ ++ - Delete a flash node entry ++ ./iscsiadm -m host -H 6 -C flashnode -x 1 -o delete ++ ++ Host mode with chap submode: ++ ++ - Display list of chap entries for a host ++ ++ ./iscsiadm -m host -H 6 -C chap -o show ++ ++ This will list all the chap entries for the given host. ++ ++ - Delete a chap entry for a host ++ ++ ./iscsiadm -m host -H 6 -C chap -o delete -x 5 ++ ++ This will delete any chap entry present at given index 5. ++ ++ - Add/Update a local chap entry for a host ++ ++ ./iscsiadm -m host -H 6 -C chap -o update -x 4 -n username \ ++ -v value -n password -v value ++ ++ This will update the local chap entry present at index 4. If index 4 ++ is free then entry of type local chap will be created at that index ++ with given username and password values. ++ ++ - Add/Update a bidi chap entry for a host ++ ++ ./iscsiadm -m host -H 6 -C chap -o update -x 5 -n username_in \ ++ -v value -n password_in -v value ++ ++ This will update the bidi chap entry present at index 5. If index 5 ++ is free then entry of type bidi chap will be created at that index ++ with given username_in and password_in values. ++ ++ Host mode with stats submode: ++ ++ - Display host statistics: ++ ./iscsiadm -m host -H 6 -C stats ++ ++ This will print the aggregate statistics on the host adapter port. ++ This includes MAC, TCP/IP, ECC & iSCSI statistics. ++ + 6. Configuration + ================ + +diff --git a/debian/README.Debian b/debian/README.Debian +deleted file mode 100644 +index 98ebd23..0000000 +--- a/debian/README.Debian ++++ /dev/null +@@ -1,44 +0,0 @@ +-linux-iscsi for Debian +------------------------------------ +- +-The linux-iscsi package contains the userspace portion the Linux iSCSI project. +-It has a dependency on the linux-iscsi-modules package, which needs to be built from the linux-iscsi-modules-source against the specific kernel version running +-on your system. +- +-Building +--------- +-Modules cannot be built against the kernel-headers alone. You will need +-to extract and configure your kernel tree, then use the make-kpkg command +-(from the kernel-package package) to build a new kernel and modules. +-See the make-kpkg man page, particularly the modules-image section. The +-following example shows how to build the linux-iscsi-modules package; just +-substitute the appropriate version strings. Follow these instructions +-(as root) in order to build the linux-iscsi-modules package for your kernel: +- +-dpkg -i linux-iscsi-modules-source_5.0.0.0.3rc6-363_all.deb +-cd /usr/src +-rm -rf modules/linux-iscsi +-tar jxpvf linux-iscsi-modules-source.tar.bz2 +-cd linux-2.6.11.11 (or your appropriate version) +-make-kpkg --added-modules linux-iscsi modules-image +- +-By default, make-kpkg will assume /usr/src/linux-iscsi-modules-source.tar.bz2 +-has been extracted under /usr/src. However, that also requires building as +-root. If you want to do the build as a non-root user, you need to use the +-MODULE_LOC environment variable. For example: +- +-cd ~/builds +-export MODULES_LOC=$PWD/modules +-tar jxpvf /usr/src/linux-iscsi-modules-source.tar.bz2 +-cd ~/builds/linux-2.6.11.11 (or your appropriate version) +-make-kpkg --added-modules linux-iscsi modules-image +- +-Installing +----------- +- +-Once you have built the linux-iscsi-modules package, you can install the +-binaries: +- +-dpkg -i linux-iscsi_5.0.0.0.3rc6-363_i386.deb linux-iscsi-modules-2.6.11.11_5.0.0.0.3rc6-363+10.00.Custom_i386.deb +- +- -- Chad Tindel , Mon, 30 May 2005 15:17:53 -0600 +diff --git a/debian/changelog b/debian/changelog +deleted file mode 100644 +index f71577e..0000000 +--- a/debian/changelog ++++ /dev/null +@@ -1,6 +0,0 @@ +-linux-iscsi (5.0.0.0.3rc6-363) unstable; urgency=low +- +- * Initial Release. +- +- -- Chad Tindel Mon, 30 May 2005 15:17:53 -0600 +- +diff --git a/debian/compat b/debian/compat +deleted file mode 100644 +index b8626c4..0000000 +--- a/debian/compat ++++ /dev/null +@@ -1 +0,0 @@ +-4 +diff --git a/debian/control b/debian/control +deleted file mode 100644 +index d333569..0000000 +--- a/debian/control ++++ /dev/null +@@ -1,27 +0,0 @@ +-Source: linux-iscsi +-Section: net +-Priority: optional +-Maintainer: Chad Tindel +-Build-Depends: debhelper (>= 4.0.0), libdb4.3, libdb4.3-dev +-Standards-Version: 3.6.1 +- +-Package: linux-iscsi +-Architecture: any +-Depends: ${shlibs:Depends}, ${misc:Depends}, linux-iscsi-modules +-Description: high performance, transport independent implementation of RFC3720. +- linux-iscsi is a high performance, transport independent, implementation of +- RFC3720. +- +-#Package: linux-iscsi +-#Architecture: all +-#Description: Documentation for linux-iscsi +-#linux-iscsi is a high performance, transport independent, implementation of +-#RFC3720. +- +-Package: linux-iscsi-modules-source +-Architecture: all +-Depends: ${shlibs:Depends}, ${misc:Depends}, module-assistant, debhelper (>= 4.0.0), bzip2 +-Description: Source Code for the Linux iSCSI Kernel Modules +- Along with make-kpkg, this package maybe used to build a linux-iscsi-modules +- package for a kernel-image package. +- +diff --git a/debian/control.modules.in b/debian/control.modules.in +deleted file mode 100644 +index 9371b34..0000000 +--- a/debian/control.modules.in ++++ /dev/null +@@ -1,20 +0,0 @@ +-Source: linux-iscsi-modules +-Section: net +-Priority: optional +-Maintainer: Chad Tindel +-Build-Depends: debhelper (>> 4.1.0), bzip2 +-Standards-Version: 3.6.1 +- +-Package: linux-iscsi-modules-_KVERS_ +-Architecture: any +-Depends: modutils, linux-iscsi +-Provides: linux-iscsi-modules +-Description: Linux Kernel Driver Modules for Linux iSCSI (kernel _KVERS_) +- This is a Linux driver for iSCSI initiator functionality. +- . +- This package contains the compiled kernel modules for _KVERS_ +- . +- If you have compiled your own kernel, you will most likely need to build +- your own linux-iscsi-modules. The linux-iscsi-source package has been +- provided for use with the Debian kernel-package utility to produce a version +- of linux-iscsi-module for your kernel. +diff --git a/debian/copyright b/debian/copyright +deleted file mode 100644 +index 11c0945..0000000 +--- a/debian/copyright ++++ /dev/null +@@ -1,12 +0,0 @@ +-This package was debianized by Chad Tindel on +-Mon, 30 May 2005 15:17:53 -0600. +- +-It was downloaded from http://sourceforge.net/projects/linux-iscsi +- +-Copyright Holder: Dmitry Yusupov +- +-License: +- +-You are free to distribute this software under the terms of the GNU General +-Public License. On Debian systems, the complete text of the GNU General Public +-License can be found in the file `/usr/share/common-licenses/GPL'. +diff --git a/debian/dirs b/debian/dirs +deleted file mode 100644 +index c386116..0000000 +--- a/debian/dirs ++++ /dev/null +@@ -1,3 +0,0 @@ +-usr/bin +-usr/sbin +-etc/init.d +diff --git a/debian/docs b/debian/docs +deleted file mode 100644 +index 9b70221..0000000 +--- a/debian/docs ++++ /dev/null +@@ -1,4 +0,0 @@ +-README +-COPYING +-THANKS +-TODO +diff --git a/debian/postinst.modules.in b/debian/postinst.modules.in +deleted file mode 100644 +index 70dc20d..0000000 +--- a/debian/postinst.modules.in ++++ /dev/null +@@ -1,11 +0,0 @@ +-#!/bin/sh +- +-set -e +- +-if [ "`uname -r`" = "_KVERS_" ]; then +- /sbin/depmod -a & +-fi +- +-#DEBHELPER# +- +-exit 0 +diff --git a/debian/rules b/debian/rules +deleted file mode 100644 +index f4695c6..0000000 +--- a/debian/rules ++++ /dev/null +@@ -1,152 +0,0 @@ +-#!/usr/bin/make -f +-# -*- makefile -*- +-# Sample debian/rules that uses debhelper. +-# +-# This file was originally written by Joey Hess and Craig Small. +-# As a special exception, when this file is copied by dh-make into a +-# dh-make output file, you may use that output file without restriction. +-# This special exception was added by Craig Small in version 0.37 of dh-make. +-# +-# Modified to make a template file for a multi-binary package with separated +-# build-arch and build-indep targets by Bill Allombert 2001 +- +-# Uncomment this to turn on verbose mode. +-#export DH_VERBOSE=1 +- +-# This has to be exported to make some magic below work. +-export DH_OPTIONS +- +- +- +-CFLAGS = -Wall -g +- +-ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) +- CFLAGS += -O0 +-else +- CFLAGS += -O2 +-endif +- +-configure: configure-stamp +-configure-stamp: +- dh_testdir +- # Add here commands to configure the package. +- +- touch configure-stamp +- +- +-#Architecture +-build: build-arch build-indep +- +-build-arch: build-arch-stamp +-build-arch-stamp: configure-stamp +- +- # Add here commands to compile the arch part of the package. +- $(MAKE) -C usr +- +- touch build-arch-stamp +- +-build-indep: build-indep-stamp +-build-indep-stamp: configure-stamp +- +- # Add here commands to compile the indep part of the package. +- #$(MAKE) doc +- touch build-indep-stamp +- +-clean: +- dh_testdir +- dh_testroot +- rm -f build-arch-stamp build-indep-stamp #CONFIGURE-STAMP# +- +- # Add here commands to clean up after the build process. +- $(MAKE) -C usr clean +- rm -rf modules +- +- dh_clean +- +-install: install-indep install-arch +-install-indep: +- dh_testdir +- dh_testroot +- dh_clean -k -i +- dh_installdirs -i +- +- # create needed directories +- dh_installdirs -i usr/src/modules/linux-iscsi +- +- mkdir -p modules/linux-iscsi/debian +- +- # copy the driver source +- tar --exclude=debian -c * | (cd modules/linux-iscsi && tar xv) +- +- # copy all relevant debian/ files +- cp debian/{compat,copyright} modules/linux-iscsi/debian +- cat debian/changelog | sed -e 's/linux-iscsi/linux-iscsi-modules/' > modules/linux-iscsi/debian/changelog +- cp debian/*.modules.in modules/linux-iscsi/debian +- install -m755 debian/rules.modules modules/linux-iscsi/debian/rules +- +- # entar the source +- tar jcf debian/linux-iscsi-modules-source/usr/src/linux-iscsi-modules-source.tar.bz2 modules +- +- # Add here commands to install the indep part of the package into +- # debian/-doc. +- #INSTALLDOC# +- +- dh_install -i +- +-install-arch: +- dh_testdir +- dh_testroot +- dh_clean -k -s +- dh_installdirs -s +- +- # Add here commands to install the arch part of the package into +- # debian/linux-iscsi. +- install -m 755 usr/iscsiadm $(CURDIR)/debian/linux-iscsi/usr/bin +- install -m 755 usr/iscsid $(CURDIR)/debian/linux-iscsi/usr/sbin +- install -m 644 etc/iscsid.conf $(CURDIR)/debian/linux-iscsi/etc/iscsid.conf.example +- install -m 755 etc/initd/initd.debian $(CURDIR)/debian/linux-iscsi/etc/init.d/iscsid +- make clean +- +- dh_install -s +- +-# Must not depend on anything. This is to be called by +-# binary-arch/binary-indep +-# in another 'make' thread. +-binary-common: +- dh_testdir +- dh_testroot +- dh_installchangelogs +- dh_installdocs +- dh_installexamples +-# dh_installmenu +-# dh_installdebconf +-# dh_installlogrotate +-# dh_installemacsen +-# dh_installpam +-# dh_installmime +-# dh_installinit +-# dh_installcron +-# dh_installinfo +- dh_installman +- dh_link +- dh_strip +- dh_compress +- dh_fixperms +-# dh_perl +-# dh_python +- dh_makeshlibs +- dh_installdeb +- dh_shlibdeps +- dh_gencontrol +- dh_md5sums +- dh_builddeb +-# Build architecture independant packages using the common target. +-binary-indep: build-indep install-indep +- $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common +- +-# Build architecture dependant packages using the common target. +-binary-arch: build-arch install-arch +- $(MAKE) -f debian/rules DH_OPTIONS=-a binary-common +- +-binary: binary-arch binary-indep +-.PHONY: build clean binary-indep binary-arch binary install install-indep install-arch configure +diff --git a/debian/rules.modules b/debian/rules.modules +deleted file mode 100644 +index 1c4dabd..0000000 +--- a/debian/rules.modules ++++ /dev/null +@@ -1,39 +0,0 @@ +-#!/usr/bin/make -f +- +-# module-assistant stuff +-PACKAGE = linux-iscsi-modules +-MA_DIR ?= /usr/share/modass +--include $(MA_DIR)/include/generic.make +--include $(MA_DIR)/include/common-rules.make +- +-kdist_clean: prep-deb-files +- dh_clean +- #$(MAKE) clean KERNEL_PATH=$(KSRC) +- make clean +- +-kdist_config: prep-deb-files +- +-TARGET = $(CURDIR)/debian/linux-iscsi-modules-$(KVERS) +-MODULES_TARGET = $(TARGET)/lib/modules/$(KVERS)/kernel/net/iscsi +- +-binary-modules: kdist_config +- dh_testdir +- dh_testroot +- dh_clean -k +- dh_installdirs lib/modules/$(KVERS) +- +- # build and install the module +- patch -d kernel < kernel/backward-compile-2.6.11.patch +- make -C kernel KSRC=$(KSRC) +- mkdir -p $(MODULES_TARGET) +- install -m 755 kernel/iscsi_tcp.ko $(MODULES_TARGET) +- install -m 755 kernel/scsi_transport_iscsi.ko $(MODULES_TARGET) +- +- dh_installdocs +- dh_installchangelogs +- dh_compress +- dh_fixperms +- dh_installdeb +- dh_gencontrol -- -v$(VERSION) +- dh_md5sums +- dh_builddeb --destdir=$(DEB_DESTDIR) +diff --git a/doc/iscsi_discovery.8 b/doc/iscsi_discovery.8 +index a4affc6..e28065c 100644 +--- a/doc/iscsi_discovery.8 ++++ b/doc/iscsi_discovery.8 +@@ -8,7 +8,17 @@ + .SH NAME + iscsi_discovery \- discover iSCSI targets + .SH SYNOPSIS +-.B iscsi_discovery [-p ] [-d] [-t [-f]] [-m] [-l] ++.B iscsi_discovery ++.I ++.RB [ -p ++.IR ] ++.RB [ -d ] ++.RB [\ -t ++.IR ++.RB [ -f ] ++.R ] ++.RB [ -m ] ++.RB [ -l ] + + .SH DESCRIPTION + Perform send-targets discovery to the specified IP. If a discovery record +diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8 +index 7c209f6..c7d8c92 100644 +--- a/doc/iscsiadm.8 ++++ b/doc/iscsiadm.8 +@@ -2,23 +2,161 @@ + .SH NAME + iscsiadm \- open-iscsi administration utility + .SH SYNOPSIS +-\fBiscsiadm\fR \-m discoverydb [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-I iface \-t type \-p ip:port [ \-lD ] ] | [ [ -p ip:port -t type ] \ +-[ \-o operation ] [ \-n name ] [ \-v value ] [ \-lD ] ] ++.B iscsiadm ++.B \-m discoverydb ++.RB [ \-hV ] ++.RB [ \-d ++.IR debug_level ] ++.RB [ \-P ++.IR printlevel ] ++.R [\ ++.BI \-I\ iface\ \-t\ type\ \-p\ ip:port ++.RB [ \-lD ] ++.R ] | [ ++.RB [ \-p ++.I ip:port ++.B \-t ++.IR type ] ++.RB [ \-o ++.IR operation ] ++.RB [ \-n ++.IR name ] ++.RB [ \-v ++.IR value ] ++.RB [ \-lD ] ++.R ] + +-\fBiscsiadm\fR \-m discovery [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-I iface \-t type \-p ip:port [ \-l ] ] | [ [ -p ip:port ] [ \-l | \-D ] ] ++.B iscsiadm ++.B \-m discovery ++.RB [ \-hV ] ++.RB [ \-d ++.IR debug_level ] ++.RB [ \-P ++.IR printlevel ] ++.R [\ ++.BI \-I\ iface\ \-t\ type\ \-p\ ip:port ++.RB [ \-l ] ++.R ] | [ ++.RB [ \-p ++.IR ip:port ] ++.RB [ \-l | \-D ] ++.R ] + +-\fBiscsiadm\fR \-m node [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-L all,manual,automatic ] [ \-U all,manual,automatic ] [ \-S ] [ [ \-T targetname \-p ip:port \-I iface ] [ \-l | \-u | \-R | \-s] ] +-[ [ \-o operation ] [ \-n name ] [ \-v value ] [ \-p ip:port ] ] ++.B iscsiadm ++.B \-m node ++.RB [ \-hV ] ++.RB [ \-d ++.IR debug_level ] ++.RB [ \-P ++.IR printlevel ] ++.RB [ \-L ++.IR all,manual,automatic ] ++.RB [ \-U ++.IR all,manual,automatic ] ++.RB [ \-S ] ++.R [ ++.RB [ \-T ++.IB targetname\ \-p\ ip:port\ \-I\ iface ++.R ] ++.RB [ \-l | \-u | \-R | \-s ] ++.R ] ++.R [ ++.RB [ \-o ++.IR operation ] ++.RB [ \-n ++.IR name ] ++.RB [ \-v ++.IR value ] ++.RB [ \-p ++.IR ip:port ] ++.R ] + +-\fBiscsiadm\fR \-m session [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-r sessionid | sysfsdir [ \-R ] [ \-u | \-s | \-o new ] ] ++.B iscsiadm ++.B \-m session ++.RB[ \-hV ] ++.RB [ \-d ++.IR debug_level ] ++.RB [ \-P ++.IR printlevel ] ++.R [ ++.B \-r ++.IR sessionid | sysfsdir ++.RB [ \-R ] ++.RB [ \-u | \-s | \-o ++.IR new ] ++.R ] + +-\fBiscsiadm\fR \-m iface [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-I ifacename | \-H hostno|MAC ] [ [ \-o operation ] [ \-n name ] [ \-v value ] ] [ \-C ping [ \-a ip ] [ \-b packetsize ] [ \-c count ] [ \-i interval ] ] ++.B iscsiadm ++.B \-m iface ++.RB [ \-hV ] ++.RB [ \-d ++.IR debug_level ] ++.RB [ \-P ++.IR printlevel ] ++.R [ ++.BI \-I\ ifacename ++.R | ++.BI \-H\ hostno|MAC ++.R ] ++.R [ ++.RB [ \-o ++.IR operation ] ++.RB [ \-n ++.IR name ] ++.RB [ \-v ++.IR value ] ++.R ] ++.R [ ++.BI \-C\ ping ++.RB [ \-a ++.IR ip ] ++.RB [ \-b ++.IR packetsize ] ++.RB [ \-c ++.IR count ] ++.RB [ \-i ++.IR interval ] ++.R ] + +-\fBiscsiadm\fR \-m fw [\-l] ++.B iscsiadm ++.B \-m fw ++.RB [ \-d ++.IR debug_level ] ++.RB [ \-l ] + +-\fBiscsiadm\fR \-m host [ \-P printlevel ] [ \-H hostno|MAC ] [ -C chap [ -o operation ] [ -v chap_tbl_idx ] ] ++.B iscsiadm ++.B \-m host ++.RB [ \-P ++.IR printlevel ] ++.RB [ \-H ++.IR hostno|MAC ] ++.R [ ++.RB [\ \-C ++.IR chap ++.RB [ \-x ++.IR chap_tbl_idx ] ++.R ] | ++.RB [\ \-C ++.IR flashnode ++.RB [ \-A ++.IR portal_type ] ++.RB [ \-x ++.IR flashnode_idx ] ++.R ] | ++.RB [\ \-C ++.IR stats \ ] ++.R ] ++.R [ ++.RB [ \-o ++.IR operation ] ++.RB [ \-n ++.IR name ] ++.RB [ \-v ++.IR value ] ++.R ] + +-\fBiscsiadm\fR \-k priority ++.B iscsiadm ++.B \-k priority + + .SH "DESCRIPTION" + The iscsiadm utility is a command-line tool allowing discovery and login +@@ -47,6 +185,12 @@ daemon (iscsid) be running. + This option is only valid for ping submode. + + .TP ++\fB\-A\fR, \fB\-\-portal_type=\fI[ipv4|ipv6]\fR ++Specify the portal type for the new flash node entry to be created. ++.IP ++This option is only valid for flashnode submode of host mode and only with \fInew\fR operation. ++ ++.TP + \fB\-b\fR, \fB\-\-packetsize=\fIpacketsize\fP + Specify the ping \fIpacketsize\fR. + +@@ -64,7 +208,15 @@ Specify the submode for mode. op must be name of submode. + + Currently iscsiadm support ping as submode for iface. For example, + +-iscsiadm -m iface -I ifacename -C ping -a ipaddr -b packetsize -c count -i interval ++iscsiadm \-m iface \-I ifacename \-C ping \-a ipaddr \-b packetsize \-c count \-i interval ++ ++For host, it supports chap , flashnode and stats as submodes. For example, ++ ++iscsiadm \-m host \-H hostno \-C chap \-x chap_tbl_idx \-o operation ++ ++iscsiadm \-m host \-H hostno \-C flashnode \-x flashnode_idx \-o operation ++ ++iscsiadm \-m host \-H hostno \-C stats + + .TP + \fB\-d\fR, \fB\-\-debug=\fIdebug_level\fP +@@ -113,7 +265,7 @@ are experimental and the use is not supported as a stable interface yet. + In discovery mode multiple interfaces can be specified by passing in multiple + \-I/\-\-interface instances. For example, + +-"iscsiadm \-m discoverydb \-t st \-p ip:port \-I iface0 \-I iface2 --discover" ++"iscsiadm \-m discoverydb \-t st \-p ip:port \-I iface0 \-I iface2 \-\-discover" + + Will direct iscsiadm to setup the node db to create records which will create + sessions though the two intefaces passed in. +@@ -160,18 +312,19 @@ for session mode). + .TP + \fB\-m, \-\-mode \fIop\fR + specify the mode. \fIop\fR +-must be one of \fIdiscoverydb\fR, \fInode\fR, \fIfw\fR, \fIhost\fR \fIiface\fR or \fIsession\fR. ++must be one of \fIdiscovery\fR, \fIdiscoverydb\fR, \fInode\fR, \fIfw\fR, \fIhost\fR \fIiface\fR or \fIsession\fR. + .IP +-If no other options are specified: for \fIdiscoverydb\fR and \fInode\fR, all +-of their respective records are displayed; for \fIsession\fR, all active +-sessions and connections are displayed; for \fIfw\fR, all boot firmware +-values are displayed; for \fIhost\fR, all iSCSI hosts are displayed; and +-for \fIiface\fR, all ifaces setup in /etc/iscsi/ifaces are displayed. ++If no other options are specified: for \fIdiscovery\fR, \fIdiscoverydb\fR and ++\fInode\fR, all of their respective records are displayed; for \fIsession\fR, ++all active sessions and connections are displayed; for \fIfw\fR, all boot ++firmware values are displayed; for \fIhost\fR, all iSCSI hosts are displayed; ++and for \fIiface\fR, all ifaces setup in /etc/iscsi/ifaces are displayed. + + .TP + \fB\-n\fR, \fB\-\-name=\fIname\fR +-Specify a field \fIname\fR in a record. For use with the \fIupdate\fR +-operator. ++In node mode, specify a field \fIname\fR in a record. In flashnode submode of host mode, specify name of the flash node parameter. ++ ++For use with the \fIupdate\fR operator. + .IP + + .TP +@@ -181,6 +334,8 @@ Specifies a database operator \fIop\fR. \fIop\fR must be one of + .IP + For iface mode, \fIapply\fR and \fIapplyall\fR are also applicable. + .IP ++For flashnode submode of host mode, \fIlogin\fR and \fIlogout\fR are also applicable. ++.IP + This option is valid for all modes except fw. Delete should not be used on a running session. If it is iscsiadm will stop the session and then delete the + record. + .IP +@@ -210,6 +365,12 @@ sid is passed in. + .IP + \fIapplyall\fR will cause the network settings to take effect on all the ifaces whose MAC address or host number matches that of the specific host. + ++.IP ++\fIlogin\fR will log into the specified flash node entry. ++ ++.IP ++\fIlogout\fR does the logout from the given flash node entry. ++ + .TP + \fB\-p\fR, \fB\-\-portal=\fIip[:port]\fR + Use target portal with ip-address \fIip\fR and \fIport\fR. If port is not passed +@@ -258,6 +419,7 @@ tuple passed in. + .TP + \fB\-s\fR, \fB\-\-stats\fR + Display session statistics. ++This option when used with host mode, displays host statistics. + + .TP + \fB\-S\fR, \fB\-\-show\fR +@@ -292,12 +454,18 @@ for session mode). + \fB\-v\fR, \fB\-\-value=\fIvalue\fR + Specify a \fIvalue\fR for use with the \fIupdate\fR operator. + .IP +-This option is only valid for node mode. ++This option is only valid for node mode and flashnode submode of host mode. + + .TP + \fB\-V\fR, \fB\-\-version\fR + display version and exit + ++.TP ++\fB\-x\fR, \fB\-\-index=\fIindex\fR ++Specify the \fIindex\fR of the entity to operate on. ++.IP ++This option is only valid for chap and flashnode submodes of host mode. ++ + .SH DISCOVERY TYPES + iSCSI defines 3 discovery types: SendTargets, SLP, and iSNS. + +@@ -460,7 +628,7 @@ ISCSI_ERR_FATAL_LOGIN - fatal iSCSI login error. + .TP + .B + 20 +-ISCSI_ERR_ISCSID_NOTCONN - could ont connect to iscsid. ++ISCSI_ERR_ISCSID_NOTCONN - could not connect to iscsid. + + .TP + .B +diff --git a/etc/iscsid.conf b/etc/iscsid.conf +index ef76dc0..c30a7dc 100644 +--- a/etc/iscsid.conf ++++ b/etc/iscsid.conf +@@ -22,6 +22,9 @@ + # Default for upstream open-iscsi scripts (uncomment to activate). + iscsid.startup = /sbin/iscsid + ++# Check for active mounts on devices reachable through a session ++# and refuse to logout if there are any. Defaults to "No". ++# iscsid.safe_logout = Yes + + ############################# + # NIC/HBA and driver settings +@@ -80,7 +83,7 @@ node.leading_login = No + # Timeouts + # ******** + # +-# See the iSCSI REAME's Advanced Configuration section for tips ++# See the iSCSI README's Advanced Configuration section for tips + # on setting timeouts when using multipath or doing root over iSCSI. + # + # To specify the length of time to wait for session re-establishment +diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service +new file mode 100644 +index 0000000..028e0b3 +--- /dev/null ++++ b/etc/systemd/iscsid.service +@@ -0,0 +1,13 @@ ++[Unit] ++Description=Open-iSCSI ++Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) ++After=network.target NetworkManager-wait-online.service iscsiuio.service tgtd.service targetcli.service ++ ++[Service] ++Type=forking ++PIDFile=/var/run/iscsid.pid ++ExecStart=/usr/sbin/iscsid ++ExecStop=/sbin/iscsiadm -k 0 2 ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/etc/systemd/iscsid.socket b/etc/systemd/iscsid.socket +new file mode 100644 +index 0000000..832451d +--- /dev/null ++++ b/etc/systemd/iscsid.socket +@@ -0,0 +1,9 @@ ++[Unit] ++Description=Open-iSCSI iscsid Socket ++Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) ++ ++[Socket] ++ListenStream=@ISCSIADM_ABSTRACT_NAMESPACE ++ ++[Install] ++WantedBy=sockets.target +diff --git a/include/fw_context.h b/include/fw_context.h +index 1640859..44053d8 100644 +--- a/include/fw_context.h ++++ b/include/fw_context.h +@@ -28,10 +28,23 @@ + #include "list.h" + #include "auth.h" + ++enum ibft_ip_prefix_origin { ++ IBFT_IP_PREFIX_ORIGIN_OTHER = 0, ++ IBFT_IP_PREFIX_ORIGIN_MANUAL, ++ IBFT_IP_PREFIX_ORIGIN_WELL_KNOWN, ++ IBFT_IP_PREFIX_ORIGIN_DHCP, ++ IBFT_IP_PREFIX_ORIGIN_ROUTER_ADVERTISEMENT, ++ IBFT_IP_PREFIX_ORIGIN_UNCHANGED = 16 ++}; ++ + struct boot_context { + struct list_head list; ++ char boot_root[BOOT_NAME_MAXLEN]; ++ char boot_nic[BOOT_NAME_MAXLEN]; ++ char boot_target[BOOT_NAME_MAXLEN]; + + /* target settings */ ++ int target_flags; + int target_port; + char targetname[TARGET_NAME_MAXLEN + 1]; + char target_ipaddr[NI_MAXHOST]; +@@ -45,6 +58,8 @@ struct boot_context { + char initiatorname[TARGET_NAME_MAXLEN + 1]; + + /* network settings */ ++ int nic_flags; ++ enum ibft_ip_prefix_origin origin; + char dhcp[NI_MAXHOST]; + char iface[IF_NAMESIZE]; + char mac[18]; +diff --git a/include/iscsi_err.h b/include/iscsi_err.h +index aabea4e..125f443 100644 +--- a/include/iscsi_err.h ++++ b/include/iscsi_err.h +@@ -62,6 +62,10 @@ enum { + ISCSI_ERR_OP_NOT_SUPP = 27, + /* device or resource in use */ + ISCSI_ERR_BUSY = 28, ++ /* Operation failed, but retrying layer may succeed */ ++ ISCSI_ERR_AGAIN = 29, ++ /* unknown discovery type */ ++ ISCSI_ERR_UNKNOWN_DISCOVERY_TYPE = 30, + + /* Always last. Indicates end of error code space */ + ISCSI_MAX_ERR_VAL, +diff --git a/include/iscsi_if.h b/include/iscsi_if.h +index dad9fd8..9d15811 100644 +--- a/include/iscsi_if.h ++++ b/include/iscsi_if.h +@@ -68,8 +68,15 @@ enum iscsi_uevent_e { + ISCSI_UEVENT_PING = UEVENT_BASE + 22, + ISCSI_UEVENT_GET_CHAP = UEVENT_BASE + 23, + ISCSI_UEVENT_DELETE_CHAP = UEVENT_BASE + 24, +- +- ISCSI_UEVENT_MAX = ISCSI_UEVENT_DELETE_CHAP, ++ ISCSI_UEVENT_SET_FLASHNODE_PARAMS = UEVENT_BASE + 25, ++ ISCSI_UEVENT_NEW_FLASHNODE = UEVENT_BASE + 26, ++ ISCSI_UEVENT_DEL_FLASHNODE = UEVENT_BASE + 27, ++ ISCSI_UEVENT_LOGIN_FLASHNODE = UEVENT_BASE + 28, ++ ISCSI_UEVENT_LOGOUT_FLASHNODE = UEVENT_BASE + 29, ++ ISCSI_UEVENT_LOGOUT_FLASHNODE_SID = UEVENT_BASE + 30, ++ ISCSI_UEVENT_SET_CHAP = UEVENT_BASE + 31, ++ ISCSI_UEVENT_GET_HOST_STATS = UEVENT_BASE + 32, ++ ISCSI_UEVENT_MAX = ISCSI_UEVENT_GET_HOST_STATS, + + /* up events */ + ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, +@@ -219,6 +226,35 @@ struct iscsi_uevent { + uint32_t host_no; + uint16_t chap_tbl_idx; + } delete_chap; ++ struct msg_set_flashnode_param { ++ uint32_t host_no; ++ uint32_t flashnode_idx; ++ uint32_t count; ++ } set_flashnode; ++ struct msg_new_flashnode { ++ uint32_t host_no; ++ uint32_t len; ++ } new_flashnode; ++ struct msg_del_flashnode { ++ uint32_t host_no; ++ uint32_t flashnode_idx; ++ } del_flashnode; ++ struct msg_login_flashnode { ++ uint32_t host_no; ++ uint32_t flashnode_idx; ++ } login_flashnode; ++ struct msg_logout_flashnode { ++ uint32_t host_no; ++ uint32_t flashnode_idx; ++ } logout_flashnode; ++ struct msg_logout_flashnode_sid { ++ uint32_t host_no; ++ uint32_t sid; ++ } logout_flashnode_sid; ++ struct msg_get_host_stats { ++ uint32_t host_no; ++ } get_host_stats; ++ + } u; + union { + /* messages k -> u */ +@@ -276,6 +312,9 @@ struct iscsi_uevent { + with each ping request */ + uint32_t data_size; + } ping_comp; ++ struct msg_new_flashnode_ret { ++ uint32_t flashnode_idx; ++ } new_flashnode_ret; + } r; + } __attribute__ ((aligned (sizeof(uint64_t)))); + +@@ -283,8 +322,18 @@ enum iscsi_param_type { + ISCSI_PARAM, /* iscsi_param (session, conn, target, LU) */ + ISCSI_HOST_PARAM, /* iscsi_host_param */ + ISCSI_NET_PARAM, /* iscsi_net_param */ ++ ISCSI_FLASHNODE_PARAM, /* iscsi_flashnode_param */ ++ ISCSI_CHAP_PARAM, /* iscsi_chap_param */ ++ ISCSI_IFACE_PARAM, /* iscsi_iface_param */ + }; + ++/* structure for minimalist usecase */ ++struct iscsi_param_info { ++ uint32_t len; /* Actual length of the param value */ ++ uint16_t param; /* iscsi param */ ++ uint8_t value[0]; /* length sized value follows */ ++} __attribute__((__packed__)); ++ + struct iscsi_iface_param_info { + uint32_t iface_num; /* iface number, 0 - n */ + uint32_t len; /* Actual length of the param */ +@@ -348,28 +397,106 @@ struct iscsi_path { + #define ISCSI_VLAN_DISABLE 0x01 + #define ISCSI_VLAN_ENABLE 0x02 + ++/* iscsi generic enable/disabled setting for various features */ ++#define ISCSI_NET_PARAM_DISABLE 0x01 ++#define ISCSI_NET_PARAM_ENABLE 0x02 ++ + /* iSCSI network params */ + enum iscsi_net_param { + ISCSI_NET_PARAM_IPV4_ADDR = 1, +- ISCSI_NET_PARAM_IPV4_SUBNET = 2, +- ISCSI_NET_PARAM_IPV4_GW = 3, +- ISCSI_NET_PARAM_IPV4_BOOTPROTO = 4, +- ISCSI_NET_PARAM_MAC = 5, +- ISCSI_NET_PARAM_IPV6_LINKLOCAL = 6, +- ISCSI_NET_PARAM_IPV6_ADDR = 7, +- ISCSI_NET_PARAM_IPV6_ROUTER = 8, +- ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG = 9, +- ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG = 10, +- ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG = 11, +- ISCSI_NET_PARAM_IFACE_ENABLE = 12, +- ISCSI_NET_PARAM_VLAN_ID = 13, +- ISCSI_NET_PARAM_VLAN_PRIORITY = 14, +- ISCSI_NET_PARAM_VLAN_ENABLED = 15, +- ISCSI_NET_PARAM_VLAN_TAG = 16, +- ISCSI_NET_PARAM_IFACE_TYPE = 17, +- ISCSI_NET_PARAM_IFACE_NAME = 18, +- ISCSI_NET_PARAM_MTU = 19, +- ISCSI_NET_PARAM_PORT = 20, ++ ISCSI_NET_PARAM_IPV4_SUBNET, ++ ISCSI_NET_PARAM_IPV4_GW, ++ ISCSI_NET_PARAM_IPV4_BOOTPROTO, ++ ISCSI_NET_PARAM_MAC, ++ ISCSI_NET_PARAM_IPV6_LINKLOCAL, ++ ISCSI_NET_PARAM_IPV6_ADDR, ++ ISCSI_NET_PARAM_IPV6_ROUTER, ++ ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG, ++ ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG, ++ ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG, ++ ISCSI_NET_PARAM_IFACE_ENABLE, ++ ISCSI_NET_PARAM_VLAN_ID, ++ ISCSI_NET_PARAM_VLAN_PRIORITY, ++ ISCSI_NET_PARAM_VLAN_ENABLED, ++ ISCSI_NET_PARAM_VLAN_TAG, ++ ISCSI_NET_PARAM_IFACE_TYPE, ++ ISCSI_NET_PARAM_IFACE_NAME, ++ ISCSI_NET_PARAM_MTU, ++ ISCSI_NET_PARAM_PORT, ++ ISCSI_NET_PARAM_IPADDR_STATE, ++ ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE, ++ ISCSI_NET_PARAM_IPV6_ROUTER_STATE, ++ ISCSI_NET_PARAM_DELAYED_ACK_EN, ++ ISCSI_NET_PARAM_TCP_NAGLE_DISABLE, ++ ISCSI_NET_PARAM_TCP_WSF_DISABLE, ++ ISCSI_NET_PARAM_TCP_WSF, ++ ISCSI_NET_PARAM_TCP_TIMER_SCALE, ++ ISCSI_NET_PARAM_TCP_TIMESTAMP_EN, ++ ISCSI_NET_PARAM_CACHE_ID, ++ ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN, ++ ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN, ++ ISCSI_NET_PARAM_IPV4_TOS_EN, ++ ISCSI_NET_PARAM_IPV4_TOS, ++ ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN, ++ ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN, ++ ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID, ++ ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN, ++ ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN, ++ ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID, ++ ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN, ++ ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE, ++ ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN, ++ ISCSI_NET_PARAM_IPV4_TTL, ++ ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN, ++ ISCSI_NET_PARAM_IPV6_MLD_EN, ++ ISCSI_NET_PARAM_IPV6_FLOW_LABEL, ++ ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS, ++ ISCSI_NET_PARAM_IPV6_HOP_LIMIT, ++ ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO, ++ ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME, ++ ISCSI_NET_PARAM_IPV6_ND_STALE_TMO, ++ ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT, ++ ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU, ++ ISCSI_NET_PARAM_REDIRECT_EN, ++}; ++ ++enum iscsi_ipaddress_state { ++ ISCSI_IPDDRESS_STATE_UNCONFIGURED, ++ ISCSI_IPDDRESS_STATE_ACQUIRING, ++ ISCSI_IPDDRESS_STATE_TENTATIVE, ++ ISCSI_IPDDRESS_STATE_VALID, ++ ISCSI_IPDDRESS_STATE_DISABLING, ++ ISCSI_IPDDRESS_STATE_INVALID, ++ ISCSI_IPDDRESS_STATE_DEPRECATED, ++}; ++ ++enum iscsi_router_state { ++ ISCSI_ROUTER_STATE_UNKNOWN, ++ ISCSI_ROUTER_STATE_ADVERTISED, ++ ISCSI_ROUTER_STATE_MANUAL, ++ ISCSI_ROUTER_STATE_STALE, ++}; ++ ++/* iSCSI specific settings params for iface */ ++enum iscsi_iface_param { ++ ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO, ++ ISCSI_IFACE_PARAM_HDRDGST_EN, ++ ISCSI_IFACE_PARAM_DATADGST_EN, ++ ISCSI_IFACE_PARAM_IMM_DATA_EN, ++ ISCSI_IFACE_PARAM_INITIAL_R2T_EN, ++ ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN, ++ ISCSI_IFACE_PARAM_PDU_INORDER_EN, ++ ISCSI_IFACE_PARAM_ERL, ++ ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH, ++ ISCSI_IFACE_PARAM_FIRST_BURST, ++ ISCSI_IFACE_PARAM_MAX_R2T, ++ ISCSI_IFACE_PARAM_MAX_BURST, ++ ISCSI_IFACE_PARAM_CHAP_AUTH_EN, ++ ISCSI_IFACE_PARAM_BIDI_CHAP_EN, ++ ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL, ++ ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN, ++ ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN, ++ ISCSI_IFACE_PARAM_INITIATOR_NAME, + }; + + enum iscsi_conn_state { +@@ -460,61 +587,157 @@ enum iscsi_param { + + ISCSI_PARAM_TGT_RESET_TMO, + ISCSI_PARAM_TARGET_ALIAS, ++ ++ ISCSI_PARAM_CHAP_IN_IDX, ++ ISCSI_PARAM_CHAP_OUT_IDX, ++ ++ ISCSI_PARAM_BOOT_ROOT, ++ ISCSI_PARAM_BOOT_NIC, ++ ISCSI_PARAM_BOOT_TARGET, ++ ++ ISCSI_PARAM_AUTO_SND_TGT_DISABLE, ++ ISCSI_PARAM_DISCOVERY_SESS, ++ ISCSI_PARAM_PORTAL_TYPE, ++ ISCSI_PARAM_CHAP_AUTH_EN, ++ ISCSI_PARAM_DISCOVERY_LOGOUT_EN, ++ ISCSI_PARAM_BIDI_CHAP_EN, ++ ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL, ++ ++ ISCSI_PARAM_DEF_TIME2WAIT, ++ ISCSI_PARAM_DEF_TIME2RETAIN, ++ ISCSI_PARAM_MAX_SEGMENT_SIZE, ++ ISCSI_PARAM_STATSN, ++ ISCSI_PARAM_KEEPALIVE_TMO, ++ ISCSI_PARAM_LOCAL_PORT, ++ ISCSI_PARAM_TSID, ++ ISCSI_PARAM_DEF_TASKMGMT_TMO, ++ ++ ISCSI_PARAM_TCP_TIMESTAMP_STAT, ++ ISCSI_PARAM_TCP_WSF_DISABLE, ++ ISCSI_PARAM_TCP_NAGLE_DISABLE, ++ ISCSI_PARAM_TCP_TIMER_SCALE, ++ ISCSI_PARAM_TCP_TIMESTAMP_EN, ++ ISCSI_PARAM_TCP_XMIT_WSF, ++ ISCSI_PARAM_TCP_RECV_WSF, ++ ISCSI_PARAM_IP_FRAGMENT_DISABLE, ++ ISCSI_PARAM_IPV4_TOS, ++ ISCSI_PARAM_IPV6_TC, ++ ISCSI_PARAM_IPV6_FLOW_LABEL, ++ ISCSI_PARAM_IS_FW_ASSIGNED_IPV6, ++ ++ ISCSI_PARAM_DISCOVERY_PARENT_IDX, ++ ISCSI_PARAM_DISCOVERY_PARENT_TYPE, + /* must always be last */ + ISCSI_PARAM_MAX, + }; + +-#define ISCSI_MAX_RECV_DLENGTH (1ULL << ISCSI_PARAM_MAX_RECV_DLENGTH) +-#define ISCSI_MAX_XMIT_DLENGTH (1ULL << ISCSI_PARAM_MAX_XMIT_DLENGTH) +-#define ISCSI_HDRDGST_EN (1ULL << ISCSI_PARAM_HDRDGST_EN) +-#define ISCSI_DATADGST_EN (1ULL << ISCSI_PARAM_DATADGST_EN) +-#define ISCSI_INITIAL_R2T_EN (1ULL << ISCSI_PARAM_INITIAL_R2T_EN) +-#define ISCSI_MAX_R2T (1ULL << ISCSI_PARAM_MAX_R2T) +-#define ISCSI_IMM_DATA_EN (1ULL << ISCSI_PARAM_IMM_DATA_EN) +-#define ISCSI_FIRST_BURST (1ULL << ISCSI_PARAM_FIRST_BURST) +-#define ISCSI_MAX_BURST (1ULL << ISCSI_PARAM_MAX_BURST) +-#define ISCSI_PDU_INORDER_EN (1ULL << ISCSI_PARAM_PDU_INORDER_EN) +-#define ISCSI_DATASEQ_INORDER_EN (1ULL << ISCSI_PARAM_DATASEQ_INORDER_EN) +-#define ISCSI_ERL (1ULL << ISCSI_PARAM_ERL) +-#define ISCSI_IFMARKER_EN (1ULL << ISCSI_PARAM_IFMARKER_EN) +-#define ISCSI_OFMARKER_EN (1ULL << ISCSI_PARAM_OFMARKER_EN) +-#define ISCSI_EXP_STATSN (1ULL << ISCSI_PARAM_EXP_STATSN) +-#define ISCSI_TARGET_NAME (1ULL << ISCSI_PARAM_TARGET_NAME) +-#define ISCSI_TPGT (1ULL << ISCSI_PARAM_TPGT) +-#define ISCSI_PERSISTENT_ADDRESS (1ULL << ISCSI_PARAM_PERSISTENT_ADDRESS) +-#define ISCSI_PERSISTENT_PORT (1ULL << ISCSI_PARAM_PERSISTENT_PORT) +-#define ISCSI_SESS_RECOVERY_TMO (1ULL << ISCSI_PARAM_SESS_RECOVERY_TMO) +-#define ISCSI_CONN_PORT (1ULL << ISCSI_PARAM_CONN_PORT) +-#define ISCSI_CONN_ADDRESS (1ULL << ISCSI_PARAM_CONN_ADDRESS) +-#define ISCSI_USERNAME (1ULL << ISCSI_PARAM_USERNAME) +-#define ISCSI_USERNAME_IN (1ULL << ISCSI_PARAM_USERNAME_IN) +-#define ISCSI_PASSWORD (1ULL << ISCSI_PARAM_PASSWORD) +-#define ISCSI_PASSWORD_IN (1ULL << ISCSI_PARAM_PASSWORD_IN) +-#define ISCSI_FAST_ABORT (1ULL << ISCSI_PARAM_FAST_ABORT) +-#define ISCSI_ABORT_TMO (1ULL << ISCSI_PARAM_ABORT_TMO) +-#define ISCSI_LU_RESET_TMO (1ULL << ISCSI_PARAM_LU_RESET_TMO) +-#define ISCSI_HOST_RESET_TMO (1ULL << ISCSI_PARAM_HOST_RESET_TMO) +-#define ISCSI_PING_TMO (1ULL << ISCSI_PARAM_PING_TMO) +-#define ISCSI_RECV_TMO (1ULL << ISCSI_PARAM_RECV_TMO) +-#define ISCSI_IFACE_NAME (1ULL << ISCSI_PARAM_IFACE_NAME) +-#define ISCSI_ISID (1ULL << ISCSI_PARAM_ISID) +-#define ISCSI_INITIATOR_NAME (1ULL << ISCSI_PARAM_INITIATOR_NAME) +-#define ISCSI_TGT_RESET_TMO (1ULL << ISCSI_PARAM_TGT_RESET_TMO) +-#define ISCSI_TARGET_ALIAS (1ULL << ISCSI_PARAM_TARGET_ALIAS) +- + /* iSCSI HBA params */ + enum iscsi_host_param { + ISCSI_HOST_PARAM_HWADDRESS, + ISCSI_HOST_PARAM_INITIATOR_NAME, + ISCSI_HOST_PARAM_NETDEV_NAME, + ISCSI_HOST_PARAM_IPADDRESS, ++ ISCSI_HOST_PARAM_PORT_STATE, ++ ISCSI_HOST_PARAM_PORT_SPEED, + ISCSI_HOST_PARAM_MAX, + }; + +-#define ISCSI_HOST_HWADDRESS (1ULL << ISCSI_HOST_PARAM_HWADDRESS) +-#define ISCSI_HOST_INITIATOR_NAME (1ULL << ISCSI_HOST_PARAM_INITIATOR_NAME) +-#define ISCSI_HOST_NETDEV_NAME (1ULL << ISCSI_HOST_PARAM_NETDEV_NAME) +-#define ISCSI_HOST_IPADDRESS (1ULL << ISCSI_HOST_PARAM_IPADDRESS) ++/* portal type */ ++#define PORTAL_TYPE_IPV4 "ipv4" ++#define PORTAL_TYPE_IPV6 "ipv6" ++ ++/* iSCSI Flash Target params */ ++enum iscsi_flashnode_param { ++ ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6, ++ ISCSI_FLASHNODE_PORTAL_TYPE, ++ ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE, ++ ISCSI_FLASHNODE_DISCOVERY_SESS, ++ ISCSI_FLASHNODE_ENTRY_EN, ++ ISCSI_FLASHNODE_HDR_DGST_EN, ++ ISCSI_FLASHNODE_DATA_DGST_EN, ++ ISCSI_FLASHNODE_IMM_DATA_EN, ++ ISCSI_FLASHNODE_INITIAL_R2T_EN, ++ ISCSI_FLASHNODE_DATASEQ_INORDER, ++ ISCSI_FLASHNODE_PDU_INORDER, ++ ISCSI_FLASHNODE_CHAP_AUTH_EN, ++ ISCSI_FLASHNODE_SNACK_REQ_EN, ++ ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN, ++ ISCSI_FLASHNODE_BIDI_CHAP_EN, ++ /* make authentication for discovery sessions optional */ ++ ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL, ++ ISCSI_FLASHNODE_ERL, ++ ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT, ++ ISCSI_FLASHNODE_TCP_NAGLE_DISABLE, ++ ISCSI_FLASHNODE_TCP_WSF_DISABLE, ++ ISCSI_FLASHNODE_TCP_TIMER_SCALE, ++ ISCSI_FLASHNODE_TCP_TIMESTAMP_EN, ++ ISCSI_FLASHNODE_IP_FRAG_DISABLE, ++ ISCSI_FLASHNODE_MAX_RECV_DLENGTH, ++ ISCSI_FLASHNODE_MAX_XMIT_DLENGTH, ++ ISCSI_FLASHNODE_FIRST_BURST, ++ ISCSI_FLASHNODE_DEF_TIME2WAIT, ++ ISCSI_FLASHNODE_DEF_TIME2RETAIN, ++ ISCSI_FLASHNODE_MAX_R2T, ++ ISCSI_FLASHNODE_KEEPALIVE_TMO, ++ ISCSI_FLASHNODE_ISID, ++ ISCSI_FLASHNODE_TSID, ++ ISCSI_FLASHNODE_PORT, ++ ISCSI_FLASHNODE_MAX_BURST, ++ ISCSI_FLASHNODE_DEF_TASKMGMT_TMO, ++ ISCSI_FLASHNODE_IPADDR, ++ ISCSI_FLASHNODE_ALIAS, ++ ISCSI_FLASHNODE_REDIRECT_IPADDR, ++ ISCSI_FLASHNODE_MAX_SEGMENT_SIZE, ++ ISCSI_FLASHNODE_LOCAL_PORT, ++ ISCSI_FLASHNODE_IPV4_TOS, ++ ISCSI_FLASHNODE_IPV6_TC, ++ ISCSI_FLASHNODE_IPV6_FLOW_LABEL, ++ ISCSI_FLASHNODE_NAME, ++ ISCSI_FLASHNODE_TPGT, ++ ISCSI_FLASHNODE_LINK_LOCAL_IPV6, ++ ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX, ++ ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE, ++ ISCSI_FLASHNODE_TCP_XMIT_WSF, ++ ISCSI_FLASHNODE_TCP_RECV_WSF, ++ ISCSI_FLASHNODE_CHAP_IN_IDX, ++ ISCSI_FLASHNODE_CHAP_OUT_IDX, ++ ISCSI_FLASHNODE_USERNAME, ++ ISCSI_FLASHNODE_USERNAME_IN, ++ ISCSI_FLASHNODE_PASSWORD, ++ ISCSI_FLASHNODE_PASSWORD_IN, ++ ISCSI_FLASHNODE_STATSN, ++ ISCSI_FLASHNODE_EXP_STATSN, ++ ISCSI_FLASHNODE_IS_BOOT_TGT, ++ ++ ISCSI_FLASHNODE_MAX, ++}; ++ ++struct iscsi_flashnode_param_info { ++ uint32_t len; /* Actual length of the param */ ++ uint16_t param; /* iscsi param value */ ++ uint8_t value[0]; /* length sized value follows */ ++} __attribute__((__packed__)); ++ ++enum iscsi_discovery_parent_type { ++ ISCSI_DISC_PARENT_UNKNOWN = 0x1, ++ ISCSI_DISC_PARENT_SENDTGT = 0x2, ++ ISCSI_DISC_PARENT_ISNS = 0x3, ++}; ++ ++/* iSCSI port Speed */ ++enum iscsi_port_speed { ++ ISCSI_PORT_SPEED_UNKNOWN = 0x1, ++ ISCSI_PORT_SPEED_10MBPS = 0x2, ++ ISCSI_PORT_SPEED_100MBPS = 0x4, ++ ISCSI_PORT_SPEED_1GBPS = 0x8, ++ ISCSI_PORT_SPEED_10GBPS = 0x10, ++}; ++ ++/* iSCSI port state */ ++enum iscsi_port_state { ++ ISCSI_PORT_STATE_DOWN = 0x1, ++ ISCSI_PORT_STATE_UP = 0x2, ++}; + + /* iSCSI PING status/error code */ + enum iscsi_ping_status_code { +@@ -551,7 +774,7 @@ enum iscsi_ping_status_code { + #define CAP_DIGEST_OFFLOAD 0x1000 /* offload hdr and data digests */ + #define CAP_PADDING_OFFLOAD 0x2000 /* offload padding insertion, removal, + and verification */ +-#define CAP_LOGIN_OFFLOAD 0x4000 /* offload normal session login */ ++#define CAP_LOGIN_OFFLOAD 0x4000 /* offload session login */ + + /* + * These flags describes reason of stop_conn() call +@@ -617,9 +840,16 @@ enum chap_type_e { + CHAP_TYPE_IN, + }; + ++enum iscsi_chap_param { ++ ISCSI_CHAP_PARAM_INDEX, ++ ISCSI_CHAP_PARAM_CHAP_TYPE, ++ ISCSI_CHAP_PARAM_USERNAME, ++ ISCSI_CHAP_PARAM_PASSWORD, ++ ISCSI_CHAP_PARAM_PASSWORD_LEN ++}; ++ + #define ISCSI_CHAP_AUTH_NAME_MAX_LEN 256 + #define ISCSI_CHAP_AUTH_SECRET_MAX_LEN 256 +- + struct iscsi_chap_rec { + uint16_t chap_tbl_idx; + enum chap_type_e chap_type; +@@ -628,4 +858,112 @@ struct iscsi_chap_rec { + uint8_t password_length; + }; + ++#define ISCSI_HOST_STATS_CUSTOM_MAX 32 ++#define ISCSI_HOST_STATS_CUSTOM_DESC_MAX 64 ++struct iscsi_host_stats_custom { ++ char desc[ISCSI_HOST_STATS_CUSTOM_DESC_MAX]; ++ uint64_t value; ++}; ++ ++/* struct iscsi_offload_host_stats: Host statistics, ++ * Include statistics for MAC, IP, TCP & iSCSI. ++ */ ++struct iscsi_offload_host_stats { ++ /* MAC */ ++ uint64_t mactx_frames; ++ uint64_t mactx_bytes; ++ uint64_t mactx_multicast_frames; ++ uint64_t mactx_broadcast_frames; ++ uint64_t mactx_pause_frames; ++ uint64_t mactx_control_frames; ++ uint64_t mactx_deferral; ++ uint64_t mactx_excess_deferral; ++ uint64_t mactx_late_collision; ++ uint64_t mactx_abort; ++ uint64_t mactx_single_collision; ++ uint64_t mactx_multiple_collision; ++ uint64_t mactx_collision; ++ uint64_t mactx_frames_dropped; ++ uint64_t mactx_jumbo_frames; ++ uint64_t macrx_frames; ++ uint64_t macrx_bytes; ++ uint64_t macrx_unknown_control_frames; ++ uint64_t macrx_pause_frames; ++ uint64_t macrx_control_frames; ++ uint64_t macrx_dribble; ++ uint64_t macrx_frame_length_error; ++ uint64_t macrx_jabber; ++ uint64_t macrx_carrier_sense_error; ++ uint64_t macrx_frame_discarded; ++ uint64_t macrx_frames_dropped; ++ uint64_t mac_crc_error; ++ uint64_t mac_encoding_error; ++ uint64_t macrx_length_error_large; ++ uint64_t macrx_length_error_small; ++ uint64_t macrx_multicast_frames; ++ uint64_t macrx_broadcast_frames; ++ /* IP */ ++ uint64_t iptx_packets; ++ uint64_t iptx_bytes; ++ uint64_t iptx_fragments; ++ uint64_t iprx_packets; ++ uint64_t iprx_bytes; ++ uint64_t iprx_fragments; ++ uint64_t ip_datagram_reassembly; ++ uint64_t ip_invalid_address_error; ++ uint64_t ip_error_packets; ++ uint64_t ip_fragrx_overlap; ++ uint64_t ip_fragrx_outoforder; ++ uint64_t ip_datagram_reassembly_timeout; ++ uint64_t ipv6tx_packets; ++ uint64_t ipv6tx_bytes; ++ uint64_t ipv6tx_fragments; ++ uint64_t ipv6rx_packets; ++ uint64_t ipv6rx_bytes; ++ uint64_t ipv6rx_fragments; ++ uint64_t ipv6_datagram_reassembly; ++ uint64_t ipv6_invalid_address_error; ++ uint64_t ipv6_error_packets; ++ uint64_t ipv6_fragrx_overlap; ++ uint64_t ipv6_fragrx_outoforder; ++ uint64_t ipv6_datagram_reassembly_timeout; ++ /* TCP */ ++ uint64_t tcptx_segments; ++ uint64_t tcptx_bytes; ++ uint64_t tcprx_segments; ++ uint64_t tcprx_byte; ++ uint64_t tcp_duplicate_ack_retx; ++ uint64_t tcp_retx_timer_expired; ++ uint64_t tcprx_duplicate_ack; ++ uint64_t tcprx_pure_ackr; ++ uint64_t tcptx_delayed_ack; ++ uint64_t tcptx_pure_ack; ++ uint64_t tcprx_segment_error; ++ uint64_t tcprx_segment_outoforder; ++ uint64_t tcprx_window_probe; ++ uint64_t tcprx_window_update; ++ uint64_t tcptx_window_probe_persist; ++ /* ECC */ ++ uint64_t ecc_error_correction; ++ /* iSCSI */ ++ uint64_t iscsi_pdu_tx; ++ uint64_t iscsi_data_bytes_tx; ++ uint64_t iscsi_pdu_rx; ++ uint64_t iscsi_data_bytes_rx; ++ uint64_t iscsi_io_completed; ++ uint64_t iscsi_unexpected_io_rx; ++ uint64_t iscsi_format_error; ++ uint64_t iscsi_hdr_digest_error; ++ uint64_t iscsi_data_digest_error; ++ uint64_t iscsi_sequence_error; ++ /* ++ * iSCSI Custom Host Statistics support, i.e. Transport could ++ * extend existing host statistics with its own specific statistics ++ * up to ISCSI_HOST_STATS_CUSTOM_MAX ++ */ ++ uint32_t custom_length; ++ struct iscsi_host_stats_custom custom[0] ++ __attribute__ ((aligned (sizeof(uint64_t)))); ++}; ++ + #endif +diff --git a/include/iscsi_proto.h b/include/iscsi_proto.h +index 1c69feb..56f757b 100644 +--- a/include/iscsi_proto.h ++++ b/include/iscsi_proto.h +@@ -619,6 +619,7 @@ struct iscsi_reject { + #define KEY_MAXLEN 64 + #define VALUE_MAXLEN 255 + #define TARGET_NAME_MAXLEN VALUE_MAXLEN ++#define BOOT_NAME_MAXLEN 256 + + #define ISCSI_DEF_MAX_RECV_SEG_LEN 8192 + #define ISCSI_MIN_MAX_RECV_SEG_LEN 512 +diff --git a/include/list.h b/include/list.h +index cccc3c3..94ad99b 100644 +--- a/include/list.h ++++ b/include/list.h +@@ -38,6 +38,12 @@ static inline int list_empty(const struct list_head *head) + #define list_entry(ptr, type, member) \ + list_container_of(ptr, type, member) + ++#define list_first_entry(ptr, type, member) \ ++ list_entry((ptr)->next, type, member) ++ ++#define list_first_entry_or_null(ptr, type, member) \ ++ (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) ++ + #define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +diff --git a/iscsiuio/.gitignore b/iscsiuio/.gitignore +new file mode 100644 +index 0000000..a27452a +--- /dev/null ++++ b/iscsiuio/.gitignore +@@ -0,0 +1,25 @@ ++# Autogenerated files ++stamp-h1 ++Makefile.in ++Makefile ++configure ++config.h.in ++config.h ++config.guess ++config.log ++config.status ++config.sub ++COPYING ++ ++.deps ++autom4te.cache ++ ++# autotools ++aclocal.m4 ++compile ++depcomp ++install-sh ++libtool ++ltmain.sh ++missing ++ +diff --git a/iscsiuio/AUTHORS b/iscsiuio/AUTHORS +new file mode 100644 +index 0000000..e69de29 +diff --git a/iscsiuio/ChangeLog b/iscsiuio/ChangeLog +new file mode 100644 +index 0000000..a91b4d5 +--- /dev/null ++++ b/iscsiuio/ChangeLog +@@ -0,0 +1,7 @@ ++Version 0.4.1 (July 20, 2009) ++ * Fix from Mike Christie to determine page size from getpagesize() ++ rather then the constant PAGE_SIZE. PAGE_SIZE is not defined om ++ ia64 and ppc. ++ * Update documentation to indicate IPv6 is not supported ++ * Fix code to catch the message from the CNIC that the network ++ interface is going down. +diff --git a/iscsiuio/INSTALL b/iscsiuio/INSTALL +new file mode 100644 +index 0000000..c9fd2c0 +--- /dev/null ++++ b/iscsiuio/INSTALL +@@ -0,0 +1,290 @@ ++Installation Instructions ++************************* ++ ++Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, ++2006, 2007, 2008 Free Software Foundation, Inc. ++ ++ This file is free documentation; the Free Software Foundation gives ++unlimited permission to copy, distribute and modify it. ++ ++Basic Installation ++================== ++ ++ Briefly, the shell commands `./configure; make; make install' should ++configure, build, and install this package. The following ++more-detailed instructions are generic; see the `README' file for ++instructions specific to this package. ++ ++ The `configure' shell script attempts to guess correct values for ++various system-dependent variables used during compilation. It uses ++those values to create a `Makefile' in each directory of the package. ++It may also create one or more `.h' files containing system-dependent ++definitions. Finally, it creates a shell script `config.status' that ++you can run in the future to recreate the current configuration, and a ++file `config.log' containing compiler output (useful mainly for ++debugging `configure'). ++ ++ It can also use an optional file (typically called `config.cache' ++and enabled with `--cache-file=config.cache' or simply `-C') that saves ++the results of its tests to speed up reconfiguring. Caching is ++disabled by default to prevent problems with accidental use of stale ++cache files. ++ ++ If you need to do unusual things to compile the package, please try ++to figure out how `configure' could check whether to do them, and mail ++diffs or instructions to the address given in the `README' so they can ++be considered for the next release. If you are using the cache, and at ++some point `config.cache' contains results you don't want to keep, you ++may remove or edit it. ++ ++ The file `configure.ac' (or `configure.in') is used to create ++`configure' by a program called `autoconf'. You need `configure.ac' if ++you want to change it or regenerate `configure' using a newer version ++of `autoconf'. ++ ++The simplest way to compile this package is: ++ ++ 1. `cd' to the directory containing the package's source code and type ++ `./configure' to configure the package for your system. ++ ++ Running `configure' might take a while. While running, it prints ++ some messages telling which features it is checking for. ++ ++ 2. Type `make' to compile the package. ++ ++ 3. Optionally, type `make check' to run any self-tests that come with ++ the package. ++ ++ 4. Type `make install' to install the programs and any data files and ++ documentation. ++ ++ 5. You can remove the program binaries and object files from the ++ source code directory by typing `make clean'. To also remove the ++ files that `configure' created (so you can compile the package for ++ a different kind of computer), type `make distclean'. There is ++ also a `make maintainer-clean' target, but that is intended mainly ++ for the package's developers. If you use it, you may have to get ++ all sorts of other programs in order to regenerate files that came ++ with the distribution. ++ ++ 6. Often, you can also type `make uninstall' to remove the installed ++ files again. ++ ++Compilers and Options ++===================== ++ ++ Some systems require unusual options for compilation or linking that ++the `configure' script does not know about. Run `./configure --help' ++for details on some of the pertinent environment variables. ++ ++ You can give `configure' initial values for configuration parameters ++by setting variables in the command line or in the environment. Here ++is an example: ++ ++ ./configure CC=c99 CFLAGS=-g LIBS=-lposix ++ ++ *Note Defining Variables::, for more details. ++ ++Compiling For Multiple Architectures ++==================================== ++ ++ You can compile the package for more than one kind of computer at the ++same time, by placing the object files for each architecture in their ++own directory. To do this, you can use GNU `make'. `cd' to the ++directory where you want the object files and executables to go and run ++the `configure' script. `configure' automatically checks for the ++source code in the directory that `configure' is in and in `..'. ++ ++ With a non-GNU `make', it is safer to compile the package for one ++architecture at a time in the source code directory. After you have ++installed the package for one architecture, use `make distclean' before ++reconfiguring for another architecture. ++ ++ On MacOS X 10.5 and later systems, you can create libraries and ++executables that work on multiple system types--known as "fat" or ++"universal" binaries--by specifying multiple `-arch' options to the ++compiler but only a single `-arch' option to the preprocessor. Like ++this: ++ ++ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ ++ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ ++ CPP="gcc -E" CXXCPP="g++ -E" ++ ++ This is not guaranteed to produce working output in all cases, you ++may have to build one architecture at a time and combine the results ++using the `lipo' tool if you have problems. ++ ++Installation Names ++================== ++ ++ By default, `make install' installs the package's commands under ++`/usr/local/bin', include files under `/usr/local/include', etc. You ++can specify an installation prefix other than `/usr/local' by giving ++`configure' the option `--prefix=PREFIX'. ++ ++ You can specify separate installation prefixes for ++architecture-specific files and architecture-independent files. If you ++pass the option `--exec-prefix=PREFIX' to `configure', the package uses ++PREFIX as the prefix for installing programs and libraries. ++Documentation and other data files still use the regular prefix. ++ ++ In addition, if you use an unusual directory layout you can give ++options like `--bindir=DIR' to specify different values for particular ++kinds of files. Run `configure --help' for a list of the directories ++you can set and what kinds of files go in them. ++ ++ If the package supports it, you can cause programs to be installed ++with an extra prefix or suffix on their names by giving `configure' the ++option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. ++ ++Optional Features ++================= ++ ++ Some packages pay attention to `--enable-FEATURE' options to ++`configure', where FEATURE indicates an optional part of the package. ++They may also pay attention to `--with-PACKAGE' options, where PACKAGE ++is something like `gnu-as' or `x' (for the X Window System). The ++`README' should mention any `--enable-' and `--with-' options that the ++package recognizes. ++ ++ For packages that use the X Window System, `configure' can usually ++find the X include and library files automatically, but if it doesn't, ++you can use the `configure' options `--x-includes=DIR' and ++`--x-libraries=DIR' to specify their locations. ++ ++Particular systems ++================== ++ ++ On HP-UX, the default C compiler is not ANSI C compatible. If GNU ++CC is not installed, it is recommended to use the following options in ++order to use an ANSI C compiler: ++ ++ ./configure CC="cc -Ae" ++ ++and if that doesn't work, install pre-built binaries of GCC for HP-UX. ++ ++ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot ++parse its `' header file. The option `-nodtk' can be used as ++a workaround. If GNU CC is not installed, it is therefore recommended ++to try ++ ++ ./configure CC="cc" ++ ++and if that doesn't work, try ++ ++ ./configure CC="cc -nodtk" ++ ++Specifying the System Type ++========================== ++ ++ There may be some features `configure' cannot figure out ++automatically, but needs to determine by the type of machine the package ++will run on. Usually, assuming the package is built to be run on the ++_same_ architectures, `configure' can figure that out, but if it prints ++a message saying it cannot guess the machine type, give it the ++`--build=TYPE' option. TYPE can either be a short name for the system ++type, such as `sun4', or a canonical name which has the form: ++ ++ CPU-COMPANY-SYSTEM ++ ++where SYSTEM can have one of these forms: ++ ++ OS KERNEL-OS ++ ++ See the file `config.sub' for the possible values of each field. If ++`config.sub' isn't included in this package, then this package doesn't ++need to know the machine type. ++ ++ If you are _building_ compiler tools for cross-compiling, you should ++use the option `--target=TYPE' to select the type of system they will ++produce code for. ++ ++ If you want to _use_ a cross compiler, that generates code for a ++platform different from the build platform, you should specify the ++"host" platform (i.e., that on which the generated programs will ++eventually be run) with `--host=TYPE'. ++ ++Sharing Defaults ++================ ++ ++ If you want to set default values for `configure' scripts to share, ++you can create a site shell script called `config.site' that gives ++default values for variables like `CC', `cache_file', and `prefix'. ++`configure' looks for `PREFIX/share/config.site' if it exists, then ++`PREFIX/etc/config.site' if it exists. Or, you can set the ++`CONFIG_SITE' environment variable to the location of the site script. ++A warning: not all `configure' scripts look for a site script. ++ ++Defining Variables ++================== ++ ++ Variables not defined in a site shell script can be set in the ++environment passed to `configure'. However, some packages may run ++configure again during the build, and the customized values of these ++variables may be lost. In order to avoid this problem, you should set ++them in the `configure' command line, using `VAR=value'. For example: ++ ++ ./configure CC=/usr/local2/bin/gcc ++ ++causes the specified `gcc' to be used as the C compiler (unless it is ++overridden in the site shell script). ++ ++Unfortunately, this technique does not work for `CONFIG_SHELL' due to ++an Autoconf bug. Until the bug is fixed you can use this workaround: ++ ++ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash ++ ++`configure' Invocation ++====================== ++ ++ `configure' recognizes the following options to control how it ++operates. ++ ++`--help' ++`-h' ++ Print a summary of all of the options to `configure', and exit. ++ ++`--help=short' ++`--help=recursive' ++ Print a summary of the options unique to this package's ++ `configure', and exit. The `short' variant lists options used ++ only in the top level, while the `recursive' variant lists options ++ also present in any nested packages. ++ ++`--version' ++`-V' ++ Print the version of Autoconf used to generate the `configure' ++ script, and exit. ++ ++`--cache-file=FILE' ++ Enable the cache: use and save the results of the tests in FILE, ++ traditionally `config.cache'. FILE defaults to `/dev/null' to ++ disable caching. ++ ++`--config-cache' ++`-C' ++ Alias for `--cache-file=config.cache'. ++ ++`--quiet' ++`--silent' ++`-q' ++ Do not print messages saying which checks are being made. To ++ suppress all normal output, redirect it to `/dev/null' (any error ++ messages will still be shown). ++ ++`--srcdir=DIR' ++ Look for the package's source code in directory DIR. Usually ++ `configure' can determine that directory automatically. ++ ++`--prefix=DIR' ++ Use DIR as the installation prefix. *Note Installation Names:: ++ for more details, including other options available for fine-tuning ++ the installation locations. ++ ++`--no-create' ++`-n' ++ Run the configure checks, but stop before creating any output ++ files. ++ ++`configure' also accepts some other, not widely useful, options. Run ++`configure --help' for more details. +diff --git a/iscsiuio/Makefile.am b/iscsiuio/Makefile.am +new file mode 100644 +index 0000000..28dd776 +--- /dev/null ++++ b/iscsiuio/Makefile.am +@@ -0,0 +1,25 @@ ++SUBDIRS= src ++ ++EXTRA_DIST = build_date ++ ++build_date: ++ echo 'char *build_date = "'`date`'";' > build_date.c ++ echo 'char *build_date;'> build_date.h ++ ++manprefix = /usr/share ++mandir = ${manprefix}/man ++logdir = /etc/logrotate.d ++ ++install-am: all-am ++ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install-man install-log install-brcm ++ ++install-man: ++ cat docs/iscsiuio.8 | GZIP=$(GZIP_ENV) gzip -c > iscsiuio.8.gz ++ $(INSTALL_PROGRAM) iscsiuio.8.gz $(mandir)/man8 ++ ++install-log: ++ $(INSTALL_PROGRAM) iscsiuiolog $(logdir) ++ ++install-brcm: ++ -rm -f $(sbindir)/brcm_iscsiuio ++ -ln -s $(sbindir)/iscsiuio $(sbindir)/brcm_iscsiuio +diff --git a/iscsiuio/NEWS b/iscsiuio/NEWS +new file mode 100644 +index 0000000..e69de29 +diff --git a/iscsiuio/README b/iscsiuio/README +new file mode 100644 +index 0000000..9ae1411 +--- /dev/null ++++ b/iscsiuio/README +@@ -0,0 +1,224 @@ ++Iscsiuio Userspace Tool ++Version 0.7.8.2 ++Dec 10, 2013 ++------------------------------------------------------ ++ ++This tool is to be used in conjunction with the QLogic NetXtreme II Linux ++driver (Kernel module name: 'bnx2' and 'bnx2x'), QLogic CNIC driver, ++and the QLogic iSCSI driver (Kernel module name: 'bnx2i'). ++This user space tool is used in conjunction with the following ++QLogic Network Controllers: ++ bnx2: BCM5706, BCM5708, BCM5709 devices ++ bnx2x: BCM57710, BCM57711, BCM57711E, BCM57712, BCM57712E, ++ BCM57800, BCM57810, BCM57840 devices ++ ++This utility will provide the ARP and DHCP functionality for the iSCSI offload. ++The communication to the driver is done via Userspace I/O (Kernel module name ++'uio'). ++ ++There is one component to this application: ++ ++1. 'iscsiuio' - This is the daemon which aids in creating iSCSI offloaded ++ connections. ++ ++Dependencies: ++======================================= ++ ++Linux Kernel Dependencies: ++1. QLogic CNIC driver (cnic) ++1. QLogic iSCSI offload driver (bnx2i) ++2. Userspace I/O driver (uio) ++ ++Directory Structure of this Package: ++======================================= ++ ++ ++ | ++ +-doc (documentation directory: man pages) ++ | ++ +-src ++ | ++ +- uip - the uIP stack ++ | ++ +- unix - iscsiuio source ++ ++ ++ ++Compiling / Installing ++======================================= ++ ++1. Please untar the tarball. ++2. Run the configure script. This will create the Makefiles and proper ++ header files needed for the build. ++3. Run 'make'. This will create the binary, 'iscsiuio' ++4. Run 'make install' to place the binaries in their installed location. ++ (The default location is '/sbin') ++ ++iscsid IFACE Configuration File: ++======================================= ++The network interface configuration files are driven by the iscsid iface ++files. The configuration data is parsed by iscsid and passed to the uIP ++stack when the connection is established. ++ ++One can use the following iscsiadm commands to create/set the configuration ++using the iface files: ++ ++1. Create the iface file: ++ ++ iscsiadm -m iface -I --op=new ++ ++2. Discover the targets associated with the new iface ++ ++ iscsiadm -m discovery -t st -p -I ++ ++3. Update the iface file: ++ ++ To use a static IPv4 address: ++ iscsiadm -m iface -I --op=update --name=iface.ipaddress --value= ++ ++ To use a DHCP address: ++ iscsiadm -m iface -I --op=update --name=iface.ipaddress --value=0.0.0.0 ++ ++ The following values are required. ++ ++ To specify the bnx2i as the transport: ++ iscsiadm -m iface -I --op=update --name=iface.transport_name --value=bnx2i ++ ++ To specify the network interface to offload with: ++ ++ a. Specify the physical network interface name ++ iscsiadm -m iface -I --op=update --name=iface.net_ifacename --value= ++ ++ b. Specify the iSCSI MAC address of the iSCSI HBA ++ iscsiadm -m iface -I --op=update --name=iface.hwaddress --value= ++ ++4. Now all the settings should be set so that one could connect to their ++ desired iSCSI target. ++ ++ iscsiadm -m node -p -T -I --login ++ ++bnx2 Limitations: ++======================================= ++* RX iSCSI ring: ++ * default ring size is 3 entries ++ * default buffer size is 0x400 bytes ++* TX iSCSI ring: ++ * default ring size of 1 entry ++ * default buffer size is 0x400 bytes ++ ++bnx2x Limitations: ++======================================= ++* RX iSCSI ring: ++ * default ring size is 15 entries ++ * default buffer size is 0x400 bytes ++* TX iSCSI ring: ++ * default ring size of 1 entry ++ * default buffer size is 0x400 bytes ++ ++Other Limiations: ++ ++Any packets larger then the buffer size will not be sent/received by the ++hardware and will be dropped. ++ ++IPv6 support: ++ ++IPv6 NDP (neighbor discovery protocol), DHCPv6 and Static IPv6 are now ++supported. The IPv6 address used for the connection will be matched against ++the DHCPv6/static IPv6 address, the RA (router advertise) address, and the ++assigned link local address. ++ ++VLAN support: ++ ++VLAN support is only supported when using static IP addresses. ++Also, currently only 1 VLAN is supported per physical network interface. ++Either non-VLAN offloaded traffic is allowed or VLAN offloaded traffic ++is allowed. The current implementation does not support both at the ++same time. ++ ++Currently there is no explicit VLAN attributes in the iface file. ++To configure the VLAN offload, the iface.hwaddress attribute or ++physical net_ifacename (without the VLAN identifier) must be used ++to specify the HBA device. For the proper CNIC routing, the ++corresponding L2 interface which has the associated VLAN interface must ++have an IP address on the same subnet. ++ ++The following attributes need to be filled when offloading via the ++VLAN interface: ++ ++ iface.iscsi_ifacename = ++ iface.hwaddress = XX:XX:XX:XX:XX:XX ++ iface.ipaddress = XX.XX.XX.XX ++ iface.transport_name = bnx2i ++ ++Setting IP address: ++ ++On RHEL5.4, RHEL5.5+, RHEL6.0+, and SLES11SP1 distributions, ++discovery login is done over the Linux TCP/IP stack and L2 network ++interface. The ethx interface corresponding to the HBA must ++therefore be in the same IP subnet in order to reach the iSCSI ++target during discovery. However, the HBA's IP address should not ++be the same as the L2 ethx's IP address. ++ ++Starting with RHEL6.1 and all other newer distributions, discovery ++using SendTargets is done over the HBA interface, so there is no ++need for the HBA and L2 network to be on the same subnet. However, ++if VLAN is used on the HBA, they still have to be on the same subnet ++as described above. ++ ++ ++Setting Netmask and Gateway addresses: ++ ++With the current limitations of the iface file, there are no entries ++to allow the user to enter a netmask or gateway IP address. ++ ++The only way to explicitly configure these options is to use DHCP ++addressing. Then the netmask/gateway are set on the DHCP server. ++These settings are then sent to uIP via the DHCPOFFERs. ++ ++If the netmask is not defined then the netmask are automatically ++generated depending on the destination IP address. ++ ++Debugging: ++======================================= ++ ++By default, the iscsiuio daemon does not output any messages to the log file, ++'/var/log/iscsiuio.log'. Message logging is only enabled when the daemon is ++run under debug mode. ++ ++To run the daemon in debug mode please pass the parameter '-d ' ++ ++where the following debug levels are defined: ++ ++DEBUG 4 - Print all messages ++INFO 3 - Print messages needed to follow the uIP code (default) ++WARN 2 - Print warning messages ++ERROR 1 - Only print critical errors ++ ++A sample banner message: ++ ++INFO [Mon Jun 20 11:23:14 2011]Started iSCSI uio stack: Ver 0.7.0.6 ++INFO [Mon Jun 20 11:23:14 2011]Build date: Mon Jun 20 11:22:05 PDT 2011 ++INFO [Mon Jun 20 11:23:14 2011]Debug mode enabled ++ ++These messages can be used to help debug any issues. ++ ++When debugging issues like the iscsid, the iscsiuio daemon can be run ++in the foreground and the maximum debugging level should be used. ++ ++To place the daemon in foreground mode please pass the parameter '-f' ++ ++Note: The messages to the log file are not flushed unless debugging is enabled. ++ ++Note: If the daemon iscsiuio is running, one will not be able to ++ trample over the existing binary. One might see the following message: ++ ++ 'cannot create regular file `/sbin/iscsiuio': Text file busy' ++ ++ The solve this, please stop the iscsid service and then install. ++ ++Warning: If full debug is enabled, this may quickly fill the partition ++containing the iscsiuio logs. This is because full debugging will log ++packet activity which on a busy network will quickly fill the logs. ++ ++Note: If the bnx2i and cnic drivers are unloaded, then iscsiuio will also ++need to be restarted so that it can determine the iscsid version. +diff --git a/iscsiuio/RELEASE.TXT b/iscsiuio/RELEASE.TXT +new file mode 100644 +index 0000000..44d67f9 +--- /dev/null ++++ b/iscsiuio/RELEASE.TXT +@@ -0,0 +1,2032 @@ ++ Release Notes ++ QLogic uIP Linux Driver ++ Version 0.7.8.2 ++ 12/10/2013 ++ ++ QLogic Corporation ++ 26650 Aliso Viejo Pkwy, ++ Aliso Viejo, CA 92656 ++ ++ Copyright (c) 2004 - 2013 Broadcom Corporation ++ Copyright (c) 2014, QLogic Corporation ++ All rights reserved ++ ++uIP v0.7.10.2 (Feb 12, 2014) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00072504 - ifconfig shows allocation failure after ++ up/down few hours with iSCSI + L2 traffic ++ Cause: A memory leak was discovered in the ongoing pthread creation ++ destruction code during the connection recovery process ++ Change: Fixed the pthread creation code ++ Impact: All ++ ++ ++uIP v0.7.8.2 (Dec 10, 2013) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00072053 - Some hardware iSCSI paths fail during test ++ Cause: The test exercised a corner case where the ARP cache flush ++ mechanism didn't work properly ++ Change: Fixed the ARP cache flush mechanism ++ Impact: All ++ ++ Enhancements ++ ------------ ++ 1. Change: Added a new tx doorbell field in the uio path to work with ++ the new bnx2x/cnic drivers that supports VF_RSS ++ Impact: 10G only ++ ++ 2. Change: Fixed the iface.subnet_mask decoding for IPv6 ++ Impact: IPv6 ++ ++ ++uIP v0.7.8.1b (May 01, 2013) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Performance optimization by caching the page size ++ Impact: All ++ ++ 2. Change: Fixed a bug in the tx completion interrupt handler ++ Impact: 10G only ++ ++ ++uIP v0.7.6.1g (Jan 14, 2013) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00067316 - IPv6 address prefix length < 32 ++ bits fails to connect ++ Cause: CIDR notation has an order bug in the IPv6 section ++ whenever the prefix length specified is < 32 ++ Change: Fixed the network order bug ++ Impact: IPv6 only ++ ++ ++uIP v0.7.6.1f (Nov 14, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00065768 - RHEL5.X iscsiuio segfault possible ++ if there is a specific 1024 byte size broadcast ++ packet ++ Cause: This is another corner case where the packet size ++ is also exactly 1024 bytes + padding that exceeded ++ the DMA rx buffer. The previous fix was not ++ sufficient ++ Change: Ensure that the packet size + padding do not ++ exceed this limit. ++ Impact: 10G only. 1G already has the guard against it. ++ ++ ++uIP v0.7.6.1e (Nov 07, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00066397 - Unable to connect to iSCSI target ++ with NPAR enabled on 57840 ++ Cause: The PCI device ID for 57840_MF has been changed from ++ 0x16ab to 0x16a4 ++ Change: Updated the PCI id table to match exactly what the ++ bnx2x 1.76 indicates ++ Impact: 57840 MF ++ ++ ++uIP v0.7.6.1d (Oct 31, 2012) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Added support for open-iscsi-2.0.873 ++ Impact: All ++ ++ ++uIP v0.7.6.1c (Oct 15, 2012) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Added support for 10G 57840 4x10 and 2x20 ++ Impact: 10G 57840 ++ ++ ++uIP v0.7.6.1b (Oct 09, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00065690 - Vconfig method of connecting over ++ tagged vlan with IPv6 failed ++ Cause: The new net param support changes has prevented ++ the old vconfig method from execising the IPv6 ++ acquisition engine properly ++ Change: Ensure that this old vconfig method to run the IPv6 ++ acquisition engine properly and to its entirety ++ Impact: IPv6 + VLAN using the network VLAN configuration ++ method ++ ++ 2. Problem: Cont00065768 - RHEL5.X iscsiuio segfault possible ++ if there is a specific 1024 byte size broadcast ++ packet ++ Cause: This is a corner case where the packet size is ++ exactly 1024 bytes + padding that exceeded the ++ DMA rx buffer. This has been there since day 1. ++ Change: Ensure that the packet size + padding do not ++ exceed this limit. ++ Impact: 10G only. 1G already has the guard against it. ++ ++ ++ Enhancements ++ ------------ ++ 1. Change: Source optimization - backported source code fixes ++ as reported from the upstream submission patch ++ Impact: ALL ++ ++ ++uIP v0.7.4.2k (Aug 10, 2012) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Enable HP SD mode ++ Impact: 577XX/578XX ++ ++ ++uIP v0.7.4.2j (Jul 18, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00064665 - Linux iSCSI connects via gateway address ++ on the wrong subnet ++ Cause: The gateway address used was not checked against the ++ subnet mask specified before the ARP requests. Since ++ this behavior deters from how L2 operates, therefore, ++ a change was made to correct this. ++ Change: Added check of the gateway specified against the subnet ++ specified. ++ Impact: Static IPv4 operation ++ ++ 2. Problem: Cont00064722 - Linux iSCSI unable to force IPv6 LL ++ override (advanced iface parameters) ++ Cause: The override LL address was not being populated to the ++ IPv6 address database correctly ++ Change: Added this correctly to the IPv6 initialization ++ Impact: Static/DHCP IPv6 LL address override only ++ ++ ++uIP v0.7.4.2i (Jul 11, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00064604 - Fails to connect to routed IPv6 target ++ via RA ++ Cause: The default router IPv6 address was not being retrieved ++ correctly. ++ Change: Fixed the default router IPv6 address read ++ Impact: All ++ ++ ++uIP v0.7.4.2h (Jun 15, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00063863 - can't boot into offload image ++ when VLAN is enabled ++ Cause: During the iSCSI login exchange, certain iSCSI targets ++ will send an ARP request even though the TCP connection ++ has been made. The bug was in this ARP reply where ++ the local MAC was corrupted when VLAN is enabled. ++ Change: Fixed the ARP reply packet ++ Impact: All ++ ++ ++uIP v0.7.4.2g (Jun 08, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00063816 - The initiator is not able to connect ++ to the iSCSI targets over VLAN ++ Cause: The process packet routine did not consider the PCP ++ of the VLAN tag to be non-zero. This created a ++ mismatch when this VLAN tag was compared against the ++ nic_iface->vlan_id which doesn't include the PCP. ++ Change: Added the consideration of non-zero PCP ++ Impact: All ++ ++ ++uIP v0.7.4.2f (Jun 04, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00063626 - Static IPv6 does not connect when ++ the prefix len is not set explicitly ++ Cause: The IPv6 prefix length was not set correctly ++ for Static IPv6 operation when CIDR notation is ++ not specified ++ Change: Fixed the default prefix length ++ Impact: Static IPv6 ++ ++ 2. Problem: Cont00063651 - Cannot connect to iSCSI targets ++ HP PTM/SF ++ Cause: Switch-Dependent mode + invalid Outer VLAN was ++ not supported ++ Change: Allow SD+invalid OV to fallback to SF operation mode ++ Impact: 5771X/578XX ++ ++ ++uIP v0.7.4.2e (May 30, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00063443 - Compilation error on SLES11sp1 ++ Cause: The iface_num field was not defined ++ Change: Fixed all references to iface_num ++ Impact: SLES11sp1 ++ ++ 2. Problem: Cont00063518 - HBA fails to connect across router ++ using iface.gateway address ++ Cause: The gateway override code did not populate the ++ address into the lower level engine ++ Change: Fixed the gateway override code ++ Impact: IPv4 Static IP operation ++ ++ 3. Problem: Cont00063567 - IPv6 LL and RA override does not work ++ Cause: The IPv6 LL/RA override addresses were overwritten ++ by the NDP engine ++ Change: Fixed the LL/RA override code ++ Impact: IPv6 operation ++ ++ Enhancements ++ ------------ ++ 1. Added support for jumbo MTU (independent from the L2 MTU) ++ ++ ++uIP v0.7.4.2d (May 21, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00063421 - Static IPv6 cannot connect via RA/LL ++ Cause: The router advertise and the linklocal address ++ were corrupted due to the override capabilities ++ added for the newer open-iscsi util ++ Change: Fixed the address override code ++ Impact: Static IPv6 ++ ++ Enhancements ++ ------------ ++ 1. Allow VLAN tag = 1 (router management) to connect offload ++ ++ ++uIP v0.7.4.2c (May 09, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: RHEL BZ 734010/804580 - issues found by the Coverity ++ scan ++ Cause: 10 code issues were flagged for revision ++ Change: Fixed all area of concern ++ Impact: All ++ ++ 2. Problem: Cont00063177 - IPv4 DHCP with VLAN specification in ++ iface file gets wrong address ++ Cause: The DHCPv4 handler was not discriminating the VLAN tag ++ associated with the DHCP offers from multiple DHCP ++ servers ++ Change: Changed the DHCPv4 handler to drop DHCP offer packets ++ that doesn't match the VLAN tag of the intended DHCP ++ discovery packet ++ Impact: DHCPv4 operation ++ ++ ++uIP v0.7.4.2b (May 01, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00062993 - IPv6 DHCP with VLAN specification in ++ iface file gets wrong address ++ Cause: The DHCPv6 request was using the same DUID as always ++ so the non-VLAN DHCP server responded to our broadcast ++ instead ++ Change: Changed the DHCPv6 request DUID to link address + time ++ instead of link address alone ++ Impact: DHCPv6 operation ++ ++ ++uIP v0.7.4.1j (Apr 24, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00062805 - Cannot login to iSCSI targets on RHEL6.3 ++ Cause: The problem was caused by a change made to the iface_rec ++ structure in the RHEL6.3 inbox open-iscsi util ++ Change: The new changes is now incorporated ++ Impact: All ++ ++ ++uIP v0.7.4.1i (Apr 16, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00062660 - Unable to login with VLAN iscsiuio ++ on RHEL6.2 ++ Cause: The open-iscsi util in RHEL6.2 has a bug which ++ does not pass the correct iface_num to iscsiuio ++ Change: Added workaround to fall back to do the legacy ++ VLAN support if iface_num and vlan_id = 0 ++ Impact: RHEL6.2 ++ ++ ++uIP v0.7.4.1h (Apr 13, 2012) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Added support for the new iface_num field in the iscsi_uevent ++ path ++ ++ 2. Fixed bug in the nic_iface search engine based on iface_num ++ ++ ++uIP v0.7.4.1g (Mar 22, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00061869 - Unable to setup an offload iSCSI ++ connection with FLR/NPAR under ESX5.0:PDA ++ Cause: The physical function ID was previously extracted ++ from the sysfs of the VM which might not be consistent ++ to the actual physical setup due to the function ++ remapping in the hypervisor ++ Change: Read the physical function ID directly from the BAR0 ++ ME register ++ Impact: All ++ ++ 2. Problem: Cont00062170 - IPv6 login/logout stress fails ++ Cause: The packet interrupt was lost after running the test ++ for a much longer period of time. A bug in the ++ packet processing routine was found to exit prematurely ++ Change: Fixed the packet processing routine to process all ++ packets before exiting ++ Impact: All ++ ++ ++uIP v0.7.4.1f (Mar 19, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00062170 - IPv6 login/logout stress fails ++ Cause: The packet buffer routine for IPv6 did not take ++ network order <-> host order into consideration ++ Change: Added a htons call to compensate for the ntohs pair ++ Impact: All ++ ++ ++uIP v0.7.4.1e (Mar 08, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00061978 - Load/unload stress test fails ++ Cause: The bnx2x open request was failing due to the module ++ request procedure. However, the open failure was ++ not being handled correctly. ++ Change: Fixed the device open error handling ++ Impact: 5771X/578XX ++ ++ ++uIP v0.7.4.1d (Mar 02, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00061708 - Unable to log into target after running ++ driver load/unload ++ Cause: A bug was introduced in the previous bug fix (CQ61459) ++ where a pthread_cond_broadcast call was erroneously ++ enabled ++ Change: Restored this back ++ Impact: All ++ ++ ++uIP v0.7.4.1c (Feb 16, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00061529 - Unable to connect to target after an ++ initial failed login attempt until iscsi service is ++ restarted ++ Cause: Upon a failed DHCPv4 acquisition due to the wrong VLAN ++ tag in the initial iface setup, any iscsid connect request ++ from the same NIC will get dropped due to a bug. ++ Change: Fixed the bug which prevented new iscsid connect requests ++ from getting honored ++ Impact: All ++ ++ Enhancements ++ ------------ ++ 1. Updated README ++ ++ ++uIP v0.7.4.1b (Feb 08, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00061513 - Unable to connect to target over VLAN ++ interface ++ Cause: The VLAN id was not properly passed back to the CNIC ++ driver for the offload request ++ Change: Fixed the VLAN id being passed back to the CNIC driver ++ Impact: All ++ ++ ++uIP v0.7.4.1a (Feb 01, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00049383 - No mechanism in iface file to support ++ gateway/routing ++ Change: Added support for the additional network parameters ++ as passed from the newer iscsi-util. ++ These parameters include: ++ IPv4: subnet_mask, gateway ++ IPv6: ipv6_linklocal, ipv6_router, ++ ipv6_autocfg, linklocal_autocfg, router_autocfg ++ VLAN: vlan_id, vlan_priority, vlan_state ++ Other: mtu, port ++ Impact: All ++ ++ 2. Problem: Cont00060806 - Unable to connect target using DHCP over ++ tagged VLAN ++ Change: DHCP+VLAN is a new feature enhancement that was added ++ alongside all other new iface parameters. ++ Impact: All ++ ++ ++ Enhancements ++ ------------ ++ 1. Lock iscsid's connect request with path_req so connect requests ++ with DHCP/Static will no longer override each other ++ ++ 2. Fixed the if_down handler from global to nic specific ++ ++ 3. Fixed various synchronization issues ++ ++ ++uIP v0.7.2.1e (Jan 05, 2012) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00060734 - ifupdown-mtu change stress with active ++ session causes iscsiuio to fail ++ Change: Fixed a race condition between the nic enable thread ++ and when DHCP fails ++ Impact: All ++ ++ ++uIP v0.7.2.1d (Dec 28, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00060368 - segfault observed after failing both ++ mpio paths ++ Change: Various memory leaks were identified and resolved in ++ the nic cleanup path ++ Impact: All ++ ++ ++uIP v0.7.2.1c (Dec 16, 2011) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Disable HP SD mode ++ ++ ++uIP v0.7.2.1b (Dec 14, 2011) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Default iscsiuio logging to off. Use the '-d' ++ option to enable ++ ++ ++uIP v0.7.0.14g (Oct 25, 2011) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Fixed the compilation under RHEL6.2 ++ 2. Change: Added oom_adjust call to prevent OOM Killer from killing ++ iscsiuio when memory is low ++ 3. Change: Added mlockall setting to prevent page swap ++ ++ ++uIP v0.7.0.14f (Oct 20, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00058994 - DOS vulnerability in uip during UDP flood ++ Cause: The warning messages from the UDP handler was logging ++ at a rate faster than the log file logrotate rate ++ Therefore, the system's OOM eventually got kicked in to ++ start terminating running processes which includes iscsiuio ++ Change: Moved several UDP warning messages from the default log ++ level to the debug log level ++ Impact: All (minor) ++ ++ 2. Problem: Cont00059288 - Show segfault w/ SLES11 SP1 Xen kernel ++ Cause: The bnx2x chip_id was not read correctly from the PCIe BAR1 ++ under the Xen kernel. The error was in the mmap area. ++ Change: Corrected the mmapping of the PCI MMIO space. ++ Impact: Xen kernels ++ ++ Enhancements ++ ------------ ++ 1. Change: Changed the log file open error to a warning and let ++ the daemon progress. This was only observed under iSCSI boot ++ ++ ++uIP v0.7.0.14e (Sep 19, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00058678 - Can not iboot target from ipv6 path ++ using VLAN ++ Cause: A bug was found in the path request path where the vlan ++ iface's protocol family was not used correctly in the ++ iface search ++ Change: This has been corrected ++ ++ ++uIP v0.7.0.14d (Sep 16, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00058602 - Can't iboot using IPv6 offload path ++ Cause: The bug was exposed by a fix in 0.7.0.14c where the ++ IPv6 router solicitation timeout exceeded the nic ++ enable thread timeout. ++ Change: The IPv6 router solicitation timeout has been adjusted ++ ++ ++uIP v0.7.0.14c (Sep 01, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00058256 - Sessions fail after loginstress to via ++ simultaneous ipv4 and ipv6 dhcp ++ Cause: Switching between DHCPv4/v6 coupled with VLAN exposed ++ a drawback in our nic_iface architecture design where ++ VLAN is not specified by iscsid. ++ Change: The code was optimized and improved the performance when ++ switching between DHCPv4/v6+VLAN. However, the ultimate ++ fix is to make use of the net config parameters introduced ++ in the newer open-iscsi util which will identify the ++ specific VLAN nic_iface to use. ++ ++ Enhancements ++ ------------ ++ 1. Change: Added support for bnx2x-1.71.00 ++ ++ ++uIP v0.7.0.14b (Aug 23, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00057840 - RHEL6.2 inbox: Unable to connect to ++ targets with 5709 ++ Cause: For cases when the bnx2/bnx2x driver gets removed, the ++ uio database that was built by cnic would have the device ++ ->net reference removed. This has caused an unnecessary ++ timeout of 5s for each stale uio entry in the database. ++ Change: Adjusted the routine which seeks the device->net entry ++ to include more logic instead of hard waiting for 5s. ++ ++ Enhancements ++ ------------ ++ 1. Change: Added support for RHEL6.2 for out-of-box release ++ 2. Change: Updated the man page with -h and -p info ++ 3. Change: Updated the -h info ++ ++ ++uIP v0.7.0.13 (Aug 10, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00057768 - iscsiuio logrotate causes daemon failure ++ Cause: The logrotate script will send a SIGUSR1 signal to notify ++ the iscsiuio daemon of such action. However, the daemon ++ wasn't programmed to catch this signal. ++ Change: Restored the catching of this signal ++ ++ ++uIP v0.7.0.12 (Aug 04, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00050634 - brcm_iscsiuio Tainted: running IoZone, ++ Iometer and receiving a UDP flood on 3260 ++ Cause: Upon iscsiuio termination, because of the UDP flood, ++ the nic thread will be busy servicing those UDP packets ++ while the signal handling thread will free up all nic ++ resources. The two threads were not in sync. ++ Change: Added a nic_remove_all routine to destroy all nic threads ++ before the nic resources get freed. ++ ++ Enhancements ++ ------------ ++ 1. Change: Fixed all warnings as reported by RHELS' Coverity testing. ++ ++ ++uIP v0.7.0.11 (Aug 02, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Erroneous VLAN tag was being passed by iscsid for connect ++ request ++ Cause: The iscsid's iface_rec_t ipc message does not contain this ++ vlan field. This field was added in uIP for future vlan ++ support. Since the buffer allocated to receive such message ++ in uIP didn't get initialized, therefore, garbled up VLAN ++ tag was getting used. ++ Change: Added the initialization of this buffer. ++ ++ ++uIP v0.7.0.10 (Jul 26, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Can't offload when switching from Static to DHCP then back to ++ Static IPv4 when connecting through a VLAN interface ++ Cause: The VLAN processing code did not reinstall the IP address ++ from the default nic_iface to the associated VLAN nic_iface. ++ This was only done on the very first time when the VLAN ++ interface was created and not on subsequent instances. ++ Change: Added code to mirror the default nic_iface IP/netmask/ip_config ++ on the VLAN nic_iface on every new connection request. ++ ++ ++uIP v0.7.0.9 (Jul 19, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Can't offload to 57810 NPAR NIC ++ Cause: The MF/VF variant of the PCI IDs were not supported previously ++ Change: Added support for the MF/VF variants for 57800/57810/57840 ++ ++ ++uIP v0.7.0.8 (Jun 30, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00056522 - Unable to connect to iSCSI target using ++ netxtreme2 package 7.0.9 ++ Cause: The iSCSI L2 ring's CID has changed from 17 to 49 ++ Change: The code now gets L2 iSCSI ring CID from the l2_buf directly. ++ This will work with any version of the cnic driver because ++ the location is a zero before this change. ++ ++ ++uIP v0.7.0.7 (Jun 23, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00056460 - iSCSI Offload boot RHEL5u5 x64 dropped tagged ++ packets with iSCSI Offload Boot with untagged ++ Cause: The ICMP echo replies to the target was corrupted in both ++ 1g and 10g mode ++ Change: The code will now handle both VLAN stripped and no VLAN stripped ++ incoming packets correctly. Also modified the transmit routine ++ to strip out any inline VLAN tag before setting up the hw to ++ insert VLAN tag. ++ ++ ++uIP v0.7.0.6 (Jun 21, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00056231 - DHCPv4 not working with iSCSI HBA w/ ++ linux-nx2 v7.0.7 ++ Cause: The 10g L2 FW HSI has been modified for PCIe performance ++ enhancement in the 7.0.7 package (FW 1.70.20) which uIP ++ has not adapted to. ++ Change: The eth_rx_cqe size has been increased from 32B to 64B. ++ ++ Enhancements ++ ------------ ++ 1. Change: The utility name has changed from brcm_iscsiuio to iscsiuio ++ as preparation for upstream submission. ++ 2. Change: Updated README ++ ++ ++uIP v0.7.0.5 (Jun 02, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00055915 - iSCSI does not connect on 57800 in 4-port mode ++ Cause: The 4-port mode was not being determined correctly ++ Change: Fixed the PORT4MODE register offset and the QZONE_ID macros ++ ++ ++uIP v0.7.0.4 (May 24, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00055832 - linux iscsiboot can not login to target using ++ offload path (57800) ++ Cause: The device ID comparison routine did not take care of the case ++ when one device ID is bitwise superset of another. ++ Change: Fixed the device ID comparison routine. ++ ++ ++uIP v0.7.0.3 (May. 19, 2011) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Updated all fixes to match the released uIP 0.6.4.17 ++ ++ 2. Change: Modified source and Copyright info as preparation for upstream ++ submission ++ ++ ++uIP v0.7.0.2 (May. 03, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00048972 - brcm-iscsi.log has no max size and would grow ++ to consume all free space on hard disk ++ Cause: There was no mechanism to rotate the log ++ Change: Added logrotate entry and SIGUSR1 signal handling for log rotate ++ action ++ ++ 2. Problem: Cont00054996 - Multi-session, multi-protocol mtu stress ++ does not recover all sessions ++ Cause: A segfault was observed during the load/unload module. The ++ problem was caused by an illegal dereference of a pointer ++ when IPv6 couldn't find the longest match address from ++ the ARP (Neighbor) table. ++ Change: Fixed the dereferencing error ++ ++ 3. Problem: Cont00054900 - Linux uIP - Please add ability to connect ++ to routed target with static iface IPv6 ++ Cause: Static IPv6 never runs the IPv6 NDP router sol/adv engine. ++ Change: IPv6 NDP router sol/adv has now been added to static IPv6 ++ operation. ++ ++ 4. Problem: Cont00054996 - Multi-session, multi-protocol mtu stress ++ does not recover all sessions ++ Cause: Segfaults were observed caused by the accessing of the IPv6 ++ NDP structure while the nic is undergoing a reset either ++ due to a DHCPv4 request from iscsid or the handling of ++ if_down due to the NL handler from CNIC. ++ Change: The fix involves the following: ++ - Fixed the handling of staggered IPv4/v6 DHCP/static requests ++ - Fixed memory leak due to reallocation of IPv4 and IPv6 ++ DHCP structs ++ - Fixed the pthread join stuck problem in the handling ++ of the if_down NL message ++ ++ 5. Problem: Cont00054810 - Linux NMI - bnx2x_init_hw_common:PXP2 CFG ++ failed running iSCSI MTU stress test ++ Cause: This only happens in DHCPv4 mode. The problem was caused ++ by contention between the elongated window of performing ++ DHCP in the enable_nic thread while receiving the asynchronous ++ if_down NL message (from the MTU change event) from the ++ CNIC NL thread. The problem occurs when the enable_nic ++ thread tries to call bnx2x_open while the other thread ++ calls the bnx2x_close routine. ++ Change: Fixed mutex lock bugs for the enable_nic thread. Also ++ extended the nic_disable timeout to 10s to compensate for ++ the DHCP operation. ++ ++ 6. Problem: Cont00054818 - RH6.0 - Unable to logout of iSCSI session ++ after running PQA baseline scripts ++ Cause: This was caused by the call to cancel the enable_nic ++ thread when disabling the nic but failed to unlock the ++ nic mutex that the enable_nic thread held. ++ Change: Wake up the enable_nic thread and wait for it to complete ++ instead of canceling it in the nic_disable path. ++ ++ 7. Problem: Cont00054725 - Previous static HBA IP will be used after ++ a new static HBA IP has been created ++ Cause: There was an assumption in the code where if the same ++ nic_iface structure was found based on the nic/vlan pair, ++ the specified IP address would not be used. Instead, it ++ will continue to use the previous defined IP address. ++ Change: The previous IP address will now be compared against the ++ the specified IP address before finishing the parce ++ iface request from iscsid. If different, the current ++ nic will be disabled and then re-enabled with the newly ++ specified IP address. ++ ++ 8. Problem: Cont00054571 - Unable to connect to routed ipv6 target ++ with RA address and iface DHCPv6 ++ Cause: The default router address was not being employed for ++ the IPv6 neighbor negotiation. Additionally, the return ++ address of our neighbor advertisement was incorrect as ++ it should use the best matched src address instead. ++ Change: Fixed both the IPv6 neighbor solicitation and advertisement ++ transmission and handling. ++ ++ 9. Problem: Cont00054510 - fails to login to 32 session with blanket ++ login IPv6 ++ Cause: A bug was introduced in uIP 0.6.4.6 where the NIC_RUNNING ++ flag might not be set when entering the main loop under ++ certain situations depending on the nic bring up. ++ Change: A new NIC_STARTED_RUNNING flag is now defined to fix CQ53511. ++ ++ 10. Problem: Cont00053807 - RA and link local are unable to connect if DHCPv6 ++ fails ++ Cause: The host link local address was not being searched as one of ++ the host address to be replied to CNIC for the connect request. ++ Change: The path reply now includes the search of host link local ++ address as well. ++ ++ 11. Problem: Cont00054236 - iSCSI service must be restarted before an IPv6 ++ connection can be made to the Equalogic target ++ Cause: The problem was intermittent as it depends on which IPv6 address ++ the target was redirecting to. Since uIP was only extracting ++ the target's IPv6 address + MAC from the target's neighbor ++ advertisement packet itself and not from the ICMPv6 option, so ++ the wrong or no MAC address will get send down to CNIC for the ++ connection establishment; hence the no connect. ++ Change: Added the updating of the neighbor discovery table to also use ++ the Target IPv6 address + MAC specified in the incoming neighbor ++ advertisement's ICMPv6 option field. ++ ++ 12. Problem: Cont00053255 - bnx2x panic dump logging into multiple ++ discovered IPv6 nodes (Equalogic IPv6 target) ++ Cause: The bnx2x panic was fixed in the 10g fw 6.4.29. ++ A IPv6 connectivity issue was then found and led to different ++ kernel/uIP crashes. This was caused by the same IPv6 ++ connectivity problem mentioned above. ++ Change: Same as above ++ ++ 13. Problem: Cont00053728 - Sessions never recover after doing initiator-side ++ cable pull test with IPv6 traffic against Equalogic targets ++ Cause: It was discovered that the Equalogic would send out periodic ++ neighbor solicitation to maintain the connection to the ++ initiator. Since uIP was responding with the assigned IPv6 ++ link local address in the neighbor advertisement ++ unconditionally, the target was observed to stop transmitting on ++ the connection specified. ++ Change: The neighbor advertisement generated will now use the dst IPv6 ++ address from the input neighbor solicitation packet instead of ++ the assigned IPv6 link local address for both the packet and the ++ ICMPv6 source IPv6 address. ++ ++ 14. Problem: Compile error under 32-bit OS ++ Cause: A bug was introduced in the previous release 0.6.4.6 which ++ caused a compilation error in 32-bit OS (64-bit compiles ++ fine) ++ Change: Fixed the bug ++ ++ 15. Problem: Cont00053807 - RA and Link local are unable to connect if dhcpv6 ++ fails ++ Cause: There was a bug in the nl reply where the RA address will never ++ be sent back to CNIC for the connection request ++ Change: The best matched address to the dst will now be sent back to ++ CNIC in the path rsp. ++ ++ Enhancements ++ ------------ ++ 1. Change: Updated README to remove the 57713/E references ++ ++ 2. Change: Allow the ICMP option field in the IPv6 Neighbor Advertisement ++ response to be included without discrimination. This fixes ++ an issue connecting against the EQL via RA for DHCPv6. ++ ++ 3. Change: Updated README for the IPv6 operation, VLAN, and discovery. ++ ++ ++uIP v0.7.0.1 (Mar. 29, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00053511 - bnx2x panic dump during ifup/down stress with ++ iSCSI traffic ++ Cause: The panic dump was resolved by the driver's rq dbell size fix. ++ After that, uIP crashed due to the asynchronous if_down event ++ that took the chip resources away while the nic thread is still ++ continuing to try to send DHCP request. ++ Change: Added synchronization between the two threads so proper clean up ++ of the threads can occur. ++ ++ Enhancements ++ ------------ ++ 1. Change: Added support for E3 (57800, 57810, and 57840) ++ ++ ++uIP v0.6.4.5 (Mar. 23, 2011) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Optimized the double VLAN fix of CQ53870 to match ++ what will be submitted for RHELS5.7 and RHELS6.1 inbox ++ ++ ++uIP v0.6.4.4 (Mar. 17, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00053870 - Unable to login to iSCSI target via offload ++ through a Nexus 5020 switch with DCBx enabled ++ Cause: Double VLAN tagging was observed due to DCBx enabled. ++ The chip actually adds a VLAN tag if the txbd does not have ++ VLAN tag enabled under the DCBx environment for PRI setting. ++ Since uIP does not make use of hw assisted VLAN tagging, ++ 2 VLAN tag was observed in the data stream. ++ Change: Enabled hw assisted VLAN tagging in uIP for both 1g and 10g. ++ ++ 2. Problem: Cont00053792 - maxconnections intermittently fail and ++ recover using iface DHCPv4 ++ Cause: The DHCPv4 engine erroneously keeps on requesting for a ++ new lease which tremendously hamper normal path_req ++ operation. The problem is that the lease time parameter ++ has overflowed when converted to ticks count. ++ Change: Expanded the lease timer ticks count parameter from 16 to ++ 32 bits. ++ ++ 3. Problem: Cont00053807 - RA and link local are unable to connect if ++ DHCPv6 fails ++ Cause: The DHCPv6 engine does not have the failover to use RA ++ mechanism ++ Change: Expanded to use best match address instead regardless of ++ DHCPv6 success or not, or using static v6. ++ ++ Enhancements ++ ------------ ++ 1. Change: Cont00051823 - Added man page for brcm_iscsiuio ++ ++ ++uIP v0.6.4.3 (Mar. 15, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00053719 - intermittent logging into targets that ++ are not in the same subnet as defined in the iface ++ Cause: The default route was used erroneously due to a miscompare ++ Change: Fixed this comparison so if the requested dst is not in ++ in the same subnet, uIP would not even ARP out. ++ ++ 2. Problem: Cont00053580 - Unable to do iSCSI boot into Linux OS using ++ 57710 adapters ++ Cause: The E1 iro USTORM_RX_PROD_OFFSET doesn't match the t6.4 fw ++ Change: This is now fixed ++ ++ ++uIP v0.6.4.2 (Feb. 24, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00050343 - HBA does not follow RFC2131 spec for IPv4 ++ DHCP lease expiration ++ Cause: The dhcp engine did not have this feature implemented ++ Change: Added lease time tracking and renewal ++ ++ 2. Problem: Cont00050801 - Unable to connect to target after switching ++ between DHCPv4 to static v4 ++ Cause: The configuration flags got corrupted when switching between ++ dhcp and static or vice versa. ++ Change: Fixed the flag handling. Also needed to zero out the static ++ ip address in the host memory when switching to dhcp. ++ Otherwise, the static ip address will get used mistakenly. ++ ++ Enhancements ++ ------------ ++ 1. Change: Cont00051936 - Added IPv6 NDP and DHCPv6 support. ++ ++ ++uIP v0.6.4.1 (Jan. 27, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00049766 - segfault seen while stopping iscsi service ++ Cause: The logger output routine was accessing the log resource ++ while another thread calls fini_logger to free the same ++ resources ++ Change: Added pthread mutex lock to the logger routine to exclude ++ the initializer, user, and finisher ++ ++ Enhancements ++ ------------ ++ 1. Change: Added new t6.4 HSI and 57713 support. ++ ++ ++uIP v0.6.2.13 (Jan. 04, 2011) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00049665 - iscsiboot:linux failed to boot into iscsi ++ boot image in offload path after 5 iterations ++ Cause: The hw consumer index for the uIP ring got out of sync ++ with the producer index. This has led to the xmit mutex ++ lock be held forever so subsequent ARP requests will not ++ get transmitted to the wire ++ Change: Added this out of sync detection and rescue the xmit mutex ++ lock ++ ++uIP v0.6.2.12 (Dec. 21, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Cont00051820 - Session fails to reconnect after gateway ++ fallback ++ Cause: Under the HSRP test scenario, it was found that an ARP ++ request from the SUT is required in order for the HSRP ++ router to begin sending packets downstream to the SUT. ++ The default ARP age was originally set to 20 minutes ++ before a new ARP request will get sent, ++ Change: Changed the ARP age default to Linux default at 5 minutes ++ ++uIP v0.6.2.11 (Dec. 17, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: For IPv4, the gateway route was not being utilized ++ when the subnet mask given or calculated does not ++ match. This resulted in many unwanted connection ++ attempts. ++ Cause: A bug was found in the default gateway calculation ++ logic which prevented the gateway address from being ++ used. ++ Change: Fixed the default gateway logic ++ ++ 2. Problem: For IPv6, there are scenarios where it won't connect ++ Cause: The IPv6 subnet mask as extracted from the CIDR ++ format might contain garbage data. This garbage data ++ was then used as part of the subnet mask which would ++ prevent the correct address mask. ++ Change: Fixed the subnet mask ++ ++uIP v0.6.2.10 (Dec. 15, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: IPv6 does not connect for non-CIDR iface.ipaddress ++ specification ++ Cause: A bug where all ones was used as the IPv6 netmask ++ instead of all zeroes. This prevented all IPv6 ++ path requests from being honored ++ Change: Fixed the subnet mask used ++ ++uIP v0.6.2.9 (Dec. 14, 2010) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Added IP address CIDR notation support for the ++ iface.ipaddress field in the iface file. ++ This will allow subnet mask to be defined and used. ++ ++uIP v0.6.2.8 (Dec. 9, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: ipv6 + ifup/down fails to reconnect ++ ++ Cause: There were 2 problems found: ++ - the xmit_mutex lock was being held indefinitely ++ - the nl_process_if_down flag for 10g doorbell ringing ++ did not get reinitialized ++ ++ Change: Fixed the xmit_mutex deadlock via trylock ++ Added nl_process_if_down initialization in the IF_DOWN ++ process ++ ++ 2. Problem: Added fix for the NPAR disabled for 57712 ++ ++ Cause: The mac address was not handled correctly ++ ++ Change: Fixed the mac address handling. Also requires corresponding ++ kernel component for the complete fix ++ ++uIP v0.6.2.7 (Dec. 7, 2010) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Use the gateway address from the DHCP server the ++ destination IP address is not in the current subnet. ++ ++uIP v0.6.2.6 (Nov. 16, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Warning message seen in the kernel logs, ++ "uio uio2: uevent: unsupported action string" ++ ++ Cause: The improper string was echo'ed into the UIO trigger ++ field. With an improper string, this message would ++ appear in the kernel logs. ++ ++ Change: uIP will now write the string "online" to the UIO ++ trigger field. This is the string expected by the ++ Linux kernel base driver. ++ ++ 2. Problem: uIP would segfault during a heavily login/logout ++ iSCSI subsystem reset senario ++ ++ Cause: A double free occurred in the logging portion of the ++ uIP code, but this was root cause to a double free when ++ manipulating the NetLink buffers. ++ ++ Change: Properly look at the return code from the routine which ++ will read NetLink messages. Also only free buffers ++ if they are allocated. ++ ++ Enhancements ++ ------------ ++ 1. Change: Add ability to print kernel version and machine ++ architecture to further help debug problems. ++ ++ 2. Change: Apply the netmask from DHCP if provided. ++ ++uIP v0.6.2.5 (Nov. 10, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: iscsid would try to conenct with unintended iSCSI ++ targets ++ ++ Cause: uIP would blindly return the iSCSI target MAC address ++ regardless if the iSCSI target is reachable via the ++ given port. ++ ++ Change: uIP will try to filter the requests coming from CNIC ++ by automatically generating a network mask based off ++ the configured IP addressed. Then this netmask is ++ masked with the destination IP address. If there is ++ a match, then the path_req is allowed through. ++ ++ 2. Problem: Problems reconnecting back to the target when running ++ MTU stress tests. ++ ++ Cause: cnic/bnx2i and uIP could possibly get out of sync when ++ an if_down message is sent. ++ ++ Change: uIP will now immediately react to the if_down message, ++ and flush all the path req's and then to process to ++ if_close. ++ ++ Enhancements ++ ------------ ++ 1. Change: Fix compile warnings for src/unix/nic_nl.c, ++ and src/unix/main.c ++ ++uIP v0.6.2.4 (Nov. 4, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: iSCSI HBA: brcm_iscsiuio segfault during ifdown ++ with many active sessions ++ ++ Cause: uIP will segfault when traversing the error path when ++ an iSCSI connection is starting but the sysfs entries ++ have not been created yet. ++ ++ Change: Use the errno value rather then the one from the file ++ descriptor because the file descriptor will be NULL and ++ the NULL dereference will cause a segfault. ++ ++ Enhancements ++ ------------ ++ 1. Change: Added initial changes for iSCSI multi-function support for ++ 10G NIC's. ++ 2. Change: Add more detailed messages for error pathes in nic_utils ++ ++uIP v0.6.2.3 (October 28, 2010) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Add support for bnx2x-1.62.x drivers ++ ++uIP v0.6.2.2 (October 18, 2010) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Only allow iSCSI connections with known bnx2x HSI's. ++ ++uIP v0.6.2.1 (October 7, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: After multiple MTU changes, the ethtool IOCTL used to ++ determine the bnx2x driver version fails and eventually ++ iSCSI connections would not reconnect. ++ ++ Cause: The socket file descriptor used during the ethtool IOCTL ++ call was never closed and leaked. ++ ++ Change: On the error path when calling the ethtool IOCTL, the ++ file descriptor is now properly closed. ++ ++uIP v0.5.39 (September 15, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Could not offload IPv4 VLAN connection when the target tries ++ to ARP the iSCSI initiator ++ ++ Cause: In the ARP reply, the ether field was incorrect. ++ ++ Change: Properly set the ether field to 802.1Q type (0x8100) ++ ++uIP v0.5.38 (September 14, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: uIP would cause a panic dump when the NIC was going down ++ ++ Cause: uIP and CNIC where not synchonized on NIC state ++ ++ Change: Check if the RX BD's which are zero'ed by CNIC when the ++ NIC is going down. If the BD addresses are zero, then ++ uIP will drop the TX packets. ++ ++uIP v0.5.37 (August 21, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: uIP would segfault on ifup/ifdown stress test when using ++ DHCP to determine local IP address. ++ ++ Cause: The uIP would use a NULL buffer during data transmission. ++ ++ Change: Drop packets when there are no buffer avaliable. ++ ++uIP v0.5.36 (August 21, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: iSCSI boot would not completely login after the pivot ++ root operation. ++ ++ Cause: The uIP would not properly start the NIC interface. ++ ++ Change: uIP should only check the NIC state to determine whether ++ to start the NIC thread or not. ++ ++ 2. Problem: uIP would segfault during if'up if'down testing. ++ ++ Cause: The uIP would improperly start 2 NIC threads for the ++ same NIC interface. ++ ++ Change: uIP should properly lock the NIC list when disabling/removing ++ the NIC threads. ++ ++ ++uIP v0.5.35 (August 20, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Sessions would hang with ethtool self-test ++ ++ Cause: The uIP would hang because the socket layer was stuck ++ because there is much contention for that socket. This ++ would hang the CNIC thread. ++ ++ Change: Remove any IOCTL calls in uIP which may colide with ++ the ethtool self test. The driver version is only ++ capture during uIP initialization. ++ ++ 2. Problem: There were session recovery issue when using DHCP ++ if up/down tests. ++ ++ Cause: The uIP would hang because the DHCP requests would ++ timeout if the network interface is downed which would ++ hang all the other uIP threads. ++ ++ Change: Ensure that the DHCP state machine had exit points ++ if the network interface was down'ed. ++ ++ ++uIP v0.5.34 (August 18, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Sessions would not recover with ethtool self-test ++ ++ Cause: The uIP would hang because either the NetLink buffer is ++ full or that any socket operations used to manipulate ++ multicast addresses would block. ++ ++ Change: Ensure that the socket used for multicast addressing is ++ set to nonblocking. Drain the NetLink buffer without ++ using the eventing, but with a more aggressive poll routine. ++ ++ 2. Problem: Sessions would not recover with L2 driver load/unload on ++ RHEL 6.0 SS9 ++ ++ Cause: The uIP would close the NIC thread too early and would ++ deadlock on cloing the NIC thread. ++ ++ Change: Ensure that the NIC thread is canceled/closed only in one ++ location, in the NIC remove routine. ++ ++ ++uIP v0.5.33 (August 17, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Error message seen from the uIP stack for valid packets. ++ ++ Cause: The uIP was incorrectly marking logging messages for valid ++ packets as errors because it didn't know how to parase them. ++ ++ Change: Changed the following from error to debug message ++ ipv6: invalid version ++ ipv4: invalid version or header length. ++ icmpv6: unknown ICMP message. ++ ip: neither tcp nor icmp ++ Changed the following from error to warn message ++ udp: bad checksum ++ tcp: bad checksum ++ tcp: got reset, aborting connection. ++ ++ 2. Problem: After multiple iterations the loading and unloading of ++ the Broadcom Linux drivers with active connections ++ would not cause the sessions to recover on RHEL 6.0 ++ snapshot 9. ++ ++ Cause: There was a deadlock in the nic mutex ++ ++ Change: Lock ordering for the nic mutex and nic list mutex must ++ be inforced. ++ ++ 3. Problem: After multiple iterations of running the ethtool selftest ++ the Broadcom Linux drivers with active connections ++ would not cause the sessions to recover on RHEL 5.5. ++ ++ Cause: The Netlink buffer between uIP and CNIC would get full. ++ ++ Change: Poll more regularly for packets in the Netlink buffer ++ from 4 times a second to 100 times a 1 second. ++ Drain packets during the PATH_REQ packet pull. ++ ++ ++uIP v0.5.32 (August 14, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Error message 'nic eth0: Didn't find type 0xaa bb' seen. ++ ++ Cause: Valid non-DIX Ethernet packets as being passed to the ++ uIP. uIP will drop these packets but should be logged ++ correctly. ++ ++ Change: These packets are valid, and should only be logged for ++ debugging purposes. ++ ++ 2. Problem: Error message 'Dropped previous transmitted packet' seen. ++ ++ Cause: The TX ring is full, and here uIP is trying to transmit a ++ packet which will be dropped. This is a valid state but ++ the log message is marked incorrectly ++ ++ Change: These messages are not warnings and should be logging when ++ debugging is enabled. ++ ++ 3. Problem: Error message: "iscsi_ipc eth0 Transport name is not ++ equal expected: got: bnx2i" seen. ++ ++ Cause: The iface_rec structure is different between iscsid version. ++ For RHEL 5.5, iscsid is versioned 871, for RHEL 6.0 is ++ versioned 872. ++ ++ Change: Allow uIP to compile against a different version of iscsid. ++ ++ ++uIP v0.5.31 (August 12, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Softlock would occur showing that the NetLink table ++ lock was taken but never released. ++ ++ Cause: NetLink socket buffer would fill with constant PATH_REQ ++ messages preventing PATH_REQ response from libiscsi ++ ++ Change: Now uIP will drain the NetLink buffer while looking for ++ a response. ++ ++ Enhancements ++ ------------ ++ 1. Change: Add documentation for VLAN configuration and restrictions. ++ ++ ++uIP v0.5.30 (August 6, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: iscsid thread will stall if closing the uio files nodes ++ is stuck ++ ++ Cause: uIP would indefinitely block waiting for the mutex shared ++ by the close routine. ++ ++ Change: Now uIP will try and poll a bit for the mutex. If it can't ++ get this mutex in the iscsid thread then an error is return ++ rather then hold the thread. ++ ++ 2. Problem: IPv6 Unicast Neighbor Adveriserments would have the ++ ICMPv6 option header specifying a MAC. ++ ++ Cause: uIP should use the source IPv6 address to detmine whether ++ to strip the option header or not and not the target address ++ in the ICMPv6 field. ++ ++ Change: The uIP stack return a unicast IPv6 Neighbor Advertisement ++ without the ICMPv6 option as a response to unicast ++ IPv6 Neighbor Solicitations. ++ ++ 3. Problem: There would be TCP SYN packets with improper MAC address. ++ ++ Cause: A zero'ed MAC address was not passed to CNIC to indicate an ++ error or if the IP address didn't resolve. ++ ++ Change: The uIP stack will now return a zero'ed MAC address if it ++ can't find any entries. ++ ++ ++uIP v0.5.29 (August 6, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: "uip udp: no matching connection found: lport: 35072" ++ seen numerous times in the brcm_iscsiuio log file ++ ++ Cause: This message was incorrectly marked as an error ++ ++ Change: These messages are valid log entries especially if the ++ packet was a broadcast UDP packet not destined for the SUT ++ I will change the code to mark these logs entries as debug. ++ ++ ++uIP v0.5.28 (August 5, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Can't login into a redirected Equilogic Target ++ ++ Cause: The Equilogic Target uses a unicast IPv6 Neighbor ++ Solicitation to test if the host is up. The uIP stack ++ would return a Neighbor Advertisement with an unneeded ++ ICMPv6 option. ++ ++ Change: Only have the uIP stack return a unicast IPv6 Neighbor ++ Advertisement without the ICMPv6 option. ++ ++ 2. Problem: With older bnx2/bnx2x/cnic/bnx2i driver combinations ++ uIP would segfault when these drivers were unloaded. ++ ++ Cause: When the older drivers were removed, the underlying uio ++ instance was removed causing uIP to have a stale file handle. ++ When uIP finally closes using this stale file handle, either ++ uIP would segfault, or there would be an error in the ++ uio_release() path. ++ ++ Change: Only have the uIP close if the UIO file node exists. ++ ++ ++uIP v0.5.27 (July 31, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: iSCSI HBA: Unable to use DHCP address for iSCSI interface ++ if a connection was previously made with a static address ++ on bnx2 devices. ++ ++ Cause: Because the device is closed and reopen'ed the TX consumer ++ indexes were not persisted ++ ++ Change: Only discard the TX consumer indexes only when the devices ++ will be discarded or closed ++ ++ Enhancements ++ ------------ ++ 1. Change: Change CNIC references to bnx2 in the bnx2 user space ++ driver. ++ ++ ++uIP v0.5.26 (July 30, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: iSCSI HBA: Unable to use DHCP address for iSCSI interface ++ if a connection was previously made with a static address on ++ bnx2x devices. ++ ++ Cause: Because the device is closed and reopen'ed the TX consumer ++ indexes were not persisted ++ ++ Change: Only discard the TX consumer indexes only when the devices ++ will be discarded ++ ++ 2. Problem: IPv6 using VLAN's didn't login ++ ++ Cause: The uIP code used to determine if the packet was an IPv6 ++ or not was not working. This VLAN packets for IPv6 were ++ being mis-interpreted. ++ ++ Change: Make the function is_ipv6() VLAN aware ++ ++ 3. Problem: Persistant targets was not loggin in during boot ++ ++ Cause: If udev was slow and the /dev/uio* were creatly slowly ++ uIP would fail. ++ ++ Change: Poll uIP waiting for /dev/uio* file nodes. ++ ++uIP v0.5.25 (July 27, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: When using IPv4 DHCP, there are no initial DHCP Discover ++ packets were not seen on the wire. ++ ++ Cause: Packets generated from the app handler from the uIP stack ++ were not placed on the wire. ++ ++ Change: Packets originating from the uIP stack are now always placed ++ on the wire. ++ ++uIP v0.5.24 (July 25, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: One would see invalid packet packets flow through the ++ uIP stack, where the logs would indicate there is a packet ++ with an invalid length ++ ++ Cause: The BD and CQE consumer indexes were not properly incremented ++ and masked. ++ ++ Change: The BD index is now properly masked. The CQE index is not ++ incremented using the CQE index rather the mistaken BD index. ++ ++ Impact: 10G only ++ ++ 2. Problem: uIP would segfault during the booting of the machine. ++ ++ Cause: uIP was using a NULL data pointer because there was an ++ incorrect packet passed to the stack. ++ ++ Change: Only allow uIP to process data if the packet exists. ++ ++ 3. Problem: uIP would stop processing packets ++ ++ Cause: The uIP code would not properly drain the CQE ring causing ++ it to eventually be full ++ ++ Change: Consume all the CQE elements even if they are ethernet types ++ or not. ++ ++ Impact: 10G only ++ ++ 4. Problem: uIP would stop after if/down of the network interface. ++ ++ Cause: uIP was not kick starting the NIC loop thread properly. ++ ++ Change: Ensure that the NIC loop thread is started by when iscsid ++ request that the interface start the offload. Mark the NIC ++ only if the thread is truly canceled. ++ ++ ++uIP v0.5.23 (July 20, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Segfault during brcm_iscsiuio initialization ++ ++ Cause: uIP was using a NULL data pointer, because a different ++ thread re-initialized the uIP stack ++ ++ Change: Properly synchronize the initialization of the stack ++ ++ 2. Problem: Deadlock during the printing of heavy debug messages ++ ++ Cause: The variable macro structures would point to invalid ++ data ++ ++ Change: With each invocation of va_copy() a corresponding ++ invocation of va_end() in the same function for the proper ++ cleanup ++ ++ 3. Problem: uIP would hang when the interface could go up/down ++ ++ Cause: uIP would get out of sync with the state of the network ++ interface ++ ++ Change: Instead of detriving state from the UIO file nodes, uIP ++ will take direction from iscsid on when interfaces will be ++ started. ++ ++uIP v0.5.22 (July 15, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Unable to reconnect via iSCSI offload after ++ ifup/ifdown ++ ++ Cause: uIP was stuck on the thread when closing the NIC main ++ loop ++ ++ Change: Properly synchronize the NetLink CNIC and uevent threads ++ ++ 2. Problem: uIP would crash during boot up. ++ ++ Cause: uIP would overwrite a memory location which was already ++ freed during nic_remove(). ++ ++ Change: Since the NIC is freed there is no need to write to ++ update the NIC flags ++ ++ Enhancements ++ ------------ ++ ++ 1. Change: Added IPv6 Link Local support ++ ++ ++uIP v0.5.21 (July 5, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Unable to connect via iSCSI offload after ++ changing L2 address ++ ++ Cause: uIP didn't notice the network inferface going down ++ ++ Change: Allow uIP to persist the stack's IP address after ++ a reset ++ ++ 2. Problem: Unable to connect via IPv4 and IPv6 concurrently ++ ++ Cause: uIP didn't notice the network inferface going down ++ ++ Change: Allow uIP to persist the stack's IP address after ++ a reset and properly bring up the interface ++ ++ 3. Problem: Unable to connect via VLAN ++ ++ Cause: IP address was no persisted after a device reset ++ ++ Change: When CNIC requests a path request, uIP will use the ++ VLAN passed by the CNIC. ++ ++ ++uIP v0.5.20 (June 24, 2010) ++ ++ ++uIP v0.5.20 (June 24, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Certain IPv6 addresses are not repsonded to by ++ the target. ++ ++ Cause: The MAC was generated from the target's IPv6 ++ address not the deterived multicast IPv6 address. ++ ++ Change: The destination MAC address should be deterived ++ from the packet's destination IPv6 address and ++ not the target. ++ ++ 2. Problem: brcm_iscsiuio would segfault when L2 interface is ++ bought up and down after being logged into ++ ++ Cause: The NIC thread was not stopped properly ++ ++ Change: When the UIO device is remove and when the ++ cooresponding NIC tracked by brcm_iscsiuio, the ++ daemon would properly wait for the NIC thread to ++ stop. ++ ++ ++uIP v0.5.19 (June 22, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Can't login after boot ++ ++ Cause: If NIC interfaces are brough up and down quickly ++ uIP wait on an invalid NIC thread ++ ++ Change: Only wait for the NIC thread if the NIC thread ++ exists. ++ ++uIP v0.5.18 (June 21, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Does not compile on SLES 11 SP1 ++ ++ Cause: Automake cached files were included as part of the ++ uIP-0.5.17 package ++ ++ Change: Remove automake cached files, and allow these files ++ to be generated each time the source is compiled ++ ++ 2. Problem: Does not always receive multicast packets ++ ++ Cause: Multicast bit was not set in SORT USER 2 register ++ ++ Change: brcm_iscsiuio will now set the SORT USER 2 registers ++ with both the broadcast and multicast bits. ++ ++ 3. Problem: Existing iSCSI connections do not reconnect after ++ operations which require equivalent driver ++ load/unload operations ++ ++ Cause: Multiple path requests would trample NIC configurations ++ ++ Change: Allow only one path request at a time ++ ++uIP v0.5.17 (June 16, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: IPv6 neighbor solicitations from brcm_iscsiuio could ++ not be responded to ++ ++ Cause: The IPv6 neighbor solicitation packet had an invalid ++ multicast MAC address ++ ++ Change: Properly set the MAC address multicast bit and OR ++ with the IPv6 destination address ++ ++ 2. Problem: NIC state was not properly synchronized and noticed ++ by Shyam Iyer ++ ++ Change: Properly lock the NIC device when changing state ++ ++ Enhancements ++ ------------ ++ ++ 1. Change: Listen for iscsid before daemonizing to close a timing ++ gap which might allow iscsid to start before uIP is ++ completely initialized. ++ ++uIP v0.5.16 (June 2, 2010) ++======================================================= ++ ++ Enhancements ++ ------------ ++ ++ 1. Change: Formally add IPv6 support. Only a static IPv6 address ++ is supported. ++ ++uIP v0.5.15 (May 20, 2010) ++======================================================= ++ ++ Fixes ++ ----- ++ 1. Problem: brcm_iscsiuio would echo packets off the wire ++ ++ Cause: Stale packets from the uIP stack could potentially ++ make it onto the wire causing a network flood ++ ++ Change: Only place on the wire packets uIP intended to place ++ on the wire. Drop all other packets. ++ ++uIP v0.5.14 (May 18, 2010) ++======================================================= ++ ++ Fixes ++ ----- ++ 1. Problem: brcm_iscsiuio would crash when offloading using a ++ bnx2x device /dev/mem could not be ++ opened, (ie. SE Linux enabled) ++ ++ Cause: /dev/mem could not be opened, (ie. SE Linux enabled) ++ and then the NIC would be improperly initialized. ++ ++ Change: If /dev/mem is not able to be opened, then the device ++ is closed ++ ++ 2. Problem: brcm_iscsiuio would crash when brcm_iscsiuio is ++ being shutdown ++ ++ Cause: The NIC mutex was deferenced imporperly when the NIC ++ is being closed ++ ++ Change: Take the NIC mutex lock only when the NIC is closed. ++ ++uIP v0.5.13 (May 16, 2010) ++======================================================= ++ ++ Fixes ++ ----- ++ 1. Problem: brcm_iscsiuio would crash with heavy traffic directed ++ at the iSCSI traffic ++ ++ Cause: Packets which are sized between 1006-1024 bytes would ++ crash brcm_iscsiuio because brcm_iscsiuio is not sized ++ to handle such large packets ++ ++ Change: Drop large packets, properly hold the NIC mutex lock ++ for the duration when NIC fields are being used. ++ ++ ++uIP v0.5.12 (May 13, 2010) ++======================================================= ++ ++ Fixes ++ ----- ++ 1. Problem: brcm_iscsiuio could crash on when L2 interface is ++ ifdown'ed ++ ++ Cause: The local NIC pointer was not initialized properly ++ in the routine parse_iface() ++ ++ Change: Properly initialize the NIC pointer ++ ++ 2. Problem: Documentation referred to older admin_client which ++ doesn't exist any more because brcm_iscsiuio uses ++ the iscsid iface file ++ ++ Change: Remove the stale references ++ ++ ++uIP v0.5.11 (May 11, 2010) ++======================================================= ++ ++ Fixes ++ ----- ++ 1. Problem: brcm_iscsiuio could crash on invalid packet sizes ++ ++ Cause: The hardware BD could be a large value because of a ++ hardware error ++ ++ Change: Limit the size of the packet dumped to the MTU size ++ ++ Enhancements ++ ------------ ++ ++ 1. Change: During the running of the configure script now ++ the script will check for ar and ranlib binaries ++ ++ ++uIP v0.5.10 (May 03, 2010) ++======================================================= ++ ++ Fixes ++ ----- ++ 1. Problem: BCM57712 not recognized ++ ++ Cause: The PCI ID's in the bnx2x file were missing. ++ ++ Change: Added proper BCM57712, BCM57712E, BCM57713, BCM57713E ++ PCI ID's ++ ++ 2. Problem: (CQ 47481) brcm_iscsiuio not installed in correct location ++ ++ Cause: Default install path for autoconf is /usr/local ++ ++ Change: Change the default prefix to '/' so the brcm_iscsiuio ++ binary is installed to /sbin/ ++ ++ Enhancements ++ ------------ ++ ++ 1. Change: Remove dependency on Yacc and Lex ++ ++ ++uIP v0.5.9 (April 28, 2010) ++======================================================= ++ ++ Fixes ++ ----- ++ 1. Problem: bnx2x T6.0 driver would not login ++ ++ Cause: The bnx2x code was not using the T6.0 HSI offsets ++ ++ Change: Determine to bnx2x driver version eariler to properly use the ++ T4.8 or T6.0 HSI ++ ++ Enhancements ++ ------------ ++ ++ 1. Change: Collapse all the various locks to use the NIC lock to shrink ++ memory footprint ++ ++ 2. Change: Consolidate upper layer checksumming code ++ ++ ++uIP v0.5.5 (March 02, 2010) ++======================================================= ++ ++ Enhancements ++ ------------ ++ ++ 1. Change: Add support for T6.0 bnx2x HSI and 57712. ++ ++ 2. Change: Initial support for IPv6 ++ ++uIP v0.5.8 (April 22, 2010) ++======================================================= ++ ++ Enhancements ++ ------------ ++ ++ 1. Change: Add support for T6.0 bnx2x HSI and 57712. ++ ++ 2. Change: Initial support for IPv6 ++ ++uIP v0.5.7 (March 17, 2010) ++======================================================= ++ ++ Enhancements ++ ------------ ++ ++ 1. Change: Add to documentation on discovering on a particular ++ iface before logging in ++ ++uIP v0.5.6 (Mar 05, 2009) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: bnx2x panic dump would be seen when sending ++ traffic to uIP ++ ++ Cause: The TX producer index was not properly ++ incrementing when the wrapping occured ++ ++ Change: Do not skip the last TX producer index like the ++ TX BD's ++ ++ Impact: None. ++ ++uIP v0.5.5 (March 02, 2010) ++======================================================= ++ Initial release ++ ++ Enhancements ++ ------------ ++ ++ 1. Change: Add to documentation on debugging/logging for uIP ++ ++ ++uIP v0.5.4 (Feb 22, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Compile error where 'ETHERTYPE_VLAN' define ++ is missing ++ ++ Cause: Certain distributions do not define 'ETHERTYPE_VLAN' ++ in the header file "net/ethernet.h". ++ ++ Change: Added proper defines for ETHERTYPE_VLAN when necessary ++ ++ Impact: None. ++ ++ ++uIP v0.5.3 (Feb 18, 2010) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Using VLAN's on offloaded iSCSI connections ++ ++ Cause: (CQ45983) VLAN tags were not being properly inserted ++ when sending the ARP request packets ++ ++ Change: Added VLAN tags when sending ARP request packets ++ ++ Impact: None. ++ ++ ++uIP v0.5.2 (Dec 10, 2009) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: Switching between 10G and 1G iSCSI offloaded ++ devices caused login connectivity problems ++ ++ Cause: The NIC devices within uIP were not cleanup ++ properly. ++ ++ Change: The NIC structure is not re-initialized and the ++ NIC thread is destroyed when the host network ++ interface is brought down. ++ ++ Impact: None. ++ ++ ++uIP v0.5.1 (Dec 9, 2009) ++======================================================= ++ Fixes ++ ----- ++ 1. Problem: 10G devices behind PCI bridges would not collect ++ ++ Cause: PCI bus:slot.func string was parsed incorrectly ++ because the bridge string was used ++ ++ Change: Parse the proper PCI bus:slot.func string. ++ ++ Impact: None. ++ ++ ++uIP v0.5.0b (Nov 24, 2009) ++======================================================= ++ Initial release ++ ++ Enhancements ++ ------------ ++ ++ 1. Change: Add Broadcom 10G iSCSI offload support ++ ++ Impact: Linux ++ +diff --git a/iscsiuio/configure.ac b/iscsiuio/configure.ac +new file mode 100644 +index 0000000..6c0013b +--- /dev/null ++++ b/iscsiuio/configure.ac +@@ -0,0 +1,78 @@ ++dnl iscsiuio uIP user space stack configure.ac file ++dnl ++dnl Copyright (c) 2004-2013 Broadcom Corporation ++dnl Copyright (c) 2014, QLogic Corporation ++dnl ++dnl This program is free software; you can redistribute it and/or modify ++dnl it under the terms of the GNU General Public License as published by ++dnl the Free Software Foundation. ++dnl ++dnl Written by: Eddie Wai (eddie.wai@broadcom.com) ++dnl Benjamin Li (benli@broadcom.com) ++dnl ++ ++PACKAGE=iscsiuio ++VERSION=0.7.8.2 ++ ++AC_INIT([iscsiuio], [0.7.8.2], [QLogic-Storage-Upstream@qlogic.com]) ++ ++AM_INIT_AUTOMAKE ++AC_CONFIG_HEADER(config.h) ++AC_PATH_PROGS(BASH, bash) ++ ++AC_PROG_CC ++AM_PROG_CC_C_O ++ ++AC_PROG_RANLIB ++ ++AC_GNU_SOURCE ++AC_PROG_INSTALL ++AC_PROG_GCC_TRADITIONAL ++ ++# Checks for typedefs, structures, and compiler characteristics. ++AC_C_CONST ++AC_C_INLINE ++AC_TYPE_OFF_T ++AC_TYPE_SIZE_T ++AC_CHECK_TYPES(int8_t) ++AC_CHECK_TYPES(uint8_t) ++AC_CHECK_TYPES(int16_t) ++AC_CHECK_TYPES(uint16_t) ++AC_CHECK_TYPES(int32_t) ++AC_CHECK_TYPES(uint32_t) ++AC_CHECK_TYPES(int64_t) ++AC_CHECK_TYPES(uint64_t) ++AC_CHECK_SIZEOF(short, 2) ++AC_CHECK_SIZEOF(int, 4) ++AC_CHECK_SIZEOF(long, 4) ++ ++AC_C_BIGENDIAN(AC_SUBST([ENDIAN],[BIG]),AC_SUBST([ENDIAN],[LITTLE])) ++ ++AC_LIBTOOL_DLOPEN ++ ++# libtool stuff ++AC_PROG_LIBTOOL ++ ++: ${CFLAGS:="-O2"} ++CFLAGS="${CFLAGS} -Wall" ++## check for --enable-debug first before checking CFLAGS before ++## so that we don't mix -O and -g ++AC_ARG_ENABLE(debug, ++[ --enable-debug Turn on compiler debugging information (default=no)], ++ [if eval "test x$enable_debug = xyes"; then ++ CFLAGS="${CFLAGS} -g -O0" ++ fi]) ++AM_CONDITIONAL([DEBUG], [test x$debug = xtrue]) ++ ++AC_CONFIG_COMMANDS([default],[[ echo 'char *build_date = "'`date`'";' > src/unix/build_date.c && echo 'char *build_date;'> src/unix/build_date.h]],[[]]) ++ ++AC_PREFIX_DEFAULT() ++ ++AC_OUTPUT([Makefile ++src/Makefile ++src/apps/Makefile ++src/apps/dhcpc/Makefile ++src/apps/brcm-iscsi/Makefile ++src/uip/Makefile ++src/unix/Makefile ++src/unix/libs/Makefile]) +diff --git a/iscsiuio/docs/iscsiuio.8 b/iscsiuio/docs/iscsiuio.8 +new file mode 100644 +index 0000000..b329979 +--- /dev/null ++++ b/iscsiuio/docs/iscsiuio.8 +@@ -0,0 +1,89 @@ ++.\" Copyright (c) 2010-2013 Broadcom Corporation ++.\" Copyright (c) 2014, QLogic Corporation ++.\" This is free documentation; you can redistribute it and/or ++.\" modify it under the terms of the GNU General Public License as ++.\" published by the Free Software Foundation. ++.\" ++.\" bnx2.4,v 0.7.8.1b ++.\" ++.TH iscsiuio 8 "12/10/2013" "QLogic Corporation" ++.\" ++.\" NAME part ++.\" ++.SH NAME ++iscsiuio \- iSCSI UserSpace I/O driver ++.\" ++.\" SYNOPSIS part ++.\" ++.SH SYNOPSIS ++.B iscsiuio ++.RB [ -d -f -v ] ++.PP ++.\" ++.\" DESCRIPTION part ++.\" ++.SH DESCRIPTION ++iscsiuio is the UserSpace I/O driver for the QLogic NetXtreme II ++BCM5706/5708/5709 series PCI/PCI-X Gigabit Ethernet Network Interface Card ++(NIC) and for the QLogic NetXtreme II BCM57710/57711/57712/57800/57810/57840 ++series PCI-E 10 Gigabit Ethernet Network Interface Card. ++The driver has been tested on 2.6.28 kernels and above. ++.PP ++Refer to the README.TXT from the driver package on how to ++compile and install the driver. ++.PP ++Refer to various Linux documentations ++on how to configure network protocol and address. ++.\" ++.\" DRIVER DEPENDENCIES part ++.\" ++.SH DRIVER DEPENDENCIES ++ ++.\" ++.\" PARAMETER part ++.\" ++.SH PARAMETERS ++There are very few parameters when running this application. ++.TP ++.BI -d ++This is to enable debug mode where debug messages will be sent to stdout ++The following debug modes are supported ++.P ++.RS ++DEBUG 4 - Print all messages ++.P ++INFO 3 - Print messages needed to follow the uIP code (default) ++.P ++WARN 2 - Print warning messages ++.P ++ERROR 1 - Only print critical errors ++.RE ++.PP ++.TP ++.TP ++.BI -f ++This is to enable forground mode so that this application doesn't get sent ++into the background. ++.PP ++.TP ++.BI -v ++This is to print the version. ++.PP ++.TP ++.BI -p ++Use pidfile (default /var/run/iscsiuio.pid ) ++.PP ++.TP ++.BI -h ++Display this help and exit. ++ ++ ++.\" ++.\" AUTHOR part ++.\" ++.SH AUTHOR ++Benjamin Li \- benli@broadcom.com ++.P ++Eddie Wai \- eddie.wai@broadcom.com ++.SH Maintained by ++QLogic-Storage-Upstream@qlogic.com +diff --git a/iscsiuio/iscsiuiolog b/iscsiuio/iscsiuiolog +new file mode 100644 +index 0000000..360947c +--- /dev/null ++++ b/iscsiuio/iscsiuiolog +@@ -0,0 +1,10 @@ ++/var/log/iscsiuio.log { ++ weekly ++ missingok ++ notifempty ++ rotate 4 ++ sharedscripts ++ postrotate ++ pkill -USR1 iscsiuio 2> /dev/null || true ++ endscript ++} +diff --git a/iscsiuio/src/Makefile.am b/iscsiuio/src/Makefile.am +new file mode 100644 +index 0000000..44b0085 +--- /dev/null ++++ b/iscsiuio/src/Makefile.am +@@ -0,0 +1 @@ ++SUBDIRS = apps uip unix +diff --git a/iscsiuio/src/README b/iscsiuio/src/README +new file mode 100644 +index 0000000..9fca6fb +--- /dev/null ++++ b/iscsiuio/src/README +@@ -0,0 +1,13 @@ ++uIP is a very small implementation of the TCP/IP stack that is written ++by Adam Dunkels . More information can be obtained ++at the uIP homepage at http://www.sics.se/~adam/uip/. ++ ++This is version $Name: uip-1-0 $. ++ ++The directory structure look as follows: ++ ++apps/ - Example applications ++doc/ - Documentation ++lib/ - Library code used by some applications ++uip/ - uIP TCP/IP stack code ++unix/ - uIP as a user space process under FreeBSD or Linux +diff --git a/iscsiuio/src/apps/Makefile.am b/iscsiuio/src/apps/Makefile.am +new file mode 100644 +index 0000000..08ed18d +--- /dev/null ++++ b/iscsiuio/src/apps/Makefile.am +@@ -0,0 +1 @@ ++SUBDIRS = dhcpc brcm-iscsi +diff --git a/iscsiuio/src/apps/README b/iscsiuio/src/apps/README +new file mode 100644 +index 0000000..0096c4e +--- /dev/null ++++ b/iscsiuio/src/apps/README +@@ -0,0 +1,2 @@ ++This directory contains a few example applications. They are not all ++heavily tested, however. +diff --git a/iscsiuio/src/apps/brcm-iscsi/Makefile.am b/iscsiuio/src/apps/brcm-iscsi/Makefile.am +new file mode 100644 +index 0000000..00cbd8e +--- /dev/null ++++ b/iscsiuio/src/apps/brcm-iscsi/Makefile.am +@@ -0,0 +1,13 @@ ++AM_CFLAGS = -I${top_srcdir}/src/unix \ ++ -I${top_srcdir}/src/uip \ ++ -I${top_srcdir}/src/apps/dhcpc \ ++ -I${top_srcdir}/src/apps/brcm-iscsi \ ++ -I${top_srcdir}/../include \ ++ -I${top_srcdir}/../usr ++ ++noinst_LIBRARIES = lib_apps_brcm_iscsi.a ++ ++lib_apps_brcm_iscsi_a_SOURCES = brcm_iscsi.c ++ ++lib_apps_brcm_iscsi_a_CFLAGS = $(AM_CFLAGS) \ ++ -DBYTE_ORDER=@ENDIAN@ +diff --git a/iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi b/iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi +new file mode 100644 +index 0000000..732275f +--- /dev/null ++++ b/iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi +@@ -0,0 +1 @@ ++APP_SOURCES += brcm-iscsi.c +diff --git a/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c b/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c +new file mode 100644 +index 0000000..4223ca4 +--- /dev/null ++++ b/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li ++ * Based on code example from Adam Dunkels ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ */ ++/** ++ * \addtogroup brcm-iscsi ++ * @{ ++ */ ++ ++/** ++ * \file ++ * An example of how to write uIP applications ++ * with protosockets ++ * \author ++ * Benjamin Li ++ */ ++ ++/* ++ * This is a short example of how to write uIP applications using ++ * protosockets. ++ */ ++ ++/* ++ * We define the application state (struct hello_world_state) in the ++ * hello-world.h file, so we need to include it here. We also include ++ * uip.h (since this cannot be included in hello-world.h) and ++ * , since we use the memcpy() function in the code. ++ */ ++#include "brcm_iscsi.h" ++#include "uip.h" ++#include ++#include ++ ++#include "uip_arp.h" ++ ++/*---------------------------------------------------------------------------*/ ++/* ++ * The initialization function. We must explicitly call this function ++ * from the system initialization code, some time after uip_init() is ++ * called. ++ */ ++void brcm_iscsi_init(void) ++{ ++} ++ ++/*---------------------------------------------------------------------------*/ ++/* ++ * In hello-world.h we have defined the UIP_APPCALL macro to ++ * hello_world_appcall so that this funcion is uIP's application ++ * function. This function is called whenever an uIP event occurs ++ * (e.g. when a new connection is established, new data arrives, sent ++ * data is acknowledged, data needs to be retransmitted, etc.). ++ */ ++void brcm_iscsi_appcall(struct uip_stack *ustack) ++{ ++} +diff --git a/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h b/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h +new file mode 100644 +index 0000000..10bfc95 +--- /dev/null ++++ b/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li ++ * Based on code example from Adam Dunkels ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ */ ++/** ++ * \addtogroup apps ++ * @{ ++ */ ++ ++/** ++ * \defgroup helloworld Hello, world ++ * @{ ++ * ++ * A small example showing how to write applications with ++ * \ref psock "protosockets". ++ */ ++ ++/** ++ * \file ++ * Header file for an example of how to write uIP applications ++ * with protosockets. ++ * \author ++ * Benjamin Li ++ */ ++ ++#ifndef __BRCM_ISCSI_H__ ++#define __BRCM_ISCSI_H__ ++ ++/* Since this file will be included by uip.h, we cannot include uip.h ++ here. But we might need to include uipopt.h if we need the u8_t and ++ u16_t datatypes. */ ++#include "uipopt.h" ++#include "uip.h" ++#include "psock.h" ++ ++/* Next, we define the hello_world_state structure. This is the state ++ of our application, and the memory required for this state is ++ allocated together with each TCP connection. One application state ++ for each TCP connection. */ ++struct hello_world_state { ++ struct psock p; ++ u8_t inputbuffer[32]; ++ u8_t name[40]; ++ ++ struct uip_udp_conn *conn; ++}; ++ ++/* Finally we define the application function to be called by uIP. */ ++void brcm_iscsi_appcall(struct uip_stack *ustack); ++#ifndef UIP_APPCALL ++#define UIP_APPCALL brcm_iscsi_appcall ++#endif /* UIP_APPCALL */ ++ ++void brcm_iscsi_init(void); ++ ++#endif /* __BRCM_ISCSI_H__ */ ++/** @} */ ++/** @} */ +diff --git a/iscsiuio/src/apps/dhcpc/Makefile.am b/iscsiuio/src/apps/dhcpc/Makefile.am +new file mode 100644 +index 0000000..1c97993 +--- /dev/null ++++ b/iscsiuio/src/apps/dhcpc/Makefile.am +@@ -0,0 +1,13 @@ ++AM_CFLAGS = -I${top_srcdir}/src/unix \ ++ -I${top_srcdir}/src/uip \ ++ -I${top_srcdir}/src/apps/dhcpc \ ++ -I${top_srcdir}/src/apps/brcm-iscsi \ ++ -I${top_srcdir}/../include \ ++ -I${top_srcdir}/../usr ++ ++noinst_LIBRARIES = lib_apps_dhcpc.a ++ ++lib_apps_dhcpc_a_SOURCES = dhcpc.c dhcpv6.c ++ ++lib_apps_dhcpc_a_CFLAGS = $(AM_CFLAGS) \ ++ -DBYTE_ORDER=@ENDIAN@ +diff --git a/iscsiuio/src/apps/dhcpc/Makefile.dhcpc b/iscsiuio/src/apps/dhcpc/Makefile.dhcpc +new file mode 100644 +index 0000000..f84c84f +--- /dev/null ++++ b/iscsiuio/src/apps/dhcpc/Makefile.dhcpc +@@ -0,0 +1 @@ ++APP_SOURCES += dhcpc.c timer.c +diff --git a/iscsiuio/src/apps/dhcpc/dhcpc.c b/iscsiuio/src/apps/dhcpc/dhcpc.c +new file mode 100644 +index 0000000..f4a9994 +--- /dev/null ++++ b/iscsiuio/src/apps/dhcpc/dhcpc.c +@@ -0,0 +1,417 @@ ++/* ++ * Copyright (c) 2005, Swedish Institute of Computer Science ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "uip.h" ++#include "dhcpc.h" ++#include "timer.h" ++#include "pt.h" ++ ++#include "debug.h" ++#include "logger.h" ++#include "nic.h" ++#include "nic_utils.h" ++ ++struct __attribute__ ((__packed__)) dhcp_msg { ++ u8_t op, htype, hlen, hops; ++ u8_t xid[4]; ++ u16_t secs, flags; ++ u8_t ciaddr[4]; ++ u8_t yiaddr[4]; ++ u8_t siaddr[4]; ++ u8_t giaddr[4]; ++ u8_t chaddr[16]; ++#ifndef UIP_CONF_DHCP_LIGHT ++ u8_t sname[64]; ++ u8_t file[128]; ++#endif ++ u8_t options[312]; ++}; ++ ++#define BOOTP_BROADCAST 0x8000 ++ ++#define DHCP_REQUEST 1 ++#define DHCP_REPLY 2 ++#define DHCP_HTYPE_ETHERNET 1 ++#define DHCP_HLEN_ETHERNET 6 ++#define DHCP_MSG_LEN 236 ++ ++#define DHCPC_SERVER_PORT 67 ++#define DHCPC_CLIENT_PORT 68 ++ ++#define DHCPDISCOVER 1 ++#define DHCPOFFER 2 ++#define DHCPREQUEST 3 ++#define DHCPDECLINE 4 ++#define DHCPACK 5 ++#define DHCPNAK 6 ++#define DHCPRELEASE 7 ++ ++#define DHCP_OPTION_SUBNET_MASK 1 ++#define DHCP_OPTION_ROUTER 3 ++#define DHCP_OPTION_DNS_SERVER 6 ++#define DHCP_OPTION_REQ_IPADDR 50 ++#define DHCP_OPTION_LEASE_TIME 51 ++#define DHCP_OPTION_MSG_TYPE 53 ++#define DHCP_OPTION_SERVER_ID 54 ++#define DHCP_OPTION_REQ_LIST 55 ++#define DHCP_OPTION_END 255 ++ ++static u8_t xid[4] = { 0xad, 0xde, 0x12, 0x23 }; ++static const u8_t magic_cookie[4] = { 99, 130, 83, 99 }; ++ ++struct dhcpc_options dhcpc_opt = { ++ .enable_random_xid = 1, ++}; ++ ++/*---------------------------------------------------------------------------*/ ++static u8_t *add_msg_type(u8_t *optptr, u8_t type) ++{ ++ *optptr++ = DHCP_OPTION_MSG_TYPE; ++ *optptr++ = 1; ++ *optptr++ = type; ++ return optptr; ++} ++ ++/*---------------------------------------------------------------------------*/ ++static u8_t *add_server_id(struct dhcpc_state *s, u8_t *optptr) ++{ ++ *optptr++ = DHCP_OPTION_SERVER_ID; ++ *optptr++ = 4; ++ memcpy(optptr, s->serverid, 4); ++ return optptr + 4; ++} ++ ++/*---------------------------------------------------------------------------*/ ++static u8_t *add_req_ipaddr(struct dhcpc_state *s, u8_t *optptr) ++{ ++ *optptr++ = DHCP_OPTION_REQ_IPADDR; ++ *optptr++ = 4; ++ memcpy(optptr, s->ipaddr, 4); ++ return optptr + 4; ++} ++ ++/*---------------------------------------------------------------------------*/ ++static u8_t *add_req_options(u8_t *optptr) ++{ ++ *optptr++ = DHCP_OPTION_REQ_LIST; ++ *optptr++ = 3; ++ *optptr++ = DHCP_OPTION_SUBNET_MASK; ++ *optptr++ = DHCP_OPTION_ROUTER; ++ *optptr++ = DHCP_OPTION_DNS_SERVER; ++ return optptr; ++} ++ ++/*---------------------------------------------------------------------------*/ ++static u8_t *add_end(u8_t *optptr) ++{ ++ *optptr++ = DHCP_OPTION_END; ++ return optptr; ++} ++ ++/*---------------------------------------------------------------------------*/ ++static void create_msg(struct dhcpc_state *s, struct dhcp_msg *m) ++{ ++ m->op = DHCP_REQUEST; ++ m->htype = DHCP_HTYPE_ETHERNET; ++ m->hlen = s->mac_len; ++ m->hops = 0; ++ memcpy(m->xid, xid, sizeof(m->xid)); ++ m->secs = 0; ++ m->flags = const_htons(BOOTP_BROADCAST); /* Broadcast bit. */ ++ /* uip_ipaddr_copy(m->ciaddr, uip_hostaddr); */ ++ memcpy(m->ciaddr, s->ustack->hostaddr, sizeof(m->ciaddr)); ++ memset(m->yiaddr, 0, sizeof(m->yiaddr)); ++ memset(m->siaddr, 0, sizeof(m->siaddr)); ++ memset(m->giaddr, 0, sizeof(m->giaddr)); ++ memcpy(m->chaddr, s->mac_addr, s->mac_len); ++ memset(&m->chaddr[s->mac_len], 0, sizeof(m->chaddr) - s->mac_len); ++#ifndef UIP_CONF_DHCP_LIGHT ++ memset(m->sname, 0, sizeof(m->sname)); ++ memset(m->file, 0, sizeof(m->file)); ++#endif ++ ++ memcpy(m->options, magic_cookie, sizeof(magic_cookie)); ++} ++ ++/*---------------------------------------------------------------------------*/ ++static void send_discover(struct dhcpc_state *s) ++{ ++ u8_t *end; ++ struct dhcp_msg *m = (struct dhcp_msg *)s->ustack->uip_appdata; ++ ++ create_msg(s, m); ++ ++ end = add_msg_type(&m->options[4], DHCPDISCOVER); ++ end = add_req_options(end); ++ end = add_end(end); ++ ++ uip_appsend(s->ustack, s->ustack->uip_appdata, ++ end - (u8_t *) s->ustack->uip_appdata); ++} ++ ++/*---------------------------------------------------------------------------*/ ++static void send_request(struct dhcpc_state *s) ++{ ++ u8_t *end; ++ struct dhcp_msg *m = (struct dhcp_msg *)s->ustack->uip_appdata; ++ ++ create_msg(s, m); ++ ++ end = add_msg_type(&m->options[4], DHCPREQUEST); ++ end = add_server_id(s, end); ++ end = add_req_ipaddr(s, end); ++ end = add_end(end); ++ ++ uip_appsend(s->ustack, s->ustack->uip_appdata, ++ end - (u8_t *) s->ustack->uip_appdata); ++} ++ ++/*---------------------------------------------------------------------------*/ ++static u8_t parse_options(struct dhcpc_state *s, u8_t *optptr, int len) ++{ ++ u8_t *end = optptr + len; ++ u8_t type = 0; ++ ++ while (optptr < end) { ++ switch (*optptr) { ++ case DHCP_OPTION_SUBNET_MASK: ++ memcpy(s->netmask, optptr + 2, 4); ++ break; ++ case DHCP_OPTION_ROUTER: ++ memcpy(s->default_router, optptr + 2, 4); ++ break; ++ case DHCP_OPTION_DNS_SERVER: ++ memcpy(s->dnsaddr, optptr + 2, 4); ++ break; ++ case DHCP_OPTION_MSG_TYPE: ++ type = *(optptr + 2); ++ break; ++ case DHCP_OPTION_SERVER_ID: ++ memcpy(s->serverid, optptr + 2, 4); ++ break; ++ case DHCP_OPTION_LEASE_TIME: ++ memcpy(s->lease_time, optptr + 2, 4); ++ break; ++ case DHCP_OPTION_END: ++ return type; ++ } ++ ++ optptr += optptr[1] + 2; ++ } ++ return type; ++} ++ ++/*---------------------------------------------------------------------------*/ ++static u8_t parse_msg(struct dhcpc_state *s) ++{ ++ struct dhcp_msg *m = (struct dhcp_msg *)s->ustack->uip_appdata; ++ ++ if (m->op == DHCP_REPLY && ++ memcmp(m->xid, xid, sizeof(xid)) == 0 && ++ memcmp(m->chaddr, s->mac_addr, s->mac_len) == 0) { ++ memcpy(s->ipaddr, m->yiaddr, 4); ++ return parse_options(s, &m->options[4], uip_datalen(s->ustack)); ++ } ++ return 0; ++} ++ ++/*---------------------------------------------------------------------------*/ ++static PT_THREAD(handle_dhcp(struct uip_stack *ustack)) ++{ ++ struct dhcpc_state *s; ++ s = ustack->dhcpc; ++ ++ if (s == NULL) { ++ LOG_WARN("Could not find dhcpc state"); ++ return PT_ENDED; ++ } ++ ++ PT_BEGIN(&s->pt); ++ ++ /* try_again: */ ++ s->state = STATE_SENDING; ++ s->ticks = CLOCK_SECOND; ++ ++ do { ++ send_discover(s); ++ timer_set(&s->timer, s->ticks); ++ PT_WAIT_UNTIL(&s->pt, uip_newdata(s->ustack) ++ || timer_expired(&s->timer)); ++ ++ if (uip_newdata(s->ustack) && parse_msg(s) == DHCPOFFER) { ++ s->state = STATE_OFFER_RECEIVED; ++ break; ++ } ++ ++ if (s->ticks < CLOCK_SECOND * 60) ++ s->ticks += CLOCK_SECOND; ++ else ++ PT_RESTART(&s->pt); ++ } while (s->state != STATE_OFFER_RECEIVED); ++ ++ s->ticks = CLOCK_SECOND; ++ ++ do { ++ send_request(s); ++ timer_set(&s->timer, s->ticks); ++ s->ustack->uip_flags &= ~UIP_NEWDATA; ++ PT_WAIT_UNTIL(&s->pt, uip_newdata(s->ustack) ++ || timer_expired(&s->timer)); ++ ++ if (uip_newdata(s->ustack) && parse_msg(s) == DHCPACK) { ++ s->state = STATE_CONFIG_RECEIVED; ++ break; ++ } ++ ++ if (s->ticks <= CLOCK_SECOND * 10) ++ s->ticks += CLOCK_SECOND; ++ else ++ PT_RESTART(&s->pt); ++ } while (s->state != STATE_CONFIG_RECEIVED); ++ ++ LOG_INFO("Got IP address %d.%d.%d.%d", ++ uip_ipaddr1(s->ipaddr), uip_ipaddr2(s->ipaddr), ++ uip_ipaddr3(s->ipaddr), uip_ipaddr4(s->ipaddr)); ++ LOG_INFO("Got netmask %d.%d.%d.%d", ++ uip_ipaddr1(s->netmask), uip_ipaddr2(s->netmask), ++ uip_ipaddr3(s->netmask), uip_ipaddr4(s->netmask)); ++ LOG_INFO("Got DNS server %d.%d.%d.%d", ++ uip_ipaddr1(s->dnsaddr), uip_ipaddr2(s->dnsaddr), ++ uip_ipaddr3(s->dnsaddr), uip_ipaddr4(s->dnsaddr)); ++ LOG_INFO("Got default router %d.%d.%d.%d", ++ uip_ipaddr1(s->default_router), uip_ipaddr2(s->default_router), ++ uip_ipaddr3(s->default_router), ++ uip_ipaddr4(s->default_router)); ++ s->lease_time_nl32 = ++ ntohs(s->lease_time[0]) * 65536ul + ntohs(s->lease_time[1]); ++ LOG_INFO("Lease expires in %ld seconds", s->lease_time_nl32); ++ ++ s->last_update = time(NULL); ++ ++ set_uip_stack(s->ustack, ++ (uip_ip4addr_t *) s->ipaddr, ++ (uip_ip4addr_t *) s->netmask, ++ (uip_ip4addr_t *) s->default_router, ++ (uint8_t *) s->mac_addr); ++ ++ /* Put the stack thread back into a long sleep */ ++ s->nic->flags |= NIC_LONG_SLEEP; ++ ++ /* timer_stop(&s.timer); */ ++ ++ /* Handle DHCP lease expiration */ ++ s->ticks = CLOCK_SECOND * s->lease_time_nl32; ++ timer_set(&s->timer, s->ticks); ++ PT_WAIT_UNTIL(&s->pt, timer_expired(&s->timer)); ++ LOG_INFO("Lease expired, re-acquire IP address"); ++ s->nic->flags &= ~NIC_LONG_SLEEP; ++ PT_RESTART(&s->pt); ++ ++ /* ++ * PT_END restarts the thread so we do this instead. Eventually we ++ * should reacquire expired leases here. ++ */ ++ ++ while (1) ++ PT_YIELD(&s->pt); ++ ++ PT_END(&(s->pt)); ++} ++ ++/*---------------------------------------------------------------------------*/ ++int dhcpc_init(nic_t *nic, struct uip_stack *ustack, ++ const void *mac_addr, int mac_len) ++{ ++ uip_ip4addr_t addr; ++ struct dhcpc_state *s = ustack->dhcpc; ++ ++ if (s) { ++ LOG_DEBUG("DHCP: DHCP context already allocated"); ++ return -EALREADY; ++ } ++ s = malloc(sizeof(*s)); ++ if (s == NULL) { ++ LOG_ERR("Couldn't allocate size for dhcpc info"); ++ return -ENOMEM; ++ } ++ ++ memset(s, 0, sizeof(*s)); ++ s->nic = nic; ++ s->ustack = ustack; ++ s->mac_addr = mac_addr; ++ s->mac_len = mac_len; ++ s->state = STATE_INITIAL; ++ ++ /* Initialize XID to randomly */ ++ if (dhcpc_opt.enable_random_xid == 1) { ++ u32_t gen_xid; ++ gen_xid = random(); ++ memcpy(xid, &gen_xid, sizeof(gen_xid)); ++ } ++ uip_ipaddr(addr, 255, 255, 255, 255); ++ s->conn = uip_udp_new(ustack, &addr, const_htons(DHCPC_SERVER_PORT)); ++ if (s->conn != NULL) ++ uip_udp_bind(s->conn, const_htons(DHCPC_CLIENT_PORT)); ++ ++ ustack->dhcpc = s; ++ ++ /* Let the RX poll value take over */ ++ nic->flags &= ~NIC_LONG_SLEEP; ++ ++ PT_INIT(&s->pt); ++ ++ return 0; ++} ++ ++/*---------------------------------------------------------------------------*/ ++void dhcpc_appcall(struct uip_stack *ustack) ++{ ++ handle_dhcp(ustack); ++} ++ ++/*---------------------------------------------------------------------------*/ ++void dhcpc_request(struct uip_stack *ustack) ++{ ++ struct dhcpc_state *s = ustack->dhcpc; ++ ++ if (s != NULL && s->state == STATE_INITIAL) ++ handle_dhcp(ustack); ++} ++ ++/*---------------------------------------------------------------------------*/ +diff --git a/iscsiuio/src/apps/dhcpc/dhcpc.h b/iscsiuio/src/apps/dhcpc/dhcpc.h +new file mode 100644 +index 0000000..89cf086 +--- /dev/null ++++ b/iscsiuio/src/apps/dhcpc/dhcpc.h +@@ -0,0 +1,86 @@ ++/* ++ * Copyright (c) 2005, Swedish Institute of Computer Science ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ */ ++#ifndef __DHCPC_H__ ++#define __DHCPC_H__ ++ ++#include ++ ++#include "nic.h" ++#include "timer.h" ++#include "pt.h" ++#include "uip.h" ++ ++#define STATE_INITIAL 0 ++#define STATE_SENDING 1 ++#define STATE_OFFER_RECEIVED 2 ++#define STATE_CONFIG_RECEIVED 3 ++ ++struct dhcpc_state { ++ struct pt pt; ++ ++ nic_t *nic; ++ struct uip_stack *ustack; ++ char state; ++ struct uip_udp_conn *conn; ++ struct timer timer; ++ u32_t ticks; ++ const void *mac_addr; ++ int mac_len; ++ ++ u8_t serverid[4]; ++ ++ u16_t lease_time[2]; ++ u32_t lease_time_nl32; ++ u16_t ipaddr[2]; ++ u16_t netmask[2]; ++ u16_t dnsaddr[2]; ++ u16_t default_router[2]; ++ ++ time_t last_update; ++}; ++ ++struct dhcpc_options { ++ u8_t enable_random_xid; ++ u8_t xid[4]; ++}; ++ ++int dhcpc_init(nic_t *nic, struct uip_stack *ustack, ++ const void *mac_addr, int mac_len); ++void dhcpc_request(struct uip_stack *ustack); ++ ++void dhcpc_appcall(struct uip_stack *ustack); ++ ++void dhcpc_configured(const struct dhcpc_state *s); ++ ++#define UIP_UDP_APPCALL dhcpc_appcall ++ ++#endif /* __DHCPC_H__ */ +diff --git a/iscsiuio/src/apps/dhcpc/dhcpv6.c b/iscsiuio/src/apps/dhcpc/dhcpv6.c +new file mode 100644 +index 0000000..a4e25f0 +--- /dev/null ++++ b/iscsiuio/src/apps/dhcpc/dhcpv6.c +@@ -0,0 +1,512 @@ ++/* ++ * Copyright (c) 2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Eddie Wai ++ * Based on code from Kevin Tran's iSCSI boot code ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * dhcpv6.c - DHCPv6 engine ++ * ++ */ ++#include ++#include ++ ++#include "ipv6.h" ++#include "ipv6_pkt.h" ++#include "dhcpv6.h" ++#include "logger.h" ++ ++/* Local function prototypes */ ++static int dhcpv6_send_solicit_packet(struct dhcpv6_context *context); ++static int dhcpv6_send_request_packet(struct dhcpv6_context *context); ++static u16_t dhcpv6_init_packet(struct dhcpv6_context *context, u8_t type); ++static void dhcpv6_init_dhcpv6_server_addr(struct ipv6_addr *addr); ++static void dhcpv6_handle_advertise(struct dhcpv6_context *context, ++ u16_t dhcpv6_len); ++static void dhcpv6_handle_reply(struct dhcpv6_context *context, ++ u16_t dhcpv6_len); ++static int dhcpv6_process_opt_ia_na(struct dhcpv6_context *context, ++ struct dhcpv6_opt_hdr *opt_hdr); ++static void dhcpv6_process_opt_dns_servers(struct dhcpv6_context *context, ++ struct dhcpv6_opt_hdr *opt_hdr); ++static void dhcpv6_parse_vendor_option(struct dhcpv6_context *context, ++ u8_t *option, int len); ++ ++void dhcpv6_init(struct dhcpv6_context *context) ++{ ++ context->seconds = 0; ++ context->our_mac_addr = ++ ipv6_get_link_addr(context->ipv6_context); ++ ++ /* Use the last four bytes of MAC address as base of the transaction ++ ID */ ++ context->dhcpv6_transaction_id = context->our_mac_addr->last_4_bytes; ++ ++ context->dhcpv6_done = FALSE; ++ strcpy(context->dhcp_vendor_id, "BRCM ISAN"); ++} ++ ++int dhcpv6_do_discovery(struct dhcpv6_context *context) ++{ ++ int retc = ISCSI_FAILURE; ++ ++ context->eth = ++ (struct eth_hdr *)context->ipv6_context->ustack->data_link_layer; ++ context->ipv6 = ++ (struct ipv6_hdr *)context->ipv6_context->ustack->network_layer; ++ context->udp = ++ (struct udp_hdr *)((u8_t *)context->ipv6 + sizeof(struct ipv6_hdr)); ++ ++ /* Send out DHCPv6 Solicit packet. */ ++ dhcpv6_send_solicit_packet(context); ++ ++ return retc; ++} ++ ++static int dhcpv6_send_solicit_packet(struct dhcpv6_context *context) ++{ ++ u16_t packet_len; ++ ++ LOG_DEBUG("DHCPV6: Send solicit"); ++ packet_len = dhcpv6_init_packet(context, DHCPV6_SOLICIT); ++ context->dhcpv6_state = DHCPV6_STATE_SOLICIT_SENT; ++ ipv6_send_udp_packet(context->ipv6_context, packet_len); ++ ++ return 0; ++} ++ ++static int dhcpv6_send_request_packet(struct dhcpv6_context *context) ++{ ++ u16_t packet_len; ++ ++ LOG_DEBUG("DHCPV6: Send request"); ++ packet_len = dhcpv6_init_packet(context, DHCPV6_REQUEST); ++ ++ context->dhcpv6_state = DHCPV6_STATE_REQ_SENT; ++ ipv6_send_udp_packet(context->ipv6_context, packet_len); ++ ++ return 0; ++} ++ ++static u16_t dhcpv6_init_packet(struct dhcpv6_context *context, u8_t type) ++{ ++ u16_t pkt_len; ++ struct udp_hdr *udp = context->udp; ++ union dhcpv6_hdr *dhcpv6; ++ struct dhcpv6_option *opt; ++ u16_t len; ++ ++ /* Initialize dest IP with well-known DHCP server address */ ++ dhcpv6_init_dhcpv6_server_addr(&context->ipv6->ipv6_dst); ++ /* Initialize dest MAC based on MC dest IP */ ++ ipv6_mc_init_dest_mac(context->eth, context->ipv6); ++ ++ /* Initialize UDP header */ ++ udp->src_port = HOST_TO_NET16(DHCPV6_CLIENT_PORT); ++ udp->dest_port = HOST_TO_NET16(DHCPV6_SERVER_PORT); ++ ++ /* ++ * DHCPv6 section has the following format per RFC 3315 ++ * ++ * 0 1 2 3 ++ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | msg-type | transaction-id | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | | ++ * . options . ++ * . (variable) . ++ * | | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ */ ++ dhcpv6 = (union dhcpv6_hdr *)((u8_t *)udp + sizeof(struct udp_hdr)); ++ ++ if (dhcpv6->dhcpv6_type != type) ++ context->dhcpv6_transaction_id++; ++ ++ dhcpv6->dhcpv6_trans_id = context->dhcpv6_transaction_id; ++ dhcpv6->dhcpv6_type = type; ++ ++ /* Keep track of length of all DHCP options. */ ++ pkt_len = sizeof(union dhcpv6_hdr); ++ ++ if (dhcpv6->dhcpv6_type == DHCPV6_REQUEST) { ++ /* We will send back whatever DHCPv6 sent us */ ++ return ((u8_t *)udp - (u8_t *)context->eth + ++ NET_TO_HOST16(udp->length)); ++ } ++ ++ opt = (struct dhcpv6_option *)((u8_t *)dhcpv6 + ++ sizeof(union dhcpv6_hdr)); ++ /* Add client ID option */ ++ opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_CLIENTID); ++ opt->hdr.length = HOST_TO_NET16(sizeof(struct dhcpv6_opt_client_id)); ++ opt->type.client_id.duid_type = ++ HOST_TO_NET16(DHCPV6_DUID_TYPE_LINK_LAYER_AND_TIME); ++ opt->type.client_id.hw_type = HOST_TO_NET16(DHCPV6_HW_TYPE_ETHERNET); ++ opt->type.client_id.time = HOST_TO_NET32(clock_time()/1000 - ++ 0x3A4FC880); ++ memcpy((char *)&opt->type.client_id.link_layer_addr, ++ (char *)context->our_mac_addr, sizeof(struct mac_address)); ++ pkt_len += sizeof(struct dhcpv6_opt_client_id) + ++ sizeof(struct dhcpv6_opt_hdr); ++ opt = (struct dhcpv6_option *)((u8_t *)opt + ++ sizeof(struct dhcpv6_opt_client_id) + ++ sizeof(struct dhcpv6_opt_hdr)); ++ ++ /* Add Vendor Class option if it's configured */ ++ len = strlen(context->dhcp_vendor_id); ++ if (len > 0) { ++ opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_VENDOR_CLASS); ++ opt->hdr.length = ++ HOST_TO_NET16(sizeof(struct dhcpv6_vendor_class) ++ + len - 1); ++ opt->type.vendor_class.enterprise_number = ++ HOST_TO_NET32(IANA_ENTERPRISE_NUM_BROADCOM); ++ opt->type.vendor_class.vendor_class_length = HOST_TO_NET16(len); ++ memcpy((char *)&opt->type.vendor_class. ++ vendor_class_data[0], ++ (char *)context->dhcp_vendor_id, len); ++ pkt_len += ++ sizeof(struct dhcpv6_vendor_class) - 1 + len + ++ sizeof(struct dhcpv6_opt_hdr); ++ opt = ++ (struct dhcpv6_option *)((u8_t *)opt + ++ sizeof(struct dhcpv6_vendor_class) - 1 + len + ++ sizeof(struct dhcpv6_opt_hdr)); ++ } ++ ++ /* Add IA_NA option */ ++ opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_IA_NA); ++ opt->hdr.length = HOST_TO_NET16(sizeof(struct dhcpv6_opt_id_assoc_na)); ++ opt->type.ida_na.iaid = htonl(context->our_mac_addr->last_4_bytes); ++ opt->type.ida_na.t1 = 0; ++ opt->type.ida_na.t2 = 0; ++ pkt_len += sizeof(struct dhcpv6_opt_id_assoc_na) + ++ sizeof(struct dhcpv6_opt_hdr); ++ opt = (struct dhcpv6_option *)((u8_t *)opt + ++ sizeof(struct dhcpv6_opt_id_assoc_na) + ++ sizeof(struct dhcpv6_opt_hdr)); ++ /* Add Elapsed Time option */ ++ opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_ELAPSED_TIME); ++ opt->hdr.length = HOST_TO_NET16(sizeof(struct dhcpv6_opt_elapse_time)); ++ opt->type.elapsed_time.time = HOST_TO_NET16(context->seconds); ++ pkt_len += sizeof(struct dhcpv6_opt_elapse_time) + ++ sizeof(struct dhcpv6_opt_hdr); ++ ++ /* Add Option Request List */ ++ opt = (struct dhcpv6_option *)((u8_t *)opt + ++ sizeof(struct dhcpv6_opt_elapse_time) + ++ sizeof(struct dhcpv6_opt_hdr)); ++ opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_ORO); ++ opt->hdr.length = HOST_TO_NET16(3 * ++ sizeof(struct dhcpv6_opt_request_list)); ++ opt->type.list.request_code[0] = HOST_TO_NET16(DHCPV6_OPT_VENDOR_CLASS); ++ opt->type.list.request_code[1] = HOST_TO_NET16(DHCPV6_OPT_VENDOR_OPTS); ++ opt->type.list.request_code[2] = HOST_TO_NET16(DHCPV6_OPT_DNS_SERVERS); ++ pkt_len += 3 * sizeof(struct dhcpv6_opt_request_list) + ++ sizeof(struct dhcpv6_opt_hdr); ++ ++ udp->length = HOST_TO_NET16(sizeof(struct udp_hdr) + pkt_len); ++ ++ pkt_len += ++ ((u8_t *)udp - (u8_t *)context->eth) + sizeof(struct udp_hdr); ++ ++ return pkt_len; ++} ++ ++static void dhcpv6_init_dhcpv6_server_addr(struct ipv6_addr *addr) ++{ ++ /* Well-known DHCPv6 server address is ff02::1:2 */ ++ memset((char *)addr, 0, sizeof(struct ipv6_addr)); ++ addr->addr8[0] = 0xff; ++ addr->addr8[1] = 0x02; ++ addr->addr8[13] = 0x01; ++ addr->addr8[15] = 0x02; ++} ++ ++void ipv6_udp_handle_dhcp(struct dhcpv6_context *context) ++{ ++ union dhcpv6_hdr *dhcpv6; ++ u16_t dhcpv6_len; ++ ++ if (context->dhcpv6_done == TRUE) ++ return; ++ ++ dhcpv6 = (union dhcpv6_hdr *)((u8_t *)context->udp + ++ sizeof(struct udp_hdr)); ++ ++ if (dhcpv6->dhcpv6_trans_id != context->dhcpv6_transaction_id) ++ return; ++ ++ dhcpv6_len = ++ NET_TO_HOST16(context->udp->length) - sizeof(struct udp_hdr); ++ ++ switch (dhcpv6->dhcpv6_type) { ++ case DHCPV6_ADVERTISE: ++ dhcpv6_handle_advertise(context, dhcpv6_len); ++ break; ++ ++ case DHCPV6_REPLY: ++ dhcpv6_handle_reply(context, dhcpv6_len); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static void dhcpv6_handle_advertise(struct dhcpv6_context *context, ++ u16_t dhcpv6_len) ++{ ++ union dhcpv6_hdr *dhcpv6 = ++ (union dhcpv6_hdr *)((u8_t *)context->udp + ++ sizeof(struct udp_hdr)); ++ struct dhcpv6_opt_hdr *opt; ++ u16_t type; ++ int i; ++ int opt_len; ++ u8_t *vendor_id = NULL; ++ u16_t vendor_id_len = 0; ++ u8_t *vendor_opt_data = NULL; ++ int vendor_opt_len = 0; ++ int addr_cnt = 0; ++ ++ /* We only handle DHCPv6 advertise if we recently sent DHCPv6 solicit */ ++ if (context->dhcpv6_state != DHCPV6_STATE_SOLICIT_SENT) ++ return; ++ ++ LOG_DEBUG("DHCPV6: handle advertise"); ++ context->dhcpv6_state = DHCPV6_STATE_ADV_RCVD; ++ ++ i = 0; ++ while (i < (dhcpv6_len - sizeof(union dhcpv6_hdr))) { ++ opt = (struct dhcpv6_opt_hdr *)((u8_t *)dhcpv6 + ++ sizeof(union dhcpv6_hdr) + i); ++ opt_len = NET_TO_HOST16(opt->length); ++ ++ type = NET_TO_HOST16(opt->type); ++ ++ /* We only care about some of the options */ ++ switch (type) { ++ case DHCPV6_OPT_IA_NA: ++ if (context-> ++ dhcpv6_task & DHCPV6_TASK_GET_IP_ADDRESS) { ++ addr_cnt += ++ dhcpv6_process_opt_ia_na(context, opt); ++ } ++ break; ++ ++ case DHCPV6_OPT_VENDOR_CLASS: ++ vendor_id_len = ++ NET_TO_HOST16(((struct dhcpv6_option *)opt)->type. ++ vendor_class.vendor_class_length); ++ vendor_id = ++ &((struct dhcpv6_option *)opt)->type.vendor_class. ++ vendor_class_data[0]; ++ break; ++ ++ case DHCPV6_OPT_VENDOR_OPTS: ++ vendor_opt_len = opt_len - 4; ++ vendor_opt_data = ++ &((struct dhcpv6_option *)opt)->type.vendor_opts. ++ vendor_opt_data[0]; ++ break; ++ ++ case DHCPV6_OPT_DNS_SERVERS: ++ if (context->dhcpv6_task & DHCPV6_TASK_GET_OTHER_PARAMS) ++ dhcpv6_process_opt_dns_servers(context, opt); ++ break; ++ ++ default: ++ break; ++ } ++ ++ i += NET_TO_HOST16(opt->length) + sizeof(struct dhcpv6_opt_hdr); ++ } ++ ++ if (context->dhcpv6_task & DHCPV6_TASK_GET_OTHER_PARAMS) { ++ if ((vendor_id_len > 0) && ++ (strncmp((char *)vendor_id, ++ (char *)context->dhcp_vendor_id, ++ vendor_id_len) == 0)) { ++ dhcpv6_parse_vendor_option(context, ++ vendor_opt_data, ++ vendor_opt_len); ++ context->dhcpv6_done = TRUE; ++ } ++ } ++ ++ if (context->dhcpv6_task & DHCPV6_TASK_GET_IP_ADDRESS) { ++ if (addr_cnt > 0) { ++ /* ++ * If we need to acquire IP address from the server, ++ * we need to send Request to server to confirm. ++ */ ++ dhcpv6_send_request_packet(context); ++ context->dhcpv6_done = TRUE; ++ } ++ } ++ ++ if (context->dhcpv6_done) { ++ /* Keep track of IPv6 address of DHCHv6 server */ ++ memcpy((char *)&context->dhcp_server, ++ (char *)&context->ipv6->ipv6_src, ++ sizeof(struct ipv6_addr)); ++ } ++} ++ ++static int dhcpv6_process_opt_ia_na(struct dhcpv6_context *context, ++ struct dhcpv6_opt_hdr *opt_hdr) ++{ ++ int i; ++ int opt_len; ++ struct dhcpv6_option *opt; ++ int len; ++ int addr_cnt; ++ opt_len = NET_TO_HOST16(opt_hdr->length) - ++ sizeof(struct dhcpv6_opt_id_assoc_na); ++ ++ i = 0; ++ addr_cnt = 0; ++ while (i < opt_len) { ++ opt = ++ (struct dhcpv6_option *)((u8_t *)opt_hdr + ++ sizeof(struct dhcpv6_opt_hdr) + ++ sizeof(struct dhcpv6_opt_id_assoc_na) + i); ++ ++ len = NET_TO_HOST16(opt->hdr.length); ++ switch (NET_TO_HOST16(opt->hdr.type)) { ++ case DHCPV6_OPT_IAADDR: ++ if (len > ++ (sizeof(struct dhcpv6_opt_hdr) + ++ sizeof(struct dhcpv6_opt_iaa_addr))) { ++ struct dhcpv6_option *in_opt; ++ ++ in_opt = (struct dhcpv6_option *)((u8_t *)opt + ++ sizeof(struct dhcpv6_opt_hdr) + ++ sizeof(struct dhcpv6_opt_iaa_addr)); ++ if (in_opt->hdr.type == ++ HOST_TO_NET16(DHCPV6_OPT_STATUS_CODE)) { ++ /* This entry has error! */ ++ if (in_opt->type.sts.status != 0) ++ break; ++ } ++ } ++ LOG_INFO("DHCPv6: Got IP Addr"); ++ /* Status is OK, let's add this addr to our address ++ list */ ++ ipv6_add_prefix_entry(context->ipv6_context, ++ &opt->type.iaa_addr.addr, 64); ++ ++ /* Add multicast address for this address */ ++ ipv6_add_solit_node_address(context-> ++ ipv6_context, ++ &opt->type.iaa_addr.addr); ++ addr_cnt++; ++ break; ++ ++ default: ++ break; ++ } ++ ++ i += len + sizeof(struct dhcpv6_opt_hdr); ++ } ++ ++ return addr_cnt; ++} ++ ++static void dhcpv6_process_opt_dns_servers(struct dhcpv6_context *context, ++ struct dhcpv6_opt_hdr *opt_hdr) ++{ ++ int opt_len; ++ ++ opt_len = NET_TO_HOST16(opt_hdr->length); ++ ++ if (opt_len >= sizeof(struct ipv6_addr)) ++ memcpy((char *)&context->primary_dns_server, ++ (char *)&((struct dhcpv6_option *)opt_hdr)->type.dns. ++ primary_addr, sizeof(struct ipv6_addr)); ++ ++ if (opt_len >= 2 * sizeof(struct ipv6_addr)) ++ memcpy((char *)&context->secondary_dns_server, ++ (char *)&((struct dhcpv6_option *)opt_hdr)->type.dns. ++ secondary_addr, sizeof(struct ipv6_addr)); ++} ++ ++static void dhcpv6_handle_reply(struct dhcpv6_context *context, ++ u16_t dhcpv6_len) ++{ ++ if (context->dhcpv6_state != DHCPV6_STATE_REQ_SENT) ++ return; ++ ++ context->dhcpv6_done = TRUE; ++} ++ ++static void dhcpv6_parse_vendor_option(struct dhcpv6_context *context, ++ u8_t *option, int len) ++{ ++ struct dhcpv6_option *opt; ++ u16_t type; ++ int opt_len; ++ int data_len; ++ int i; ++ u8_t *data; ++ ++ for (i = 0; i < len; i += opt_len + sizeof(struct dhcpv6_opt_hdr)) { ++ opt = (struct dhcpv6_option *)((u8_t *)option + i); ++ type = HOST_TO_NET16(opt->hdr.type); ++ opt_len = HOST_TO_NET16(opt->hdr.length); ++ data = &opt->type.data[0]; ++ data_len = strlen((char *)data); ++ ++ switch (type) { ++ case 201: ++ /* iSCSI target 1 */ ++ break; ++ ++ case 202: ++ /* iSCSI target 2 */ ++ break; ++ ++ case 203: ++ if (data_len > ISCSI_MAX_ISCSI_NAME_LENGTH) ++ data_len = ISCSI_MAX_ISCSI_NAME_LENGTH; ++ data[data_len] = '\0'; ++ strcpy(context->initiatorName, (char *)data); ++ break; ++ ++ default: ++ break; ++ } ++ } ++} +diff --git a/iscsiuio/src/apps/dhcpc/dhcpv6.h b/iscsiuio/src/apps/dhcpc/dhcpv6.h +new file mode 100644 +index 0000000..d4ec4b9 +--- /dev/null ++++ b/iscsiuio/src/apps/dhcpc/dhcpv6.h +@@ -0,0 +1,253 @@ ++/* ++ * Copyright (c) 2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Eddie Wai ++ * Based on code from Kevin Tran's iSCSI boot code ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * dhcpv6.h - DHCPv6 engine header ++ * ++ */ ++#ifndef __IDHCPV6_H__ ++#define __IDHCPV6_H__ ++ ++#include "ipv6_ndpc.h" ++#include "ipv6.h" ++ ++#define ISCSI_MAX_ISCSI_NAME_LENGTH 128 ++/* DHCPv6 Message types. */ ++#define DHCPV6_SOLICIT 1 ++#define DHCPV6_ADVERTISE 2 ++#define DHCPV6_REQUEST 3 ++#define DHCPV6_CONFIRM 4 ++#define DHCPV6_RENEW 5 ++#define DHCPV6_REBIND 6 ++#define DHCPV6_REPLY 7 ++#define DHCPV6_RELEASE 8 ++#define DHCPV6_DECLINE 9 ++#define DHCPV6_RECONFIGURE 10 ++#define DHCPV6_INFO_REQUEST 11 ++#define DHCPV6_RELAY_FORW 12 ++#define DHCPV6_RELAY_REPL 13 ++ ++/* Option codes. */ ++#define DHCPV6_OPT_CLIENTID 1 /* Client ID option - built by stack */ ++#define DHCPV6_OPT_SERVERID 2 /* Server ID option - built by stack */ ++#define DHCPV6_OPT_IA_NA 3 /* IA_NA option - built by user */ ++#define DHCPV6_OPT_IA_TA 4 /* IA_TA option - not supported */ ++#define DHCPV6_OPT_IAADDR 5 /* IA_ADDR option - built by user */ ++#define DHCPV6_OPT_ORO 6 /* Option Request Option - built by ++ stack */ ++#define DHCPV6_OPT_PREFERENCE 7 /* Preference option - built by server ++ */ ++#define DHCPV6_OPT_ELAPSED_TIME 8 /* Elapsed Time option - built by stack ++ */ ++#define DHCPV6_OPT_RELAY_MSG 9 /* Relay Message option - not supported ++ */ ++#define DHCPV6_OPT_AUTH 11 /* Authentication option - built by ++ stack */ ++#define DHCPV6_OPT_UNICAST 12 /* Server Unicast option - built by ++ server */ ++#define DHCPV6_OPT_STATUS_CODE 13 /* Status Code option - built by stack ++ */ ++#define DHCPV6_OPT_RAPID_COMMIT 14 /* Rapid Commit option - built by user ++ */ ++#define DHCPV6_OPT_USER_CLASS 15 /* User Class option - built by user */ ++#define DHCPV6_OPT_VENDOR_CLASS 16 /* Vendor Class option - built by user ++ */ ++#define DHCPV6_OPT_VENDOR_OPTS 17 /* Vendor-Specific Information option - ++ build by user */ ++#define DHCPV6_OPT_INTERFACE_ID 18 /* Interface ID option - not supported ++ */ ++#define DHCPV6_OPT_RECONF_MSG 19 /* Reconfigure Message option - built ++ by server */ ++#define DHCPV6_OPT_RECONF_ACCEPT 20 /* Reconfigure Accept option - built by ++ user */ ++#define DHCPV6_OPT_SIP_SERVER_D 21 /* NOT SUPPORTED - included for ++ completeness only */ ++#define DHCPV6_OPT_SIP_SERVER_A 22 /* NOT SUPPORTED - included for ++ completeness only */ ++#define DHCPV6_OPT_DNS_SERVERS 23 /* DNS Recursive Name Server option - ++ built by server */ ++#define DHCPV6_OPT_DOMAIN_LIST 24 /* Domain Search List option - not ++ supported */ ++#define DHCPV6_MAX_OPT_CODES 25 /* This will be the count + 1 since ++ the parsing array starts ++ at [1] instead of [0] */ ++ ++/* Authentication protocol types. */ ++#define DHCPV6_DELAYED_AUTH_PROT 2 /* Delayed Authentication protocol. */ ++#define DHCPV6_RECON_KEY_AUTH_PROT 3 /* Reconfigure Key Authentication ++ protocol. */ ++ ++struct dhcpv6_context { ++#define DHCP_VENDOR_ID_LEN 128 ++ char dhcp_vendor_id[DHCP_VENDOR_ID_LEN]; ++ struct mac_address *our_mac_addr; ++ u32_t dhcpv6_transaction_id; ++ u16_t seconds; ++ int timeout; ++ int dhcpv6_done; ++ ++#define DHCPV6_STATE_UNKNOWN 0 ++#define DHCPV6_STATE_SOLICIT_SENT 1 ++#define DHCPV6_STATE_ADV_RCVD 2 ++#define DHCPV6_STATE_REQ_SENT 3 ++#define DHCPV6_STATE_CONFIRM_SENT 4 ++ int dhcpv6_state; ++ u16_t dhcpv6_task; ++ struct ipv6_context *ipv6_context; ++ struct eth_hdr *eth; ++ struct ipv6_hdr *ipv6; ++ struct udp_hdr *udp; ++ ++ char initiatorName[ISCSI_MAX_ISCSI_NAME_LENGTH]; ++ struct ipv6_addr dhcp_server; ++ struct ipv6_addr primary_dns_server; ++ struct ipv6_addr secondary_dns_server; ++ ++}; ++ ++union dhcpv6_hdr { ++ struct { ++ u32_t type:8; ++ u32_t trans_id:24; ++ } field; ++ ++ u32_t type_transaction; ++}; ++ ++#define dhcpv6_type field.type ++#define dhcpv6_trans_id field.trans_id ++ ++struct dhcpv6_opt_hdr { ++ u16_t type; ++ u16_t length; ++}; ++ ++struct dhcpv6_opt_client_id { ++ u16_t duid_type; ++#define DHCPV6_DUID_TYPE_LINK_LAYER_AND_TIME 1 ++#define DHCPV6_DUID_TYPE_VENDOR_BASED 2 ++#define DHCPV6_DUID_TYPE_LINK_LAYER 3 ++ u16_t hw_type; ++#define DHCPV6_HW_TYPE_ETHERNET 1 ++ u32_t time; ++ struct mac_address link_layer_addr; ++}; ++ ++struct dhcpv6_opt_id_assoc_na { ++ u32_t iaid; ++#define DHCPV6_OPT_IA_NA_IAID 0x306373L ++ u32_t t1; ++ u32_t t2; ++}; ++ ++struct dhcpv6_opt_elapse_time { ++ u16_t time; ++}; ++ ++struct dhcpv6_opt_iaa_addr { ++ struct ipv6_addr addr; ++ u32_t preferred_lifetime; ++ u32_t valid_lifetime; ++}; ++ ++struct dhcpv6_opt_status { ++ u16_t status; ++}; ++ ++struct dhcpv6_opt_request_list { ++ u16_t request_code[1]; ++}; ++ ++struct dhcpv6_opt_dns { ++ struct ipv6_addr primary_addr; ++ struct ipv6_addr secondary_addr; ++}; ++ ++struct dhcpv6_vendor_class { ++ u32_t enterprise_number; ++ u16_t vendor_class_length; ++ u8_t vendor_class_data[1]; ++}; ++ ++struct dhcpv6_vendor_opts { ++ u32_t enterprise_number; ++ u8_t vendor_opt_data[1]; ++}; ++ ++struct dhcpv6_option { ++ struct dhcpv6_opt_hdr hdr; ++ union { ++ struct dhcpv6_vendor_opts vendor_opts; ++ struct dhcpv6_vendor_class vendor_class; ++ struct dhcpv6_opt_client_id client_id; ++ struct dhcpv6_opt_id_assoc_na ida_na; ++ struct dhcpv6_opt_elapse_time elapsed_time; ++ struct dhcpv6_opt_iaa_addr iaa_addr; ++ struct dhcpv6_opt_status sts; ++ struct dhcpv6_opt_request_list list; ++ struct dhcpv6_opt_dns dns; ++ u8_t data[1]; ++ } type; ++}; ++ ++#define DHCPV6_NUM_OF_RETRY 4 ++ ++#define DHCPV6_ACK_TIMEOUT 2 ++ ++#define IANA_ENTERPRISE_NUM_BROADCOM 0x113d ++ ++/* QLogic Extended DHCP options used in iSCSI boot */ ++#define DHCPV6_TAG_FIRST_ISCSI_TARGET_NAME 201 ++#define DHCPV6_TAG_SECOND_ISCSI_TARGET_NAME 202 ++#define DHCPV6_TAG_ISCSI_INITIATOR_NAME 203 ++ ++#define MAX_DHCP_RX_OFFERS 4 ++#define MAX_DHCP_OPTION43_LENGTH 1024 ++ ++#define DHCPV6_TASK_GET_IP_ADDRESS 0x1 ++#define DHCPV6_TASK_GET_OTHER_PARAMS 0x2 ++ ++enum { ++ ISCSI_FAILURE, ++ ISCSI_USER_ABORT, ++ ISCSI_SUCCESS ++}; ++ ++/* Function prototypes */ ++int dhcpv6_do_discovery(struct dhcpv6_context *context); ++void ipv6_udp_handle_dhcp(struct dhcpv6_context *context); ++void dhcpv6_init(struct dhcpv6_context *context); ++ ++#endif /* __IDHCPV6_H__ */ +diff --git a/iscsiuio/src/uip-1.0-changelog.txt b/iscsiuio/src/uip-1.0-changelog.txt +new file mode 100644 +index 0000000..800e444 +--- /dev/null ++++ b/iscsiuio/src/uip-1.0-changelog.txt +@@ -0,0 +1,98 @@ ++* A new API: protosockets that are similar to BSD sockets but does not ++ require any underlying multithreading system. ++ ++* Very rudimentary IPv6 support ++ ++* New application: DHCP client. Web server rewritten with protosockets. ++ ++* Removed uIP zero-copy functionality in order to simplify uIP device ++ driver coding: outbound packets are now *always* stored in full in ++ the uip_buf buffer. ++ ++* Checksum computation is now part of uip.c, but it still is possible ++ to implement them in assembly code by specifying a configuration ++ option. Checksum code now runs on architectures with 2-byte alignment. ++ ++* Added TCP persistent timer. ++ ++* Made all IP address representations use the new uip_ipaddr_ip ++ datatype for clarity. ++ ++* Updated window behavior so that sending to a host with a small open ++ window works better now. ++ ++* UDP API change: uip_udp_new() now takes port numbers in network byte ++ order like TCP functions. ++ ++* Allow reception of packets when no IP address is configured to make ++ DHCP work. ++ ++* Moved Ethernet address into main uIP module from ARP module. ++ ++* Made constants explicit #defines and moved them out of the code ++ (header sizes, TCP options, TCP header length field). ++ ++* If uip_len is less than that reported by the IP header, the packet ++ is discarded. If uip_len is greater than the length reported by the ++ IP header, uip_len is adjusted. ++ ++* Moved header size definitions into header file. ++ ++* Added uIP call for polling an application without triggering any ++ timer events. Removed redundant assignments of uip_len and uip_slen. ++ ++* Removed compiler warning about icmp_input label being defined when ++ UIP_PINGADDRCONF was not used. ++ ++* Added UIP_APPDATA_SIZE macro that holds the available buffer size ++ for user data. ++ ++* Added uip_udp_bind() call. ++ ++* Moved checksum code into main uIP module. ++ ++* Switched the TCP, UDP and IP header structures to be structs rather ++ than typedefs. ++ ++* Prefixed TCP state names with UIP_ to avoid name space ++ contamination. ++ ++* Changed declarations of uip_appdatap and friends to void * to avoid ++ explicit typecasts. ++ ++* Bugfixes ++ ++ o TCP: Fixed bug with high byte of peer window size. ++ ++ o TCP: Fixed bug that in some cases prevented concurrent reception and ++ transmission of TCP data. ++ ++ o TCP: uip_connect() didn't correctly calculate age of TIME_WAIT ++ connections. ++ ++ o TCP: Array index for uip_conns[] array was out of bounds in ++ comparison. Comparison changed to make index within bounds. ++ ++ o TCP: if the remote host crashes and tries to reestablish an old ++ connection, uIP should respond with an ACK with the correct ++ sequence and acknowledgment numbers, to which the remote host ++ should respond with an ACK. uIP did not respond with the correct ++ ACK. ++ ++ o TCP: Fixed check for SYNACK segment: now checks only relevant TCP ++ control flags and discards flags reserved for future expansion. ++ ++ o TCP: Fixed bug where uIP did not inform application that a connection ++ had been aborted during an active open. ++ ++ o TCP: FIN segment was accepted even though application had stopped ++ incoming data with uip_stop(). ++ ++ o TCP: A FINACK segment would not always correctly acknowledge data. ++ ++ o UDP: checksums are now calculated after all fields have been ++ filled in. ++ ++ o UDP: network byte order on lastport in uip_udp_new(). ++ ++ o IP: memset() bugs in IP fragment reassembly code fixed. +diff --git a/iscsiuio/src/uip/Makefile.am b/iscsiuio/src/uip/Makefile.am +new file mode 100644 +index 0000000..16170d7 +--- /dev/null ++++ b/iscsiuio/src/uip/Makefile.am +@@ -0,0 +1,18 @@ ++AM_CFLAGS = -I${top_srcdir}/src/unix \ ++ -I${top_srcdir}/src/apps/dhcpc \ ++ -I${top_srcdir}/src/apps/brcm-iscsi \ ++ -I${top_srcdir}/../include \ ++ -I${top_srcdir}/../usr ++ ++noinst_LIBRARIES = lib_iscsi_uip.a ++ ++lib_iscsi_uip_a_SOURCES = uip.c \ ++ uip_arp.c \ ++ psock.c \ ++ timer.c \ ++ uip-neighbor.c \ ++ uip_eth.c \ ++ ipv6_ndpc.c \ ++ ipv6.c ++ ++lib_iscsi_uip_a_CFLAGS = -DBYTE_ORDER=@ENDIAN@ $(AM_CFLAGS) +diff --git a/iscsiuio/src/uip/Makefile.include b/iscsiuio/src/uip/Makefile.include +new file mode 100644 +index 0000000..aa3ac63 +--- /dev/null ++++ b/iscsiuio/src/uip/Makefile.include +@@ -0,0 +1,47 @@ ++ ++ ++ifdef APPS ++ APPDIRS = $(foreach APP, $(APPS), ../apps/$(APP)) ++ -include $(foreach APP, $(APPS), ../apps/$(APP)/Makefile.$(APP)) ++ CFLAGS += $(addprefix -I../apps/,$(APPS)) ++endif ++ ++ifndef CCDEP ++ CCDEP = $(CC) ++endif ++ifndef CCDEPCFLAGS ++ CCDEPCFLAGS = $(CFLAGS) ++endif ++ifndef OBJECTDIR ++ OBJECTDIR = obj ++endif ++ ++ifeq (${wildcard $(OBJECTDIR)},) ++ DUMMY := ${shell mkdir $(OBJECTDIR)} ++endif ++ ++ ++vpath %.c . ../uip ../lib $(APPDIRS) ++ ++$(OBJECTDIR)/%.o: %.c ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++$(OBJECTDIR)/%.d: %.c ++ @set -e; rm -f $@; \ ++ $(CCDEP) -MM $(CCDEPCFLAGS) $< > $@.$$$$; \ ++ sed 's,\($*\)\.o[ :]*,$(OBJECTDIR)/\1.o $@ : ,g' < $@.$$$$ > $@; \ ++ rm -f $@.$$$$ ++ ++UIP_SOURCES=uip.c uip_arp.c uiplib.c psock.c timer.c uip-neighbor.c uip_eth.c ipv6_ndp.c ipv6.c ++ ++ ++ifneq ($(MAKECMDGOALS),clean) ++-include $(addprefix $(OBJECTDIR)/,$(UIP_SOURCES:.c=.d) \ ++ $(APP_SOURCES:.c=.d)) ++endif ++ ++libuip.a: ${addprefix $(OBJECTDIR)/, $(UIP_SOURCES:.c=.o)} ++ $(AR) rc $@ $^ ++ ++libapps.a: ${addprefix $(OBJECTDIR)/, $(APP_SOURCES:.c=.o)} ++ $(AR) rc $@ $^ +diff --git a/iscsiuio/src/uip/clock.h b/iscsiuio/src/uip/clock.h +new file mode 100644 +index 0000000..d79326b +--- /dev/null ++++ b/iscsiuio/src/uip/clock.h +@@ -0,0 +1,87 @@ ++/** ++ * \defgroup clock Clock interface ++ * ++ * The clock interface is the interface between the \ref timer "timer library" ++ * and the platform specific clock functionality. The clock ++ * interface must be implemented for each platform that uses the \ref ++ * timer "timer library". ++ * ++ * The clock interface does only one this: it measures time. The clock ++ * interface provides a macro, CLOCK_SECOND, which corresponds to one ++ * second of system time. ++ * ++ * \sa \ref timer "Timer library" ++ * ++ * @{ ++ */ ++ ++/* ++ * Copyright (c) 2004, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ * Author: Adam Dunkels ++ * ++ */ ++#ifndef __CLOCK_H__ ++#define __CLOCK_H__ ++ ++#include "clock-arch.h" ++ ++/** ++ * Initialize the clock library. ++ * ++ * This function initializes the clock library and should be called ++ * from the main() function of the system. ++ * ++ */ ++void clock_init(void); ++ ++/** ++ * Get the current clock time. ++ * ++ * This function returns the current system clock time. ++ * ++ * \return The current clock time, measured in system ticks. ++ */ ++clock_time_t clock_time(void); ++ ++/** ++ * A second, measured in system clock time. ++ * ++ * \hideinitializer ++ */ ++#ifdef CLOCK_CONF_SECOND ++#define CLOCK_SECOND CLOCK_CONF_SECOND ++#else ++#define CLOCK_SECOND (clock_time_t)32 ++#endif ++ ++#endif /* __CLOCK_H__ */ ++ ++/** @} */ +diff --git a/iscsiuio/src/uip/debug.h b/iscsiuio/src/uip/debug.h +new file mode 100644 +index 0000000..a58fa7a +--- /dev/null ++++ b/iscsiuio/src/uip/debug.h +@@ -0,0 +1,13 @@ ++#ifndef __DEBUG_H__ ++#define __DEBUG_H__ ++ ++#ifdef DEBUG ++#define UIP_DEBUG(args...) \ ++ do { \ ++ fprintf(stdout, args); \ ++ fflush(stdout); \ ++ } while (0); ++#else ++#endif ++ ++#endif +diff --git a/iscsiuio/src/uip/icmpv6.h b/iscsiuio/src/uip/icmpv6.h +new file mode 100644 +index 0000000..cbf9aa8 +--- /dev/null ++++ b/iscsiuio/src/uip/icmpv6.h +@@ -0,0 +1,302 @@ ++/* ++ * Copyright (c) 2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Eddie Wai (eddie.wai@broadcom.com) ++ * Based on Kevin Tran's iSCSI boot code ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * icmpv6.h - This file contains macro definitions pertaining to ICMPv6 ++ * ++ * RFC 2463 : ICMPv6 Specification ++ * RFC 2461 : Neighbor Discovery for IPv6 ++ * ++ */ ++#ifndef __ICMPV6_H__ ++#define __ICMPV6_H__ ++ ++/* Base ICMP Header sizes */ ++#define IPV6_RTR_SOL_HDR_SIZE 8 ++#define IPV6_RTR_ADV_HDR_SIZE 16 ++#define IPV6_NEIGH_SOL_HDR_SIZE 24 ++#define IPV6_NEIGH_ADV_HDR_SIZE 24 ++#define IPV6_LINK_LAYER_OPT_SIZE 2 ++#define IPV6_LINK_LAYER_OPT_LENGTH 8 ++#define IPV6_MTU_OPT_SIZE 8 ++#define IPV6_PREFIX_OPT_SIZE 32 ++#define IPV6_ECHO_REQUEST_HDR_SIZE 8 ++#define IPV6_ECHO_REPLY_HDR_SIZE 8 ++#define IPV6_REDIRECT_SIZE 40 ++#define IPV6_DHAAD_REQ_HDR_SIZE 8 ++#define IPV6_DHAAD_REPLY_HDR_SIZE 8 ++#define IPV6_PRFXSOL_HDR_SIZE 8 ++#define IPV6_PRFXADV_HDR_SIZE 8 ++#define IPV6_RTR_ADV_INT_OPT_SIZE 8 ++ ++/* ICMP Message Types */ ++/* Error messages are always less than 128 */ ++#define ICMPV6_DST_UNREACH 1 /* Destination Unreachable */ ++#define ICMPV6_PACKET_TOO_BIG 2 /* Packet Too Big */ ++#define ICMPV6_TIME_EXCEEDED 3 /* Time Exceeded */ ++#define ICMPV6_PARAM_PROB 4 /* Parameter Problem */ ++ ++#define ICMPV6_RTR_SOL 133 /* Router Solicitation */ ++#define ICMPV6_RTR_ADV 134 /* Router Advertisement */ ++#define ICMPV6_NEIGH_SOL 135 /* Neighbor Solicitation */ ++#define ICMPV6_NEIGH_ADV 136 /* Neighbor Advertisement */ ++#define ICMPV6_REDIRECT 137 /* Redirect */ ++#define ICMPV6_ECHO_REQUEST 128 /* Echo Request */ ++#define ICMPV6_ECHO_REPLY 129 /* Echo Reply */ ++#define ICMPV6_WRUREQUEST 139 /* Who Are You Request */ ++#define ICMPV6_WRUREPLY 140 /* Who Are You Reply */ ++#define ICMPV6_ROUTER_RENUMBERING 138 /* Router Renumbering */ ++#define ICMPV6_HA_ADDR_DISC_REQ 144 /* Dynamic Home Agent Address ++ Discovery Request */ ++#define ICMPV6_HA_ADDR_DISC_REPLY 145 /* Dynamic Home Agent Address ++ Discovery Reply */ ++#define ICMPV6_MP_SOLICIT 146 /* Mobile Prefix Solicitation */ ++#define ICMPV6_MP_ADV 147 /* Mobile Prefix Reply */ ++ ++/* Destination Unreachable Codes */ ++#define ICMPV6_DST_UNREACH_NOROUTE 0 ++#define ICMPV6_DST_UNREACH_ADMIN 1 ++#define ICMPV6_DST_UNREACH_ADDRESS 3 ++#define ICMPV6_DST_UNREACH_PORT 4 ++ ++/* Time Exceeded Codes */ ++#define ICMPV6_TIME_EXCD_HPLMT 0 /* Hop Limit exceeded in transit */ ++#define ICMPV6_TIME_EXCD_REASM 1 /* Fragment reassembly time exceeded */ ++ ++/* Parameter Problem Codes */ ++#define ICMPV6_PARM_PROB_HEADER 0 ++#define ICMPV6_PARM_PROB_NEXT_HDR 1 ++#define ICMPV6_PARM_PROB_OPTION 2 ++ ++/* ICMP Option Types */ ++#define IPV6_ICMP_OPTION_SRC_ADDR 1 /* Source Link-Layer Address */ ++#define IPV6_ICMP_OPTION_TAR_ADDR 2 /* Target Link-Layer Address */ ++#define IPV6_ICMP_OPTION_PREFIX 3 /* Prefix */ ++#define IPV6_ICMP_OPTION_RED_HDR 4 /* Redirect Header */ ++#define IPV6_ICMP_OPTION_MTU 5 /* Link MTU */ ++#define IPV6_ICMP_OPTION_RTR_ADV_INT 7 /* Rtr Advertisement Interval */ ++ ++/* ICMP Offsets */ ++#define IPV6_ICMP_TYPE_OFFSET 0 ++#define IPV6_ICMP_CODE_OFFSET 1 ++#define IPV6_ICMP_CKSUM_OFFSET 2 ++#define IPV6_ICMP_RESERVED_OFFSET 4 ++#define IPV6_ICMP_DATA_OFFSET 8 ++ ++/* ICMP Router Solicitation Offsets */ ++#define IPV6_ICMP_RTR_SOL_RES_OFFSET 4 ++#define IPV6_ICMP_RTR_SOL_OPTIONS_OFFSET 8 ++ ++/* ICMP Router Advertisement Offsets */ ++#define IPV6_ICMP_RTR_ADV_CURHOPLMT_OFFSET 4 ++#define IPV6_ICMP_RTR_ADV_MGDANDCFG_BIT_OFFSET 5 ++#define IPV6_ICMP_RTR_ADV_RTR_LIFETIME_OFFSET 6 ++#define IPV6_ICMP_RTR_ADV_RCHBL_TIME_OFFSET 8 ++#define IPV6_ICMP_RTR_ADV_RTRNS_TMR_OFFSET 12 ++#define IPV6_ICMP_RTR_ADV_OPTIONS_OFFSET 16 ++ ++/* ICMP Neighbor Solicitation Offsets */ ++#define IPV6_ICMP_NEIGH_SOL_RES_OFFSET 4 ++#define IPV6_ICMP_NEIGH_SOL_TRGT_ADDRS_OFFSET 8 ++#define IPV6_ICMP_NEIGH_SOL_OPTIONS_OFFSET 24 ++ ++/* ICMP Neighbor Advertisement Offsets */ ++#define IPV6_ICMP_NEIGH_ADV_FLAG_OFFSET 4 ++#define IPV6_ICMP_NEIGH_ADV_TRGT_ADDRS_OFFSET 8 ++#define IPV6_ICMP_NEIGH_ADV_OPTIONS_OFFSET 24 ++ ++/* ICMP Redirect Offsets */ ++#define IPV6_ICMP_REDIRECT_TRGT_ADDRS_OFFSET 8 ++#define IPV6_ICMP_REDIRECT_DEST_ADDRS_OFFSET 24 ++#define IPV6_ICMP_REDIRECT_OPTIONS_OFFSET 40 ++ ++/* ICMP Option Offsets */ ++#define IPV6_ICMP_OPTION_TYPE_OFFSET 0 ++#define IPV6_ICMP_OPTION_LENGTH_OFFSET 1 ++ ++/* ICMP Link-Layer Address Option Offsets */ ++#define IPV6_ICMP_LL_OPTION_ADDRESS_OFFSET 2 ++ ++/* ICMP Prefix Option Offsets */ ++#define IPV6_ICMP_PREFIX_PRE_LENGTH_OFFSET 2 ++#define IPV6_ICMP_PREFIX_FLAG_OFFSET 3 ++#define IPV6_ICMP_PREFIX_VALID_LIFETIME_OFFSET 4 ++#define IPV6_ICMP_PREFIX_PREF_LIFETIME_OFFSET 8 ++#define IPV6_ICMP_PREFIX_RES2_OFFSET 12 ++#define IPV6_ICMP_PREFIX_PREFIX_OFFSET 16 ++ ++/* ICMP Redirected Header Option Offsets */ ++#define IPV6_ICMP_RED_OPTION_TYPE_OFFSET 0 ++#define IPV6_ICMP_RED_OPTION_LEN_OFFSET 1 ++#define IPV6_ICMP_RED_OPTION_RES1_OFFSET 2 ++#define IPV6_ICMP_RED_OPTION_RES2_OFFSET 4 ++#define IPV6_ICMP_RED_OPTION_DATA_OFFSET 8 ++ ++/* ICMP MTU Option Offsets */ ++#define IPV6_ICMP_MTU_RESERVED_OFFSET 2 ++#define IPV6_ICMP_MTU_OFFSET 4 ++ ++/* ICMP Echo Request Offsets */ ++#define IPV6_ICMP_ECHO_ID 4 ++#define IPV6_ICMP_ECHO_SEQ 6 ++#define IPV6_ICMP_ECHO_DATA 8 ++ ++/* ICMP Destination Unreachable Offsets */ ++#define IPV6_DST_UNREACH_UNUSED 4 ++#define IPV6_DST_UNREACH_DATA 8 ++ ++/* ICMP Parameter Problem Offsets */ ++#define IPV6_PARAM_PROB_PTR 4 ++#define IPV6_PARAM_PROT_DATA 8 ++ ++/* ICMP Time Exceeded Offsets */ ++#define IPV6_TIME_EXCEEDED_DATA 8 ++ ++/* ICMP Packet Too Big Offsets */ ++#define IPV6_PKT_TOO_BIG_MTU 4 ++#define IPV6_PKT_TOO_BIG_DATA 8 ++ ++/* Home Agent Address Discovery Request Header Offsets */ ++#define ICMPV6_HA_ADDR_DISC_REQ_ID_OFFSET 4 ++#define ICMPV6_HA_ADDR_DISC_REQ_RSVD_OFFSET 6 ++ ++/* Home Agent Address Discovery Reply Header Offsets */ ++#define ICMPV6_HA_ADDR_DISC_REPLY_ID_OFFSET 4 ++#define ICMPV6_HA_ADDR_DISC_REPLY_RSVD_OFFSET 6 ++#define ICMPV6_HA_ADDR_DISC_REPLY_HA_ADDR_OFFSET 8 ++ ++/* Mobile Prefix Solicitation Header Offsets */ ++#define ICMPV6_MP_SOLICIT_ID_OFFSET 4 ++#define ICMPV6_MP_SOLICIT_RSVD_OFFSET 6 ++ ++/* Mobile Prefix Advertisement Header Offsets */ ++#define ICMPV6_MP_ADV_ID_OFFSET 4 ++#define ICMPV6_MP_ADV_MGDANDCFG_BIT_OFFSET 6 ++#define ICMPV6_MP_ADV_OPT_OFFSET 8 ++ ++/* Advertisement Interval Option Header Offsets */ ++#define ICMPV6_ADV_INT_TYPE_OFFSET 0 ++#define ICMPV6_ADV_INT_LEN_OFFSET 1 ++#define ICMPV6_ADV_INT_RSVD_OFFSET 2 ++#define ICMPV6_ADV_INT_ADV_INT_OFFSET 4 ++ ++#define ICMPV6_HEADER_LEN 4 ++ ++#define IPV6_PREFIX_FLAG_ONLINK 0x80 ++#define IPV6_PREFIX_FLAG_AUTO 0x40 ++#define IPV6_PREFIX_FLAG_ROUTER 0x20 ++ ++#define IPV6_NA_FLAG_ROUTER 0x80 ++#define IPV6_NA_FLAG_SOLICITED 0x40 ++#define IPV6_NA_FLAG_OVERRIDE 0x20 ++ ++/* Router Advertisement Flags */ ++#define IPV6_RA_MANAGED_FLAG 0x80 ++#define IPV6_RA_CONFIG_FLAG 0x40 ++ ++/* Mobile Prefix Advertisement Flags */ ++#define IPV6_PA_MANAGED_FLAG 0x80 ++#define IPV6_PA_CONFIG_FLAG 0x40 ++ ++/* Validation Values */ ++#define ICMPV6_VALID_HOP_LIMIT 255 /* Valid Hop Limit */ ++#define ICMPV6_VALID_CODE 0 /* Valid Code */ ++#define ICMPV6_RTRSOL_MIN_LENGTH 8 /* Minimum valid length for ++ Router Solicitation */ ++#define ICMPV6_RTRADV_MIN_LENGTH 16 /* Minimum valid length for ++ Router Advertisement */ ++#define ICMPV6_NEIGHSOL_MIN_LENGTH 24 /* Minimum valid length for ++ Neighbor Solicitation */ ++#define ICMPV6_NEIGHADV_MIN_LENGTH 24 /* Minimum valid length for ++ Neighbor Advertisement */ ++#define ICMPV6_REDIRECT_MIN_LENGTH 40 /* Minimum valid length for ++ Neighbor Advertisement */ ++ ++/* ICMPV6 Header */ ++struct icmpv6_hdr { ++ u8_t icmpv6_type; /* type field */ ++ u8_t icmpv6_code; /* code field */ ++ u16_t icmpv6_cksum; /* checksum field */ ++ union { ++ u32_t icmpv6_un_data32[1]; /* type-specific field */ ++ u16_t icmpv6_un_data16[2]; /* type-specific field */ ++ u8_t icmpv6_un_data8[4]; /* type-specific field */ ++ } data; ++}; ++ ++#define icmpv6_data data.icmpv6_un_data32[0] ++ ++struct icmpv6_opt_hdr { ++ u8_t type; ++ u8_t len; ++}; ++ ++struct icmpv6_opt_link_addr { ++ struct icmpv6_opt_hdr hdr; ++ u8_t link_addr[6]; ++}; ++ ++struct icmpv6_opt_prefix { ++ struct icmpv6_opt_hdr hdr; ++ u8_t prefix_len; ++ u8_t flags; ++#define ICMPV6_OPT_PREFIX_FLAG_ON_LINK (1 << 7) ++#define ICMPV6_OPT_PREFIX_FLAG_BIT_A (1 << 6) ++ u32_t valid_lifetime; ++ u32_t preferred_lifetime; ++ u32_t reserved; ++ struct ipv6_addr prefix; ++}; ++ ++/* Neighbor Solicitation */ ++struct icmpv6_nd_solicit { ++ struct icmpv6_hdr nd_ns_hdr; ++}; ++ ++/* Router Advertisement */ ++struct icmpv6_router_advert { ++ struct icmpv6_hdr header; ++ u32_t reachable_time; ++ u32_t retransmit_timer; ++}; ++ ++#define nd_ra_type header.icmpv6_type ++#define nd_ra_code header.icmpv6_code ++#define nd_ra_cksum header.icmpv6_cksum ++#define nd_ra_curhoplimit header.data.icmpv6_un_data8[0] ++#define nd_ra_flags_reserved header.data.icmpv6_un_data8[1] ++#define nd_ra_router_lifetime header.data.icmpv6_un_data16[1] ++ ++#endif /* __ICMPV6_H__ */ +diff --git a/iscsiuio/src/uip/ipv6.c b/iscsiuio/src/uip/ipv6.c +new file mode 100644 +index 0000000..ced98a6 +--- /dev/null ++++ b/iscsiuio/src/uip/ipv6.c +@@ -0,0 +1,1306 @@ ++/* ++ * Copyright (c) 2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Eddie Wai (eddie.wai@broadcom.com) ++ * Based on Kevin Tran's iSCSI boot code ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ipv6.c - This file contains simplifed IPv6 processing code. ++ * ++ */ ++#include ++#include ++#include ++#include "logger.h" ++#include "uip.h" ++#include "ipv6.h" ++#include "ipv6_pkt.h" ++#include "icmpv6.h" ++#include "uipopt.h" ++#include "dhcpv6.h" ++#include "ping.h" ++ ++inline int best_match_bufcmp(u8_t *a, u8_t *b, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) { ++ if (a[i] != b[i]) ++ break; ++ } ++ return i; ++} ++ ++/* Local function prototypes */ ++static int ipv6_is_it_our_address(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr); ++static void ipv6_insert_protocol_chksum(struct ipv6_hdr *ipv6); ++static void ipv6_update_arp_table(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr, ++ struct mac_address *mac_addr); ++static void ipv6_icmp_init_link_option(struct ipv6_context *context, ++ struct icmpv6_opt_link_addr *link_opt, ++ u8_t type); ++static void ipv6_icmp_rx(struct ipv6_context *context); ++static void ipv6_icmp_handle_nd_adv(struct ipv6_context *context); ++static void ipv6_icmp_handle_nd_sol(struct ipv6_context *context); ++static void ipv6_icmp_handle_echo_request(struct ipv6_context *context); ++static void ipv6_icmp_handle_router_adv(struct ipv6_context *context); ++static void ipv6_icmp_process_prefix(struct ipv6_context *context, ++ struct icmpv6_opt_prefix *icmp_prefix); ++static void ipv6_udp_rx(struct ipv6_context *context); ++ ++int iscsiL2Send(struct ipv6_context *context, int pkt_len) ++{ ++ LOG_DEBUG("IPv6: iscsiL2Send"); ++ uip_send(context->ustack, ++ (void *)context->ustack->data_link_layer, pkt_len); ++ ++ return pkt_len; ++} ++ ++int iscsiL2AddMcAddr(struct ipv6_context *context, ++ struct mac_address *new_mc_addr) ++{ ++ int i; ++ struct mac_address *mc_addr; ++ const struct mac_address all_zeroes_mc = { { { 0, 0, 0, 0, 0, 0 } } }; ++ ++ mc_addr = context->mc_addr; ++ for (i = 0; i < MAX_MCADDR_TABLE; i++, mc_addr++) ++ if (!memcmp((char *)mc_addr, ++ (char *)new_mc_addr, sizeof(struct mac_address))) ++ return TRUE; /* Already in the mc table */ ++ ++ mc_addr = context->mc_addr; ++ for (i = 0; i < MAX_MCADDR_TABLE; i++, mc_addr++) { ++ if (!memcmp((char *)mc_addr, ++ (char *)&all_zeroes_mc, sizeof(struct mac_address))) { ++ memcpy((char *)mc_addr, ++ (char *)new_mc_addr, sizeof(struct mac_address)); ++ LOG_DEBUG("IPv6: mc_addr added " ++ "%02x:%02x:%02x:%02x:%02x:%02x", ++ *(u8_t *)new_mc_addr, ++ *((u8_t *)new_mc_addr + 1), ++ *((u8_t *)new_mc_addr + 2), ++ *((u8_t *)new_mc_addr + 3), ++ *((u8_t *)new_mc_addr + 4), ++ *((u8_t *)new_mc_addr + 5)); ++ return TRUE; ++ } ++ } ++ return FALSE; ++} ++ ++int iscsiL2IsOurMcAddr(struct ipv6_context *context, ++ struct mac_address *dest_mac) ++{ ++ int i; ++ struct mac_address *mc_addr; ++ ++ mc_addr = context->mc_addr; ++ for (i = 0; i < MAX_MCADDR_TABLE; i++, mc_addr++) ++ if (!memcmp((char *)mc_addr, ++ (char *)dest_mac->addr, sizeof(struct mac_address))) ++ return TRUE; ++ return FALSE; ++} ++ ++void ipv6_init(struct ndpc_state *ndp, int cfg) ++{ ++ int i; ++ struct ipv6_context *context = (struct ipv6_context *)ndp->ipv6_context; ++ struct mac_address *mac_addr = (struct mac_address *)ndp->mac_addr; ++ struct ipv6_arp_entry *ipv6_arp_table; ++ struct ipv6_prefix_entry *ipv6_prefix_table; ++ struct mac_address mc_addr; ++ ++ if (context == NULL) { ++ LOG_ERR("IPV6: INIT ipv6_context is NULL"); ++ return; ++ } ++ ++ memset((char *)context, 0, sizeof(struct ipv6_context)); ++ ++ /* Associate the nic_iface's ustack to this ipv6_context */ ++ context->ustack = ndp->ustack; ++ ++ ipv6_arp_table = &context->ipv6_arp_table[0]; ++ ipv6_prefix_table = &context->ipv6_prefix_table[0]; ++ ++ memset((char *)ipv6_arp_table, 0, sizeof(*ipv6_arp_table)); ++ memset((char *)ipv6_prefix_table, 0, sizeof(*ipv6_prefix_table)); ++ memcpy((char *)&context->mac_addr, ++ (char *)mac_addr, sizeof(struct mac_address)); ++ /* ++ * Per RFC 2373. ++ * There are two types of local-use unicast addresses defined. These ++ * are Link-Local and Site-Local. The Link-Local is for use on a single ++ * link and the Site-Local is for use in a single site. Link-Local ++ * addresses have the following format: ++ * ++ * | 10 | ++ * | bits | 54 bits | 64 bits | ++ * +----------+-------------------------+----------------------------+ ++ * |1111111010| 0 | interface ID | ++ * +----------+-------------------------+----------------------------+ ++ */ ++ if (context->ustack->linklocal_autocfg != IPV6_LL_AUTOCFG_OFF) { ++ context->link_local_addr.addr8[0] = 0xfe; ++ context->link_local_addr.addr8[1] = 0x80; ++ /* Bit 1 is 1 to indicate universal scope. */ ++ context->link_local_addr.addr8[8] = mac_addr->addr[0] | 0x2; ++ context->link_local_addr.addr8[9] = mac_addr->addr[1]; ++ context->link_local_addr.addr8[10] = mac_addr->addr[2]; ++ context->link_local_addr.addr8[11] = 0xff; ++ context->link_local_addr.addr8[12] = 0xfe; ++ context->link_local_addr.addr8[13] = mac_addr->addr[3]; ++ context->link_local_addr.addr8[14] = mac_addr->addr[4]; ++ context->link_local_addr.addr8[15] = mac_addr->addr[5]; ++ ++ context->link_local_multi.addr8[0] = 0xff; ++ context->link_local_multi.addr8[1] = 0x02; ++ context->link_local_multi.addr8[11] = 0x01; ++ context->link_local_multi.addr8[12] = 0xff; ++ context->link_local_multi.addr8[13] |= ++ context->link_local_addr.addr8[13]; ++ context->link_local_multi.addr16[7] = ++ context->link_local_addr.addr16[7]; ++ ++ /* Default Prefix length is 64 */ ++ /* Add Link local address to the head of the ipv6 address ++ list */ ++ ipv6_add_prefix_entry(context, ++ &context->link_local_addr, 64); ++ } ++ /* ++ * Convert Multicast IP address to Multicast MAC adress per ++ * RFC 2464: Transmission of IPv6 Packets over Ethernet Networks ++ * ++ * An IPv6 packet with a multicast destination address DST, consisting ++ * of the sixteen octets DST[1] through DST[16], is transmitted to the ++ * Ethernet multicast address whose first two octets are the value 3333 ++ * hexadecimal and whose last four octets are the last four octets of ++ * DST. ++ * ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * |0 0 1 1 0 0 1 1|0 0 1 1 0 0 1 1| ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | DST[13] | DST[14] | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | DST[15] | DST[16] | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * ++ * IPv6 requires the following Multicast IP addresses setup per node. ++ */ ++ for (i = 0; i < 3; i++) { ++ mc_addr.addr[0] = 0x33; ++ mc_addr.addr[1] = 0x33; ++ mc_addr.addr[2] = 0x0; ++ mc_addr.addr[3] = 0x0; ++ mc_addr.addr[4] = 0x0; ++ ++ switch (i) { ++ case 0: ++ /* All Nodes Multicast IPv6 address : ff02::1 */ ++ mc_addr.addr[5] = 0x1; ++ break; ++ ++ case 1: ++ /* All Host Multicast IPv6 address : ff02::3 */ ++ mc_addr.addr[5] = 0x3; ++ break; ++ ++ case 2: ++ /* Solicited Node Multicast Address: ff02::01:ffxx:yyzz ++ */ ++ mc_addr.addr[2] = 0xff; ++ mc_addr.addr[3] = mac_addr->addr[3]; ++ mc_addr.addr[4] = mac_addr->addr[4]; ++ mc_addr.addr[5] = mac_addr->addr[5]; ++ break; ++ ++ default: ++ break; ++ } ++ iscsiL2AddMcAddr(context, &mc_addr); ++ } ++ ++ /* Default HOP number */ ++ context->hop_limit = IPV6_HOP_LIMIT; ++} ++ ++int ipv6_add_prefix_entry(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr, u8_t prefix_len) ++{ ++ int i; ++ struct ipv6_prefix_entry *prefix_entry; ++ struct ipv6_prefix_entry *ipv6_prefix_table = ++ context->ipv6_prefix_table; ++ char addr_str[INET6_ADDRSTRLEN]; ++ ++ /* Check if there is an valid entry already. */ ++ for (i = 0; i < IPV6_NUM_OF_ADDRESS_ENTRY; i++) { ++ prefix_entry = &ipv6_prefix_table[i]; ++ ++ if (prefix_entry->prefix_len != 0) { ++ if (memcmp((char *)&prefix_entry->ip_addr, ++ (char *)ip_addr, ++ sizeof(struct ipv6_addr)) == 0) { ++ /* We already initialize on this interface. ++ There is nothing to do */ ++ return 0; ++ } ++ } ++ } ++ ++ /* Find an unused entry */ ++ for (i = 0; i < IPV6_NUM_OF_ADDRESS_ENTRY; i++) { ++ prefix_entry = &ipv6_prefix_table[i]; ++ ++ if (prefix_entry->prefix_len == 0) ++ break; ++ } ++ ++ if (prefix_entry->prefix_len != 0) ++ return -1; ++ ++ prefix_entry->prefix_len = prefix_len / 8; ++ ++ memcpy((char *)&prefix_entry->ip_addr, ++ (char *)ip_addr, sizeof(struct ipv6_addr)); ++ ++ inet_ntop(AF_INET6, &prefix_entry->ip_addr.addr8, addr_str, ++ sizeof(addr_str)); ++ ++ LOG_DEBUG("IPv6: add prefix IP addr %s", addr_str); ++ ++ /* Put it on the list on head of the list. */ ++ if (context->addr_list != NULL) ++ prefix_entry->next = context->addr_list; ++ else ++ prefix_entry->next = NULL; ++ ++ context->addr_list = prefix_entry; ++ ++ return 0; ++} ++ ++void ipv6_rx_packet(struct ipv6_context *context, u16_t len) ++{ ++ struct ipv6_hdr *ipv6; ++ u16_t protocol; ++ ++ if (!context->ustack) { ++ LOG_WARN("ipv6 rx pkt ipv6_context = %p ustack = %p", context, ++ context->ustack); ++ return; ++ } ++ ipv6 = (struct ipv6_hdr *)context->ustack->network_layer; ++ /* Make sure it's an IPv6 packet */ ++ if ((ipv6->ipv6_version_fc & 0xf0) != IPV6_VERSION) { ++ /* It's not an IPv6 packet. Drop it. */ ++ LOG_WARN("IPv6 version 0x%x not IPv6", ipv6->ipv6_version_fc); ++ return; ++ } ++ protocol = ipv6_process_rx(ipv6); ++ ++ switch (protocol) { ++ case IPPROTO_ICMPV6: ++ ipv6_icmp_rx(context); ++ break; ++ ++ case IPPROTO_UDP: ++ /* Indicate to UDP processing code */ ++ ipv6_udp_rx(context); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++void ipv6_mc_init_dest_mac(struct eth_hdr *eth, struct ipv6_hdr *ipv6) ++{ ++ int i; ++ /* ++ * Initialize address mapping of IPV6 Multicast to multicast MAC ++ * address per RFC 2464. ++ * ++ * An IPv6 packet with a multicast destination address DST, consisting ++ * of the sixteen octets DST[1] through DST[16], is transmitted to the ++ * Ethernet multicast address whose first two octets are the value 3333 ++ * hexadecimal and whose last four octets are the last four octets of ++ * DST. ++ * ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * |0 0 1 1 0 0 1 1|0 0 1 1 0 0 1 1| ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | DST[13] | DST[14] | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | DST[15] | DST[16] | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ */ ++ eth->dest_mac.addr[0] = 0x33; ++ eth->dest_mac.addr[1] = 0x33; ++ for (i = 0; i < 4; i++) ++ eth->dest_mac.addr[2 + i] = ipv6->ipv6_dst.addr8[12 + i]; ++} ++ ++int ipv6_autoconfig(struct ipv6_context *context) ++{ ++ return ipv6_discover_address(context); ++} ++ ++int ipv6_discover_address(struct ipv6_context *context) ++{ ++ struct eth_hdr *eth = ++ (struct eth_hdr *)context->ustack->data_link_layer; ++ struct ipv6_hdr *ipv6 = ++ (struct ipv6_hdr *)context->ustack->network_layer; ++ struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 + ++ sizeof(struct ipv6_hdr)); ++ int rc = 0; ++ ++ /* Retrieve tx buffer */ ++ if (eth == NULL || ipv6 == NULL) ++ return -EAGAIN; ++ ++ /* Setup IPv6 All Routers Multicast address : ff02::2 */ ++ memset((char *)&ipv6->ipv6_dst, 0, sizeof(struct ipv6_addr)); ++ ipv6->ipv6_dst.addr8[0] = 0xff; ++ ipv6->ipv6_dst.addr8[1] = 0x02; ++ ipv6->ipv6_dst.addr8[15] = 0x02; ++ ipv6->ipv6_hop_limit = 255; ++ ++ /* Initialize MAC header based on destination MAC address */ ++ ipv6_mc_init_dest_mac(eth, ipv6); ++ ipv6->ipv6_nxt_hdr = IPPROTO_ICMPV6; ++ ++ icmp->icmpv6_type = ICMPV6_RTR_SOL; ++ icmp->icmpv6_code = 0; ++ icmp->icmpv6_data = 0; ++ icmp->icmpv6_cksum = 0; ++ ipv6_icmp_init_link_option(context, ++ (struct icmpv6_opt_link_addr *)((u8_t *)icmp ++ + sizeof(struct icmpv6_hdr)), ++ IPV6_ICMP_OPTION_SRC_ADDR); ++ ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) + ++ sizeof(struct icmpv6_opt_link_addr))); ++ memcpy((char *)&ipv6->ipv6_src, ++ (char *)&context->link_local_addr, ++ sizeof(struct ipv6_addr)); ++ ++ icmp->icmpv6_cksum = 0; ++ LOG_DEBUG("IPv6: Send rtr sol"); ++ ipv6_send(context, (u8_t *) icmp - (u8_t *) eth + ++ sizeof(struct icmpv6_hdr) + ++ sizeof(struct icmpv6_opt_link_addr)); ++ return rc; ++} ++ ++u16_t ipv6_process_rx(struct ipv6_hdr *ipv6) ++{ ++ return ipv6->ipv6_nxt_hdr; ++} ++ ++int ipv6_send(struct ipv6_context *context, u16_t packet_len) ++{ ++ struct eth_hdr *eth = ++ (struct eth_hdr *)context->ustack->data_link_layer; ++ struct ipv6_hdr *ipv6 = ++ (struct ipv6_hdr *)context->ustack->network_layer; ++ ++ ipv6_setup_hdrs(context, eth, ipv6, packet_len); ++ ++ return iscsiL2Send(context, packet_len); ++} ++ ++void ipv6_send_udp_packet(struct ipv6_context *context, u16_t packet_len) ++{ ++ struct eth_hdr *eth = ++ (struct eth_hdr *)context->ustack->data_link_layer; ++ struct ipv6_hdr *ipv6 = ++ (struct ipv6_hdr *)context->ustack->network_layer; ++ struct udp_hdr *udp = (struct udp_hdr *)((u8_t *)ipv6 + ++ sizeof(struct ipv6_hdr)); ++ ++ ipv6->ipv6_nxt_hdr = IPPROTO_UDP; ++ ipv6->ipv6_plen = ++ HOST_TO_NET16(packet_len - ((u8_t *)udp - (u8_t *)eth)); ++ ++ udp->chksum = 0; ++ ++ /* ++ * We only use UDP packet for DHCPv6. The source address is always ++ * link-local address. ++ */ ++ ipv6->ipv6_src.addr[0] = 0; ++ ++ /* Hop limit is always 1 for DHCPv6 packet. */ ++ ipv6->ipv6_hop_limit = 1; ++ ++ ipv6_send(context, packet_len); ++} ++ ++void ipv6_setup_hdrs(struct ipv6_context *context, struct eth_hdr *eth, ++ struct ipv6_hdr *ipv6, u16_t packet_len) ++{ ++ struct ipv6_addr *our_address; ++ ++ /* VLAN will be taken cared of in the nic layer */ ++ eth->len_type = HOST_TO_NET16(LAYER2_TYPE_IPV6); ++ memcpy((char *)ð->src_mac, ++ (char *)&context->mac_addr, sizeof(struct mac_address)); ++ ++ /* Put the traffic class into the packet. */ ++ memset(&ipv6->ipv6_version_fc, 0, sizeof(u32_t)); ++ ipv6->ipv6_version_fc = IPV6_VERSION; ++ if (ipv6->ipv6_hop_limit == 0) ++ ipv6->ipv6_hop_limit = context->hop_limit; ++ ++ if (ipv6->ipv6_src.addr[0] == 0) { ++ /* Need to initialize source IP address. */ ++ our_address = ipv6_our_address(context); ++ if (our_address != NULL) { ++ /* Assume that caller has filled in the destination ++ IP address */ ++ memcpy((char *)&ipv6->ipv6_src, ++ (char *)our_address, sizeof(struct ipv6_addr)); ++ } ++ } ++ ++ ipv6_insert_protocol_chksum(ipv6); ++} ++ ++static void ipv6_insert_protocol_chksum(struct ipv6_hdr *ipv6) ++{ ++ u32_t sum; ++ u16_t *ptr; ++ u16_t *protocol_data_ptr; ++ int i; ++ u16_t protocol_data_len; ++ u16_t checksum; ++ ++ /* ++ * This routine assumes that there is no extension header. This driver ++ * doesn't user extension header to keep driver small and simple. ++ * ++ * Pseudo check consists of the following: ++ * SRC IP, DST IP, Protocol Data Length, and Next Header. ++ */ ++ sum = 0; ++ ptr = (u16_t *)&ipv6->ipv6_src; ++ ++ for (i = 0; i < sizeof(struct ipv6_addr); i++) { ++ sum += HOST_TO_NET16(*ptr); ++ ptr++; ++ } ++ ++ /* Keep track where the layer header is */ ++ protocol_data_ptr = ptr; ++ ++ protocol_data_len = HOST_TO_NET16(ipv6->ipv6_plen); ++ sum += protocol_data_len; ++ sum += ipv6->ipv6_nxt_hdr; ++ /* Sum now contains sum of IPv6 pseudo header. Let's add the data ++ streams. */ ++ if (protocol_data_len & 1) { ++ /* Length of data is odd */ ++ *((u8_t *) ptr + protocol_data_len) = 0; ++ protocol_data_len++; ++ } ++ ++ for (i = 0; i < protocol_data_len / 2; i++) { ++ sum += HOST_TO_NET16(*ptr); ++ ptr++; ++ } ++ ++ sum = (sum >> 16) + (sum & 0xffff); ++ sum += (sum >> 16); ++ sum &= 0xffff; ++ checksum = (u16_t) (~sum); ++ checksum = HOST_TO_NET16(checksum); ++ ++ switch (ipv6->ipv6_nxt_hdr) { ++ case IPPROTO_ICMPV6: ++ /* Insert correct ICMPv6 checksum */ ++ ((struct icmpv6_hdr *)(protocol_data_ptr))->icmpv6_cksum = ++ checksum; ++ break; ++ case IPPROTO_UDP: ++ /* Insert correct UDP checksum */ ++ ((struct udp_hdr *)protocol_data_ptr)->chksum = checksum; ++ break; ++ default: ++ break; ++ } ++} ++ ++int ipv6_is_it_our_link_local_address(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr) ++{ ++ u8_t *test_addr = (u8_t *) ip_addr->addr8; ++ u8_t test_remainder; ++ ++ if (test_addr[0] != context->link_local_addr.addr8[0]) ++ return FALSE; ++ ++ test_remainder = (test_addr[1] & 0xC0) >> 6; ++ if (test_remainder != 2) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++static int ipv6_is_it_our_address(struct ipv6_context *context, ++ struct ipv6_addr *ipv6_addr) ++{ ++ struct ipv6_prefix_entry *ipv6_prefix; ++ ++ for (ipv6_prefix = context->addr_list; ipv6_prefix != NULL; ++ ipv6_prefix = ipv6_prefix->next) { ++ if (IPV6_ARE_ADDR_EQUAL(&ipv6_prefix->ip_addr, ipv6_addr)) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++struct ipv6_addr *ipv6_our_address(struct ipv6_context *context) ++{ ++ return &context->link_local_addr; ++} ++ ++int ipv6_ip_in_arp_table(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr, ++ struct mac_address *mac_addr) ++{ ++ struct ipv6_arp_entry *arp_entry; ++ int i; ++ ++ for (i = 0; i < UIP_ARPTAB_SIZE; i++) { ++ arp_entry = &context->ipv6_arp_table[i]; ++ ++ if (IPV6_ARE_ADDR_EQUAL(&arp_entry->ip_addr, ip_addr)) { ++ memcpy((char *)mac_addr, &arp_entry->mac_addr, ++ sizeof(struct mac_address)); ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++struct ipv6_addr *ipv6_find_longest_match(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr) ++{ ++ struct ipv6_prefix_entry *ipv6_prefix; ++ struct ipv6_prefix_entry *best_match = NULL; ++ int longest_len = -1; ++ int len; ++ ++ for (ipv6_prefix = context->addr_list; ipv6_prefix != NULL; ++ ipv6_prefix = ipv6_prefix->next) { ++ if (!IPV6_IS_ADDR_LINKLOCAL(&ipv6_prefix->ip_addr)) { ++ len = best_match_bufcmp((u8_t *)&ipv6_prefix->ip_addr, ++ (u8_t *)ip_addr, ++ sizeof(struct ipv6_addr)); ++ if (len > longest_len) { ++ best_match = ipv6_prefix; ++ longest_len = len; ++ } ++ } ++ } ++ ++ if (best_match) ++ return &best_match->ip_addr; ++ ++ return NULL; ++} ++ ++void ipv6_arp_out(struct ipv6_context *context, int *uip_len) ++{ ++ /* Empty routine */ ++} ++ ++ ++static void ipv6_update_arp_table(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr, ++ struct mac_address *mac_addr) ++{ ++ struct ipv6_arp_entry *arp_entry; ++ int i; ++ struct ipv6_arp_entry *ipv6_arp_table = context->ipv6_arp_table; ++ ++ LOG_DEBUG("IPv6: Neighbor update"); ++ /* ++ * Walk through the ARP mapping table and try to find an entry to ++ * update. If none is found, the IP -> MAC address mapping is ++ * inserted in the ARP table. ++ */ ++ for (i = 0; i < UIP_ARPTAB_SIZE; i++) { ++ arp_entry = &ipv6_arp_table[i]; ++ ++ /* Only check those entries that are actually in use. */ ++ if (arp_entry->ip_addr.addr[0] != 0) { ++ /* ++ * Check if the source IP address of the incoming ++ * packet matches the IP address in this ARP table ++ * entry. ++ */ ++ if (IPV6_ARE_ADDR_EQUAL(&arp_entry->ip_addr, ip_addr)) { ++ /* An old entry found, update this and return */ ++ memcpy((char *)&arp_entry->mac_addr, ++ (char *)mac_addr, ++ sizeof(struct mac_address)); ++ arp_entry->time = context->arptime; ++ return; ++ } ++ } ++ } ++ ++ /* ++ * If we get here, no existing ARP table entry was found, so we ++ * create one. ++ * ++ * First, we try to find an unused entry in the ARP table. ++ */ ++ for (i = 0; i < UIP_ARPTAB_SIZE; i++) { ++ arp_entry = &ipv6_arp_table[i]; ++ ++ if (arp_entry->ip_addr.addr[0] == 0) ++ break; ++ } ++ ++ if (i == UIP_ARPTAB_SIZE) ++ return; ++ ++ /* Index j is the entry that is least used */ ++ arp_entry = &ipv6_arp_table[i]; ++ memcpy((char *)&arp_entry->ip_addr, (char *)ip_addr, ++ sizeof(struct ipv6_addr)); ++ memcpy((char *)&arp_entry->mac_addr, ++ (char *)mac_addr, sizeof(struct mac_address)); ++ ++ arp_entry->time = context->arptime; ++} ++ ++/* DestIP is intact */ ++int ipv6_send_nd_solicited_packet(struct ipv6_context *context, ++ struct eth_hdr *eth, struct ipv6_hdr *ipv6) ++{ ++ struct icmpv6_hdr *icmp; ++ int pkt_len = 0; ++ struct ipv6_addr *longest_match_addr; ++ char addr_str[INET6_ADDRSTRLEN]; ++ ++ ipv6->ipv6_nxt_hdr = IPPROTO_ICMPV6; ++ ++ /* Depending on the IPv6 address of the target, we'll need to determine ++ whether we use the assigned IPv6 address/RA or the link local address ++ */ ++ /* Use Link-local as source address */ ++ if (ipv6_is_it_our_link_local_address(context, &ipv6->ipv6_dst) == ++ TRUE) { ++ LOG_DEBUG("IPv6: NS using link local"); ++ memcpy((char *)&ipv6->ipv6_src, ++ (char *)&context->link_local_addr, ++ sizeof(struct ipv6_addr)); ++ } else { ++ longest_match_addr = ++ ipv6_find_longest_match(context, &ipv6->ipv6_dst); ++ if (longest_match_addr) { ++ LOG_DEBUG("IPv6: NS using longest match addr"); ++ memcpy((char *)&ipv6->ipv6_src, ++ (char *)longest_match_addr, ++ sizeof(struct ipv6_addr)); ++ } else { ++ LOG_DEBUG("IPv6: NS using link local instead"); ++ memcpy((char *)&ipv6->ipv6_src, ++ (char *)&context->link_local_addr, ++ sizeof(struct ipv6_addr)); ++ } ++ } ++ icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 + sizeof(struct ipv6_hdr)); ++ ++ inet_ntop(AF_INET6, &ipv6->ipv6_src.addr8, addr_str, sizeof(addr_str)); ++ LOG_DEBUG("IPv6: NS host IP addr: %s", addr_str); ++ /* ++ * Destination IP address to be resolved is after the ICMPv6 ++ * header. ++ */ ++ memcpy((char *)((u8_t *)icmp + sizeof(struct icmpv6_hdr)), ++ (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr)); ++ ++ /* ++ * Destination IP in the IPv6 header contains solicited-node multicast ++ * address corresponding to the target address. ++ * ++ * ff02::01:ffxx:yyzz. Where xyz are least ++ * significant of 24-bit MAC address. ++ */ ++ memset((char *)&ipv6->ipv6_dst, 0, sizeof(struct ipv6_addr) - 3); ++ ipv6->ipv6_dst.addr8[0] = 0xff; ++ ipv6->ipv6_dst.addr8[1] = 0x02; ++ ipv6->ipv6_dst.addr8[11] = 0x01; ++ ipv6->ipv6_dst.addr8[12] = 0xff; ++ ipv6_mc_init_dest_mac(eth, ipv6); ++ ipv6->ipv6_hop_limit = 255; ++ ++ icmp->icmpv6_type = ICMPV6_NEIGH_SOL; ++ icmp->icmpv6_code = 0; ++ icmp->icmpv6_data = 0; ++ icmp->icmpv6_cksum = 0; ++ ipv6_icmp_init_link_option(context, ++ (struct icmpv6_opt_link_addr *)((u8_t *)icmp ++ + sizeof(struct icmpv6_hdr) ++ + sizeof(struct ipv6_addr)), ++ IPV6_ICMP_OPTION_SRC_ADDR); ++ ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) + ++ sizeof(struct icmpv6_opt_link_addr) + ++ sizeof(struct ipv6_addr))); ++ /* Total packet size */ ++ pkt_len = (u8_t *) icmp - (u8_t *) eth + ++ sizeof(struct icmpv6_hdr) + ++ sizeof(struct icmpv6_opt_link_addr) + sizeof(struct ipv6_addr); ++ ipv6_setup_hdrs(context, eth, ipv6, pkt_len); ++ return pkt_len; ++} ++ ++static void ipv6_icmp_init_link_option(struct ipv6_context *context, ++ struct icmpv6_opt_link_addr *link_opt, ++ u8_t type) ++{ ++ link_opt->hdr.type = type; ++ link_opt->hdr.len = sizeof(struct icmpv6_opt_link_addr) / 8; ++ memcpy((char *)&link_opt->link_addr, ++ (char *)&context->mac_addr, sizeof(struct mac_address)); ++} ++ ++static void ipv6_icmp_rx(struct ipv6_context *context) ++{ ++ struct ipv6_hdr *ipv6 = ++ (struct ipv6_hdr *)context->ustack->network_layer; ++ struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 + ++ sizeof(struct ipv6_hdr)); ++ uip_icmp_echo_hdr_t *icmp_echo_hdr = ++ (uip_icmp_echo_hdr_t *)((u8_t *)ipv6 + ++ sizeof(struct ipv6_hdr)); ++ ++ switch (icmp->icmpv6_type) { ++ case ICMPV6_RTR_ADV: ++ ipv6_icmp_handle_router_adv(context); ++ break; ++ ++ case ICMPV6_NEIGH_SOL: ++ ipv6_icmp_handle_nd_sol(context); ++ break; ++ ++ case ICMPV6_NEIGH_ADV: ++ ipv6_icmp_handle_nd_adv(context); ++ break; ++ ++ case ICMPV6_ECHO_REQUEST: ++ /* Response with ICMP reply */ ++ ipv6_icmp_handle_echo_request(context); ++ break; ++ ++ case ICMPV6_ECHO_REPLY: ++ /* Handle ICMP reply */ ++ process_icmp_packet(icmp_echo_hdr, context->ustack); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static void ipv6_icmp_handle_router_adv(struct ipv6_context *context) ++{ ++ struct ipv6_hdr *ipv6 = ++ (struct ipv6_hdr *)context->ustack->network_layer; ++ struct icmpv6_router_advert *icmp = ++ (struct icmpv6_router_advert *)((u8_t *)ipv6 + sizeof(struct ipv6_hdr)); ++ struct icmpv6_opt_hdr *icmp_opt; ++ u16_t opt_len; ++ u16_t len; ++ char addr_str[INET6_ADDRSTRLEN]; ++ ++ if (context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED) ++ return; ++ ++ opt_len = HOST_TO_NET16(ipv6->ipv6_plen) - ++ sizeof(struct icmpv6_router_advert); ++ ++ icmp_opt = (struct icmpv6_opt_hdr *)((u8_t *)icmp + ++ sizeof(struct icmpv6_router_advert)); ++ len = 0; ++ while (len < opt_len) { ++ icmp_opt = (struct icmpv6_opt_hdr *)((u8_t *)icmp + ++ sizeof(struct icmpv6_router_advert) + ++ len); ++ ++ switch (icmp_opt->type) { ++ case IPV6_ICMP_OPTION_PREFIX: ++ ipv6_icmp_process_prefix(context, ++ (struct icmpv6_opt_prefix *)icmp_opt); ++ context->flags |= IPV6_FLAGS_ROUTER_ADV_RECEIVED; ++ break; ++ ++ default: ++ break; ++ } ++ ++ len += icmp_opt->len * 8; ++ } ++ ++ if (context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED) { ++ LOG_DEBUG("IPv6: RTR ADV nd_ra_flags = 0x%x", ++ icmp->nd_ra_flags_reserved); ++ if (icmp->nd_ra_curhoplimit > 0) ++ context->hop_limit = icmp->nd_ra_curhoplimit; ++ ++ if (icmp->nd_ra_flags_reserved & IPV6_RA_MANAGED_FLAG) ++ context->flags |= IPV6_FLAGS_MANAGED_ADDR_CONFIG; ++ ++ if (icmp->nd_ra_flags_reserved & IPV6_RA_CONFIG_FLAG) ++ context->flags |= IPV6_FLAGS_OTHER_STATEFUL_CONFIG; ++ ++ if (icmp->nd_ra_router_lifetime != 0) { ++ /* There is a default router. */ ++ if (context->ustack->router_autocfg != ++ IPV6_RTR_AUTOCFG_OFF) ++ memcpy( ++ (char *)&context->default_router, ++ (char *)&ipv6->ipv6_src, ++ sizeof(struct ipv6_addr)); ++ inet_ntop(AF_INET6, &context->default_router, ++ addr_str, sizeof(addr_str)); ++ LOG_DEBUG("IPv6: Got default router IP addr: %s", ++ addr_str); ++ } ++ } ++} ++ ++static void ipv6_icmp_process_prefix(struct ipv6_context *context, ++ struct icmpv6_opt_prefix *icmp_prefix) ++{ ++ struct ipv6_addr addr; ++ char addr_str[INET6_ADDRSTRLEN]; ++ ++ /* we only process on-link address info */ ++ if (!(icmp_prefix->flags & ICMPV6_OPT_PREFIX_FLAG_ON_LINK)) ++ return; ++ ++ /* ++ * We only process prefix length of 64 since our Identifier is 64-bit ++ */ ++ if (icmp_prefix->prefix_len == 64) { ++ /* Copy 64-bit from the local-link address to create ++ IPv6 address */ ++ memcpy((char *)&addr, ++ (char *)&icmp_prefix->prefix, 8); ++ memcpy((char *)&addr.addr8[8], ++ &context->link_local_addr.addr8[8], 8); ++ inet_ntop(AF_INET6, &addr, addr_str, sizeof(addr_str)); ++ LOG_DEBUG("IPv6: Got RA ICMP option IP addr: %s", addr_str); ++ ipv6_add_prefix_entry(context, &addr, 64); ++ } ++} ++ ++static void ipv6_icmp_handle_nd_adv(struct ipv6_context *context) ++{ ++ struct eth_hdr *eth = ++ (struct eth_hdr *)context->ustack->data_link_layer; ++ struct ipv6_hdr *ipv6 = ++ (struct ipv6_hdr *)context->ustack->network_layer; ++ struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 + ++ sizeof(struct ipv6_hdr)); ++ struct icmpv6_opt_link_addr *link_opt = ++ (struct icmpv6_opt_link_addr *)((u8_t *)icmp + ++ sizeof(struct icmpv6_hdr) + sizeof(struct ipv6_addr)); ++ struct ipv6_addr *tar_addr6; ++ char addr_str[INET6_ADDRSTRLEN]; ++ ++ /* Added the multicast check for ARP table update */ ++ /* Should we qualify for only our host's multicast and our ++ link_local_multicast?? */ ++ LOG_DEBUG("IPv6: Handle nd adv"); ++ if ((ipv6_is_it_our_address(context, &ipv6->ipv6_dst) == TRUE) || ++ (memcmp((char *)&context->link_local_multi, ++ (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr)) == 0) || ++ (memcmp((char *)&context->multi, ++ (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr)) == 0)) { ++ /* ++ * This is an ARP reply for our addresses. Let's update the ++ * ARP table. ++ */ ++ ipv6_update_arp_table(context, &ipv6->ipv6_src, ++ ð->src_mac); ++ ++ /* Now check for the target address option and update that as ++ well */ ++ if (link_opt->hdr.type == IPV6_ICMP_OPTION_TAR_ADDR) { ++ tar_addr6 = (struct ipv6_addr *)((u8_t *)icmp + ++ sizeof(struct icmpv6_hdr)); ++ LOG_DEBUG("IPV6: Target MAC " ++ "%02x:%02x:%02x:%02x:%02x:%02x", ++ link_opt->link_addr[0], link_opt->link_addr[1], ++ link_opt->link_addr[2], link_opt->link_addr[3], ++ link_opt->link_addr[4], link_opt->link_addr[5]); ++ inet_ntop(AF_INET6, &tar_addr6->addr8, addr_str, ++ sizeof(addr_str)); ++ LOG_DEBUG("IPv6: Target IP addr %s", addr_str); ++ ipv6_update_arp_table(context, tar_addr6, ++ (struct mac_address *)link_opt->link_addr); ++ } ++ ++ } ++} ++ ++static void ipv6_icmp_handle_nd_sol(struct ipv6_context *context) ++{ ++ struct eth_hdr *eth = ++ (struct eth_hdr *)context->ustack->data_link_layer; ++ struct ipv6_hdr *ipv6 = ++ (struct ipv6_hdr *)context->ustack->network_layer; ++ struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 + ++ sizeof(struct ipv6_hdr)); ++ struct icmpv6_opt_link_addr *link_opt = ++ (struct icmpv6_opt_link_addr *)((u8_t *)icmp + ++ sizeof(struct icmpv6_hdr) + sizeof(struct ipv6_addr)); ++ int icmpv6_opt_len = 0; ++ struct ipv6_addr tmp; ++ struct ipv6_addr *longest_match_addr, *tar_addr6; ++ ++ LOG_DEBUG("IPv6: Handle nd sol"); ++ ++ if ((memcmp((char *)&context->mac_addr, ++ (char *)ð->dest_mac, sizeof(struct mac_address)) != 0) && ++ (iscsiL2IsOurMcAddr(context, (struct mac_address *)ð->dest_mac) ++ == FALSE)) { ++ /* This packet is not for us to handle */ ++ LOG_DEBUG("IPv6: MAC not addressed to us " ++ "%02x:%02x:%02x:%02x:%02x:%02x", ++ eth->dest_mac.addr[0], eth->dest_mac.addr[1], ++ eth->dest_mac.addr[2], eth->dest_mac.addr[3], ++ eth->dest_mac.addr[4], eth->dest_mac.addr[5]); ++ return; ++ } ++ ++ /* Also check for the icmpv6_data before generating the reply */ ++ if (ipv6_is_it_our_address(context, ++ (struct ipv6_addr *) ((u8_t *) icmp + ++ sizeof(struct icmpv6_hdr))) ++ == FALSE) { ++ /* This packet is not for us to handle */ ++ LOG_DEBUG("IPv6: IP not addressed to us"); ++ return; ++ } ++ ++ /* Copy source MAC to Destination MAC */ ++ memcpy((char *)ð->dest_mac, ++ (char *)ð->src_mac, sizeof(struct mac_address)); ++ ++ /* Dest IP contains source IP */ ++ memcpy((char *)&tmp, ++ (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr)); ++ memcpy((char *)&ipv6->ipv6_dst, ++ (char *)&ipv6->ipv6_src, sizeof(struct ipv6_addr)); ++ ++ /* Examine the Neighbor Solicitation ICMPv6 target address field. ++ If target address exist, use that to find best match src address ++ for the reply */ ++ if (link_opt->hdr.type == IPV6_ICMP_OPTION_SRC_ADDR) { ++ tar_addr6 = (struct ipv6_addr *)((u8_t *)icmp + ++ sizeof(struct icmpv6_hdr)); ++ if (ipv6_is_it_our_link_local_address(context, tar_addr6) ++ == TRUE) { ++ LOG_DEBUG("IPv6: NA using link local"); ++ memcpy((char *)&ipv6->ipv6_src, ++ (char *)&context->link_local_addr, ++ sizeof(struct ipv6_addr)); ++ } else { ++ longest_match_addr = ++ ipv6_find_longest_match(context, tar_addr6); ++ if (longest_match_addr) { ++ LOG_DEBUG("IPv6: NA using longest match addr"); ++ memcpy((char *)&ipv6->ipv6_src, ++ (char *)longest_match_addr, ++ sizeof(struct ipv6_addr)); ++ } else { ++ LOG_DEBUG("IPv6: NA using link local instead"); ++ memcpy((char *)&ipv6->ipv6_src, ++ (char *)&context->link_local_addr, ++ sizeof(struct ipv6_addr)); ++ } ++ } ++ } else { ++ /* No target link address, just use whatever it sent to us */ ++ LOG_DEBUG("IPv6: NA use dst addr"); ++ memcpy((char *)&ipv6->ipv6_src, ++ (char *)&tmp, ++ sizeof(struct ipv6_addr)); ++ } ++ ipv6->ipv6_hop_limit = 255; ++ icmp->icmpv6_type = ICMPV6_NEIGH_ADV; ++ icmp->icmpv6_code = 0; ++ icmp->icmpv6_data = 0; ++ icmp->icmpv6_cksum = 0; ++ icmp->data.icmpv6_un_data8[0] = ++ IPV6_NA_FLAG_SOLICITED | IPV6_NA_FLAG_OVERRIDE; ++ memcpy((char *)((u8_t *)icmp + sizeof(struct icmpv6_hdr)), ++ (char *)&ipv6->ipv6_src, ++ sizeof(struct ipv6_addr)); ++ ++ /* Add the target link address option only for all solicitation */ ++ ipv6_icmp_init_link_option(context, ++ (struct icmpv6_opt_link_addr *)((u8_t *)icmp + ++ sizeof(struct icmpv6_hdr) + ++ sizeof(struct ipv6_addr)), ++ IPV6_ICMP_OPTION_TAR_ADDR); ++ icmpv6_opt_len = sizeof(struct icmpv6_opt_link_addr); ++ ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) + ++ icmpv6_opt_len + sizeof(struct ipv6_addr))); ++ LOG_DEBUG("IPv6: Send nd adv"); ++ ipv6_send(context, ++ (u8_t *) icmp - (u8_t *) eth + ++ sizeof(struct icmpv6_hdr) + ++ sizeof(struct icmpv6_opt_link_addr) + ++ sizeof(struct ipv6_addr)); ++ return; ++} ++ ++static void ipv6_icmp_handle_echo_request(struct ipv6_context *context) ++{ ++ struct eth_hdr *eth = ++ (struct eth_hdr *)context->ustack->data_link_layer; ++ struct ipv6_hdr *ipv6 = ++ (struct ipv6_hdr *)context->ustack->network_layer; ++ struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 + ++ sizeof(struct ipv6_hdr)); ++ struct ipv6_addr temp; ++ ++ /* Copy source MAC to Destination MAC */ ++ memcpy((char *)ð->dest_mac, ++ (char *)ð->src_mac, sizeof(struct mac_address)); ++ ++ memcpy((char *)&temp, ++ (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr)); ++ ++ /* Dest IP contains source IP */ ++ memcpy((char *)&ipv6->ipv6_dst, ++ (char *)&ipv6->ipv6_src, sizeof(struct ipv6_addr)); ++ /* Use Link-local as source address */ ++ memcpy((char *)&ipv6->ipv6_src, ++ (char *)&temp, sizeof(struct ipv6_addr)); ++ ++ ipv6->ipv6_hop_limit = context->hop_limit; ++ icmp->icmpv6_type = ICMPV6_ECHO_REPLY; ++ icmp->icmpv6_code = 0; ++ icmp->icmpv6_cksum = 0; ++ LOG_DEBUG("IPv6: Send echo reply"); ++ ipv6_send(context, (u8_t *) icmp - (u8_t *) eth + ++ sizeof(struct ipv6_hdr) + HOST_TO_NET16(ipv6->ipv6_plen)); ++ return; ++} ++ ++void ipv6_set_ip_params(struct ipv6_context *context, ++ struct ipv6_addr *src_ip, u8_t prefix_len, ++ struct ipv6_addr *default_gateway, ++ struct ipv6_addr *linklocal) ++{ ++ if (!(IPV6_IS_ADDR_UNSPECIFIED(src_ip))) { ++ ipv6_add_prefix_entry(context, src_ip, prefix_len); ++ /* Create the multi_dest address */ ++ memset(&context->multi_dest, 0, sizeof(struct ipv6_addr)); ++ context->multi_dest.addr8[0] = 0xff; ++ context->multi_dest.addr8[1] = 0x02; ++ context->multi_dest.addr8[11] = 0x01; ++ context->multi_dest.addr8[12] = 0xff; ++ context->multi_dest.addr8[13] = src_ip->addr8[13]; ++ context->multi_dest.addr16[7] = src_ip->addr16[7]; ++ /* Create the multi address */ ++ memset(&context->multi, 0, sizeof(struct ipv6_addr)); ++ context->multi.addr8[0] = 0xfc; ++ context->multi.addr8[2] = 0x02; ++ context->multi.addr16[7] = src_ip->addr16[7]; ++ } ++ ++ if (!(IPV6_IS_ADDR_UNSPECIFIED(default_gateway))) { ++ /* Override the default gateway addr */ ++ memcpy((char *)&context->default_router, ++ (char *)default_gateway, sizeof(struct ipv6_addr)); ++ ipv6_add_prefix_entry(context, default_gateway, ++ prefix_len); ++ } ++ if (!(IPV6_IS_ADDR_UNSPECIFIED(linklocal))) { ++ /* Override the linklocal addr */ ++ memcpy((char *)&context->link_local_addr, ++ (char *)linklocal, sizeof(struct ipv6_addr)); ++ context->link_local_multi.addr8[0] = 0xff; ++ context->link_local_multi.addr8[1] = 0x02; ++ context->link_local_multi.addr8[11] = 0x01; ++ context->link_local_multi.addr8[12] = 0xff; ++ context->link_local_multi.addr8[13] |= ++ context->link_local_addr.addr8[13]; ++ context->link_local_multi.addr16[7] = ++ context->link_local_addr.addr16[7]; ++ ++ /* Default Prefix length is 64 */ ++ /* Add Link local address to the head of the ipv6 address ++ list */ ++ ipv6_add_prefix_entry(context, ++ &context->link_local_addr, 64); ++ } ++} ++ ++int ipv6_get_source_ip_addrs(struct ipv6_context *context, ++ struct ipv6_addr_entry *addr_list) ++{ ++ struct ipv6_prefix_entry *ipv6_prefix; ++ int i; ++ ++ for (i = 0, ipv6_prefix = context->addr_list; ipv6_prefix != NULL; ++ ipv6_prefix = ipv6_prefix->next) { ++ memcpy((char *)&addr_list->ip_addr, ++ (char *)&ipv6_prefix->ip_addr, ++ sizeof(struct ipv6_addr)); ++ addr_list->prefix_len = ipv6_prefix->prefix_len * 8; ++ ++ i++; ++ addr_list++; ++ } ++ ++ return i; ++} ++ ++int ipv6_get_default_router_ip_addrs(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr) ++{ ++ /* This is a default router. */ ++ memcpy((char *)ip_addr, ++ (char *)&context->default_router, ++ sizeof(struct ipv6_addr)); ++ ++ return 1; ++} ++ ++static void ipv6_udp_rx(struct ipv6_context *context) ++{ ++ struct eth_hdr *eth = ++ (struct eth_hdr *)context->ustack->data_link_layer; ++ struct ipv6_hdr *ipv6 = ++ (struct ipv6_hdr *)context->ustack->network_layer; ++ struct udp_hdr *udp = (struct udp_hdr *)((u8_t *)ipv6 + ++ sizeof(struct ipv6_hdr)); ++ struct dhcpv6_context *dhcpv6c; ++ ++ /* ++ * We only care about DHCPv6 packets from the DHCPv6 server. We drop ++ * all others. ++ */ ++ if (!(context->flags & IPV6_FLAGS_DISABLE_DHCPV6)) { ++ if ((udp->src_port == HOST_TO_NET16(DHCPV6_SERVER_PORT)) && ++ (udp->dest_port == HOST_TO_NET16(DHCPV6_CLIENT_PORT))) { ++ dhcpv6c = context->dhcpv6_context; ++ dhcpv6c->eth = eth; ++ dhcpv6c->ipv6 = ipv6; ++ dhcpv6c->udp = udp; ++ ipv6_udp_handle_dhcp(dhcpv6c); ++ } ++ } ++} ++ ++struct mac_address *ipv6_get_link_addr(struct ipv6_context *context) ++{ ++ return &context->mac_addr; ++} ++ ++u16_t ipv6_do_stateful_dhcpv6(struct ipv6_context *context, u32_t flags) ++{ ++ u16_t task = 0; ++ u16_t ra_flags; ++ ++ ra_flags = context->flags & ++ (IPV6_FLAGS_MANAGED_ADDR_CONFIG | IPV6_FLAGS_OTHER_STATEFUL_CONFIG); ++ ++ if (!(context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED)) { ++ LOG_DEBUG("IPv6: There is no IPv6 router on the network"); ++ ra_flags |= ++ (IPV6_FLAGS_MANAGED_ADDR_CONFIG | ++ IPV6_FLAGS_OTHER_STATEFUL_CONFIG); ++ } ++ ++ if ((flags & ISCSI_FLAGS_DHCP_TCPIP_CONFIG) && ++ (ra_flags & IPV6_FLAGS_MANAGED_ADDR_CONFIG)) ++ task |= DHCPV6_TASK_GET_IP_ADDRESS; ++ ++ if ((flags & ISCSI_FLAGS_DHCP_ISCSI_CONFIG) && ++ (ra_flags & IPV6_FLAGS_OTHER_STATEFUL_CONFIG)) ++ task |= DHCPV6_TASK_GET_OTHER_PARAMS; ++ ++ LOG_DEBUG("IPv6: Stateful flags = 0x%x, ra_flags = 0x%x, task = 0x%x", ++ flags, ra_flags, task); ++ ++ return task; ++} ++ ++void ipv6_add_solit_node_address(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr) ++{ ++ struct mac_address mac_addr; ++ ++ /* ++ * Add Solicited Node Multicast Address for statically configured IPv6 ++ * address. ++ */ ++ mac_addr.addr[0] = 0x33; ++ mac_addr.addr[1] = 0x33; ++ mac_addr.addr[2] = 0xff; ++ mac_addr.addr[3] = ip_addr->addr8[13]; ++ mac_addr.addr[4] = ip_addr->addr8[14]; ++ mac_addr.addr[5] = ip_addr->addr8[15]; ++ iscsiL2AddMcAddr(context, (struct mac_address *)&mac_addr); ++} ++ ++void ipv6_cfg_link_local_addr(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr) ++{ ++ memcpy((char *)&context->link_local_addr, ++ (char *)ip_addr, sizeof(struct ipv6_addr)); ++} ++ ++void ipv6_disable_dhcpv6(struct ipv6_context *context) ++{ ++ context->flags |= IPV6_FLAGS_DISABLE_DHCPV6; ++} +diff --git a/iscsiuio/src/uip/ipv6.h b/iscsiuio/src/uip/ipv6.h +new file mode 100644 +index 0000000..bc63762 +--- /dev/null ++++ b/iscsiuio/src/uip/ipv6.h +@@ -0,0 +1,332 @@ ++/* ++ * Copyright (c) 2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Eddie Wai (eddie.wai@broadcom.com) ++ * Based on Kevin Tran's iSCSI boot code ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ipv6.h - This file contains macro definitions pertaining to IPv6. ++ * ++ * RFC 2460 : IPv6 Specification. ++ * RFC 2373 : IPv6 Addressing Architecture. ++ * RFC 2462 : IPv6 Stateless Address Autoconfiguration. ++ * RFC 2464 : Transmission of IPv6 Packets over Ethernet Networks. ++ * ++ */ ++#ifndef __IPV6_H__ ++#define __IPV6_H__ ++ ++#include "ipv6_ndpc.h" ++ ++#define FALSE 0 ++#define TRUE 1 ++ ++#define LINK_LOCAL_PREFIX_LENGTH 2 ++#define LAYER2_HEADER_LENGTH 14 ++#define LAYER2_VLAN_HEADER_LENGTH 16 ++#define LAYER2_TYPE_IPV6 0x86dd ++ ++struct ipv6_addr { ++ union { ++ u8_t addr8[16]; ++ u16_t addr16[8]; ++ u32_t addr[4]; ++ }; ++}; ++ ++struct udp_hdr { ++ u16_t src_port; ++ u16_t dest_port; ++ u16_t length; ++ u16_t chksum; ++}; ++ ++struct mac_address { ++ union { ++ u8_t addr[6]; ++ struct { ++ u16_t first_2_bytes; ++ u32_t last_4_bytes; ++ } __attribute__ ((packed)); ++ }; ++}; ++ ++#define HOST_TO_NET16(a) htons(a) ++#define HOST_TO_NET32(a) htonl(a) ++#define NET_TO_HOST16(a) ntohs(a) ++/* ++ * Local definition for masks ++ */ ++#define IPV6_MASK0 { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } } ++#define IPV6_MASK32 { { { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } } ++#define IPV6_MASK64 { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } } ++#define IPV6_MASK96 { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } } ++#define IPV6_MASK128 { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } } ++ ++#ifdef BIG_ENDIAN ++#define IPV6_ADDR_INT32_ONE 1 ++#define IPV6_ADDR_INT32_TWO 2 ++#define IPV6_ADDR_INT32_MNL 0xff010000 ++#define IPV6_ADDR_INT32_MLL 0xff020000 ++#define IPV6_ADDR_INT32_SMP 0x0000ffff ++#define IPV6_ADDR_INT16_ULL 0xfe80 ++#define IPV6_ADDR_INT16_USL 0xfec0 ++#define IPV6_ADDR_INT16_MLL 0xff02 ++#else /* LITTE ENDIAN */ ++#define IPV6_ADDR_INT32_ONE 0x01000000 ++#define IPV6_ADDR_INT32_TWO 0x02000000 ++#define IPV6_ADDR_INT32_MNL 0x000001ff ++#define IPV6_ADDR_INT32_MLL 0x000002ff ++#define IPV6_ADDR_INT32_SMP 0xffff0000 ++#define IPV6_ADDR_INT16_ULL 0x80fe ++#define IPV6_ADDR_INT16_USL 0xc0fe ++#define IPV6_ADDR_INT16_MLL 0x02ff ++#endif ++ ++/* ++ * Definition of some useful macros to handle IP6 addresses ++ */ ++#define IPV6_ADDR_ANY_INIT \ ++ { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } } ++#define IPV6_ADDR_LOOPBACK_INIT \ ++ { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } } ++#define IPV6_ADDR_NODELOCAL_ALLNODES_INIT \ ++ { { { 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } } ++#define IPV6_ADDR_INTFACELOCAL_ALLNODES_INIT \ ++ { { { 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } } ++#define IPV6_ADDR_LINKLOCAL_ALLNODES_INIT \ ++ { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } } ++#define IPV6_ADDR_LINKLOCAL_ALLROUTERS_INIT \ ++ { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } } ++ ++#define IPV6_ARE_ADDR_EQUAL(a, b) \ ++ (memcmp((char *)a, (char *)b, sizeof(struct ipv6_addr)) == 0) ++ ++/* Unspecified IPv6 address */ ++#define IPV6_IS_ADDR_UNSPECIFIED(a) \ ++ ((((a)->addr[0]) == 0) && \ ++ (((a)->addr[1]) == 0) && \ ++ (((a)->addr[2]) == 0) && \ ++ (((a)->addr[3]) == 0)) ++ ++/* IPv6 Scope Values */ ++#define IPV6_ADDR_SCOPE_INTFACELOCAL 0x01 /* Node-local scope */ ++#define IPV6_ADDR_SCOPE_LINKLOCAL 0x02 /* Link-local scope */ ++#define IPV6_ADDR_SCOPE_SITELOCAL 0x05 /* Site-local scope */ ++#define IPV6_ADDR_SCOPE_ORGLOCAL 0x08 /* Organization-local scope */ ++#define IPV6_ADDR_SCOPE_GLOBAL 0x0e /* Global scope */ ++ ++/* Link-local Unicast : 10-bits much be 1111111010b --> 0xfe80. */ ++#define IPV6_IS_ADDR_LINKLOCAL(a) \ ++ (((a)->addr8[0] == 0xfe) && (((a)->addr8[1] & 0xc0) == 0x80)) ++ ++/* Site-local Unicast : 10-bits much be 1111111011b --> 0xfec0. */ ++#define IPV6_IS_ADDR_SITELOCAL(a) \ ++ (((a)->addr8[0] == 0xfe) && (((a)->addr8[1] & 0xc0) == 0xc0)) ++ ++/* Multicast : 10bits much be 11111111b. Next 4 bits is flags | 4-bit scope */ ++#define IPV6_IS_ADDR_MULTICAST(a) ((a)->addr8[0] == 0xff) ++ ++#define IPV6_ADDR_MC_SCOPE(a) ((a)->addr8[1] & 0x0f) ++ ++/* Multicast Scope */ ++ ++struct eth_hdr { ++ struct mac_address dest_mac; ++ struct mac_address src_mac; ++ u16_t len_type; ++}; ++ ++struct ipv6_hdr { ++ union { ++ struct { ++ u32_t ipv6_flow; /* Version (4-bit) | ++ Traffic Class (8-bit) | ++ Flow ID (20-bit) */ ++ u16_t ipv6_plen; /* Payload length */ ++ u8_t ipv6_nxt_hdr; /* Next Header */ ++ u8_t ipv6_hop_limit; /* hop limit */ ++ } ipv6_dw1; ++ ++ u8_t ipv6_version_fc; /* 4 bits version, top 4 bits class */ ++ } ipv6_ctrl; ++ ++ struct ipv6_addr ipv6_src; /* Source address */ ++ struct ipv6_addr ipv6_dst; /* Destination address */ ++}; ++ ++#define ipv6_version_fc ipv6_ctrl.ipv6_version_fc ++#define ipv6_flow ipv6_ctrl.ipv6_dw1.ipv6_flow ++#define ipv6_plen ipv6_ctrl.ipv6_dw1.ipv6_plen ++#define ipv6_nxt_hdr ipv6_ctrl.ipv6_dw1.ipv6_nxt_hdr ++#define ipv6_hop_limit ipv6_ctrl.ipv6_dw1.ipv6_hop_limit ++ ++#define IPV6_VERSION 0x60 ++#define IPV6_VERSION_MASK 0xf0 ++#define IPV6_HOP_LIMIT 64 ++ ++/* Length of the IP header with no next header */ ++#define IPV6_HEADER_LEN sizeof(struct ipv6_hdr) ++ ++#ifdef BIG_ENDIAN ++#define IPV6_FLOWINFO_MASK 0x0fffffff /* flow info (28 bits) */ ++#define IPV6_FLOWLABEL_MASK 0x000fffff /* flow label (20 bits) */ ++#else /* LITTLE_ENDIAN */ ++#define IPV6_FLOWINFO_MASK 0xffffff0f /* flow info (28 bits) */ ++#define IPV6_FLOWLABEL_MASK 0xffff0f00 /* flow label (20 bits) */ ++#endif ++ ++struct packet_ipv6 { ++ struct mac_address dest_mac; ++ struct mac_address src_mac; ++ u16_t len_type; ++ struct ipv6_hdr ipv6; ++ union { ++ struct udp_hdr udp; ++ } layer4_prot; ++}; ++ ++struct packet_ipv6_vlan { ++ struct mac_address dest_mac; ++ struct mac_address src_mac; ++ u16_t len_type; ++ u16_t vlan_id; ++ struct ipv6_hdr ipv6; ++ union { ++ struct udp_hdr udp; ++ } layer4_prot; ++}; ++ ++struct ipv6_arp_entry { ++ struct ipv6_addr ip_addr; ++ struct mac_address mac_addr; ++ u8_t time; ++}; ++ ++#define IPV6_NUM_OF_ADDRESS_ENTRY 4 ++ ++struct ipv6_prefix_entry { ++ struct ipv6_prefix_entry *next; ++ struct ipv6_addr ip_addr; ++ u8_t prefix_len; ++}; ++ ++struct ipv6_addr_entry { ++ struct ipv6_addr ip_addr; ++ u8_t prefix_len; ++}; ++ ++struct ipv6_context { ++ u16_t flags; ++#define IPV6_FLAGS_MANAGED_ADDR_CONFIG (1 << 0) ++#define IPV6_FLAGS_OTHER_STATEFUL_CONFIG (1 << 1) ++#define IPV6_FLAGS_ROUTER_ADV_RECEIVED (1 << 2) ++#define IPV6_FLAGS_DISABLE_DHCPV6 (1 << 3) ++ ++ struct mac_address mac_addr; ++ struct ipv6_addr link_local_addr; ++ struct ipv6_addr link_local_multi; ++ struct ipv6_addr multi; /* For Static IPv6 only */ ++ struct ipv6_addr multi_dest; /* For Static IPv6 only */ ++ struct ipv6_addr default_router; ++ struct ipv6_prefix_entry *addr_list; ++ u8_t hop_limit; ++#define UIP_ARPTAB_SIZE 8 ++ ++ struct uip_stack *ustack; ++#define MAX_MCADDR_TABLE 5 ++ struct mac_address mc_addr[MAX_MCADDR_TABLE]; ++ u8_t arptime; ++ struct ipv6_arp_entry ipv6_arp_table[UIP_ARPTAB_SIZE]; ++ struct ipv6_prefix_entry ipv6_prefix_table[IPV6_NUM_OF_ADDRESS_ENTRY]; ++ ++ /* VLAN support */ ++ ++ void *dhcpv6_context; ++}; ++ ++#define ISCSI_FLAGS_DHCP_TCPIP_CONFIG (1<<0) ++#define ISCSI_FLAGS_DHCP_ISCSI_CONFIG (1<<1) ++ ++#define IPV6_MAX_ROUTER_SOL_DELAY 4 ++#define IPV6_MAX_ROUTER_SOL_RETRY 3 ++ ++#define DHCPV6_CLIENT_PORT 546 ++#define DHCPV6_SERVER_PORT 547 ++ ++/* Function prototype */ ++void ipv6_init(struct ndpc_state *ndp, int cfg); ++int ipv6_autoconfig(struct ipv6_context *context); ++int ipv6_discover_address(struct ipv6_context *context); ++struct ipv6_addr *ipv6_our_address(struct ipv6_context *context); ++int ipv6_ip_in_arp_table(struct ipv6_context *context, ++ struct ipv6_addr *ipv6_addr, ++ struct mac_address *mac_addr); ++void ipv6_arp_timer(struct ipv6_context *context); ++void ipv6_arp_out(struct ipv6_context *context, int *uip_len); ++int ipv6_add_prefix_entry(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr, u8_t prefix_len); ++void ipv6_set_ip_params(struct ipv6_context *context, ++ struct ipv6_addr *src_ip, u8_t prefix_len, ++ struct ipv6_addr *default_gateway, ++ struct ipv6_addr *linklocal); ++void ipv6_set_host_addr(struct ipv6_context *context, struct ipv6_addr *src_ip); ++int ipv6_get_default_router_ip_addrs(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr); ++struct mac_address *ipv6_get_link_addr(struct ipv6_context *context); ++u16_t ipv6_do_stateful_dhcpv6(struct ipv6_context *context, u32_t flags); ++void ipv6_add_solit_node_address(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr); ++int ipv6_get_source_ip_addrs(struct ipv6_context *context, ++ struct ipv6_addr_entry *addr_list); ++void ipv6_cfg_link_local_addr(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr); ++void ipv6_disable_dhcpv6(struct ipv6_context *context); ++int ipv6_send_nd_solicited_packet(struct ipv6_context *context, ++ struct eth_hdr *eth, struct ipv6_hdr *ipv6); ++int ipv6_is_it_our_link_local_address(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr); ++void ipv6_mc_init_dest_mac(struct eth_hdr *eth, struct ipv6_hdr *ipv6); ++struct ipv6_addr *ipv6_find_longest_match(struct ipv6_context *context, ++ struct ipv6_addr *ip_addr); ++ ++#endif /* __IPV6_H__ */ +diff --git a/iscsiuio/src/uip/ipv6_ndpc.c b/iscsiuio/src/uip/ipv6_ndpc.c +new file mode 100644 +index 0000000..a396cb7 +--- /dev/null ++++ b/iscsiuio/src/uip/ipv6_ndpc.c +@@ -0,0 +1,427 @@ ++/* ++ * Copyright (c) 2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Eddie Wai (eddie.wai@broadcom.com) ++ * Based on the Swedish Institute of Computer Science's ++ * dhcpc.c code ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ipv6_ndpc.c - Top level IPv6 Network Discovery Protocol Engine (RFC4861) ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "uip.h" ++#include "ipv6_ndpc.h" ++#include "timer.h" ++#include "pt.h" ++ ++#include "debug.h" ++#include "logger.h" ++#include "nic.h" ++#include "nic_utils.h" ++#include "ipv6.h" ++#include "ipv6_pkt.h" ++#include "dhcpv6.h" ++ ++const int dhcpv6_retry_timeout[DHCPV6_NUM_OF_RETRY] = { 1, 2, 4, 8 }; ++ ++static PT_THREAD(handle_ndp(struct uip_stack *ustack, int force)) ++{ ++ struct ndpc_state *s; ++ struct ipv6_context *ipv6c; ++ struct dhcpv6_context *dhcpv6c = NULL; ++ u16_t task = 0; ++ char buf[INET6_ADDRSTRLEN]; ++ ++ s = ustack->ndpc; ++ if (s == NULL) { ++ LOG_DEBUG("NDP: Could not find ndpc state"); ++ return PT_ENDED; ++ } ++ ++ ipv6c = s->ipv6_context; ++ if (!ipv6c) ++ goto ndpc_state_null; ++ ++ dhcpv6c = s->dhcpv6_context; ++ ++ PT_BEGIN(&s->pt); ++ ++ if (s->state == NDPC_STATE_BACKGROUND_LOOP) ++ goto ipv6_loop; ++ ++ if (s->state == NDPC_STATE_RTR_ADV) ++ goto rtr_adv; ++ ++ /* For AUTOCFG == DHCPv6, do all ++ For == ND, skip DHCP only and do RTR ++ For == UNUSED/UNSPEC, do all as according to DHCP or not */ ++ s->state = NDPC_STATE_RTR_SOL; ++ /* try_again: */ ++ s->ticks = CLOCK_SECOND * IPV6_MAX_ROUTER_SOL_DELAY; ++ s->retry_count = 0; ++ do { ++ /* Perform router solicitation and wait for ++ router advertisement */ ++ LOG_DEBUG("%s: ndpc_handle send rtr sol", s->nic->log_name); ++ ipv6_autoconfig(s->ipv6_context); ++ ++ timer_set(&s->timer, s->ticks); ++wait_rtr: ++ s->ustack->uip_flags &= ~UIP_NEWDATA; ++ LOG_DEBUG("%s: ndpc_handle wait for rtr adv flags=0x%x", ++ s->nic->log_name, ipv6c->flags); ++ PT_WAIT_UNTIL(&s->pt, uip_newdata(s->ustack) ++ || timer_expired(&s->timer) || force); ++ ++ if (uip_newdata(s->ustack)) { ++ /* Validate incoming packets ++ Note that the uip_len is init from nic loop */ ++ ipv6_rx_packet(ipv6c, (u16_t) uip_datalen(s->ustack)); ++ if (ipv6c->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED) { ++ LOG_INFO("%s: ROUTER_ADV_RECEIVED", ++ s->nic->log_name); ++ /* Success */ ++ break; ++ } else if (!timer_expired(&s->timer)) { ++ /* Yes new data, but not what we want, ++ check for timer expiration before bumping ++ tick */ ++ goto wait_rtr; ++ } ++ } ++ s->retry_count++; ++ if (s->retry_count >= IPV6_MAX_ROUTER_SOL_RETRY) ++ /* Max router solicitation retry reached. Move to ++ IPv6 loop (no DHCPv6) */ ++ goto no_rtr_adv; ++ ++ } while (!(ipv6c->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED)); ++ ++ LOG_DEBUG("%s: ndpc_handle got rtr adv", s->nic->log_name); ++ ++no_rtr_adv: ++ s->state = NDPC_STATE_RTR_ADV; ++ ++rtr_adv: ++ if (!(ustack->ip_config & IPV6_CONFIG_DHCP)) ++ goto staticv6; ++ ++ /* Only DHCPv6 comes here */ ++ task = ipv6_do_stateful_dhcpv6(ipv6c, ISCSI_FLAGS_DHCP_TCPIP_CONFIG); ++ if (task) { ++ /* Run the DHCPv6 engine */ ++ ++ if (!dhcpv6c) ++ goto ipv6_loop; ++ ++ dhcpv6c->dhcpv6_task = task; ++ s->retry_count = 0; ++ s->state = NDPC_STATE_DHCPV6_DIS; ++ do { ++ /* Do dhcpv6 */ ++ dhcpv6c->timeout = dhcpv6_retry_timeout[s->retry_count]; ++ s->ticks = CLOCK_SECOND * dhcpv6c->timeout; ++ LOG_DEBUG("%s: ndpc_handle send dhcpv6 sol retry " ++ "cnt=%d", s->nic->log_name, s->retry_count); ++ dhcpv6_do_discovery(dhcpv6c); ++ ++ timer_set(&s->timer, s->ticks); ++wait_dhcp: ++ s->ustack->uip_flags &= ~UIP_NEWDATA; ++ PT_WAIT_UNTIL(&s->pt, uip_newdata(s->ustack) ++ || timer_expired(&s->timer) || force); ++ ++ if (uip_newdata(s->ustack)) { ++ /* Validate incoming packets ++ Note that the uip_len is init from nic ++ loop */ ++ ipv6_rx_packet(ipv6c, ++ (u16_t) uip_datalen(s->ustack)); ++ if (dhcpv6c->dhcpv6_done == TRUE) ++ break; ++ else if (!timer_expired(&s->timer)) { ++ /* Yes new data, but not what we want, ++ check for timer expiration before ++ bumping tick */ ++ goto wait_dhcp; ++ } ++ } ++ s->retry_count++; ++ if (s->retry_count < DHCPV6_NUM_OF_RETRY) { ++ dhcpv6c->seconds += dhcpv6c->timeout; ++ } else { ++ LOG_DEBUG("%s: ndpc_handle DHCP failed", ++ s->nic->log_name); ++ /* Allow to goto background loop */ ++ goto ipv6_loop; ++ } ++ } while (dhcpv6c->dhcpv6_done == FALSE); ++ s->state = NDPC_STATE_DHCPV6_DONE; ++ ++ LOG_DEBUG("%s: ndpc_handle got dhcpv6", s->nic->log_name); ++ ++ /* End of DHCPv6 engine */ ++ } else { ++ /* Static IPv6 */ ++ if (ustack->ip_config == IPV6_CONFIG_DHCP) { ++ LOG_DEBUG("%s: ndpc_handle DHCP failed", ++ s->nic->log_name); ++ PT_RESTART(&s->pt); ++ } ++staticv6: ++ ipv6_disable_dhcpv6(ipv6c); ++ } ++ /* Copy out the default_router_addr6 and ll */ ++ if (ustack->router_autocfg != IPV6_RTR_AUTOCFG_OFF) ++ memcpy(&ustack->default_route_addr6, ++ &ipv6c->default_router, sizeof(struct ipv6_addr)); ++ inet_ntop(AF_INET6, &ustack->default_route_addr6, ++ buf, sizeof(buf)); ++ LOG_INFO("%s: Default router IP: %s", s->nic->log_name, ++ buf); ++ ++ if (ustack->linklocal_autocfg != IPV6_LL_AUTOCFG_OFF) ++ memcpy(&ustack->linklocal6, &ipv6c->link_local_addr, ++ sizeof(struct ipv6_addr)); ++ inet_ntop(AF_INET6, &ustack->linklocal6, ++ buf, sizeof(buf)); ++ LOG_INFO("%s: Linklocal IP: %s", s->nic->log_name, ++ buf); ++ ++ipv6_loop: ++ s->state = NDPC_STATE_BACKGROUND_LOOP; ++ LOG_DEBUG("%s: Loop", s->nic->log_name); ++ /* Background IPv6 loop */ ++ while (1) { ++ /* Handle all neightbor solicitation/advertisement here */ ++ s->ustack->uip_flags &= ~UIP_NEWDATA; ++ PT_WAIT_UNTIL(&s->pt, uip_newdata(s->ustack)); ++ ++ /* Validate incoming packets */ ++ ipv6_rx_packet(ipv6c, (u16_t) uip_datalen(s->ustack)); ++ } ++ ++ndpc_state_null: ++ ++ while (1) ++ PT_YIELD(&s->pt); ++ ++ PT_END(&(s->pt)); ++} ++ ++/*---------------------------------------------------------------------------*/ ++int ndpc_init(nic_t *nic, struct uip_stack *ustack, ++ const void *mac_addr, int mac_len) ++{ ++ struct ipv6_context *ipv6c; ++ struct dhcpv6_context *dhcpv6c; ++ struct ndpc_state *s = ustack->ndpc; ++ struct ipv6_addr src, gw, ll; ++ char buf[INET6_ADDRSTRLEN]; ++ ++ if (s) { ++ LOG_DEBUG("NDP: NDP context already allocated"); ++ /* Already allocated, skip*/ ++ return -EALREADY; ++ } ++ s = malloc(sizeof(*s)); ++ if (s == NULL) { ++ LOG_ERR("%s: Couldn't allocate size for ndpc info", ++ nic->log_name); ++ goto error; ++ } ++ memset(s, 0, sizeof(*s)); ++ ++ if (s->ipv6_context) { ++ LOG_DEBUG("NDP: IPv6 context already allocated"); ++ ipv6c = s->ipv6_context; ++ goto init1; ++ } ++ ipv6c = malloc(sizeof(struct ipv6_context)); ++ if (ipv6c == NULL) { ++ LOG_ERR("%s: Couldn't allocate mem for IPv6 context info", ++ nic->log_name); ++ goto error1; ++ } ++init1: ++ if (s->dhcpv6_context) { ++ LOG_DEBUG("NDP: DHCPv6 context already allocated"); ++ dhcpv6c = s->dhcpv6_context; ++ goto init2; ++ } ++ dhcpv6c = malloc(sizeof(struct dhcpv6_context)); ++ if (dhcpv6c == NULL) { ++ LOG_ERR("%s: Couldn't allocate mem for DHCPv6 context info", ++ nic->log_name); ++ goto error2; ++ } ++init2: ++ memset(s, 0, sizeof(*s)); ++ memset(ipv6c, 0, sizeof(*ipv6c)); ++ memset(dhcpv6c, 0, sizeof(*dhcpv6c)); ++ ++ s->ipv6_context = ipv6c; ++ s->dhcpv6_context = dhcpv6c; ++ ++ s->nic = nic; ++ s->ustack = ustack; ++ s->mac_addr = (void *)mac_addr; ++ s->mac_len = mac_len; ++ s->state = NDPC_STATE_INIT; ++ ++ /* Init IPV6_CONTEXT */ ++ ipv6_init(s, ustack->ip_config); ++ ++ dhcpv6c->ipv6_context = ipv6c; ++ ipv6c->dhcpv6_context = dhcpv6c; ++ ++ /* Init DHCPV6_CONTEXT */ ++ dhcpv6_init(dhcpv6c); ++ ++ ustack->ndpc = s; ++ ++ PT_INIT(&s->pt); ++ ++ if (ustack->ip_config == IPV6_CONFIG_DHCP) { ++ /* DHCPv6 specific */ ++ memset(&src, 0, sizeof(src)); ++ } else { ++ /* Static v6 specific */ ++ memcpy(&src.addr8, &ustack->hostaddr6, ++ sizeof(struct ipv6_addr)); ++ ipv6_add_solit_node_address(ipv6c, &src); ++ ++ inet_ntop(AF_INET6, &src.addr8, buf, sizeof(buf)); ++ LOG_INFO("%s: Static hostaddr IP: %s", s->nic->log_name, ++ buf); ++ } ++ /* Copy out the default_router_addr6 and ll */ ++ if (ustack->router_autocfg == IPV6_RTR_AUTOCFG_OFF) ++ memcpy(&gw.addr8, &ustack->default_route_addr6, ++ sizeof(struct ipv6_addr)); ++ else ++ memset(&gw, 0, sizeof(gw)); ++ ++ if (ustack->linklocal_autocfg == IPV6_LL_AUTOCFG_OFF) ++ memcpy(&ll.addr8, &ustack->linklocal6, ++ sizeof(struct ipv6_addr)); ++ else ++ memset(&ll, 0, sizeof(ll)); ++ ipv6_set_ip_params(ipv6c, &src, ++ ustack->prefix_len, &gw, &ll); ++ ++ return 0; ++error2: ++ free(ipv6c); ++ s->ipv6_context = NULL; ++error1: ++ free(s); ++ ustack->ndpc = NULL; ++error: ++ return -ENOMEM; ++} ++ ++/*---------------------------------------------------------------------------*/ ++void ndpc_call(struct uip_stack *ustack) ++{ ++ handle_ndp(ustack, 0); ++} ++ ++void ndpc_exit(struct ndpc_state *ndp) ++{ ++ LOG_DEBUG("NDP - Exit ndpc_state = %p", ndp); ++ if (!ndp) ++ return; ++ if (ndp->ipv6_context) ++ free(ndp->ipv6_context); ++ if (ndp->dhcpv6_context) ++ free(ndp->dhcpv6_context); ++ free(ndp); ++} ++ ++int ndpc_request(struct uip_stack *ustack, void *in, void *out, int request) ++{ ++ struct ndpc_state *s; ++ struct ipv6_context *ipv6c; ++ int ret = 0; ++ ++ if (!ustack) { ++ LOG_DEBUG("NDP: ustack == NULL"); ++ return -EINVAL; ++ } ++ s = ustack->ndpc; ++ if (s == NULL) { ++ LOG_DEBUG("NDP: Could not find ndpc state for request %d", ++ request); ++ return -EINVAL; ++ } ++ while (s->state != NDPC_STATE_BACKGROUND_LOOP) { ++ LOG_DEBUG("%s: ndpc state not in background loop, run handler " ++ "request = %d", s->nic->log_name, request); ++ handle_ndp(ustack, 1); ++ } ++ ++ ipv6c = s->ipv6_context; ++ switch (request) { ++ case NEIGHBOR_SOLICIT: ++ *(int *)out = ipv6_send_nd_solicited_packet(ipv6c, ++ (struct eth_hdr *)((struct ndpc_reqptr *)in)->eth, ++ (struct ipv6_hdr *)((struct ndpc_reqptr *)in)->ipv6); ++ break; ++ case CHECK_LINK_LOCAL_ADDR: ++ *(int *)out = ipv6_is_it_our_link_local_address(ipv6c, ++ (struct ipv6_addr *)in); ++ break; ++ case CHECK_ARP_TABLE: ++ *(int *)out = ipv6_ip_in_arp_table(ipv6c, ++ (struct ipv6_addr *)((struct ndpc_reqptr *)in)->ipv6, ++ (struct mac_address *)((struct ndpc_reqptr *)in)->eth); ++ break; ++ case GET_HOST_ADDR: ++ *(struct ipv6_addr **)out = ipv6_find_longest_match(ipv6c, ++ (struct ipv6_addr *)in); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++/*---------------------------------------------------------------------------*/ +diff --git a/iscsiuio/src/uip/ipv6_ndpc.h b/iscsiuio/src/uip/ipv6_ndpc.h +new file mode 100644 +index 0000000..709a050 +--- /dev/null ++++ b/iscsiuio/src/uip/ipv6_ndpc.h +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (c) 2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Eddie Wai (eddie.wai@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ipv6_ndpc.h - Top level IPv6 Network Discovery Protocol Engine (RFC4861) ++ * ++ */ ++#ifndef __NDPC_H__ ++#define __NDPC_H__ ++ ++#include ++ ++#include "nic.h" ++#include "timer.h" ++#include "pt.h" ++ ++struct ndpc_reqptr { ++ void *eth; ++ void *ipv6; ++}; ++ ++struct ndpc_state { ++ struct pt pt; ++ ++ nic_t *nic; ++ struct uip_stack *ustack; ++ char state; ++ struct timer timer; ++ u16_t ticks; ++ void *mac_addr; ++ int mac_len; ++ int retry_count; ++ ++ time_t last_update; ++ ++ void *ipv6_context; ++ void *dhcpv6_context; ++}; ++ ++enum { ++ NDPC_STATE_INIT, ++ NDPC_STATE_RTR_SOL, ++ NDPC_STATE_RTR_ADV, ++ NDPC_STATE_DHCPV6_DIS, ++ NDPC_STATE_DHCPV6_DONE, ++ NDPC_STATE_BACKGROUND_LOOP ++}; ++ ++int ndpc_init(nic_t *nic, struct uip_stack *ustack, ++ const void *mac_addr, int mac_len); ++void ndpc_call(struct uip_stack *ustack); ++void ndpc_exit(struct ndpc_state *ndp); ++ ++enum { ++ NEIGHBOR_SOLICIT, ++ CHECK_LINK_LOCAL_ADDR, ++ GET_LINK_LOCAL_ADDR, ++ GET_DEFAULT_ROUTER_ADDR, ++ CHECK_ARP_TABLE, ++ GET_HOST_ADDR ++}; ++ ++int ndpc_request(struct uip_stack *ustack, void *in, void *out, int request); ++ ++#define UIP_NDP_CALL ndpc_call ++ ++#endif /* __NDPC_H__ */ +diff --git a/iscsiuio/src/uip/ipv6_pkt.h b/iscsiuio/src/uip/ipv6_pkt.h +new file mode 100644 +index 0000000..b42f1aa +--- /dev/null ++++ b/iscsiuio/src/uip/ipv6_pkt.h +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (c) 2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Eddie Wai (eddie.wai@broadcom.com) ++ * Based on Kevin Tran's iSCSI boot code ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ipv6_packet.h - IPv6 routine include file ++ * ++ */ ++#ifndef __IPV6_PKT_H__ ++#define __IPV6_PKT_H__ ++ ++u16_t ipv6_process_rx(struct ipv6_hdr *ipv6); ++void ipv6_rx_packet(struct ipv6_context *context, u16_t len); ++void ipv6_setup_hdrs(struct ipv6_context *context, struct eth_hdr *eth, ++ struct ipv6_hdr *ipv6, u16_t packet_len); ++int ipv6_send(struct ipv6_context *context, u16_t packet_len); ++void ipv6_send_udp_packet(struct ipv6_context *context, u16_t packet_len); ++ ++#endif /* __IPV6_PKT_H__ */ +diff --git a/iscsiuio/src/uip/lc-addrlabels.h b/iscsiuio/src/uip/lc-addrlabels.h +new file mode 100644 +index 0000000..c394b22 +--- /dev/null ++++ b/iscsiuio/src/uip/lc-addrlabels.h +@@ -0,0 +1,80 @@ ++/* ++ * Copyright (c) 2004-2005, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ * Author: Adam Dunkels ++ * ++ */ ++ ++/** ++ * \addtogroup lc ++ * @{ ++ */ ++ ++/** ++ * \file ++ * Implementation of local continuations based on the "Labels as ++ * values" feature of gcc ++ * \author ++ * Adam Dunkels ++ * ++ * This implementation of local continuations is based on a special ++ * feature of the GCC C compiler called "labels as values". This ++ * feature allows assigning pointers with the address of the code ++ * corresponding to a particular C label. ++ * ++ * For more information, see the GCC documentation: ++ * http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html ++ * ++ * Thanks to dividuum for finding the nice local scope label ++ * implementation. ++ */ ++ ++#ifndef __LC_ADDRLABELS_H__ ++#define __LC_ADDRLABELS_H__ ++ ++/** \hideinitializer */ ++ ++#define LC_INIT(s) (s = NULL) ++ ++#define LC_RESUME(s) \ ++ do { \ ++ if (s != NULL) { \ ++ goto *s; \ ++ } \ ++ } while (0) ++ ++#define LC_SET(s) \ ++ do { ({ __label__ resume; resume: (s) = &&resume; }); } while (0) ++ ++#define LC_END(s) ++ ++#endif /* __LC_ADDRLABELS_H__ */ ++ ++/** @} */ +diff --git a/iscsiuio/src/uip/lc-switch.h b/iscsiuio/src/uip/lc-switch.h +new file mode 100644 +index 0000000..1839b36 +--- /dev/null ++++ b/iscsiuio/src/uip/lc-switch.h +@@ -0,0 +1,73 @@ ++/* ++ * Copyright (c) 2004-2005, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ * Author: Adam Dunkels ++ * ++ */ ++ ++/** ++ * \addtogroup lc ++ * @{ ++ */ ++ ++/** ++ * \file ++ * Implementation of local continuations based on switch() statment ++ * \author Adam Dunkels ++ * ++ * This implementation of local continuations uses the C switch() ++ * statement to resume execution of a function somewhere inside the ++ * function's body. The implementation is based on the fact that ++ * switch() statements are able to jump directly into the bodies of ++ * control structures such as if() or while() statmenets. ++ * ++ * This implementation borrows heavily from Simon Tatham's coroutines ++ * implementation in C: ++ * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html ++ */ ++ ++#ifndef __LC_SWITCH_H__ ++#define __LC_SWTICH_H__ ++ ++/* WARNING! lc implementation using switch() does not work if an ++ LC_SET() is done within another switch() statement! */ ++ ++/** \hideinitializer */ ++#define LC_INIT(s) s = 0; ++ ++#define LC_RESUME(s) switch (s) { case 0: ++ ++#define LC_SET(s) s = __LINE__; case __LINE__: ++ ++#define LC_END(s) } ++ ++#endif /* __LC_SWITCH_H__ */ ++ ++/** @} */ +diff --git a/iscsiuio/src/uip/lc.h b/iscsiuio/src/uip/lc.h +new file mode 100644 +index 0000000..2e4a7bb +--- /dev/null ++++ b/iscsiuio/src/uip/lc.h +@@ -0,0 +1,130 @@ ++/* ++ * Copyright (c) 2004-2005, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ * Author: Adam Dunkels ++ * ++ */ ++ ++/** ++ * \addtogroup pt ++ * @{ ++ */ ++ ++/** ++ * \defgroup lc Local continuations ++ * @{ ++ * ++ * Local continuations form the basis for implementing protothreads. A ++ * local continuation can be set in a specific function to ++ * capture the state of the function. After a local continuation has ++ * been set can be resumed in order to restore the state of the ++ * function at the point where the local continuation was set. ++ * ++ * ++ */ ++ ++/** ++ * \file lc.h ++ * Local continuations ++ * \author ++ * Adam Dunkels ++ * ++ */ ++ ++#ifdef DOXYGEN ++/** ++ * Initialize a local continuation. ++ * ++ * This operation initializes the local continuation, thereby ++ * unsetting any previously set continuation state. ++ * ++ * \hideinitializer ++ */ ++#define LC_INIT(lc) ++ ++/** ++ * Set a local continuation. ++ * ++ * The set operation saves the state of the function at the point ++ * where the operation is executed. As far as the set operation is ++ * concerned, the state of the function does not include the ++ * call-stack or local (automatic) variables, but only the program ++ * counter and such CPU registers that needs to be saved. ++ * ++ * \hideinitializer ++ */ ++#define LC_SET(lc) ++ ++/** ++ * Resume a local continuation. ++ * ++ * The resume operation resumes a previously set local continuation, thus ++ * restoring the state in which the function was when the local ++ * continuation was set. If the local continuation has not been ++ * previously set, the resume operation does nothing. ++ * ++ * \hideinitializer ++ */ ++#define LC_RESUME(lc) ++ ++/** ++ * Mark the end of local continuation usage. ++ * ++ * The end operation signifies that local continuations should not be ++ * used any more in the function. This operation is not needed for ++ * most implementations of local continuation, but is required by a ++ * few implementations. ++ * ++ * \hideinitializer ++ */ ++#define LC_END(lc) ++ ++/** ++ * \var typedef lc_t; ++ * ++ * The local continuation type. ++ * ++ * \hideinitializer ++ */ ++#endif /* DOXYGEN */ ++ ++#ifndef __LC_H__ ++#define __LC_H__ ++ ++#ifdef LC_CONF_INCLUDE ++#include LC_CONF_INCLUDE ++#else ++#include "lc-switch.h" ++#endif /* LC_CONF_INCLUDE */ ++ ++#endif /* __LC_H__ */ ++ ++/** @} */ ++/** @} */ +diff --git a/iscsiuio/src/uip/psock.c b/iscsiuio/src/uip/psock.c +new file mode 100644 +index 0000000..fcffbe7 +--- /dev/null ++++ b/iscsiuio/src/uip/psock.c +@@ -0,0 +1,339 @@ ++/* ++ * Copyright (c) 2004, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ * Author: Adam Dunkels ++ * ++ */ ++ ++#include ++#include ++ ++#include "uipopt.h" ++#include "psock.h" ++#include "uip.h" ++ ++#define STATE_NONE 0 ++#define STATE_ACKED 1 ++#define STATE_READ 2 ++#define STATE_BLOCKED_NEWDATA 3 ++#define STATE_BLOCKED_CLOSE 4 ++#define STATE_BLOCKED_SEND 5 ++#define STATE_DATA_SENT 6 ++ ++/* ++ * Return value of the buffering functions that indicates that a ++ * buffer was not filled by incoming data. ++ * ++ */ ++#define BUF_NOT_FULL 0 ++#define BUF_NOT_FOUND 0 ++ ++/* ++ * Return value of the buffering functions that indicates that a ++ * buffer was completely filled by incoming data. ++ * ++ */ ++#define BUF_FULL 1 ++ ++/* ++ * Return value of the buffering functions that indicates that an ++ * end-marker byte was found. ++ * ++ */ ++#define BUF_FOUND 2 ++ ++/*---------------------------------------------------------------------------*/ ++static void buf_setup(struct psock_buf *buf, u8_t *bufptr, u16_t bufsize) ++{ ++ buf->ptr = bufptr; ++ buf->left = bufsize; ++} ++ ++/*---------------------------------------------------------------------------*/ ++static u8_t ++buf_bufdata(struct psock_buf *buf, u16_t len, u8_t **dataptr, u16_t *datalen) ++{ ++ if (*datalen < buf->left) { ++ memcpy(buf->ptr, *dataptr, *datalen); ++ buf->ptr += *datalen; ++ buf->left -= *datalen; ++ *dataptr += *datalen; ++ *datalen = 0; ++ return BUF_NOT_FULL; ++ } else if (*datalen == buf->left) { ++ memcpy(buf->ptr, *dataptr, *datalen); ++ buf->ptr += *datalen; ++ buf->left = 0; ++ *dataptr += *datalen; ++ *datalen = 0; ++ return BUF_FULL; ++ } else { ++ memcpy(buf->ptr, *dataptr, buf->left); ++ buf->ptr += buf->left; ++ *datalen -= buf->left; ++ *dataptr += buf->left; ++ buf->left = 0; ++ return BUF_FULL; ++ } ++} ++ ++/*---------------------------------------------------------------------------*/ ++static u8_t ++buf_bufto(register struct psock_buf *buf, u8_t endmarker, ++ register u8_t **dataptr, register u16_t *datalen) ++{ ++ u8_t c; ++ while (buf->left > 0 && *datalen > 0) { ++ c = *buf->ptr = **dataptr; ++ ++*dataptr; ++ ++buf->ptr; ++ --*datalen; ++ --buf->left; ++ ++ if (c == endmarker) ++ return BUF_FOUND; ++ } ++ ++ if (*datalen == 0) ++ return BUF_NOT_FOUND; ++ ++ while (*datalen > 0) { ++ c = **dataptr; ++ --*datalen; ++ ++*dataptr; ++ ++ if (c == endmarker) ++ return BUF_FOUND | BUF_FULL; ++ } ++ ++ return BUF_FULL; ++} ++ ++/*---------------------------------------------------------------------------*/ ++static char send_data(register struct psock *s) ++{ ++ if (s->state != STATE_DATA_SENT || uip_rexmit(s->ustack)) { ++ if (s->sendlen > uip_mss(s->ustack)) ++ uip_appsend(s->ustack, s->sendptr, uip_mss(s->ustack)); ++ else ++ uip_appsend(s->ustack, s->sendptr, s->sendlen); ++ s->state = STATE_DATA_SENT; ++ return 1; ++ } ++ return 0; ++} ++ ++/*---------------------------------------------------------------------------*/ ++static char data_acked(struct psock *s) ++{ ++ if (s->state == STATE_DATA_SENT && uip_acked(s->ustack)) { ++ if (s->sendlen > uip_mss(s->ustack)) { ++ s->sendlen -= uip_mss(s->ustack); ++ s->sendptr += uip_mss(s->ustack); ++ } else { ++ s->sendptr += s->sendlen; ++ s->sendlen = 0; ++ } ++ s->state = STATE_ACKED; ++ return 1; ++ } ++ return 0; ++} ++ ++/*---------------------------------------------------------------------------*/ ++PT_THREAD(psock_send(struct uip_stack *ustack, ++ register struct psock *s, const u8_t *buf, ++ unsigned int len)) ++{ ++ PT_BEGIN(&s->psockpt); ++ ++ /* If there is no data to send, we exit immediately. */ ++ if (len == 0) { ++ PT_EXIT(&s->psockpt); ++ } ++ ++ /* Save the length of and a pointer to the data that is to be ++ sent. */ ++ s->sendptr = buf; ++ s->sendlen = len; ++ ++ s->state = STATE_NONE; ++ ++ /* We loop here until all data is sent. The s->sendlen variable is ++ updated by the data_sent() function. */ ++ while (s->sendlen > 0) { ++ ++ /* ++ * The condition for this PT_WAIT_UNTIL is a little tricky: the ++ * protothread will wait here until all data has been acked ++ * (data_acked() returns true) and until all data has been sent ++ * (send_data() returns true). The two functions data_acked() ++ * and send_data() must be called in succession to ensure that ++ * all data is sent. Therefore the & operator is used instead of ++ * the && operator, which would cause only the data_acked() ++ * function to be called when it returns false. ++ */ ++ PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s)); ++ } ++ ++ s->state = STATE_NONE; ++ ++ PT_END(&s->psockpt); ++} ++ ++/*---------------------------------------------------------------------------*/ ++PT_THREAD(psock_generator_send(register struct psock *s, ++ unsigned short (*generate) (void *), void *arg)) ++{ ++ PT_BEGIN(&s->psockpt); ++ ++ /* Ensure that there is a generator function to call. */ ++ if (generate == NULL) { ++ PT_EXIT(&s->psockpt); ++ } ++ ++ /* Call the generator function to generate the data in the ++ uip_appdata buffer. */ ++ s->sendlen = generate(arg); ++ s->sendptr = s->ustack->uip_appdata; ++ ++ s->state = STATE_NONE; ++ do { ++ /* Call the generator function again if we are called to perform ++ a retransmission. */ ++ if (uip_rexmit(s->ustack)) ++ generate(arg); ++ /* Wait until all data is sent and acknowledged. */ ++ PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s)); ++ } while (s->sendlen > 0); ++ ++ s->state = STATE_NONE; ++ ++ PT_END(&s->psockpt); ++} ++ ++/*---------------------------------------------------------------------------*/ ++u16_t psock_datalen(struct psock *psock) ++{ ++ return psock->bufsize - psock->buf.left; ++} ++ ++/*---------------------------------------------------------------------------*/ ++char psock_newdata(struct psock *s) ++{ ++ if (s->readlen > 0) { ++ /* There is data in the uip_appdata buffer that has not yet been ++ read with the PSOCK_READ functions. */ ++ return 1; ++ } else if (s->state == STATE_READ) { ++ /* All data in uip_appdata buffer already consumed. */ ++ s->state = STATE_BLOCKED_NEWDATA; ++ return 0; ++ } else if (uip_newdata(s->ustack)) { ++ /* There is new data that has not been consumed. */ ++ return 1; ++ } else { ++ /* There is no new data. */ ++ return 0; ++ } ++} ++ ++/*---------------------------------------------------------------------------*/ ++PT_THREAD(psock_readto(register struct psock *psock, u8_t c)) ++{ ++ PT_BEGIN(&psock->psockpt); ++ ++ buf_setup(&psock->buf, psock->bufptr, psock->bufsize); ++ ++ /* XXX: Should add buf_checkmarker() before do{} loop, if ++ incoming data has been handled while waiting for a write. */ ++ ++ do { ++ if (psock->readlen == 0) { ++ PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock)); ++ psock->state = STATE_READ; ++ psock->readptr = (u8_t *) psock->ustack->uip_appdata; ++ psock->readlen = uip_datalen(psock->ustack); ++ } ++ } while ((buf_bufto(&psock->buf, c, ++ &psock->readptr, ++ &psock->readlen) & BUF_FOUND) == 0); ++ ++ if (psock_datalen(psock) == 0) { ++ psock->state = STATE_NONE; ++ PT_RESTART(&psock->psockpt); ++ } ++ PT_END(&psock->psockpt); ++} ++ ++/*---------------------------------------------------------------------------*/ ++PT_THREAD(psock_readbuf(register struct psock *psock)) ++{ ++ PT_BEGIN(&psock->psockpt); ++ ++ buf_setup(&psock->buf, psock->bufptr, psock->bufsize); ++ ++ /* XXX: Should add buf_checkmarker() before do{} loop, if ++ incoming data has been handled while waiting for a write. */ ++ ++ do { ++ if (psock->readlen == 0) { ++ PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock)); ++ printf("Waited for newdata\n"); ++ psock->state = STATE_READ; ++ psock->readptr = (u8_t *) psock->ustack->uip_appdata; ++ psock->readlen = uip_datalen(psock->ustack); ++ } ++ } while (buf_bufdata(&psock->buf, psock->bufsize, ++ &psock->readptr, &psock->readlen) != BUF_FULL); ++ ++ if (psock_datalen(psock) == 0) { ++ psock->state = STATE_NONE; ++ PT_RESTART(&psock->psockpt); ++ } ++ PT_END(&psock->psockpt); ++} ++ ++/*---------------------------------------------------------------------------*/ ++void ++psock_init(struct uip_stack *ustack, ++ register struct psock *psock, u8_t *buffer, unsigned int buffersize) ++{ ++ psock->state = STATE_NONE; ++ psock->readlen = 0; ++ psock->bufptr = buffer; ++ psock->bufsize = buffersize; ++ psock->ustack = ustack; ++ buf_setup(&psock->buf, buffer, buffersize); ++ PT_INIT(&psock->pt); ++ PT_INIT(&psock->psockpt); ++} ++ ++/*---------------------------------------------------------------------------*/ +diff --git a/iscsiuio/src/uip/psock.h b/iscsiuio/src/uip/psock.h +new file mode 100644 +index 0000000..ea86ef5 +--- /dev/null ++++ b/iscsiuio/src/uip/psock.h +@@ -0,0 +1,383 @@ ++/* ++ * Copyright (c) 2004, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ * Author: Adam Dunkels ++ * ++ */ ++ ++/** ++ * \defgroup psock Protosockets library ++ * @{ ++ * ++ * The protosocket library provides an interface to the uIP stack that is ++ * similar to the traditional BSD socket interface. Unlike programs ++ * written for the ordinary uIP event-driven interface, programs ++ * written with the protosocket library are executed in a sequential ++ * fashion and does not have to be implemented as explicit state ++ * machines. ++ * ++ * Protosockets only work with TCP connections. ++ * ++ * The protosocket library uses \ref pt protothreads to provide ++ * sequential control flow. This makes the protosockets lightweight in ++ * terms of memory, but also means that protosockets inherits the ++ * functional limitations of protothreads. Each protosocket lives only ++ * within a single function. Automatic variables (stack variables) are ++ * not retained across a protosocket library function call. ++ * ++ * \note Because the protosocket library uses protothreads, local ++ * variables will not always be saved across a call to a protosocket ++ * library function. It is therefore advised that local variables are ++ * used with extreme care. ++ * ++ * The protosocket library provides functions for sending data without ++ * having to deal with retransmissions and acknowledgements, as well ++ * as functions for reading data without having to deal with data ++ * being split across more than one TCP segment. ++ * ++ * Because each protosocket runs as a protothread, the protosocket has to be ++ * started with a call to PSOCK_BEGIN() at the start of the function ++ * in which the protosocket is used. Similarly, the protosocket protothread can ++ * be terminated by a call to PSOCK_EXIT(). ++ * ++ */ ++ ++/** ++ * \file ++ * Protosocket library header file ++ * \author ++ * Adam Dunkels ++ * ++ */ ++ ++#ifndef __PSOCK_H__ ++#define __PSOCK_H__ ++ ++#include "uip.h" ++#include "uipopt.h" ++#include "pt.h" ++ ++ /* ++ * The structure that holds the state of a buffer. ++ * ++ * This structure holds the state of a uIP buffer. The structure has ++ * no user-visible elements, but is used through the functions ++ * provided by the library. ++ * ++ */ ++struct psock_buf { ++ u8_t *ptr; ++ unsigned short left; ++}; ++ ++/** ++ * The representation of a protosocket. ++ * ++ * The protosocket structrure is an opaque structure with no user-visible ++ * elements. ++ */ ++struct psock { ++ struct pt pt, psockpt; /* Protothreads - one that's using the psock ++ functions, and one that runs inside the ++ psock functions. */ ++ const u8_t *sendptr; /* Pointer to the next data to be sent. */ ++ u8_t *readptr; /* Pointer to the next data to be read. */ ++ ++ u8_t *bufptr; /* Pointer to the buffer used for buffering ++ incoming data. */ ++ ++ u16_t sendlen; /* The number of bytes left to be sent. */ ++ u16_t readlen; /* The number of bytes left to be read. */ ++ ++ struct psock_buf buf; /* The structure holding the state of the ++ input buffer. */ ++ unsigned int bufsize; /* The size of the input buffer. */ ++ ++ unsigned char state; /* The state of the protosocket. */ ++ ++ struct uip_stack *ustack; ++}; ++ ++void psock_init(struct uip_stack *ustack, ++ struct psock *psock, u8_t *buffer, unsigned int buffersize); ++/** ++ * Initialize a protosocket. ++ * ++ * This macro initializes a protosocket and must be called before the ++ * protosocket is used. The initialization also specifies the input buffer ++ * for the protosocket. ++ * ++ * \param psock (struct psock *) A pointer to the protosocket to be ++ * initialized ++ * ++ * \param buffer (char *) A pointer to the input buffer for the ++ * protosocket. ++ * ++ * \param buffersize (unsigned int) The size of the input buffer. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_INIT(psock, buffer, buffersize) \ ++ psock_init(psock, buffer, buffersize) ++ ++/** ++ * Start the protosocket protothread in a function. ++ * ++ * This macro starts the protothread associated with the protosocket and ++ * must come before other protosocket calls in the function it is used. ++ * ++ * \param psock (struct psock *) A pointer to the protosocket to be ++ * started. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_BEGIN(psock) PT_BEGIN(&((psock)->pt)) ++ ++PT_THREAD(psock_send(struct uip_stack *ustack, ++ struct psock *psock, const u8_t *buf, unsigned int len)); ++/** ++ * Send data. ++ * ++ * This macro sends data over a protosocket. The protosocket protothread blocks ++ * until all data has been sent and is known to have been received by ++ * the remote end of the TCP connection. ++ * ++ * \param psock (struct psock *) A pointer to the protosocket over which ++ * data is to be sent. ++ * ++ * \param data (char *) A pointer to the data that is to be sent. ++ * ++ * \param datalen (unsigned int) The length of the data that is to be ++ * sent. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_SEND(psock, data, datalen) \ ++ PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, data, datalen)) ++ ++/** ++ * \brief Send a null-terminated string. ++ * \param psock Pointer to the protosocket. ++ * \param str The string to be sent. ++ * ++ * This function sends a null-terminated string over the ++ * protosocket. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_SEND_STR(psock, str) \ ++ PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, str, strlen(str))) ++ ++PT_THREAD(psock_generator_send(struct psock *psock, ++ unsigned short (*f) (void *), void *arg)); ++ ++/** ++ * \brief Generate data with a function and send it ++ * \param psock Pointer to the protosocket. ++ * \param generator Pointer to the generator function ++ * \param arg Argument to the generator function ++ * ++ * This function generates data and sends it over the ++ * protosocket. This can be used to dynamically generate ++ * data for a transmission, instead of generating the data ++ * in a buffer beforehand. This function reduces the need for ++ * buffer memory. The generator function is implemented by ++ * the application, and a pointer to the function is given ++ * as an argument with the call to PSOCK_GENERATOR_SEND(). ++ * ++ * The generator function should place the generated data ++ * directly in the uip_appdata buffer, and return the ++ * length of the generated data. The generator function is ++ * called by the protosocket layer when the data first is ++ * sent, and once for every retransmission that is needed. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_GENERATOR_SEND(psock, generator, arg) \ ++ PT_WAIT_THREAD(&((psock)->pt), \ ++ psock_generator_send(psock, generator, arg)) ++ ++/** ++ * Close a protosocket. ++ * ++ * This macro closes a protosocket and can only be called from within the ++ * protothread in which the protosocket lives. ++ * ++ * \param psock (struct psock *) A pointer to the protosocket that is to ++ * be closed. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_CLOSE(psock) uip_close() ++ ++PT_THREAD(psock_readbuf(struct psock *psock)); ++/** ++ * Read data until the buffer is full. ++ * ++ * This macro will block waiting for data and read the data into the ++ * input buffer specified with the call to PSOCK_INIT(). Data is read ++ * until the buffer is full.. ++ * ++ * \param psock (struct psock *) A pointer to the protosocket from which ++ * data should be read. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_READBUF(psock) \ ++ PT_WAIT_THREAD(&((psock)->pt), psock_readbuf(psock)) ++ ++PT_THREAD(psock_readto(struct psock *psock, unsigned char c)); ++/** ++ * Read data up to a specified character. ++ * ++ * This macro will block waiting for data and read the data into the ++ * input buffer specified with the call to PSOCK_INIT(). Data is only ++ * read until the specifieed character appears in the data stream. ++ * ++ * \param psock (struct psock *) A pointer to the protosocket from which ++ * data should be read. ++ * ++ * \param c (char) The character at which to stop reading. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_READTO(psock, c) \ ++ PT_WAIT_THREAD(&((psock)->pt), psock_readto(psock, c)) ++ ++/** ++ * The length of the data that was previously read. ++ * ++ * This macro returns the length of the data that was previously read ++ * using PSOCK_READTO() or PSOCK_READ(). ++ * ++ * \param psock (struct psock *) A pointer to the protosocket holding the data. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_DATALEN(psock) psock_datalen(psock) ++ ++u16_t psock_datalen(struct psock *psock); ++ ++/** ++ * Exit the protosocket's protothread. ++ * ++ * This macro terminates the protothread of the protosocket and should ++ * almost always be used in conjunction with PSOCK_CLOSE(). ++ * ++ * \sa PSOCK_CLOSE_EXIT() ++ * ++ * \param psock (struct psock *) A pointer to the protosocket. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_EXIT(psock) PT_EXIT(&((psock)->pt)) ++ ++/** ++ * Close a protosocket and exit the protosocket's protothread. ++ * ++ * This macro closes a protosocket and exits the protosocket's protothread. ++ * ++ * \param psock (struct psock *) A pointer to the protosocket. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_CLOSE_EXIT(psock) \ ++ do { \ ++ PSOCK_CLOSE(psock); \ ++ PSOCK_EXIT(psock); \ ++ } while (0) ++ ++/** ++ * Declare the end of a protosocket's protothread. ++ * ++ * This macro is used for declaring that the protosocket's protothread ++ * ends. It must always be used together with a matching PSOCK_BEGIN() ++ * macro. ++ * ++ * \param psock (struct psock *) A pointer to the protosocket. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_END(psock) PT_END(&((psock)->pt)) ++ ++char psock_newdata(struct psock *s); ++ ++/** ++ * Check if new data has arrived on a protosocket. ++ * ++ * This macro is used in conjunction with the PSOCK_WAIT_UNTIL() ++ * macro to check if data has arrived on a protosocket. ++ * ++ * \param psock (struct psock *) A pointer to the protosocket. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_NEWDATA(psock) psock_newdata(psock) ++ ++/** ++ * Wait until a condition is true. ++ * ++ * This macro blocks the protothread until the specified condition is ++ * true. The macro PSOCK_NEWDATA() can be used to check if new data ++ * arrives when the protosocket is waiting. ++ * ++ * Typically, this macro is used as follows: ++ * ++ \code ++ PT_THREAD(thread(struct psock *s, struct timer *t)) ++ { ++ PSOCK_BEGIN(s); ++ ++ PSOCK_WAIT_UNTIL(s, PSOCK_NEWADATA(s) || timer_expired(t)); ++ ++ if(PSOCK_NEWDATA(s)) { ++ PSOCK_READTO(s, '\n'); ++ } else { ++ handle_timed_out(s); ++ } ++ ++ PSOCK_END(s); ++ } ++ \endcode ++ * ++ * \param psock (struct psock *) A pointer to the protosocket. ++ * \param condition The condition to wait for. ++ * ++ * \hideinitializer ++ */ ++#define PSOCK_WAIT_UNTIL(psock, condition) \ ++ PT_WAIT_UNTIL(&((psock)->pt), (condition)); ++ ++#define PSOCK_WAIT_THREAD(psock, condition) \ ++ PT_WAIT_THREAD(&((psock)->pt), (condition)) ++ ++#endif /* __PSOCK_H__ */ ++ ++/** @} */ +diff --git a/iscsiuio/src/uip/pt.h b/iscsiuio/src/uip/pt.h +new file mode 100644 +index 0000000..ffb1d15 +--- /dev/null ++++ b/iscsiuio/src/uip/pt.h +@@ -0,0 +1,322 @@ ++/* ++ * Copyright (c) 2004-2005, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ * Author: Adam Dunkels ++ * ++ */ ++ ++/** ++ * \addtogroup pt ++ * @{ ++ */ ++ ++/** ++ * \file ++ * Protothreads implementation. ++ * \author ++ * Adam Dunkels ++ * ++ */ ++ ++#ifndef __PT_H__ ++#define __PT_H__ ++ ++#include "lc.h" ++ ++struct pt { ++ unsigned short lc; ++}; ++ ++#define PT_WAITING 0 ++#define PT_EXITED 1 ++#define PT_ENDED 2 ++#define PT_YIELDED 3 ++ ++/** ++ * \name Initialization ++ * @{ ++ */ ++ ++/** ++ * Initialize a protothread. ++ * ++ * Initializes a protothread. Initialization must be done prior to ++ * starting to execute the protothread. ++ * ++ * \param pt A pointer to the protothread control structure. ++ * ++ * \sa PT_SPAWN() ++ * ++ * \hideinitializer ++ */ ++#define PT_INIT(pt) LC_INIT((pt)->lc) ++ ++/** @} */ ++ ++/** ++ * \name Declaration and definition ++ * @{ ++ */ ++ ++/** ++ * Declaration of a protothread. ++ * ++ * This macro is used to declare a protothread. All protothreads must ++ * be declared with this macro. ++ * ++ * \param name_args The name and arguments of the C function ++ * implementing the protothread. ++ * ++ * \hideinitializer ++ */ ++#define PT_THREAD(name_args) char name_args ++ ++/** ++ * Declare the start of a protothread inside the C function ++ * implementing the protothread. ++ * ++ * This macro is used to declare the starting point of a ++ * protothread. It should be placed at the start of the function in ++ * which the protothread runs. All C statements above the PT_BEGIN() ++ * invokation will be executed each time the protothread is scheduled. ++ * ++ * \param pt A pointer to the protothread control structure. ++ * ++ * \hideinitializer ++ */ ++#define PT_BEGIN(pt) { char PT_YIELD_FLAG __attribute__((__unused__)) = 1; LC_RESUME((pt)->lc) ++ ++/** ++ * Declare the end of a protothread. ++ * ++ * This macro is used for declaring that a protothread ends. It must ++ * always be used together with a matching PT_BEGIN() macro. ++ * ++ * \param pt A pointer to the protothread control structure. ++ * ++ * \hideinitializer ++ */ ++#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \ ++ PT_INIT(pt); return PT_ENDED; } ++ ++/** @} */ ++ ++/** ++ * \name Blocked wait ++ * @{ ++ */ ++ ++/** ++ * Block and wait until condition is true. ++ * ++ * This macro blocks the protothread until the specified condition is ++ * true. ++ * ++ * \param pt A pointer to the protothread control structure. ++ * \param condition The condition. ++ * ++ * \hideinitializer ++ */ ++#define PT_WAIT_UNTIL(pt, condition) \ ++ do { \ ++ LC_SET((pt)->lc); \ ++ if (!(condition)) { \ ++ return PT_WAITING; \ ++ } \ ++ } while (0) ++ ++/** ++ * Block and wait while condition is true. ++ * ++ * This function blocks and waits while condition is true. See ++ * PT_WAIT_UNTIL(). ++ * ++ * \param pt A pointer to the protothread control structure. ++ * \param cond The condition. ++ * ++ * \hideinitializer ++ */ ++#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond)) ++ ++/** @} */ ++ ++/** ++ * \name Hierarchical protothreads ++ * @{ ++ */ ++ ++/** ++ * Block and wait until a child protothread completes. ++ * ++ * This macro schedules a child protothread. The current protothread ++ * will block until the child protothread completes. ++ * ++ * \note The child protothread must be manually initialized with the ++ * PT_INIT() function before this function is used. ++ * ++ * \param pt A pointer to the protothread control structure. ++ * \param thread The child protothread with arguments ++ * ++ * \sa PT_SPAWN() ++ * ++ * \hideinitializer ++ */ ++#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread)) ++ ++/** ++ * Spawn a child protothread and wait until it exits. ++ * ++ * This macro spawns a child protothread and waits until it exits. The ++ * macro can only be used within a protothread. ++ * ++ * \param pt A pointer to the protothread control structure. ++ * \param child A pointer to the child protothread's control structure. ++ * \param thread The child protothread with arguments ++ * ++ * \hideinitializer ++ */ ++#define PT_SPAWN(pt, child, thread) \ ++ do { \ ++ PT_INIT((child)); \ ++ PT_WAIT_THREAD((pt), (thread)); \ ++ } while (0) ++ ++/** @} */ ++ ++/** ++ * \name Exiting and restarting ++ * @{ ++ */ ++ ++/** ++ * Restart the protothread. ++ * ++ * This macro will block and cause the running protothread to restart ++ * its execution at the place of the PT_BEGIN() call. ++ * ++ * \param pt A pointer to the protothread control structure. ++ * ++ * \hideinitializer ++ */ ++#define PT_RESTART(pt) \ ++ do { \ ++ PT_INIT(pt); \ ++ return PT_WAITING; \ ++ } while (0) ++ ++/** ++ * Exit the protothread. ++ * ++ * This macro causes the protothread to exit. If the protothread was ++ * spawned by another protothread, the parent protothread will become ++ * unblocked and can continue to run. ++ * ++ * \param pt A pointer to the protothread control structure. ++ * ++ * \hideinitializer ++ */ ++#define PT_EXIT(pt) \ ++ do { \ ++ PT_INIT(pt); \ ++ return PT_EXITED; \ ++ } while (0) ++ ++/** @} */ ++ ++/** ++ * \name Calling a protothread ++ * @{ ++ */ ++ ++/** ++ * Schedule a protothread. ++ * ++ * This function shedules a protothread. The return value of the ++ * function is non-zero if the protothread is running or zero if the ++ * protothread has exited. ++ * ++ * \param f The call to the C function implementing the protothread to ++ * be scheduled ++ * ++ * \hideinitializer ++ */ ++#define PT_SCHEDULE(f) ((f) == PT_WAITING) ++ ++/** @} */ ++ ++/** ++ * \name Yielding from a protothread ++ * @{ ++ */ ++ ++/** ++ * Yield from the current protothread. ++ * ++ * This function will yield the protothread, thereby allowing other ++ * processing to take place in the system. ++ * ++ * \param pt A pointer to the protothread control structure. ++ * ++ * \hideinitializer ++ */ ++#define PT_YIELD(pt) \ ++ do { \ ++ PT_YIELD_FLAG = 0; \ ++ LC_SET((pt)->lc); \ ++ if (PT_YIELD_FLAG == 0) { \ ++ return PT_YIELDED; \ ++ } \ ++ } while (0) ++ ++/** ++ * \brief Yield from the protothread until a condition occurs. ++ * \param pt A pointer to the protothread control structure. ++ * \param cond The condition. ++ * ++ * This function will yield the protothread, until the ++ * specified condition evaluates to true. ++ * ++ * ++ * \hideinitializer ++ */ ++#define PT_YIELD_UNTIL(pt, cond) \ ++ do { \ ++ PT_YIELD_FLAG = 0; \ ++ LC_SET((pt)->lc); \ ++ if ((PT_YIELD_FLAG == 0) || !(cond)) { \ ++ return PT_YIELDED; \ ++ } \ ++ } while (0) ++ ++/** @} */ ++ ++#endif /* __PT_H__ */ ++ ++/** @} */ +diff --git a/iscsiuio/src/uip/timer.c b/iscsiuio/src/uip/timer.c +new file mode 100644 +index 0000000..da77148 +--- /dev/null ++++ b/iscsiuio/src/uip/timer.c +@@ -0,0 +1,127 @@ ++/** ++ * \addtogroup timer ++ * @{ ++ */ ++ ++/** ++ * \file ++ * Timer library implementation. ++ * \author ++ * Adam Dunkels ++ */ ++ ++/* ++ * Copyright (c) 2004, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ * Author: Adam Dunkels ++ * ++ */ ++ ++#include "clock.h" ++#include "timer.h" ++ ++/*---------------------------------------------------------------------------*/ ++/** ++ * Set a timer. ++ * ++ * This function is used to set a timer for a time sometime in the ++ * future. The function timer_expired() will evaluate to true after ++ * the timer has expired. ++ * ++ * \param t A pointer to the timer ++ * \param interval The interval before the timer expires. ++ * ++ */ ++void timer_set(struct timer *t, clock_time_t interval) ++{ ++ t->interval = interval; ++ t->start = clock_time(); ++} ++ ++/*---------------------------------------------------------------------------*/ ++/** ++ * Reset the timer with the same interval. ++ * ++ * This function resets the timer with the same interval that was ++ * given to the timer_set() function. The start point of the interval ++ * is the exact time that the timer last expired. Therefore, this ++ * function will cause the timer to be stable over time, unlike the ++ * timer_rester() function. ++ * ++ * \param t A pointer to the timer. ++ * ++ * \sa timer_restart() ++ */ ++void timer_reset(struct timer *t) ++{ ++ t->start += t->interval; ++} ++ ++/*---------------------------------------------------------------------------*/ ++/** ++ * Restart the timer from the current point in time ++ * ++ * This function restarts a timer with the same interval that was ++ * given to the timer_set() function. The timer will start at the ++ * current time. ++ * ++ * \note A periodic timer will drift if this function is used to reset ++ * it. For preioric timers, use the timer_reset() function instead. ++ * ++ * \param t A pointer to the timer. ++ * ++ * \sa timer_reset() ++ */ ++void timer_restart(struct timer *t) ++{ ++ t->start = clock_time(); ++} ++ ++/*---------------------------------------------------------------------------*/ ++/** ++ * Check if a timer has expired. ++ * ++ * This function tests if a timer has expired and returns true or ++ * false depending on its status. ++ * ++ * \param t A pointer to the timer ++ * ++ * \return Non-zero if the timer has expired, zero otherwise. ++ * ++ */ ++int timer_expired(struct timer *t) ++{ ++ return (clock_time_t) (clock_time() - t->start) >= ++ (clock_time_t) t->interval; ++} ++ ++/*---------------------------------------------------------------------------*/ ++ ++/** @} */ +diff --git a/iscsiuio/src/uip/timer.h b/iscsiuio/src/uip/timer.h +new file mode 100644 +index 0000000..12739fd +--- /dev/null ++++ b/iscsiuio/src/uip/timer.h +@@ -0,0 +1,84 @@ ++/** ++ * \defgroup timer Timer library ++ * ++ * The timer library provides functions for setting, resetting and ++ * restarting timers, and for checking if a timer has expired. An ++ * application must "manually" check if its timers have expired; this ++ * is not done automatically. ++ * ++ * A timer is declared as a \c struct \c timer and all access to the ++ * timer is made by a pointer to the declared timer. ++ * ++ * \note The timer library uses the \ref clock "Clock library" to ++ * measure time. Intervals should be specified in the format used by ++ * the clock library. ++ * ++ * @{ ++ */ ++ ++/** ++ * \file ++ * Timer library header file. ++ * \author ++ * Adam Dunkels ++ */ ++ ++/* ++ * Copyright (c) 2004, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ * Author: Adam Dunkels ++ * ++ */ ++#ifndef __TIMER_H__ ++#define __TIMER_H__ ++ ++#include "clock.h" ++ ++/** ++ * A timer. ++ * ++ * This structure is used for declaring a timer. The timer must be set ++ * with timer_set() before it can be used. ++ * ++ * \hideinitializer ++ */ ++struct timer { ++ clock_time_t start; ++ clock_time_t interval; ++}; ++ ++void timer_set(struct timer *t, clock_time_t interval); ++void timer_reset(struct timer *t); ++void timer_restart(struct timer *t); ++int timer_expired(struct timer *t); ++ ++#endif /* __TIMER_H__ */ ++ ++/** @} */ +diff --git a/iscsiuio/src/uip/uip-neighbor.c b/iscsiuio/src/uip/uip-neighbor.c +new file mode 100644 +index 0000000..4c80c32 +--- /dev/null ++++ b/iscsiuio/src/uip/uip-neighbor.c +@@ -0,0 +1,219 @@ ++/* ++ * Copyright (c) 2006, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ */ ++ ++/** ++ * \file ++ * Database of link-local neighbors, used by IPv6 code and ++ * to be used by a future ARP code rewrite. ++ * \author ++ * Adam Dunkels ++ */ ++ ++#include "logger.h" ++#include "uip.h" ++#include "uip-neighbor.h" ++ ++#include ++#include ++#include ++ ++/******************************************************************************* ++ * Constants ++ ******************************************************************************/ ++#define PFX "uip-neigh " ++ ++#define MAX_TIME 128 ++ ++/*---------------------------------------------------------------------------*/ ++void uip_neighbor_init(struct uip_stack *ustack) ++{ ++ int i; ++ ++ pthread_mutex_lock(&ustack->lock); ++ for (i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) { ++ memset(&(ustack->neighbor_entries[i].ipaddr), 0, ++ sizeof(ustack->neighbor_entries[i].ipaddr)); ++ memset(&(ustack->neighbor_entries[i].mac_addr), 0, ++ sizeof(ustack->neighbor_entries[i].mac_addr)); ++ ustack->neighbor_entries[i].time = MAX_TIME; ++ } ++ pthread_mutex_unlock(&ustack->lock); ++} ++ ++void uip_neighbor_add(struct uip_stack *ustack, ++ struct in6_addr *addr6, struct uip_eth_addr *addr) ++{ ++ int i, oldest; ++ u8_t oldest_time; ++ char buf[INET6_ADDRSTRLEN]; ++ ++ inet_ntop(AF_INET6, addr6, buf, sizeof(buf)); ++ ++ pthread_mutex_lock(&ustack->lock); ++ ++ /* Find the first unused entry or the oldest used entry. */ ++ oldest_time = 0; ++ oldest = 0; ++ for (i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) { ++ if (ustack->neighbor_entries[i].time == MAX_TIME) { ++ oldest = i; ++ break; ++ } ++ if (uip_ip6addr_cmp ++ (ustack->neighbor_entries[i].ipaddr.s6_addr, addr6)) { ++ oldest = i; ++ break; ++ } ++ if (ustack->neighbor_entries[i].time > oldest_time) { ++ oldest = i; ++ oldest_time = ustack->neighbor_entries[i].time; ++ } ++ } ++ ++ /* Use the oldest or first free entry (either pointed to by the ++ "oldest" variable). */ ++ ustack->neighbor_entries[oldest].time = 0; ++ uip_ip6addr_copy(ustack->neighbor_entries[oldest].ipaddr.s6_addr, ++ addr6); ++ memcpy(&ustack->neighbor_entries[oldest].mac_addr, addr, ++ sizeof(struct uip_eth_addr)); ++ ++ LOG_DEBUG("Adding neighbor %s with " ++ "mac address %02x:%02x:%02x:%02x:%02x:%02x at %d", ++ buf, addr->addr[0], addr->addr[1], addr->addr[2], ++ addr->addr[3], addr->addr[4], addr->addr[5], oldest); ++ ++ pthread_mutex_unlock(&ustack->lock); ++} ++ ++/*---------------------------------------------------------------------------*/ ++static struct neighbor_entry *find_entry(struct uip_stack *ustack, ++ struct in6_addr *addr6) ++{ ++ int i; ++ ++ for (i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) { ++ if (uip_ip6addr_cmp ++ (ustack->neighbor_entries[i].ipaddr.s6_addr, ++ addr6->s6_addr)) { ++ return &ustack->neighbor_entries[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++/*---------------------------------------------------------------------------*/ ++void uip_neighbor_update(struct uip_stack *ustack, struct in6_addr *addr6) ++{ ++ struct neighbor_entry *e; ++ ++ pthread_mutex_lock(&ustack->lock); ++ ++ e = find_entry(ustack, addr6); ++ if (e != NULL) ++ e->time = 0; ++ ++ pthread_mutex_unlock(&ustack->lock); ++} ++ ++/*---------------------------------------------------------------------------*/ ++int uip_neighbor_lookup(struct uip_stack *ustack, ++ struct in6_addr *addr6, uint8_t *mac_addr) ++{ ++ struct neighbor_entry *e; ++ ++ pthread_mutex_lock(&ustack->lock); ++ e = find_entry(ustack, addr6); ++ if (e != NULL) { ++ char addr6_str[INET6_ADDRSTRLEN]; ++ uint8_t *entry_mac_addr; ++ ++ addr6_str[0] = '\0'; ++ inet_ntop(AF_INET6, addr6->s6_addr, addr6_str, ++ sizeof(addr6_str)); ++ entry_mac_addr = (uint8_t *)&e->mac_addr.addr; ++ ++ LOG_DEBUG(PFX ++ "Found %s at %02x:%02x:%02x:%02x:%02x:%02x", ++ addr6_str, ++ entry_mac_addr[0], entry_mac_addr[1], ++ entry_mac_addr[2], entry_mac_addr[3], ++ entry_mac_addr[4], entry_mac_addr[5]); ++ ++ memcpy(mac_addr, entry_mac_addr, sizeof(e->mac_addr)); ++ pthread_mutex_unlock(&ustack->lock); ++ return 0; ++ } ++ ++ pthread_mutex_unlock(&ustack->lock); ++ return -ENOENT; ++} ++ ++void uip_neighbor_out(struct uip_stack *ustack) ++{ ++ struct neighbor_entry *e; ++ struct uip_eth_hdr *eth_hdr = ++ (struct uip_eth_hdr *)ustack->data_link_layer; ++ struct uip_ipv6_hdr *ipv6_hdr = ++ (struct uip_ipv6_hdr *)ustack->network_layer; ++ ++ pthread_mutex_lock(&ustack->lock); ++ ++ /* Find the destination IP address in the neighbor table and construct ++ the Ethernet header. If the destination IP addres isn't on the ++ local network, we use the default router's IP address instead. ++ ++ If not ARP table entry is found, we overwrite the original IP ++ packet with an ARP request for the IP address. */ ++ e = find_entry(ustack, (struct in6_addr *)ipv6_hdr->destipaddr); ++ if (e == NULL) { ++ struct uip_eth_addr eth_addr_tmp; ++ ++ memcpy(ð_addr_tmp, eth_hdr->src.addr, sizeof(eth_addr_tmp)); ++ memcpy(eth_hdr->src.addr, ustack->uip_ethaddr.addr, ++ sizeof(eth_hdr->src.addr)); ++ memcpy(eth_hdr->dest.addr, ð_addr_tmp, ++ sizeof(eth_hdr->dest.addr)); ++ ++ pthread_mutex_unlock(&ustack->lock); ++ return; ++ } ++ ++ memcpy(eth_hdr->dest.addr, &e->mac_addr, sizeof(eth_hdr->dest.addr)); ++ memcpy(eth_hdr->src.addr, ustack->uip_ethaddr.addr, ++ sizeof(eth_hdr->src.addr)); ++ ++ pthread_mutex_unlock(&ustack->lock); ++} ++ ++/*---------------------------------------------------------------------------*/ +diff --git a/iscsiuio/src/uip/uip-neighbor.h b/iscsiuio/src/uip/uip-neighbor.h +new file mode 100644 +index 0000000..d10c57b +--- /dev/null ++++ b/iscsiuio/src/uip/uip-neighbor.h +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (c) 2006, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ */ ++ ++/** ++ * \file ++ * Header file for database of link-local neighbors, used by ++ * IPv6 code and to be used by future ARP code. ++ * \author ++ * Adam Dunkels ++ */ ++ ++#ifndef __UIP_NEIGHBOR_H__ ++#define __UIP_NEIGHBOR_H__ ++ ++#include "uip.h" ++#include "uip_eth.h" ++ ++/* ICMP types */ ++/* ICMPv6 error Messages */ ++#define ICMPV6_DEST_UNREACH 1 ++#define ICMPV6_PKT_TOOBIG 2 ++#define ICMPV6_TIME_EXCEED 3 ++#define ICMPV6_PARAMPROB 4 ++ ++/* ICMPv6 Informational Messages */ ++#define ICMPV6_ECHO_REQUEST 128 ++#define ICMPV6_ECHO_REPLY 129 ++#define ICMPV6_MGM_QUERY 130 ++#define ICMPV6_MGM_REPORT 131 ++#define ICMPV6_MGM_REDUCTION 132 ++ ++/* Codes for Destination Unreachable */ ++#define ICMPV6_NOROUTE 0 ++#define ICMPV6_ADM_PROHIBITED 1 ++#define ICMPV6_NOT_NEIGHBOUR 2 ++#define ICMPV6_ADDR_UNREACH 3 ++#define ICMPV6_PORT_UNREACH 4 ++ ++/* Codes for Time Exceeded */ ++#define ICMPV6_EXC_HOPLIMIT 0 ++#define ICMPV6_EXC_FRAGTIME 1 ++ ++/* Codes for Parameter Problem */ ++#define ICMPV6_HDR_FIELD 0 ++#define ICMPV6_UNK_NEXTHDR 1 ++#define ICMPV6_UNK_OPTION 2 ++ ++#if 0 ++struct __attribute__ ((__packed__)) icmpv6_hdr { ++ u8_t type; ++ u8_t code; ++ u16_t checksum; ++ union { ++ struct { ++ u16_t id; ++ u16_t sequence; ++ } echo; ++ u32_t gateway; ++ struct { ++ u16_t unused; ++ u16_t mtu; ++ } frag; ++ } un; ++}; ++#endif ++ ++void uip_neighbor_init(struct uip_stack *ustack); ++void uip_neighbor_add(struct uip_stack *ustack, ++ struct in6_addr *addr6, struct uip_eth_addr *addr); ++void uip_neighbor_update(struct uip_stack *ustack, struct in6_addr *addr6); ++int uip_neighbor_lookup(struct uip_stack *ustack, struct in6_addr *ipaddr, ++ uint8_t *mac_addr); ++void uip_neighbor_periodic(void); ++void uip_neighbor_out(struct uip_stack *ustack); ++ ++#endif /* __UIP-NEIGHBOR_H__ */ +diff --git a/iscsiuio/src/uip/uip.c b/iscsiuio/src/uip/uip.c +new file mode 100644 +index 0000000..9e6dcc3 +--- /dev/null ++++ b/iscsiuio/src/uip/uip.c +@@ -0,0 +1,2416 @@ ++#include ++#include ++#include ++#include ++#include ++#include "uip.h" ++#include "dhcpc.h" ++#include "ipv6_ndpc.h" ++#include "brcm_iscsi.h" ++#include "ping.h" ++ ++/** ++ * \defgroup uip The uIP TCP/IP stack ++ * @{ ++ * ++ * uIP is an implementation of the TCP/IP protocol stack intended for ++ * small 8-bit and 16-bit microcontrollers. ++ * ++ * uIP provides the necessary protocols for Internet communication, ++ * with a very small code footprint and RAM requirements - the uIP ++ * code size is on the order of a few kilobytes and RAM usage is on ++ * the order of a few hundred bytes. ++ */ ++ ++/** ++ * \file ++ * The uIP TCP/IP stack code. ++ * \author Adam Dunkels ++ */ ++ ++/* ++ * Copyright (c) 2001-2003, Adam Dunkels. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack. ++ * ++ * ++ */ ++ ++/* ++ * uIP is a small implementation of the IP, UDP and TCP protocols (as ++ * well as some basic ICMP stuff). The implementation couples the IP, ++ * UDP, TCP and the application layers very tightly. To keep the size ++ * of the compiled code down, this code frequently uses the goto ++ * statement. While it would be possible to break the uip_process() ++ * function into many smaller functions, this would increase the code ++ * size because of the overhead of parameter passing and the fact that ++ * the optimier would not be as efficient. ++ * ++ * The principle is that we have a small buffer, called the uip_buf, ++ * in which the device driver puts an incoming packet. The TCP/IP ++ * stack parses the headers in the packet, and calls the ++ * application. If the remote host has sent data to the application, ++ * this data is present in the uip_buf and the application read the ++ * data from there. It is up to the application to put this data into ++ * a byte stream if needed. The application will not be fed with data ++ * that is out of sequence. ++ * ++ * If the application whishes to send data to the peer, it should put ++ * its data into the uip_buf. The uip_appdata pointer points to the ++ * first available byte. The TCP/IP stack will calculate the ++ * checksums, and fill in the necessary header fields and finally send ++ * the packet back to the peer. ++*/ ++ ++#include "logger.h" ++ ++#include "uip.h" ++#include "uipopt.h" ++#include "uip_arch.h" ++#include "uip_eth.h" ++#include "uip-neighbor.h" ++ ++#include ++ ++/******************************************************************************* ++ * Constants ++ ******************************************************************************/ ++#define PFX "uip " ++ ++static const uip_ip6addr_t all_ones_addr6 = { ++ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff ++}; ++static const uip_ip4addr_t all_ones_addr4 = { 0xffff, 0xffff }; ++ ++const uip_ip6addr_t all_zeroes_addr6 = { ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 ++}; ++const uip_ip4addr_t all_zeroes_addr4 = { 0x0000, 0x0000 }; ++ ++const uint8_t mutlicast_ipv6_prefix[16] = { ++ 0xfc, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++ ++const uint8_t link_local_addres_prefix[16] = { ++ 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++const uint32_t link_local_address_prefix_length = 10; ++ ++/* Structures and definitions. */ ++#define TCP_FIN 0x01 ++#define TCP_SYN 0x02 ++#define TCP_RST 0x04 ++#define TCP_PSH 0x08 ++#define TCP_ACK 0x10 ++#define TCP_URG 0x20 ++#define TCP_CTL 0x3f ++ ++#define TCP_OPT_END 0 /* End of TCP options list */ ++#define TCP_OPT_NOOP 1 /* "No-operation" TCP option */ ++#define TCP_OPT_MSS 2 /* Maximum segment size TCP option */ ++ ++#define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */ ++ ++#define ICMP_ECHO_REPLY 0 ++#define ICMP_ECHO 8 ++ ++#define ICMP6_ECHO_REPLY 129 ++#define ICMP6_ECHO 128 ++#define ICMP6_NEIGHBOR_SOLICITATION 135 ++#define ICMP6_NEIGHBOR_ADVERTISEMENT 136 ++ ++#define ICMP6_FLAG_S (1 << 6) ++ ++#define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1 ++#define ICMP6_OPTION_TARGET_LINK_ADDRESS 2 ++ ++/* Macros. */ ++#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0]) ++#define UDPBUF(ustack) ((struct uip_udpip_hdr *)ustack->network_layer) ++ ++/****************************************************************************** ++ * Utility Functions ++ *****************************************************************************/ ++static int is_ipv6(struct uip_stack *ustack) ++{ ++ u16_t type; ++ ++ type = ETH_BUF(ustack->uip_buf)->type; ++ type = ntohs(type); ++ if (type == UIP_ETHTYPE_8021Q) ++ type = ntohs(VLAN_ETH_BUF(ustack->uip_buf)->type); ++ else ++ type = ntohs(ETH_BUF(ustack->uip_buf)->type); ++ ++ return (type == UIP_ETHTYPE_IPv6); ++} ++ ++int is_ipv6_link_local_address(uip_ip6addr_t *addr) ++{ ++ u8_t *test_adddr = (u8_t *) addr; ++ u8_t test_remainder; ++ ++ if (test_adddr[0] != link_local_addres_prefix[0]) ++ return 0; ++ ++ test_remainder = (test_adddr[1] & 0xC0) >> 6; ++ if (test_remainder != 2) ++ return 0; ++ ++ return 1; ++} ++ ++void uip_sethostaddr4(struct uip_stack *ustack, uip_ip4addr_t *addr) ++{ ++ pthread_mutex_lock(&ustack->lock); ++ uip_ip4addr_copy(ustack->hostaddr, (addr)); ++ pthread_mutex_unlock(&ustack->lock); ++} ++ ++void uip_setdraddr4(struct uip_stack *ustack, uip_ip4addr_t *addr) ++{ ++ pthread_mutex_lock(&ustack->lock); ++ uip_ip4addr_copy(ustack->default_route_addr, (addr)); ++ pthread_mutex_unlock(&ustack->lock); ++} ++ ++void uip_setnetmask4(struct uip_stack *ustack, uip_ip4addr_t *addr) ++{ ++ pthread_mutex_lock(&ustack->lock); ++ uip_ip4addr_copy(ustack->netmask, (addr)); ++ pthread_mutex_unlock(&ustack->lock); ++} ++ ++void uip_setethernetmac(struct uip_stack *ustack, uint8_t *mac) ++{ ++ pthread_mutex_lock(&ustack->lock); ++ memcpy(ustack->uip_ethaddr.addr, (mac), 6); ++ pthread_mutex_unlock(&ustack->lock); ++} ++ ++void set_uip_stack(struct uip_stack *ustack, ++ uip_ip4addr_t *ip, ++ uip_ip4addr_t *netmask, ++ uip_ip4addr_t *default_route, uint8_t *mac_addr) ++{ ++ if (ip) ++ uip_sethostaddr4(ustack, ip); ++ if (netmask) ++ uip_setnetmask4(ustack, netmask); ++ if (default_route) ++ uip_setdraddr4(ustack, default_route); ++ if (mac_addr) ++ uip_setethernetmac(ustack, mac_addr); ++} ++ ++#if !UIP_ARCH_ADD32 ++void uip_add32(u8_t *op32, u16_t op16, u8_t *uip_acc32) ++{ ++ uip_acc32[3] = op32[3] + (op16 & 0xff); ++ uip_acc32[2] = op32[2] + (op16 >> 8); ++ uip_acc32[1] = op32[1]; ++ uip_acc32[0] = op32[0]; ++ ++ if (uip_acc32[2] < (op16 >> 8)) { ++ ++uip_acc32[1]; ++ if (uip_acc32[1] == 0) ++ ++uip_acc32[0]; ++ } ++ ++ if (uip_acc32[3] < (op16 & 0xff)) { ++ ++uip_acc32[2]; ++ if (uip_acc32[2] == 0) { ++ ++uip_acc32[1]; ++ if (uip_acc32[1] == 0) ++ ++uip_acc32[0]; ++ } ++ } ++} ++ ++#endif /* UIP_ARCH_ADD32 */ ++ ++#if !UIP_ARCH_CHKSUM ++/*---------------------------------------------------------------------------*/ ++static u16_t chksum(u16_t sum, const u8_t *data, u16_t len) ++{ ++ u16_t t; ++ const u8_t *dataptr; ++ const u8_t *last_byte; ++ ++ dataptr = data; ++ last_byte = data + len - 1; ++ ++ while (dataptr < last_byte) { /* At least two more bytes */ ++ t = (dataptr[0] << 8) + dataptr[1]; ++ sum += t; ++ if (sum < t) ++ sum++; /* carry */ ++ dataptr += 2; ++ } ++ ++ if (dataptr == last_byte) { ++ t = (dataptr[0] << 8) + 0; ++ sum += t; ++ if (sum < t) ++ sum++; /* carry */ ++ } ++ ++ /* Return sum in host byte order. */ ++ return sum; ++} ++ ++/*---------------------------------------------------------------------------*/ ++u16_t uip_chksum(u16_t *data, u16_t len) ++{ ++ return htons(chksum(0, (u8_t *)data, len)); ++} ++ ++/*---------------------------------------------------------------------------*/ ++#ifndef UIP_ARCH_IPCHKSUM ++u16_t uip_ipchksum(struct uip_stack *ustack) ++{ ++ u16_t sum; ++ u16_t uip_iph_len; ++ ++ if (is_ipv6(ustack)) ++ uip_iph_len = UIP_IPv6_H_LEN; ++ else ++ uip_iph_len = UIP_IPv4_H_LEN; ++ ++ sum = chksum(0, ustack->network_layer, uip_iph_len); ++ return (sum == 0) ? 0xffff : htons(sum); ++} ++#endif ++ ++/*---------------------------------------------------------------------------*/ ++static u16_t upper_layer_chksum_ipv4(struct uip_stack *ustack, u8_t proto) ++{ ++ u16_t upper_layer_len; ++ u16_t sum; ++ struct uip_tcp_ipv4_hdr *tcp_ipv4_hdr = NULL; ++ ++ tcp_ipv4_hdr = (struct uip_tcp_ipv4_hdr *)ustack->network_layer; ++ ++ upper_layer_len = (((u16_t) (tcp_ipv4_hdr->len[0]) << 8) + ++ tcp_ipv4_hdr->len[1]) - UIP_IPv4_H_LEN; ++ ++ /* First sum pseudoheader. */ ++ /* IP protocol and length fields. This addition cannot carry. */ ++ sum = upper_layer_len + proto; ++ ++ sum = ++ chksum(sum, (u8_t *)&tcp_ipv4_hdr->srcipaddr[0], ++ 2 * sizeof(uip_ip4addr_t)); ++ /* Sum TCP header and data. */ ++ sum = chksum(sum, ustack->network_layer + UIP_IPv4_H_LEN, ++ upper_layer_len); ++ ++ return (sum == 0) ? 0xffff : htons(sum); ++} ++ ++/*---------------------------------------------------------------------------*/ ++static uint16_t upper_layer_checksum_ipv6(uint8_t *data, uint8_t proto) ++{ ++ uint16_t upper_layer_len; ++ uint16_t sum; ++ struct ip6_hdr *ipv6_hdr; ++ uint8_t *upper_layer; ++ uint32_t val; ++ ++ ipv6_hdr = (struct ip6_hdr *)data; ++ ++ upper_layer_len = ntohs(ipv6_hdr->ip6_plen); ++ ++ /* First sum pseudoheader. */ ++ sum = 0; ++ sum = chksum(sum, (const u8_t *)ipv6_hdr->ip6_src.s6_addr, ++ sizeof(ipv6_hdr->ip6_src)); ++ sum = chksum(sum, (const u8_t *)ipv6_hdr->ip6_dst.s6_addr, ++ sizeof(ipv6_hdr->ip6_dst)); ++ ++ val = htons(upper_layer_len); ++ sum = chksum(sum, (u8_t *)&val, sizeof(val)); ++ ++ val = htons(proto); ++ sum = chksum(sum, (u8_t *)&val, sizeof(val)); ++ ++ upper_layer = (uint8_t *)(ipv6_hdr + 1); ++ sum = chksum(sum, upper_layer, upper_layer_len); ++ ++ return (sum == 0) ? 0xffff : htons(sum); ++} ++ ++/*---------------------------------------------------------------------------*/ ++ ++u16_t uip_icmp6chksum(struct uip_stack *ustack) ++{ ++ uint8_t *data = ustack->network_layer; ++ ++ return upper_layer_checksum_ipv6(data, UIP_PROTO_ICMP6); ++} ++ ++uint16_t icmpv6_checksum(uint8_t *data) ++{ ++ return upper_layer_checksum_ipv6(data, IPPROTO_ICMPV6); ++} ++ ++/*---------------------------------------------------------------------------*/ ++u16_t uip_tcpchksum(struct uip_stack *ustack) ++{ ++ return upper_layer_chksum_ipv4(ustack, UIP_PROTO_TCP); ++} ++ ++/*---------------------------------------------------------------------------*/ ++#if UIP_UDP_CHECKSUMS ++static u16_t uip_udpchksum_ipv4(struct uip_stack *ustack) ++{ ++ return upper_layer_chksum_ipv4(ustack, UIP_PROTO_UDP); ++} ++ ++static u16_t uip_udpchksum_ipv6(struct uip_stack *ustack) ++{ ++ uint8_t *data = ustack->network_layer; ++ ++ return upper_layer_checksum_ipv6(data, UIP_PROTO_UDP); ++} ++ ++u16_t uip_udpchksum(struct uip_stack *ustack) ++{ ++ if (is_ipv6(ustack)) ++ return uip_udpchksum_ipv6(ustack); ++ else ++ return uip_udpchksum_ipv4(ustack); ++} ++#endif /* UIP_UDP_CHECKSUMS */ ++#endif /* UIP_ARCH_CHKSUM */ ++/*---------------------------------------------------------------------------*/ ++void uip_init(struct uip_stack *ustack, uint8_t ipv6_enabled) ++{ ++ u8_t c; ++ ++ for (c = 0; c < UIP_LISTENPORTS; ++c) ++ ustack->uip_listenports[c] = 0; ++ for (c = 0; c < UIP_CONNS; ++c) ++ ustack->uip_conns[c].tcpstateflags = UIP_CLOSED; ++#if UIP_ACTIVE_OPEN ++ ustack->lastport = 1024; ++#endif /* UIP_ACTIVE_OPEN */ ++ ++#if UIP_UDP ++ for (c = 0; c < UIP_UDP_CONNS; ++c) ++ ustack->uip_udp_conns[c].lport = 0; ++#endif /* UIP_UDP */ ++ ++ /* IPv4 initialization. */ ++#if UIP_FIXEDADDR == 0 ++ /* uip_hostaddr[0] = uip_hostaddr[1] = 0; */ ++#endif /* UIP_FIXEDADDR */ ++ ++ /* zero out the uIP statistics */ ++ memset(&ustack->stats, 0, sizeof(ustack->stats)); ++ ++ /* prepare the uIP lock */ ++ pthread_mutex_init(&ustack->lock, NULL); ++ ++ if (ipv6_enabled) ++ ustack->enable_IPv6 = UIP_SUPPORT_IPv6_ENABLED; ++ else ++ ustack->enable_IPv6 = UIP_SUPPORT_IPv6_DISABLED; ++ ++ ustack->dhcpc = NULL; ++ ustack->ndpc = NULL; ++ ustack->ping_conf = NULL; ++} ++void uip_reset(struct uip_stack *ustack) ++{ ++ /* There was an associated DHCP object, this memory needs to be ++ * freed */ ++ if (ustack->dhcpc) ++ free(ustack->dhcpc); ++ ++ ndpc_exit(ustack->ndpc); ++ ++ memset(ustack, 0, sizeof(*ustack)); ++} ++ ++/*---------------------------------------------------------------------------*/ ++#if UIP_ACTIVE_OPEN ++struct uip_conn *uip_connect(struct uip_stack *ustack, uip_ip4addr_t *ripaddr, ++ u16_t rport) ++{ ++ u8_t c; ++ register struct uip_conn *conn, *cconn; ++ ++ /* Find an unused local port. */ ++again: ++ ++ustack->lastport; ++ ++ if (ustack->lastport >= 32000) ++ ustack->lastport = 4096; ++ ++ /* Check if this port is already in use, and if so try to find ++ another one. */ ++ for (c = 0; c < UIP_CONNS; ++c) { ++ conn = &ustack->uip_conns[c]; ++ if (conn->tcpstateflags != UIP_CLOSED && ++ conn->lport == htons(ustack->lastport)) { ++ goto again; ++ } ++ } ++ ++ conn = 0; ++ for (c = 0; c < UIP_CONNS; ++c) { ++ cconn = &ustack->uip_conns[c]; ++ if (cconn->tcpstateflags == UIP_CLOSED) { ++ conn = cconn; ++ break; ++ } ++ if (cconn->tcpstateflags == UIP_TIME_WAIT) { ++ if (conn == 0 || cconn->timer > conn->timer) ++ conn = cconn; ++ } ++ } ++ ++ if (conn == 0) ++ return 0; ++ ++ conn->tcpstateflags = UIP_SYN_SENT; ++ ++ conn->snd_nxt[0] = ustack->iss[0]; ++ conn->snd_nxt[1] = ustack->iss[1]; ++ conn->snd_nxt[2] = ustack->iss[2]; ++ conn->snd_nxt[3] = ustack->iss[3]; ++ ++ conn->initialmss = conn->mss = UIP_TCP_MSS; ++ ++ conn->len = 1; /* TCP length of the SYN is one. */ ++ conn->nrtx = 0; ++ conn->timer = 1; /* Send the SYN next time around. */ ++ conn->rto = UIP_RTO; ++ conn->sa = 0; ++ conn->sv = 16; /* Initial value of the RTT variance. */ ++ conn->lport = htons(ustack->lastport); ++ conn->rport = rport; ++ uip_ip4addr_copy(&conn->ripaddr, ripaddr); ++ ++ return conn; ++} ++#endif /* UIP_ACTIVE_OPEN */ ++/*---------------------------------------------------------------------------*/ ++#if UIP_UDP ++struct uip_udp_conn *uip_udp_new(struct uip_stack *ustack, ++ uip_ip4addr_t *ripaddr, u16_t rport) ++{ ++ u8_t c; ++ register struct uip_udp_conn *conn; ++ ++ /* Find an unused local port. */ ++again: ++ ++ustack->lastport; ++ ++ if (ustack->lastport >= 32000) ++ ustack->lastport = 4096; ++ ++ for (c = 0; c < UIP_UDP_CONNS; ++c) { ++ if (ustack->uip_udp_conns[c].lport == htons(ustack->lastport)) ++ goto again; ++ } ++ ++ conn = 0; ++ for (c = 0; c < UIP_UDP_CONNS; ++c) { ++ if (ustack->uip_udp_conns[c].lport == 0) { ++ conn = &ustack->uip_udp_conns[c]; ++ break; ++ } ++ } ++ ++ if (conn == 0) ++ return 0; ++ ++ conn->lport = htons(ustack->lastport); ++ conn->rport = rport; ++ if (ripaddr == NULL) ++ memset(conn->ripaddr, 0, sizeof(uip_ip4addr_t)); ++ else ++ uip_ip4addr_copy(&conn->ripaddr, ripaddr); ++ conn->ttl = UIP_TTL; ++ ++ return conn; ++} ++#endif /* UIP_UDP */ ++/*---------------------------------------------------------------------------*/ ++void uip_unlisten(struct uip_stack *ustack, u16_t port) ++{ ++ u8_t c; ++ ++ for (c = 0; c < UIP_LISTENPORTS; ++c) { ++ if (ustack->uip_listenports[c] == port) { ++ ustack->uip_listenports[c] = 0; ++ return; ++ } ++ } ++} ++ ++/*---------------------------------------------------------------------------*/ ++void uip_listen(struct uip_stack *ustack, u16_t port) ++{ ++ u8_t c; ++ ++ for (c = 0; c < UIP_LISTENPORTS; ++c) { ++ if (ustack->uip_listenports[c] == 0) { ++ ustack->uip_listenports[c] = port; ++ return; ++ } ++ } ++} ++ ++/** ++ * Is new incoming data available? ++ * ++ * Will reduce to non-zero if there is new data for the application ++ * present at the uip_appdata pointer. The size of the data is ++ * avaliable through the uip_len variable. ++ * ++ * \hideinitializer ++ */ ++int uip_newdata(struct uip_stack *ustack) ++{ ++ return ustack->uip_flags & UIP_NEWDATA; ++} ++ ++/** ++ * Has previously sent data been acknowledged? ++ * ++ * Will reduce to non-zero if the previously sent data has been ++ * acknowledged by the remote host. This means that the application ++ * can send new data. ++ * ++ * \hideinitializer ++ */ ++#define uip_acked() (uip_flags & UIP_ACKDATA) ++ ++/** ++ * Has the connection just been connected? ++ * ++ * Reduces to non-zero if the current connection has been connected to ++ * a remote host. This will happen both if the connection has been ++ * actively opened (with uip_connect()) or passively opened (with ++ * uip_listen()). ++ * ++ * \hideinitializer ++ */ ++int uip_connected(struct uip_stack *ustack) ++{ ++ return ustack->uip_flags & UIP_CONNECTED; ++} ++ ++/** ++ * Has the connection been closed by the other end? ++ * ++ * Is non-zero if the connection has been closed by the remote ++ * host. The application may then do the necessary clean-ups. ++ * ++ * \hideinitializer ++ */ ++int uip_closed(struct uip_stack *ustack) ++{ ++ return ustack->uip_flags & UIP_CLOSE; ++} ++ ++/** ++ * Has the connection been aborted by the other end? ++ * ++ * Non-zero if the current connection has been aborted (reset) by the ++ * remote host. ++ * ++ * \hideinitializer ++ */ ++int uip_aborted(struct uip_stack *ustack) ++{ ++ return ustack->uip_flags & UIP_ABORT; ++} ++ ++/** ++ * Has the connection timed out? ++ * ++ * Non-zero if the current connection has been aborted due to too many ++ * retransmissions. ++ * ++ * \hideinitializer ++ */ ++int uip_timedout(struct uip_stack *ustack) ++{ ++ return ustack->uip_flags & UIP_TIMEDOUT; ++} ++ ++/** ++ * Do we need to retransmit previously data? ++ * ++ * Reduces to non-zero if the previously sent data has been lost in ++ * the network, and the application should retransmit it. The ++ * application should send the exact same data as it did the last ++ * time, using the uip_send() function. ++ * ++ * \hideinitializer ++ */ ++int uip_rexmit(struct uip_stack *ustack) ++{ ++ return ustack->uip_flags & UIP_REXMIT; ++} ++ ++/** ++ * Is the connection being polled by uIP? ++ * ++ * Is non-zero if the reason the application is invoked is that the ++ * current connection has been idle for a while and should be ++ * polled. ++ * ++ * The polling event can be used for sending data without having to ++ * wait for the remote host to send data. ++ * ++ * \hideinitializer ++ */ ++int uip_poll(struct uip_stack *ustack) ++{ ++ return ustack->uip_flags & UIP_POLL; ++} ++ ++int uip_initialmss(struct uip_stack *ustack) ++{ ++ return ustack->uip_conn->initialmss; ++} ++ ++int uip_mss(struct uip_stack *ustack) ++{ ++ return ustack->uip_conn->mss; ++} ++ ++/*---------------------------------------------------------------------------*/ ++/* XXX: IP fragment reassembly: not well-tested. */ ++ ++#if UIP_REASSEMBLY && !UIP_CONF_IPV6 ++#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN) ++static u8_t uip_reassbuf[UIP_REASS_BUFSIZE]; ++static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)]; ++static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f, ++ 0x0f, 0x07, 0x03, 0x01 ++}; ++static u16_t uip_reasslen; ++static u8_t uip_reassflags; ++#define UIP_REASS_FLAG_LASTFRAG 0x01 ++static u8_t uip_reasstmr; ++ ++#define IP_MF 0x20 ++ ++static u8_t uip_reass(void) ++{ ++ u16_t offset, len; ++ u16_t i; ++ ++ /* If ip_reasstmr is zero, no packet is present in the buffer, so we ++ write the IP header of the fragment into the reassembly ++ buffer. The timer is updated with the maximum age. */ ++ if (uip_reasstmr == 0) { ++ memcpy(uip_reassbuf, &BUF(ustack)->vhl, uip_iph_len); ++ uip_reasstmr = UIP_REASS_MAXAGE; ++ uip_reassflags = 0; ++ /* Clear the bitmap. */ ++ memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap)); ++ } ++ ++ /* Check if the incoming fragment matches the one currently present ++ in the reasembly buffer. If so, we proceed with copying the ++ fragment into the buffer. */ ++ if (BUF(ustack)->srcipaddr[0] == FBUF(ustack)->srcipaddr[0] && ++ BUF(ustack)->srcipaddr[1] == FBUF(ustack)->srcipaddr[1] && ++ BUF(ustack)->destipaddr[0] == FBUF(ustack)->destipaddr[0] && ++ BUF(ustack)->destipaddr[1] == FBUF(ustack)->destipaddr[1] && ++ BUF(ustack)->ipid[0] == FBUF(ustack)->ipid[0] && ++ BUF(ustack)->ipid[1] == FBUF(ustack)->ipid[1]) { ++ ++ len = ++ (BUF(ustack)->len[0] << 8) + BUF(ustack)->len[1] - ++ (BUF(ustack)->vhl & 0x0f) * 4; ++ offset = ++ (((BUF(ustack)->ipoffset[0] & 0x3f) << 8) + ++ BUF(ustack)->ipoffset[1]) * 8; ++ ++ /* If the offset or the offset + fragment length overflows the ++ reassembly buffer, we discard the entire packet. */ ++ if (offset > UIP_REASS_BUFSIZE || ++ offset + len > UIP_REASS_BUFSIZE) { ++ uip_reasstmr = 0; ++ goto nullreturn; ++ } ++ ++ /* Copy the fragment into the reassembly buffer, at the right ++ offset. */ ++ memcpy(&uip_reassbuf[uip_iph_len + offset], ++ (char *)BUF + (int)((BUF(ustack)->vhl & 0x0f) * 4), len); ++ ++ /* Update the bitmap. */ ++ if (offset / (8 * 8) == (offset + len) / (8 * 8)) { ++ /* If the two endpoints are in the same byte, we only ++ update that byte. */ ++ ++ uip_reassbitmap[offset / (8 * 8)] |= ++ bitmap_bits[(offset / 8) & 7] & ++ ~bitmap_bits[((offset + len) / 8) & 7]; ++ } else { ++ /* If the two endpoints are in different bytes, we ++ update the bytes in the endpoints and fill the ++ stuff inbetween with 0xff. */ ++ uip_reassbitmap[offset / (8 * 8)] |= ++ bitmap_bits[(offset / 8) & 7]; ++ for (i = 1 + offset / (8 * 8); ++ i < (offset + len) / (8 * 8); ++i) { ++ uip_reassbitmap[i] = 0xff; ++ } ++ uip_reassbitmap[(offset + len) / (8 * 8)] |= ++ ~bitmap_bits[((offset + len) / 8) & 7]; ++ } ++ ++ /* If this fragment has the More Fragments flag set to zero, we ++ know that this is the last fragment, so we can calculate the ++ size of the entire packet. We also set the ++ IP_REASS_FLAG_LASTFRAG flag to indicate that we have received ++ the final fragment. */ ++ ++ if ((BUF(ustack)->ipoffset[0] & IP_MF) == 0) { ++ uip_reassflags |= UIP_REASS_FLAG_LASTFRAG; ++ uip_reasslen = offset + len; ++ } ++ ++ /* Finally, we check if we have a full packet in the buffer. ++ We do this by checking if we have the last fragment and if ++ all bits in the bitmap are set. */ ++ if (uip_reassflags & UIP_REASS_FLAG_LASTFRAG) { ++ /* Check all bytes up to and including all but the last ++ byte in the bitmap. */ ++ for (i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) { ++ if (uip_reassbitmap[i] != 0xff) ++ goto nullreturn; ++ } ++ /* Check the last byte in the bitmap. It should contain ++ just the right amount of bits. */ ++ if (uip_reassbitmap[uip_reasslen / (8 * 8)] != ++ (u8_t) ~bitmap_bits[uip_reasslen / 8 & 7]) ++ goto nullreturn; ++ ++ /* If we have come this far, we have a full packet in ++ the buffer, so we allocate a pbuf and copy the ++ packet into it. We also reset the timer. */ ++ uip_reasstmr = 0; ++ memcpy(BUF, FBUF, uip_reasslen); ++ ++ /* Pretend to be a "normal" (i.e., not fragmented) IP ++ packet from now on. */ ++ BUF(ustack)->ipoffset[0] = BUF(ustack)->ipoffset[1] = 0; ++ BUF(ustack)->len[0] = uip_reasslen >> 8; ++ BUF(ustack)->len[1] = uip_reasslen & 0xff; ++ BUF(ustack)->ipchksum = 0; ++ BUF(ustack)->ipchksum = ~(uip_ipchksum()); ++ ++ return uip_reasslen; ++ } ++ } ++ ++nullreturn: ++ return 0; ++} ++#endif /* UIP_REASSEMBLY */ ++/*---------------------------------------------------------------------------*/ ++static void uip_add_rcv_nxt(struct uip_stack *ustack, u16_t n) ++{ ++ u8_t uip_acc32[4]; ++ ++ uip_add32(ustack->uip_conn->rcv_nxt, n, uip_acc32); ++ ustack->uip_conn->rcv_nxt[0] = uip_acc32[0]; ++ ustack->uip_conn->rcv_nxt[1] = uip_acc32[1]; ++ ustack->uip_conn->rcv_nxt[2] = uip_acc32[2]; ++ ustack->uip_conn->rcv_nxt[3] = uip_acc32[3]; ++} ++ ++/*---------------------------------------------------------------------------*/ ++ ++/** @} */ ++ ++/** ++ * \defgroup uipdevfunc uIP device driver functions ++ * @{ ++ * ++ * These functions are used by a network device driver for interacting ++ * with uIP. ++ */ ++ ++/** ++ * Process an incoming packet. ++ * ++ * This function should be called when the device driver has received ++ * a packet from the network. The packet from the device driver must ++ * be present in the uip_buf buffer, and the length of the packet ++ * should be placed in the uip_len variable. ++ * ++ * When the function returns, there may be an outbound packet placed ++ * in the uip_buf packet buffer. If so, the uip_len variable is set to ++ * the length of the packet. If no packet is to be sent out, the ++ * uip_len variable is set to 0. ++ * ++ * The usual way of calling the function is presented by the source ++ * code below. ++ \code ++ uip_len = devicedriver_poll(); ++ if(uip_len > 0) { ++ uip_input(); ++ if(uip_len > 0) { ++ devicedriver_send(); ++ } ++ } ++ \endcode ++ * ++ * \note If you are writing a uIP device driver that needs ARP ++ * (Address Resolution Protocol), e.g., when running uIP over ++ * Ethernet, you will need to call the uIP ARP code before calling ++ * this function: ++ \code ++ #define BUF ((struct uip_eth_hdr *)&uip_buf[0]) ++ uip_len = ethernet_devicedrver_poll(); ++ if(uip_len > 0) { ++ if (BUF(ustack)->type == HTONS(UIP_ETHTYPE_IP)) { ++ uip_arp_ipin(); ++ uip_input(); ++ if (uip_len > 0) { ++ uip_arp_out(); ++ ethernet_devicedriver_send(); ++ } ++ } else if (BUF(ustack)->type == HTONS(UIP_ETHTYPE_ARP)) { ++ uip_arp_arpin(); ++ if (uip_len > 0) ++ ethernet_devicedriver_send(); ++ } ++ \endcode ++ * ++ * \hideinitializer ++ */ ++void uip_input(struct uip_stack *ustack) ++{ ++ uip_process(ustack, UIP_DATA); ++} ++ ++/** ++ * Periodic processing for a connection identified by its number. ++ * ++ * This function does the necessary periodic processing (timers, ++ * polling) for a uIP TCP conneciton, and should be called when the ++ * periodic uIP timer goes off. It should be called for every ++ * connection, regardless of whether they are open of closed. ++ * ++ * When the function returns, it may have an outbound packet waiting ++ * for service in the uIP packet buffer, and if so the uip_len ++ * variable is set to a value larger than zero. The device driver ++ * should be called to send out the packet. ++ * ++ * The ususal way of calling the function is through a for() loop like ++ * this: ++ \code ++ for(i = 0; i < UIP_CONNS; ++i) { ++ uip_periodic(i); ++ if(uip_len > 0) { ++ devicedriver_send(); ++ } ++ } ++ \endcode ++ * ++ * \note If you are writing a uIP device driver that needs ARP ++ * (Address Resolution Protocol), e.g., when running uIP over ++ * Ethernet, you will need to call the uip_arp_out() function before ++ * calling the device driver: ++ \code ++ for(i = 0; i < UIP_CONNS; ++i) { ++ uip_periodic(i); ++ if(uip_len > 0) { ++ uip_arp_out(); ++ ethernet_devicedriver_send(); ++ } ++ } ++ \endcode ++ * ++ * \param conn The number of the connection which is to be periodically polled. ++ * ++ * \hideinitializer ++ */ ++void uip_periodic(struct uip_stack *ustack, int conn) ++{ ++ ustack->uip_conn = &ustack->uip_conns[conn]; ++ uip_process(ustack, UIP_TIMER); ++} ++ ++#if UIP_UDP ++/** ++ * Periodic processing for a UDP connection identified by its number. ++ * ++ * This function is essentially the same as uip_periodic(), but for ++ * UDP connections. It is called in a similar fashion as the ++ * uip_periodic() function: ++ \code ++ for(i = 0; i < UIP_UDP_CONNS; i++) { ++ uip_udp_periodic(i); ++ if(uip_len > 0) { ++ devicedriver_send(); ++ } ++ } ++ \endcode ++ * ++ * \note As for the uip_periodic() function, special care has to be ++ * taken when using uIP together with ARP and Ethernet: ++ \code ++ for(i = 0; i < UIP_UDP_CONNS; i++) { ++ uip_udp_periodic(i); ++ if(uip_len > 0) { ++ uip_arp_out(); ++ ethernet_devicedriver_send(); ++ } ++ } ++ \endcode ++ * ++ * \param conn The number of the UDP connection to be processed. ++ * ++ * \hideinitializer ++ */ ++void uip_udp_periodic(struct uip_stack *ustack, int conn) ++{ ++ ustack->uip_udp_conn = &ustack->uip_udp_conns[conn]; ++ uip_process(ustack, UIP_UDP_TIMER); ++} ++#endif ++ ++void uip_ndp_periodic(struct uip_stack *ustack) ++{ ++ uip_process(ustack, UIP_NDP_TIMER); ++} ++ ++void uip_process(struct uip_stack *ustack, u8_t flag) ++{ ++ u8_t c; ++ u16_t tmp16; ++ register struct uip_conn *uip_connr = ustack->uip_conn; ++ ++ u16_t uip_iph_len = 0; ++ u16_t uip_ip_udph_len = 0; ++ u16_t uip_ip_tcph_len = 0; ++ struct ip6_hdr *ipv6_hdr = NULL; ++ struct uip_tcp_ipv4_hdr *tcp_ipv4_hdr = NULL; ++ struct uip_tcp_hdr *tcp_hdr = NULL; ++ struct uip_icmpv4_hdr *icmpv4_hdr = NULL; ++ struct uip_icmpv6_hdr *icmpv6_hdr __attribute__((__unused__)) = NULL; ++ struct uip_udp_hdr *udp_hdr = NULL; ++ ++ /* Drop invalid packets */ ++ if (ustack->uip_buf == NULL) { ++ LOG_ERR(PFX "ustack->uip_buf == NULL."); ++ return; ++ } ++ ++ if (is_ipv6(ustack)) { ++ uint8_t *buf; ++ uip_iph_len = UIP_IPv6_H_LEN; ++ uip_ip_udph_len = UIP_IPv6_UDPH_LEN; ++ uip_ip_tcph_len = UIP_IPv6_TCPH_LEN; ++ ++ ipv6_hdr = (struct ip6_hdr *)ustack->network_layer; ++ ++ buf = ustack->network_layer; ++ buf += sizeof(struct uip_ipv6_hdr); ++ tcp_hdr = (struct uip_tcp_hdr *)buf; ++ ++ buf = ustack->network_layer; ++ buf += sizeof(struct uip_ipv6_hdr); ++ udp_hdr = (struct uip_udp_hdr *)buf; ++ ++ buf = ustack->network_layer; ++ buf += sizeof(struct uip_ipv6_hdr); ++ icmpv6_hdr = (struct uip_icmpv6_hdr *)buf; ++ } else { ++ uint8_t *buf; ++ ++ uip_iph_len = UIP_IPv4_H_LEN; ++ uip_ip_udph_len = UIP_IPv4_UDPH_LEN; ++ uip_ip_tcph_len = UIP_IPv4_TCPH_LEN; ++ ++ tcp_ipv4_hdr = (struct uip_tcp_ipv4_hdr *)ustack->network_layer; ++ ++ buf = ustack->network_layer; ++ buf += sizeof(struct uip_ipv4_hdr); ++ tcp_hdr = (struct uip_tcp_hdr *)buf; ++ ++ buf = ustack->network_layer; ++ buf += sizeof(struct uip_ipv4_hdr); ++ icmpv4_hdr = (struct uip_icmpv4_hdr *)buf; ++ ++ buf = ustack->network_layer; ++ buf += sizeof(struct uip_ipv4_hdr); ++ udp_hdr = (struct uip_udp_hdr *)buf; ++ } /* End of ipv6 */ ++ ++#if UIP_UDP ++ if (flag == UIP_UDP_SEND_CONN) ++ goto udp_send; ++#endif /* UIP_UDP */ ++ ustack->uip_sappdata = ustack->uip_appdata = ustack->network_layer + ++ uip_ip_tcph_len; ++ ++ /* Check if we were invoked because of a poll request for a ++ particular connection. */ ++ if (flag == UIP_POLL_REQUEST) { ++ if ((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED ++ && !uip_outstanding(uip_connr)) { ++ ustack->uip_flags = UIP_POLL; ++ UIP_APPCALL(ustack); ++ goto appsend; ++ } ++ goto drop; ++ ++ /* Check if we were invoked because of the perodic timer ++ firing. */ ++ } else if (flag == UIP_TIMER) { ++#if UIP_REASSEMBLY ++ if (uip_reasstmr != 0) ++ --uip_reasstmr; ++#endif /* UIP_REASSEMBLY */ ++ /* Increase the initial sequence number. */ ++ if (++ustack->iss[3] == 0) { ++ if (++ustack->iss[2] == 0) { ++ if (++ustack->iss[1] == 0) ++ ++ustack->iss[0]; ++ } ++ } ++ ++ /* Reset the length variables. */ ++ ustack->uip_len = 0; ++ ustack->uip_slen = 0; ++ ++ /* Check if the connection is in a state in which we simply wait ++ for the connection to time out. If so, we increase the ++ connection's timer and remove the connection if it times ++ out. */ ++ if (uip_connr->tcpstateflags == UIP_TIME_WAIT || ++ uip_connr->tcpstateflags == UIP_FIN_WAIT_2) { ++ ++(uip_connr->timer); ++ if (uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) ++ uip_connr->tcpstateflags = UIP_CLOSED; ++ } else if (uip_connr->tcpstateflags != UIP_CLOSED) { ++ /* If the connection has outstanding data, we increase ++ the connection's timer and see if it has reached the ++ RTO value in which case we retransmit. */ ++ if (uip_outstanding(uip_connr)) { ++ if (uip_connr->timer-- == 0) { ++ if (uip_connr->nrtx == UIP_MAXRTX || ++ ((uip_connr->tcpstateflags == ++ UIP_SYN_SENT ++ || uip_connr->tcpstateflags == ++ UIP_SYN_RCVD) ++ && uip_connr->nrtx == ++ UIP_MAXSYNRTX)) { ++ uip_connr->tcpstateflags = ++ UIP_CLOSED; ++ ++ /* We call UIP_APPCALL() with ++ uip_flags set to UIP_TIMEDOUT ++ to inform the application ++ that the connection has timed ++ out. */ ++ ustack->uip_flags = ++ UIP_TIMEDOUT; ++ UIP_APPCALL(ustack); ++ ++ /* We also send a reset packet ++ to the remote host. */ ++ tcp_hdr->flags = ++ TCP_RST | TCP_ACK; ++ goto tcp_send_nodata; ++ } ++ ++ /* Exponential backoff. */ ++ uip_connr->timer = ++ UIP_RTO << (uip_connr->nrtx > ++ 4 ? 4 : uip_connr-> ++ nrtx); ++ ++(uip_connr->nrtx); ++ ++ /* Ok, so we need to retransmit. ++ We do this differently depending on ++ which state we are in. ++ In ESTABLISHED, we call upon the ++ application so that it may prepare ++ the data for the retransmit. ++ In SYN_RCVD, we resend the SYNACK ++ that we sent earlier and in LAST_ACK ++ we have to retransmit our FINACK. */ ++ ++ustack->stats.tcp.rexmit; ++ switch (uip_connr-> ++ tcpstateflags & UIP_TS_MASK) { ++ case UIP_SYN_RCVD: ++ /* In the SYN_RCVD state, we ++ should retransmit our SYNACK ++ */ ++ goto tcp_send_synack; ++#if UIP_ACTIVE_OPEN ++ case UIP_SYN_SENT: ++ /* In the SYN_SENT state, ++ we retransmit out SYN. */ ++ tcp_hdr->flags = 0; ++ goto tcp_send_syn; ++#endif /* UIP_ACTIVE_OPEN */ ++ ++ case UIP_ESTABLISHED: ++ /* In the ESTABLISHED state, ++ we call upon the application ++ to do the actual retransmit ++ after which we jump into ++ the code for sending out the ++ packet (the apprexmit ++ label). */ ++ ustack->uip_flags = UIP_REXMIT; ++ UIP_APPCALL(ustack); ++ goto apprexmit; ++ ++ case UIP_FIN_WAIT_1: ++ case UIP_CLOSING: ++ case UIP_LAST_ACK: ++ /* In all these states we should ++ retransmit a FINACK. */ ++ goto tcp_send_finack; ++ ++ } ++ } ++ } else if ((uip_connr->tcpstateflags & UIP_TS_MASK) == ++ UIP_ESTABLISHED) { ++ /* If there was no need for a retransmission, ++ we poll the application for new data. */ ++ ustack->uip_flags = UIP_POLL; ++ UIP_APPCALL(ustack); ++ goto appsend; ++ } ++ } ++ goto drop; ++ } /* End of UIP_TIMER */ ++#if UIP_UDP ++ if (flag == UIP_UDP_TIMER) { ++ /* This is for IPv4 DHCP only! */ ++ if (ustack->uip_udp_conn->lport != 0) { ++ ustack->uip_conn = NULL; ++ ustack->uip_sappdata = ustack->uip_appdata = ++ ustack->network_layer + uip_ip_udph_len; ++ ustack->uip_len = ustack->uip_slen = 0; ++ ustack->uip_flags = UIP_POLL; ++ UIP_UDP_APPCALL(ustack); ++ goto udp_send; ++ } else { ++ goto drop; ++ } ++ } ++#endif ++ if (flag == UIP_NDP_TIMER) { ++ /* This is for IPv6 NDP Only! */ ++ if (1) { /* If NDP engine active */ ++ ustack->uip_len = ustack->uip_slen = 0; ++ ustack->uip_flags = UIP_POLL; ++ goto ndp_send; ++ } ++ } ++ ++ /* This is where the input processing starts. */ ++ ++ustack->stats.ip.recv; ++ ++ /* Start of IP input header processing code. */ ++ ++ if (is_ipv6(ustack)) { ++ u8_t version = ((ipv6_hdr->ip6_vfc) & 0xf0) >> 4; ++ ++ /* Check validity of the IP header. */ ++ if (version != 0x6) { /* IP version and header length. */ ++ ++ustack->stats.ip.drop; ++ ++ustack->stats.ip.vhlerr; ++ LOG_DEBUG(PFX "ipv6: invalid version(0x%x).", version); ++ goto drop; ++ } ++ } else { ++ /* Check validity of the IP header. */ ++ if (tcp_ipv4_hdr->vhl != 0x45) { ++ /* IP version and header length. */ ++ ++ustack->stats.ip.drop; ++ ++ustack->stats.ip.vhlerr; ++ LOG_DEBUG(PFX ++ "ipv4: invalid version or header length: " ++ "0x%x.", ++ tcp_ipv4_hdr->vhl); ++ goto drop; ++ } ++ } ++ ++ /* Check the size of the packet. If the size reported to us in ++ uip_len is smaller the size reported in the IP header, we assume ++ that the packet has been corrupted in transit. If the size of ++ uip_len is larger than the size reported in the IP packet header, ++ the packet has been padded and we set uip_len to the correct ++ value.. */ ++ ++ if (is_ipv6(ustack)) { ++ u16_t len = ntohs(ipv6_hdr->ip6_plen); ++ if (len > ustack->uip_len) { ++ LOG_DEBUG(PFX ++ "ip: packet shorter than reported in IP header" ++ ":IPv6_BUF(ustack)->len: %d ustack->uip_len: " ++ "%d", len, ustack->uip_len); ++ goto drop; ++ } ++ } else { ++ if ((tcp_ipv4_hdr->len[0] << 8) + ++ tcp_ipv4_hdr->len[1] <= ustack->uip_len) { ++ ustack->uip_len = (tcp_ipv4_hdr->len[0] << 8) + ++ tcp_ipv4_hdr->len[1]; ++ } else { ++ LOG_DEBUG(PFX ++ "ip: packet shorter than reported in IP header" ++ ":tcp_ipv4_hdr->len: %d ustack->uip_len:%d.", ++ (tcp_ipv4_hdr->len[0] << 8) + ++ tcp_ipv4_hdr->len[1], ustack->uip_len); ++ goto drop; ++ } ++ } ++ ++ if (!is_ipv6(ustack)) { ++ /* Check the fragment flag. */ ++ if ((tcp_ipv4_hdr->ipoffset[0] & 0x3f) != 0 || ++ tcp_ipv4_hdr->ipoffset[1] != 0) { ++#if UIP_REASSEMBLY ++ uip_len = uip_reass(); ++ if (uip_len == 0) ++ goto drop; ++#else /* UIP_REASSEMBLY */ ++ ++ustack->stats.ip.drop; ++ ++ustack->stats.ip.fragerr; ++ LOG_WARN(PFX "ip: fragment dropped."); ++ goto drop; ++#endif /* UIP_REASSEMBLY */ ++ } ++ } ++ ++ if (!is_ipv6(ustack)) { ++ /* ipv4 */ ++ if (uip_ip4addr_cmp(ustack->hostaddr, all_zeroes_addr4)) { ++ /* If we are configured to use ping IP address ++ configuration and hasn't been assigned an IP ++ address yet, we accept all ICMP packets. */ ++#if UIP_PINGADDRCONF && !UIP_CONF_IPV6 ++ if (tcp_ipv4_hdr->proto == UIP_PROTO_ICMP) { ++ LOG_WARN(PFX ++ "ip: possible ping config packet " ++ "received."); ++ goto icmp_input; ++ } else { ++ LOG_WARN(PFX ++ "ip: packet dropped since no " ++ "address assigned."); ++ goto drop; ++ } ++#endif /* UIP_PINGADDRCONF */ ++ } else { ++ int broadcast_addr = 0xFFFFFFFF; ++ /* If IP broadcast support is configured, we check for ++ a broadcast UDP packet, which may be destined to us ++ */ ++ if ((tcp_ipv4_hdr->proto == UIP_PROTO_UDP) && ++ (uip_ip4addr_cmp ++ (tcp_ipv4_hdr->destipaddr, &broadcast_addr)) ++ /*&& ++ uip_ipchksum() == 0xffff */ ++ ) { ++ goto udp_input; ++ } ++ ++ /* Check if the packet is destined for our IP address ++ */ ++ if (!uip_ip4addr_cmp(tcp_ipv4_hdr->destipaddr, ++ ustack->hostaddr)) { ++ ++ustack->stats.ip.drop; ++ goto drop; ++ } ++ } ++ if (uip_ipchksum(ustack) != 0xffff) { ++ /* Compute and check the IP header checksum. */ ++ ++ustack->stats.ip.drop; ++ ++ustack->stats.ip.chkerr; ++ LOG_ERR(PFX "ip: bad checksum."); ++ goto drop; ++ } ++ } /* End of ipv4 */ ++ ++ if (is_ipv6(ustack)) { ++ if (ipv6_hdr->ip6_nxt == UIP_PROTO_TCP) { ++ /* Check for TCP packet. If so, proceed with TCP input ++ processing. */ ++ goto ndp_newdata; ++ } ++#if UIP_UDP ++ if (ipv6_hdr->ip6_nxt == UIP_PROTO_UDP) ++ goto ndp_newdata; ++#endif /* UIP_UDP */ ++ ++ /* This is IPv6 ICMPv6 processing code. */ ++ if (ipv6_hdr->ip6_nxt != UIP_PROTO_ICMP6) { ++ /* We only allow ICMPv6 packets from here. */ ++ ++ustack->stats.ip.drop; ++ ++ustack->stats.ip.protoerr; ++ goto drop; ++ } ++ ++ ++ustack->stats.icmp.recv; ++ ++ndp_newdata: ++ /* This call is to handle the IPv6 Network Discovery Protocol */ ++ ustack->uip_flags = UIP_NEWDATA; ++ ustack->uip_slen = 0; ++ndp_send: ++ UIP_NDP_CALL(ustack); ++ if (ustack->uip_slen != 0) { ++ ustack->uip_len = ustack->uip_slen; ++ goto send; ++ } else { ++ goto drop; ++ } ++ } else { ++ /* IPv4 Processing */ ++ if (tcp_ipv4_hdr->proto == UIP_PROTO_TCP) { ++ /* Check for TCP packet. If so, proceed with TCP input ++ processing. */ ++ goto tcp_input; ++ } ++#if UIP_UDP ++ if (tcp_ipv4_hdr->proto == UIP_PROTO_UDP) ++ goto udp_input; ++#endif /* UIP_UDP */ ++ ++ /* ICMPv4 processing code follows. */ ++ if (tcp_ipv4_hdr->proto != UIP_PROTO_ICMP) { ++ /* We only allow ICMP packets from here. */ ++ ++ustack->stats.ip.drop; ++ ++ustack->stats.ip.protoerr; ++ LOG_DEBUG(PFX "ip: neither tcp nor icmp."); ++ goto drop; ++ } ++#if UIP_PINGADDRCONF ++icmp_input: ++#endif /* UIP_PINGADDRCONF */ ++ ++ustack->stats.icmp.recv; ++ ++ if (icmpv4_hdr->type == ICMP_ECHO_REPLY) { ++ if (process_icmp_packet(icmpv4_hdr, ustack) == 0) ++ goto drop; ++ } ++ ++ /* ICMP echo (i.e., ping) processing. This is simple, we only ++ change the ICMP type from ECHO to ECHO_REPLY and adjust the ++ ICMP checksum before we return the packet. */ ++ if (icmpv4_hdr->type != ICMP_ECHO) { ++ ++ustack->stats.icmp.drop; ++ ++ustack->stats.icmp.typeerr; ++ LOG_DEBUG(PFX "icmp: not icmp echo."); ++ goto drop; ++ } ++ ++ /* If we are configured to use ping IP address assignment, we ++ use the destination IP address of this ping packet and assign ++ it to ourself. */ ++#if UIP_PINGADDRCONF ++ if ((ustack->hostaddr[0] | ustack->hostaddr[1]) == 0) { ++ ustack->hostaddr[0] = tcp_ipv4_hdr->destipaddr[0]; ++ ustack->hostaddr[1] = tcp_ipv4_hdr->destipaddr[1]; ++ } ++#endif /* UIP_PINGADDRCONF */ ++ ++ icmpv4_hdr->type = ICMP_ECHO_REPLY; ++ ++ if (icmpv4_hdr->icmpchksum >= htons(0xffff - ++ (ICMP_ECHO << 8))) { ++ icmpv4_hdr->icmpchksum += htons(ICMP_ECHO << 8) + 1; ++ } else { ++ icmpv4_hdr->icmpchksum += htons(ICMP_ECHO << 8); ++ } ++ ++ /* Swap IP addresses. */ ++ uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr, ++ tcp_ipv4_hdr->srcipaddr); ++ uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr); ++ ++ ++ustack->stats.icmp.sent; ++ goto send; ++ ++ /* End of IPv4 input header processing code. */ ++ } ++ ++#if UIP_UDP ++ /* UDP input processing. */ ++udp_input: ++ /* UDP processing is really just a hack. We don't do anything to the ++ UDP/IP headers, but let the UDP application do all the hard ++ work. If the application sets uip_slen, it has a packet to ++ send. */ ++#if UIP_UDP_CHECKSUMS ++ ustack->uip_len = ustack->uip_len - uip_ip_udph_len; ++ ustack->uip_appdata = ustack->network_layer + uip_ip_udph_len; ++ if (UDPBUF(ustack)->udpchksum != 0 && uip_udpchksum(ustack) != 0xffff) { ++ ++ustack->stats.udp.drop; ++ ++ustack->stats.udp.chkerr; ++ LOG_DEBUG(PFX "udp: bad checksum."); ++ goto drop; ++ } ++#else /* UIP_UDP_CHECKSUMS */ ++ uip_len = uip_len - uip_ip_udph_len; ++#endif /* UIP_UDP_CHECKSUMS */ ++ ++ if (is_ipv6(ustack)) ++ goto udp_found; ++ ++ /* Demultiplex this UDP packet between the UDP "connections". */ ++ for (ustack->uip_udp_conn = &ustack->uip_udp_conns[0]; ++ ustack->uip_udp_conn < &ustack->uip_udp_conns[UIP_UDP_CONNS]; ++ ++ustack->uip_udp_conn) { ++ /* If the local UDP port is non-zero, the connection is ++ considered to be used. If so, the local port number is ++ checked against the destination port number in the ++ received packet. If the two port ++ numbers match, the remote port number is checked if the ++ connection is bound to a remote port. Finally, if the ++ connection is bound to a remote IP address, the source IP ++ address of the packet is checked. */ ++ ++ if (ustack->uip_udp_conn->lport != 0 && ++ UDPBUF(ustack)->destport == ustack->uip_udp_conn->lport && ++ (ustack->uip_udp_conn->rport == 0 || ++ UDPBUF(ustack)->srcport == ustack->uip_udp_conn->rport) && ++ (uip_ip4addr_cmp(ustack->uip_udp_conn->ripaddr, ++ all_zeroes_addr4) || ++ uip_ip4addr_cmp(ustack->uip_udp_conn->ripaddr, ++ all_ones_addr4) || ++ uip_ip4addr_cmp(tcp_ipv4_hdr->srcipaddr, ++ ustack->uip_udp_conn->ripaddr))) { ++ goto udp_found; ++ } ++ } ++ LOG_DEBUG(PFX ++ "udp: no matching connection found: dest port: %d src port: " ++ "%d", udp_hdr->destport, udp_hdr->srcport); ++ goto drop; ++ ++udp_found: ++ ustack->uip_conn = NULL; ++ ustack->uip_flags = UIP_NEWDATA; ++ ustack->uip_sappdata = ustack->uip_appdata = ustack->network_layer + ++ uip_ip_udph_len; ++ ustack->uip_slen = 0; ++ if (is_ipv6(ustack)) ++ UIP_NDP_CALL(ustack); ++ else ++ UIP_UDP_APPCALL(ustack); ++udp_send: ++ if (ustack->uip_slen == 0) ++ goto drop; ++ ++ ustack->uip_len = ustack->uip_slen + uip_ip_udph_len; ++ ++ if (is_ipv6(ustack)) { ++ goto ip_send_nolen; ++ } else { ++ tcp_ipv4_hdr->len[0] = (ustack->uip_len >> 8); ++ tcp_ipv4_hdr->len[1] = (ustack->uip_len & 0xff); ++ tcp_ipv4_hdr->ttl = ustack->uip_udp_conn->ttl; ++ tcp_ipv4_hdr->proto = UIP_PROTO_UDP; ++ } ++ ++ udp_hdr->udplen = htons(ustack->uip_slen + UIP_UDPH_LEN); ++ udp_hdr->udpchksum = 0; ++ ++ udp_hdr->srcport = ustack->uip_udp_conn->lport; ++ udp_hdr->destport = ustack->uip_udp_conn->rport; ++ ++ uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr); ++ uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr, ++ ustack->uip_udp_conn->ripaddr); ++ ++ ustack->uip_appdata = ustack->network_layer + uip_ip_tcph_len; ++ ++ if (ustack->uip_buf == NULL) { ++ LOG_WARN(PFX "uip_buf == NULL on udp send"); ++ goto drop; ++ } ++#if UIP_UDP_CHECKSUMS ++ /* Calculate UDP checksum. */ ++ udp_hdr->udpchksum = ~(uip_udpchksum(ustack)); ++ if (udp_hdr->udpchksum == 0) ++ udp_hdr->udpchksum = 0xffff; ++#endif /* UIP_UDP_CHECKSUMS */ ++ ++ goto ip_send_nolen; ++#endif /* UIP_UDP */ ++ ++ /* TCP input processing. */ ++tcp_input: ++ ++ustack->stats.tcp.recv; ++ ++ /* Start of TCP input header processing code. */ ++ ++ if (uip_tcpchksum(ustack) != 0xffff) { /* Compute and check the TCP ++ checksum. */ ++ ++ustack->stats.tcp.drop; ++ ++ustack->stats.tcp.chkerr; ++ LOG_WARN(PFX "tcp: bad checksum."); ++ goto drop; ++ } ++ ++ if (is_ipv6(ustack)) { ++ /* Demultiplex this segment. */ ++ /* First check any active connections. */ ++ for (uip_connr = &ustack->uip_conns[0]; ++ uip_connr <= &ustack->uip_conns[UIP_CONNS - 1]; ++ ++uip_connr) { ++ if (uip_connr->tcpstateflags != UIP_CLOSED && ++ tcp_hdr->destport == uip_connr->lport && ++ tcp_hdr->srcport == uip_connr->rport && ++ uip_ip6addr_cmp(IPv6_BUF(ustack)->srcipaddr, ++ uip_connr->ripaddr)) { ++ goto found; ++ } ++ } ++ } else { ++ /* Demultiplex this segment. */ ++ /* First check any active connections. */ ++ for (uip_connr = &ustack->uip_conns[0]; ++ uip_connr <= &ustack->uip_conns[UIP_CONNS - 1]; ++ ++uip_connr) { ++ if (uip_connr->tcpstateflags != UIP_CLOSED && ++ tcp_hdr->destport == uip_connr->lport && ++ tcp_hdr->srcport == uip_connr->rport && ++ uip_ip4addr_cmp(tcp_ipv4_hdr->srcipaddr, ++ uip_connr->ripaddr)) { ++ goto found; ++ } ++ } ++ } ++ ++ /* If we didn't find and active connection that expected the packet, ++ either this packet is an old duplicate, or this is a SYN packet ++ destined for a connection in LISTEN. If the SYN flag isn't set, ++ it is an old packet and we send a RST. */ ++ if ((tcp_hdr->flags & TCP_CTL) != TCP_SYN) ++ goto reset; ++ ++ tmp16 = tcp_hdr->destport; ++ /* Next, check listening connections. */ ++ for (c = 0; c < UIP_LISTENPORTS; ++c) { ++ if (tmp16 == ustack->uip_listenports[c]) ++ goto found_listen; ++ } ++ ++ /* No matching connection found, so we send a RST packet. */ ++ ++ustack->stats.tcp.synrst; ++reset: ++ ++ /* We do not send resets in response to resets. */ ++ if (tcp_hdr->flags & TCP_RST) ++ goto drop; ++ ++ ++ustack->stats.tcp.rst; ++ ++ tcp_hdr->flags = TCP_RST | TCP_ACK; ++ ustack->uip_len = uip_ip_tcph_len; ++ tcp_hdr->tcpoffset = 5 << 4; ++ ++ /* Flip the seqno and ackno fields in the TCP header. */ ++ c = tcp_hdr->seqno[3]; ++ tcp_hdr->seqno[3] = tcp_hdr->ackno[3]; ++ tcp_hdr->ackno[3] = c; ++ ++ c = tcp_hdr->seqno[2]; ++ tcp_hdr->seqno[2] = tcp_hdr->ackno[2]; ++ tcp_hdr->ackno[2] = c; ++ ++ c = tcp_hdr->seqno[1]; ++ tcp_hdr->seqno[1] = tcp_hdr->ackno[1]; ++ tcp_hdr->ackno[1] = c; ++ ++ c = tcp_hdr->seqno[0]; ++ tcp_hdr->seqno[0] = tcp_hdr->ackno[0]; ++ tcp_hdr->ackno[0] = c; ++ ++ /* We also have to increase the sequence number we are ++ acknowledging. If the least significant byte overflowed, we need ++ to propagate the carry to the other bytes as well. */ ++ if (++tcp_hdr->ackno[3] == 0) { ++ if (++tcp_hdr->ackno[2] == 0) { ++ if (++tcp_hdr->ackno[1] == 0) ++ ++tcp_hdr->ackno[0]; ++ } ++ } ++ ++ /* Swap port numbers. */ ++ tmp16 = tcp_hdr->srcport; ++ tcp_hdr->srcport = tcp_hdr->destport; ++ tcp_hdr->destport = tmp16; ++ ++ /* Swap IP addresses. */ ++ if (is_ipv6(ustack)) { ++ uip_ip6addr_copy(IPv6_BUF(ustack)->destipaddr, ++ IPv6_BUF(ustack)->srcipaddr); ++ uip_ip6addr_copy(IPv6_BUF(ustack)->srcipaddr, ++ ustack->hostaddr6); ++ } else { ++ uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr, ++ tcp_ipv4_hdr->srcipaddr); ++ uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr); ++ } ++ ++ /* And send out the RST packet! */ ++ goto tcp_send_noconn; ++ ++ /* This label will be jumped to if we matched the incoming packet ++ with a connection in LISTEN. In that case, we should create a new ++ connection and send a SYNACK in return. */ ++found_listen: ++ /* First we check if there are any connections avaliable. Unused ++ connections are kept in the same table as used connections, but ++ unused ones have the tcpstate set to CLOSED. Also, connections in ++ TIME_WAIT are kept track of and we'll use the oldest one if no ++ CLOSED connections are found. Thanks to Eddie C. Dost for a very ++ nice algorithm for the TIME_WAIT search. */ ++ uip_connr = 0; ++ for (c = 0; c < UIP_CONNS; ++c) { ++ if (ustack->uip_conns[c].tcpstateflags == UIP_CLOSED) { ++ uip_connr = &ustack->uip_conns[c]; ++ break; ++ } ++ if (ustack->uip_conns[c].tcpstateflags == UIP_TIME_WAIT) { ++ if (uip_connr == 0 || ++ ustack->uip_conns[c].timer > uip_connr->timer) { ++ uip_connr = &ustack->uip_conns[c]; ++ } ++ } ++ } ++ ++ if (uip_connr == 0) { ++ /* All connections are used already, we drop packet and hope ++ that the remote end will retransmit the packet at a time when ++ we have more spare connections. */ ++ ++ustack->stats.tcp.syndrop; ++ LOG_WARN(PFX "tcp: found no unused connections."); ++ goto drop; ++ } ++ ustack->uip_conn = uip_connr; ++ ++ /* Fill in the necessary fields for the new connection. */ ++ uip_connr->rto = uip_connr->timer = UIP_RTO; ++ uip_connr->sa = 0; ++ uip_connr->sv = 4; ++ uip_connr->nrtx = 0; ++ uip_connr->lport = tcp_hdr->destport; ++ uip_connr->rport = tcp_hdr->srcport; ++ if (is_ipv6(ustack)) { ++ uip_ip6addr_copy(uip_connr->ripaddr, ++ IPv6_BUF(ustack)->srcipaddr); ++ } else { ++ uip_ip4addr_copy(uip_connr->ripaddr, tcp_ipv4_hdr->srcipaddr); ++ } ++ uip_connr->tcpstateflags = UIP_SYN_RCVD; ++ ++ uip_connr->snd_nxt[0] = ustack->iss[0]; ++ uip_connr->snd_nxt[1] = ustack->iss[1]; ++ uip_connr->snd_nxt[2] = ustack->iss[2]; ++ uip_connr->snd_nxt[3] = ustack->iss[3]; ++ uip_connr->len = 1; ++ ++ /* rcv_nxt should be the seqno from the incoming packet + 1. */ ++ uip_connr->rcv_nxt[3] = tcp_hdr->seqno[3]; ++ uip_connr->rcv_nxt[2] = tcp_hdr->seqno[2]; ++ uip_connr->rcv_nxt[1] = tcp_hdr->seqno[1]; ++ uip_connr->rcv_nxt[0] = tcp_hdr->seqno[0]; ++ uip_add_rcv_nxt(ustack, 1); ++ ++ /* Parse the TCP MSS option, if present. */ ++ if ((tcp_hdr->tcpoffset & 0xf0) > 0x50) { ++ for (c = 0; c < ((tcp_hdr->tcpoffset >> 4) - 5) << 2;) { ++ ustack->opt = ++ ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + c]; ++ if (ustack->opt == TCP_OPT_END) { ++ /* End of options. */ ++ break; ++ } else if (ustack->opt == TCP_OPT_NOOP) { ++ ++c; ++ /* NOP option. */ ++ } else if (ustack->opt == TCP_OPT_MSS && ++ ustack->uip_buf[uip_ip_tcph_len + ++ UIP_LLH_LEN + 1 + c] == ++ TCP_OPT_MSS_LEN) { ++ /* An MSS option with the right option length.*/ ++ tmp16 = ++ ((u16_t) ustack-> ++ uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 2 + ++ c] << 8) | (u16_t) ustack-> ++ uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 3 + ++ c]; ++ uip_connr->initialmss = uip_connr->mss = ++ tmp16 > UIP_TCP_MSS ? UIP_TCP_MSS : tmp16; ++ ++ /* And we are done processing options. */ ++ break; ++ } else { ++ /* All other options have a length field, so ++ that we easily can skip past them. */ ++ if (ustack-> ++ uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 1 + ++ c] == 0) { ++ /* If the length field is zero, the ++ options are malformed ++ and we don't process them further. */ ++ break; ++ } ++ c += ustack->uip_buf[uip_ip_tcph_len + ++ UIP_LLH_LEN + 1 + c]; ++ } ++ } ++ } ++ ++ /* Our response will be a SYNACK. */ ++#if UIP_ACTIVE_OPEN ++tcp_send_synack: ++ tcp_hdr->flags = TCP_ACK; ++ ++tcp_send_syn: ++ tcp_hdr->flags |= TCP_SYN; ++#else /* UIP_ACTIVE_OPEN */ ++tcp_send_synack: ++ tcp_hdr->flags = TCP_SYN | TCP_ACK; ++#endif /* UIP_ACTIVE_OPEN */ ++ ++ /* We send out the TCP Maximum Segment Size option with our ++ SYNACK. */ ++ tcp_hdr->optdata[0] = TCP_OPT_MSS; ++ tcp_hdr->optdata[1] = TCP_OPT_MSS_LEN; ++ tcp_hdr->optdata[2] = (UIP_TCP_MSS) / 256; ++ tcp_hdr->optdata[3] = (UIP_TCP_MSS) & 255; ++ ustack->uip_len = uip_ip_tcph_len + TCP_OPT_MSS_LEN; ++ tcp_hdr->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4; ++ goto tcp_send; ++ ++ /* This label will be jumped to if we found an active connection. */ ++found: ++ ustack->uip_conn = uip_connr; ++ ustack->uip_flags = 0; ++ /* We do a very naive form of TCP reset processing; we just accept ++ any RST and kill our connection. We should in fact check if the ++ sequence number of this reset is wihtin our advertised window ++ before we accept the reset. */ ++ if (tcp_hdr->flags & TCP_RST) { ++ uip_connr->tcpstateflags = UIP_CLOSED; ++ LOG_WARN(PFX "tcp: got reset, aborting connection."); ++ ustack->uip_flags = UIP_ABORT; ++ UIP_APPCALL(ustack); ++ goto drop; ++ } ++ /* Calculated the length of the data, if the application has sent ++ any data to us. */ ++ c = (tcp_hdr->tcpoffset >> 4) << 2; ++ /* uip_len will contain the length of the actual TCP data. This is ++ calculated by subtracing the length of the TCP header (in ++ c) and the length of the IP header (20 bytes). */ ++ ustack->uip_len = ustack->uip_len - c - uip_iph_len; ++ ++ /* First, check if the sequence number of the incoming packet is ++ what we're expecting next. If not, we send out an ACK with the ++ correct numbers in. */ ++ if (!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) && ++ ((tcp_hdr->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) { ++ if ((ustack->uip_len > 0 ++ || ((tcp_hdr->flags & (TCP_SYN | TCP_FIN)) != 0)) ++ && (tcp_hdr->seqno[0] != uip_connr->rcv_nxt[0] ++ || tcp_hdr->seqno[1] != uip_connr->rcv_nxt[1] ++ || tcp_hdr->seqno[2] != uip_connr->rcv_nxt[2] ++ || tcp_hdr->seqno[3] != uip_connr->rcv_nxt[3])) { ++ goto tcp_send_ack; ++ } ++ } ++ ++ { ++ u8_t uip_acc32[4]; ++ ++ /* Next, check if the incoming segment acks any outstanding ++ data. If so, we update the sequence number, reset the len of ++ the outstanding data, calc RTT estimations, and reset the ++ retransmission timer. */ ++ if ((tcp_hdr->flags & TCP_ACK) && uip_outstanding(uip_connr)) { ++ uip_add32(uip_connr->snd_nxt, uip_connr->len, ++ uip_acc32); ++ ++ if (tcp_hdr->ackno[0] == uip_acc32[0] && ++ tcp_hdr->ackno[1] == uip_acc32[1] && ++ tcp_hdr->ackno[2] == uip_acc32[2] && ++ tcp_hdr->ackno[3] == uip_acc32[3]) { ++ /* Update sequence number. */ ++ uip_connr->snd_nxt[0] = uip_acc32[0]; ++ uip_connr->snd_nxt[1] = uip_acc32[1]; ++ uip_connr->snd_nxt[2] = uip_acc32[2]; ++ uip_connr->snd_nxt[3] = uip_acc32[3]; ++ ++ /* Do RTT estimation, unless we have done ++ retransmissions. */ ++ if (uip_connr->nrtx == 0) { ++ signed char m; ++ m = uip_connr->rto - uip_connr->timer; ++ /* This is taken directly from VJs ++ original code in his paper */ ++ m = m - (uip_connr->sa >> 3); ++ uip_connr->sa += m; ++ if (m < 0) ++ m = -m; ++ m = m - (uip_connr->sv >> 2); ++ uip_connr->sv += m; ++ uip_connr->rto = ++ (uip_connr->sa >> 3) + ++ uip_connr->sv; ++ ++ } ++ /* Set the acknowledged flag. */ ++ ustack->uip_flags = UIP_ACKDATA; ++ /* Reset the retransmission timer. */ ++ uip_connr->timer = uip_connr->rto; ++ ++ /* Reset length of outstanding data. */ ++ uip_connr->len = 0; ++ } ++ ++ } ++ ++ } ++ ++ /* Do different things depending on in what state the connection is. */ ++ switch (uip_connr->tcpstateflags & UIP_TS_MASK) { ++ /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not ++ implemented, since we force the application to close when the ++ peer sends a FIN (hence the application goes directly from ++ ESTABLISHED to LAST_ACK). */ ++ case UIP_SYN_RCVD: ++ /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, ++ and we are waiting for an ACK that acknowledges the data we ++ sent out the last time. Therefore, we want to have the ++ UIP_ACKDATA flag set. ++ If so, we enter the ESTABLISHED state. */ ++ if (ustack->uip_flags & UIP_ACKDATA) { ++ uip_connr->tcpstateflags = UIP_ESTABLISHED; ++ ustack->uip_flags = UIP_CONNECTED; ++ uip_connr->len = 0; ++ if (ustack->uip_len > 0) { ++ ustack->uip_flags |= UIP_NEWDATA; ++ uip_add_rcv_nxt(ustack, ustack->uip_len); ++ } ++ ustack->uip_slen = 0; ++ UIP_APPCALL(ustack); ++ goto appsend; ++ } ++ goto drop; ++#if UIP_ACTIVE_OPEN ++ case UIP_SYN_SENT: ++ /* In SYN_SENT, we wait for a SYNACK that is sent in response to ++ our SYN. The rcv_nxt is set to sequence number in the SYNACK ++ plus one, and we send an ACK. We move into the ESTABLISHED ++ state. */ ++ if ((ustack->uip_flags & UIP_ACKDATA) && ++ (tcp_hdr->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) { ++ ++ /* Parse the TCP MSS option, if present. */ ++ if ((tcp_hdr->tcpoffset & 0xf0) > 0x50) { ++ for (c = 0; ++ c < ++ ((tcp_hdr->tcpoffset >> 4) - 5) << 2;) { ++ ustack->opt = ++ ustack->uip_buf[uip_ip_tcph_len + ++ UIP_LLH_LEN + c]; ++ if (ustack->opt == TCP_OPT_END) { ++ /* End of options. */ ++ break; ++ } else if (ustack->opt == ++ TCP_OPT_NOOP) { ++ ++c; ++ /* NOP option. */ ++ } else if (ustack->opt == TCP_OPT_MSS && ++ ustack-> ++ uip_buf[uip_ip_tcph_len + ++ UIP_LLH_LEN + 1 + ++ c] == ++ TCP_OPT_MSS_LEN) { ++ /* An MSS option with the right ++ option length. */ ++ tmp16 = ++ (ustack-> ++ uip_buf[uip_ip_tcph_len + ++ UIP_LLH_LEN + 2 + ++ c] << 8) | ustack-> ++ uip_buf[uip_ip_tcph_len + ++ UIP_LLH_LEN + 3 + ++ c]; ++ uip_connr->initialmss = ++ uip_connr->mss = ++ tmp16 > ++ UIP_TCP_MSS ? UIP_TCP_MSS : ++ tmp16; ++ ++ /* And we are done processing ++ options. */ ++ break; ++ } else { ++ /* All other options have a ++ length field, so that we ++ easily can skip past them */ ++ if (ustack-> ++ uip_buf[uip_ip_tcph_len + ++ UIP_LLH_LEN + 1 + ++ c] == 0) { ++ /* If the length field ++ is zero, the options ++ are malformed and we ++ don't process them ++ further. */ ++ break; ++ } ++ c += ustack-> ++ uip_buf[uip_ip_tcph_len + ++ UIP_LLH_LEN + 1 + ++ c]; ++ } ++ } ++ } ++ uip_connr->tcpstateflags = UIP_ESTABLISHED; ++ uip_connr->rcv_nxt[0] = tcp_hdr->seqno[0]; ++ uip_connr->rcv_nxt[1] = tcp_hdr->seqno[1]; ++ uip_connr->rcv_nxt[2] = tcp_hdr->seqno[2]; ++ uip_connr->rcv_nxt[3] = tcp_hdr->seqno[3]; ++ uip_add_rcv_nxt(ustack, 1); ++ ustack->uip_flags = UIP_CONNECTED | UIP_NEWDATA; ++ uip_connr->len = 0; ++ ustack->uip_len = 0; ++ ustack->uip_slen = 0; ++ UIP_APPCALL(ustack); ++ goto appsend; ++ } ++ /* Inform the application that the connection failed */ ++ ustack->uip_flags = UIP_ABORT; ++ UIP_APPCALL(ustack); ++ /* The connection is closed after we send the RST */ ++ ustack->uip_conn->tcpstateflags = UIP_CLOSED; ++ goto reset; ++#endif /* UIP_ACTIVE_OPEN */ ++ ++ case UIP_ESTABLISHED: ++ /* In the ESTABLISHED state, we call upon the application to ++ feed data into the uip_buf. If the UIP_ACKDATA flag is set, ++ the application should put new data into the buffer, ++ otherwise we are retransmitting an old segment, and the ++ application should put that data into the buffer. ++ ++ If the incoming packet is a FIN, we should close the ++ connection on this side as well, and we send out a FIN and ++ enter the LAST_ACK state. We require that there is no ++ outstanding data; otherwise the sequence numbers will be ++ screwed up. */ ++ ++ if (tcp_hdr->flags & TCP_FIN ++ && !(uip_connr->tcpstateflags & UIP_STOPPED)) { ++ if (uip_outstanding(uip_connr)) ++ goto drop; ++ uip_add_rcv_nxt(ustack, 1 + ustack->uip_len); ++ ustack->uip_flags |= UIP_CLOSE; ++ if (ustack->uip_len > 0) ++ ustack->uip_flags |= UIP_NEWDATA; ++ UIP_APPCALL(ustack); ++ uip_connr->len = 1; ++ uip_connr->tcpstateflags = UIP_LAST_ACK; ++ uip_connr->nrtx = 0; ++tcp_send_finack: ++ tcp_hdr->flags = TCP_FIN | TCP_ACK; ++ goto tcp_send_nodata; ++ } ++ ++ /* Check the URG flag. If this is set, the segment carries ++ urgent data that we must pass to the application. */ ++ if ((tcp_hdr->flags & TCP_URG) != 0) { ++#if UIP_URGDATA > 0 ++ uip_urglen = (tcp_hdr->urgp[0] << 8) | tcp_hdr->urgp[1]; ++ if (uip_urglen > uip_len) { ++ /* There is more urgent data in the next segment ++ to come. */ ++ uip_urglen = uip_len; ++ } ++ uip_add_rcv_nxt(uip_urglen); ++ uip_len -= uip_urglen; ++ uip_urgdata = uip_appdata; ++ uip_appdata += uip_urglen; ++ } else { ++ uip_urglen = 0; ++#else /* UIP_URGDATA > 0 */ ++ ustack->uip_appdata = ++ ((char *)ustack->uip_appdata) + ++ ((tcp_hdr->urgp[0] << 8) | tcp_hdr->urgp[1]); ++ ustack->uip_len -= ++ (tcp_hdr->urgp[0] << 8) | tcp_hdr->urgp[1]; ++#endif /* UIP_URGDATA > 0 */ ++ } ++ ++ /* If uip_len > 0 we have TCP data in the packet, and we flag ++ this by setting the UIP_NEWDATA flag and update the sequence ++ number we acknowledge. If the application has stopped the ++ dataflow using uip_stop(), we must not accept any data ++ packets from the remote host. */ ++ if (ustack->uip_len > 0 ++ && !(uip_connr->tcpstateflags & UIP_STOPPED)) { ++ ustack->uip_flags |= UIP_NEWDATA; ++ uip_add_rcv_nxt(ustack, ustack->uip_len); ++ } ++ ++ /* Check if the available buffer space advertised by the other ++ end is smaller than the initial MSS for this connection. ++ If so, we set the current MSS to the window size to ensure ++ that the application does not send more data than the other ++ end can handle. ++ ++ If the remote host advertises a zero window, we set the MSS ++ to the initial MSS so that the application will send an ++ entire MSS of data. This data will not be acknowledged by ++ the receiver, and the application will retransmit it. ++ This is called the "persistent timer" and uses the ++ retransmission mechanim. ++ */ ++ tmp16 = ++ ((u16_t) tcp_hdr->wnd[0] << 8) + (u16_t) tcp_hdr->wnd[1]; ++ if (tmp16 > uip_connr->initialmss || tmp16 == 0) ++ tmp16 = uip_connr->initialmss; ++ uip_connr->mss = tmp16; ++ ++ /* If this packet constitutes an ACK for outstanding data ++ (flagged by the UIP_ACKDATA flag, we should call the ++ application since it might want to send more data. ++ If the incoming packet had data from the peer ++ (as flagged by the UIP_NEWDATA flag), the application ++ must also be notified. ++ ++ When the application is called, the global variable uip_len ++ contains the length of the incoming data. The application can ++ access the incoming data through the global pointer ++ uip_appdata, which usually points uip_ip_tcph_len + ++ UIP_LLH_LEN bytes into the uip_buf array. ++ ++ If the application wishes to send any data, this data should ++ be put into the uip_appdata and the length of the data should ++ be put into uip_len. If the application don't have any data ++ to send, uip_len must be set to 0. */ ++ if (ustack->uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) { ++ ustack->uip_slen = 0; ++ UIP_APPCALL(ustack); ++ ++appsend: ++ ++ if (ustack->uip_flags & UIP_ABORT) { ++ ustack->uip_slen = 0; ++ uip_connr->tcpstateflags = UIP_CLOSED; ++ tcp_hdr->flags = TCP_RST | TCP_ACK; ++ goto tcp_send_nodata; ++ } ++ ++ if (ustack->uip_flags & UIP_CLOSE) { ++ ustack->uip_slen = 0; ++ uip_connr->len = 1; ++ uip_connr->tcpstateflags = UIP_FIN_WAIT_1; ++ uip_connr->nrtx = 0; ++ tcp_hdr->flags = TCP_FIN | TCP_ACK; ++ goto tcp_send_nodata; ++ } ++ ++ /* If uip_slen > 0, the application has data to be sent ++ */ ++ if (ustack->uip_slen > 0) { ++ ++ /* If the connection has acknowledged data, the ++ contents of the ->len variable should be ++ discarded. */ ++ if ((ustack->uip_flags & UIP_ACKDATA) != 0) ++ uip_connr->len = 0; ++ ++ /* If the ->len variable is non-zero the ++ connection has already data in transit and ++ cannot send anymore right now. */ ++ if (uip_connr->len == 0) { ++ ++ /* The application cannot send more than ++ what is allowed by the mss (the ++ minumum of the MSS and the available ++ window). */ ++ if (ustack->uip_slen > uip_connr->mss) { ++ ustack->uip_slen = ++ uip_connr->mss; ++ } ++ ++ /* Remember how much data we send out ++ now so that we know when everything ++ has been acknowledged. */ ++ uip_connr->len = ustack->uip_slen; ++ } else { ++ ++ /* If the application already had ++ unacknowledged data, we make sure ++ that the application does not send ++ (i.e., retransmit) out more than it ++ previously sent out. */ ++ ustack->uip_slen = uip_connr->len; ++ } ++ } ++ uip_connr->nrtx = 0; ++apprexmit: ++ ustack->uip_appdata = ustack->uip_sappdata; ++ ++ /* If the application has data to be sent, or if the ++ incoming packet had new data in it, we must send ++ out a packet. */ ++ if (ustack->uip_slen > 0 && uip_connr->len > 0) { ++ /* Add the length of the IP and TCP headers. */ ++ ustack->uip_len = ++ uip_connr->len + uip_ip_tcph_len; ++ /* We always set the ACK flag in response ++ packets. */ ++ tcp_hdr->flags = TCP_ACK | TCP_PSH; ++ /* Send the packet. */ ++ goto tcp_send_noopts; ++ } ++ /* If there is no data to send, just send out a pure ACK ++ if there is newdata. */ ++ if (ustack->uip_flags & UIP_NEWDATA) { ++ ustack->uip_len = uip_ip_tcph_len; ++ tcp_hdr->flags = TCP_ACK; ++ goto tcp_send_noopts; ++ } ++ } ++ goto drop; ++ case UIP_LAST_ACK: ++ /* We can close this connection if the peer has acknowledged our ++ FIN. This is indicated by the UIP_ACKDATA flag. */ ++ if (ustack->uip_flags & UIP_ACKDATA) { ++ uip_connr->tcpstateflags = UIP_CLOSED; ++ ustack->uip_flags = UIP_CLOSE; ++ UIP_APPCALL(ustack); ++ } ++ break; ++ ++ case UIP_FIN_WAIT_1: ++ /* The application has closed the connection, but the remote ++ host hasn't closed its end yet. Thus we do nothing but wait ++ for a FIN from the other side. */ ++ if (ustack->uip_len > 0) ++ uip_add_rcv_nxt(ustack, ustack->uip_len); ++ if (tcp_hdr->flags & TCP_FIN) { ++ if (ustack->uip_flags & UIP_ACKDATA) { ++ uip_connr->tcpstateflags = UIP_TIME_WAIT; ++ uip_connr->timer = 0; ++ uip_connr->len = 0; ++ } else { ++ uip_connr->tcpstateflags = UIP_CLOSING; ++ } ++ uip_add_rcv_nxt(ustack, 1); ++ ustack->uip_flags = UIP_CLOSE; ++ UIP_APPCALL(ustack); ++ goto tcp_send_ack; ++ } else if (ustack->uip_flags & UIP_ACKDATA) { ++ uip_connr->tcpstateflags = UIP_FIN_WAIT_2; ++ uip_connr->len = 0; ++ goto drop; ++ } ++ if (ustack->uip_len > 0) ++ goto tcp_send_ack; ++ goto drop; ++ ++ case UIP_FIN_WAIT_2: ++ if (ustack->uip_len > 0) ++ uip_add_rcv_nxt(ustack, ustack->uip_len); ++ if (tcp_hdr->flags & TCP_FIN) { ++ uip_connr->tcpstateflags = UIP_TIME_WAIT; ++ uip_connr->timer = 0; ++ uip_add_rcv_nxt(ustack, 1); ++ ustack->uip_flags = UIP_CLOSE; ++ UIP_APPCALL(ustack); ++ goto tcp_send_ack; ++ } ++ if (ustack->uip_len > 0) ++ goto tcp_send_ack; ++ goto drop; ++ ++ case UIP_TIME_WAIT: ++ goto tcp_send_ack; ++ ++ case UIP_CLOSING: ++ if (ustack->uip_flags & UIP_ACKDATA) { ++ uip_connr->tcpstateflags = UIP_TIME_WAIT; ++ uip_connr->timer = 0; ++ } ++ } ++ goto drop; ++ ++ /* We jump here when we are ready to send the packet, and just want ++ to set the appropriate TCP sequence numbers in the TCP header. */ ++tcp_send_ack: ++ tcp_hdr->flags = TCP_ACK; ++tcp_send_nodata: ++ ustack->uip_len = uip_ip_tcph_len; ++tcp_send_noopts: ++ tcp_hdr->tcpoffset = (UIP_TCPH_LEN / 4) << 4; ++tcp_send: ++ /* We're done with the input processing. We are now ready to send a ++ reply. Our job is to fill in all the fields of the TCP and IP ++ headers before calculating the checksum and finally send the ++ packet. */ ++ tcp_hdr->ackno[0] = uip_connr->rcv_nxt[0]; ++ tcp_hdr->ackno[1] = uip_connr->rcv_nxt[1]; ++ tcp_hdr->ackno[2] = uip_connr->rcv_nxt[2]; ++ tcp_hdr->ackno[3] = uip_connr->rcv_nxt[3]; ++ ++ tcp_hdr->seqno[0] = uip_connr->snd_nxt[0]; ++ tcp_hdr->seqno[1] = uip_connr->snd_nxt[1]; ++ tcp_hdr->seqno[2] = uip_connr->snd_nxt[2]; ++ tcp_hdr->seqno[3] = uip_connr->snd_nxt[3]; ++ ++ if (is_ipv6(ustack)) { ++ IPv6_BUF(ustack)->proto = UIP_PROTO_TCP; ++ uip_ip6addr_copy(IPv6_BUF(ustack)->srcipaddr, ++ ustack->hostaddr6); ++ uip_ip6addr_copy(IPv6_BUF(ustack)->destipaddr, ++ uip_connr->ripaddr6); ++ } else { ++ tcp_ipv4_hdr->proto = UIP_PROTO_TCP; ++ uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr); ++ uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr, uip_connr->ripaddr); ++ } ++ ++ tcp_hdr->srcport = uip_connr->lport; ++ tcp_hdr->destport = uip_connr->rport; ++ ++ if (uip_connr->tcpstateflags & UIP_STOPPED) { ++ /* If the connection has issued uip_stop(), we advertise a zero ++ window so that the remote host will stop sending data. */ ++ tcp_hdr->wnd[0] = tcp_hdr->wnd[1] = 0; ++ } else { ++ tcp_hdr->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8); ++ tcp_hdr->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff); ++ } ++ ++tcp_send_noconn: ++ if (is_ipv6(ustack)) { ++ IPv6_BUF(ustack)->ttl = UIP_TTL; ++ ++ /* For IPv6, the IP length field does not include the IPv6 IP ++ header length. */ ++ IPv6_BUF(ustack)->len[0] = ++ ((ustack->uip_len - uip_iph_len) >> 8); ++ IPv6_BUF(ustack)->len[1] = ++ ((ustack->uip_len - uip_iph_len) & 0xff); ++ } else { ++ tcp_ipv4_hdr->ttl = UIP_TTL; ++ tcp_ipv4_hdr->len[0] = (ustack->uip_len >> 8); ++ tcp_ipv4_hdr->len[1] = (ustack->uip_len & 0xff); ++ } ++ ++ tcp_hdr->urgp[0] = tcp_hdr->urgp[1] = 0; ++ ++ /* Calculate TCP checksum. */ ++ tcp_hdr->tcpchksum = 0; ++ tcp_hdr->tcpchksum = ~(uip_tcpchksum(ustack)); ++ ++ip_send_nolen: ++ ++ if (!is_ipv6(ustack)) { ++ tcp_ipv4_hdr->vhl = 0x45; ++ tcp_ipv4_hdr->tos = 0; ++ tcp_ipv4_hdr->ipoffset[0] = tcp_ipv4_hdr->ipoffset[1] = 0; ++ ++ustack->ipid; ++ tcp_ipv4_hdr->ipid[0] = ustack->ipid >> 8; ++ tcp_ipv4_hdr->ipid[1] = ustack->ipid & 0xff; ++ /* Calculate IP checksum. */ ++ tcp_ipv4_hdr->ipchksum = 0; ++ tcp_ipv4_hdr->ipchksum = ~(uip_ipchksum(ustack)); ++ } ++ ++ ++ustack->stats.tcp.sent; ++send: ++ if (is_ipv6(ustack)) { ++ LOG_DEBUG(PFX "Sending packet with length %d (%d)", ++ ustack->uip_len, ipv6_hdr ? ipv6_hdr->ip6_plen : 0); ++ } else { ++ LOG_DEBUG(PFX "Sending packet with length %d (%d)", ++ ustack->uip_len, ++ (tcp_ipv4_hdr->len[0] << 8) | tcp_ipv4_hdr->len[1]); ++ } ++ ++ustack->stats.ip.sent; ++ /* Return and let the caller do the actual transmission. */ ++ ustack->uip_flags = 0; ++ return; ++drop: ++ ustack->uip_len = 0; ++ ustack->uip_flags = 0; ++ return; ++} ++ ++/*---------------------------------------------------------------------------*/ ++void uip_send(struct uip_stack *ustack, const void *data, int len) ++{ ++ if (len > 0) { ++ ustack->uip_slen = len; ++ if (data != ustack->uip_buf) ++ memcpy(ustack->uip_buf, (data), ustack->uip_slen); ++ } ++} ++ ++void uip_appsend(struct uip_stack *ustack, const void *data, int len) ++{ ++ if (len > 0) { ++ ustack->uip_slen = len; ++ if (data != ustack->uip_sappdata) ++ memcpy(ustack->uip_sappdata, (data), ustack->uip_slen); ++ } ++} ++ ++u16_t uip_datalen(struct uip_stack *ustack) ++{ ++ return ustack->uip_len; ++} ++ ++/** @} */ +diff --git a/iscsiuio/src/uip/uip.h b/iscsiuio/src/uip/uip.h +new file mode 100644 +index 0000000..1180ab5 +--- /dev/null ++++ b/iscsiuio/src/uip/uip.h +@@ -0,0 +1,1574 @@ ++ ++/** ++ * \addtogroup uip ++ * @{ ++ */ ++ ++/** ++ * \file ++ * Header file for the uIP TCP/IP stack. ++ * \author Adam Dunkels ++ * ++ * The uIP TCP/IP stack header file contains definitions for a number ++ * of C macros that are used by uIP programs as well as internal uIP ++ * structures, TCP/IP header structures and function declarations. ++ * ++ */ ++ ++/* ++ * Copyright (c) 2001-2003, Adam Dunkels. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack. ++ * ++ * ++ */ ++ ++#ifndef __UIP_H__ ++#define __UIP_H__ ++ ++#include ++#include ++ ++#include "uipopt.h" ++ ++#include "debug.h" ++ ++#include "uip_eth.h" ++ ++/* Forware declaration */ ++struct uip_stack; ++ ++/** ++ * Repressentation of an IP address. ++ * ++ */ ++typedef u16_t uip_ip4addr_t[2]; ++typedef u16_t uip_ip6addr_t[8]; ++ ++const uip_ip6addr_t all_zeroes_addr6; ++const uip_ip4addr_t all_zeroes_addr4; ++ ++#define ETH_BUF(buf) ((struct uip_eth_hdr *)buf) ++#define VLAN_ETH_BUF(buf) ((struct uip_vlan_eth_hdr *)buf) ++#define IPv4_BUF(buf) ((struct uip_tcp_ipv4_hdr *)buf) ++#define IPv6_BUF(buf) ((struct uip_tcp_ipv6_hdr *)buf) ++ ++/*---------------------------------------------------------------------------*/ ++/* First, the functions that should be called from the ++ * system. Initialization, the periodic timer and incoming packets are ++ * handled by the following three functions. ++ */ ++ ++/** ++ * Set the IP address of this host. ++ * ++ * The IP address is represented as a 4-byte array where the first ++ * octet of the IP address is put in the first member of the 4-byte ++ * array. ++ * ++ * Example: ++ \code ++ ++ uip_ipaddr_t addr; ++ ++ uip_ipaddr(&addr, 192,168,1,2); ++ uip_sethostaddr(&addr); ++ ++ \endcode ++ * \param addr A pointer to an IP address of type uip_ipaddr_t; ++ * ++ * \sa uip_ipaddr() ++ * ++ * \hideinitializer ++ */ ++void uip_sethostaddr4(struct uip_stack *ustack, uip_ip4addr_t *addr); ++ ++/** ++ * Set the default router's IP address. ++ * ++ * \param addr A pointer to a uip_ipaddr_t variable containing the IP ++ * address of the default router. ++ * ++ * \sa uip_ipaddr() ++ * ++ * \hideinitializer ++ */ ++void uip_setdraddr4(struct uip_stack *ustack, uip_ip4addr_t *addr); ++ ++/** ++ * Set the netmask. ++ * ++ * \param addr A pointer to a uip_ipaddr_t variable containing the IP ++ * address of the netmask. ++ * ++ * \sa uip_ipaddr() ++ * ++ * \hideinitializer ++ */ ++void uip_setnetmask4(struct uip_stack *ustack, uip_ip4addr_t *addr); ++ ++/** ++ * Set the ethernet MAC address. ++ * ++ * \param addr A pointer to a uip_ipaddr_t variable containing the IP ++ * address of the netmask. ++ * ++ * \sa uip_ipaddr() ++ * ++ * \hideinitializer ++ */ ++void uip_setethernetmac(struct uip_stack *ustack, uint8_t *mac); ++ ++/** ++ * Get the default router's IP address. ++ * ++ * \param addr A pointer to a uip_ipaddr_t variable that will be ++ * filled in with the IP address of the default router. ++ * ++ * \hideinitializer ++ */ ++#define uip_getdraddr(addr) uip_ipaddr_copy((addr), uip_draddr) ++ ++/** ++ * Get the netmask. ++ * ++ * \param addr A pointer to a uip_ipaddr_t variable that will be ++ * filled in with the value of the netmask. ++ * ++ * \hideinitializer ++ */ ++#define uip_getnetmask(addr) uip_ipaddr_copy((addr), uip_netmask) ++ ++void set_uip_stack(struct uip_stack *ustack, ++ uip_ip4addr_t *ip, ++ uip_ip4addr_t *netmask, ++ uip_ip4addr_t *default_route, uint8_t *mac_addr); ++ ++/** @} */ ++ ++/** ++ * \defgroup uipinit uIP initialization functions ++ * @{ ++ * ++ * The uIP initialization functions are used for booting uIP. ++ */ ++ ++/** ++ * uIP initialization function. ++ * ++ * This function should be called at boot up to initilize the uIP ++ * TCP/IP stack. ++ */ ++void uip_init(struct uip_stack *ustack, uint8_t enable_ipv6); ++ ++/** ++ * uIP reset function. ++ * ++ * This function should be called at to reset the uIP TCP/IP stack. ++ */ ++void uip_reset(struct uip_stack *ustack); ++ ++/** ++ * uIP initialization function. ++ * ++ * This function may be used at boot time to set the initial ip_id. ++ */ ++void uip_setipid(u16_t id); ++ ++/** ++ * ++ * ++ */ ++#define uip_conn_active(conn) (uip_conns[conn].tcpstateflags != UIP_CLOSED) ++ ++#if UIP_UDP ++void uip_udp_periodic(struct uip_stack *ustack, int conn); ++#endif /* UIP_UDP */ ++ ++void uip_ndp_periodic(struct uip_stack *ustack); ++ ++/** ++ * The uIP packet buffer. ++ * ++ * The uip_buf array is used to hold incoming and outgoing ++ * packets. The device driver should place incoming data into this ++ * buffer. When sending data, the device driver should read the link ++ * level headers and the TCP/IP headers from this buffer. The size of ++ * the link level headers is configured by the UIP_LLH_LEN define. ++ * ++ * \note The application data need not be placed in this buffer, so ++ * the device driver must read it from the place pointed to by the ++ * uip_appdata pointer as illustrated by the following example: ++ \code ++ void ++ devicedriver_send(void) ++ { ++ hwsend(&uip_buf[0], UIP_LLH_LEN); ++ if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) { ++ hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN); ++ } else { ++ hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN); ++ hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN); ++ } ++ } ++ \endcode ++ */ ++/*extern u8_t uip_buf[UIP_BUFSIZE+2]; */ ++ ++/** @} */ ++ ++/*---------------------------------------------------------------------------*/ ++/* Functions that are used by the uIP application program. Opening and ++ * closing connections, sending and receiving data, etc. is all ++ * handled by the functions below. ++*/ ++/** ++ * \defgroup uipappfunc uIP application functions ++ * @{ ++ * ++ * Functions used by an application running of top of uIP. ++ */ ++ ++/** ++ * Start listening to the specified port. ++ * ++ * \note Since this function expects the port number in network byte ++ * order, a conversion using HTONS() or htons() is necessary. ++ * ++ \code ++ uip_listen(HTONS(80)); ++ \endcode ++ * ++ * \param port A 16-bit port number in network byte order. ++ */ ++void uip_listen(struct uip_stack *ustack, u16_t port); ++ ++/** ++ * Stop listening to the specified port. ++ * ++ * \note Since this function expects the port number in network byte ++ * order, a conversion using HTONS() or htons() is necessary. ++ * ++ \code ++ uip_unlisten(HTONS(80)); ++ \endcode ++ * ++ * \param port A 16-bit port number in network byte order. ++ */ ++void uip_unlisten(struct uip_stack *ustack, u16_t port); ++ ++/** ++ * Connect to a remote host using TCP. ++ * ++ * This function is used to start a new connection to the specified ++ * port on the specied host. It allocates a new connection identifier, ++ * sets the connection to the SYN_SENT state and sets the ++ * retransmission timer to 0. This will cause a TCP SYN segment to be ++ * sent out the next time this connection is periodically processed, ++ * which usually is done within 0.5 seconds after the call to ++ * uip_connect(). ++ * ++ * \note This function is avaliable only if support for active open ++ * has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h. ++ * ++ * \note Since this function requires the port number to be in network ++ * byte order, a conversion using HTONS() or htons() is necessary. ++ * ++ \code ++ uip_ipaddr_t ipaddr; ++ ++ uip_ipaddr(&ipaddr, 192,168,1,2); ++ uip_connect(&ipaddr, HTONS(80)); ++ \endcode ++ * ++ * \param ripaddr The IP address of the remote hot. ++ * ++ * \param port A 16-bit port number in network byte order. ++ * ++ * \return A pointer to the uIP connection identifier for the new connection, ++ * or NULL if no connection could be allocated. ++ * ++ */ ++struct uip_conn *uip_connect(struct uip_stack *ustack, ++ uip_ip4addr_t *ripaddr, u16_t port); ++ ++/** ++ * \internal ++ * ++ * Check if a connection has outstanding (i.e., unacknowledged) data. ++ * ++ * \param conn A pointer to the uip_conn structure for the connection. ++ * ++ * \hideinitializer ++ */ ++#define uip_outstanding(conn) ((conn)->len) ++ ++/** ++ * Send data on the current connection. ++ * ++ * This function is used to send out a single segment of TCP ++ * data. Only applications that have been invoked by uIP for event ++ * processing can send data. ++ * ++ * The amount of data that actually is sent out after a call to this ++ * funcion is determined by the maximum amount of data TCP allows. uIP ++ * will automatically crop the data so that only the appropriate ++ * amount of data is sent. The function uip_mss() can be used to query ++ * uIP for the amount of data that actually will be sent. ++ * ++ * \note This function does not guarantee that the sent data will ++ * arrive at the destination. If the data is lost in the network, the ++ * application will be invoked with the uip_rexmit() event being ++ * set. The application will then have to resend the data using this ++ * function. ++ * ++ * \param data A pointer to the data which is to be sent. ++ * ++ * \param len The maximum amount of data bytes to be sent. ++ * ++ * \hideinitializer ++ */ ++void uip_send(struct uip_stack *ustack, const void *data, int len); ++void uip_appsend(struct uip_stack *ustack, const void *data, int len); ++ ++/** ++ * The length of any incoming data that is currently avaliable (if avaliable) ++ * in the uip_appdata buffer. ++ * ++ * The test function uip_data() must first be used to check if there ++ * is any data available at all. ++ * ++ * \hideinitializer ++ */ ++/*void uip_datalen(void);*/ ++u16_t uip_datalen(struct uip_stack *ustack); ++ ++/** ++ * The length of any out-of-band data (urgent data) that has arrived ++ * on the connection. ++ * ++ * \note The configuration parameter UIP_URGDATA must be set for this ++ * function to be enabled. ++ * ++ * \hideinitializer ++ */ ++#define uip_urgdatalen() uip_urglen ++ ++/** ++ * Close the current connection. ++ * ++ * This function will close the current connection in a nice way. ++ * ++ * \hideinitializer ++ */ ++#define uip_close() (uip_flags = UIP_CLOSE) ++ ++/** ++ * Abort the current connection. ++ * ++ * This function will abort (reset) the current connection, and is ++ * usually used when an error has occured that prevents using the ++ * uip_close() function. ++ * ++ * \hideinitializer ++ */ ++#define uip_abort() (uip_flags = UIP_ABORT) ++ ++/** ++ * Tell the sending host to stop sending data. ++ * ++ * This function will close our receiver's window so that we stop ++ * receiving data for the current connection. ++ * ++ * \hideinitializer ++ */ ++#define uip_stop() (uip_conn->tcpstateflags |= UIP_STOPPED) ++ ++/** ++ * Find out if the current connection has been previously stopped with ++ * uip_stop(). ++ * ++ * \hideinitializer ++ */ ++#define uip_stopped(conn) ((conn)->tcpstateflags & UIP_STOPPED) ++ ++/** ++ * Restart the current connection, if is has previously been stopped ++ * with uip_stop(). ++ * ++ * This function will open the receiver's window again so that we ++ * start receiving data for the current connection. ++ * ++ * \hideinitializer ++ */ ++#define uip_restart() do { uip_flags |= UIP_NEWDATA; \ ++ uip_conn->tcpstateflags &= ~UIP_STOPPED; \ ++ } while (0) ++ ++/* uIP tests that can be made to determine in what state the current ++ connection is, and what the application function should do. */ ++ ++/** ++ * Is the current connection a UDP connection? ++ * ++ * This function checks whether the current connection is a UDP connection. ++ * ++ * \hideinitializer ++ * ++ */ ++#define uip_udpconnection() (uip_conn == NULL) ++ ++/** ++ * Function declarations for hte uip_flags ++ */ ++/** ++ * Is new incoming data available? ++ * ++ * Will reduce to non-zero if there is new data for the application ++ * present at the uip_appdata pointer. The size of the data is ++ * avaliable through the uip_len variable. ++ * ++ * \hideinitializer ++ */ ++int uip_newdata(struct uip_stack *ustack); ++ ++/** ++ * Has previously sent data been acknowledged? ++ * ++ * Will reduce to non-zero if the previously sent data has been ++ * acknowledged by the remote host. This means that the application ++ * can send new data. ++ * ++ * \hideinitializer ++ */ ++int uip_acked(struct uip_stack *ustack); ++ ++/** ++ * Has the connection just been connected? ++ * ++ * Reduces to non-zero if the current connection has been connected to ++ * a remote host. This will happen both if the connection has been ++ * actively opened (with uip_connect()) or passively opened (with ++ * uip_listen()). ++ * ++ * \hideinitializer ++ */ ++int uip_connected(struct uip_stack *ustack); ++ ++/** ++ * Has the connection been closed by the other end? ++ * ++ * Is non-zero if the connection has been closed by the remote ++ * host. The application may then do the necessary clean-ups. ++ * ++ * \hideinitializer ++ */ ++int uip_closed(struct uip_stack *ustack); ++ ++/** ++ * Has the connection been aborted by the other end? ++ * ++ * Non-zero if the current connection has been aborted (reset) by the ++ * remote host. ++ * ++ * \hideinitializer ++ */ ++int uip_aborted(struct uip_stack *ustack); ++ ++/** ++ * Has the connection timed out? ++ * ++ * Non-zero if the current connection has been aborted due to too many ++ * retransmissions. ++ * ++ * \hideinitializer ++ */ ++int uip_timedout(struct uip_stack *ustack); ++ ++/** ++ * Do we need to retransmit previously data? ++ * ++ * Reduces to non-zero if the previously sent data has been lost in ++ * the network, and the application should retransmit it. The ++ * application should send the exact same data as it did the last ++ * time, using the uip_send() function. ++ * ++ * \hideinitializer ++ */ ++int uip_rexmit(struct uip_stack *ustack); ++ ++/** ++ * Is the connection being polled by uIP? ++ * ++ * Is non-zero if the reason the application is invoked is that the ++ * current connection has been idle for a while and should be ++ * polled. ++ * ++ * The polling event can be used for sending data without having to ++ * wait for the remote host to send data. ++ * ++ * \hideinitializer ++ */ ++int uip_poll(struct uip_stack *ustack); ++ ++/** ++ * Get the initial maxium segment size (MSS) of the current ++ * connection. ++ * ++ * \hideinitializer ++ */ ++int uip_initialmss(struct uip_stack *ustack); ++ ++/** ++ * Get the current maxium segment size that can be sent on the current ++ * connection. ++ * ++ * The current maxiumum segment size that can be sent on the ++ * connection is computed from the receiver's window and the MSS of ++ * the connection (which also is available by calling ++ * uip_initialmss()). ++ * ++ * \hideinitializer ++ */ ++int uip_mss(struct uip_stack *ustack); ++ ++/** ++ * Set up a new UDP connection. ++ * ++ * This function sets up a new UDP connection. The function will ++ * automatically allocate an unused local port for the new ++ * connection. However, another port can be chosen by using the ++ * uip_udp_bind() call, after the uip_udp_new() function has been ++ * called. ++ * ++ * Example: ++ \code ++ uip_ipaddr_t addr; ++ struct uip_udp_conn *c; ++ ++ uip_ipaddr(&addr, 192,168,2,1); ++ c = uip_udp_new(&addr, HTONS(12345)); ++ if(c != NULL) { ++ uip_udp_bind(c, HTONS(12344)); ++ } ++ \endcode ++ * \param ripaddr The IP address of the remote host. ++ * ++ * \param rport The remote port number in network byte order. ++ * ++ * \return The uip_udp_conn structure for the new connection or NULL ++ * if no connection could be allocated. ++ */ ++struct uip_udp_conn *uip_udp_new(struct uip_stack *ustack, ++ uip_ip4addr_t *ripaddr, u16_t rport); ++ ++/** ++ * Removed a UDP connection. ++ * ++ * \param conn A pointer to the uip_udp_conn structure for the connection. ++ * ++ * \hideinitializer ++ */ ++#define uip_udp_remove(conn) ((conn)->lport = 0) ++ ++/** ++ * Bind a UDP connection to a local port. ++ * ++ * \param conn A pointer to the uip_udp_conn structure for the ++ * connection. ++ * ++ * \param port The local port number, in network byte order. ++ * ++ * \hideinitializer ++ */ ++#define uip_udp_bind(conn, port) ((conn)->lport = port) ++ ++/** ++ * Send a UDP datagram of length len on the current connection. ++ * ++ * This function can only be called in response to a UDP event (poll ++ * or newdata). The data must be present in the uip_buf buffer, at the ++ * place pointed to by the uip_appdata pointer. ++ * ++ * \param len The length of the data in the uip_buf buffer. ++ * ++ * \hideinitializer ++ */ ++#define uip_udp_send(len) uip_appsend((char *)uip_appdata, len) ++ ++/** @} */ ++ ++/* uIP convenience and converting functions. */ ++ ++/** ++ * \defgroup uipconvfunc uIP conversion functions ++ * @{ ++ * ++ * These functions can be used for converting between different data ++ * formats used by uIP. ++ */ ++ ++/** ++ * Construct an IP address from four bytes. ++ * ++ * This function constructs an IP address of the type that uIP handles ++ * internally from four bytes. The function is handy for specifying IP ++ * addresses to use with e.g. the uip_connect() function. ++ * ++ * Example: ++ \code ++ uip_ipaddr_t ipaddr; ++ struct uip_conn *c; ++ ++ uip_ipaddr(&ipaddr, 192,168,1,2); ++ c = uip_connect(&ipaddr, HTONS(80)); ++ \endcode ++ * ++ * \param addr A pointer to a uip_ipaddr_t variable that will be ++ * filled in with the IP address. ++ * ++ * \param addr0 The first octet of the IP address. ++ * \param addr1 The second octet of the IP address. ++ * \param addr2 The third octet of the IP address. ++ * \param addr3 The forth octet of the IP address. ++ * ++ * \hideinitializer ++ */ ++#define uip_ipaddr(addr, addr0, addr1, addr2, addr3) do { \ ++ ((u16_t *)(addr))[0] = const_htons(((addr0) << 8) | (addr1)); \ ++ ((u16_t *)(addr))[1] = const_htons(((addr2) << 8) | (addr3)); \ ++ } while (0) ++ ++/** ++ * Construct an IPv6 address from eight 16-bit words. ++ * ++ * This function constructs an IPv6 address. ++ * ++ * \hideinitializer ++ */ ++#define uip_ip6addr(addr, addr0, addr1, addr2, addr3, addr4, addr5, addr6, \ ++ addr7) \ ++ do { \ ++ ((u16_t *)(addr))[0] = HTONS((addr0)); \ ++ ((u16_t *)(addr))[1] = HTONS((addr1)); \ ++ ((u16_t *)(addr))[2] = HTONS((addr2)); \ ++ ((u16_t *)(addr))[3] = HTONS((addr3)); \ ++ ((u16_t *)(addr))[4] = HTONS((addr4)); \ ++ ((u16_t *)(addr))[5] = HTONS((addr5)); \ ++ ((u16_t *)(addr))[6] = HTONS((addr6)); \ ++ ((u16_t *)(addr))[7] = HTONS((addr7)); \ ++ } while (0) ++ ++/** ++ * Copy an IP address to another IP address. ++ * ++ * Copies an IP address from one place to another. ++ * ++ * Example: ++ \code ++ uip_ipaddr_t ipaddr1, ipaddr2; ++ ++ uip_ipaddr(&ipaddr1, 192,16,1,2); ++ uip_ipaddr_copy(&ipaddr2, &ipaddr1); ++ \endcode ++ * ++ * \param dest The destination for the copy. ++ * \param src The source from where to copy. ++ * ++ * \hideinitializer ++ */ ++#define uip_ip4addr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip4addr_t)) ++#define uip_ip6addr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip6addr_t)) ++ ++/** ++ * Compare two IP addresses ++ * ++ * Compares two IP addresses. ++ * ++ * Example: ++ \code ++ uip_ipaddr_t ipaddr1, ipaddr2; ++ ++ uip_ipaddr(&ipaddr1, 192,16,1,2); ++ if(uip_ipaddr_cmp(&ipaddr2, &ipaddr1)) { ++ printf("They are the same"); ++ } ++ \endcode ++ * ++ * \param addr1 The first IP address. ++ * \param addr2 The second IP address. ++ * ++ * \hideinitializer ++ */ ++#define uip_ip4addr_cmp(addr1, addr2) (memcmp(addr1, addr2, \ ++ sizeof(uip_ip4addr_t)) == 0) ++#define uip_ip6addr_cmp(addr1, addr2) (memcmp(addr1, addr2, \ ++ sizeof(uip_ip6addr_t)) == 0) ++ ++/** ++ * Compare two IP addresses with netmasks ++ * ++ * Compares two IP addresses with netmasks. The masks are used to mask ++ * out the bits that are to be compared. ++ * ++ * Example: ++ \code ++ uip_ipaddr_t ipaddr1, ipaddr2, mask; ++ ++ uip_ipaddr(&mask, 255,255,255,0); ++ uip_ipaddr(&ipaddr1, 192,16,1,2); ++ uip_ipaddr(&ipaddr2, 192,16,1,3); ++ if(uip_ipaddr_maskcmp(&ipaddr1, &ipaddr2, &mask)) { ++ printf("They are the same"); ++ } ++ \endcode ++ * ++ * \param addr1 The first IP address. ++ * \param addr2 The second IP address. ++ * \param mask The netmask. ++ * ++ * \hideinitializer ++ */ ++#define uip_ip4addr_maskcmp(addr1, addr2, mask) \ ++ (((((u16_t *)addr1)[0] & ((u16_t *)mask)[0]) == \ ++ (((u16_t *)addr2)[0] & ((u16_t *)mask)[0])) && \ ++ ((((u16_t *)addr1)[1] & ((u16_t *)mask)[1]) == \ ++ (((u16_t *)addr2)[1] & ((u16_t *)mask)[1]))) ++ ++/** ++ * Mask out the network part of an IP address. ++ * ++ * Masks out the network part of an IP address, given the address and ++ * the netmask. ++ * ++ * Example: ++ \code ++ uip_ipaddr_t ipaddr1, ipaddr2, netmask; ++ ++ uip_ipaddr(&ipaddr1, 192,16,1,2); ++ uip_ipaddr(&netmask, 255,255,255,0); ++ uip_ipaddr_mask(&ipaddr2, &ipaddr1, &netmask); ++ \endcode ++ * ++ * In the example above, the variable "ipaddr2" will contain the IP ++ * address 192.168.1.0. ++ * ++ * \param dest Where the result is to be placed. ++ * \param src The IP address. ++ * \param mask The netmask. ++ * ++ * \hideinitializer ++ */ ++#define uip_ip4addr_mask(dest, src, mask) do { \ ++ ((u16_t *)dest)[0] = ((u16_t *)src)[0] & ((u16_t *)mask)[0]; \ ++ ((u16_t *)dest)[1] = ((u16_t *)src)[1] & ((u16_t *)mask)[1]; \ ++ } while (0) ++ ++/** ++ * Pick the first octet of an IP address. ++ * ++ * Picks out the first octet of an IP address. ++ * ++ * Example: ++ \code ++ uip_ipaddr_t ipaddr; ++ u8_t octet; ++ ++ uip_ipaddr(&ipaddr, 1,2,3,4); ++ octet = uip_ipaddr1(&ipaddr); ++ \endcode ++ * ++ * In the example above, the variable "octet" will contain the value 1. ++ * ++ * \hideinitializer ++ */ ++#define uip_ipaddr1(addr) (htons(((u16_t *)(addr))[0]) >> 8) ++ ++/** ++ * Pick the second octet of an IP address. ++ * ++ * Picks out the second octet of an IP address. ++ * ++ * Example: ++ \code ++ uip_ipaddr_t ipaddr; ++ u8_t octet; ++ ++ uip_ipaddr(&ipaddr, 1,2,3,4); ++ octet = uip_ipaddr2(&ipaddr); ++ \endcode ++ * ++ * In the example above, the variable "octet" will contain the value 2. ++ * ++ * \hideinitializer ++ */ ++#define uip_ipaddr2(addr) (htons(((u16_t *)(addr))[0]) & 0xff) ++ ++/** ++ * Pick the third octet of an IP address. ++ * ++ * Picks out the third octet of an IP address. ++ * ++ * Example: ++ \code ++ uip_ipaddr_t ipaddr; ++ u8_t octet; ++ ++ uip_ipaddr(&ipaddr, 1,2,3,4); ++ octet = uip_ipaddr3(&ipaddr); ++ \endcode ++ * ++ * In the example above, the variable "octet" will contain the value 3. ++ * ++ * \hideinitializer ++ */ ++#define uip_ipaddr3(addr) (htons(((u16_t *)(addr))[1]) >> 8) ++ ++/** ++ * Pick the fourth octet of an IP address. ++ * ++ * Picks out the fourth octet of an IP address. ++ * ++ * Example: ++ \code ++ uip_ipaddr_t ipaddr; ++ u8_t octet; ++ ++ uip_ipaddr(&ipaddr, 1,2,3,4); ++ octet = uip_ipaddr4(&ipaddr); ++ \endcode ++ * ++ * In the example above, the variable "octet" will contain the value 4. ++ * ++ * \hideinitializer ++ */ ++#define uip_ipaddr4(addr) (htons(((u16_t *)(addr))[1]) & 0xff) ++ ++/** ++ * Convert 16-bit quantity from host byte order to network byte order. ++ * ++ * This macro is primarily used for converting constants from host ++ * byte order to network byte order. For converting variables to ++ * network byte order, use the htons() function instead. ++ * ++ * \hideinitializer ++ */ ++#if 0 ++#ifndef HTONS ++# if UIP_BYTE_ORDER == UIP_BIG_ENDIAN ++# define HTONS(n) (n) ++# else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */ ++# define HTONS(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8)) ++# endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */ ++#else ++#error "HTONS already defined!" ++#endif /* HTONS */ ++#endif ++ ++#if UIP_BYTE_ORDER == UIP_BIG_ENDIAN ++# error "Should not be here" ++# define const_htons(n) (n) ++# else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */ ++# define const_htons(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8)) ++# endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */ ++ ++/* BWL */ ++#if 0 ++/** ++ * Convert 16-bit quantity from host byte order to network byte order. ++ * ++ * This function is primarily used for converting variables from host ++ * byte order to network byte order. For converting constants to ++ * network byte order, use the HTONS() macro instead. ++ */ ++#ifndef htons ++u16_t htons(u16_t val); ++#endif /* htons */ ++#ifndef ntohs ++#define ntohs htons ++#endif ++#endif ++ ++/** @} */ ++ ++/** ++ * Pointer to the application data in the packet buffer. ++ * ++ * This pointer points to the application data when the application is ++ * called. If the application wishes to send data, the application may ++ * use this space to write the data into before calling uip_send(). ++ */ ++/* extern void *uip_appdata; */ ++ ++#if UIP_URGDATA > 0 ++/* u8_t *uip_urgdata: ++ * ++ * This pointer points to any urgent data that has been received. Only ++ * present if compiled with support for urgent data (UIP_URGDATA). ++ */ ++extern void *uip_urgdata; ++#endif /* UIP_URGDATA > 0 */ ++ ++/** ++ * \defgroup uipdrivervars Variables used in uIP device drivers ++ * @{ ++ * ++ * uIP has a few global variables that are used in device drivers for ++ * uIP. ++ */ ++ ++/** ++ * The length of the packet in the uip_buf buffer. ++ * ++ * The global variable uip_len holds the length of the packet in the ++ * uip_buf buffer. ++ * ++ * When the network device driver calls the uIP input function, ++ * uip_len should be set to the length of the packet in the uip_buf ++ * buffer. ++ * ++ * When sending packets, the device driver should use the contents of ++ * the uip_len variable to determine the length of the outgoing ++ * packet. ++ * ++ */ ++/* extern u16_t uip_len; */ ++ ++/** @} */ ++ ++#if UIP_URGDATA > 0 ++extern u16_t uip_urglen, uip_surglen; ++#endif /* UIP_URGDATA > 0 */ ++ ++/** ++ * Representation of a uIP TCP connection. ++ * ++ * The uip_conn structure is used for identifying a connection. All ++ * but one field in the structure are to be considered read-only by an ++ * application. The only exception is the appstate field whos purpose ++ * is to let the application store application-specific state (e.g., ++ * file pointers) for the connection. The type of this field is ++ * configured in the "uipopt.h" header file. ++ */ ++struct __attribute__ ((__packed__)) uip_conn { ++ uip_ip4addr_t ripaddr; ++ uip_ip6addr_t ripaddr6; ++ /**< The IP address of the remote host. */ ++ ++ u16_t lport; /**< The local TCP port, in network byte order. */ ++ u16_t rport; /**< The local remote TCP port, in network byte ++ order. */ ++ ++ u8_t rcv_nxt[4]; ++ /**< The sequence number that we expect to ++ receive next. */ ++ u8_t snd_nxt[4]; ++ /**< The sequence number that was last sent by ++ us. */ ++ u16_t len; /**< Length of the data that was previously sent. */ ++ u16_t mss; /**< Current maximum segment size for the ++ connection. */ ++ u16_t initialmss; ++ /**< Initial maximum segment size for the ++ connection. */ ++ u8_t sa; /**< Retransmission time-out calculation state ++ variable. */ ++ u8_t sv; /**< Retransmission time-out calculation state ++ variable. */ ++ u8_t rto; /**< Retransmission time-out. */ ++ u8_t tcpstateflags; ++ /**< TCP state and flags. */ ++ u8_t timer; /**< The retransmission timer. */ ++ u8_t nrtx; /**< The number of retransmissions for the last ++ segment sent. */ ++}; ++ ++/** ++ * \addtogroup uiparch ++ * @{ ++ */ ++ ++/** ++ * 4-byte array used for the 32-bit sequence number calculations. ++ */ ++extern u8_t uip_acc32[4]; ++ ++/** @} */ ++ ++#if UIP_UDP ++/** ++ * Representation of a uIP UDP connection. ++ */ ++struct uip_udp_conn { ++ uip_ip4addr_t ripaddr; ++ /**< The IP address of the remote peer. */ ++ u16_t lport; /**< The local port number in network byte order. */ ++ u16_t rport; /**< The remote port number in network byte order. */ ++ u8_t ttl; /**< Default time-to-live. */ ++ ++ /** The application state. */ ++/* uip_udp_appstate_t appstate; */ ++}; ++ ++#endif /* UIP_UDP */ ++ ++/** ++ * The structure holding the TCP/IP statistics that are gathered if ++ * UIP_STATISTICS is set to 1. ++ * ++ */ ++struct uip_stats { ++ struct { ++ uip_stats_t drop; ++ /**< Number of dropped packets at the IP ++ layer. */ ++ uip_stats_t recv; ++ /**< Number of received packets at the IP ++ layer. */ ++ uip_stats_t sent; ++ /**< Number of sent packets at the IP ++ layer. */ ++ uip_stats_t vhlerr; ++ /**< Number of packets dropped due to wrong ++ IP version or header length. */ ++ uip_stats_t hblenerr; ++ /**< Number of packets dropped due to wrong ++ IP length, high byte. */ ++ uip_stats_t lblenerr; ++ /**< Number of packets dropped due to wrong ++ IP length, low byte. */ ++ uip_stats_t fragerr; ++ /**< Number of packets dropped since they ++ were IP fragments. */ ++ uip_stats_t chkerr; ++ /**< Number of packets dropped due to IP ++ checksum errors. */ ++ uip_stats_t protoerr; ++ /**< Number of packets dropped since they ++ were neither ICMP, UDP nor TCP. */ ++ } ip; /**< IP statistics. */ ++ struct { ++ uip_stats_t drop; ++ /**< Number of dropped ICMP packets. */ ++ uip_stats_t recv; ++ /**< Number of received ICMP packets. */ ++ uip_stats_t sent; ++ /**< Number of sent ICMP packets. */ ++ uip_stats_t typeerr; ++ /**< Number of ICMP packets with a wrong ++ type. */ ++ } icmp; /**< ICMP statistics. */ ++ struct { ++ uip_stats_t drop; ++ /**< Number of dropped TCP segments. */ ++ uip_stats_t recv; ++ /**< Number of recived TCP segments. */ ++ uip_stats_t sent; ++ /**< Number of sent TCP segments. */ ++ uip_stats_t chkerr; ++ /**< Number of TCP segments with a bad ++ checksum. */ ++ uip_stats_t ackerr; ++ /**< Number of TCP segments with a bad ACK ++ number. */ ++ uip_stats_t rst; ++ /**< Number of recevied TCP RST (reset) segments. */ ++ uip_stats_t rexmit; ++ /**< Number of retransmitted TCP segments. */ ++ uip_stats_t syndrop; ++ /**< Number of dropped SYNs due to too few ++ connections was avaliable. */ ++ uip_stats_t synrst; ++ /**< Number of SYNs for closed ports, ++ triggering a RST. */ ++ } tcp; /**< TCP statistics. */ ++#if UIP_UDP ++ struct { ++ uip_stats_t drop; ++ /**< Number of dropped UDP segments. */ ++ uip_stats_t recv; ++ /**< Number of recived UDP segments. */ ++ uip_stats_t sent; ++ /**< Number of sent UDP segments. */ ++ uip_stats_t chkerr; ++ /**< Number of UDP segments with a bad ++ checksum. */ ++ } udp; /**< UDP statistics. */ ++#endif /* UIP_UDP */ ++}; ++ ++/*---------------------------------------------------------------------------*/ ++/* All the stuff below this point is internal to uIP and should not be ++ * used directly by an application or by a device driver. ++ */ ++/*---------------------------------------------------------------------------*/ ++/* u8_t uip_flags: ++ * ++ * When the application is called, uip_flags will contain the flags ++ * that are defined in this file. Please read below for more ++ * infomation. ++ */ ++/* extern u8_t uip_flags; */ ++ ++/* The following flags may be set in the global variable uip_flags ++ before calling the application callback. The UIP_ACKDATA, ++ UIP_NEWDATA, and UIP_CLOSE flags may both be set at the same time, ++ whereas the others are mutualy exclusive. Note that these flags ++ should *NOT* be accessed directly, but only through the uIP ++ functions/macros. */ ++ ++#define UIP_ACKDATA 1 /* Signifies that the outstanding data was ++ acked and the application should send ++ out new data instead of retransmitting ++ the last data. */ ++#define UIP_NEWDATA 2 /* Flags the fact that the peer has sent ++ us new data. */ ++#define UIP_REXMIT 4 /* Tells the application to retransmit the ++ data that was last sent. */ ++#define UIP_POLL 8 /* Used for polling the application, to ++ check if the application has data that ++ it wants to send. */ ++#define UIP_CLOSE 16 /* The remote host has closed the ++ connection, thus the connection has ++ gone away. Or the application signals ++ that it wants to close the ++ connection. */ ++#define UIP_ABORT 32 /* The remote host has aborted the ++ connection, thus the connection has ++ gone away. Or the application signals ++ that it wants to abort the ++ connection. */ ++#define UIP_CONNECTED 64 /* We have got a connection from a remote ++ host and have set up a new connection ++ for it, or an active connection has ++ been successfully established. */ ++ ++#define UIP_TIMEDOUT 128 /* The connection has been aborted due to ++ too many retransmissions. */ ++ ++void uip_input(struct uip_stack *ustack); ++void uip_periodic(struct uip_stack *ustack, int conn); ++ ++/* uip_process(flag): ++ * ++ * The actual uIP function which does all the work. ++ */ ++void uip_process(struct uip_stack *ustack, u8_t flag); ++ ++/* The following flags are passed as an argument to the uip_process() ++ function. They are used to distinguish between the two cases where ++ uip_process() is called. It can be called either because we have ++ incoming data that should be processed, or because the periodic ++ timer has fired. These values are never used directly, but only in ++ the macrose defined in this file. */ ++ ++#define UIP_DATA 1 /* Tells uIP that there is incoming ++ data in the uip_buf buffer. The ++ length of the data is stored in the ++ global variable uip_len. */ ++#define UIP_TIMER 2 /* Tells uIP that the periodic timer ++ has fired. */ ++#define UIP_POLL_REQUEST 3 /* Tells uIP that a connection should ++ be polled. */ ++#define UIP_UDP_SEND_CONN 4 /* Tells uIP that a UDP datagram ++ should be constructed in the ++ uip_buf buffer. */ ++#if UIP_UDP ++#define UIP_UDP_TIMER 5 ++#endif /* UIP_UDP */ ++ ++#define UIP_NDP_TIMER 6 ++ ++/* The TCP states used in the uip_conn->tcpstateflags. */ ++#define UIP_CLOSED 0 ++#define UIP_SYN_RCVD 1 ++#define UIP_SYN_SENT 2 ++#define UIP_ESTABLISHED 3 ++#define UIP_FIN_WAIT_1 4 ++#define UIP_FIN_WAIT_2 5 ++#define UIP_CLOSING 6 ++#define UIP_TIME_WAIT 7 ++#define UIP_LAST_ACK 8 ++#define UIP_TS_MASK 15 ++ ++#define UIP_STOPPED 16 ++ ++struct __attribute__ ((__packed__)) uip_tcp_hdr { ++ /* TCP header. */ ++ u16_t srcport, destport; ++ u8_t seqno[4], ackno[4], tcpoffset, flags, wnd[2]; ++ u16_t tcpchksum; ++ u8_t urgp[2]; ++ u8_t optdata[4]; ++}; ++ ++struct __attribute__ ((__packed__)) uip_ipv4_hdr { ++ /* IPv4 header. */ ++ u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto; ++ u16_t ipchksum; ++ u16_t srcipaddr[2], destipaddr[2]; ++}; ++ ++struct __attribute__ ((__packed__)) uip_ipv6_hdr { ++ /* IPv6 header. */ ++ u8_t vtc, tcflow; ++ u16_t flow; ++ u16_t len; ++ u8_t proto, ttl; ++ uip_ip6addr_t srcipaddr, destipaddr; ++}; ++ ++/* The TCP and IPv4 headers. */ ++struct __attribute__ ((__packed__)) uip_tcp_ipv4_hdr { ++ /* IPv4 header. */ ++ u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto; ++ u16_t ipchksum; ++ u16_t srcipaddr[2], destipaddr[2]; ++ ++ /* TCP header. */ ++ u16_t srcport, destport; ++ u8_t seqno[4], ackno[4], tcpoffset, flags, wnd[2]; ++ u16_t tcpchksum; ++ u8_t urgp[2]; ++ u8_t optdata[4]; ++}; ++ ++/* The TCP and IP headers. */ ++struct __attribute__ ((__packed__)) uip_tcp_ipv6_hdr { ++ /* IPv6 header. */ ++ u8_t vtc, tcflow; ++ u16_t flow; ++ u8_t len[2]; ++ u8_t proto, ttl; ++ uip_ip6addr_t srcipaddr, destipaddr; ++ ++ /* TCP header. */ ++ u16_t srcport, destport; ++ u8_t seqno[4], ackno[4], tcpoffset, flags, wnd[2]; ++ u16_t tcpchksum; ++ u8_t urgp[2]; ++ u8_t optdata[4]; ++}; ++ ++/* The ICMPv4 */ ++struct __attribute__ ((__packed__)) uip_icmpv4_hdr { ++ /* ICMP (echo) header. */ ++ u8_t type, icode; ++ u16_t icmpchksum; ++ u16_t id, seqno; ++}; ++ ++typedef struct uip_icmpv4_hdr uip_icmp_echo_hdr_t; ++ ++/* The ICMPv6 */ ++struct __attribute__ ((__packed__)) uip_icmpv6_hdr { ++ /* ICMP (echo) header. */ ++ u8_t type, icode; ++ u16_t icmpchksum; ++ u8_t flags, reserved1, reserved2, reserved3; ++ u8_t icmp6data[16]; ++ u8_t options[1]; ++}; ++ ++/* The ICMP and IP headers. */ ++struct __attribute__ ((__packed__)) uip_icmpip_hdr { ++#if UIP_CONF_IPV6 ++ /* IPv6 header. */ ++ u8_t vtc, tcf; ++ u16_t flow; ++ u8_t len[2]; ++ u8_t proto, ttl; ++ uip_ip6addr_t srcipaddr, destipaddr; ++#else /* UIP_CONF_IPV6 */ ++ /* IPv4 header. */ ++ u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto; ++ u16_t ipchksum; ++ u16_t srcipaddr[2], destipaddr[2]; ++#endif /* UIP_CONF_IPV6 */ ++ ++ /* ICMP (echo) header. */ ++ u8_t type, icode; ++ u16_t icmpchksum; ++#if !UIP_CONF_IPV6 ++ u16_t id, seqno; ++#else /* !UIP_CONF_IPV6 */ ++ u8_t flags, reserved1, reserved2, reserved3; ++ u8_t icmp6data[16]; ++ u8_t options[1]; ++#endif /* !UIP_CONF_IPV6 */ ++}; ++ ++/* The UDP */ ++struct __attribute__ ((__packed__)) uip_udp_hdr { ++ /* UDP header. */ ++ u16_t srcport, destport; ++ u16_t udplen; ++ u16_t udpchksum; ++}; ++ ++/* The UDP and IP headers. */ ++struct __attribute__ ((__packed__)) uip_udpip_hdr { ++#if UIP_CONF_IPV6 ++ /* IPv6 header. */ ++ u8_t vtc, tcf; ++ u16_t flow; ++ u8_t len[2]; ++ u8_t proto, ttl; ++ uip_ip6addr_t srcipaddr, destipaddr; ++#else /* UIP_CONF_IPV6 */ ++ /* IP header. */ ++ u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto; ++ u16_t ipchksum; ++ u16_t srcipaddr[2], destipaddr[2]; ++#endif /* UIP_CONF_IPV6 */ ++ ++ /* UDP header. */ ++ u16_t srcport, destport; ++ u16_t udplen; ++ u16_t udpchksum; ++}; ++ ++/** ++ * The buffer size available for user data in the \ref uip_buf buffer. ++ * ++ * This macro holds the available size for user data in the \ref ++ * uip_buf buffer. The macro is intended to be used for checking ++ * bounds of available user data. ++ * ++ * Example: ++ \code ++ snprintf(uip_appdata, UIP_APPDATA_SIZE, "%u\n", i); ++ \endcode ++ * ++ * \hideinitializer ++ */ ++#define UIP_APPDATA_SIZE (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN) ++ ++#define UIP_PROTO_ICMP 1 ++#define UIP_PROTO_TCP 6 ++#define UIP_PROTO_UDP 17 ++#define UIP_PROTO_ICMP6 58 ++ ++/* Header sizes. */ ++#define UIP_IPv6_H_LEN 40 /* Size of IPv6 header */ ++#define UIP_IPv4_H_LEN 20 /* Size of IPv4 header */ ++ ++#define UIP_UDPH_LEN 8 /* Size of UDP header */ ++#define UIP_TCPH_LEN 20 /* Size of TCP header */ ++ ++#define UIP_IPv4_UDPH_LEN (UIP_UDPH_LEN + UIP_IPv4_H_LEN) /* Size of IPv4 ++ + UDP ++ header */ ++#define UIP_IPv4_TCPH_LEN (UIP_TCPH_LEN + UIP_IPv4_H_LEN) /* Size of IPv4 ++ + TCP ++ header */ ++#define UIP_TCP_IPv4_HLEN UIP_IPv4_TCPH_LEN ++ ++#define UIP_IPv6_UDPH_LEN (UIP_UDPH_LEN + UIP_IPv6_H_LEN) /* Size of IPv6 ++ + UDP ++ header */ ++#define UIP_IPv6_TCPH_LEN (UIP_TCPH_LEN + UIP_IPv6_H_LEN) /* Size of IPv6 ++ + TCP ++ header */ ++#define UIP_TCP_IPv6_HLEN UIP_IPv6_TCPH_LEN ++ ++/** ++ * Calculate the Internet checksum over a buffer. ++ * ++ * The Internet checksum is the one's complement of the one's ++ * complement sum of all 16-bit words in the buffer. ++ * ++ * See RFC1071. ++ * ++ * \param buf A pointer to the buffer over which the checksum is to be ++ * computed. ++ * ++ * \param len The length of the buffer over which the checksum is to ++ * be computed. ++ * ++ * \return The Internet checksum of the buffer. ++ */ ++u16_t uip_chksum(u16_t *buf, u16_t len); ++ ++/** ++ * Calculate the IP header checksum of the packet header in uip_buf. ++ * ++ * The IP header checksum is the Internet checksum of the 20 bytes of ++ * the IP header. ++ * ++ * \return The IP header checksum of the IP header in the uip_buf ++ * buffer. ++ */ ++u16_t uip_ipchksum(struct uip_stack *ustack); ++ ++/** ++ * Calculate the TCP checksum of the packet in uip_buf and uip_appdata. ++ * ++ * The TCP checksum is the Internet checksum of data contents of the ++ * TCP segment, and a pseudo-header as defined in RFC793. ++ * ++ * \return The TCP checksum of the TCP segment in uip_buf and pointed ++ * to by uip_appdata. ++ */ ++u16_t uip_tcpchksum(struct uip_stack *ustack); ++ ++/** ++ * Calculate the UDP checksum of the packet in uip_buf and uip_appdata. ++ * ++ * The UDP checksum is the Internet checksum of data contents of the ++ * UDP segment, and a pseudo-header as defined in RFC768. ++ * ++ * \return The UDP checksum of the UDP segment in uip_buf and pointed ++ * to by uip_appdata. ++ */ ++u16_t uip_udpchksum(struct uip_stack *ustack); ++ ++/* IPv6 checksum */ ++uint16_t icmpv6_checksum(uint8_t *data); ++ ++struct neighbor_entry { ++ struct in6_addr ipaddr; ++ struct uip_eth_addr mac_addr; ++ u8_t time; ++}; ++ ++struct uip_stack { ++ struct uip_eth_addr uip_ethaddr; ++ ++ u8_t *uip_buf; ++ ++ uint8_t *data_link_layer; /* Pointer to the data link layer */ ++ uint8_t *network_layer; /* Pointer to the network layer */ ++ void *uip_appdata; /* The uip_appdata pointer points to ++ application data. */ ++ void *uip_sappdata; /* The uip_appdata pointer points to ++ the application data which is to ++ be sent. */ ++#if UIP_URGDATA > 0 ++ void *uip_urgdata; /* The uip_urgdata pointer points to ++ urgent data (out-of-band data), if ++ present. */ ++ u16_t uip_urglen, uip_surglen; ++#endif /* UIP_URGDATA > 0 */ ++ ++ u16_t uip_len, uip_slen; /* The uip_len is either 8 or 16 bits, ++ depending on the maximum packet ++ size. */ ++ u8_t uip_flags; /* The uip_flags variable is used for ++ communication between the TCP/IP stack ++ and the application program. */ ++ struct uip_conn *uip_conn; /* uip_conn always points to the current ++ connection. */ ++ ++ struct uip_conn uip_conns[UIP_CONNS]; ++ /* The uip_conns array holds all TCP ++ connections. */ ++ u16_t uip_listenports[UIP_LISTENPORTS]; ++ /* The uip_listenports list all currently ++ listning ports. */ ++#if UIP_UDP ++ struct uip_udp_conn *uip_udp_conn; ++ struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; ++#endif /* UIP_UDP */ ++ ++ u16_t ipid; /* This ipid variable is an increasing ++ number that is used for the IP ID ++ field. */ ++ ++ u8_t iss[4]; /* The iss variable is used for the TCP ++ initial sequence number. */ ++ ++#if UIP_ACTIVE_OPEN ++ u16_t lastport; /* Keeps track of the last port used for ++ a new connection. */ ++#endif /* UIP_ACTIVE_OPEN */ ++ ++#define IP_CONFIG_OFF 0x00 ++#define IPV4_CONFIG_OFF 0x01 ++#define IPV4_CONFIG_STATIC 0x02 ++#define IPV4_CONFIG_DHCP 0x04 ++#define IPV6_CONFIG_OFF 0x10 ++#define IPV6_CONFIG_STATIC 0x20 ++#define IPV6_CONFIG_DHCP 0x40 ++ u8_t ip_config; ++ ++ uip_ip4addr_t hostaddr, netmask, default_route_addr; ++ uip_ip6addr_t hostaddr6, netmask6, default_route_addr6, ++ linklocal6; ++ int prefix_len; ++ u8_t ipv6_autocfg; ++#define IPV6_AUTOCFG_DHCPV6 (1<<0) ++#define IPV6_AUTOCFG_ND (1<<1) ++#define IPV6_AUTOCFG_NOTSPEC (1<<6) ++#define IPV6_AUTOCFG_NOTUSED (1<<7) ++ u8_t linklocal_autocfg; ++#define IPV6_LL_AUTOCFG_ON (1<<0) ++#define IPV6_LL_AUTOCFG_OFF (1<<1) ++#define IPV6_LL_AUTOCFG_NOTSPEC (1<<6) ++#define IPV6_LL_AUTOCFG_NOTUSED (1<<7) ++ u8_t router_autocfg; ++#define IPV6_RTR_AUTOCFG_ON (1<<0) ++#define IPV6_RTR_AUTOCFG_OFF (1<<1) ++#define IPV6_RTR_AUTOCFG_NOTSPEC (1<<6) ++#define IPV6_RTR_AUTOCFG_NOTUSED (1<<7) ++ ++#define UIP_NEIGHBOR_ENTRIES 8 ++ struct neighbor_entry neighbor_entries[UIP_NEIGHBOR_ENTRIES]; ++ ++ struct uip_stats stats; ++ ++ u8_t opt; ++ ++ pthread_mutex_t lock; ++ ++ /* IPv6 support */ ++#define UIP_SUPPORT_IPv6_ENABLED 0x01 ++#define UIP_SUPPORT_IPv6_DISABLED 0x02 ++ u8_t enable_IPv6; ++ ++ /* DHCPC client attached */ ++ void *dhcpc; ++ ++ /* NDP client */ ++ void *ndpc; ++ ++ void *ping_conf; ++}; ++ ++/******************************************************************************* ++ * IPv6 Support ++ ******************************************************************************/ ++int set_ipv6_link_local_address(struct uip_stack *ustack); ++int is_ipv6_link_local_address(uip_ip6addr_t *addr); ++ ++void dump_uip_packet(struct uip_stack *ustack); ++u16_t uip_icmp6chksum(struct uip_stack *ustack); ++ ++#endif /* __UIP_H__ */ ++ ++/** @} */ +diff --git a/iscsiuio/src/uip/uip_arch.h b/iscsiuio/src/uip/uip_arch.h +new file mode 100644 +index 0000000..3ddacec +--- /dev/null ++++ b/iscsiuio/src/uip/uip_arch.h +@@ -0,0 +1,137 @@ ++/** ++ * \addtogroup uip ++ * {@ ++ */ ++ ++/** ++ * \defgroup uiparch Architecture specific uIP functions ++ * @{ ++ * ++ * The functions in the architecture specific module implement the IP ++ * check sum and 32-bit additions. ++ * ++ * The IP checksum calculation is the most computationally expensive ++ * operation in the TCP/IP stack and it therefore pays off to ++ * implement this in efficient assembler. The purpose of the uip-arch ++ * module is to let the checksum functions to be implemented in ++ * architecture specific assembler. ++ * ++ */ ++ ++/** ++ * \file ++ * Declarations of architecture specific functions. ++ * \author Adam Dunkels ++ */ ++ ++/* ++ * Copyright (c) 2001, Adam Dunkels. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack. ++ * ++ * ++ */ ++ ++#ifndef __UIP_ARCH_H__ ++#define __UIP_ARCH_H__ ++ ++#include "uip.h" ++ ++/** ++ * Carry out a 32-bit addition. ++ * ++ * Because not all architectures for which uIP is intended has native ++ * 32-bit arithmetic, uIP uses an external C function for doing the ++ * required 32-bit additions in the TCP protocol processing. This ++ * function should add the two arguments and place the result in the ++ * global variable uip_acc32. ++ * ++ * \note The 32-bit integer pointed to by the op32 parameter and the ++ * result in the uip_acc32 variable are in network byte order (big ++ * endian). ++ * ++ * \param op32 A pointer to a 4-byte array representing a 32-bit ++ * integer in network byte order (big endian). ++ * ++ * \param op16 A 16-bit integer in host byte order. ++ */ ++void uip_add32(u8_t *op32, u16_t op16, u8_t *uip_add32); ++ ++/** ++ * Calculate the Internet checksum over a buffer. ++ * ++ * The Internet checksum is the one's complement of the one's ++ * complement sum of all 16-bit words in the buffer. ++ * ++ * See RFC1071. ++ * ++ * \note This function is not called in the current version of uIP, ++ * but future versions might make use of it. ++ * ++ * \param buf A pointer to the buffer over which the checksum is to be ++ * computed. ++ * ++ * \param len The length of the buffer over which the checksum is to ++ * be computed. ++ * ++ * \return The Internet checksum of the buffer. ++ */ ++u16_t uip_chksum(u16_t *buf, u16_t len); ++ ++/** ++ * Calculate the IP header checksum of the packet header in uip_buf. ++ * ++ * The IP header checksum is the Internet checksum of the 20 bytes of ++ * the IP header. ++ * ++ * \return The IP header checksum of the IP header in the uip_buf ++ * buffer. ++ */ ++u16_t uip_ipchksum(struct uip_stack *ustack); ++ ++/** ++ * Calculate the TCP checksum of the packet in uip_buf and uip_appdata. ++ * ++ * The TCP checksum is the Internet checksum of data contents of the ++ * TCP segment, and a pseudo-header as defined in RFC793. ++ * ++ * \note The uip_appdata pointer that points to the packet data may ++ * point anywhere in memory, so it is not possible to simply calculate ++ * the Internet checksum of the contents of the uip_buf buffer. ++ * ++ * \return The TCP checksum of the TCP segment in uip_buf and pointed ++ * to by uip_appdata. ++ */ ++u16_t uip_tcpchksum(struct uip_stack *ustack); ++ ++u16_t uip_udpchksum(struct uip_stack *ustack); ++ ++/** @} */ ++/** @} */ ++ ++#endif /* __UIP_ARCH_H__ */ +diff --git a/iscsiuio/src/uip/uip_arp.c b/iscsiuio/src/uip/uip_arp.c +new file mode 100644 +index 0000000..1b3761f +--- /dev/null ++++ b/iscsiuio/src/uip/uip_arp.c +@@ -0,0 +1,479 @@ ++#include ++#include ++#include ++ ++#include "logger.h" ++#include "packet.h" ++ ++/** ++ * \addtogroup uip ++ * @{ ++ */ ++ ++/** ++ * \defgroup uiparp uIP Address Resolution Protocol ++ * @{ ++ * ++ * The Address Resolution Protocol ARP is used for mapping between IP ++ * addresses and link level addresses such as the Ethernet MAC ++ * addresses. ARP uses broadcast queries to ask for the link level ++ * address of a known IP address and the host which is configured with ++ * the IP address for which the query was meant, will respond with its ++ * link level address. ++ * ++ * \note This ARP implementation only supports Ethernet. ++ */ ++ ++/** ++ * \file ++ * Implementation of the ARP Address Resolution Protocol. ++ * \author Adam Dunkels ++ * ++ */ ++ ++/* ++ * Copyright (c) 2001-2003, Adam Dunkels. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack. ++ * ++ * ++ */ ++ ++#include "uip_arp.h" ++#include "uip_eth.h" ++ ++#include ++#include ++ ++static const struct uip_eth_addr broadcast_ethaddr = { ++ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} }; ++static const u16_t broadcast_ipaddr[2] = { 0xffff, 0xffff }; ++ ++pthread_mutex_t arp_table_mutex = PTHREAD_MUTEX_INITIALIZER; ++static struct arp_entry arp_table[UIP_ARPTAB_SIZE]; ++ ++static u8_t arptime; ++ ++/** ++ * Initialize the ARP module. ++ * ++ */ ++/*----------------------------------------------------------------------------*/ ++void uip_arp_init(void) ++{ ++ u8_t i; ++ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) ++ memset(&arp_table[i], 0, sizeof(arp_table[i])); ++ ++ pthread_mutex_init(&arp_table_mutex, NULL); ++} ++ ++/*----------------------------------------------------------------------------*/ ++/** ++ * Periodic ARP processing function. ++ * ++ * This function performs periodic timer processing in the ARP module ++ * and should be called at regular intervals. The recommended interval ++ * is 10 seconds between the calls. ++ * ++ */ ++/*----------------------------------------------------------------------------*/ ++void uip_arp_timer(void) ++{ ++ u8_t i; ++ struct arp_entry *tabptr; ++ ++ ++arptime; ++ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) { ++ tabptr = &arp_table[i]; ++ if ((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 && ++ (u8_t)(arptime - tabptr->time) >= UIP_ARP_MAXAGE) ++ memset(tabptr->ipaddr, 0, 4); ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------*/ ++static void uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr) ++{ ++ u8_t i; ++ struct arp_entry *tabptr; ++ ++ pthread_mutex_lock(&arp_table_mutex); ++ /* Walk through the ARP mapping table and try to find an entry to ++ update. If none is found, the IP -> MAC address mapping is ++ inserted in the ARP table. */ ++ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) { ++ ++ tabptr = &arp_table[i]; ++ /* Only check those entries that are actually in use. */ ++ if (tabptr->ipaddr[0] != 0 && tabptr->ipaddr[1] != 0) { ++ ++ /* Check if the source IP address of the incoming packet ++ matches the IP address in this ARP table entry. */ ++ if (ipaddr[0] == tabptr->ipaddr[0] && ++ ipaddr[1] == tabptr->ipaddr[1]) { ++ ++ tabptr->time = arptime; ++ ++ pthread_mutex_unlock(&arp_table_mutex); ++ return; ++ } ++ } ++ } ++ ++ /* If we get here, no existing ARP table entry was found, so we ++ create one. */ ++ ++ /* First, we try to find an unused entry in the ARP table. */ ++ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) { ++ tabptr = &arp_table[i]; ++ if (tabptr->ipaddr[0] == 0 && tabptr->ipaddr[1] == 0) ++ break; ++ } ++ ++ /* If no unused entry is found, we try to find the oldest entry and ++ throw it away. */ ++ if (i == UIP_ARPTAB_SIZE) { ++ u8_t c; ++ u8_t tmpage = 0; ++ c = 0; ++ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) { ++ tabptr = &arp_table[i]; ++ if ((u8_t)(arptime - tabptr->time) > tmpage) { ++ tmpage = (u8_t)(arptime - tabptr->time); ++ c = i; ++ } ++ } ++ i = c; ++ tabptr = &arp_table[i]; ++ } ++ ++ /* Now, i is the ARP table entry which we will fill with the new ++ information. */ ++ memcpy(tabptr->ipaddr, ipaddr, 4); ++ memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); ++ tabptr->time = arptime; ++ ++ pthread_mutex_unlock(&arp_table_mutex); ++} ++ ++/** ++ * ARP processing for incoming ARP packets. ++ * ++ * This function should be called by the device driver when an ARP ++ * packet has been received. The function will act differently ++ * depending on the ARP packet type: if it is a reply for a request ++ * that we previously sent out, the ARP cache will be filled in with ++ * the values from the ARP reply. If the incoming ARP packet is an ARP ++ * request for our IP address, an ARP reply packet is created and put ++ * into the uip_buf[] buffer. ++ * ++ * When the function returns, the value of the global variable uip_len ++ * indicates whether the device driver should send out a packet or ++ * not. If uip_len is zero, no packet should be sent. If uip_len is ++ * non-zero, it contains the length of the outbound packet that is ++ * present in the uip_buf[] buffer. ++ * ++ * This function expects an ARP packet with a prepended Ethernet ++ * header in the uip_buf[] buffer, and the length of the packet in the ++ * global variable uip_len. ++ */ ++void uip_arp_ipin(struct uip_stack *ustack, packet_t *pkt) ++{ ++ struct ip_hdr *ip; ++ struct uip_eth_hdr *eth; ++ ++ eth = (struct uip_eth_hdr *)pkt->data_link_layer; ++ ip = (struct ip_hdr *)pkt->network_layer; ++ ++ if (uip_ip4addr_cmp(ip->destipaddr, ustack->hostaddr)) { ++ /* First, we register the one who made the request in our ARP ++ table, since it is likely that we will do more communication ++ with this host in the future. */ ++ uip_arp_update(ip->srcipaddr, ð->src); ++ } ++} ++ ++void ++uip_arp_arpin(nic_interface_t *nic_iface, ++ struct uip_stack *ustack, packet_t *pkt) ++{ ++ struct arp_hdr *arp; ++ struct uip_eth_hdr *eth; ++ ++ if (pkt->buf_size < sizeof(struct arp_hdr)) { ++ pkt->buf_size = 0; ++ return; ++ } ++ pkt->buf_size = 0; ++ ++ eth = (struct uip_eth_hdr *)pkt->data_link_layer; ++ arp = (struct arp_hdr *)pkt->network_layer; ++ ++ switch (arp->opcode) { ++ case const_htons(ARP_REQUEST): ++ /* ARP request. If it asked for our address, we send out a ++ reply. */ ++ if (uip_ip4addr_cmp(arp->dipaddr, ustack->hostaddr)) { ++ /* First, we register the one who made the request in ++ our ARP table, since it is likely that we will do ++ more communication with this host in the future. */ ++ uip_arp_update(arp->sipaddr, &arp->shwaddr); ++ ++ /* The reply opcode is 2. */ ++ arp->opcode = htons(2); ++ ++ memcpy(arp->dhwaddr.addr, arp->shwaddr.addr, 6); ++ memcpy(arp->shwaddr.addr, ustack->uip_ethaddr.addr, 6); ++ memcpy(eth->src.addr, ustack->uip_ethaddr.addr, 6); ++ memcpy(eth->dest.addr, arp->dhwaddr.addr, 6); ++ ++ arp->dipaddr[0] = arp->sipaddr[0]; ++ arp->dipaddr[1] = arp->sipaddr[1]; ++ arp->sipaddr[0] = ustack->hostaddr[0]; ++ arp->sipaddr[1] = ustack->hostaddr[1]; ++ ++ if (nic_iface->vlan_id == 0) { ++ eth->type = htons(UIP_ETHTYPE_ARP); ++ pkt->buf_size = sizeof(*arp) + sizeof(*eth); ++ } else { ++ eth->type = htons(UIP_ETHTYPE_8021Q); ++ pkt->buf_size = sizeof(*arp) + ++ sizeof(struct uip_vlan_eth_hdr); ++ } ++ } ++ break; ++ case const_htons(ARP_REPLY): ++ uip_arp_update(arp->sipaddr, &arp->shwaddr); ++ break; ++ default: ++ LOG_WARN("Unknown ARP opcode: %d", ntohs(arp->opcode)); ++ break; ++ } ++ ++ return; ++} ++ ++/** ++ * Prepend Ethernet header to an outbound IP packet and see if we need ++ * to send out an ARP request. ++ * ++ * This function should be called before sending out an IP packet. The ++ * function checks the destination IP address of the IP packet to see ++ * what Ethernet MAC address that should be used as a destination MAC ++ * address on the Ethernet. ++ * ++ * If the destination IP address is in the local network (determined ++ * by logical ANDing of netmask and our IP address), the function ++ * checks the ARP cache to see if an entry for the destination IP ++ * address is found. If so, an Ethernet header is prepended and the ++ * function returns. If no ARP cache entry is found for the ++ * destination IP address, the packet in the uip_buf[] is replaced by ++ * an ARP request packet for the IP address. The IP packet is dropped ++ * and it is assumed that they higher level protocols (e.g., TCP) ++ * eventually will retransmit the dropped packet. ++ * ++ * If the destination IP address is not on the local network, the IP ++ * address of the default router is used instead. ++ * ++ * When the function returns, a packet is present in the uip_buf[] ++ * buffer, and the length of the packet is in the global variable ++ * uip_len. ++ */ ++ ++dest_ipv4_addr_t ++uip_determine_dest_ipv4_addr(struct uip_stack *ustack, u16_t *ipaddr) ++{ ++ struct uip_eth_hdr *eth; ++ struct ip_hdr *ip_buf; ++ ++ eth = (struct uip_eth_hdr *)ustack->data_link_layer; ++ ip_buf = (struct ip_hdr *)ustack->network_layer; ++ ++ /* Find the destination IP address in the ARP table and construct ++ the Ethernet header. If the destination IP addres isn't on the ++ local network, we use the default router's IP address instead. ++ ++ If not ARP table entry is found, we overwrite the original IP ++ packet with an ARP request for the IP address. */ ++ ++ /* First check if destination is a local broadcast. */ ++ if (uip_ip4addr_cmp(ip_buf->destipaddr, broadcast_ipaddr)) { ++ memcpy(ð->dest, broadcast_ethaddr.addr, 6); ++ ++ return LOCAL_BROADCAST; ++ } else { ++ /* Check if the destination address is on the local network. */ ++ if (!uip_ip4addr_maskcmp(ip_buf->destipaddr, ++ ustack->hostaddr, ustack->netmask)) { ++ /* Destination address was not on the local network, ++ so we need to use the default router's IP address ++ instead of the destination address when determining ++ the MAC address. */ ++ uip_ip4addr_copy(ipaddr, ustack->default_route_addr); ++ } else { ++ /* Else, we use the destination IP address. */ ++ uip_ip4addr_copy(ipaddr, ip_buf->destipaddr); ++ } ++ ++ return NONLOCAL_BROADCAST; ++ } ++} ++ ++arp_out_t is_in_arp_table(u16_t *ipaddr, struct arp_entry **tabptr) ++{ ++ u8_t i; ++ ++ pthread_mutex_lock(&arp_table_mutex); ++ ++ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) { ++ if (uip_ip4addr_cmp(ipaddr, arp_table[i].ipaddr)) { ++ *tabptr = &arp_table[i]; ++ break; ++ } ++ } ++ ++ pthread_mutex_unlock(&arp_table_mutex); ++ ++ if (i == UIP_ARPTAB_SIZE) ++ return NOT_IN_ARP_TABLE; ++ else ++ return IS_IN_ARP_TABLE; ++} ++ ++void uip_build_arp_request(struct uip_stack *ustack, u16_t *ipaddr) ++{ ++ struct arp_hdr *arp; ++ struct uip_eth_hdr *eth; ++ ++ arp = (struct arp_hdr *)ustack->network_layer; ++ eth = (struct uip_eth_hdr *)ustack->data_link_layer; ++ ++ /* The destination address was not in our ARP table, so we ++ overwrite the IP packet with an ARP request. */ ++ ++ memset(eth->dest.addr, 0xff, 6); ++ memset(arp->dhwaddr.addr, 0x00, 6); ++ memcpy(eth->src.addr, ustack->uip_ethaddr.addr, 6); ++ memcpy(arp->shwaddr.addr, ustack->uip_ethaddr.addr, 6); ++ ++ uip_ip4addr_copy(arp->dipaddr, ipaddr); ++ uip_ip4addr_copy(arp->sipaddr, ustack->hostaddr); ++ arp->opcode = const_htons(ARP_REQUEST); /* ARP request. */ ++ arp->hwtype = const_htons(ARP_HWTYPE_ETH); ++ arp->protocol = const_htons(UIP_ETHTYPE_IPv4); ++ arp->hwlen = 6; ++ arp->protolen = 4; ++ eth->type = const_htons(UIP_ETHTYPE_ARP); ++ ++ ustack->uip_appdata = &ustack->uip_buf[UIP_TCP_IPv4_HLEN + UIP_LLH_LEN]; ++ ++ ustack->uip_len = sizeof(*arp) + sizeof(*eth); ++} ++ ++void ++uip_build_eth_header(struct uip_stack *ustack, ++ u16_t *ipaddr, ++ struct arp_entry *tabptr, ++ struct packet *pkt, u16_t vlan_id) ++{ ++ struct uip_ipv4_hdr *ip_buf; ++ struct uip_eth_hdr *eth; ++ struct uip_vlan_eth_hdr *eth_vlan; ++ ++ ip_buf = (struct uip_ipv4_hdr *)ustack->network_layer; ++ eth = (struct uip_eth_hdr *)ustack->data_link_layer; ++ eth_vlan = (struct uip_vlan_eth_hdr *)ustack->data_link_layer; ++ ++ /* First check if destination is a local broadcast. */ ++ if (uip_ip4addr_cmp(ip_buf->destipaddr, broadcast_ipaddr)) { ++ memcpy(eth->dest.addr, broadcast_ethaddr.addr, 6); ++ } else { ++ /* Build an ethernet header. */ ++ memcpy(eth->dest.addr, tabptr->ethaddr.addr, 6); ++ } ++ memcpy(eth->src.addr, ustack->uip_ethaddr.addr, 6); ++ ++ if (vlan_id == 0) { ++ eth->type = htons(UIP_ETHTYPE_IPv4); ++ ++ ustack->uip_len += sizeof(struct uip_eth_hdr); ++ pkt->buf_size += sizeof(struct uip_eth_hdr); ++ } else { ++ eth_vlan->tpid = htons(UIP_ETHTYPE_8021Q); ++ eth_vlan->vid = htons(vlan_id); ++ eth_vlan->type = htons(UIP_ETHTYPE_IPv4); ++ ++ ustack->uip_len += sizeof(struct uip_vlan_eth_hdr); ++ pkt->buf_size += sizeof(struct uip_vlan_eth_hdr); ++ } ++} ++ ++static struct arp_entry *uip_get_arp_entry(int index) ++{ ++ return &arp_table[index]; ++} ++ ++int uip_lookup_arp_entry(uint32_t ip_addr, uint8_t *mac_addr) ++{ ++ int i; ++ int rc = -EINVAL; ++ ++ pthread_mutex_lock(&arp_table_mutex); ++ ++ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) { ++ struct arp_entry *entry = uip_get_arp_entry(i); ++ ++ if (((entry->ipaddr[1] << 16) == (ip_addr & 0xffff0000)) && ++ ((entry->ipaddr[0]) == (ip_addr & 0x0000ffff))) { ++ struct in_addr addr; ++ char *addr_str; ++ ++ addr.s_addr = ip_addr; ++ addr_str = inet_ntoa(addr); ++ ++ memcpy(mac_addr, entry->ethaddr.addr, 6); ++ ++ LOG_INFO("Found %s at %02x:%02x:%02x:%02x:%02x:%02x", ++ addr_str, ++ mac_addr[0], mac_addr[1], mac_addr[2], ++ mac_addr[3], mac_addr[4], mac_addr[5]); ++ rc = 0; ++ break; ++ } ++ } ++ ++ pthread_mutex_unlock(&arp_table_mutex); ++ return rc; ++} ++ ++/*----------------------------------------------------------------------------*/ ++ ++/** @} */ ++/** @} */ +diff --git a/iscsiuio/src/uip/uip_arp.h b/iscsiuio/src/uip/uip_arp.h +new file mode 100644 +index 0000000..339d57d +--- /dev/null ++++ b/iscsiuio/src/uip/uip_arp.h +@@ -0,0 +1,197 @@ ++/** ++ * \addtogroup uip ++ * @{ ++ */ ++ ++/** ++ * \addtogroup uiparp ++ * @{ ++ */ ++ ++/** ++ * \file ++ * Macros and definitions for the ARP module. ++ * \author Adam Dunkels ++ */ ++ ++/* ++ * Copyright (c) 2001-2003, Adam Dunkels. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack. ++ * ++ * ++ */ ++ ++#ifndef __UIP_ARP_H__ ++#define __UIP_ARP_H__ ++ ++#include "packet.h" ++#include "uip.h" ++#include "uip_eth.h" ++ ++#define ARP_REQUEST 1 ++#define ARP_REPLY 2 ++ ++#define ARP_HWTYPE_ETH 1 ++ ++struct __attribute__ ((__packed__)) arp_hdr { ++ u16_t hwtype; ++ u16_t protocol; ++ u8_t hwlen; ++ u8_t protolen; ++ u16_t opcode; ++ struct uip_eth_addr shwaddr; ++ u16_t sipaddr[2]; ++ struct uip_eth_addr dhwaddr; ++ u16_t dipaddr[2]; ++}; ++ ++struct __attribute__ ((__packed__)) ip_hdr { ++ /* IP header. */ ++ u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto; ++ u16_t ipchksum; ++ u16_t srcipaddr[2], destipaddr[2]; ++}; ++ ++struct __attribute__ ((__packed__)) ethip_hdr { ++ struct uip_eth_hdr ethhdr; ++ /* IP header. */ ++ u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto; ++ u16_t ipchksum; ++ u16_t srcipaddr[2], destipaddr[2]; ++}; ++ ++struct arp_entry { ++ u16_t ipaddr[2]; ++ struct uip_eth_addr ethaddr; ++ u8_t time; ++}; ++ ++/* The uip_arp_init() function must be called before any of the other ++ ARP functions. */ ++void uip_arp_init(void); ++ ++/* The uip_arp_ipin() function should be called whenever an IP packet ++ arrives from the Ethernet. This function refreshes the ARP table or ++ inserts a new mapping if none exists. The function assumes that an ++ IP packet with an Ethernet header is present in the uip_buf buffer ++ and that the length of the packet is in the uip_len variable. */ ++/*void uip_arp_ipin(void);*/ ++/* #define uip_arp_ipin() */ ++void uip_arp_ipin(struct uip_stack *ustack, struct packet *pkt); ++ ++/* The uip_arp_arpin() should be called when an ARP packet is received ++ by the Ethernet driver. This function also assumes that the ++ Ethernet frame is present in the uip_buf buffer. When the ++ uip_arp_arpin() function returns, the contents of the uip_buf ++ buffer should be sent out on the Ethernet if the uip_len variable ++ is > 0. */ ++void uip_arp_arpin(nic_interface_t *nic_iface, ++ struct uip_stack *ustack, struct packet *pkt); ++ ++typedef enum { ++ ARP_SENT = 1, ++ ETH_HEADER_APPEDEND = 2, ++} arp_out_t; ++ ++typedef enum { ++ LOCAL_BROADCAST = 1, ++ NONLOCAL_BROADCAST = 2, ++} dest_ipv4_addr_t; ++ ++typedef enum { ++ IS_IN_ARP_TABLE = 1, ++ NOT_IN_ARP_TABLE = 2, ++} arp_table_query_t; ++ ++dest_ipv4_addr_t ++uip_determine_dest_ipv4_addr(struct uip_stack *ustack, u16_t *ipaddr); ++arp_out_t is_in_arp_table(u16_t *ipaddr, struct arp_entry **tabptr); ++ ++void uip_build_arp_request(struct uip_stack *ustack, u16_t *ipaddr); ++ ++void ++uip_build_eth_header(struct uip_stack *ustack, ++ u16_t *ipaddr, ++ struct arp_entry *tabptr, ++ struct packet *pkt, u16_t vlan_id); ++ ++/* The uip_arp_out() function should be called when an IP packet ++ should be sent out on the Ethernet. This function creates an ++ Ethernet header before the IP header in the uip_buf buffer. The ++ Ethernet header will have the correct Ethernet MAC destination ++ address filled in if an ARP table entry for the destination IP ++ address (or the IP address of the default router) is present. If no ++ such table entry is found, the IP packet is overwritten with an ARP ++ request and we rely on TCP to retransmit the packet that was ++ overwritten. In any case, the uip_len variable holds the length of ++ the Ethernet frame that should be transmitted. */ ++arp_out_t uip_arp_out(struct uip_stack *ustack); ++ ++/* The uip_arp_timer() function should be called every ten seconds. It ++ is responsible for flushing old entries in the ARP table. */ ++void uip_arp_timer(void); ++ ++int uip_lookup_arp_entry(uint32_t ip_addr, uint8_t *mac_addr); ++ ++/** @} */ ++ ++/** ++ * \addtogroup uipconffunc ++ * @{ ++ */ ++ ++/** ++ * Specifiy the Ethernet MAC address. ++ * ++ * The ARP code needs to know the MAC address of the Ethernet card in ++ * order to be able to respond to ARP queries and to generate working ++ * Ethernet headers. ++ * ++ * \note This macro only specifies the Ethernet MAC address to the ARP ++ * code. It cannot be used to change the MAC address of the Ethernet ++ * card. ++ * ++ * \param eaddr A pointer to a struct uip_eth_addr containing the ++ * Ethernet MAC address of the Ethernet card. ++ * ++ * \hideinitializer ++ */ ++#define uip_setethaddr(eaddr) do { \ ++ uip_ethaddr.addr[0] = eaddr.addr[0]; \ ++ uip_ethaddr.addr[1] = eaddr.addr[1]; \ ++ uip_ethaddr.addr[2] = eaddr.addr[2]; \ ++ uip_ethaddr.addr[3] = eaddr.addr[3]; \ ++ uip_ethaddr.addr[4] = eaddr.addr[4]; \ ++ uip_ethaddr.addr[5] = eaddr.addr[5]; \ ++ } while (0) ++ ++/** @} */ ++/** @} */ ++ ++#endif /* __UIP_ARP_H__ */ +diff --git a/iscsiuio/src/uip/uip_eth.c b/iscsiuio/src/uip/uip_eth.c +new file mode 100644 +index 0000000..9e1ea81 +--- /dev/null ++++ b/iscsiuio/src/uip/uip_eth.c +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * uip_eth.c - CNIC UIO uIP user space stack ++ * ++ */ ++ ++#include "uip.h" ++#include "uip_eth.h" ++ ++int is_vlan_packet(struct uip_vlan_eth_hdr *hdr) ++{ ++ /* The TPID field in a 802.1Q Header must be 0x8100 */ ++ if (hdr->tpid == const_htons(UIP_ETHTYPE_8021Q)) ++ return 1; ++ ++ return 0; ++} +diff --git a/iscsiuio/src/uip/uip_eth.h b/iscsiuio/src/uip/uip_eth.h +new file mode 100644 +index 0000000..830c04c +--- /dev/null ++++ b/iscsiuio/src/uip/uip_eth.h +@@ -0,0 +1,43 @@ ++#ifndef __UIP_ETH_H__ ++#define __UIP_ETH_H__ ++ ++#include "uipopt.h" ++ ++/******************************************************************************* ++ * Ether types ++ ******************************************************************************/ ++#define UIP_ETHTYPE_ARP 0x0806 ++#define UIP_ETHTYPE_IPv4 0x0800 ++#define UIP_ETHTYPE_8021Q 0x8100 ++#define UIP_ETHTYPE_IPv6 0x86dd ++ ++/** ++ * Representation of a 48-bit Ethernet address. ++ */ ++struct uip_eth_addr { ++ u8_t addr[6]; ++}; ++ ++/** ++ * The Ethernet header. ++ */ ++struct __attribute__ ((__packed__)) uip_eth_hdr { ++ struct uip_eth_addr dest; ++ struct uip_eth_addr src; ++ u16_t type; ++}; ++ ++/** ++ * The 802.1Q Ethernet header (VLAN). ++ */ ++struct __attribute__ ((__packed__)) uip_vlan_eth_hdr { ++ struct uip_eth_addr dest; ++ struct uip_eth_addr src; ++ u16_t tpid; ++ u16_t vid; ++ u16_t type; ++}; ++ ++int is_vlan_packet(struct uip_vlan_eth_hdr *hdr); ++ ++#endif /* __UIP_ETH_H__ */ +diff --git a/iscsiuio/src/uip/uipopt.h b/iscsiuio/src/uip/uipopt.h +new file mode 100644 +index 0000000..946fce2 +--- /dev/null ++++ b/iscsiuio/src/uip/uipopt.h +@@ -0,0 +1,536 @@ ++/** ++ * \defgroup uipopt Configuration options for uIP ++ * @{ ++ * ++ * uIP is configured using the per-project configuration file ++ * uipopt.h. This file contains all compile-time options for uIP and ++ * should be tweaked to match each specific project. The uIP ++ * distribution contains a documented example "uipopt.h" that can be ++ * copied and modified for each project. ++ * ++ * \note Most of the configuration options in the uipopt.h should not ++ * be changed, but rather the per-project uip-conf.h file. ++ */ ++ ++/** ++ * \file ++ * Configuration options for uIP. ++ * \author Adam Dunkels ++ * ++ * This file is used for tweaking various configuration options for ++ * uIP. You should make a copy of this file into one of your project's ++ * directories instead of editing this example "uipopt.h" file that ++ * comes with the uIP distribution. ++ */ ++ ++/* ++ * Copyright (c) 2001-2003, Adam Dunkels. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack. ++ * ++ * ++ */ ++ ++#ifndef __UIPOPT_H__ ++#define __UIPOPT_H__ ++ ++#ifndef UIP_LITTLE_ENDIAN ++#define UIP_LITTLE_ENDIAN 3412 ++#endif /* UIP_LITTLE_ENDIAN */ ++#ifndef UIP_BIG_ENDIAN ++#define UIP_BIG_ENDIAN 1234 ++#endif /* UIP_BIG_ENDIAN */ ++ ++#include "uip-conf.h" ++ ++/*----------------------------------------------------------------------------*/ ++ ++/** ++ * \name Static configuration options ++ * @{ ++ * ++ * These configuration options can be used for setting the IP address ++ * settings statically, but only if UIP_FIXEDADDR is set to 1. The ++ * configuration options for a specific node includes IP address, ++ * netmask and default router as well as the Ethernet address. The ++ * netmask, default router and Ethernet address are appliciable only ++ * if uIP should be run over Ethernet. ++ * ++ * All of these should be changed to suit your project. ++*/ ++ ++/** ++ * Determines if uIP should use a fixed IP address or not. ++ * ++ * If uIP should use a fixed IP address, the settings are set in the ++ * uipopt.h file. If not, the macros uip_sethostaddr(), ++ * uip_setdraddr() and uip_setnetmask() should be used instead. ++ * ++ * \hideinitializer ++ */ ++#define UIP_FIXEDADDR 0 ++ ++/** ++ * Ping IP address asignment. ++ * ++ * uIP uses a "ping" packets for setting its own IP address if this ++ * option is set. If so, uIP will start with an empty IP address and ++ * the destination IP address of the first incoming "ping" (ICMP echo) ++ * packet will be used for setting the hosts IP address. ++ * ++ * \note This works only if UIP_FIXEDADDR is 0. ++ * ++ * \hideinitializer ++ */ ++#ifdef UIP_CONF_PINGADDRCONF ++#define UIP_PINGADDRCONF UIP_CONF_PINGADDRCONF ++#else /* UIP_CONF_PINGADDRCONF */ ++#define UIP_PINGADDRCONF 0 ++#endif /* UIP_CONF_PINGADDRCONF */ ++ ++/** ++ * Specifies if the uIP ARP module should be compiled with a fixed ++ * Ethernet MAC address or not. ++ * ++ * If this configuration option is 0, the macro uip_setethaddr() can ++ * be used to specify the Ethernet address at run-time. ++ * ++ * \hideinitializer ++ */ ++#define UIP_FIXEDETHADDR 0 ++ ++/** @} */ ++/*------------------------------------------------------------------------------*/ ++/** ++ * \name IP configuration options ++ * @{ ++ * ++ */ ++/** ++ * The IP TTL (time to live) of IP packets sent by uIP. ++ * ++ * This should normally not be changed. ++ */ ++#define UIP_TTL 64 ++ ++/** ++ * Turn on support for IP packet reassembly. ++ * ++ * uIP supports reassembly of fragmented IP packets. This features ++ * requires an additonal amount of RAM to hold the reassembly buffer ++ * and the reassembly code size is approximately 700 bytes. The ++ * reassembly buffer is of the same size as the uip_buf buffer ++ * (configured by UIP_BUFSIZE). ++ * ++ * \note IP packet reassembly is not heavily tested. ++ * ++ * \hideinitializer ++ */ ++#define UIP_REASSEMBLY 0 ++ ++/** ++ * The maximum time an IP fragment should wait in the reassembly ++ * buffer before it is dropped. ++ * ++ */ ++#define UIP_REASS_MAXAGE 40 ++ ++/** @} */ ++ ++/*----------------------------------------------------------------------------*/ ++/** ++ * \name UDP configuration options ++ * @{ ++ */ ++ ++/** ++ * Toggles wether UDP support should be compiled in or not. ++ * ++ * \hideinitializer ++ */ ++#ifdef UIP_CONF_UDP ++#define UIP_UDP UIP_CONF_UDP ++#else /* UIP_CONF_UDP */ ++#define UIP_UDP 0 ++#endif /* UIP_CONF_UDP */ ++ ++/** ++ * Toggles if UDP checksums should be used or not. ++ * ++ * \note Support for UDP checksums is currently not included in uIP, ++ * so this option has no function. ++ * ++ * \hideinitializer ++ */ ++#ifdef UIP_CONF_UDP_CHECKSUMS ++#define UIP_UDP_CHECKSUMS UIP_CONF_UDP_CHECKSUMS ++#else ++#define UIP_UDP_CHECKSUMS 0 ++#endif ++ ++/** ++ * The maximum amount of concurrent UDP connections. ++ * ++ * \hideinitializer ++ */ ++#ifdef UIP_CONF_UDP_CONNS ++#define UIP_UDP_CONNS UIP_CONF_UDP_CONNS ++#else /* UIP_CONF_UDP_CONNS */ ++#define UIP_UDP_CONNS 10 ++#endif /* UIP_CONF_UDP_CONNS */ ++ ++/** ++ * The name of the function that should be called when UDP datagrams arrive. ++ * ++ * \hideinitializer ++ */ ++ ++/** @} */ ++/*------------------------------------------------------------------------------*/ ++/** ++ * \name TCP configuration options ++ * @{ ++ */ ++ ++/** ++ * Determines if support for opening connections from uIP should be ++ * compiled in. ++ * ++ * If the applications that are running on top of uIP for this project ++ * do not need to open outgoing TCP connections, this configration ++ * option can be turned off to reduce the code size of uIP. ++ * ++ * \hideinitializer ++ */ ++#define UIP_ACTIVE_OPEN 1 ++ ++/** ++ * The maximum number of simultaneously open TCP connections. ++ * ++ * Since the TCP connections are statically allocated, turning this ++ * configuration knob down results in less RAM used. Each TCP ++ * connection requires approximatly 30 bytes of memory. ++ * ++ * \hideinitializer ++ */ ++#ifndef UIP_CONF_MAX_CONNECTIONS ++#define UIP_CONNS 10 ++#else /* UIP_CONF_MAX_CONNECTIONS */ ++#define UIP_CONNS UIP_CONF_MAX_CONNECTIONS ++#endif /* UIP_CONF_MAX_CONNECTIONS */ ++ ++/** ++ * The maximum number of simultaneously listening TCP ports. ++ * ++ * Each listening TCP port requires 2 bytes of memory. ++ * ++ * \hideinitializer ++ */ ++#ifndef UIP_CONF_MAX_LISTENPORTS ++#define UIP_LISTENPORTS 20 ++#else /* UIP_CONF_MAX_LISTENPORTS */ ++#define UIP_LISTENPORTS UIP_CONF_MAX_LISTENPORTS ++#endif /* UIP_CONF_MAX_LISTENPORTS */ ++ ++/** ++ * Determines if support for TCP urgent data notification should be ++ * compiled in. ++ * ++ * Urgent data (out-of-band data) is a rarely used TCP feature that ++ * very seldom would be required. ++ * ++ * \hideinitializer ++ */ ++#define UIP_URGDATA 0 ++ ++/** ++ * The initial retransmission timeout counted in timer pulses. ++ * ++ * This should not be changed. ++ */ ++#define UIP_RTO 3 ++ ++/** ++ * The maximum number of times a segment should be retransmitted ++ * before the connection should be aborted. ++ * ++ * This should not be changed. ++ */ ++#define UIP_MAXRTX 8 ++ ++/** ++ * The maximum number of times a SYN segment should be retransmitted ++ * before a connection request should be deemed to have been ++ * unsuccessful. ++ * ++ * This should not need to be changed. ++ */ ++#define UIP_MAXSYNRTX 5 ++ ++/** ++ * The TCP maximum segment size. ++ * ++ * This is should not be to set to more than ++ * UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN. ++ */ ++#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCP_IPv4_HLEN) ++ ++/** ++ * The size of the advertised receiver's window. ++ * ++ * Should be set low (i.e., to the size of the uip_buf buffer) is the ++ * application is slow to process incoming data, or high (32768 bytes) ++ * if the application processes data quickly. ++ * ++ * \hideinitializer ++ */ ++#ifndef UIP_CONF_RECEIVE_WINDOW ++#define UIP_RECEIVE_WINDOW UIP_TCP_MSS ++#else ++#define UIP_RECEIVE_WINDOW UIP_CONF_RECEIVE_WINDOW ++#endif ++ ++/** ++ * How long a connection should stay in the TIME_WAIT state. ++ * ++ * This configiration option has no real implication, and it should be ++ * left untouched. ++ */ ++#define UIP_TIME_WAIT_TIMEOUT 120 ++ ++/** @} */ ++/*------------------------------------------------------------------------------*/ ++/** ++ * \name ARP configuration options ++ * @{ ++ */ ++ ++/** ++ * The size of the ARP table. ++ * ++ * This option should be set to a larger value if this uIP node will ++ * have many connections from the local network. ++ * ++ * \hideinitializer ++ */ ++#ifdef UIP_CONF_ARPTAB_SIZE ++#define UIP_ARPTAB_SIZE UIP_CONF_ARPTAB_SIZE ++#else ++#define UIP_ARPTAB_SIZE 8 ++#endif ++ ++/** ++ * The maxium age of ARP table entries measured in 10ths of seconds. ++ * ++ * An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD ++ * default). ++ * Changed the default to 30 which corresponds to 5 minutes (Linux default) ++ */ ++#define UIP_ARP_MAXAGE 30 ++ ++/** @} */ ++ ++/*----------------------------------------------------------------------------*/ ++ ++/** ++ * \name General configuration options ++ * @{ ++ */ ++ ++/** ++ * The size of the uIP packet buffer. ++ * ++ * The uIP packet buffer should not be smaller than 60 bytes, and does ++ * not need to be larger than 1500 bytes. Lower size results in lower ++ * TCP throughput, larger size results in higher TCP throughput. ++ * ++ * \hideinitializer ++ */ ++#ifndef UIP_CONF_BUFFER_SIZE ++#define UIP_BUFSIZE 400 ++#else /* UIP_CONF_BUFFER_SIZE */ ++#define UIP_BUFSIZE UIP_CONF_BUFFER_SIZE ++#endif /* UIP_CONF_BUFFER_SIZE */ ++ ++/** ++ * Determines if statistics support should be compiled in. ++ * ++ * The statistics is useful for debugging and to show the user. ++ * ++ * \hideinitializer ++ */ ++#ifndef UIP_CONF_STATISTICS ++#define UIP_STATISTICS 0 ++#else /* UIP_CONF_STATISTICS */ ++#define UIP_STATISTICS UIP_CONF_STATISTICS ++#endif /* UIP_CONF_STATISTICS */ ++ ++/** ++ * Determines if logging of certain events should be compiled in. ++ * ++ * This is useful mostly for debugging. The function uip_log() ++ * must be implemented to suit the architecture of the project, if ++ * logging is turned on. ++ * ++ * \hideinitializer ++ */ ++#ifndef UIP_CONF_LOGGING ++#define UIP_LOGGING 0 ++#else /* UIP_CONF_LOGGING */ ++#define UIP_LOGGING UIP_CONF_LOGGING ++#endif /* UIP_CONF_LOGGING */ ++ ++/** ++ * Broadcast support. ++ * ++ * This flag configures IP broadcast support. This is useful only ++ * together with UDP. ++ * ++ * \hideinitializer ++ * ++ */ ++#ifndef UIP_CONF_BROADCAST ++#define UIP_BROADCAST 0 ++#else /* UIP_CONF_BROADCAST */ ++#define UIP_BROADCAST UIP_CONF_BROADCAST ++#endif /* UIP_CONF_BROADCAST */ ++ ++/** ++ * Print out a uIP log message. ++ * ++ * This function must be implemented by the module that uses uIP, and ++ * is called by uIP whenever a log message is generated. ++ */ ++void uip_log(char *msg); ++ ++/** ++ * The link level header length. ++ * ++ * This is the offset into the uip_buf where the IP header can be ++ * found. For Ethernet, this should be set to 14. For SLIP, this ++ * should be set to 0. ++ * ++ * \hideinitializer ++ */ ++#ifdef UIP_CONF_LLH_LEN ++#define UIP_LLH_LEN UIP_CONF_LLH_LEN ++#else /* UIP_CONF_LLH_LEN */ ++#define UIP_LLH_LEN 14 ++#endif /* UIP_CONF_LLH_LEN */ ++ ++#if 0 ++/** @} */ ++/*------------------------------------------------------------------------------*/ ++/** ++ * \name CPU architecture configuration ++ * @{ ++ * ++ * The CPU architecture configuration is where the endianess of the ++ * CPU on which uIP is to be run is specified. Most CPUs today are ++ * little endian, and the most notable exception are the Motorolas ++ * which are big endian. The BYTE_ORDER macro should be changed to ++ * reflect the CPU architecture on which uIP is to be run. ++ */ ++ ++/** ++ * The byte order of the CPU architecture on which uIP is to be run. ++ * ++ * This option can be either BIG_ENDIAN (Motorola byte order) or ++ * LITTLE_ENDIAN (Intel byte order). ++ * ++ * \hideinitializer ++ */ ++#ifdef UIP_CONF_BYTE_ORDER ++#define UIP_BYTE_ORDER UIP_CONF_BYTE_ORDER ++#else /* UIP_CONF_BYTE_ORDER */ ++#define UIP_BYTE_ORDER UIP_LITTLE_ENDIAN ++#endif /* UIP_CONF_BYTE_ORDER */ ++#endif ++ ++/** @} */ ++/*------------------------------------------------------------------------------*/ ++ ++/** ++ * \name Appication specific configurations ++ * @{ ++ * ++ * An uIP application is implemented using a single application ++ * function that is called by uIP whenever a TCP/IP event occurs. The ++ * name of this function must be registered with uIP at compile time ++ * using the UIP_APPCALL definition. ++ * ++ * uIP applications can store the application state within the ++ * uip_conn structure by specifying the type of the application ++ * structure by typedef:ing the type uip_tcp_appstate_t and uip_udp_appstate_t. ++ * ++ * The file containing the definitions must be included in the ++ * uipopt.h file. ++ * ++ * The following example illustrates how this can look. ++ \code ++ ++void httpd_appcall(void); ++#define UIP_APPCALL httpd_appcall ++ ++struct httpd_state { ++ u8_t state; ++ u16_t count; ++ char *dataptr; ++ char *script; ++}; ++typedef struct httpd_state uip_tcp_appstate_t ++ \endcode ++ */ ++ ++/** ++ * \var #define UIP_APPCALL ++ * ++ * The name of the application function that uIP should call in ++ * response to TCP/IP events. ++ * ++ */ ++ ++/** ++ * \var typedef uip_tcp_appstate_t ++ * ++ * The type of the application state that is to be stored in the ++ * uip_conn structure. This usually is typedef:ed to a struct holding ++ * application state information. ++ */ ++ ++/** ++ * \var typedef uip_udp_appstate_t ++ * ++ * The type of the application state that is to be stored in the ++ * uip_conn structure. This usually is typedef:ed to a struct holding ++ * application state information. ++ */ ++/** @} */ ++/** @} */ ++ ++#endif /* __UIPOPT_H__ */ +diff --git a/iscsiuio/src/unix/.gitignore b/iscsiuio/src/unix/.gitignore +new file mode 100644 +index 0000000..a2dca2d +--- /dev/null ++++ b/iscsiuio/src/unix/.gitignore +@@ -0,0 +1,2 @@ ++build_date.c ++build_date.h +diff --git a/iscsiuio/src/unix/Makefile.am b/iscsiuio/src/unix/Makefile.am +new file mode 100644 +index 0000000..71d5463 +--- /dev/null ++++ b/iscsiuio/src/unix/Makefile.am +@@ -0,0 +1,40 @@ ++SUBDIRS= libs ++ ++AM_CFLAGS = -I${top_srcdir}/src/uip \ ++ -I${top_srcdir}/src/apps/brcm-iscsi \ ++ -I${top_srcdir}/src/apps/dhcpc \ ++ -I${top_srcdir}/src/unix/libs \ ++ -I${top_srcdir}/../include \ ++ -I${top_srcdir}/../usr ++ ++sbin_PROGRAMS = iscsiuio ++ ++iscsiuio_SOURCES = build_date.c \ ++ main.c \ ++ clock-arch.c \ ++ logger.c \ ++ nic.c \ ++ nic_id.c \ ++ nic_vlan.c \ ++ nic_nl.c \ ++ nic_utils.c \ ++ packet.c \ ++ iscsid_ipc.c \ ++ ping.c ++ ++iscsiuio_CFLAGS = $(AM_CFLAGS) \ ++ $(LIBNL_CFLAGS) \ ++ -DBYTE_ORDER=@ENDIAN@ ++ ++iscsiuio_LDFLAGS= $(AM_LDADD) \ ++ -ldl \ ++ -rdynamic \ ++ $(LIBNL_LIBS) \ ++ -lpthread ++ ++iscsiuio_LDADD = ${top_srcdir}/src/uip/lib_iscsi_uip.a \ ++ ${top_srcdir}/src/apps/dhcpc/lib_apps_dhcpc.a\ ++ ${top_srcdir}/src/apps/brcm-iscsi/lib_apps_brcm_iscsi.a \ ++ ${top_srcdir}/src/unix/libs/lib_iscsiuio_hw_cnic.a ++ ++iscsiuio_YFLAGS = -d +diff --git a/iscsiuio/src/unix/clock-arch.c b/iscsiuio/src/unix/clock-arch.c +new file mode 100644 +index 0000000..d853101 +--- /dev/null ++++ b/iscsiuio/src/unix/clock-arch.c +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2006, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ */ ++ ++/** ++ * \file ++ * Implementation of architecture-specific clock functionality ++ * \author ++ * Adam Dunkels ++ */ ++ ++#include "clock-arch.h" ++#include ++ ++/*---------------------------------------------------------------------------*/ ++clock_time_t clock_time(void) ++{ ++ struct timeval tv; ++ struct timezone tz; ++ ++ gettimeofday(&tv, &tz); ++ ++ return tv.tv_sec * 1000 + tv.tv_usec / 1000; ++} ++ ++/*---------------------------------------------------------------------------*/ +diff --git a/iscsiuio/src/unix/clock-arch.h b/iscsiuio/src/unix/clock-arch.h +new file mode 100644 +index 0000000..888933f +--- /dev/null ++++ b/iscsiuio/src/unix/clock-arch.h +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (c) 2006, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ */ ++ ++#ifndef __CLOCK_ARCH_H__ ++#define __CLOCK_ARCH_H__ ++ ++typedef int clock_time_t; ++#define CLOCK_CONF_SECOND 1000 ++ ++#endif /* __CLOCK_ARCH_H__ */ +diff --git a/iscsiuio/src/unix/iscsid_ipc.c b/iscsiuio/src/unix/iscsid_ipc.c +new file mode 100644 +index 0000000..a2a59a8 +--- /dev/null ++++ b/iscsiuio/src/unix/iscsid_ipc.c +@@ -0,0 +1,1210 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * iscsi_ipc.c - Generic NIC management/utility functions ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define PFX "iscsi_ipc " ++ ++/* TODO fix me */ ++#define IFNAMSIZ 15 ++ ++#include "nic.h" ++#include "nic_utils.h" ++#include "nic_vlan.h" ++#include "options.h" ++#include "mgmt_ipc.h" ++#include "iscsid_ipc.h" ++#include "uip.h" ++#include "uip_mgmt_ipc.h" ++ ++#include "logger.h" ++#include "uip.h" ++#include "ping.h" ++ ++/* private iscsid options stucture */ ++struct iscsid_options { ++ int fd; ++ pthread_t thread; ++}; ++ ++struct iface_rec_decode { ++ /* General */ ++ int32_t iface_num; ++ uint32_t ip_type; ++ ++ /* IPv4 */ ++ struct in_addr ipv4_addr; ++ struct in_addr ipv4_subnet_mask; ++ struct in_addr ipv4_gateway; ++ ++ /* IPv6 */ ++ struct in6_addr ipv6_addr; ++ struct in6_addr ipv6_subnet_mask; ++ uint32_t prefix_len; ++ struct in6_addr ipv6_linklocal; ++ struct in6_addr ipv6_router; ++ ++ uint8_t ipv6_autocfg; ++ uint8_t linklocal_autocfg; ++ uint8_t router_autocfg; ++ ++ uint8_t vlan_state; ++ uint8_t vlan_priority; ++ uint16_t vlan_id; ++ ++#define MIN_MTU_SUPPORT 46 ++#define MAX_MTU_SUPPORT 9000 ++ uint16_t mtu; ++}; ++ ++ ++/****************************************************************************** ++ * iscsid_ipc Constants ++ *****************************************************************************/ ++static const char uio_udev_path_template[] = "/dev/uio%d"; ++ ++/****************************************************************************** ++ * Globals ++ *****************************************************************************/ ++static struct iscsid_options iscsid_opts = { ++ .fd = INVALID_FD, ++ .thread = INVALID_THREAD, ++}; ++ ++/****************************************************************************** ++ * iscsid Functions ++ *****************************************************************************/ ++ ++static void *enable_nic_thread(void *data) ++{ ++ nic_t *nic = (nic_t *) data; ++ ++ prepare_nic_thread(nic); ++ LOG_INFO(PFX "%s: started NIC enable thread state: 0x%x", ++ nic->log_name, nic->state) ++ ++ /* Enable the NIC */ ++ nic_enable(nic); ++ ++ nic->enable_thread = INVALID_THREAD; ++ ++ pthread_exit(NULL); ++} ++ ++static int decode_cidr(char *in_ipaddr_str, struct iface_rec_decode *ird) ++{ ++ int rc = 0, i; ++ char *tmp, *tok; ++ char ipaddr_str[NI_MAXHOST]; ++ char str[INET6_ADDRSTRLEN]; ++ int keepbits = 0; ++ struct in_addr ia; ++ struct in6_addr ia6; ++ ++ if (strlen(in_ipaddr_str) > NI_MAXHOST) ++ strncpy(ipaddr_str, in_ipaddr_str, NI_MAXHOST); ++ else ++ strcpy(ipaddr_str, in_ipaddr_str); ++ ++ /* Find the CIDR if any */ ++ tmp = strchr(ipaddr_str, '/'); ++ if (tmp) { ++ /* CIDR found, now decode, tmpbuf = ip, tmp = netmask */ ++ tmp = ipaddr_str; ++ tok = strsep(&tmp, "/"); ++ LOG_INFO(PFX "in cidr: bitmask '%s' ip '%s'", tmp, tok); ++ keepbits = atoi(tmp); ++ strcpy(ipaddr_str, tok); ++ } ++ ++ /* Determine if the IP address passed from the iface file is ++ * an IPv4 or IPv6 address */ ++ rc = inet_pton(AF_INET, ipaddr_str, &ird->ipv6_addr); ++ if (rc == 0) { ++ /* Test to determine if the addres is an IPv6 address */ ++ rc = inet_pton(AF_INET6, ipaddr_str, &ird->ipv6_addr); ++ if (rc == 0) { ++ LOG_ERR(PFX "Could not parse IP address: '%s'", ++ ipaddr_str); ++ goto out; ++ } ++ ird->ip_type = AF_INET6; ++ if (keepbits > 128) { ++ LOG_ERR(PFX "CIDR netmask > 128 for IPv6: %d(%s)", ++ keepbits, tmp); ++ goto out; ++ } ++ if (!keepbits) { ++ /* Default prefix mask to 64 */ ++ memcpy(&ird->ipv6_subnet_mask.s6_addr, all_zeroes_addr6, ++ sizeof(struct in6_addr)); ++ ird->prefix_len = 64; ++ for (i = 0; i < 2; i++) ++ ird->ipv6_subnet_mask.s6_addr32[i] = 0xffffffff; ++ goto out; ++ } ++ ird->prefix_len = keepbits; ++ memcpy(&ia6.s6_addr, all_zeroes_addr6, sizeof(struct in6_addr)); ++ for (i = 0; i < 4; i++) { ++ if (keepbits < 32) { ++ ia6.s6_addr32[i] = keepbits > 0 ? ++ 0x00 - (1 << (32 - keepbits)) : 0; ++ ia6.s6_addr32[i] = htonl(ia6.s6_addr32[i]); ++ break; ++ } else ++ ia6.s6_addr32[i] = 0xFFFFFFFF; ++ keepbits -= 32; ++ } ++ ird->ipv6_subnet_mask = ia6; ++ if (inet_ntop(AF_INET6, &ia6, str, sizeof(str))) ++ LOG_INFO(PFX "Using netmask: %s", str); ++ } else { ++ ird->ip_type = AF_INET; ++ rc = inet_pton(AF_INET, ipaddr_str, &ird->ipv4_addr); ++ ++ if (keepbits > 32) { ++ LOG_ERR(PFX "CIDR netmask > 32 for IPv4: %d(%s)", ++ keepbits, tmp); ++ goto out; ++ } ++ ia.s_addr = keepbits > 0 ? 0x00 - (1 << (32 - keepbits)) : 0; ++ ird->ipv4_subnet_mask.s_addr = htonl(ia.s_addr); ++ LOG_INFO(PFX "Using netmask: %s", ++ inet_ntoa(ird->ipv4_subnet_mask)); ++ } ++out: ++ return rc; ++} ++ ++static int decode_iface(struct iface_rec_decode *ird, struct iface_rec *rec) ++{ ++ int rc = 0; ++ char ipaddr_str[NI_MAXHOST]; ++ ++ /* Decodes the rec contents */ ++ memset(ird, 0, sizeof(struct iface_rec_decode)); ++ ++ /* Detect for CIDR notation and strip off the netmask if present */ ++ rc = decode_cidr(rec->ipaddress, ird); ++ if (rc && !ird->ip_type) { ++ LOG_ERR(PFX "cidr decode err: rc=%d, ip_type=%d", ++ rc, ird->ip_type); ++ /* Can't decode address, just exit */ ++ return rc; ++ } ++ rc = 0; ++ ird->iface_num = rec->iface_num; ++ ird->vlan_id = rec->vlan_id; ++ if (rec->iface_num != IFACE_NUM_INVALID) { ++ ird->mtu = rec->mtu; ++ if (rec->vlan_id && strcmp(rec->vlan_state, "disable")) { ++ ird->vlan_state = 1; ++ ird->vlan_priority = rec->vlan_priority; ++ ird->vlan_id = rec->vlan_id; ++ } ++ if (ird->ip_type == AF_INET6) { ++ if (!strcmp(rec->ipv6_autocfg, "dhcpv6")) ++ ird->ipv6_autocfg = IPV6_AUTOCFG_DHCPV6; ++ else if (!strcmp(rec->ipv6_autocfg, "nd")) ++ ird->ipv6_autocfg = IPV6_AUTOCFG_ND; ++ else ++ ird->ipv6_autocfg = IPV6_AUTOCFG_NOTSPEC; ++ ++ if (!strcmp(rec->linklocal_autocfg, "auto")) ++ ird->linklocal_autocfg = IPV6_LL_AUTOCFG_ON; ++ else if (!strcmp(rec->linklocal_autocfg, "off")) ++ ird->linklocal_autocfg = IPV6_LL_AUTOCFG_OFF; ++ else /* default */ ++ ird->linklocal_autocfg = IPV6_LL_AUTOCFG_ON; ++ ++ if (!strcmp(rec->router_autocfg, "auto")) ++ ird->router_autocfg = IPV6_RTR_AUTOCFG_ON; ++ else if (!strcmp(rec->router_autocfg, "off")) ++ ird->router_autocfg = IPV6_RTR_AUTOCFG_OFF; ++ else /* default */ ++ ird->router_autocfg = IPV6_RTR_AUTOCFG_ON; ++ ++ /* Decode the addresses based on the control flags */ ++ /* For DHCP, ignore the IPv6 addr in the iface */ ++ if (ird->ipv6_autocfg == IPV6_AUTOCFG_DHCPV6) ++ memcpy(&ird->ipv6_addr, all_zeroes_addr6, ++ sizeof(struct in6_addr)); ++ /* Subnet mask priority: CIDR, then rec */ ++ if (!ird->ipv6_subnet_mask.s6_addr) ++ inet_pton(AF_INET6, rec->subnet_mask, ++ &ird->ipv6_subnet_mask); ++ ++ /* For LL on, ignore the IPv6 addr in the iface */ ++ if (ird->linklocal_autocfg == IPV6_LL_AUTOCFG_OFF) { ++ if (strlen(rec->ipv6_linklocal) > NI_MAXHOST) ++ strncpy(ipaddr_str, rec->ipv6_linklocal, ++ NI_MAXHOST); ++ else ++ strcpy(ipaddr_str, rec->ipv6_linklocal); ++ inet_pton(AF_INET6, ipaddr_str, ++ &ird->ipv6_linklocal); ++ } ++ ++ /* For RTR on, ignore the IPv6 addr in the iface */ ++ if (ird->router_autocfg == IPV6_RTR_AUTOCFG_OFF) { ++ if (strlen(rec->ipv6_router) > NI_MAXHOST) ++ strncpy(ipaddr_str, rec->ipv6_router, ++ NI_MAXHOST); ++ else ++ strcpy(ipaddr_str, rec->ipv6_router); ++ inet_pton(AF_INET6, ipaddr_str, ++ &ird->ipv6_router); ++ } ++ } else { ++ /* Subnet mask priority: CIDR, rec, default */ ++ if (!ird->ipv4_subnet_mask.s_addr) ++ inet_pton(AF_INET, rec->subnet_mask, ++ &ird->ipv4_subnet_mask); ++ if (!ird->ipv4_subnet_mask.s_addr) ++ ird->ipv4_subnet_mask.s_addr = ++ calculate_default_netmask( ++ ird->ipv4_addr.s_addr); ++ ++ if (strlen(rec->gateway) > NI_MAXHOST) ++ strncpy(ipaddr_str, rec->gateway, NI_MAXHOST); ++ else ++ strcpy(ipaddr_str, rec->gateway); ++ inet_pton(AF_INET, ipaddr_str, &ird->ipv4_gateway); ++ } ++ } else { ++ ird->ipv6_autocfg = IPV6_AUTOCFG_NOTUSED; ++ ird->linklocal_autocfg = IPV6_LL_AUTOCFG_NOTUSED; ++ ird->router_autocfg = IPV6_RTR_AUTOCFG_NOTUSED; ++ } ++ return rc; ++} ++ ++static void *perform_ping(void *arg) ++{ ++ struct ping_conf *png_c = (struct ping_conf *)arg; ++ nic_interface_t *nic_iface = png_c->nic_iface; ++ nic_t *nic = nic_iface->parent; ++ iscsid_uip_broadcast_t *data; ++ struct sockaddr_in *addr; ++ struct sockaddr_in6 *addr6; ++ uip_ip6addr_t dst_addr; ++ int rc = 0; ++ int datalen; ++ struct timespec ts = {.tv_sec = 5, ++ .tv_nsec = 0}; ++ ++ data = (iscsid_uip_broadcast_t *)png_c->data; ++ datalen = data->u.ping_rec.datalen; ++ ++ memset(dst_addr, 0, sizeof(uip_ip6addr_t)); ++ if (nic_iface->protocol == AF_INET) { ++ /* IPv4 */ ++ addr = (struct sockaddr_in *)&data->u.ping_rec.ipaddr; ++ memcpy(dst_addr, &addr->sin_addr.s_addr, sizeof(uip_ip4addr_t)); ++ } else { ++ /* IPv6 */ ++ addr6 = (struct sockaddr_in6 *)&data->u.ping_rec.ipaddr; ++ memcpy(dst_addr, &addr6->sin6_addr.s6_addr, ++ sizeof(uip_ip6addr_t)); ++ } ++ ++ /* Ensure that the NIC is RUNNING */ ++ if ((nic->state != NIC_RUNNING) || !(nic->flags & NIC_ENABLED)) { ++ pthread_mutex_lock(&nic->nic_mutex); ++ rc = pthread_cond_timedwait(&nic->enable_done_cond, ++ &nic->nic_mutex, &ts); ++ if ((rc == 0) && (nic->state == NIC_RUNNING)) { ++ LOG_DEBUG(PFX "%s: nic running", nic->log_name); ++ } else if (rc) { ++ LOG_DEBUG(PFX "%s: err %d", nic->log_name, rc); ++ rc = -EAGAIN; ++ } ++ pthread_mutex_unlock(&nic->nic_mutex); ++ } ++ ++ if (rc || nic->state != NIC_RUNNING) { ++ png_c->state = rc; ++ goto ping_done; ++ } ++ ++ ping_init(png_c, dst_addr, nic_iface->protocol, datalen); ++ ++ rc = do_ping_from_nic_iface(png_c); ++ if (png_c->state == -1) ++ png_c->state = rc; ++ ++ping_done: ++ LOG_INFO(PFX "ping thread end"); ++ nic->ping_thread = INVALID_THREAD; ++ pthread_exit(NULL); ++} ++ ++static int parse_iface(void *arg, int do_ping) ++{ ++ int rc, i; ++ nic_t *nic = NULL; ++ nic_interface_t *nic_iface; ++ char *transport_name; ++ size_t transport_name_size; ++ nic_lib_handle_t *handle; ++ iscsid_uip_broadcast_t *data; ++ char ipv6_buf_str[INET6_ADDRSTRLEN]; ++ int request_type = 0; ++ struct iface_rec *rec; ++ struct iface_rec_decode ird; ++ struct in_addr src_match, dst_match; ++ pthread_attr_t attr; ++ struct ping_conf *png_c; ++ ++ data = (iscsid_uip_broadcast_t *) arg; ++ if (do_ping) ++ rec = &data->u.ping_rec.ifrec; ++ else ++ rec = &data->u.iface_rec.rec; ++ ++ LOG_INFO(PFX "Received request for '%s' to set IP address: '%s' " ++ "VLAN: '%d'", ++ rec->netdev, ++ rec->ipaddress, ++ rec->vlan_id); ++ ++ rc = decode_iface(&ird, rec); ++ if (ird.vlan_id && valid_vlan(ird.vlan_id) == 0) { ++ LOG_ERR(PFX "Invalid VLAN tag: %d", ird.vlan_id); ++ rc = -EIO; ++ goto early_exit; ++ } ++ if (rc && !ird.ip_type) { ++ LOG_ERR(PFX "iface err: rc=%d, ip_type=%d", rc, ird.ip_type); ++ goto early_exit; ++ } ++ ++ for (i = 0; i < 10; i++) { ++ struct timespec sleep_req, sleep_rem; ++ ++ if (pthread_mutex_trylock(&nic_list_mutex) == 0) ++ break; ++ ++ sleep_req.tv_sec = 0; ++ sleep_req.tv_nsec = 100000; ++ nanosleep(&sleep_req, &sleep_rem); ++ } ++ ++ if (i >= 10) { ++ LOG_WARN(PFX "Could not acquire nic_list_mutex lock"); ++ rc = -EIO; ++ goto early_exit; ++ } ++ ++ /* nic_list_mutex locked */ ++ ++ /* Check if we can find the NIC device using the netdev ++ * name */ ++ rc = from_netdev_name_find_nic(rec->netdev, &nic); ++ ++ if (rc != 0) { ++ LOG_WARN(PFX "Couldn't find NIC: %s, creating an instance", ++ rec->netdev); ++ ++ nic = nic_init(); ++ if (nic == NULL) { ++ LOG_ERR(PFX "Couldn't allocate space for NIC %s", ++ rec->netdev); ++ ++ rc = -ENOMEM; ++ goto done; ++ } ++ ++ strncpy(nic->eth_device_name, ++ rec->netdev, ++ sizeof(nic->eth_device_name)); ++ nic->config_device_name = nic->eth_device_name; ++ nic->log_name = nic->eth_device_name; ++ ++ if (nic_fill_name(nic) != 0) { ++ free(nic); ++ rc = -EIO; ++ goto done; ++ } ++ ++ nic_add(nic); ++ } else { ++ LOG_INFO(PFX " %s, using existing NIC", ++ rec->netdev); ++ } ++ ++ pthread_mutex_lock(&nic->nic_mutex); ++ if (nic->flags & NIC_GOING_DOWN) { ++ pthread_mutex_unlock(&nic->nic_mutex); ++ rc = -EIO; ++ LOG_INFO(PFX "nic->flags GOING DOWN"); ++ goto done; ++ } ++ ++ /* If we retry too many times allow iscsid to timeout */ ++ if (nic->pending_count > 1000) { ++ nic->pending_count = 0; ++ nic->flags &= ~NIC_ENABLED_PENDING; ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ LOG_WARN(PFX "%s: pending count exceeded 1000", nic->log_name); ++ ++ rc = 0; ++ goto done; ++ } ++ ++ if (nic->flags & NIC_ENABLED_PENDING) { ++ struct timespec sleep_req, sleep_rem; ++ ++ nic->pending_count++; ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ sleep_req.tv_sec = 2; ++ sleep_req.tv_nsec = 0; ++ nanosleep(&sleep_req, &sleep_rem); ++ ++ pthread_mutex_lock(&nic->nic_mutex); ++ if (!(nic->flags & NIC_ENABLED) || ++ nic->state != NIC_RUNNING) { ++ pthread_mutex_unlock(&nic->nic_mutex); ++ LOG_INFO(PFX "%s: enabled pending", nic->log_name); ++ rc = -EAGAIN; ++ goto done; ++ } ++ } ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ prepare_library(nic); ++ ++ /* Sanity Check to ensure the transport names are the same */ ++ handle = nic->nic_library; ++ if (handle != NULL) { ++ (*handle->ops->lib_ops.get_transport_name) (&transport_name, ++ &transport_name_size); ++ ++ if (strncmp(transport_name, ++ rec->transport_name, ++ transport_name_size) != 0) { ++ LOG_ERR(PFX "%s Transport name is not equal " ++ "expected: %s got: %s", ++ nic->log_name, ++ rec->transport_name, ++ transport_name); ++ } ++ } else { ++ LOG_ERR(PFX "%s Couldn't find nic library ", nic->log_name); ++ rc = -EIO; ++ goto done; ++ } ++ ++ LOG_INFO(PFX "%s library set using transport_name %s", ++ nic->log_name, transport_name); ++ ++ /* Determine how to configure the IP address */ ++ if (ird.ip_type == AF_INET) { ++ if (memcmp(&ird.ipv4_addr, ++ all_zeroes_addr4, sizeof(uip_ip4addr_t)) == 0) { ++ LOG_INFO(PFX "%s: requesting configuration using DHCP", ++ nic->log_name); ++ request_type = IPV4_CONFIG_DHCP; ++ } else { ++ LOG_INFO(PFX "%s: requesting configuration using " ++ "static IP address", nic->log_name); ++ request_type = IPV4_CONFIG_STATIC; ++ } ++ } else if (ird.ip_type == AF_INET6) { ++ /* For the new 872_22, check ipv6_autocfg for DHCPv6 instead */ ++ switch (ird.ipv6_autocfg) { ++ case IPV6_AUTOCFG_DHCPV6: ++ request_type = IPV6_CONFIG_DHCP; ++ break; ++ case IPV6_AUTOCFG_ND: ++ request_type = IPV6_CONFIG_STATIC; ++ break; ++ case IPV6_AUTOCFG_NOTSPEC: ++ /* Treat NOTSPEC the same as NOTUSED for now */ ++ case IPV6_AUTOCFG_NOTUSED: ++ /* For 871 */ ++ default: ++ /* Just the IP address to determine */ ++ if (memcmp(&ird.ipv6_addr, ++ all_zeroes_addr6, ++ sizeof(struct in6_addr)) == 0) ++ request_type = IPV6_CONFIG_DHCP; ++ else ++ request_type = IPV6_CONFIG_STATIC; ++ } ++ } else { ++ LOG_ERR(PFX "%s: unknown ip_type to configure: 0x%x", ++ nic->log_name, ird.ip_type); ++ ++ rc = -EIO; ++ goto done; ++ } ++ ++ pthread_mutex_lock(&nic->nic_mutex); ++ ++ nic_iface = nic_find_nic_iface(nic, ird.ip_type, ird.vlan_id, ++ ird.iface_num, request_type); ++ ++ if (nic->flags & NIC_PATHREQ_WAIT) { ++ if (!nic_iface || ++ !(nic_iface->flags & NIC_IFACE_PATHREQ_WAIT)) { ++ int pathreq_wait; ++ ++ if (nic_iface && ++ (nic_iface->flags & NIC_IFACE_PATHREQ_WAIT2)) ++ pathreq_wait = 12; ++ else ++ pathreq_wait = 10; ++ ++ if (nic->pathreq_pending_count < pathreq_wait) { ++ struct timespec sleep_req, sleep_rem; ++ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ nic->pathreq_pending_count++; ++ sleep_req.tv_sec = 0; ++ sleep_req.tv_nsec = 100000; ++ nanosleep(&sleep_req, &sleep_rem); ++ /* Somebody else is waiting for PATH_REQ */ ++ LOG_INFO(PFX "%s: path req pending cnt=%d", ++ nic->log_name, ++ nic->pathreq_pending_count); ++ rc = -EAGAIN; ++ goto done; ++ } else { ++ nic->pathreq_pending_count = 0; ++ LOG_DEBUG(PFX "%s: path req pending cnt " ++ "exceeded!", nic->log_name); ++ /* Allow to fall thru */ ++ } ++ } ++ } ++ ++ nic->flags |= NIC_PATHREQ_WAIT; ++ ++ /* Create the network interface if it doesn't exist */ ++ if (nic_iface == NULL) { ++ LOG_DEBUG(PFX "%s couldn't find interface with " ++ "ip_type: 0x%x creating it", ++ nic->log_name, ird.ip_type); ++ nic_iface = nic_iface_init(); ++ ++ if (nic_iface == NULL) { ++ pthread_mutex_unlock(&nic->nic_mutex); ++ LOG_ERR(PFX "%s Couldn't allocate " ++ "interface with ip_type: 0x%x", ++ nic->log_name, ird.ip_type); ++ goto done; ++ } ++ nic_iface->protocol = ird.ip_type; ++ nic_iface->vlan_id = ird.vlan_id; ++ nic_iface->vlan_priority = ird.vlan_priority; ++ if (ird.mtu >= MIN_MTU_SUPPORT && ird.mtu <= MAX_MTU_SUPPORT) ++ nic_iface->mtu = ird.mtu; ++ nic_iface->iface_num = ird.iface_num; ++ nic_iface->request_type = request_type; ++ nic_add_nic_iface(nic, nic_iface); ++ ++ persist_all_nic_iface(nic); ++ ++ LOG_INFO(PFX "%s: created network interface", ++ nic->log_name); ++ } else { ++ /* Move the nic_iface to the front */ ++ set_nic_iface(nic, nic_iface); ++ LOG_INFO(PFX "%s: using existing network interface", ++ nic->log_name); ++ } ++ ++ nic_iface->flags |= NIC_IFACE_PATHREQ_WAIT1; ++ if (nic->nl_process_thread == INVALID_THREAD) { ++ pthread_attr_init(&attr); ++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ++ rc = pthread_create(&nic->nl_process_thread, &attr, ++ nl_process_handle_thread, nic); ++ if (rc != 0) { ++ LOG_ERR(PFX "%s: Could not create NIC NL " ++ "processing thread [%s]", nic->log_name, ++ strerror(rc)); ++ nic->nl_process_thread = INVALID_THREAD; ++ /* Reset both WAIT flags */ ++ nic_iface->flags &= ~NIC_IFACE_PATHREQ_WAIT; ++ nic->flags &= ~NIC_PATHREQ_WAIT; ++ } ++ } ++ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ if (nic_iface->ustack.ip_config == request_type) { ++ /* Same request_type, check for STATIC address change */ ++ if (request_type == IPV4_CONFIG_STATIC) { ++ if (memcmp(nic_iface->ustack.hostaddr, &ird.ipv4_addr, ++ sizeof(struct in_addr))) ++ goto reacquire; ++ } else if (request_type == IPV6_CONFIG_STATIC) { ++ if (memcmp(nic_iface->ustack.hostaddr6, &ird.ipv6_addr, ++ sizeof(struct in6_addr))) ++ goto reacquire; ++ else ++ inet_ntop(AF_INET6, &ird.ipv6_addr, ++ ipv6_buf_str, ++ sizeof(ipv6_buf_str)); ++ } ++ LOG_INFO(PFX "%s: IP configuration didn't change using 0x%x", ++ nic->log_name, nic_iface->ustack.ip_config); ++ /* No need to acquire the IP address */ ++ inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str, ++ sizeof(ipv6_buf_str)); ++ ++ goto enable_nic; ++ } ++reacquire: ++ /* Config needs to re-acquire for this nic_iface */ ++ pthread_mutex_lock(&nic->nic_mutex); ++ nic_iface->flags |= NIC_IFACE_ACQUIRE; ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ /* Disable the nic loop from further processing, upon returned, ++ the nic_iface should be cleared */ ++ nic_disable(nic, 0); ++ ++ /* Check to see if this is using DHCP or if this is ++ * a static IPv4 address. This is done by checking ++ * if the IP address is equal to 0.0.0.0. If it is ++ * then the user has specified to use DHCP. If not ++ * then the user has spcicied to use a static IP address ++ * an the default netmask will be used */ ++ switch (request_type) { ++ case IPV4_CONFIG_DHCP: ++ memset(nic_iface->ustack.hostaddr, 0, sizeof(struct in_addr)); ++ LOG_INFO(PFX "%s: configuring using DHCP", nic->log_name); ++ nic_iface->ustack.ip_config = IPV4_CONFIG_DHCP; ++ break; ++ ++ case IPV4_CONFIG_STATIC: ++ memcpy(nic_iface->ustack.hostaddr, &ird.ipv4_addr, ++ sizeof(struct in_addr)); ++ LOG_INFO(PFX "%s: configuring using static IP " ++ "IPv4 address :%s ", ++ nic->log_name, inet_ntoa(ird.ipv4_addr)); ++ ++ if (ird.ipv4_subnet_mask.s_addr) ++ memcpy(nic_iface->ustack.netmask, ++ &ird.ipv4_subnet_mask, sizeof(struct in_addr)); ++ LOG_INFO(PFX " netmask: %s", inet_ntoa(ird.ipv4_subnet_mask)); ++ ++ /* Default route */ ++ if (ird.ipv4_gateway.s_addr) { ++ /* Check for validity */ ++ src_match.s_addr = ird.ipv4_addr.s_addr & ++ ird.ipv4_subnet_mask.s_addr; ++ dst_match.s_addr = ird.ipv4_gateway.s_addr & ++ ird.ipv4_subnet_mask.s_addr; ++ if (src_match.s_addr == dst_match.s_addr) ++ memcpy(nic_iface->ustack.default_route_addr, ++ &ird.ipv4_gateway, ++ sizeof(struct in_addr)); ++ } ++ nic_iface->ustack.ip_config = IPV4_CONFIG_STATIC; ++ break; ++ ++ case IPV6_CONFIG_DHCP: ++ memset(nic_iface->ustack.hostaddr6, 0, ++ sizeof(struct in6_addr)); ++ nic_iface->ustack.prefix_len = ird.prefix_len; ++ nic_iface->ustack.ipv6_autocfg = ird.ipv6_autocfg; ++ nic_iface->ustack.linklocal_autocfg = ird.linklocal_autocfg; ++ nic_iface->ustack.router_autocfg = ird.router_autocfg; ++ ++ if (memcmp(&ird.ipv6_subnet_mask, all_zeroes_addr6, ++ sizeof(struct in6_addr))) ++ memcpy(nic_iface->ustack.netmask6, ++ &ird.ipv6_subnet_mask, sizeof(struct in6_addr)); ++ if (ird.linklocal_autocfg == IPV6_LL_AUTOCFG_OFF) ++ memcpy(nic_iface->ustack.linklocal6, ++ &ird.ipv6_linklocal, sizeof(struct in6_addr)); ++ if (ird.router_autocfg == IPV6_RTR_AUTOCFG_OFF) ++ memcpy(nic_iface->ustack.default_route_addr6, ++ &ird.ipv6_router, sizeof(struct in6_addr)); ++ inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str, ++ sizeof(ipv6_buf_str)); ++ LOG_INFO(PFX "%s: configuring using DHCPv6", ++ nic->log_name); ++ nic_iface->ustack.ip_config = IPV6_CONFIG_DHCP; ++ break; ++ ++ case IPV6_CONFIG_STATIC: ++ memcpy(nic_iface->ustack.hostaddr6, &ird.ipv6_addr, ++ sizeof(struct in6_addr)); ++ nic_iface->ustack.prefix_len = ird.prefix_len; ++ nic_iface->ustack.ipv6_autocfg = ird.ipv6_autocfg; ++ nic_iface->ustack.linklocal_autocfg = ird.linklocal_autocfg; ++ nic_iface->ustack.router_autocfg = ird.router_autocfg; ++ ++ if (memcmp(&ird.ipv6_subnet_mask, all_zeroes_addr6, ++ sizeof(struct in6_addr))) ++ memcpy(nic_iface->ustack.netmask6, ++ &ird.ipv6_subnet_mask, sizeof(struct in6_addr)); ++ if (ird.linklocal_autocfg == IPV6_LL_AUTOCFG_OFF) ++ memcpy(nic_iface->ustack.linklocal6, ++ &ird.ipv6_linklocal, sizeof(struct in6_addr)); ++ if (ird.router_autocfg == IPV6_RTR_AUTOCFG_OFF) ++ memcpy(nic_iface->ustack.default_route_addr6, ++ &ird.ipv6_router, sizeof(struct in6_addr)); ++ ++ inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str, ++ sizeof(ipv6_buf_str)); ++ LOG_INFO(PFX "%s: configuring using static IP " ++ "IPv6 address: '%s'", nic->log_name, ipv6_buf_str); ++ ++ nic_iface->ustack.ip_config = IPV6_CONFIG_STATIC; ++ break; ++ ++ default: ++ LOG_INFO(PFX "%s: Unknown request type: 0x%x", ++ nic->log_name, request_type); ++ ++ } ++ ++enable_nic: ++ switch (nic->state) { ++ case NIC_STOPPED: ++ /* This thread will be thrown away when completed */ ++ if (nic->enable_thread != INVALID_THREAD) { ++ rc = pthread_cancel(nic->enable_thread); ++ if (rc != 0) { ++ LOG_INFO(PFX "%s: failed to cancel enable NIC " ++ "thread\n", nic->log_name); ++ goto eagain; ++ } ++ } ++ pthread_attr_init(&attr); ++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ++ rc = pthread_create(&nic->enable_thread, &attr, ++ enable_nic_thread, (void *)nic); ++ if (rc != 0) ++ LOG_WARN(PFX "%s: failed starting enable NIC thread\n", ++ nic->log_name); ++eagain: ++ rc = -EAGAIN; ++ break; ++ ++ case NIC_RUNNING: ++ LOG_INFO(PFX "%s: NIC already enabled " ++ "flags: 0x%x state: 0x%x\n", ++ nic->log_name, nic->flags, nic->state); ++ rc = 0; ++ break; ++ default: ++ LOG_INFO(PFX "%s: NIC enable still in progress " ++ "flags: 0x%x state: 0x%x\n", ++ nic->log_name, nic->flags, nic->state); ++ rc = -EAGAIN; ++ } ++ ++ LOG_INFO(PFX "ISCSID_UIP_IPC_GET_IFACE: command: %x " ++ "name: %s, netdev: %s ipaddr: %s vlan: %d transport_name:%s", ++ data->header.command, rec->name, rec->netdev, ++ (ird.ip_type == AF_INET) ? inet_ntoa(ird.ipv4_addr) : ++ ipv6_buf_str, ++ ird.vlan_id, rec->transport_name); ++ ++ if (do_ping) { ++ if (nic->ping_thread != INVALID_THREAD) { ++ rc = pthread_cancel(nic->ping_thread); ++ if (rc != 0) { ++ LOG_INFO(PFX "%s: failed to cancel ping thread", ++ nic->log_name); ++ rc = -EAGAIN; ++ goto done; ++ } ++ } ++ ++ png_c = malloc(sizeof(struct ping_conf)); ++ if (!png_c) { ++ LOG_ERR(PFX "Memory alloc failed for ping conf"); ++ rc = -ENOMEM; ++ goto done; ++ } ++ ++ memset(png_c, 0, sizeof(struct ping_conf)); ++ png_c->nic_iface = nic_iface; ++ png_c->data = arg; ++ nic_iface->ustack.ping_conf = png_c; ++ ++ /* Spawn a thread to perform ping operation. ++ * This thread will exit when done. ++ */ ++ rc = pthread_create(&nic->ping_thread, NULL, ++ perform_ping, (void *)png_c); ++ if (rc != 0) { ++ LOG_WARN(PFX "%s: failed starting ping thread\n", ++ nic->log_name); ++ } else { ++ pthread_join(nic->ping_thread, NULL); ++ rc = png_c->state; ++ if (rc == -EAGAIN) ++ png_c->state = 0; ++ } ++ free(png_c); ++ nic_iface->ustack.ping_conf = NULL; ++ } ++ ++done: ++ pthread_mutex_unlock(&nic_list_mutex); ++ ++early_exit: ++ return rc; ++} ++ ++/** ++ * process_iscsid_broadcast() - This function is used to process the ++ * broadcast messages from iscsid ++ */ ++int process_iscsid_broadcast(int s2) ++{ ++ int rc = 0; ++ iscsid_uip_broadcast_t *data; ++ iscsid_uip_rsp_t rsp; ++ FILE *fd; ++ size_t size; ++ iscsid_uip_cmd_e cmd; ++ uint32_t payload_len; ++ ++ fd = fdopen(s2, "r+"); ++ if (fd == NULL) { ++ LOG_ERR(PFX "Couldn't open file descriptor: %d(%s)", ++ errno, strerror(errno)); ++ return -EIO; ++ } ++ ++ /* This will be freed by parse_iface_thread() */ ++ data = (iscsid_uip_broadcast_t *) calloc(1, sizeof(*data)); ++ if (data == NULL) { ++ LOG_ERR(PFX "Couldn't allocate memory for iface data"); ++ rc = -ENOMEM; ++ goto error; ++ } ++ memset(data, 0, sizeof(*data)); ++ ++ size = fread(data, sizeof(iscsid_uip_broadcast_header_t), 1, fd); ++ if (!size) { ++ LOG_ERR(PFX "Could not read request: %d(%s)", ++ errno, strerror(errno)); ++ rc = ferror(fd); ++ goto error; ++ } ++ ++ cmd = data->header.command; ++ payload_len = data->header.payload_len; ++ ++ LOG_DEBUG(PFX "recv iscsid request: cmd: %d, payload_len: %d", ++ cmd, payload_len); ++ ++ switch (cmd) { ++ case ISCSID_UIP_IPC_GET_IFACE: ++ size = fread(&data->u.iface_rec, payload_len, 1, fd); ++ if (!size) { ++ LOG_ERR(PFX "Could not read data: %d(%s)", ++ errno, strerror(errno)); ++ goto error; ++ } ++ ++ rc = parse_iface(data, 0); ++ switch (rc) { ++ case 0: ++ rsp.command = cmd; ++ rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_UP; ++ break; ++ case -EAGAIN: ++ rsp.command = cmd; ++ rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING; ++ break; ++ default: ++ rsp.command = cmd; ++ rsp.err = ISCSID_UIP_MGMT_IPC_ERR; ++ } ++ ++ break; ++ case ISCSID_UIP_IPC_PING: ++ size = fread(&data->u.ping_rec, payload_len, 1, fd); ++ if (!size) { ++ LOG_ERR(PFX "Could not read data: %d(%s)", ++ errno, strerror(errno)); ++ goto error; ++ } ++ ++ rc = parse_iface(data, 1); ++ rsp.command = cmd; ++ rsp.ping_sc = rc; ++ ++ switch (rc) { ++ case 0: ++ rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_UP; ++ break; ++ case -EAGAIN: ++ rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING; ++ break; ++ default: ++ rsp.err = ISCSID_UIP_MGMT_IPC_ERR; ++ } ++ ++ break; ++ default: ++ LOG_WARN(PFX "Unknown iscsid broadcast command: %x", ++ data->header.command); ++ ++ /* Send a response back to iscsid to tell it the ++ operation succeeded */ ++ rsp.command = cmd; ++ rsp.err = ISCSID_UIP_MGMT_IPC_OK; ++ break; ++ } ++ ++ size = fwrite(&rsp, sizeof(rsp), 1, fd); ++ if (size == -1) { ++ LOG_ERR(PFX "Could not send response: %d(%s)", ++ errno, strerror(errno)); ++ rc = ferror(fd); ++ } ++ ++error: ++ free(data); ++ fclose(fd); ++ ++ return rc; ++} ++ ++static void iscsid_loop_close(void *arg) ++{ ++ close(iscsid_opts.fd); ++ ++ LOG_INFO(PFX "iSCSI daemon socket closed"); ++} ++ ++/** ++ * iscsid_loop() - This is the function which will process the broadcast ++ * messages from iscsid ++ * ++ */ ++static void *iscsid_loop(void *arg) ++{ ++ int rc; ++ sigset_t set; ++ ++ pthread_cleanup_push(iscsid_loop_close, arg); ++ ++ sigfillset(&set); ++ rc = pthread_sigmask(SIG_BLOCK, &set, NULL); ++ if (rc != 0) { ++ LOG_ERR(PFX ++ "Couldn't set signal mask for the iscisd listening " ++ "thread"); ++ } ++ ++ LOG_DEBUG(PFX "Started iscsid listening thread"); ++ ++ while (1) { ++ struct sockaddr_un remote; ++ socklen_t sock_len; ++ int s2; ++ ++ LOG_DEBUG(PFX "Waiting for iscsid command"); ++ ++ sock_len = sizeof(remote); ++ s2 = accept(iscsid_opts.fd, ++ (struct sockaddr *)&remote, &sock_len); ++ if (s2 == -1) { ++ if (errno == EAGAIN) { ++ LOG_DEBUG("Got EAGAIN from accept"); ++ sleep(1); ++ continue; ++ } else if (errno == EINTR) { ++ LOG_DEBUG("Got EINTR from accept"); ++ /* The program is terminating, time to exit */ ++ break; ++ } ++ ++ LOG_ERR(PFX "Could not accept: %d(%s)", ++ s2, strerror(errno)); ++ continue; ++ } ++ ++ process_iscsid_broadcast(s2); ++ close(s2); ++ } ++ ++ pthread_cleanup_pop(0); ++ ++ LOG_ERR(PFX "exit iscsid listening thread"); ++ ++ pthread_exit(NULL); ++} ++ ++#define SD_SOCKET_FDS_START 3 ++ ++static int ipc_systemd(void) ++{ ++ char *env; ++ ++ env = getenv("LISTEN_PID"); ++ ++ if (!env || (strtoul(env, NULL, 10) != getpid())) ++ return -EINVAL; ++ ++ env = getenv("LISTEN_FDS"); ++ ++ if (!env) ++ return -EINVAL; ++ ++ if (strtoul(env, NULL, 10) != 1) { ++ LOG_ERR("Did not receive exactly one IPC socket from systemd"); ++ return -EINVAL; ++ } ++ ++ return SD_SOCKET_FDS_START; ++} ++ ++/****************************************************************************** ++ * Initialize/Cleanup routines ++ ******************************************************************************/ ++/** ++ * iscsid_init() - This function will setup the thread used to listen for ++ * the iscsid broadcast messages ++ * @return 0 on success, <0 on failure ++ */ ++int iscsid_init() ++{ ++ int rc, addr_len; ++ struct sockaddr_un addr; ++ ++ iscsid_opts.fd = ipc_systemd(); ++ if (iscsid_opts.fd >= 0) ++ return 0; ++ ++ iscsid_opts.fd = socket(AF_LOCAL, SOCK_STREAM, 0); ++ if (iscsid_opts.fd < 0) { ++ LOG_ERR(PFX "Can not create IPC socket"); ++ return iscsid_opts.fd; ++ } ++ ++ addr_len = offsetof(struct sockaddr_un, sun_path) + strlen(ISCSID_UIP_NAMESPACE) + 1; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sun_family = AF_LOCAL; ++ memcpy((char *)&addr.sun_path + 1, ISCSID_UIP_NAMESPACE, ++ strlen(ISCSID_UIP_NAMESPACE)); ++ ++ rc = bind(iscsid_opts.fd, (struct sockaddr *)&addr, addr_len); ++ if (rc < 0) { ++ LOG_ERR(PFX "Can not bind IPC socket: %s", strerror(errno)); ++ goto error; ++ } ++ ++ rc = listen(iscsid_opts.fd, 32); ++ if (rc < 0) { ++ LOG_ERR(PFX "Can not listen IPC socket: %s", strerror(errno)); ++ goto error; ++ } ++ ++ return 0; ++error: ++ close(iscsid_opts.fd); ++ iscsid_opts.fd = INVALID_FD; ++ ++ return rc; ++} ++ ++/** ++ * iscsid_start() - This function will start the thread used to listen for ++ * the iscsid broadcast messages ++ * @return 0 on success, <0 on failure ++ */ ++int iscsid_start() ++{ ++ pthread_attr_t attr; ++ int rc; ++ ++ pthread_attr_init(&attr); ++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ++ rc = pthread_create(&iscsid_opts.thread, &attr, iscsid_loop, NULL); ++ if (rc != 0) { ++ LOG_ERR(PFX "Could not start iscsid listening thread rc=%d", ++ rc); ++ goto error; ++ } ++ ++ return 0; ++ ++error: ++ close(iscsid_opts.fd); ++ iscsid_opts.fd = INVALID_FD; ++ ++ return rc; ++} ++ ++/** ++ * iscsid_cleanup() - This is called when stoping the thread listening ++ * for the iscsid broadcast messages ++ */ ++void iscsid_cleanup() ++{ ++ int rc; ++ ++ if (iscsid_opts.fd != INVALID_FD) { ++ rc = pthread_cancel(iscsid_opts.thread); ++ if (rc != 0) { ++ LOG_ERR("Could not cancel iscsid listening thread: %s", ++ strerror(rc)); ++ } ++ } ++ ++ LOG_INFO(PFX "iscsid listening thread has shutdown"); ++} +diff --git a/iscsiuio/src/unix/iscsid_ipc.h b/iscsiuio/src/unix/iscsid_ipc.h +new file mode 100644 +index 0000000..60bcd71 +--- /dev/null ++++ b/iscsiuio/src/unix/iscsid_ipc.h +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * iscsid_ipc.h: Generic NIC management/utility functions ++ * ++ */ ++#ifndef __ISCSID_IPC_H__ ++#define __ISCSID_IPC_H__ ++ ++#include "uip.h" ++#include "mgmt_ipc.h" ++ ++enum mgmt_ipc_err iscsid_connect(int *fd); ++int iscsid_get_ipaddr(int fd, uip_ip4addr_t *ipaddr); ++ ++int iscsid_init(); ++int iscsid_start(); ++void iscsid_cleanup(); ++ ++#endif /* __ISCSID_IPC_H__ */ +diff --git a/iscsiuio/src/unix/libs/Makefile.am b/iscsiuio/src/unix/libs/Makefile.am +new file mode 100644 +index 0000000..890415f +--- /dev/null ++++ b/iscsiuio/src/unix/libs/Makefile.am +@@ -0,0 +1,13 @@ ++AM_CFLAGS = -I${top_srcdir}/src/uip \ ++ -I${top_srcdir}/src/unix \ ++ -I${top_srcdir}/src/unix/libs \ ++ -I${top_srcdir}/src/apps/dhcpc \ ++ -I${top_srcdir}/../include \ ++ -I${top_srcdir}/../usr ++ ++noinst_LIBRARIES = lib_iscsiuio_hw_cnic.a ++ ++lib_iscsiuio_hw_cnic_a_SOURCES = ../build_date.c \ ++ cnic.c \ ++ bnx2.c \ ++ bnx2x.c +diff --git a/iscsiuio/src/unix/libs/bnx2.c b/iscsiuio/src/unix/libs/bnx2.c +new file mode 100644 +index 0000000..937336e +--- /dev/null ++++ b/iscsiuio/src/unix/libs/bnx2.c +@@ -0,0 +1,1165 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * bnx2.c - bnx2 user space driver ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "config.h" ++ ++#include "build_date.h" ++#include "bnx2.h" ++#include "cnic.h" ++#include "logger.h" ++#include "nic.h" ++#include "nic_utils.h" ++#include "options.h" ++ ++#define PFX "bnx2 " ++ ++/* Foward struct declarations */ ++struct nic_ops bnx2_op; ++ ++/******************************************************************************* ++ * NIC Library Strings ++ ******************************************************************************/ ++static const char library_name[] = "bnx2"; ++static const char library_version[] = PACKAGE_VERSION; ++static const char library_uio_name[] = "bnx2_cnic"; ++ ++/* The name that should be returned from /sys/class/uio/uio0/name */ ++static const char cnic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name"; ++static const char cnic_uio_sysfs_name[] = "bnx2_cnic"; ++ ++/******************************************************************************* ++ * String constants used to display human readable adapter name ++ ******************************************************************************/ ++static const char brcm_5706C[] = "QLogic NetXtreme II BCM5706 1000Base-T"; ++static const char hp_NC370T[] = ++ "HP NC370T Multifunction Gigabit Server Adapter"; ++static const char hp_NC370I[] = ++ "HP NC370i Multifunction Gigabit Server Adapter"; ++static const char brcm_5706S[] = "QLogic NetXtreme II BCM5706 1000Base-SX"; ++static const char hp_NC370F[] = ++ "HP NC370F Multifunction Gigabit Server Adapter"; ++static const char brcm_5708C[] = "QLogic NetXtreme II BCM5708 1000Base-T"; ++static const char brcm_5708S[] = "QLogic NetXtreme II BCM5708 1000Base-SX"; ++static const char brcm_5709C[] = "QLogic NetXtreme II BCM5709 1000Base-T"; ++static const char brcm_5709S[] = "QLogic NetXtreme II BCM5709 1000Base-SX"; ++static const char brcm_5716C[] = "QLogic NetXtreme II BCM5716 1000Base-T"; ++static const char brcm_5716S[] = "QLogic NetXtreme II BCM5716 1000Base-SX"; ++ ++/******************************************************************************* ++ * PCI ID constants ++ ******************************************************************************/ ++#define PCI_VENDOR_ID_BROADCOM 0x14e4 ++#define PCI_DEVICE_ID_NX2_5709 0x1639 ++#define PCI_DEVICE_ID_NX2_5709S 0x163a ++#define PCI_DEVICE_ID_NX2_5706 0x164a ++#define PCI_DEVICE_ID_NX2_5708 0x164c ++#define PCI_DEVICE_ID_NX2_5706S 0x16aa ++#define PCI_DEVICE_ID_NX2_5708S 0x16ac ++ ++#define PCI_VENDOR_ID_HP 0x103c ++ ++#define PCI_ANY_ID (~0) ++ ++/* This is the table used to match PCI vendor and device ID's to the ++ * human readable string names of the devices */ ++static const struct pci_device_id bnx2_pci_tbl[] = { ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706, ++ PCI_VENDOR_ID_HP, 0x3101, hp_NC370T}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706, ++ PCI_VENDOR_ID_HP, 0x3106, hp_NC370I}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_5706S}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_5708C}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S, ++ PCI_VENDOR_ID_HP, 0x3102, hp_NC370F}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_5706S}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_5708S}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_5709C}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_5709S}, ++ {PCI_VENDOR_ID_BROADCOM, 0x163b, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_5716C}, ++ {PCI_VENDOR_ID_BROADCOM, 0x163c, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_5716S}, ++}; ++ ++/******************************************************************************* ++ * bnx2 Library Functions ++ ******************************************************************************/ ++/** ++ * bnx2_get_library_name() - Used to get the name of this NIC libary ++ * @param name - This function will return the pointer to this NIC ++ * library name ++ * @param name_size ++ */ ++static void bnx2_get_library_name(char **name, size_t *name_size) ++{ ++ *name = (char *)library_name; ++ *name_size = sizeof(library_name); ++} ++ ++/** ++ * bnx2_get_library_version() - Used to get the version string of this ++ * NIC libary ++ * @param version - This function will return the pointer to this NIC ++ * library version string ++ * @param version_size - This will be set with the version size ++ */ ++static void bnx2_get_library_version(char **version, size_t *version_size) ++{ ++ *version = (char *)library_version; ++ *version_size = sizeof(library_version); ++} ++ ++/** ++ * bnx2_get_build_date() - Used to get the build date string of this library ++ * @param version - This function will return the pointer to this NIC ++ * library build date string ++ * @param version_size - This will be set with the build date string size ++ */ ++static void bnx2_get_build_date(char **build, size_t *build_size) ++{ ++ *build = (char *)build_date; ++ *build_size = sizeof(build_date); ++} ++ ++/** ++ * bnx2_get_transport_name() - Used to get the transport name associated ++ * with this this NIC libary ++ * @param transport_name - This function will return the pointer to this NIC ++ * library's associated transport string ++ * @param transport_name_size - This will be set with the transport name size ++ */ ++static void bnx2_get_transport_name(char **transport_name, ++ size_t *transport_name_size) ++{ ++ *transport_name = (char *)bnx2i_library_transport_name; ++ *transport_name_size = bnx2i_library_transport_name_size; ++} ++ ++/** ++ * bnx2_get_uio_name() - Used to get the uio name associated with this this ++ * NIC libary ++ * @param uio_name - This function will return the pointer to this NIC ++ * library's associated uio string ++ * @param transport_name_size - This will be set with the uio name size ++ */ ++static void bnx2_get_uio_name(char **uio_name, size_t *uio_name_size) ++{ ++ *uio_name = (char *)library_uio_name; ++ *uio_name_size = sizeof(library_uio_name); ++} ++ ++/** ++ * bnx2_get_pci_table() - Used to get the PCI table for this NIC libary ++ * to determine which NIC's based off of PCI ID's ++ * are supported ++ * @param table - This function will return the pointer to the PCI table ++ * @param entries - This function will return the number of entries in the NIC ++ * library's PCI table ++ */ ++static void bnx2_get_pci_table(struct pci_device_id **table, uint32_t *entries) ++{ ++ *table = (struct pci_device_id *)bnx2_pci_tbl; ++ *entries = (uint32_t) (sizeof(bnx2_pci_tbl) / sizeof(bnx2_pci_tbl[0])); ++} ++ ++/** ++ * bnx2_get_ops() - Used to get the NIC library op table ++ * @param op - The op table of this NIC library ++ */ ++struct nic_ops *bnx2_get_ops() ++{ ++ return &bnx2_op; ++} ++ ++/******************************************************************************* ++ * bnx2 Utility Functions ++ ******************************************************************************/ ++/******************************************************************************* ++ * Utility Functions Used to read register from the bnx2 device ++ ******************************************************************************/ ++static void bnx2_wr32(bnx2_t *bp, __u32 off, __u32 val) ++{ ++ *((volatile __u32 *)(bp->reg + off)) = val; ++} ++ ++static void bnx2_wr16(bnx2_t *bp, __u32 off, __u16 val) ++{ ++ *((volatile __u16 *)(bp->reg + off)) = val; ++} ++ ++static __u32 bnx2_rd32(bnx2_t *bp, __u32 off) ++{ ++ return *((volatile __u32 *)(bp->reg + off)); ++} ++ ++static int bnx2_reg_sync(bnx2_t *bp, __u32 off, __u16 length) ++{ ++ return msync(bp->reg + off, length, MS_SYNC); ++} ++ ++/** ++ * bnx2_get_chip_id() - Used to retrive the chip ID from the nic ++ * @param dev - Device used to determin NIC type ++ * @return Chip ID read from the MISC ID register ++ */ ++static int bnx2_get_chip_id(bnx2_t *bp) ++{ ++ return bnx2_rd32(bp, BNX2_MISC_ID); ++} ++ ++/** ++ * bnx2_uio_verify() ++ * ++ */ ++static int bnx2_uio_verify(nic_t *nic) ++{ ++ char *raw = NULL, *raw_tmp; ++ uint32_t raw_size = 0; ++ char temp_path[sizeof(cnic_uio_sysfs_name_tempate) + 8]; ++ int rc = 0; ++ ++ /* Build the path to determine uio name */ ++ snprintf(temp_path, sizeof(temp_path), ++ cnic_uio_sysfs_name_tempate, nic->uio_minor); ++ ++ rc = capture_file(&raw, &raw_size, temp_path); ++ if (rc != 0) ++ goto error; ++ ++ /* sanitize name string by replacing newline with null termination */ ++ raw_tmp = raw; ++ while (*raw_tmp != '\n') ++ raw_tmp++; ++ *raw_tmp = '\0'; ++ ++ if (strncmp(raw, cnic_uio_sysfs_name, sizeof(cnic_uio_sysfs_name)) != ++ 0) { ++ LOG_ERR(PFX "%s: uio names not equal: " ++ "expecting %s got %s from %s", ++ nic->log_name, cnic_uio_sysfs_name, raw, temp_path); ++ rc = -EIO; ++ } ++ ++ free(raw); ++ ++ LOG_INFO(PFX "%s: Verified is a cnic_uio device", nic->log_name); ++ ++error: ++ return rc; ++} ++ ++/******************************************************************************* ++ * bnx2 Utility Functions to get to the hardware consumer indexes ++ ******************************************************************************/ ++static __u16 bnx2_get_rx_msix(bnx2_t *bp) ++{ ++ struct status_block_msix *sblk = bp->status_blk.msix; ++ __u16 rx_cons; ++ ++ msync(sblk, sizeof(*sblk), MS_SYNC); ++ rx_cons = sblk->status_rx_quick_consumer_index; ++ barrier(); ++ if ((rx_cons & (MAX_RX_DESC_CNT)) == (MAX_RX_DESC_CNT)) ++ rx_cons++; ++ ++ return rx_cons; ++} ++ ++static __u16 bnx2_get_rx_msi(bnx2_t *bp) ++{ ++ struct status_block *sblk = bp->status_blk.msi; ++ __u16 rx_cons; ++ ++ msync(sblk, sizeof(*sblk), MS_SYNC); ++ rx_cons = BNX2_SBLK_EVEN_IDX(sblk->rx2); ++ barrier(); ++ if ((rx_cons & (MAX_RX_DESC_CNT)) == (MAX_RX_DESC_CNT)) ++ rx_cons++; ++ ++ return rx_cons; ++} ++ ++static __u16 bnx2_get_tx_msix(bnx2_t *bp) ++{ ++ struct status_block_msix *sblk = bp->status_blk.msix; ++ __u16 tx_cons; ++ ++ msync(sblk, sizeof(*sblk), MS_SYNC); ++ tx_cons = sblk->status_tx_quick_consumer_index; ++ barrier(); ++ if ((tx_cons & (MAX_TX_DESC_CNT)) == (MAX_TX_DESC_CNT)) ++ tx_cons++; ++ ++ return tx_cons; ++} ++ ++static __u16 bnx2_get_tx_msi(bnx2_t *bp) ++{ ++ struct status_block *sblk = bp->status_blk.msi; ++ __u16 tx_cons; ++ ++ msync(sblk, sizeof(*sblk), MS_SYNC); ++ tx_cons = BNX2_SBLK_EVEN_IDX(sblk->tx2); ++ barrier(); ++ if ((tx_cons & (MAX_TX_DESC_CNT)) == (MAX_TX_DESC_CNT)) ++ tx_cons++; ++ ++ return tx_cons; ++} ++ ++typedef enum { ++ CNIC_VLAN_STRIPPING_ENABLED = 1, ++ CNIC_VLAN_STRIPPING_DISABLED = 2, ++} CNIC_VLAN_STRIPPING_MODE; ++ ++/** ++ * bnx2_strip_vlan_enabled() - This will query the device to determine whether ++ * VLAN tag stripping is enabled or not ++ * @param dev - device to check stripping or not ++ * @ return CNIC_VLAN_STRIPPING_ENABLED stripping is enabled ++ * CNIC_VLAN_STRIPPING_DISABLED stripping is not enabled ++ */ ++static CNIC_VLAN_STRIPPING_MODE bnx2_strip_vlan_enabled(bnx2_t *bp) ++{ ++ uint32_t val; ++ ++ val = bnx2_rd32(bp, BNX2_EMAC_RX_MODE); ++ ++ if (val & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG) ++ return CNIC_VLAN_STRIPPING_DISABLED; ++ else ++ return CNIC_VLAN_STRIPPING_ENABLED; ++} ++ ++/** ++ * bnx2_free() - Used to free a bnx2 structure ++ */ ++static void bnx2_free(nic_t *nic) ++{ ++ if (nic->priv) ++ free(nic->priv); ++ nic->priv = NULL; ++} ++ ++ ++/** ++ * bnx2_alloc() - Used to allocate a bnx2 structure ++ */ ++static bnx2_t *bnx2_alloc(nic_t *nic) ++{ ++ bnx2_t *bp = malloc(sizeof(*bp)); ++ if (bp == NULL) { ++ LOG_ERR(PFX "%s: Could not allocate bnx2 space", nic->log_name); ++ return NULL; ++ } ++ ++ /* Clear out the bnx2 contents */ ++ memset(bp, 0, sizeof(*bp)); ++ ++ bp->bar0_fd = INVALID_FD; ++ bp->flags = BNX2_UIO_TX_HAS_SENT; ++ ++ bp->parent = nic; ++ nic->priv = (void *)bp; ++ ++ return bp; ++} ++ ++/** ++ * bnx2_open() - This will initialize all the hardware resources ++ * @param dev - The struct nic device to open ++ * @return 0 on success, on failure a errno will be returned ++ */ ++static int bnx2_open(nic_t *nic) ++{ ++ bnx2_t *bp; ++ struct stat uio_stat; ++ int i, rc; ++ __u32 val; ++ uint32_t tx_cid; ++ __u32 msix_vector = 0; ++ char sysfs_resc_path[80]; ++ ++ /* Sanity Check: validate the parameters */ ++ if (nic == NULL) { ++ LOG_ERR(PFX "bnx2_open(): nic == NULL"); ++ return -EINVAL; ++ } ++ ++ if ((nic->priv) != NULL && ++ (((bnx2_t *) (nic->priv))->flags & BNX2_OPENED)) { ++ return 0; ++ } ++ ++ bp = bnx2_alloc(nic); ++ if (bp == NULL) { ++ LOG_ERR(PFX "bnx2_open(): Couldn't allocate bp priv struct", ++ nic->log_name); ++ return -ENOMEM; ++ } ++ ++ while (nic->fd < 0) { ++ nic->fd = open(nic->uio_device_name, O_RDWR | O_NONBLOCK); ++ if (nic->fd != INVALID_FD) { ++ LOG_ERR(PFX ++ "%s: uio device has been brought up via pid: " ++ "%d on fd: %d", ++ nic->uio_device_name, getpid(), nic->fd); ++ ++ rc = bnx2_uio_verify(nic); ++ if (rc != 0) ++ continue; ++ ++ break; ++ } else { ++ LOG_WARN(PFX "%s: Could not open device: %s, [%s]", ++ nic->log_name, nic->uio_device_name, ++ strerror(errno)); ++ manually_trigger_uio_event(nic, nic->uio_minor); ++ ++ /* udev might not have created the file yet */ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ sleep(1); ++ pthread_mutex_lock(&nic->nic_mutex); ++ } ++ } ++ if (fstat(nic->fd, &uio_stat) < 0) { ++ LOG_ERR(PFX "%s: Could not fstat device", nic->log_name); ++ errno = -ENODEV; ++ goto error_alloc_rx_ring; ++ } ++ nic->uio_minor = minor(uio_stat.st_rdev); ++ ++ cnic_get_sysfs_pci_resource_path(nic, 0, sysfs_resc_path, 80); ++ bp->bar0_fd = open(sysfs_resc_path, O_RDWR | O_SYNC); ++ if (bp->bar0_fd < 0) { ++ LOG_ERR(PFX "%s: Could not open %s", nic->log_name, ++ sysfs_resc_path); ++ errno = -ENODEV; ++ goto error_alloc_rx_ring; ++ } ++ ++ /* TODO: hardcoded with the cnic driver */ ++ bp->rx_ring_size = 3; ++ bp->rx_buffer_size = 0x400; ++ ++ LOG_DEBUG(PFX "%s: using rx ring size: %d, rx buffer size: %d", ++ nic->log_name, bp->rx_ring_size, bp->rx_buffer_size); ++ ++ /* Determine the number of UIO events that have already occured */ ++ rc = detemine_initial_uio_events(nic, &nic->intr_count); ++ if (rc != 0) { ++ LOG_ERR("Could not determine the number ofinitial UIO events"); ++ nic->intr_count = 0; ++ } ++ ++ /* Allocate space for rx ring pointer */ ++ bp->rx_ring = malloc(sizeof(struct l2_fhdr *) * bp->rx_ring_size); ++ if (bp->rx_ring == NULL) { ++ LOG_ERR(PFX "%s: Could not allocate space for rx_ring", ++ nic->log_name); ++ errno = -ENOMEM; ++ goto error_alloc_rx_ring; ++ } ++ mlock(bp->rx_ring, sizeof(struct l2_fhdr *) * bp->rx_ring_size); ++ ++ /* Allocate space for rx pkt ring */ ++ bp->rx_pkt_ring = malloc(sizeof(void *) * bp->rx_ring_size); ++ if (bp->rx_pkt_ring == NULL) { ++ LOG_ERR(PFX "%s: Could not allocate space for rx_pkt_ring", ++ nic->log_name); ++ errno = -ENOMEM; ++ goto error_alloc_rx_pkt_ring; ++ } ++ mlock(bp->rx_pkt_ring, sizeof(void *) * bp->rx_ring_size); ++ ++ bp->reg = mmap(NULL, 0x12800, PROT_READ | PROT_WRITE, MAP_SHARED, ++ bp->bar0_fd, (off_t) 0); ++ if (bp->reg == MAP_FAILED) { ++ LOG_INFO(PFX "%s: Couldn't mmap registers: %s", ++ nic->log_name, strerror(errno)); ++ bp->reg = NULL; ++ goto error_regs; ++ } ++ ++ msync(bp->reg, 0x12800, MS_SYNC); ++ LOG_DEBUG(PFX "Chip ID: %x", bnx2_get_chip_id(bp)); ++ ++ /* on a 5709 when using MSI-X the status block is at an offset */ ++ if (BNX2_CHIP_NUM(bnx2_get_chip_id(bp)) == CHIP_NUM_5709) { ++ /* determine if we are using MSI-X */ ++ val = bnx2_rd32(bp, BNX2_TSCH_TSS_CFG); ++ if (val) { ++ /* We are in MSI-X mode */ ++ uint32_t base_cid = ((val >> 10) & 0x7ff) << 3; ++ msix_vector = (val >> 24) & 0xf; ++ ++ bp->status_blk_size = (128 * 9); ++ ++ tx_cid = base_cid + msix_vector - 1; ++ bp->flags |= BNX2_UIO_MSIX_ENABLED; ++ ++ bp->get_tx_cons = bnx2_get_tx_msix; ++ bp->get_rx_cons = bnx2_get_rx_msix; ++ ++ LOG_DEBUG(PFX "%s: tss_cfg: 0x%x tx cid: %d", ++ nic->log_name, val, tx_cid); ++ ++ LOG_INFO(PFX "%s: detected using MSI-X vector: %d", ++ nic->log_name, msix_vector); ++ } else { ++ /* We are not in MSI-X mode */ ++ bp->status_blk_size = 64; ++ tx_cid = 20; ++ ++ bp->get_tx_cons = bnx2_get_tx_msi; ++ bp->get_rx_cons = bnx2_get_rx_msi; ++ } ++ } else { ++ bp->status_blk_size = 64; ++ tx_cid = 20; ++ ++ bp->get_tx_cons = bnx2_get_tx_msi; ++ bp->get_rx_cons = bnx2_get_rx_msi; ++ } ++ ++ bp->sblk_map = mmap(NULL, bp->status_blk_size, ++ PROT_READ | PROT_WRITE, MAP_SHARED, ++ nic->fd, (off_t) nic->page_size); ++ if (bp->sblk_map == MAP_FAILED) { ++ LOG_INFO(PFX "%s: Could not mmap status block: %s", ++ nic->log_name, strerror(errno)); ++ goto error_sblk; ++ } ++ ++ if (bp->flags & BNX2_UIO_MSIX_ENABLED) { ++ uint8_t *status_blk = (uint8_t *) bp->sblk_map; ++ status_blk += (msix_vector * 128); ++ ++ bp->status_blk.msix = (struct status_block_msix *)status_blk; ++ ++ LOG_DEBUG(PFX "%s: msix initial cons: tx:%d rx:%d", ++ nic->log_name, ++ bp->status_blk.msix->status_tx_quick_consumer_index, ++ bp->status_blk.msix->status_rx_quick_consumer_index); ++ } else { ++ bp->status_blk.msi = (struct status_block *)bp->sblk_map; ++ ++ LOG_DEBUG(PFX "%s: msi initial tx:%d rx:%d", ++ nic->log_name, ++ BNX2_SBLK_EVEN_IDX(bp->status_blk.msi->tx2), ++ BNX2_SBLK_EVEN_IDX(bp->status_blk.msi->rx2)); ++ } ++ ++ bp->tx_ring = mmap(NULL, 2 * nic->page_size, ++ PROT_READ | PROT_WRITE, MAP_SHARED, nic->fd, ++ (off_t) 2 * nic->page_size); ++ if (bp->tx_ring == MAP_FAILED) { ++ LOG_INFO(PFX "%s: Could not mmap tx ring: %s", ++ nic->log_name, strerror(errno)); ++ bp->tx_ring = NULL; ++ goto error_tx_ring; ++ } ++ ++ bp->bufs = mmap(NULL, (bp->rx_ring_size + 1) * bp->rx_buffer_size, ++ PROT_READ | PROT_WRITE, ++ MAP_SHARED, nic->fd, (off_t) 3 * nic->page_size); ++ if (bp->bufs == MAP_FAILED) { ++ LOG_INFO(PFX "%s: Could not mmap buffers: %s", ++ nic->log_name, strerror(errno)); ++ bp->bufs = NULL; ++ goto error_bufs; ++ } ++ ++ bp->tx_bidx_io = MB_GET_CID_ADDR(tx_cid) + BNX2_L2CTX_TX_HOST_BIDX; ++ bp->tx_bseq_io = MB_GET_CID_ADDR(tx_cid) + BNX2_L2CTX_TX_HOST_BSEQ; ++ LOG_INFO(PFX "%s: tx_bidx_io: 0x%x tx_bseq_io: 0x%x", ++ nic->log_name, bp->tx_bidx_io, bp->tx_bseq_io); ++ ++ bp->rx_bidx_io = MB_GET_CID_ADDR(2) + BNX2_L2CTX_HOST_BDIDX; ++ bp->rx_bseq_io = MB_GET_CID_ADDR(2) + BNX2_L2CTX_HOST_BSEQ; ++ ++ bp->tx_cons = 0; ++ bp->tx_prod = 0; ++ bp->tx_pkt = bp->bufs; ++ ++ bp->rx_index = 0; ++ bp->rx_cons = 0; ++ bp->rx_prod = bp->rx_ring_size; ++ bp->rx_bseq = bp->rx_prod * bp->rx_buffer_size; ++ bnx2_wr16(bp, bp->rx_bidx_io, bp->rx_prod); ++ bnx2_wr32(bp, bp->rx_bseq_io, bp->rx_bseq); ++ ++ bnx2_reg_sync(bp, bp->rx_bidx_io, sizeof(__u16)); ++ bnx2_reg_sync(bp, bp->rx_bseq_io, sizeof(__u32)); ++ ++ for (i = 0; i < bp->rx_ring_size; i++) { ++ void *ptr = bp->bufs + (bp->rx_buffer_size * (i + 1)); ++ ++ bp->rx_ring[i] = (struct l2_fhdr *)ptr; ++ bp->rx_pkt_ring[i] = ptr + sizeof(struct l2_fhdr) + 2; ++ } ++ ++ /* Read the MAC address used for the iSCSI interface */ ++ val = bnx2_rd32(bp, BNX2_EMAC_MAC_MATCH4); ++ nic->mac_addr[0] = (__u8) (val >> 8); ++ nic->mac_addr[1] = (__u8) val; ++ ++ val = bnx2_rd32(bp, BNX2_EMAC_MAC_MATCH5); ++ nic->mac_addr[2] = (__u8) (val >> 24); ++ nic->mac_addr[3] = (__u8) (val >> 16); ++ nic->mac_addr[4] = (__u8) (val >> 8); ++ nic->mac_addr[5] = (__u8) val; ++ ++ LOG_INFO(PFX "%s: Using mac address: %2x:%2x:%2x:%2x:%2x:%2x", ++ nic->log_name, ++ nic->mac_addr[0], nic->mac_addr[1], nic->mac_addr[2], ++ nic->mac_addr[3], nic->mac_addr[4], nic->mac_addr[5]); ++ ++ /* Determine if Hardware VLAN tag stripping is enabled or not */ ++ if (CNIC_VLAN_STRIPPING_ENABLED == bnx2_strip_vlan_enabled(bp)) ++ nic->flags |= NIC_VLAN_STRIP_ENABLED; ++ ++ /* Prepare the multicast addresses */ ++ val = 4 | BNX2_RPM_SORT_USER2_BC_EN | BNX2_RPM_SORT_USER2_MC_EN; ++ if (BNX2_CHIP_NUM(bnx2_get_chip_id(bp)) != CHIP_NUM_5709) ++ val |= BNX2_RPM_SORT_USER2_PROM_VLAN; ++ ++ bnx2_wr32(bp, BNX2_RPM_SORT_USER2, 0x0); ++ bnx2_wr32(bp, BNX2_RPM_SORT_USER2, val); ++ bnx2_wr32(bp, BNX2_RPM_SORT_USER2, val | BNX2_RPM_SORT_USER2_ENA); ++ ++ rc = enable_multicast(nic); ++ if (rc != 0) { ++ errno = rc; ++ goto error_bufs; ++ } ++ msync(bp->reg, 0x12800, MS_SYNC); ++ LOG_INFO("%s: bnx2 uio initialized", nic->log_name); ++ ++ bp->flags |= BNX2_OPENED; ++ ++ return 0; ++ ++error_bufs: ++ munmap(bp->tx_ring, 2 * nic->page_size); ++ ++error_tx_ring: ++ munmap(bp->status_blk.msi, bp->status_blk_size); ++ ++error_sblk: ++ munmap(bp->reg, 0x12800); ++ ++error_regs: ++ munlock(bp->rx_pkt_ring, sizeof(void *) * bp->rx_ring_size); ++ free(bp->rx_pkt_ring); ++ bp->rx_pkt_ring = NULL; ++ ++error_alloc_rx_pkt_ring: ++ munlock(bp->rx_ring, sizeof(struct l2_fhdr *) * bp->rx_ring_size); ++ free(bp->rx_ring); ++ bp->rx_ring = NULL; ++ ++error_alloc_rx_ring: ++ if (nic->fd != INVALID_FD) { ++ close(nic->fd); ++ nic->fd = INVALID_FD; ++ } ++ bnx2_free(nic); ++ ++ return errno; ++} ++ ++/** ++ * bnx2_uio_close_resources() - Used to free resource for the bnx2 NIC ++ * @param nic - NIC device to free resource ++ * @param graceful - whether to wait to close gracefully ++ * @return 0 on success, <0 on failure ++ */ ++static int bnx2_uio_close_resources(nic_t *nic, NIC_SHUTDOWN_T graceful) ++{ ++ bnx2_t *bp = (bnx2_t *) nic->priv; ++ int rc = 0; ++ ++ /* Remove the multicast addresses if added */ ++ if ((nic->flags & NIC_ADDED_MULICAST) && ++ (graceful == ALLOW_GRACEFUL_SHUTDOWN)) ++ disable_multicast(nic); ++ ++ /* Check if there is an assoicated bnx2 device */ ++ if (bp == NULL) { ++ LOG_WARN(PFX "%s: when closing resources there is " ++ "no assoicated bnx2", nic->log_name); ++ return -EIO; ++ } ++ ++ /* Clean up allocated memory */ ++ if (bp->rx_ring != NULL) { ++ free(bp->rx_ring); ++ bp->rx_ring = NULL; ++ } ++ ++ if (bp->rx_pkt_ring != NULL) { ++ free(bp->rx_pkt_ring); ++ bp->rx_pkt_ring = NULL; ++ } ++ ++ /* Clean up mapped registers */ ++ if (bp->bufs != NULL) { ++ rc = munmap(bp->bufs, ++ (bp->rx_ring_size + 1) * bp->rx_buffer_size); ++ if (rc != 0) ++ LOG_WARN(PFX "%s: Couldn't unmap bufs", nic->log_name); ++ bp->bufs = NULL; ++ } ++ ++ if (bp->tx_ring != NULL) { ++ rc = munmap(bp->tx_ring, 2 * nic->page_size); ++ if (rc != 0) ++ LOG_WARN(PFX "%s: Couldn't unmap tx_rings", ++ nic->log_name); ++ bp->tx_ring = NULL; ++ } ++ ++ if (bp->status_blk.msix != NULL || bp->status_blk.msi != NULL) { ++ rc = munmap(bp->sblk_map, bp->status_blk_size); ++ if (rc != 0) ++ LOG_WARN(PFX "%s: Couldn't unmap status block", ++ nic->log_name); ++ bp->sblk_map = NULL; ++ ++ bp->status_blk.msix = NULL; ++ bp->status_blk.msi = NULL; ++ } ++ ++ if (bp->reg != NULL) { ++ rc = munmap(bp->reg, 0x12800); ++ if (rc != 0) ++ LOG_WARN(PFX "%s: Couldn't unmap regs", nic->log_name); ++ bp->reg = NULL; ++ } ++ ++ if (bp->bar0_fd != INVALID_FD) { ++ close(bp->bar0_fd); ++ bp->bar0_fd = INVALID_FD; ++ } ++ ++ if (nic->fd != INVALID_FD) { ++ rc = close(nic->fd); ++ if (rc != 0) { ++ LOG_WARN(PFX ++ "%s: Couldn't close uio file descriptor: %d", ++ nic->log_name, nic->fd); ++ } else { ++ LOG_DEBUG(PFX "%s: Closed uio file descriptor: %d", ++ nic->log_name, nic->fd); ++ } ++ ++ nic->fd = INVALID_FD; ++ } else { ++ LOG_WARN(PFX "%s: Invalid uio file descriptor: %d", ++ nic->log_name, nic->fd); ++ } ++ ++ LOG_INFO(PFX "%s: Closed all resources", nic->log_name); ++ ++ return 0; ++} ++ ++/** ++ * bnx2_close() - Used to close the NIC device ++ * @param nic - NIC device to close ++ * @param graceful - whether to wait to close gracefully ++ * @return 0 if successful, <0 if there is an error ++ */ ++static int bnx2_close(nic_t *nic, NIC_SHUTDOWN_T graceful) ++{ ++ /* Sanity Check: validate the parameters */ ++ if (nic == NULL) { ++ LOG_ERR(PFX "bnx2_close(): nic == NULL"); ++ return -EINVAL; ++ } ++ ++ LOG_INFO(PFX "Closing NIC device: %s", nic->log_name); ++ ++ bnx2_uio_close_resources(nic, graceful); ++ bnx2_free(nic); ++ ++ return 0; ++} ++ ++static void bnx2_prepare_xmit_packet(nic_t *nic, ++ nic_interface_t *nic_iface, ++ struct packet *pkt) ++{ ++ bnx2_t *bp = (bnx2_t *) nic->priv; ++ struct uip_vlan_eth_hdr *eth_vlan = (struct uip_vlan_eth_hdr *)pkt->buf; ++ struct uip_eth_hdr *eth = (struct uip_eth_hdr *)bp->tx_pkt; ++ ++ if (eth_vlan->tpid == htons(UIP_ETHTYPE_8021Q)) { ++ memcpy(bp->tx_pkt, pkt->buf, sizeof(struct uip_eth_hdr)); ++ eth->type = eth_vlan->type; ++ pkt->buf_size -= (sizeof(struct uip_vlan_eth_hdr) - ++ sizeof(struct uip_eth_hdr)); ++ memcpy(bp->tx_pkt + sizeof(struct uip_eth_hdr), ++ pkt->buf + sizeof(struct uip_vlan_eth_hdr), ++ pkt->buf_size - sizeof(struct uip_eth_hdr)); ++ } else ++ memcpy(bp->tx_pkt, pkt->buf, pkt->buf_size); ++ ++ msync(bp->tx_pkt, pkt->buf_size, MS_SYNC); ++} ++ ++/** ++ * bnx2_get_tx_pkt() - This function is used to a TX packet from the NIC ++ * @param nic - The NIC device to send the packet ++ * ++ */ ++void *bnx2_get_tx_pkt(nic_t *nic) ++{ ++ bnx2_t *bp = (bnx2_t *) nic->priv; ++ return bp->tx_pkt; ++} ++ ++/** ++ * bnx2_start_xmit() - This function is used to send a packet of data ++ * @param nic - The NIC device to send the packet ++ * @param len - the length of the TX packet ++ * ++ */ ++void bnx2_start_xmit(nic_t *nic, size_t len, u16_t vlan_id) ++{ ++ bnx2_t *bp = (bnx2_t *) nic->priv; ++ uint16_t ring_prod; ++ struct tx_bd *txbd; ++ struct rx_bd *rxbd; ++ rxbd = (struct rx_bd *)(((__u8 *) bp->tx_ring) + nic->page_size); ++ ++ if ((rxbd->rx_bd_haddr_hi == 0) && (rxbd->rx_bd_haddr_lo == 0)) { ++ LOG_PACKET(PFX "%s: trying to transmit when device is closed", ++ nic->log_name); ++ pthread_mutex_unlock(&nic->xmit_mutex); ++ return; ++ } ++ ++ ring_prod = TX_RING_IDX(bp->tx_prod); ++ txbd = &bp->tx_ring[ring_prod]; ++ ++ txbd->tx_bd_mss_nbytes = len; ++ ++ if (vlan_id) { ++ txbd->tx_bd_vlan_tag_flags = (vlan_id << 16) | ++ TX_BD_FLAGS_VLAN_TAG | TX_BD_FLAGS_END | TX_BD_FLAGS_START; ++ } else ++ txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_END | ++ TX_BD_FLAGS_START; ++ ++ bp->tx_bseq += len; ++ bp->tx_prod = NEXT_TX_BD(bp->tx_prod); ++ ++ bnx2_wr16(bp, bp->tx_bidx_io, bp->tx_prod); ++ bnx2_wr32(bp, bp->tx_bseq_io, bp->tx_bseq); ++ ++ bnx2_reg_sync(bp, bp->tx_bidx_io, sizeof(__u16)); ++ bnx2_reg_sync(bp, bp->tx_bseq_io, sizeof(__u32)); ++ ++ LOG_PACKET(PFX "%s: sent %d bytes using dev->tx_prod: %d", ++ nic->log_name, len, bp->tx_prod); ++} ++ ++/** ++ * bnx2_write() - Used to write the data to the hardware ++ * @param nic - NIC hardware to read from ++ * @param pkt - The packet which will hold the data to be sent on the wire ++ * @return 0 if successful, <0 if failed ++ */ ++int bnx2_write(nic_t *nic, nic_interface_t *nic_iface, packet_t *pkt) ++{ ++ bnx2_t *bp; ++ struct uip_stack *uip; ++ ++ /* Sanity Check: validate the parameters */ ++ if (nic == NULL || nic_iface == NULL || pkt == NULL) { ++ LOG_ERR(PFX "%s: bnx2_write() nic == 0x%p || " ++ " nic_iface == 0x%p || " ++ " pkt == 0x%x", nic, nic_iface, pkt); ++ return -EINVAL; ++ } ++ bp = (bnx2_t *)nic->priv; ++ uip = &nic_iface->ustack; ++ ++ if (pkt->buf_size == 0) { ++ LOG_ERR(PFX "%s: Trying to transmitted 0 sized packet", ++ nic->log_name); ++ return -EINVAL; ++ } ++ ++ if (pthread_mutex_trylock(&nic->xmit_mutex) != 0) { ++ LOG_PACKET(PFX "%s: Dropped previous transmitted packet", ++ nic->log_name); ++ return -EINVAL; ++ } ++ ++ bnx2_prepare_xmit_packet(nic, nic_iface, pkt); ++ bnx2_start_xmit(nic, pkt->buf_size, ++ (nic_iface->vlan_priority << 12) | ++ nic_iface->vlan_id); ++ ++ /* bump the bnx2 dev send statistics */ ++ nic->stats.tx.packets++; ++ nic->stats.tx.bytes += uip->uip_len; ++ ++ LOG_PACKET(PFX "%s: transmitted %d bytes " ++ "dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bseq:%d", ++ nic->log_name, pkt->buf_size, ++ bp->tx_cons, bp->tx_prod, bp->tx_bseq); ++ ++ return 0; ++} ++ ++/** ++ * bnx2_read() - Used to read the data from the hardware ++ * @param nic - NIC hardware to read from ++ * @param pkt - The packet which will hold the data ++ * @return 0 if successful, <0 if failed ++ */ ++static int bnx2_read(nic_t *nic, packet_t *pkt) ++{ ++ bnx2_t *bp; ++ int rc = 0; ++ uint16_t hw_cons, sw_cons; ++ ++ /* Sanity Check: validate the parameters */ ++ if (unlikely(nic == NULL || pkt == NULL)) { ++ LOG_ERR(PFX "%s: bnx2_write() nic == 0x%p || " ++ " pkt == 0x%x", nic, pkt); ++ return -EINVAL; ++ } ++ bp = (bnx2_t *)nic->priv; ++ ++ hw_cons = bp->get_rx_cons(bp); ++ sw_cons = bp->rx_cons; ++ ++ if (sw_cons != hw_cons) { ++ uint8_t rx_index = bp->rx_index % 3; ++ struct l2_fhdr *rx_hdr = bp->rx_ring[rx_index]; ++ void *rx_pkt = bp->rx_pkt_ring[rx_index]; ++ int len; ++ uint16_t errors; ++ ++ LOG_PACKET(PFX "%s: clearing rx interrupt: %d %d %d", ++ nic->log_name, sw_cons, hw_cons, rx_index); ++ ++ msync(rx_hdr, sizeof(struct l2_fhdr), MS_SYNC); ++ errors = ((rx_hdr->l2_fhdr_status & 0xffff0000) >> 16); ++ len = ((rx_hdr->l2_fhdr_vtag_len & 0xffff0000) >> 16) - 4; ++ ++ if (unlikely((errors & (L2_FHDR_ERRORS_BAD_CRC | ++ L2_FHDR_ERRORS_PHY_DECODE | ++ L2_FHDR_ERRORS_ALIGNMENT | ++ L2_FHDR_ERRORS_TOO_SHORT | ++ L2_FHDR_ERRORS_GIANT_FRAME)) || ++ (len <= 0) || ++ (len > (bp->rx_buffer_size - ++ (sizeof(struct l2_fhdr) + 2))) || ++ (len > pkt->max_buf_size))) { ++ /* One of the fields in the BD is bad */ ++ uint16_t status = ((rx_hdr->l2_fhdr_status & ++ 0x0000ffff)); ++ ++ LOG_ERR(PFX "%s: Recv error: 0x%x status: 0x%x " ++ "len: %d", nic->log_name, errors, status, len); ++ ++ if ((len < (bp->rx_buffer_size - ++ (sizeof(struct l2_fhdr) + 2))) && ++ (len < pkt->max_buf_size)) ++ dump_packet_to_log(pkt->nic_iface, rx_pkt, len); ++ } else { ++ if (len < (bp->rx_buffer_size - ++ (sizeof(struct l2_fhdr) + 2))) { ++ msync(rx_pkt, len, MS_SYNC); ++ /* Copy the data */ ++ memcpy(pkt->buf, rx_pkt, len); ++ pkt->buf_size = len; ++ ++ /* Properly set the packet flags */ ++ /* check if there is VLAN tagging on the ++ * packet */ ++ if (rx_hdr->l2_fhdr_status & ++ L2_FHDR_STATUS_VLAN_TAG) { ++ pkt->vlan_tag = ++ rx_hdr->l2_fhdr_vtag_len & 0x0FFF; ++ pkt->flags |= VLAN_TAGGED; ++ } else { ++ pkt->vlan_tag = 0; ++ } ++ ++ rc = 1; ++ ++ LOG_PACKET(PFX "%s: processing packet " ++ "length: %d", nic->log_name, len); ++ } else { ++ /* If the NIC passes up a packet bigger ++ * then the RX buffer, flag it */ ++ LOG_ERR(PFX "%s: invalid packet length %d " ++ "recieve ", nic->log_name, len); ++ } ++ } ++ ++ bp->rx_index++; ++ sw_cons = NEXT_RX_BD(sw_cons); ++ bp->rx_prod = NEXT_RX_BD(bp->rx_prod); ++ bp->rx_bseq += 0x400; ++ ++ bp->rx_cons = sw_cons; ++ bnx2_wr16(bp, bp->rx_bidx_io, bp->rx_prod); ++ bnx2_wr32(bp, bp->rx_bseq_io, bp->rx_bseq); ++ ++ bnx2_reg_sync(bp, bp->rx_bidx_io, sizeof(__u16)); ++ bnx2_reg_sync(bp, bp->rx_bseq_io, sizeof(__u32)); ++ ++ /* bump the bnx2 dev recv statistics */ ++ nic->stats.rx.packets++; ++ nic->stats.rx.bytes += pkt->buf_size; ++ } ++ ++ return rc; ++} ++ ++/******************************************************************************* ++ * Clearing TX interrupts ++ ******************************************************************************/ ++/** ++ * bnx2_clear_tx_intr() - This routine is called when a TX interrupt occurs ++ * @param nic - the nic the interrupt occured on ++ * @return 0 on success ++ */ ++static int bnx2_clear_tx_intr(nic_t *nic) ++{ ++ bnx2_t *bp; ++ uint16_t hw_cons; ++ ++ /* Sanity check: ensure the parameters passed in are valid */ ++ if (unlikely(nic == NULL)) { ++ LOG_ERR(PFX "bnx2_read() nic == NULL"); ++ return -EINVAL; ++ } ++ bp = (bnx2_t *) nic->priv; ++ hw_cons = bp->get_tx_cons(bp); ++ ++ if (bp->flags & BNX2_UIO_TX_HAS_SENT) ++ bp->flags &= ~BNX2_UIO_TX_HAS_SENT; ++ ++ LOG_PACKET(PFX "%s: clearing tx interrupt [%d %d]", ++ nic->log_name, bp->tx_cons, hw_cons); ++ ++ bp->tx_cons = hw_cons; ++ ++ /* There is a queued TX packet that needs to be sent out. The usual ++ * case is when stack will send an ARP packet out before sending the ++ * intended packet */ ++ if (nic->tx_packet_queue != NULL) { ++ packet_t *pkt; ++ ++ LOG_PACKET(PFX "%s: sending queued tx packet", nic->log_name); ++ pkt = nic_dequeue_tx_packet(nic); ++ ++ /* Got a TX packet buffer of the TX queue and put it onto ++ * the hardware */ ++ if (pkt != NULL) { ++ bnx2_prepare_xmit_packet(nic, pkt->nic_iface, pkt); ++ ++ bnx2_start_xmit(nic, pkt->buf_size, ++ (pkt->nic_iface->vlan_priority << 12) | ++ pkt->nic_iface->vlan_id); ++ ++ LOG_PACKET(PFX "%s: transmitted queued packet %d bytes " ++ "dev->tx_cons: %d, dev->tx_prod: %d, " ++ "dev->tx_bseq:%d", ++ nic->log_name, pkt->buf_size, ++ bp->tx_cons, bp->tx_prod, bp->tx_bseq); ++ ++ return -EAGAIN; ++ } ++ } ++ ++ pthread_mutex_unlock(&nic->xmit_mutex); ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * bnx2 NIC op's table ++ ******************************************************************************/ ++struct nic_ops bnx2_op = { ++ .description = "bnx2", ++ .open = bnx2_open, ++ .close = bnx2_close, ++ .write = bnx2_write, ++ .get_tx_pkt = bnx2_get_tx_pkt, ++ .start_xmit = bnx2_start_xmit, ++ .read = bnx2_read, ++ .clear_tx_intr = bnx2_clear_tx_intr, ++ .handle_iscsi_path_req = cnic_handle_iscsi_path_req, ++ ++ .lib_ops = { ++ .get_library_name = bnx2_get_library_name, ++ .get_pci_table = bnx2_get_pci_table, ++ .get_library_version = bnx2_get_library_version, ++ .get_build_date = bnx2_get_build_date, ++ .get_transport_name = bnx2_get_transport_name, ++ .get_uio_name = bnx2_get_uio_name, ++ }, ++}; +diff --git a/iscsiuio/src/unix/libs/bnx2.h b/iscsiuio/src/unix/libs/bnx2.h +new file mode 100644 +index 0000000..3ec9437 +--- /dev/null ++++ b/iscsiuio/src/unix/libs/bnx2.h +@@ -0,0 +1,304 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * bnx2.h - bnx2 user space driver ++ * ++ */ ++#ifndef __BNX2_H__ ++#define __BNX2_H__ ++ ++#include "nic.h" ++ ++/****************************************************************************** ++ * Default BNX2 values ++ ******************************************************************************/ ++#define DEFAULT_NUM_RXBD 3 ++#define DEFAULT_RX_LEN 0x400 ++ ++/****************************************************************************** ++ * BNX2 Hardware structures ++ ******************************************************************************/ ++/* status_block definition for MSI */ ++struct status_block { ++ volatile __u32 status_attn_bits; ++ volatile __u32 status_attn_bits_ack; ++ volatile __u32 tx0; ++ volatile __u32 tx2; ++ volatile __u32 rx0; ++ volatile __u32 rx2; ++ volatile __u32 rx4; ++ volatile __u32 rx6; ++ volatile __u32 rx8; ++ volatile __u32 rx10; ++ volatile __u32 rx12; ++ volatile __u32 rx14; ++ volatile __u32 cmd; ++ volatile __u32 idx; ++}; ++ ++/* status_block definition for MSI-X */ ++struct status_block_msix { ++#if 0 ++#if defined(__BIG_ENDIAN) ++ __u16 status_tx_quick_consumer_index; ++ __u16 status_rx_quick_consumer_index; ++ __u16 status_completion_producer_index; ++ __u16 status_cmd_consumer_index; ++ __u32 status_unused; ++ __u16 status_idx; ++ __u8 status_unused2; ++ __u8 status_blk_num; ++#elif defined(__LITTLE_ENDIAN) ++ __u16 status_rx_quick_consumer_index; ++ __u16 status_tx_quick_consumer_index; ++ __u16 status_cmd_consumer_index; ++ __u16 status_completion_producer_index; ++ __u32 status_unused; ++ __u8 status_blk_num; ++ __u8 status_unused2; ++ __u16 status_idx; ++#endif ++#endif ++ __u16 status_rx_quick_consumer_index; ++ __u16 status_tx_quick_consumer_index; ++ __u16 status_cmd_consumer_index; ++ __u16 status_completion_producer_index; ++ __u32 status_unused; ++ __u8 status_blk_num; ++ __u8 status_unused2; ++ __u16 status_idx; ++}; ++ ++/* TX Buffer descriptor */ ++struct tx_bd { ++ __u32 tx_bd_haddr_hi; ++ __u32 tx_bd_haddr_lo; ++ __u32 tx_bd_mss_nbytes; ++ __u32 tx_bd_vlan_tag_flags; ++#define TX_BD_FLAGS_VLAN_TAG (1<<3) ++#define TX_BD_FLAGS_END (1<<6) ++#define TX_BD_FLAGS_START (1<<7) ++}; ++ ++/* RX Buffer descriptor */ ++struct rx_bd { ++ __u32 rx_bd_haddr_hi; ++ __u32 rx_bd_haddr_lo; ++ ++ __u32 rx_bd_len; ++ __u32 rx_bd_flags; ++#define RX_BD_FLAGS_END (1<<2) ++#define RX_BD_FLAGS_START (1<<3) ++ ++}; ++ ++/* This is the RX L2 Frame header */ ++struct l2_fhdr { ++ __u32 l2_fhdr_status; ++#define L2_FHDR_ERRORS_BAD_CRC (1<<17) ++#define L2_FHDR_ERRORS_PHY_DECODE (1<<18) ++#define L2_FHDR_ERRORS_ALIGNMENT (1<<19) ++#define L2_FHDR_ERRORS_TOO_SHORT (1<<20) ++#define L2_FHDR_ERRORS_GIANT_FRAME (1<<21) ++#define L2_FHDR_ERRORS_TCP_XSUM (1<<28) ++#define L2_FHDR_ERRORS_UDP_XSUM (1<<31) ++ ++#define L2_FHDR_STATUS_UDP_DATAGRAM (1<<15) ++#define L2_FHDR_STATUS_TCP_DATAGRAM (1<<14) ++#define L2_FHDR_STATUS_IP_DATAGRAM (1<<13) ++#define L2_FHDR_STATUS_LLC_SNAP (1<<7) ++#define L2_FHDR_STATUS_VLAN_TAG (1<<6) ++ ++ __u32 l2_fhdr_hash; ++ ++ __u32 l2_fhdr_vtag_len; ++ __u32 l2_fhdr_xsum; ++}; ++ ++/****************************************************************************** ++ * BNX2 Registers Defitions/Values ++ ******************************************************************************/ ++#define BNX2_MISC_ID 0x00000808 ++#define BNX2_EMAC_MAC_MATCH4 0x00001420 ++#define BNX2_EMAC_MAC_MATCH5 0x00001424 ++ ++#define BNX2_EMAC_RX_MODE 0x000014c8 ++#define BNX2_EMAC_RX_MODE_RESET (1L<<0) ++#define BNX2_EMAC_RX_MODE_FLOW_EN (1L<<2) ++#define BNX2_EMAC_RX_MODE_KEEP_MAC_CONTROL (1L<<3) ++#define BNX2_EMAC_RX_MODE_KEEP_PAUSE (1L<<4) ++#define BNX2_EMAC_RX_MODE_ACCEPT_OVERSIZE (1L<<5) ++#define BNX2_EMAC_RX_MODE_ACCEPT_RUNTS (1L<<6) ++#define BNX2_EMAC_RX_MODE_LLC_CHK (1L<<7) ++#define BNX2_EMAC_RX_MODE_PROMISCUOUS (1L<<8) ++#define BNX2_EMAC_RX_MODE_NO_CRC_CHK (1L<<9) ++#define BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG (1L<<10) ++#define BNX2_EMAC_RX_MODE_FILT_BROADCAST (1L<<11) ++#define BNX2_EMAC_RX_MODE_SORT_MODE (1L<<12) ++ ++#define BNX2_RPM_SORT_USER2 0x00001828 ++#define BNX2_RPM_SORT_USER2_PM_EN (0xffffL<<0) ++#define BNX2_RPM_SORT_USER2_BC_EN (1L<<16) ++#define BNX2_RPM_SORT_USER2_MC_EN (1L<<17) ++#define BNX2_RPM_SORT_USER2_MC_HSH_EN (1L<<18) ++#define BNX2_RPM_SORT_USER2_PROM_EN (1L<<19) ++#define BNX2_RPM_SORT_USER2_VLAN_EN (0xfL<<20) ++#define BNX2_RPM_SORT_USER2_PROM_VLAN (1L<<24) ++#define BNX2_RPM_SORT_USER2_ENA (1L<<31) ++ ++/* ++ * tsch_reg definition ++ * offset: 0x4c00 ++ */ ++#define BNX2_TSCH_TSS_CFG 0x00004c1c ++#define BNX2_TSCH_TSS_CFG_TSS_START_CID (0x7ffL<<8) ++#define BNX2_TSCH_TSS_CFG_NUM_OF_TSS_CON (0xfL<<24) ++#define CNIC_UIO_INVALID_FD -1 ++ ++#define BNX2_L2CTX_TX_HOST_BIDX 0x00000088 ++#define BNX2_L2CTX_TX_HOST_BSEQ 0x00000090 ++ ++#define BNX2_L2CTX_HOST_BDIDX 0x00000004 ++#define BNX2_L2CTX_HOST_BSEQ 0x00000008 ++ ++/* Used to determin the CHIP ID */ ++/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ ++#define BNX2_CHIP_NUM(bp) ((bp) & 0xffff0000) ++#define CHIP_NUM_5706 0x57060000 ++#define CHIP_NUM_5708 0x57080000 ++#define CHIP_NUM_5709 0x57090000 ++ ++#define CHIP_REV(bp) ((bp) & 0x0000f000) ++#define CHIP_REV_Ax 0x00000000 ++#define CHIP_REV_Bx 0x00001000 ++#define CHIP_REV_Cx 0x00002000 ++ ++#define CHIP_METAL(bp) ((bp) & 0x00000ff0) ++#define CHIP_BONDING(bp) ((bp) & 0x0000000f) ++ ++#define CHIP_ID(bp) ((bp) & 0xfffffff0) ++#define CHIP_ID_5706_A0 0x57060000 ++#define CHIP_ID_5706_A1 0x57060010 ++#define CHIP_ID_5706_A2 0x57060020 ++#define CHIP_ID_5708_A0 0x57080000 ++#define CHIP_ID_5708_B0 0x57081000 ++#define CHIP_ID_5708_B1 0x57081010 ++#define CHIP_ID_5709_A0 0x57090000 ++#define CHIP_ID_5709_A1 0x57090010 ++ ++#define CHIP_BOND_ID(bp) ((bp) & 0xf) ++ ++#define BNX2_SBLK_EVEN_IDX(x) (((x) & 0xffff0000) >> 16) ++ ++#define TX_DESC_CNT (4096 / sizeof(struct tx_bd)) ++#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1) ++ ++#define NEXT_TX_BD(x) ((((x) & (MAX_TX_DESC_CNT - 1)) == \ ++ (MAX_TX_DESC_CNT - 1)) ? \ ++ (x) + 2 : (x) + 1) ++ ++#define TX_RING_IDX(x) ((x) & MAX_TX_DESC_CNT) ++ ++#define RX_DESC_CNT (4096 / sizeof(struct rx_bd)) ++#define MAX_RX_DESC_CNT (RX_DESC_CNT - 1) ++ ++#define NEXT_RX_BD(x) ((((x) & (MAX_RX_DESC_CNT - 1)) == \ ++ (MAX_RX_DESC_CNT - 1)) ? \ ++ (x) + 2 : (x) + 1) ++ ++#define MB_KERNEL_CTX_SHIFT 8 ++#define MB_KERNEL_CTX_SIZE (1 << MB_KERNEL_CTX_SHIFT) ++#define MB_KERNEL_CTX_MASK (MB_KERNEL_CTX_SIZE - 1) ++#define MB_GET_CID_ADDR(_cid) (0x10000 + ((_cid) << MB_KERNEL_CTX_SHIFT)) ++ ++typedef struct bnx2 { ++ nic_t *parent; ++ ++ uint16_t flags; ++#define BNX2_UIO_MSIX_ENABLED 0x0001 ++#define BNX2_UIO_TX_HAS_SENT 0x0002 ++#define BNX2_OPENED 0x0004 ++ ++ int bar0_fd; ++ void *reg; /* Pointer to the mapped registers */ ++ ++ __u32 tx_bidx_io; ++ __u32 tx_bseq_io; ++ ++ __u16 tx_prod; ++ __u16 tx_cons; ++ __u32 tx_bseq; ++ ++ __u32 rx_bidx_io; ++ __u32 rx_bseq_io; ++ ++ __u16 rx_prod; ++ __u16 rx_cons; ++ __u32 rx_bseq; ++ ++ /* RX ring parameters */ ++ uint32_t rx_ring_size; ++ uint32_t rx_buffer_size; ++ ++ void *bufs; /* Pointer to the mapped buffer space */ ++ ++ /* Hardware Status Block locations */ ++ void *sblk_map; ++ union { ++ struct status_block *msi; ++ struct status_block_msix *msix; ++ } status_blk; ++ size_t status_blk_size; ++ ++ __u16(*get_rx_cons) (struct bnx2 *); ++ __u16(*get_tx_cons) (struct bnx2 *); ++ ++ uint16_t rx_index; ++ struct l2_fhdr **rx_ring; ++ void **rx_pkt_ring; ++ ++ struct tx_bd *tx_ring; ++ void *tx_pkt; ++ ++ struct l2_fhdr rcv_l2_fhdr; ++ __u8 rcv_buf[1500 + 2]; ++ __u32 rcv_size; ++} bnx2_t; ++ ++/****************************************************************************** ++ * bnx2 Function Declarations ++ ******************************************************************************/ ++struct nic_ops *bnx2_get_ops(); ++#endif /* __BNX2_H__ */ +diff --git a/iscsiuio/src/unix/libs/bnx2x.c b/iscsiuio/src/unix/libs/bnx2x.c +new file mode 100644 +index 0000000..19cbcec +--- /dev/null ++++ b/iscsiuio/src/unix/libs/bnx2x.c +@@ -0,0 +1,1653 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * bnx2x.c - bnx2x user space driver ++ * ++ */ ++#include ++#include ++#include ++#include ++#include /* Needed for linux/ethtool.h on RHEL 5.x */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "config.h" ++ ++#include "build_date.h" ++#include "bnx2x.h" ++#include "cnic.h" ++#include "logger.h" ++#include "nic.h" ++#include "nic_id.h" ++#include "nic_utils.h" ++#include "options.h" ++ ++#define PFX "bnx2x " ++ ++/* Foward struct declarations */ ++struct nic_ops bnx2x_op; ++ ++/******************************************************************************* ++ * NIC Library Strings ++ ******************************************************************************/ ++static const char library_name[] = "bnx2x"; ++static const char library_version[] = PACKAGE_VERSION; ++static const char library_uio_name[] = "bnx2x_cnic"; ++ ++/* The name that should be returned from /sys/class/uio/uio0/name */ ++static const char cnic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name"; ++static const char bnx2x_uio_sysfs_name[] = "bnx2x_cnic"; ++ ++/******************************************************************************* ++ * String constants used to display human readable adapter name ++ ******************************************************************************/ ++static const char brcm_57710[] = "QLogic NetXtreme II BCM57710 10-Gigabit"; ++static const char brcm_57711[] = "QLogic NetXtreme II BCM57711 10-Gigabit"; ++static const char brcm_57711e[] = "QLogic NetXtreme II BCM57711E 10-Gigabit"; ++static const char brcm_57712[] = "QLogic NetXtreme II BCM57712 10-Gigabit"; ++static const char brcm_57712_MF[] = "QLogic NetXtreme II BCM57712 MF " ++ "10-Gigabit"; ++static const char brcm_57712_VF[] = "QLogic NetXtreme II BCM57712 VF " ++ "10-Gigabit"; ++static const char brcm_57713[] = "QLogic NetXtreme II BCM57713 10-Gigabit"; ++static const char brcm_57713e[] = "QLogic NetXtreme II BCM57713E 10-Gigabit"; ++static const char brcm_57800[] = "QLogic NetXtreme II BCM57800 10-Gigabit"; ++static const char brcm_57800_MF[] = "QLogic NetXtreme II BCM57800 MF " ++ "10-Gigabit"; ++static const char brcm_57800_VF[] = "QLogic NetXtreme II BCM57800 VF " ++ "10-Gigabit"; ++static const char brcm_57810[] = "QLogic NetXtreme II BCM57810 10-Gigabit"; ++static const char brcm_57810_MF[] = "QLogic NetXtreme II BCM57810 MF " ++ "10-Gigabit"; ++static const char brcm_57810_VF[] = "QLogic NetXtreme II BCM57810 VF " ++ "10-Gigabit"; ++static const char brcm_57811[] = "QLogic NetXtreme II BCM57811 10-Gigabit"; ++static const char brcm_57811_MF[] = "QLogic NetXtreme II BCM57811 MF " ++ "10-Gigabit"; ++static const char brcm_57811_VF[] = "QLogic NetXtreme II BCM57811 VF " ++ "10-Gigabit"; ++static const char brcm_57840[] = "QLogic NetXtreme II BCM57840 10-Gigabit"; ++static const char brcm_57840_MF[] = "QLogic NetXtreme II BCM57840 MF " ++ "10-Gigabit"; ++static const char brcm_57840_VF[] = "QLogic NetXtreme II BCM57840 VF " ++ "10-Gigabit"; ++static const char brcm_57840_4_10[] = "QLogic NetXtreme II BCM57840 4x" ++ "10-Gigabit"; ++static const char brcm_57840_2_20[] = "QLogic NetXtreme II BCM57840 2x" ++ "20-Gigabit"; ++ ++/******************************************************************************* ++ * PCI ID constants ++ ******************************************************************************/ ++#define PCI_VENDOR_ID_BROADCOM 0x14e4 ++#define PCI_VENDOR_ID_QLOGIC 0x1077 ++#define PCI_DEVICE_ID_NX2_57710 0x164e ++#define PCI_DEVICE_ID_NX2_57711 0x164f ++#define PCI_DEVICE_ID_NX2_57711E 0x1650 ++#define PCI_DEVICE_ID_NX2_57712 0x1662 ++#define PCI_DEVICE_ID_NX2_57712_MF 0x1663 ++#define PCI_DEVICE_ID_NX2_57712_VF 0x166f ++#define PCI_DEVICE_ID_NX2_57713 0x1651 ++#define PCI_DEVICE_ID_NX2_57713E 0x1652 ++#define PCI_DEVICE_ID_NX2_57800 0x168a ++#define PCI_DEVICE_ID_NX2_57800_MF 0x16a5 ++#define PCI_DEVICE_ID_NX2_57800_VF 0x16a9 ++#define PCI_DEVICE_ID_NX2_57810 0x168e ++#define PCI_DEVICE_ID_NX2_57810_MF 0x16ae ++#define PCI_DEVICE_ID_NX2_57810_VF 0x16af ++#define PCI_DEVICE_ID_NX2_57811 0x163d ++#define PCI_DEVICE_ID_NX2_57811_MF 0x163e ++#define PCI_DEVICE_ID_NX2_57811_VF 0x163f ++#define PCI_DEVICE_ID_NX2_57840_OBSOLETE 0x168d ++#define PCI_DEVICE_ID_NX2_57840_MF_OBSOLETE 0x16ab ++#define PCI_DEVICE_ID_NX2_57840_4_10 0x16a1 ++#define PCI_DEVICE_ID_NX2_57840_2_20 0x16a2 ++#define PCI_DEVICE_ID_NX2_57840_MF 0x16a4 ++#define PCI_DEVICE_ID_NX2_57840_VF 0x16ad ++#define PCI_ANY_ID (~0) ++ ++/* This is the table used to match PCI vendor and device ID's to the ++ * human readable string names of the devices */ ++static const struct pci_device_id bnx2x_pci_tbl[] = { ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57710}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57711}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711E, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57711e}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57712, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57712}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57712_MF, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57712_MF}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57712_VF, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57712_VF}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57713, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57713}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57713E, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57713e}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57800, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57800}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57800_MF, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57800_MF}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57800_VF, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57800_VF}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57810, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57810}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57810_MF, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57810_MF}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57810_VF, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57810_VF}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57811, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57811}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57811_MF, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57811_MF}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57811_VF, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57811_VF}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_OBSOLETE, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57840}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_MF_OBSOLETE, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_MF}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_4_10, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_4_10}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_2_20, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_2_20}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_MF, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_MF}, ++ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_VF, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_VF}, ++ {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_NX2_57840_4_10, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_4_10}, ++ {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_NX2_57840_2_20, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_2_20}, ++ {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_NX2_57840_MF, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_MF}, ++ {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_NX2_57840_VF, ++ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_VF}, ++}; ++ ++static struct iro e1_iro[2] = { ++ {0x45a0, 0x90, 0x8, 0x0, 0x8}, /* T6.0 */ ++ {0x50c8, 0x90, 0x8, 0x0, 0x8}, /* T6.4 */ ++}; ++ ++static struct iro e1h_iro[2] = { ++ {0x1c40, 0xe0, 0x8, 0x0, 0x8}, /* T6.0 */ ++ {0x1e00, 0xe0, 0x8, 0x0, 0x8}, /* T6.4 */ ++}; ++ ++static struct iro e2_iro[2] = { ++ {0x6000, 0x20, 0x0, 0x0, 0x8}, /* T6.0 */ ++ {0x6000, 0x20, 0x0, 0x0, 0x8}, /* T6.4 */ ++}; ++ ++struct bnx2x_driver_version bnx2x_version = { ++ BNX2X_UNKNOWN_MAJOR_VERSION, ++ BNX2X_UNKNOWN_MINOR_VERSION, ++ BNX2X_UNKNOWN_SUB_MINOR_VERSION, ++}; ++ ++static int bnx2x_clear_tx_intr(nic_t *nic); ++ ++/******************************************************************************* ++ * BNX2X Library Functions ++ ******************************************************************************/ ++/** ++ * bnx2x_get_library_name() - Used to get the name of this NIC libary ++ * @param name - This function will return the pointer to this NIC ++ * library name ++ * @param name_size ++ */ ++static void bnx2x_get_library_name(char **name, size_t *name_size) ++{ ++ *name = (char *)library_name; ++ *name_size = sizeof(library_name); ++} ++ ++/** ++ * bnx2x_get_library_version() - Used to get the version string of this ++ * NIC libary ++ * @param version - This function will return the pointer to this NIC ++ * library version string ++ * @param version_size - This will be set with the version size ++ */ ++static void bnx2x_get_library_version(char **version, size_t *version_size) ++{ ++ *version = (char *)library_version; ++ *version_size = sizeof(library_version); ++} ++ ++/** ++ * bnx2x_get_build_date() - Used to get the build date string of this library ++ * @param version - This function will return the pointer to this NIC ++ * library build date string ++ * @param version_size - This will be set with the build date string size ++ */ ++static void bnx2x_get_build_date(char **build, size_t *build_size) ++{ ++ *build = (char *)build_date; ++ *build_size = sizeof(build_date); ++} ++ ++/** ++ * bnx2x_get_transport_name() - Used to get the transport name associated ++ * with this this NIC libary ++ * @param transport_name - This function will return the pointer to this NIC ++ * library's associated transport string ++ * @param transport_name_size - This will be set with the transport name size ++ */ ++static void bnx2x_get_transport_name(char **transport_name, ++ size_t *transport_name_size) ++{ ++ *transport_name = (char *)bnx2i_library_transport_name; ++ *transport_name_size = bnx2i_library_transport_name_size; ++} ++ ++/** ++ * bnx2x_get_uio_name() - Used to get the uio name associated with this this ++ * NIC libary ++ * @param uio_name - This function will return the pointer to this NIC ++ * library's associated uio string ++ * @param transport_name_size - This will be set with the uio name size ++ */ ++static void bnx2x_get_uio_name(char **uio_name, size_t *uio_name_size) ++{ ++ *uio_name = (char *)library_uio_name; ++ *uio_name_size = sizeof(library_uio_name); ++} ++ ++/** ++ * bnx2x_get_pci_table() - Used to get the PCI table for this NIC libary to ++ * determine which NIC's based off of PCI ID's are ++ * supported ++ * @param table - This function will return the pointer to the PCI table ++ * @param entries - This function will return the number of entries in the NIC ++ * library's PCI table ++ */ ++static void bnx2x_get_pci_table(struct pci_device_id **table, ++ uint32_t *entries) ++{ ++ *table = (struct pci_device_id *)bnx2x_pci_tbl; ++ *entries = ++ (uint32_t) (sizeof(bnx2x_pci_tbl) / sizeof(bnx2x_pci_tbl[0])); ++} ++ ++/** ++ * bnx2x_get_ops() - Used to get the NIC library op table ++ * @param op - The op table of this NIC library ++ */ ++struct nic_ops *bnx2x_get_ops() ++{ ++ return &bnx2x_op; ++} ++ ++/******************************************************************************* ++ * bnx2x Utility Functions ++ ******************************************************************************/ ++/******************************************************************************* ++ * Utility Functions Used to read register from the bnx2x device ++ ******************************************************************************/ ++static void bnx2x_set_drv_version_unknown(bnx2x_t *bp) ++{ ++ bp->version.major = BNX2X_UNKNOWN_MAJOR_VERSION; ++ bp->version.minor = BNX2X_UNKNOWN_MINOR_VERSION; ++ bp->version.sub_minor = BNX2X_UNKNOWN_SUB_MINOR_VERSION; ++} ++ ++/* Return: 1 = Unknown, 0 = Known */ ++static int bnx2x_is_drv_version_unknown(struct bnx2x_driver_version *version) ++{ ++ if ((version->major == (uint16_t)BNX2X_UNKNOWN_MAJOR_VERSION) && ++ (version->minor == (uint16_t)BNX2X_UNKNOWN_MINOR_VERSION) && ++ (version->sub_minor == (uint16_t)BNX2X_UNKNOWN_SUB_MINOR_VERSION)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/** ++ * bnx2x_get_drv_version() - Used to determine the driver version ++ * @param bp - Device used to determine bnx2x driver version ++ */ ++static int bnx2x_get_drv_version(bnx2x_t *bp) ++{ ++ nic_t *nic = bp->parent; ++ int fd, rc; ++ struct ifreq ifr; ++ struct ethtool_drvinfo drvinfo; ++ char *tok, *save_ptr = NULL; ++ ++ /* Setup our control structures. */ ++ memset(&ifr, 0, sizeof(ifr)); ++ strcpy(ifr.ifr_name, nic->eth_device_name); ++ ++ /* Open control socket. */ ++ fd = socket(AF_INET, SOCK_DGRAM, 0); ++ if (fd < 0) { ++ LOG_ERR(PFX "%s: Cannot get socket to determine version " ++ "[0x%x %s]", nic->log_name, errno, strerror(errno)); ++ return -EIO; ++ } ++ ++ memset(&drvinfo, 0, sizeof(drvinfo)); ++ drvinfo.cmd = ETHTOOL_GDRVINFO; ++ ifr.ifr_data = (caddr_t) &drvinfo; ++ rc = ioctl(fd, SIOCETHTOOL, &ifr); ++ if (rc < 0) { ++ LOG_ERR(PFX "%s: call to ethool IOCTL failed [0x%x %s]", ++ nic->log_name, errno, strerror(errno)); ++ goto error; ++ } ++ ++ tok = strtok_r(drvinfo.version, ".", &save_ptr); ++ if (tok == NULL) { ++ rc = -EIO; ++ goto error; ++ } ++ bp->version.major = atoi(tok); ++ ++ tok = strtok_r(NULL, ".", &save_ptr); ++ if (tok == NULL) { ++ rc = -EIO; ++ goto error; ++ } ++ bp->version.minor = atoi(tok); ++ ++ tok = strtok_r(NULL, ".", &save_ptr); ++ if (tok == NULL) { ++ rc = -EIO; ++ goto error; ++ } ++ bp->version.sub_minor = atoi(tok); ++ ++ LOG_INFO(PFX "%s: bnx2x driver using version %d.%d.%d", ++ nic->log_name, ++ bp->version.major, bp->version.minor, bp->version.sub_minor); ++ ++ close(fd); ++ ++ return 0; ++ ++error: ++ close(fd); ++ bnx2x_set_drv_version_unknown(bp); ++ ++ LOG_ERR(PFX "%s: error parsing driver string: '%s'", ++ nic->log_name, drvinfo.version); ++ ++ return rc; ++ ++} ++ ++static inline int bnx2x_is_ver70(bnx2x_t *bp) ++{ ++ return (bp->version.major == 1 && bp->version.minor >= 70); ++} ++ ++static inline int bnx2x_is_ver60(bnx2x_t *bp) ++{ ++ return (bp->version.major == 1 && (bp->version.minor == 60 || ++ bp->version.minor == 62 || ++ bp->version.minor == 64)); ++} ++ ++static inline int bnx2x_is_ver60_plus(bnx2x_t *bp) ++{ ++ return bnx2x_is_ver60(bp) || bnx2x_is_ver70(bp); ++} ++ ++static inline int bnx2x_is_ver52(bnx2x_t *bp) ++{ ++ return (bp->version.major == 1 && bp->version.minor == 52); ++} ++ ++static void bnx2x_wr32(bnx2x_t *bp, __u32 off, __u32 val) ++{ ++ *((volatile __u32 *)(bp->reg + off)) = val; ++} ++ ++static void bnx2x_doorbell(bnx2x_t *bp, __u32 off, __u32 val) ++{ ++ *((volatile __u32 *)(bp->reg2 + off)) = val; ++} ++ ++static void bnx2x_flush_doorbell(bnx2x_t *bp, __u32 off) ++{ ++ volatile __u32 tmp __attribute__((__unused__)); ++ ++ barrier(); ++ tmp = *((volatile __u32 *)(bp->reg2 + off)); ++} ++ ++static __u32 bnx2x_rd32(bnx2x_t *bp, __u32 off) ++{ ++ return *((volatile __u32 *)(bp->reg + off)); ++} ++ ++static int bnx2x_reg_sync(bnx2x_t *bp, __u32 off, __u16 length) ++{ ++ return msync(bp->reg + off, length, MS_SYNC); ++} ++ ++static void bnx2x_update_rx_prod(bnx2x_t *bp) ++{ ++ struct ustorm_eth_rx_producers rx_prods = { 0 }; ++ int i; ++ ++ rx_prods.bd_prod = bp->rx_bd_prod; ++ rx_prods.cqe_prod = bp->rx_prod; ++ ++ barrier(); ++ ++ for (i = 0; i < sizeof(struct ustorm_eth_rx_producers) / 4; i++) ++ bnx2x_wr32(bp, bp->rx_prod_io + i * 4, ++ ((__u32 *)&rx_prods)[i]); ++ ++ barrier(); ++ ++ bnx2x_reg_sync(bp, bp->rx_prod_io, ++ sizeof(struct ustorm_eth_rx_producers)); ++} ++ ++/** ++ * bnx2x_get_chip_id() - Used to retrive the chip ID from the nic ++ * @param dev - Device used to determin NIC type ++ * @return Chip ID read from the MISC ID register ++ */ ++static int bnx2x_get_chip_id(bnx2x_t *bp) ++{ ++ int val, id; ++ ++ /* Get the chip revision id and number. */ ++ /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ ++ val = bnx2x_rd32(bp, BNX2X_MISC_REG_CHIP_NUM); ++ id = ((val & 0xffff) << 16); ++ val = bnx2x_rd32(bp, BNX2X_MISC_REG_CHIP_REV); ++ id |= ((val & 0xf) << 12); ++ val = bnx2x_rd32(bp, BNX2X_MISC_REG_CHIP_METAL); ++ id |= ((val & 0xff) << 4); ++ val = bnx2x_rd32(bp, BNX2X_MISC_REG_BOND_ID); ++ id |= (val & 0xf); ++ ++ return id; ++} ++ ++/** ++ * bnx2x_uio_verify() ++ * ++ */ ++static int bnx2x_uio_verify(nic_t *nic) ++{ ++ char *raw = NULL, *raw_tmp; ++ uint32_t raw_size = 0; ++ char temp_path[sizeof(cnic_uio_sysfs_name_tempate) + 8]; ++ int rc = 0; ++ ++ /* Build the path to determine uio name */ ++ snprintf(temp_path, sizeof(temp_path), ++ cnic_uio_sysfs_name_tempate, nic->uio_minor); ++ ++ rc = capture_file(&raw, &raw_size, temp_path); ++ if (rc != 0) ++ goto error; ++ ++ /* sanitize name string by replacing newline with null termination */ ++ raw_tmp = raw; ++ while (*raw_tmp != '\n') ++ raw_tmp++; ++ *raw_tmp = '\0'; ++ ++ if (strncmp(raw, bnx2x_uio_sysfs_name, ++ sizeof(bnx2x_uio_sysfs_name)) != 0) { ++ LOG_ERR(PFX "%s: uio names not equal: " ++ "expecting %s got %s from %s", ++ nic->log_name, bnx2x_uio_sysfs_name, raw, temp_path); ++ rc = -EIO; ++ } ++ ++ free(raw); ++ ++ LOG_INFO(PFX "%s: Verified is a cnic_uio device", nic->log_name); ++ ++error: ++ return rc; ++} ++ ++/******************************************************************************* ++ * bnx2x Utility Functions to get to the hardware consumer indexes ++ ******************************************************************************/ ++static __u16 bnx2x_get_rx(bnx2x_t *bp) ++{ ++ struct host_def_status_block *sblk = bp->status_blk.def; ++ __u16 rx_comp_cons; ++ ++ msync(sblk, sizeof(*sblk), MS_SYNC); ++ rx_comp_cons = ++ sblk->u_def_status_block. ++ index_values[HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS]; ++ if ((rx_comp_cons & BNX2X_MAX_RCQ_DESC_CNT(bp)) == ++ BNX2X_MAX_RCQ_DESC_CNT(bp)) ++ rx_comp_cons++; ++ ++ return rx_comp_cons; ++} ++ ++static __u16 bnx2x_get_rx_60(bnx2x_t *bp) ++{ ++ struct host_sp_status_block *sblk = bp->status_blk.sp; ++ __u16 rx_comp_cons; ++ ++ msync(sblk, sizeof(*sblk), MS_SYNC); ++ rx_comp_cons = ++ sblk->sp_sb.index_values[HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS]; ++ if ((rx_comp_cons & BNX2X_MAX_RCQ_DESC_CNT(bp)) == ++ BNX2X_MAX_RCQ_DESC_CNT(bp)) ++ rx_comp_cons++; ++ ++ return rx_comp_cons; ++} ++ ++static __u16 bnx2x_get_tx(bnx2x_t *bp) ++{ ++ struct host_def_status_block *sblk = bp->status_blk.def; ++ __u16 tx_cons; ++ ++ msync(sblk, sizeof(*sblk), MS_SYNC); ++ tx_cons = ++ sblk->c_def_status_block. ++ index_values[HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS]; ++ ++ return tx_cons; ++} ++ ++static __u16 bnx2x_get_tx_60(bnx2x_t *bp) ++{ ++ struct host_sp_status_block *sblk = bp->status_blk.sp; ++ __u16 tx_cons; ++ ++ msync(sblk, sizeof(*sblk), MS_SYNC); ++ tx_cons = sblk->sp_sb.index_values[HC_SP_INDEX_ETH_ISCSI_CQ_CONS]; ++ ++ return tx_cons; ++} ++ ++typedef enum { ++ CNIC_VLAN_STRIPPING_ENABLED = 1, ++ CNIC_VLAN_STRIPPING_DISABLED = 2, ++} CNIC_VLAN_STRIPPING_MODE; ++ ++/** ++ * bnx2x_strip_vlan_enabled() - This will query the device to determine whether ++ * VLAN tag stripping is enabled or not ++ * @param dev - device to check stripping or not ++ * @ return CNIC_VLAN_STRIPPING_ENABLED stripping is enabled ++ * CNIC_VLAN_STRIPPING_DISABLED stripping is not enabled ++ */ ++static CNIC_VLAN_STRIPPING_MODE bnx2x_strip_vlan_enabled(bnx2x_t *bp) ++{ ++ return CNIC_VLAN_STRIPPING_DISABLED; ++} ++ ++/** ++ * bnx2x_free() - Used to free a bnx2x structure ++ */ ++static void bnx2x_free(nic_t *nic) ++{ ++ if (nic->priv) ++ free(nic->priv); ++ nic->priv = NULL; ++} ++ ++/** ++ * bnx2x_alloc() - Used to allocate a bnx2x structure ++ */ ++static bnx2x_t *bnx2x_alloc(nic_t *nic) ++{ ++ bnx2x_t *bp = malloc(sizeof(*bp)); ++ ++ if (bp == NULL) { ++ LOG_ERR(PFX "%s: Could not allocate BNX2X space", ++ nic->log_name); ++ return NULL; ++ } ++ ++ /* Clear out the CNIC contents */ ++ memset(bp, 0, sizeof(*bp)); ++ ++ bp->bar0_fd = INVALID_FD; ++ bp->bar2_fd = INVALID_FD; ++ ++ bp->parent = nic; ++ nic->priv = (void *)bp; ++ ++ bnx2x_set_drv_version_unknown(bp); ++ ++ return bp; ++} ++ ++/** ++ * bnx2x_open() - This will initialize all the hardware resources underneath ++ * a struct cnic_uio device ++ * @param dev - The struct cnic_uio device to attach the hardware with ++ * @return 0 on success, on failure a errno will be returned ++ */ ++static int bnx2x_open(nic_t *nic) ++{ ++ bnx2x_t *bp; ++ struct stat uio_stat; ++ int i, rc; ++ __u32 val; ++ int count; ++ char sysfs_resc_path[80]; ++ uint32_t bus; ++ uint32_t slot; ++ uint32_t func; ++ uint32_t mode; ++ __u32 proto_offset; ++ __u32 ovtag_offset; ++ ++ /* Sanity Check: validate the parameters */ ++ if (nic == NULL) { ++ LOG_ERR(PFX "nic == NULL"); ++ return -EINVAL; ++ } ++ ++ if ((nic->priv) != NULL && ++ (((bnx2x_t *) (nic->priv))->flags & BNX2X_OPENED)) { ++ return 0; ++ } ++ ++ bp = bnx2x_alloc(nic); ++ if (bp == NULL) ++ return -ENOMEM; ++ ++ if (bnx2x_is_drv_version_unknown(&bnx2x_version)) { ++ /* If version is unknown, go read from ethtool */ ++ rc = bnx2x_get_drv_version(bp); ++ if (rc) ++ goto open_error; ++ } else { ++ /* Version is not unknown, just use it */ ++ bnx2x_version.major = bp->version.major; ++ bnx2x_version.minor = bp->version.minor; ++ bnx2x_version.sub_minor = bp->version.sub_minor; ++ } ++ ++ count = 0; ++ while ((nic->fd < 0) && count < 15) { ++ /* udev might not have created the file yet */ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ sleep(1); ++ pthread_mutex_lock(&nic->nic_mutex); ++ ++ nic->fd = open(nic->uio_device_name, O_RDWR | O_NONBLOCK); ++ if (nic->fd != INVALID_FD) { ++ LOG_ERR(PFX "%s: uio device has been brought up " ++ "via pid: %d on fd: %d", ++ nic->uio_device_name, getpid(), nic->fd); ++ ++ rc = bnx2x_uio_verify(nic); ++ if (rc != 0) ++ continue; ++ ++ break; ++ } else { ++ LOG_WARN(PFX "%s: Could not open device: %s, [%s]", ++ nic->log_name, nic->uio_device_name, ++ strerror(errno)); ++ ++ manually_trigger_uio_event(nic, nic->uio_minor); ++ ++ /* udev might not have created the file yet */ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ sleep(1); ++ pthread_mutex_lock(&nic->nic_mutex); ++ ++ count++; ++ } ++ } ++ if (fstat(nic->fd, &uio_stat) < 0) { ++ LOG_ERR(PFX "%s: Could not fstat device", nic->log_name); ++ rc = -ENODEV; ++ goto open_error; ++ } ++ nic->uio_minor = minor(uio_stat.st_rdev); ++ ++ cnic_get_sysfs_pci_resource_path(nic, 0, sysfs_resc_path, 80); ++ bp->bar0_fd = open(sysfs_resc_path, O_RDWR | O_SYNC); ++ if (bp->bar0_fd < 0) { ++ LOG_ERR(PFX "%s: Could not open %s", nic->log_name, ++ sysfs_resc_path); ++ rc = -ENODEV; ++ goto open_error; ++ } ++ ++ bp->reg = mmap(NULL, BNX2X_BAR_SIZE, PROT_READ | PROT_WRITE, ++ MAP_SHARED, bp->bar0_fd, (off_t) 0); ++ ++ if (bp->reg == MAP_FAILED) { ++ LOG_INFO(PFX "%s: Couldn't mmap BAR registers: %s", ++ nic->log_name, strerror(errno)); ++ bp->reg = NULL; ++ rc = errno; ++ goto open_error; ++ } ++ ++ msync(bp->reg, BNX2X_BAR_SIZE, MS_SYNC); ++ ++ cnic_get_sysfs_pci_resource_path(nic, 2, sysfs_resc_path, 80); ++ bp->bar2_fd = open(sysfs_resc_path, O_RDWR | O_SYNC); ++ if (bp->bar2_fd < 0) { ++ LOG_ERR(PFX "%s: Could not open %s", nic->log_name, ++ sysfs_resc_path); ++ rc = -ENODEV; ++ goto open_error; ++ } ++ ++ bp->reg2 = mmap(NULL, BNX2X_BAR2_SIZE, PROT_READ | PROT_WRITE, ++ MAP_SHARED, bp->bar2_fd, (off_t) 0); ++ ++ if (bp->reg2 == MAP_FAILED) { ++ LOG_INFO(PFX "%s: Couldn't mmap BAR2 registers: %s", ++ nic->log_name, strerror(errno)); ++ bp->reg2 = NULL; ++ rc = errno; ++ goto open_error; ++ } ++ ++ /* TODO: hardcoded with the cnic driver */ ++ bp->rx_ring_size = 15; ++ bp->rx_buffer_size = 0x400; ++ ++ LOG_DEBUG(PFX "%s: using rx ring size: %d, rx buffer size: %d", ++ nic->log_name, bp->rx_ring_size, bp->rx_buffer_size); ++ ++ /* Determine the number of UIO events that have already occured */ ++ rc = detemine_initial_uio_events(nic, &nic->intr_count); ++ if (rc != 0) { ++ LOG_ERR("Could not determine the number ofinitial UIO events"); ++ nic->intr_count = 0; ++ } ++ ++ /* Allocate space for rx pkt ring */ ++ bp->rx_pkt_ring = malloc(sizeof(void *) * bp->rx_ring_size); ++ if (bp->rx_pkt_ring == NULL) { ++ LOG_ERR(PFX "%s: Could not allocate space for rx_pkt_ring", ++ nic->log_name); ++ rc = errno; ++ goto open_error; ++ } ++ ++ if (bnx2x_is_ver60_plus(bp)) ++ bp->status_blk_size = sizeof(struct host_sp_status_block); ++ else if (bnx2x_is_ver52(bp)) ++ bp->status_blk_size = sizeof(struct host_def_status_block); ++ else { ++ LOG_INFO(PFX "%s: Unsupported bnx2x driver [%d.%d]", ++ nic->log_name, bp->version.major, bp->version.minor); ++ ++ rc = -ENOTSUP; ++ goto open_error; ++ } ++ ++ bp->status_blk.def = mmap(NULL, bp->status_blk_size, ++ PROT_READ | PROT_WRITE, MAP_SHARED, ++ nic->fd, (off_t) nic->page_size); ++ if (bp->status_blk.def == MAP_FAILED) { ++ LOG_INFO(PFX "%s: Could not mmap status block: %s", ++ nic->log_name, strerror(errno)); ++ bp->status_blk.def = NULL; ++ rc = errno; ++ goto open_error; ++ } ++ ++ bp->tx_ring = mmap(NULL, 4 * nic->page_size, ++ PROT_READ | PROT_WRITE, ++ MAP_SHARED | MAP_LOCKED, ++ nic->fd, (off_t) 2 * nic->page_size); ++ if (bp->tx_ring == MAP_FAILED) { ++ LOG_INFO(PFX "%s: Could not mmap tx ring: %s", ++ nic->log_name, strerror(errno)); ++ bp->tx_ring = NULL; ++ rc = errno; ++ goto open_error; ++ } ++ ++ bp->rx_comp_ring.cqe = (union eth_rx_cqe *) ++ (((__u8 *) bp->tx_ring) + 2 * nic->page_size); ++ ++ bp->bufs = mmap(NULL, (bp->rx_ring_size + 1) * bp->rx_buffer_size, ++ PROT_READ | PROT_WRITE, ++ MAP_SHARED | MAP_LOCKED, ++ nic->fd, (off_t) 3 * nic->page_size); ++ if (bp->bufs == MAP_FAILED) { ++ LOG_INFO(PFX "%s: Could not mmap buffers: %s", ++ nic->log_name, strerror(errno)); ++ bp->bufs = NULL; ++ rc = errno; ++ goto open_error; ++ } ++ ++ bp->chip_id = bnx2x_get_chip_id(bp); ++ LOG_DEBUG(PFX "Chip ID: %x", bp->chip_id); ++ ++ rc = get_bus_slot_func_num(nic, &bus, &slot, &func); ++ if (rc != 0) { ++ LOG_INFO(PFX "%s: Couldn't determine bus:slot.func", ++ nic->log_name); ++ goto open_error; ++ } ++ /* In E1/E1H use pci device function as read from sysfs. ++ * In E2/E3 read physical function from ME register since these chips ++ * support Physical Device Assignment where kernel BDF maybe arbitrary ++ * (depending on hypervisor). ++ */ ++ if (CHIP_IS_E2_PLUS(bp)) { ++ func = (bnx2x_rd32(bp, BAR_ME_REGISTER) & ME_REG_ABS_PF_NUM) >> ++ ME_REG_ABS_PF_NUM_SHIFT; ++ } ++ bp->func = func; ++ bp->port = bp->func % PORT_MAX; ++ ++ if (CHIP_IS_E2_PLUS(bp)) { ++ __u32 val = bnx2x_rd32(bp, MISC_REG_PORT4MODE_EN_OVWR); ++ if (!(val & 1)) ++ val = bnx2x_rd32(bp, MISC_REG_PORT4MODE_EN); ++ else ++ val = (val >> 1) & 1; ++ ++ if (val) ++ bp->pfid = func >> 1; ++ else ++ bp->pfid = func & 0x6; ++ } else { ++ bp->pfid = func; ++ } ++ ++ if (bnx2x_is_ver60_plus(bp)) ++ bp->port = bp->pfid & 1; ++ ++ bp->cid = 17; ++ bp->client_id = 17; ++ ++ if (bnx2x_is_ver60_plus(bp)) { ++ struct client_init_general_data *data = bp->bufs; ++ ++ bp->client_id = data->client_id; ++ if (data->uid.cid) ++ bp->cid = data->uid.cid; ++ if (bp->version.minor >= 78 && bp->version.sub_minor >= 55 && ++ data->uid.cid_override_key == UIO_USE_TX_DOORBELL) { ++ bp->tx_doorbell = data->uid.tx_db_off; ++ LOG_INFO(PFX "%s: tx doorbell override offset = 0x%x", ++ nic->log_name, bp->tx_doorbell); ++ } ++ } ++ ++ LOG_INFO(PFX "%s: func 0x%x, pfid 0x%x, client_id 0x%x, cid 0x%x", ++ nic->log_name, bp->func, bp->pfid, bp->client_id, bp->cid); ++ ++ if (CHIP_IS_E1(bp)) ++ bp->iro = e1_iro; ++ else if (CHIP_IS_E1H(bp)) ++ bp->iro = e1h_iro; ++ else if (CHIP_IS_E2_PLUS(bp)) ++ bp->iro = e2_iro; ++ ++ if (bnx2x_is_ver60_plus(bp)) { ++ __u32 cl_qzone_id = BNX2X_CL_QZONE_ID(bp, bp->client_id); ++ ++ bp->iro_idx = 0; ++ if (bp->version.minor >= 64) { ++ bp->iro_idx = 1; ++ cl_qzone_id = BNX2X_CL_QZONE_ID_64(bp, bp->client_id); ++ } ++ ++ bp->rx_prod_io = BAR_USTRORM_INTMEM + ++ (CHIP_IS_E2_PLUS(bp) ? ++ USTORM_RX_PRODS_E2_OFFSET(cl_qzone_id) : ++ USTORM_RX_PRODS_E1X_OFFSET(bp->port, bp->client_id)); ++ ++ if (!bp->tx_doorbell) ++ bp->tx_doorbell = bp->cid * 0x80 + 0x40; ++ ++ bp->get_rx_cons = bnx2x_get_rx_60; ++ bp->get_tx_cons = bnx2x_get_tx_60; ++ bp->tx_vlan_tag_bit = ETH_TX_BD_FLAGS_VLAN_TAG_T6X; ++ } else { ++ bp->rx_prod_io = BAR_USTRORM_INTMEM + ++ USTORM_RX_PRODS_OFFSET(bp->port, bp->client_id); ++ ++ bp->tx_doorbell = bp->cid * nic->page_size + 0x40; ++ ++ bp->get_rx_cons = bnx2x_get_rx; ++ bp->get_tx_cons = bnx2x_get_tx; ++ bp->tx_vlan_tag_bit = ETH_TX_BD_FLAGS_VLAN_TAG_T5X; ++ } ++ ++ bp->tx_cons = 0; ++ bp->tx_prod = 0; ++ bp->tx_bd_prod = 0; ++ bp->tx_pkt = bp->bufs; ++ ++ bp->rx_index = 0; ++ bp->rx_cons = 0; ++ bp->rx_bd_cons = 0; ++ bp->rx_prod = 127; ++ bp->rx_bd_prod = bp->rx_ring_size; ++ ++ for (i = 0; i < bp->rx_ring_size; i++) { ++ void *ptr = bp->bufs + (bp->rx_buffer_size * (i + 1)); ++ ++ bp->rx_pkt_ring[i] = ptr; ++ } ++ ++ val = bnx2x_rd32(bp, MISC_REG_SHARED_MEM_ADDR); ++ ++ bp->shmem_base = val; ++ val = bnx2x_rd32(bp, bp->shmem_base + SHMEM_ISCSI_MAC_UPPER(bp)); ++ nic->mac_addr[0] = (__u8) (val >> 8); ++ nic->mac_addr[1] = (__u8) val; ++ val = bnx2x_rd32(bp, bp->shmem_base + SHMEM_ISCSI_MAC_LOWER(bp)); ++ nic->mac_addr[2] = (__u8) (val >> 24); ++ nic->mac_addr[3] = (__u8) (val >> 16); ++ nic->mac_addr[4] = (__u8) (val >> 8); ++ nic->mac_addr[5] = (__u8) val; ++ ++ if (bnx2x_is_ver60_plus(bp) && CHIP_IS_E2_PLUS(bp)) { ++ __u32 mf_cfg_addr = 0; ++ __u32 mac_offset; ++ __u8 mac[6]; ++ ++ val = bnx2x_rd32(bp, (BNX2X_PATH(bp) ? MISC_REG_GENERIC_CR_1 : ++ MISC_REG_GENERIC_CR_0)); ++ bp->shmem_base2 = val; ++ if (bp->shmem_base2) { ++ /* size */ ++ val = bnx2x_rd32(bp, bp->shmem_base2); ++ ++ if (val > 0x10) ++ mf_cfg_addr = ++ bnx2x_rd32(bp, bp->shmem_base2 + 0x10); ++ } ++ ++ if (!mf_cfg_addr) ++ mf_cfg_addr = bp->shmem_base + 0x7e4; ++ ++ /* shared_feat_cfg.config */ ++ mode = bnx2x_rd32(bp, bp->shmem_base + 0x354); ++ mode &= 0x700; ++ LOG_DEBUG(PFX "%s: mode = 0x%x", nic->log_name, mode); ++ switch (mode) { ++ case 0x300: /* SI mode */ ++ mac_offset = 0xe4 + (bp->func * 0x28) + 4; ++ val = bnx2x_rd32(bp, mf_cfg_addr + mac_offset); ++ mac[0] = (__u8) (val >> 8); ++ mac[1] = (__u8) val; ++ mac_offset += 4; ++ val = bnx2x_rd32(bp, mf_cfg_addr + mac_offset); ++ mac[2] = (__u8) (val >> 24); ++ mac[3] = (__u8) (val >> 16); ++ mac[4] = (__u8) (val >> 8); ++ mac[5] = (__u8) val; ++ ++ if (mac[0] != 0xff) { ++ memcpy(nic->mac_addr, mac, 6); ++ } else if (bp->func > 1) { ++ LOG_INFO(PFX "%s: Invalid mac address: " ++ "%02x:%02x:%02x:%02x:%02x:%02x, abort", ++ nic->log_name, ++ mac[0], mac[1], mac[2], ++ mac[3], mac[4], mac[5]); ++ rc = -ENOTSUP; ++ goto open_error; ++ } ++ break; ++ ++ case 0x0: /* MF SD mode */ ++ case 0x500: ++ case 0x600: ++ proto_offset = 0x24 + (bp->func * 0x18); ++ ovtag_offset = proto_offset + 0xc; ++ ++ rc = -ENOTSUP; ++ val = bnx2x_rd32(bp, mf_cfg_addr + ovtag_offset); ++ val &= 0xffff; ++ /* SD mode, check for valid outer VLAN */ ++ if (val == 0xffff) { ++ LOG_ERR(PFX "%s: Invalid OV detected for SD, " ++ " fallback to SF mode!\n", ++ nic->log_name); ++ goto SF; ++ } ++ /* Check for iSCSI protocol */ ++ val = bnx2x_rd32(bp, mf_cfg_addr + proto_offset); ++ if ((val & 6) != 6) ++ goto open_error; ++ ++ mac_offset = proto_offset + 0x4; ++ val = bnx2x_rd32(bp, mf_cfg_addr + mac_offset); ++ mac[0] = (__u8) (val >> 8); ++ mac[1] = (__u8) val; ++ mac_offset += 4; ++ val = bnx2x_rd32(bp, mf_cfg_addr + mac_offset); ++ mac[2] = (__u8) (val >> 24); ++ mac[3] = (__u8) (val >> 16); ++ mac[4] = (__u8) (val >> 8); ++ mac[5] = (__u8) val; ++ memcpy(nic->mac_addr, mac, 6); ++ break; ++ } ++ } ++SF: ++ LOG_INFO(PFX "%s: Using mac address: %02x:%02x:%02x:%02x:%02x:%02x", ++ nic->log_name, ++ nic->mac_addr[0], nic->mac_addr[1], nic->mac_addr[2], ++ nic->mac_addr[3], nic->mac_addr[4], nic->mac_addr[5]); ++ ++ /* Determine if Hardware VLAN tag stripping is enabled or not */ ++ if (CNIC_VLAN_STRIPPING_ENABLED == bnx2x_strip_vlan_enabled(bp)) ++ nic->flags |= NIC_VLAN_STRIP_ENABLED; ++ ++ msync(bp->reg, BNX2X_BAR_SIZE, MS_SYNC); ++ ++ LOG_INFO("%s: bnx2x initialized", nic->log_name); ++ ++ bnx2x_update_rx_prod(bp); ++ bp->flags |= BNX2X_OPENED; ++ ++ return 0; ++ ++open_error: ++ if (bp->tx_ring) { ++ munmap(bp->tx_ring, 4 * nic->page_size); ++ bp->tx_ring = NULL; ++ } ++ ++ if (bp->status_blk.def) { ++ munmap(bp->status_blk.def, bp->status_blk_size); ++ bp->status_blk.def = NULL; ++ } ++ ++ if (bp->reg) { ++ munmap(bp->reg, BNX2X_BAR_SIZE); ++ bp->reg = NULL; ++ } ++ ++ if (bp->reg2) { ++ munmap(bp->reg2, BNX2X_BAR2_SIZE); ++ bp->reg2 = NULL; ++ } ++ ++ if (bp->rx_pkt_ring) { ++ free(bp->rx_pkt_ring); ++ bp->rx_pkt_ring = NULL; ++ } ++ ++ if (bp->bar2_fd != INVALID_FD) { ++ close(bp->bar2_fd); ++ bp->bar2_fd = INVALID_FD; ++ } ++ ++ if (bp->bar0_fd != INVALID_FD) { ++ close(bp->bar0_fd); ++ bp->bar0_fd = INVALID_FD; ++ } ++ if (nic->fd != INVALID_FD) { ++ close(nic->fd); ++ nic->fd = INVALID_FD; ++ } ++ bnx2x_free(nic); ++ ++ return rc; ++} ++ ++/** ++ * bnx2x_uio_close_resources() - Used to free resource for the NIC/CNIC ++ * @param nic - NIC device to free resource ++ * @param graceful - whether to wait to close gracefully ++ * @return 0 on success, <0 on failure ++ */ ++static int bnx2x_uio_close_resources(nic_t *nic, NIC_SHUTDOWN_T graceful) ++{ ++ bnx2x_t *bp = (bnx2x_t *) nic->priv; ++ int rc = 0; ++ ++ /* Check if there is an assoicated bnx2x device */ ++ if (bp == NULL) { ++ LOG_WARN(PFX "%s: when closing resources there is " ++ "no assoicated bnx2x", nic->log_name); ++ return -EIO; ++ } ++ ++ /* Clean up allocated memory */ ++ ++ if (bp->rx_pkt_ring != NULL) { ++ free(bp->rx_pkt_ring); ++ bp->rx_pkt_ring = NULL; ++ } ++ ++ /* Clean up mapped registers */ ++ if (bp->bufs != NULL) { ++ rc = munmap(bp->bufs, ++ (bp->rx_ring_size + 1) * bp->rx_buffer_size); ++ if (rc != 0) ++ LOG_WARN(PFX "%s: Couldn't unmap bufs", nic->log_name); ++ bp->bufs = NULL; ++ } ++ ++ if (bp->tx_ring != NULL) { ++ rc = munmap(bp->tx_ring, 4 * nic->page_size); ++ if (rc != 0) ++ LOG_WARN(PFX "%s: Couldn't unmap tx_rings", ++ nic->log_name); ++ bp->tx_ring = NULL; ++ } ++ ++ if (bp->status_blk.def != NULL) { ++ rc = munmap(bp->status_blk.def, bp->status_blk_size); ++ if (rc != 0) ++ LOG_WARN(PFX "%s: Couldn't unmap status block", ++ nic->log_name); ++ bp->status_blk.def = NULL; ++ } ++ ++ if (bp->reg != NULL) { ++ rc = munmap(bp->reg, BNX2X_BAR_SIZE); ++ if (rc != 0) ++ LOG_WARN(PFX "%s: Couldn't unmap regs", nic->log_name); ++ bp->reg = NULL; ++ } ++ ++ if (bp->reg2 != NULL) { ++ rc = munmap(bp->reg2, BNX2X_BAR2_SIZE); ++ if (rc != 0) ++ LOG_WARN(PFX "%s: Couldn't unmap regs", nic->log_name); ++ bp->reg2 = NULL; ++ } ++ ++ if (bp->bar2_fd != INVALID_FD) { ++ close(bp->bar2_fd); ++ bp->bar2_fd = INVALID_FD; ++ } ++ ++ if (bp->bar0_fd != INVALID_FD) { ++ close(bp->bar0_fd); ++ bp->bar0_fd = INVALID_FD; ++ } ++ ++ if (nic->fd != INVALID_FD) { ++ rc = close(nic->fd); ++ if (rc != 0) { ++ LOG_WARN(PFX ++ "%s: Couldn't close uio file descriptor: %d", ++ nic->log_name, nic->fd); ++ } else { ++ LOG_DEBUG(PFX "%s: Closed uio file descriptor: %d", ++ nic->log_name, nic->fd); ++ } ++ ++ nic->fd = INVALID_FD; ++ } else { ++ LOG_WARN(PFX "%s: Invalid uio file descriptor: %d", ++ nic->log_name, nic->fd); ++ } ++ ++ bnx2x_set_drv_version_unknown(bp); ++ ++ LOG_INFO(PFX "%s: Closed all resources", nic->log_name); ++ ++ return 0; ++} ++ ++/** ++ * bnx2x_close() - Used to close the NIC device ++ * @param nic - NIC device to close ++ * @param graceful - whether to wait to close gracefully ++ * @return 0 if successful, <0 if there is an error ++ */ ++static int bnx2x_close(nic_t *nic, NIC_SHUTDOWN_T graceful) ++{ ++ /* Sanity Check: validate the parameters */ ++ if (nic == NULL) { ++ LOG_ERR(PFX "bnx2x_close(): nic == NULL"); ++ return -EINVAL; ++ } ++ if (nic->priv == NULL) { ++ LOG_ERR(PFX "bnx2x_close(): nic->priv == NULL"); ++ return -EINVAL; ++ } ++ ++ LOG_INFO(PFX "Closing NIC device: %s", nic->log_name); ++ ++ bnx2x_uio_close_resources(nic, graceful); ++ bnx2x_free(nic); ++ ++ return 0; ++} ++ ++static void bnx2x_prepare_xmit_packet(nic_t *nic, ++ nic_interface_t *nic_iface, ++ struct packet *pkt) ++{ ++ bnx2x_t *bp = (bnx2x_t *) nic->priv; ++ struct uip_vlan_eth_hdr *eth_vlan = (struct uip_vlan_eth_hdr *)pkt->buf; ++ struct uip_eth_hdr *eth = (struct uip_eth_hdr *)bp->tx_pkt; ++ ++ if (eth_vlan->tpid == htons(UIP_ETHTYPE_8021Q)) { ++ memcpy(bp->tx_pkt, pkt->buf, sizeof(struct uip_eth_hdr)); ++ eth->type = eth_vlan->type; ++ pkt->buf_size -= (sizeof(struct uip_vlan_eth_hdr) - ++ sizeof(struct uip_eth_hdr)); ++ memcpy(bp->tx_pkt + sizeof(struct uip_eth_hdr), ++ pkt->buf + sizeof(struct uip_vlan_eth_hdr), ++ pkt->buf_size - sizeof(struct uip_eth_hdr)); ++ } else ++ memcpy(bp->tx_pkt, pkt->buf, pkt->buf_size); ++ ++ msync(bp->tx_pkt, pkt->buf_size, MS_SYNC); ++} ++ ++/** ++ * bnx2x_get_tx_pkt() - This function is used to a TX packet from the NIC ++ * @param nic - The NIC device to send the packet ++ */ ++void *bnx2x_get_tx_pkt(nic_t *nic) ++{ ++ bnx2x_t *bp = (bnx2x_t *) nic->priv; ++ return bp->tx_pkt; ++} ++ ++/** ++ * bnx2x_start_xmit() - This function is used to send a packet of data ++ * @param nic - The NIC device to send the packet ++ * @param len - the length of the TX packet ++ * ++ */ ++void bnx2x_start_xmit(nic_t *nic, size_t len, u16_t vlan_id) ++{ ++ bnx2x_t *bp = (bnx2x_t *) nic->priv; ++ uint16_t ring_prod; ++ struct eth_tx_start_bd *txbd; ++ struct eth_tx_bd *txbd2; ++ struct eth_rx_bd *rx_bd; ++ rx_bd = (struct eth_rx_bd *)(((__u8 *) bp->tx_ring) + nic->page_size); ++ ++ if ((rx_bd->addr_hi == 0) && (rx_bd->addr_lo == 0)) { ++ LOG_PACKET(PFX "%s: trying to transmit when device is closed", ++ nic->log_name); ++ pthread_mutex_unlock(&nic->xmit_mutex); ++ return; ++ } ++ ++ ring_prod = BNX2X_TX_RING_IDX(bp->tx_bd_prod); ++ txbd = &bp->tx_ring[ring_prod]; ++ ++ BNX2X_SET_TX_VLAN(bp, txbd, vlan_id); ++ ++ bp->tx_prod++; ++ bp->tx_bd_prod = BNX2X_NEXT_TX_BD(bp->tx_bd_prod); ++ bp->tx_bd_prod = BNX2X_NEXT_TX_BD(bp->tx_bd_prod); ++ ++ ring_prod = BNX2X_TX_RING_IDX(bp->tx_bd_prod); ++ txbd2 = (struct eth_tx_bd *)&bp->tx_ring[ring_prod]; ++ ++ txbd2->nbytes = len - 0x10; ++ txbd2->total_pkt_bytes = len; ++ ++ bp->tx_bd_prod = BNX2X_NEXT_TX_BD(bp->tx_bd_prod); ++ ++ barrier(); ++ if (nic->nl_process_if_down == 0) { ++ bnx2x_doorbell(bp, bp->tx_doorbell, 0x02 | ++ (bp->tx_bd_prod << 16)); ++ bnx2x_flush_doorbell(bp, bp->tx_doorbell); ++ } else { ++ /* If the doorbell is not rung, the packet will not ++ get sent. Hence, the xmit_mutex lock will not ++ get freed. ++ */ ++ pthread_mutex_unlock(&nic->xmit_mutex); ++ } ++ LOG_PACKET(PFX "%s: sent %d bytes using bp->tx_prod: %d", ++ nic->log_name, len, bp->tx_prod); ++} ++ ++/** ++ * bnx2x_write() - Used to write the data to the hardware ++ * @param nic - NIC hardware to read from ++ * @param pkt - The packet which will hold the data to be sent on the wire ++ * @return 0 if successful, <0 if failed ++ */ ++int bnx2x_write(nic_t *nic, nic_interface_t *nic_iface, packet_t *pkt) ++{ ++ bnx2x_t *bp; ++ struct uip_stack *uip; ++ int i = 0; ++ ++ /* Sanity Check: validate the parameters */ ++ if (nic == NULL || nic_iface == NULL || pkt == NULL) { ++ LOG_ERR(PFX "%s: bnx2x_write() nic == 0x%p || " ++ " nic_iface == 0x%p || " ++ " pkt == 0x%x", nic, nic_iface, pkt); ++ return -EINVAL; ++ } ++ bp = (bnx2x_t *) nic->priv; ++ uip = &nic_iface->ustack; ++ ++ if (pkt->buf_size == 0) { ++ LOG_ERR(PFX "%s: Trying to transmitted 0 sized packet", ++ nic->log_name); ++ return -EINVAL; ++ } ++ ++ /* Try to wait for a TX completion */ ++ for (i = 0; i < 15; i++) { ++ struct timespec sleep_req = {.tv_sec = 0, .tv_nsec = 5000000 }, ++ sleep_rem; ++ ++ if (bnx2x_clear_tx_intr(nic) == 0) ++ break; ++ ++ nanosleep(&sleep_req, &sleep_rem); ++ } ++ ++ if (pthread_mutex_trylock(&nic->xmit_mutex) != 0) { ++ LOG_PACKET(PFX "%s: Dropped previous transmitted packet", ++ nic->log_name); ++ return -EINVAL; ++ } ++ ++ bnx2x_prepare_xmit_packet(nic, nic_iface, pkt); ++ bnx2x_start_xmit(nic, pkt->buf_size, ++ (nic_iface->vlan_priority << 12) | ++ nic_iface->vlan_id); ++ ++ /* bump the cnic dev send statistics */ ++ nic->stats.tx.packets++; ++ nic->stats.tx.bytes += uip->uip_len; ++ ++ LOG_PACKET(PFX "%s: transmitted %d bytes " ++ "dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bd_prod:%d", ++ nic->log_name, pkt->buf_size, ++ bp->tx_cons, bp->tx_prod, bp->tx_bd_prod); ++ ++ return 0; ++} ++ ++static inline int bnx2x_get_rx_pad(bnx2x_t *bp, union eth_rx_cqe *cqe) ++{ ++ int pad = 0; ++ ++ if (bnx2x_is_ver70(bp)) ++ pad = ((union eth_rx_cqe_70 *)cqe)->fast_path_cqe_70. \ ++ placement_offset; ++ else if (bnx2x_is_ver60(bp)) { ++ if (bp->version.minor >= 64) ++ pad = cqe->fast_path_cqe_64.placement_offset; ++ else ++ pad = cqe->fast_path_cqe.placement_offset; ++ } ++ return pad; ++} ++ ++/** ++ * bnx2x_read() - Used to read the data from the hardware ++ * @param nic - NIC hardware to read from ++ * @param pkt - The packet which will hold the data ++ * @return 0 if successful, <0 if failed ++ */ ++static int bnx2x_read(nic_t *nic, packet_t *pkt) ++{ ++ bnx2x_t *bp; ++ int rc = 0; ++ uint16_t hw_cons, sw_cons, bd_cons, bd_prod; ++ ++ /* Sanity Check: validate the parameters */ ++ if (nic == NULL || pkt == NULL) { ++ LOG_ERR(PFX "%s: bnx2x_read() nic == 0x%p || " ++ " pkt == 0x%x", nic, pkt); ++ return -EINVAL; ++ } ++ bp = (bnx2x_t *) nic->priv; ++ ++ hw_cons = bp->get_rx_cons(bp); ++ sw_cons = bp->rx_cons; ++ bd_cons = BNX2X_RX_BD(bp->rx_bd_cons); ++ bd_prod = BNX2X_RX_BD(bp->rx_bd_prod); ++ ++ if (sw_cons != hw_cons) { ++ uint16_t comp_ring_index = sw_cons & BNX2X_MAX_RCQ_DESC_CNT(bp); ++ uint8_t ring_index; ++ union eth_rx_cqe *cqe; ++ __u8 cqe_fp_flags; ++ void *rx_pkt; ++ int len, pad, cqe_size, max_len; ++ rc = 1; ++ ++ if (bnx2x_is_ver70(bp)) { ++ cqe = (union eth_rx_cqe *) ++ &bp->rx_comp_ring.cqe70[comp_ring_index]; ++ cqe_size = sizeof(union eth_rx_cqe_70); ++ } else { ++ cqe = &bp->rx_comp_ring.cqe[comp_ring_index]; ++ cqe_size = sizeof(union eth_rx_cqe); ++ } ++ cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; ++ ++ LOG_PACKET(PFX "%s: clearing rx interrupt: %d %d", ++ nic->log_name, sw_cons, hw_cons); ++ ++ msync(cqe, cqe_size, MS_SYNC); ++ ++ if (!(cqe_fp_flags & ETH_FAST_PATH_RX_CQE_TYPE)) { ++ ring_index = bd_cons % 15; ++ len = cqe->fast_path_cqe.pkt_len; ++ pad = bnx2x_get_rx_pad(bp, cqe); ++ rx_pkt = bp->rx_pkt_ring[ring_index] + pad; ++ ++ /* Doto query MTU size of physical device */ ++ /* Ensure len is valid */ ++ max_len = pkt->max_buf_size < bp->rx_buffer_size ? ++ pkt->max_buf_size : bp->rx_buffer_size; ++ if (len + pad > max_len) { ++ LOG_DEBUG(PFX "%s: bad BD length: %d", ++ nic->log_name, len); ++ len = max_len - pad; ++ } ++ if (len > 0) { ++ msync(rx_pkt, len, MS_SYNC); ++ /* Copy the data */ ++ memcpy(pkt->buf, rx_pkt, len); ++ pkt->buf_size = len; ++ ++ /* Properly set the packet flags */ ++ /* check if there is VLAN tagging */ ++ if (cqe->fast_path_cqe.vlan_tag != 0) { ++ pkt->vlan_tag = ++ cqe->fast_path_cqe.vlan_tag; ++ pkt->flags |= VLAN_TAGGED; ++ } else { ++ pkt->vlan_tag = 0; ++ } ++ ++ LOG_PACKET(PFX ++ "%s: processing packet length: %d", ++ nic->log_name, len); ++ ++ /* bump the cnic dev recv statistics */ ++ nic->stats.rx.packets++; ++ nic->stats.rx.bytes += pkt->buf_size; ++ } ++ ++ bd_cons = BNX2X_NEXT_RX_IDX(bd_cons); ++ bd_prod = BNX2X_NEXT_RX_IDX(bd_prod); ++ ++ } ++ sw_cons = BNX2X_NEXT_RCQ_IDX(bp, sw_cons); ++ bp->rx_prod = BNX2X_NEXT_RCQ_IDX(bp, bp->rx_prod); ++ } ++ bp->rx_cons = sw_cons; ++ bp->rx_bd_cons = bd_cons; ++ bp->rx_bd_prod = bd_prod; ++ bp->rx_hw_prod = hw_cons; ++ ++ if (rc) ++ bnx2x_update_rx_prod(bp); ++ ++ return rc; ++} ++ ++/******************************************************************************* ++ * Clearing TX interrupts ++ ******************************************************************************/ ++/** ++ * bnx2x_clear_tx_intr() - This routine is called when a TX interrupt occurs ++ * @param nic - the nic the interrupt occured on ++ * @return 0 on success ++ */ ++static int bnx2x_clear_tx_intr(nic_t *nic) ++{ ++ bnx2x_t *bp; ++ uint16_t hw_cons; ++ ++ /* Sanity check: ensure the parameters passed in are valid */ ++ if (unlikely(nic == NULL)) { ++ LOG_ERR(PFX "bnx2x_read() nic == NULL"); ++ return -EINVAL; ++ } ++ bp = (bnx2x_t *) nic->priv; ++ hw_cons = bp->get_tx_cons(bp); ++ ++ if (bp->tx_cons == hw_cons) { ++ if (bp->tx_cons == bp->tx_prod) { ++ /* Make sure the xmit_mutex lock is unlock */ ++ if (pthread_mutex_trylock(&nic->xmit_mutex)) ++ LOG_ERR(PFX "bnx2x tx lock with prod == cons"); ++ ++ pthread_mutex_unlock(&nic->xmit_mutex); ++ return 0; ++ } ++ return -EAGAIN; ++ } ++ ++ LOG_PACKET(PFX "%s: clearing tx interrupt [%d %d]", ++ nic->log_name, bp->tx_cons, hw_cons); ++ bp->tx_cons = hw_cons; ++ ++ /* There is a queued TX packet that needs to be sent out. The usual ++ * case is when stack will send an ARP packet out before sending the ++ * intended packet */ ++ if (nic->tx_packet_queue != NULL) { ++ packet_t *pkt; ++ int i; ++ ++ LOG_PACKET(PFX "%s: sending queued tx packet", nic->log_name); ++ pkt = nic_dequeue_tx_packet(nic); ++ ++ /* Got a TX packet buffer of the TX queue and put it onto ++ * the hardware */ ++ if (pkt != NULL) { ++ bnx2x_prepare_xmit_packet(nic, pkt->nic_iface, pkt); ++ ++ bnx2x_start_xmit(nic, pkt->buf_size, ++ (pkt->nic_iface->vlan_priority << 12) | ++ pkt->nic_iface->vlan_id); ++ ++ LOG_PACKET(PFX "%s: transmitted queued packet %d bytes " ++ "dev->tx_cons: %d, dev->tx_prod: %d, " ++ "dev->tx_bd_prod:%d", ++ nic->log_name, pkt->buf_size, ++ bp->tx_cons, bp->tx_prod, bp->tx_bd_prod); ++ ++ return 0; ++ } ++ ++ /* Try to wait for a TX completion */ ++ for (i = 0; i < 15; i++) { ++ struct timespec sleep_req = {.tv_sec = 0, ++ .tv_nsec = 5000000 ++ }, sleep_rem; ++ ++ hw_cons = bp->get_tx_cons(bp); ++ if (bp->tx_cons != hw_cons) { ++ LOG_PACKET(PFX ++ "%s: clearing tx interrupt [%d %d]", ++ nic->log_name, bp->tx_cons, hw_cons); ++ bp->tx_cons = hw_cons; ++ ++ break; ++ } ++ ++ nanosleep(&sleep_req, &sleep_rem); ++ } ++ } ++ ++ pthread_mutex_unlock(&nic->xmit_mutex); ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * bnx2x NIC op's table ++ ******************************************************************************/ ++struct nic_ops bnx2x_op = { ++ .description = "bnx2x", ++ .open = bnx2x_open, ++ .close = bnx2x_close, ++ .write = bnx2x_write, ++ .get_tx_pkt = bnx2x_get_tx_pkt, ++ .start_xmit = bnx2x_start_xmit, ++ .read = bnx2x_read, ++ .clear_tx_intr = bnx2x_clear_tx_intr, ++ .handle_iscsi_path_req = cnic_handle_iscsi_path_req, ++ ++ .lib_ops = { ++ .get_library_name = bnx2x_get_library_name, ++ .get_pci_table = bnx2x_get_pci_table, ++ .get_library_version = bnx2x_get_library_version, ++ .get_build_date = bnx2x_get_build_date, ++ .get_transport_name = bnx2x_get_transport_name, ++ .get_uio_name = bnx2x_get_uio_name, ++ }, ++}; +diff --git a/iscsiuio/src/unix/libs/bnx2x.h b/iscsiuio/src/unix/libs/bnx2x.h +new file mode 100644 +index 0000000..ce55cfc +--- /dev/null ++++ b/iscsiuio/src/unix/libs/bnx2x.h +@@ -0,0 +1,712 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * bnx2x.h - bnx2x user space driver ++ * ++ */ ++#ifndef __BNX2X_H__ ++#define __BNX2X_H__ ++ ++#include "nic.h" ++ ++/****************************************************************************** ++ * Default CNIC values ++ ******************************************************************************/ ++#define DEFAULT_BNX2X_NUM_RXBD 15 ++#define DEFAULT_BNX2X_RX_LEN 0x400 ++ ++/****************************************************************************** ++ * BNX2X Hardware structures ++ ******************************************************************************/ ++#define HC_USTORM_DEF_SB_NUM_INDICES 8 ++#define HC_CSTORM_DEF_SB_NUM_INDICES 8 ++#define HC_XSTORM_DEF_SB_NUM_INDICES 4 ++#define HC_TSTORM_DEF_SB_NUM_INDICES 4 ++ ++struct atten_def_status_block { ++ volatile __u32 attn_bits; ++ volatile __u32 attn_bits_ack; ++ volatile __u8 status_block_id; ++ volatile __u8 reserved0; ++ volatile __u16 attn_bits_index; ++ volatile __u32 reserved1; ++}; ++ ++struct cstorm_def_status_block_u { ++ volatile __u16 index_values[HC_USTORM_DEF_SB_NUM_INDICES]; ++ volatile __u16 status_block_index; ++ volatile __u8 func; ++ volatile __u8 status_block_id; ++ volatile __u32 __flags; ++}; ++ ++struct cstorm_def_status_block_c { ++ volatile __u16 index_values[HC_CSTORM_DEF_SB_NUM_INDICES]; ++ volatile __u16 status_block_index; ++ volatile __u8 func; ++ volatile __u8 status_block_id; ++ volatile __u32 __flags; ++}; ++ ++struct xstorm_def_status_block { ++ volatile __u16 index_values[HC_XSTORM_DEF_SB_NUM_INDICES]; ++ volatile __u16 status_block_index; ++ volatile __u8 func; ++ volatile __u8 status_block_id; ++ volatile __u32 __flags; ++}; ++ ++struct tstorm_def_status_block { ++ volatile __u16 index_values[HC_TSTORM_DEF_SB_NUM_INDICES]; ++ volatile __u16 status_block_index; ++ volatile __u8 func; ++ volatile __u8 status_block_id; ++ volatile __u32 __flags; ++}; ++ ++struct host_def_status_block { ++ struct atten_def_status_block atten_status_block; ++ struct cstorm_def_status_block_u u_def_status_block; ++ struct cstorm_def_status_block_c c_def_status_block; ++ struct xstorm_def_status_block x_def_status_block; ++ struct tstorm_def_status_block t_def_status_block; ++}; ++ ++#define HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS 1 ++#define HC_INDEX_DEF_U_ETH_ISCSI_RX_BD_CONS 3 ++#define HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS 5 ++ ++struct atten_sp_status_block { ++ __u32 attn_bits; ++ __u32 attn_bits_ack; ++ __u8 status_block_id; ++ __u8 reserved0; ++ __u16 attn_bits_index; ++ __u32 reserved1; ++}; ++ ++#define HC_SP_SB_MAX_INDICES 16 ++ ++struct hc_sp_status_block { ++ __u16 index_values[HC_SP_SB_MAX_INDICES]; ++ __u16 running_index; ++ __u16 rsrv; ++ __u32 rsrv1; ++}; ++ ++struct host_sp_status_block { ++ struct atten_sp_status_block atten_status_block; ++ struct hc_sp_status_block sp_sb; ++}; ++ ++#define HC_SP_INDEX_ETH_ISCSI_CQ_CONS 5 ++#define HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS 1 ++ ++/* ++ * VLAN mode on TX BDs ++ */ ++enum eth_tx_vlan_type { ++ X_ETH_NO_VLAN = 0, ++ X_ETH_OUTBAND_VLAN = 1, ++ X_ETH_INBAND_VLAN = 2, ++ X_ETH_FW_ADDED_VLAN = 3, ++ MAX_ETH_TX_VLAN_TYPE ++}; ++ ++/* TX Buffer descriptor */ ++struct eth_tx_bd_flags { ++ __u8 as_bitfield; ++/* t6.X HSI */ ++#define ETH_TX_BD_FLAGS_IP_CSUM_T6X (0x1<<0) ++#define ETH_TX_BD_FLAGS_IP_CSUM_SHIFT_T6X 0 ++#define ETH_TX_BD_FLAGS_L4_CSUM_T6X (0x1<<1) ++#define ETH_TX_BD_FLAGS_L4_CSUM_SHIFT_T6X 1 ++#define ETH_TX_BD_FLAGS_VLAN_MODE_T6X (0x3<<2) ++#define ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT_T6X 2 ++#define ETH_TX_BD_FLAGS_START_BD_T6X (0x1<<4) ++#define ETH_TX_BD_FLAGS_START_BD_SHIFT_T6X 4 ++#define ETH_TX_BD_FLAGS_IS_UDP_T6X (0x1<<5) ++#define ETH_TX_BD_FLAGS_IS_UDP_SHIFT_T6X 5 ++#define ETH_TX_BD_FLAGS_SW_LSO_T6X (0x1<<6) ++#define ETH_TX_BD_FLAGS_SW_LSO_SHIFT_T6X 6 ++#define ETH_TX_BD_FLAGS_IPV6_T6X (0x1<<7) ++#define ETH_TX_BD_FLAGS_IPV6_SHIFT_T6X 7 ++ ++/* Legacy t5.2 HSI defines */ ++#define ETH_TX_BD_FLAGS_VLAN_TAG_T5X (0x1<<0) ++#define ETH_TX_BD_FLAGS_VLAN_TAG_SHIFT_T5X 0 ++#define ETH_TX_BD_FLAGS_IP_CSUM_T5X (0x1<<1) ++#define ETH_TX_BD_FLAGS_IP_CSUM_SHIFT_T5X 1 ++#define ETH_TX_BD_FLAGS_L4_CSUM_T5X (0x1<<2) ++#define ETH_TX_BD_FLAGS_L4_CSUM_SHIFT_T5X 2 ++#define ETH_TX_BD_FLAGS_END_BD_T5X (0x1<<3) ++#define ETH_TX_BD_FLAGS_END_BD_SHIFT_T5X 3 ++#define ETH_TX_BD_FLAGS_START_BD_T5X (0x1<<4) ++#define ETH_TX_BD_FLAGS_START_BD_SHIFT_T5X 4 ++#define ETH_TX_BD_FLAGS_HDR_POOL_T5X (0x1<<5) ++#define ETH_TX_BD_FLAGS_HDR_POOL_SHIFT_T5X 5 ++#define ETH_TX_BD_FLAGS_SW_LSO_T5X (0x1<<6) ++#define ETH_TX_BD_FLAGS_SW_LSO_SHIFT_T5X 6 ++#define ETH_TX_BD_FLAGS_IPV6_T5X (0x1<<7) ++#define ETH_TX_BD_FLAGS_IPV6_SHIFT_T5X 7 ++}; ++ ++#define ETH_TX_BD_FLAGS_VLAN_TAG_T6X \ ++ (X_ETH_OUTBAND_VLAN << ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT_T6X) ++ ++#define BNX2X_SET_TX_VLAN(bp, txbd, vlan_id) \ ++ do { \ ++ if (vlan_id) { \ ++ (txbd)->vlan = vlan_id; \ ++ (txbd)->bd_flags.as_bitfield |= \ ++ (bp)->tx_vlan_tag_bit; \ ++ } else { \ ++ (txbd)->vlan = (bp)->tx_prod; \ ++ (txbd)->bd_flags.as_bitfield &= \ ++ ~(bp)->tx_vlan_tag_bit; \ ++ } \ ++ } while (0) ++ ++struct eth_tx_start_bd { ++ __u32 addr_lo; ++ __u32 addr_hi; ++ __u16 nbd; ++ __u16 nbytes; ++ __u16 vlan; ++ struct eth_tx_bd_flags bd_flags; ++ __u8 general_data; ++#define ETH_TX_START_BD_HDR_NBDS (0x3F<<0) ++#define ETH_TX_START_BD_HDR_NBDS_SHIFT 0 ++#define ETH_TX_START_BD_ETH_ADDR_TYPE (0x3<<6) ++#define ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT 6 ++}; ++ ++struct eth_tx_bd { ++ __u32 addr_lo; ++ __u32 addr_hi; ++ __u16 total_pkt_bytes; ++ __u16 nbytes; ++ __u8 reserved[4]; ++}; ++ ++/* RX Buffer descriptor */ ++struct eth_rx_bd { ++ __u32 addr_lo; ++ __u32 addr_hi; ++}; ++ ++struct ramrod_data { ++ volatile __u32 data_lo; ++ volatile __u32 data_hi; ++}; ++ ++struct common_ramrod_eth_rx_cqe { ++ volatile __u8 ramrod_type; ++#define COMMON_RAMROD_ETH_RX_CQE_TYPE (0x1<<0) ++#define COMMON_RAMROD_ETH_RX_CQE_TYPE_SHIFT 0 ++#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0 (0x7F<<1) ++#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0_SHIFT 1 ++ volatile __u8 conn_type; ++ volatile __u16 reserved1; ++ volatile __u32 conn_and_cmd_data; ++#define COMMON_RAMROD_ETH_RX_CQE_CID (0xFFFFFF<<0) ++#define COMMON_RAMROD_ETH_RX_CQE_CID_SHIFT 0 ++#define COMMON_RAMROD_ETH_RX_CQE_CMD_ID (0xFF<<24) ++#define COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT 24 ++ struct ramrod_data protocol_data; ++ __u32 reserved2[4]; ++}; ++ ++struct common_ramrod_eth_rx_cqe_70 { ++ volatile __u8 ramrod_type; ++ volatile __u8 conn_type; ++ volatile __u16 reserved1; ++ volatile __u32 conn_and_cmd_data; ++ struct ramrod_data protocol_data; ++ __u32 echo; ++ __u32 reserved2[11]; ++}; ++ ++struct parsing_flags { ++ volatile __u16 flags; ++}; ++ ++struct eth_fast_path_rx_cqe { ++ volatile __u8 type_error_flags; ++#define ETH_FAST_PATH_RX_CQE_TYPE (0x1<<0) ++#define ETH_FAST_PATH_RX_CQE_TYPE_SHIFT 0 ++#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG (0x1<<1) ++#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG_SHIFT 1 ++#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG (0x1<<2) ++#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_SHIFT 2 ++#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG (0x1<<3) ++#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_SHIFT 3 ++#define ETH_FAST_PATH_RX_CQE_START_FLG (0x1<<4) ++#define ETH_FAST_PATH_RX_CQE_START_FLG_SHIFT 4 ++#define ETH_FAST_PATH_RX_CQE_END_FLG (0x1<<5) ++#define ETH_FAST_PATH_RX_CQE_END_FLG_SHIFT 5 ++#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x3<<6) ++#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 6 ++ volatile __u8 status_flags; ++#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE (0x7<<0) ++#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE_SHIFT 0 ++#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG (0x1<<3) ++#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG_SHIFT 3 ++#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG (0x1<<4) ++#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG_SHIFT 4 ++#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG (0x1<<5) ++#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG_SHIFT 5 ++#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG (0x1<<6) ++#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG_SHIFT 6 ++#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG (0x1<<7) ++#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG_SHIFT 7 ++ volatile __u8 placement_offset; ++ volatile __u8 queue_index; ++ volatile __u32 rss_hash_result; ++ volatile __u16 vlan_tag; ++ volatile __u16 pkt_len; ++ volatile __u16 len_on_bd; ++ struct parsing_flags pars_flags; ++ volatile __u16 sgl[8]; ++}; ++ ++union eth_sgl_or_raw_data { ++ volatile __u16 sgl[8]; ++ volatile __u32 raw_data[4]; ++}; ++ ++struct eth_fast_path_rx_cqe_64 { ++ volatile __u8 type_error_flags; ++#define ETH_FAST_PATH_RX_CQE_TYPE_64 (0x3<<0) ++#define ETH_FAST_PATH_RX_CQE_TYPE_SHIFT_64 0 ++#define ETH_FAST_PATH_RX_CQE_SGL_RAW_SEL (0x1<<2) ++#define ETH_FAST_PATH_RX_CQE_SGL_RAW_SEL_SHIFT 2 ++#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG_64 (0x1<<3) ++#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG_SHIFT_64 3 ++#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_64 (0x1<<4) ++#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_SHIFT_64 4 ++#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_64 (0x1<<5) ++#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_SHIFT_64 5 ++#define ETH_FAST_PATH_RX_CQE_RESERVED0_64 (0x3<<6) ++#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT_64 6 ++ volatile __u8 status_flags; ++#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE (0x7<<0) ++#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE_SHIFT 0 ++#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG (0x1<<3) ++#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG_SHIFT 3 ++#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG (0x1<<4) ++#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG_SHIFT 4 ++#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG (0x1<<5) ++#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG_SHIFT 5 ++#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG (0x1<<6) ++#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG_SHIFT 6 ++#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG (0x1<<7) ++#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG_SHIFT 7 ++ volatile __u8 queue_index; ++ volatile __u8 placement_offset; ++ volatile __u32 rss_hash_result; ++ volatile __u16 vlan_tag; ++ volatile __u16 pkt_len; ++ volatile __u16 len_on_bd; ++ struct parsing_flags pars_flags; ++ union eth_sgl_or_raw_data sgl_or_raw_data; ++}; ++ ++struct eth_fast_path_rx_cqe_70 { ++ volatile __u8 type_error_flags; ++ volatile __u8 status_flags; ++ volatile __u8 queue_index; ++ volatile __u8 placement_offset; ++ volatile __u32 rss_hash_result; ++ volatile __u16 vlan_tag; ++ volatile __u16 pkt_len; ++ volatile __u16 len_on_bd; ++ struct parsing_flags pars_flags; ++ union eth_sgl_or_raw_data sgl_or_raw_data; ++ __u32 reserved1[8]; ++}; ++ ++struct eth_rx_cqe_next_page { ++ __u32 addr_lo; ++ __u32 addr_hi; ++ __u32 reserved[6]; ++}; ++ ++struct eth_rx_cqe_next_page_70 { ++ __u32 addr_lo; ++ __u32 addr_hi; ++ __u32 reserved[14]; ++}; ++ ++union eth_rx_cqe { ++ struct eth_fast_path_rx_cqe fast_path_cqe; ++ struct eth_fast_path_rx_cqe_64 fast_path_cqe_64; ++ struct common_ramrod_eth_rx_cqe ramrod_cqe; ++ struct eth_rx_cqe_next_page next_page_cqe; ++}; ++ ++union eth_rx_cqe_70 { ++ struct eth_fast_path_rx_cqe_70 fast_path_cqe_70; ++ struct common_ramrod_eth_rx_cqe_70 ramrod_cqe_70; ++ struct eth_rx_cqe_next_page_70 next_page_cqe_70; ++}; ++ ++struct uio_init_data { ++ __u32 cid; ++ __u32 tx_db_off; ++ __u32 cid_override_key; ++#define UIO_USE_TX_DOORBELL 0x017855DB ++}; ++ ++struct client_init_general_data { ++ __u8 client_id; ++ __u8 statistics_counter_id; ++ __u8 statistics_en_flg; ++ __u8 is_fcoe_flg; ++ __u8 activate_flg; ++ __u8 sp_client_id; ++ __u16 mtu; ++ __u8 statistics_zero_flg; ++ __u8 func_id; ++ __u8 cos; ++ __u8 traffic_type; ++ struct uio_init_data uid; ++}; ++ ++/****************************************************************************** ++ * BNX2X Registers and HSI ++ ******************************************************************************/ ++#define BNX2X_BAR_SIZE 0x500000 ++#define BNX2X_BAR2_SIZE 0x12000 ++ ++#define BNX2X_CHIP_ID(bp) (bp->chip_id & 0xfffffff0) ++ ++#define PORT_MAX 2 ++ ++/* [R 4] This field indicates the type of the device. '0' - 2 Ports; '1' - 1 ++ * Port. */ ++#define BNX2X_MISC_REG_BOND_ID 0xa400 ++/* [R 8] These bits indicate the metal revision of the chip. This value ++ * starts at 0x00 for each all-layer tape-out and increments by one for each ++ * tape-out. */ ++#define BNX2X_MISC_REG_CHIP_METAL 0xa404 ++/* [R 16] These bits indicate the part number for the chip. */ ++#define BNX2X_MISC_REG_CHIP_NUM 0xa408 ++/* [R 4] These bits indicate the base revision of the chip. This value ++ * starts at 0x0 for the A0 tape-out and increments by one for each ++ * all-layer tape-out. */ ++#define BNX2X_MISC_REG_CHIP_REV 0xa40c ++ ++/* From the bnx2x driver */ ++#define CHIP_NUM(bp) (bp->chip_id >> 16) ++#define CHIP_NUM_57710 0x164e ++#define CHIP_NUM_57711 0x164f ++#define CHIP_NUM_57711E 0x1650 ++#define CHIP_NUM_57712 0x1662 ++#define CHIP_NUM_57712_MF 0x1663 ++#define CHIP_NUM_57712_VF 0x166f ++#define CHIP_NUM_57713 0x1651 ++#define CHIP_NUM_57713E 0x1652 ++#define CHIP_NUM_57800 0x168a ++#define CHIP_NUM_57800_MF 0x16a5 ++#define CHIP_NUM_57800_VF 0x16a9 ++#define CHIP_NUM_57810 0x168e ++#define CHIP_NUM_57810_MF 0x16ae ++#define CHIP_NUM_57810_VF 0x16af ++#define CHIP_NUM_57811 0x163d ++#define CHIP_NUM_57811_MF 0x163e ++#define CHIP_NUM_57811_VF 0x163f ++#define CHIP_NUM_57840_OBSOLETE 0x168d ++#define CHIP_NUM_57840_MF_OBSOLETE 0x16ab ++#define CHIP_NUM_57840_4_10 0x16a1 ++#define CHIP_NUM_57840_2_20 0x16a2 ++#define CHIP_NUM_57840_MF 0x16a4 ++#define CHIP_NUM_57840_VF 0x16ad ++ ++#define CHIP_IS_E1(bp) (CHIP_NUM(bp) == CHIP_NUM_57710) ++#define CHIP_IS_57711(bp) (CHIP_NUM(bp) == CHIP_NUM_57711) ++#define CHIP_IS_57711E(bp) (CHIP_NUM(bp) == CHIP_NUM_57711E) ++#define CHIP_IS_57712(bp) (CHIP_NUM(bp) == CHIP_NUM_57712) ++#define CHIP_IS_57712_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57712_VF) ++#define CHIP_IS_57712_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57712_MF) ++#define CHIP_IS_57800(bp) (CHIP_NUM(bp) == CHIP_NUM_57800) ++#define CHIP_IS_57800_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57800_MF) ++#define CHIP_IS_57800_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57800_VF) ++#define CHIP_IS_57810(bp) (CHIP_NUM(bp) == CHIP_NUM_57810) ++#define CHIP_IS_57810_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57810_MF) ++#define CHIP_IS_57810_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57810_VF) ++#define CHIP_IS_57811(bp) (CHIP_NUM(bp) == CHIP_NUM_57811) ++#define CHIP_IS_57811_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57811_MF) ++#define CHIP_IS_57811_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57811_VF) ++ ++#define CHIP_IS_57840(bp) \ ++ ((CHIP_NUM(bp) == CHIP_NUM_57840_4_10) || \ ++ (CHIP_NUM(bp) == CHIP_NUM_57840_2_20) || \ ++ (CHIP_NUM(bp) == CHIP_NUM_57840_OBSOLETE)) ++#define CHIP_IS_57840_MF(bp) ((CHIP_NUM(bp) == CHIP_NUM_57840_MF) || \ ++ (CHIP_NUM(bp) == CHIP_NUM_57840_MF_OBSOLETE)) ++#define CHIP_IS_57840_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57840_VF) ++#define CHIP_IS_E1H(bp) (CHIP_IS_57711(bp) || \ ++ CHIP_IS_57711E(bp)) ++ ++#define CHIP_IS_E2(bp) (CHIP_IS_57712(bp) || \ ++ CHIP_IS_57712_MF(bp) || \ ++ CHIP_IS_57712_VF(bp)) ++#define CHIP_IS_E3(bp) (CHIP_IS_57800(bp) || \ ++ CHIP_IS_57800_MF(bp) || \ ++ CHIP_IS_57800_VF(bp) || \ ++ CHIP_IS_57810(bp) || \ ++ CHIP_IS_57810_MF(bp) || \ ++ CHIP_IS_57810_VF(bp) || \ ++ CHIP_IS_57840(bp) || \ ++ CHIP_IS_57840_MF(bp) || \ ++ CHIP_IS_57840_VF(bp) || \ ++ CHIP_IS_57811(bp) || \ ++ CHIP_IS_57811_MF(bp) || \ ++ CHIP_IS_57811_VF(bp)) ++ ++#define CHIP_IS_E1x(bp) (CHIP_IS_E1((bp)) || CHIP_IS_E1H((bp))) ++#define USES_WARPCORE(bp) (CHIP_IS_E3(bp)) ++#define IS_E1H_OFFSET (!CHIP_IS_E1H(bp)) ++/* End of From the bnx2x driver */ ++ ++#define CHIP_IS_E2_PLUS(bp) (CHIP_IS_E2(bp) || CHIP_IS_E3(bp)) ++ ++#define MISC_REG_SHARED_MEM_ADDR 0xa2b4 ++ ++#define MISC_REG_BOND_ID 0xa400 ++#define MISC_REG_CHIP_METAL 0xa404 ++#define MISC_REG_CHIP_NUM 0xa408 ++#define MISC_REG_CHIP_REV 0xa40c ++ ++#define MISC_REG_PORT4MODE_EN 0xa750 ++#define MISC_REG_PORT4MODE_EN_OVWR 0xa720 ++ ++#define MISC_REG_GENERIC_CR_0 0xa460 ++#define MISC_REG_GENERIC_CR_1 0xa464 ++ ++#define BAR_USTRORM_INTMEM 0x400000 ++#define BAR_CSTRORM_INTMEM 0x410000 ++#define BAR_XSTRORM_INTMEM 0x420000 ++#define BAR_TSTRORM_INTMEM 0x430000 ++ ++#define BAR_ME_REGISTER 0x450000 ++#define ME_REG_PF_NUM_SHIFT 0 ++#define ME_REG_PF_NUM\ ++ (7L<iro[bp->iro_idx]) ++ ++#define USTORM_RX_PRODS_E1X_OFFSET(port, client_id) \ ++ (IRO_ENT.base + ((port) * IRO_ENT.m1) + ((client_id) * IRO_ENT.m2)) ++ ++#define USTORM_RX_PRODS_E2_OFFSET(qzone_id) \ ++ (IRO_ENT.base + ((qzone_id) * IRO_ENT.m1)) ++ ++#define ETH_MAX_RX_CLIENTS_E1H 28 ++#define ETH_MAX_RX_CLIENTS_E2 28 ++ ++#define BNX2X_CL_QZONE_ID(bp, cli) \ ++ (cli + (bp->port * (CHIP_IS_E2(bp) ? \ ++ ETH_MAX_RX_CLIENTS_E2 : \ ++ ETH_MAX_RX_CLIENTS_E1H))) ++ ++#define BNX2X_CL_QZONE_ID_64(bp, cli) \ ++ (CHIP_IS_E2_PLUS(bp) ? (cli) : \ ++ (cli + (bp->port * ETH_MAX_RX_CLIENTS_E1H))) ++ ++#define BNX2X_PATH(bp) (!CHIP_IS_E2_PLUS(bp) ? 0 : (bp)->func & 1) ++ ++#define SHMEM_P0_ISCSI_MAC_UPPER 0x4c ++#define SHMEM_P0_ISCSI_MAC_LOWER 0x50 ++#define SHMEM_P1_ISCSI_MAC_UPPER 0x1dc ++#define SHMEM_P1_ISCSI_MAC_LOWER 0x1e0 ++ ++#define SHMEM_ISCSI_MAC_UPPER(bp) \ ++ (((bp)->port == 0) ? \ ++ SHMEM_P0_ISCSI_MAC_UPPER : SHMEM_P1_ISCSI_MAC_UPPER) ++ ++#define SHMEM_ISCSI_MAC_LOWER(bp) \ ++ (((bp)->port == 0) ? \ ++ SHMEM_P0_ISCSI_MAC_LOWER : SHMEM_P1_ISCSI_MAC_LOWER) ++ ++#define BNX2X_RCQ_DESC_CNT (4096 / sizeof(union eth_rx_cqe)) ++#define BNX2X_RCQ_DESC_CNT_70 (4096 / sizeof(union eth_rx_cqe_70)) ++#define BNX2X_MAX_RCQ_DESC_CNT(bp) \ ++ ((bnx2x_is_ver70(bp) ? BNX2X_RCQ_DESC_CNT_70 : BNX2X_RCQ_DESC_CNT) - 1) ++ ++#define BNX2X_RX_DESC_CNT (4096 / sizeof(struct eth_rx_bd)) ++#define BNX2X_MAX_RX_DESC_CNT (BNX2X_RX_DESC_CNT - 2) ++#define BNX2X_NUM_RX_BD (BNX2X_RX_DESC_CNT * 1) ++#define BNX2X_MAX_RX_BD (BNX2X_NUM_RX_BD - 1) ++ ++#define BNX2X_TX_DESC_CNT (4096 / sizeof(struct eth_tx_start_bd)) ++#define BNX2X_MAX_TX_DESC_CNT (BNX2X_TX_DESC_CNT - 1) ++ ++#define BNX2X_NEXT_RX_IDX(x) ((((x) & (BNX2X_RX_DESC_CNT - 1)) == \ ++ (BNX2X_MAX_RX_DESC_CNT - 1)) ? \ ++ (x) + 3 : (x) + 1) ++ ++#define BNX2X_NEXT_RCQ_IDX(bp, x) \ ++ ((((x) & BNX2X_MAX_RCQ_DESC_CNT(bp)) == \ ++ (BNX2X_MAX_RCQ_DESC_CNT(bp) - 1)) ? (x) + 2 : (x) + 1) ++#define BNX2X_RX_BD(x) ((x) & BNX2X_MAX_RX_BD) ++ ++#define BNX2X_NEXT_TX_BD(x) ((((x) & (BNX2X_MAX_TX_DESC_CNT - 1)) == \ ++ (BNX2X_MAX_TX_DESC_CNT - 1)) ? \ ++ (x) + 2 : (x) + 1) ++ ++#define BNX2X_TX_RING_IDX(x) ((x) & BNX2X_MAX_TX_DESC_CNT) ++ ++struct ustorm_eth_rx_producers { ++ __u16 cqe_prod; ++ __u16 bd_prod; ++ __u16 sge_prod; ++ __u16 reserved; ++}; ++ ++#define BNX2X_UNKNOWN_MAJOR_VERSION -1 ++#define BNX2X_UNKNOWN_MINOR_VERSION -1 ++#define BNX2X_UNKNOWN_SUB_MINOR_VERSION -1 ++struct bnx2x_driver_version { ++ uint16_t major; ++ uint16_t minor; ++ uint16_t sub_minor; ++}; ++ ++typedef struct bnx2x { ++ nic_t *parent; ++ ++ struct bnx2x_driver_version version; ++ ++ uint16_t flags; ++#define CNIC_UIO_UNITIALIZED 0x0001 ++#define CNIC_UIO_INITIALIZED 0x0002 ++#define CNIC_UIO_ENABLED 0x0004 ++#define CNIC_UIO_DISABLED 0x0008 ++#define CNIC_UIO_IPv6_ENABLED 0x0010 ++#define CNIC_UIO_ADDED_MULICAST 0x0020 ++#define CNIC_UIO_MSIX_ENABLED 0x0200 ++#define CNIC_UIO_TX_HAS_SENT 0x0400 ++#define BNX2X_OPENED 0x0800 ++ ++ void *reg; /* Pointer to the BAR1 mapped registers */ ++ void *reg2; /* Pointer to the BAR2 mapped registers */ ++ ++ int bar0_fd; ++ int bar2_fd; ++ ++ __u32 chip_id; ++ __u32 shmem_base; ++ __u32 shmem_base2; ++ int func; ++ int port; ++ int pfid; ++ __u32 cid; ++ __u32 client_id; ++ ++ struct iro *iro; ++ int iro_idx; ++ ++ __u32 tx_doorbell; ++ ++ __u16 tx_prod; ++ __u16 tx_bd_prod; ++ __u16 tx_cons; ++ __u8 tx_vlan_tag_bit; ++ ++ __u32 rx_prod_io; ++ ++ __u16 rx_prod; ++ __u16 rx_bd_prod; ++ __u16 rx_cons; ++ __u16 rx_bd_cons; ++ __u16 rx_hw_prod; ++ ++ __u16(*get_rx_cons) (struct bnx2x *); ++ __u16(*get_tx_cons) (struct bnx2x *); ++ ++ /* RX ring parameters */ ++ uint32_t rx_ring_size; ++ uint32_t rx_buffer_size; ++ ++ void *bufs; /* Pointer to the mapped buffer space */ ++ ++ /* Hardware Status Block locations */ ++ void *sblk_map; ++ union { ++ struct host_def_status_block *def; ++ struct host_sp_status_block *sp; ++ } status_blk; ++ ++ int status_blk_size; ++ ++ uint16_t rx_index; ++ union { ++ union eth_rx_cqe *cqe; ++ union eth_rx_cqe_70 *cqe70; ++ } rx_comp_ring; ++ void **rx_pkt_ring; ++ ++ struct eth_tx_start_bd *tx_ring; ++ void *tx_pkt; ++ ++} bnx2x_t; ++ ++/****************************************************************************** ++ * bnx2x Function Declarations ++ ******************************************************************************/ ++void bnx2x_start_xmit(nic_t *nic, size_t len, u16_t vlan_id); ++ ++struct nic_ops *bnx2x_get_ops(); ++#endif /* __BNX2X_H__ */ +diff --git a/iscsiuio/src/unix/libs/cnic.c b/iscsiuio/src/unix/libs/cnic.c +new file mode 100644 +index 0000000..228c4b9 +--- /dev/null ++++ b/iscsiuio/src/unix/libs/cnic.c +@@ -0,0 +1,666 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * cnic.c - CNIC UIO uIP user space stack ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "uip_arp.h" ++#include "nic.h" ++#include "nic_utils.h" ++#include "logger.h" ++#include "options.h" ++ ++#include "cnic.h" ++#include "iscsi_if.h" ++#include "ipv6_ndpc.h" ++ ++/******************************************************************************* ++ * Constants ++ ******************************************************************************/ ++#define PFX "CNIC " ++ ++static const uip_ip6addr_t all_ones_addr6 = { ++ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }; ++ ++/******************************************************************************* ++ * Constants shared between the bnx2 and bnx2x modules ++ ******************************************************************************/ ++const char bnx2i_library_transport_name[] = "bnx2i"; ++const size_t bnx2i_library_transport_name_size = ++ sizeof(bnx2i_library_transport_name); ++ ++/****************************************************************************** ++ * Netlink Functions ++ ******************************************************************************/ ++ ++static int cnic_arp_send(nic_t *nic, nic_interface_t *nic_iface, int fd, ++ __u8 *mac_addr, __u32 ip_addr, char *addr_str) ++{ ++ struct ether_header *eth; ++ struct ether_arp *arp; ++ __u32 dst_ip = ip_addr; ++ int pkt_size = sizeof(*eth) + sizeof(*arp); ++ int rc; ++ struct in_addr addr; ++ static const uint8_t multicast_mac[] = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ++ ++ rc = pthread_mutex_trylock(&nic->xmit_mutex); ++ if (rc != 0) { ++ LOG_DEBUG(PFX "%s: could not get xmit_mutex", nic->log_name); ++ return -EAGAIN; ++ } ++ ++ eth = (*nic->ops->get_tx_pkt) (nic); ++ if (eth == NULL) { ++ LOG_WARN(PFX "%s: couldn't get tx packet", nic->log_name); ++ return -EAGAIN; ++ } ++ ++ nic_fill_ethernet_header(nic_iface, eth, ++ nic->mac_addr, (void *)multicast_mac, ++ &pkt_size, (void *)&arp, ETHERTYPE_ARP); ++ ++ arp->arp_hrd = htons(ARPHRD_ETHER); ++ arp->arp_pro = htons(ETHERTYPE_IP); ++ arp->arp_hln = ETH_ALEN; ++ arp->arp_pln = 4; ++ arp->arp_op = htons(ARPOP_REQUEST); ++ memcpy(arp->arp_sha, nic->mac_addr, ETH_ALEN); ++ memset(arp->arp_tha, 0, ETH_ALEN); ++ ++ /* Copy the IP address's into the ARP response */ ++ memcpy(arp->arp_spa, nic_iface->ustack.hostaddr, 4); ++ memcpy(arp->arp_tpa, &dst_ip, 4); ++ ++ (*nic->nic_library->ops->start_xmit) (nic, pkt_size, ++ (nic_iface->vlan_priority << 12) | ++ nic_iface->vlan_id); ++ ++ memcpy(&addr.s_addr, &dst_ip, sizeof(addr.s_addr)); ++ LOG_DEBUG(PFX "%s: Sent cnic arp request for IP: %s", ++ nic->log_name, addr_str); ++ ++ return 0; ++} ++ ++static int cnic_neigh_soliciation_send(nic_t *nic, ++ nic_interface_t *nic_iface, int fd, ++ __u8 *mac_addr, ++ struct in6_addr *addr6_dst, ++ char *addr_str) ++{ ++ struct ether_header *eth; ++ struct ip6_hdr *ipv6_hdr; ++ int rc, pkt_size; ++ char buf[INET6_ADDRSTRLEN]; ++ struct ndpc_reqptr req_ptr; ++ ++ rc = pthread_mutex_trylock(&nic->xmit_mutex); ++ if (rc != 0) { ++ LOG_WARN(PFX "%s: could not get xmit_mutex", nic->log_name); ++ return -EAGAIN; ++ } ++ ++ /* Build the ethernet header */ ++ eth = (*nic->ops->get_tx_pkt) (nic); ++ if (eth == NULL) { ++ LOG_WARN(PFX "%s: couldn't get tx packet", nic->log_name); ++ return -EAGAIN; ++ } ++ ++ /* Copy the requested target address to the ipv6.dst */ ++ ipv6_hdr = ++ (struct ip6_hdr *)((u8_t *) eth + sizeof(struct ether_header)); ++ ++ memcpy(ipv6_hdr->ip6_dst.s6_addr, addr6_dst->s6_addr, ++ sizeof(struct in6_addr)); ++ ++ nic_fill_ethernet_header(nic_iface, eth, nic->mac_addr, nic->mac_addr, ++ &pkt_size, (void *)&ipv6_hdr, ETHERTYPE_IPV6); ++ req_ptr.eth = (void *)eth; ++ req_ptr.ipv6 = (void *)ipv6_hdr; ++ if (ndpc_request(&nic_iface->ustack, &req_ptr, &pkt_size, ++ NEIGHBOR_SOLICIT)) ++ return -EAGAIN; ++ ++ /* Debug to print out the pkt context */ ++ inet_ntop(AF_INET6, ipv6_hdr->ip6_dst.s6_addr, buf, sizeof(buf)); ++ LOG_DEBUG(PFX "%s: ipv6 dst addr: %s", nic->log_name, buf); ++ LOG_DEBUG(PFX "neighbor sol content " ++ "dst mac %02x:%02x:%02x:%02x:%02x:%02x", ++ eth->ether_dhost[0], eth->ether_dhost[1], ++ eth->ether_dhost[2], eth->ether_dhost[3], ++ eth->ether_dhost[4], eth->ether_dhost[5]); ++ LOG_DEBUG(PFX "src mac %02x:%02x:%02x:%02x:%02x:%02x", ++ eth->ether_shost[0], eth->ether_shost[1], ++ eth->ether_shost[2], eth->ether_shost[3], ++ eth->ether_shost[4], eth->ether_shost[5]); ++ (*nic->nic_library->ops->start_xmit) (nic, pkt_size, ++ (nic_iface->vlan_priority << 12) | ++ nic_iface->vlan_id); ++ ++ LOG_DEBUG(PFX "%s: Sent cnic ICMPv6 neighbor request %s", ++ nic->log_name, addr_str); ++ ++ return 0; ++} ++ ++static int cnic_nl_neigh_rsp(nic_t *nic, int fd, ++ struct iscsi_uevent *ev, ++ struct iscsi_path *path_req, ++ __u8 *mac_addr, ++ nic_interface_t *nic_iface, int status, int type) ++{ ++ int rc; ++ uint8_t *ret_buf; ++ struct iscsi_uevent *ret_ev; ++ struct iscsi_path *path_rsp; ++ struct sockaddr_nl dest_addr; ++ char addr_dst_str[INET6_ADDRSTRLEN]; ++ ++ memset(&dest_addr, 0, sizeof(dest_addr)); ++ dest_addr.nl_family = AF_NETLINK; ++ dest_addr.nl_pid = 0; ++ dest_addr.nl_groups = 0; /* unicast */ ++ ++ ret_buf = calloc(1, NLMSG_SPACE(sizeof(struct iscsi_uevent) + 256)); ++ if (ret_buf == NULL) { ++ LOG_ERR(PFX "Could not allocate memory for path req resposne"); ++ return -ENOMEM; ++ } ++ ++ memset(ret_buf, 0, NLMSG_SPACE(sizeof(struct iscsi_uevent) + 256)); ++ ++ /* prepare the iscsi_uevent buffer */ ++ ret_ev = (struct iscsi_uevent *)ret_buf; ++ ret_ev->type = ISCSI_UEVENT_PATH_UPDATE; ++ ret_ev->transport_handle = ev->transport_handle; ++ ret_ev->u.set_path.host_no = ev->r.req_path.host_no; ++ ++ /* Prepare the iscsi_path buffer */ ++ path_rsp = (struct iscsi_path *)(ret_buf + sizeof(*ret_ev)); ++ path_rsp->handle = path_req->handle; ++ if (type == AF_INET) { ++ path_rsp->ip_addr_len = 4; ++ memcpy(&path_rsp->src.v4_addr, nic_iface->ustack.hostaddr, ++ sizeof(nic_iface->ustack.hostaddr)); ++ ++ inet_ntop(AF_INET, &path_rsp->src.v4_addr, ++ addr_dst_str, sizeof(addr_dst_str)); ++ } else { ++ u8_t *src_ipv6; ++ int ret; ++ ++ /* Depending on the IPv6 address of the target we will need to ++ * determine whether we use the assigned IPv6 address or the ++ * link local IPv6 address */ ++ if (ndpc_request(&nic_iface->ustack, &path_req->dst.v6_addr, ++ &ret, CHECK_LINK_LOCAL_ADDR)) { ++ src_ipv6 = (u8_t *)all_zeroes_addr6; ++ LOG_DEBUG(PFX "RSP Check LL failed"); ++ goto src_done; ++ } ++ if (ret) { ++ /* Get link local IPv6 address */ ++ src_ipv6 = (u8_t *)&nic_iface->ustack.linklocal6; ++ } else { ++ if (ndpc_request(&nic_iface->ustack, ++ &path_req->dst.v6_addr, ++ &src_ipv6, GET_HOST_ADDR)) { ++ src_ipv6 = (u8_t *)all_zeroes_addr6; ++ LOG_DEBUG(PFX "RSP Get host addr failed"); ++ } ++ if (src_ipv6 == NULL) { ++ src_ipv6 = (u8_t *)all_zeroes_addr6; ++ LOG_DEBUG(PFX "RSP no Best matched addr found"); ++ } ++ } ++src_done: ++ path_rsp->ip_addr_len = 16; ++ memcpy(&path_rsp->src.v6_addr, src_ipv6, ++ sizeof(nic_iface->ustack.hostaddr6)); ++ ++ inet_ntop(AF_INET6, &path_rsp->src.v6_addr, ++ addr_dst_str, sizeof(addr_dst_str)); ++ } ++ memcpy(path_rsp->mac_addr, mac_addr, 6); ++ path_rsp->vlan_id = (nic_iface->vlan_priority << 12) | ++ nic_iface->vlan_id; ++ path_rsp->pmtu = nic_iface->mtu ? nic_iface->mtu : path_req->pmtu; ++ ++ rc = __kipc_call(fd, ret_ev, sizeof(*ret_ev) + sizeof(*path_rsp)); ++ if (rc > 0) { ++ LOG_DEBUG(PFX "neighbor reply sent back to kernel " ++ "%s at %02x:%02x:%02x:%02x:%02x:%02x with vlan %d", ++ addr_dst_str, ++ mac_addr[0], mac_addr[1], ++ mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], ++ nic_iface->vlan_id); ++ ++ } else { ++ LOG_ERR(PFX "send neighbor reply failed: %d", rc); ++ } ++ ++ free(ret_buf); ++ ++ return rc; ++} ++ ++static const struct timeval tp_wait = { ++ .tv_sec = 0, ++ .tv_usec = 250000, ++}; ++ ++/** ++ * cnic_handle_ipv4_iscsi_path_req() - This function will handle the IPv4 ++ * path req calls the bnx2i kernel module ++ * @param nic - The nic the message is directed towards ++ * @param fd - The file descriptor to be used to extract the private data ++ * @param ev - The iscsi_uevent ++ * @param buf - The private message buffer ++ */ ++int cnic_handle_ipv4_iscsi_path_req(nic_t *nic, int fd, ++ struct iscsi_uevent *ev, ++ struct iscsi_path *path, ++ nic_interface_t *nic_iface) ++{ ++ struct in_addr src_addr, dst_addr, ++ src_matching_addr, dst_matching_addr, netmask; ++ __u8 mac_addr[6]; ++ int rc; ++ uint16_t arp_retry; ++ int status = 0; ++#define MAX_ARP_RETRY 4 ++ ++ memset(mac_addr, 0, sizeof(mac_addr)); ++ memcpy(&dst_addr, &path->dst.v4_addr, sizeof(dst_addr)); ++ memcpy(&src_addr, nic_iface->ustack.hostaddr, sizeof(src_addr)); ++ ++ if (nic_iface->ustack.netmask[0] | nic_iface->ustack.netmask[1]) ++ memcpy(&netmask.s_addr, nic_iface->ustack.netmask, ++ sizeof(src_addr)); ++ else ++ netmask.s_addr = calculate_default_netmask(dst_addr.s_addr); ++ ++ src_matching_addr.s_addr = src_addr.s_addr & netmask.s_addr; ++ dst_matching_addr.s_addr = dst_addr.s_addr & netmask.s_addr; ++ ++ LOG_DEBUG(PFX "%s: src=%s", nic->log_name, inet_ntoa(src_addr)); ++ LOG_DEBUG(PFX "%s: dst=%s", nic->log_name, inet_ntoa(dst_addr)); ++ LOG_DEBUG(PFX "%s: nm=%s", nic->log_name, inet_ntoa(netmask)); ++ if (src_matching_addr.s_addr != dst_matching_addr.s_addr) { ++ /* If there is an assigned gateway address then use it ++ * if the source address doesn't match */ ++ if (nic_iface->ustack.default_route_addr[0] | ++ nic_iface->ustack.default_route_addr[1]) { ++ memcpy(&dst_addr, ++ &nic_iface->ustack.default_route_addr, ++ sizeof(dst_addr)); ++ } else { ++ arp_retry = MAX_ARP_RETRY; ++ LOG_DEBUG(PFX "%s: no default", nic->log_name); ++ goto done; ++ } ++ } ++ arp_retry = 0; ++ ++ rc = uip_lookup_arp_entry(dst_addr.s_addr, mac_addr); ++ if (rc != 0) { ++ while ((arp_retry < MAX_ARP_RETRY) && (event_loop_stop == 0)) { ++ char *dst_addr_str; ++ int count; ++ struct timespec ts; ++ struct timeval tp; ++ struct timeval tp_abs; ++ ++ dst_addr_str = inet_ntoa(dst_addr); ++ ++ LOG_INFO(PFX "%s: Didn't find IPv4: '%s' in ARP table", ++ nic->log_name, dst_addr_str); ++ rc = cnic_arp_send(nic, nic_iface, fd, ++ mac_addr, ++ dst_addr.s_addr, dst_addr_str); ++ if (rc != 0) { ++ status = -EIO; ++ goto done; ++ } ++ ++ for (count = 0; count < 8; count++) { ++ /* Convert from timeval to timespec */ ++ rc = gettimeofday(&tp, NULL); ++ ++ timeradd(&tp, &tp_wait, &tp_abs); ++ ++ ts.tv_sec = tp_abs.tv_sec; ++ ts.tv_nsec = tp_abs.tv_usec * 1000; ++ ++ /* Wait 1s for if_down */ ++ pthread_mutex_lock(&nic->nl_process_mutex); ++ rc = pthread_cond_timedwait ++ (&nic->nl_process_if_down_cond, ++ &nic->nl_process_mutex, &ts); ++ ++ if (rc == ETIMEDOUT) { ++ pthread_mutex_unlock ++ (&nic->nl_process_mutex); ++ ++ rc = uip_lookup_arp_entry(dst_addr. ++ s_addr, ++ mac_addr); ++ if (rc == 0) ++ goto done; ++ } else { ++ nic->nl_process_if_down = 0; ++ pthread_mutex_unlock ++ (&nic->nl_process_mutex); ++ ++ arp_retry = MAX_ARP_RETRY; ++ goto done; ++ ++ } ++ } ++ ++ arp_retry++; ++ } ++ } ++ ++done: ++ ++ if (arp_retry >= MAX_ARP_RETRY) { ++ status = -EIO; ++ rc = -EIO; ++ } ++ ++ if (status != 0 || rc != 0) ++ pthread_mutex_unlock(&nic->xmit_mutex); ++ ++ if (ev) { ++ cnic_nl_neigh_rsp(nic, fd, ev, path, mac_addr, ++ nic_iface, status, AF_INET); ++ } ++ ++ return rc; ++} ++ ++/** ++ * cnic_handle_ipv6_iscsi_path_req() - This function will handle the IPv4 ++ * path req calls the bnx2i kernel module ++ * @param nic - The nic the message is directed towards ++ * @param fd - The file descriptor to be used to extract the private data ++ * @param ev - The iscsi_uevent ++ * @param buf - The private message buffer ++ */ ++int cnic_handle_ipv6_iscsi_path_req(nic_t *nic, int fd, ++ struct iscsi_uevent *ev, ++ struct iscsi_path *path, ++ nic_interface_t *nic_iface) ++{ ++ __u8 mac_addr[6]; ++ int rc, i; ++ uint16_t neighbor_retry; ++ int status = 0; ++ char addr_dst_str[INET6_ADDRSTRLEN]; ++ struct in6_addr src_addr, dst_addr, ++ src_matching_addr, dst_matching_addr, netmask; ++ struct in6_addr *addr; ++ struct ndpc_reqptr req_ptr; ++ ++ memset(mac_addr, 0, sizeof(mac_addr)); ++ ++ inet_ntop(AF_INET6, &path->dst.v6_addr, ++ addr_dst_str, sizeof(addr_dst_str)); ++ ++ /* Depending on the IPv6 address of the target we will need to ++ * determine whether we use the assigned IPv6 address or the ++ * link local IPv6 address */ ++ memcpy(&dst_addr, &path->dst.v6_addr, sizeof(struct in6_addr)); ++ if (ndpc_request(&nic_iface->ustack, &dst_addr, ++ &rc, CHECK_LINK_LOCAL_ADDR)) { ++ neighbor_retry = MAX_ARP_RETRY; ++ LOG_DEBUG(PFX "Check LL failed"); ++ goto done; ++ } ++ if (rc) { ++ LOG_DEBUG(PFX "Use LL"); ++ /* Get link local IPv6 address */ ++ addr = (struct in6_addr *)&nic_iface->ustack.linklocal6; ++ } else { ++ LOG_DEBUG(PFX "Use Best matched"); ++ if (ndpc_request(&nic_iface->ustack, ++ &dst_addr, ++ &addr, GET_HOST_ADDR)) { ++ neighbor_retry = MAX_ARP_RETRY; ++ LOG_DEBUG(PFX "Use Best matched failed"); ++ goto done; ++ } ++ if (addr == NULL) { ++ neighbor_retry = MAX_ARP_RETRY; ++ LOG_DEBUG(PFX "No Best matched found"); ++ goto done; ++ } ++ } ++ /* Got the best matched src IP address */ ++ memcpy(&src_addr, addr, sizeof(struct in6_addr)); ++ ++ if (nic_iface->ustack.netmask6[0] | nic_iface->ustack.netmask6[1] | ++ nic_iface->ustack.netmask6[2] | nic_iface->ustack.netmask6[3] | ++ nic_iface->ustack.netmask6[4] | nic_iface->ustack.netmask6[5] | ++ nic_iface->ustack.netmask6[6] | nic_iface->ustack.netmask6[7]) ++ memcpy(&netmask.s6_addr, nic_iface->ustack.netmask6, ++ sizeof(struct in6_addr)); ++ else ++ memcpy(&netmask.s6_addr, all_zeroes_addr6, ++ sizeof(struct in6_addr)); ++ ++ inet_ntop(AF_INET6, &src_addr.s6_addr16, addr_dst_str, ++ sizeof(addr_dst_str)); ++ LOG_DEBUG(PFX "src IP addr %s", addr_dst_str); ++ inet_ntop(AF_INET6, &dst_addr.s6_addr16, addr_dst_str, ++ sizeof(addr_dst_str)); ++ LOG_DEBUG(PFX "dst IP addr %s", addr_dst_str); ++ inet_ntop(AF_INET6, &netmask.s6_addr16, addr_dst_str, ++ sizeof(addr_dst_str)); ++ LOG_DEBUG(PFX "prefix mask %s", addr_dst_str); ++ ++ for (i = 0; i < 4; i++) { ++ src_matching_addr.s6_addr32[i] = src_addr.s6_addr32[i] & ++ netmask.s6_addr32[i]; ++ dst_matching_addr.s6_addr32[i] = dst_addr.s6_addr32[i] & ++ netmask.s6_addr32[i]; ++ if (src_matching_addr.s6_addr32[i] != ++ dst_matching_addr.s6_addr32[i]) { ++ /* No match with the prefix mask, use default route */ ++ if (memcmp(nic_iface->ustack.default_route_addr6, ++ all_zeroes_addr6, sizeof(*addr))) { ++ memcpy(&dst_addr, ++ nic_iface->ustack.default_route_addr6, ++ sizeof(dst_addr)); ++ inet_ntop(AF_INET6, &dst_addr.s6_addr16, ++ addr_dst_str, sizeof(addr_dst_str)); ++ LOG_DEBUG(PFX "Use default router IP addr %s", ++ addr_dst_str); ++ break; ++ } else { ++ neighbor_retry = MAX_ARP_RETRY; ++ goto done; ++ } ++ } ++ } ++ ++#define MAX_ARP_RETRY 4 ++ neighbor_retry = 0; ++ ++ req_ptr.eth = (void *)mac_addr; ++ req_ptr.ipv6 = (void *)&dst_addr; ++ if (ndpc_request(&nic_iface->ustack, &req_ptr, &rc, CHECK_ARP_TABLE)) { ++ /* ndpc request failed, skip neighbor solicit send */ ++ neighbor_retry = MAX_ARP_RETRY; ++ goto done; ++ } ++ if (!rc) { ++ inet_ntop(AF_INET6, &dst_addr.s6_addr16, ++ addr_dst_str, sizeof(addr_dst_str)); ++ LOG_DEBUG(PFX ++ "%s: Preparing to send IPv6 neighbor solicitation " ++ "to dst: '%s'", nic->log_name, addr_dst_str); ++ while ((neighbor_retry < MAX_ARP_RETRY) ++ && (event_loop_stop == 0)) { ++ int count; ++ struct timespec ts; ++ struct timeval tp; ++ struct timeval tp_abs; ++ ++ LOG_INFO(PFX "%s: Didn't find IPv6: '%s'\n", ++ nic->log_name, addr_dst_str); ++ ++ rc = cnic_neigh_soliciation_send(nic, nic_iface, fd, ++ mac_addr, ++ &dst_addr, ++ addr_dst_str); ++ if (rc != 0) { ++ status = -EIO; ++ goto done; ++ } ++ ++ for (count = 0; count < 8; count++) { ++ /* Convert from timeval to timespec */ ++ rc = gettimeofday(&tp, NULL); ++ ++ timeradd(&tp, &tp_wait, &tp_abs); ++ ++ ts.tv_sec = tp_abs.tv_sec; ++ ts.tv_nsec = tp_abs.tv_usec * 1000; ++ ++ pthread_mutex_lock(&nic->nl_process_mutex); ++ rc = pthread_cond_timedwait ++ (&nic->nl_process_if_down_cond, ++ &nic->nl_process_mutex, &ts); ++ ++ if (rc == ETIMEDOUT) { ++ pthread_mutex_unlock ++ (&nic->nl_process_mutex); ++ ++ req_ptr.eth = (void *)mac_addr; ++ req_ptr.ipv6 = (void *)&dst_addr; ++ if (ndpc_request ++ (&nic_iface->ustack, &req_ptr, &rc, ++ CHECK_ARP_TABLE)) { ++ /* ndpc request failed, ++ force retry */ ++ rc = 0; ++ } ++ if (rc) ++ goto done; ++ } else { ++ nic->nl_process_if_down = 0; ++ pthread_mutex_unlock ++ (&nic->nl_process_mutex); ++ ++ neighbor_retry = MAX_ARP_RETRY; ++ goto done; ++ } ++ } ++ neighbor_retry++; ++ } ++ } ++ ++done: ++ if (neighbor_retry >= MAX_ARP_RETRY) { ++ status = -EIO; ++ rc = -EIO; ++ } ++ ++ if (status != 0 || rc != 0) ++ pthread_mutex_unlock(&nic->xmit_mutex); ++ ++ if (ev) { ++ cnic_nl_neigh_rsp(nic, fd, ev, path, mac_addr, ++ nic_iface, status, AF_INET6); ++ } ++ return rc; ++} ++ ++/** ++ * cnic_handle_iscsi_path_req() - This function will handle the path req calls ++ * the bnx2i kernel module ++ * @param nic - The nic the message is directed towards ++ * @param fd - The file descriptor to be used to extract the private data ++ * @param ev - The iscsi_uevent ++ * @param path - The private message buffer ++ * @param nic_iface - The nic_iface to use for this connection request ++ */ ++int cnic_handle_iscsi_path_req(nic_t *nic, int fd, struct iscsi_uevent *ev, ++ struct iscsi_path *path, ++ nic_interface_t *nic_iface) ++{ ++ ++ LOG_DEBUG(PFX "%s: Netlink message with VLAN ID: %d, path MTU: %d " ++ "minor: %d ip_addr_len: %d", ++ nic->log_name, path->vlan_id, path->pmtu, 0 /* TODO FIX */ , ++ path->ip_addr_len); ++ ++ if (path->ip_addr_len == 4) ++ return cnic_handle_ipv4_iscsi_path_req(nic, fd, ev, path, ++ nic_iface); ++ else if (path->ip_addr_len == 16) ++ return cnic_handle_ipv6_iscsi_path_req(nic, fd, ev, path, ++ nic_iface); ++ else { ++ LOG_DEBUG(PFX "%s: unknown ip_addr_len: %d size dropping ", ++ nic->log_name, path->ip_addr_len); ++ return -EIO; ++ } ++} +diff --git a/iscsiuio/src/unix/libs/cnic.h b/iscsiuio/src/unix/libs/cnic.h +new file mode 100644 +index 0000000..6244a94 +--- /dev/null ++++ b/iscsiuio/src/unix/libs/cnic.h +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * cnic.h - CNIC UIO uIP user space stack ++ * ++ */ ++#ifndef __CNIC_NL_H__ ++#define __CNIC_NL_H__ ++ ++/******************************************************************************* ++ * Constants shared between the bnx2 and bnx2x modules ++ ******************************************************************************/ ++extern const char bnx2i_library_transport_name[]; ++extern const size_t bnx2i_library_transport_name_size; ++ ++int cnic_nl_open(); ++void cnic_nl_close(); ++ ++int cnic_handle_iscsi_path_req(nic_t *nic, int, struct iscsi_uevent *, ++ struct iscsi_path *path, ++ nic_interface_t *nic_iface); ++ ++#endif /* __CNIC_NL_H__ */ +diff --git a/iscsiuio/src/unix/logger.c b/iscsiuio/src/unix/logger.c +new file mode 100644 +index 0000000..d41f9e8 +--- /dev/null ++++ b/iscsiuio/src/unix/logger.c +@@ -0,0 +1,181 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * logger.c - Logging Utilities ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include "options.h" ++#include "logger.h" ++ ++/****************************************************************************** ++ * Default logger values ++ ******************************************************************************/ ++static const char default_logger_filename[] = "/var/log/iscsiuio.log"; ++ ++struct logger main_log = { ++ .enabled = LOGGER_ENABLED, ++ .fp = NULL, ++ .log_file = (char *)default_logger_filename, ++ .level = LOG_LEVEL_INFO, ++ .lock = PTHREAD_MUTEX_INITIALIZER, ++ ++ .stats = { ++ .debug = 0, ++ .info = 0, ++ .warn = 0, ++ .error = 0, ++ ++ .last_log_time = 0, ++ }, ++}; ++ ++/****************************************************************************** ++ * Logger Functions ++ ******************************************************************************/ ++/** ++ * log_uip() - Main logging function ++ * @param level_str - log level string ++ * @param fmt - log format ++ */ ++void log_uip(char *level_str, char *fmt, ...) ++{ ++ char time_buf[32]; ++ va_list ap, ap2; ++ ++ pthread_mutex_lock(&main_log.lock); ++ va_start(ap, fmt); ++ ++ if (main_log.fp == NULL) ++ goto end; ++ ++ main_log.stats.last_log_time = time(NULL); ++ strftime(time_buf, 26, "%a %b %d %T %Y", ++ localtime(&main_log.stats.last_log_time)); ++ va_copy(ap2, ap); ++ ++ if (main_log.enabled == LOGGER_ENABLED) { ++ fprintf(main_log.fp, "%s [%s]", level_str, time_buf); ++ vfprintf(main_log.fp, fmt, ap); ++ fprintf(main_log.fp, "\n"); ++ } ++ ++ if (opt.debug == DEBUG_ON) { ++ fprintf(stdout, "%s [%s]", level_str, time_buf); ++ vfprintf(stdout, fmt, ap2); ++ fprintf(stdout, "\n"); ++ ++ /* Force the printing of the log file */ ++ fflush(main_log.fp); ++ ++ /* Force the printing of the log out to standard output */ ++ fflush(stdout); ++ } ++ ++end: ++ va_end(ap2); ++ va_end(ap); ++ pthread_mutex_unlock(&main_log.lock); ++} ++ ++/****************************************************************************** ++ * Initialize/Clean up routines ++ ******************************************************************************/ ++/** ++ * init_logger() - Prepare the logger ++ * @param filename - path to where the log will be written to ++ * @return 0 on success, <0 on failure ++ */ ++int init_logger(char *filename) ++{ ++ int rc = 0; ++ ++ pthread_mutex_lock(&main_log.lock); ++ ++ if (opt.debug != DEBUG_ON) { ++ rc = -EIO; ++ goto disable; ++ } ++ main_log.fp = fopen(filename, "a"); ++ if (main_log.fp == NULL) { ++ printf("Could not create log file: %s <%s>\n", ++ filename, strerror(errno)); ++ rc = -EIO; ++ } ++disable: ++ if (rc) ++ main_log.enabled = LOGGER_DISABLED; ++ else ++ main_log.enabled = LOGGER_ENABLED; ++ ++ pthread_mutex_unlock(&main_log.lock); ++ ++ if (!rc) ++ LOG_INFO("Initialize logger using log file: %s", filename); ++ ++ return rc; ++} ++ ++void fini_logger(int type) ++{ ++ pthread_mutex_lock(&main_log.lock); ++ ++ if (main_log.fp != NULL) { ++ fclose(main_log.fp); ++ main_log.fp = NULL; ++ ++ if (opt.debug == DEBUG_ON) { ++ printf("Closed logger\n"); ++ fflush(stdout); ++ } ++ } ++ ++ if (type == SHUTDOWN_LOGGER) { ++ if ((main_log.log_file != NULL) && ++ (main_log.log_file != default_logger_filename)) { ++ free(main_log.log_file); ++ main_log.log_file = NULL; ++ } ++ } ++ ++ main_log.enabled = LOGGER_DISABLED; ++ ++ pthread_mutex_unlock(&main_log.lock); ++} +diff --git a/iscsiuio/src/unix/logger.h b/iscsiuio/src/unix/logger.h +new file mode 100644 +index 0000000..06e2084 +--- /dev/null ++++ b/iscsiuio/src/unix/logger.h +@@ -0,0 +1,129 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * logger.h - Logging Utilities ++ * ++ */ ++#ifndef __LOGGER_H__ ++#define __LOGGER_H__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/******************************************************************************* ++ * Logger Levels ++ ******************************************************************************/ ++#define LOG_LEVEL_PACKET 5 ++#define LOG_LEVEL_DEBUG 4 ++#define LOG_LEVEL_INFO 3 ++#define LOG_LEVEL_WARN 2 ++#define LOG_LEVEL_ERR 1 ++#define LOG_LEVEL_UNKNOWN 0 ++ ++#define LOG_LEVEL_PACKET_STR "PKT " ++#define LOG_LEVEL_DEBUG_STR "DBG " ++#define LOG_LEVEL_INFO_STR "INFO " ++#define LOG_LEVEL_WARN_STR "WARN " ++#define LOG_LEVEL_ERR_STR "ERR " ++#define LOG_LEVEL_UNKNOWN_STR "? " ++ ++/******************************************************************************* ++ * Logging Macro's ++ ******************************************************************************/ ++#define LOG_PACKET(fmt, args...) { if (LOG_LEVEL_PACKET <= \ ++ main_log.level) { \ ++ log_uip(LOG_LEVEL_PACKET_STR, fmt,\ ++ ##args);\ ++ } } ++#define LOG_DEBUG(fmt, args...) { if (LOG_LEVEL_DEBUG <= main_log.level) { \ ++ log_uip(LOG_LEVEL_DEBUG_STR, fmt,\ ++ ##args);\ ++ } } ++ ++#define LOG_INFO(fmt, args...) { if (LOG_LEVEL_INFO <= main_log.level) { \ ++ log_uip(LOG_LEVEL_INFO_STR, fmt,\ ++ ##args); \ ++ } } ++#define LOG_WARN(fmt, args...) { if (LOG_LEVEL_WARN <= main_log.level) { \ ++ log_uip(LOG_LEVEL_WARN_STR, fmt,\ ++ ##args); \ ++ } } ++#define LOG_ERR(fmt, args...) { if (LOG_LEVEL_ERR <= main_log.level) { \ ++ log_uip(LOG_LEVEL_ERR_STR, fmt,\ ++ ##args); \ ++ } } ++ ++/******************************************************************************* ++ * Logging Statistics ++ ******************************************************************************/ ++struct logger_stats { ++ uint64_t debug; ++ uint64_t info; ++ uint64_t warn; ++ uint64_t error; ++ ++ time_t last_log_time; ++}; ++ ++/******************************************************************************* ++ * Logger Structure ++ ******************************************************************************/ ++struct logger { ++ FILE *fp; ++ char *log_file; ++ int8_t level; ++ ++#define LOGGER_ENABLED 0x01 ++#define LOGGER_DISABLED 0x02 ++ int8_t enabled; ++ ++ pthread_mutex_t lock; ++ ++ struct logger_stats stats; ++}; ++ ++extern struct logger main_log; ++ ++int init_logger(char *); ++void log_uip(char *level_str, char *fmt, ...); ++void fini_logger(int); ++ ++#define CLOSE_LOGGER 0x01 ++#define SHUTDOWN_LOGGER 0x02 ++ ++#endif +diff --git a/iscsiuio/src/unix/main.c b/iscsiuio/src/unix/main.c +new file mode 100644 +index 0000000..c1a72d8 +--- /dev/null ++++ b/iscsiuio/src/unix/main.c +@@ -0,0 +1,399 @@ ++/* ++ * Copyright (c) 2001, Adam Dunkels. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack. ++ * ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "uip.h" ++#include "uip_arp.h" ++#include "uip_eth.h" ++ ++#include "timer.h" ++ ++#include "build_date.h" ++#include "config.h" ++#include "iscsid_ipc.h" ++#include "logger.h" ++#include "nic.h" ++#include "nic_id.h" ++#include "nic_nl.h" ++#include "nic_utils.h" ++#include "options.h" ++#include "packet.h" ++ ++#include "dhcpc.h" ++ ++#include "iscsid_ipc.h" ++#include "brcm_iscsi.h" ++ ++/******************************************************************************* ++ * Constants ++ ******************************************************************************/ ++#define PFX "main " ++ ++static const char default_pid_filepath[] = "/var/run/iscsiuio.pid"; ++ ++/******************************************************************************* ++ * Global Variables ++ ******************************************************************************/ ++static const struct option long_options[] = { ++ {"debug", 0, 0, 0}, ++ {"version", 0, 0, 0}, ++ {"help", 0, 0, 0}, ++ {0, 0, 0, 0} ++}; ++ ++struct options opt = { ++ .debug = DEBUG_OFF, ++}; ++ ++int event_loop_stop; ++extern nic_t *nic_list; ++ ++struct utsname cur_utsname; ++ ++/** ++ * cleanup() - This function is called when this program is to be closed ++ * This function will clean up all the cnic uio interfaces and ++ * flush/close the logger ++ */ ++static void cleanup() ++{ ++ iscsid_cleanup(); ++ ++ nic_remove_all(); ++ ++ unload_all_nic_libraries(); ++ ++ LOG_INFO("Done waiting for cnic's/stacks to gracefully close"); ++ ++ fini_logger(SHUTDOWN_LOGGER); ++} ++ ++/** ++ * signal_handle_thread() - This is the signal handling thread of this program ++ * This is the only thread which will handle signals. ++ * All signals are routed here and handled here to ++ * provide consistant handling. ++ */ ++static pthread_t signal_thread; ++static void *signal_handle_thread(void *arg) ++{ ++ sigset_t set; ++ int rc; ++ int signal; ++ ++ sigfillset(&set); ++ ++ LOG_INFO("signal handling thread ready"); ++ ++signal_wait: ++ rc = sigwait(&set, &signal); ++ ++ switch (signal) { ++ case SIGINT: ++ LOG_INFO("Caught SIGINT signal"); ++ break; ++ case SIGUSR1: ++ LOG_INFO("Caught SIGUSR1 signal, rotate log"); ++ fini_logger(SHUTDOWN_LOGGER); ++ rc = init_logger(main_log.log_file); ++ if (rc != 0) ++ printf("Could not initialize the logger in " ++ "signal!\n"); ++ goto signal_wait; ++ default: ++ break; ++ } ++ event_loop_stop = 1; ++ ++ LOG_INFO("terminating..."); ++ ++ cleanup(); ++ exit(EXIT_SUCCESS); ++} ++ ++static void show_version() ++{ ++ printf("%s: Version '%s', Build Date: '%s'\n", ++ APP_NAME, PACKAGE_VERSION, build_date); ++} ++ ++static void main_usage() ++{ ++ show_version(); ++ ++ printf("\nUsage: %s [OPTION]\n", APP_NAME); ++ printf("iscsiuio daemon.\n" ++ "-f, --foreground make the program run in the foreground\n" ++ "-d, --debug debuglevel print debugging information\n" ++ "-p, --pid=pidfile use pid file (default %s).\n" ++ "-h, --help display this help and exit\n" ++ "-v, --version display version and exit\n", ++ default_pid_filepath); ++} ++ ++static void daemon_init() ++{ ++ int fd; ++ ++ fd = open("/dev/null", O_RDWR); ++ if (fd == -1) ++ exit(-1); ++ ++ dup2(fd, 0); ++ dup2(fd, 1); ++ dup2(fd, 2); ++ setsid(); ++ chdir("/"); ++} ++ ++#define ISCSI_OOM_PATH_LEN 48 ++ ++int oom_adjust(void) ++{ ++ int fd; ++ char path[ISCSI_OOM_PATH_LEN]; ++ struct stat statb; ++ ++ if (nice(-10) < 0) ++ LOG_DEBUG("Could not increase process priority: %s", ++ strerror(errno)); ++ ++ snprintf(path, ISCSI_OOM_PATH_LEN, "/proc/%d/oom_score_adj", getpid()); ++ if (stat(path, &statb)) { ++ /* older kernel so use old oom_adj file */ ++ snprintf(path, ISCSI_OOM_PATH_LEN, "/proc/%d/oom_adj", ++ getpid()); ++ } ++ fd = open(path, O_WRONLY); ++ if (fd < 0) ++ return -1; ++ if (write(fd, "-16", 3) < 0) /* for 2.6.11 */ ++ LOG_DEBUG("Could not set oom score to -16: %s", ++ strerror(errno)); ++ if (write(fd, "-17", 3) < 0) /* for Andrea's patch */ ++ LOG_DEBUG("Could not set oom score to -17: %s", ++ strerror(errno)); ++ close(fd); ++ return 0; ++} ++ ++ ++/******************************************************************************* ++ * Main routine ++ ******************************************************************************/ ++int main(int argc, char *argv[]) ++{ ++ int rc; ++ sigset_t set; ++ const char *pid_file = default_pid_filepath; ++ int fd; ++ int foreground = 0; ++ pid_t pid; ++ pthread_attr_t attr; ++ ++ /* Record the start time for the user space daemon */ ++ opt.start_time = time(NULL); ++ ++ /* parse the parameters */ ++ while (1) { ++ int c, option_index; ++ ++ c = getopt_long(argc, argv, "fd:p:vh", ++ long_options, &option_index); ++ ++ if (c == -1) ++ break; ++ ++ switch (c) { ++ ++ case 'f': ++ foreground = 1; ++ break; ++ ++ /* Enable debugging mode */ ++ case 'd': ++ main_log.level = atoi(optarg); ++ opt.debug = DEBUG_ON; ++ break; ++ case 'p': ++ pid_file = optarg; ++ break; ++ case 'v': ++ show_version(); ++ exit(EXIT_SUCCESS); ++ case 'h': ++ default: ++ main_usage(); ++ exit(EXIT_SUCCESS); ++ } ++ } ++ ++ if (main_log.enabled == LOGGER_ENABLED) { ++ /* initialize the logger */ ++ rc = init_logger(main_log.log_file); ++ if (rc != 0 && opt.debug == DEBUG_ON) ++ printf("WARN: Could not initialize the logger\n"); ++ } ++ ++ LOG_INFO("Started iSCSI uio stack: Ver " PACKAGE_VERSION); ++ LOG_INFO("Build date: %s", build_date); ++ ++ if (opt.debug == DEBUG_ON) ++ LOG_INFO("Debug mode enabled"); ++ ++ event_loop_stop = 0; ++ nic_list = NULL; ++ ++ /* Determine the current kernel version */ ++ memset(&cur_utsname, 0, sizeof(cur_utsname)); ++ ++ rc = uname(&cur_utsname); ++ if (rc == 0) { ++ LOG_INFO("Running on sysname: '%s', release: '%s', " ++ "version '%s' machine: '%s'", ++ cur_utsname.sysname, cur_utsname.release, ++ cur_utsname.version, cur_utsname.machine); ++ } else ++ LOG_WARN("Could not determine kernel version"); ++ ++ /* Initialze the iscsid listener */ ++ rc = iscsid_init(); ++ if (rc != 0) ++ goto error; ++ ++ if (!foreground) { ++ char buf[64]; ++ ssize_t written_bytes; ++ ++ fd = open(pid_file, O_WRONLY | O_CREAT, 0644); ++ if (fd < 0) { ++ printf("Unable to create pid file: %s", pid_file); ++ exit(1); ++ } ++ ++ pid = fork(); ++ if (pid < 0) { ++ printf("Starting daemon failed"); ++ exit(1); ++ } else if (pid) { ++ exit(0); ++ } ++ ++ rc = chdir("/"); ++ if (rc == -1) ++ printf("Unable to chdir(\") [%s]", strerror(errno)); ++ ++ if (lockf(fd, F_TLOCK, 0) < 0) { ++ printf("Unable to lock pid file: %s [%s]", ++ pid_file, strerror(errno)); ++ exit(1); ++ } ++ ++ rc = ftruncate(fd, 0); ++ if (rc == -1) ++ printf("ftruncate(%d, 0) failed [%s]", ++ fd, strerror(errno)); ++ ++ sprintf(buf, "%d\n", getpid()); ++ written_bytes = write(fd, buf, strlen(buf)); ++ if (written_bytes == -1) ++ printf("Could not write lock file [%s]", ++ strerror(errno)); ++ ++ daemon_init(); ++ } ++ ++ /* Load the NIC libraries */ ++ rc = load_all_nic_libraries(); ++ if (rc != 0) ++ goto error; ++ ++ brcm_iscsi_init(); ++ ++ /* ensure we don't see any signals */ ++ sigemptyset(&set); ++ sigaddset(&set, SIGINT); ++ sigaddset(&set, SIGQUIT); ++ sigaddset(&set, SIGTERM); ++ sigaddset(&set, SIGUSR1); ++ rc = pthread_sigmask(SIG_SETMASK, &set, NULL); ++ ++ /* Spin off the signal handling thread */ ++ pthread_attr_init(&attr); ++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ++ rc = pthread_create(&signal_thread, &attr, signal_handle_thread, NULL); ++ if (rc != 0) ++ LOG_ERR("Could not create signal handling thread"); ++ ++ /* Using sysfs to discover iSCSI hosts */ ++ nic_discover_iscsi_hosts(); ++ ++ /* oom-killer will not kill us at the night... */ ++ if (oom_adjust()) ++ LOG_DEBUG("Can not adjust oom-killer's pardon"); ++ ++ /* we don't want our active sessions to be paged out... */ ++ if (mlockall(MCL_CURRENT | MCL_FUTURE)) { ++ LOG_ERR("failed to mlockall, exiting..."); ++ goto error; ++ } ++ ++ /* Start the iscsid listener */ ++ rc = iscsid_start(); ++ if (rc != 0) ++ goto error; ++ ++ /* NetLink connection to listen to NETLINK_ISCSI private messages */ ++ nic_nl_open(); ++ ++error: ++ cleanup(); ++ exit(EXIT_FAILURE); ++} +diff --git a/iscsiuio/src/unix/nic.c b/iscsiuio/src/unix/nic.c +new file mode 100644 +index 0000000..74b7c5e +--- /dev/null ++++ b/iscsiuio/src/unix/nic.c +@@ -0,0 +1,1545 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * nic.c - Generic NIC management/utility functions ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dhcpc.h" ++#include "ipv6_ndpc.h" ++ ++#include "logger.h" ++#include "nic.h" ++#include "nic_utils.h" ++#include "options.h" ++ ++#include "uip.h" ++#include "uip_arp.h" ++#include "uip_eth.h" ++#include "uip-neighbor.h" ++ ++#include "bnx2.h" ++#include "bnx2x.h" ++#include "ipv6.h" ++ ++/****************************************************************************** ++ * Constants ++ *****************************************************************************/ ++#define PFX "nic " ++#define PCI_ANY_ID (~0) ++ ++/****************************************************************************** ++ * Global variables ++ *****************************************************************************/ ++/* Used to store a list of NIC libraries */ ++pthread_mutex_t nic_lib_list_mutex = PTHREAD_MUTEX_INITIALIZER; ++nic_lib_handle_t *nic_lib_list; ++ ++/* Used to store a list of active cnic devices */ ++pthread_mutex_t nic_list_mutex = PTHREAD_MUTEX_INITIALIZER; ++nic_t *nic_list; ++ ++/****************************************************************************** ++ * Functions to handle NIC libraries ++ *****************************************************************************/ ++/** ++ * alloc_nic_library_handle() - Used to allocate a NIC library handle ++ * @return NULL if memory couldn't be allocated, pointer to the handle ++ * to the NIC library handle ++ */ ++static nic_lib_handle_t *alloc_nic_library_handle() ++{ ++ nic_lib_handle_t *handle; ++ ++ handle = malloc(sizeof(*handle)); ++ if (handle == NULL) { ++ LOG_ERR("Could not allocate memory for library handle"); ++ return NULL; ++ } ++ ++ memset(handle, 0, sizeof(*handle)); ++ handle->ops = NULL; ++ ++ pthread_mutex_init(&handle->mutex, NULL); ++ ++ return handle; ++} ++ ++static void free_nic_library_handle(nic_lib_handle_t *handle) ++{ ++ free(handle); ++} ++ ++/** ++ * load_nic_library() - This function is used to load a NIC library ++ * @param handle - This is the library handle to load ++ * @return 0 = Success; <0 = failure ++ */ ++static int load_nic_library(nic_lib_handle_t *handle) ++{ ++ int rc; ++ char *library_name; ++ size_t library_name_size; ++ char *library_version; ++ size_t library_version_size; ++ char *build_date_str; ++ size_t build_date_str_size; ++ ++ pthread_mutex_lock(&handle->mutex); ++ ++ /* Validate the NIC ops table ensure that all the fields are not NULL */ ++ if ((handle->ops->open) == NULL || ++ (handle->ops->close) == NULL || ++ (handle->ops->read) == NULL || ++ (handle->ops->write) == NULL || ++ (handle->ops->clear_tx_intr == NULL)) { ++ LOG_ERR("Invalid NIC ops table: open: 0x%x, close: 0x%x," ++ "read: 0x%x, write: 0x%x clear_tx_intr: 0x%x " ++ "lib_ops: 0x%x", ++ handle->ops->open, handle->ops->close, ++ handle->ops->read, handle->ops->write, ++ handle->ops->clear_tx_intr, handle->ops->lib_ops); ++ rc = -EINVAL; ++ handle->ops = NULL; ++ goto error; ++ } ++ ++ /* Validate the NIC library ops table to ensure that all the proper ++ * fields are filled */ ++ if ((handle->ops->lib_ops.get_library_name == NULL) || ++ (handle->ops->lib_ops.get_library_version == NULL) || ++ (handle->ops->lib_ops.get_build_date == NULL) || ++ (handle->ops->lib_ops.get_transport_name == NULL)) { ++ rc = -EINVAL; ++ goto error; ++ } ++ ++ (*handle->ops->lib_ops.get_library_name) (&library_name, ++ &library_name_size); ++ (*handle->ops->lib_ops.get_library_version) (&library_version, ++ &library_version_size); ++ (*handle->ops->lib_ops.get_build_date) (&build_date_str, ++ &build_date_str_size); ++ ++ LOG_DEBUG("Loaded nic library '%s' Version: '%s' build on %s'", ++ library_name, library_version, build_date_str); ++ ++ pthread_mutex_unlock(&handle->mutex); ++ ++ return 0; ++ ++error: ++ pthread_mutex_unlock(&handle->mutex); ++ ++ return rc; ++} ++ ++static struct nic_ops *(*nic_get_ops[]) () = { ++bnx2_get_ops, bnx2x_get_ops,}; ++ ++int load_all_nic_libraries() ++{ ++ int rc, i = 0; ++ nic_lib_handle_t *handle; ++ ++ for (i = 0; i < sizeof(nic_get_ops) / sizeof(nic_get_ops[0]); i++) { ++ /* Add the CNIC library */ ++ handle = alloc_nic_library_handle(); ++ if (handle == NULL) { ++ LOG_ERR("Could not allocate memory for CNIC nic lib"); ++ return -ENOMEM; ++ } ++ ++ handle->ops = (*nic_get_ops[i]) (); ++ ++ rc = load_nic_library(handle); ++ if (rc != 0) { ++ free_nic_library_handle(handle); ++ return rc; ++ } ++ /* Add the CNIC library to the list of library handles */ ++ pthread_mutex_lock(&nic_lib_list_mutex); ++ ++ /* Add this library to the list of nic libraries we ++ * know about */ ++ if (nic_lib_list == NULL) { ++ nic_lib_list = handle; ++ } else { ++ nic_lib_handle_t *current = nic_lib_list; ++ ++ while (current->next != NULL) ++ current = current->next; ++ ++ current->next = handle; ++ } ++ pthread_mutex_unlock(&nic_lib_list_mutex); ++ ++ LOG_DEBUG("Added '%s' nic library", handle->ops->description); ++ } ++ ++ return rc; ++} ++ ++int unload_all_nic_libraries() ++{ ++ nic_lib_handle_t *current, *next; ++ ++ pthread_mutex_lock(&nic_lib_list_mutex); ++ current = nic_lib_list; ++ ++ while (current != NULL) { ++ next = current->next; ++ free_nic_library_handle(current); ++ ++ current = next; ++ } ++ ++ pthread_mutex_unlock(&nic_lib_list_mutex); ++ ++ nic_lib_list = NULL; ++ ++ return 0; ++} ++ ++NIC_LIBRARY_EXIST_T does_nic_uio_name_exist(char *name, ++ nic_lib_handle_t **handle) ++{ ++ NIC_LIBRARY_EXIST_T rc; ++ nic_lib_handle_t *current; ++ ++ pthread_mutex_lock(&nic_lib_list_mutex); ++ current = nic_lib_list; ++ ++ while (current != NULL) { ++ char *uio_name; ++ size_t uio_name_size; ++ ++ (*current->ops->lib_ops.get_uio_name) (&uio_name, ++ &uio_name_size); ++ ++ if (strncmp(name, uio_name, uio_name_size) == 0) { ++ if (handle) ++ *handle = current; ++ ++ rc = NIC_LIBRARY_EXSITS; ++ goto done; ++ } ++ ++ current = current->next; ++ } ++ ++ rc = NIC_LIBRARY_DOESNT_EXIST; ++ ++done: ++ pthread_mutex_unlock(&nic_lib_list_mutex); ++ return rc; ++} ++ ++NIC_LIBRARY_EXIST_T does_nic_library_exist(char *name, ++ nic_lib_handle_t **handle) ++{ ++ NIC_LIBRARY_EXIST_T rc; ++ nic_lib_handle_t *current; ++ ++ pthread_mutex_lock(&nic_lib_list_mutex); ++ current = nic_lib_list; ++ ++ while (current != NULL) { ++ char *library_name; ++ size_t library_name_size; ++ ++ (*current->ops->lib_ops.get_library_name) (&library_name, ++ &library_name_size); ++ ++ if (strncmp(name, library_name, library_name_size) == 0) { ++ if (handle) ++ *handle = current; ++ ++ rc = NIC_LIBRARY_EXSITS; ++ goto done; ++ } ++ ++ current = current->next; ++ } ++ ++ rc = NIC_LIBRARY_DOESNT_EXIST; ++ ++done: ++ pthread_mutex_unlock(&nic_lib_list_mutex); ++ return rc; ++} ++ ++/** ++ * find_nic_lib_using_pci_id() - Find the proper NIC library using the ++ * PCI ID's ++ * @param vendor - PCI vendor ID to search on ++ * @param device - PCI device ID to search on ++ * @param subvendor - PCI subvendor ID to search on ++ * @param subdevice - PCI subdevice ID to search on ++ * @param handle - This function will return the nic lib handle if found ++ * @return 0 if found, <0 not found ++ */ ++int find_nic_lib_using_pci_id(uint32_t vendor, uint32_t device, ++ uint32_t subvendor, uint32_t subdevice, ++ nic_lib_handle_t **handle, ++ struct pci_device_id **pci_entry) ++{ ++ int rc; ++ nic_lib_handle_t *current; ++ ++ pthread_mutex_lock(&nic_lib_list_mutex); ++ current = nic_lib_list; ++ ++ while (current != NULL) { ++ struct pci_device_id *pci_table; ++ uint32_t entries; ++ int i; ++ ++ if (current->ops->lib_ops.get_pci_table != NULL) { ++ current->ops->lib_ops.get_pci_table(&pci_table, ++ &entries); ++ } else { ++ current = current->next; ++ continue; ++ } ++ /* Sanity check the the pci table coming from the ++ * hardware library */ ++ if (entries > MAX_PCI_DEVICE_ENTRIES) { ++ LOG_WARN(PFX "Too many pci_table entries(%d) skipping", ++ entries); ++ continue; ++ } ++ ++ for (i = 0; i < entries; i++) { ++ LOG_DEBUG(PFX "Checking against: " ++ "vendor: 0x%x device:0x%x " ++ "subvendor:0x%x subdevice:0x%x", ++ pci_table[i].vendor, pci_table[i].device, ++ pci_table[i].subvendor, ++ pci_table[i].subdevice); ++ ++ if ((pci_table[i].vendor == vendor) && ++ (pci_table[i].device == device) && ++ (pci_table[i].subvendor == PCI_ANY_ID || ++ pci_table[i].subvendor == subvendor) && ++ (pci_table[i].subdevice == PCI_ANY_ID || ++ pci_table[i].subdevice == subdevice)) { ++ *handle = current; ++ *pci_entry = &pci_table[i]; ++ rc = 0; ++ goto done; ++ } ++ } ++ ++ current = current->next; ++ } ++ rc = -EINVAL; ++ ++done: ++ pthread_mutex_unlock(&nic_lib_list_mutex); ++ ++ return rc; ++} ++ ++/** ++ * nic_init() - This will properly initialize a struct cnic_uio device ++ * @return NULL is there is a failure and pointer to an allocated/initialized ++ * struct cnic_uio on success ++ */ ++nic_t *nic_init() ++{ ++ nic_t *nic; ++ ++ nic = malloc(sizeof(*nic)); ++ if (nic == NULL) { ++ LOG_ERR("Couldn't malloc space for nic"); ++ return NULL; ++ } ++ ++ memset(nic, 0, sizeof(*nic)); ++ nic->uio_minor = -1; ++ nic->fd = INVALID_FD; ++ nic->next = NULL; ++ nic->thread = INVALID_THREAD; ++ nic->enable_thread = INVALID_THREAD; ++ nic->flags |= NIC_DISABLED; ++ nic->state = NIC_STOPPED; ++ nic->free_packet_queue = NULL; ++ nic->tx_packet_queue = NULL; ++ nic->nic_library = NULL; ++ nic->pci_id = NULL; ++ nic->page_size = getpagesize(); ++ ++ /* nic_mutex is used to protect nic ops */ ++ pthread_mutex_init(&nic->nic_mutex, NULL); ++ pthread_mutex_init(&nic->xmit_mutex, NULL); ++ pthread_mutex_init(&nic->free_packet_queue_mutex, NULL); ++ ++ pthread_cond_init(&nic->enable_wait_cond, NULL); ++ pthread_cond_init(&nic->enable_done_cond, NULL); ++ pthread_cond_init(&nic->nic_loop_started_cond, NULL); ++ pthread_cond_init(&nic->disable_wait_cond, NULL); ++ ++ nic->rx_poll_usec = DEFAULT_RX_POLL_USEC; ++ ++ pthread_mutex_init(&nic->nl_process_mutex, NULL); ++ pthread_cond_init(&nic->nl_process_if_down_cond, NULL); ++ pthread_cond_init(&nic->nl_process_cond, NULL); ++ nic->nl_process_thread = INVALID_THREAD; ++ nic->nl_process_if_down = 0; ++ nic->nl_process_head = 0; ++ nic->nl_process_tail = 0; ++ memset(&nic->nl_process_ring, 0, sizeof(nic->nl_process_ring)); ++ ++ nic->ping_thread = INVALID_THREAD; ++ ++ return nic; ++} ++ ++void nic_add(nic_t *nic) ++{ ++ /* Add this device to our list of nics */ ++ if (nic_list == NULL) { ++ nic_list = nic; ++ } else { ++ nic_t *current = nic_list; ++ ++ while (current->next != NULL) ++ current = current->next; ++ ++ current->next = nic; ++ } ++} ++ ++/** ++ * nic_remove() - Used to remove the NIC for the nic list ++ * @param nic - the nic to remove ++ */ ++int nic_remove(nic_t *nic) ++{ ++ int rc; ++ nic_t *prev, *current; ++ struct stat file_stat; ++ nic_interface_t *nic_iface, *next_nic_iface, *vlan_iface; ++ ++ pthread_mutex_lock(&nic->nic_mutex); ++ ++ /* Check if the file node exists before closing */ ++ if (nic->uio_device_name) { ++ rc = stat(nic->uio_device_name, &file_stat); ++ if ((rc == 0) && (nic->ops)) ++ nic->ops->close(nic, 0); ++ } ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ nic->state = NIC_EXIT; ++ ++ if (nic->enable_thread != INVALID_THREAD) { ++ LOG_DEBUG(PFX "%s: Canceling nic enable thread", nic->log_name); ++ ++ rc = pthread_cancel(nic->enable_thread); ++ if (rc != 0) ++ LOG_DEBUG(PFX "%s: Couldn't send cancel to nic enable " ++ "thread", nic->log_name); ++ ++ nic->enable_thread = INVALID_THREAD; ++ LOG_DEBUG(PFX "%s: nic enable thread cleaned", nic->log_name); ++ } else { ++ LOG_DEBUG(PFX "%s: NIC enable thread already canceled", ++ nic->log_name); ++ } ++ ++ if (nic->thread != INVALID_THREAD) { ++ LOG_DEBUG(PFX "%s: Canceling nic thread", nic->log_name); ++ ++ rc = pthread_cancel(nic->thread); ++ if (rc != 0) ++ LOG_DEBUG(PFX "%s: Couldn't send cancel to nic", ++ nic->log_name); ++ ++ nic->thread = INVALID_THREAD; ++ LOG_DEBUG(PFX "%s: nic thread cleaned", nic->log_name); ++ } else { ++ LOG_DEBUG(PFX "%s: NIC thread already canceled", nic->log_name); ++ } ++ ++ if (nic->nl_process_thread != INVALID_THREAD) { ++ LOG_DEBUG(PFX "%s: Canceling nic nl thread", nic->log_name); ++ ++ rc = pthread_cancel(nic->nl_process_thread); ++ if (rc != 0) ++ LOG_DEBUG(PFX "%s: Couldn't send cancel to nic nl " ++ "thread", nic->log_name); ++ ++ nic->nl_process_thread = INVALID_THREAD; ++ LOG_DEBUG(PFX "%s: nic nl thread cleaned", nic->log_name); ++ } else { ++ LOG_DEBUG(PFX "%s: NIC nl thread already canceled", ++ nic->log_name); ++ } ++ ++ current = prev = nic_list; ++ while (current != NULL) { ++ if (current == nic) ++ break; ++ ++ prev = current; ++ current = current->next; ++ } ++ ++ if (current != NULL) { ++ if (current == nic_list) ++ nic_list = current->next; ++ else ++ prev->next = current->next; ++ ++ /* Before freeing the nic, must free all the associated ++ nic_iface */ ++ nic_iface = current->nic_iface; ++ while (nic_iface != NULL) { ++ vlan_iface = nic_iface->vlan_next; ++ while (vlan_iface != NULL) { ++ next_nic_iface = vlan_iface->vlan_next; ++ free(vlan_iface); ++ vlan_iface = next_nic_iface; ++ } ++ next_nic_iface = nic_iface->next; ++ free(nic_iface); ++ nic_iface = next_nic_iface; ++ } ++ free(nic); ++ } else { ++ LOG_ERR(PFX "%s: Couldn't find nic to remove", nic->log_name); ++ } ++ ++ return 0; ++} ++ ++/** ++ * nic_close() - Used to indicate to a NIC that it should close ++ * Must be called with nic->nic_mutex ++ * @param nic - the nic to close ++ * @param graceful - ALLOW_GRACEFUL_SHUTDOWN will check the nic state ++ * before proceeding to close() ++ * FORCE_SHUTDOWN will force the nic to close() ++ * reguardless of the state ++ * @param clean - this will free the proper strings assoicated ++ * with the NIC ++ * ++ */ ++void nic_close(nic_t *nic, NIC_SHUTDOWN_T graceful, int clean) ++{ ++ int rc; ++ nic_interface_t *nic_iface, *vlan_iface; ++ struct stat file_stat; ++ ++ /* The NIC could be configured by the uIP config file ++ * but not assoicated with a hardware library just yet ++ * we will need to check for this */ ++ if (nic->ops == NULL) { ++ LOG_WARN(PFX "%s: when closing nic->ops == NULL", ++ nic->log_name); ++ goto error; ++ } ++ ++ /* Check if the file node exists */ ++ rc = stat(nic->uio_device_name, &file_stat); ++ if ((rc == 0) && (nic->ops)) ++ rc = (*nic->ops->close) (nic, graceful); ++ if (rc != 0) { ++ LOG_ERR(PFX "%s: Could not close nic", nic->log_name); ++ } else { ++ nic->state = NIC_STOPPED; ++ nic->flags &= ~NIC_ENABLED; ++ nic->flags |= NIC_DISABLED; ++ } ++ ++ nic_iface = nic->nic_iface; ++ while (nic_iface != NULL) { ++ if (!((nic_iface->flags & NIC_IFACE_PERSIST) == ++ NIC_IFACE_PERSIST)) { ++ uip_reset(&nic_iface->ustack); ++ vlan_iface = nic_iface->vlan_next; ++ while (vlan_iface != NULL) { ++ uip_reset(&vlan_iface->ustack); ++ vlan_iface = vlan_iface->vlan_next; ++ } ++ } ++ nic_iface = nic_iface->next; ++ } ++ ++ /* The NIC must be destroyed and init'ed once again, ++ * POSIX defines that the mutex will be undefined it ++ * init'ed twice without a destroy */ ++ pthread_mutex_destroy(&nic->xmit_mutex); ++ pthread_mutex_init(&nic->xmit_mutex, NULL); ++ ++ if (clean & FREE_CONFIG_NAME) { ++ /* Free any named strings we might be holding onto */ ++ if (nic->flags & NIC_CONFIG_NAME_MALLOC) { ++ free(nic->config_device_name); ++ nic->flags &= ~NIC_CONFIG_NAME_MALLOC; ++ } ++ nic->config_device_name = NULL; ++ } ++ ++ if (clean & FREE_UIO_NAME) { ++ if (nic->flags & NIC_UIO_NAME_MALLOC) { ++ free(nic->uio_device_name); ++ nic->uio_device_name = NULL; ++ ++ nic->flags &= ~NIC_UIO_NAME_MALLOC; ++ } ++ } ++ ++ LOG_ERR(PFX "%s: nic closed", nic->log_name); ++error: ++ return; ++} ++ ++/** ++ * nic_iface_init() - This function is used to add an interface to the ++ * structure cnic_uio ++ * @return 0 on success, <0 on failure ++ */ ++nic_interface_t *nic_iface_init() ++{ ++ nic_interface_t *nic_iface = malloc(sizeof(*nic_iface)); ++ if (nic_iface == NULL) { ++ LOG_ERR("Could not allocate space for nic iface"); ++ return NULL; ++ } ++ ++ memset(nic_iface, 0, sizeof(*nic_iface)); ++ nic_iface->next = NULL; ++ nic_iface->vlan_next = NULL; ++ nic_iface->iface_num = IFACE_NUM_INVALID; ++ nic_iface->request_type = IP_CONFIG_OFF; ++ ++ return nic_iface; ++} ++ ++/** ++ * nic_add_nic_iface() - This function is used to add an interface to the ++ * nic structure ++ * Called with nic_mutex held ++ * @param nic - struct nic device to add the interface to ++ * @param nic_iface - network interface used to add to the nic ++ * @return 0 on success, <0 on failure ++ */ ++int nic_add_nic_iface(nic_t *nic, nic_interface_t *nic_iface) ++{ ++ nic_interface_t *current, *prev; ++ ++ /* Make sure it doesn't already exist */ ++ current = nic_find_nic_iface(nic, nic_iface->protocol, ++ nic_iface->vlan_id, nic_iface->iface_num, ++ nic_iface->request_type); ++ if (current) { ++ LOG_DEBUG(PFX "%s: nic interface for VLAN: %d, protocol: %d" ++ " already exist", nic->log_name, nic_iface->vlan_id, ++ nic_iface->protocol); ++ return 0; ++ } ++ ++ prev = NULL; ++ current = nic->nic_iface; ++ while (current != NULL) { ++ if (current->protocol == nic_iface->protocol) { ++ /* Replace parent */ ++ nic_iface->vlan_next = current; ++ nic_iface->next = current->next; ++ current->next = NULL; ++ if (prev) ++ prev->next = nic_iface; ++ else ++ nic->nic_iface = nic_iface; ++ goto done; ++ } ++ prev = current; ++ current = current->next; ++ } ++ nic_iface->next = nic->nic_iface; ++ nic->nic_iface = nic_iface; ++done: ++ /* Set nic_interface common fields */ ++ nic_iface->parent = nic; ++ memcpy(&nic_iface->ustack.uip_ethaddr.addr, nic->mac_addr, ETH_ALEN); ++ nic->num_of_nic_iface++; ++ ++ LOG_INFO(PFX "%s: Added nic interface for VLAN: %d, protocol: %d", ++ nic->log_name, nic_iface->vlan_id, nic_iface->protocol); ++ ++ return 0; ++} ++ ++/****************************************************************************** ++ * Routine to process interrupts from the NIC device ++ ******************************************************************************/ ++/** ++ * nic_process_intr() - Routine used to process interrupts from the hardware ++ * @param nic - NIC hardware to process the interrupt on ++ * @return 0 on success, <0 on failure ++ */ ++int nic_process_intr(nic_t *nic, int discard_check) ++{ ++ fd_set fdset; ++ int ret; ++ int count; ++ struct timeval tv; ++ ++ /* Simple sanity checks */ ++ if (discard_check != 1 && nic->state != NIC_RUNNING) { ++ LOG_ERR(PFX "%s: Couldn't process interupt NIC not running", ++ nic->log_name); ++ return -EBUSY; ++ } ++ ++ if (discard_check != 1 && nic->fd == INVALID_FD) { ++ LOG_ERR(PFX "%s: NIC fd not valid", nic->log_name); ++ return -EIO; ++ } ++ ++ FD_ZERO(&fdset); ++ FD_SET(nic->fd, &fdset); ++ ++ tv.tv_sec = 0; ++ pthread_mutex_lock(&nic->nic_mutex); ++ if (nic->flags & NIC_LONG_SLEEP) ++ tv.tv_usec = 1000; ++ else ++ tv.tv_usec = nic->rx_poll_usec; ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ /* Wait for an interrupt to come in or timeout */ ++ ret = select(nic->fd + 1, &fdset, NULL, NULL, &tv); ++ switch (ret) { ++ case 1: ++ /* Usually there should only be one file descriptor ready ++ * to read */ ++ break; ++ case 0: ++ return ret; ++ case -1: ++ LOG_ERR(PFX "%s: error waiting for interrupt: %s", ++ nic->log_name, strerror(errno)); ++ return 0; ++ default: ++ LOG_ERR(PFX "%s: unknown number of FD's, ignoring: %d ret", ++ nic->log_name, ret); ++ return 0; ++ } ++ ++ ret = read(nic->fd, &count, sizeof(count)); ++ pthread_mutex_lock(&nic->nic_mutex); ++ if (ret > 0) { ++ nic->stats.interrupts++; ++ LOG_PACKET(PFX "%s: interrupt count: %d prev: %d", ++ nic->log_name, count, nic->intr_count); ++ ++ if (count == nic->intr_count) { ++ LOG_PACKET(PFX "%s: got interrupt but count still the " ++ "same", nic->log_name, count); ++ } ++ ++ /* Check if we missed an interrupt. With UIO, ++ * the count should be incremental */ ++ if (count != nic->intr_count + 1) { ++ nic->stats.missed_interrupts++; ++ LOG_PACKET(PFX "%s: Missed interrupt! on %d not %d", ++ nic->log_name, count, nic->intr_count); ++ } ++ ++ nic->intr_count = count; ++ ++ (*nic->ops->clear_tx_intr) (nic); ++ ret = 1; ++ } ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ return ret; ++} ++ ++void prepare_ipv4_packet(nic_t *nic, ++ nic_interface_t *nic_iface, ++ struct uip_stack *ustack, packet_t *pkt) ++{ ++ u16_t ipaddr[2]; ++ arp_table_query_t arp_query; ++ dest_ipv4_addr_t dest_ipv4_addr; ++ struct arp_entry *tabptr; ++ int queue_rc; ++ int vlan_id = 0; ++ ++ /* If the rx vlan tag is not stripped and vlan is present in the pkt, ++ manual stripping is required because tx is using hw vlan tag! */ ++ if (pkt->network_layer == pkt->data_link_layer + ++ sizeof(struct uip_vlan_eth_hdr)) { ++ /* VLAN is detected in the pkt buf */ ++ memcpy(pkt->data_link_layer + 12, pkt->network_layer - 2, ++ pkt->buf_size - sizeof(struct uip_vlan_eth_hdr) + 2); ++ } ++ dest_ipv4_addr = uip_determine_dest_ipv4_addr(ustack, ipaddr); ++ if (dest_ipv4_addr == LOCAL_BROADCAST) { ++ uip_build_eth_header(ustack, ipaddr, NULL, pkt, vlan_id); ++ return; ++ } ++ ++ arp_query = is_in_arp_table(ipaddr, &tabptr); ++ ++ switch (arp_query) { ++ case IS_IN_ARP_TABLE: ++ uip_build_eth_header(ustack, ++ ipaddr, tabptr, pkt, vlan_id); ++ break; ++ case NOT_IN_ARP_TABLE: ++ queue_rc = nic_queue_tx_packet(nic, nic_iface, pkt); ++ if (queue_rc) { ++ LOG_ERR("could not queue TX packet: %d", queue_rc); ++ } else { ++ uip_build_arp_request(ustack, ipaddr); ++ } ++ break; ++ default: ++ LOG_ERR("Unknown arp state"); ++ break; ++ } ++} ++ ++void prepare_ipv6_packet(nic_t *nic, ++ nic_interface_t *nic_iface, ++ struct uip_stack *ustack, packet_t *pkt) ++{ ++ struct uip_eth_hdr *eth; ++ struct uip_vlan_eth_hdr *eth_vlan; ++ int vlan_id = 0; ++ ++ if (pkt->network_layer == pkt->data_link_layer + ++ sizeof(struct uip_vlan_eth_hdr)) { ++ /* VLAN is detected in the pkt buf */ ++ memcpy(pkt->data_link_layer + 12, pkt->network_layer - 2, ++ pkt->buf_size - sizeof(struct uip_vlan_eth_hdr) + 2); ++ } ++ eth = (struct uip_eth_hdr *)ustack->data_link_layer; ++ eth_vlan = (struct uip_vlan_eth_hdr *)ustack->data_link_layer; ++ if (vlan_id == 0) { ++ eth->type = htons(UIP_ETHTYPE_IPv6); ++ } else { ++ eth_vlan->tpid = htons(UIP_ETHTYPE_8021Q); ++ eth_vlan->vid = htons(vlan_id); ++ eth_vlan->type = htons(UIP_ETHTYPE_IPv6); ++ } ++} ++ ++void prepare_ustack(nic_t *nic, ++ nic_interface_t *nic_iface, ++ struct uip_stack *ustack, struct packet *pkt) ++{ ++ struct ether_header *eth = NULL; ++ ustack->uip_buf = pkt->buf; ++ ustack->uip_len = pkt->buf_size; ++ ++ pkt->nic = nic; ++ pkt->nic_iface = nic_iface; ++ ++ ustack->data_link_layer = pkt->buf; ++ /* Adjust the network layer pointer depending if ++ * there is a VLAN tag or not, or if the hardware ++ * has stripped out the ++ * VLAN tag */ ++ ustack->network_layer = ustack->data_link_layer + ++ sizeof(struct uip_eth_hdr); ++ /* Init buffer to be IPv6 */ ++ if (nic_iface->ustack.ip_config == IPV6_CONFIG_DHCP || ++ nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) { ++ eth = (struct ether_header *)ustack->data_link_layer; ++ eth->ether_type = htons(UIP_ETHTYPE_IPv6); ++ } ++} ++ ++int do_timers_per_nic_iface(nic_t *nic, nic_interface_t *nic_iface, ++ struct timer *arp_timer) ++{ ++ packet_t *pkt; ++ struct uip_stack *ustack = &nic_iface->ustack; ++ int i; ++ ++ pkt = get_next_free_packet(nic); ++ if (pkt == NULL) ++ return -EIO; ++ ++ if (nic_iface->protocol == AF_INET) { ++ for (i = 0; i < UIP_UDP_CONNS; i++) { ++ prepare_ustack(nic, nic_iface, ustack, pkt); ++ ++ uip_udp_periodic(ustack, i); ++ /* If the above function invocation resulted ++ * in data that should be sent out on the ++ * network, the global variable uip_len is ++ * set to a value > 0. */ ++ if (ustack->uip_len > 0) { ++ pkt->buf_size = ustack->uip_len; ++ ++ prepare_ipv4_packet(nic, nic_iface, ustack, ++ pkt); ++ ++ (*nic->ops->write) (nic, nic_iface, pkt); ++ ustack->uip_len = 0; ++ } ++ } ++ } else { ++ /* Added periodic poll for IPv6 NDP engine */ ++ if (ustack->ndpc != NULL) { /* If engine is active */ ++ prepare_ustack(nic, nic_iface, ustack, pkt); ++ ++ uip_ndp_periodic(ustack); ++ /* If the above function invocation resulted ++ * in data that should be sent out on the ++ * network, the global variable uip_len is ++ * set to a value > 0. */ ++ if (ustack->uip_len > 0) { ++ pkt->buf_size = ustack->uip_len; ++ prepare_ipv6_packet(nic, nic_iface, ustack, ++ pkt); ++ (*nic->ops->write) (nic, nic_iface, pkt); ++ ustack->uip_len = 0; ++ } ++ } ++ } ++ /* Call the ARP timer function every 10 seconds. */ ++ if (timer_expired(arp_timer)) { ++ timer_reset(arp_timer); ++ uip_arp_timer(); ++ } ++ put_packet_in_free_queue(pkt, nic); ++ return 0; ++} ++ ++static int check_timers(nic_t *nic, ++ struct timer *periodic_timer, struct timer *arp_timer) ++{ ++ if (timer_expired(periodic_timer)) { ++ nic_interface_t *nic_iface, *vlan_iface; ++ ++ timer_reset(periodic_timer); ++ ++ pthread_mutex_lock(&nic->nic_mutex); ++ ++ nic_iface = nic->nic_iface; ++ while (nic_iface != NULL) { ++ do_timers_per_nic_iface(nic, nic_iface, arp_timer); ++ vlan_iface = nic_iface->vlan_next; ++ while (vlan_iface != NULL) { ++ do_timers_per_nic_iface(nic, vlan_iface, ++ arp_timer); ++ vlan_iface = vlan_iface->vlan_next; ++ } ++ nic_iface = nic_iface->next; ++ } ++ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ } ++ return 0; ++} ++ ++int process_packets(nic_t *nic, ++ struct timer *periodic_timer, ++ struct timer *arp_timer, nic_interface_t *nic_iface) ++{ ++ int rc; ++ packet_t *pkt; ++ ++ pkt = get_next_free_packet(nic); ++ if (pkt == NULL) { ++ LOG_DEBUG(PFX "%s: Couldn't get buffer for processing packet", ++ nic->log_name); ++ return -ENOMEM; ++ } ++ ++ pthread_mutex_lock(&nic->nic_mutex); ++ rc = (*nic->ops->read) (nic, pkt); ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ if ((rc != 0) && (pkt->buf_size > 0)) { ++ uint16_t type = 0; ++ int af_type = 0; ++ struct uip_stack *ustack; ++ uint16_t vlan_id; ++ ++ pkt->data_link_layer = pkt->buf; ++ ++ vlan_id = pkt->vlan_tag & 0xFFF; ++ if ((vlan_id == 0) || ++ (NIC_VLAN_STRIP_ENABLED & nic->flags)) { ++ struct uip_eth_hdr *hdr = ETH_BUF(pkt->buf); ++ type = ntohs(hdr->type); ++ pkt->network_layer = pkt->data_link_layer + ++ sizeof(struct uip_eth_hdr); ++ } else { ++ struct uip_vlan_eth_hdr *hdr = VLAN_ETH_BUF(pkt->buf); ++ type = ntohs(hdr->type); ++ pkt->network_layer = pkt->data_link_layer + ++ sizeof(struct uip_vlan_eth_hdr); ++ } ++ ++ switch (type) { ++ case UIP_ETHTYPE_IPv6: ++ af_type = AF_INET6; ++ break; ++ case UIP_ETHTYPE_IPv4: ++ case UIP_ETHTYPE_ARP: ++ af_type = AF_INET; ++ break; ++ default: ++ LOG_PACKET(PFX "%s: Ignoring vlan:0x%x ethertype:0x%x", ++ nic->log_name, vlan_id, type); ++ goto done; ++ } ++ ++ pthread_mutex_lock(&nic->nic_mutex); ++ ++ /* check if we have the given VLAN interface */ ++ if (nic_iface != NULL) { ++ if (vlan_id != nic_iface->vlan_id) { ++ /* Matching nic_iface not found, drop */ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ rc = EINVAL; /* Return the +error code */ ++ goto done; ++ } ++ goto nic_iface_present; ++ } ++ ++ /* Best effort to find the correct instance ++ Input: protocol and vlan_tag */ ++ nic_iface = nic_find_nic_iface(nic, af_type, vlan_id, ++ IFACE_NUM_INVALID, ++ IP_CONFIG_OFF); ++ if (nic_iface == NULL) { ++ /* Matching nic_iface not found */ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ LOG_PACKET(PFX "%s: Couldn't find interface for " ++ "VLAN: %d af_type %d", ++ nic->log_name, vlan_id, af_type); ++ rc = EINVAL; /* Return the +error code */ ++ goto done; ++ } ++nic_iface_present: ++ pkt->nic_iface = nic_iface; ++ ++ ustack = &nic_iface->ustack; ++ ++ ustack->uip_buf = pkt->buf; ++ ustack->uip_len = pkt->buf_size; ++ ustack->data_link_layer = pkt->buf; ++ ++ /* Adjust the network layer pointer depending if there is a ++ * VLAN tag or not, or if the hardware has stripped out the ++ * VLAN tag */ ++ if ((vlan_id == 0) || ++ (NIC_VLAN_STRIP_ENABLED & nic->flags)) ++ ustack->network_layer = ustack->data_link_layer + ++ sizeof(struct uip_eth_hdr); ++ else ++ ustack->network_layer = ustack->data_link_layer + ++ sizeof(struct uip_vlan_eth_hdr); ++ ++ /* determine how we should process this packet based on the ++ * ethernet type */ ++ switch (type) { ++ case UIP_ETHTYPE_IPv6: ++ uip_input(ustack); ++ if (ustack->uip_len > 0) { ++ /* The pkt generated has already consulted ++ the IPv6 ARP table */ ++ pkt->buf_size = ustack->uip_len; ++ prepare_ipv6_packet(nic, nic_iface, ++ ustack, pkt); ++ ++ (*nic->ops->write) (nic, nic_iface, pkt); ++ } ++ break; ++ case UIP_ETHTYPE_IPv4: ++ uip_arp_ipin(ustack, pkt); ++ uip_input(ustack); ++ /* If the above function invocation resulted ++ * in data that should be sent out on the ++ * network, the global variable uip_len is ++ * set to a value > 0. */ ++ if (ustack->uip_len > 0) { ++ prepare_ipv4_packet(nic, nic_iface, ++ ustack, pkt); ++ ++ (*nic->ops->write) (nic, nic_iface, pkt); ++ } ++ ++ break; ++ case UIP_ETHTYPE_ARP: ++ uip_arp_arpin(nic_iface, ustack, pkt); ++ ++ /* If the above function invocation resulted ++ * in data that should be sent out on the ++ * network, the global variable uip_len ++ * is set to a value > 0. */ ++ if (pkt->buf_size > 0) ++ (*nic->ops->write) (nic, nic_iface, pkt); ++ break; ++ } ++ ustack->uip_len = 0; ++ pthread_mutex_unlock(&nic->nic_mutex); ++ } ++ ++done: ++ put_packet_in_free_queue(pkt, nic); ++ ++ return rc; ++} ++ ++static int process_dhcp_loop(nic_t *nic, ++ nic_interface_t *nic_iface, ++ struct timer *periodic_timer, ++ struct timer *arp_timer) ++{ ++ struct dhcpc_state *s; ++ struct ndpc_state *n; ++ int rc; ++ struct timeval start_time; ++ struct timeval current_time; ++ struct timeval wait_time; ++ struct timeval total_time; ++ ++ /* 10s loop time to wait for DHCP */ ++ switch (nic_iface->ustack.ip_config) { ++ case IPV4_CONFIG_DHCP: ++ wait_time.tv_sec = 10; ++ break; ++ case IPV6_CONFIG_DHCP: ++ wait_time.tv_sec = 15; ++ break; ++ case IPV6_CONFIG_STATIC: ++ wait_time.tv_sec = 4; ++ break; ++ default: ++ wait_time.tv_sec = 2; ++ } ++ wait_time.tv_usec = 0; ++ ++ s = nic_iface->ustack.dhcpc; ++ n = nic_iface->ustack.ndpc; ++ ++ if (gettimeofday(&start_time, NULL)) { ++ LOG_ERR(PFX "%s: Couldn't get time of day to start DHCP timer", ++ nic->log_name); ++ return -EIO; ++ } ++ ++ timeradd(&start_time, &wait_time, &total_time); ++ ++ periodic_timer->start = periodic_timer->start - ++ periodic_timer->interval; ++ ++ while ((event_loop_stop == 0) && ++ (nic->flags & NIC_ENABLED) && !(nic->flags & NIC_GOING_DOWN)) { ++ ++ if (nic_iface->ustack.ip_config == IPV4_CONFIG_DHCP) { ++ if (s->state == STATE_CONFIG_RECEIVED) ++ break; ++ } ++ if (nic_iface->ustack.ip_config == IPV6_CONFIG_DHCP || ++ nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) { ++ if (n->state == NDPC_STATE_BACKGROUND_LOOP) ++ break; ++ } ++ ++ /* Check the periodic and ARP timer */ ++ check_timers(nic, periodic_timer, arp_timer); ++ ++ rc = nic_process_intr(nic, 1); ++ ++ while ((rc > 0) && (!(nic->flags & NIC_GOING_DOWN))) { ++ rc = process_packets(nic, ++ periodic_timer, ++ arp_timer, nic_iface); ++ } ++ ++ if (gettimeofday(¤t_time, NULL)) { ++ LOG_ERR(PFX "%s: Couldn't get current time for " ++ "DHCP start", nic->log_name); ++ return -EIO; ++ } ++ ++ if (timercmp(&total_time, ¤t_time, <)) { ++ LOG_ERR(PFX "%s: timeout waiting for DHCP/NDP", ++ nic->log_name); ++ if (nic_iface->ustack.ip_config == IPV6_CONFIG_DHCP || ++ nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) ++ n->retry_count = IPV6_MAX_ROUTER_SOL_RETRY; ++ return -EIO; ++ } ++ } ++ ++ if (nic->flags & NIC_GOING_DOWN) ++ return -EIO; ++ else if (nic->flags & NIC_DISABLED) ++ return -EINVAL; ++ else ++ return 0; ++} ++ ++/* Called with nic_mutex locked */ ++static int do_acquisition(nic_t *nic, nic_interface_t *nic_iface, ++ struct timer *periodic_timer, struct timer *arp_timer) ++{ ++ struct in_addr addr; ++ struct in6_addr addr6; ++ char buf[INET6_ADDRSTRLEN]; ++ int rc = -1; ++ ++ /* New acquisition */ ++ uip_init(&nic_iface->ustack, nic->flags & NIC_IPv6_ENABLED); ++ memcpy(&nic_iface->ustack.uip_ethaddr.addr, nic->mac_addr, ETH_ALEN); ++ ++ LOG_INFO(PFX "%s: Initialized ip stack: VLAN: %d", ++ nic->log_name, nic_iface->vlan_id); ++ ++ LOG_INFO(PFX "%s: mac: %02x:%02x:%02x:%02x:%02x:%02x", ++ nic->log_name, ++ nic_iface->mac_addr[0], ++ nic_iface->mac_addr[1], ++ nic_iface->mac_addr[2], ++ nic_iface->mac_addr[3], ++ nic_iface->mac_addr[4], ++ nic_iface->mac_addr[5]); ++ ++ switch (nic_iface->ustack.ip_config) { ++ case IPV4_CONFIG_STATIC: ++ memcpy(&addr.s_addr, nic_iface->ustack.hostaddr, ++ sizeof(addr.s_addr)); ++ ++ LOG_INFO(PFX "%s: Using IP address: %s", ++ nic->log_name, inet_ntoa(addr)); ++ ++ memcpy(&addr.s_addr, nic_iface->ustack.netmask, ++ sizeof(addr.s_addr)); ++ ++ LOG_INFO(PFX "%s: Using netmask: %s", ++ nic->log_name, inet_ntoa(addr)); ++ ++ set_uip_stack(&nic_iface->ustack, ++ NULL, NULL, NULL, ++ nic_iface->mac_addr); ++ break; ++ ++ case IPV4_CONFIG_DHCP: ++ set_uip_stack(&nic_iface->ustack, ++ NULL, NULL, NULL, ++ nic_iface->mac_addr); ++ if (dhcpc_init(nic, &nic_iface->ustack, ++ nic_iface->mac_addr, ETH_ALEN)) { ++ if (nic_iface->ustack.dhcpc) { ++ LOG_DEBUG(PFX "%s: DHCPv4 engine already " ++ "initialized!", nic->log_name); ++ goto skip; ++ } else { ++ LOG_DEBUG(PFX "%s: DHCPv4 engine failed " ++ "initialization!", nic->log_name); ++ goto error; ++ } ++ } ++ pthread_mutex_unlock(&nic->nic_mutex); ++ rc = process_dhcp_loop(nic, nic_iface, periodic_timer, ++ arp_timer); ++ pthread_mutex_lock(&nic->nic_mutex); ++ ++ if (rc) { ++ LOG_ERR(PFX "%s: DHCP failed", nic->log_name); ++ /* For DHCPv4 failure, the ustack must be cleaned so ++ it can re-acquire on the next iscsid request */ ++ uip_reset(&nic_iface->ustack); ++ ++ /* Signal that the device enable is ++ done */ ++ pthread_cond_broadcast(&nic->enable_done_cond); ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ if (nic->enable_thread == INVALID_THREAD) ++ goto dhcp_err; ++ ++ rc = pthread_cancel(nic->enable_thread); ++ if (rc != 0) ++ LOG_ERR(PFX "%s: Couldn't cancel " ++ "enable nic thread", nic->log_name); ++dhcp_err: ++ pthread_mutex_lock(&nic->nic_mutex); ++ goto error; ++ } ++ ++ if (nic->flags & NIC_DISABLED) { ++ /* Break out of this loop */ ++ break; ++ } ++ ++ LOG_INFO(PFX "%s: Initialized dhcp client", nic->log_name); ++ break; ++ ++ case IPV6_CONFIG_DHCP: ++ case IPV6_CONFIG_STATIC: ++ if (ndpc_init(nic, &nic_iface->ustack, nic_iface->mac_addr, ++ ETH_ALEN)) { ++ LOG_DEBUG(PFX "%s: IPv6 engine already initialized!", ++ nic->log_name); ++ goto skip; ++ } ++ pthread_mutex_unlock(&nic->nic_mutex); ++ rc = process_dhcp_loop(nic, nic_iface, periodic_timer, ++ arp_timer); ++ pthread_mutex_lock(&nic->nic_mutex); ++ if (rc) { ++ /* Don't reset and allow to use RA and LL */ ++ LOG_ERR(PFX "%s: IPv6 DHCP/NDP failed", nic->log_name); ++ } ++ if (nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) { ++ memcpy(&addr6.s6_addr, nic_iface->ustack.hostaddr6, ++ sizeof(addr6.s6_addr)); ++ inet_ntop(AF_INET6, addr6.s6_addr, buf, sizeof(buf)); ++ LOG_INFO(PFX "%s: hostaddr IP: %s", nic->log_name, buf); ++ memcpy(&addr6.s6_addr, nic_iface->ustack.netmask6, ++ sizeof(addr6.s6_addr)); ++ inet_ntop(AF_INET6, addr6.s6_addr, buf, sizeof(buf)); ++ LOG_INFO(PFX "%s: netmask IP: %s", nic->log_name, buf); ++ } ++ break; ++ ++ default: ++ LOG_INFO(PFX "%s: ipconfig = %d?", nic->log_name, ++ nic_iface->ustack.ip_config); ++ } ++skip: ++ /* Mark acquisition done for this nic iface */ ++ nic_iface->flags &= ~NIC_IFACE_ACQUIRE; ++ ++ LOG_INFO(PFX "%s: enabled vlan %d protocol: %d", nic->log_name, ++ nic_iface->vlan_id, nic_iface->protocol); ++ return 0; ++ ++error: ++ return -EIO; ++} ++ ++ ++void *nic_loop(void *arg) ++{ ++ nic_t *nic = (nic_t *) arg; ++ int rc = -1; ++ sigset_t set; ++ struct timer periodic_timer, arp_timer; ++ ++ sigfillset(&set); ++ rc = pthread_sigmask(SIG_BLOCK, &set, NULL); ++ if (rc != 0) { ++ /* TODO: determine if we need to exit this thread if we fail ++ * to set the signal mask */ ++ LOG_ERR(PFX "%s: Couldn't set signal mask", nic->log_name); ++ } ++ ++ /* Signal the device to enable itself */ ++ pthread_mutex_lock(&nic->nic_mutex); ++ pthread_cond_signal(&nic->nic_loop_started_cond); ++ ++ /* nic_mutex must be locked */ ++ while ((event_loop_stop == 0) && ++ !(nic->flags & NIC_EXIT_MAIN_LOOP) && ++ !(nic->flags & NIC_GOING_DOWN)) { ++ nic_interface_t *nic_iface, *vlan_iface; ++ ++ if (nic->flags & NIC_DISABLED) { ++ LOG_DEBUG(PFX "%s: Waiting to be enabled", ++ nic->log_name); ++ ++ /* Wait for the device to be enabled */ ++ /* nic_mutex is already locked */ ++ pthread_cond_wait(&nic->enable_wait_cond, ++ &nic->nic_mutex); ++ ++ if (nic->state == NIC_EXIT) { ++ pthread_mutex_unlock(&nic->nic_mutex); ++ pthread_exit(NULL); ++ } ++ LOG_DEBUG(PFX "%s: is now enabled", nic->log_name); ++ } ++ /* initialize the device to send/rec data */ ++ rc = (*nic->ops->open) (nic); ++ if (rc != 0) { ++ LOG_ERR(PFX "%s: Could not initialize CNIC UIO device", ++ nic->log_name); ++ ++ if (rc == -ENOTSUP) ++ nic->flags |= NIC_EXIT_MAIN_LOOP; ++ else ++ nic->flags &= ~NIC_ENABLED; ++ ++ /* Signal that the device enable is done */ ++ pthread_cond_broadcast(&nic->enable_done_cond); ++ pthread_mutex_unlock(&nic->nic_mutex); ++ goto dev_close; ++ } ++ nic_set_all_nic_iface_mac_to_parent(nic); ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ rc = alloc_free_queue(nic, 5); ++ if (rc != 5) { ++ if (rc != 0) { ++ LOG_WARN(PFX "%s: Allocated %d packets " ++ "instead of %d", nic->log_name, rc, 5); ++ } else { ++ LOG_ERR(PFX "%s: No packets allocated " ++ "instead of %d", nic->log_name, 5); ++ /* Signal that the device enable is done */ ++ pthread_cond_broadcast(&nic->enable_done_cond); ++ goto dev_close; ++ } ++ } ++ /* Indication for the nic_disable routine that the nic ++ has started running */ ++ nic->state = NIC_STARTED_RUNNING; ++ ++ /* Initialize the system clocks */ ++ timer_set(&periodic_timer, CLOCK_SECOND / 2); ++ timer_set(&arp_timer, CLOCK_SECOND * 10); ++ ++ /* Prepare the stack for each of the VLAN interfaces */ ++ pthread_mutex_lock(&nic->nic_mutex); ++ ++ /* If DHCP fails, exit loop and restart the engine */ ++ nic_iface = nic->nic_iface; ++ while (nic_iface != NULL) { ++ if (nic_iface->flags & NIC_IFACE_ACQUIRE) { ++ do_acquisition(nic, nic_iface, ++ &periodic_timer, ++ &arp_timer); ++ } ++ vlan_iface = nic_iface->vlan_next; ++ while (vlan_iface != NULL) { ++ if (vlan_iface->flags & NIC_IFACE_ACQUIRE) { ++ do_acquisition(nic, vlan_iface, ++ &periodic_timer, ++ &arp_timer); ++ } ++ vlan_iface = vlan_iface->next; ++ } ++ nic_iface = nic_iface->next; ++ } ++ if (nic->flags & NIC_DISABLED) { ++ LOG_WARN(PFX "%s: nic was disabled during nic loop, " ++ "closing flag 0x%x", ++ nic->log_name, nic->flags); ++ /* Signal that the device enable is done */ ++ pthread_cond_broadcast(&nic->enable_done_cond); ++ pthread_mutex_unlock(&nic->nic_mutex); ++ goto dev_close_free; ++ } ++ ++ /* This is when we start the processing of packets */ ++ nic->start_time = time(NULL); ++ nic->state = NIC_RUNNING; ++ ++ nic->flags &= ~NIC_ENABLED_PENDING; ++ ++ /* Signal that the device enable is done */ ++ pthread_cond_broadcast(&nic->enable_done_cond); ++ ++ LOG_INFO(PFX "%s: entering main nic loop", nic->log_name); ++ ++ while ((nic->state == NIC_RUNNING) && ++ (event_loop_stop == 0) && ++ !(nic->flags & NIC_GOING_DOWN)) { ++ pthread_mutex_unlock(&nic->nic_mutex); ++ /* Check the periodic and ARP timer */ ++ check_timers(nic, &periodic_timer, &arp_timer); ++ rc = nic_process_intr(nic, 0); ++ while ((rc > 0) && ++ (nic->state == NIC_RUNNING) && ++ !(nic->flags & NIC_GOING_DOWN)) { ++ rc = process_packets(nic, ++ &periodic_timer, ++ &arp_timer, NULL); ++ } ++ pthread_mutex_lock(&nic->nic_mutex); ++ } ++ ++ LOG_INFO(PFX "%s: exited main processing loop", nic->log_name); ++ ++dev_close_free: ++ free_free_queue(nic); ++dev_close: ++ ++ if (nic->flags & NIC_GOING_DOWN) { ++ nic_close(nic, 1, FREE_NO_STRINGS); ++ ++ nic->flags &= ~NIC_GOING_DOWN; ++ } else { ++ pthread_mutex_destroy(&nic->xmit_mutex); ++ pthread_mutex_init(&nic->xmit_mutex, NULL); ++ } ++ nic->pending_count = 0; ++ ++ if (!(nic->flags & NIC_EXIT_MAIN_LOOP)) { ++ /* Signal we are done closing CNIC/UIO device */ ++ pthread_cond_broadcast(&nic->disable_wait_cond); ++ } ++ } ++ /* clean up the nic flags */ ++ nic->flags &= ~NIC_ENABLED_PENDING; ++ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ LOG_INFO(PFX "%s: nic loop thread exited", nic->log_name); ++ ++ nic->thread = INVALID_THREAD; ++ ++ pthread_exit(NULL); ++} +diff --git a/iscsiuio/src/unix/nic.h b/iscsiuio/src/unix/nic.h +new file mode 100644 +index 0000000..ec15781 +--- /dev/null ++++ b/iscsiuio/src/unix/nic.h +@@ -0,0 +1,406 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * nic.h - NIC header file ++ * ++ */ ++ ++#include ++ ++#ifndef __NIC_H__ ++#define __NIC_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "nic_nl.h" ++#include "packet.h" ++#include "uip.h" ++#include "timer.h" ++ ++#include "iscsi_if.h" ++ ++/* Foward declarations */ ++struct nic_ops; ++struct nic_lib_handle; ++struct packet; ++struct nic_op; ++ ++extern pthread_mutex_t nic_lib_list_mutex; ++extern struct nic_lib_handle *nic_lib_list; ++ ++/* Used to store a list of active cnic devices */ ++extern pthread_mutex_t nic_list_mutex; ++extern struct nic *nic_list; ++ ++extern void *nl_process_handle_thread(void *arg); ++ ++/******************************************************************************* ++ * Constants ++ ******************************************************************************/ ++#define MAX_PCI_DEVICE_ENTRIES 64 /* Maxium number of pci_device_id ++ entries a hw library may contain */ ++ ++#define FREE_CONFIG_NAME 0x0001 ++#define FREE_UIO_NAME 0x0002 ++#define FREE_ALL_STRINGS (FREE_CONFIG_NAME | FREE_UIO_NAME) ++#define FREE_NO_STRINGS 0x0000 ++ ++/****************************************************************************** ++ * Enumerations ++ ******************************************************************************/ ++typedef enum { ++ ALLOW_GRACEFUL_SHUTDOWN = 1, ++ FORCE_SHUTDOWN = 2, ++} NIC_SHUTDOWN_T; ++ ++/******************************************************************************* ++ * Structure used to hold PCI vendor, device, subvendor and subdevice ID's ++ ******************************************************************************/ ++struct pci_device_id { ++ const uint32_t vendor, device; /* Vendor and device ID or PCI_ANY_ID */ ++ const uint32_t subvendor, subdevice; /* Subsystem ID's/PCI_ANY_ID */ ++ const char *device_name; /* Data private to the driver */ ++}; ++ ++/****************************************************************************** ++ * NIC statistics structure ++ ******************************************************************************/ ++struct nic_stats { ++ uint64_t interrupts; ++ uint64_t missed_interrupts; ++ ++ struct { ++ uint64_t packets; ++ uint64_t bytes; ++ } tx; ++ ++ struct { ++ uint64_t packets; ++ uint64_t bytes; ++ } rx; ++}; ++ ++/****************************************************************************** ++ * NIC interface structure ++ ******************************************************************************/ ++typedef struct nic_interface { ++ struct nic_interface *vlan_next; ++ struct nic_interface *next; ++ struct nic *parent; ++ ++ uint16_t protocol; ++ uint16_t flags; ++#define NIC_IFACE_PERSIST (1<<0) ++#define NIC_IFACE_ACQUIRE (1<<1) ++#define NIC_IFACE_PATHREQ_WAIT1 (1<<2) ++#define NIC_IFACE_PATHREQ_WAIT2 (1<<3) ++#define NIC_IFACE_PATHREQ_WAIT (NIC_IFACE_PATHREQ_WAIT1 | \ ++ NIC_IFACE_PATHREQ_WAIT2) ++ uint8_t mac_addr[ETH_ALEN]; ++ uint8_t vlan_priority; ++ uint16_t vlan_id; ++#define NO_VLAN 0x8000 ++ ++ uint16_t mtu; ++ time_t start_time; ++ ++ struct uip_stack ustack; ++ ++#define IFACE_NUM_PRESENT (1<<0) ++#define IFACE_NUM_INVALID -1 ++ int iface_num; ++ int request_type; ++} nic_interface_t; ++ ++/****************************************************************************** ++ * NIC lib operations structure ++ ******************************************************************************/ ++struct nic_lib_ops { ++ /* Used to get the NIC library name */ ++ void (*get_library_name) (char **library_name, ++ size_t *library_name_size); ++ ++ /* Used to get to the PCI table supported by the NIC library */ ++ void (*get_pci_table) (struct pci_device_id **table, ++ uint32_t *entries); ++ ++ /* Used to get the version of this NIC library */ ++ void (*get_library_version) (char **version_string, ++ size_t *version_string_size); ++ ++ /* Used to get the NIC library build date */ ++ void (*get_build_date) (char **build_date_string, ++ size_t *build_date_string_size); ++ ++ /* Used to get the transport name assoicated with this library */ ++ void (*get_transport_name) (char **transport_name, ++ size_t *transport_name_size); ++ ++ /* Used to get the uio name assoicated with this library */ ++ void (*get_uio_name) (char **uio_name, size_t *uio_name_size); ++ ++}; ++ ++/******************************************************************************* ++ * NIC op table definition ++ ******************************************************************************/ ++typedef struct nic_ops { ++ struct nic_lib_ops lib_ops; ++ ++ char *description; ++ int (*open) (struct nic *); ++ int (*close) (struct nic *, NIC_SHUTDOWN_T); ++ int (*read) (struct nic *, struct packet *); ++ int (*write) (struct nic *, nic_interface_t *, struct packet *); ++ void *(*get_tx_pkt) (struct nic *); ++ void (*start_xmit) (struct nic *, size_t, u16_t vlan_id); ++ int (*clear_tx_intr) (struct nic *); ++ int (*handle_iscsi_path_req) (struct nic *, ++ int, ++ struct iscsi_uevent *ev, ++ struct iscsi_path *path, ++ nic_interface_t *nic_iface); ++} net_ops_t; ++ ++typedef struct nic_lib_handle { ++ struct nic_lib_handle *next; ++ ++ pthread_mutex_t mutex; ++ struct nic_ops *ops; ++} nic_lib_handle_t; ++ ++typedef struct nic { ++ struct nic *next; ++ ++ uint32_t flags; ++#define NIC_UNITIALIZED 0x0001 ++#define NIC_INITIALIZED 0x0002 ++#define NIC_ENABLED 0x0004 ++#define NIC_DISABLED 0x0008 ++#define NIC_IPv6_ENABLED 0x0010 ++#define NIC_ADDED_MULICAST 0x0020 ++#define NIC_LONG_SLEEP 0x0040 ++#define NIC_PATHREQ_WAIT 0x0080 ++ ++#define NIC_VLAN_STRIP_ENABLED 0x0100 ++#define NIC_MSIX_ENABLED 0x0200 ++#define NIC_TX_HAS_SENT 0x0400 ++#define NIC_ENABLED_PENDING 0x0800 ++ ++#define NIC_UIO_NAME_MALLOC 0x1000 ++#define NIC_CONFIG_NAME_MALLOC 0x2000 ++#define NIC_EXIT_MAIN_LOOP 0x4000 ++#define NIC_GOING_DOWN 0x8000 ++#define NIC_RESET_UIP 0x10000 ++ ++ uint16_t state; ++#define NIC_STOPPED 0x0001 ++#define NIC_STARTED_RUNNING 0x0002 ++#define NIC_RUNNING 0x0004 ++#define NIC_EXIT 0x0010 ++ ++ int fd; /* Holds the file descriptor to UIO */ ++ uint16_t uio_minor; /* Holds the UIO minor number */ ++ ++ uint32_t host_no; /* Holds the associated host number */ ++ ++ char *library_name; /* Name of the library to assoicate with */ ++ char *log_name; /* Human friendly name used in the log ++ file */ ++ char *config_device_name; /* Name read from the XML configuration ++ file */ ++ char eth_device_name[IFNAMSIZ]; /* Network interface name */ ++ char *uio_device_name; /* UIO device name */ ++ ++ uint32_t intr_count; /* Total UIO interrupt count */ ++ ++ int page_size; ++ ++ /* Held for nic ops manipulation */ ++ pthread_mutex_t nic_mutex; ++ ++ /* iSCSI ring ethernet MAC address */ ++ __u8 mac_addr[ETH_ALEN]; ++ ++ /* Used to manage the network interfaces of this device */ ++ __u32 num_of_nic_iface; ++ nic_interface_t *nic_iface; ++ ++ /* Wait for the device to be enabled */ ++ pthread_cond_t enable_wait_cond; ++ ++ /* Wait for the device to be finished enabled */ ++ pthread_cond_t enable_done_cond; ++ ++ /* Wait for the nic loop to start */ ++ pthread_cond_t nic_loop_started_cond; ++ ++ /* Wait for the device to be disabled */ ++ pthread_cond_t disable_wait_cond; ++ ++ /* Held when transmitting */ ++ pthread_mutex_t xmit_mutex; ++ ++ /* The thread this device is running on */ ++ pthread_t thread; ++ ++ /* The thread used to enable the device */ ++ pthread_t enable_thread; ++ ++ /* Statistical Information on this device */ ++ time_t start_time; ++ struct nic_stats stats; ++ ++ /* Number of retrys from iscsid */ ++ uint32_t pending_count; ++ uint32_t pathreq_pending_count; ++ ++#define DEFAULT_RX_POLL_USEC 100 /* usec */ ++ /* options enabled by the user */ ++ uint32_t rx_poll_usec; ++ ++ /* Used to hold hardware specific data */ ++ void *priv; ++ ++ /* Used to hold the TX packets that are needed to be sent */ ++ struct packet *tx_packet_queue; ++ ++ /* Mutex to protect the list of free packets */ ++ pthread_mutex_t free_packet_queue_mutex; ++ ++ /* Used to hold the free packets that are needed to be sent */ ++ struct packet *free_packet_queue; ++ ++ /* Points to the NIC library */ ++ nic_lib_handle_t *nic_library; ++ ++ /* Points to the PCI table entry */ ++ struct pci_device_id *pci_id; ++ ++ /* Used to process the interrupt */ ++ int (*process_intr) (struct nic *nic); ++ ++ struct nic_ops *ops; ++ ++ /* NL processing parameters */ ++ pthread_t nl_process_thread; ++ pthread_cond_t nl_process_cond; ++ pthread_cond_t nl_process_if_down_cond; ++ pthread_mutex_t nl_process_mutex; ++ int nl_process_if_down; ++ int nl_process_head; ++ int nl_process_tail; ++#define NIC_NL_PROCESS_MAX_RING_SIZE 128 ++#define NIC_NL_PROCESS_LAST_ENTRY (NIC_NL_PROCESS_MAX_RING_SIZE - 1) ++#define NIC_NL_PROCESS_NEXT_ENTRY(x) ((x + 1) & NIC_NL_PROCESS_MAX_RING_SIZE) ++ void *nl_process_ring[NIC_NL_PROCESS_MAX_RING_SIZE]; ++ ++ /* The thread used to perform ping */ ++ pthread_t ping_thread; ++} nic_t; ++ ++/****************************************************************************** ++ * Function Prototypes ++ *****************************************************************************/ ++int load_all_nic_libraries(); ++ ++nic_t *nic_init(); ++void nic_add(nic_t *nic); ++int nic_remove(nic_t *nic); ++ ++int nic_add_nic_iface(nic_t *nic, nic_interface_t *nic_iface); ++int nic_process_intr(nic_t *nic, int discard_check); ++ ++nic_interface_t *nic_iface_init(); ++ ++typedef enum { ++ NIC_LIBRARY_EXSITS = 1, ++ NIC_LIBRARY_DOESNT_EXIST = 2, ++} NIC_LIBRARY_EXIST_T; ++ ++NIC_LIBRARY_EXIST_T does_nic_uio_name_exist(char *name, ++ nic_lib_handle_t **handle); ++NIC_LIBRARY_EXIST_T does_nic_library_exist(char *name, ++ nic_lib_handle_t **handle); ++ ++/******************************************************************************* ++ * Packet management utility functions ++ ******************************************************************************/ ++struct packet *get_next_tx_packet(nic_t *nic); ++struct packet *get_next_free_packet(nic_t *nic); ++void put_packet_in_tx_queue(struct packet *pkt, nic_t *nic); ++void put_packet_in_free_queue(struct packet *pkt, nic_t *nic); ++ ++int unload_all_nic_libraries(); ++void nic_close(nic_t *nic, NIC_SHUTDOWN_T graceful, int clean); ++ ++/* Use this function to fill in minor number and uio, and eth names */ ++int nic_fill_name(nic_t *nic); ++ ++int enable_multicast(nic_t *nic); ++int disable_multicast(nic_t *nic); ++ ++void nic_set_all_nic_iface_mac_to_parent(nic_t *nic); ++int find_nic_lib_using_pci_id(uint32_t vendor, uint32_t device, ++ uint32_t subvendor, uint32_t subdevice, ++ nic_lib_handle_t **handle, ++ struct pci_device_id **pci_entry); ++ ++void *nic_loop(void *arg); ++ ++int nic_packet_capture(struct nic *, struct packet *pkt); ++ ++int process_packets(nic_t *nic, ++ struct timer *periodic_timer, ++ struct timer *arp_timer, nic_interface_t *nic_iface); ++ ++void prepare_ustack(nic_t *nic, ++ nic_interface_t *nic_iface, ++ struct uip_stack *ustack, struct packet *pkt); ++ ++void prepare_ipv4_packet(nic_t *nic, ++ nic_interface_t *nic_iface, ++ struct uip_stack *ustack, struct packet *pkt); ++ ++void prepare_ipv6_packet(nic_t *nic, ++ nic_interface_t *nic_iface, ++ struct uip_stack *ustack, struct packet *pkt); ++ ++#endif /* __NIC_H__ */ +diff --git a/iscsiuio/src/unix/nic_id.c b/iscsiuio/src/unix/nic_id.c +new file mode 100644 +index 0000000..6da0a38 +--- /dev/null ++++ b/iscsiuio/src/unix/nic_id.c +@@ -0,0 +1,364 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * nic_id.c - Using sysfs to determine the PCI vendor, device, subvendor and ++ * subdevice ID's ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "logger.h" ++#include "nic.h" ++ ++#define PFX "nic_id " ++ ++/******************************************************************************* ++ * Sysfs constant strings used to get PCI vendor, and device ID's ++ ******************************************************************************/ ++const char uio_vendor_id_template[] = "/sys/class/uio/uio%d/device/vendor"; ++const char uio_subvendor_id_template[] = ++ "/sys/class/uio/uio%d/device/subsystem_vendor"; ++const char uio_device_id_template[] = "/sys/class/uio/uio%d/device/device"; ++const char uio_subdevice_id_template[] = ++ "/sys/class/uio/uio%d/device/subsystem_device"; ++const char uio_device_symlink_template[] = "/sys/class/uio/uio%d/device"; ++ ++/** ++ * get_id() - Utility function to read hex values from sysfs ++ * @param nic - NIC device to use ++ * @param sysfs_template - sysfs path template to use ++ * @param sysfs_template_size - sysfs path template size in bytes ++ * @parm id - this is the value returned from the sysfs entry ++ * @return 0 on success <0 on failure ++ */ ++static int get_id(nic_t *nic, ++ const char *sysfs_template, ++ const size_t sysfs_template_size, uint32_t *id) ++{ ++ int rc = 0; ++ FILE *fp; ++ size_t chars_read; ++ char buf[7]; ++ char *path; ++ size_t path_size; ++ ++ path_size = sysfs_template_size + 4; ++ path = malloc(path_size); ++ if (path == NULL) { ++ LOG_ERR("Could not allocate memory for %s", sysfs_template); ++ return -ENOMEM; ++ } ++ ++ snprintf(path, path_size, sysfs_template, nic->uio_minor); ++ ++ fp = fopen(path, "r"); ++ if (fp == NULL) { ++ LOG_ERR(PFX "%s: Could not open path: %s [%s]", ++ nic->log_name, path, strerror(errno)); ++ rc = -EIO; ++ goto error_fopen; ++ } ++ ++ chars_read = fread(buf, sizeof(buf), 1, fp); ++ if (chars_read != 1) { ++ LOG_ERR(PFX "%s: Could not read from: %s [%s]", ++ nic->log_name, path, strerror(ferror(fp))); ++ rc = -EIO; ++ goto error; ++ } ++ ++ chars_read = sscanf(buf, "%x", id); ++ if (chars_read != 1) { ++ LOG_ERR(PFX "%s: Could interpret value: %s from: %s [%s]", ++ nic->log_name, buf, path, strerror(errno)); ++ rc = -EIO; ++ goto error; ++ } ++ ++error: ++ fclose(fp); ++ ++error_fopen: ++ free(path); ++ ++ return rc; ++} ++ ++static int get_vendor(nic_t *nic, uint32_t *id) ++{ ++ return get_id(nic, ++ uio_vendor_id_template, sizeof(uio_vendor_id_template), ++ id); ++} ++ ++static int get_subvendor(nic_t *nic, uint32_t *id) ++{ ++ return get_id(nic, ++ uio_subvendor_id_template, ++ sizeof(uio_subvendor_id_template), id); ++} ++ ++static int get_device(nic_t *nic, uint32_t *id) ++{ ++ return get_id(nic, ++ uio_device_id_template, ++ sizeof(uio_device_id_template), id); ++} ++ ++static int get_subdevice(nic_t *nic, uint32_t *id) ++{ ++ return get_id(nic, ++ uio_subdevice_id_template, ++ sizeof(uio_subdevice_id_template), id); ++} ++ ++int get_bus_slot_func_num(nic_t *nic, ++ uint32_t *bus, uint32_t *slot, uint32_t *func) ++{ ++ size_t size; ++ char *path, *tok, *tok2; ++ int path_tokens, i; ++ size_t path_size; ++ char *read_pci_bus_slot_func_str; ++ char pci_bus_slot_func_str[32]; ++ int rc; ++ char *saveptr; ++ ++ path_size = sizeof(uio_device_symlink_template) + 4; ++ path = malloc(path_size); ++ if (path == NULL) { ++ LOG_ERR(PFX "%s: Could not allocate path memory for %s", ++ nic->log_name, uio_device_symlink_template); ++ rc = -ENOMEM; ++ goto error_alloc_path; ++ } ++ ++ read_pci_bus_slot_func_str = malloc(128); ++ if (read_pci_bus_slot_func_str == NULL) { ++ LOG_ERR(PFX "%s: Could not allocate read pci bus memory for %s", ++ nic->log_name, uio_device_symlink_template); ++ rc = -ENOMEM; ++ goto error_alloc_read_pci_bus; ++ } ++ ++ snprintf(path, path_size, uio_device_symlink_template, nic->uio_minor); ++ ++ size = readlink(path, read_pci_bus_slot_func_str, 128); ++ if (size == -1) { ++ LOG_ERR(PFX "%s: Error with %s: %s", ++ nic->log_name, path, strerror(errno)); ++ rc = errno; ++ goto error; ++ } ++ ++ if (size > ((128) - 1)) { ++ read_pci_bus_slot_func_str[128 - 1] = '\0'; ++ LOG_ERR(PFX "%s: not enough space (%d) for reading PCI " ++ "slot:bus.func %s: %s", ++ nic->log_name, size, path, strerror(errno)); ++ rc = -EIO; ++ goto error; ++ } ++ ++ /* readlink() doesn't NULL terminate the string */ ++ read_pci_bus_slot_func_str[size] = '\0'; ++ ++ path_tokens = 0; ++ tok = strtok_r(read_pci_bus_slot_func_str, "/", &saveptr); ++ while (tok != NULL) { ++ path_tokens++; ++ tok = strtok_r(NULL, "/", &saveptr); ++ } ++ ++ size = readlink(path, read_pci_bus_slot_func_str, 128); ++ if (size == -1) { ++ LOG_ERR(PFX "%s: Error with %s: %s", ++ nic->log_name, path, strerror(errno)); ++ rc = errno; ++ goto error; ++ } ++ ++ if (size > ((128) - 1)) { ++ read_pci_bus_slot_func_str[128 - 1] = '\0'; ++ LOG_ERR(PFX "%s: not enough space for reading PCI " ++ "slot:bus.func %s: %s", ++ nic->log_name, path, strerror(errno)); ++ rc = -EIO; ++ goto error; ++ } ++ ++ /* readlink() doesn't NULL terminate the string */ ++ read_pci_bus_slot_func_str[size] = '\0'; ++ ++ tok = strtok_r(read_pci_bus_slot_func_str, "/", &saveptr); ++ for (i = 0; i < path_tokens - 1; i++) ++ tok = strtok_r(NULL, "/", &saveptr); ++ strcpy(pci_bus_slot_func_str, tok); ++ ++ tok = strtok_r(pci_bus_slot_func_str, ":", &saveptr); ++ if (tok == NULL) { ++ LOG_ERR(PFX "%s: Error with slot string: %s", ++ nic->log_name, pci_bus_slot_func_str); ++ rc = -EIO; ++ goto error; ++ } ++ ++ tok = strtok_r(NULL, ":", &saveptr); ++ if (tok == NULL) { ++ LOG_ERR(PFX "%s: Error parsing slot: %s", ++ nic->log_name, pci_bus_slot_func_str); ++ rc = -EIO; ++ goto error; ++ } ++ ++ sscanf(tok, "%x", bus); ++ ++ /* Need to extract the next token "xx.x" */ ++ tok = strtok_r(NULL, ":", &saveptr); ++ if (tok == NULL) { ++ LOG_ERR(PFX "%s: Error extracing bus.func: %s", ++ nic->log_name, pci_bus_slot_func_str); ++ rc = -EIO; ++ goto error; ++ } ++ ++ tok2 = strtok_r(tok, ".", &saveptr); ++ if (tok2 == NULL) { ++ LOG_ERR(PFX "%s: Error parsing bus: %s", ++ nic->log_name, pci_bus_slot_func_str); ++ rc = -EIO; ++ goto error; ++ } ++ ++ sscanf(tok2, "%x", slot); ++ ++ tok2 = strtok_r(NULL, ".", &saveptr); ++ if (tok2 == NULL) { ++ LOG_ERR(PFX "%s: Error parsing func: %s", ++ nic->log_name, pci_bus_slot_func_str); ++ rc = -EIO; ++ goto error; ++ } ++ ++ sscanf(tok2, "%x", func); ++ LOG_INFO(PFX "%s: is found at %02x:%02x.%02x", nic->log_name, ++ *bus, *slot, *func); ++ rc = 0; ++error: ++ free(read_pci_bus_slot_func_str); ++error_alloc_read_pci_bus: ++ free(path); ++error_alloc_path: ++ return rc; ++} ++ ++/** ++ * find_set_nic_lib() - Match the NIC library to the NIC ++ * @param nic - NIC device to determine which NIC library to use ++ * @return 0 on success <0 on failure ++ */ ++int find_set_nic_lib(nic_t *nic) ++{ ++ uint32_t vendor; ++ uint32_t subvendor; ++ uint32_t device; ++ uint32_t subdevice; ++ ++ uint32_t pci_bus; ++ uint32_t pci_slot; ++ uint32_t pci_func; ++ int rc = 0; ++ ++ nic_lib_handle_t *handle; ++ struct pci_device_id *pci_entry; ++ size_t name_size; ++ ++ rc = get_vendor(nic, &vendor); ++ if (rc != 0) { ++ LOG_ERR(PFX "%s: Could not get vendor id [0x%x]", ++ nic->log_name, rc); ++ return rc; ++ } ++ ++ rc = get_subvendor(nic, &subvendor); ++ if (rc != 0) { ++ LOG_ERR(PFX "%s: Could not get subvendor id [0x%x]", ++ nic->log_name, rc); ++ return rc; ++ } ++ ++ rc = get_device(nic, &device); ++ if (rc != 0) { ++ LOG_ERR(PFX "%s: Could not get device id [0x%x]", ++ nic->log_name, rc); ++ return rc; ++ } ++ ++ rc = get_subdevice(nic, &subdevice); ++ if (rc != 0) { ++ LOG_ERR(PFX "%s: Could not get subdevice id [0x%x]", ++ nic->log_name, rc); ++ return rc; ++ } ++ ++ get_bus_slot_func_num(nic, &pci_bus, &pci_slot, &pci_func); ++ ++ LOG_DEBUG(PFX "%s: Looking for device vendor: " ++ "0x%x subvendor: 0x%x device: 0x%x subdevice: 0x%x", ++ nic->log_name, vendor, subvendor, device, subdevice); ++ ++ rc = find_nic_lib_using_pci_id(vendor, device, subvendor, subdevice, ++ &handle, &pci_entry); ++ ++ if (rc != 0) { ++ LOG_WARN(PFX "%s: Couldn't find proper NIC library", ++ nic->log_name); ++ return rc; ++ } ++ ++ nic->nic_library = handle; ++ nic->pci_id = pci_entry; ++ ++ /* Prepare the NIC library op table */ ++ nic->ops = handle->ops; ++ (*nic->ops->lib_ops.get_library_name) (&nic->library_name, &name_size); ++ ++ return 0; ++} +diff --git a/iscsiuio/src/unix/nic_id.h b/iscsiuio/src/unix/nic_id.h +new file mode 100644 +index 0000000..340580f +--- /dev/null ++++ b/iscsiuio/src/unix/nic_id.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * nic_id.h - NIC uIP NetLink user space stack ++ * ++ */ ++#ifndef __NIC_ID_H__ ++#define __NIC_ID_H__ ++ ++int find_set_nic_lib(nic_t *nic); ++ ++int get_bus_slot_func_num(nic_t *nic, ++ uint32_t *bus, uint32_t *slot, uint32_t *func); ++ ++#endif /* __NIC_ID_H__ */ +diff --git a/iscsiuio/src/unix/nic_nl.c b/iscsiuio/src/unix/nic_nl.c +new file mode 100644 +index 0000000..391003f +--- /dev/null ++++ b/iscsiuio/src/unix/nic_nl.c +@@ -0,0 +1,678 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * nic_nl.c - NIC uIP NetLink user space stack ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "uip_arp.h" ++#include "logger.h" ++#include "options.h" ++ ++#include "nic.h" ++#include "nic_nl.h" ++#include "nic_utils.h" ++ ++/******************************************************************************* ++ * Constants ++ ******************************************************************************/ ++#define PFX "NIC_NL " ++ ++static u8_t nlm_sendbuf[NLM_BUF_DEFAULT_MAX]; ++ ++static struct sockaddr_nl src_addr; ++ ++static const struct sockaddr_nl dest_addr = { ++ .nl_family = AF_NETLINK, ++ .nl_pid = 0, /* kernel */ ++ .nl_groups = 0, /* unicast */ ++}; ++ ++#define POLL_NL 0 ++#define POLL_MAX 1 ++ ++/* Netlink */ ++int nl_sock = INVALID_FD; ++ ++static int nl_read(int ctrl_fd, char *data, int size, int flags) ++{ ++ int rc; ++ struct iovec iov; ++ struct msghdr msg; ++ ++ iov.iov_base = data; ++ iov.iov_len = size; ++ ++ memset(&src_addr, 0, sizeof(src_addr)); ++ src_addr.nl_family = AF_NETLINK; ++ src_addr.nl_pid = getpid(); ++ src_addr.nl_groups = 1; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_name = (void *)&src_addr; ++ msg.msg_namelen = sizeof(src_addr); ++ msg.msg_iov = &iov; ++ msg.msg_iovlen = 1; ++ ++ rc = recvmsg(ctrl_fd, &msg, flags); ++ ++ return rc; ++} ++ ++static int ++kwritev(int fd, enum iscsi_uevent_e type, struct iovec *iovp, int count) ++{ ++ int i, rc; ++ struct nlmsghdr *nlh; ++ struct msghdr msg; ++ struct iovec iov; ++ int datalen = 0; ++ ++ for (i = 0; i < count; i++) ++ datalen += iovp[i].iov_len; ++ ++ nlh = (struct nlmsghdr *)nlm_sendbuf; ++ memset(nlh, 0, NLMSG_SPACE(datalen)); ++ ++ nlh->nlmsg_len = NLMSG_SPACE(datalen); ++ nlh->nlmsg_pid = getpid(); ++ nlh->nlmsg_flags = 0; ++ nlh->nlmsg_type = type; ++ ++ datalen = 0; ++ for (i = 0; i < count; i++) { ++ memcpy(NLMSG_DATA(nlh) + datalen, iovp[i].iov_base, ++ iovp[i].iov_len); ++ datalen += iovp[i].iov_len; ++ } ++ iov.iov_base = (void *)nlh; ++ iov.iov_len = nlh->nlmsg_len; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_name = (void *)&dest_addr; ++ msg.msg_namelen = sizeof(dest_addr); ++ msg.msg_iov = &iov; ++ msg.msg_iovlen = 1; ++ ++ do { ++ rc = sendmsg(fd, &msg, 0); ++ if (rc == -ENOMEM) { ++ LOG_ERR(PFX "sendmsg: alloc_skb() failed"); ++ sleep(1); ++ } else if (rc < 0) { ++ LOG_ERR(PFX "sendmsg: bug?: on %d %s[0x%x]", ++ fd, strerror(errno), errno); ++ sleep(1); ++ } ++ } while ((rc < 0) && (event_loop_stop == 0)); ++ ++ return rc; ++} ++ ++/* ++ * __kipc_call() should never block. Therefore ++ * Netlink's xmit logic is serialized. This means we do not allocate on ++ * xmit path. Instead we reuse nlm_sendbuf buffer. ++ * ++ * Transport must assure non-blocking operations for: ++ * ++ * - session_create() ++ * - conn_create() ++ * - conn_bind() ++ * _ set_param() ++ * - conn_start() ++ * - conn_stop() ++ * ++ * Its OK to block for cleanup for short period of time in operatations for: ++ * ++ * - conn_destroy() ++ * - session_destroy() ++ * ++ * FIXME: interface needs to be extended to allow longer blocking on ++ * cleanup. (Dima) ++ */ ++int __kipc_call(int fd, void *iov_base, int iov_len) ++{ ++ int rc; ++ struct iovec iov; ++ struct iscsi_uevent *ev = iov_base; ++ enum iscsi_uevent_e type = ev->type; ++ ++ /* Sanity check */ ++ if (iov_base == NULL) ++ return -EINVAL; ++ ++ iov.iov_base = iov_base; ++ iov.iov_len = iov_len; ++ ++ rc = kwritev(fd, type, &iov, 1); ++ ++ return rc; ++} ++ ++static int pull_from_nl(char **buf) ++{ ++ int rc; ++ size_t ev_size, payload_size, alloc_size; ++ char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))]; ++ struct nlmsghdr *nlh; ++ char *data = NULL; ++ struct iscsi_uevent *ev; ++ ++ /* Take a quick peek at what how much uIP will need to read */ ++ rc = nl_read(nl_sock, nlm_ev, ++ NLMSG_SPACE(sizeof(struct iscsi_uevent)), ++ MSG_PEEK | MSG_WAITALL); ++ if (rc <= 0) { ++ LOG_ERR("can not read nlm_ev, error %s[%d]", ++ strerror(errno), rc); ++ if (rc == 0) ++ return -EIO; ++ else ++ return errno; ++ } ++ nlh = (struct nlmsghdr *)nlm_ev; ++ ++ if (unlikely(nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsghdr)))) { ++ LOG_ERR(PFX "Invalid nlh->nlmsg_len length: " ++ "nlh->nlmsg_len(%d) < " ++ "NLMSG_ALIGN(sizeof(struct nlmsghdr))(%d)", ++ nlh->nlmsg_len, NLMSG_ALIGN(sizeof(struct nlmsghdr))); ++ return -EINVAL; ++ } ++ ++ ev = (struct iscsi_uevent *)NLMSG_DATA(nlh); ++ if (ev->type == ISCSI_KEVENT_PATH_REQ) { ++ ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr)); ++ payload_size = ev_size - sizeof(struct iscsi_uevent); ++ if (payload_size < sizeof(struct iscsi_path)) ++ alloc_size = nlh->nlmsg_len + (payload_size - ++ sizeof(struct iscsi_path)); ++ else ++ alloc_size = nlh->nlmsg_len; ++ } else { ++ alloc_size = nlh->nlmsg_len; ++ } ++ data = (char *)malloc(alloc_size); ++ if (unlikely(data == NULL)) { ++ LOG_ERR(PFX "Couldn't allocate %d bytes for Netlink " ++ "iSCSI message", alloc_size); ++ return -ENOMEM; ++ } ++ ++ memset(data, 0, alloc_size); ++ rc = nl_read(nl_sock, data, (int)nlh->nlmsg_len, MSG_WAITALL); ++ if (rc <= 0) { ++ LOG_ERR("can not read nlm_ev, error %s[%d]", ++ strerror(errno), rc); ++ if (rc == 0) ++ rc = -EIO; ++ else ++ rc = errno; ++ ++ goto error; ++ } ++ *buf = data; ++ return 0; ++error: ++ if (data != NULL) ++ free(data); ++ ++ return rc; ++} ++ ++static const struct timespec ctldev_sleep_req = { ++ .tv_sec = 0, ++ .tv_nsec = 250000000, ++}; ++ ++static int ctldev_handle(char *data, nic_t *nic) ++{ ++ int rc; ++ struct iscsi_uevent *ev; ++ uint8_t *payload; ++ struct iscsi_path *path; ++ char *msg_type_str; ++ int i; ++ nic_interface_t *nic_iface = NULL; ++ ++ ev = (struct iscsi_uevent *)NLMSG_DATA(data); ++ switch (ev->type) { ++ case ISCSI_KEVENT_PATH_REQ: ++ msg_type_str = "path_req"; ++ break; ++ default: ++ /* We don't care about other iSCSI Netlink messages */ ++ LOG_DEBUG(PFX "Received ev->type: 0x%x", ev->type); ++ rc = 0; ++ goto error; ++ } ++ ++ /* This is a message that drivers should be interested in */ ++ LOG_INFO(PFX "%s: Processing '%s'", nic->log_name, msg_type_str); ++ ++ payload = (uint8_t *) ((uint8_t *) ev) + sizeof(*ev); ++ path = (struct iscsi_path *)payload; ++ ++ if (ev->type == ISCSI_KEVENT_PATH_REQ) { ++ struct timespec sleep_rem; ++ nic_interface_t *vlan_iface; ++ uint16_t ip_type; ++ int iface_num, vlan_id; ++ ++ if (path->ip_addr_len == 4) ++ ip_type = AF_INET; ++ else if (path->ip_addr_len == 16) ++ ip_type = AF_INET6; ++ else ++ ip_type = 0; ++#ifdef REQ_PATH_IFACE_NUM ++ /* Find the nic_iface to use */ ++ iface_num = ev->r.req_path.iface_num ? ++ ev->r.req_path.iface_num : IFACE_NUM_INVALID; ++#else ++ iface_num = IFACE_NUM_INVALID; ++#endif ++ vlan_id = path->vlan_id ? path->vlan_id : NO_VLAN; ++ ++ LOG_DEBUG(PFX "%s: PATH_REQ with iface_num %d VLAN %d", ++ nic->log_name, iface_num, vlan_id); ++ ++ pthread_mutex_lock(&nic->nic_mutex); ++ ++ nic_iface = nic_find_nic_iface(nic, ip_type, vlan_id, ++ iface_num, IP_CONFIG_OFF); ++ if (nic_iface == NULL) { ++ nic_iface = nic_find_nic_iface(nic, ip_type, ++ NO_VLAN, ++ IFACE_NUM_INVALID, ++ IP_CONFIG_OFF); ++ if (nic_iface == NULL) { ++ pthread_mutex_unlock(&nic->nic_mutex); ++ LOG_ERR(PFX "%s: Couldn't find nic iface parent" ++ " vlan: %d ip_type: %d " ++ "ip_addr_len: %d to clone", ++ nic->log_name, path->vlan_id, ip_type, ++ path->ip_addr_len); ++ goto error; ++ } ++ if (nic_iface->iface_num != IFACE_NUM_INVALID) { ++ /* New VLAN support: ++ Use the nic_iface found from the top ++ of the protocol family and ignore ++ the VLAN id from the path_req */ ++ if (!(nic_iface->iface_num == 0 && ++ nic_iface->vlan_id == 0 && ++ path->vlan_id)) { ++ pthread_mutex_unlock(&nic->nic_mutex); ++ goto nic_iface_done; ++ } ++ /* If iface_num == 0 and vlan_id == 0 but ++ the vlan_id from path_req is > 0, ++ then fallthru to the legacy support since ++ this is most likely from an older iscsid ++ (RHEL6.2/6.3 but has iface_num support) ++ */ ++ } ++ /* Legacy VLAN support: ++ This newly created nic_iface must inherit the ++ network parameters from the parent nic_iface ++ */ ++ LOG_DEBUG(PFX "%s: Created the nic_iface for vlan: %d " ++ "ip_type: %d", nic->log_name, path->vlan_id, ++ ip_type); ++ vlan_iface = nic_iface_init(); ++ if (vlan_iface == NULL) { ++ pthread_mutex_unlock(&nic->nic_mutex); ++ LOG_ERR(PFX "%s: Couldn't allocate " ++ "space for vlan: %d ip_type: " ++ "%d", nic->log_name, path->vlan_id, ++ ip_type); ++ goto error; ++ } ++ vlan_iface->protocol = ip_type; ++ vlan_iface->vlan_id = path->vlan_id; ++ nic_add_nic_iface(nic, vlan_iface); ++ ++ vlan_iface->ustack.ip_config = ++ nic_iface->ustack.ip_config; ++ memcpy(vlan_iface->ustack.hostaddr, ++ nic_iface->ustack.hostaddr, ++ sizeof(nic_iface->ustack.hostaddr)); ++ memcpy(vlan_iface->ustack.netmask, ++ nic_iface->ustack.netmask, ++ sizeof(nic_iface->ustack.netmask)); ++ memcpy(vlan_iface->ustack.netmask6, ++ nic_iface->ustack.netmask6, ++ sizeof(nic_iface->ustack.netmask6)); ++ memcpy(vlan_iface->ustack.hostaddr6, ++ nic_iface->ustack.hostaddr6, ++ sizeof(nic_iface->ustack.hostaddr6)); ++ ++ /* Persist so when nic_close won't call uip_reset ++ to nullify nic_iface->ustack */ ++ persist_all_nic_iface(nic); ++ ++ nic_iface = vlan_iface; ++ nic_iface->flags |= NIC_IFACE_ACQUIRE; ++ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ /* nic_disable but not going down */ ++ nic_disable(nic, 0); ++ } else { ++ pthread_mutex_unlock(&nic->nic_mutex); ++ } ++nic_iface_done: ++ /* Force enable the NIC */ ++ if (nic->state == NIC_STOPPED) ++ nic_enable(nic); ++ ++ /* Ensure that the NIC is RUNNING */ ++ rc = -EIO; ++ for (i = 0; i < 10; i++) { ++ if (nic->state == NIC_RUNNING) { ++ rc = 0; ++ break; ++ } ++ ++ nanosleep(&ctldev_sleep_req, &sleep_rem); ++ } ++ ++ if (rc != 0) { ++ LOG_WARN(PFX "%s[vlan: %d protocol: %d]: not running, " ++ "cmd: 0x%x nic state: 0x%x flags: 0x%x", ++ nic->log_name, ++ nic_iface->vlan_id, nic_iface->protocol, ++ ev->type, nic->state, nic->flags); ++ goto error; ++ } ++ } ++ ++ if (nic->ops) { ++ switch (ev->type) { ++ case ISCSI_KEVENT_PATH_REQ: ++ /* pass the request up to the user space ++ * library driver */ ++ nic_iface->flags |= NIC_IFACE_PATHREQ_WAIT2; ++ nic_iface->flags &= ~NIC_IFACE_PATHREQ_WAIT1; ++ if (nic->ops->handle_iscsi_path_req) ++ nic->ops->handle_iscsi_path_req(nic, ++ nl_sock, ev, ++ path, ++ nic_iface); ++ nic_iface->flags &= ~NIC_IFACE_PATHREQ_WAIT; ++ pthread_mutex_lock(&nic->nic_mutex); ++ nic->flags &= ~NIC_PATHREQ_WAIT; ++ pthread_mutex_unlock(&nic->nic_mutex); ++ LOG_INFO(PFX "%s: 'path_req' operation finished", ++ nic->log_name); ++ ++ rc = 0; ++ break; ++ default: ++ rc = -EAGAIN; ++ break; ++ } ++ } ++ ++error: ++ ++ return rc; ++} ++ ++/* NIC specific nl processing thread */ ++void *nl_process_handle_thread(void *arg) ++{ ++ int rc; ++ nic_t *nic = (nic_t *)arg; ++ ++ if (nic == NULL) ++ goto error; ++ ++ while (!event_loop_stop) { ++ char *data = NULL; ++ ++ rc = pthread_cond_wait(&nic->nl_process_cond, ++ &nic->nl_process_mutex); ++ if (rc != 0) { ++ LOG_ERR("Fatal error in NL processing thread " ++ "during wait[%s]", strerror(rc)); ++ break; ++ } ++ ++ data = nic->nl_process_ring[nic->nl_process_head]; ++ nic->nl_process_ring[nic->nl_process_head] = NULL; ++ nic->nl_process_tail = ++ NIC_NL_PROCESS_NEXT_ENTRY(nic->nl_process_tail); ++ ++ pthread_mutex_unlock(&nic->nl_process_mutex); ++ ++ if (data) { ++ ctldev_handle(data, nic); ++ free(data); ++ } ++ } ++error: ++ return NULL; ++} ++ ++static void flush_nic_nl_process_ring(nic_t *nic) ++{ ++ int i; ++ ++ for (i = 0; i < NIC_NL_PROCESS_MAX_RING_SIZE; i++) { ++ if (nic->nl_process_ring[i] != NULL) { ++ free(nic->nl_process_ring[i]); ++ nic->nl_process_ring[i] = NULL; ++ } ++ } ++ ++ nic->nl_process_head = 0; ++ nic->nl_process_tail = 0; ++ ++ LOG_DEBUG(PFX "%s: Flushed NIC NL ring", nic->log_name); ++} ++ ++/** ++ * nic_nl_open() - This is called when opening/creating the Netlink listening ++ * thread ++ * @param dev - CNIC UIO device to create a NetLink listener on ++ * @return 0 on success, <0 on failure ++ */ ++int nic_nl_open() ++{ ++ int rc; ++ char *msg_type_str; ++ ++ /* Prepare the thread to issue the ARP's */ ++ nl_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ISCSI); ++ if (nl_sock < 0) { ++ LOG_ERR(PFX "can not create NETLINK_ISCSI socket [%s]", ++ strerror(errno)); ++ rc = -ENOMEM; ++ goto error; ++ } ++ ++ memset(&src_addr, 0, sizeof(src_addr)); ++ src_addr.nl_family = AF_NETLINK; ++ src_addr.nl_pid = getpid(); ++ src_addr.nl_groups = ISCSI_NL_GRP_UIP; ++ ++ while ((!event_loop_stop)) { ++ rc = bind(nl_sock, ++ (struct sockaddr *)&src_addr, sizeof(src_addr)); ++ if (rc == 0) ++ break; ++ ++ LOG_ERR(PFX "waiting binding to NETLINK_ISCSI socket"); ++ ++ sleep(1); ++ } ++ ++ if (event_loop_stop) { ++ rc = -EINVAL; ++ goto error; ++ } ++ ++ LOG_INFO(PFX "Netlink to CNIC on pid %d is ready", src_addr.nl_pid); ++ ++ while (!event_loop_stop) { ++ struct iscsi_uevent *ev; ++ char *buf = NULL; ++ uint32_t host_no; ++ nic_t *nic; ++ ++ rc = pull_from_nl(&buf); ++ if (rc != 0) ++ continue; ++ ++ /* Try to abort ARP'ing if a if_down was received */ ++ ev = (struct iscsi_uevent *)NLMSG_DATA(buf); ++ switch (ev->type) { ++ case ISCSI_KEVENT_IF_DOWN: ++ host_no = ev->r.notify_if_down.host_no; ++ msg_type_str = "if_down"; ++ break; ++ case ISCSI_KEVENT_PATH_REQ: ++ host_no = ev->r.req_path.host_no; ++ msg_type_str = "path_req"; ++ break; ++ default: ++ /* We don't care about other iSCSI Netlink messages */ ++ continue; ++ } ++ LOG_INFO(PFX "Received %s for host %d", msg_type_str, host_no); ++ ++ /* Make sure the nic list doesn't get yanked */ ++ pthread_mutex_lock(&nic_list_mutex); ++ ++ rc = from_host_no_find_associated_eth_device(host_no, &nic); ++ if (rc != 0) { ++ pthread_mutex_unlock(&nic_list_mutex); ++ LOG_ERR(PFX "Dropping msg, couldn't find nic with host " ++ "no: %d", host_no); ++ continue; ++ } ++ ++ /* Found the nic */ ++ if (nic->nl_process_thread == INVALID_THREAD) { ++ /* If thread is not valid, just drop it */ ++ pthread_mutex_unlock(&nic_list_mutex); ++ LOG_ERR(PFX "Dropping msg, nic nl process thread " ++ "not ready for host no: %d", host_no); ++ continue; ++ } ++ ++ if (ev->type == ISCSI_KEVENT_IF_DOWN) { ++ char eth_device_name[IFNAMSIZ]; ++ ++ pthread_mutex_lock(&nic->nl_process_mutex); ++ nic->nl_process_if_down = 1; ++ flush_nic_nl_process_ring(nic); ++ pthread_cond_broadcast(&nic->nl_process_if_down_cond); ++ pthread_mutex_unlock(&nic->nl_process_mutex); ++ ++ memcpy(eth_device_name, nic->eth_device_name, ++ sizeof(eth_device_name)); ++ ++ pthread_mutex_lock(&nic->nic_mutex); ++ nic->flags &= ~NIC_PATHREQ_WAIT; ++ nic->flags |= NIC_EXIT_MAIN_LOOP; ++ pthread_cond_broadcast(&nic->enable_done_cond); ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ pthread_mutex_lock(&nic->nl_process_mutex); ++ nic->nl_process_if_down = 0; ++ pthread_mutex_unlock(&nic->nl_process_mutex); ++ ++ nic_disable(nic, 1); ++ ++ nic_remove(nic); ++ pthread_mutex_unlock(&nic_list_mutex); ++ ++ LOG_INFO(PFX "%s: 'if_down' operation finished", ++ eth_device_name); ++ continue; ++ } ++ ++ /* Place msg into the nic specific queue */ ++ pthread_mutex_lock(&nic->nl_process_mutex); ++ if ((nic->nl_process_head + 1 == nic->nl_process_tail) || ++ (nic->nl_process_tail == 0 && ++ nic->nl_process_head == NIC_NL_PROCESS_LAST_ENTRY)) { ++ pthread_mutex_unlock(&nic->nl_process_mutex); ++ pthread_mutex_unlock(&nic_list_mutex); ++ LOG_WARN(PFX "%s: No space on Netlink ring", ++ nic->log_name); ++ continue; ++ } ++ ++ nic->nl_process_ring[nic->nl_process_head] = buf; ++ nic->nl_process_head = ++ NIC_NL_PROCESS_NEXT_ENTRY(nic->nl_process_head); ++ pthread_cond_signal(&nic->nl_process_cond); ++ ++ pthread_mutex_unlock(&nic->nl_process_mutex); ++ ++ pthread_mutex_unlock(&nic_list_mutex); ++ ++ LOG_DEBUG(PFX "Pulled nl event"); ++ } ++ ++ LOG_INFO(PFX "Netlink thread exit'ing"); ++ rc = 0; ++ ++error: ++ return 0; ++} +diff --git a/iscsiuio/src/unix/nic_nl.h b/iscsiuio/src/unix/nic_nl.h +new file mode 100644 +index 0000000..c68d81c +--- /dev/null ++++ b/iscsiuio/src/unix/nic_nl.h +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * nic_nl.h - NIC uIP NetLink user space stack ++ * ++ */ ++ ++#ifndef __NIC_NL_H__ ++#define __NIC_NL_H__ ++ ++#include ++ ++int nic_nl_open(); ++void nic_nl_close(); ++ ++int __kipc_call(int fd, void *iov_base, int iov_len); ++ ++extern pthread_cond_t nl_process_if_down_cond; ++extern pthread_mutex_t nl_process_mutex; ++extern int nl_process_if_down; ++ ++#endif /* __NIC_NL_H__ */ +diff --git a/iscsiuio/src/unix/nic_utils.c b/iscsiuio/src/unix/nic_utils.c +new file mode 100644 +index 0000000..0daffd2 +--- /dev/null ++++ b/iscsiuio/src/unix/nic_utils.c +@@ -0,0 +1,1661 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * nic_util.c - shared NIC utility functions ++ * ++ */ ++#include ++#include ++#include ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "logger.h" ++#include "nic.h" ++#include "nic_id.h" ++#include "nic_vlan.h" ++#include "nic_utils.h" ++#include "options.h" ++ ++#define PFX "nic_utils " ++ ++/****************************************************************************** ++ * String constants ++ *****************************************************************************/ ++static const char nic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name"; ++static const char cnic_sysfs_uio_event_template[] = ++ "/sys/class/uio/uio%d/event"; ++static const char base_uio_sysfs_name[] = "/sys/class/uio/"; ++static const char uio_name[] = "uio"; ++ ++static const char uio_base_dir[] = "/dev/uio"; ++static const char uio_udev_path_template[] = "/dev/uio%hd"; ++static const char uio_uevent_path_template[] = "/sys/class/uio/uio%d/uevent"; ++ ++static const char base_iscsi_host_name[] = "/sys/class/iscsi_host/"; ++static const char host_template[] = "host%d"; ++static const char iscsi_host_path_template[] = "/sys/class/iscsi_host/host%d"; ++static const char iscsi_host_path_netdev_template[] = ++ "/sys/class/iscsi_host/host%d/netdev"; ++static const char cnic_uio_sysfs_resc_template[] = ++ "/sys/class/uio/uio%i/device/resource%i"; ++ ++/** ++ * manually_trigger_uio_event() - If the uio file node doesn't exist then ++ * try to retrigger udev to create the file ++ * node by touch the uevent file in sysfs ++ * @param nic - the nic to trigger on ++ * @param uio_minor - UIO the minor number to use ++ * @return 0 on success ++ */ ++int manually_trigger_uio_event(nic_t *nic, int uio_minor) ++{ ++ int fd; ++ char uio_uevent_path[sizeof(uio_uevent_path_template) + 10]; ++ char enable_str[] = "online"; ++ int rc; ++ size_t bytes_wrote; ++ ++ rc = sprintf(uio_uevent_path, uio_uevent_path_template, uio_minor); ++ if (rc < 0) { ++ LOG_ERR(PFX "%s: Could not build uio uevent path", ++ nic->log_name); ++ return -EIO; ++ } ++ ++ LOG_DEBUG(PFX "%s: triggering UIO uevent path: %s", ++ nic->log_name, uio_uevent_path); ++ ++ fd = open(uio_uevent_path, O_WRONLY); ++ if (fd == -1) { ++ LOG_ERR(PFX "%s: Could not open uio uevent path: %s [%s]", ++ nic->log_name, uio_uevent_path, strerror(errno)); ++ return -EIO; ++ } ++ ++ bytes_wrote = write(fd, enable_str, sizeof(enable_str)); ++ if (bytes_wrote != sizeof(enable_str)) { ++ LOG_ERR(PFX "%s: Could write to uio uevent path: %s [%s]", ++ nic->log_name, uio_uevent_path, strerror(errno)); ++ rc = -EIO; ++ } else ++ rc = 0; ++ ++ close(fd); ++ return rc; ++} ++ ++static int wait_for_file_node_timed(nic_t *nic, char *filepath, int seconds) ++{ ++ struct timeval start_time; ++ struct timeval wait_time; ++ struct timeval total_time; ++ struct timespec sleep_req, sleep_rem; ++ ++ sleep_req.tv_sec = 0; ++ sleep_req.tv_nsec = 250000000; ++ ++ wait_time.tv_sec = seconds; ++ wait_time.tv_usec = 0; ++ ++ if (gettimeofday(&start_time, NULL)) { ++ LOG_ERR(PFX "%s: Couldn't gettimeofday() during watch file: %s" ++ "[%s]", nic->log_name, filepath, strerror(errno)); ++ return -EIO; ++ } ++ ++ timeradd(&start_time, &wait_time, &total_time); ++ ++ while (1) { ++ struct timeval current_time; ++ struct stat file_stat; ++ ++ /* Check if the file node exists */ ++ if (stat(filepath, &file_stat) == 0) ++ return 0; ++ ++ if (gettimeofday(¤t_time, NULL)) { ++ LOG_ERR(PFX "%s: Couldn't get current time for " ++ "watching file: %s [%s]", ++ nic->log_name, filepath, strerror(errno)); ++ return -EIO; ++ } ++ ++ /* Timeout has excceded return -ETIME */ ++ if (timercmp(&total_time, ¤t_time, <)) { ++ LOG_ERR(PFX "%s: timeout waiting %d secs for file: %s", ++ nic->log_name, seconds, filepath); ++ return -ETIME; ++ } ++ ++ nanosleep(&sleep_req, &sleep_rem); ++ } ++} ++ ++/****************************************************************************** ++ * Autodiscovery of iscsi_hosts ++ *****************************************************************************/ ++static int filter_host_name(const struct dirent *entry) ++{ ++ if ((memcmp(entry->d_name, "host", 4) == 0)) ++ return 1; ++ else ++ return 0; ++} ++ ++int nic_discover_iscsi_hosts() ++{ ++ struct dirent **files; ++ int count; ++ int i; ++ int rc; ++ ++ count = scandir(base_iscsi_host_name, &files, filter_host_name, ++ alphasort); ++ ++ switch (count) { ++ case 0: ++ /* Currently there are no iSCSI hosts */ ++ rc = 0; ++ break; ++ ++ case -1: ++ LOG_WARN(PFX "Error when scanning path: %s[%s]", ++ base_iscsi_host_name, strerror(errno)); ++ rc = -EINVAL; ++ break; ++ ++ default: ++ /* There are iSCSI hosts */ ++ pthread_mutex_lock(&nic_list_mutex); ++ for (i = 0; i < count; i++) { ++ int host_no; ++ char *raw = NULL; ++ uint32_t raw_size = 0; ++ char temp_path[sizeof(iscsi_host_path_netdev_template) + ++ 8]; ++ rc = sscanf(files[i]->d_name, host_template, &host_no); ++ nic_t *nic; ++ ++ LOG_INFO(PFX "Found host[%d]: %s", ++ host_no, files[i]->d_name); ++ ++ /* Build the path to determine netdev name */ ++ snprintf(temp_path, sizeof(temp_path), ++ iscsi_host_path_netdev_template, host_no); ++ ++ rc = capture_file(&raw, &raw_size, temp_path); ++ if (rc != 0) ++ continue; ++ ++ rc = from_host_no_find_associated_eth_device(host_no, ++ &nic); ++ if (rc != 0) { ++ /* Normalize the string */ ++ if (raw[raw_size - 1] == '\n') ++ raw[raw_size - 1] = '\0'; ++ ++ nic = nic_init(); ++ if (nic == NULL) { ++ LOG_ERR(PFX "Couldn't allocate " ++ "space for NIC %s " ++ "during scan", raw); ++ ++ rc = -ENOMEM; ++ break; ++ } ++ ++ strncpy(nic->eth_device_name, raw, raw_size); ++ nic->config_device_name = nic->eth_device_name; ++ nic->log_name = nic->eth_device_name; ++ ++ if (nic_fill_name(nic) != 0) { ++ free(nic); ++ free(raw); ++ rc = -EIO; ++ continue; ++ } ++ ++ nic_add(nic); ++ ++ LOG_INFO(PFX "NIC not found creating an " ++ "instance for host_no: %d %s", ++ host_no, nic->eth_device_name); ++ } else ++ LOG_INFO(PFX "%s: NIC found host_no: %d", ++ nic->log_name, host_no); ++ ++ free(raw); ++ } ++ pthread_mutex_unlock(&nic_list_mutex); ++ ++ /* Cleanup the scandir() call */ ++ for (i = 0; i < count; i++) ++ free(files[i]); ++ free(files); ++ ++ rc = 0; ++ break; ++ } ++ ++ return rc; ++} ++ ++/****************************************************************************** ++ * Enable/Disable Multicast on physical interface ++ *****************************************************************************/ ++static int nic_util_enable_disable_multicast(nic_t *nic, uint32_t cmd) ++{ ++ int rc = 0; ++ struct uip_eth_addr multicast_addr; ++ int fd; ++ struct ifreq ifr; ++ ++ /* adding ethernet multicast address for IPv6 */ ++ memcpy(&multicast_addr, nic->mac_addr, ETH_ALEN); ++ multicast_addr.addr[0] = 0x33; ++ multicast_addr.addr[1] = 0x33; ++ multicast_addr.addr[2] = 0xff; ++ ++ /* Prepare the request */ ++ memset(&ifr, 0, sizeof(ifr)); ++ strncpy(ifr.ifr_name, nic->eth_device_name, ++ sizeof(nic->eth_device_name)); ++ memcpy(ifr.ifr_hwaddr.sa_data, multicast_addr.addr, ETH_ALEN); ++ ++ fd = socket(AF_INET, SOCK_DGRAM, 0); ++ if (fd < 0) { ++ LOG_ERR(PFX "%s: Couldn't create socket to %s " ++ "multicast address: %s", ++ nic->log_name, ++ cmd == SIOCADDMULTI ? "added" : "delete", ++ strerror(errno)); ++ return errno; ++ } ++ ++ rc = fcntl(fd, F_SETFL, O_NONBLOCK); ++ if (rc != 0) { ++ LOG_WARN("%s: Couldn't set to ethtool IOCTL to " ++ "non-blocking [%s]", nic->log_name, strerror(errno)); ++ } ++ ++ if (ioctl(fd, cmd, (char *)&ifr) != 0) { ++ LOG_ERR("%s: Couldn't issue ioctl socket to %s " ++ "multicast address: %s", ++ nic->log_name, ++ cmd == SIOCADDMULTI ? "add" : "delete", ++ strerror(errno)); ++ rc = errno; ++ goto error; ++ } ++ ++ LOG_INFO(PFX "%s: %s address %02x:%02x:%02x:%02x:%02x:%02x " ++ "to multicast list", ++ nic->log_name, ++ cmd == SIOCADDMULTI ? "Added" : "Deleted", ++ multicast_addr.addr[0], multicast_addr.addr[1], ++ multicast_addr.addr[2], multicast_addr.addr[3], ++ multicast_addr.addr[4], multicast_addr.addr[5]); ++ ++ if (cmd == SIOCADDMULTI) ++ nic->flags |= NIC_ADDED_MULICAST; ++ else ++ nic->flags &= ~NIC_ADDED_MULICAST; ++ ++error: ++ close(fd); ++ ++ return rc; ++} ++ ++/** ++ * enable_multicast() - This fuction is used to enable ++ * the listening of multicast addresses for a given network interface ++ * @param nic - NIC device to enable multicast on ++ * @return 0 for success or <0 for failure ++ */ ++int enable_multicast(nic_t *nic) ++{ ++ return nic_util_enable_disable_multicast(nic, SIOCADDMULTI); ++} ++ ++/** ++ * disable_multicast() - This fuction is used to disable ++ * the listening of multicast addresses for a given network interface ++ * @param dev - NIC device to disable multicast on ++ * @return 0 for success or <0 for failure ++ */ ++int disable_multicast(nic_t *nic) ++{ ++ return nic_util_enable_disable_multicast(nic, SIOCDELMULTI); ++} ++ ++/******************************************************************************* ++ * Finding associated UIO/physical network interfaces ++ ******************************************************************************/ ++static int filter_net_name(const struct dirent *entry) ++{ ++ if ((memcmp(entry->d_name, "net:", 4) == 0)) ++ return 1; ++ else ++ return 0; ++} ++ ++static char *extract_net_name(struct dirent **files) ++{ ++ return strstr(files[0]->d_name, ":"); ++} ++ ++static int filter_dot_out(const struct dirent *entry) ++{ ++ if ((memcmp(entry->d_name, ".", 1) == 0)) ++ return 0; ++ else ++ return 1; ++} ++ ++static char *extract_none(struct dirent **files) ++{ ++ return files[0]->d_name; ++} ++ ++/** ++ * from_host_no_find_nic() - Given the host number ++ * this function will try to find the assoicated nic interface ++ * Must be called with nic_list_mutex lock ++ * @param host_no - minor number of the UIO device ++ * @param nic - pointer to the NIC will set if successful ++ * @return 0 on success, <0 on error ++ */ ++int from_host_no_find_associated_eth_device(int host_no, nic_t **nic) ++{ ++ nic_t *current_nic = nic_list; ++ char *raw = NULL, *raw_tmp; ++ uint32_t raw_size = 0; ++ ++ char temp_path[sizeof(iscsi_host_path_netdev_template) + 8]; ++ int rc = -EIO; ++ ++ /* Build the path to determine uio name */ ++ snprintf(temp_path, sizeof(temp_path), ++ iscsi_host_path_netdev_template, host_no); ++ ++ rc = capture_file(&raw, &raw_size, temp_path); ++ if (rc != 0) ++ goto error; ++ ++ /* sanitize name string by replacing newline with null termination */ ++ raw_tmp = raw; ++ while (*raw_tmp != '\n' && raw_size--) ++ raw_tmp++; ++ *raw_tmp = '\0'; ++ ++ rc = -EIO; ++ ++ current_nic = nic_list; ++ while (current_nic != NULL) { ++ if (strcmp(raw, current_nic->eth_device_name) == 0) { ++ *nic = current_nic; ++ rc = 0; ++ break; ++ } ++ ++ current_nic = current_nic->next; ++ } ++ ++ free(raw); ++ ++error: ++ return rc; ++} ++ ++/******************************************************************************* ++ * NIC packet handling functions ++ ******************************************************************************/ ++/** ++ * from_uio_find_associated_eth_device() - Given the uio minor number ++ * this function will try to find the assoicated phyisical network ++ * interface ++ * @param uio_minor - minor number of the UIO device ++ * @param name - char buffer which will be filled if successful ++ * @param name_size - size of the name buffer ++ * @return >0 minor number <0 an error ++ */ ++static int from_uio_find_associated_eth_device(nic_t *nic, ++ int uio_minor, ++ char *name, size_t name_size) ++{ ++ char *path; ++ int rc; ++ int count; ++ struct dirent **files; ++ char *parsed_name; ++ int i; ++ int path_iterator; ++ char *search_paths[] = { "/sys/class/uio/uio%i/device/", ++ "/sys/class/uio/uio%i/device/net" ++ }; ++ int path_to[] = { 5, 1 }; ++ int (*search_filters[]) (const struct dirent *) = { ++ filter_net_name, filter_dot_out,}; ++ char *(*extract_name[]) (struct dirent **files) = { ++ extract_net_name, extract_none,}; ++ int extract_name_offset[] = { 1, 0 }; ++ ++ path = malloc(PATH_MAX); ++ if (path == NULL) { ++ LOG_ERR(PFX "Could not allocate memory for path"); ++ rc = -ENOMEM; ++ goto error; ++ } ++ ++ for (path_iterator = 0; ++ path_iterator < sizeof(search_paths) / sizeof(search_paths[0]); ++ path_iterator++) { ++ /* Build the path to determine uio name */ ++ rc = sprintf(path, search_paths[path_iterator], uio_minor); ++ ++ wait_for_file_node_timed(nic, path, path_to[path_iterator]); ++ ++ count = scandir(path, &files, ++ search_filters[path_iterator], alphasort); ++ ++ switch (count) { ++ case 1: ++ parsed_name = (*extract_name[path_iterator]) (files); ++ if (parsed_name == NULL) { ++ LOG_WARN(PFX "Couldn't find delimiter in: %s", ++ files[0]->d_name); ++ ++ break; ++ } ++ ++ strncpy(name, ++ parsed_name + ++ extract_name_offset[path_iterator], name_size); ++ ++ free(files[0]); ++ free(files); ++ ++ rc = 0; ++ break; ++ ++ case 0: ++ rc = -EINVAL; ++ break; ++ ++ case -1: ++ LOG_WARN(PFX "Error when scanning path: %s[%s]", ++ path, strerror(errno)); ++ rc = -EINVAL; ++ break; ++ ++ default: ++ LOG_WARN(PFX ++ "Too many entries when looking for device: %s", ++ path); ++ ++ /* Cleanup the scandir() call */ ++ for (i = 0; i < count; i++) ++ free(files[i]); ++ free(files); ++ ++ rc = -EINVAL; ++ break; ++ } ++ ++ if (rc == 0) ++ break; ++ } ++ ++error: ++ free(path); ++ ++ return rc; ++} ++ ++/** ++ * filter_uio_name() - This is the callback used by scandir when looking for ++ * the number of uio entries ++ */ ++static int filter_uio_name(const struct dirent *entry) ++{ ++ /* Only return if the name of the file begins with 'uio' */ ++ if ((memcmp(entry->d_name, uio_name, sizeof(uio_name) - 1) == 0)) ++ return 1; ++ else ++ return 0; ++} ++ ++/** ++ * from_netdev_name_find_nic() - This is used to find the NIC device given ++ * the netdev name ++ * @param interface_name - name of the interface to search on ++ * @param nic - pointer of the pointer to the NIC ++ * @return 0 on success, <0 on failure ++ */ ++int from_netdev_name_find_nic(char *interface_name, nic_t **nic) ++{ ++ nic_t *current_nic; ++ ++ current_nic = nic_list; ++ while (current_nic != NULL) { ++ if (strcmp(interface_name, current_nic->eth_device_name) == 0) ++ break; ++ ++ current_nic = current_nic->next; ++ } ++ ++ if (current_nic == NULL) ++ return -EINVAL; ++ ++ *nic = current_nic; ++ return 0; ++} ++ ++/** ++ * from_phys_name_find_assoicated_uio_device() - This is used to find the ++ * uio minor ++ * when given a network interface name ++ * @param interface_name - network interface name to search for ++ * @return >0 minor number <0 an error ++ */ ++int from_phys_name_find_assoicated_uio_device(nic_t *nic) ++{ ++ char *path = NULL; ++ int count; ++ struct dirent **files; ++ int i; ++ int rc; ++ char *interface_name = nic->config_device_name; ++ ++ if (interface_name == NULL) ++ interface_name = nic->eth_device_name; ++ ++ /* Wait at least 10 seconds for uio sysfs entries to appear */ ++ rc = wait_for_file_node_timed(nic, (char *)base_uio_sysfs_name, 10); ++ if (rc != 0) ++ return rc; ++ ++ count = scandir(base_uio_sysfs_name, ++ &files, filter_uio_name, alphasort); ++ ++ switch (count) { ++ case 0: ++ LOG_WARN(PFX "Couldn't find %s to determine uio minor", ++ interface_name); ++ return -EINVAL; ++ ++ case -1: ++ LOG_WARN(PFX "Error when scanning for %s in path: %s [%s]", ++ interface_name, base_uio_sysfs_name, strerror(errno)); ++ return -EINVAL; ++ } ++ ++ path = malloc(PATH_MAX); ++ if (path == NULL) { ++ LOG_ERR(PFX "Could not allocate memory for path"); ++ return -ENOMEM; ++ } ++ ++ /* Run through the contents of the filtered files to see if the ++ * network interface name matches that of the uio device */ ++ for (i = 0; i < count; i++) { ++ int uio_minor; ++ char eth_name[IFNAMSIZ]; ++ ++ rc = sscanf(files[i]->d_name, "uio%d", &uio_minor); ++ if (rc != 1) { ++ LOG_WARN("Could not parse: %s", files[i]->d_name); ++ continue; ++ } ++ ++ rc = from_uio_find_associated_eth_device(nic, ++ uio_minor, ++ eth_name, ++ sizeof(eth_name)); ++ if (rc != 0) { ++ LOG_WARN("uio minor: %d not valid [%D]", uio_minor, rc); ++ continue; ++ } ++ ++ if (strncmp(eth_name, interface_name, sizeof(eth_name)) == 0) { ++ memcpy(nic->eth_device_name, ++ eth_name, sizeof(nic->eth_device_name)); ++ ++ LOG_INFO(PFX "%s associated with uio%d", ++ nic->eth_device_name, uio_minor); ++ ++ rc = uio_minor; ++ goto done; ++ } ++ } ++ ++ LOG_WARN("Could not find assoicate uio device with %s", interface_name); ++ ++ rc = -EINVAL; ++done: ++ if (path != NULL) ++ free(path); ++ ++ for (i = 0; i < count; i++) ++ free(files[i]); ++ free(files); ++ ++ return rc; ++ ++} ++ ++/** ++ * nic_verify_uio_sysfs_name() - Using the name entry in sysfs it will try to ++ * match the NIC library name ++ * @param nic - The NIC hardware to check ++ * ++ */ ++int nic_verify_uio_sysfs_name(nic_t *nic) ++{ ++ char *raw = NULL, *raw_tmp; ++ uint32_t raw_size = 0; ++ char temp_path[sizeof(nic_uio_sysfs_name_tempate) + 8]; ++ int rc = 0; ++ nic_lib_handle_t *handle = NULL; ++ size_t name_size; ++ ++ ++ /* Build the path to determine uio name */ ++ snprintf(temp_path, sizeof(temp_path), ++ nic_uio_sysfs_name_tempate, nic->uio_minor); ++ ++ rc = capture_file(&raw, &raw_size, temp_path); ++ if (rc != 0) ++ goto error; ++ ++ /* sanitize name string by replacing newline with null termination */ ++ raw_tmp = raw; ++ while (*raw_tmp != '\n' && raw_size--) ++ raw_tmp++; ++ *raw_tmp = '\0'; ++ ++ /* If the nic library is not set then check if there is a library ++ * which matches the uio sysfs name */ ++ if (nic->nic_library == NULL) { ++ NIC_LIBRARY_EXIST_T exist; ++ ++ exist = does_nic_uio_name_exist(raw, &handle); ++ if (exist == NIC_LIBRARY_DOESNT_EXIST) { ++ LOG_ERR(PFX "%s: could not find library for uio name: %s", ++ nic->log_name, raw); ++ rc = -EINVAL; ++ goto error; ++ } ++ ++ /* fill the lib info */ ++ nic->nic_library = handle; ++ nic->ops = handle->ops; ++ (*nic->ops->lib_ops.get_library_name) (&nic->library_name, ++ &name_size); ++ } else { ++ /* Get the uio sysfs name from the NIC library */ ++ (*nic->ops->lib_ops.get_uio_name) (&raw_tmp, &name_size); ++ ++ if (strncmp(raw, raw_tmp, name_size) != 0) { ++ LOG_ERR(PFX "%s: uio names not equal: " ++ "expecting %s got %s from %s", ++ nic->log_name, raw, raw_tmp, temp_path); ++ rc = -EINVAL; ++ goto error; ++ } ++ } ++ ++ LOG_INFO(PFX "%s: Verified uio name %s with library %s", ++ nic->log_name, raw, nic->library_name); ++ ++error: ++ if (raw) ++ free(raw); ++ ++ return rc; ++} ++ ++/** ++ * nic_fill_name() - This will initialize all the hardware resources underneath ++ * a struct cnic_uio device ++ * @param nic - The nic device to attach the hardware with ++ * @return 0 on success, on failure a errno will be returned ++ */ ++int nic_fill_name(nic_t *nic) ++{ ++ int rc; ++ ++ if ((nic->config_device_name != NULL) && ++ (memcmp(uio_base_dir, nic->config_device_name, ++ sizeof(uio_base_dir) - 1) == 0)) { ++ uint16_t uio_minor; ++ char eth_name[sizeof(nic->eth_device_name)]; ++ ++ wait_for_file_node_timed(nic, nic->config_device_name, 5); ++ ++ /* Determine the minor number for the UIO device */ ++ rc = sscanf(nic->config_device_name, uio_udev_path_template, ++ &uio_minor); ++ if (rc != 1) { ++ LOG_WARN(PFX "%s: Could not parse for minor number", ++ nic->uio_device_name); ++ return -EINVAL; ++ } else ++ nic->uio_minor = uio_minor; ++ ++ nic->uio_device_name = nic->config_device_name; ++ ++ /* Determine the assoicated physical network interface */ ++ rc = from_uio_find_associated_eth_device(nic, ++ nic->uio_minor, ++ eth_name, ++ sizeof(eth_name)); ++ if (rc != 0) { ++ LOG_WARN(PFX "%s: Couldn't find associated eth device", ++ nic->uio_device_name); ++ } else { ++ memcpy(nic->eth_device_name, ++ eth_name, sizeof(eth_name)); ++ } ++ ++ LOG_INFO(PFX "%s: configured for uio device for %s", ++ nic->log_name, nic->uio_device_name); ++ ++ } else { ++ LOG_INFO(PFX "looking for uio device for %s", ++ nic->config_device_name); ++ ++ rc = from_phys_name_find_assoicated_uio_device(nic); ++ if (rc < 0) { ++ LOG_ERR(PFX "Could not determine UIO name for %s", ++ nic->config_device_name); ++ ++ return -rc; ++ } ++ ++ nic->uio_minor = rc; ++ ++ if (nic->flags & NIC_UIO_NAME_MALLOC) ++ free(nic->uio_device_name); ++ ++ nic->uio_device_name = ++ malloc(sizeof(uio_udev_path_template) + 8); ++ if (nic->uio_device_name == NULL) { ++ LOG_INFO(PFX "%s: Couldn't malloc space for uio name", ++ nic->log_name); ++ return -ENOMEM; ++ } ++ ++ snprintf(nic->uio_device_name, ++ sizeof(uio_udev_path_template) + 8, ++ uio_udev_path_template, nic->uio_minor); ++ ++ nic->flags |= NIC_UIO_NAME_MALLOC; ++ } ++ ++ return 0; ++} ++ ++void cnic_get_sysfs_pci_resource_path(nic_t *nic, int resc_no, ++ char *sys_path, size_t size) ++{ ++ /* Build the path to sysfs pci resource */ ++ snprintf(sys_path, size, ++ cnic_uio_sysfs_resc_template, nic->uio_minor, resc_no); ++ ++} ++ ++void prepare_library(nic_t *nic) ++{ ++ int rc; ++ NIC_LIBRARY_EXIST_T exist; ++ nic_lib_handle_t *handle = NULL; ++ ++ nic_fill_name(nic); ++ ++ /* No assoicated library, we can skip it */ ++ if (nic->library_name != NULL) { ++ /* Check that we have the proper NIC library loaded */ ++ exist = does_nic_library_exist(nic->library_name, &handle); ++ if (exist == NIC_LIBRARY_DOESNT_EXIST) { ++ LOG_ERR(PFX "NIC library doesn't exists: %s", ++ nic->library_name); ++ goto error; ++ } else if (handle && (nic->nic_library == handle) && ++ (nic->ops == handle->ops)) { ++ LOG_INFO("%s: Have NIC library '%s'", ++ nic->log_name, nic->library_name); ++ } ++ } ++ ++ /* Verify the NIC library to use */ ++ rc = nic_verify_uio_sysfs_name(nic); ++ if (rc != 0) { ++ /* Determine the NIC library to use based on the PCI Id */ ++ rc = find_set_nic_lib(nic); ++ if (rc != 0) { ++ LOG_ERR(PFX "%s: Couldn't find NIC library", ++ nic->log_name); ++ goto error; ++ } ++ ++ } ++ ++ LOG_INFO("%s: found NIC with library '%s'", ++ nic->log_name, nic->library_name); ++error: ++ return; ++} ++ ++void prepare_nic_thread(nic_t *nic) ++{ ++ pthread_attr_t attr; ++ int rc; ++ ++ pthread_mutex_lock(&nic->nic_mutex); ++ if (nic->thread == INVALID_THREAD) { ++ struct timespec ts; ++ struct timeval tp; ++ ++ LOG_INFO(PFX "%s: spinning up thread for nic", nic->log_name); ++ ++ /* Try to spin up the nic thread */ ++ pthread_attr_init(&attr); ++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ++ rc = pthread_create(&nic->thread, &attr, nic_loop, nic); ++ if (rc != 0) { ++ LOG_ERR(PFX "%s: Couldn't create thread for nic", ++ nic->log_name); ++ goto error; ++ } ++ ++ /* Convert from timeval to timespec */ ++ rc = gettimeofday(&tp, NULL); ++ ts.tv_sec = tp.tv_sec; ++ ts.tv_nsec = tp.tv_usec * 1000; ++ ts.tv_sec += 5; /* TODO: hardcoded wait for 5 seconds */ ++ ++ /* Wait for the nic loop thread to to running */ ++ rc = pthread_cond_timedwait(&nic->nic_loop_started_cond, ++ &nic->nic_mutex, &ts); ++ ++ LOG_INFO("Created nic thread: %s", nic->log_name); ++ } ++ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++error: ++ return; ++} ++ ++/******************************************************************************* ++ * Functions used to enable/disable the NIC ++ ******************************************************************************/ ++/** ++ * nic_enable() - Function used to enable the NIC ++ * @param nic - NIC to enable ++ * @return 0 on success, <0 on failure ++ */ ++int nic_enable(nic_t *nic) ++{ ++ if (nic->flags & NIC_GOING_DOWN) { ++ LOG_INFO(PFX "%s: NIC device is going down, " ++ "flag: 0x%x state: 0x%x", ++ nic->log_name, nic->flags, nic->state); ++ return -EINVAL; ++ } ++ if (nic->state == NIC_STOPPED) { ++ struct timespec ts; ++ struct timeval tp; ++ int rc; ++ ++ pthread_mutex_lock(&nic->nic_mutex); ++ /* Signal the device to enable itself */ ++ pthread_cond_broadcast(&nic->enable_wait_cond); ++ ++ nic->flags &= ~NIC_DISABLED; ++ nic->flags |= NIC_ENABLED; ++ nic->flags |= NIC_ENABLED_PENDING; ++ ++ /* Convert from timeval to timespec */ ++ rc = gettimeofday(&tp, NULL); ++ ts.tv_sec = tp.tv_sec; ++ ts.tv_nsec = tp.tv_usec * 1000; ++ ts.tv_sec += 100; ++ ++ /* Wait for the device to be enabled */ ++ rc = pthread_cond_timedwait(&nic->enable_done_cond, ++ &nic->nic_mutex, &ts); ++ if (rc == 0 && nic->flags & NIC_ENABLED) { ++ LOG_DEBUG(PFX "%s: device enabled", nic->log_name); ++ } else { ++ nic->flags &= ~NIC_ENABLED; ++ nic->flags |= NIC_DISABLED; ++ nic->flags &= ~NIC_ENABLED_PENDING; ++ ++ LOG_ERR(PFX "%s: waiting to finish nic_enable err: %s", ++ nic->log_name, strerror(rc)); ++ } ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ return rc; ++ } else { ++ LOG_INFO(PFX "%s: device already enabled: " ++ "flag: 0x%x state: 0x%x", ++ nic->log_name, nic->flags, nic->state); ++ return -EALREADY; ++ } ++} ++ ++/** ++ * nic_disable() - Function used to disable the NIC ++ * @param nic - NIC to disble ++ * @return void ++ */ ++void nic_disable(nic_t *nic, int going_down) ++{ ++ if (nic->state == NIC_STARTED_RUNNING || ++ nic->state == NIC_RUNNING) { ++ struct timespec ts; ++ struct timeval tp; ++ int rc; ++ ++ /* Wait for the device to be disabled */ ++ pthread_mutex_lock(&nic->nic_mutex); ++ ++ nic->flags &= ~NIC_ENABLED; ++ nic->flags |= NIC_DISABLED; ++ nic->flags &= ~NIC_STARTED_RUNNING; ++ nic->state = NIC_STOPPED; ++ ++ if (going_down) ++ nic->flags |= NIC_GOING_DOWN; ++ ++ /* Convert from timeval to timespec */ ++ rc = gettimeofday(&tp, NULL); ++ if (rc) { ++ LOG_ERR("gettimeofday failed, should never happen: %d\n", errno); ++ pthread_mutex_unlock(&nic->nic_mutex); ++ return; ++ } ++ ++ ts.tv_sec = tp.tv_sec; ++ ts.tv_nsec = tp.tv_usec * 1000; ++ ts.tv_sec += 5; /* TODO: hardcoded wait for 5 seconds */ ++ ++ /* Wait for the device to be disabled */ ++ rc = pthread_cond_timedwait(&nic->disable_wait_cond, ++ &nic->nic_mutex, &ts); ++ if (rc) { ++ LOG_ERR("cond_timedwait failed, should never happen: %d\n", errno); ++ } ++ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ LOG_DEBUG(PFX "%s: device disabled", nic->log_name); ++ ++ } else { ++ LOG_WARN(PFX "%s: device already disabled: " ++ "flag: 0x%x state: 0x%x", ++ nic->log_name, nic->flags, nic->state); ++ } ++} ++ ++void nic_close_all() ++{ ++ nic_t *nic; ++ ++ pthread_mutex_lock(&nic_list_mutex); ++ ++ /* Start the shutdown process */ ++ nic = nic_list; ++ while (nic != NULL) { ++ pthread_mutex_lock(&nic->nic_mutex); ++ nic_close(nic, 1, FREE_ALL_STRINGS); ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ nic = nic->next; ++ } ++ pthread_mutex_unlock(&nic_list_mutex); ++ ++ LOG_INFO(PFX "All NICs closed"); ++} ++ ++void nic_remove_all() ++{ ++ nic_t *nic, *nic_next; ++ ++ pthread_mutex_lock(&nic_list_mutex); ++ ++ /* Start the shutdown process */ ++ nic = nic_list; ++ while (nic != NULL) { ++ nic_next = nic->next; ++ pthread_mutex_lock(&nic->nic_mutex); ++ nic_close(nic, 1, FREE_ALL_STRINGS); ++ pthread_mutex_unlock(&nic->nic_mutex); ++ nic_remove(nic); ++ nic = nic_next; ++ } ++ pthread_mutex_unlock(&nic_list_mutex); ++ ++ LOG_INFO(PFX "All NICs removed"); ++} ++ ++ ++/****************************************************************************** ++ * Routines to read initialized UIO values from sysfs ++ *****************************************************************************/ ++/** ++ * determine_initial_uio_events() - This utility function will ++ * determine the number of uio events that have occured on the ++ * given device. This value is read from the UIO sysfs entry ++ * @param dev - device to read from ++ * @param num_of_event - number of UIO events ++ * @return 0 is success, <0 failure ++ */ ++int detemine_initial_uio_events(nic_t *nic, uint32_t *num_of_events) ++{ ++ char *raw = NULL; ++ uint32_t raw_size = 0; ++ ssize_t elements_read; ++ char temp_path[sizeof(cnic_sysfs_uio_event_template) + 8]; ++ int rc; ++ ++ /* Capture RX buffer size */ ++ snprintf(temp_path, sizeof(temp_path), ++ cnic_sysfs_uio_event_template, nic->uio_minor); ++ ++ rc = capture_file(&raw, &raw_size, temp_path); ++ if (rc != 0) ++ goto error; ++ ++ elements_read = sscanf(raw, "%d", num_of_events); ++ if (elements_read != 1) { ++ LOG_ERR(PFX "%s: Couldn't parse UIO events size from %s", ++ nic->log_name, temp_path); ++ rc = -EIO; ++ goto error; ++ } ++ ++ rc = 0; ++error: ++ if (raw != NULL) ++ free(raw); ++ ++ return rc; ++} ++ ++/** ++ * nic_set_all_nic_iface_mac_to_parent() - This is a utility function used to ++ * intialize all the MAC addresses of the network interfaces for a given ++ * CNIC UIO device ++ * Call with nic mutex held ++ * @param dev - CNIC UIO device to initialize ++ */ ++void nic_set_all_nic_iface_mac_to_parent(nic_t *nic) ++{ ++ nic_interface_t *current, *vlan_current; ++ ++ current = nic->nic_iface; ++ while (current != NULL) { ++ /* Set the initial MAC address of this interface to the parent ++ * adapter */ ++ memcpy(current->mac_addr, nic->mac_addr, 6); ++ ++ vlan_current = current->vlan_next; ++ while (vlan_current != NULL) { ++ memcpy(vlan_current->mac_addr, nic->mac_addr, 6); ++ vlan_current = vlan_current->vlan_next; ++ } ++ current = current->next; ++ } ++} ++ ++/******************************************************************************* ++ * NIC packet handling functions ++ ******************************************************************************/ ++/** ++ * nic_alloc_packet_buffer() - Used to allocate a packet buffer used to ++ * send a TX packet later ++ * @param nic - nic device to send the packet on ++ * @param nic_iface - nic interface to send out on ++ * @param buf - pointer to the buffer to send ++ * @param buf_size - size in bytes of the buffer to send ++ * @return pointer to the allocated packet buffer ++ * NULL if memory could not be allocated ++ */ ++static packet_t *nic_alloc_packet_buffer(nic_t *nic, ++ nic_interface_t *nic_iface, ++ uint8_t *buf, size_t buf_size) ++{ ++ packet_t *pkt; ++ ++ pkt = malloc(sizeof(*pkt) + buf_size); ++ if (pkt == NULL) { ++ LOG_ERR(PFX "%s: Couldn't allocate space for packet buffer", ++ nic->log_name); ++ return NULL; ++ } ++ ++ pkt->next = NULL; ++ pkt->nic = nic; ++ pkt->nic_iface = nic_iface; ++ pkt->buf_size = buf_size; ++ memcpy(pkt->buf, buf, buf_size); ++ ++ return pkt; ++} ++ ++/** ++ * nic_queue_tx_packet() - Used to queue a TX packet buffer to send later ++ * @param nic - NIC device to send the packet on ++ * @param nic_iface - NIC interface to send on the packet on ++ * @param pkt - packet to queue ++ * @return 0 if successful or <0 if unsuccessful ++ */ ++int nic_queue_tx_packet(nic_t *nic, ++ nic_interface_t *nic_iface, packet_t *pkt) ++{ ++ packet_t *queued_pkt; ++ ++ queued_pkt = nic_alloc_packet_buffer(nic, nic_iface, ++ pkt->buf, pkt->buf_size); ++ if (queued_pkt == NULL) { ++ LOG_ERR(PFX "%s: Couldn't allocate tx packet to queue", ++ nic->log_name); ++ return -ENOMEM; ++ } ++ ++ if (nic->tx_packet_queue == NULL) { ++ nic->tx_packet_queue = queued_pkt; ++ } else { ++ packet_t *current_pkt; ++ ++ current_pkt = nic->tx_packet_queue; ++ while (current_pkt->next != NULL) ++ current_pkt = current_pkt->next; ++ ++ current_pkt->next = queued_pkt; ++ } ++ ++ LOG_DEBUG(PFX "%s: tx packet queued", nic->log_name); ++ ++ return 0; ++} ++ ++/** ++ * nic_dequeue_tx_packet() - Used pop a TX packet buffer of the TX ++ * @param dev - cnic_uio device to send the packet on ++ * @param buf - pointer to the buffer to send ++ * @param buf_size - size in bytes of the buffer to send ++ * @return NULL if there are no more TX packet buffers to send ++ * pointer to the packet buffer which is detached from the device ++ */ ++packet_t *nic_dequeue_tx_packet(nic_t *nic) ++{ ++ packet_t *pkt; ++ ++ pkt = nic->tx_packet_queue; ++ ++ /* There is a packet buffer to send, time to detach it from the ++ * cnic_uio device */ ++ if (pkt != NULL) { ++ nic->tx_packet_queue = pkt->next; ++ pkt->next = NULL; ++ } ++ ++ return pkt; ++} ++ ++void nic_fill_ethernet_header(nic_interface_t *nic_iface, ++ void *data, ++ void *src_addr, void *dest_addr, ++ int *pkt_size, void **start_addr, ++ uint16_t ether_type) ++{ ++ struct ether_header *eth; ++ uint16_t *vlan_hdr; ++ ++ eth = data; ++ ++ memcpy(eth->ether_shost, src_addr, ETH_ALEN); ++ memcpy(eth->ether_dhost, dest_addr, ETH_ALEN); ++ ++ vlan_hdr = (uint16_t *) (eth + 1); ++ eth->ether_type = htons(ether_type); ++ ++ *start_addr = vlan_hdr; ++} ++ ++/******************************************************************************* ++ * NIC interface management utility functions ++ ******************************************************************************/ ++/** ++ * nic_find_nic_iface() - This function is used to find an interface ++ * from the NIC ++ * @param nic - NIC to look for network interfaces ++ * @param vlan_id - VLAN id to look for ++ * @param protocol - either AF_INET or AF_INET6 ++ * @param iface_num - iface num to use if present ++ * @param request_type - IPV4/6 DHCP/STATIC ++ * @return nic_iface - if found network interface with the given VLAN ID ++ * if not found a NULL is returned ++ */ ++nic_interface_t *nic_find_nic_iface(nic_t *nic, ++ uint16_t protocol, ++ uint16_t vlan_id, ++ int iface_num, ++ int request_type) ++{ ++ nic_interface_t *current = nic->nic_iface; ++ nic_interface_t *current_vlan = NULL; ++ ++ while (current != NULL) { ++ if (current->protocol != protocol) ++ goto next; ++ ++ /* Check for iface_num first */ ++ if (iface_num != IFACE_NUM_INVALID) { ++ if (current->iface_num == iface_num) { ++ /* Exception is when iface_num == 0, need to ++ check for request_type also if != ++ IP_CONFIG_OFF */ ++ if (!iface_num && request_type != ++ IP_CONFIG_OFF) { ++ if (current->request_type == ++ request_type) ++ goto found; ++ } else { ++ goto found; ++ } ++ } ++ } else if (vlan_id == NO_VLAN) { ++ /* Just return the top of the family */ ++ goto found; ++ } else { ++ if ((current->vlan_id == vlan_id) && ++ ((request_type == IP_CONFIG_OFF) || ++ (current->request_type == request_type))) ++ goto found; ++ } ++ /* vlan_next loop */ ++ current_vlan = current->vlan_next; ++ while (current_vlan != NULL) { ++ if (iface_num != IFACE_NUM_INVALID) { ++ if (current_vlan->iface_num == iface_num) { ++ if (!iface_num && request_type != ++ IP_CONFIG_OFF) { ++ if (current_vlan->request_type ++ == request_type) ++ goto vlan_found; ++ } else { ++ goto vlan_found; ++ } ++ } ++ } ++ if ((current_vlan->vlan_id == vlan_id) && ++ ((request_type == IP_CONFIG_OFF) || ++ (current_vlan->request_type == request_type))) ++ goto vlan_found; ++ ++ current_vlan = current_vlan->vlan_next; ++ } ++next: ++ current = current->next; ++ } ++vlan_found: ++ current = current_vlan; ++found: ++ return current; ++} ++ ++/* Called with nic mutex held */ ++void persist_all_nic_iface(nic_t *nic) ++{ ++ nic_interface_t *current_vlan, *current; ++ ++ current = nic->nic_iface; ++ while (current != NULL) { ++ current->flags |= NIC_IFACE_PERSIST; ++ current_vlan = current->vlan_next; ++ while (current_vlan != NULL) { ++ current_vlan->flags |= NIC_IFACE_PERSIST; ++ current_vlan = current_vlan->vlan_next; ++ } ++ current = current->next; ++ } ++} ++ ++/* Sets the nic_iface to the front of the AF */ ++void set_nic_iface(nic_t *nic, nic_interface_t *nic_iface) ++{ ++ nic_interface_t *current, *prev; ++ nic_interface_t *current_vlan, *prev_vlan; ++ ++ prev = NULL; ++ current = nic->nic_iface; ++ while (current != NULL) { ++ if (current->protocol != nic_iface->protocol) ++ goto next; ++ /* If its already on top of the list, exit */ ++ if (current == nic_iface) ++ goto done; ++ ++ prev_vlan = current; ++ current_vlan = current->vlan_next; ++ ++ while (current_vlan != NULL) { ++ if (current_vlan == nic_iface) { ++ /* Found inside the vlan list */ ++ /* For vlan == 0, place on top of ++ the AF list */ ++ prev_vlan->vlan_next = ++ current_vlan->vlan_next; ++ current_vlan->vlan_next = current; ++ if (prev) ++ prev->next = current_vlan; ++ else ++ nic->nic_iface = current_vlan; ++ goto done; ++ } ++ prev_vlan = current_vlan; ++ current_vlan = current_vlan->vlan_next; ++ } ++next: ++ prev = current; ++ current = current->next; ++ } ++done: ++ return; ++} ++ ++/******************************************************************************* ++ * Packet management utility functions ++ ******************************************************************************/ ++/** ++ * get_next_packet_in_queue() - This function will return the next packet in ++ * the queue ++ * @param queue - the queue to pull the packet from ++ * @return the packet in the queue ++ */ ++static packet_t *get_next_packet_in_queue(packet_t **queue) ++{ ++ packet_t *pkt; ++ ++ if (*queue == NULL) ++ return NULL; ++ ++ pkt = *queue; ++ *queue = pkt->next; ++ ++ return pkt; ++} ++ ++/** ++ * get_next_tx_packet() - This function will return the next packet in ++ * the TX queue ++ * @param nic - NIC to pull the TX packet from ++ * @return the packet in hte queue ++ */ ++packet_t *get_next_tx_packet(nic_t *nic) ++{ ++ return get_next_packet_in_queue(&nic->tx_packet_queue); ++} ++ ++/** ++ * get_next_free_packet() - This function will return the next packet in ++ * the free queue ++ * @param nic - NIC to pull the RX packet from ++ * @return the packet in hte queue ++ */ ++packet_t *get_next_free_packet(nic_t *nic) ++{ ++ packet_t *pkt; ++ pthread_mutex_lock(&nic->free_packet_queue_mutex); ++ pkt = get_next_packet_in_queue(&nic->free_packet_queue); ++ pthread_mutex_unlock(&nic->free_packet_queue_mutex); ++ ++ if (pkt != NULL) ++ reset_packet(pkt); ++ ++ return pkt; ++} ++ ++/** ++ * put_packet_in_queue() - This function will place the packet in the given ++ * queue ++ * @param pkt - the packet to place ++ * @param queue - the queue to place the packet ++ * @return the packet in the queue ++ */ ++static void put_packet_in_queue(packet_t *pkt, packet_t **queue) ++{ ++ if (*queue == NULL) ++ *queue = pkt; ++ else { ++ pkt->next = *queue; ++ *queue = pkt; ++ } ++} ++ ++/** ++ * put_packet_in_tx_queue() - This function will place the packet in ++ * the TX queue ++ * @param pkt - packet to place ++ * @param nic - NIC to pull the TX packet from ++ * @return the packet in hte queue ++ */ ++void put_packet_in_tx_queue(packet_t *pkt, nic_t *nic) ++{ ++ return put_packet_in_queue(pkt, &nic->tx_packet_queue); ++} ++ ++/** ++ * put_packet_in_free_queue() - This function will place the packet in ++ * the RX queue ++ * @param pkt - packet to place ++ * @param nic - NIC to pull the RX packet from ++ * @return the packet in hte queue ++ */ ++void put_packet_in_free_queue(packet_t *pkt, nic_t *nic) ++{ ++ pthread_mutex_lock(&nic->free_packet_queue_mutex); ++ put_packet_in_queue(pkt, &nic->free_packet_queue); ++ pthread_mutex_unlock(&nic->free_packet_queue_mutex); ++} ++ ++uint32_t calculate_default_netmask(uint32_t ip_addr) ++{ ++ uint32_t netmask; ++ ++ if (IN_CLASSA(ntohl(ip_addr))) ++ netmask = htonl(IN_CLASSA_NET); ++ else if (IN_CLASSB(ntohl(ip_addr))) ++ netmask = htonl(IN_CLASSB_NET); ++ else if (IN_CLASSC(ntohl(ip_addr))) ++ netmask = htonl(IN_CLASSC_NET); ++ else { ++ LOG_ERR("Unable to guess netmask for address %x\n", &ip_addr); ++ return -1; ++ } ++ ++ return netmask; ++} ++ ++void dump_packet_to_log(struct nic_interface *iface, ++ uint8_t *buf, uint16_t buf_len) ++{ ++ ++ FILE *file; ++ char str[80]; ++ int i, count; ++ ++ file = fmemopen(str, sizeof(str), "w+"); ++ if (file == NULL) { ++ LOG_ERR(PFX "Could not create logging file stream for packet " ++ "logging: [%d: %s]", errno, strerror(errno)); ++ return; ++ } ++ ++ LOG_PACKET(PFX "%s: Start packet dump len: %d", iface->parent->log_name, ++ buf_len); ++ ++ for (i = 0; i < buf_len; i++) { ++ rewind(file); ++ fprintf(file, "%03x: ", i); ++ ++ for (count = 0; (count < 8) && i < buf_len; count++, i++) ++ fprintf(file, " %02x", buf[i]); ++ fflush(file); ++ ++ LOG_PACKET(PFX "%s: %s", iface->parent->log_name, str); ++ } ++ ++ LOG_PACKET(PFX "%s: end packet dump", iface->parent->log_name); ++ ++ fclose(file); ++} ++ ++/******************************************************************************* ++ * File Management ++ ******************************************************************************/ ++ /** ++ * determine_file_size_read() - when fstat doesn't work on filepath ++ * within the /proc filesytem, we need to read/count the size of the file ++ * until we hit a EOF ++ * @parm filepath - path of the file in which to determine the filesize in ++ * bytes ++ * @return file size in bytes, <0 on failure ++ */ ++int determine_file_size_read(const char *filepath) ++{ ++ size_t total_size = 0; ++ ssize_t size = 1; ++ int fd; ++ char buf[1024]; ++ ++ fd = open(filepath, O_RDONLY); ++ if (fd == -1) { ++ LOG_ERR("Could not open file: %s [%s]", ++ filepath, strerror(errno)); ++ return -1; ++ } ++ ++ while (size > 0) { ++ size = read(fd, buf, sizeof(buf)); ++ ++ switch (size) { ++ case 0: ++ break; ++ case -1: ++ LOG_ERR("Error reading file: %s [%s]", ++ filepath, strerror(errno)); ++ total_size = -1; ++ break; ++ default: ++ total_size += size; ++ break; ++ } ++ } ++ ++ close(fd); ++ ++ return total_size; ++} ++ ++/** ++ * capture_file() - Used to capture a file into a buffer ++ * @param raw - This pointer will be set to the buffer which will hold the ++ * file contents ++ * @param raw_size - This is the size of the buffer returned ++ * @param path - The file path to capture the data from ++ * @return 0 is returned on success, <0 is returned on failure ++ */ ++int capture_file(char **raw, uint32_t *raw_size, const char *path) ++{ ++ FILE *fp; ++ size_t read_size; ++ int rc = 0; ++ int file_size; ++ ++ file_size = determine_file_size_read(path); ++ if (file_size < 0) { ++ LOG_ERR("Could not determine size %s", path); ++ return -EIO; ++ } ++ ++ fp = fopen(path, "r"); ++ if (fp == NULL) { ++ LOG_ERR("Could not open path %s [%s]", path, strerror(errno)); ++ return -EIO; ++ } ++ ++ *raw = malloc(file_size); ++ if (*raw == NULL) { ++ LOG_ERR("Could not malloc space for capture %s", path); ++ rc = -ENOMEM; ++ goto error; ++ } ++ ++ read_size = fread(*raw, file_size, 1, fp); ++ if (!read_size) { ++ LOG_ERR("Could not read capture, path: %s len: %d [%s]", ++ path, file_size, strerror(ferror(fp))); ++ free(*raw); ++ *raw = NULL; ++ rc = errno; ++ } else ++ *raw_size = file_size; ++ ++error: ++ fclose(fp); ++ ++ LOG_INFO("Done capturing %s", path); ++ ++ return rc; ++} +diff --git a/iscsiuio/src/unix/nic_utils.h b/iscsiuio/src/unix/nic_utils.h +new file mode 100644 +index 0000000..d5c1b58 +--- /dev/null ++++ b/iscsiuio/src/unix/nic_utils.h +@@ -0,0 +1,102 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * nic_util.h - NIC utility functions ++ * ++ */ ++#ifndef __NIC_UTILS_H__ ++#define __NIC_UTILS_H__ ++ ++#include "nic.h" ++ ++/****************************************************************************** ++ * Function Prototype ++ ******************************************************************************/ ++int manually_trigger_uio_event(nic_t *nic, int uio_minor); ++ ++int nic_discover_iscsi_hosts(); ++ ++int enable_mutlicast(nic_t *nic); ++int disable_mutlicast(nic_t *nic); ++ ++int from_netdev_name_find_nic(char *interface_name, nic_t **nic); ++ ++int from_host_no_find_associated_eth_device(int host_no, nic_t **nic); ++ ++int from_phys_name_find_assoicated_uio_device(nic_t *nic); ++ ++int nic_queue_tx_packet(nic_t *nic, ++ nic_interface_t *nic_iface, packet_t *pkt); ++ ++packet_t *nic_dequeue_tx_packet(nic_t *nic); ++ ++void nic_fill_ethernet_header(nic_interface_t *nic_iface, ++ void *data, ++ void *src_addr, void *dest_addr, ++ int *pkt_size, void **start_addr, ++ uint16_t ether_type); ++ ++struct nic_interface *nic_find_nic_iface(nic_t *nic, uint16_t protocol, ++ uint16_t vlan_id, int iface_num, ++ int request_type); ++void set_nic_iface(nic_t *nic, nic_interface_t *nic_iface); ++ ++void persist_all_nic_iface(nic_t *nic); ++ ++int add_vlan_interfaces(nic_t *nic); ++ ++int nic_verify_uio_sysfs_name(nic_t *nic); ++void cnic_get_sysfs_pci_resource_path(nic_t *nic, int resc_no, ++ char *sys_path, size_t size); ++void nic_close_all(); ++void nic_remove_all(); ++ ++int detemine_initial_uio_events(nic_t *nic, uint32_t *num_of_events); ++ ++uint32_t calculate_default_netmask(uint32_t ip_addr); ++ ++void prepare_nic_thread(nic_t *nic); ++void prepare_library(nic_t *nic); ++ ++int nic_enable(nic_t *nic); ++void nic_disable(nic_t *nic, int going_down); ++ ++void dump_packet_to_log(struct nic_interface *iface, ++ uint8_t *buf, uint16_t buf_len); ++ ++int determine_file_size_read(const char *filepath); ++int capture_file(char **raw, uint32_t *raw_size, const char *path); ++ ++#endif /* __NIC_UTILS_H__ */ +diff --git a/iscsiuio/src/unix/nic_vlan.c b/iscsiuio/src/unix/nic_vlan.c +new file mode 100644 +index 0000000..eb33381 +--- /dev/null ++++ b/iscsiuio/src/unix/nic_vlan.c +@@ -0,0 +1,337 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * nic_vlan.c - uIP user space stack VLAN utilities ++ * ++ */ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "logger.h" ++#include "nic.h" ++#include "nic_utils.h" ++#include "nic_vlan.h" ++ ++/******************************************************************************* ++ * Constants ++ ******************************************************************************/ ++#define PFX "vlan" ++ ++static const char proc_vlan_config_path[] = "/proc/net/vlan/config"; ++ ++/******************************************************************************* ++ * Resolving Found VLAN's for CNIC ++ ******************************************************************************/ ++int init_vlan_found_handle(struct vlan_found_handle *found_handle, ++ struct vlan_handle *handle) ++{ ++ memset(found_handle, 0, sizeof(*found_handle)); ++ ++ found_handle->entries = malloc(found_handle->num_of_entries * ++ sizeof(struct vlan_found_entry)); ++ if (found_handle->entries == NULL) { ++ LOG_ERR("Could not allocate space for found entries"); ++ return -ENOMEM; ++ } ++ ++ found_handle->handle = handle; ++ found_handle->num_of_entries = handle->num_of_entries; ++ ++ memset(found_handle->entries, 0, found_handle->num_of_entries * ++ sizeof(struct vlan_found_entry)); ++ ++ handle->outstanding_found_handles++; ++ ++ return 0; ++} ++ ++void release_vlan_found_handle(struct vlan_found_handle *found_handle) ++{ ++ if (found_handle->entries != NULL) { ++ free(found_handle->entries); ++ found_handle->entries = NULL; ++ } ++ ++ found_handle->num_of_entries = 0; ++ ++ found_handle->handle->outstanding_found_handles--; ++ ++ found_handle->handle = NULL; ++ ++} ++ ++/******************************************************************************* ++ * Resolving VLAN's for CNIC ++ ******************************************************************************/ ++/** ++ * init_vlan_handle() - Used to initialize struct ipv4_route_handle so ++ * that is can be used ++ * @param handle - Pointer to struct ipv4_route_handle to initialize ++ * @return 0 on success and <0 on failure ++ */ ++void init_vlan_table(struct vlan_handle *handle) ++{ ++ handle->entries = NULL; ++ handle->num_of_entries = 0; ++} ++ ++/** ++ * parse_vlan_table() - Given the raw dump of a Linux vlan table, this ++ * function will parse the into entries held by ++ * struct vlan_handle ++ * @param handle - struct vlan_handle used to hold the parsed contents ++ * @param raw - buffer to parse the contents from ++ * @param raw_size - size of the buffer in bytes ++ * @return 0 on success, <0 on failure ++ */ ++int parse_vlan_table(struct vlan_handle *handle, char *raw, uint32_t raw_size) ++{ ++ FILE *fp; ++ int i; ++ char *token; ++ size_t size; ++ int rc; ++ ++ token = raw; ++ ++ /* determine the number of entries */ ++ while (*token != '\0') { ++ if (*token == '\n') ++ handle->num_of_entries++; ++ ++ token++; ++ } ++ ++ /* There are 2 lines which describe the vlan table ++ * This lines need to be skipped with counting */ ++ handle->num_of_entries -= 2; ++ ++ LOG_INFO("Number of vlan entries: %d", handle->num_of_entries); ++ ++ size = handle->num_of_entries * sizeof(struct vlan_entry); ++ handle->entries = malloc(size); ++ if (handle->entries == NULL) { ++ LOG_ERR ++ ("Couldn't malloc space to parse vlan table. entires: %d " ++ "size: %d", ++ handle->num_of_entries, size); ++ return -ENOMEM; ++ } ++ ++ fp = fmemopen(raw, raw_size, "r"); ++ if (fp == NULL) { ++ LOG_ERR("Could not open raw dump of vlan table"); ++ rc = errno; ++ goto fmemopen_error; ++ } ++ ++ if (fscanf(fp, "%*[^\n]\n") < 0) { /* Skip the first line. */ ++ LOG_ERR("Empty or missing line, or read error"); ++ rc = -EIO; ++ goto error; ++ } ++ ++ if (fscanf(fp, "%*[^\n]\n") < 0) { /* Skip the second line. */ ++ LOG_ERR("Empty or missing line, or read error"); ++ rc = -EIO; ++ goto error; ++ } ++ ++ i = 0; ++ /* Time to parse the routing table */ ++ while (1) { ++ struct vlan_entry *entry = &handle->entries[i]; ++ int r; ++ ++ r = fscanf(fp, "%15s |%hu |%15s", ++ entry->vlan_iface_name, ++ &entry->vlan_id, entry->phy_iface_name); ++ if (r != 3) { ++ if (feof(fp)) { /* EOF with no (nonspace) chars read. */ ++ break; ++ } ++ ++ LOG_WARN("Parsing error: parsed %d elements", r); ++ break; ++ } ++ ++ i++; ++ ++ LOG_DEBUG("Vlan %d: vlan iface:%s vlan id:%d phys iface:%s", ++ i, ++ entry->vlan_iface_name, ++ entry->vlan_id, entry->phy_iface_name); ++ } ++ ++ fclose(fp); ++ ++ return 0; ++ ++error: ++ fclose(fp); ++ ++fmemopen_error: ++ if (handle->entries != NULL) ++ free(handle->entries); ++ ++ return rc; ++} ++ ++/** ++ * capture_vlan_table() - This function will snapshot the Linux vlan ++ * routing table for further processing ++ * @param handle - struct vlan_handle used to hold the routing context ++ * @return 0 on success, <0 on failure ++ */ ++int capture_vlan_table(struct vlan_handle *handle) ++{ ++ char *raw = NULL; ++ uint32_t raw_size = 0; ++ int rc; ++ ++ rc = capture_file(&raw, &raw_size, proc_vlan_config_path); ++ if (rc != 0) ++ goto error; ++ ++ rc = parse_vlan_table(handle, raw, raw_size); ++ if (rc != 0) ++ goto error; ++ ++error: ++ if (raw != NULL) ++ free(raw); ++ ++ return rc; ++} ++ ++/** ++ * release_vlan_table() - This function will free all resources used by ++ * the handle ++ * @param handle - struct vlan_handle used to hold the routing context ++ */ ++void release_vlan_table(struct vlan_handle *handle) ++{ ++ if (handle->entries != NULL) { ++ free(handle->entries); ++ handle->entries = NULL; ++ } ++ ++ handle->num_of_entries = 0; ++} ++ ++/** ++ * find_phy_using_vlan_interface() - Given the interface name determine VLAN ++ * tag ID to match either the physical or VLAN interface name ++ * @param vlan_iface_name - VLAN interface used to find the physical ++ * interface ++ * @param phy_iface_name - returned value is the physical interface name ++ * @param vlan_id - returned value is the VLAN id ++ * @return 1 is returned if the interface is a VLAN, 0 if the interface is not ++ * <0 is returned if there is an error ++ */ ++int find_phy_using_vlan_interface(struct vlan_handle *handle, ++ char *vlan_iface_name, ++ char **phy_iface_name, uint16_t *vlan_id) ++{ ++ int i, rc = 0; ++ ++ for (i = 0; i < handle->num_of_entries; i++) { ++ struct vlan_entry *entry = &handle->entries[i]; ++ ++ /* Compare VLAN interface names to find a match */ ++ if (strcmp(entry->vlan_iface_name, vlan_iface_name) == 0) { ++ *phy_iface_name = entry->phy_iface_name; ++ *vlan_id = entry->vlan_id; ++ rc = 1; ++ break; ++ } ++ } ++ ++ return rc; ++} ++ ++/** ++ * find_vlans_using_phy_interface() - Given the physical interface name this ++ * function will determine the VLAN interface name and VLAN ID ++ * @param iface_name - physical interface used to find the vlan interface ++ * @param vlan_iface_name - returned value is the VLAN interface name ++ * @return The number of VLAN interfaces found ++ */ ++int find_vlans_using_phy_interface(struct vlan_handle *handle, ++ struct vlan_found_handle *found_handle, ++ char *phy_iface_name) ++{ ++ int i, num_found = 0; ++ ++ for (i = 0; i < handle->num_of_entries; i++) { ++ struct vlan_entry *entry = &handle->entries[i]; ++ ++ /* Compare interface names to find a match */ ++ if (strcmp(entry->phy_iface_name, phy_iface_name) == 0) { ++ found_handle->entries[i].found = VLAN_ENTRY_FOUND; ++ num_found++; ++ } ++ } ++ ++ return num_found; ++} ++ ++/** ++ * valid_vlan() - determine if the vlan value which is passed is valid ++ * @param vlan - vlan value to test ++ * @return 0 - not valid, 1 - valid ++ */ ++int valid_vlan(short int vlan) ++{ ++ /* Allow vlan 1 to connect */ ++ if (vlan > 0 && vlan < 4095) ++ return 1; ++ ++ return 0; ++} +diff --git a/iscsiuio/src/unix/nic_vlan.h b/iscsiuio/src/unix/nic_vlan.h +new file mode 100644 +index 0000000..610f721 +--- /dev/null ++++ b/iscsiuio/src/unix/nic_vlan.h +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * nic_vlan.h - uIP user space stack VLAN utilities ++ * ++ */ ++#ifndef __NIC_VLAN_H__ ++#define __NIC_VLAN_H__ ++ ++#include ++ ++/* Used to hold entries in the vlan table */ ++struct vlan_entry { ++ char vlan_iface_name[16]; ++ char phy_iface_name[16]; ++ uint16_t vlan_id; ++}; ++ ++struct vlan_handle { ++ struct vlan_entry *entries; ++ uint32_t num_of_entries; ++ ++ uint32_t outstanding_found_handles; ++}; ++ ++struct vlan_found_entry { ++#define VLAN_ENTRY_FOUND 1 ++#define VLAN_ENTRY_NOT_FOUND 0 ++ uint8_t found; ++}; ++ ++struct vlan_found_handle { ++ struct vlan_handle *handle; ++ uint32_t num_of_entries; ++ struct vlan_found_entry *entries; ++}; ++ ++/******************************************************************************* ++ * Function Prototypes ++ ******************************************************************************/ ++void init_vlan_table(struct vlan_handle *handle); ++int capture_vlan_table(struct vlan_handle *handle); ++void release_vlan_table(struct vlan_handle *handle); ++ ++int find_phy_using_vlan_interface(struct vlan_handle *handle, ++ char *vlan_iface_name, ++ char **phy_iface_name, uint16_t *vlan_id); ++int find_vlans_using_phy_interface(struct vlan_handle *handle, ++ struct vlan_found_handle *found_handle, ++ char *phy_iface_name); ++ ++int init_vlan_found_handle(struct vlan_found_handle *found_handle, ++ struct vlan_handle *handle); ++void release_vlan_found_handle(struct vlan_found_handle *found_handle); ++ ++int valid_vlan(short int vlan); ++#endif /* __NIC_VLAN_H__ */ +diff --git a/iscsiuio/src/unix/options.h b/iscsiuio/src/unix/options.h +new file mode 100644 +index 0000000..df03255 +--- /dev/null ++++ b/iscsiuio/src/unix/options.h +@@ -0,0 +1,117 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * options.h - CNIC UIO uIP user space stack ++ * ++ */ ++#ifndef __OPTIONS_H__ ++#define __OPTIONS_H__ ++ ++#include ++#include ++#include ++ ++/****************************************************************************** ++ * Constants which are tuned at compile time by the user ++ *****************************************************************************/ ++ ++/** ++ * MAX_COUNT_NIC_NL_RESP - This is the maximum number of polls uIP will ++ * try for a kernel response after a PATH_REQ ++ */ ++#define MAX_COUNT_NIC_NL_RESP 128 ++ ++/** ++ * NLM_BUF_DEFAULT_MAX - This is the buffer size allocated for the send/receive ++ * buffers used by the uIP Netlink subsystem. This ++ * value is in bytes. ++ */ ++#define NLM_BUF_DEFAULT_MAX 8192 /* bytes */ ++ ++/****************************************************************************** ++ * Non adjustable constants ++ *****************************************************************************/ ++#ifndef ETHERTYPE_IP ++#define ETHERTYPE_IP 0x0800 /* IP */ ++#endif /* ETHERTYPE_IP */ ++ ++#ifndef ETHERTYPE_IPV6 ++#define ETHERTYPE_IPV6 0x86dd /* IP protocol version 6 */ ++#endif /* ETHERTYPE_IPV6 */ ++ ++#ifndef ETHERTYPE_ARP ++#define ETHERTYPE_ARP 0x0806 /* Address resolution */ ++#endif /* ETHERTYPE_ARP */ ++ ++#ifndef ETHERTYPE_VLAN ++#define ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tagging */ ++#endif /* ETHERTYPE_VLAN */ ++ ++#define APP_NAME "iscsiuio" ++/* BUILD_DATE is automatically generated from the Makefile */ ++ ++#define DEBUG_OFF 0x1 ++#define DEBUG_ON 0x2 ++ ++#define INVALID_FD -1 ++#define INVALID_THREAD -1 ++ ++struct options { ++ char debug; ++ ++ /* Time the userspace daemon was started */ ++ time_t start_time; ++}; ++ ++extern int event_loop_stop; ++extern struct options opt; ++ ++#ifdef WORDS_BIGENDIAN ++#define ntohll(x) (x) ++#define htonll(x) (x) ++#else ++#define ntohll(x) bswap_64(x) ++#define htonll(x) bswap_64(x) ++#endif ++ ++# define likely(x) __builtin_expect(!!(x), 1) ++# define unlikely(x) __builtin_expect(!!(x), 0) ++ ++/* taken from Linux kernel, include/linux/compiler-gcc.h */ ++/* Optimization barrier */ ++/* The "volatile" is due to gcc bugs */ ++#define barrier() __asm__ __volatile__("": : :"memory") ++ ++#endif +diff --git a/iscsiuio/src/unix/packet.c b/iscsiuio/src/unix/packet.c +new file mode 100644 +index 0000000..ecea09b +--- /dev/null ++++ b/iscsiuio/src/unix/packet.c +@@ -0,0 +1,145 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * packet.c - packet management ++ * ++ */ ++#include ++#include ++#include ++ ++#include "logger.h" ++#include "packet.h" ++#include "nic.h" ++ ++/** ++ * alloc_packet() - Function used to allocate memory for a packet ++ * @param max_buf_size - max packet size ++ * @param priv_size - size of the assoicated private data ++ * @return NULL if failed, on success return a pointer to the packet ++ */ ++struct packet *alloc_packet(size_t max_buf_size, size_t priv_size) ++{ ++ struct packet *pkt; ++ void *priv; ++ ++ pkt = malloc(max_buf_size + sizeof(struct packet)); ++ if (pkt == NULL) { ++ LOG_ERR("Could not allocate any memory for packet"); ++ return NULL; ++ } ++ memset(pkt, 0, max_buf_size + sizeof(struct packet)); ++ ++ priv = malloc(priv_size); ++ if (priv == NULL) { ++ LOG_ERR("Could not allocate any memory for private structure"); ++ goto free_pkt; ++ } ++ memset(priv, 0, priv_size); ++ pkt->max_buf_size = max_buf_size; ++ pkt->priv = priv; ++ ++ return pkt; ++ ++free_pkt: ++ free(pkt); ++ ++ return NULL; ++} ++ ++void free_packet(struct packet *pkt) ++{ ++ if (pkt->priv != NULL) ++ free(pkt->priv); ++ ++ free(pkt); ++} ++ ++/** ++ * reset_packet() - This will reset the packet fields to default values ++ * @param pkt - the packet to reset ++ */ ++void reset_packet(packet_t *pkt) ++{ ++ pkt->next = NULL; ++ ++ pkt->flags = 0; ++ pkt->vlan_tag = 0; ++ ++ pkt->buf_size = 0; ++ ++ pkt->data_link_layer = NULL; ++ pkt->network_layer = NULL; ++} ++ ++int alloc_free_queue(nic_t *nic, size_t num_of_packets) ++{ ++ int i; ++ ++ pthread_mutex_lock(&nic->free_packet_queue_mutex); ++ for (i = 0; i < num_of_packets; i++) { ++ packet_t *pkt; ++ ++ pkt = alloc_packet(1500, 1500); ++ if (pkt == NULL) { ++ goto done; ++ } ++ ++ reset_packet(pkt); ++ ++ pkt->next = nic->free_packet_queue; ++ nic->free_packet_queue = pkt; ++ } ++ ++done: ++ pthread_mutex_unlock(&nic->free_packet_queue_mutex); ++ ++ return i; ++} ++ ++void free_free_queue(nic_t *nic) ++{ ++ packet_t *pkt, *pkt_next; ++ ++ pthread_mutex_lock(&nic->free_packet_queue_mutex); ++ pkt = nic->free_packet_queue; ++ while (pkt) { ++ pkt_next = pkt->next; ++ free_packet(pkt); ++ pkt = pkt_next; ++ } ++ nic->free_packet_queue = NULL; ++ pthread_mutex_unlock(&nic->free_packet_queue_mutex); ++} +diff --git a/iscsiuio/src/unix/packet.h b/iscsiuio/src/unix/packet.h +new file mode 100644 +index 0000000..b63d688 +--- /dev/null ++++ b/iscsiuio/src/unix/packet.h +@@ -0,0 +1,76 @@ ++/* ++ * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2014, QLogic Corporation ++ * ++ * Written by: Benjamin Li (benli@broadcom.com) ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * packet.h - packet definitions ++ * ++ */ ++#include ++ ++#ifndef __PACKET_H__ ++#define __PACKET_H__ ++ ++#include "nic.h" ++ ++struct nic; ++struct nic_interface; ++ ++typedef struct packet { ++ struct packet *next; ++ ++ uint32_t flags; ++#define VLAN_TAGGED 0x0001 ++ uint16_t vlan_tag; ++ ++ size_t max_buf_size; ++ size_t buf_size; ++ ++ uint8_t *data_link_layer; ++ uint8_t *network_layer; ++ ++ struct nic *nic; ++ struct nic_interface *nic_iface; ++ ++ void *priv; ++ uint8_t buf[]; ++} packet_t; ++ ++/****************************************************************************** ++ * Packet Function Declarations ++ *****************************************************************************/ ++int alloc_free_queue(struct nic *, size_t num_of_packets); ++void free_free_queue(struct nic *); ++void reset_packet(packet_t *pkt); ++ ++#endif /* __PACKET_H__ */ +diff --git a/iscsiuio/src/unix/ping.c b/iscsiuio/src/unix/ping.c +new file mode 100644 +index 0000000..58a6d14 +--- /dev/null ++++ b/iscsiuio/src/unix/ping.c +@@ -0,0 +1,518 @@ ++/* ++ * Copyright (c) 2015, QLogic Corporation ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ping.c - Ping implementation for iscsiuio using ICMP/ICMPv6 ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "iscsi_if.h" ++ ++#include "uip.h" ++#include "uip_arp.h" ++#include "uip_eth.h" ++#include "dhcpc.h" ++#include "ipv6_ndpc.h" ++#include "ipv6.h" ++ ++#include "logger.h" ++#include "nic.h" ++#include "nic_utils.h" ++#include "options.h" ++#include "packet.h" ++#include "bnx2.h" ++#include "bnx2x.h" ++#include "cnic.h" ++#include "ping.h" ++ ++#define PFX "ping " ++ ++static void fill_payload_data(struct uip_stack *ustack) ++{ ++ if (ustack->uip_slen) ++ memset(ustack->uip_appdata, 'A', ustack->uip_slen); ++} ++ ++static int prepare_icmpv4_req_pkt(struct ping_conf *png_c, struct packet *pkt, ++ uip_ip4addr_t *dst_addr) ++{ ++ nic_interface_t *nic_iface = png_c->nic_iface; ++ struct uip_stack *ustack = &nic_iface->ustack; ++ struct uip_ipv4_hdr *ipv4_hdr = NULL; ++ struct uip_icmpv4_hdr *icmpv4_hdr = NULL; ++ u16_t uip_iph_len = 0; ++ u16_t icmpv4_hdr_len = 0; ++ u16_t uip_ip_icmph_len = 0; ++ int mtu = 1500; ++ int rc = 0; ++ ++ uip_iph_len = UIP_IPv4_H_LEN; ++ icmpv4_hdr_len = sizeof(*icmpv4_hdr); ++ uip_ip_icmph_len = uip_iph_len + icmpv4_hdr_len; ++ ++ ipv4_hdr = (struct uip_ipv4_hdr *)ustack->network_layer; ++ ++ icmpv4_hdr = (struct uip_icmpv4_hdr *) (ustack->network_layer + ++ sizeof(struct uip_ipv4_hdr)); ++ ++ /* fill IP header */ ++ ipv4_hdr->vhl = 0x45; ++ ipv4_hdr->tos = 0; ++ ++ustack->ipid; ++ ipv4_hdr->ipid[0] = ustack->ipid >> 8; ++ ipv4_hdr->ipid[1] = ustack->ipid & 0xff; ++ ipv4_hdr->ipoffset[0] = 0; ++ ipv4_hdr->ipoffset[1] = 0; ++ ipv4_hdr->ttl = UIP_TTL; ++ ipv4_hdr->proto = UIP_PROTO_ICMP; ++ uip_ip4addr_copy(ipv4_hdr->srcipaddr, ustack->hostaddr); ++ uip_ip4addr_copy(ipv4_hdr->destipaddr, dst_addr); ++ ++ LOG_INFO(PFX "src ipaddr: %d.%d.%d.%d", ++ uip_ipaddr1(ipv4_hdr->srcipaddr), ++ uip_ipaddr2(ipv4_hdr->srcipaddr), ++ uip_ipaddr3(ipv4_hdr->srcipaddr), ++ uip_ipaddr4(ipv4_hdr->srcipaddr)); ++ ++ LOG_INFO(PFX "dest ipaddr: %d.%d.%d.%d", ++ uip_ipaddr1(ipv4_hdr->destipaddr), ++ uip_ipaddr2(ipv4_hdr->destipaddr), ++ uip_ipaddr3(ipv4_hdr->destipaddr), ++ uip_ipaddr4(ipv4_hdr->destipaddr)); ++ ++ /* fill ICMP header */ ++ icmpv4_hdr->type = ICMP_ECHO; ++ icmpv4_hdr->icode = 0; ++ icmpv4_hdr->id = getpid() & 0xffff; ++ png_c->id = icmpv4_hdr->id; ++ icmpv4_hdr->seqno = ustack->ipid; ++ png_c->seqno =icmpv4_hdr->seqno; ++ ++ /* appdata and sappdata point to the icmp payload */ ++ ustack->uip_appdata = ustack->network_layer + uip_ip_icmph_len; ++ ustack->uip_sappdata = ustack->uip_appdata; ++ ++ if (nic_iface->mtu) ++ mtu = nic_iface->mtu; ++ ++ if ((mtu - uip_ip_icmph_len) > png_c->datalen) { ++ ustack->uip_slen = png_c->datalen; ++ } else { ++ png_c->state = ISCSI_PING_OVERSIZE_PACKET; ++ LOG_ERR(PFX "MTU=%d, payload=%d\n", ++ mtu, png_c->datalen); ++ rc = -EINVAL; ++ goto done; ++ } ++ ++ fill_payload_data(ustack); ++ ++ /* Calculate ICMP checksum. */ ++ icmpv4_hdr->icmpchksum = 0; ++ icmpv4_hdr->icmpchksum = ~(uip_chksum((u16_t *)icmpv4_hdr, ++ icmpv4_hdr_len + ++ ustack->uip_slen)); ++ if (icmpv4_hdr->icmpchksum == 0) ++ icmpv4_hdr->icmpchksum = 0xffff; ++ ++ /* IPv4 total length = IPv4 HLEN + ICMP HLEN + Payload len */ ++ ustack->uip_len = uip_ip_icmph_len + ustack->uip_slen; ++ ipv4_hdr->len[0] = (ustack->uip_len >> 8); ++ ipv4_hdr->len[1] = (ustack->uip_len & 0xff); ++ ++ /* Calculate IP checksum. */ ++ ipv4_hdr->ipchksum = 0; ++ ipv4_hdr->ipchksum = ~(uip_ipchksum(ustack)); ++ if (ipv4_hdr->ipchksum == 0) ++ ipv4_hdr->ipchksum = 0xffff; ++ ++ ++ustack->stats.ip.sent; ++ /* Return and let the caller do the actual transmission. */ ++ ustack->uip_flags = 0; ++ ++done: ++ return rc; ++} ++ ++static void prepare_icmpv6_req_pkt(struct ping_conf *png_c, struct packet *pkt, ++ uip_ip6addr_t *dst_addr, ++ uip_ip6addr_t *src_addr) ++{ ++ nic_interface_t *nic_iface = png_c->nic_iface; ++ struct uip_stack *ustack = &nic_iface->ustack; ++ struct uip_ipv6_hdr *ipv6_hdr = NULL; ++ uip_icmp_echo_hdr_t *icmp_echo_hdr = NULL; ++ u16_t uip_iph_len = 0; ++ u16_t icmp_echo_hdr_len = 0; ++ u16_t uip_ip_icmph_len = 0; ++ char ipbuf[INET6_ADDRSTRLEN] = {0}; ++ ++ uip_iph_len = UIP_IPv6_H_LEN; ++ icmp_echo_hdr_len = sizeof(*icmp_echo_hdr); ++ uip_ip_icmph_len = uip_iph_len + icmp_echo_hdr_len; ++ ++ ipv6_hdr = (struct uip_ipv6_hdr *)ustack->network_layer; ++ ++ icmp_echo_hdr = (uip_icmp_echo_hdr_t *) (ustack->network_layer + ++ sizeof(struct uip_ipv6_hdr)); ++ ++ /* fill IPv6 header */ ++ ipv6_hdr->vtc = 0x60; ++ ipv6_hdr->tcflow = 0; ++ ipv6_hdr->flow = 0; ++ ipv6_hdr->proto = UIP_PROTO_ICMP6; ++ ipv6_hdr->ttl = UIP_TTL; ++ uip_ip6addr_copy(ipv6_hdr->srcipaddr, src_addr); ++ uip_ip6addr_copy(ipv6_hdr->destipaddr, dst_addr); ++ ++ memset(ipbuf, 0, sizeof(ipbuf)); ++ if (inet_ntop(AF_INET6, &ipv6_hdr->srcipaddr, ipbuf, INET6_ADDRSTRLEN)) ++ LOG_INFO(PFX "src ipaddr=%s", ipbuf); ++ ++ memset(ipbuf, 0, sizeof(ipbuf)); ++ if (inet_ntop(AF_INET6, &ipv6_hdr->destipaddr, ipbuf, INET6_ADDRSTRLEN)) ++ LOG_INFO(PFX "dest ipaddr=%s", ipbuf); ++ ++ /* fill ICMP header */ ++ icmp_echo_hdr->type = ICMPV6_ECHO_REQ; ++ icmp_echo_hdr->icode = 0; ++ icmp_echo_hdr->id = HOST_TO_NET16(getpid() & 0xffff); ++ png_c->id = icmp_echo_hdr->id; ++ ++ustack->ipid; ++ icmp_echo_hdr->seqno = HOST_TO_NET16(ustack->ipid); ++ png_c->seqno = icmp_echo_hdr->seqno; ++ ++ /* appdata and sappdata point to the icmp payload */ ++ ustack->uip_appdata = ustack->network_layer + uip_ip_icmph_len; ++ ustack->uip_sappdata = ustack->uip_appdata; ++ ustack->uip_slen = png_c->datalen; ++ ++ fill_payload_data(ustack); ++ ++ /* Total length = ETH HLEN + IPv6 HLEN + ICMP HLEN + Data len */ ++ ustack->uip_len = UIP_LLH_LEN + uip_ip_icmph_len + ustack->uip_slen; ++ /* IPv6 payload len */ ++ ipv6_hdr->len = HOST_TO_NET16(icmp_echo_hdr_len + ustack->uip_slen); ++ ++ /* Calculate ICMP checksum. */ ++ icmp_echo_hdr->icmpchksum = 0; ++ icmp_echo_hdr->icmpchksum = ~(uip_icmp6chksum(ustack)); ++ ++ ++ustack->stats.ip.sent; ++ /* Return and let the caller do the actual transmission. */ ++ ustack->uip_flags = 0; ++ return; ++} ++ ++static int chk_arp_entry_for_dst_addr(nic_t *nic, nic_interface_t *nic_iface, ++ void *addr) ++{ ++ struct iscsi_path path; ++ uip_ip4addr_t dst_addr4; ++ uip_ip6addr_t dst_addr6; ++ ++ if (nic_iface->protocol == AF_INET) { ++ memcpy(dst_addr4, addr, sizeof(uip_ip4addr_t)); ++ memcpy(&path.dst.v4_addr, dst_addr4, sizeof(struct in_addr)); ++ path.ip_addr_len = 4; ++ } else { ++ memcpy(dst_addr6, addr, sizeof(uip_ip6addr_t)); ++ memcpy(&path.dst.v6_addr, dst_addr6, sizeof(struct in6_addr)); ++ path.ip_addr_len = 16; ++ } ++ ++ return cnic_handle_iscsi_path_req(nic, 0, NULL, &path, nic_iface); ++} ++ ++static int fill_icmpv6_eth_hdr(struct uip_stack *ustack, ++ uip_ip6addr_t *dst_addr6) ++{ ++ struct uip_eth_hdr *eth; ++ __u8 mac_addr[6]; ++ struct ndpc_reqptr req_ptr; ++ int rc = 0; ++ int ret = 0; ++ ++ eth = (struct uip_eth_hdr *)ustack->data_link_layer; ++ memcpy(eth->src.addr, ustack->uip_ethaddr.addr, sizeof(eth->src.addr)); ++ ++ memset(mac_addr, 0, sizeof(mac_addr)); ++ req_ptr.eth = (void *)mac_addr; ++ req_ptr.ipv6 = (void *)dst_addr6; ++ ++ ret = ndpc_request(ustack, &req_ptr, &rc, CHECK_ARP_TABLE); ++ if (ret) { ++ LOG_DEBUG(PFX "ndpc request failed"); ++ rc = ret; ++ } else if (rc) { ++ memcpy(eth->dest.addr, mac_addr, sizeof(eth->dest.addr)); ++ LOG_DEBUG(PFX "ipv6 arp entry present"); ++ rc = 0; ++ } else { ++ LOG_DEBUG(PFX "ipv6 arp entry not present"); ++ rc = -EAGAIN; ++ } ++ ++ return rc; ++} ++ ++static int determine_src_ipv6_addr(nic_interface_t *nic_iface, ++ uip_ip6addr_t *dst_addr6, ++ uip_ip6addr_t *src_addr6) ++{ ++ struct in6_addr *addr; ++ int rc = 0; ++ int ret = 0; ++ ++ if (nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) { ++ memcpy(src_addr6, &nic_iface->ustack.hostaddr6, ++ sizeof(uip_ip6addr_t)); ++ goto done; ++ } ++ ++ ret = ndpc_request(&nic_iface->ustack, dst_addr6, ++ &rc, CHECK_LINK_LOCAL_ADDR); ++ if (ret) { ++ LOG_DEBUG(PFX "Check LL failed"); ++ rc = ret; ++ goto done; ++ } ++ ++ if (rc) { ++ LOG_DEBUG(PFX "Use LL"); ++ /* Get link local IPv6 address */ ++ addr = (struct in6_addr *)&nic_iface->ustack.linklocal6; ++ rc = 0; ++ } else { ++ LOG_DEBUG(PFX "Use Best matched"); ++ ret = ndpc_request(&nic_iface->ustack, ++ dst_addr6, ++ &addr, GET_HOST_ADDR); ++ if (ret) { ++ LOG_DEBUG(PFX "Use Best matched failed"); ++ rc = ret; ++ goto done; ++ } ++ if (addr == NULL) { ++ LOG_DEBUG(PFX "No Best matched found"); ++ rc = -EINVAL; ++ goto done; ++ } ++ } ++ ++ /* Got the best matched src IP address */ ++ memcpy(src_addr6, addr, sizeof(struct in6_addr)); ++ ++done: ++ return rc; ++} ++ ++void ping_init(struct ping_conf *png_c, void *addr, u16_t type, int datalen) ++{ ++ png_c->dst_addr = addr; ++ png_c->proto = type; ++ png_c->state = PING_INIT_STATE; ++ png_c->datalen = datalen; ++ return; ++} ++ ++int do_ping_from_nic_iface(struct ping_conf *png_c) ++{ ++ packet_t *pkt; ++ nic_interface_t *nic_iface = png_c->nic_iface; ++ nic_t *nic = nic_iface->parent; ++ struct uip_stack *ustack = &nic_iface->ustack; ++ uip_ip4addr_t dst_addr4; ++ uip_ip6addr_t dst_addr6; ++ uip_ip6addr_t src_addr6; ++ struct timer ping_timer; ++ int rc = 0; ++ ++ memset(dst_addr4, 0, sizeof(uip_ip4addr_t)); ++ memset(dst_addr6, 0, sizeof(uip_ip6addr_t)); ++ memset(src_addr6, 0, sizeof(uip_ip6addr_t)); ++ ++ if (nic_iface->protocol == AF_INET) ++ memcpy(dst_addr4, png_c->dst_addr, sizeof(uip_ip4addr_t)); ++ else ++ memcpy(dst_addr6, png_c->dst_addr, sizeof(uip_ip6addr_t)); ++ ++ rc = chk_arp_entry_for_dst_addr(nic, nic_iface, png_c->dst_addr); ++ ++ if (rc && (nic_iface->protocol == AF_INET)) { ++ png_c->state = ISCSI_PING_NO_ARP_RECEIVED; ++ LOG_ERR(PFX "ARP failure for IPv4 dest addr"); ++ goto done; ++ } else if ((rc < 1) && (nic_iface->protocol == AF_INET6)) { ++ png_c->state = ISCSI_PING_NO_ARP_RECEIVED; ++ LOG_ERR(PFX "ARP failure for IPv6 dest addr"); ++ goto done; ++ } else if (rc < 0) { ++ LOG_ERR(PFX "ARP failure"); ++ goto done; ++ } ++ ++ pthread_mutex_lock(&nic->nic_mutex); ++ pkt = get_next_free_packet(nic); ++ if (pkt == NULL) { ++ pthread_mutex_unlock(&nic->nic_mutex); ++ LOG_ERR(PFX "Unable to get a free packet buffer"); ++ rc = -EIO; ++ goto done; ++ } ++ ++ prepare_ustack(nic, nic_iface, ustack, pkt); ++ ++ if (nic_iface->protocol == AF_INET) { ++ rc = prepare_icmpv4_req_pkt(png_c, pkt, &dst_addr4); ++ if (rc) ++ goto put_pkt; ++ ++ /* If the above function invocation resulted ++ * in data that should be sent out on the ++ * network, the global variable uip_len is ++ * set to a value > 0. */ ++ if (ustack->uip_len > 0) { ++ pkt->buf_size = ustack->uip_len; ++ ++ prepare_ipv4_packet(nic, nic_iface, ustack, pkt); ++ ++ LOG_DEBUG(PFX "Send ICMP echo request"); ++ (*nic->ops->write) (nic, nic_iface, pkt); ++ ustack->uip_len = 0; ++ } ++ } else { ++ rc = determine_src_ipv6_addr(nic_iface, &dst_addr6, &src_addr6); ++ if (rc) ++ goto put_pkt; ++ ++ prepare_icmpv6_req_pkt(png_c, pkt, &dst_addr6, &src_addr6); ++ ++ /* If the above function invocation resulted ++ * in data that should be sent out on the ++ * network, the global variable uip_len is ++ * set to a value > 0. */ ++ if (ustack->uip_len > 0) { ++ pkt->buf_size = ustack->uip_len; ++ ++ prepare_ipv6_packet(nic, nic_iface, ustack, pkt); ++ rc = fill_icmpv6_eth_hdr(ustack, &dst_addr6); ++ if (rc) { ++ ustack->uip_len = 0; ++ goto put_pkt; ++ } ++ ++ LOG_DEBUG(PFX "Send ICMPv6 echo request"); ++ (*nic->ops->write) (nic, nic_iface, pkt); ++ ustack->uip_len = 0; ++ } ++ } ++ ++put_pkt: ++ put_packet_in_free_queue(pkt, nic); ++ pthread_mutex_unlock(&nic->nic_mutex); ++ ++ if (rc) { ++ LOG_DEBUG(PFX "Ping request not transmitted"); ++ goto done; ++ } ++ ++ timer_set(&ping_timer, CLOCK_SECOND * 10); ++ ++ while ((event_loop_stop == 0) && ++ (nic->flags & NIC_ENABLED) && !(nic->flags & NIC_GOING_DOWN)) { ++ ++ rc = nic_process_intr(nic, 1); ++ ++ while ((rc > 0) && (!(nic->flags & NIC_GOING_DOWN))) { ++ rc = process_packets(nic, NULL, NULL, nic_iface); ++ } ++ ++ if (!rc && (png_c->state == ISCSI_PING_SUCCESS)) { ++ LOG_INFO(PFX "PING successful!"); ++ break; ++ } ++ ++ if (timer_expired(&ping_timer)) { ++ png_c->state = ISCSI_PING_TIMEOUT; ++ LOG_ERR(PFX "PING timeout"); ++ rc = -EIO; ++ break; ++ } ++ } ++ ++done: ++ return rc; ++} ++ ++int process_icmp_packet(uip_icmp_echo_hdr_t *icmp_hdr, ++ struct uip_stack *ustack) ++{ ++ struct ping_conf *png_c = (struct ping_conf *)ustack->ping_conf; ++ int rc = 0; ++ ++ LOG_INFO(PFX "Verify ICMP echo reply"); ++ ++ if ((icmp_hdr->type == ICMPV6_ECHO_REPLY && ++ png_c->proto == AF_INET6) || ++ (icmp_hdr->type == ICMP_ECHO_REPLY && ++ png_c->proto == AF_INET)) { ++ ++ if ((icmp_hdr->icode == 0) && ++ (icmp_hdr->id == png_c->id) && ++ (icmp_hdr->seqno == png_c->seqno)) { ++ png_c->state = ISCSI_PING_SUCCESS; ++ } else { ++ rc = 1; ++ } ++ } else { ++ rc = 1; ++ } ++ ++ if (rc) { ++ LOG_INFO(PFX "ICMP echo reply verification failed!"); ++ } else { ++ LOG_INFO(PFX "ICMP echo reply OK"); ++ } ++ ++ return rc; ++} +diff --git a/iscsiuio/src/unix/ping.h b/iscsiuio/src/unix/ping.h +new file mode 100644 +index 0000000..82ace6f +--- /dev/null ++++ b/iscsiuio/src/unix/ping.h +@@ -0,0 +1,73 @@ ++/* ++ * Copyright (c) 2015, QLogic Corporation ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ping.h - PING header file ++ * ++ */ ++ ++#ifndef __PING_H__ ++#define __PING_H__ ++ ++#include "nic_nl.h" ++#include "uip.h" ++ ++#define ICMP_ECHO_REPLY 0 ++#define ICMP_ECHO 8 ++ ++#define ICMPV6_ECHO_REQ 128 ++#define ICMPV6_ECHO_REPLY 129 ++ ++#define DEF_ICMP_PAYLOAD 32 ++#define DEF_ICMPV6_PAYLOAD 16 ++ ++#define PING_INIT_STATE (-1) ++ ++struct ping_conf ++{ ++ nic_t *nic; ++ nic_interface_t *nic_iface; ++ void *data; ++ int state; ++ void *dst_addr; ++ u16_t proto; ++ u16_t id; ++ u16_t seqno; ++ u16_t datalen; ++}; ++ ++void ping_init(struct ping_conf *png_c, void *addr, u16_t type, int datalen); ++ ++int do_ping_from_nic_iface(struct ping_conf *png_c); ++ ++int process_icmp_packet(uip_icmp_echo_hdr_t *icmp_hdr, ++ struct uip_stack *ustack); ++ ++#endif /* __PING_H__ */ +diff --git a/iscsiuio/src/unix/uip-conf.h b/iscsiuio/src/unix/uip-conf.h +new file mode 100644 +index 0000000..e6e11a5 +--- /dev/null ++++ b/iscsiuio/src/unix/uip-conf.h +@@ -0,0 +1,160 @@ ++/** ++ * \addtogroup uipopt ++ * @{ ++ */ ++ ++/** ++ * \name Project-specific configuration options ++ * @{ ++ * ++ * uIP has a number of configuration options that can be overridden ++ * for each project. These are kept in a project-specific uip-conf.h ++ * file and all configuration names have the prefix UIP_CONF. ++ */ ++ ++/* ++ * Copyright (c) 2006, Swedish Institute of Computer Science. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. Neither the name of the Institute nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * This file is part of the uIP TCP/IP stack ++ * ++ */ ++ ++/** ++ * \file ++ * An example uIP configuration file ++ * \author ++ * Adam Dunkels ++ */ ++ ++#ifndef __UIP_CONF_H__ ++#define __UIP_CONF_H__ ++ ++#include ++ ++/** ++ * 8 bit datatype ++ * ++ * This typedef defines the 8-bit type used throughout uIP. ++ * ++ * \hideinitializer ++ */ ++typedef uint8_t u8_t; ++ ++/** ++ * 16 bit datatype ++ * ++ * This typedef defines the 16-bit type used throughout uIP. ++ * ++ * \hideinitializer ++ */ ++typedef uint16_t u16_t; ++ ++/** ++ * 32 bit datatype ++ * ++ * This typedef defines the 16-bit type used throughout uIP. ++ * ++ * \hideinitializer ++ */ ++typedef uint32_t u32_t; ++ ++/** ++ * Statistics datatype ++ * ++ * This typedef defines the dataype used for keeping statistics in ++ * uIP. ++ * ++ * \hideinitializer ++ */ ++typedef uint64_t uip_stats_t; ++ ++/** ++ * Maximum number of TCP connections. ++ * ++ * \hideinitializer ++ */ ++#define UIP_CONF_MAX_CONNECTIONS 40 ++ ++/** ++ * Maximum number of listening TCP ports. ++ * ++ * \hideinitializer ++ */ ++#define UIP_CONF_MAX_LISTENPORTS 40 ++ ++/** ++ * uIP buffer size. ++ * ++ * \hideinitializer ++ */ ++#define UIP_CONF_BUFFER_SIZE 420 ++ ++/** ++ * CPU byte order. ++ * ++ * \hideinitializer ++ */ ++#define UIP_CONF_BYTE_ORDER LITTLE_ENDIAN ++ ++/** ++ * Logging on or off ++ * ++ * \hideinitializer ++ */ ++#define UIP_CONF_LOGGING 1 ++ ++/** ++ * UDP support on or off ++ * ++ * \hideinitializer ++ */ ++#define UIP_CONF_UDP 1 ++ ++/** ++ * UDP checksums on or off ++ * ++ * \hideinitializer ++ */ ++#define UIP_CONF_UDP_CHECKSUMS 1 ++ ++/** ++ * uIP statistics on or off ++ * ++ * \hideinitializer ++ */ ++#define UIP_CONF_STATISTICS 1 ++ ++#define UIP_CONF_IPV6 0 ++ ++#define INET_ADDRSTRLEN 16 ++#define INET6_ADDRSTRLEN 46 ++ ++#endif /* __UIP_CONF_H__ */ ++ ++/** @} */ ++/** @} */ +diff --git a/sysfs-documentation b/sysfs-documentation +new file mode 100644 +index 0000000..54fc497 +--- /dev/null ++++ b/sysfs-documentation +@@ -0,0 +1,514 @@ ++Description of iface attributes and their valid values ++====================================================== ++ ++== IPv4 attributes == ++ ++ipaddress ++--------- ++IP address in format XXX.XXX.XXX.XXX ++ ++gateway ++------- ++IP address of the network router or gateway device in format XXX.XXX.XXX.XXX ++ ++subnet ++------ ++Broadcast address in format XXX.XXX.XXX.XXX ++ ++bootproto ++--------- ++The protocol type used to initialize interface ++ ++Valid values: "dhcp" or "static" ++ ++dhcp_dns_address_en ++------------------- ++Request DNS Server IP Addresses and Domain Name ++ ++If bootproto is set to dhcp and dhcp_dns_address_en is enable, ++requests DNS addresses (option 6) and domain name (option 15) in its ++DHCP parameter request list. ++ ++Valid values: "enable" or "disable" ++ ++dhcp_slp_da_info_en ++------------------- ++Request SLP DA Information and SLP Scope ++If bootproto is set to dhcp and dhcp_slp_da_info_en is enable, ++requests SLP DA information (option 78) and SLP scope (option 79) ++in its DHCP parameter request list. ++ ++Valid values: "enable" or "disable" ++ ++tos_en ++------ ++Enable IPv4 type of service (ToS) ++ ++When tos_en is set to enable, use value set in tos when transmitting IPv4 TCP ++packets on iSCSI connections. ++ ++Valid values: "enable" or "disable" ++ ++tos ++--- ++IPv4 Type of service (ToS) ++ ++When tos_en is set to enable, use value set in tos when transmitting IPv4 TCP ++packets on iSCSI connections. ++ ++Valid range: 8-bit value. [0-255] ++ ++grat_arp_en ++----------- ++Enable Gratuitous ARP Requests ++ ++Valid values: "enable" or "disable" ++ ++dhcp_alt_client_id_en ++--------------------- ++DHCP Use Alternate Client ID ++ ++When dhcp_alt_client_id_en is set to enable, use the Client ID configured in ++dhcp_alt_client_id as its Client ID (DHCP option 61) in outgoing DHCP messages. ++ ++Valid values: "enable" or "disable" ++ ++dhcp_alt_client_id ++------------------ ++DHCP Alternate Client ID ++ ++When dhcp_alt_client_id_en is set to enable, use value set in dhcp_alt_client_id ++for Client ID in DHCP messages. ++ ++Valid values: 11-byte Client ID ++ ++dhcp_req_vendor_id_en ++--------------------- ++DHCP Require Vendor ID ++ ++When dhcp_req_vendor_id_en is set to enable, use value set in dhcp_vendor_id as ++its vendor ID (DHCP option 60) in outgoing DHCP messages. ++ ++Valid values: "enable" or "disable" ++ ++dhcp_use_vendor_id_en ++--------------------- ++DHCP Use Vendor ID ++ ++When dhcp_use_vendor_id_en is set to enable, use value set in dhcp_vendor_id as ++its vendor ID (DHCP option 60) in outgoing DHCP messages. ++ ++Valid values: "enable" or "disable" ++ ++dhcp_vendor_id ++-------------- ++DHCP Vendor ID ++ ++When dhcp_req_vendor_id_en or dhcp_use_vendor_id_en is set to enable, ++use value set in dhcp_vendor_id for Vendor ID in DHCP messages. ++ ++Valid values: 11-byte Client ID ++ ++dhcp_learn_iqn_en ++----------------- ++DHCP Learn IQN ++ ++When dhcp_learn_iqn_en is set to enable, iSCSI initiator attempts to use DHCP ++to learn its (IQN) iSCSI name. ++ ++Valid values: "enable" or "disable" ++ ++fragment_disable ++---------------- ++Fragmentation Disable. ++ ++When fragment_disable is set to disable, iSCSI initiator cannot fragment IP ++datagrams. ++ ++Valid values: "enable" or "disable" ++ ++incoming_forwarding_en ++---------------------- ++When incoming_forwarding_en is set to enable, iSCSI initiator forwards all ++incoming network traffic to the network driver, except for iSCSI TCP packets ++destined to the iSCSI initiator. ++ ++Valid values: "enable" or "disable" ++ ++ttl ++--- ++IPv4 Time to Live (TTL) ++ ++This attribute contain TTL value sent in IPv4 TCP packets transmitted on ++iSCSI connections. ++ ++Valid range: 8-bit value. [0-255] ++ ++== IPv6 attributes == ++ ++ipaddress ++--------- ++IP address in IPv6 format. ++ ++link_local_addr ++--------------- ++Link local address in IPv6 format. ++ ++router_addr ++----------- ++Router address in IPv6 format. ++ ++ipaddr_autocfg ++-------------- ++Autoconfigure IPv6 Address. ++ ++Valid values: nd, dhcpv6 or disable ++qla4xxx don't support dhcpv6. ++ ++link_local_autocfg ++------------------ ++Autoconfigure IPv6 Link Local Address. ++ ++IPv6 neighbor discovery protocol to discover Link Local Address. ++ ++Valid values: auto or disable ++ ++ ++router_autocfg ++-------------- ++Autoconfigure IPv6 Router address. ++ ++IPv6 neighbor discovery protocol to discover a default router address. ++ ++Valid values: auto or disable ++ ++link_local_state ++---------------- ++This Read-only attribute show Link Local IP address state in sysfs. ++ ++Valid values: Unconfigured, Acquiring, Tentative, Valid, Disabling, Invalid, ++ Deprecated. ++ ++ ++router_state ++------------ ++This Read-only attribute shows router state. ++ ++Valid values: Unknown, Advertised, Manual, Stale. ++ ++ ++grat_neighbor_adv_en ++-------------------- ++Enable Gratuitious Neighbor Advertisement ++ ++Valid values: "enable" or "disable" ++ ++mld_en ++------ ++Enable IPv6 Multicast Listener Discovery ++ ++Valid values: "enable" or "disable" ++ ++flow_label ++---------- ++This attribute specifies the default value of the Flow Label field in the ++IPv6 header of TCP packets transmitted on iSCSI connections ++ ++Valid range: 20-bit value. [0-1048575] ++Value zero indicates that the traffic is not assigned to a labelled flow. ++ ++traffic_class ++------------- ++This attribute specifies the IPv6 traffic class value to be used in IPv6 ++TCP packets transmitted from the firmware on iSCSI connections. ++ ++Valid range: 8-bit value. [0-255] ++ ++hop_limit ++--------- ++This attribute specifies the IPv6 hop limit value to be used in IPv6 TCP ++packets transmitted from the firmware on iSCSI connections ++ ++Valid range: 8-bit value. [0-255] ++ ++nd_reachable_tmo ++---------------- ++This attribute specifies the time (in milliseconds) that a node assumes ++that the neighbor is reachable after confirmation. ++ ++Valid range: 4-byte value. [0-4294967295] ++ ++nd_rexmit_time ++-------------- ++This attribute specifies the time (in milliseconds) between retransmitted ++neighbor solicitation messages. ++ ++Valid range: 4-byte value. [0-4294967295] ++ ++nd_stale_tmo ++------------ ++This attribute specifies the time (in milliseconds) after which a stale ++neighbor or destination cache entry is discarded. ++ ++Valid range: 4-byte value. [0-4294967295] ++ ++dup_addr_detect_cnt ++------------------- ++This attribute specifies the IPv6 duplicate address detection count ++ ++Valid range: 8-bit value. [0-255] ++ 0 - Disable ++ 1 - TryOnce ++ 2 - TryTwice, and so on ++ ++router_adv_link_mtu ++------------------- ++IPv6 Router Advertised Link MTU Size. ++ ++Valid range: 1280 bytes to 1500 bytes ++ ++== Common == ++enabled ++------- ++This attribute is used to enable or disable IPv4 or IPv6 protocol. ++ ++Valid values: "enable" or "disable" ++ ++vlan_id ++------- ++This attribute specifies 12-bit VLAN identifier (VID) ++ ++Valid range: 12-bit value. [1-4094] ++ ++vlan_priority ++------------- ++This attribute specifies Priority to outbound packets containing the ++specified VLAN-ID (VID) ++ ++Valid range: 3-bit value. [0-7] ++ ++vlan_enabled ++------------ ++VLAN Tagging Enable. ++ ++When this attribute is set to enable, use value set in vlan_id and ++vlan_priority to transmit IP packets, and discards IP packets that were ++received without a matching VLAN ID ++ ++Valid values: "enable" or "disable" ++ ++mtu ++--- ++Ethernet MTU Size. ++ ++This field specifies the maximum payload length in byte of an ++Ethernet frame supported by iSCSI initiator. ++ ++Valid values: 576 bytes to 9000 bytes ++ ++port ++---- ++This attribute shows the initiator iSCSI port number. ++ ++ipaddress_state ++--------------- ++This Read-only attribute show IP address state. ++ ++Valid values: Unconfigured, Acquiring, Tentative, Valid, Disabling, Invalid, ++ Deprecated. ++ ++delayed_ack_en ++-------------- ++When this attribute is set to enable, TCP delayed ACK is enabled. ++ ++Valid values: "enable" or "disable" ++ ++tcp_nagle_disable ++----------------- ++When this attribute is set to disable, TCP Nagle algorithm is disabled. ++ ++Valid values: "enable" or "disable" ++ ++tcp_wsf_disable ++--------------- ++When this attribute is set to disable, TCP window scale is disabled. ++ ++Valid values: "enable" or "disable" ++ ++tcp_wsf ++------- ++This attribute specifies the TCP window scale factor to be negotiated ++on TCP connections. ++ ++Valid range: 8-bit value. [0-255] ++ ++tcp_timer_scale ++--------------- ++The TCP Timer Scale is scale factor that adjusts the time interval between ++timer ticks on a TCP connection. The scale factor allows for faster time-outs ++for connections running on a very small network, versus connections running ++on a very large network. ++ ++Valid range: 3-bit value. [0-7] ++ ++tcp_timestamp_en ++---------------- ++When this attribute is set to enable, iSCSI initiator negotiates to use time ++stamps in TCP headers ++ ++Valid values: "enable" or "disable" ++ ++cache_id ++-------- ++This Read-only attribute is used to find the valid cache entries for the ++interface. ++ ++For IPv4, ARP cache entry ++For IPv6, Neighbor cache entry ++ ++redirect_en ++----------- ++For IPv4: ++When this attribute is set to enable, an ARP redirect can modify the address ++resolution protocol (ARP) table and any active connections. ++ ++For IPv6: ++When this attribute is set to enable and neighbor advertisements are received, ++the connection table is examined and updated if any active connections match ++the IP address on the neighbor advertisement. This action is required for ++failover and redirect. ++ ++Valid values: "enable" or "disable" ++ ++def_taskmgmt_tmo ++---------------- ++This attribute specifies timeout interval in seconds that iSCSI uses for ++timing out task-management commands. ++ ++Valid range: 16-bit value [0-65535]. ++ ++header_digest ++------------- ++When this attribute is set to enable iSCSI initiator negotiates for ++HeaderDigest=CRC32 and when set to disable negotiates HeaderDigest=none. ++ ++Valid values: "enable" or "disable" ++ ++data_digest ++----------- ++When this attribute is set to enable iSCSI initiator negotiates for ++DataDigest=CRC32 and when set to disable negotiates DataDigest=none. ++ ++Valid values: "enable" or "disable" ++ ++immediate_data ++-------------- ++When this attribute is set to enable iSCSI initiator negotiates for ++ImmediateData=yes and When set to disable negotiates ImmediateData=none ++ ++Valid values: "enable" or "disable" ++ ++initial_r2t ++----------- ++When this attribute is set to enable iSCSI initiator negotiates for ++InitialR2T=yes. When set to disable negotiates InitialR2T=no. ++ ++Valid values: "enable" or "disable" ++ ++data_seq_in_order ++----------------- ++When this attribute is set to enable iSCSI initiator set data sequences ++in order ++ ++Valid values: "enable" or "disable" ++qla4xxx does not support out-of-order data sequences ++ ++data_pdu_in_order ++----------------- ++When this attribute is set to enable iSCSI initiator set Data PDU ++in order ++ ++Valid values: "enable" or "disable" ++qla4xxx does not support out-of-order Data PDUs. ++ ++erl ++--- ++Error Recovery Level ++ ++This attribute specifies error recovery level (ERL) supported by the ++connection. ++ ++Valid values: 2-bit value [0-2] ++ ++max_recv_dlength ++---------------- ++iSCSI Maximum Receive Data Segment Length. ++ ++This attribute specifies Maximum data segment length in bytes, that receive ++in an iSCSI PDU. ++ ++first_burst_len ++--------------- ++iSCSI First Burst Length ++ ++This attribute Specifies the maximum amount of unsolicited data an iSCSI ++initiator can send to the target during the execution of a single SCSI command, ++in bytes. ++ ++max_outstanding_r2t ++------------------- ++iSCSI Maximum Outstanding R2T ++ ++This attribute Specifies how many R2T PDUs per command can be outstanding ++during an iSCSI session. ++ ++max_burst_len ++------------- ++This attribute Specifies the maximum length for unsolicited or immediate data ++iSCSI session can send or receive. ++ ++chap_auth ++--------- ++When this attribute is set to enable iSCSI session performs authentication ++during the security state of login phase. ++ ++Valid values: "enable" or "disable" ++ ++bidi_chap ++--------- ++When this attribute is set to enable iSCSI session generates a CHAP challenge ++to any target that has issued a CHAP challenge to the iSCSI session. ++iSCSI session issues the challenge to the target after responding to the ++targets challenge. This attribute is ignored if chap_auth is set to disable. ++ ++Valid values: "enable" or "disable" ++ ++discovery_auth_optional ++----------------------- ++When this attribute is set to enable and the chap_auth is set to enable, ++iSCSI session does not require authentication on discovery sessions unless ++requested by the peer. When this attribute is set to disable iSCSI session ++requires CHAP authentication for a discovery session. ++ ++Valid values: "enable" or "disable" ++ ++discovery_logout ++---------------- ++When this attribute is set to enable, iSCSI initiator initiates an iSCSI logout ++on a discovery session when discovery is complete (before closing the connection). ++When this attribute is set to disable, iSCSI initiator closes the connection when ++discovery is complete. ++ ++Valid values: "enable" or "disable" ++ ++strict_login_comp_en ++-------------------- ++When this attribute is set to enable, iSCSI initiator enforces the iSCSI login ++negotiation rules. When this attribute is set to disable, iSCSI initiator does ++not enforce iSCSI login negotiation. ++ ++Valid values: "enable" or "disable" ++ ++initiator_name ++-------------- ++This Read-only attribute contains the iSCSI Name string used by the firmware. +diff --git a/usr/Makefile b/usr/Makefile +index 673b7f1..5ac0726 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -28,10 +28,9 @@ IPC_OBJ=ioctl.o + endif + endif + +-OPTFLAGS ?= -O2 -g ++CFLAGS ?= -O2 -g + WARNFLAGS ?= -Wall -Wstrict-prototypes +-CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -I../include -I. -I../utils/open-isns \ +- -D$(OSNAME) $(IPC_CFLAGS) ++CFLAGS += $(WARNFLAGS) -I../include -I. -D$(OSNAME) $(IPC_CFLAGS) + PROGRAMS = iscsid iscsiadm iscsistart + + # libc compat files +@@ -40,7 +39,8 @@ SYSDEPS_SRCS = $(wildcard ../utils/sysdeps/*.o) + ISCSI_LIB_SRCS = iscsi_util.o io.o auth.o iscsi_timer.o login.o log.o md5.o \ + sha1.o iface.o idbm.o sysfs.o host.o session_info.o iscsi_sysfs.o \ + iscsi_net_util.o iscsid_req.o transport.o iser.o cxgbi.o be2iscsi.o \ +- initiator_common.o iscsi_err.o $(IPC_OBJ) $(SYSDEPS_SRCS) ++ initiator_common.o iscsi_err.o flashnode.o uip_mgmt_ipc.o \ ++ $(IPC_OBJ) $(SYSDEPS_SRCS) + # core initiator files + INITIATOR_SRCS = initiator.o scsi.o actor.o event_poll.o mgmt_ipc.o kern_err_table.o + +@@ -54,14 +54,14 @@ all: $(PROGRAMS) + + iscsid: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(DISCOVERY_SRCS) \ + iscsid.o session_mgmt.o discoveryd.o +- $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns ++ $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lisns -lcrypto -lrt -lmount + + iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o +- $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns ++ $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lisns -lcrypto + + iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \ + iscsistart.o statics.o +- $(CC) $(CFLAGS) -static $^ -o $@ ++ $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lrt -lmount + clean: + rm -f *.o $(PROGRAMS) .depend $(LIBSYS) + +diff --git a/usr/actor.c b/usr/actor.c +index b8f8e61..91a9506 100644 +--- a/usr/actor.c ++++ b/usr/actor.c +@@ -1,7 +1,8 @@ + /* +- * iSCSI usermode single-threaded scheduler ++ * iSCSI timeout & deferred work handling + * + * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman ++ * Copyright (C) 2014 Red Hat Inc. + * maintained by open-iscsi@googlegroups.com + * + * This program is free software; you can redistribute it and/or modify +@@ -17,53 +18,32 @@ + * See the file COPYING included with this distribution for more details. + */ + #include ++#include ++#include ++#include ++#include + #include "actor.h" + #include "log.h" + #include "list.h" + + static LIST_HEAD(pend_list); +-static LIST_HEAD(poll_list); +-static LIST_HEAD(actor_list); +-static volatile uint64_t previous_time; +-static volatile uint32_t scheduler_loops; ++static LIST_HEAD(ready_list); + static volatile int poll_in_progress; +-static volatile uint64_t actor_jiffies = 0; +- +-#define actor_diff(_time1, _time2) ({ \ +- uint64_t __ret; \ +- if ((_time2) >= (_time1)) \ +- __ret = (_time2) - (_time1); \ +- else \ +- __ret = ((~0ULL) - (_time1)) + (_time2); \ +- __ret; \ +-}) +- +-#define ACTOR_TICKS actor_jiffies +-#define ACTOR_TICKS_10MS(_a) (_a) +-#define ACTOR_MS_TO_TICKS(_a) ((_a)/ACTOR_RESOLUTION) + + static uint64_t +-actor_diff_time(actor_t *thread, uint64_t current_time) ++actor_time_left(actor_t *thread, uint64_t current_time) + { +- uint64_t diff_time = actor_diff(thread->scheduled_at, current_time); +- if(diff_time >= thread->ttschedule) ++ if (current_time > thread->ttschedule) + return 0; +- return (thread->ttschedule - diff_time); ++ else ++ return (thread->ttschedule - current_time); + } + + #define time_after(a,b) \ + ((int64_t)(b) - (int64_t)(a) < 0) + + void +-actor_init(void) +-{ +- poll_in_progress = 0; +- previous_time = 0; +- scheduler_loops = 0; +-} +- +-void +-actor_new(actor_t *thread, void (*callback)(void *), void *data) ++actor_init(actor_t *thread, void (*callback)(void *), void *data) + { + INIT_LIST_HEAD(&thread->list); + thread->state = ACTOR_NOTSCHEDULED; +@@ -77,11 +57,18 @@ actor_delete(actor_t *thread) + log_debug(7, "thread %08lx delete: state %d", (long)thread, + thread->state); + switch(thread->state) { +- case ACTOR_SCHEDULED: + case ACTOR_WAITING: +- case ACTOR_POLL_WAITING: ++ /* TODO: remove/reset alarm if we were 1st entry in pend_list */ ++ /* priority: low */ ++ /* fallthrough */ ++ case ACTOR_SCHEDULED: + log_debug(1, "deleting a scheduled/waiting thread!"); + list_del_init(&thread->list); ++ if (list_empty(&pend_list)) { ++ log_debug(7, "nothing left on pend_list, deactivating alarm"); ++ alarm(0); ++ } ++ + break; + default: + break; +@@ -89,73 +76,94 @@ actor_delete(actor_t *thread) + thread->state = ACTOR_NOTSCHEDULED; + } + ++/* ++ * Inserts actor on pend list and sets alarm if new item is ++ * sooner than previous entries. ++ */ + static void +-actor_schedule_private(actor_t *thread, uint32_t ttschedule, int head) ++actor_insert_on_pend_list(actor_t *thread, uint32_t delay_secs) + { +- uint64_t delay_time, current_time; +- actor_t *next_thread; ++ struct actor *orig_head; ++ struct actor *new_head; ++ struct actor *next_thread; + +- delay_time = ACTOR_MS_TO_TICKS(ttschedule); +- current_time = ACTOR_TICKS; ++ orig_head = list_first_entry_or_null(&pend_list, ++ struct actor, list); + +- log_debug(7, "thread %p schedule: delay %" PRIu64 " state %d", +- thread, delay_time, thread->state); ++ /* insert new entry in sort order */ ++ list_for_each_entry(next_thread, &pend_list, list) { ++ if (time_after(next_thread->ttschedule, thread->ttschedule)) { ++ log_debug(7, "next thread %p due %lld", next_thread, ++ (long long)next_thread->ttschedule); ++ log_debug(7, "new thread %p is before (%lld), inserting", thread, ++ (long long)thread->ttschedule); ++ ++ /* insert new thread before the next thread */ ++ __list_add(&thread->list, next_thread->list.prev, &next_thread->list); ++ goto inserted; ++ } ++ } ++ ++ if (orig_head) { ++ log_debug(7, "last thread %p due %lld", next_thread, ++ (long long)next_thread->ttschedule); ++ log_debug(7, "new thread %p is after (%lld), inserting at tail", thread, ++ (long long)thread->ttschedule); ++ } ++ else ++ log_debug(7, "new thread %p due %lld is first item on pend_list", thread, ++ (long long)thread->ttschedule); ++ ++ /* Not before any existing entries */ ++ list_add_tail(&thread->list, &pend_list); ++ ++inserted: ++ new_head = list_first_entry(&pend_list, struct actor, list); ++ if (orig_head != new_head) { ++ int result = alarm(delay_secs); ++ log_debug(7, "new alarm set for %d seconds, old alarm %d", ++ delay_secs, result); ++ } ++} ++ ++static void ++actor_schedule_private(actor_t *thread, uint32_t delay_secs, int head) ++{ ++ time_t current_time; ++ ++ struct timespec tv; ++ ++ if (clock_gettime(CLOCK_MONOTONIC_COARSE, &tv)) { ++ log_error("clock_getime failed, can't schedule!"); ++ return; ++ } ++ ++ current_time = tv.tv_sec; ++ ++ log_debug(7, "thread %p schedule: delay %u state %d", ++ thread, delay_secs, thread->state); + +- /* convert ttscheduled msecs in 10s of msecs by dividing for now. +- * later we will change param to 10s of msecs */ + switch(thread->state) { + case ACTOR_WAITING: + log_error("rescheduling a waiting thread!"); + list_del(&thread->list); ++ /* fall-through */ + case ACTOR_NOTSCHEDULED: + INIT_LIST_HEAD(&thread->list); +- /* if ttschedule is 0, put in scheduled queue and change +- * state to scheduled, else add current time to ttschedule and +- * insert in the queue at the correct point */ +- if (delay_time == 0) { +- /* For head addition, it must go onto the head of the +- actor_list regardless if poll is in progress or not +- */ +- if (poll_in_progress && !head) { +- thread->state = ACTOR_POLL_WAITING; +- list_add_tail(&thread->list, +- &poll_list); +- } else { +- thread->state = ACTOR_SCHEDULED; +- if (head) +- list_add(&thread->list, +- &actor_list); +- else +- list_add_tail(&thread->list, +- &actor_list); +- } ++ ++ if (delay_secs == 0) { ++ thread->state = ACTOR_SCHEDULED; ++ if (head) ++ list_add(&thread->list, &ready_list); ++ else ++ list_add_tail(&thread->list, &ready_list); + } else { + thread->state = ACTOR_WAITING; +- thread->ttschedule = delay_time; +- thread->scheduled_at = current_time; ++ thread->ttschedule = current_time + delay_secs; + +- /* insert new entry in sort order */ +- list_for_each_entry(next_thread, &pend_list, list) { +- log_debug(7, "thread %p %" PRIu64 " %"PRIu64, +- next_thread, +- next_thread->scheduled_at + +- next_thread->ttschedule, +- current_time + delay_time); +- +- if (time_after(next_thread->scheduled_at + +- next_thread->ttschedule, +- current_time + delay_time)) { +- list_add(&thread->list, +- &next_thread->list); +- goto done; +- } +- } +- +- list_add_tail(&thread->list, &pend_list); ++ actor_insert_on_pend_list(thread, delay_secs); + } +-done: + break; +- case ACTOR_POLL_WAITING: + case ACTOR_SCHEDULED: + // don't do anything + break; +@@ -180,117 +188,98 @@ actor_schedule(actor_t *thread) + } + + void +-actor_timer(actor_t *thread, uint32_t timeout, void (*callback)(void *), ++actor_timer(actor_t *thread, uint32_t timeout_secs, void (*callback)(void *), + void *data) + { +- actor_new(thread, callback, data); +- actor_schedule_private(thread, timeout, 0); +-} +- +-int +-actor_timer_mod(actor_t *thread, uint32_t timeout, void *data) +-{ +- if (thread->state == ACTOR_WAITING) { +- list_del_init(&thread->list); +- thread->data = data; +- actor_schedule_private(thread, timeout, 0); +- return 1; +- } +- return 0; ++ actor_init(thread, callback, data); ++ actor_schedule_private(thread, timeout_secs, 0); + } + + void +-actor_check(uint64_t current_time) ++actor_timer_mod(actor_t *thread, uint32_t new_timeout_secs, void *data) + { +- struct actor *thread, *tmp; +- +- list_for_each_entry_safe(thread, tmp, &pend_list, list) { +- if (actor_diff_time(thread, current_time)) { +- log_debug(7, "thread %08lx wait some more", +- (long)thread); +- /* wait some more */ +- break; +- } +- +- /* it is time to schedule this entry */ +- list_del_init(&thread->list); +- +- log_debug(2, "thread %08lx was scheduled at %" PRIu64 ":" +- "%" PRIu64 ", curtime %" PRIu64 " q_forw %p " +- "&pend_list %p", +- (long)thread, thread->scheduled_at, thread->ttschedule, +- current_time, pend_list.next, &pend_list); +- +- if (poll_in_progress) { +- thread->state = ACTOR_POLL_WAITING; +- list_add_tail(&thread->list, &poll_list); +- log_debug(7, "thread %08lx now in poll_list", +- (long)thread); +- } else { +- thread->state = ACTOR_SCHEDULED; +- list_add_tail(&thread->list, &actor_list); +- log_debug(7, "thread %08lx now in actor_list", +- (long)thread); +- } +- } ++ actor_delete(thread); ++ thread->data = data; ++ actor_schedule_private(thread, new_timeout_secs, 0); + } + ++/* ++ * Execute all items that have expired. ++ * ++ * Set an alarm if items remain. Caller must catch SIGALRM and ++ * then re-invoke this function. ++ */ + void + actor_poll(void) + { ++ struct actor *thread, *tmp; + uint64_t current_time; +- struct actor *thread; ++ struct timespec tv; + +- /* check that there are no any concurrency */ + if (poll_in_progress) { +- log_error("concurrent actor_poll() is not allowed"); ++ log_error("recursive actor_poll() is not allowed"); ++ return; + } + +- /* don't check wait list every single poll. +- * get new time. Shift it to make 10s of msecs approx +- * if new time is not same as old time */ +- if (scheduler_loops++ > ACTOR_MAX_LOOPS) { +- /* try coming in about every 100 msecs */ +- current_time = ACTOR_TICKS; +- scheduler_loops = 0; +- /* checking whether we are in the same tick... */ +- if ( ACTOR_TICKS_10MS(current_time) != +- ACTOR_TICKS_10MS(previous_time)) { +- previous_time = current_time; +- actor_check(current_time); ++ if (clock_gettime(CLOCK_MONOTONIC_COARSE, &tv)) { ++ log_error("clock_gettime failed, can't schedule!"); ++ return; ++ } ++ ++ current_time = tv.tv_sec; ++ ++ /* ++ * Move items that are ripe from pend_list to ready_list. ++ * Actors are in sorted order of ascending run time, so ++ * stop at the first unripe entry. ++ */ ++ log_debug(7, "current time %" PRIu64, current_time); ++ ++ list_for_each_entry_safe(thread, tmp, &pend_list, list) { ++ uint64_t time_left = actor_time_left(thread, current_time); ++ if (time_left) { ++ log_debug(7, "thread %08lx due %" PRIu64 ", wait %" PRIu64 " more", ++ (long)thread, thread->ttschedule, time_left); ++ ++ alarm(time_left); ++ break; + } ++ ++ /* This entry can be run now */ ++ list_del_init(&thread->list); ++ ++ log_debug(2, "thread %08lx was scheduled for " ++ "%" PRIu64 ", curtime %" PRIu64 " q_forw %p " ++ "&pend_list %p", ++ (long)thread, thread->ttschedule, ++ current_time, pend_list.next, &pend_list); ++ ++ list_add_tail(&thread->list, &ready_list); ++ assert(thread->state == ACTOR_WAITING); ++ thread->state = ACTOR_SCHEDULED; ++ log_debug(7, "thread %08lx now in ready_list", ++ (long)thread); ++ } ++ ++ /* Disable alarm if nothing else pending */ ++ if (list_empty(&pend_list)) { ++ log_debug(7, "nothing on pend_list, deactivating alarm"); ++ alarm(0); + } + +- /* the following code to check in the main data path */ + poll_in_progress = 1; +- while (!list_empty(&actor_list)) { +- thread = list_entry(actor_list.next, struct actor, list); ++ while (!list_empty(&ready_list)) { ++ thread = list_first_entry(&ready_list, struct actor, list); + list_del_init(&thread->list); + + if (thread->state != ACTOR_SCHEDULED) +- log_error("actor_list: thread state corrupted! " ++ log_error("ready_list: thread state corrupted! " + "Thread with state %d in actor list.", + thread->state); + thread->state = ACTOR_NOTSCHEDULED; + log_debug(7, "exec thread %08lx callback", (long)thread); + thread->callback(thread->data); +- log_debug(7, "thread removed\n"); ++ log_debug(7, "thread %08lx done", (long)thread); + } + poll_in_progress = 0; +- +- while (!list_empty(&poll_list)) { +- thread = list_entry(poll_list.next, struct actor, list); +- list_del_init(&thread->list); +- +- if (thread->state != ACTOR_POLL_WAITING) +- log_error("poll_list: thread state corrupted!" +- "Thread with state %d in poll list.", +- thread->state); +- thread->state = ACTOR_SCHEDULED; +- list_add_tail(&thread->list, &actor_list); +- log_debug(7, "thread %08lx removed from poll_list", +- (long)thread); +- } +- +- ACTOR_TICKS++; + } +diff --git a/usr/actor.h b/usr/actor.h +index 704224d..f572f2e 100644 +--- a/usr/actor.h ++++ b/usr/actor.h +@@ -22,15 +22,11 @@ + #include "types.h" + #include "list.h" + +-#define ACTOR_RESOLUTION 250 /* in millis */ +-#define ACTOR_MAX_LOOPS 1 +- + typedef enum actor_state_e { + ACTOR_INVALID, + ACTOR_WAITING, + ACTOR_SCHEDULED, + ACTOR_NOTSCHEDULED, +- ACTOR_POLL_WAITING + } actor_state_e; + + typedef struct actor { +@@ -38,18 +34,17 @@ typedef struct actor { + actor_state_e state; + void *data; + void (*callback)(void * ); +- uint64_t scheduled_at; +- uint64_t ttschedule; ++ time_t ttschedule; + } actor_t; + +-extern void actor_new(actor_t *thread, void (*callback)(void *), void * data); ++extern void actor_init(actor_t *thread, void (*callback)(void *), void * data); + extern void actor_delete(actor_t *thread); + extern void actor_schedule_head(actor_t *thread); + extern void actor_schedule(actor_t *thread); +-extern void actor_timer(actor_t *thread, uint32_t timeout, ++extern void actor_timer(actor_t *thread, uint32_t delay_secs, + void (*callback)(void *), void *data); +-extern int actor_timer_mod(actor_t *thread, uint32_t new_timeout, void *data); ++extern void actor_timer_mod(actor_t *thread, uint32_t new_delay_secs, ++ void *data); + extern void actor_poll(void); +-extern void actor_init(void); + + #endif /* ACTOR_H */ +diff --git a/usr/auth.c b/usr/auth.c +index c924545..00b4388 100644 +--- a/usr/auth.c ++++ b/usr/auth.c +@@ -109,13 +109,13 @@ acl_chap_auth_request(struct iscsi_acl *client, char *username, unsigned int id, + /* the expected credentials are in the session */ + if (session->username_in == NULL) { + log_error("failing authentication, no incoming username " +- "configured to authenticate target %s\n", ++ "configured to authenticate target %s", + session->target_name); + return AUTH_STATUS_FAIL; + } + if (strcmp(username, session->username_in) != 0) { + log_error("failing authentication, received incorrect " +- "username from target %s\n", session->target_name); ++ "username from target %s", session->target_name); + return AUTH_STATUS_FAIL; + } + +@@ -123,7 +123,7 @@ acl_chap_auth_request(struct iscsi_acl *client, char *username, unsigned int id, + (session->password_in == NULL) || + (session->password_in[0] == '\0')) { + log_error("failing authentication, no incoming password " +- "configured to authenticate target %s\n", ++ "configured to authenticate target %s", + session->target_name); + return AUTH_STATUS_FAIL; + } +@@ -132,7 +132,7 @@ acl_chap_auth_request(struct iscsi_acl *client, char *username, unsigned int id, + + if (rsp_length != sizeof(verify_data)) { + log_error("failing authentication, received incorrect " +- "CHAP response length %u from target %s\n", ++ "CHAP response length %u from target %s", + rsp_length, session->target_name); + return AUTH_STATUS_FAIL; + } +@@ -154,13 +154,13 @@ acl_chap_auth_request(struct iscsi_acl *client, char *username, unsigned int id, + auth_md5_final(verify_data, &context); + + if (memcmp(response_data, verify_data, sizeof(verify_data)) == 0) { +- log_debug(1, "initiator authenticated target %s\n", ++ log_debug(1, "initiator authenticated target %s", + session->target_name); + return AUTH_STATUS_PASS; + } + + log_error("failing authentication, received incorrect CHAP " +- "response from target %s\n", session->target_name); ++ "response from target %s", session->target_name); + return AUTH_STATUS_FAIL; + } + +@@ -189,24 +189,24 @@ get_random_bytes(unsigned char *data, unsigned int length) + + long r; + unsigned n; +- int fd; ++ int fd, r_size = sizeof(r); + + fd = open("/dev/urandom", O_RDONLY); + while (length > 0) { + +- if (!fd || read(fd, &r, sizeof(long)) != -1) ++ if (fd == -1 || read(fd, &r, r_size) != r_size) + r = rand(); + r = r ^ (r >> 8); + r = r ^ (r >> 4); + n = r & 0x7; + +- if (!fd || read(fd, &r, sizeof(long)) != -1) ++ if (fd == -1 || read(fd, &r, r_size) != r_size) + r = rand(); + r = r ^ (r >> 8); + r = r ^ (r >> 5); + n = (n << 3) | (r & 0x7); + +- if (!fd || read(fd, &r, sizeof(long)) != -1) ++ if (fd == -1 || read(fd, &r, r_size) != r_size) + r = rand(); + r = r ^ (r >> 8); + r = r ^ (r >> 5); +@@ -2002,7 +2002,7 @@ acl_dbg_status_to_text(int dbg_status) + "AuthMethod negotiation failed", + "AuthMethod negotiated to none", + "CHAP algorithm negotiation failed", +- "CHAP challange reflected", ++ "CHAP challenge reflected", + "Local password same as remote", + "Local password not set", + "CHAP identifier bad", +diff --git a/usr/be2iscsi.c b/usr/be2iscsi.c +index ce8b719..8a346a5 100644 +--- a/usr/be2iscsi.c ++++ b/usr/be2iscsi.c +@@ -19,7 +19,6 @@ + void be2iscsi_create_conn(struct iscsi_conn *conn) + { + struct iscsi_session *session = conn->session; +- conn_rec_t *conn_rec = &session->nrec.conn[conn->id]; + + if (conn->max_recv_dlength > 65536) + conn->max_recv_dlength = 65536; +@@ -33,10 +32,6 @@ void be2iscsi_create_conn(struct iscsi_conn *conn) + if (conn->max_xmit_dlength > 65536) + conn->max_xmit_dlength = 65536; + +- if (!conn_rec->iscsi.MaxXmitDataSegmentLength || +- conn_rec->iscsi.MaxXmitDataSegmentLength > 65536) +- conn_rec->iscsi.MaxXmitDataSegmentLength = 65536; +- + session->erl = 0; + session->initial_r2t_en = 1; + } +diff --git a/usr/config.h b/usr/config.h +index 998caff..fd31a54 100644 +--- a/usr/config.h ++++ b/usr/config.h +@@ -201,6 +201,9 @@ typedef struct session_rec { + * allowed to be initiated on this record + */ + unsigned char multiple; ++ char boot_root[BOOT_NAME_MAXLEN]; ++ char boot_nic[BOOT_NAME_MAXLEN]; ++ char boot_target[BOOT_NAME_MAXLEN]; + } session_rec_t; + + #define ISCSI_TRANSPORT_NAME_MAXLEN 16 +@@ -229,11 +232,59 @@ typedef struct iface_rec { + * 1 = enable */ + uint16_t mtu; + uint16_t port; ++ char delayed_ack[ISCSI_MAX_STR_LEN]; ++ char nagle[ISCSI_MAX_STR_LEN]; ++ char tcp_wsf_state[ISCSI_MAX_STR_LEN]; ++ uint8_t tcp_wsf; ++ uint8_t tcp_timer_scale; ++ char tcp_timestamp[ISCSI_MAX_STR_LEN]; ++ char dhcp_dns[ISCSI_MAX_STR_LEN]; ++ char dhcp_slp_da[ISCSI_MAX_STR_LEN]; ++ char tos_state[ISCSI_MAX_STR_LEN]; ++ uint8_t tos; ++ char gratuitous_arp[ISCSI_MAX_STR_LEN]; ++ char dhcp_alt_client_id_state[ISCSI_MAX_STR_LEN]; ++ char dhcp_alt_client_id[ISCSI_MAX_STR_LEN]; ++ char dhcp_req_vendor_id_state[ISCSI_MAX_STR_LEN]; ++ char dhcp_vendor_id_state[ISCSI_MAX_STR_LEN]; ++ char dhcp_vendor_id[ISCSI_MAX_STR_LEN]; ++ char dhcp_learn_iqn[ISCSI_MAX_STR_LEN]; ++ char fragmentation[ISCSI_MAX_STR_LEN]; ++ char incoming_forwarding[ISCSI_MAX_STR_LEN]; ++ uint8_t ttl; ++ char gratuitous_neighbor_adv[ISCSI_MAX_STR_LEN]; ++ char redirect[ISCSI_MAX_STR_LEN]; ++ char mld[ISCSI_MAX_STR_LEN]; ++ uint32_t flow_label; ++ uint32_t traffic_class; ++ uint8_t hop_limit; ++ uint32_t nd_reachable_tmo; ++ uint32_t nd_rexmit_time; ++ uint32_t nd_stale_tmo; ++ uint8_t dup_addr_detect_cnt; ++ uint32_t router_adv_link_mtu; ++ uint16_t def_task_mgmt_tmo; ++ char header_digest[ISCSI_MAX_STR_LEN]; ++ char data_digest[ISCSI_MAX_STR_LEN]; ++ char immediate_data[ISCSI_MAX_STR_LEN]; ++ char initial_r2t[ISCSI_MAX_STR_LEN]; ++ char data_seq_inorder[ISCSI_MAX_STR_LEN]; ++ char data_pdu_inorder[ISCSI_MAX_STR_LEN]; ++ uint8_t erl; ++ uint32_t max_recv_dlength; ++ uint32_t first_burst_len; ++ uint16_t max_out_r2t; ++ uint32_t max_burst_len; ++ char chap_auth[ISCSI_MAX_STR_LEN]; ++ char bidi_chap[ISCSI_MAX_STR_LEN]; ++ char strict_login_comp[ISCSI_MAX_STR_LEN]; ++ char discovery_auth[ISCSI_MAX_STR_LEN]; ++ char discovery_logout[ISCSI_MAX_STR_LEN]; + char port_state[ISCSI_MAX_STR_LEN]; + char port_speed[ISCSI_MAX_STR_LEN]; + /* + * TODO: we may have to make this bigger and interconnect +- * specific for infinniband ++ * specific for infiniband + */ + char hwaddress[ISCSI_HWADDRESS_BUF_SIZE]; + char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN]; +diff --git a/usr/discovery.c b/usr/discovery.c +index afce6c0..593d226 100644 +--- a/usr/discovery.c ++++ b/usr/discovery.c +@@ -50,9 +50,9 @@ + #include "iscsi_timer.h" + #include "iscsi_err.h" + /* libisns includes */ +-#include "isns.h" +-#include "paths.h" +-#include "message.h" ++#include ++#include ++#include + + #ifdef SLP_ENABLE + #include "iscsi-slp-discovery.h" +@@ -111,7 +111,7 @@ int discovery_isns_set_servername(char *address, int port) + int len; + + if (port > USHRT_MAX) { +- log_error("Invalid port %d\n", port); ++ log_error("Invalid port %d", port); + return ISCSI_ERR_INVAL; + } + +@@ -193,7 +193,7 @@ int discovery_isns_query(struct discovery_rec *drec, const char *iname, + status = isns_query_response_get_objects(qry, &objects); + if (status) { + log_error("Unable to extract object list from query " +- "response: %s\n", isns_strerror(status)); ++ "response: %s", isns_strerror(status)); + rc = ISCSI_ERR; + goto free_query; + } +@@ -391,7 +391,7 @@ int discovery_fw(void *data, struct iface_rec *iface, + rc = fw_get_targets(&targets); + if (rc) { + log_error("Could not get list of targets from firmware. " +- "(err %d)\n", rc); ++ "(err %d)", rc); + return rc; + } + if (list_empty(&targets)) +@@ -406,7 +406,7 @@ int discovery_fw(void *data, struct iface_rec *iface, + rec = idbm_create_rec_from_boot_context(bcontext); + if (!rec) { + log_error("Could not convert firmware info to " +- "node record.\n"); ++ "node record."); + rc = ISCSI_ERR_NOMEM; + goto free_targets; + } +@@ -456,7 +456,7 @@ int discovery_offload_sendtargets(int host_no, int do_login, + */ + rc = iscsid_exec_req(&req, &rsp, 1); + if (rc) { +- log_error("Could not offload sendtargets to %s.\n", ++ log_error("Could not offload sendtargets to %s.", + drec->address); + iscsi_err_print_msg(rc); + return rc; +@@ -817,7 +817,7 @@ iscsi_alloc_session(struct iscsi_sendtargets_config *config, + session->t = iscsi_sysfs_get_transport_by_name(iface->transport_name); + if (!session->t) { + log_error("iSCSI driver %s is not loaded. Load the module " +- "then retry the command.\n", iface->transport_name); ++ "then retry the command.", iface->transport_name); + *rc = ISCSI_ERR_TRANS_NOT_FOUND; + goto fail; + } +@@ -1036,7 +1036,7 @@ static void iscsi_destroy_session(struct iscsi_session *session) + rc = ipc->stop_conn(session->t->handle, session->id, + conn->id, STOP_CONN_TERM); + if (rc) { +- log_error("Could not stop conn %d:%d cleanly (err %d)\n", ++ log_error("Could not stop conn %d:%d cleanly (err %d)", + session->id, conn->id, rc); + goto done; + } +@@ -1091,7 +1091,7 @@ static int iscsi_create_leading_conn(struct iscsi_session *session) + */ + conn->socket_fd = ipc->ctldev_open(); + if (conn->socket_fd < 0) { +- log_error("Could not open netlink interface (err %d)\n", ++ log_error("Could not open netlink interface (err %d)", + errno); + return ISCSI_ERR_INTERNAL; + } +@@ -1109,14 +1109,15 @@ static int iscsi_create_leading_conn(struct iscsi_session *session) + + rc = iscsi_host_set_net_params(iface, session); + if (rc) { +- log_error("Could not set host net params (err %d)\n", ++ log_error("Could not set host net params (err %d)", + rc); +- rc = ISCSI_ERR_INTERNAL; ++ if (rc != ISCSI_ERR_AGAIN) ++ rc = ISCSI_ERR_INTERNAL; + goto close_ipc; + } + + /* create interconnect endpoint */ +- log_debug(2, "%s discovery ep connect\n", __FUNCTION__); ++ log_debug(2, "%s discovery ep connect", __FUNCTION__); + rc = t->template->ep_connect(conn, 1); + if (rc < 0) { + rc = ISCSI_ERR_TRANS; +@@ -1139,21 +1140,23 @@ static int iscsi_create_leading_conn(struct iscsi_session *session) + break; + } while (1); + +- log_debug(2, "%s discovery create session\n", __FUNCTION__); ++ log_debug(2, "%s discovery create session", __FUNCTION__); + /* create kernel structs */ + rc = ipc->create_session(session->t->handle, + conn->transport_ep_handle, 1, 32, 1, + &session->id, &host_no); + if (rc) { +- log_error("Could not create kernel session (err %d).\n", rc); ++ log_error("Could not create kernel session (err %d).", rc); + rc = ISCSI_ERR_INTERNAL; + goto disconnect; + } +- log_debug(2, "%s discovery created session %u\n", __FUNCTION__, ++ log_debug(2, "%s discovery created session %u", __FUNCTION__, + session->id); +- session->isid[3] = session->id; ++ session->isid[3] = (session->id >> 16) & 0xff; ++ session->isid[4] = (session->id >> 8) & 0xff; ++ session->isid[5] = session->id & 0xff; + +- log_debug(2, "%s discovery create conn\n", __FUNCTION__); ++ log_debug(2, "%s discovery create conn", __FUNCTION__); + rc = ipc->create_conn(t->handle, session->id, conn->id, &conn->id); + if (rc) { + log_error("Could not create connection (err %d)", rc); +@@ -1161,7 +1164,7 @@ static int iscsi_create_leading_conn(struct iscsi_session *session) + goto disconnect; + } + +- log_debug(2, "%s discovery bind conn\n", __FUNCTION__); ++ log_debug(2, "%s discovery bind conn", __FUNCTION__); + if (ipc->bind_conn(t->handle, session->id, conn->id, + conn->transport_ep_handle, (conn->id == 0), &rc) || + rc) { +@@ -1207,7 +1210,7 @@ close_ipc: + static struct iscsi_ev_context * + iscsi_ev_context_get(struct iscsi_conn *conn, int ev_size) + { +- log_debug(2, "%s: ev_size %d\n", __FUNCTION__, ev_size); ++ log_debug(2, "%s: ev_size %d", __FUNCTION__, ev_size); + + ipc_ev_context.data = calloc(1, ev_size); + if (!ipc_ev_context.data) +@@ -1403,6 +1406,17 @@ redirect_reconnect: + iscsi_copy_operational_params(&session->conn[0], &config->session_conf, + &config->conn_conf); + ++ if (t->caps & CAP_TEXT_NEGO) { ++ log_debug(2, "%s discovery set params", __FUNCTION__); ++ rc = iscsi_session_set_params(conn); ++ if (rc) { ++ log_error("Could not set iscsi params for conn %d:%d " ++ "(err %d)", session->id, conn->id, rc); ++ rc = ISCSI_ERR_INTERNAL; ++ goto login_failed; ++ } ++ } ++ + if ((session->t->caps & CAP_LOGIN_OFFLOAD)) + goto start_conn; + +@@ -1477,7 +1491,7 @@ redirect_reconnect: + case ISCSI_LOGIN_STATUS_AUTH_FAILED: + case ISCSI_LOGIN_STATUS_TGT_FORBIDDEN: + log_error("discovery login to %s rejected: " +- "initiator failed authorization\n", ++ "initiator failed authorization", + conn->host); + rc = ISCSI_ERR_LOGIN_AUTH_FAILED; + goto login_failed; +@@ -1509,16 +1523,16 @@ redirect_reconnect: + return 0; + + start_conn: +- log_debug(2, "%s discovery set params\n", __FUNCTION__); +- rc = iscsi_session_set_params(conn); ++ log_debug(2, "%s discovery set neg params", __FUNCTION__); ++ rc = iscsi_session_set_neg_params(conn); + if (rc) { + log_error("Could not set iscsi params for conn %d:%d (err " +- "%d)\n", session->id, conn->id, rc); ++ "%d)", session->id, conn->id, rc); + rc = ISCSI_ERR_INTERNAL; + goto login_failed; + } + +- log_debug(2, "%s discovery start conn\n", __FUNCTION__); ++ log_debug(2, "%s discovery start conn", __FUNCTION__); + if (ipc->start_conn(t->handle, session->id, conn->id, &rc) || rc) { + log_error("Cannot start conn %d:%d (err %d)", + session->id, conn->id, rc); +diff --git a/usr/discoveryd.c b/usr/discoveryd.c +index de080ea..f5359c7 100644 +--- a/usr/discoveryd.c ++++ b/usr/discoveryd.c +@@ -40,11 +40,11 @@ + #include "iface.h" + #include "session_mgmt.h" + #include "session_info.h" +-#include "isns-proto.h" +-#include "isns.h" +-#include "paths.h" +-#include "message.h" + #include "iscsi_err.h" ++#include ++#include ++#include ++#include + + #define DISC_DEF_POLL_INVL 30 + +@@ -211,7 +211,7 @@ static void fork_disc(const char *def_iname, struct discovery_rec *drec, + exit(0); + } else if (pid < 0) + log_error("Fork failed (err %d - %s). Will not be able " +- "to perform discovery to %s.\n", ++ "to perform discovery to %s.", + errno, strerror(errno), drec->address); + else { + shutdown_callback(pid); +@@ -254,7 +254,7 @@ static int isns_build_objs(isns_portal_info_t *portal_info, + nportals = isns_enumerate_portals(iflist, nportals); + if (nportals == 0) { + log_error("Unable to enumerate portals - " +- "no usable interfaces found\n"); ++ "no usable interfaces found"); + free(iflist); + return ISCSI_ERR_NO_OBJS_FOUND; + } +@@ -557,7 +557,7 @@ static int isns_setup_registration_refresh(isns_simple_t *rsp, int poll_inval) + status = isns_query_response_get_objects(rsp, &objs); + if (status) { + log_error("Unable to extract object list from " +- "registration response: %s\n", ++ "registration response: %s", + isns_strerror(status)); + return ISCSI_ERR; + } +@@ -693,7 +693,7 @@ static int isns_register_objs(isns_client_t *clnt, isns_object_list_t *objs, + + status = isns_simple_call(clnt->ic_socket, ®); + if (status != ISNS_SUCCESS) { +- log_error("SCN registration for node %s failed: %s\n", ++ log_error("SCN registration for node %s failed: %s", + isns_source_name(node->source), + isns_strerror(status)); + /* +@@ -907,7 +907,7 @@ static int isns_scn_recv(isns_server_t *svr, isns_socket_t *svr_sock, + + function = isns_message_function(msg); + if (function != ISNS_STATE_CHANGE_NOTIFICATION) { +- log_warning("Discarding unexpected %s message\n", ++ log_warning("Discarding unexpected %s message", + isns_function_name(function)); + isns_message_release(msg); + continue; +diff --git a/usr/event_poll.c b/usr/event_poll.c +index f36fec1..209ee02 100644 +--- a/usr/event_poll.c ++++ b/usr/event_poll.c +@@ -26,6 +26,8 @@ + #include + #include + #include ++#include ++#include + + #include "mgmt_ipc.h" + #include "iscsi_ipc.h" +@@ -37,7 +39,9 @@ + #include "initiator.h" + #include "iscsi_err.h" + +-static int reap_count; ++static unsigned int reap_count; ++ ++#define REAP_WAKEUP 1000 /* in millisecs */ + + void reap_inc(void) + { +@@ -50,7 +54,7 @@ void reap_proc(void) + + /* + * We don't really need reap_count, but calling wait() all the +- * time seems execessive. ++ * time seems excessive. + */ + max_reaps = reap_count; + for (i = 0; i < max_reaps; i++) { +@@ -80,7 +84,7 @@ int shutdown_callback(pid_t pid) + + INIT_LIST_HEAD(&cb->list); + cb->pid = pid; +- log_debug(1, "adding %d for shutdown cb\n", pid); ++ log_debug(1, "adding %d for shutdown cb", pid); + list_add_tail(&cb->list, &shutdown_callbacks); + return 0; + } +@@ -90,7 +94,7 @@ static void shutdown_notify_pids(void) + struct shutdown_callback *cb; + + list_for_each_entry(cb, &shutdown_callbacks, list) { +- log_debug(1, "Killing %d\n", cb->pid); ++ log_debug(1, "Killing %d", cb->pid); + kill(cb->pid, SIGTERM); + } + } +@@ -105,7 +109,7 @@ static int shutdown_wait_pids(void) + * sign that it is gone. + */ + if (waitpid(cb->pid, NULL, WNOHANG)) { +- log_debug(1, "%d done\n", cb->pid); ++ log_debug(1, "%d done", cb->pid); + list_del(&cb->list); + free(cb); + } +@@ -116,12 +120,12 @@ static int shutdown_wait_pids(void) + + #define POLL_CTRL 0 + #define POLL_IPC 1 +-#define POLL_MAX 2 ++#define POLL_ALARM 2 ++#define POLL_MAX 3 + + static int event_loop_stop; + static queue_task_t *shutdown_qtask; + +- + void event_loop_exit(queue_task_t *qtask) + { + shutdown_qtask = qtask; +@@ -132,11 +136,26 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd) + { + struct pollfd poll_array[POLL_MAX]; + int res, has_shutdown_children = 0; ++ sigset_t sigset; ++ int sig_fd; ++ ++ /* Mask off SIGALRM so we can recv it via signalfd */ ++ sigemptyset(&sigset); ++ sigaddset(&sigset, SIGALRM); ++ sigprocmask(SIG_SETMASK, &sigset, NULL); ++ ++ sig_fd = signalfd(-1, &sigset, SFD_NONBLOCK); ++ if (sig_fd == -1) { ++ log_error("signalfd failed: %m"); ++ return; ++ } + + poll_array[POLL_CTRL].fd = control_fd; + poll_array[POLL_CTRL].events = POLLIN; + poll_array[POLL_IPC].fd = mgmt_ipc_fd; + poll_array[POLL_IPC].events = POLLIN; ++ poll_array[POLL_ALARM].fd = sig_fd; ++ poll_array[POLL_ALARM].events = POLLIN; + + event_loop_stop = 0; + while (1) { +@@ -149,7 +168,11 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd) + break; + } + +- res = poll(poll_array, POLL_MAX, ACTOR_RESOLUTION); ++ /* Runs actors and may set alarm for future actors */ ++ actor_poll(); ++ ++ res = poll(poll_array, POLL_MAX, reap_count ? REAP_WAKEUP : -1); ++ + if (res > 0) { + log_debug(6, "poll result %d", res); + if (poll_array[POLL_CTRL].revents) +@@ -157,6 +180,18 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd) + + if (poll_array[POLL_IPC].revents) + mgmt_ipc_handle(mgmt_ipc_fd); ++ ++ if (poll_array[POLL_ALARM].revents) { ++ struct signalfd_siginfo si; ++ ++ if (read(sig_fd, &si, sizeof(si)) == -1) { ++ log_error("got sigfd read() error, errno (%d), " ++ "exiting", errno); ++ break; ++ } else { ++ log_debug(1, "Poll was woken by an alarm"); ++ } ++ } + } else if (res < 0) { + if (errno == EINTR) { + log_debug(1, "event_loop interrupted"); +@@ -165,15 +200,20 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd) + "exiting", res, errno); + break; + } +- } else +- actor_poll(); ++ } ++ + reap_proc(); ++ + /* + * flush sysfs cache since kernel objs may + * have changed as a result of handling op + */ + sysfs_cleanup(); + } ++ + if (shutdown_qtask) + mgmt_ipc_write_rsp(shutdown_qtask, ISCSI_SUCCESS); ++ ++ close(sig_fd); ++ sigprocmask(SIG_UNBLOCK, &sigset, NULL); + } +diff --git a/usr/flashnode.c b/usr/flashnode.c +new file mode 100644 +index 0000000..fe5ab57 +--- /dev/null ++++ b/usr/flashnode.c +@@ -0,0 +1,615 @@ ++/* ++ * iSCSI flashnode helpers ++ * ++ * Copyright (C) 2013 QLogic Corporation. ++ * Maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "log.h" ++#include "idbm.h" ++#include "iscsi_util.h" ++#include "transport.h" ++#include "iscsi_sysfs.h" ++#include "list.h" ++#include "sysdeps.h" ++#include "idbm_fields.h" ++#include "iscsi_err.h" ++#include "iscsi_ipc.h" ++#include "iscsi_netlink.h" ++#include "flashnode.h" ++#include "iscsi_settings.h" ++ ++char key[NAME_MAXVAL]; ++ ++char *to_key(const char *fmt) ++{ ++ int i = 0; ++ memset(key, 0, sizeof(key)); ++ sprintf(key, fmt, i); ++ return key; ++} ++ ++int flashnode_info_print_flat(void *data, struct flashnode_rec *fnode, ++ uint32_t host_no, uint32_t flashnode_idx) ++{ ++ printf("%s: [%d] ", fnode->transport_name, flashnode_idx); ++ if (!strlen((char *)fnode->conn[0].ipaddress)) ++ printf("%s:", UNKNOWN_VALUE); ++ else if (strchr((char *)fnode->conn[0].ipaddress, '.')) ++ printf("%s:", fnode->conn[0].ipaddress); ++ else ++ printf("[%s]:", fnode->conn[0].ipaddress); ++ ++ if (!fnode->conn[0].port) ++ printf("%s,", UNKNOWN_VALUE); ++ else ++ printf("%u,", fnode->conn[0].port); ++ ++ printf("%u ", fnode->sess.tpgt); ++ ++ if (!strlen(fnode->sess.targetname)) ++ printf("%s\n", UNKNOWN_VALUE); ++ else ++ printf("%s\n", fnode->sess.targetname); ++ ++ return 0; ++} ++ ++static int flashnode_fill_isid(struct flashnode_rec *fnode, struct iovec *iov) ++{ ++ struct iscsi_flashnode_param_info *fnode_param; ++ struct nlattr *attr; ++ int len; ++ uint8_t isid[6]; ++ ++ len = sizeof(struct iscsi_flashnode_param_info) + 6; ++ iov->iov_base = iscsi_nla_alloc(ISCSI_FLASHNODE_ISID, len); ++ if (!iov->iov_base) ++ return 1; ++ ++ attr = iov->iov_base; ++ iov->iov_len = NLA_ALIGN(attr->nla_len); ++ ++ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr); ++ fnode_param->param = ISCSI_FLASHNODE_ISID; ++ fnode_param->len = 6; ++ ++ sscanf(fnode->sess.isid, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", ++ &isid[0], &isid[1], &isid[2], &isid[3], &isid[4], &isid[5]); ++ ++ memcpy(fnode_param->value, isid, fnode_param->len); ++ return 0; ++} ++ ++static int flashnode_fill_ipv4_addr(struct flashnode_rec *fnode, ++ struct iovec *iov, int param_type) ++{ ++ struct iscsi_flashnode_param_info *fnode_param; ++ struct nlattr *attr; ++ int len; ++ int rc; ++ ++ len = sizeof(struct iscsi_flashnode_param_info) + 4; ++ iov->iov_base = iscsi_nla_alloc(param_type, len); ++ if (!iov->iov_base) ++ return 1; ++ ++ attr = iov->iov_base; ++ iov->iov_len = NLA_ALIGN(attr->nla_len); ++ ++ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr); ++ fnode_param->param = param_type; ++ fnode_param->len = 4; ++ ++ switch (param_type) { ++ case ISCSI_FLASHNODE_IPADDR: ++ rc = inet_pton(AF_INET, (char *)fnode->conn[0].ipaddress, ++ fnode_param->value); ++ break; ++ case ISCSI_FLASHNODE_REDIRECT_IPADDR: ++ rc = inet_pton(AF_INET, (char *)fnode->conn[0].redirect_ipaddr, ++ fnode_param->value); ++ break; ++ default: ++ goto free; ++ } ++ ++ if (rc <= 0) ++ goto free; ++ ++ return 0; ++ ++free: ++ free(iov->iov_base); ++ iov->iov_base = NULL; ++ iov->iov_len = 0; ++ return 1; ++} ++ ++static int flashnode_fill_ipv6_addr(struct flashnode_rec *fnode, ++ struct iovec *iov, int param_type) ++{ ++ struct iscsi_flashnode_param_info *fnode_param; ++ struct nlattr *attr; ++ int len; ++ int rc; ++ ++ len = sizeof(struct iscsi_flashnode_param_info) + 16; ++ iov->iov_base = iscsi_nla_alloc(param_type, len); ++ if (!iov->iov_base) ++ return 1; ++ ++ attr = iov->iov_base; ++ iov->iov_len = NLA_ALIGN(attr->nla_len); ++ ++ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr); ++ fnode_param->param = param_type; ++ fnode_param->len = 16; ++ ++ switch (param_type) { ++ case ISCSI_FLASHNODE_IPADDR: ++ rc = inet_pton(AF_INET6, (char *)fnode->conn[0].ipaddress, ++ fnode_param->value); ++ break; ++ case ISCSI_FLASHNODE_REDIRECT_IPADDR: ++ rc = inet_pton(AF_INET6, (char *)fnode->conn[0].redirect_ipaddr, ++ fnode_param->value); ++ break; ++ case ISCSI_FLASHNODE_LINK_LOCAL_IPV6: ++ rc = inet_pton(AF_INET6, (char *)fnode->conn[0].link_local_ipv6, ++ fnode_param->value); ++ break; ++ default: ++ goto free; ++ } ++ ++ if (rc <= 0) ++ goto free; ++ ++ return 0; ++ ++free: ++ free(iov->iov_base); ++ iov->iov_base = NULL; ++ iov->iov_len = 0; ++ return 1; ++} ++ ++static int flashnode_fill_ipaddr(struct flashnode_rec *fnode, struct iovec *iov, ++ int param_type) ++{ ++ int rc = 0; ++ ++ if (!strncmp(fnode->sess.portal_type, "ipv4", 4)) ++ rc = flashnode_fill_ipv4_addr(fnode, iov, param_type); ++ else ++ rc = flashnode_fill_ipv6_addr(fnode, iov, param_type); ++ ++ return rc; ++} ++ ++static int flashnode_fill_uint8(struct flashnode_rec *fnode, struct iovec *iov, ++ int param_type, uint8_t val) ++{ ++ struct iscsi_flashnode_param_info *fnode_param; ++ struct nlattr *attr; ++ int len; ++ ++ len = sizeof(struct iscsi_flashnode_param_info) + 1; ++ iov->iov_base = iscsi_nla_alloc(param_type, len); ++ if (!iov->iov_base) ++ return 1; ++ ++ attr = iov->iov_base; ++ iov->iov_len = NLA_ALIGN(attr->nla_len); ++ ++ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr); ++ fnode_param->param = param_type; ++ fnode_param->len = 1; ++ fnode_param->value[0] = val; ++ return 0; ++} ++ ++static int flashnode_fill_uint16(struct flashnode_rec *fnode, struct iovec *iov, ++ int param_type, uint16_t val) ++{ ++ struct iscsi_flashnode_param_info *fnode_param; ++ struct nlattr *attr; ++ int len; ++ ++ len = sizeof(struct iscsi_flashnode_param_info) + 2; ++ iov->iov_base = iscsi_nla_alloc(param_type, len); ++ if (!iov->iov_base) ++ return 1; ++ ++ attr = iov->iov_base; ++ iov->iov_len = NLA_ALIGN(attr->nla_len); ++ ++ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr); ++ fnode_param->param = param_type; ++ fnode_param->len = 2; ++ memcpy(fnode_param->value, &val, fnode_param->len); ++ return 0; ++} ++ ++static int flashnode_fill_uint32(struct flashnode_rec *fnode, struct iovec *iov, ++ int param_type, uint32_t val) ++{ ++ struct iscsi_flashnode_param_info *fnode_param; ++ struct nlattr *attr; ++ int len; ++ ++ len = sizeof(struct iscsi_flashnode_param_info) + 4; ++ iov->iov_base = iscsi_nla_alloc(param_type, len); ++ if (!iov->iov_base) ++ return 1; ++ ++ attr = iov->iov_base; ++ iov->iov_len = NLA_ALIGN(attr->nla_len); ++ ++ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr); ++ fnode_param->param = param_type; ++ fnode_param->len = 4; ++ memcpy(fnode_param->value, &val, fnode_param->len); ++ return 0; ++} ++ ++static int flashnode_fill_str(struct flashnode_rec *fnode, struct iovec *iov, ++ int param_type, char *buf, int buflen) ++{ ++ struct iscsi_flashnode_param_info *fnode_param; ++ struct nlattr *attr; ++ int len; ++ ++ len = sizeof(struct iscsi_flashnode_param_info) + buflen; ++ iov->iov_base = iscsi_nla_alloc(param_type, len); ++ if (!iov->iov_base) ++ return 1; ++ ++ attr = iov->iov_base; ++ iov->iov_len = NLA_ALIGN(attr->nla_len); ++ ++ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr); ++ fnode_param->param = param_type; ++ fnode_param->len = buflen; ++ memcpy(fnode_param->value, buf, fnode_param->len); ++ return 0; ++} ++ ++int flashnode_build_config(struct list_head *params, ++ struct flashnode_rec *fnode, struct iovec *iovs) ++{ ++ struct user_param *param; ++ struct iovec *iov = NULL; ++ int count = 0; ++ int port = 3260; ++ ++ /* start at 2, because 0 is for nlmsghdr and 1 for event */ ++ iov = iovs + 2; ++ ++ list_for_each_entry(param, params, list) { ++ if (!strcmp(param->name, FLASHNODE_SESS_AUTO_SND_TGT_DISABLE)) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE, ++ fnode->sess.auto_snd_tgt_disable)) ++ count++; ++ } else if (!strcmp(param->name, ++ FLASHNODE_SESS_DISCOVERY_SESS)) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_DISCOVERY_SESS, ++ fnode->sess.discovery_session)) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_ENTRY_EN)) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_ENTRY_EN, ++ fnode->sess.entry_enable)) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_IMM_DATA_EN)) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_IMM_DATA_EN, ++ fnode->sess.immediate_data)) ++ count++; ++ } else if (!strcmp(param->name, ++ FLASHNODE_SESS_INITIAL_R2T_EN)) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_INITIAL_R2T_EN, ++ fnode->sess.initial_r2t)) ++ count++; ++ } else if (!strcmp(param->name, ++ FLASHNODE_SESS_DATASEQ_INORDER)) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_DATASEQ_INORDER, ++ fnode->sess.data_seq_in_order)) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_PDU_INORDER)) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_PDU_INORDER, ++ fnode->sess.data_pdu_in_order)) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_CHAP_AUTH_EN)) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_CHAP_AUTH_EN, ++ fnode->sess.chap_auth_en)) ++ count++; ++ } else if (!strcmp(param->name, ++ FLASHNODE_SESS_DISCOVERY_LOGOUT_EN)) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN, ++ fnode->sess.discovery_logout_en)) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_BIDI_CHAP_EN )) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_BIDI_CHAP_EN, ++ fnode->sess.bidi_chap_en)) ++ count++; ++ } else if (!strcmp(param->name, ++ FLASHNODE_SESS_DISCOVERY_AUTH_OPTIONAL)) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL, ++ fnode->sess.discovery_auth_optional)) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_ERL)) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_ERL, ++ fnode->sess.erl)) ++ count++; ++ } else if (!strcmp(param->name, ++ FLASHNODE_SESS_DEF_TIME2WAIT)) { ++ if (!flashnode_fill_uint16(fnode, &iov[count], ++ ISCSI_FLASHNODE_DEF_TIME2WAIT, ++ fnode->sess.def_time2wait)) ++ count++; ++ } else if (!strcmp(param->name, ++ FLASHNODE_SESS_DEF_TIME2RETAIN)) { ++ if (!flashnode_fill_uint16(fnode, &iov[count], ++ ISCSI_FLASHNODE_DEF_TIME2RETAIN, ++ fnode->sess.def_time2retain)) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_MAX_R2T)) { ++ if (!flashnode_fill_uint16(fnode, &iov[count], ++ ISCSI_FLASHNODE_MAX_R2T, ++ fnode->sess.max_outstanding_r2t)) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_TSID)) { ++ if (!flashnode_fill_uint16(fnode, &iov[count], ++ ISCSI_FLASHNODE_TSID, ++ fnode->sess.tsid)) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_MAX_BURST)) { ++ if (!flashnode_fill_uint32(fnode, &iov[count], ++ ISCSI_FLASHNODE_MAX_BURST, ++ fnode->sess.max_burst_len)) ++ count++; ++ } else if (!strcmp(param->name, ++ FLASHNODE_SESS_DEF_TASKMGMT_TMO)) { ++ if (!flashnode_fill_uint16(fnode, &iov[count], ++ ISCSI_FLASHNODE_DEF_TASKMGMT_TMO, ++ fnode->sess.def_taskmgmt_tmo)) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_NAME)) { ++ if (!flashnode_fill_str(fnode, &iov[count], ++ ISCSI_FLASHNODE_NAME, ++ fnode->sess.targetname, ++ sizeof(fnode->sess.targetname))) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_FIRST_BURST)) { ++ if (!flashnode_fill_uint32(fnode, &iov[count], ++ ISCSI_FLASHNODE_FIRST_BURST, ++ fnode->sess.first_burst_len)) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_ISID)) { ++ if (!flashnode_fill_isid(fnode, &iov[count])) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_ALIAS)) { ++ if (!flashnode_fill_str(fnode, &iov[count], ++ ISCSI_FLASHNODE_ALIAS, ++ fnode->sess.targetalias, ++ sizeof(fnode->sess.targetalias))) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_TPGT)) { ++ if (!flashnode_fill_uint16(fnode, &iov[count], ++ ISCSI_FLASHNODE_TPGT, ++ fnode->sess.tpgt)) ++ count++; ++ } else if (!strcmp(param->name, ++ FLASHNODE_SESS_DISCOVERY_PARENT_IDX)) { ++ if (!flashnode_fill_uint16(fnode, &iov[count], ++ ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX, ++ fnode->sess.discovery_parent_idx)) ++ count++; ++ } else if (!strcmp(param->name, ++ FLASHNODE_SESS_DISCOVERY_PARENT_TYPE)) { ++ if (!flashnode_fill_str(fnode, &iov[count], ++ ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE, ++ fnode->sess.discovery_parent_type, ++ sizeof(fnode->sess.discovery_parent_type))) ++ count++; ++ } else if (!strcmp(param->name, FLASHNODE_SESS_PORTAL_TYPE)) { ++ if (!flashnode_fill_str(fnode, &iov[count], ++ ISCSI_FLASHNODE_PORTAL_TYPE, ++ fnode->sess.portal_type, ++ sizeof(fnode->sess.portal_type))) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_SESS_CHAP_OUT_IDX))) { ++ if (!flashnode_fill_uint32(fnode, &iov[count], ++ ISCSI_FLASHNODE_CHAP_OUT_IDX, ++ fnode->sess.chap_out_idx)) ++ count++; ++ } else if (!strcmp(param->name, to_key(FLASHNODE_CONN_PORT))) { ++ if (fnode->conn[0].port) ++ port = fnode->conn[0].port; ++ if (!flashnode_fill_uint16(fnode, &iov[count], ++ ISCSI_FLASHNODE_PORT, port)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_IPADDR))) { ++ if (!flashnode_fill_ipaddr(fnode, &iov[count], ++ ISCSI_FLASHNODE_IPADDR)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_MAX_RECV_DLENGTH))) { ++ if (!flashnode_fill_uint32(fnode, &iov[count], ++ ISCSI_FLASHNODE_MAX_RECV_DLENGTH, ++ fnode->conn[0].max_recv_dlength)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_IS_FW_ASSIGNED_IPV6))) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6, ++ fnode->conn[0].is_fw_assigned_ipv6)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_HDR_DGST_EN))) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_HDR_DGST_EN, ++ fnode->conn[0].header_digest_en)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_DATA_DGST_EN))) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_DATA_DGST_EN, ++ fnode->conn[0].data_digest_en)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_SNACK_REQ_EN))) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_SNACK_REQ_EN, ++ fnode->conn[0].snack_req_en)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_TCP_TIMESTAMP_STAT))) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT, ++ fnode->conn[0].tcp_timestamp_stat)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_TCP_NAGLE_DISABLE))) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_TCP_NAGLE_DISABLE, ++ fnode->conn[0].tcp_nagle_disable)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_TCP_WSF_DISABLE))) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_TCP_WSF_DISABLE, ++ fnode->conn[0].tcp_wsf_disable)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_TCP_TIMER_SCALE))) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_TCP_TIMER_SCALE, ++ fnode->conn[0].tcp_timer_scale)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_TCP_TIMESTAMP_EN))) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_TCP_TIMESTAMP_EN, ++ fnode->conn[0].tcp_timestamp_en)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_IP_FRAG_DISABLE))) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_IP_FRAG_DISABLE, ++ fnode->conn[0].fragment_disable)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_MAX_XMIT_DLENGTH))) { ++ if (!flashnode_fill_uint32(fnode, &iov[count], ++ ISCSI_FLASHNODE_MAX_XMIT_DLENGTH, ++ fnode->conn[0].max_xmit_dlength)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_KEEPALIVE_TMO))) { ++ if (!flashnode_fill_uint16(fnode, &iov[count], ++ ISCSI_FLASHNODE_KEEPALIVE_TMO, ++ fnode->conn[0].keepalive_tmo)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_REDIRECT_IPADDR))) { ++ if (!flashnode_fill_ipaddr(fnode, &iov[count], ++ ISCSI_FLASHNODE_REDIRECT_IPADDR)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_MAX_SEGMENT_SIZE))) { ++ if (!flashnode_fill_uint32(fnode, &iov[count], ++ ISCSI_FLASHNODE_MAX_SEGMENT_SIZE, ++ fnode->conn[0].max_segment_size)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_LOCAL_PORT))) { ++ if (!flashnode_fill_uint16(fnode, &iov[count], ++ ISCSI_FLASHNODE_LOCAL_PORT, ++ fnode->conn[0].local_port)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_IPV4_TOS))) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_IPV4_TOS, ++ fnode->conn[0].ipv4_tos)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_IPV6_TC))) { ++ if (!flashnode_fill_uint8(fnode, &iov[count], ++ ISCSI_FLASHNODE_IPV6_TC, ++ fnode->conn[0].ipv6_traffic_class)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_IPV6_FLOW_LABEL))) { ++ if (!flashnode_fill_uint16(fnode, &iov[count], ++ ISCSI_FLASHNODE_IPV6_FLOW_LABEL, ++ fnode->conn[0].ipv6_flow_lbl)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_LINK_LOCAL_IPV6))) { ++ if (!flashnode_fill_ipv6_addr(fnode, &iov[count], ++ ISCSI_FLASHNODE_LINK_LOCAL_IPV6)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_TCP_XMIT_WSF))) { ++ if (!flashnode_fill_uint32(fnode, &iov[count], ++ ISCSI_FLASHNODE_TCP_XMIT_WSF, ++ fnode->conn[0].tcp_xmit_wsf)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_TCP_RECV_WSF))) { ++ if (!flashnode_fill_uint32(fnode, &iov[count], ++ ISCSI_FLASHNODE_TCP_RECV_WSF, ++ fnode->conn[0].tcp_recv_wsf)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_STATSN))) { ++ if (!flashnode_fill_uint32(fnode, &iov[count], ++ ISCSI_FLASHNODE_STATSN, ++ fnode->conn[0].stat_sn)) ++ count++; ++ } else if (!strcmp(param->name, ++ to_key(FLASHNODE_CONN_EXP_STATSN))) { ++ if (!flashnode_fill_uint32(fnode, &iov[count], ++ ISCSI_FLASHNODE_EXP_STATSN, ++ fnode->conn[0].exp_stat_sn)) ++ count++; ++ } ++ } ++ ++ return count; ++} +diff --git a/usr/flashnode.h b/usr/flashnode.h +new file mode 100644 +index 0000000..2950fb5 +--- /dev/null ++++ b/usr/flashnode.h +@@ -0,0 +1,129 @@ ++/* ++ * iSCSI flashnode helpers ++ * ++ * Copyright (C) 2013 QLogic Corporation. ++ * Maintained by open-iscsi@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++#ifndef FLASHNODE_H ++#define FLASHNODE_H ++#include ++#include ++#include ++ ++#include "types.h" ++#include "config.h" ++#include "auth.h" ++ ++#define MAX_FLASHNODE_IDX UINT_MAX ++ ++typedef enum portal_type { ++ IPV4, ++ IPV6, ++} portal_type_e; ++ ++typedef struct flashnode_sess_rec { ++ char targetname[TARGET_NAME_MAXLEN]; ++ char targetalias[TARGET_NAME_MAXLEN]; ++ char username[AUTH_STR_MAX_LEN]; ++ char username_in[AUTH_STR_MAX_LEN]; ++ char password[AUTH_STR_MAX_LEN]; ++ char password_in[AUTH_STR_MAX_LEN]; ++ /* indicates if discovery was done through iSNS discovery service ++ * or through sendTarget */ ++ char discovery_parent_type[ISCSI_MAX_STR_LEN]; ++ char isid[16]; ++ char portal_type[5]; /* ipv4 or ipv6 */ ++ unsigned first_burst_len; ++ unsigned max_burst_len; ++ uint16_t def_time2wait; ++ uint16_t def_time2retain; ++ uint16_t max_outstanding_r2t; ++ uint16_t tsid; ++ uint16_t def_taskmgmt_tmo; ++ uint16_t tpgt; ++ uint16_t chap_out_idx; ++ uint16_t chap_in_idx; ++ /* index of iSCSI discovery session if the entry is ++ * discovered by iSCSI discovery session ++ */ ++ uint16_t discovery_parent_idx; ++ /* Firmware auto sendtarget discovery disable */ ++ uint8_t auto_snd_tgt_disable; ++ uint8_t discovery_session; ++ /* indicates if this flashnode entry is enabled or disabled */ ++ uint8_t entry_enable; ++ uint8_t immediate_data; ++ uint8_t initial_r2t; ++ uint8_t data_seq_in_order; ++ uint8_t data_pdu_in_order; ++ uint8_t chap_auth_en; ++ /* enables firmware to auto logout the discovery session on discovery ++ * completion ++ */ ++ uint8_t discovery_logout_en; ++ uint8_t bidi_chap_en; ++ /* makes authentication for discovery session optional */ ++ uint8_t discovery_auth_optional; ++ uint8_t erl; ++ uint8_t is_boot_target; ++} flashnode_sess_rec_t; ++ ++typedef struct flashnode_conn_rec { ++ char ipaddress[NI_MAXHOST]; ++ char redirect_ipaddr[NI_MAXHOST]; ++ char link_local_ipv6[NI_MAXHOST]; ++ unsigned max_recv_dlength; ++ unsigned max_xmit_dlength; ++ unsigned max_segment_size; ++ unsigned tcp_xmit_wsf; ++ unsigned tcp_recv_wsf; ++ uint32_t stat_sn; ++ uint32_t exp_stat_sn; ++ uint16_t keepalive_tmo; ++ uint16_t port; ++ uint16_t local_port; ++ uint16_t ipv6_flow_lbl; ++ /* Link local IPv6 address is assigned by firmware or driver */ ++ uint8_t is_fw_assigned_ipv6; ++ uint8_t header_digest_en; ++ uint8_t data_digest_en; ++ uint8_t snack_req_en; ++ /* tcp timestamp negotiation status */ ++ uint8_t tcp_timestamp_stat; ++ uint8_t tcp_nagle_disable; ++ /* tcp window scale factor */ ++ uint8_t tcp_wsf_disable; ++ uint8_t tcp_timer_scale; ++ uint8_t tcp_timestamp_en; ++ uint8_t fragment_disable; ++ uint8_t ipv4_tos; ++ uint8_t ipv6_traffic_class; ++} flashnode_conn_rec_t; ++ ++struct flashnode_rec { ++ struct list_head list; ++ char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN]; ++ flashnode_sess_rec_t sess; ++ flashnode_conn_rec_t conn[ISCSI_CONN_MAX]; ++}; ++ ++extern int flashnode_info_print_flat(void *data, struct flashnode_rec *tgt, ++ uint32_t host_no, uint32_t flashnode_idx); ++extern int iscsi_logout_flashnode_sid(struct iscsi_transport *t, ++ uint32_t host_no, uint32_t sid); ++extern int flashnode_build_config(struct list_head *params, ++ struct flashnode_rec *flashnode, ++ struct iovec *iovs); ++#endif +diff --git a/usr/host.c b/usr/host.c +index b03e50f..f2052d3 100644 +--- a/usr/host.c ++++ b/usr/host.c +@@ -34,6 +34,7 @@ + #include "initiator.h" + #include "iface.h" + #include "iscsi_err.h" ++#include "iscsi_netlink.h" + + static int match_host_to_session(void *data, struct session_info *info) + { +@@ -242,7 +243,7 @@ static int host_info_print_tree(void *data, struct host_info *hinfo) + link_info.data = &hinfo->host_no; + + err = iscsi_sysfs_for_each_session(&link_info, &num_found, +- session_info_create_list); ++ session_info_create_list, 0); + if (err || !num_found) + return 0; + +@@ -314,3 +315,112 @@ int host_info_print(int info_level, uint32_t host_no) + } + return 0; + } ++ ++static int chap_fill_param_uint(struct iovec *iov, int param, ++ uint32_t param_val, int param_len) ++{ ++ struct iscsi_param_info *param_info; ++ struct nlattr *attr; ++ int len; ++ uint8_t val8 = 0; ++ uint16_t val16 = 0; ++ uint32_t val32 = 0; ++ char *val = NULL; ++ ++ len = sizeof(struct iscsi_param_info) + param_len; ++ iov->iov_base = iscsi_nla_alloc(param, len); ++ if (!iov->iov_base) ++ return 1; ++ ++ attr = iov->iov_base; ++ iov->iov_len = NLA_ALIGN(attr->nla_len); ++ ++ param_info = (struct iscsi_param_info *)ISCSI_NLA_DATA(attr); ++ param_info->param = param; ++ param_info->len = param_len; ++ ++ switch (param_len) { ++ case 1: ++ val8 = (uint8_t)param_val; ++ val = (char *)&val8; ++ break; ++ ++ case 2: ++ val16 = (uint16_t)param_val; ++ val = (char *)&val16; ++ break; ++ ++ case 4: ++ val32 = (uint32_t)param_val; ++ val = (char *)&val32; ++ break; ++ ++ default: ++ goto free; ++ } ++ memcpy(param_info->value, val, param_len); ++ ++ return 0; ++ ++free: ++ free(iov->iov_base); ++ iov->iov_base = NULL; ++ iov->iov_len = 0; ++ return 1; ++} ++ ++static int chap_fill_param_str(struct iovec *iov, int param, char *param_val, ++ int param_len) ++{ ++ struct iscsi_param_info *param_info; ++ struct nlattr *attr; ++ int len; ++ ++ len = sizeof(struct iscsi_param_info) + param_len; ++ iov->iov_base = iscsi_nla_alloc(param, len); ++ if (!iov->iov_base) ++ return 1; ++ ++ attr = iov->iov_base; ++ iov->iov_len = NLA_ALIGN(attr->nla_len); ++ ++ param_info = (struct iscsi_param_info *)ISCSI_NLA_DATA(attr); ++ param_info->param = param; ++ param_info->len = param_len; ++ memcpy(param_info->value, param_val, param_len); ++ return 0; ++} ++ ++int chap_build_config(struct iscsi_chap_rec *crec, struct iovec *iovs) ++{ ++ struct iovec *iov = NULL; ++ int count = 0; ++ ++ /* start at 2, because 0 is for nlmsghdr and 1 for event */ ++ iov = iovs + 2; ++ ++ if (!chap_fill_param_uint(&iov[count], ISCSI_CHAP_PARAM_INDEX, ++ crec->chap_tbl_idx, ++ sizeof(crec->chap_tbl_idx))) ++ count++; ++ ++ if (!chap_fill_param_uint(&iov[count], ISCSI_CHAP_PARAM_CHAP_TYPE, ++ crec->chap_type, sizeof(crec->chap_type))) ++ count++; ++ ++ if (!chap_fill_param_str(&iov[count], ISCSI_CHAP_PARAM_USERNAME, ++ crec->username, strlen(crec->username))) ++ count++; ++ ++ if (!chap_fill_param_str(&iov[count], ISCSI_CHAP_PARAM_PASSWORD, ++ (char *)crec->password, ++ strlen((char *)crec->password))) ++ count++; ++ ++ if (!chap_fill_param_uint(&iov[count], ISCSI_CHAP_PARAM_PASSWORD_LEN, ++ crec->password_length, ++ sizeof(crec->password_length))) ++ count++; ++ ++ return count; ++} +diff --git a/usr/host.h b/usr/host.h +index 894ab91..149aa0d 100644 +--- a/usr/host.h ++++ b/usr/host.h +@@ -5,6 +5,9 @@ + #include "types.h" + #include "config.h" + ++#define MAX_HOST_NO UINT_MAX ++ ++#define MAX_CHAP_ENTRIES 2048 + #define MAX_CHAP_BUF_SZ 4096 + #define REQ_CHAP_BUF_SZ (MAX_CHAP_BUF_SZ + sizeof(struct iscsi_uevent)) + +@@ -14,5 +17,6 @@ struct host_info { + }; + + extern int host_info_print(int info_level, uint32_t host_no); ++extern int chap_build_config(struct iscsi_chap_rec *crec, struct iovec *iovs); + + #endif +diff --git a/usr/idbm.c b/usr/idbm.c +index 4d30aa9..198a5ef 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -94,6 +94,17 @@ static struct idbm *db; + _n++; \ + } while (0) + ++#define __recinfo_uint32(_key, _info, _rec, _name, _show, _n, _mod) do { \ ++ _info[_n].type = TYPE_UINT32; \ ++ strlcpy(_info[_n].name, _key, NAME_MAXVAL); \ ++ snprintf(_info[_n].value, VALUE_MAXVAL, "%d", _rec->_name); \ ++ _info[_n].data = &_rec->_name; \ ++ _info[_n].data_len = sizeof(_rec->_name); \ ++ _info[_n].visible = _show; \ ++ _info[_n].can_modify = _mod; \ ++ _n++; \ ++} while (0) ++ + #define __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod) do { \ + _info[_n].type = TYPE_INT_O; \ + strlcpy(_info[_n].name, _key, NAME_MAXVAL); \ +@@ -226,6 +237,9 @@ void + idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) + { + int num = 0, i; ++ int iface_type; ++ ++ iface_type = iface_get_iptype(&r->iface); + + __recinfo_str(NODE_NAME, ri, r, name, IDBM_SHOW, num, 0); + __recinfo_int(NODE_TPGT, ri, r, tpgt, IDBM_SHOW, num, 0); +@@ -248,6 +262,8 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) + __recinfo_str(IFACE_IPADDR, ri, r, iface.ipaddress, IDBM_SHOW, num, 1); + __recinfo_str(IFACE_ISCSINAME, ri, r, iface.name, IDBM_SHOW, num, 1); + __recinfo_str(IFACE_NETNAME, ri, r, iface.netdev, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_GATEWAY, ri, r, iface.gateway, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_SUBNET_MASK, ri, r, iface.subnet_mask, IDBM_SHOW, num, 1); + /* + * svn 780 compat: older versions used node.transport_name and + * rec->transport_name +@@ -255,21 +271,6 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) + __recinfo_str(IFACE_TRANSPORTNAME, ri, r, iface.transport_name, + IDBM_SHOW, num, 1); + __recinfo_str(IFACE_INAME, ri, r, iface.iname, IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_BOOT_PROTO, ri, r, iface.bootproto, IDBM_SHOW, +- num, 1); +- __recinfo_str(IFACE_SUBNET_MASK, ri, r, iface.subnet_mask, +- IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_GATEWAY, ri, r, iface.gateway, IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_IPV6_AUTOCFG, ri, r, iface.ipv6_autocfg, +- IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_LINKLOCAL_AUTOCFG, ri, r, iface.linklocal_autocfg, +- IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_ROUTER_AUTOCFG, ri, r, iface.router_autocfg, +- IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_LINKLOCAL, ri, r, iface.ipv6_linklocal, +- IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_ROUTER, ri, r, iface.ipv6_router, IDBM_SHOW, num, +- 1); + __recinfo_str(IFACE_STATE, ri, r, iface.state, IDBM_SHOW, num, 1); + __recinfo_uint16(IFACE_VLAN_ID, ri, r, iface.vlan_id, IDBM_SHOW, num, + 1); +@@ -281,6 +282,115 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) + __recinfo_uint16(IFACE_MTU, ri, r, iface.mtu, IDBM_SHOW, num, 1); + __recinfo_uint16(IFACE_PORT, ri, r, iface.port, IDBM_SHOW, num, 1); + ++ if (iface_type == ISCSI_IFACE_TYPE_IPV4) { ++ __recinfo_str(IFACE_BOOT_PROTO, ri, r, iface.bootproto, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DHCP_ALT_CID, ri, r, ++ iface.dhcp_alt_client_id_state, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_DHCP_ALT_CID_STR, ri, r, ++ iface.dhcp_alt_client_id, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DHCP_DNS, ri, r, iface.dhcp_dns, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_DHCP_LEARN_IQN, ri, r, ++ iface.dhcp_learn_iqn, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DHCP_REQ_VID, ri, r, ++ iface.dhcp_req_vendor_id_state, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_DHCP_VID, ri, r, iface.dhcp_vendor_id_state, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DHCP_VID_STR, ri, r, iface.dhcp_vendor_id, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DHCP_SLP_DA, ri, r, iface.dhcp_slp_da, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_FRAGMENTATION, ri, r, iface.fragmentation, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_GRAT_ARP, ri, r, iface.gratuitous_arp, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_IN_FORWARD, ri, r, ++ iface.incoming_forwarding, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_TOS_STATE, ri, r, iface.tos_state, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint8(IFACE_TOS, ri, r, iface.tos, IDBM_SHOW, num, 1); ++ __recinfo_uint8(IFACE_TTL, ri, r, iface.ttl, IDBM_SHOW, num, 1); ++ } else if (iface_type == ISCSI_IFACE_TYPE_IPV6) { ++ __recinfo_str(IFACE_IPV6_AUTOCFG, ri, r, iface.ipv6_autocfg, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_LINKLOCAL_AUTOCFG, ri, r, ++ iface.linklocal_autocfg, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_ROUTER_AUTOCFG, ri, r, iface.router_autocfg, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_LINKLOCAL, ri, r, iface.ipv6_linklocal, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_ROUTER, ri, r, iface.ipv6_router, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint8(IFACE_DUP_ADDR_DETECT_CNT, ri, r, ++ iface.dup_addr_detect_cnt, IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_FLOW_LABEL, ri, r, iface.flow_label, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_GRAT_NEIGHBOR_ADV, ri, r, ++ iface.gratuitous_neighbor_adv, IDBM_SHOW, num, 1); ++ __recinfo_uint8(IFACE_HOP_LIMIT, ri, r, iface.hop_limit, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_MLD, ri, r, iface.mld, IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_ND_REACHABLE_TMO, ri, r, ++ iface.nd_reachable_tmo, IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_ND_REXMIT_TIME, ri, r, ++ iface.nd_rexmit_time, IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_ND_STALE_TMO, ri, r, iface.nd_stale_tmo, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_RTR_ADV_LINK_MTU, ri, r, ++ iface.router_adv_link_mtu, IDBM_SHOW, num, 1); ++ __recinfo_uint8(IFACE_TRAFFIC_CLASS, ri, r, iface.traffic_class, ++ IDBM_SHOW, num, 1); ++ } ++ ++ __recinfo_str(IFACE_DELAYED_ACK, ri, r, iface.delayed_ack, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_TCP_NAGLE, ri, r, iface.nagle, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_TCP_WSF_STATE, ri, r, iface.tcp_wsf_state, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint8(IFACE_TCP_WSF, ri, r, iface.tcp_wsf, IDBM_SHOW, num, 1); ++ __recinfo_uint8(IFACE_TCP_TIMER_SCALE, ri, r, iface.tcp_timer_scale, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_TCP_TIMESTAMP, ri, r, iface.tcp_timestamp, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_REDIRECT, ri, r, iface.redirect, IDBM_SHOW, num, 1); ++ __recinfo_uint16(IFACE_DEF_TMF_TMO, ri, r, iface.def_task_mgmt_tmo, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_HDRDGST, ri, r, iface.header_digest, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_DATADGST, ri, r, iface.data_digest, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_IMM_DATA, ri, r, iface.immediate_data, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_INITIAL_R2T, ri, r, iface.initial_r2t, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_DSEQ_INORDER, ri, r, iface.data_seq_inorder, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DPDU_INORDER, ri, r, iface.data_pdu_inorder, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint8(IFACE_ERL, ri, r, iface.erl, IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_MAX_RECV_DLEN, ri, r, iface.max_recv_dlength, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_FIRST_BURST, ri, r, iface.first_burst_len, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint16(IFACE_MAX_R2T, ri, r, iface.max_out_r2t, IDBM_SHOW, ++ num, 1); ++ __recinfo_uint32(IFACE_MAX_BURST, ri, r, iface.max_burst_len, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_CHAP_AUTH, ri, r, iface.chap_auth, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_BIDI_CHAP, ri, r, iface.bidi_chap, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_STRICT_LOGIN_COMP, ri, r, iface.strict_login_comp, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DISCOVERY_AUTH, ri, r, iface.discovery_auth, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DISCOVERY_LOGOUT, ri, r, iface.discovery_logout, ++ IDBM_SHOW, num, 1); ++ ++ + __recinfo_str(NODE_DISC_ADDR, ri, r, disc_address, IDBM_SHOW, + num, 0); + __recinfo_int(NODE_DISC_PORT, ri, r, disc_port, IDBM_SHOW, +@@ -414,6 +524,9 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) + void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri) + { + int num = 0; ++ int iface_type; ++ ++ iface_type = iface_get_iptype(r); + + __recinfo_str(IFACE_ISCSINAME, ri, r, name, IDBM_SHOW, num, 0); + __recinfo_str(IFACE_NETNAME, ri, r, netdev, IDBM_SHOW, num, 1); +@@ -422,19 +535,6 @@ void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri) + __recinfo_str(IFACE_TRANSPORTNAME, ri, r, transport_name, + IDBM_SHOW, num, 1); + __recinfo_str(IFACE_INAME, ri, r, iname, IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_BOOT_PROTO, ri, r, bootproto, IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_SUBNET_MASK, ri, r, subnet_mask, +- IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_GATEWAY, ri, r, gateway, IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_IPV6_AUTOCFG, ri, r, ipv6_autocfg, +- IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_LINKLOCAL_AUTOCFG, ri, r, linklocal_autocfg, +- IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_ROUTER_AUTOCFG, ri, r, router_autocfg, +- IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_LINKLOCAL, ri, r, ipv6_linklocal, +- IDBM_SHOW, num, 1); +- __recinfo_str(IFACE_ROUTER, ri, r, ipv6_router, IDBM_SHOW, num, 1); + __recinfo_str(IFACE_STATE, ri, r, state, IDBM_SHOW, num, 1); + __recinfo_uint16(IFACE_VLAN_ID, ri, r, vlan_id, IDBM_SHOW, num, 1); + __recinfo_uint8(IFACE_VLAN_PRIORITY, ri, r, vlan_priority, +@@ -443,9 +543,110 @@ void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri) + __recinfo_int(IFACE_NUM, ri, r, iface_num, IDBM_SHOW, num, 1); + __recinfo_uint16(IFACE_MTU, ri, r, mtu, IDBM_SHOW, num, 1); + __recinfo_uint16(IFACE_PORT, ri, r, port, IDBM_SHOW, num, 1); ++ ++ if (iface_type == ISCSI_IFACE_TYPE_IPV4) { ++ __recinfo_str(IFACE_BOOT_PROTO, ri, r, bootproto, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_SUBNET_MASK, ri, r, subnet_mask, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_GATEWAY, ri, r, gateway, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DHCP_ALT_CID, ri, r, ++ dhcp_alt_client_id_state, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DHCP_ALT_CID_STR, ri, r, dhcp_alt_client_id, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DHCP_DNS, ri, r, dhcp_dns, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_DHCP_LEARN_IQN, ri, r, dhcp_learn_iqn, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DHCP_REQ_VID, ri, r, ++ dhcp_req_vendor_id_state, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DHCP_VID, ri, r, dhcp_vendor_id_state, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DHCP_VID_STR, ri, r, dhcp_vendor_id, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DHCP_SLP_DA, ri, r, dhcp_slp_da, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_FRAGMENTATION, ri, r, fragmentation, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_GRAT_ARP, ri, r, gratuitous_arp, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_IN_FORWARD, ri, r, incoming_forwarding, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_TOS_STATE, ri, r, tos_state, IDBM_SHOW, ++ num, 1); ++ __recinfo_uint8(IFACE_TOS, ri, r, tos, IDBM_SHOW, num, 1); ++ __recinfo_uint8(IFACE_TTL, ri, r, ttl, IDBM_SHOW, num, 1); ++ } else if (iface_type == ISCSI_IFACE_TYPE_IPV6) { ++ __recinfo_str(IFACE_IPV6_AUTOCFG, ri, r, ipv6_autocfg, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_LINKLOCAL_AUTOCFG, ri, r, linklocal_autocfg, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_ROUTER_AUTOCFG, ri, r, router_autocfg, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_LINKLOCAL, ri, r, ipv6_linklocal, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_ROUTER, ri, r, ipv6_router, IDBM_SHOW, ++ num, 1); ++ __recinfo_uint8(IFACE_DUP_ADDR_DETECT_CNT, ri, r, ++ dup_addr_detect_cnt, IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_FLOW_LABEL, ri, r, flow_label, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_GRAT_NEIGHBOR_ADV, ri, r, ++ gratuitous_neighbor_adv, IDBM_SHOW, num, 1); ++ __recinfo_uint8(IFACE_HOP_LIMIT, ri, r, hop_limit, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_MLD, ri, r, mld, IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_ND_REACHABLE_TMO, ri, r, ++ nd_reachable_tmo, IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_ND_REXMIT_TIME, ri, r, nd_rexmit_time, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_ND_STALE_TMO, ri, r, nd_stale_tmo, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_RTR_ADV_LINK_MTU, ri, r, ++ router_adv_link_mtu, IDBM_SHOW, num, 1); ++ __recinfo_uint8(IFACE_TRAFFIC_CLASS, ri, r, traffic_class, ++ IDBM_SHOW, num, 1); ++ } ++ ++ __recinfo_str(IFACE_DELAYED_ACK, ri, r, delayed_ack, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_TCP_NAGLE, ri, r, nagle, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_TCP_WSF_STATE, ri, r, tcp_wsf_state, IDBM_SHOW, ++ num, 1); ++ __recinfo_uint8(IFACE_TCP_WSF, ri, r, tcp_wsf, IDBM_SHOW, num, 1); ++ __recinfo_uint8(IFACE_TCP_TIMER_SCALE, ri, r, tcp_timer_scale, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_TCP_TIMESTAMP, ri, r, tcp_timestamp, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_REDIRECT, ri, r, redirect, IDBM_SHOW, num, 1); ++ __recinfo_uint16(IFACE_DEF_TMF_TMO, ri, r, def_task_mgmt_tmo, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_HDRDGST, ri, r, header_digest, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DATADGST, ri, r, data_digest, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_IMM_DATA, ri, r, immediate_data, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_INITIAL_R2T, ri, r, initial_r2t, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DSEQ_INORDER, ri, r, data_seq_inorder, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_DPDU_INORDER, ri, r, data_pdu_inorder, IDBM_SHOW, ++ num, 1); ++ __recinfo_uint8(IFACE_ERL, ri, r, erl, IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_MAX_RECV_DLEN, ri, r, max_recv_dlength, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_FIRST_BURST, ri, r, first_burst_len, IDBM_SHOW, ++ num, 1); ++ __recinfo_uint16(IFACE_MAX_R2T, ri, r, max_out_r2t, IDBM_SHOW, num, 1); ++ __recinfo_uint32(IFACE_MAX_BURST, ri, r, max_burst_len, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_CHAP_AUTH, ri, r, chap_auth, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_BIDI_CHAP, ri, r, bidi_chap, IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_STRICT_LOGIN_COMP, ri, r, strict_login_comp, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(IFACE_DISCOVERY_AUTH, ri, r, discovery_auth, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(IFACE_DISCOVERY_LOGOUT, ri, r, discovery_logout, ++ IDBM_SHOW, num, 1); + } + +-static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri) ++void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri) + { + int num = 0; + +@@ -454,14 +655,14 @@ static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri) + + if (r->chap_type == CHAP_TYPE_OUT) { + __recinfo_str(HOST_AUTH_USERNAME, ri, r, username, IDBM_SHOW, +- num, 0); ++ num, 1); + __recinfo_str(HOST_AUTH_PASSWORD, ri, r, password, IDBM_MASKED, + num, 1); + __recinfo_int(HOST_AUTH_PASSWORD_LEN, ri, r, password_length, + IDBM_HIDE, num, 1); + } else { + __recinfo_str(HOST_AUTH_USERNAME_IN, ri, r, username, IDBM_SHOW, +- num, 0); ++ num, 1); + __recinfo_str(HOST_AUTH_PASSWORD_IN, ri, r, password, + IDBM_MASKED, num, 1); + __recinfo_int(HOST_AUTH_PASSWORD_IN_LEN, ri, r, password_length, +@@ -469,6 +670,158 @@ static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri) + } + } + ++void idbm_recinfo_flashnode(struct flashnode_rec *r, recinfo_t *ri) ++{ ++ int num = 0; ++ int i; ++ ++ __recinfo_uint8(FLASHNODE_SESS_AUTO_SND_TGT_DISABLE, ri, r, ++ sess.auto_snd_tgt_disable, IDBM_SHOW, num, 1); ++ __recinfo_uint8(FLASHNODE_SESS_DISCOVERY_SESS, ri, r, ++ sess.discovery_session, IDBM_SHOW, num, 1); ++ __recinfo_str(FLASHNODE_SESS_PORTAL_TYPE, ri, r, sess.portal_type, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint8(FLASHNODE_SESS_ENTRY_EN, ri, r, ++ sess.entry_enable, IDBM_SHOW, num, 1); ++ __recinfo_uint8(FLASHNODE_SESS_IMM_DATA_EN, ri, r, sess.immediate_data, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint8(FLASHNODE_SESS_INITIAL_R2T_EN, ri, r, sess.initial_r2t, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint8(FLASHNODE_SESS_DATASEQ_INORDER, ri, r, ++ sess.data_seq_in_order, IDBM_SHOW, num, 1); ++ __recinfo_uint8(FLASHNODE_SESS_PDU_INORDER, ri, r, ++ sess.data_pdu_in_order, IDBM_SHOW, num, 1); ++ __recinfo_uint8(FLASHNODE_SESS_CHAP_AUTH_EN, ri, r, sess.chap_auth_en, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint8(FLASHNODE_SESS_DISCOVERY_LOGOUT_EN, ri, r, ++ sess.discovery_logout_en, IDBM_SHOW, num, 1); ++ __recinfo_uint8(FLASHNODE_SESS_BIDI_CHAP_EN, ri, r, sess.bidi_chap_en, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint8(FLASHNODE_SESS_DISCOVERY_AUTH_OPTIONAL, ri, r, ++ sess.discovery_auth_optional, IDBM_SHOW, num, 1); ++ __recinfo_uint8(FLASHNODE_SESS_ERL, ri, r, sess.erl, IDBM_SHOW, num, 1); ++ __recinfo_uint32(FLASHNODE_SESS_FIRST_BURST, ri, r, ++ sess.first_burst_len, IDBM_SHOW, num, 1); ++ __recinfo_uint16(FLASHNODE_SESS_DEF_TIME2WAIT, ri, r, ++ sess.def_time2wait, IDBM_SHOW, num, 1); ++ __recinfo_uint16(FLASHNODE_SESS_DEF_TIME2RETAIN, ri, r, ++ sess.def_time2retain, IDBM_SHOW, num, 1); ++ __recinfo_uint16(FLASHNODE_SESS_MAX_R2T, ri, r, ++ sess.max_outstanding_r2t, IDBM_SHOW, num, 1); ++ __recinfo_str(FLASHNODE_SESS_ISID, ri, r, sess.isid, IDBM_SHOW, num, 1); ++ __recinfo_uint16(FLASHNODE_SESS_TSID, ri, r, sess.tsid, IDBM_SHOW, ++ num, 1); ++ __recinfo_uint32(FLASHNODE_SESS_MAX_BURST, ri, r, sess.max_burst_len, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint16(FLASHNODE_SESS_DEF_TASKMGMT_TMO, ri, r, ++ sess.def_taskmgmt_tmo, IDBM_SHOW, num, 1); ++ __recinfo_str(FLASHNODE_SESS_ALIAS, ri, r, sess.targetalias, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(FLASHNODE_SESS_NAME, ri, r, sess.targetname, IDBM_SHOW, ++ num, 1); ++ __recinfo_uint16(FLASHNODE_SESS_DISCOVERY_PARENT_IDX, ri, r, ++ sess.discovery_parent_idx, IDBM_SHOW, num, 1); ++ __recinfo_str(FLASHNODE_SESS_DISCOVERY_PARENT_TYPE, ri, r, ++ sess.discovery_parent_type, IDBM_SHOW, num, 1); ++ __recinfo_uint16(FLASHNODE_SESS_TPGT, ri, r, sess.tpgt, IDBM_SHOW, ++ num, 1); ++ __recinfo_uint16(FLASHNODE_SESS_CHAP_OUT_IDX, ri, r, sess.chap_out_idx, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint16(FLASHNODE_SESS_CHAP_IN_IDX, ri, r, sess.chap_in_idx, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(FLASHNODE_SESS_USERNAME, ri, r, sess.username, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(FLASHNODE_SESS_USERNAME_IN, ri, r, sess.username_in, ++ IDBM_SHOW, num, 1); ++ __recinfo_str(FLASHNODE_SESS_PASSWORD, ri, r, sess.password, IDBM_SHOW, ++ num, 1); ++ __recinfo_str(FLASHNODE_SESS_PASSWORD_IN, ri, r, sess.password_in, ++ IDBM_SHOW, num, 1); ++ __recinfo_uint8(FLASHNODE_SESS_IS_BOOT_TGT, ri, r, sess.is_boot_target, ++ IDBM_SHOW, num, 1); ++ ++ for (i = 0; i < ISCSI_CONN_MAX; i++) { ++ char key[NAME_MAXVAL]; ++ ++ sprintf(key, FLASHNODE_CONN_IS_FW_ASSIGNED_IPV6, i); ++ __recinfo_uint8(key, ri, r, conn[i].is_fw_assigned_ipv6, ++ IDBM_SHOW, num, 1); ++ sprintf(key, FLASHNODE_CONN_HDR_DGST_EN, i); ++ __recinfo_uint8(key, ri, r, conn[i].header_digest_en, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_DATA_DGST_EN, i); ++ __recinfo_uint8(key, ri, r, conn[i].data_digest_en, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_SNACK_REQ_EN, i); ++ __recinfo_uint8(key, ri, r, conn[i].snack_req_en, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_TCP_TIMESTAMP_STAT, i); ++ __recinfo_uint8(key, ri, r, conn[i].tcp_timestamp_stat, ++ IDBM_SHOW, num, 1); ++ sprintf(key, FLASHNODE_CONN_TCP_NAGLE_DISABLE, i); ++ __recinfo_uint8(key, ri, r, conn[i].tcp_nagle_disable, ++ IDBM_SHOW, num, 1); ++ sprintf(key, FLASHNODE_CONN_TCP_WSF_DISABLE, i); ++ __recinfo_uint8(key, ri, r, conn[i].tcp_wsf_disable, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_TCP_TIMER_SCALE, i); ++ __recinfo_uint8(key, ri, r, conn[i].tcp_timer_scale, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_TCP_TIMESTAMP_EN, i); ++ __recinfo_uint8(key, ri, r, conn[i].tcp_timestamp_en, ++ IDBM_SHOW, num, 1); ++ sprintf(key, FLASHNODE_CONN_IP_FRAG_DISABLE, i); ++ __recinfo_uint8(key, ri, r, conn[i].fragment_disable, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_MAX_XMIT_DLENGTH, i); ++ __recinfo_uint32(key, ri, r, conn[i].max_xmit_dlength, ++ IDBM_SHOW, num, 1); ++ sprintf(key, FLASHNODE_CONN_MAX_RECV_DLENGTH, i); ++ __recinfo_uint32(key, ri, r, conn[i].max_recv_dlength, ++ IDBM_SHOW, num, 1); ++ sprintf(key, FLASHNODE_CONN_KEEPALIVE_TMO, i); ++ __recinfo_uint16(key, ri, r, conn[i].keepalive_tmo, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_PORT, i); ++ __recinfo_uint16(key, ri, r, conn[i].port, IDBM_SHOW, num, 1); ++ sprintf(key, FLASHNODE_CONN_IPADDR, i); ++ __recinfo_str(key, ri, r, conn[i].ipaddress, IDBM_SHOW, num, 1); ++ sprintf(key, FLASHNODE_CONN_REDIRECT_IPADDR, i); ++ __recinfo_str(key, ri, r, conn[i].redirect_ipaddr, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_MAX_SEGMENT_SIZE, i); ++ __recinfo_uint32(key, ri, r, conn[i].max_segment_size, ++ IDBM_SHOW, num, 1); ++ sprintf(key, FLASHNODE_CONN_LOCAL_PORT, i); ++ __recinfo_uint16(key, ri, r, conn[i].local_port, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_IPV4_TOS, i); ++ __recinfo_uint8(key, ri, r, conn[i].ipv4_tos, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_IPV6_TC, i); ++ __recinfo_uint8(key, ri, r, conn[i].ipv6_traffic_class, ++ IDBM_SHOW, num, 1); ++ sprintf(key, FLASHNODE_CONN_IPV6_FLOW_LABEL, i); ++ __recinfo_uint16(key, ri, r, conn[i].ipv6_flow_lbl, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_LINK_LOCAL_IPV6, i); ++ __recinfo_str(key, ri, r, conn[i].link_local_ipv6, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_TCP_XMIT_WSF, i); ++ __recinfo_uint32(key, ri, r, conn[i].tcp_xmit_wsf, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_TCP_RECV_WSF, i); ++ __recinfo_uint32(key, ri, r, conn[i].tcp_recv_wsf, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_STATSN, i); ++ __recinfo_uint32(key, ri, r, conn[i].stat_sn, IDBM_SHOW, ++ num, 1); ++ sprintf(key, FLASHNODE_CONN_EXP_STATSN, i); ++ __recinfo_uint32(key, ri, r, conn[i].exp_stat_sn, IDBM_SHOW, ++ num, 1); ++ } ++} ++ + recinfo_t *idbm_recinfo_alloc(int max_keys) + { + recinfo_t *info; +@@ -502,6 +855,9 @@ void idbm_print(int type, void *rec, int show, FILE *f) + case IDBM_PRINT_TYPE_HOST_CHAP: + idbm_recinfo_host_chap((struct iscsi_chap_rec *)rec, info); + break; ++ case IDBM_PRINT_TYPE_FLASHNODE: ++ idbm_recinfo_flashnode((struct flashnode_rec *)rec, info); ++ break; + } + + fprintf(f, "%s\n", ISCSI_BEGIN_REC); +@@ -629,6 +985,13 @@ setup_passwd_len: + *(uint16_t *)info[i].data = + strtoul(value, NULL, 10); + goto updated; ++ } else if (info[i].type == TYPE_UINT32) { ++ if (!info[i].data) ++ continue; ++ ++ *(uint32_t *)info[i].data = ++ strtoul(value, NULL, 10); ++ goto updated; + } else if (info[i].type == TYPE_STR) { + if (!info[i].data) + continue; +@@ -679,6 +1042,8 @@ updated: + check_password_param(discovery.sendtargets.auth.password_in); + check_password_param(discovery.slp.auth.password); + check_password_param(discovery.slp.auth.password_in); ++ check_password_param(host.auth.password); ++ check_password_param(host.auth.password_in); + + return 0; + } +@@ -694,7 +1059,7 @@ int idbm_verify_param(recinfo_t *info, char *name) + if (strcmp(name, info[i].name)) + continue; + +- log_debug(7, "verify %s %d\n", name, info[i].can_modify); ++ log_debug(7, "verify %s %d", name, info[i].can_modify); + if (info[i].can_modify) + return 0; + else { +@@ -797,20 +1162,20 @@ static void idbm_sync_config(void) + idbm_recinfo_node(&db->nrec, db->ninfo); + + if (!db->get_config_file) { +- log_debug(1, "Could not get config file. No config file fn\n"); ++ log_debug(1, "Could not get config file. No config file fn"); + return; + } + + config_file = db->get_config_file(); + if (!config_file) { +- log_debug(1, "Could not get config file for sync config\n"); ++ log_debug(1, "Could not get config file for sync config"); + return; + } + + f = fopen(config_file, "r"); + if (!f) { + log_debug(1, "cannot open configuration file %s. " +- "Default location is %s.\n", ++ "Default location is %s.", + config_file, CONFIG_FILE); + return; + } +@@ -880,6 +1245,12 @@ int idbm_print_host_chap_info(struct iscsi_chap_rec *chap) + return 0; + } + ++int idbm_print_flashnode_info(struct flashnode_rec *fnode) ++{ ++ idbm_print(IDBM_PRINT_TYPE_FLASHNODE, fnode, 1, stdout); ++ return 0; ++} ++ + int idbm_print_node_flat(void *data, node_rec_t *rec) + { + if (strchr(rec->conn[0].address, '.')) +@@ -960,7 +1331,7 @@ int idbm_lock(void) + + if (access(LOCK_DIR, F_OK) != 0) { + if (mkdir(LOCK_DIR, 0660) != 0) { +- log_error("Could not open %s: %s\n", LOCK_DIR, ++ log_error("Could not open %s: %s", LOCK_DIR, + strerror(errno)); + return ISCSI_ERR_IDBM; + } +@@ -1040,7 +1411,7 @@ static int __idbm_rec_read(node_rec_t *out_rec, char *conf) + + f = fopen(conf, "r"); + if (!f) { +- log_debug(5, "Could not open %s err %s\n", conf, ++ log_debug(5, "Could not open %s err %s", conf, + strerror(errno)); + rc = ISCSI_ERR_IDBM; + goto unlock; +@@ -1182,7 +1553,7 @@ static int idbm_for_each_drec(int type, char *config_root, void *data, + !strcmp(entity_dent->d_name, "..")) + continue; + +- log_debug(5, "found %s\n", entity_dent->d_name); ++ log_debug(5, "found %s", entity_dent->d_name); + + tmp_port = strchr(entity_dent->d_name, ','); + if (!tmp_port) +@@ -1439,7 +1810,7 @@ int idbm_for_each_portal(int *found, void *data, idbm_portal_op_fn *fn, + !strcmp(portal_dent->d_name, "..")) + continue; + +- log_debug(5, "found %s\n", portal_dent->d_name); ++ log_debug(5, "found %s", portal_dent->d_name); + tmp_port = strchr(portal_dent->d_name, ','); + if (!tmp_port) + continue; +@@ -1481,7 +1852,7 @@ int idbm_for_each_node(int *found, void *data, idbm_node_op_fn *fn) + !strcmp(node_dent->d_name, "..")) + continue; + +- log_debug(5, "searching %s\n", node_dent->d_name); ++ log_debug(5, "searching %s", node_dent->d_name); + curr_rc = fn(found, data, node_dent->d_name); + /* less than zero means it was not a match */ + if (curr_rc > 0 && !rc) +@@ -1557,7 +1928,7 @@ idbm_discovery_read(discovery_rec_t *out_rec, int drec_type, + snprintf(portal, PATH_MAX, "%s/%s,%d", + disc_type_to_config_vals[drec_type].config_root, + addr, port); +- log_debug(5, "Looking for config file %s\n", portal); ++ log_debug(5, "Looking for config file %s", portal); + + rc = idbm_lock(); + if (rc) +@@ -1566,7 +1937,7 @@ idbm_discovery_read(discovery_rec_t *out_rec, int drec_type, + f = idbm_open_rec_r(portal, + disc_type_to_config_vals[drec_type].config_name); + if (!f) { +- log_debug(1, "Could not open %s: %s\n", portal, ++ log_debug(1, "Could not open %s: %s", portal, + strerror(errno)); + rc = ISCSI_ERR_IDBM; + goto unlock; +@@ -1596,7 +1967,7 @@ static FILE *idbm_open_rec_w(char *portal, char *config) + FILE *f; + int err; + +- log_debug(5, "Looking for config file %s\n", portal); ++ log_debug(5, "Looking for config file %s", portal); + + err = stat(portal, &statb); + if (err) +@@ -1608,14 +1979,14 @@ static FILE *idbm_open_rec_w(char *portal, char *config) + */ + if (unlink(portal)) { + log_error("Could not convert %s to %s/%s. " +- "err %d\n", portal, portal, ++ "err %d", portal, portal, + config, errno); + return NULL; + } + + mkdir_portal: + if (mkdir(portal, 0660) != 0) { +- log_error("Could not make dir %s err %d\n", ++ log_error("Could not make dir %s err %d", + portal, errno); + return NULL; + } +@@ -1625,7 +1996,7 @@ mkdir_portal: + strlcat(portal, config, PATH_MAX); + f = fopen(portal, "w"); + if (!f) +- log_error("Could not open %s err %d\n", portal, errno); ++ log_error("Could not open %s err %d", portal, errno); + return f; + } + +@@ -1638,14 +2009,14 @@ static int idbm_rec_write(node_rec_t *rec) + + portal = malloc(PATH_MAX); + if (!portal) { +- log_error("Could not alloc portal\n"); ++ log_error("Could not alloc portal"); + return ISCSI_ERR_NOMEM; + } + + snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR); + if (access(portal, F_OK) != 0) { + if (mkdir(portal, 0660) != 0) { +- log_error("Could not make %s: %s\n", portal, ++ log_error("Could not make %s: %s", portal, + strerror(errno)); + rc = ISCSI_ERR_IDBM; + goto free_portal; +@@ -1655,7 +2026,7 @@ static int idbm_rec_write(node_rec_t *rec) + snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name); + if (access(portal, F_OK) != 0) { + if (mkdir(portal, 0660) != 0) { +- log_error("Could not make %s: %s\n", portal, ++ log_error("Could not make %s: %s", portal, + strerror(errno)); + rc = ISCSI_ERR_IDBM; + goto free_portal; +@@ -1698,7 +2069,7 @@ static int idbm_rec_write(node_rec_t *rec) + * Old style portal as a file, but with tpgt. Let's update it. + */ + if (unlink(portal)) { +- log_error("Could not convert %s: %s\n", portal, ++ log_error("Could not convert %s: %s", portal, + strerror(errno)); + rc = ISCSI_ERR_IDBM; + goto unlock; +@@ -1713,7 +2084,7 @@ mkdir_portal: + rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt); + if (stat(portal, &statb)) { + if (mkdir(portal, 0660) != 0) { +- log_error("Could not make dir %s: %s\n", ++ log_error("Could not make dir %s: %s", + portal, strerror(errno)); + rc = ISCSI_ERR_IDBM; + goto unlock; +@@ -1726,7 +2097,7 @@ mkdir_portal: + open_conf: + f = fopen(portal, "w"); + if (!f) { +- log_error("Could not open %s: %sd\n", portal, strerror(errno)); ++ log_error("Could not open %s: %s", portal, strerror(errno)); + rc = ISCSI_ERR_IDBM; + goto unlock; + } +@@ -1752,7 +2123,7 @@ idbm_discovery_write(discovery_rec_t *rec) + + portal = malloc(PATH_MAX); + if (!portal) { +- log_error("Could not alloc portal\n"); ++ log_error("Could not alloc portal"); + return ISCSI_ERR_NOMEM; + } + +@@ -1764,7 +2135,7 @@ idbm_discovery_write(discovery_rec_t *rec) + disc_type_to_config_vals[rec->type].config_root); + if (access(portal, F_OK) != 0) { + if (mkdir(portal, 0660) != 0) { +- log_error("Could not make %s: %s\n", portal, ++ log_error("Could not make %s: %s", portal, + strerror(errno)); + rc = ISCSI_ERR_IDBM; + goto unlock; +@@ -1778,7 +2149,7 @@ idbm_discovery_write(discovery_rec_t *rec) + f = idbm_open_rec_w(portal, + disc_type_to_config_vals[rec->type].config_name); + if (!f) { +- log_error("Could not open %s: %s\n", portal, strerror(errno)); ++ log_error("Could not open %s: %s", portal, strerror(errno)); + rc = ISCSI_ERR_IDBM; + goto unlock; + } +@@ -2150,10 +2521,10 @@ int idbm_delete_discovery(discovery_rec_t *drec) + snprintf(portal, PATH_MAX, "%s/%s,%d", + disc_type_to_config_vals[drec->type].config_root, + drec->address, drec->port); +- log_debug(5, "Removing config file %s\n", portal); ++ log_debug(5, "Removing config file %s", portal); + + if (stat(portal, &statb)) { +- log_debug(5, "Could not stat %s to delete disc err %d\n", ++ log_debug(5, "Could not stat %s to delete disc err %d", + portal, errno); + goto free_portal; + } +@@ -2166,7 +2537,7 @@ int idbm_delete_discovery(discovery_rec_t *drec) + } + + if (unlink(portal)) +- log_debug(5, "Could not remove %s err %d\n", portal, errno); ++ log_debug(5, "Could not remove %s err %d", portal, errno); + + memset(portal, 0, PATH_MAX); + snprintf(portal, PATH_MAX, "%s/%s,%d", +@@ -2216,7 +2587,7 @@ static int idbm_remove_disc_to_node_link(node_rec_t *rec, + goto done; + } + +- log_debug(7, "found drec %s %d\n", ++ log_debug(7, "found drec %s %d", + tmprec->disc_address, tmprec->disc_port); + /* rm link from discovery source to node */ + memset(portal, 0, PATH_MAX); +@@ -2230,7 +2601,7 @@ static int idbm_remove_disc_to_node_link(node_rec_t *rec, + + if (!stat(portal, &statb)) { + if (unlink(portal)) { +- log_error("Could not remove link %s: %s\n", ++ log_error("Could not remove link %s: %s", + portal, strerror(errno)); + rc = ISCSI_ERR_IDBM; + } else +@@ -2267,7 +2638,7 @@ int idbm_delete_node(node_rec_t *rec) + memset(portal, 0, PATH_MAX); + snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR, + rec->name, rec->conn[0].address, rec->conn[0].port); +- log_debug(5, "Removing config file %s iface id %s\n", ++ log_debug(5, "Removing config file %s iface id %s", + portal, rec->iface.name); + + rc = idbm_lock(); +@@ -2285,14 +2656,14 @@ int idbm_delete_node(node_rec_t *rec) + if (!stat(portal, &statb)) + goto rm_conf; + +- log_error("Could not stat %s to delete node: %s\n", ++ log_error("Could not stat %s to delete node: %s", + portal, strerror(errno)); + rc = ISCSI_ERR_IDBM; + goto unlock; + + rm_conf: + if (unlink(portal)) { +- log_error("Could not remove %s: %s\n", portal, strerror(errno)); ++ log_error("Could not remove %s: %s", portal, strerror(errno)); + rc = ISCSI_ERR_IDBM; + goto unlock; + } +@@ -2470,7 +2841,7 @@ int idbm_init(idbm_get_config_file_fn *fn) + /* make sure root db dir is there */ + if (access(ISCSI_CONFIG_ROOT, F_OK) != 0) { + if (mkdir(ISCSI_CONFIG_ROOT, 0660) != 0) { +- log_error("Could not make %s %d\n", ISCSI_CONFIG_ROOT, ++ log_error("Could not make %s %d", ISCSI_CONFIG_ROOT, + errno); + return errno; + } +@@ -2569,6 +2940,12 @@ struct node_rec *idbm_create_rec_from_boot_context(struct boot_context *context) + strlen((char *)context->chap_password); + rec->session.auth.password_in_length = + strlen((char *)context->chap_password_in); ++ strlcpy(rec->session.boot_root, context->boot_root, ++ sizeof(context->boot_root)); ++ strlcpy(rec->session.boot_nic, context->boot_nic, ++ sizeof(context->boot_nic)); ++ strlcpy(rec->session.boot_target, context->boot_target, ++ sizeof(context->boot_target)); + + iface_setup_from_boot_context(&rec->iface, context); + +diff --git a/usr/idbm.h b/usr/idbm.h +index 245f046..b9020fe 100644 +--- a/usr/idbm.h ++++ b/usr/idbm.h +@@ -27,6 +27,7 @@ + #include "initiator.h" + #include "config.h" + #include "list.h" ++#include "flashnode.h" + + #define NODE_CONFIG_DIR ISCSI_CONFIG_ROOT"nodes" + #define SLP_CONFIG_DIR ISCSI_CONFIG_ROOT"slp" +@@ -42,6 +43,7 @@ + #define TYPE_STR 2 + #define TYPE_UINT8 3 + #define TYPE_UINT16 4 ++#define TYPE_UINT32 5 + #define MAX_KEYS 256 /* number of keys total(including CNX_MAX) */ + #define NAME_MAXVAL 128 /* the maximum length of key name */ + #define VALUE_MAXVAL 256 /* the maximum length of 223 bytes in the RFC. */ +@@ -85,6 +87,7 @@ struct user_param { + struct list_head list; + char *name; + char *value; ++ int param; + }; + + typedef int (idbm_iface_op_fn)(void *data, node_rec_t *rec); +@@ -168,6 +171,7 @@ enum { + IDBM_PRINT_TYPE_NODE, + IDBM_PRINT_TYPE_IFACE, + IDBM_PRINT_TYPE_HOST_CHAP, ++ IDBM_PRINT_TYPE_FLASHNODE + }; + + extern void idbm_print(int type, void *rec, int show, FILE *f); +@@ -181,5 +185,9 @@ extern struct node_rec * + idbm_create_rec_from_boot_context(struct boot_context *context); + + extern int idbm_print_host_chap_info(struct iscsi_chap_rec *chap); ++extern void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri); ++ ++extern int idbm_print_flashnode_info(struct flashnode_rec *target); ++extern void idbm_recinfo_flashnode(struct flashnode_rec *r, recinfo_t *ri); + + #endif /* IDBM_H */ +diff --git a/usr/idbm_fields.h b/usr/idbm_fields.h +index 358d014..5790a03 100644 +--- a/usr/idbm_fields.h ++++ b/usr/idbm_fields.h +@@ -89,6 +89,55 @@ + #define IFACE_NUM "iface.iface_num" + #define IFACE_MTU "iface.mtu" + #define IFACE_PORT "iface.port" ++#define IFACE_DELAYED_ACK "iface.delayed_ack" ++#define IFACE_TCP_NAGLE "iface.tcp_nagle" ++#define IFACE_TCP_WSF_STATE "iface.tcp_wsf_state" ++#define IFACE_TCP_WSF "iface.tcp_wsf" ++#define IFACE_TCP_TIMER_SCALE "iface.tcp_timer_scale" ++#define IFACE_TCP_TIMESTAMP "iface.tcp_timestamp" ++#define IFACE_DHCP_DNS "iface.dhcp_dns" ++#define IFACE_DHCP_SLP_DA "iface.dhcp_slp_da" ++#define IFACE_TOS_STATE "iface.tos_state" ++#define IFACE_TOS "iface.tos" ++#define IFACE_GRAT_ARP "iface.gratuitous_arp" ++#define IFACE_DHCP_ALT_CID "iface.dhcp_alt_client_id_state" ++#define IFACE_DHCP_ALT_CID_STR "iface.dhcp_alt_client_id" ++#define IFACE_DHCP_REQ_VID "iface.dhcp_req_vendor_id_state" ++#define IFACE_DHCP_VID "iface.dhcp_vendor_id_state" ++#define IFACE_DHCP_VID_STR "iface.dhcp_vendor_id" ++#define IFACE_DHCP_LEARN_IQN "iface.dhcp_learn_iqn" ++#define IFACE_FRAGMENTATION "iface.fragmentation" ++#define IFACE_IN_FORWARD "iface.incoming_forwarding" ++#define IFACE_TTL "iface.ttl" ++#define IFACE_GRAT_NEIGHBOR_ADV "iface.gratuitous_neighbor_adv" ++#define IFACE_REDIRECT "iface.redirect" ++#define IFACE_IGNORE_ICMP_ECHO_REQ "iface.ignore_icmp_echo_request" ++#define IFACE_MLD "iface.mld" ++#define IFACE_FLOW_LABEL "iface.flow_label" ++#define IFACE_TRAFFIC_CLASS "iface.traffic_class" ++#define IFACE_HOP_LIMIT "iface.hop_limit" ++#define IFACE_ND_REACHABLE_TMO "iface.nd_reachable_tmo" ++#define IFACE_ND_REXMIT_TIME "iface.nd_rexmit_time" ++#define IFACE_ND_STALE_TMO "iface.nd_stale_tmo" ++#define IFACE_DUP_ADDR_DETECT_CNT "iface.dup_addr_detect_cnt" ++#define IFACE_RTR_ADV_LINK_MTU "iface.router_adv_link_mtu" ++#define IFACE_DEF_TMF_TMO "iface.def_task_mgmt_timeout" ++#define IFACE_HDRDGST "iface.header_digest" ++#define IFACE_DATADGST "iface.data_digest" ++#define IFACE_IMM_DATA "iface.immediate_data" ++#define IFACE_INITIAL_R2T "iface.initial_r2t" ++#define IFACE_DSEQ_INORDER "iface.data_seq_inorder" ++#define IFACE_DPDU_INORDER "iface.data_pdu_inorder" ++#define IFACE_ERL "iface.erl" ++#define IFACE_MAX_RECV_DLEN "iface.max_receive_data_len" ++#define IFACE_FIRST_BURST "iface.first_burst_len" ++#define IFACE_MAX_R2T "iface.max_outstanding_r2t" ++#define IFACE_MAX_BURST "iface.max_burst_len" ++#define IFACE_CHAP_AUTH "iface.chap_auth" ++#define IFACE_BIDI_CHAP "iface.bidi_chap" ++#define IFACE_STRICT_LOGIN_COMP "iface.strict_login_compliance" ++#define IFACE_DISCOVERY_AUTH "iface.discovery_auth" ++#define IFACE_DISCOVERY_LOGOUT "iface.discovery_logout" + + /* discovery fields */ + #define DISC_STARTUP "discovery.startup" +@@ -126,4 +175,67 @@ + #define HOST_AUTH_PASSWORD_IN "host.auth.password_in" + #define HOST_AUTH_PASSWORD_IN_LEN "host.auth.password_in_length" + ++/* flash target session fields */ ++#define FLASHNODE_SESS_AUTO_SND_TGT_DISABLE "flashnode.session.auto_snd_tgt_disable" ++#define FLASHNODE_SESS_DISCOVERY_SESS "flashnode.session.discovery_session" ++#define FLASHNODE_SESS_PORTAL_TYPE "flashnode.session.portal_type" ++#define FLASHNODE_SESS_ENTRY_EN "flashnode.session.entry_enable" ++#define FLASHNODE_SESS_IMM_DATA_EN "flashnode.session.immediate_data" ++#define FLASHNODE_SESS_INITIAL_R2T_EN "flashnode.session.initial_r2t" ++#define FLASHNODE_SESS_DATASEQ_INORDER "flashnode.session.data_seq_in_order" ++#define FLASHNODE_SESS_PDU_INORDER "flashnode.session.data_pdu_in_order" ++#define FLASHNODE_SESS_CHAP_AUTH_EN "flashnode.session.chap_auth_en" ++#define FLASHNODE_SESS_DISCOVERY_LOGOUT_EN "flashnode.session.discovery_logout_en" ++#define FLASHNODE_SESS_BIDI_CHAP_EN "flashnode.session.bidi_chap_en" ++#define FLASHNODE_SESS_DISCOVERY_AUTH_OPTIONAL "flashnode.session.discovery_auth_optional" ++#define FLASHNODE_SESS_ERL "flashnode.session.erl" ++#define FLASHNODE_SESS_FIRST_BURST "flashnode.session.first_burst_len" ++#define FLASHNODE_SESS_DEF_TIME2WAIT "flashnode.session.def_time2wait" ++#define FLASHNODE_SESS_DEF_TIME2RETAIN "flashnode.session.def_time2retain" ++#define FLASHNODE_SESS_MAX_R2T "flashnode.session.max_outstanding_r2t" ++#define FLASHNODE_SESS_ISID "flashnode.session.isid" ++#define FLASHNODE_SESS_TSID "flashnode.session.tsid" ++#define FLASHNODE_SESS_MAX_BURST "flashnode.session.max_burst_len" ++#define FLASHNODE_SESS_DEF_TASKMGMT_TMO "flashnode.session.def_taskmgmt_tmo" ++#define FLASHNODE_SESS_ALIAS "flashnode.session.targetalias" ++#define FLASHNODE_SESS_NAME "flashnode.session.targetname" ++#define FLASHNODE_SESS_TPGT "flashnode.session.tpgt" ++#define FLASHNODE_SESS_DISCOVERY_PARENT_IDX "flashnode.session.discovery_parent_idx" ++#define FLASHNODE_SESS_DISCOVERY_PARENT_TYPE "flashnode.session.discovery_parent_type" ++#define FLASHNODE_SESS_CHAP_OUT_IDX "flashnode.session.chap_out_idx" ++#define FLASHNODE_SESS_CHAP_IN_IDX "flashnode.session.chap_in_idx" ++#define FLASHNODE_SESS_USERNAME "flashnode.session.username" ++#define FLASHNODE_SESS_USERNAME_IN "flashnode.session.username_in" ++#define FLASHNODE_SESS_PASSWORD "flashnode.session.password" ++#define FLASHNODE_SESS_PASSWORD_IN "flashnode.session.password_in" ++#define FLASHNODE_SESS_IS_BOOT_TGT "flashnode.session.is_boot_target" ++ ++/* flash target connection fields */ ++#define FLASHNODE_CONN_IS_FW_ASSIGNED_IPV6 "flashnode.conn[%d].is_fw_assigned_ipv6" ++#define FLASHNODE_CONN_HDR_DGST_EN "flashnode.conn[%d].header_digest_en" ++#define FLASHNODE_CONN_DATA_DGST_EN "flashnode.conn[%d].data_digest_en" ++#define FLASHNODE_CONN_SNACK_REQ_EN "flashnode.conn[%d].snack_req_en" ++#define FLASHNODE_CONN_TCP_TIMESTAMP_STAT "flashnode.conn[%d].tcp_timestamp_stat" ++#define FLASHNODE_CONN_TCP_NAGLE_DISABLE "flashnode.conn[%d].tcp_nagle_disable" ++#define FLASHNODE_CONN_TCP_WSF_DISABLE "flashnode.conn[%d].tcp_wsf_disable" ++#define FLASHNODE_CONN_TCP_TIMER_SCALE "flashnode.conn[%d].tcp_timer_scale" ++#define FLASHNODE_CONN_TCP_TIMESTAMP_EN "flashnode.conn[%d].tcp_timestamp_en" ++#define FLASHNODE_CONN_IP_FRAG_DISABLE "flashnode.conn[%d].fragment_disable" ++#define FLASHNODE_CONN_MAX_RECV_DLENGTH "flashnode.conn[%d].max_recv_dlength" ++#define FLASHNODE_CONN_MAX_XMIT_DLENGTH "flashnode.conn[%d].max_xmit_dlength" ++#define FLASHNODE_CONN_KEEPALIVE_TMO "flashnode.conn[%d].keepalive_tmo" ++#define FLASHNODE_CONN_PORT "flashnode.conn[%d].port" ++#define FLASHNODE_CONN_IPADDR "flashnode.conn[%d].ipaddress" ++#define FLASHNODE_CONN_REDIRECT_IPADDR "flashnode.conn[%d].redirect_ipaddr" ++#define FLASHNODE_CONN_MAX_SEGMENT_SIZE "flashnode.conn[%d].max_segment_size" ++#define FLASHNODE_CONN_LOCAL_PORT "flashnode.conn[%d].local_port" ++#define FLASHNODE_CONN_IPV4_TOS "flashnode.conn[%d].ipv4_tos" ++#define FLASHNODE_CONN_IPV6_TC "flashnode.conn[%d].ipv6_traffic_class" ++#define FLASHNODE_CONN_IPV6_FLOW_LABEL "flashnode.conn[%d].ipv6_flow_label" ++#define FLASHNODE_CONN_LINK_LOCAL_IPV6 "flashnode.conn[%d].link_local_ipv6" ++#define FLASHNODE_CONN_TCP_XMIT_WSF "flashnode.conn[%d].tcp_xmit_wsf" ++#define FLASHNODE_CONN_TCP_RECV_WSF "flashnode.conn[%d].tcp_recv_wsf" ++#define FLASHNODE_CONN_STATSN "flashnode.conn[%d].statsn" ++#define FLASHNODE_CONN_EXP_STATSN "flashnode.conn[%d].exp_statsn" ++ + #endif +diff --git a/usr/iface.c b/usr/iface.c +index 3a9582e..0a7f0bb 100644 +--- a/usr/iface.c ++++ b/usr/iface.c +@@ -227,7 +227,7 @@ int iface_conf_delete(struct iface_rec *iface) + def_iface = iface_match_default(iface); + if (def_iface) { + log_error("iface %s is a special interface and " +- "cannot be deleted.\n", iface->name); ++ "cannot be deleted.", iface->name); + return ISCSI_ERR_INVAL; + } + +@@ -259,7 +259,7 @@ int iface_conf_write(struct iface_rec *iface) + def_iface = iface_match_default(iface); + if (def_iface) { + log_error("iface %s is a special interface and " +- "is not stored in %s.\n", iface->name, ++ "is not stored in %s.", iface->name, + IFACE_CONFIG_DIR); + return ISCSI_ERR_INVAL; + } +@@ -299,7 +299,7 @@ int iface_conf_update(struct list_head *params, struct iface_rec *iface) + def_iface = iface_match_default(iface); + if (def_iface) { + log_error("iface %s is a special interface and " +- "cannot be modified.\n", iface->name); ++ "cannot be modified.", iface->name); + return ISCSI_ERR_INVAL; + } + +@@ -450,8 +450,10 @@ int iface_get_iptype(struct iface_rec *iface) + /* try to figure out by name */ + if (strstr(iface->name, "ipv4")) + return ISCSI_IFACE_TYPE_IPV4; +- else ++ else if (strstr(iface->name, "ipv6")) + return ISCSI_IFACE_TYPE_IPV6; ++ else /* assume ipv4 by default */ ++ return ISCSI_IFACE_TYPE_IPV4; + } else { + if (strcmp(iface->bootproto, "dhcp") && + !strstr(iface->ipaddress, ".")) +@@ -470,17 +472,14 @@ static int iface_setup_binding_from_kern_iface(void *data, + + if (!strlen(hinfo->iface.hwaddress)) { + log_error("Invalid offload iSCSI host %u. Missing " +- "hwaddress. Try upgrading %s driver.\n", ++ "hwaddress. Try upgrading %s driver.", + hinfo->host_no, hinfo->iface.transport_name); + return 0; + } + + memset(&iface, 0, sizeof(struct iface_rec)); +- strcpy(iface.hwaddress, hinfo->iface.hwaddress); +- strcpy(iface.transport_name, hinfo->iface.transport_name); +- + if (kern_iface) { +- iface.iface_num = kern_iface->iface_num; ++ memcpy(&iface, kern_iface, sizeof(iface)); + + snprintf(iface.name, sizeof(iface.name), "%s.%s.%s.%u", + kern_iface->transport_name, +@@ -492,6 +491,9 @@ static int iface_setup_binding_from_kern_iface(void *data, + hinfo->iface.transport_name, hinfo->iface.hwaddress); + } + ++ strcpy(iface.hwaddress, hinfo->iface.hwaddress); ++ strcpy(iface.transport_name, hinfo->iface.transport_name); ++ + memset(iface_path, 0, sizeof(iface_path)); + snprintf(iface_path, PATH_MAX, "%s/%s", IFACE_CONFIG_DIR, + iface.name); +@@ -601,6 +603,105 @@ void iface_copy(struct iface_rec *dst, struct iface_rec *src) + dst->mtu = src->mtu; + if (src->port) + dst->port = src->port; ++ if (strlen(src->delayed_ack)) ++ strcpy(dst->delayed_ack, src->delayed_ack); ++ if (strlen(src->nagle)) ++ strcpy(dst->nagle, src->nagle); ++ if (strlen(src->tcp_wsf_state)) ++ strcpy(dst->tcp_wsf_state, src->tcp_wsf_state); ++ if (src->tcp_wsf) ++ dst->tcp_wsf = src->tcp_wsf; ++ if (src->tcp_timer_scale) ++ dst->tcp_timer_scale = src->tcp_timer_scale; ++ if (strlen(src->tcp_timestamp)) ++ strcpy(dst->tcp_timestamp, src->tcp_timestamp); ++ if (strlen(src->dhcp_dns)) ++ strcpy(dst->dhcp_dns, src->dhcp_dns); ++ if (strlen(src->dhcp_slp_da)) ++ strcpy(dst->dhcp_slp_da, src->dhcp_slp_da); ++ if (strlen(src->tos_state)) ++ strcpy(dst->tos_state, src->tos_state); ++ if (src->tos) ++ dst->tos = src->tos; ++ if (strlen(src->gratuitous_arp)) ++ strcpy(dst->gratuitous_arp, src->gratuitous_arp); ++ if (strlen(src->dhcp_alt_client_id_state)) ++ strcpy(dst->dhcp_alt_client_id_state, ++ src->dhcp_alt_client_id_state); ++ if (strlen(src->dhcp_alt_client_id)) ++ strcpy(dst->dhcp_alt_client_id, src->dhcp_alt_client_id); ++ if (strlen(src->dhcp_req_vendor_id_state)) ++ strcpy(dst->dhcp_req_vendor_id_state, ++ src->dhcp_req_vendor_id_state); ++ if (strlen(src->dhcp_vendor_id_state)) ++ strcpy(dst->dhcp_vendor_id_state, src->dhcp_vendor_id_state); ++ if (strlen(src->dhcp_vendor_id)) ++ strcpy(dst->dhcp_vendor_id, src->dhcp_vendor_id); ++ if (strlen(src->dhcp_learn_iqn)) ++ strcpy(dst->dhcp_learn_iqn, src->dhcp_learn_iqn); ++ if (strlen(src->fragmentation)) ++ strcpy(dst->fragmentation, src->fragmentation); ++ if (strlen(src->incoming_forwarding)) ++ strcpy(dst->incoming_forwarding, src->incoming_forwarding); ++ if (src->ttl) ++ dst->ttl = src->ttl; ++ if (strlen(src->gratuitous_neighbor_adv)) ++ strcpy(dst->gratuitous_neighbor_adv, ++ src->gratuitous_neighbor_adv); ++ if (strlen(src->redirect)) ++ strcpy(dst->redirect, src->redirect); ++ if (strlen(src->mld)) ++ strcpy(dst->mld, src->mld); ++ if (src->flow_label) ++ dst->flow_label = src->flow_label; ++ if (src->traffic_class) ++ dst->traffic_class = src->traffic_class; ++ if (src->hop_limit) ++ dst->hop_limit = src->hop_limit; ++ if (src->nd_reachable_tmo) ++ dst->nd_reachable_tmo = src->nd_reachable_tmo; ++ if (src->nd_rexmit_time) ++ dst->nd_rexmit_time = src->nd_rexmit_time; ++ if (src->nd_stale_tmo) ++ dst->nd_stale_tmo = src->nd_stale_tmo; ++ if (src->dup_addr_detect_cnt) ++ dst->dup_addr_detect_cnt = src->dup_addr_detect_cnt; ++ if (src->router_adv_link_mtu) ++ dst->router_adv_link_mtu = src->router_adv_link_mtu; ++ if (src->def_task_mgmt_tmo) ++ dst->def_task_mgmt_tmo = src->def_task_mgmt_tmo; ++ if (strlen(src->header_digest)) ++ strcpy(dst->header_digest, src->header_digest); ++ if (strlen(src->data_digest)) ++ strcpy(dst->data_digest, src->data_digest); ++ if (strlen(src->immediate_data)) ++ strcpy(dst->immediate_data, src->immediate_data); ++ if (strlen(src->initial_r2t)) ++ strcpy(dst->initial_r2t, src->initial_r2t); ++ if (strlen(src->data_seq_inorder)) ++ strcpy(dst->data_seq_inorder, src->data_seq_inorder); ++ if (strlen(src->data_pdu_inorder)) ++ strcpy(dst->data_pdu_inorder, src->data_pdu_inorder); ++ if (src->erl) ++ dst->erl = src->erl; ++ if (src->max_recv_dlength) ++ dst->max_recv_dlength = src->max_recv_dlength; ++ if (src->first_burst_len) ++ dst->first_burst_len = src->first_burst_len; ++ if (src->max_out_r2t) ++ dst->max_out_r2t = src->max_out_r2t; ++ if (src->max_burst_len) ++ dst->max_burst_len = src->max_burst_len; ++ if (strlen(src->chap_auth)) ++ strcpy(dst->chap_auth, src->chap_auth); ++ if (strlen(src->bidi_chap)) ++ strcpy(dst->bidi_chap, src->bidi_chap); ++ if (strlen(src->strict_login_comp)) ++ strcpy(dst->strict_login_comp, src->strict_login_comp); ++ if (strlen(src->discovery_auth)) ++ strcpy(dst->discovery_auth, src->discovery_auth); ++ if (strlen(src->discovery_logout)) ++ strcpy(dst->discovery_logout, src->discovery_logout); + if (strlen(src->hwaddress)) + strcpy(dst->hwaddress, src->hwaddress); + if (strlen(src->transport_name)) +@@ -894,7 +995,6 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + struct boot_context *context) + { + struct iscsi_transport *t = NULL; +- char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN]; + uint32_t hostno; + + if (strlen(context->initiatorname)) +@@ -902,7 +1002,8 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + sizeof(iface->iname)); + + if (strlen(context->scsi_host_name)) { +- if (sscanf(context->scsi_host_name, "iscsi_boot%u", &hostno) != 1) { ++ if (sscanf(context->scsi_host_name, ++ "iscsi_boot%u", &hostno) != 1) { + log_error("Could not parse %s's host no.", + context->scsi_host_name); + return 0; +@@ -910,6 +1011,8 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + } else if (strlen(context->iface)) { + /* this ifdef is only temp until distros and firmwares are updated */ + #ifdef OFFLOAD_BOOT_SUPPORTED ++ char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN]; ++ int rc; + + memset(transport_name, 0, ISCSI_TRANSPORT_NAME_MAXLEN); + /* make sure offload driver is loaded */ +@@ -917,6 +1020,10 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + transport_name)) + t = iscsi_sysfs_get_transport_by_name(transport_name); + ++ if (net_ifup_netdev(context->iface)) ++ log_warning("Could not bring up netdev %s for boot", ++ context->iface); ++ + hostno = iscsi_sysfs_get_host_no_from_hwaddress(context->mac, + &rc); + if (rc) { +@@ -925,7 +1032,7 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + * host then the MAC must be for network card, so boot + * is not going to be offloaded. + */ +- log_debug(3, "Could not match %s to host\n", ++ log_debug(3, "Could not match %s to host", + context->mac); + return 0; + } +@@ -957,7 +1064,12 @@ int iface_setup_from_boot_context(struct iface_rec *iface, + sizeof(iface->hwaddress)); + strlcpy(iface->ipaddress, context->ipaddr, + sizeof(iface->ipaddress)); +- log_debug(1, "iface " iface_fmt "\n", iface_str(iface)); ++ iface->vlan_id = atoi(context->vlan); ++ strlcpy(iface->subnet_mask, context->mask, ++ sizeof(iface->subnet_mask)); ++ strlcpy(iface->gateway, context->gateway, ++ sizeof(iface->gateway)); ++ log_debug(1, "iface " iface_fmt "", iface_str(iface)); + return 1; + } + +@@ -982,7 +1094,7 @@ int iface_create_ifaces_from_boot_contexts(struct list_head *ifaces, + /* use dummy name. If valid it will get overwritten below */ + iface = iface_alloc(DEFAULT_IFACENAME, &rc); + if (!iface) { +- log_error("Could not setup iface %s for boot\n", ++ log_error("Could not setup iface %s for boot", + context->iface); + goto fail; + } +@@ -1016,6 +1128,79 @@ struct iface_param_count { + int count; + }; + ++#define IFACE_NET_PARAM_EN_CNT(param_val, cnt) { \ ++ if (!strcmp(param_val, "disable") || \ ++ !strcmp(param_val, "enable")) \ ++ (*cnt)++; \ ++} ++ ++/** ++ * iface_get_common_param_count - Gets common parameters count for given iface ++ * @iface: iface to setup ++ * @count: number of parameters to set ++ */ ++static void iface_get_common_param_count(struct iface_rec *iface, int *count) ++{ ++ if (strcmp(iface->vlan_state, "disable")) { ++ /* vlan_state enabled */ ++ (*count)++; ++ ++ if (iface->vlan_id) ++ /* For vlan value */ ++ (*count)++; ++ } else { ++ /* vlan_state disabled */ ++ (*count)++; ++ } ++ ++ if (iface->mtu) ++ (*count)++; ++ ++ if (iface->port) ++ (*count)++; ++ ++ IFACE_NET_PARAM_EN_CNT(iface->delayed_ack, count); ++ IFACE_NET_PARAM_EN_CNT(iface->nagle, count); ++ IFACE_NET_PARAM_EN_CNT(iface->tcp_wsf_state, count); ++ IFACE_NET_PARAM_EN_CNT(iface->tcp_timestamp, count); ++ IFACE_NET_PARAM_EN_CNT(iface->redirect, count); ++ IFACE_NET_PARAM_EN_CNT(iface->header_digest, count); ++ IFACE_NET_PARAM_EN_CNT(iface->data_digest, count); ++ IFACE_NET_PARAM_EN_CNT(iface->immediate_data, count); ++ IFACE_NET_PARAM_EN_CNT(iface->initial_r2t, count); ++ IFACE_NET_PARAM_EN_CNT(iface->data_seq_inorder, count); ++ IFACE_NET_PARAM_EN_CNT(iface->data_pdu_inorder, count); ++ IFACE_NET_PARAM_EN_CNT(iface->chap_auth, count); ++ IFACE_NET_PARAM_EN_CNT(iface->bidi_chap, count); ++ IFACE_NET_PARAM_EN_CNT(iface->strict_login_comp, count); ++ IFACE_NET_PARAM_EN_CNT(iface->discovery_auth, count); ++ IFACE_NET_PARAM_EN_CNT(iface->discovery_logout, count); ++ ++ if (iface->tcp_wsf) ++ (*count)++; ++ ++ if (iface->tcp_timer_scale) ++ (*count)++; ++ ++ if (iface->def_task_mgmt_tmo) ++ (*count)++; ++ ++ if (iface->erl) ++ (*count)++; ++ ++ if (iface->max_recv_dlength) ++ (*count)++; ++ ++ if (iface->first_burst_len) ++ (*count)++; ++ ++ if (iface->max_burst_len) ++ (*count)++; ++ ++ if (iface->max_out_r2t) ++ (*count)++; ++} ++ + /** + * __iface_get_param_count - Gets netconfig parameter count for given iface + * @data: iface_param_count structure +@@ -1034,10 +1219,10 @@ static int __iface_get_param_count(void *data, struct iface_rec *iface) + if (iptype == ISCSI_IFACE_TYPE_IPV4) { + + if (strcmp(iface->state, "disable")) { +- if (strstr(iface->bootproto, "dhcp")) ++ if (strstr(iface->bootproto, "dhcp")) { + /* DHCP enabled */ + count++; +- else { ++ } else { + /* DHCP disabled */ + count++; + +@@ -1052,12 +1237,13 @@ static int __iface_get_param_count(void *data, struct iface_rec *iface) + if (strstr(iface->gateway, ".")) + /* User configured Gateway */ + count++; +- } else ++ } else { + /* + * IPv4 Address not valid, decrement + * count of DHCP + */ + count--; ++ } + } + + /* +@@ -1068,37 +1254,68 @@ static int __iface_get_param_count(void *data, struct iface_rec *iface) + /* iface state */ + count++; + +- if (strcmp(iface->vlan_state, "disable")) { +- /* vlan_state enabled */ ++ IFACE_NET_PARAM_EN_CNT(iface->dhcp_dns, ++ &count); ++ ++ IFACE_NET_PARAM_EN_CNT(iface->dhcp_slp_da, ++ &count); ++ ++ IFACE_NET_PARAM_EN_CNT(iface->tos_state, ++ &count); ++ ++ IFACE_NET_PARAM_EN_CNT(iface->gratuitous_arp, ++ &count); ++ ++ IFACE_NET_PARAM_EN_CNT( ++ iface->dhcp_alt_client_id_state, ++ &count); ++ ++ if (iface->dhcp_alt_client_id[0]) + count++; + +- if (iface->vlan_id) +- /* For vlan value */ +- count++; +- } else +- /* vlan_state disabled */ ++ IFACE_NET_PARAM_EN_CNT( ++ iface->dhcp_req_vendor_id_state, ++ &count); ++ ++ IFACE_NET_PARAM_EN_CNT( ++ iface->dhcp_vendor_id_state, ++ &count); ++ ++ if (iface->dhcp_vendor_id[0]) + count++; + +- if (iface->mtu) ++ IFACE_NET_PARAM_EN_CNT(iface->dhcp_learn_iqn, ++ &count); ++ ++ IFACE_NET_PARAM_EN_CNT(iface->fragmentation, ++ &count); ++ ++ IFACE_NET_PARAM_EN_CNT( ++ iface->incoming_forwarding, ++ &count); ++ ++ if (iface->tos) + count++; + +- if (iface->port) ++ if (iface->ttl) + count++; ++ ++ iface_get_common_param_count(iface, &count); + } +- } else ++ } else { + /* IPv4 is disabled, iface state */ + count++; +- ++ } + } else if (iptype == ISCSI_IFACE_TYPE_IPV6) { + + if (strcmp(iface->state, "disable")) { + + /* IPv6 Address */ + if (strstr(iface->ipv6_autocfg, "nd") || +- strstr(iface->ipv6_autocfg, "dhcpv6")) ++ strstr(iface->ipv6_autocfg, "dhcpv6")) { + /* Autocfg enabled */ + count++; +- else { ++ } else { + /* Autocfg disabled */ + count++; + +@@ -1159,26 +1376,42 @@ static int __iface_get_param_count(void *data, struct iface_rec *iface) + /* iface state */ + count++; + +- if (strcmp(iface->vlan_state, "disable")) { +- /* vlan_state enabled */ ++ IFACE_NET_PARAM_EN_CNT( ++ iface->gratuitous_neighbor_adv, ++ &count); ++ ++ IFACE_NET_PARAM_EN_CNT(iface->mld, &count); ++ ++ if (iface->flow_label) ++ count++; ++ ++ if (iface->traffic_class) ++ count++; ++ ++ if (iface->hop_limit) + count++; + +- if (iface->vlan_id) +- /* For vlan value */ +- count++; +- } else +- /* vlan_state disabled */ ++ if (iface->nd_reachable_tmo) + count++; + +- if (iface->mtu) ++ if (iface->nd_rexmit_time) + count++; + +- if (iface->port) ++ if (iface->nd_stale_tmo) + count++; ++ ++ if (iface->dup_addr_detect_cnt) ++ count++; ++ ++ if (iface->router_adv_link_mtu) ++ count++; ++ ++ iface_get_common_param_count(iface, &count); + } +- } else ++ } else { + /* IPv6 is disabled, iface state */ + count++; ++ } + } + + iface_params->count += count; +@@ -1197,7 +1430,7 @@ int iface_get_param_count(struct iface_rec *iface, int iface_all) + int num_found = 0, rc; + struct iface_param_count iface_params; + +- log_debug(8, "In iface_get_param_count\n"); ++ log_debug(8, "In iface_get_param_count"); + + iface_params.primary = iface; + iface_params.count = 0; +@@ -1208,63 +1441,73 @@ int iface_get_param_count(struct iface_rec *iface, int iface_all) + else + rc = __iface_get_param_count(&iface_params, iface); + +- log_debug(8, "iface_get_param_count: rc = %d, count = %d\n", ++ log_debug(8, "iface_get_param_count: rc = %d, count = %d", + rc, iface_params.count); + return iface_params.count; + } + +-/* IPv4/IPv6 Port: 3260 or User defined */ +-static int iface_fill_port(struct iovec *iov, struct iface_rec *iface, +- uint32_t iface_type) ++/* write integer parameter value */ ++static int iface_fill_int_param_val(struct iovec *iov, uint32_t iface_num, ++ uint8_t iface_type, uint16_t param, ++ uint8_t param_type, uint32_t param_len, ++ uint32_t param_val) + { + int len; + struct iscsi_iface_param_info *net_param; +- uint16_t port = 3260; + struct nlattr *attr; ++ uint8_t val8 = 0; ++ uint16_t val16 = 0; ++ uint32_t val32 = 0; ++ char *val = NULL; + +- len = sizeof(struct iscsi_iface_param_info) + sizeof(port); +- iov->iov_base = iscsi_nla_alloc(ISCSI_NET_PARAM_PORT, len); +- if (!iov->iov_base) +- return 1; +- attr = iov->iov_base; +- iov->iov_len = NLA_ALIGN(attr->nla_len); +- +- net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr); +- net_param->param = ISCSI_NET_PARAM_PORT; +- net_param->iface_type = iface_type; +- net_param->iface_num = iface->iface_num; +- net_param->param_type = ISCSI_NET_PARAM; +- net_param->len = 2; +- if (iface->port) +- port = iface->port; +- memcpy(net_param->value, &port, net_param->len); +- return 0; +-} +- +-static int iface_fill_mtu(struct iovec *iov, struct iface_rec *iface, +- uint32_t iface_type) +-{ +- int len; +- struct iscsi_iface_param_info *net_param; +- uint16_t mtu = 0; +- struct nlattr *attr; +- +- len = sizeof(struct iscsi_iface_param_info) + 2; +- iov->iov_base = iscsi_nla_alloc(ISCSI_NET_PARAM_MTU, len); ++ len = sizeof(struct iscsi_iface_param_info) + param_len; ++ iov->iov_base = iscsi_nla_alloc(param, len); + if (!(iov->iov_base)) + return 1; ++ + attr = iov->iov_base; + iov->iov_len = NLA_ALIGN(attr->nla_len); +- + net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr); +- net_param->param = ISCSI_NET_PARAM_MTU; ++ net_param->iface_num = iface_num; ++ net_param->len = param_len; ++ net_param->param = param; + net_param->iface_type = iface_type; +- net_param->iface_num = iface->iface_num; +- net_param->param_type = ISCSI_NET_PARAM; +- net_param->len = 2; +- mtu = iface->mtu; +- memcpy(net_param->value, &mtu, net_param->len); ++ net_param->param_type = param_type; ++ switch (param_len) { ++ case 1: ++ val8 = (uint8_t)param_val; ++ val = (char *)&val8; ++ break; ++ ++ case 2: ++ val16 = (uint16_t)param_val; ++ val = (char *)&val16; ++ break; ++ ++ case 4: ++ val32 = (uint32_t)param_val; ++ val = (char *)&val32; ++ break; ++ ++ default: ++ goto free; ++ } ++ memcpy(net_param->value, val, param_len); + return 0; ++free: ++ free(iov->iov_base); ++ iov->iov_base = NULL; ++ iov->iov_len = 0; ++ return 1; ++} ++ ++#define IFACE_SET_PARAM_INTVAL(iov, inum, itype, param, ptype, plen, \ ++ ival, gcnt, lcnt) { \ ++ if (ival && !iface_fill_int_param_val(iov, inum, itype, param, \ ++ ptype, plen, ival)) { \ ++ (*gcnt)++; \ ++ (*lcnt)++; \ ++ } \ + } + + /* IPv4/IPv6 VLAN_ID: decimal value <= 4095 */ +@@ -1301,60 +1544,52 @@ static int iface_fill_vlan_id(struct iovec *iov, struct iface_rec *iface, + return 0; + } + +-/* IPv4/IPv6 VLAN state: disable/enable */ +-static int iface_fill_vlan_state(struct iovec *iov, struct iface_rec *iface, +- uint32_t iface_type) ++/* disable/enable parameters */ ++static int iface_fill_param_state(struct iovec *iov, uint32_t iface_num, ++ uint8_t iface_type, uint16_t param, ++ uint8_t param_type, char *param_val) + { + int len; + struct iscsi_iface_param_info *net_param; + struct nlattr *attr; + ++ if (!param_val[0]) ++ return 1; ++ + len = sizeof(struct iscsi_iface_param_info) + 1; +- iov->iov_base = iscsi_nla_alloc(ISCSI_NET_PARAM_VLAN_ENABLED, len); ++ iov->iov_base = iscsi_nla_alloc(param, len); + if (!(iov->iov_base)) + return 1; + + attr = iov->iov_base; + iov->iov_len = NLA_ALIGN(attr->nla_len); + net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr); +- net_param->param = ISCSI_NET_PARAM_VLAN_ENABLED; +- net_param->iface_type = iface_type; +- net_param->iface_num = iface->iface_num; +- net_param->param_type = ISCSI_NET_PARAM; ++ net_param->iface_num = iface_num; + net_param->len = 1; +- if (strcmp(iface->vlan_state, "disable") && iface->vlan_id) +- net_param->value[0] = ISCSI_VLAN_ENABLE; +- else /* Assume disabled */ +- net_param->value[0] = ISCSI_VLAN_DISABLE; ++ net_param->param = param; ++ net_param->iface_type = iface_type; ++ net_param->param_type = param_type; ++ if (!strcmp(param_val, "disable")) ++ net_param->value[0] = ISCSI_NET_PARAM_DISABLE; ++ else if (!strcmp(param_val, "enable")) ++ net_param->value[0] = ISCSI_NET_PARAM_ENABLE; ++ else ++ goto free; + return 0; ++free: ++ free(iov->iov_base); ++ iov->iov_base = NULL; ++ iov->iov_len = 0; ++ return 1; + } + +-/* IPv4/IPv6 Network state: disable/enable */ +-static int iface_fill_net_state(struct iovec *iov, struct iface_rec *iface, +- uint32_t iface_type) +-{ +- int len; +- struct iscsi_iface_param_info *net_param; +- struct nlattr *attr; +- +- len = sizeof(struct iscsi_iface_param_info) + 1; +- iov->iov_base = iscsi_nla_alloc(ISCSI_NET_PARAM_IFACE_ENABLE, len); +- if (!(iov->iov_base)) +- return 1; +- +- attr = iov->iov_base; +- iov->iov_len = NLA_ALIGN(attr->nla_len); +- net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr); +- net_param->param = ISCSI_NET_PARAM_IFACE_ENABLE; +- net_param->iface_type = iface_type; +- net_param->iface_num = iface->iface_num; +- net_param->param_type = ISCSI_NET_PARAM; +- net_param->len = 1; +- if (!strcmp(iface->state, "disable")) +- net_param->value[0] = ISCSI_IFACE_DISABLE; +- else /* Assume enabled */ +- net_param->value[0] = ISCSI_IFACE_ENABLE; +- return 0; ++#define IFACE_SET_PARAM_STATE(iov, inum, itype, param, ptype, ival, \ ++ gcnt, lcnt) { \ ++ if (!iface_fill_param_state(iov, inum, itype, param, ptype, \ ++ ival)) { \ ++ (*gcnt)++; \ ++ (*lcnt)++; \ ++ } \ + } + + /* IPv4 Bootproto: DHCP/static */ +@@ -1474,8 +1709,8 @@ static int iface_fill_router_autocfg(struct iovec *iov, struct iface_rec *iface) + } + + /* IPv4 IPAddress/Subnet Mask/Gateway: 4 bytes */ +-static int iface_fill_net_ipv4_addr(struct iovec *iov, struct iface_rec *iface, +- uint32_t param) ++static int iface_fill_net_ipv4_addr(struct iovec *iov, uint32_t iface_num, ++ uint16_t param, char *param_val) + { + int rc = 1; + int len; +@@ -1492,29 +1727,12 @@ static int iface_fill_net_ipv4_addr(struct iovec *iov, struct iface_rec *iface, + net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr); + net_param->param = param; + net_param->iface_type = ISCSI_IFACE_TYPE_IPV4; +- net_param->iface_num = iface->iface_num; ++ net_param->iface_num = iface_num; + net_param->len = 4; + net_param->param_type = ISCSI_NET_PARAM; +- +- switch (param) { +- case ISCSI_NET_PARAM_IPV4_ADDR: +- rc = inet_pton(AF_INET, iface->ipaddress, net_param->value); +- if (rc <= 0) +- goto free; +- break; +- case ISCSI_NET_PARAM_IPV4_SUBNET: +- rc = inet_pton(AF_INET, iface->subnet_mask, net_param->value); +- if (rc <= 0) +- goto free; +- break; +- case ISCSI_NET_PARAM_IPV4_GW: +- rc = inet_pton(AF_INET, iface->gateway, net_param->value); +- if (rc <= 0) +- goto free; +- break; +- default: ++ rc = inet_pton(AF_INET, param_val, net_param->value); ++ if (rc <= 0) + goto free; +- } + + /* validate */ + if (!net_param->value[0] && !net_param->value[1] && +@@ -1529,9 +1747,19 @@ free: + return 1; + } + ++#define IFACE_SET_NET_PARAM_IPV4_ADDR(iov, inum, param, ival, gcnt, \ ++ lcnt) { \ ++ if (strstr(ival, ".")) { \ ++ if (!iface_fill_net_ipv4_addr(iov, inum, param, ival)) {\ ++ (*gcnt)++; \ ++ (*lcnt)++; \ ++ } \ ++ } \ ++} ++ + /* IPv6 IPAddress/LinkLocal/Router: 16 bytes */ +-static int iface_fill_net_ipv6_addr(struct iovec *iov, struct iface_rec *iface, +- uint32_t param) ++static int iface_fill_net_ipv6_addr(struct iovec *iov, uint32_t iface_num, ++ uint16_t param, char *param_val) + { + int rc; + int len; +@@ -1548,30 +1776,12 @@ static int iface_fill_net_ipv6_addr(struct iovec *iov, struct iface_rec *iface, + net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr); + net_param->param = param; + net_param->iface_type = ISCSI_IFACE_TYPE_IPV6; +- net_param->iface_num = iface->iface_num; ++ net_param->iface_num = iface_num; + net_param->param_type = ISCSI_NET_PARAM; + net_param->len = 16; +- +- switch (param) { +- case ISCSI_NET_PARAM_IPV6_ADDR: +- rc = inet_pton(AF_INET6, iface->ipaddress, net_param->value); +- if (rc <= 0) +- goto free; +- break; +- case ISCSI_NET_PARAM_IPV6_LINKLOCAL: +- rc = inet_pton(AF_INET6, iface->ipv6_linklocal, +- net_param->value); +- if (rc <= 0) +- goto free; +- break; +- case ISCSI_NET_PARAM_IPV6_ROUTER: +- rc = inet_pton(AF_INET6, iface->ipv6_router, net_param->value); +- if (rc <= 0) +- goto free; +- break; +- default: ++ rc = inet_pton(AF_INET6, param_val, net_param->value); ++ if (rc <= 0) + goto free; +- } + + return 0; + free: +@@ -1581,6 +1791,54 @@ free: + return 1; + } + ++#define IFACE_SET_NET_PARAM_IPV6_ADDR(iov, inum, param, ival, gcnt, \ ++ lcnt) { \ ++ if (strstr(ival, ":")) { \ ++ if (!iface_fill_net_ipv6_addr(iov, inum, param, ival)) {\ ++ (*gcnt)++; \ ++ (*lcnt)++; \ ++ } \ ++ } \ ++} ++ ++/* write string parameter value */ ++static int iface_fill_str_param_val(struct iovec *iov, uint32_t iface_num, ++ uint8_t iface_type, uint16_t param, ++ uint32_t param_len, char *param_val) ++{ ++ int len; ++ struct iscsi_iface_param_info *net_param; ++ struct nlattr *attr; ++ ++ if (!param_val[0]) ++ return 1; ++ ++ len = sizeof(struct iscsi_iface_param_info) + param_len; ++ iov->iov_base = iscsi_nla_alloc(param, len); ++ if (!(iov->iov_base)) ++ return 1; ++ ++ attr = iov->iov_base; ++ iov->iov_len = NLA_ALIGN(attr->nla_len); ++ net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr); ++ net_param->iface_num = iface_num; ++ net_param->len = param_len; ++ net_param->param = param; ++ net_param->iface_type = iface_type; ++ net_param->param_type = ISCSI_NET_PARAM; ++ memcpy(net_param->value, param_val, param_len); ++ return 0; ++} ++ ++#define IFACE_SET_NET_PARAM_STRVAL(iov, inum, itype, param, plen, \ ++ ival, gcnt, lcnt) { \ ++ if (!iface_fill_str_param_val(iov, inum, itype, param, plen, \ ++ ival)) { \ ++ (*gcnt)++; \ ++ (*lcnt)++; \ ++ } \ ++} ++ + struct iface_net_config { + struct iface_rec *primary; + struct iovec *iovs; +@@ -1600,16 +1858,21 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface) + /* start at 2, because 0 is for nlmsghdr and 1 for event */ + iov = net_config->iovs + 2; + ++ if (!iface->port) ++ iface->port = 3260; ++ + iptype = iface_get_iptype(iface); +- if (iptype == ISCSI_IFACE_TYPE_IPV4) { ++ switch (iptype) { ++ case ISCSI_IFACE_TYPE_IPV4: + if (!strcmp(iface->state, "disable")) { +- if (!iface_fill_net_state(&iov[net_config->count], +- iface, +- ISCSI_IFACE_TYPE_IPV4)) { +- net_config->count++; +- count++; +- } +- ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IFACE_ENABLE, ++ ISCSI_NET_PARAM, ++ iface->state, ++ &net_config->count, ++ &count); + return 0; + } + +@@ -1625,28 +1888,27 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface) + net_config->count++; + count++; + } +- if (!iface_fill_net_ipv4_addr(&iov[net_config->count], +- iface, +- ISCSI_NET_PARAM_IPV4_ADDR)) { +- net_config->count++; +- count++; +- } +- if (strstr(iface->subnet_mask, ".")) { +- if (!iface_fill_net_ipv4_addr( +- &iov[net_config->count], iface, +- ISCSI_NET_PARAM_IPV4_SUBNET)) { +- net_config->count++; +- count++; +- } +- } +- if (strstr(iface->gateway, ".")) { +- if (!iface_fill_net_ipv4_addr( +- &iov[net_config->count], iface, +- ISCSI_NET_PARAM_IPV4_GW)) { +- net_config->count++; +- count++; +- } +- } ++ ++ IFACE_SET_NET_PARAM_IPV4_ADDR(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_NET_PARAM_IPV4_ADDR, ++ iface->ipaddress, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_NET_PARAM_IPV4_ADDR(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_NET_PARAM_IPV4_SUBNET, ++ iface->subnet_mask, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_NET_PARAM_IPV4_ADDR(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_NET_PARAM_IPV4_GW, ++ iface->gateway, ++ &net_config->count, ++ &count); + } + + /* +@@ -1654,51 +1916,146 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface) + * fill state and other parameters (if any) + */ + if (count) { +- if (!iface_fill_net_state(&iov[net_config->count], +- iface, +- ISCSI_IFACE_TYPE_IPV4)) { +- net_config->count++; +- count++; +- } +- if (!iface_fill_vlan_state(&iov[net_config->count], +- iface, +- ISCSI_IFACE_TYPE_IPV4)) { +- net_config->count++; +- count++; +- } +- if (strcmp(iface->vlan_state, "disable") && +- iface->vlan_id) { +- if (!iface_fill_vlan_id(&iov[net_config->count], +- iface, ISCSI_IFACE_TYPE_IPV4)) { +- net_config->count++; +- count++; +- } +- } +- if (iface->mtu) { +- if (!iface_fill_mtu(&iov[net_config->count], +- iface, +- ISCSI_IFACE_TYPE_IPV4)) { +- net_config->count++; +- count++; +- } +- } +- if (iface->port) { +- if (!iface_fill_port(&iov[net_config->count], +- iface, +- ISCSI_IFACE_TYPE_IPV4)) { +- net_config->count++; +- count++; +- } +- } ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN, ++ ISCSI_NET_PARAM, ++ iface->dhcp_dns, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN, ++ ISCSI_NET_PARAM, ++ iface->dhcp_slp_da, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_TOS_EN, ++ ISCSI_NET_PARAM, ++ iface->tos_state, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_TOS, ++ ISCSI_NET_PARAM, ++ 1, ++ iface->tos, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN, ++ ISCSI_NET_PARAM, ++ iface->gratuitous_arp, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN, ++ ISCSI_NET_PARAM, ++ iface->dhcp_alt_client_id_state, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_NET_PARAM_STRVAL(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID, ++ strlen(iface->dhcp_alt_client_id), ++ iface->dhcp_alt_client_id, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN, ++ ISCSI_NET_PARAM, ++ iface->dhcp_req_vendor_id_state, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN, ++ ISCSI_NET_PARAM, ++ iface->dhcp_vendor_id_state, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_NET_PARAM_STRVAL(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID, ++ strlen(iface->dhcp_vendor_id), ++ iface->dhcp_vendor_id, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN, ++ ISCSI_NET_PARAM, ++ iface->dhcp_learn_iqn, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE, ++ ISCSI_NET_PARAM, ++ iface->fragmentation, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN, ++ ISCSI_NET_PARAM, ++ iface->incoming_forwarding, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV4, ++ ISCSI_NET_PARAM_IPV4_TTL, ++ ISCSI_NET_PARAM, ++ 1, ++ iface->ttl, ++ &net_config->count, ++ &count); + } +- } else if (iptype == ISCSI_IFACE_TYPE_IPV6) { ++ break; ++ ++ case ISCSI_IFACE_TYPE_IPV6: + if (!strcmp(iface->state, "disable")) { +- if (!iface_fill_net_state(&iov[net_config->count], +- iface, +- ISCSI_IFACE_TYPE_IPV6)) { +- net_config->count++; +- count++; +- } ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV6, ++ ISCSI_NET_PARAM_IFACE_ENABLE, ++ ISCSI_NET_PARAM, ++ iface->state, ++ &net_config->count, ++ &count); + return 0; + } + +@@ -1717,12 +2074,12 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface) + count++; + } + /* User provided IPv6 Address */ +- if (!iface_fill_net_ipv6_addr(&iov[net_config->count], +- iface, +- ISCSI_NET_PARAM_IPV6_ADDR)) { +- net_config->count++; +- count++; +- } ++ IFACE_SET_NET_PARAM_IPV6_ADDR(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_NET_PARAM_IPV6_ADDR, ++ iface->ipaddress, ++ &net_config->count, ++ &count); + } + + /* For LinkLocal Address */ +@@ -1741,12 +2098,12 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface) + count++; + } + /* User provided Link Local Address */ +- if (!iface_fill_net_ipv6_addr(&iov[net_config->count], +- iface, +- ISCSI_NET_PARAM_IPV6_LINKLOCAL)) { +- net_config->count++; +- count++; +- } ++ IFACE_SET_NET_PARAM_IPV6_ADDR(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_NET_PARAM_IPV6_LINKLOCAL, ++ iface->ipv6_linklocal, ++ &net_config->count, ++ &count); + } + + /* For Router Address */ +@@ -1763,12 +2120,12 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface) + count++; + } + /* User provided Router Address */ +- if (!iface_fill_net_ipv6_addr(&iov[net_config->count], +- iface, +- ISCSI_NET_PARAM_IPV6_ROUTER)) { +- net_config->count++; +- count++; +- } ++ IFACE_SET_NET_PARAM_IPV6_ADDR(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_NET_PARAM_IPV6_ROUTER, ++ iface->ipv6_router, ++ &net_config->count, ++ &count); + } + + /* +@@ -1776,44 +2133,378 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface) + * fill state and other parameters + */ + if (count) { +- if (!iface_fill_net_state(&iov[net_config->count], +- iface, +- ISCSI_IFACE_TYPE_IPV6)) { +- net_config->count++; +- count++; +- } +- if (!iface_fill_vlan_state(&iov[net_config->count], +- iface, +- ISCSI_IFACE_TYPE_IPV6)) { ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV6, ++ ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN, ++ ISCSI_NET_PARAM, ++ iface->gratuitous_neighbor_adv, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV6, ++ ISCSI_NET_PARAM_IPV6_MLD_EN, ++ ISCSI_NET_PARAM, ++ iface->mld, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV6, ++ ISCSI_NET_PARAM_IPV6_FLOW_LABEL, ++ ISCSI_NET_PARAM, ++ 4, ++ iface->flow_label, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV6, ++ ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS, ++ ISCSI_NET_PARAM, ++ 1, ++ iface->traffic_class, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV6, ++ ISCSI_NET_PARAM_IPV6_HOP_LIMIT, ++ ISCSI_NET_PARAM, ++ 1, ++ iface->hop_limit, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV6, ++ ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO, ++ ISCSI_NET_PARAM, ++ 4, ++ iface->nd_reachable_tmo, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV6, ++ ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME, ++ ISCSI_NET_PARAM, ++ 4, ++ iface->nd_rexmit_time, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV6, ++ ISCSI_NET_PARAM_IPV6_ND_STALE_TMO, ++ ISCSI_NET_PARAM, ++ 4, ++ iface->nd_stale_tmo, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV6, ++ ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT, ++ ISCSI_NET_PARAM, ++ 1, ++ iface->dup_addr_detect_cnt, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ ISCSI_IFACE_TYPE_IPV6, ++ ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU, ++ ISCSI_NET_PARAM, ++ 4, ++ iface->router_adv_link_mtu, ++ &net_config->count, ++ &count); ++ } ++ break; ++ } ++ ++ /* Fill parameters common to IPv4 and IPv6 ifaces */ ++ if (count) { ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_NET_PARAM_IFACE_ENABLE, ++ ISCSI_NET_PARAM, ++ iface->state, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_NET_PARAM_VLAN_ENABLED, ++ ISCSI_NET_PARAM, ++ iface->vlan_state, ++ &net_config->count, ++ &count); ++ ++ if (strcmp(iface->vlan_state, "disable") && iface->vlan_id) { ++ if (!iface_fill_vlan_id(&iov[net_config->count], iface, ++ iptype)) { + net_config->count++; + count++; + } +- if (strcmp(iface->vlan_state, "disable") && +- iface->vlan_id) { +- if (!iface_fill_vlan_id(&iov[net_config->count], +- iface, +- ISCSI_IFACE_TYPE_IPV6)) { +- net_config->count++; +- count++; +- } +- } +- if (iface->mtu) { +- if (!iface_fill_mtu(&iov[net_config->count], +- iface, +- ISCSI_IFACE_TYPE_IPV6)) { +- net_config->count++; +- count++; +- } +- } +- if (iface->port) { +- if (!iface_fill_port(&iov[net_config->count], +- iface, +- ISCSI_IFACE_TYPE_IPV6)) { +- net_config->count++; +- count++; +- } +- } + } ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_NET_PARAM_MTU, ++ ISCSI_NET_PARAM, ++ 2, ++ iface->mtu, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_NET_PARAM_PORT, ++ ISCSI_NET_PARAM, ++ 2, ++ iface->port, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_NET_PARAM_DELAYED_ACK_EN, ++ ISCSI_NET_PARAM, ++ iface->delayed_ack, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_NET_PARAM_TCP_NAGLE_DISABLE, ++ ISCSI_NET_PARAM, ++ iface->nagle, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_NET_PARAM_TCP_WSF_DISABLE, ++ ISCSI_NET_PARAM, ++ iface->tcp_wsf_state, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_NET_PARAM_TCP_WSF, ++ ISCSI_NET_PARAM, ++ 1, ++ iface->tcp_wsf, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_NET_PARAM_TCP_TIMER_SCALE, ++ ISCSI_NET_PARAM, ++ 1, ++ iface->tcp_timer_scale, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_NET_PARAM_TCP_TIMESTAMP_EN, ++ ISCSI_NET_PARAM, ++ iface->tcp_timestamp, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_NET_PARAM_REDIRECT_EN, ++ ISCSI_NET_PARAM, ++ iface->redirect, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO, ++ ISCSI_IFACE_PARAM, ++ 2, ++ iface->def_task_mgmt_tmo, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_HDRDGST_EN, ++ ISCSI_IFACE_PARAM, ++ iface->header_digest, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_DATADGST_EN, ++ ISCSI_IFACE_PARAM, ++ iface->data_digest, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_IMM_DATA_EN, ++ ISCSI_IFACE_PARAM, ++ iface->immediate_data, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_INITIAL_R2T_EN, ++ ISCSI_IFACE_PARAM, ++ iface->initial_r2t, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN, ++ ISCSI_IFACE_PARAM, ++ iface->data_seq_inorder, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_PDU_INORDER_EN, ++ ISCSI_IFACE_PARAM, ++ iface->data_pdu_inorder, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_ERL, ++ ISCSI_IFACE_PARAM, ++ 1, ++ iface->erl, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH, ++ ISCSI_IFACE_PARAM, ++ 4, ++ iface->max_recv_dlength, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_FIRST_BURST, ++ ISCSI_IFACE_PARAM, ++ 4, ++ iface->first_burst_len, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_MAX_R2T, ++ ISCSI_IFACE_PARAM, ++ 2, ++ iface->max_out_r2t, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_INTVAL(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_MAX_BURST, ++ ISCSI_IFACE_PARAM, ++ 4, ++ iface->max_burst_len, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_CHAP_AUTH_EN, ++ ISCSI_IFACE_PARAM, ++ iface->chap_auth, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_BIDI_CHAP_EN, ++ ISCSI_IFACE_PARAM, ++ iface->bidi_chap, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN, ++ ISCSI_IFACE_PARAM, ++ iface->strict_login_comp, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL, ++ ISCSI_IFACE_PARAM, ++ iface->discovery_auth, ++ &net_config->count, ++ &count); ++ ++ IFACE_SET_PARAM_STATE(&iov[net_config->count], ++ iface->iface_num, ++ iptype, ++ ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN, ++ ISCSI_IFACE_PARAM, ++ iface->discovery_logout, ++ &net_config->count, ++ &count); + } + return 0; + } +@@ -1832,7 +2523,7 @@ int iface_build_net_config(struct iface_rec *iface, int iface_all, + int num_found = 0, rc; + struct iface_net_config net_config; + +- log_debug(8, "In iface_build_net_config\n"); ++ log_debug(8, "In iface_build_net_config"); + + net_config.primary = iface; + net_config.iovs = iovs; +@@ -1844,7 +2535,7 @@ int iface_build_net_config(struct iface_rec *iface, int iface_all, + else + rc = __iface_build_net_config(&net_config, iface); + +- log_debug(8, "iface_build_net_config: rc = %d, count = %d\n", ++ log_debug(8, "iface_build_net_config: rc = %d, count = %d", + rc, net_config.count); + return net_config.count; + } +diff --git a/usr/initiator.c b/usr/initiator.c +index 79ca32c..8cd1896 100644 +--- a/usr/initiator.c ++++ b/usr/initiator.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + #include "initiator.h" + #include "transport.h" +@@ -45,6 +46,7 @@ + #include "iscsi_sysfs.h" + #include "iscsi_settings.h" + #include "iface.h" ++#include "host.h" + #include "sysdeps.h" + #include "iscsi_err.h" + #include "kern_err_table.h" +@@ -54,10 +56,19 @@ + + #define PROC_DIR "/proc" + ++struct login_task_retry_info { ++ actor_t retry_actor; ++ queue_task_t *qtask; ++ node_rec_t *rec; ++ int retry_count; ++}; ++ + static void iscsi_login_timedout(void *data); + static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context, + struct iscsi_conn *conn, unsigned long tmo, + int event); ++static int queue_session_login_task_retry(struct login_task_retry_info *info, ++ node_rec_t *rec, queue_task_t *qtask); + + static int iscsi_ev_context_alloc(iscsi_conn_t *conn) + { +@@ -222,7 +233,7 @@ __check_iscsi_status_class(iscsi_session_t *session, int cid, + } + case ISCSI_STATUS_CLS_TARGET_ERR: + log_error("conn %d login rejected: target error " +- "(%02x/%02x)\n", conn->id, status_class, status_detail); ++ "(%02x/%02x)", conn->id, status_class, status_detail); + /* + * We have no idea what the problem is. But spec says initiator + * may retry later. +@@ -230,7 +241,7 @@ __check_iscsi_status_class(iscsi_session_t *session, int cid, + return CONN_LOGIN_RETRY; + default: + log_error("conn %d login response with unknown status " +- "class 0x%x, detail 0x%x\n", conn->id, status_class, ++ "class 0x%x, detail 0x%x", conn->id, status_class, + status_detail); + break; + } +@@ -252,6 +263,7 @@ __session_conn_create(iscsi_session_t *session, int cid) + + conn->state = ISCSI_CONN_STATE_FREE; + conn->session = session; ++ actor_init(&conn->login_timer, iscsi_login_timedout, NULL); + /* + * TODO: we must export the socket_fd/transport_eph from sysfs + * so if iscsid is resyncing up we can pick that up and cleanup up +@@ -265,7 +277,7 @@ __session_conn_create(iscsi_session_t *session, int cid) + conn->logout_timeout = conn_rec->timeo.logout_timeout; + if (!conn->logout_timeout) { + log_error("Invalid timeo.logout_timeout. Must be greater " +- "than zero. Using default %d.\n", ++ "than zero. Using default %d.", + DEF_LOGOUT_TIMEO); + conn->logout_timeout = DEF_LOGOUT_TIMEO; + } +@@ -273,7 +285,7 @@ __session_conn_create(iscsi_session_t *session, int cid) + conn->login_timeout = conn_rec->timeo.login_timeout; + if (!conn->login_timeout) { + log_error("Invalid timeo.login_timeout. Must be greater " +- "than zero. Using default %d.\n", ++ "than zero. Using default %d.", + DEF_LOGIN_TIMEO); + conn->login_timeout = DEF_LOGIN_TIMEO; + } +@@ -285,14 +297,14 @@ __session_conn_create(iscsi_session_t *session, int cid) + conn->noop_out_timeout = conn_rec->timeo.noop_out_timeout; + if (conn->noop_out_interval && !conn->noop_out_timeout) { + log_error("Invalid timeo.noop_out_timeout. Must be greater " +- "than zero. Using default %d.\n", ++ "than zero. Using default %d.", + DEF_NOOP_OUT_TIMEO); + conn->noop_out_timeout = DEF_NOOP_OUT_TIMEO; + } + + if (conn->noop_out_timeout && !conn->noop_out_interval) { + log_error("Invalid timeo.noop_out_interval. Must be greater " +- "than zero. Using default %d.\n", ++ "than zero. Using default %d.", + DEF_NOOP_OUT_INTERVAL); + conn->noop_out_interval = DEF_NOOP_OUT_INTERVAL; + } +@@ -323,14 +335,17 @@ session_release(iscsi_session_t *session) + } + + static iscsi_session_t* +-__session_create(node_rec_t *rec, struct iscsi_transport *t) ++__session_create(node_rec_t *rec, struct iscsi_transport *t, int *rc) + { + iscsi_session_t *session; +- int hostno, rc = 0; ++ int hostno; ++ ++ *rc = 0; + + session = calloc(1, sizeof (*session)); + if (session == NULL) { + log_debug(1, "can not allocate memory for session"); ++ *rc = ISCSI_ERR_NOMEM; + return NULL; + } + log_debug(2, "Allocted session %p", session); +@@ -355,8 +370,8 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t) + session->initiator_name = dconfig->initiator_name; + else { + log_error("No initiator name set. Cannot create session."); +- free(session); +- return NULL; ++ *rc = ISCSI_ERR_INVAL; ++ goto free_session; + } + + if (strlen(session->nrec.iface.alias)) +@@ -383,31 +398,31 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t) + /* setup authentication variables for the session*/ + iscsi_setup_authentication(session, &rec->session.auth); + +- session->param_mask = ~0ULL; +- if (!(t->caps & CAP_MULTI_R2T)) +- session->param_mask &= ~ISCSI_MAX_R2T; +- if (!(t->caps & CAP_HDRDGST)) +- session->param_mask &= ~ISCSI_HDRDGST_EN; +- if (!(t->caps & CAP_DATADGST)) +- session->param_mask &= ~ISCSI_DATADGST_EN; +- if (!(t->caps & CAP_MARKERS)) { +- session->param_mask &= ~ISCSI_IFMARKER_EN; +- session->param_mask &= ~ISCSI_OFMARKER_EN; +- } ++ iscsi_session_init_params(session); + +- hostno = iscsi_sysfs_get_host_no_from_hwinfo(&rec->iface, &rc); +- if (!rc) { +- /* +- * if the netdev or mac was set, then we are going to want +- * to want to bind the all the conns/eps to a specific host +- * if offload is used. +- */ +- session->conn[0].bind_ep = 1; +- session->hostno = hostno; +- } ++ if (t->template->bind_ep_required) { ++ hostno = iscsi_sysfs_get_host_no_from_hwinfo(&rec->iface, rc); ++ if (!*rc) { ++ /* ++ * if the netdev or mac was set, then we are going to want ++ * to want to bind the all the conns/eps to a specific host ++ * if offload is used. ++ */ ++ session->conn[0].bind_ep = 1; ++ session->hostno = hostno; ++ } else if (*rc == ISCSI_ERR_HOST_NOT_FOUND) { ++ goto free_session; ++ } else { ++ *rc = 0; ++ } ++ } + + list_add_tail(&session->list, &t->sessions); + return session; ++ ++free_session: ++ free(session); ++ return NULL; + } + + static void iscsi_flush_context_pool(struct iscsi_session *session) +@@ -431,7 +446,7 @@ static void iscsi_flush_context_pool(struct iscsi_session *session) + static void + __session_destroy(iscsi_session_t *session) + { +- log_debug(1, "destroying session\n"); ++ log_debug(1, "destroying session"); + list_del(&session->list); + iscsi_flush_context_pool(session); + session_release(session); +@@ -509,15 +524,13 @@ queue_delayed_reopen(queue_task_t *qtask, int delay) + { + iscsi_conn_t *conn = qtask->conn; + +- log_debug(4, "Requeue reopen attempt in %d secs\n", delay); ++ log_debug(4, "Requeue reopen attempt in %d secs", delay); + + /* + * iscsi_login_eh can handle the login resched as + * if it were login time out + */ +- actor_delete(&conn->login_timer); +- actor_timer(&conn->login_timer, delay * 1000, +- iscsi_login_timedout, qtask); ++ actor_timer_mod(&conn->login_timer, delay, qtask); + } + + static int iscsi_conn_connect(struct iscsi_conn *conn, queue_task_t *qtask) +@@ -552,8 +565,7 @@ static int iscsi_conn_connect(struct iscsi_conn *conn, queue_task_t *qtask) + iscsi_sched_ev_context(ev_context, conn, 0, EV_CONN_POLL); + log_debug(3, "Setting login timer %p timeout %d", &conn->login_timer, + conn->login_timeout); +- actor_timer(&conn->login_timer, conn->login_timeout * 1000, +- iscsi_login_timedout, qtask); ++ actor_timer_mod(&conn->login_timer, conn->login_timeout, qtask); + return 0; + } + +@@ -598,6 +610,11 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop, + if (!redirected) + session->reopen_cnt++; + ++ /* uIP will needs to be re-triggered on the connection re-open */ ++ if (iscsi_set_net_config(conn->session->t, conn->session, ++ &conn->session->nrec.iface) != 0) ++ goto queue_reopen; ++ + if (iscsi_conn_connect(conn, qtask)) { + delay = ISCSI_CONN_ERR_REOPEN_DELAY; + goto queue_reopen; +@@ -605,7 +622,7 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop, + return; + + queue_reopen: +- log_debug(4, "Waiting %u seconds before trying to reconnect.\n", delay); ++ log_debug(4, "Waiting %u seconds before trying to reconnect.", delay); + queue_delayed_reopen(qtask, delay); + } + +@@ -638,7 +655,7 @@ static int iscsi_retry_initial_login(struct iscsi_conn *conn) + timeout.tv_sec = initial_login_retry_max * conn->login_timeout; + if (gettimeofday(&now, NULL)) { + log_error("Could not get time of day. Dropping down to " +- "max retry check.\n"); ++ "max retry check."); + return initial_login_retry_max > conn->session->reopen_cnt; + } + timeradd(&conn->initial_connect_time, &timeout, &fail_time); +@@ -649,7 +666,7 @@ static int iscsi_retry_initial_login(struct iscsi_conn *conn) + */ + if (timercmp(&now, &fail_time, >)) { + log_debug(1, "Giving up on initial login attempt after " +- "%u seconds.\n", ++ "%u seconds.", + initial_login_retry_max * conn->login_timeout); + return 0; + } +@@ -756,7 +773,7 @@ static void iscsi_login_eh(struct iscsi_conn *conn, struct queue_task *qtask, + + break; + default: +- log_error("Ignoring login error %d in conn state %d.\n", ++ log_error("Ignoring login error %d in conn state %d.", + err, conn->state); + break; + } +@@ -830,7 +847,7 @@ __conn_error_handle(iscsi_session_t *session, iscsi_conn_t *conn) + "let connection stop"); + return; + default: +- log_debug(8, "invalid state %d\n", conn->state); ++ log_debug(8, "invalid state %d", conn->state); + return; + } + +@@ -887,7 +904,7 @@ static void iscsi_login_redirect(iscsi_conn_t *conn) + iscsi_session_t *session = conn->session; + iscsi_login_context_t *c = &conn->login_context; + +- log_debug(3, "login redirect ...\n"); ++ log_debug(3, "login redirect ..."); + + if (session->r_stage == R_STAGE_NO_CHANGE) + session->r_stage = R_STAGE_SESSION_REDIRECT; +@@ -954,9 +971,9 @@ static void conn_send_nop_out(void *data) + + __send_nopout(conn); + +- actor_timer(&conn->nop_out_timer, conn->noop_out_timeout*1000, ++ actor_timer(&conn->nop_out_timer, conn->noop_out_timeout, + conn_nop_out_timeout, conn); +- log_debug(3, "noop out timeout timer %p start, timeout %d\n", ++ log_debug(3, "noop out timeout timer %p start, timeout %d", + &conn->nop_out_timer, conn->noop_out_timeout); + } + +@@ -993,7 +1010,7 @@ static void session_scan_host(struct iscsi_session *session, int hostno, + exit(0); + } else if (pid > 0) { + reap_inc(); +- if (qtask) { ++ if (qtask && qtask->mgmt_ipc_fd >= 0) { + close(qtask->mgmt_ipc_fd); + free(qtask); + } +@@ -1010,12 +1027,7 @@ setup_full_feature_phase(iscsi_conn_t *conn) + + actor_delete(&conn->login_timer); + +- if (iscsi_session_set_params(conn)) { +- iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN); +- return; +- } +- +- if (iscsi_host_set_params(session)) { ++ if (iscsi_session_set_neg_params(conn)) { + iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN); + return; + } +@@ -1062,9 +1074,9 @@ setup_full_feature_phase(iscsi_conn_t *conn) + + /* noop_out */ + if (conn->userspace_nop && conn->noop_out_interval) { +- actor_timer(&conn->nop_out_timer, conn->noop_out_interval*1000, ++ actor_timer(&conn->nop_out_timer, conn->noop_out_interval, + conn_send_nop_out, conn); +- log_debug(3, "noop out timer %p start\n", ++ log_debug(3, "noop out timer %p start", + &conn->nop_out_timer); + } + } +@@ -1079,7 +1091,7 @@ static void iscsi_logout_timedout(void *data) + * assume we were in ISCSI_CONN_STATE_IN_LOGOUT or there + * was some nasty error + */ +- log_debug(3, "logout timeout, dropping conn...\n"); ++ log_debug(3, "logout timeout, dropping conn..."); + __conn_error_handle(conn->session, conn); + } + +@@ -1110,7 +1122,7 @@ static int iscsi_send_logout(iscsi_conn_t *conn) + iscsi_sched_ev_context(ev_context, conn, + conn->logout_timeout, + EV_CONN_LOGOUT_TIMER); +- log_debug(3, "logout timeout timer %u\n", ++ log_debug(3, "logout timeout timer %u", + conn->logout_timeout * 1000); + } + +@@ -1146,7 +1158,7 @@ static void iscsi_recv_nop_in(iscsi_conn_t *conn, struct iscsi_hdr *hdr) + /* noop out rsp */ + actor_delete(&conn->nop_out_timer); + /* schedule a new ping */ +- actor_timer(&conn->nop_out_timer, conn->noop_out_interval*1000, ++ actor_timer(&conn->nop_out_timer, conn->noop_out_interval, + conn_send_nop_out, conn); + } else /* noop in req */ + if (!__send_nopin_rsp(conn, (struct iscsi_nopin*)hdr, +@@ -1159,7 +1171,7 @@ static void iscsi_recv_logout_rsp(iscsi_conn_t *conn, struct iscsi_hdr *hdr) + { + struct iscsi_logout_rsp *logout_rsp = (struct iscsi_logout_rsp *)hdr; + +- log_debug(3, "Recv: logout response %d\n", logout_rsp->response); ++ log_debug(3, "Recv: logout response %d", logout_rsp->response); + if (logout_rsp->response == 2 || logout_rsp->response == 3) { + conn->session->def_time2wait = ntohs(logout_rsp->t2wait); + log_debug(4, "logout rsp returned time2wait %u", +@@ -1177,7 +1189,7 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr) + unsigned int senselen; + struct scsi_sense_hdr sshdr; + +- log_debug(3, "Read AEN %d\n", async_hdr->async_event); ++ log_debug(3, "Read AEN %d", async_hdr->async_event); + + switch (async_hdr->async_event) { + case ISCSI_ASYNC_MSG_SCSI_EVENT: +@@ -1195,33 +1207,33 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr) + break; + case ISCSI_ASYNC_MSG_REQUEST_LOGOUT: + log_warning("Target requests logout within %u seconds for " +- "connection\n", ntohs(async_hdr->param3)); ++ "connection", ntohs(async_hdr->param3)); + if (iscsi_send_logout(conn)) + log_error("Could not send logout in response to" +- "logout request aen\n"); ++ "logout request aen"); + break; + case ISCSI_ASYNC_MSG_DROPPING_CONNECTION: + log_warning("Target dropping connection %u, reconnect min %u " +- "max %u\n", ntohs(async_hdr->param1), ++ "max %u", ntohs(async_hdr->param1), + ntohs(async_hdr->param2), ntohs(async_hdr->param3)); + session->def_time2wait = + (uint32_t)ntohs(async_hdr->param2) & 0x0000FFFFFL; + break; + case ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS: + log_warning("Target dropping all connections, reconnect min %u " +- "max %u\n", ntohs(async_hdr->param2), ++ "max %u", ntohs(async_hdr->param2), + ntohs(async_hdr->param3)); + session->def_time2wait = + (uint32_t)ntohs(async_hdr->param2) & 0x0000FFFFFL; + break; + case ISCSI_ASYNC_MSG_PARAM_NEGOTIATION: + log_warning("Received async event param negotiation, " +- "dropping session\n"); ++ "dropping session"); + __conn_error_handle(session, conn); + break; + case ISCSI_ASYNC_MSG_VENDOR_SPECIFIC: + default: +- log_warning("AEN not supported\n"); ++ log_warning("AEN not supported"); + } + } + +@@ -1336,7 +1348,7 @@ static void session_conn_recv_pdu(void *data) + break; + default: + iscsi_ev_context_put(ev_context); +- log_error("Invalid state. Dropping PDU.\n"); ++ log_error("Invalid state. Dropping PDU."); + } + } + +@@ -1420,7 +1432,7 @@ static void session_increase_wq_priority(struct iscsi_session *session) + fail: + log_error("Could not set session%d priority. " + "READ/WRITE throughout and latency could be " +- "affected.\n", session->id); ++ "affected.", session->id); + } + + static int session_ipc_create(struct iscsi_session *session) +@@ -1469,6 +1481,11 @@ static void setup_offload_login_phase(iscsi_conn_t *conn) + return; + } + ++ if (iscsi_session_set_neg_params(conn)) { ++ iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN); ++ return; ++ } ++ + if (iscsi_host_set_params(session)) { + iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN); + return; +@@ -1511,7 +1528,6 @@ static void session_conn_poll(void *data) + rc = session->t->template->ep_poll(conn, 1); + if (rc == 0) { + log_debug(4, "poll not connected %d", rc); +- /* timedout: Poll again. */ + ev_context = iscsi_ev_context_get(conn, 0); + if (!ev_context) { + /* while polling the recv pool should be full */ +@@ -1521,7 +1537,8 @@ static void session_conn_poll(void *data) + return; + } + ev_context->data = qtask; +- iscsi_sched_ev_context(ev_context, conn, 0, EV_CONN_POLL); ++ /* not connected yet, check later */ ++ iscsi_sched_ev_context(ev_context, conn, 1, EV_CONN_POLL); + } else if (rc > 0) { + /* connected! */ + memset(c, 0, sizeof(iscsi_login_context_t)); +@@ -1554,7 +1571,9 @@ static void session_conn_poll(void *data) + * TODO: use the iface number or some other value + * so this will be persistent + */ +- session->isid[3] = session->id; ++ session->isid[3] = (session->id >> 16) & 0xff; ++ session->isid[4] = (session->id >> 8) & 0xff; ++ session->isid[5] = session->id & 0xff; + + if (ipc->bind_conn(session->t->handle, session->id, + conn->id, conn->transport_ep_handle, +@@ -1580,6 +1599,16 @@ static void session_conn_poll(void *data) + return; + } + ++ if (iscsi_session_set_params(conn)) { ++ iscsi_login_eh(conn, qtask, ISCSI_ERR_LOGIN); ++ return; ++ } ++ ++ if (iscsi_host_set_params(session)) { ++ iscsi_login_eh(conn, qtask, ISCSI_ERR_LOGIN); ++ return; ++ } ++ + if (iscsi_login_begin(session, c)) { + iscsi_login_eh(conn, qtask, ISCSI_ERR_LOGIN); + return; +@@ -1618,6 +1647,9 @@ static void session_conn_process_login(void *data) + if (state == ISCSI_CONN_STATE_FREE) + goto failed_login; + ++ if (conn->state == ISCSI_CONN_STATE_LOGGED_IN) ++ return; ++ + conn->state = ISCSI_CONN_STATE_LOGGED_IN; + /* + * ok we were in_login and now we got the notification that we are +@@ -1679,14 +1711,14 @@ static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context, + ev_context->conn = conn; + switch (event) { + case EV_CONN_RECV_PDU: +- actor_new(&ev_context->actor, session_conn_recv_pdu, ++ actor_init(&ev_context->actor, session_conn_recv_pdu, + ev_context); + actor_schedule(&ev_context->actor); + break; + case EV_CONN_ERROR: + error = *(enum iscsi_err *)ev_context->data; + +- actor_new(&ev_context->actor, session_conn_error, ++ actor_init(&ev_context->actor, session_conn_error, + ev_context); + /* + * We handle invalid host, by killing the session. +@@ -1699,21 +1731,20 @@ static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context, + actor_schedule(&ev_context->actor); + break; + case EV_CONN_LOGIN: +- actor_new(&ev_context->actor, session_conn_process_login, ++ actor_init(&ev_context->actor, session_conn_process_login, + ev_context); + actor_schedule(&ev_context->actor); + break; + case EV_CONN_POLL: +- actor_new(&ev_context->actor, session_conn_poll, +- ev_context); +- actor_schedule(&ev_context->actor); ++ actor_timer(&ev_context->actor, tmo, ++ session_conn_poll, ev_context); + break; + case EV_CONN_LOGOUT_TIMER: +- actor_timer(&ev_context->actor, tmo * 1000, ++ actor_timer(&ev_context->actor, tmo, + iscsi_logout_timedout, ev_context); + break; + case EV_CONN_STOP: +- actor_new(&ev_context->actor, iscsi_stop, ++ actor_init(&ev_context->actor, iscsi_stop, + ev_context); + actor_schedule(&ev_context->actor); + break; +@@ -1752,14 +1783,14 @@ static int session_is_running(node_rec_t *rec) + if (session_find_by_rec(rec)) + return 1; + +- if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session)) ++ if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session, ++ 0)) + return 1; + + return 0; + } + +-int +-session_login_task(node_rec_t *rec, queue_task_t *qtask) ++static int __session_login_task(node_rec_t *rec, queue_task_t *qtask) + { + iscsi_session_t *session; + iscsi_conn_t *conn; +@@ -1782,7 +1813,7 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask) + (!(t->caps & CAP_RECOVERY_L1) && + rec->session.iscsi.ERL > 1)) { + log_error("Transport '%s' does not support ERL %d." +- "Setting ERL to ERL0.\n", ++ "Setting ERL to ERL0.", + t->name, rec->session.iscsi.ERL); + rec->session.iscsi.ERL = 0; + } +@@ -1815,19 +1846,21 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask) + if (!(t->caps & CAP_MARKERS) && + rec->conn[0].iscsi.IFMarker) { + log_error("Transport '%s' does not support IFMarker. " +- "Disabling IFMarkers.\n", t->name); ++ "Disabling IFMarkers.", t->name); + rec->conn[0].iscsi.IFMarker = 0; + } + + if (!(t->caps & CAP_MARKERS) && + rec->conn[0].iscsi.OFMarker) { + log_error("Transport '%s' does not support OFMarker." +- "Disabling OFMarkers.\n", t->name); ++ "Disabling OFMarkers.", t->name); + rec->conn[0].iscsi.OFMarker = 0; + } + +- session = __session_create(rec, t); +- if (!session) ++ session = __session_create(rec, t, &rc); ++ if (rc == ISCSI_ERR_HOST_NOT_FOUND) ++ return rc; ++ else if (!session) + return ISCSI_ERR_LOGIN; + + /* FIXME: login all connections! marked as "automatic" */ +@@ -1841,7 +1874,15 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask) + conn = &session->conn[0]; + qtask->conn = conn; + +- if (iscsi_host_set_net_params(&rec->iface, session)) { ++ rc = iscsi_host_set_net_params(&rec->iface, session); ++ if (rc == ISCSI_ERR_AGAIN) { ++ /* ++ * host/iscsiuio not ready. Cannot block iscsid, so caller is ++ * going to internally retry the operation. ++ */ ++ __session_destroy(session); ++ return ISCSI_ERR_HOST_NOT_FOUND; ++ } else if (rc) { + __session_destroy(session); + return ISCSI_ERR_LOGIN; + } +@@ -1857,7 +1898,7 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask) + + if (iscsi_conn_connect(conn, qtask)) { + log_debug(4, "Initial connect failed. Waiting %u seconds " +- "before trying to reconnect.\n", ++ "before trying to reconnect.", + ISCSI_CONN_ERR_REOPEN_DELAY); + queue_delayed_reopen(qtask, ISCSI_CONN_ERR_REOPEN_DELAY); + } +@@ -1865,6 +1906,74 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask) + return ISCSI_SUCCESS; + } + ++int ++session_login_task(node_rec_t *rec, queue_task_t *qtask) ++{ ++ int rc; ++ ++ rc = __session_login_task(rec, qtask); ++ if (rc == ISCSI_ERR_HOST_NOT_FOUND) { ++ rc = queue_session_login_task_retry(NULL, rec, qtask); ++ if (rc) ++ return rc; ++ /* ++ * we are going to internally retry. Will return final rc ++ * when completed ++ */ ++ return ISCSI_SUCCESS; ++ } ++ return rc; ++} ++ ++static void session_login_task_retry(void *data) ++{ ++ struct login_task_retry_info *info = data; ++ struct node_rec *rec = info->rec; ++ int rc; ++ ++ rc = __session_login_task(rec, info->qtask); ++ if (rc == ISCSI_ERR_HOST_NOT_FOUND) { ++ if (info->retry_count == rec->conn[0].timeo.login_timeout) { ++ /* give up */ ++ goto write_rsp; ++ } ++ ++ rc = queue_session_login_task_retry(info, rec, info->qtask); ++ if (rc) ++ goto write_rsp; ++ /* we are going to internally retry */ ++ return; ++ } else if (rc) { ++ /* hard error - no retry */ ++ goto write_rsp; ++ } else ++ /* successfully started login operation */ ++ goto free; ++write_rsp: ++ mgmt_ipc_write_rsp(info->qtask, rc); ++free: ++ free(info); ++} ++ ++static int queue_session_login_task_retry(struct login_task_retry_info *info, ++ node_rec_t *rec, queue_task_t *qtask) ++{ ++ if (!info) { ++ info = malloc(sizeof(*info)); ++ if (!info) ++ return ISCSI_ERR_NOMEM; ++ memset(info, 0, sizeof(*info)); ++ info->qtask = qtask; ++ info->rec = rec; ++ } ++ ++ info->retry_count++; ++ log_debug(4, "queue session setup attempt in %d secs, retries %d", ++ 1, info->retry_count); ++ actor_timer(&info->retry_actor, 1, session_login_task_retry, info); ++ return 0; ++} ++ + static int + sync_conn(iscsi_session_t *session, uint32_t cid) + { +@@ -1892,14 +2001,14 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid) + if (!t) + return ISCSI_ERR_TRANS_NOT_FOUND; + +- session = __session_create(rec, t); ++ session = __session_create(rec, t, &err); + if (!session) + return ISCSI_ERR_LOGIN; + + session->id = sid; + session->hostno = iscsi_sysfs_get_host_no_from_sid(sid, &err); + if (err) { +- log_error("Could not get hostno for session %d\n", sid); ++ log_error("Could not get hostno for session %d", sid); + goto destroy_session; + } + +@@ -1920,7 +2029,7 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid) + + destroy_session: + __session_destroy(session); +- log_error("Could not sync session%d err %d\n", sid, err); ++ log_error("Could not sync session%d err %d", sid, err); + return err; + } + +@@ -1931,10 +2040,199 @@ static int session_unbind(struct iscsi_session *session) + err = ipc->unbind_session(session->t->handle, session->id); + if (err) + /* older kernels did not support unbind */ +- log_debug(2, "Could not unbind session %d.\n", err); ++ log_debug(2, "Could not unbind session %d.", err); + return err; + } + ++static struct libmnt_table *mtab, *swaps; ++ ++static void libmount_cleanup(void) ++{ ++ mnt_free_table(mtab); ++ mnt_free_table(swaps); ++ mtab = swaps = NULL; ++} ++ ++static int libmount_init(void) ++{ ++ mnt_init_debug(0); ++ mtab = mnt_new_table(); ++ swaps = mnt_new_table(); ++ if (!mtab || !swaps) { ++ libmount_cleanup(); ++ return -ENOMEM; ++ } ++ mnt_table_parse_mtab(mtab, NULL); ++ mnt_table_parse_swaps(swaps, NULL); ++ return 0; ++} ++ ++static int trans_filter(const struct dirent *d) ++{ ++ if (!strcmp(".", d->d_name) || !strcmp("..", d->d_name)) ++ return 0; ++ return 1; ++} ++ ++static int subdir_filter(const struct dirent *d) ++{ ++ if (!(d->d_type & DT_DIR)) ++ return 0; ++ return trans_filter(d); ++} ++ ++static int is_partition(const char *path) ++{ ++ char *devtype; ++ int rc = 0; ++ ++ devtype = sysfs_get_uevent_devtype(path); ++ if (!devtype) ++ return 0; ++ if (strcmp(devtype, "partition") == 0) ++ rc = 1; ++ free(devtype); ++ return rc; ++} ++ ++static int blockdev_check_mnts(char *syspath) ++{ ++ struct libmnt_fs *fs; ++ char *devname = NULL; ++ char *_devname = NULL; ++ int rc = 0; ++ ++ devname = sysfs_get_uevent_devname(syspath); ++ if (!devname) ++ goto out; ++ ++ _devname = calloc(1, PATH_MAX); ++ if (!_devname) ++ goto out; ++ snprintf(_devname, PATH_MAX, "/dev/%s", devname); ++ ++ fs = mnt_table_find_source(mtab, _devname, MNT_ITER_FORWARD); ++ if (fs) { ++ rc = 1; ++ goto out; ++ } ++ fs = mnt_table_find_source(swaps, _devname, MNT_ITER_FORWARD); ++ if (fs) ++ rc = 1; ++out: ++ free(devname); ++ free(_devname); ++ return rc; ++} ++ ++static int count_device_users(char *syspath); ++ ++static int blockdev_get_partitions(char *syspath) ++{ ++ struct dirent **parts = NULL; ++ int n, i; ++ int count = 0; ++ ++ n = scandir(syspath, &parts, subdir_filter, alphasort); ++ for (i = 0; i < n; i++) { ++ char *newpath; ++ ++ newpath = calloc(1, PATH_MAX); ++ if (!newpath) ++ continue; ++ snprintf(newpath, PATH_MAX, "%s/%s", syspath, parts[i]->d_name); ++ free(parts[i]); ++ if (is_partition(newpath)) { ++ count += count_device_users(newpath); ++ } ++ free(newpath); ++ } ++ free(parts); ++ return count; ++} ++ ++static int blockdev_get_holders(char *syspath) ++{ ++ char *path = NULL; ++ struct dirent **holds = NULL; ++ int n, i; ++ int count = 0; ++ ++ path = calloc(1, PATH_MAX); ++ if (!path) ++ return 0; ++ snprintf(path, PATH_MAX, "%s/holders", syspath); ++ ++ n = scandir(path, &holds, trans_filter, alphasort); ++ for (i = 0; i < n; i++) { ++ char *newpath; ++ char *rp; ++ ++ newpath = calloc(1, PATH_MAX); ++ if (!newpath) ++ continue; ++ snprintf(newpath, PATH_MAX, "%s/%s", path, holds[i]->d_name); ++ ++ free(holds[i]); ++ rp = realpath(newpath, NULL); ++ if (rp) ++ count += count_device_users(rp); ++ free(newpath); ++ free(rp); ++ } ++ free(path); ++ free(holds); ++ return count; ++} ++ ++static int count_device_users(char *syspath) ++{ ++ int count = 0; ++ count += blockdev_check_mnts(syspath); ++ count += blockdev_get_partitions(syspath); ++ count += blockdev_get_holders(syspath); ++ return count; ++}; ++ ++static void device_in_use(void *data, int host_no, int target, int lun) ++{ ++ char *syspath = NULL; ++ char *devname = NULL; ++ int *count = data; ++ ++ devname = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun); ++ if (!devname) ++ goto out; ++ syspath = calloc(1, PATH_MAX); ++ if (!syspath) ++ goto out; ++ snprintf(syspath, PATH_MAX, "/sys/class/block/%s", devname); ++ *count += count_device_users(syspath); ++out: ++ free(syspath); ++ free(devname); ++} ++ ++static int session_in_use(int sid) ++{ ++ int host_no = -1, err = 0; ++ int count = 0; ++ ++ if (libmount_init()) { ++ log_error("Failed to initialize libmount, " ++ "not checking for active mounts on session [%d].", ++ sid); ++ return 0; ++ } ++ ++ host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err); ++ if (!err) ++ iscsi_sysfs_for_each_device(&count, host_no, sid, device_in_use); ++ ++ libmount_cleanup(); ++ return count; ++} ++ + int session_logout_task(int sid, queue_task_t *qtask) + { + iscsi_session_t *session; +@@ -1943,7 +2241,7 @@ int session_logout_task(int sid, queue_task_t *qtask) + + session = session_find_by_sid(sid); + if (!session) { +- log_debug(1, "session sid %d not found.\n", sid); ++ log_debug(1, "session sid %d not found.", sid); + return ISCSI_ERR_SESS_NOT_FOUND; + } + conn = &session->conn[0]; +@@ -1958,10 +2256,16 @@ int session_logout_task(int sid, queue_task_t *qtask) + session->r_stage == R_STAGE_SESSION_REDIRECT))) { + invalid_state: + log_error("session in invalid state for logout. " +- "Try again later\n"); ++ "Try again later"); + return ISCSI_ERR_INTERNAL; + } + ++ if (dconfig->safe_logout && session_in_use(sid)) { ++ log_error("Session is actively in use for mounted storage, " ++ "and iscsid.safe_logout is configured."); ++ return ISCSI_ERR_BUSY; ++ } ++ + /* FIXME: logout all active connections */ + conn = &session->conn[0]; + if (conn->logout_qtask) +@@ -1983,7 +2287,7 @@ invalid_state: + return ISCSI_SUCCESS; + } + +- log_error("Could not send logout pdu. Dropping session\n"); ++ log_error("Could not send logout pdu. Dropping session"); + /* fallthrough */ + default: + rc = session_conn_shutdown(conn, qtask, ISCSI_SUCCESS); +@@ -2001,7 +2305,7 @@ iscsi_host_send_targets(queue_task_t *qtask, int host_no, int do_login, + + t = iscsi_sysfs_get_transport_by_hba(host_no); + if (!t) { +- log_error("Invalid host no %d for sendtargets\n", host_no); ++ log_error("Invalid host no %d for sendtargets", host_no); + return ISCSI_ERR_TRANS_NOT_FOUND; + } + if (!(t->caps & CAP_SENDTARGETS_OFFLOAD)) +diff --git a/usr/initiator.h b/usr/initiator.h +index b45caab..c11d77f 100644 +--- a/usr/initiator.h ++++ b/usr/initiator.h +@@ -343,6 +343,7 @@ extern void free_initiator(void); + extern void iscsi_initiator_init(void); + + /* initiator code common to discovery and normal sessions */ ++extern int iscsi_session_set_neg_params(struct iscsi_conn *conn); + extern int iscsi_session_set_params(struct iscsi_conn *conn); + extern int iscsi_host_set_params(struct iscsi_session *session); + extern int iscsi_host_set_net_params(struct iface_rec *iface, +@@ -353,5 +354,9 @@ extern void iscsi_copy_operational_params(struct iscsi_conn *conn, + extern int iscsi_setup_authentication(struct iscsi_session *session, + struct iscsi_auth_config *auth_cfg); + extern int iscsi_setup_portal(struct iscsi_conn *conn, char *address, int port); ++extern int iscsi_set_net_config(struct iscsi_transport *t, ++ iscsi_session_t *session, ++ struct iface_rec *iface); ++extern void iscsi_session_init_params(struct iscsi_session *session); + + #endif /* INITIATOR_H */ +diff --git a/usr/initiator_common.c b/usr/initiator_common.c +index ef6820c..c02643a 100644 +--- a/usr/initiator_common.c ++++ b/usr/initiator_common.c +@@ -51,21 +51,9 @@ struct iscsi_session *session_find_by_sid(uint32_t sid) + return NULL; + } + +-/* +- * calculate parameter's padding +- */ +-static unsigned int +-__padding(unsigned int param) ++const static unsigned int align_32_down(unsigned int param) + { +- int pad; +- +- pad = param & 3; +- if (pad) { +- pad = 4 - pad; +- log_debug(1, "parameter's value %d padded to %d bytes\n", +- param, param + pad); +- } +- return param + pad; ++ return param & ~0x3; + } + + int iscsi_setup_authentication(struct iscsi_session *session, +@@ -77,7 +65,7 @@ int iscsi_setup_authentication(struct iscsi_session *session, + if (auth_cfg->username_in[0] || auth_cfg->password_in_length) { + /* sanity check the config */ + if (auth_cfg->password_length == 0) { +- log_warning("CHAP configuratoin has incoming " ++ log_warning("CHAP configuration has incoming " + "authentication credentials but has no " + "outgoing credentials configured."); + return EINVAL; +@@ -151,11 +139,11 @@ iscsi_copy_operational_params(struct iscsi_conn *conn, + conn->datadgst_en = conn_conf->DataDigest; + + conn->max_recv_dlength = +- __padding(conn_conf->MaxRecvDataSegmentLength); ++ align_32_down(conn_conf->MaxRecvDataSegmentLength); + if (conn->max_recv_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN || + conn->max_recv_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) { + log_error("Invalid iscsi.MaxRecvDataSegmentLength. Must be " +- "within %u and %u. Setting to %u\n", ++ "within %u and %u. Setting to %u", + ISCSI_MIN_MAX_RECV_SEG_LEN, + ISCSI_MAX_MAX_RECV_SEG_LEN, + DEF_INI_MAX_RECV_SEG_LEN); +@@ -166,13 +154,13 @@ iscsi_copy_operational_params(struct iscsi_conn *conn, + + /* zero indicates to use the target's value */ + conn->max_xmit_dlength = +- __padding(conn_conf->MaxXmitDataSegmentLength); ++ align_32_down(conn_conf->MaxXmitDataSegmentLength); + if (conn->max_xmit_dlength == 0) + conn->max_xmit_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN; + if (conn->max_xmit_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN || + conn->max_xmit_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) { + log_error("Invalid iscsi.MaxXmitDataSegmentLength. Must be " +- "within %u and %u. Setting to %u\n", ++ "within %u and %u. Setting to %u", + ISCSI_MIN_MAX_RECV_SEG_LEN, + ISCSI_MAX_MAX_RECV_SEG_LEN, + DEF_INI_MAX_RECV_SEG_LEN); +@@ -184,7 +172,7 @@ iscsi_copy_operational_params(struct iscsi_conn *conn, + /* session's operational parameters */ + session->initial_r2t_en = session_conf->InitialR2T; + session->imm_data_en = session_conf->ImmediateData; +- session->first_burst = __padding(session_conf->FirstBurstLength); ++ session->first_burst = align_32_down(session_conf->FirstBurstLength); + /* + * some targets like netapp fail the login if sent bad first_burst + * and max_burst lens, even when immediate data=no and +@@ -193,7 +181,7 @@ iscsi_copy_operational_params(struct iscsi_conn *conn, + if (session->first_burst < ISCSI_MIN_FIRST_BURST_LEN || + session->first_burst > ISCSI_MAX_FIRST_BURST_LEN) { + log_error("Invalid iscsi.FirstBurstLength of %u. Must be " +- "within %u and %u. Setting to %u\n", ++ "within %u and %u. Setting to %u", + session->first_burst, + ISCSI_MIN_FIRST_BURST_LEN, + ISCSI_MAX_FIRST_BURST_LEN, +@@ -202,11 +190,11 @@ iscsi_copy_operational_params(struct iscsi_conn *conn, + session->first_burst = DEF_INI_FIRST_BURST_LEN; + } + +- session->max_burst = __padding(session_conf->MaxBurstLength); ++ session->max_burst = align_32_down(session_conf->MaxBurstLength); + if (session->max_burst < ISCSI_MIN_MAX_BURST_LEN || + session->max_burst > ISCSI_MAX_MAX_BURST_LEN) { + log_error("Invalid iscsi.MaxBurstLength of %u. Must be " +- "within %u and %u. Setting to %u\n", ++ "within %u and %u. Setting to %u", + session->max_burst, ISCSI_MIN_MAX_BURST_LEN, + ISCSI_MAX_MAX_BURST_LEN, DEF_INI_MAX_BURST_LEN); + session_conf->MaxBurstLength = DEF_INI_MAX_BURST_LEN; +@@ -215,7 +203,7 @@ iscsi_copy_operational_params(struct iscsi_conn *conn, + + if (session->first_burst > session->max_burst) { + log_error("Invalid iscsi.FirstBurstLength of %u. Must be " +- "less than iscsi.MaxBurstLength. Setting to %u\n", ++ "less than iscsi.MaxBurstLength. Setting to %u", + session->first_burst, session->max_burst); + session_conf->FirstBurstLength = session->max_burst; + session->first_burst = session->max_burst; +@@ -261,7 +249,7 @@ int iscsi_setup_portal(struct iscsi_conn *conn, char *address, int port) + return 0; + } + +-int host_set_param(struct iscsi_transport *t, ++static int host_set_param(struct iscsi_transport *t, + uint32_t host_no, int param, char *value, + int type) + { +@@ -273,7 +261,7 @@ int host_set_param(struct iscsi_transport *t, + log_error("can't set operational parameter %d for " + "host %d, retcode %d (%d)", param, host_no, + rc, errno); +- return rc; ++ return ISCSI_ERR_INVAL; + } + return 0; + } +@@ -324,12 +312,32 @@ int iscsi_host_set_params(struct iscsi_session *session) + return 0; + } + +-#define MAX_SESSION_PARAMS 32 ++static inline void iscsi_session_clear_param(struct iscsi_session *session, ++ int param) ++{ ++ session->param_mask &= ~(1ULL << param); ++} + +-int iscsi_session_set_params(struct iscsi_conn *conn) ++void iscsi_session_init_params(struct iscsi_session *session) ++{ ++ session->param_mask = ~0ULL; ++ if (!(session->t->caps & CAP_MULTI_R2T)) ++ iscsi_session_clear_param(session, ISCSI_PARAM_MAX_R2T); ++ if (!(session->t->caps & CAP_HDRDGST)) ++ iscsi_session_clear_param(session, ISCSI_PARAM_HDRDGST_EN); ++ if (!(session->t->caps & CAP_DATADGST)) ++ iscsi_session_clear_param(session, ISCSI_PARAM_DATADGST_EN); ++ if (!(session->t->caps & CAP_MARKERS)) { ++ iscsi_session_clear_param(session, ISCSI_PARAM_IFMARKER_EN); ++ iscsi_session_clear_param(session, ISCSI_PARAM_OFMARKER_EN); ++ } ++} ++ ++#define MAX_SESSION_NEG_PARAMS 16 ++ ++int iscsi_session_set_neg_params(struct iscsi_conn *conn) + { + struct iscsi_session *session = conn->session; +- struct iscsi_transport *t = session->t; + int i, rc; + uint32_t one = 1, zero = 0; + struct connparam { +@@ -337,7 +345,7 @@ int iscsi_session_set_params(struct iscsi_conn *conn) + int type; + void *value; + int conn_only; +- } conntbl[MAX_SESSION_PARAMS] = { ++ } conntbl[MAX_SESSION_NEG_PARAMS] = { + { + .param = ISCSI_PARAM_MAX_RECV_DLENGTH, + .value = &conn->max_recv_dlength, +@@ -411,18 +419,61 @@ int iscsi_session_set_params(struct iscsi_conn *conn) + }, { + .param = ISCSI_PARAM_EXP_STATSN, + .value = &conn->exp_statsn, +- .type = ISCSI_INT, ++ .type = ISCSI_UINT, + .conn_only = 1, + }, { +- .param = ISCSI_PARAM_TARGET_NAME, +- .conn_only = 0, +- .type = ISCSI_STRING, +- .value = session->target_name, +- }, { + .param = ISCSI_PARAM_TPGT, + .value = &session->portal_group_tag, + .type = ISCSI_INT, + .conn_only = 0, ++ }, ++ }; ++ ++ iscsi_session_init_params(session); ++ ++ /* Entered full-feature phase! */ ++ for (i = 0; i < MAX_SESSION_NEG_PARAMS; i++) { ++ if (conn->id != 0 && !conntbl[i].conn_only) ++ continue; ++ ++ if (!(session->param_mask & (1ULL << conntbl[i].param))) ++ continue; ++ ++ rc = ipc->set_param(session->t->handle, session->id, ++ conn->id, conntbl[i].param, conntbl[i].value, ++ conntbl[i].type); ++ if (rc && rc != -ENOSYS) { ++ log_error("can't set operational parameter %d for " ++ "connection %d:%d, retcode %d (%d)", ++ conntbl[i].param, session->id, conn->id, ++ rc, errno); ++ return EPERM; ++ } ++ ++ print_param_value(conntbl[i].param, conntbl[i].value, ++ conntbl[i].type); ++ } ++ ++ return 0; ++} ++ ++#define MAX_SESSION_PARAMS 20 ++ ++int iscsi_session_set_params(struct iscsi_conn *conn) ++{ ++ struct iscsi_session *session = conn->session; ++ int i, rc; ++ struct connparam { ++ int param; ++ int type; ++ void *value; ++ int conn_only; ++ } conntbl[MAX_SESSION_PARAMS] = { ++ { ++ .param = ISCSI_PARAM_TARGET_NAME, ++ .conn_only = 0, ++ .type = ISCSI_STRING, ++ .value = session->target_name, + }, { + .param = ISCSI_PARAM_PERSISTENT_ADDRESS, + .value = session->nrec.conn[conn->id].address, +@@ -492,29 +543,41 @@ int iscsi_session_set_params(struct iscsi_conn *conn) + .param = ISCSI_PARAM_IFACE_NAME, + .value = session->nrec.iface.name, + .type = ISCSI_STRING, ++ .conn_only = 0, + }, { + .param = ISCSI_PARAM_INITIATOR_NAME, + .value = session->initiator_name, + .type = ISCSI_STRING, ++ .conn_only = 0, ++ }, { ++ .param = ISCSI_PARAM_BOOT_ROOT, ++ .value = session->nrec.session.boot_root, ++ .type = ISCSI_STRING, ++ .conn_only = 0, ++ }, { ++ .param = ISCSI_PARAM_BOOT_NIC, ++ .value = session->nrec.session.boot_nic, ++ .type = ISCSI_STRING, ++ .conn_only = 0, ++ }, { ++ .param = ISCSI_PARAM_BOOT_TARGET, ++ .value = session->nrec.session.boot_target, ++ .type = ISCSI_STRING, ++ .conn_only = 0, ++ }, { ++ .param = ISCSI_PARAM_DISCOVERY_SESS, ++ .value = &session->type, ++ .type = ISCSI_INT, ++ .conn_only = 0, + }, + }; + +- session->param_mask = ~0ULL; +- if (!(t->caps & CAP_MULTI_R2T)) +- session->param_mask &= ~ISCSI_MAX_R2T; +- if (!(t->caps & CAP_HDRDGST)) +- session->param_mask &= ~ISCSI_HDRDGST_EN; +- if (!(t->caps & CAP_DATADGST)) +- session->param_mask &= ~ISCSI_DATADGST_EN; +- if (!(t->caps & CAP_MARKERS)) { +- session->param_mask &= ~ISCSI_IFMARKER_EN; +- session->param_mask &= ~ISCSI_OFMARKER_EN; +- } ++ iscsi_session_init_params(session); + + /* some llds will send nops internally */ + if (!iscsi_sysfs_session_supports_nop(session->id)) { +- session->param_mask &= ~ISCSI_PING_TMO; +- session->param_mask &= ~ISCSI_RECV_TMO; ++ iscsi_session_clear_param(session, ISCSI_PARAM_PING_TMO); ++ iscsi_session_clear_param(session, ISCSI_PARAM_RECV_TMO); + } + + /* Entered full-feature phase! */ +@@ -562,6 +625,36 @@ TODO handle this + return 0; + } + ++int iscsi_set_net_config(struct iscsi_transport *t, iscsi_session_t *session, ++ struct iface_rec *iface) ++{ ++ if (t->template->set_net_config) { ++ /* uip needs the netdev name */ ++ struct host_info hinfo; ++ int hostno, rc; ++ ++ /* this assumes that the netdev or hw address is going to be ++ set */ ++ hostno = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc); ++ if (rc) { ++ log_debug(4, "Couldn't get host no."); ++ return rc; ++ } ++ ++ /* uip needs the netdev name */ ++ if (!strlen(iface->netdev)) { ++ memset(&hinfo, 0, sizeof(hinfo)); ++ hinfo.host_no = hostno; ++ iscsi_sysfs_get_hostinfo_by_host_no(&hinfo); ++ strcpy(iface->netdev, hinfo.iface.netdev); ++ } ++ ++ return t->template->set_net_config(t, iface, session); ++ } ++ ++ return 0; ++} ++ + int iscsi_host_set_net_params(struct iface_rec *iface, + struct iscsi_session *session) + { +@@ -571,7 +664,7 @@ int iscsi_host_set_net_params(struct iface_rec *iface, + struct host_info hinfo; + + log_debug(3, "setting iface %s, dev %s, set ip %s, hw %s, " +- "transport %s.\n", ++ "transport %s.", + iface->name, iface->netdev, iface->ipaddress, + iface->hwaddress, iface->transport_name); + +@@ -580,9 +673,18 @@ int iscsi_host_set_net_params(struct iface_rec *iface, + + /* if we need to set the ip addr then set all the iface net settings */ + if (!iface_is_bound_by_ipaddr(iface)) { +- log_warning("Please set the iface.ipaddress for iface %s, " +- "then retry the login command.\n", iface->name); +- return EINVAL; ++ if (t->template->set_host_ip == SET_HOST_IP_REQ) { ++ log_warning("Please set the iface.ipaddress for iface " ++ "%s, then retry the login command.", ++ iface->name); ++ return ISCSI_ERR_INVAL; ++ } else if (t->template->set_host_ip == SET_HOST_IP_OPT) { ++ log_info("Optional iface.ipaddress for iface %s " ++ "not set.", iface->name); ++ return 0; ++ } else { ++ return ISCSI_ERR_INVAL; ++ } + } + + /* these type of drivers need the netdev upd */ +@@ -600,6 +702,10 @@ int iscsi_host_set_net_params(struct iface_rec *iface, + log_warning("Could not brining up netdev %s. Try running " + "'ifup %s' first if login fails.", netdev, netdev); + ++ rc = iscsi_set_net_config(t, session, iface); ++ if (rc != 0) ++ return rc; ++ + rc = host_set_param(t, session->hostno, + ISCSI_HOST_PARAM_IPADDRESS, + iface->ipaddress, ISCSI_STRING); +diff --git a/usr/io.c b/usr/io.c +index 45adea5..f552e1e 100644 +--- a/usr/io.c ++++ b/usr/io.c +@@ -113,14 +113,14 @@ static int get_hwaddress_from_netdev(char *netdev, char *hwaddress) + (void *)&(s4->sin_addr), buf, + INET_ADDRSTRLEN)) + continue; +- log_debug(4, "name %s addr %s\n", ifa->ifa_name, buf); ++ log_debug(4, "name %s addr %s", ifa->ifa_name, buf); + break; + case AF_INET6: + s6 = (struct sockaddr_in6 *)(ifa->ifa_addr); + if (!inet_ntop(ifa->ifa_addr->sa_family, + (void *)&(s6->sin6_addr), buf, INET6_ADDRSTRLEN)) + continue; +- log_debug(4, "name %s addr %s\n", ifa->ifa_name, buf); ++ log_debug(4, "name %s addr %s", ifa->ifa_name, buf); + break; + default: + continue; +@@ -239,7 +239,7 @@ static int bind_conn_to_iface(iscsi_conn_t *conn, struct iface_rec *iface) + if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_BINDTODEVICE, + session->netdev, + strlen(session->netdev) + 1) < 0) { +- log_error("Could not bind connection %d to %s\n", ++ log_error("Could not bind connection %d to %s", + conn->id, session->netdev); + return -1; + } +@@ -357,7 +357,7 @@ iscsi_io_tcp_poll(iscsi_conn_t *conn, int timeout_ms) + len = sizeof(int); + if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_ERROR, + (char *) &rc, &len) < 0) { +- log_error("getsockopt for connect poll failed\n"); ++ log_error("getsockopt for connect poll failed"); + return -1; + } + if (rc) { +@@ -366,7 +366,7 @@ iscsi_io_tcp_poll(iscsi_conn_t *conn, int timeout_ms) + conn->host, sizeof(conn->host), serv, sizeof(serv), + NI_NUMERICHOST|NI_NUMERICSERV); + +- log_error("connect to %s:%s failed (%s)\n", ++ log_error("connect to %s:%s failed (%s)", + conn->host, serv, strerror(rc)); + return -rc; + } +diff --git a/usr/iscsi_err.c b/usr/iscsi_err.c +index 4fe1c53..11e0348 100644 +--- a/usr/iscsi_err.c ++++ b/usr/iscsi_err.c +@@ -51,6 +51,8 @@ static char *iscsi_err_msgs[] = { + /* 26 */ "iSNS registration failed", + /* 27 */ "operation not supported", + /* 28 */ "device or resource in use", ++ /* 29 */ "operation failed but retry may succeed", ++ /* 30 */ "unknown discovery type", + }; + + char *iscsi_err_to_str(int err) +diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h +index db5f1f0..5087b5c 100644 +--- a/usr/iscsi_ipc.h ++++ b/usr/iscsi_ipc.h +@@ -30,6 +30,7 @@ + + enum { + ISCSI_INT, ++ ISCSI_UINT, + ISCSI_STRING, + }; + +@@ -143,8 +144,26 @@ struct iscsi_ipc { + uint16_t chap_tbl_idx, uint32_t num_entries, + char *chap_buf, uint32_t *valid_chap_entries); + ++ int (*set_chap) (uint64_t transport_handle, uint32_t host_no, ++ struct iovec *iovs, uint32_t param_count); ++ + int (*delete_chap) (uint64_t transport_handle, uint32_t host_no, + uint16_t chap_tbl_idx); ++ int (*set_flash_node_params) (uint64_t transport_handle, ++ uint32_t host_no, uint32_t flashnode_idx, ++ struct iovec *iovs, uint32_t param_count); ++ int (*new_flash_node) (uint64_t transport_handle, uint32_t host_no, ++ void *value, uint32_t *flashnode_idx); ++ int (*del_flash_node) (uint64_t transport_handle, uint32_t host_no, ++ uint32_t flashnode_idx); ++ int (*login_flash_node) (uint64_t transport_handle, uint32_t host_no, ++ uint32_t flashnode_idx); ++ int (*logout_flash_node) (uint64_t transport_handle, uint32_t host_no, ++ uint32_t flashnode_idx); ++ int (*logout_flash_node_sid) (uint64_t transport_handle, ++ uint32_t host_no, uint32_t sid); ++ int (*get_host_stats) (uint64_t transport_handle, uint32_t host_no, ++ char *host_stats); + }; + + #endif /* ISCSI_IPC_H */ +diff --git a/usr/iscsi_net_util.c b/usr/iscsi_net_util.c +index 6d0ebf9..848b4c6 100644 +--- a/usr/iscsi_net_util.c ++++ b/usr/iscsi_net_util.c +@@ -188,7 +188,7 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway, + int ret; + + if (!strlen(netdev)) { +- log_error("No netdev name in fw entry.\n"); ++ log_error("No netdev name in fw entry."); + return EINVAL; + } + +@@ -203,13 +203,13 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway, + * has already been handled (2 targets in IBFT may share one NIC) + */ + if (!inet_aton(local_ip, &sk_ipaddr.sin_addr)) { +- log_error("Invalid or missing ipaddr in fw entry\n"); ++ log_error("Invalid or missing ipaddr in fw entry"); + ret = EINVAL; + goto done; + } + + if (!inet_aton(mask, &sk_netmask.sin_addr)) { +- log_error("Invalid or missing netmask in fw entry\n"); ++ log_error("Invalid or missing netmask in fw entry"); + ret = EINVAL; + goto done; + } +@@ -217,7 +217,7 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway, + inet_aton("255.255.255.255", &sk_hostmask.sin_addr); + + if (!inet_aton(remote_ip, &sk_tgt_ipaddr.sin_addr)) { +- log_error("Invalid or missing target ipaddr in fw entry\n"); ++ log_error("Invalid or missing target ipaddr in fw entry"); + ret = EINVAL; + goto done; + } +@@ -317,7 +317,7 @@ int net_ifup_netdev(char *netdev) + int ret = 0; + + if (!strlen(netdev)) { +- log_error("No netdev name in fw entry.\n"); ++ log_error("No netdev name in fw entry."); + return EINVAL; + } + +@@ -338,11 +338,11 @@ int net_ifup_netdev(char *netdev) + } + + if (ifr.ifr_flags & IFF_UP) { +- log_debug(3, "%s up\n", netdev); ++ log_debug(3, "%s up", netdev); + goto done; + } + +- log_debug(3, "bringing %s up\n", netdev); ++ log_debug(3, "bringing %s up", netdev); + + /* Bring up interface */ + memset(&ifr, 0, sizeof(ifr)); +diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c +index 123dde3..3a37a48 100644 +--- a/usr/iscsi_sysfs.c ++++ b/usr/iscsi_sysfs.c +@@ -24,11 +24,13 @@ + #include + #include + #include ++#include + + #include "log.h" + #include "initiator.h" + #include "transport.h" + #include "idbm.h" ++#include "idbm_fields.h" + #include "version.h" + #include "iscsi_sysfs.h" + #include "sysdeps.h" +@@ -37,6 +39,7 @@ + #include "session_info.h" + #include "host.h" + #include "iscsi_err.h" ++#include "flashnode.h" + + /* + * TODO: remove the _DIR defines and search for subsys dirs like +@@ -45,18 +48,22 @@ + #define ISCSI_TRANSPORT_DIR "/sys/class/iscsi_transport" + #define ISCSI_SESSION_DIR "/sys/class/iscsi_session" + #define ISCSI_HOST_DIR "/sys/class/iscsi_host" ++#define ISCSI_FLASHNODE_DIR "/sys/bus/iscsi_flashnode/devices" + + #define ISCSI_SESSION_SUBSYS "iscsi_session" + #define ISCSI_CONN_SUBSYS "iscsi_connection" + #define ISCSI_HOST_SUBSYS "iscsi_host" + #define ISCSI_TRANSPORT_SUBSYS "iscsi_transport" + #define ISCSI_IFACE_SUBSYS "iscsi_iface" ++#define ISCSI_FLASHNODE_SUBSYS "iscsi_flashnode" + #define SCSI_HOST_SUBSYS "scsi_host" + #define SCSI_SUBSYS "scsi" + + #define ISCSI_SESSION_ID "session%d" + #define ISCSI_CONN_ID "connection%d:0" + #define ISCSI_HOST_ID "host%d" ++#define ISCSI_FLASHNODE_SESS "flashnode_sess-%d:%d" ++#define ISCSI_FLASHNODE_CONN "flashnode_conn-%d:%d:0" + + /* + * TODO: make this into a real API and check inputs better and add doc. +@@ -130,7 +137,7 @@ static int read_transports(void) + if (list_empty(&t->list)) + free(t); + else +- log_error("Could not update %s.\n", ++ log_error("Could not update %s.", + t->name); + continue; + } +@@ -140,7 +147,7 @@ static int read_transports(void) + if (list_empty(&t->list)) + free(t); + else +- log_error("Could not update %s.\n", ++ log_error("Could not update %s.", + t->name); + continue; + } +@@ -265,7 +272,7 @@ uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err) + if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath), + ISCSI_SESSION_SUBSYS, id)) { + log_error("Could not lookup devpath for %s. Possible sysfs " +- "incompatibility.\n", id); ++ "incompatibility.", id); + *err = ISCSI_ERR_SYSFS_LOOKUP; + return 0; + } +@@ -273,7 +280,7 @@ uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err) + session_dev = sysfs_device_get(devpath); + if (!session_dev) { + log_error("Could not get dev for %s. Possible sysfs " +- "incompatibility.\n", id); ++ "incompatibility.", id); + *err = ISCSI_ERR_SYSFS_LOOKUP; + return 0; + } +@@ -298,7 +305,7 @@ uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err) + + if (!host_dev) { + log_error("Could not get host dev for %s. Possible " +- "sysfs incompatibility.\n", id); ++ "sysfs incompatibility.", id); + *err = ISCSI_ERR_SYSFS_LOOKUP; + return 0; + } +@@ -440,6 +447,271 @@ uint32_t iscsi_sysfs_get_host_no_from_hwinfo(struct iface_rec *iface, int *rc) + } + + /* ++ * Read the flash node attributes based on host and flash node index. ++ */ ++int iscsi_sysfs_get_flashnode_info(struct flashnode_rec *fnode, ++ uint32_t host_no, ++ uint32_t flashnode_idx) ++{ ++ char sess_id[NAME_SIZE] = {'\0'}; ++ char conn_id[NAME_SIZE] = {'\0'}; ++ char fnode_path[PATH_SIZE] = {'\0'}; ++ struct iscsi_transport *t; ++ int ret = 0; ++ ++ t = iscsi_sysfs_get_transport_by_hba(host_no); ++ if (!t) ++ log_debug(7, "could not get transport name for host%d", ++ host_no); ++ else ++ strncpy(fnode->transport_name, t->name, ++ ISCSI_TRANSPORT_NAME_MAXLEN); ++ ++ snprintf(sess_id, sizeof(sess_id), ISCSI_FLASHNODE_SESS, host_no, ++ flashnode_idx); ++ ++ snprintf(fnode_path, sizeof(fnode_path), ISCSI_FLASHNODE_DIR"/%s", ++ sess_id); ++ if (access(fnode_path, F_OK) != 0) ++ return errno; ++ ++ snprintf(conn_id, sizeof(conn_id), ISCSI_FLASHNODE_CONN, host_no, ++ flashnode_idx); ++ ++ snprintf(fnode_path, sizeof(fnode_path), ISCSI_FLASHNODE_DIR"/%s", ++ conn_id); ++ if (access(fnode_path, F_OK) != 0) ++ return errno; ++ ++ ++ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "is_fw_assigned_ipv6", ++ &((fnode->conn[0]).is_fw_assigned_ipv6)); ++ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "portal_type", ++ (fnode->sess).portal_type, ++ sizeof((fnode->sess).portal_type)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "auto_snd_tgt_disable", ++ &((fnode->sess).auto_snd_tgt_disable)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "discovery_session", ++ &((fnode->sess).discovery_session)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "entry_enable", ++ &((fnode->sess).entry_enable)); ++ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "header_digest", ++ &((fnode->conn[0]).header_digest_en)); ++ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "data_digest", ++ &((fnode->conn[0]).data_digest_en)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "immediate_data", ++ &((fnode->sess).immediate_data)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "initial_r2t", ++ &((fnode->sess).initial_r2t)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "data_seq_in_order", ++ &((fnode->sess).data_seq_in_order)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "data_pdu_in_order", ++ &((fnode->sess).data_pdu_in_order)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "chap_auth", ++ &((fnode->sess).chap_auth_en)); ++ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "snack_req", ++ &((fnode->conn[0]).snack_req_en)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "discovery_logout", ++ &((fnode->sess).discovery_logout_en)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "bidi_chap", ++ &((fnode->sess).bidi_chap_en)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, ++ "discovery_auth_optional", ++ &((fnode->sess).discovery_auth_optional)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "erl", ++ &((fnode->sess).erl)); ++ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_timestamp_stat", ++ &((fnode->conn[0]).tcp_timestamp_stat)); ++ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_nagle_disable", ++ &((fnode->conn[0]).tcp_nagle_disable)); ++ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_wsf_disable", ++ &((fnode->conn[0]).tcp_wsf_disable)); ++ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_timer_scale", ++ &((fnode->conn[0]).tcp_timer_scale)); ++ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_timestamp_enable", ++ &((fnode->conn[0]).tcp_timestamp_en)); ++ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "fragment_disable", ++ &((fnode->conn[0]).fragment_disable)); ++ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "max_recv_dlength", ++ &((fnode->conn[0]).max_recv_dlength)); ++ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "max_xmit_dlength", ++ &((fnode->conn[0]).max_xmit_dlength)); ++ sysfs_get_uint(sess_id, ISCSI_FLASHNODE_SUBSYS, "first_burst_len", ++ &((fnode->sess).first_burst_len)); ++ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "def_time2wait", ++ &((fnode->sess).def_time2wait)); ++ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "def_time2retain", ++ &((fnode->sess).def_time2retain)); ++ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "max_outstanding_r2t", ++ &((fnode->sess).max_outstanding_r2t)); ++ sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "keepalive_tmo", ++ &((fnode->conn[0]).keepalive_tmo)); ++ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "isid", ++ (fnode->sess).isid, sizeof((fnode->sess).isid)); ++ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "tsid", ++ &((fnode->sess).tsid)); ++ sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "port", ++ &((fnode->conn[0]).port)); ++ sysfs_get_uint(sess_id, ISCSI_FLASHNODE_SUBSYS, "max_burst_len", ++ &((fnode->sess).max_burst_len)); ++ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "def_taskmgmt_tmo", ++ &((fnode->sess).def_taskmgmt_tmo)); ++ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "targetalias", ++ (fnode->sess).targetalias, ++ sizeof((fnode->sess).targetalias)); ++ sysfs_get_str(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipaddress", ++ (fnode->conn[0]).ipaddress, ++ sizeof((fnode->conn[0]).ipaddress)); ++ sysfs_get_str(conn_id, ISCSI_FLASHNODE_SUBSYS, "redirect_ipaddr", ++ (fnode->conn[0]).redirect_ipaddr, ++ sizeof((fnode->conn[0]).redirect_ipaddr)); ++ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "max_segment_size", ++ &((fnode->conn[0]).max_segment_size)); ++ sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "local_port", ++ &((fnode->conn[0]).local_port)); ++ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipv4_tos", ++ &((fnode->conn[0]).ipv4_tos)); ++ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipv6_traffic_class", ++ &((fnode->conn[0]).ipv6_traffic_class)); ++ sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipv6_flow_label", ++ &((fnode->conn[0]).ipv6_flow_lbl)); ++ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "targetname", ++ (fnode->sess).targetname, ++ sizeof((fnode->sess).targetname)); ++ sysfs_get_str(conn_id, ISCSI_FLASHNODE_SUBSYS, "link_local_ipv6", ++ (fnode->conn[0]).link_local_ipv6, ++ sizeof((fnode->conn[0]).link_local_ipv6)); ++ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, ++ "discovery_parent_idx", ++ &((fnode->sess).discovery_parent_idx)); ++ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, ++ "discovery_parent_type", ++ (fnode->sess).discovery_parent_type, ++ sizeof((fnode->sess).discovery_parent_type)); ++ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "tpgt", ++ &((fnode->sess).tpgt)); ++ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_xmit_wsf", ++ &((fnode->conn[0]).tcp_xmit_wsf)); ++ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_recv_wsf", ++ &((fnode->conn[0]).tcp_recv_wsf)); ++ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "chap_out_idx", ++ &((fnode->sess).chap_out_idx)); ++ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "chap_in_idx", ++ &((fnode->sess).chap_in_idx)); ++ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "username", ++ (fnode->sess).username, sizeof((fnode->sess).username)); ++ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "username_in", ++ (fnode->sess).username_in, ++ sizeof((fnode->sess).username_in)); ++ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "password", ++ (fnode->sess).password, sizeof((fnode->sess).password)); ++ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "password_in", ++ (fnode->sess).password_in, ++ sizeof((fnode->sess).password_in)); ++ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "statsn", ++ &((fnode->conn[0]).stat_sn)); ++ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "exp_statsn", ++ &((fnode->conn[0]).exp_stat_sn)); ++ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "is_boot_target", ++ &((fnode->sess).is_boot_target)); ++ return ret; ++} ++ ++/* ++ * For each flash node of the given host, perform operation specified in fn. ++ */ ++int iscsi_sysfs_for_each_flashnode(void *data, uint32_t host_no, int *nr_found, ++ iscsi_sysfs_flashnode_op_fn *fn) ++{ ++ struct dirent **namelist; ++ int rc = 0, i, n; ++ struct flashnode_rec *fnode; ++ uint32_t flashnode_idx; ++ uint32_t hostno; ++ ++ fnode = malloc(sizeof(*fnode)); ++ if (!fnode) ++ return ISCSI_ERR_NOMEM; ++ ++ n = scandir(ISCSI_FLASHNODE_DIR, &namelist, trans_filter, alphasort); ++ if (n <= 0) ++ goto free_fnode; ++ ++ for (i = 0; i < n; i++) { ++ memset(fnode, 0, sizeof(*fnode)); ++ ++ if (!strncmp(namelist[i]->d_name, "flashnode_conn", ++ strlen("flashnode_conn"))) ++ continue; ++ ++ if (sscanf(namelist[i]->d_name, ISCSI_FLASHNODE_SESS, ++ &hostno, &flashnode_idx) != 2) { ++ log_error("Invalid iscsi target dir: %s", ++ namelist[i]->d_name); ++ break; ++ } ++ ++ if (host_no != hostno) ++ continue; ++ ++ rc = iscsi_sysfs_get_flashnode_info(fnode, host_no, ++ flashnode_idx); ++ if (rc) ++ break; ++ ++ rc = fn(data, fnode, host_no, flashnode_idx); ++ if (rc != 0) ++ break; ++ (*nr_found)++; ++ } ++ ++ for (i = 0; i < n; i++) ++ free(namelist[i]); ++ free(namelist); ++ ++free_fnode: ++ free(fnode); ++ return rc; ++} ++ ++static int iscsi_sysfs_read_boot(struct iface_rec *iface, char *session) ++{ ++ char boot_root[BOOT_NAME_MAXLEN], boot_nic[BOOT_NAME_MAXLEN]; ++ char boot_name[BOOT_NAME_MAXLEN], boot_content[BOOT_NAME_MAXLEN]; ++ ++ /* Extract boot info */ ++ strlcpy(boot_name, "boot_target", sizeof(boot_name)); ++ if (sysfs_get_str(session, ISCSI_SESSION_SUBSYS, boot_name, ++ boot_content, BOOT_NAME_MAXLEN)) ++ return -1; ++ strlcpy(boot_name, "boot_nic", sizeof(boot_name)); ++ if (sysfs_get_str(session, ISCSI_SESSION_SUBSYS, boot_name, boot_nic, ++ BOOT_NAME_MAXLEN)) ++ return -1; ++ strlcpy(boot_name, "boot_root", sizeof(boot_name)); ++ if (sysfs_get_str(session, ISCSI_SESSION_SUBSYS, boot_name, boot_root, ++ BOOT_NAME_MAXLEN)) ++ return -1; ++ ++ /* If all boot_root/boot_target/boot_nic exist, then extract the ++ info from the boot nic */ ++ if (sysfs_get_str(boot_nic, boot_root, "vlan", boot_content, ++ BOOT_NAME_MAXLEN)) ++ log_debug(5, "could not read %s/%s/vlan", boot_root, boot_nic); ++ else ++ iface->vlan_id = atoi(boot_content); ++ ++ if (sysfs_get_str(boot_nic, boot_root, "subnet-mask", ++ iface->subnet_mask, NI_MAXHOST)) ++ log_debug(5, "could not read %s/%s/subnet", boot_root, ++ boot_nic); ++ ++ log_debug(5, "sysfs read boot returns %s/%s/ vlan = %d subnet = %s", ++ boot_root, boot_nic, iface->vlan_id, iface->subnet_mask); ++ return 0; ++} ++ ++/* + * Read in iface settings based on host and session values. If + * session is not passed in, then the ifacename will not be set. And + * if the session is not passed in then iname will only be set for +@@ -469,7 +741,7 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no, + ret = sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "hwaddress", + iface->hwaddress, sizeof(iface->hwaddress)); + if (ret) +- log_debug(7, "could not read hwaddress for host%d\n", host_no); ++ log_debug(7, "could not read hwaddress for host%d", host_no); + + if (iface_kern_id) + ret = sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, +@@ -480,14 +752,14 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no, + ret = sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "ipaddress", + iface->ipaddress, sizeof(iface->ipaddress)); + if (ret) +- log_debug(7, "could not read local address for host%d\n", ++ log_debug(7, "could not read local address for host%d", + host_no); + + /* if not found just print out default */ + ret = sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "netdev", + iface->netdev, sizeof(iface->netdev)); + if (ret) +- log_debug(7, "could not read netdev for host%d\n", host_no); ++ log_debug(7, "could not read netdev for host%d", host_no); + + /* + * For drivers like qla4xxx we can only set the iname at the +@@ -527,7 +799,7 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no, + * global iname so we can just fill it in here. + */ + log_debug(7, "Could not read initiatorname for " +- "host%d\n", host_no); ++ "host%d", host_no); + /* optional so do not return error */ + ret = 0; + } +@@ -553,7 +825,7 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no, + iface->name, sizeof(iface->name)); + if (ret) { + log_debug(7, "could not read iface name for " +- "session %s\n", session); ++ "session %s", session); + /* + * if the ifacename file is not there then we are + * using a older kernel and can try to find the +@@ -562,11 +834,14 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no, + */ + if (iface_get_by_net_binding(iface, iface)) + log_debug(7, "Could not find iface for session " +- "bound to:" iface_fmt "\n", ++ "bound to:" iface_fmt "", + iface_str(iface)); + } + } + ++ if (session && t->template->use_boot_info) ++ iscsi_sysfs_read_boot(iface, session); ++ + if (!iface_kern_id) + goto done; + +@@ -581,6 +856,71 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no, + + sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "subnet", + iface->subnet_mask, sizeof(iface->subnet_mask)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "dhcp_alt_client_id_en", ++ iface->dhcp_alt_client_id_state, ++ sizeof(iface->dhcp_alt_client_id_state)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "dhcp_alt_client_id", ++ iface->dhcp_alt_client_id, ++ sizeof(iface->dhcp_alt_client_id)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "dhcp_dns_address_en", ++ iface->dhcp_dns, sizeof(iface->dhcp_dns)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "dhcp_learn_iqn_en", ++ iface->dhcp_learn_iqn, ++ sizeof(iface->dhcp_learn_iqn)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "dhcp_req_vendor_id_en", ++ iface->dhcp_req_vendor_id_state, ++ sizeof(iface->dhcp_req_vendor_id_state)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "dhcp_use_vendor_id_en", ++ iface->dhcp_vendor_id_state, ++ sizeof(iface->dhcp_vendor_id_state)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "dhcp_vendor_id", ++ iface->dhcp_vendor_id, ++ sizeof(iface->dhcp_vendor_id)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "dhcp_slp_da_info_en", ++ iface->dhcp_slp_da, sizeof(iface->dhcp_slp_da)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "fragment_disable", ++ iface->fragmentation, ++ sizeof(iface->fragmentation)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "grat_arp_en", ++ iface->gratuitous_arp, ++ sizeof(iface->gratuitous_arp)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "incoming_forwarding_en", ++ iface->incoming_forwarding, ++ sizeof(iface->incoming_forwarding)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "tos_en", ++ iface->tos_state, sizeof(iface->tos_state)); ++ ++ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "tos", &iface->tos)) ++ iface->tos = 0; ++ ++ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "ttl", &iface->ttl)) ++ iface->ttl = 0; + } else { + sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, + "ipaddr_autocfg", +@@ -597,6 +937,53 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no, + sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "router_addr", + iface->ipv6_router, + sizeof(iface->ipv6_router)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "router_state", ++ iface->router_autocfg, ++ sizeof(iface->router_autocfg)); ++ ++ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "dup_addr_detect_cnt", ++ &iface->dup_addr_detect_cnt)) ++ iface->dup_addr_detect_cnt = 0; ++ ++ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "flow_label", &iface->flow_label)) ++ iface->flow_label = 0; ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "grat_neighbor_adv_en", ++ iface->gratuitous_neighbor_adv, ++ sizeof(iface->gratuitous_neighbor_adv)); ++ ++ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "hop_limit", &iface->hop_limit)) ++ iface->hop_limit = 0; ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "mld_en", ++ iface->mld, sizeof(iface->mld)); ++ ++ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "nd_reachable_tmo", ++ &iface->nd_reachable_tmo)) ++ iface->nd_reachable_tmo = 0; ++ ++ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "nd_rexmit_time", &iface->nd_rexmit_time)) ++ iface->nd_rexmit_time = 0; ++ ++ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "nd_stale_tmo", &iface->nd_stale_tmo)) ++ iface->nd_stale_tmo = 0; ++ ++ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "router_adv_link_mtu", ++ &iface->router_adv_link_mtu)) ++ iface->router_adv_link_mtu = 0; ++ ++ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "traffic_class", &iface->traffic_class)) ++ iface->traffic_class = 0; + } + + if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS, "port", +@@ -613,6 +1000,94 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no, + &iface->vlan_priority)) + iface->vlan_priority = UINT8_MAX; + ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "vlan_enabled", ++ iface->vlan_state, sizeof(iface->vlan_state)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "enabled", ++ iface->state, sizeof(iface->state)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "delayed_ack_en", ++ iface->delayed_ack, sizeof(iface->delayed_ack)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "tcp_nagle_disable", ++ iface->nagle, sizeof(iface->nagle)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "tcp_wsf_disable", ++ iface->tcp_wsf_state, sizeof(iface->tcp_wsf_state)); ++ ++ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, "tcp_wsf", ++ &iface->tcp_wsf)) ++ iface->tcp_wsf = 0; ++ ++ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "tcp_timer_scale", &iface->tcp_timer_scale)) ++ iface->tcp_timer_scale = 0; ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "tcp_timestamp_en", ++ iface->tcp_timestamp, sizeof(iface->tcp_timestamp)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "redirect_en", ++ iface->redirect, sizeof(iface->redirect)); ++ ++ if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "def_taskmgmt_tmo", &iface->def_task_mgmt_tmo)) ++ iface->def_task_mgmt_tmo = 0; ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "header_digest", ++ iface->header_digest, sizeof(iface->header_digest)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "data_digest", ++ iface->data_digest, sizeof(iface->data_digest)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "immediate_data", ++ iface->immediate_data, sizeof(iface->immediate_data)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "initial_r2t", ++ iface->initial_r2t, sizeof(iface->initial_r2t)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "data_seq_in_order", ++ iface->data_seq_inorder, sizeof(iface->data_seq_inorder)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "data_pdu_in_order", ++ iface->data_pdu_inorder, sizeof(iface->data_pdu_inorder)); ++ ++ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, "erl", ++ &iface->erl)) ++ iface->erl = 0; ++ ++ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "max_recv_dlength", &iface->max_recv_dlength)) ++ iface->max_recv_dlength = 0; ++ ++ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "first_burst_len", &iface->first_burst_len)) ++ iface->first_burst_len = 0; ++ ++ if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "max_outstanding_r2t", &iface->max_out_r2t)) ++ iface->max_out_r2t = 0; ++ ++ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "max_burst_len", &iface->max_burst_len)) ++ iface->max_burst_len = 0; ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "chap_auth", ++ iface->chap_auth, sizeof(iface->chap_auth)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "bidi_chap", ++ iface->bidi_chap, sizeof(iface->bidi_chap)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "strict_login_comp_en", ++ iface->strict_login_comp, ++ sizeof(iface->strict_login_comp)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, ++ "discovery_auth_optional", ++ iface->discovery_auth, sizeof(iface->discovery_auth)); ++ ++ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "discovery_logout", ++ iface->discovery_logout, sizeof(iface->discovery_logout)); ++ + if (sscanf(iface_kern_id, "ipv%d-iface-%u-%u", &iface_type, + &tmp_host_no, &iface_num) == 3) + iface->iface_num = iface_num; +@@ -740,7 +1215,7 @@ int iscsi_sysfs_session_has_leadconn(uint32_t sid) + * /sys/devices/platform/hostH/sessionS/targetH:B:I + * /sys/devices/platform/hostH/sessionS + * +- * return the sid S. If just the sid is passed in it will be covnerted ++ * return the sid S. If just the sid is passed in it will be converted + * to a int. + */ + int iscsi_sysfs_get_sid_from_path(char *session) +@@ -748,15 +1223,16 @@ int iscsi_sysfs_get_sid_from_path(char *session) + struct sysfs_device *dev_parent, *dev; + struct stat statb; + char devpath[PATH_SIZE]; ++ char *end; ++ int sid; ++ ++ sid = strtol(session, &end, 10); ++ if (sid > 0 && *session != '\0' && *end == '\0') ++ return sid; + + if (lstat(session, &statb)) { +- log_debug(1, "Could not stat %s failed with %d", +- session, errno); +- if (index(session, '/')) { +- log_error("%s is an invalid session path\n", session); +- exit(1); +- } +- return atoi(session); ++ log_error("%s is an invalid session ID or path", session); ++ exit(1); + } + + if (!S_ISDIR(statb.st_mode) && !S_ISLNK(statb.st_mode)) { +@@ -772,7 +1248,7 @@ int iscsi_sysfs_get_sid_from_path(char *session) + dev = sysfs_device_get(devpath); + if (!dev) { + log_error("Could not get dev for %s. Possible sysfs " +- "incompatibility.\n", devpath); ++ "incompatibility.", devpath); + return -1; + } + +@@ -932,11 +1408,13 @@ int iscsi_sysfs_get_sessioninfo_by_id(struct session_info *info, char *session) + } + + int iscsi_sysfs_for_each_session(void *data, int *nr_found, +- iscsi_sysfs_session_op_fn *fn) ++ iscsi_sysfs_session_op_fn *fn, ++ int in_parallel) + { + struct dirent **namelist; +- int rc = 0, n, i; ++ int rc = 0, n, i, chldrc = 0; + struct session_info *info; ++ pid_t pid = 0; + + info = calloc(1, sizeof(*info)); + if (!info) +@@ -958,14 +1436,52 @@ int iscsi_sysfs_for_each_session(void *data, int *nr_found, + continue; + } + +- rc = fn(data, info); +- if (rc > 0) +- break; +- else if (rc == 0) +- (*nr_found)++; +- else +- /* if less than zero it means it was not a match */ +- rc = 0; ++ if (in_parallel) { ++ pid = fork(); ++ } ++ if (pid == 0) { ++ rc = fn(data, info); ++ if (in_parallel) { ++ exit(rc); ++ } else { ++ if (rc > 0) { ++ break; ++ } else if (rc == 0) { ++ (*nr_found)++; ++ } else { ++ /* if less than zero it means it was not a match */ ++ rc = 0; ++ } ++ } ++ } else if (pid < 0) { ++ log_error("could not fork() for session %s, err %d", ++ namelist[i]->d_name, errno); ++ } ++ } ++ ++ if (in_parallel) { ++ while (1) { ++ if (wait(&chldrc) < 0) { ++ /* ++ * ECHILD means no more children which is ++ * expected to happen sooner or later. ++ */ ++ if (errno != ECHILD) { ++ rc = errno; ++ } ++ break; ++ } ++ ++ if ((chldrc > 0) && (rc == 0)) { ++ /* ++ * The non-parallel code path returns the first ++ * error so this keeps the same semantics. ++ */ ++ rc = chldrc; ++ } else if (chldrc == 0) { ++ (*nr_found)++; ++ } ++ } + } + + for (i = 0; i < n; i++) +@@ -1006,7 +1522,7 @@ int iscsi_sysfs_get_device_state(char *state, int host_no, int target, int lun) + snprintf(id, sizeof(id), "%d:0:%d:%d", host_no, target, lun); + if (sysfs_get_str(id, SCSI_SUBSYS, "state", state, + SCSI_MAX_STATE_VALUE)) { +- log_debug(3, "Could not read attr state for %s\n", id); ++ log_debug(3, "Could not read attr state for %s", id); + return ISCSI_ERR_SYSFS_LOOKUP; + } + +@@ -1027,7 +1543,7 @@ char *iscsi_sysfs_get_blockdev_from_lun(int host_no, int target, int lun) + snprintf(id, sizeof(id), "%d:0:%d:%d", host_no, target, lun); + if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath), + SCSI_SUBSYS, id)) { +- log_debug(3, "Could not lookup devpath for %s %s\n", ++ log_debug(3, "Could not lookup devpath for %s %s", + SCSI_SUBSYS, id); + return NULL; + } +@@ -1055,7 +1571,7 @@ char *iscsi_sysfs_get_blockdev_from_lun(int host_no, int target, int lun) + * 2.6.25 dropped the symlink and now block is a dir. + */ + if (lstat(path_full, &statbuf)) { +- log_error("Could not stat block path %s err %d\n", ++ log_error("Could not stat block path %s err %d", + path_full, errno); + break; + } +@@ -1074,7 +1590,7 @@ char *iscsi_sysfs_get_blockdev_from_lun(int host_no, int target, int lun) + /* it should not be this hard should it? :) */ + blk_dirfd = opendir(path_full); + if (!blk_dirfd) { +- log_debug(3, "Could not open blk path %s\n", ++ log_debug(3, "Could not open blk path %s", + path_full); + break; + } +@@ -1110,7 +1626,7 @@ static uint32_t get_target_no_from_sid(uint32_t sid, int *err) + snprintf(id, sizeof(id), "session%u", sid); + if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath), + ISCSI_SESSION_SUBSYS, id)) { +- log_debug(3, "Could not lookup devpath for %s %s\n", ++ log_debug(3, "Could not lookup devpath for %s %s", + ISCSI_SESSION_SUBSYS, id); + return 0; + } +@@ -1283,7 +1799,7 @@ int iscsi_sysfs_for_each_device(void *data, int host_no, uint32_t sid, + snprintf(id, sizeof(id), "session%u", sid); + if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath), + ISCSI_SESSION_SUBSYS, id)) { +- log_debug(3, "Could not lookup devpath for %s %s\n", ++ log_debug(3, "Could not lookup devpath for %s %s", + ISCSI_SESSION_SUBSYS, id); + return ISCSI_ERR_SYSFS_LOOKUP; + } +@@ -1367,7 +1883,7 @@ pid_t iscsi_sysfs_scan_host(int hostno, int async) + snprintf(id, sizeof(id), ISCSI_HOST_ID, hostno); + sysfs_set_param(id, SCSI_HOST_SUBSYS, "scan", write_buf, + strlen(write_buf)); +- log_debug(4, "scanning host%d completed\n", hostno); ++ log_debug(4, "scanning host%d completed", hostno); + } else if (pid > 0) { + log_debug(4, "scanning host%d from pid %d", hostno, pid); + } else +diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h +index 2b15d78..9a56105 100644 +--- a/usr/iscsi_sysfs.h ++++ b/usr/iscsi_sysfs.h +@@ -31,6 +31,7 @@ struct iscsi_conn; + struct iscsi_session_operational_config; + struct iscsi_conn_operational_config; + struct iscsi_auth_config; ++struct flashnode_rec; + + #define SCSI_MAX_STATE_VALUE 32 + +@@ -42,13 +43,16 @@ extern int iscsi_sysfs_session_has_leadconn(uint32_t sid); + + typedef int (iscsi_sysfs_session_op_fn)(void *, struct session_info *); + typedef int (iscsi_sysfs_host_op_fn)(void *, struct host_info *); ++typedef int (iscsi_sysfs_flashnode_op_fn)(void *, struct flashnode_rec *, ++ uint32_t, uint32_t); + typedef int (iscsi_sysfs_iface_op_fn)(void *, struct iface_rec *); + + extern int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no, + int *nr_found, + iscsi_sysfs_iface_op_fn *fn); + extern int iscsi_sysfs_for_each_session(void *data, int *nr_found, +- iscsi_sysfs_session_op_fn *fn); ++ iscsi_sysfs_session_op_fn *fn, ++ int in_parallel); + extern int iscsi_sysfs_for_each_host(void *data, int *nr_found, + iscsi_sysfs_host_op_fn *fn); + extern uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err); +@@ -56,6 +60,20 @@ extern uint32_t iscsi_sysfs_get_host_no_from_hwinfo(struct iface_rec *iface, + int *rc); + extern uint32_t iscsi_sysfs_get_host_no_from_hwaddress(char *hwaddress, int *rc); + extern int iscsi_sysfs_get_hostinfo_by_host_no(struct host_info *hinfo); ++extern int iscsi_sysfs_for_each_flashnode(void *data, uint32_t host_no, ++ int *nr_found, ++ iscsi_sysfs_flashnode_op_fn *fn); ++extern int iscsi_sysfs_get_flashnode_info(struct flashnode_rec *fnode, ++ uint32_t host_no, ++ uint32_t flashnode_id); ++extern int iscsi_sysfs_update_flashnode_param(uint32_t host_no, ++ uint32_t flashnode_id, ++ char *name, char *val); ++extern int iscsi_sysfs_create_flashnode(uint32_t host_no, char *ipver); ++extern int iscsi_sysfs_del_flashnode(uint32_t host_no, uint32_t flashnode_id); ++extern int iscsi_sysfs_login_flashnode(uint32_t host_no, uint32_t flashnode_id); ++extern int iscsi_sysfs_logout_flashnode(uint32_t host_no, ++ uint32_t flashnode_id); + extern int iscsi_sysfs_get_sid_from_path(char *session); + extern char *iscsi_sysfs_get_blockdev_from_lun(int hostno, int target, int sid); + +diff --git a/usr/iscsi_util.c b/usr/iscsi_util.c +index 5e3420e..a4f33cf 100644 +--- a/usr/iscsi_util.c ++++ b/usr/iscsi_util.c +@@ -25,16 +25,28 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include + ++#include "sysdeps.h" + #include "log.h" + #include "iscsi_settings.h" + #include "iface.h" + #include "session_info.h" + #include "iscsi_util.h" + ++int setup_abstract_addr(struct sockaddr_un *addr, char *unix_sock_name) ++{ ++ memset(addr, 0, sizeof(*addr)); ++ addr->sun_family = AF_LOCAL; ++ strlcpy(addr->sun_path + 1, unix_sock_name, sizeof(addr->sun_path) - 1); ++ return offsetof(struct sockaddr_un, sun_path) + ++ strlen(addr->sun_path + 1) + 1; ++} ++ + void daemon_init(void) + { + int fd; +@@ -60,7 +72,8 @@ int oom_adjust(void) + char path[ISCSI_OOM_PATH_LEN]; + struct stat statb; + +- if (nice(-10) < 0) ++ errno = 0; ++ if (nice(-10) == -1 && errno != 0) + log_debug(1, "Could not increase process priority: %s", + strerror(errno)); + +@@ -135,10 +148,10 @@ int increase_max_files(void) + + err = getrlimit(RLIMIT_NOFILE, &rl); + if (err) { +- log_debug(1, "Could not get file limit (err %d)\n", errno); ++ log_debug(1, "Could not get file limit (err %d)", errno); + return errno; + } +- log_debug(1, "Max file limits %lu %lu\n", rl.rlim_cur, rl.rlim_max); ++ log_debug(1, "Max file limits %lu %lu", rl.rlim_cur, rl.rlim_max); + + if (rl.rlim_cur < ISCSI_MAX_FILES) + rl.rlim_cur = ISCSI_MAX_FILES; +@@ -147,7 +160,7 @@ int increase_max_files(void) + + err = setrlimit(RLIMIT_NOFILE, &rl); + if (err) { +- log_debug(1, "Could not set file limit to %lu/%lu (err %d)\n", ++ log_debug(1, "Could not set file limit to %lu/%lu (err %d)", + rl.rlim_cur, rl.rlim_max, errno); + return errno; + } +@@ -306,7 +319,7 @@ int __iscsi_match_session(node_rec_t *rec, char *targetname, + unsigned sid) + { + if (!rec) { +- log_debug(6, "no rec info to match\n"); ++ log_debug(6, "no rec info to match"); + return 1; + } + +diff --git a/usr/iscsi_util.h b/usr/iscsi_util.h +index 110dfa8..ff725eb 100644 +--- a/usr/iscsi_util.h ++++ b/usr/iscsi_util.h +@@ -26,4 +26,7 @@ extern int __iscsi_match_session(struct node_rec *rec, char *targetname, + extern char *strstrip(char *s); + extern char *cfg_get_string_param(char *pathname, const char *key); + ++struct sockaddr_un; ++extern int setup_abstract_addr(struct sockaddr_un *addr, char *unix_sock_name); ++ + #endif +diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c +index 8f9de05..c6705bd 100644 +--- a/usr/iscsiadm.c ++++ b/usr/iscsiadm.c +@@ -49,10 +49,11 @@ + #include "idbm_fields.h" + #include "session_mgmt.h" + #include "iscsid_req.h" +-#include "isns-proto.h" ++#include + #include "iscsi_err.h" + #include "iscsi_ipc.h" + #include "iscsi_timer.h" ++#include "flashnode.h" + + static char program_name[] = "iscsiadm"; + static char config_file[TARGET_NAME_MAXLEN]; +@@ -67,7 +68,9 @@ enum iscsiadm_mode { + MODE_IFACE, + MODE_FW, + MODE_PING, +- MODE_CHAP ++ MODE_CHAP, ++ MODE_FLASHNODE, ++ MODE_HOST_STATS + }; + + enum iscsiadm_op { +@@ -78,7 +81,9 @@ enum iscsiadm_op { + OP_SHOW = 0x8, + OP_NONPERSISTENT = 0x10, + OP_APPLY = 0x20, +- OP_APPLY_ALL = 0x40 ++ OP_APPLY_ALL = 0x40, ++ OP_LOGIN = 0x80, ++ OP_LOGOUT = 0x100 + }; + + static struct option const long_options[] = +@@ -111,9 +116,11 @@ static struct option const long_options[] = + {"packetsize", required_argument, NULL, 'b'}, + {"count", required_argument, NULL, 'c'}, + {"interval", required_argument, NULL, 'i'}, ++ {"index", required_argument, NULL, 'x'}, ++ {"portal_type", optional_argument, NULL, 'A'}, + {NULL, 0, NULL, 0}, + }; +-static char *short_options = "RlDVhm:a:b:c:C:p:P:T:H:i:I:U:k:L:d:r:n:v:o:sSt:u"; ++static char *short_options = "RlDVhm:a:b:c:C:p:P:T:H:i:I:U:k:L:d:r:n:v:o:sSt:ux:A:"; + + static void usage(int status) + { +@@ -129,8 +136,8 @@ iscsiadm -m node [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -L all,manual,au + [ [ -o operation ] [ -n name ] [ -v value ] ]\n\ + iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\ + iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename | -H hostno|MAC ] [ [ -o operation ] [ -n name ] [ -v value ] ] [ -C ping [ -a ip ] [ -b packetsize ] [ -c count ] [ -i interval ] ]\n\ +-iscsiadm -m fw [ -l ]\n\ +-iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ] [ -C chap [ -o operation ] [ -v chap_tbl_idx ] ]\n\ ++iscsiadm -m fw [ -d debug_level ] [ -l ]\n\ ++iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ] [ [ -C chap [ -x chap_tbl_idx ] ] | [ -C flashnode [ -A portal_type ] [ -x flashnode_idx ] ] | [ -C stats ] ] [ [ -o operation ] [ -n name ] [ -v value ] ] \n\ + iscsiadm -k priority\n"); + } + exit(status); +@@ -155,6 +162,10 @@ str_to_op(char *str) + op = OP_APPLY; + else if (!strcmp("applyall", str)) + op = OP_APPLY_ALL; ++ else if (!strcmp("login", str)) ++ op = OP_LOGIN; ++ else if (!strcmp("logout", str)) ++ op = OP_LOGOUT; + else + op = OP_NOOP; + +@@ -195,6 +206,11 @@ str_to_submode(char *str) + sub_mode = MODE_PING; + else if (!strcmp("chap", str)) + sub_mode = MODE_CHAP; ++ else if (!strcmp("flashnode", str)) ++ sub_mode = MODE_FLASHNODE; ++ else if (!strcmp("stats", str)) ++ sub_mode = MODE_HOST_STATS; ++ + else + sub_mode = -1; + +@@ -221,6 +237,21 @@ str_to_type(char *str) + return type; + } + ++static int ++str_to_portal_type(char *str) ++{ ++ int ptype; ++ ++ if (!strcmp("ipv4", str)) ++ ptype = IPV4; ++ else if (!strcmp("ipv6", str)) ++ ptype = IPV6; ++ else ++ ptype = -1; ++ ++ return ptype; ++} ++ + static void kill_iscsid(int priority) + { + iscsiadm_req_t req; +@@ -247,7 +278,7 @@ static void kill_iscsid(int priority) + if (rc) { + iscsi_err_print_msg(rc); + log_error("Could not stop iscsid. Trying sending iscsid " +- "SIGTERM or SIGKILL signals manually\n"); ++ "SIGTERM or SIGKILL signals manually"); + } + } + +@@ -272,7 +303,7 @@ static int print_ifaces(struct iface_rec *iface, int info_level) + if (iface) { + err = iface_conf_read(iface); + if (err) { +- log_error("Could not read iface %s.\n", ++ log_error("Could not read iface %s.", + iface->name); + return err; + } +@@ -320,7 +351,8 @@ match_startup_mode(node_rec_t *rec, char *mode) + } + + static int +-for_each_session(struct node_rec *rec, iscsi_sysfs_session_op_fn *fn) ++for_each_session(struct node_rec *rec, iscsi_sysfs_session_op_fn *fn, ++ int in_parallel) + { + int err, num_found = 0; + +@@ -328,7 +360,8 @@ for_each_session(struct node_rec *rec, iscsi_sysfs_session_op_fn *fn) + num_found = 1; + err = fn(rec, rec->session.info); + } else { +- err = iscsi_sysfs_for_each_session(rec, &num_found, fn); ++ err = iscsi_sysfs_for_each_session(rec, &num_found, fn, ++ in_parallel); + } + if (err) + log_error("Could not execute operation on all sessions: %s", +@@ -370,7 +403,7 @@ __logout_by_startup(void *data, struct list_head *list, + * this is due to a HW driver or some other driver + * not hooked in + */ +- log_debug(7, "could not read data for [%s,%s.%d]\n", ++ log_debug(7, "could not read data for [%s,%s.%d]", + info->targetname, info->persistent_address, + info->persistent_port); + return -1; +@@ -408,7 +441,7 @@ logout_by_startup(char *mode) + rc = iscsi_logout_portals(mode, &nr_found, 1, __logout_by_startup); + if (rc == ISCSI_ERR_NO_OBJS_FOUND) + log_error("No matching sessions found"); +- return rc; ++ return rc; + } + + struct startup_data { +@@ -452,7 +485,7 @@ __do_leading_login(void *data, struct list_head *list, struct node_rec *rec) + * If there is an existing session that matcthes the target, + * the leading login is complete. + */ +- if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_target)) { ++ if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_target, 0)) { + log_debug(1, "Skipping %s: Already a session for that target", + rec->name); + return -1; +@@ -552,7 +585,7 @@ login_by_startup(char *mode) + list_for_each_entry_safe(rec, tmp_rec, &startup.leading_logins, + list) { + if (!iscsi_sysfs_for_each_session(rec, &nr_found, +- iscsi_match_target)) ++ iscsi_match_target, 0)) + missed_leading_login++; + /* + * Cleanup the list, since 'iscsi_login_portals_safe' +@@ -582,6 +615,8 @@ static int iscsi_logout_matched_portal(void *data, struct list_head *list, + { + struct node_rec *pattern_rec = data; + struct iscsi_transport *t; ++ uint32_t host_no; ++ int rc = 0; + + t = iscsi_sysfs_get_transport_by_sid(info->sid); + if (!t) +@@ -590,7 +625,19 @@ static int iscsi_logout_matched_portal(void *data, struct list_head *list, + if (!iscsi_match_session(pattern_rec, info)) + return -1; + +- return iscsi_logout_portal(info, list); ++ host_no = iscsi_sysfs_get_host_no_from_sid(info->sid, &rc); ++ if (rc) { ++ log_error("could not get host_no for session%d: %s.", ++ info->sid, iscsi_err_to_str(rc)); ++ return -1; ++ } ++ ++ if (!iscsi_sysfs_session_user_created(info->sid)) ++ rc = iscsi_logout_flashnode_sid(t, host_no, info->sid); ++ else ++ rc = iscsi_logout_portal(info, list); ++ ++ return rc; + } + + static int rec_match_fn(void *data, node_rec_t *rec) +@@ -1092,17 +1139,55 @@ do_software_sendtargets(discovery_rec_t *drec, struct list_head *ifaces, + return rc; + } + ++static int do_isns(discovery_rec_t *drec, struct list_head *ifaces, ++ int info_level, int do_login, int op) ++{ ++ struct list_head rec_list; ++ struct node_rec *rec, *tmp; ++ int rc; ++ ++ INIT_LIST_HEAD(&rec_list); ++ /* ++ * compat: if the user did not pass any op then we do all ++ * ops for them ++ */ ++ if (!op) ++ op = OP_NEW | OP_DELETE | OP_UPDATE; ++ ++ ++ rc = idbm_bind_ifaces_to_nodes(discovery_isns, drec, ifaces, ++ &rec_list); ++ if (rc) { ++ log_error("Could not perform iSNS discovery: %s", ++ iscsi_err_to_str(rc)); ++ return rc; ++ } else if (list_empty(&rec_list)) { ++ log_error("No portals found"); ++ return ISCSI_ERR_NO_OBJS_FOUND; ++ } ++ ++ rc = exec_disc_op_on_recs(drec, &rec_list, info_level, do_login, op); ++ ++ list_for_each_entry_safe(rec, tmp, &rec_list, list) { ++ list_del(&rec->list); ++ free(rec); ++ } ++ ++ return rc; ++} ++ + static int +-do_sendtargets(discovery_rec_t *drec, struct list_head *ifaces, +- int info_level, int do_login, int op, int sync_drec) ++do_target_discovery(discovery_rec_t *drec, struct list_head *ifaces, ++ int info_level, int do_login, int op, int sync_drec) + { ++ + struct iface_rec *tmp, *iface; + int rc, host_no; + struct iscsi_transport *t; + + if (list_empty(ifaces)) { + ifaces = NULL; +- goto sw_st; ++ goto sw_discovery; + } + + /* we allow users to mix hw and sw iscsi so we have to sort it out */ +@@ -1131,64 +1216,36 @@ do_sendtargets(discovery_rec_t *drec, struct list_head *ifaces, + host_no = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc); + if (rc || host_no == -1) { + log_debug(1, "Could not match iface" iface_fmt " to " +- "host.", iface_str(iface)); ++ "host.", iface_str(iface)); + /* try software iscsi */ + continue; + } + +- if (t->caps & CAP_SENDTARGETS_OFFLOAD) { +- do_offload_sendtargets(drec, host_no, do_login); +- list_del(&iface->list); +- free(iface); +- } ++ if (drec->type == DISCOVERY_TYPE_SENDTARGETS) ++ if (t->caps & CAP_SENDTARGETS_OFFLOAD) { ++ do_offload_sendtargets(drec, host_no, do_login); ++ list_del(&iface->list); ++ free(iface); ++ } + } + + if (list_empty(ifaces)) + return ISCSI_ERR_NO_OBJS_FOUND; + +-sw_st: +- return do_software_sendtargets(drec, ifaces, info_level, do_login, +- op, sync_drec); +-} +- +-static int do_isns(discovery_rec_t *drec, struct list_head *ifaces, +- int info_level, int do_login, int op) +-{ +- struct list_head rec_list; +- struct node_rec *rec, *tmp; +- int rc; +- +- INIT_LIST_HEAD(&rec_list); +- /* +- * compat: if the user did not pass any op then we do all +- * ops for them +- */ +- if (!op) +- op = OP_NEW | OP_DELETE | OP_UPDATE; +- +- drec->type = DISCOVERY_TYPE_ISNS; +- +- rc = idbm_bind_ifaces_to_nodes(discovery_isns, drec, ifaces, +- &rec_list); +- if (rc) { +- log_error("Could not perform iSNS discovery: %s", +- iscsi_err_to_str(rc)); +- return rc; +- } else if (list_empty(&rec_list)) { +- log_error("No portals found"); +- return ISCSI_ERR_NO_OBJS_FOUND; ++sw_discovery: ++ switch (drec->type) { ++ case DISCOVERY_TYPE_SENDTARGETS: ++ return do_software_sendtargets(drec, ifaces, info_level, ++ do_login, op, sync_drec); ++ case DISCOVERY_TYPE_ISNS: ++ return do_isns(drec, ifaces, info_level, do_login, op); ++ default: ++ log_debug(1, "Unknown Discovery Type : %d", drec->type); ++ return ISCSI_ERR_UNKNOWN_DISCOVERY_TYPE; + } +- +- rc = exec_disc_op_on_recs(drec, &rec_list, info_level, do_login, op); +- +- list_for_each_entry_safe(rec, tmp, &rec_list, list) { +- list_del(&rec->list); +- free(rec); +- } +- +- return rc; + } + ++ + static int + verify_mode_params(int argc, char **argv, char *allowed, int skip_m) + { +@@ -1229,7 +1286,7 @@ static int iface_apply_net_config(struct iface_rec *iface, int op) + int fd; + + log_debug(8, "Calling iscsid, to apply net config for" +- "iface.name = %s\n", iface->name); ++ "iface.name = %s", iface->name); + + if (op == OP_APPLY_ALL) + iface_all = 1; +@@ -1373,19 +1430,193 @@ exit_chap_info: + return rc; + } + +-static int delete_host_chap_info(uint32_t host_no, char *value) ++static int fill_host_chap_rec(struct list_head *params, ++ struct iscsi_chap_rec *crec, recinfo_t *cinfo, ++ uint16_t chap_tbl_idx, int type, int *param_count) ++{ ++ struct user_param *param; ++ int rc = 0; ++ ++ crec->chap_tbl_idx = chap_tbl_idx; ++ crec->chap_type = type; ++ ++ idbm_recinfo_host_chap(crec, cinfo); ++ ++ list_for_each_entry(param, params, list) { ++ rc = idbm_rec_update_param(cinfo, param->name, param->value, 0); ++ if (rc) ++ break; ++ } ++ ++ if (!rc) ++ *param_count += 3; /* index, type and password_length */ ++ ++ return rc; ++} ++ ++static int verify_host_chap_params(struct list_head *params, int *type, ++ int *param_count) ++{ ++ struct user_param *param; ++ int username = -1; ++ int password = -1; ++ int rc = 0; ++ ++ list_for_each_entry(param, params, list) { ++ *param_count += 1; ++ ++ if (!strcmp(param->name, HOST_AUTH_USERNAME)) ++ username = CHAP_TYPE_OUT; ++ else if (!strcmp(param->name, HOST_AUTH_PASSWORD)) ++ password = CHAP_TYPE_OUT; ++ else if (!strcmp(param->name, HOST_AUTH_USERNAME_IN)) ++ username = CHAP_TYPE_IN; ++ else if (!strcmp(param->name, HOST_AUTH_PASSWORD_IN)) ++ password = CHAP_TYPE_IN; ++ else ++ continue; ++ } ++ ++ if ((username == CHAP_TYPE_OUT) && (password == CHAP_TYPE_OUT)) { ++ if (type) ++ *type = CHAP_TYPE_OUT; ++ ++ rc = ISCSI_SUCCESS; ++ } else if ((username == CHAP_TYPE_IN) && (password == CHAP_TYPE_IN)) { ++ if (type) ++ *type = CHAP_TYPE_IN; ++ ++ rc = ISCSI_SUCCESS; ++ } else { ++ rc = ISCSI_ERR; ++ } ++ ++ return rc; ++} ++ ++static int set_host_chap_info(uint32_t host_no, uint64_t chap_index, ++ struct list_head *params) ++{ ++ struct iscsi_transport *t = NULL; ++ struct iscsi_chap_rec crec; ++ recinfo_t *chap_info = NULL; ++ struct iovec *iovs = NULL; ++ struct iovec *iov = NULL; ++ int type; ++ int param_count = 0; ++ int param_used; ++ int rc = 0; ++ int fd, i = 0; ++ ++ if (list_empty(params)) { ++ log_error("Chap username/password not provided."); ++ goto exit_set_chap; ++ } ++ ++ chap_info = idbm_recinfo_alloc(MAX_KEYS); ++ if (!chap_info) { ++ log_error("Out of Memory."); ++ rc = ISCSI_ERR_NOMEM; ++ goto exit_set_chap; ++ } ++ ++ t = iscsi_sysfs_get_transport_by_hba(host_no); ++ if (!t) { ++ log_error("Could not match hostno %d to transport.", host_no); ++ rc = ISCSI_ERR_TRANS_NOT_FOUND; ++ goto free_info_rec; ++ } ++ ++ rc = verify_host_chap_params(params, &type, ¶m_count); ++ if (rc) { ++ log_error("Invalid username/password pair passed. Unable to determine the type of chap entry"); ++ rc = ISCSI_ERR_INVAL; ++ goto free_info_rec; ++ } ++ ++ if (param_count > 2) { ++ log_error("Only one pair of username/password can be passed."); ++ rc = ISCSI_ERR; ++ goto free_info_rec; ++ } ++ ++ memset(&crec, 0, sizeof(crec)); ++ rc = fill_host_chap_rec(params, &crec, chap_info, chap_index, type, ++ ¶m_count); ++ if (rc) { ++ log_error("Unable to fill CHAP record"); ++ goto free_info_rec; ++ } ++ ++ /* +2 for event and nlmsghdr */ ++ param_count += 2; ++ iovs = calloc((param_count * sizeof(struct iovec)), ++ sizeof(char)); ++ if (!iovs) { ++ log_error("Out of Memory."); ++ rc = ISCSI_ERR_NOMEM; ++ goto free_info_rec; ++ } ++ ++ /* param_used gives actual number of iovecs used for chap */ ++ param_used = chap_build_config(&crec, iovs); ++ if (!param_used) { ++ log_error("Build chap config failed."); ++ rc = ISCSI_ERR; ++ goto free_iovec; ++ } ++ ++ fd = ipc->ctldev_open(); ++ if (fd < 0) { ++ rc = ISCSI_ERR_INTERNAL; ++ log_error("Netlink open failed."); ++ goto free_iovec; ++ } ++ ++ rc = ipc->set_chap(t->handle, host_no, iovs, param_count); ++ if (rc < 0) { ++ log_error("CHAP setting failed"); ++ if (rc == -EBUSY) { ++ rc = ISCSI_ERR_BUSY; ++ log_error("CHAP index %d is in use.", ++ crec.chap_tbl_idx); ++ } else { ++ rc = ISCSI_ERR; ++ } ++ ++ goto exit_set_chap; ++ } ++ ++ ipc->ctldev_close(); ++ ++free_iovec: ++ /* start at 2, because 0 is for nlmsghdr and 1 for event */ ++ iov = iovs + 2; ++ for (i = 0; i < param_used; i++, iov++) { ++ if (iov->iov_base) ++ free(iov->iov_base); ++ } ++ ++ free(iovs); ++ ++free_info_rec: ++ if (chap_info) ++ free(chap_info); ++ ++exit_set_chap: ++ return rc; ++} ++ ++static int delete_host_chap_info(uint32_t host_no, uint16_t chap_tbl_idx) + { + struct iscsi_transport *t = NULL; + int fd, rc = 0; +- uint16_t chap_tbl_idx; + +- if (!value) { +- log_error("CHAP deletion requires --value=table_index."); +- return ISCSI_ERR_INVAL; ++ if (chap_tbl_idx > MAX_CHAP_ENTRIES) { ++ log_error("Invalid chap table index."); ++ goto exit_delete_chap; + } + +- chap_tbl_idx = (uint16_t)atoi(value); +- + t = iscsi_sysfs_get_transport_by_hba(host_no); + if (!t) { + log_error("Could not match hostno %d to " +@@ -1401,7 +1632,7 @@ static int delete_host_chap_info(uint32_t host_no, char *value) + goto exit_delete_chap; + } + +- log_info("Deleteing CHAP index: %d\n", chap_tbl_idx); ++ log_info("Deleteing CHAP index: %d", chap_tbl_idx); + rc = ipc->delete_chap(t->handle, host_no, chap_tbl_idx); + if (rc < 0) { + log_error("CHAP Delete failed."); +@@ -1419,7 +1650,7 @@ exit_delete_chap: + } + + static int exec_host_chap_op(int op, int info_level, uint32_t host_no, +- char *value) ++ uint64_t chap_index, struct list_head *params) + { + int rc = ISCSI_ERR_INVAL; + +@@ -1427,8 +1658,12 @@ static int exec_host_chap_op(int op, int info_level, uint32_t host_no, + case OP_SHOW: + rc = get_host_chap_info(host_no); + break; ++ case OP_NEW: ++ case OP_UPDATE: ++ rc = set_host_chap_info(host_no, chap_index, params); ++ break; + case OP_DELETE: +- rc = delete_host_chap_info(host_no, value); ++ rc = delete_host_chap_info(host_no, chap_index); + break; + default: + log_error("Invalid operation."); +@@ -1438,6 +1673,588 @@ static int exec_host_chap_op(int op, int info_level, uint32_t host_no, + return rc; + } + ++static int get_flashnode_info(uint32_t host_no, uint32_t flashnode_idx) ++{ ++ struct flashnode_rec fnode; ++ int rc = 0; ++ ++ memset(&fnode, 0, sizeof(fnode)); ++ rc = iscsi_sysfs_get_flashnode_info(&fnode, host_no, flashnode_idx); ++ if (rc) { ++ log_error("Could not read info for flashnode %u of host %u, %s", ++ flashnode_idx, host_no, strerror(rc)); ++ return rc; ++ } ++ ++ idbm_print_flashnode_info(&fnode); ++ return rc; ++} ++ ++static int list_flashnodes(int info_level, uint32_t host_no) ++{ ++ int rc = 0; ++ int num_found = 0; ++ ++ rc = iscsi_sysfs_for_each_flashnode(NULL, host_no, &num_found, ++ flashnode_info_print_flat); ++ ++ if (!num_found) { ++ log_error("No flashnodes attached to host %u.", host_no); ++ rc = ISCSI_ERR_NO_OBJS_FOUND; ++ } ++ ++ return rc; ++} ++ ++int iscsi_set_flashnode_params(struct iscsi_transport *t, uint32_t host_no, ++ uint32_t flashnode_idx, struct list_head *params) ++{ ++ struct flashnode_rec fnode; ++ recinfo_t *flashnode_info; ++ struct user_param *param; ++ struct iovec *iovs = NULL; ++ struct iovec *iov = NULL; ++ int fd, rc = 0; ++ int param_count = 0; ++ int param_used = 0; ++ int i; ++ ++ flashnode_info = idbm_recinfo_alloc(MAX_KEYS); ++ if (!flashnode_info) { ++ log_error("Out of Memory."); ++ rc = ISCSI_ERR_NOMEM; ++ goto free_info_rec; ++ } ++ ++ memset(&fnode, 0, sizeof(fnode)); ++ rc = iscsi_sysfs_get_flashnode_info(&fnode, host_no, flashnode_idx); ++ if (rc) { ++ log_error("Could not read info for flashnode %u, %s", ++ flashnode_idx, strerror(rc)); ++ goto free_info_rec; ++ } ++ ++ idbm_recinfo_flashnode(&fnode, flashnode_info); ++ ++ i = 0; ++ list_for_each_entry(param, params, list) { ++ param_count++; ++ rc = idbm_verify_param(flashnode_info, param->name); ++ if (rc) ++ goto free_info_rec; ++ } ++ ++ list_for_each_entry(param, params, list) { ++ rc = idbm_rec_update_param(flashnode_info, param->name, ++ param->value, 0); ++ if (rc) ++ goto free_info_rec; ++ } ++ ++ /* +2 for event and nlmsghdr */ ++ param_count += 2; ++ iovs = calloc((param_count * sizeof(struct iovec)), ++ sizeof(char)); ++ if (!iovs) { ++ log_error("Out of Memory."); ++ rc = ISCSI_ERR_NOMEM; ++ goto free_info_rec; ++ } ++ ++ /* param_used gives actual number of iovecs used for flashnode */ ++ param_used = flashnode_build_config(params, &fnode, iovs); ++ if (!param_used) { ++ log_error("Build flashnode config failed."); ++ rc = ISCSI_ERR; ++ goto free_iovec; ++ } ++ ++ fd = ipc->ctldev_open(); ++ if (fd < 0) { ++ log_error("Netlink open failed."); ++ rc = ISCSI_ERR_INTERNAL; ++ goto free_iovec; ++ } ++ ++ log_info("Update flashnode %u.", flashnode_idx); ++ rc = ipc->set_flash_node_params(t->handle, host_no, flashnode_idx, ++ iovs, param_count); ++ if (rc < 0) ++ rc = ISCSI_ERR; ++ ++ ++ ipc->ctldev_close(); ++ ++free_iovec: ++ /* start at 2, because 0 is for nlmsghdr and 1 for event */ ++ iov = iovs + 2; ++ for (i = 0; i < param_used; i++, iov++) { ++ if (iov->iov_base) ++ free(iov->iov_base); ++ } ++ ++ free(iovs); ++ ++free_info_rec: ++ if (flashnode_info) ++ free(flashnode_info); ++ ++ return rc; ++} ++ ++int iscsi_new_flashnode(struct iscsi_transport *t, uint32_t host_no, char *val, ++ uint32_t *flashnode_idx) ++{ ++ int fd, rc = 0; ++ ++ fd = ipc->ctldev_open(); ++ if (fd < 0) { ++ log_error("Netlink open failed."); ++ rc = ISCSI_ERR_INTERNAL; ++ goto exit_new_flashnode; ++ } ++ ++ log_info("Create new flashnode for host %u.", host_no); ++ rc = ipc->new_flash_node(t->handle, host_no, val, flashnode_idx); ++ if (rc < 0) ++ rc = ISCSI_ERR; ++ ++ ipc->ctldev_close(); ++ ++exit_new_flashnode: ++ return rc; ++} ++ ++int iscsi_del_flashnode(struct iscsi_transport *t, uint32_t host_no, ++ uint32_t flashnode_idx) ++{ ++ int fd, rc = 0; ++ ++ fd = ipc->ctldev_open(); ++ if (fd < 0) { ++ log_error("Netlink open failed."); ++ rc = ISCSI_ERR_INTERNAL; ++ goto exit_del_flashnode; ++ } ++ ++ log_info("Delete flashnode %u.", flashnode_idx); ++ rc = ipc->del_flash_node(t->handle, host_no, flashnode_idx); ++ if (rc < 0) ++ rc = ISCSI_ERR; ++ ++ ipc->ctldev_close(); ++ ++exit_del_flashnode: ++ return rc; ++} ++ ++int iscsi_login_flashnode(struct iscsi_transport *t, uint32_t host_no, ++ uint32_t flashnode_idx) ++{ ++ int fd, rc = 0; ++ ++ fd = ipc->ctldev_open(); ++ if (fd < 0) { ++ log_error("Netlink open failed."); ++ rc = ISCSI_ERR_INTERNAL; ++ goto exit_login_flashnode; ++ } ++ ++ log_info("Login to flashnode %u.", flashnode_idx); ++ rc = ipc->login_flash_node(t->handle, host_no, flashnode_idx); ++ if (rc == -EPERM) ++ rc = ISCSI_ERR_SESS_EXISTS; ++ else if (rc < 0) ++ rc = ISCSI_ERR_LOGIN; ++ ++ ipc->ctldev_close(); ++ ++exit_login_flashnode: ++ return rc; ++} ++ ++int iscsi_logout_flashnode(struct iscsi_transport *t, uint32_t host_no, ++ uint32_t flashnode_idx) ++{ ++ int fd, rc = 0; ++ ++ fd = ipc->ctldev_open(); ++ if (fd < 0) { ++ log_error("Netlink open failed."); ++ rc = ISCSI_ERR_INTERNAL; ++ goto exit_logout; ++ } ++ ++ log_info("Logout flashnode %u.", flashnode_idx); ++ rc = ipc->logout_flash_node(t->handle, host_no, flashnode_idx); ++ if (rc == -ESRCH) ++ rc = ISCSI_ERR_SESS_NOT_FOUND; ++ else if (rc < 0) ++ rc = ISCSI_ERR_LOGOUT; ++ ++ ipc->ctldev_close(); ++ ++exit_logout: ++ return rc; ++} ++ ++int iscsi_logout_flashnode_sid(struct iscsi_transport *t, uint32_t host_no, ++ uint32_t sid) ++{ ++ int fd, rc = 0; ++ ++ fd = ipc->ctldev_open(); ++ if (fd < 0) { ++ log_error("Netlink open failed."); ++ rc = ISCSI_ERR_INTERNAL; ++ goto exit_logout_sid; ++ } ++ ++ log_info("Logout sid %u.", sid); ++ rc = ipc->logout_flash_node_sid(t->handle, host_no, sid); ++ if (rc < 0) { ++ log_error("Logout of sid %u failed.", sid); ++ rc = ISCSI_ERR_LOGOUT; ++ } else { ++ log_info("Logout of sid %u successful.", sid); ++ } ++ ++ ipc->ctldev_close(); ++ ++exit_logout_sid: ++ return rc; ++} ++ ++static int exec_flashnode_op(int op, int info_level, uint32_t host_no, ++ uint64_t fnode_idx, int type, ++ struct list_head *params) ++{ ++ struct iscsi_transport *t = NULL; ++ int rc = ISCSI_SUCCESS; ++ char *portal_type; ++ uint32_t flashnode_idx; ++ ++ if (op != OP_SHOW && op != OP_NOOP && op != OP_NEW && ++ fnode_idx > MAX_FLASHNODE_IDX) { ++ log_error("Invalid flashnode index"); ++ rc = ISCSI_ERR_INVAL; ++ goto exit_flashnode_op; ++ } ++ ++ flashnode_idx = (uint32_t)fnode_idx; ++ t = iscsi_sysfs_get_transport_by_hba(host_no); ++ if (!t) { ++ log_error("Could not match hostno %u to transport.", host_no); ++ rc = ISCSI_ERR_TRANS_NOT_FOUND; ++ goto exit_flashnode_op; ++ } ++ ++ switch (op) { ++ case OP_NOOP: ++ case OP_SHOW: ++ if (fnode_idx > MAX_FLASHNODE_IDX) ++ rc = list_flashnodes(info_level, host_no); ++ else ++ rc = get_flashnode_info(host_no, flashnode_idx); ++ break; ++ case OP_NEW: ++ if (type == IPV4) { ++ portal_type = "ipv4"; ++ } else if (type == IPV6) { ++ portal_type = "ipv6"; ++ } else { ++ log_error("Invalid type mentioned for flashnode"); ++ rc = ISCSI_ERR_INVAL; ++ goto exit_flashnode_op; ++ } ++ rc = iscsi_new_flashnode(t, host_no, portal_type, ++ &flashnode_idx); ++ if (!rc) ++ log_info("New flashnode for host %u added at index %u.", ++ host_no, flashnode_idx); ++ else ++ log_error("Creation of flashnode for host %u failed.", ++ host_no); ++ break; ++ case OP_DELETE: ++ rc = iscsi_del_flashnode(t, host_no, flashnode_idx); ++ if (!rc) ++ log_info("Flashnode %u of host %u deleted.", ++ flashnode_idx, host_no); ++ else ++ log_error("Deletion of flashnode %u of host %u failed.", ++ flashnode_idx, host_no); ++ break; ++ case OP_UPDATE: ++ rc = iscsi_set_flashnode_params(t, host_no, flashnode_idx, ++ params); ++ if (!rc) ++ log_info("Update for flashnode %u of host %u successful.", ++ flashnode_idx, host_no); ++ else ++ log_error("Update for flashnode %u of host %u failed.", ++ flashnode_idx, host_no); ++ break; ++ case OP_LOGIN: ++ rc = iscsi_login_flashnode(t, host_no, flashnode_idx); ++ if (!rc) ++ log_info("Login to flashnode %u of host %u successful.", ++ flashnode_idx, host_no); ++ else if (rc == ISCSI_ERR_SESS_EXISTS) ++ log_info("Flashnode %u of host %u already logged in.", ++ flashnode_idx, host_no); ++ else ++ log_error("Login to flashnode %u of host %u failed.", ++ flashnode_idx, host_no); ++ break; ++ case OP_LOGOUT: ++ rc = iscsi_logout_flashnode(t, host_no, flashnode_idx); ++ if (!rc) ++ log_info("Logout of flashnode %u of host %u successful.", ++ flashnode_idx, host_no); ++ else if (rc == ISCSI_ERR_SESS_NOT_FOUND) ++ log_info("Flashnode %u of host %u not logged in.", ++ flashnode_idx, host_no); ++ else ++ log_error("Logout of flashnode %u of host %u failed.", ++ flashnode_idx, host_no); ++ break; ++ default: ++ log_error("Invalid operation"); ++ rc = ISCSI_ERR_INVAL; ++ break; ++ } ++ ++exit_flashnode_op: ++ return rc; ++} ++ ++static void print_host_stats(struct iscsi_offload_host_stats *host_stats) ++{ ++ /* MAC */ ++ printf("Host Statistics:\n" ++ "\tmactx_frames: %lld\n" ++ "\tmactx_bytes: %lld\n" ++ "\tmactx_multicast_frames: %lld\n" ++ "\tmactx_broadcast_frames: %lld\n" ++ "\tmactx_pause_frames: %lld\n" ++ "\tmactx_control_frames: %lld\n" ++ "\tmactx_deferral: %lld\n" ++ "\tmactx_excess_deferral: %lld\n" ++ "\tmactx_late_collision: %lld\n" ++ "\tmactx_abort: %lld\n" ++ "\tmactx_single_collision: %lld\n" ++ "\tmactx_multiple_collision: %lld\n" ++ "\tmactx_collision: %lld\n" ++ "\tmactx_frames_dropped: %lld\n" ++ "\tmactx_jumbo_frames: %lld\n" ++ "\tmacrx_frames: %lld\n" ++ "\tmacrx_bytes: %lld\n" ++ "\tmacrx_unknown_control_frames: %lld\n" ++ "\tmacrx_pause_frames: %lld\n" ++ "\tmacrx_control_frames: %lld\n" ++ "\tmacrx_dribble: %lld\n" ++ "\tmacrx_frame_length_error: %lld\n" ++ "\tmacrx_jabber: %lld\n" ++ "\tmacrx_carrier_sense_error: %lld\n" ++ "\tmacrx_frame_discarded: %lld\n" ++ "\tmacrx_frames_dropped: %lld\n" ++ "\tmac_crc_error: %lld\n" ++ "\tmac_encoding_error: %lld\n" ++ "\tmacrx_length_error_large: %lld\n" ++ "\tmacrx_length_error_small: %lld\n" ++ "\tmacrx_multicast_frames: %lld\n" ++ "\tmacrx_broadcast_frames: %lld\n" ++ /* IP */ ++ "\tiptx_packets: %lld\n" ++ "\tiptx_bytes: %lld\n" ++ "\tiptx_fragments: %lld\n" ++ "\tiprx_packets: %lld\n" ++ "\tiprx_bytes: %lld\n" ++ "\tiprx_fragments: %lld\n" ++ "\tip_datagram_reassembly: %lld\n" ++ "\tip_invalid_address_error: %lld\n" ++ "\tip_error_packets: %lld\n" ++ "\tip_fragrx_overlap: %lld\n" ++ "\tip_fragrx_outoforder: %lld\n" ++ "\tip_datagram_reassembly_timeout: %lld\n" ++ "\tipv6tx_packets: %lld\n" ++ "\tipv6tx_bytes: %lld\n" ++ "\tipv6tx_fragments: %lld\n" ++ "\tipv6rx_packets: %lld\n" ++ "\tipv6rx_bytes: %lld\n" ++ "\tipv6rx_fragments: %lld\n" ++ "\tipv6_datagram_reassembly: %lld\n" ++ "\tipv6_invalid_address_error: %lld\n" ++ "\tipv6_error_packets: %lld\n" ++ "\tipv6_fragrx_overlap: %lld\n" ++ "\tipv6_fragrx_outoforder: %lld\n" ++ "\tipv6_datagram_reassembly_timeout: %lld\n" ++ /* TCP */ ++ "\ttcptx_segments: %lld\n" ++ "\ttcptx_bytes: %lld\n" ++ "\ttcprx_segments: %lld\n" ++ "\ttcprx_byte: %lld\n" ++ "\ttcp_duplicate_ack_retx: %lld\n" ++ "\ttcp_retx_timer_expired: %lld\n" ++ "\ttcprx_duplicate_ack: %lld\n" ++ "\ttcprx_pure_ackr: %lld\n" ++ "\ttcptx_delayed_ack: %lld\n" ++ "\ttcptx_pure_ack: %lld\n" ++ "\ttcprx_segment_error: %lld\n" ++ "\ttcprx_segment_outoforder: %lld\n" ++ "\ttcprx_window_probe: %lld\n" ++ "\ttcprx_window_update: %lld\n" ++ "\ttcptx_window_probe_persist: %lld\n" ++ /* ECC */ ++ "\tecc_error_correction: %lld\n" ++ /* iSCSI */ ++ "\tiscsi_pdu_tx: %lld\n" ++ "\tiscsi_data_bytes_tx: %lld\n" ++ "\tiscsi_pdu_rx: %lld\n" ++ "\tiscsi_data_bytes_rx: %lld\n" ++ "\tiscsi_io_completed: %lld\n" ++ "\tiscsi_unexpected_io_rx: %lld\n" ++ "\tiscsi_format_error: %lld\n" ++ "\tiscsi_hdr_digest_error: %lld\n" ++ "\tiscsi_data_digest_error: %lld\n" ++ "\tiscsi_sequence_error: %lld\n", ++ /* MAC */ ++ (unsigned long long)host_stats->mactx_frames, ++ (unsigned long long)host_stats->mactx_bytes, ++ (unsigned long long)host_stats->mactx_multicast_frames, ++ (unsigned long long)host_stats->mactx_broadcast_frames, ++ (unsigned long long)host_stats->mactx_pause_frames, ++ (unsigned long long)host_stats->mactx_control_frames, ++ (unsigned long long)host_stats->mactx_deferral, ++ (unsigned long long)host_stats->mactx_excess_deferral, ++ (unsigned long long)host_stats->mactx_late_collision, ++ (unsigned long long)host_stats->mactx_abort, ++ (unsigned long long)host_stats->mactx_single_collision, ++ (unsigned long long)host_stats->mactx_multiple_collision, ++ (unsigned long long)host_stats->mactx_collision, ++ (unsigned long long)host_stats->mactx_frames_dropped, ++ (unsigned long long)host_stats->mactx_jumbo_frames, ++ (unsigned long long)host_stats->macrx_frames, ++ (unsigned long long)host_stats->macrx_bytes, ++ (unsigned long long)host_stats->macrx_unknown_control_frames, ++ (unsigned long long)host_stats->macrx_pause_frames, ++ (unsigned long long)host_stats->macrx_control_frames, ++ (unsigned long long)host_stats->macrx_dribble, ++ (unsigned long long)host_stats->macrx_frame_length_error, ++ (unsigned long long)host_stats->macrx_jabber, ++ (unsigned long long)host_stats->macrx_carrier_sense_error, ++ (unsigned long long)host_stats->macrx_frame_discarded, ++ (unsigned long long)host_stats->macrx_frames_dropped, ++ (unsigned long long)host_stats->mac_crc_error, ++ (unsigned long long)host_stats->mac_encoding_error, ++ (unsigned long long)host_stats->macrx_length_error_large, ++ (unsigned long long)host_stats->macrx_length_error_small, ++ (unsigned long long)host_stats->macrx_multicast_frames, ++ (unsigned long long)host_stats->macrx_broadcast_frames, ++ /* IP */ ++ (unsigned long long)host_stats->iptx_packets, ++ (unsigned long long)host_stats->iptx_bytes, ++ (unsigned long long)host_stats->iptx_fragments, ++ (unsigned long long)host_stats->iprx_packets, ++ (unsigned long long)host_stats->iprx_bytes, ++ (unsigned long long)host_stats->iprx_fragments, ++ (unsigned long long)host_stats->ip_datagram_reassembly, ++ (unsigned long long)host_stats->ip_invalid_address_error, ++ (unsigned long long)host_stats->ip_error_packets, ++ (unsigned long long)host_stats->ip_fragrx_overlap, ++ (unsigned long long)host_stats->ip_fragrx_outoforder, ++ (unsigned long long)host_stats->ip_datagram_reassembly_timeout, ++ (unsigned long long)host_stats->ipv6tx_packets, ++ (unsigned long long)host_stats->ipv6tx_bytes, ++ (unsigned long long)host_stats->ipv6tx_fragments, ++ (unsigned long long)host_stats->ipv6rx_packets, ++ (unsigned long long)host_stats->ipv6rx_bytes, ++ (unsigned long long)host_stats->ipv6rx_fragments, ++ (unsigned long long)host_stats->ipv6_datagram_reassembly, ++ (unsigned long long)host_stats->ipv6_invalid_address_error, ++ (unsigned long long)host_stats->ipv6_error_packets, ++ (unsigned long long)host_stats->ipv6_fragrx_overlap, ++ (unsigned long long)host_stats->ipv6_fragrx_outoforder, ++ (unsigned long long)host_stats->ipv6_datagram_reassembly_timeout, ++ /* TCP */ ++ (unsigned long long)host_stats->tcptx_segments, ++ (unsigned long long)host_stats->tcptx_bytes, ++ (unsigned long long)host_stats->tcprx_segments, ++ (unsigned long long)host_stats->tcprx_byte, ++ (unsigned long long)host_stats->tcp_duplicate_ack_retx, ++ (unsigned long long)host_stats->tcp_retx_timer_expired, ++ (unsigned long long)host_stats->tcprx_duplicate_ack, ++ (unsigned long long)host_stats->tcprx_pure_ackr, ++ (unsigned long long)host_stats->tcptx_delayed_ack, ++ (unsigned long long)host_stats->tcptx_pure_ack, ++ (unsigned long long)host_stats->tcprx_segment_error, ++ (unsigned long long)host_stats->tcprx_segment_outoforder, ++ (unsigned long long)host_stats->tcprx_window_probe, ++ (unsigned long long)host_stats->tcprx_window_update, ++ (unsigned long long)host_stats->tcptx_window_probe_persist, ++ /* ECC */ ++ (unsigned long long)host_stats->ecc_error_correction, ++ /* iSCSI */ ++ (unsigned long long)host_stats->iscsi_pdu_tx, ++ (unsigned long long)host_stats->iscsi_data_bytes_tx, ++ (unsigned long long)host_stats->iscsi_pdu_rx, ++ (unsigned long long)host_stats->iscsi_data_bytes_rx, ++ (unsigned long long)host_stats->iscsi_io_completed, ++ (unsigned long long)host_stats->iscsi_unexpected_io_rx, ++ (unsigned long long)host_stats->iscsi_format_error, ++ (unsigned long long)host_stats->iscsi_hdr_digest_error, ++ (unsigned long long)host_stats->iscsi_data_digest_error, ++ (unsigned long long)host_stats->iscsi_sequence_error); ++} ++ ++static int exec_host_stats_op(int op, int info_level, uint32_t host_no) ++{ ++ struct iscsi_transport *t = NULL; ++ char *req_buf = NULL; ++ int rc = ISCSI_SUCCESS; ++ int fd = 0, buf_size = 0; ++ ++ t = iscsi_sysfs_get_transport_by_hba(host_no); ++ if (!t) { ++ log_error("Could not match hostno %u to transport.", host_no); ++ rc = ISCSI_ERR_TRANS_NOT_FOUND; ++ goto exit_host_stats; ++ } ++ ++ buf_size = sizeof(struct iscsi_offload_host_stats) + ++ sizeof(struct iscsi_uevent); ++ req_buf = calloc(1, buf_size); ++ if (!req_buf) { ++ log_error("Could not allocate memory for host stats request."); ++ rc = ISCSI_ERR_NOMEM; ++ goto exit_host_stats; ++ } ++ ++ fd = ipc->ctldev_open(); ++ if (fd < 0) { ++ rc = ISCSI_ERR_INTERNAL; ++ log_error("Netlink open failed."); ++ goto exit_host_stats; ++ } ++ ++ rc = ipc->get_host_stats(t->handle, host_no, req_buf); ++ if (rc < 0) { ++ log_error("get_host_stats failed. errno=%d", errno); ++ rc = ISCSI_ERR; ++ goto exit_host_stats; ++ } ++ ++ print_host_stats((struct iscsi_offload_host_stats *)(req_buf + ++ sizeof(struct iscsi_uevent))); ++ ++ ipc->ctldev_close(); ++ ++exit_host_stats: ++ free(req_buf); ++ return rc; ++} ++ + static int verify_iface_params(struct list_head *params, struct node_rec *rec) + { + struct user_param *param; +@@ -1473,7 +2290,7 @@ static int verify_iface_params(struct list_head *params, struct node_rec *rec) + + /* TODO: merge iter helpers and clean them up, so we can use them here */ + static int exec_iface_op(int op, int do_show, int info_level, +- struct iface_rec *iface, uint32_t host_no, ++ struct iface_rec *iface, uint64_t host_no, + struct list_head *params) + { + struct host_info hinfo; +@@ -1594,9 +2411,9 @@ update_fail: + printf("%s applied.\n", iface->name); + break; + case OP_APPLY_ALL: +- if (host_no == -1) { +- log_error("Applyall requires a host number or MAC " +- "passed in with the --host argument."); ++ if (host_no > MAX_HOST_NO) { ++ log_error("Applyall requires a valid host number or MAC" ++ " passed in with the --host argument."); + rc = ISCSI_ERR_INVAL; + break; + } +@@ -1607,7 +2424,7 @@ update_fail: + memset(&hinfo, 0, sizeof(struct host_info)); + hinfo.host_no = host_no; + if (iscsi_sysfs_get_hostinfo_by_host_no(&hinfo)) { +- log_error("Could not match host%u to ifaces.", host_no); ++ log_error("Could not match host%lu to ifaces.", host_no); + rc = ISCSI_ERR_INVAL; + break; + } +@@ -1618,7 +2435,7 @@ update_fail: + break; + } + +- printf("Applied settings to ifaces attached to host%u.\n", ++ printf("Applied settings to ifaces attached to host%lu.\n", + host_no); + break; + default: +@@ -1711,12 +2528,12 @@ static int exec_node_op(int op, int do_login, int do_logout, + } + + if (do_rescan) { +- rc = for_each_session(rec, rescan_portal); ++ rc = for_each_session(rec, rescan_portal, 1); + goto out; + } + + if (do_stats) { +- rc = for_each_session(rec, session_stats); ++ rc = for_each_session(rec, session_stats, 0); + goto out; + } + +@@ -1832,7 +2649,7 @@ static int exec_fw_disc_op(discovery_rec_t *drec, struct list_head *ifaces, + rc = fw_get_targets(&targets); + if (rc) { + log_error("Could not get list of targets from firmware. " +- "(err %d)\n", rc); ++ "(err %d)", rc); + return rc; + } + rc = iface_create_ifaces_from_boot_contexts(&new_ifaces, &targets); +@@ -1845,7 +2662,7 @@ discover_fw_tgts: + rc = idbm_bind_ifaces_to_nodes(discovery_fw, drec, + ifaces, &rec_list); + if (rc) +- log_error("Could not perform fw discovery.\n"); ++ log_error("Could not perform fw discovery."); + else + rc = exec_disc_op_on_recs(drec, &rec_list, info_level, + do_login, op); +@@ -1883,7 +2700,7 @@ static int exec_fw_op(discovery_rec_t *drec, struct list_head *ifaces, + rc = fw_get_targets(&targets); + if (rc) { + log_error("Could not get list of targets from firmware. " +- "(err %d)\n", rc); ++ "(err %d)", rc); + return rc; + } + +@@ -1892,7 +2709,7 @@ static int exec_fw_op(discovery_rec_t *drec, struct list_head *ifaces, + rec = idbm_create_rec_from_boot_context(context); + if (!rec) { + log_error("Could not convert firmware info to " +- "node record.\n"); ++ "node record."); + rc = ISCSI_ERR_NOMEM; + break; + } +@@ -1999,16 +2816,10 @@ static int exec_discover(int disc_type, char *ip, int port, + rc = 0; + switch (disc_type) { + case DISCOVERY_TYPE_SENDTARGETS: +- /* +- * idbm_add_discovery call above handles drec syncing so +- * we always pass in 0 here. +- */ +- rc = do_sendtargets(drec, ifaces, info_level, do_login, op, ++ case DISCOVERY_TYPE_ISNS: ++ rc = do_target_discovery(drec, ifaces, info_level, do_login, op, + 0); + break; +- case DISCOVERY_TYPE_ISNS: +- rc = do_isns(drec, ifaces, info_level, do_login, op); +- break; + default: + log_error("Unsupported discovery type."); + break; +@@ -2140,8 +2951,7 @@ static int exec_disc_op(int disc_type, char *ip, int port, + idbm_sendtargets_defaults(&drec.u.sendtargets); + strlcpy(drec.address, ip, sizeof(drec.address)); + drec.port = port; +- +- rc = do_sendtargets(&drec, ifaces, info_level, ++ rc = do_target_discovery(&drec, ifaces, info_level, + do_login, op, 1); + if (rc) + goto done; +@@ -2164,7 +2974,9 @@ static int exec_disc_op(int disc_type, char *ip, int port, + else + drec.port = port; + +- rc = do_isns(&drec, ifaces, info_level, do_login, op); ++ drec.type = DISCOVERY_TYPE_ISNS; ++ rc = do_target_discovery(&drec, ifaces, info_level, ++ do_login, op, 0); + if (rc) + goto done; + break; +@@ -2195,8 +3007,9 @@ static int exec_disc_op(int disc_type, char *ip, int port, + } + if ((do_discover || do_login) && + drec.type == DISCOVERY_TYPE_SENDTARGETS) { +- rc = do_sendtargets(&drec, ifaces, info_level, +- do_login, op, 0); ++ rc = do_target_discovery(&drec, ifaces, ++ info_level, do_login, ++ op, 0); + } else if (op == OP_NOOP || op == OP_SHOW) { + if (!idbm_print_discovery_info(&drec, + do_show)) { +@@ -2234,10 +3047,10 @@ done: + return rc; + } + +-static uint32_t parse_host_info(char *optarg, int *rc) ++static uint64_t parse_host_info(char *optarg, int *rc) + { + int err = 0; +- uint32_t host_no = -1; ++ uint64_t host_no; + + *rc = 0; + if (strstr(optarg, ":")) { +@@ -2250,8 +3063,11 @@ static uint32_t parse_host_info(char *optarg, int *rc) + *rc = ISCSI_ERR_INVAL; + } + } else { +- host_no = strtoul(optarg, NULL, 10); +- if (errno) { ++ host_no = strtoull(optarg, NULL, 10); ++ if (errno || (host_no > MAX_HOST_NO)) { ++ if (host_no > MAX_HOST_NO) ++ errno = ERANGE; ++ + log_error("Invalid host no %s. %s.", + optarg, strerror(errno)); + *rc = ISCSI_ERR_INVAL; +@@ -2286,7 +3102,7 @@ static char *iscsi_ping_stat_strs[] = { + static char *iscsi_ping_stat_to_str(uint32_t status) + { + if (status < 0 || status > ISCSI_PING_NO_ARP_RECEIVED) { +- log_error("Invalid ping status %u\n", status); ++ log_error("Invalid ping status %u", status); + return NULL; + } + +@@ -2301,6 +3117,7 @@ static int exec_ping_op(struct iface_rec *iface, char *ip, int size, int count, + struct iscsi_transport *t = NULL; + uint32_t host_no, status = 0; + struct sockaddr_storage addr; ++ struct host_info hinfo; + int i; + + if (!iface) { +@@ -2369,13 +3186,32 @@ static int exec_ping_op(struct iface_rec *iface, char *ip, int size, int count, + for (i = 1; i <= count; i++) { + /* + * To support drivers like bnx2i that do not use +- * the iscsi if to send a ping, we can add a transport ++ * the iscsi iface to send a ping, we invoke transport + * callout here. + */ + status = 0; +- rc = ipc->exec_ping(t->handle, host_no, +- (struct sockaddr *)&addr, iface->iface_num, +- iface_type, size, &status); ++ if (t->template->exec_ping) { ++ if (!strlen(iface->netdev)) { ++ memset(&hinfo, 0, sizeof(hinfo)); ++ hinfo.host_no = host_no; ++ iscsi_sysfs_get_hostinfo_by_host_no(&hinfo); ++ strcpy(iface->netdev, hinfo.iface.netdev); ++ } ++ ++ rc = iscsi_set_net_config(t, NULL, iface); ++ if (rc && (rc != ISCSI_ERR_AGAIN)) ++ goto ping_err; ++ ++ rc = t->template->exec_ping(t, iface, size, &addr, ++ &status); ++ } else { ++ rc = ipc->exec_ping(t->handle, host_no, ++ (struct sockaddr *)&addr, ++ iface->iface_num, iface_type, ++ (uint32_t)size, &status); ++ } ++ ++ping_err: + if (!rc && !status) + printf("Ping %d completed\n", i); + else if (status) +@@ -2403,12 +3239,14 @@ main(int argc, char **argv) + int tpgt = PORTAL_GROUP_TAG_UNKNOWN, killiscsid=-1, do_show=0; + int packet_size=32, ping_count=1, ping_interval=0; + int do_discover = 0, sub_mode = -1; ++ int portal_type = -1; + struct sigaction sa_old; + struct sigaction sa_new; + struct list_head ifaces; + struct iface_rec *iface = NULL, *tmp; + struct node_rec *rec = NULL; +- uint32_t host_no = -1; ++ uint64_t host_no = (uint64_t)MAX_HOST_NO + 1; ++ uint64_t index = ULLONG_MAX; + struct user_param *param; + struct list_head params; + +@@ -2551,6 +3389,18 @@ main(int argc, char **argv) + printf("%s version %s\n", program_name, + ISCSI_VERSION_STR); + return 0; ++ case 'x': ++ index = strtoull(optarg, NULL, 10); ++ if (errno) { ++ log_error("Invalid index %s. %s.", ++ optarg, strerror(errno)); ++ rc = ISCSI_ERR_INVAL; ++ goto free_ifaces; ++ } ++ break; ++ case 'A': ++ portal_type = str_to_portal_type(optarg); ++ break; + case 'h': + usage(0); + } +@@ -2583,7 +3433,7 @@ main(int argc, char **argv) + usage(ISCSI_ERR_INVAL); + + if (mode == MODE_FW) { +- if ((rc = verify_mode_params(argc, argv, "ml", 0))) { ++ if ((rc = verify_mode_params(argc, argv, "dml", 0))) { + log_error("fw mode: option '-%c' is not " + "allowed/supported", rc); + rc = ISCSI_ERR_INVAL; +@@ -2603,7 +3453,7 @@ main(int argc, char **argv) + + switch (mode) { + case MODE_HOST: +- if ((rc = verify_mode_params(argc, argv, "CHdmPov", 0))) { ++ if ((rc = verify_mode_params(argc, argv, "CHdmPotnvxA", 0))) { + log_error("host mode: option '-%c' is not " + "allowed/supported", rc); + rc = ISCSI_ERR_INVAL; +@@ -2612,15 +3462,44 @@ main(int argc, char **argv) + if (sub_mode != -1) { + switch (sub_mode) { + case MODE_CHAP: +- if (!op || !host_no) { ++ if (!op || (host_no > MAX_HOST_NO)) { + log_error("CHAP mode requires host " + "no and valid operation"); + rc = ISCSI_ERR_INVAL; + break; + } ++ ++ if (index == ULLONG_MAX) ++ index = (uint64_t)MAX_CHAP_ENTRIES + 1; ++ + rc = exec_host_chap_op(op, info_level, host_no, +- value); ++ index, ¶ms); + break; ++ case MODE_FLASHNODE: ++ if (host_no > MAX_HOST_NO) { ++ log_error("FLASHNODE mode requires host no"); ++ rc = ISCSI_ERR_INVAL; ++ break; ++ } ++ ++ if (index == ULLONG_MAX) ++ index = (uint64_t)MAX_FLASHNODE_IDX + 1; ++ ++ rc = exec_flashnode_op(op, info_level, host_no, ++ index, portal_type, ++ ¶ms); ++ break; ++ case MODE_HOST_STATS: ++ if (host_no > MAX_HOST_NO) { ++ log_error("STATS mode requires host no"); ++ rc = ISCSI_ERR_INVAL; ++ break; ++ } ++ ++ rc = exec_host_stats_op(op, info_level, ++ host_no); ++ break; ++ + default: + log_error("Invalid Sub Mode"); + break; +diff --git a/usr/iscsid.c b/usr/iscsid.c +index b4bb65b..f8ffd23 100644 +--- a/usr/iscsid.c ++++ b/usr/iscsid.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -111,9 +112,7 @@ setup_rec_from_negotiated_values(node_rec_t *rec, struct session_info *info) + strlcpy(rec->name, info->targetname, TARGET_NAME_MAXLEN); + rec->conn[0].port = info->persistent_port; + strlcpy(rec->conn[0].address, info->persistent_address, NI_MAXHOST); +- memcpy(&rec->iface, &info->iface, sizeof(struct iface_rec)); + rec->tpgt = info->tpgt; +- iface_copy(&rec->iface, &info->iface); + + iscsi_sysfs_get_negotiated_session_conf(info->sid, &session_conf); + iscsi_sysfs_get_negotiated_conn_conf(info->sid, &conn_conf); +@@ -194,7 +193,7 @@ static int sync_session(void *data, struct session_info *info) + struct iscsi_transport *t; + int rc, retries = 0; + +- log_debug(7, "sync session [%d][%s,%s.%d][%s]\n", info->sid, ++ log_debug(7, "sync session [%d][%s,%s.%d][%s]", info->sid, + info->targetname, info->persistent_address, + info->port, info->iface.hwaddress); + +@@ -236,8 +235,9 @@ static int sync_session(void *data, struct session_info *info) + info->persistent_address, info->persistent_port, + &info->iface)) { + log_warning("Could not read data from db. Using default and " +- "currently negotiated values\n"); ++ "currently negotiated values"); + setup_rec_from_negotiated_values(&rec, info); ++ iface_copy(&rec.iface, &info->iface); + } else { + /* + * we have a valid record and iface so lets merge +@@ -251,13 +251,12 @@ static int sync_session(void *data, struct session_info *info) + memset(&sysfsrec, 0, sizeof(node_rec_t)); + setup_rec_from_negotiated_values(&sysfsrec, info); + /* +- * target, portal and iface name values have to be the same ++ * target, portal and iface values have to be the same + * or we would not have found the record, so just copy +- * CHAP and iface settings. ++ * CHAP settings. + */ + memcpy(&rec.session.auth, &sysfsrec.session.auth, + sizeof(struct iscsi_auth_config)); +- memcpy(&rec.iface, &info->iface, sizeof(rec.iface)); + } + + /* multiple drivers could be connected to the same portal */ +@@ -333,7 +332,7 @@ static void missing_iname_warn(char *initiatorname_file) + "iqn.yyyy-mm.[:identifier].\n\n" + "Example: InitiatorName=iqn.2001-04.com.redhat:fc6.\n" + "If using hardware iscsi like qla4xxx this message can be " +- "ignored.\n", initiatorname_file, initiatorname_file); ++ "ignored.", initiatorname_file, initiatorname_file); + } + + int main(int argc, char *argv[]) +@@ -342,6 +341,7 @@ int main(int argc, char *argv[]) + char *config_file = CONFIG_FILE; + char *initiatorname_file = INITIATOR_NAME_FILE; + char *pid_file = PID_FILE; ++ char *safe_logout; + int ch, longindex; + uid_t uid = 0; + struct sigaction sa_old; +@@ -477,11 +477,25 @@ int main(int argc, char *argv[]) + } + } + +- if (uid && setuid(uid) < 0) +- perror("setuid\n"); ++ if (gid && setgid(gid) < 0) { ++ log_error("Unable to setgid to %d", gid); ++ log_close(log_pid); ++ exit(ISCSI_ERR); ++ } + +- if (gid && setgid(gid) < 0) +- perror("setgid\n"); ++ if ((geteuid() == 0) && (getgroups(0, NULL))) { ++ if (setgroups(0, NULL) != 0) { ++ log_error("Unable to drop supplementary group ids"); ++ log_close(log_pid); ++ exit(ISCSI_ERR); ++ } ++ } ++ ++ if (uid && setuid(uid) < 0) { ++ log_error("Unable to setuid to %d", uid); ++ log_close(log_pid); ++ exit(ISCSI_ERR); ++ } + + memset(&daemon_config, 0, sizeof (daemon_config)); + daemon_config.pid_file = pid_file; +@@ -507,11 +521,17 @@ int main(int argc, char *argv[]) + daemon_config.initiator_name : "NOT SET"); + log_debug(1, "InitiatorAlias=%s", daemon_config.initiator_alias); + ++ safe_logout = cfg_get_string_param(config_file, "iscsid.safe_logout"); ++ if (safe_logout && !strcmp(safe_logout, "Yes")) ++ daemon_config.safe_logout = 1; ++ free(safe_logout); ++ + pid = fork(); + if (pid == 0) { + int nr_found = 0; + /* child */ +- iscsi_sysfs_for_each_session(NULL, &nr_found, sync_session); ++ /* TODO - test with async support enabled */ ++ iscsi_sysfs_for_each_session(NULL, &nr_found, sync_session, 0); + exit(0); + } else if (pid < 0) { + log_error("Fork failed error %d: existing sessions" +@@ -534,7 +554,6 @@ int main(int argc, char *argv[]) + exit(ISCSI_ERR); + } + +- actor_init(); + event_loop(ipc, control_fd, mgmt_ipc_fd); + + idbm_terminate(); +diff --git a/usr/iscsid.h b/usr/iscsid.h +index 15f264f..b9f3d54 100644 +--- a/usr/iscsid.h ++++ b/usr/iscsid.h +@@ -29,6 +29,7 @@ struct iscsi_daemon_config { + char *pid_file; + char *initiator_name; + char *initiator_alias; ++ int safe_logout; + }; + extern struct iscsi_daemon_config *dconfig; + +diff --git a/usr/iscsid_req.c b/usr/iscsid_req.c +index 0902011..2950d74 100644 +--- a/usr/iscsid_req.c ++++ b/usr/iscsid_req.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -32,6 +33,7 @@ + #include "iscsi_util.h" + #include "config.h" + #include "iscsi_err.h" ++#include "uip_mgmt_ipc.h" + + static void iscsid_startup(void) + { +@@ -54,9 +56,9 @@ static void iscsid_startup(void) + + #define MAXSLEEP 128 + +-static int iscsid_connect(int *fd, int start_iscsid) ++static int ipc_connect(int *fd, char *unix_sock_name, int start_iscsid) + { +- int nsec; ++ int nsec, addr_len; + struct sockaddr_un addr; + + *fd = socket(AF_LOCAL, SOCK_STREAM, 0); +@@ -65,15 +67,13 @@ static int iscsid_connect(int *fd, int start_iscsid) + return ISCSI_ERR_ISCSID_NOTCONN; + } + +- memset(&addr, 0, sizeof(addr)); +- addr.sun_family = AF_LOCAL; +- memcpy((char *) &addr.sun_path + 1, ISCSIADM_NAMESPACE, +- strlen(ISCSIADM_NAMESPACE)); ++ addr_len = setup_abstract_addr(&addr, unix_sock_name); ++ + /* + * Trying to connect with exponential backoff + */ + for (nsec = 1; nsec <= MAXSLEEP; nsec <<= 1) { +- if (connect(*fd, (struct sockaddr *) &addr, sizeof(addr)) == 0) ++ if (connect(*fd, (struct sockaddr *) &addr, addr_len) == 0) + /* Connection established */ + return ISCSI_SUCCESS; + +@@ -96,6 +96,11 @@ static int iscsid_connect(int *fd, int start_iscsid) + return ISCSI_ERR_ISCSID_NOTCONN; + } + ++static int iscsid_connect(int *fd, int start_iscsid) ++{ ++ return ipc_connect(fd, ISCSIADM_NAMESPACE, start_iscsid); ++} ++ + int iscsid_request(int *fd, iscsiadm_req_t *req, int start_iscsid) + { + int err; +@@ -192,3 +197,109 @@ int iscsid_req_by_sid(iscsiadm_cmd_e cmd, int sid) + return err; + return iscsid_req_wait(cmd, fd); + } ++ ++static int uip_connect(int *fd) ++{ ++ return ipc_connect(fd, ISCSID_UIP_NAMESPACE, 0); ++} ++ ++int uip_broadcast(void *buf, size_t buf_len, int fd_flags, uint32_t *status) ++{ ++ int err; ++ int fd; ++ iscsid_uip_rsp_t rsp; ++ int flags; ++ int count; ++ ++ err = uip_connect(&fd); ++ if (err) { ++ log_warning("uIP daemon is not up"); ++ return err; ++ } ++ ++ log_debug(3, "connected to uIP daemon"); ++ ++ /* Send the data to uIP */ ++ err = write(fd, buf, buf_len); ++ if (err != buf_len) { ++ log_error("got write error (%d/%d), daemon died?", ++ err, errno); ++ close(fd); ++ return ISCSI_ERR_ISCSID_COMM_ERR; ++ } ++ ++ log_debug(3, "send iface config to uIP daemon"); ++ ++ /* Set the socket to a non-blocking read, this way if there are ++ * problems waiting for uIP, iscsid can bailout early */ ++ flags = fcntl(fd, F_GETFL, 0); ++ if (flags == -1) ++ flags = 0; ++ ++ if (fd_flags) ++ flags |= fd_flags; ++ ++ err = fcntl(fd, F_SETFL, flags); ++ if (err) { ++ log_error("could not set uip broadcast to non-blocking: %d", ++ errno); ++ close(fd); ++ return ISCSI_ERR; ++ } ++ ++#define MAX_UIP_BROADCAST_READ_TRIES 5 ++ for (count = 0; count < MAX_UIP_BROADCAST_READ_TRIES; count++) { ++ /* Wait for the response */ ++ err = read(fd, &rsp, sizeof(rsp)); ++ if (err == sizeof(rsp)) { ++ log_debug(3, "Broadcasted to uIP with length: %ld " ++ "cmd: 0x%x rsp: 0x%x", buf_len, ++ rsp.command, rsp.err); ++ err = 0; ++ break; ++ } else if ((err == -1) && (errno == EAGAIN)) { ++ usleep(1000000); ++ continue; ++ } else { ++ log_error("Could not read response (%d/%d), daemon " ++ "died?", err, errno); ++ err = ISCSI_ERR; ++ break; ++ } ++ } ++ ++ if (count == MAX_UIP_BROADCAST_READ_TRIES) { ++ log_error("Could not broadcast to uIP after %d tries", ++ count); ++ err = ISCSI_ERR_AGAIN; ++ } ++ ++ if (err) ++ goto done; ++ ++ switch (rsp.command) { ++ case ISCSID_UIP_IPC_GET_IFACE: ++ if (rsp.err != ISCSID_UIP_MGMT_IPC_DEVICE_UP) { ++ log_debug(3, "Device is not ready\n"); ++ err = ISCSI_ERR_AGAIN; ++ } ++ ++ break; ++ case ISCSID_UIP_IPC_PING: ++ *status = rsp.ping_sc; ++ if (rsp.err == ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING) { ++ log_debug(3, "Device is not ready\n"); ++ err = ISCSI_ERR_AGAIN; ++ } else if (*status) { ++ err = ISCSI_ERR; ++ } ++ ++ break; ++ default: ++ err = ISCSI_ERR; ++ } ++ ++done: ++ close(fd); ++ return err; ++} +diff --git a/usr/iscsid_req.h b/usr/iscsid_req.h +index 68f5256..8cb4a92 100644 +--- a/usr/iscsid_req.h ++++ b/usr/iscsid_req.h +@@ -33,4 +33,7 @@ extern int iscsid_req_by_rec(int cmd, struct node_rec *rec); + extern int iscsid_req_by_sid_async(int cmd, int sid, int *fd); + extern int iscsid_req_by_sid(int cmd, int sid); + ++extern int uip_broadcast(void *buf, size_t buf_len, int fd_flags, ++ uint32_t *status); ++ + #endif +diff --git a/usr/iscsistart.c b/usr/iscsistart.c +index 6924d49..7ff2236 100644 +--- a/usr/iscsistart.c ++++ b/usr/iscsistart.c +@@ -126,7 +126,7 @@ static int stop_event_loop(void) + rc = iscsid_exec_req(&req, &rsp, 0); + if (rc) { + iscsi_err_print_msg(rc); +- log_error("Could not stop event_loop\n"); ++ log_error("Could not stop event_loop"); + } + return rc; + } +@@ -287,22 +287,22 @@ static void catch_signal(int signo) + static int check_params(char *initiatorname) + { + if (!initiatorname) { +- log_error("InitiatorName not set. Exiting %s\n", program_name); ++ log_error("InitiatorName not set. Exiting %s", program_name); + return EINVAL; + } + + if (config_rec.tpgt == PORTAL_GROUP_TAG_UNKNOWN) { +- log_error("Portal Group not set. Exiting %s\n", program_name); ++ log_error("Portal Group not set. Exiting %s", program_name); + return EINVAL; + } + + if (!strlen(config_rec.name)) { +- log_error("TargetName not set. Exiting %s\n", program_name); ++ log_error("TargetName not set. Exiting %s", program_name); + return EINVAL; + } + + if (!strlen(config_rec.conn[0].address)) { +- log_error("IP Address not set. Exiting %s\n", program_name); ++ log_error("IP Address not set. Exiting %s", program_name); + return EINVAL; + } + +@@ -472,7 +472,7 @@ int main(int argc, char *argv[]) + + mgmt_ipc_fd = mgmt_ipc_listen(); + if (mgmt_ipc_fd < 0) { +- log_error("Could not setup mgmt ipc\n"); ++ log_error("Could not setup mgmt ipc"); + exit(ISCSI_ERR_NOMEM); + } + +@@ -509,7 +509,6 @@ int main(int argc, char *argv[]) + * Start Main Event Loop + */ + iscsi_initiator_init(); +- actor_init(); + event_loop(ipc, control_fd, mgmt_ipc_fd); + ipc->ctldev_close(); + mgmt_ipc_close(mgmt_ipc_fd); +diff --git a/usr/login.c b/usr/login.c +index db76c80..8289b03 100644 +--- a/usr/login.c ++++ b/usr/login.c +@@ -50,16 +50,14 @@ iscsi_add_text(struct iscsi_hdr *pdu, char *data, int max_data_length, + int pdu_length = ntoh24(pdu->dlength); + char *text = data; + char *end = data + max_data_length; +- char *pdu_text; + + /* find the end of the current text */ + text += pdu_length; +- pdu_text = text; + pdu_length += length; + + if (text + length >= end) { + log_warning("Failed to add login text " +- "'%s=%s'\n", param, value); ++ "'%s=%s'", param, value); + return 0; + } + +@@ -170,7 +168,7 @@ resolve_address(char *host, char *port, struct sockaddr_storage *ss) + + if ((rc = getaddrinfo(host, port, &hints, &res))) { + log_error("Cannot resolve host %s. getaddrinfo error: " +- "[%s]\n", host, gai_strerror(rc)); ++ "[%s]", host, gai_strerror(rc)); + return rc; + } + +@@ -1558,10 +1556,10 @@ iscsi_login(iscsi_session_t *session, int cid, char *buffer, size_t bufsize, + repoll: + pfd.revents = 0; + ret = poll(&pfd, 1, timeout); +- log_debug(7, "%s: Poll return %d\n", __FUNCTION__, ret); ++ log_debug(7, "%s: Poll return %d", __FUNCTION__, ret); + if (iscsi_timer_expired(&connection_timer)) { + log_warning("Login response timeout. Waited %d " +- "seconds and did not get reponse PDU.\n", ++ "seconds and did not get reponse PDU.", + session->conn[0].active_timeout); + c->ret = LOGIN_FAILED; + return c->ret; +@@ -1595,7 +1593,7 @@ repoll: + } + + } else if (ret < 0) { +- log_error("Login poll error.\n"); ++ log_error("Login poll error."); + c->ret = LOGIN_FAILED; + return c->ret; + } +diff --git a/usr/md5.c b/usr/md5.c +index 4ef1cb7..ba6c86d 100644 +--- a/usr/md5.c ++++ b/usr/md5.c +@@ -127,7 +127,7 @@ MD5Final(md5byte digest[16], struct MD5Context *ctx) + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); +- memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ ++ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ + } + + #ifndef ASM_MD5 +diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c +index 5c39c2e..c16bce9 100644 +--- a/usr/mgmt_ipc.c ++++ b/usr/mgmt_ipc.c +@@ -36,28 +36,33 @@ + #include "sysdeps.h" + #include "iscsi_ipc.h" + #include "iscsi_err.h" ++#include "iscsi_util.h" + + #define PEERUSER_MAX 64 + #define EXTMSG_MAX (64 * 1024) ++#define SD_SOCKET_FDS_START 3 + + int + mgmt_ipc_listen(void) + { +- int fd, err; ++ int fd, err, addr_len; + struct sockaddr_un addr; + ++ /* first check if we have fd handled by systemd */ ++ fd = mgmt_ipc_systemd(); ++ if (fd >= 0) ++ return fd; ++ ++ /* manually establish a socket */ + fd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (fd < 0) { + log_error("Can not create IPC socket"); + return fd; + } + +- memset(&addr, 0, sizeof(addr)); +- addr.sun_family = AF_LOCAL; +- memcpy((char *) &addr.sun_path + 1, ISCSIADM_NAMESPACE, +- strlen(ISCSIADM_NAMESPACE)); ++ addr_len = setup_abstract_addr(&addr, ISCSIADM_NAMESPACE); + +- if ((err = bind(fd, (struct sockaddr *) &addr, sizeof(addr))) < 0) { ++ if ((err = bind(fd, (struct sockaddr *) &addr, addr_len)) < 0 ) { + log_error("Can not bind IPC socket"); + close(fd); + return err; +@@ -72,6 +77,28 @@ mgmt_ipc_listen(void) + return fd; + } + ++int mgmt_ipc_systemd(void) ++{ ++ const char *env; ++ ++ env = getenv("LISTEN_PID"); ++ ++ if (!env || (strtoul(env, NULL, 10) != getpid())) ++ return -EINVAL; ++ ++ env = getenv("LISTEN_FDS"); ++ ++ if (!env) ++ return -EINVAL; ++ ++ if (strtoul(env, NULL, 10) != 1) { ++ log_error("Did not receive exactly one IPC socket from systemd"); ++ return -EINVAL; ++ } ++ ++ return SD_SOCKET_FDS_START; ++} ++ + void + mgmt_ipc_close(int fd) + { +@@ -437,7 +464,6 @@ mgmt_ipc_write_rsp(queue_task_t *qtask, int err) + qtask->rsp.err = err; + if (write(qtask->mgmt_ipc_fd, &qtask->rsp, sizeof(qtask->rsp)) < 0) + log_error("IPC qtask write failed: %s", strerror(errno)); +- close(qtask->mgmt_ipc_fd); + mgmt_ipc_destroy_queue_task(qtask); + } + +diff --git a/usr/mgmt_ipc.h b/usr/mgmt_ipc.h +index 7d8ce72..55972ed 100644 +--- a/usr/mgmt_ipc.h ++++ b/usr/mgmt_ipc.h +@@ -112,6 +112,7 @@ typedef int mgmt_ipc_fn_t(struct queue_task *); + struct queue_task; + void mgmt_ipc_write_rsp(struct queue_task *qtask, int err); + int mgmt_ipc_listen(void); ++int mgmt_ipc_systemd(void); + void mgmt_ipc_close(int fd); + void mgmt_ipc_handle(int accept_fd); + +diff --git a/usr/netlink.c b/usr/netlink.c +index c43f686..2b85efe 100644 +--- a/usr/netlink.c ++++ b/usr/netlink.c +@@ -339,6 +339,10 @@ __kipc_call(struct iovec *iovp, int count) + } else if (ev->type == ISCSI_UEVENT_GET_CHAP) { + /* kget_chap() will read */ + return 0; ++ } else if (ev->type == ISCSI_UEVENT_GET_HOST_STATS) { ++ /* kget_host_stats() will read */ ++ return 0; ++ + } else { + if ((rc = nlpayload_read(ctrl_fd, (void*)ev, + sizeof(*ev), 0)) < 0) { +@@ -372,7 +376,7 @@ ksendtargets(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr) + else if (addr->sa_family == PF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else { +- log_error("%s unknown addr family %d\n", ++ log_error("%s unknown addr family %d", + __FUNCTION__, addr->sa_family); + return -EINVAL; + } +@@ -382,7 +386,7 @@ ksendtargets(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr) + iov[1].iov_len = sizeof(*ev) + addrlen; + rc = __kipc_call(iov, 2); + if (rc < 0) { +- log_error("sendtargets failed rc%d\n", rc); ++ log_error("sendtargets failed rc%d", rc); + return rc; + } + return 0; +@@ -674,7 +678,7 @@ kset_host_param(uint64_t transport_handle, uint32_t host_no, + sprintf(param_str, "%s", (char *)value); + break; + default: +- log_error("invalid type %d\n", type); ++ log_error("invalid type %d", type); + return -EINVAL; + } + ev->u.set_host_param.len = len = strlen(param_str) + 1; +@@ -712,13 +716,16 @@ kset_param(uint64_t transport_handle, uint32_t sid, uint32_t cid, + case ISCSI_INT: + sprintf(param_str, "%d", *((int *)value)); + break; ++ case ISCSI_UINT: ++ sprintf(param_str, "%u", *((unsigned int *)value)); ++ break; + case ISCSI_STRING: + if (!strlen(value)) + return 0; + sprintf(param_str, "%s", (char *)value); + break; + default: +- log_error("invalid type %d\n", type); ++ log_error("invalid type %d", type); + return -EINVAL; + } + ev->u.set_param.len = len = strlen(param_str) + 1; +@@ -866,7 +873,7 @@ ktransport_ep_connect(iscsi_conn_t *conn, int non_blocking) + else if (dst_addr->sa_family == PF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else { +- log_error("%s unknown addr family %d\n", ++ log_error("%s unknown addr family %d", + __FUNCTION__, dst_addr->sa_family); + return -EINVAL; + } +@@ -935,7 +942,7 @@ ktransport_ep_disconnect(iscsi_conn_t *conn) + iov[1].iov_len = sizeof(ev); + rc = __kipc_call(iov, 2); + if (rc < 0) { +- log_error("connnection %d:%d transport disconnect failed for " ++ log_error("connection %d:%d transport disconnect failed for " + "ep %" PRIu64 " with error %d.", conn->session->id, + conn->id, conn->transport_ep_handle, rc); + } else +@@ -1031,6 +1038,10 @@ static int krecv_conn_state(struct iscsi_conn *conn, uint32_t *state) + /* fatal handling error or conn error */ + goto exit; + ++ /* unexpected event without a receive context */ ++ if (!conn->recv_context) ++ return -EAGAIN; ++ + *state = *(enum iscsi_conn_state *)conn->recv_context->data; + + ipc_ev_clbk->put_ev_context(conn->recv_context); +@@ -1068,7 +1079,7 @@ ksend_ping(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr, + else if (addr->sa_family == PF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else { +- log_error("%s unknown addr family %d\n", ++ log_error("%s unknown addr family %d", + __FUNCTION__, addr->sa_family); + return -EINVAL; + } +@@ -1228,6 +1239,29 @@ static int kget_chap(uint64_t transport_handle, uint32_t host_no, + return rc; + } + ++static int kset_chap(uint64_t transport_handle, uint32_t host_no, ++ struct iovec *iovs, uint32_t param_count) ++{ ++ int rc; ++ struct iscsi_uevent ev; ++ struct iovec *iov = iovs + 1; ++ ++ log_debug(8, "in %s", __func__); ++ ++ ev.type = ISCSI_UEVENT_SET_CHAP; ++ ev.transport_handle = transport_handle; ++ ev.u.set_path.host_no = host_no; ++ ++ iov->iov_base = &ev; ++ iov->iov_len = sizeof(ev); ++ ++ rc = __kipc_call(iovs, param_count); ++ if (rc < 0) ++ return rc; ++ ++ return 0; ++} ++ + static int kdelete_chap(uint64_t transport_handle, uint32_t host_no, + uint16_t chap_tbl_idx) + { +@@ -1252,6 +1286,211 @@ static int kdelete_chap(uint64_t transport_handle, uint32_t host_no, + return rc; + } + ++static int ++kset_flashnode_params(uint64_t transport_handle, uint32_t host_no, ++ uint32_t flashnode_idx, struct iovec *iovs, ++ uint32_t param_count) ++{ ++ struct iscsi_uevent ev; ++ int rc, ev_len; ++ struct iovec *iov = iovs + 1; ++ ++ log_debug(8, "in %s", __FUNCTION__); ++ ++ ev_len = sizeof(ev); ++ ev.type = ISCSI_UEVENT_SET_FLASHNODE_PARAMS; ++ ev.transport_handle = transport_handle; ++ ev.u.set_flashnode.host_no = host_no; ++ ev.u.set_flashnode.flashnode_idx = flashnode_idx; ++ /* first two iovs for nlmsg hdr and ev */ ++ ev.u.set_flashnode.count = param_count - 2; ++ ++ iov->iov_base = &ev; ++ iov->iov_len = ev_len; ++ rc = __kipc_call(iovs, param_count); ++ if (rc < 0) ++ return rc; ++ ++ return 0; ++} ++ ++static int ++knew_flashnode(uint64_t transport_handle, uint32_t host_no, void *value, ++ uint32_t *flashnode_idx) ++{ ++ struct iscsi_uevent *ev; ++ char *param_str; ++ int rc, len; ++ struct iovec iov[2]; ++ ++ log_debug(7, "in %s", __FUNCTION__); ++ ++ memset(setparam_buf, 0, NLM_SETPARAM_DEFAULT_MAX); ++ ev = (struct iscsi_uevent *)setparam_buf; ++ ev->type = ISCSI_UEVENT_NEW_FLASHNODE; ++ ev->transport_handle = transport_handle; ++ ev->u.new_flashnode.host_no = host_no; ++ ++ param_str = setparam_buf + sizeof(*ev); ++ if (!strlen(value)) ++ return 0; ++ sprintf(param_str, "%s", (char *)value); ++ len = strlen(param_str) + 1; ++ ev->u.new_flashnode.len = len; ++ ++ ++ iov[1].iov_base = ev; ++ iov[1].iov_len = sizeof(*ev) + len; ++ rc = __kipc_call(iov, 2); ++ if (rc < 0) ++ return rc; ++ ++ *flashnode_idx = ev->r.new_flashnode_ret.flashnode_idx; ++ return 0; ++} ++ ++static int ++kdel_flashnode(uint64_t transport_handle, uint32_t host_no, ++ uint32_t flashnode_idx) ++{ ++ struct iscsi_uevent ev; ++ int rc; ++ struct iovec iov[2]; ++ ++ log_debug(7, "in %s", __FUNCTION__); ++ ++ memset(&ev, 0, sizeof(struct iscsi_uevent)); ++ ev.type = ISCSI_UEVENT_DEL_FLASHNODE; ++ ev.transport_handle = transport_handle; ++ ev.u.del_flashnode.host_no = host_no; ++ ev.u.del_flashnode.flashnode_idx = flashnode_idx; ++ ++ iov[1].iov_base = &ev; ++ iov[1].iov_len = sizeof(ev); ++ rc = __kipc_call(iov, 2); ++ if (rc < 0) ++ return rc; ++ ++ return 0; ++} ++ ++static int ++klogin_flashnode(uint64_t transport_handle, uint32_t host_no, ++ uint32_t flashnode_idx) ++{ ++ struct iscsi_uevent ev; ++ int rc; ++ struct iovec iov[2]; ++ ++ log_debug(7, "in %s", __FUNCTION__); ++ ++ memset(&ev, 0, sizeof(struct iscsi_uevent)); ++ ev.type = ISCSI_UEVENT_LOGIN_FLASHNODE; ++ ev.transport_handle = transport_handle; ++ ev.u.login_flashnode.host_no = host_no; ++ ev.u.login_flashnode.flashnode_idx = flashnode_idx; ++ ++ iov[1].iov_base = &ev; ++ iov[1].iov_len = sizeof(ev); ++ rc = __kipc_call(iov, 2); ++ if (rc < 0) ++ return rc; ++ ++ return 0; ++} ++ ++static int ++klogout_flashnode(uint64_t transport_handle, uint32_t host_no, ++ uint32_t flashnode_idx) ++{ ++ struct iscsi_uevent ev; ++ int rc; ++ struct iovec iov[2]; ++ ++ log_debug(7, "in %s", __FUNCTION__); ++ ++ memset(&ev, 0, sizeof(struct iscsi_uevent)); ++ ev.type = ISCSI_UEVENT_LOGOUT_FLASHNODE; ++ ev.transport_handle = transport_handle; ++ ev.u.logout_flashnode.host_no = host_no; ++ ev.u.logout_flashnode.flashnode_idx = flashnode_idx; ++ ++ iov[1].iov_base = &ev; ++ iov[1].iov_len = sizeof(ev); ++ rc = __kipc_call(iov, 2); ++ if (rc < 0) ++ return rc; ++ ++ return 0; ++} ++ ++static int ++klogout_flashnode_sid(uint64_t transport_handle, uint32_t host_no, ++ uint32_t sid) ++{ ++ struct iscsi_uevent ev; ++ int rc; ++ struct iovec iov[2]; ++ ++ log_debug(7, "in %s", __FUNCTION__); ++ ++ memset(&ev, 0, sizeof(struct iscsi_uevent)); ++ ev.type = ISCSI_UEVENT_LOGOUT_FLASHNODE_SID; ++ ev.transport_handle = transport_handle; ++ ev.u.logout_flashnode_sid.host_no = host_no; ++ ev.u.logout_flashnode_sid.sid = sid; ++ ++ iov[1].iov_base = &ev; ++ iov[1].iov_len = sizeof(ev); ++ rc = __kipc_call(iov, 2); ++ if (rc < 0) ++ return rc; ++ ++ return 0; ++} ++ ++static int kget_host_stats(uint64_t transport_handle, uint32_t host_no, ++ char *host_stats) ++{ ++ int rc = 0; ++ int ev_size; ++ struct iscsi_uevent ev; ++ struct iovec iov[2]; ++ char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))]; ++ struct nlmsghdr *nlh; ++ ++ memset(&ev, 0, sizeof(struct iscsi_uevent)); ++ ++ ev.type = ISCSI_UEVENT_GET_HOST_STATS; ++ ev.transport_handle = transport_handle; ++ ev.u.get_host_stats.host_no = host_no; ++ ++ iov[1].iov_base = &ev; ++ iov[1].iov_len = sizeof(ev); ++ rc = __kipc_call(iov, 2); ++ if (rc < 0) ++ return rc; ++ ++ if ((rc = nl_read(ctrl_fd, nlm_ev, ++ NLMSG_SPACE(sizeof(struct iscsi_uevent)), ++ MSG_PEEK)) < 0) { ++ log_error("can not read nlm_ev, error %d", rc); ++ return rc; ++ } ++ ++ nlh = (struct nlmsghdr *)nlm_ev; ++ ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr)); ++ ++ if ((rc = nlpayload_read(ctrl_fd, (void *)host_stats, ++ ev_size, 0)) < 0) { ++ log_error("can not read from NL socket, error %d", rc); ++ return rc; ++ } ++ ++ return rc; ++} ++ ++ + static void drop_data(struct nlmsghdr *nlh) + { + int ev_size; +@@ -1281,7 +1520,7 @@ static int ctldev_handle(void) + nlh = (struct nlmsghdr *)nlm_ev; + ev = (struct iscsi_uevent *)NLMSG_DATA(nlm_ev); + +- log_debug(7, "%s got event type %u\n", __FUNCTION__, ev->type); ++ log_debug(7, "%s got event type %u", __FUNCTION__, ev->type); + /* drivers like qla4xxx can be inserted after iscsid is started */ + switch (ev->type) { + case ISCSI_KEVENT_CREATE_SESSION: +@@ -1296,10 +1535,10 @@ static int ctldev_handle(void) + ev->r.c_session_ret.sid); + return 0; + case ISCSI_KEVENT_DESTROY_SESSION: ++ drop_data(nlh); + if (!ipc_ev_clbk) + return 0; + +- drop_data(nlh); + if (ipc_ev_clbk->destroy_session) + ipc_ev_clbk->destroy_session(ev->r.d_session.host_no, + ev->r.d_session.sid); +@@ -1324,15 +1563,15 @@ static int ctldev_handle(void) + case ISCSI_KEVENT_HOST_EVENT: + switch (ev->r.host_event.code) { + case ISCSI_EVENT_LINKUP: +- log_warning("Host%u: Link Up.\n", ++ log_warning("Host%u: Link Up.", + ev->r.host_event.host_no); + break; + case ISCSI_EVENT_LINKDOWN: +- log_warning("Host%u: Link Down.\n", ++ log_warning("Host%u: Link Down.", + ev->r.host_event.host_no); + break; + default: +- log_debug(7, "Host%u: Unknwon host event: %u.\n", ++ log_debug(7, "Host%u: Unknwon host event: %u.", + ev->r.host_event.host_no, + ev->r.host_event.code); + } +@@ -1372,7 +1611,7 @@ static int ctldev_handle(void) + * nl interface. + */ + log_debug(1, "Could not verify connection %d:%d. Dropping " +- "event.\n", sid, cid); ++ "event.", sid, cid); + drop_data(nlh); + return -ENXIO; + } +@@ -1382,8 +1621,8 @@ static int ctldev_handle(void) + + ev_context = ipc_ev_clbk->get_ev_context(conn, ev_size); + if (!ev_context) { +- /* retry later */ + log_error("Can not allocate memory for receive context."); ++ drop_data(nlh); + return -ENOMEM; + } + +@@ -1542,7 +1781,15 @@ struct iscsi_ipc nl_ipc = { + .recv_conn_state = krecv_conn_state, + .exec_ping = kexec_ping, + .get_chap = kget_chap, ++ .set_chap = kset_chap, + .delete_chap = kdelete_chap, ++ .set_flash_node_params = kset_flashnode_params, ++ .new_flash_node = knew_flashnode, ++ .del_flash_node = kdel_flashnode, ++ .login_flash_node = klogin_flashnode, ++ .logout_flash_node = klogout_flashnode, ++ .logout_flash_node_sid = klogout_flashnode_sid, ++ .get_host_stats = kget_host_stats, + }; + struct iscsi_ipc *ipc = &nl_ipc; + +diff --git a/usr/session_info.c b/usr/session_info.c +index 1f84c49..2f48e65 100644 +--- a/usr/session_info.c ++++ b/usr/session_info.c +@@ -64,20 +64,32 @@ void session_info_free_list(struct list_head *list) + } + } + ++static char *get_iscsi_node_type(struct session_info *info) ++{ ++ int pid = iscsi_sysfs_session_user_created(info->sid); ++ ++ if (!pid) ++ return "flash"; ++ else ++ return "non-flash"; ++} ++ + static int session_info_print_flat(void *data, struct session_info *info) + { + struct iscsi_transport *t = iscsi_sysfs_get_transport_by_sid(info->sid); + + if (strchr(info->persistent_address, '.')) +- printf("%s: [%d] %s:%d,%d %s\n", ++ printf("%s: [%d] %s:%d,%d %s (%s)\n", + t ? t->name : UNKNOWN_VALUE, + info->sid, info->persistent_address, +- info->persistent_port, info->tpgt, info->targetname); ++ info->persistent_port, info->tpgt, info->targetname, ++ get_iscsi_node_type(info)); + else +- printf("%s: [%d] [%s]:%d,%d %s\n", ++ printf("%s: [%d] [%s]:%d,%d %s (%s)\n", + t ? t->name : UNKNOWN_VALUE, + info->sid, info->persistent_address, +- info->persistent_port, info->tpgt, info->targetname); ++ info->persistent_port, info->tpgt, info->targetname, ++ get_iscsi_node_type(info)); + return 0; + } + +@@ -230,7 +242,8 @@ void session_info_print_tree(struct list_head *list, char *prefix, + + list_for_each_entry(curr, list, list) { + if (!prev || strcmp(prev->targetname, curr->targetname)) { +- printf("%sTarget: %s\n", prefix, curr->targetname); ++ printf("%sTarget: %s (%s)\n", prefix, curr->targetname, ++ get_iscsi_node_type(curr)); + prev = NULL; + } + +@@ -278,6 +291,7 @@ void session_info_print_tree(struct list_head *list, char *prefix, + printf("%s\t\tSID: %d\n", prefix, curr->sid); + print_iscsi_state(curr->sid, prefix); + } ++ + if (flags & SESSION_INFO_ISCSI_TIM) { + printf("%s\t\t*********\n", prefix); + printf("%s\t\tTimeouts:\n", prefix); +@@ -368,7 +382,7 @@ int session_info_print(int info_level, struct session_info *info, int do_show) + num_found = 1; + } else + err = iscsi_sysfs_for_each_session(info, &num_found, +- session_info_print_flat); ++ session_info_print_flat, 0); + break; + case 3: + version = iscsi_sysfs_get_iscsi_kernel_version(); +@@ -403,7 +417,7 @@ int session_info_print(int info_level, struct session_info *info, int do_show) + link_info.match_fn = NULL; + + err = iscsi_sysfs_for_each_session(&link_info, &num_found, +- session_info_create_list); ++ session_info_create_list, 0); + if (err || !num_found) + break; + +diff --git a/usr/session_mgmt.c b/usr/session_mgmt.c +index ec1f43a..596085b 100644 +--- a/usr/session_mgmt.c ++++ b/usr/session_mgmt.c +@@ -172,18 +172,18 @@ int iscsi_login_portal(void *data, struct list_head *list, struct node_rec *rec) + * that are missing. + */ + rc = iscsi_sysfs_for_each_session(rec, &session_count, +- iscsi_match_session_count); ++ iscsi_match_session_count, 0); + if (rc) { + log_error("Could not count current number of sessions"); + goto done; + } + if (session_count >= rec->session.nr_sessions) { +- log_debug(1, "%s: %d session%s requested, but %d " ++ log_warning("%s: %d session%s requested, but %d " + "already present.", + rec->iface.name, rec->session.nr_sessions, + rec->session.nr_sessions == 1 ? "" : "s", + session_count); +- rc = 0; ++ rc = ISCSI_ERR_SESS_EXISTS; + goto done; + } + +@@ -343,7 +343,7 @@ static int iscsid_logout_reqs_wait(struct list_head *list) + } + + /** +- * iscsi_logout_portal - logou tof portal ++ * iscsi_logout_portal - logout of portal + * @info: session to log out of + * @list: if async, this is the list to add the logout req to + */ +@@ -421,7 +421,7 @@ int iscsi_logout_portals(void *data, int *nr_found, int wait, + *nr_found = 0; + + err = iscsi_sysfs_for_each_session(&link_info, nr_found, +- session_info_create_list); ++ session_info_create_list, 0); + if (err && !list_empty(&session_list)) + log_error("Could not read in all sessions: %s", + iscsi_err_to_str(err)); +@@ -466,7 +466,8 @@ free_list: + int iscsi_check_for_running_session(struct node_rec *rec) + { + int nr_found = 0; +- if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session)) ++ if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session, ++ 0)) + return 1; + return 0; + } +diff --git a/usr/strings.c b/usr/strings.c +index 638cb4d..da5df28 100644 +--- a/usr/strings.c ++++ b/usr/strings.c +@@ -74,7 +74,7 @@ int str_enlarge_data(struct str_buffer *s, int length) + if (s) { + s->data_length += length; + if (s->data_length > s->allocated_length) { +- log_debug(7, "enlarge buffer from %lu to %lu\n", ++ log_debug(7, "enlarge buffer from %lu to %lu", + s->allocated_length, s->data_length); + new_buf = realloc(s->buffer, s->data_length); + if (!new_buf) { +diff --git a/usr/sysfs.c b/usr/sysfs.c +index 7f31c1a..6520bf6 100644 +--- a/usr/sysfs.c ++++ b/usr/sysfs.c +@@ -82,7 +82,7 @@ int sysfs_init(void) + remove_trailing_chars(sysfs_path, '/'); + } else + strlcpy(sysfs_path, "/sys", sizeof(sysfs_path)); +- dbg("sysfs_path='%s'\n", sysfs_path); ++ dbg("sysfs_path='%s'", sysfs_path); + + INIT_LIST_HEAD(&dev_list); + INIT_LIST_HEAD(&attr_list); +@@ -123,7 +123,7 @@ void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath, + if (pos == NULL) + return; + strlcpy(dev->kernel, &pos[1], sizeof(dev->kernel)); +- dbg("kernel='%s'\n", dev->kernel); ++ dbg("kernel='%s'", dev->kernel); + + /* some devices have '!' in their name, change that to '/' */ + pos = dev->kernel; +@@ -138,7 +138,7 @@ void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath, + while (isdigit(pos[-1])) + pos--; + strlcpy(dev->kernel_number, pos, sizeof(dev->kernel_number)); +- dbg("kernel_number='%s'\n", dev->kernel_number); ++ dbg("kernel_number='%s'", dev->kernel_number); + } + + int sysfs_resolve_link(char *devpath, size_t size) +@@ -155,11 +155,11 @@ int sysfs_resolve_link(char *devpath, size_t size) + if (len <= 0) + return -1; + link_target[len] = '\0'; +- dbg("path link '%s' points to '%s'\n", devpath, link_target); ++ dbg("path link '%s' points to '%s'", devpath, link_target); + + for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++) + ; +- dbg("base '%s', tail '%s', back %i\n", devpath, &link_target[back * 3], back); ++ dbg("base '%s', tail '%s', back %i", devpath, &link_target[back * 3], back); + for (i = 0; i <= back; i++) { + char *pos = strrchr(devpath, '/'); + +@@ -167,7 +167,7 @@ int sysfs_resolve_link(char *devpath, size_t size) + return -1; + pos[0] = '\0'; + } +- dbg("after moving back '%s'\n", devpath); ++ dbg("after moving back '%s'", devpath); + strlcat(devpath, "/", size); + strlcat(devpath, &link_target[back * 3], size); + return 0; +@@ -195,7 +195,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath) + strncmp(devpath, "/block/", 7) != 0) + return NULL; + +- dbg("open '%s'\n", devpath); ++ dbg("open '%s'", devpath); + strlcpy(devpath_real, devpath, sizeof(devpath_real)); + remove_trailing_chars(devpath_real, '/'); + if (devpath[0] == '\0' ) +@@ -204,7 +204,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath) + /* look for device already in cache (we never put an untranslated path in the cache) */ + list_for_each_entry(dev_loop, &dev_list, node) { + if (strcmp(dev_loop->devpath, devpath_real) == 0) { +- dbg("found in cache '%s'\n", dev_loop->devpath); ++ dbg("found in cache '%s'", dev_loop->devpath); + return dev_loop; + } + } +@@ -213,7 +213,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath) + strlcpy(path, sysfs_path, sizeof(path)); + strlcat(path, devpath_real, sizeof(path)); + if (lstat(path, &statbuf) != 0) { +- dbg("stat '%s' failed: %s\n", path, strerror(errno)); ++ dbg("stat '%s' failed: %s", path, strerror(errno)); + return NULL; + } + if (S_ISLNK(statbuf.st_mode)) { +@@ -223,14 +223,14 @@ struct sysfs_device *sysfs_device_get(const char *devpath) + /* now look for device in cache after path translation */ + list_for_each_entry(dev_loop, &dev_list, node) { + if (strcmp(dev_loop->devpath, devpath_real) == 0) { +- dbg("found in cache '%s'\n", dev_loop->devpath); ++ dbg("found in cache '%s'", dev_loop->devpath); + return dev_loop; + } + } + } + + /* it is a new device */ +- dbg("new uncached device '%s'\n", devpath_real); ++ dbg("new uncached device '%s'", devpath_real); + dev = malloc(sizeof(struct sysfs_device)); + if (dev == NULL) + return NULL; +@@ -246,7 +246,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath) + if (len > 0) { + /* get subsystem from "subsystem" link */ + link_target[len] = '\0'; +- dbg("subsystem link '%s' points to '%s'\n", link_path, link_target); ++ dbg("subsystem link '%s' points to '%s'", link_path, link_target); + pos = strrchr(link_target, '/'); + if (pos != NULL) + strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem)); +@@ -275,13 +275,13 @@ struct sysfs_device *sysfs_device_get(const char *devpath) + len = readlink(link_path, link_target, sizeof(link_target)); + if (len > 0) { + link_target[len] = '\0'; +- dbg("driver link '%s' points to '%s'\n", link_path, link_target); ++ dbg("driver link '%s' points to '%s'", link_path, link_target); + pos = strrchr(link_target, '/'); + if (pos != NULL) + strlcpy(dev->driver, &pos[1], sizeof(dev->driver)); + } + +- dbg("add to cache 'devpath=%s', subsystem='%s', driver='%s'\n", dev->devpath, dev->subsystem, dev->driver); ++ dbg("add to cache 'devpath=%s', subsystem='%s', driver='%s'", dev->devpath, dev->subsystem, dev->driver); + list_add(&dev->node, &dev_list); + + return dev; +@@ -292,14 +292,14 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev) + char parent_devpath[PATH_SIZE]; + char *pos; + +- dbg("open '%s'\n", dev->devpath); ++ dbg("open '%s'", dev->devpath); + + /* look if we already know the parent */ + if (dev->parent != NULL) + return dev->parent; + + strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath)); +- dbg("'%s'\n", parent_devpath); ++ dbg("'%s'", parent_devpath); + + /* strip last element */ + pos = strrchr(parent_devpath, '/'); +@@ -310,12 +310,12 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev) + if (strncmp(parent_devpath, "/class", 6) == 0) { + pos = strrchr(parent_devpath, '/'); + if (pos == &parent_devpath[6] || pos == parent_devpath) { +- dbg("/class top level, look for device link\n"); ++ dbg("/class top level, look for device link"); + goto device_link; + } + } + if (strcmp(parent_devpath, "/block") == 0) { +- dbg("/block top level, look for device link\n"); ++ dbg("/block top level, look for device link"); + goto device_link; + } + +@@ -364,7 +364,7 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name) + ssize_t size; + size_t sysfs_len; + +- dbg("open '%s'/'%s'\n", devpath, attr_name); ++ dbg("open '%s'/'%s'", devpath, attr_name); + sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full)); + if(sysfs_len >= sizeof(path_full)) + sysfs_len = sizeof(path_full) - 1; +@@ -376,23 +376,23 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name) + /* look for attribute in cache */ + list_for_each_entry(attr_loop, &attr_list, node) { + if (strcmp(attr_loop->path, path) == 0) { +- dbg("found in cache '%s'\n", attr_loop->path); ++ dbg("found in cache '%s'", attr_loop->path); + return attr_loop->value; + } + } + + /* store attribute in cache (also negatives are kept in cache) */ +- dbg("new uncached attribute '%s'\n", path_full); ++ dbg("new uncached attribute '%s'", path_full); + attr = malloc(sizeof(struct sysfs_attr)); + if (attr == NULL) + return NULL; + memset(attr, 0x00, sizeof(struct sysfs_attr)); + strlcpy(attr->path, path, sizeof(attr->path)); +- dbg("add to cache '%s'\n", path_full); ++ dbg("add to cache '%s'", path_full); + list_add(&attr->node, &attr_list); + + if (lstat(path_full, &statbuf) != 0) { +- dbg("stat '%s' failed: %s\n", path_full, strerror(errno)); ++ dbg("stat '%s' failed: %s", path_full, strerror(errno)); + goto out; + } + +@@ -407,7 +407,7 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name) + link_target[len] = '\0'; + pos = strrchr(link_target, '/'); + if (pos != NULL) { +- dbg("cache '%s' with link value '%s'\n", path_full, value); ++ dbg("cache '%s' with link value '%s'", path_full, value); + strlcpy(attr->value_local, &pos[1], sizeof(attr->value_local)); + attr->value = attr->value_local; + } +@@ -426,7 +426,7 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name) + /* read attribute value */ + fd = open(path_full, O_RDONLY); + if (fd < 0) { +- dbg("attribute '%s' can not be opened\n", path_full); ++ dbg("attribute '%s' can not be opened", path_full); + goto out; + } + size = read(fd, value, sizeof(value)); +@@ -439,7 +439,7 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name) + /* got a valid value, store and return it */ + value[size] = '\0'; + remove_trailing_chars(value, '\n'); +- dbg("cache '%s' with attribute value '%s'\n", path_full, value); ++ dbg("cache '%s' with attribute value '%s'", path_full, value); + strlcpy(attr->value_local, value, sizeof(attr->value_local)); + attr->value = attr->value_local; + +@@ -554,14 +554,14 @@ char *sysfs_get_value(const char *id, char *subsys, char *param) + + if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath), + subsys, id)) { +- log_debug(3, "Could not lookup devpath for %s %s\n", ++ log_debug(3, "Could not lookup devpath for %s %s", + subsys, id); + return NULL; + } + + sysfs_value = sysfs_attr_get_value(devpath, param); + if (!sysfs_value) { +- log_debug(3, "Could not read attr %s on path %s\n", ++ log_debug(3, "Could not read attr %s on path %s", + param, devpath); + return NULL; + } +@@ -671,12 +671,11 @@ int sysfs_set_param(char *id, char *subsys, char *attr_name, + char devpath[PATH_SIZE]; + size_t sysfs_len; + char path_full[PATH_SIZE]; +- const char *path; + int rc = 0, fd; + + if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath), + subsys, id)) { +- log_debug(3, "Could not lookup devpath for %s %s\n", ++ log_debug(3, "Could not lookup devpath for %s %s", + subsys, id); + return EIO; + } +@@ -684,25 +683,24 @@ int sysfs_set_param(char *id, char *subsys, char *attr_name, + sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full)); + if(sysfs_len >= sizeof(path_full)) + sysfs_len = sizeof(path_full) - 1; +- path = &path_full[sysfs_len]; + strlcat(path_full, devpath, sizeof(path_full)); + strlcat(path_full, "/", sizeof(path_full)); + strlcat(path_full, attr_name, sizeof(path_full)); + + if (lstat(path_full, &statbuf)) { +- log_debug(3, "Could not stat %s\n", path_full); ++ log_debug(3, "Could not stat %s", path_full); + return errno; + } + + if ((statbuf.st_mode & S_IWUSR) == 0) { +- log_error("Could not write to %s. Invalid permissions.\n", ++ log_error("Could not write to %s. Invalid permissions.", + path_full); + return EACCES; + } + + fd = open(path_full, O_WRONLY); + if (fd < 0) { +- log_error("Could not open %s err %d\n", path_full, errno); ++ log_error("Could not open %s err %d", path_full, errno); + return errno; + } + +@@ -711,3 +709,43 @@ int sysfs_set_param(char *id, char *subsys, char *attr_name, + close(fd); + return rc; + } ++ ++char *sysfs_get_uevent_field(const char *path, const char *field) ++{ ++ char *uevent_path = NULL; ++ FILE *f = NULL; ++ char *line, buffer[1024]; ++ char *ff, *d; ++ char *out = NULL; ++ ++ uevent_path = calloc(1, PATH_MAX); ++ if (!uevent_path) ++ return NULL; ++ snprintf(uevent_path, PATH_MAX, "%s/uevent", path); ++ ++ f = fopen(uevent_path, "r"); ++ if (!f) ++ goto out; ++ while ((line = fgets(buffer, sizeof (buffer), f))) { ++ ff = strtok(line, "="); ++ d = strtok(NULL, "\n"); ++ if (strcmp(ff, field)) ++ continue; ++ out = strdup(d); ++ break; ++ } ++ fclose(f); ++out: ++ free(uevent_path); ++ return out; ++} ++ ++char *sysfs_get_uevent_devtype(const char *path) ++{ ++ return sysfs_get_uevent_field(path, "DEVTYPE"); ++} ++ ++char *sysfs_get_uevent_devname(const char *path) ++{ ++ return sysfs_get_uevent_field(path, "DEVNAME"); ++} +diff --git a/usr/sysfs.h b/usr/sysfs.h +index 304dbbf..462060e 100644 +--- a/usr/sysfs.h ++++ b/usr/sysfs.h +@@ -66,4 +66,8 @@ extern int sysfs_get_uint16(char *id, char *subsys, char *param, + extern int sysfs_set_param(char *id, char *subsys, char *attr_name, + char *write_buf, ssize_t buf_size); + ++extern char *sysfs_get_uevent_field(const char *path, const char *field); ++extern char *sysfs_get_uevent_devtype(const char *path); ++extern char *sysfs_get_uevent_devname(const char *path); ++ + #endif +diff --git a/usr/transport.c b/usr/transport.c +index e6e3dfc..18b7704 100644 +--- a/usr/transport.c ++++ b/usr/transport.c +@@ -35,6 +35,7 @@ + #include "log.h" + #include "iscsi_util.h" + #include "iscsi_sysfs.h" ++#include "uip_mgmt_ipc.h" + #include "cxgbi.h" + #include "be2iscsi.h" + #include "iser.h" +@@ -57,7 +58,8 @@ struct iscsi_transport_template iscsi_iser = { + + struct iscsi_transport_template cxgb3i = { + .name = "cxgb3i", +- .set_host_ip = 1, ++ .set_host_ip = SET_HOST_IP_OPT, ++ .bind_ep_required = 1, + .ep_connect = ktransport_ep_connect, + .ep_poll = ktransport_ep_poll, + .ep_disconnect = ktransport_ep_disconnect, +@@ -66,7 +68,8 @@ struct iscsi_transport_template cxgb3i = { + + struct iscsi_transport_template cxgb4i = { + .name = "cxgb4i", +- .set_host_ip = 1, ++ .set_host_ip = SET_HOST_IP_NOT_REQ, ++ .bind_ep_required = 1, + .ep_connect = ktransport_ep_connect, + .ep_poll = ktransport_ep_poll, + .ep_disconnect = ktransport_ep_disconnect, +@@ -75,14 +78,19 @@ struct iscsi_transport_template cxgb4i = { + + struct iscsi_transport_template bnx2i = { + .name = "bnx2i", +- .set_host_ip = 1, ++ .set_host_ip = SET_HOST_IP_REQ, ++ .use_boot_info = 1, ++ .bind_ep_required = 1, + .ep_connect = ktransport_ep_connect, + .ep_poll = ktransport_ep_poll, + .ep_disconnect = ktransport_ep_disconnect, ++ .set_net_config = uip_broadcast_params, ++ .exec_ping = uip_broadcast_ping_req, + }; + + struct iscsi_transport_template be2iscsi = { + .name = "be2iscsi", ++ .bind_ep_required = 1, + .create_conn = be2iscsi_create_conn, + .ep_connect = ktransport_ep_connect, + .ep_poll = ktransport_ep_poll, +@@ -91,7 +99,16 @@ struct iscsi_transport_template be2iscsi = { + + struct iscsi_transport_template qla4xxx = { + .name = "qla4xxx", +- .set_host_ip = 0, ++ .set_host_ip = SET_HOST_IP_NOT_REQ, ++ .bind_ep_required = 1, ++ .ep_connect = ktransport_ep_connect, ++ .ep_poll = ktransport_ep_poll, ++ .ep_disconnect = ktransport_ep_disconnect, ++}; ++ ++struct iscsi_transport_template ocs = { ++ .name = "ocs", ++ .bind_ep_required = 1, + .ep_connect = ktransport_ep_connect, + .ep_poll = ktransport_ep_poll, + .ep_disconnect = ktransport_ep_disconnect, +@@ -105,6 +122,7 @@ static struct iscsi_transport_template *iscsi_transport_templates[] = { + &bnx2i, + &qla4xxx, + &be2iscsi, ++ &ocs, + NULL + }; + +@@ -132,7 +150,7 @@ int transport_probe_for_offload(void) + for (i = 0; ifni[i].if_index && ifni[i].if_name; i++) { + struct if_nameindex *n = &ifni[i]; + +- log_debug(6, "kmod probe found %s\n", n->if_name); ++ log_debug(6, "kmod probe found %s", n->if_name); + + strlcpy(if_hwaddr.ifr_name, n->if_name, IFNAMSIZ); + if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0) +@@ -264,12 +282,12 @@ int set_transport_template(struct iscsi_transport *t) + + if (!strcmp(tmpl->name, t->name)) { + t->template = tmpl; +- log_debug(3, "Matched transport %s\n", t->name); ++ log_debug(3, "Matched transport %s", t->name); + return 0; + } + } + + log_error("Could not find template for %s. An updated iscsiadm " +- "is probably needed.\n", t->name); ++ "is probably needed.", t->name); + return ENOSYS; + } +diff --git a/usr/transport.h b/usr/transport.h +index 672561b..4d3bdbf 100644 +--- a/usr/transport.h ++++ b/usr/transport.h +@@ -20,6 +20,12 @@ + #include "types.h" + #include "config.h" + ++enum set_host_ip_opts { ++ SET_HOST_IP_NOT_REQ, /* iface.ipaddress is not supported */ ++ SET_HOST_IP_REQ, /* iface.ipaddress must be specified */ ++ SET_HOST_IP_OPT, /* iface.ipaddress is not required */ ++}; ++ + struct iscsi_transport; + struct iscsi_conn; + +@@ -31,10 +37,18 @@ struct iscsi_transport_template { + * the host's ip address. + */ + uint8_t set_host_ip; ++ uint8_t use_boot_info; ++ uint8_t bind_ep_required; + int (*ep_connect) (struct iscsi_conn *conn, int non_blocking); + int (*ep_poll) (struct iscsi_conn *conn, int timeout_ms); + void (*ep_disconnect) (struct iscsi_conn *conn); + void (*create_conn) (struct iscsi_conn *conn); ++ int (*set_net_config) (struct iscsi_transport *t, ++ struct iface_rec *iface, ++ struct iscsi_session *session); ++ int (*exec_ping) (struct iscsi_transport *t, ++ struct iface_rec *iface, int datalen, ++ struct sockaddr_storage *dst_addr, uint32_t *status); + }; + + /* represents data path provider */ +diff --git a/usr/types.h b/usr/types.h +index 77e3f97..9d9ba86 100644 +--- a/usr/types.h ++++ b/usr/types.h +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + /* + * using the __be types allows stricter static +diff --git a/usr/uip_mgmt_ipc.c b/usr/uip_mgmt_ipc.c +new file mode 100644 +index 0000000..2f74657 +--- /dev/null ++++ b/usr/uip_mgmt_ipc.c +@@ -0,0 +1,78 @@ ++/* ++ * uIP iSCSI Daemon/Admin Management IPC ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++ ++#include "log.h" ++#include "uip_mgmt_ipc.h" ++#include "iscsid_req.h" ++#include "iscsi_err.h" ++ ++int uip_broadcast_params(struct iscsi_transport *t, ++ struct iface_rec *iface, ++ struct iscsi_session *session) ++{ ++ struct iscsid_uip_broadcast broadcast; ++ ++ log_debug(3, "broadcasting to uip"); ++ ++ memset(&broadcast, 0, sizeof(broadcast)); ++ ++ broadcast.header.command = ISCSID_UIP_IPC_GET_IFACE; ++ broadcast.header.payload_len = sizeof(*iface); ++ ++ memcpy(&broadcast.u.iface_rec, iface, sizeof(*iface)); ++ ++ return uip_broadcast(&broadcast, ++ sizeof(iscsid_uip_broadcast_header_t) + ++ sizeof(*iface), O_NONBLOCK, NULL); ++} ++ ++int uip_broadcast_ping_req(struct iscsi_transport *t, ++ struct iface_rec *iface, int datalen, ++ struct sockaddr_storage *dst_addr, uint32_t *status) ++{ ++ struct iscsid_uip_broadcast broadcast; ++ int len = 0; ++ ++ log_debug(3, "broadcasting ping request to uip\n"); ++ ++ memset(&broadcast, 0, sizeof(broadcast)); ++ ++ broadcast.header.command = ISCSID_UIP_IPC_PING; ++ len = sizeof(*iface) + sizeof(*dst_addr) + sizeof(datalen); ++ broadcast.header.payload_len = len; ++ ++ memcpy(&broadcast.u.ping_rec.ifrec, iface, sizeof(*iface)); ++ ++ if (dst_addr->ss_family == PF_INET) { ++ len = sizeof(struct sockaddr_in); ++ } else if (dst_addr->ss_family == PF_INET6) { ++ len = sizeof(struct sockaddr_in6); ++ } else { ++ log_error("%s unknown addr family %d\n", ++ __FUNCTION__, dst_addr->ss_family); ++ return ISCSI_ERR_INVAL; ++ } ++ ++ memcpy(&broadcast.u.ping_rec.ipaddr, dst_addr, len); ++ broadcast.u.ping_rec.datalen = datalen; ++ ++ return uip_broadcast(&broadcast, ++ sizeof(iscsid_uip_broadcast_header_t) + ++ broadcast.header.payload_len, 0, status); ++} +diff --git a/usr/uip_mgmt_ipc.h b/usr/uip_mgmt_ipc.h +new file mode 100644 +index 0000000..916113d +--- /dev/null ++++ b/usr/uip_mgmt_ipc.h +@@ -0,0 +1,86 @@ ++/* ++ * uIP iSCSI Daemon/Admin Management IPC ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++#ifndef UIP_MGMT_IPC_H ++#define UIP_MGMT_IPC_H ++ ++#include "types.h" ++#include "iscsi_if.h" ++#include "config.h" ++#include "mgmt_ipc.h" ++ ++#include "initiator.h" ++#include "transport.h" ++ ++#define ISCSID_UIP_NAMESPACE "ISCSID_UIP_ABSTRACT_NAMESPACE" ++ ++typedef enum iscsid_uip_cmd { ++ ISCSID_UIP_IPC_UNKNOWN = 0, ++ ISCSID_UIP_IPC_GET_IFACE = 1, ++ ISCSID_UIP_IPC_PING = 2, ++ ++ __ISCSID_UIP_IPC_MAX_COMMAND ++} iscsid_uip_cmd_e; ++ ++typedef struct iscsid_uip_broadcast_header { ++ iscsid_uip_cmd_e command; ++ uint32_t payload_len; ++} iscsid_uip_broadcast_header_t; ++ ++/* IPC Request */ ++typedef struct iscsid_uip_broadcast { ++ struct iscsid_uip_broadcast_header header; ++ ++ union { ++ /* messages */ ++ struct ipc_broadcast_iface_rec { ++ struct iface_rec rec; ++ } iface_rec; ++ ++ struct ipc_broadcast_ping_rec { ++ struct iface_rec ifrec; ++ struct sockaddr_storage ipaddr; ++ int datalen; ++ int *status; ++ } ping_rec; ++ } u; ++} iscsid_uip_broadcast_t; ++ ++typedef enum iscsid_uip_mgmt_ipc_err { ++ ISCSID_UIP_MGMT_IPC_OK = 0, ++ ISCSID_UIP_MGMT_IPC_ERR = 1, ++ ISCSID_UIP_MGMT_IPC_ERR_NOT_FOUND = 2, ++ ISCSID_UIP_MGMT_IPC_ERR_NOMEM = 3, ++ ISCSID_UIP_MGMT_IPC_DEVICE_UP = 4, ++ ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING = 5, ++} iscsid_uip_mgmt_ipc_err_e; ++ ++/* IPC Response */ ++typedef struct iscsid_uip_mgmt_rsp { ++ iscsid_uip_cmd_e command; ++ iscsid_uip_mgmt_ipc_err_e err; ++ enum iscsi_ping_status_code ping_sc; ++} iscsid_uip_rsp_t; ++ ++extern int uip_broadcast_params(struct iscsi_transport *t, ++ struct iface_rec *iface, ++ struct iscsi_session *session); ++ ++extern int uip_broadcast_ping_req(struct iscsi_transport *t, ++ struct iface_rec *iface, int datalen, ++ struct sockaddr_storage *dst_addr, ++ uint32_t *status); ++ ++#endif /* UIP_MGMT_IPC_H */ +diff --git a/utils/Makefile b/utils/Makefile +index 2c7e891..f65f1e7 100644 +--- a/utils/Makefile ++++ b/utils/Makefile +@@ -1,12 +1,13 @@ + # This Makefile will work only with GNU make. + +-CFLAGS += $(OPTFLAGS) -O2 -fno-inline -Wall -Wstrict-prototypes -g ++CFLAGS ?= -O2 -fno-inline -g ++CFLAGS += -Wall -Wstrict-prototypes + PROGRAMS = iscsi-iname + + all: $(PROGRAMS) + + iscsi-iname: md5.o iscsi-iname.o +- $(CC) $(CFLAGS) $^ $(DBM_LIB) -o $@ ++ $(CC) $(CFLAGS) $(LDFLAGS) $^ $(DBM_LIB) -o $@ + + clean: + rm -f *.o $(PROGRAMS) .depend +diff --git a/utils/fwparam_ibft/Makefile b/utils/fwparam_ibft/Makefile +index c72bb7f..773d8eb 100644 +--- a/utils/fwparam_ibft/Makefile ++++ b/utils/fwparam_ibft/Makefile +@@ -26,9 +26,9 @@ OBJS := fw_entry.o fwparam_sysfs.o $(SYSDEPS_OBJS) ../../usr/iscsi_net_util.o + OBJS += prom_lex.o prom_parse.tab.o fwparam_ppc.o + CLEANFILES = $(OBJS) *.output *~ + +-OPTFLAGS ?= -O2 -g -fPIC ++CFLAGS ?= -O2 -g + WARNFLAGS ?= -Wall -Wstrict-prototypes +-CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -I../../include -I../../usr -D_GNU_SOURCE ++CFLAGS += -fPIC $(WARNFLAGS) -I../../include -I../../usr -D_GNU_SOURCE + + all: $(OBJS) + +diff --git a/utils/fwparam_ibft/fw_entry.c b/utils/fwparam_ibft/fw_entry.c +index b6f05c1..f94a035 100644 +--- a/utils/fwparam_ibft/fw_entry.c ++++ b/utils/fwparam_ibft/fw_entry.c +@@ -67,15 +67,15 @@ int fw_setup_nics(void) + * to force iSCSI traffic through correct NIC + */ + list_for_each_entry(context, &targets, list) { +- /* if it is a offload nic ignore it */ +- if (!net_get_transport_name_from_netdev(context->iface, ++ /* if it is a offload nic ignore it */ ++ if (!net_get_transport_name_from_netdev(context->iface, + transport)) + continue; + + if (iface_prev == NULL || strcmp(context->iface, iface_prev)) { + /* Note: test above works because there is a +- * maximum of two targets in the iBFT +- */ ++ * maximum of two targets in the iBFT ++ */ + iface_prev = context->iface; + needs_bringup = 1; + } +@@ -192,10 +192,13 @@ static void dump_network(struct boot_context *context) + if (strlen(context->mac)) + printf("%s = %s\n", IFACE_HWADDR, context->mac); + /* +- * If this has a valid address then DHCP was used (broadcom sends +- * 0.0.0.0). ++ * If the 'origin' field is 3 (IBFT_IP_PREFIX_ORIGIN_DHCP), ++ * then DHCP is used. ++ * Otherwise evaluate the 'dhcp' field, if this has a valid ++ * address then DHCP was used (broadcom sends 0.0.0.0). + */ +- if (strlen(context->dhcp) && strcmp(context->dhcp, "0.0.0.0")) ++ if ((context->origin == IBFT_IP_PREFIX_ORIGIN_DHCP) || ++ (strlen(context->dhcp) && strcmp(context->dhcp, "0.0.0.0"))) + printf("%s = DHCP\n", IFACE_BOOT_PROTO); + else + printf("%s = STATIC\n", IFACE_BOOT_PROTO); +diff --git a/utils/fwparam_ibft/fwparam_ibft_sysfs.c b/utils/fwparam_ibft/fwparam_ibft_sysfs.c +index 9185c85..2dc6f6d 100644 +--- a/utils/fwparam_ibft/fwparam_ibft_sysfs.c ++++ b/utils/fwparam_ibft/fwparam_ibft_sysfs.c +@@ -201,6 +201,8 @@ static int fill_nic_context(char *id, struct boot_context *context) + sizeof(context->secondary_dns)); + sysfs_get_str(id, IBFT_SUBSYS, "dhcp", context->dhcp, + sizeof(context->dhcp)); ++ sysfs_get_str(id, IBFT_SUBSYS, "origin", context->origin, ++ sizeof(context->origin)); + return 0; + } + +diff --git a/utils/fwparam_ibft/fwparam_sysfs.c b/utils/fwparam_ibft/fwparam_sysfs.c +index 3997363..23eb913 100644 +--- a/utils/fwparam_ibft/fwparam_sysfs.c ++++ b/utils/fwparam_ibft/fwparam_sysfs.c +@@ -170,6 +170,18 @@ static int fill_nic_context(char *subsys, char *id, + { + int rc; + ++ rc = sysfs_get_int(id, subsys, "flags", &context->nic_flags); ++ /* ++ * Per spec we would need to check against Bit 0 ++ * (Block Valid Flag), but some firmware only ++ * sets Bit 1 (Firmware Booting Selected). ++ * So any setting is deemed okay. ++ */ ++ if (!rc && (context->nic_flags == 0)) ++ rc = ENODEV; ++ if (rc) ++ return rc; ++ + rc = sysfs_get_str(id, subsys, "mac", context->mac, + sizeof(context->mac)); + if (rc) +@@ -200,6 +212,9 @@ static int fill_nic_context(char *subsys, char *id, + strlcpy(context->scsi_host_name, subsys, + sizeof(context->scsi_host_name)); + ++ memset(&context->boot_nic, 0, sizeof(context->boot_nic)); ++ snprintf(context->boot_nic, sizeof(context->boot_nic), "%s", id); ++ + sysfs_get_str(id, subsys, "ip-addr", context->ipaddr, + sizeof(context->ipaddr)); + sysfs_get_str(id, subsys, "vlan", context->vlan, +@@ -214,6 +229,7 @@ static int fill_nic_context(char *subsys, char *id, + sizeof(context->secondary_dns)); + sysfs_get_str(id, subsys, "dhcp", context->dhcp, + sizeof(context->dhcp)); ++ sysfs_get_int(id, subsys, "origin", (int *)&context->origin); + return 0; + } + +@@ -224,12 +240,26 @@ static void fill_initiator_context(char *subsys, struct boot_context *context) + sizeof(context->initiatorname)); + sysfs_get_str("initiator", subsys, "isid", context->isid, + sizeof(context->isid)); ++ ++ strlcpy(context->boot_root, subsys, sizeof(context->boot_root)); + } + static int fill_tgt_context(char *subsys, char *id, + struct boot_context *context) + { + int rc; + ++ rc = sysfs_get_int(id, subsys, "flags", &context->target_flags); ++ /* ++ * Per spec we would need to check against Bit 0 ++ * (Block Valid Flag), but some firmware only ++ * sets Bit 1 (Firmware Booting Selected). ++ * So any setting is deemed okay. ++ */ ++ if (!rc && (context->target_flags == 0)) ++ rc = ENODEV; ++ if (rc) ++ return rc; ++ + rc = sysfs_get_str(id, subsys, "target-name", context->targetname, + sizeof(context->targetname)); + if (rc) +@@ -240,6 +270,9 @@ static int fill_tgt_context(char *subsys, char *id, + if (rc) + return rc; + ++ memset(&context->boot_target, 0, sizeof(context->boot_target)); ++ snprintf(context->boot_target, sizeof(context->boot_target), "%s", id); ++ + /* + * We can live without the rest of they do not exist. If we + * failed to get them we will figure it out when we login. +@@ -315,7 +348,7 @@ static int get_boot_info(struct boot_context *context, char *rootdir, + nic_cnt = 0; + tgt_cnt = 0; + if (file_exist(initiator_dir)) { +- /* Find the target's and the ethernet's */ ++ /* Find the targets and the ethernets */ + rc = nftw(rootdir, find_sysfs_dirs, 20, 1); + + /* Find wihch target and which ethernet have +@@ -391,7 +424,7 @@ static int get_targets(struct list_head *list, char *rootdir, char *subsys) + nic_cnt = 0; + tgt_cnt = 0; + +- /* Find the target's and the ethernet's */ ++ /* Find the targets and the ethernets */ + nftw(rootdir, find_sysfs_dirs, 20, 1); + for (i = 0; i < tgt_cnt; i++) { + context = calloc(1, sizeof(*context)); +diff --git a/utils/iscsi-gen-initiatorname b/utils/iscsi-gen-initiatorname +new file mode 100755 +index 0000000..88bd43b +--- /dev/null ++++ b/utils/iscsi-gen-initiatorname +@@ -0,0 +1,73 @@ ++#!/bin/bash ++# ++# /sbin/iscsi-gen-initiatorname ++# ++# Generate a default iSCSI Initiatorname for SUSE installations. ++# ++# Copyright (c) 2011 Hannes Reinecke, SUSE Labs ++# This script is licensed under the GPL. ++# ++ ++if [ "$1" ] ; then ++ if [ "$1" = "-f" ] ; then ++ FORCE=1 ++ else ++ echo "Invalid option $1" ++ echo "Usage: $0 [-f]" ++ exit 1 ++ fi ++fi ++ ++if [ -d /sys/firmware/ibft/initiator ] ; then ++ read iSCSI_INITIATOR_NAME < /sys/firmware/ibft/initiator/initiator-name ++fi ++ ++if [ -f /etc/iscsi/initiatorname.iscsi -a -z "$FORCE" ] ; then ++ if [ "$iSCSI_INITIATOR_NAME" ] ; then ++ eval $(cat /etc/iscsi/initiatorname.iscsi | sed -e '/^#/d') ++ if [ "$iSCSI_INITIATOR_NAME" != "$InitiatorName" ] ; then ++ echo "iSCSI Initiatorname from iBFT is different from the current setting." ++ echo "Please call '/sbin/iscsi-gen-initiatorname -f' to update the iSCSI Initiatorname." ++ exit 1 ++ fi ++ fi ++fi ++ ++if [ "$iSCSI_INITIATOR_NAME" ] ; then ++ cat << EOF >> /etc/iscsi/initiatorname.iscsi ++## ++## /etc/iscsi/iscsi.initiatorname ++## ++## iSCSI Initiatorname taken from iBFT BIOS tables. ++## ++## DO NOT EDIT OR REMOVE THIS FILE! ++## If you remove this file, the iSCSI daemon will not start. ++## Any change here will not be reflected to the iBFT BIOS tables. ++## If a different initiatorname is required please change the ++## initiatorname in the BIOS setup and call ++## /sbin/iscsi-gen-initiatorname -f ++## to recreate an updated version of this file. ++## ++InitiatorName=$iSCSI_INITIATOR_NAME ++EOF ++fi ++ ++if [ ! -f /etc/iscsi/initiatorname.iscsi ] ; then ++ cat << EOF >> /etc/iscsi/initiatorname.iscsi ++## ++## /etc/iscsi/iscsi.initiatorname ++## ++## Default iSCSI Initiatorname. ++## ++## DO NOT EDIT OR REMOVE THIS FILE! ++## If you remove this file, the iSCSI daemon will not start. ++## If you change the InitiatorName, existing access control lists ++## may reject this initiator. The InitiatorName must be unique ++## for each iSCSI initiator. Do NOT duplicate iSCSI InitiatorNames. ++EOF ++ ISSUEDATE="1996-04" ++ INAME=$(/sbin/iscsi-iname -p iqn.$ISSUEDATE.de.suse:01) ++ printf "InitiatorName=$INAME\n" >>/etc/iscsi/initiatorname.iscsi ++ chmod 0600 /etc/iscsi/initiatorname.iscsi ++fi ++ +diff --git a/utils/iscsi_offload b/utils/iscsi_offload +new file mode 100755 +index 0000000..7cd1dad +--- /dev/null ++++ b/utils/iscsi_offload +@@ -0,0 +1,378 @@ ++#!/bin/bash ++# ++# iscsi_offload ++# ++# Configure iSCSI offload engines for use with open-iscsi ++# Usage: ++# iscsi_offload [-d | -f | -i | -t ] ++# ++# Copyright (c) 2011 Hannes Reinecke, SUSE Labs ++# This script is licensed under the GPL. ++# ++# The script creates an open-iscsi interface definition ++# in the style -, where matches the ++# network interface passed on the commandline. ++# If '-t' (test mode) is passed as an option, the script ++# will not create nor modify any setting but just print ++# the currently active ones. ++# ++# Currently the script works with Broadcom (bnx2i) and ++# Chelsio T3 (cxgbi) iSCSI offload engines. ++# Should work with Chelsio T4, but has not been tested. ++# ServerEngines (be2iscsi) and QLogic (qla4xxx) can only ++# be configured via BIOS, open-iscsi support is still in ++# development. ++# ++ ++# ++# Return codes: ++# 0: Success ++# 1: Invalid command line parameter ++# 2: iSCSI offloading not supported ++# 3: Error during module loading ++# 4: Cannot configure interface via iscsiadm, use BIOS setup ++# 5: internal error running iscsiadm ++# ++# Output: ++# [none|dhcp|ip |ibft] ++# where ++# : MAC Address of the iSCSI offload engine ++# none: No IP configuration set for the iSCSI offload engine ++# dhcp: iSCSI offload engine configured for DHCP ++# ip: iSCSI offload engine configured with static IP address ++# ibft: iSCSI offload engine configured from iBFT values ++# ++ ++# ++# Figure out the MAC address of the iSCSI offload engine ++# corresponding to a NIC from a given PCI device. ++# bnx2 is using one PCI device per port for both network and iSCSI offloading ++# cxgb3 is using one PCI device for everything. ++# ++iscsi_macaddress_from_pcidevice() ++{ ++ local path=$1 ++ local if=$2 ++ local h ++ local host ++ ++ for h in $path/host* ; do ++ if [ -d "$h" ] ; then ++ host=${h##*/} ++ read netdev < /sys/class/iscsi_host/$host/netdev ++ if [ "$netdev" = "$IFNAME" ] ; then ++ read mac < /sys/class/iscsi_host/$host/hwaddress ++ if [ "$mac" != "00:00:00:00:00:00" ] ; then ++ echo "$mac" ++ fi ++ break; ++ fi ++ fi ++ done ++} ++ ++# ++# Figure out the MAC address of the iSCSI offload engine ++# corresponding to a NIC from a given PCI function. ++# It is assumed that the MAC address of the iSCSI offload ++# engine is equal of the MAC address of the NIC plus one. ++# Suitable for be2iscsi and qla4xxx ++# ++iscsi_macaddress_from_pcifn() ++{ ++ local path=$1 ++ local if=$2 ++ local h ++ local host ++ local ifmac ++ ++ ifmac=$(ip addr show dev $if | sed -n 's/ *link\/ether \(.*\) brd.*/\1/p') ++ m5=$(( 0x${ifmac##*:} )) ++ m5=$(( $m5 + 1 )) ++ ifmac=$(printf "%s:%02x" ${ifmac%:*} $m5) ++ for host in /sys/class/iscsi_host/host* ; do ++ if [ -L "$host" ] ; then ++ read mac < $host/hwaddress ++ if [ "$mac" = "$ifmac" ] ; then ++ echo "$mac" ++ break; ++ fi ++ fi ++ done ++} ++ ++update_iface_setting() { ++ local iface="$1" ++ local name="$2" ++ local value="$3" ++ ++ iface_value=$(iscsiadm -m iface -I $iface | sed -n "s/$name = \(.*\)/\1/p") ++ if [ "$iface_value" = "" ] ; then ++ iface_value= ++ fi ++ if [ "$iface_value" != "$value" ] ; then ++ if ! iscsiadm -m iface -I $iface -o update -n "$name" -v "$value" ; then ++ return 1 ++ fi ++ fi ++ return 0 ++} ++ ++while getopts di:t options ; do ++ case $options in ++ d ) mode=dhcp;; ++ i ) mode=static ++ optaddr=$OPTARG ++ ;; ++ f ) mode=firmware;; ++ t ) dry_run=1;; ++ ?) printf "Usage: %s [-d|-t|-i ipaddr|-f] ifname\n" $0 ++ exit 1;; ++ esac ++done ++shift $(($OPTIND - 1)) ++ ++IFNAME=$1 ++ibft_mode="none" ++ ++if [ -z "$IFNAME" ] ; then ++ echo "No interface specified" ++ exit 1 ++fi ++ ++if [ "$dry_run" ] ; then ++ if [ "$mode" = "dhcp" ] ; then ++ echo "'-t' specified, ignoring '-d'" ++ mode= ++ elif [ "$mode" = "static" ] ; then ++ echo "'-t' specified, ignoring '-s'" ++ mode= ++ fi ++fi ++ ++if [ ! -L /sys/class/net/$IFNAME ] ; then ++ echo "Interface $IFNAME not found" ++ exit 1 ++fi ++ ++if [ "$optaddr" ] && ! ip route get $optaddr ; then ++ echo "Invalid IP address $optaddr" ++ exit 1 ++fi ++if [ "$dry_run" ] ; then ++ mode= ++fi ++ ++ ++ifpath=$(cd -P /sys/class/net/$IFNAME; echo $PWD) ++pcipath=$(cd -P $ifpath/device; echo $PWD) ++ ++if [ -d $pcipath ] ; then ++ drvlink=$(readlink $pcipath/driver) ++ driver=${drvlink##*/} ++fi ++ ++if [ -z "$driver" ] ; then ++ echo "No driver found for interface $IFNAME" ++ exit 1 ++fi ++ ++case "$driver" in ++ bnx2*) ++ mod=bnx2i ++ ;; ++ cxgb*) ++ mod=cxgb3i ++ ;; ++ be2*) ++ mod=be2iscsi ++ ;; ++ qla*) ++ mod=qla4xxx ++ ;; ++esac ++ ++if [ -z "$mod" ] ; then ++ echo "iSCSI offloading not supported on interface $IFNAME" ++ exit 2 ++fi ++ ++# Check if the required modules are already loaded ++loaded=$(sed -n "/^$mod/p" /proc/modules) ++if [ -z "$loaded" ] ; then ++ modprobe $mod ++fi ++ ++loaded=$(sed -n "/^$mod/p" /proc/modules) ++if [ -z "$loaded" ] ; then ++ echo "Loading of $mod.ko failed, please check dmesg" ++ exit 3 ++fi ++ ++# Get the correct MAC address for the various devices ++if [ "$mod" = "bnx2i" ] ; then ++ mac=$(iscsi_macaddress_from_pcidevice $pcipath $IFNAME) ++elif [ "$mod" = "cxgb3i" ] ; then ++ mac=$(iscsi_macaddress_from_pcidevice $pcipath $IFNAME) ++elif [ "$mod" = "be2iscsi" ] ; then ++ mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME) ++elif [ "$mod" = "qla4xxx" ] ; then ++ mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME) ++fi ++ ++if [ -z "$mac" ] ; then ++ echo "iSCSI offloading not supported on interface $IFNAME" ++ exit 2 ++fi ++ ++gen_iface="$mod.$mac" ++ioe_iface="${IFNAME}-${mod}" ++ ++# Get existing settings ++if iscsiadm -m iface -I $ioe_iface > /dev/null 2>&1 ; then ++ ioe_mac=$(iscsiadm -m iface -I $ioe_iface 2> /dev/null| sed -n "s/iface\.hwaddress = \(.*\)/\1/p") ++ ioe_mod=$(iscsiadm -m iface -I $ioe_iface 2> /dev/null| sed -n "s/iface\.transport_name = \(.*\)/\1/p") ++ ipaddr=$(iscsiadm -m iface -I $ioe_iface 2> /dev/null| sed -n "s/iface\.ipaddress = \(.*\)/\1/p") ++ if [ "$ipaddr" == "" ] ; then ++ ipaddr= ++ fi ++elif [ "$mod" = "be2iscsi" ] ; then ++ ioe_mac=$mac ++ ioe_mod=$mod ++else ++ # Create new interface ++ iscsiadm -m iface -I $ioe_iface --op=new 2> /dev/null ++ ioe_mac= ++ ioe_mod= ++ ipaddr= ++fi ++ ++if [ -z "$dry_run" ] ; then ++ if [ "$ioe_mac" != "$mac" ] ; then ++ if [ -n "$ioe_mac" ] ; then ++ echo "Warning: Updating MAC address on iface $ioe_iface" ++ fi ++ update_iface_setting $ioe_iface iface.hwaddress "$mac" ++ fi ++ ++ if [ "$ioe_mod" != "$mod" ] ; then ++ if [ -n "$ioe_mod" ] ; then ++ echo "Warning: Update transport on iface $ioe_iface" ++ fi ++ update_iface_setting $ioe_iface iface.transport_name "$mod" ++ fi ++elif [ -z "$ipaddr" ] ; then ++ ipaddr=$(iscsiadm -m iface -I $gen_iface 2> /dev/null| sed -n "s/iface\.ipaddress = \(.*\)/\1/p") ++ if [ "$ipaddr" = "" ] ; then ++ ipaddr= ++ fi ++elif [ "$ioe_mod" != "$mod" ] ; then ++ echo "Warning: Transport mismatch on iface $ioe_iface: $ioe_mod should be $mod" ++fi ++ ++# Check iBFT setting ++for d in /sys/firmware/* ; do ++ [ -d $d ] || continue ++ [ -d $d/ethernet0 ] || continue ++ iboot_dir=$d ++done ++if [ -n "$iboot_dir" ] && [ -d "$iboot_dir" ] ; then ++ for if in ${iboot_dir}/ethernet* ; do ++ read ibft_mac < $if/mac ++ [ "$ibft_mac" = "$mac" ] || continue ++ ibft_origin=0 ++ [ -f ${if}/origin ] && read ibft_origin < $if/origin ++ if [ "$ibft_origin" -eq 1 ] ; then ++ ibft_mode="static" ++ elif [ "$ibft_origin" -eq 3 ] ; then ++ ibft_mode="dhcp" ++ fi ++ [ -f $if/dhcp ] && read ibft_dhcp < $if/dhcp ++ if [ -n "$ibft_dhcp" -a "$ibft_mode" != "dhcp" ] ; then ++ ibft_mode=dhcp ++ fi ++ if [ "$ibft_mode" = "dhcp" ] ; then ++ ibft_ipaddr="0.0.0.0" ++ ibft_gateway= ++ ibft_mask= ++ break ++ fi ++ [ -f $if/ip-addr ] && read ibft_ipaddr < $if/ip-addr ++ [ -f $if/gateway ] && read ibft_gateway < $if/gateway ++ [ -f $if/subnet-mask ] && read ibft_mask < $if/subnet-mask ++ break ++ done ++fi ++ ++if [ -z "$optaddr" ] && [ "$ibft_ipaddr" ] ; then ++ optaddr=$ibft_ipaddr ++fi ++ ++# Check if the interface needs to be configured ++if [ -z "$mode" ] ; then ++ if [ "$ibft_mode" != "none" ] ; then ++ echo "$mac ibft" ++ mode="ibft" ++ elif [ -z "$ipaddr" ] ; then ++ echo "$mac none" ++ mode="none" ++ elif [ "$ipaddr" = "0.0.0.0" ] ; then ++ echo "$mac dhcp" ++ ipaddr= ++ mode="dhcp" ++ else ++ echo "$mac ip $ipaddr" ++ mode="static" ++ fi ++ [ "$dry_run" ] && exit 0 ++elif [ "$mode" = "dhcp" ] ; then ++ if [ "$ipaddr" = "0.0.0.0" ] ; then ++ echo "$mac dhcp" ++ exit 0 ++ fi ++ optaddr="0.0.0.0" ++elif [ "$mode" = "static" ] && [ "$ipaddr" = "$optaddr" ] ; then ++ echo "$mac ip $ipaddr" ++ exit 0 ++fi ++ ++if [ "$mod" = "be2iscsi" ] ; then ++ exit 4 ++fi ++ ++if ! update_iface_setting $ioe_iface iface.ipaddress "$optaddr" ; then ++ echo "Failed to set IP address: $?" ++ exit 1 ++fi ++if ! update_iface_setting $gen_iface iface.ipaddress "$optaddr" ; then ++ echo "Failed to set IP address for generic interface: $?" ++ exit 1 ++fi ++ ++if ! update_iface_setting $ioe_iface iface.gateway "$ibft_gateway" ; then ++ echo "Failed to set gateway address: $?" ++ exit 1 ++fi ++ ++if ! update_iface_setting $gen_iface iface.gateway "$ibft_gateway" ; then ++ echo "Failed to set gateway address for generic interface: $?" ++ exit 1 ++fi ++ ++if ! update_iface_setting $ioe_iface iface.subnet_mask "$ibft_mask" ; then ++ echo "Failed to set subnet mask: $?" ++ exit 1 ++fi ++ ++if ! update_iface_setting $gen_iface iface.subnet_mask "$ibft_mask" ; then ++ echo "Failed to set subnet mask for generic interface: $?" ++ exit 1 ++fi ++ ++if [ "$mod" = "qla4xxx" ] ; then ++ iscsiadm -m iface -H $mac -o applyall ++fi ++ip link set dev $IFNAME up ++ ++exit 0 ++ +diff --git a/utils/md5.c b/utils/md5.c +index 53956c6..cbe8d08 100644 +--- a/utils/md5.c ++++ b/utils/md5.c +@@ -133,7 +133,7 @@ MD5Final(md5byte digest[16], struct MD5Context *ctx) + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); +- memset(ctx, 0, sizeof (ctx)); /* In case it's sensitive */ ++ memset(ctx, 0, sizeof (*ctx)); /* In case it's sensitive */ + } + + #ifndef ASM_MD5 +diff --git a/utils/open-isns/COPYING b/utils/open-isns/COPYING +deleted file mode 100644 +index b1e3f5a..0000000 +--- a/utils/open-isns/COPYING ++++ /dev/null +@@ -1,504 +0,0 @@ +- GNU LESSER GENERAL PUBLIC LICENSE +- Version 2.1, February 1999 +- +- Copyright (C) 1991, 1999 Free Software Foundation, Inc. +- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- Everyone is permitted to copy and distribute verbatim copies +- of this license document, but changing it is not allowed. +- +-[This is the first released version of the Lesser GPL. It also counts +- as the successor of the GNU Library Public License, version 2, hence +- the version number 2.1.] +- +- Preamble +- +- The licenses for most software are designed to take away your +-freedom to share and change it. By contrast, the GNU General Public +-Licenses are intended to guarantee your freedom to share and change +-free software--to make sure the software is free for all its users. +- +- This license, the Lesser General Public License, applies to some +-specially designated software packages--typically libraries--of the +-Free Software Foundation and other authors who decide to use it. You +-can use it too, but we suggest you first think carefully about whether +-this license or the ordinary General Public License is the better +-strategy to use in any particular case, based on the explanations below. +- +- When we speak of free software, we are referring to freedom of use, +-not price. Our General Public Licenses are designed to make sure that +-you have the freedom to distribute copies of free software (and charge +-for this service if you wish); that you receive source code or can get +-it if you want it; that you can change the software and use pieces of +-it in new free programs; and that you are informed that you can do +-these things. +- +- To protect your rights, we need to make restrictions that forbid +-distributors to deny you these rights or to ask you to surrender these +-rights. These restrictions translate to certain responsibilities for +-you if you distribute copies of the library or if you modify it. +- +- For example, if you distribute copies of the library, whether gratis +-or for a fee, you must give the recipients all the rights that we gave +-you. You must make sure that they, too, receive or can get the source +-code. If you link other code with the library, you must provide +-complete object files to the recipients, so that they can relink them +-with the library after making changes to the library and recompiling +-it. And you must show them these terms so they know their rights. +- +- We protect your rights with a two-step method: (1) we copyright the +-library, and (2) we offer you this license, which gives you legal +-permission to copy, distribute and/or modify the library. +- +- To protect each distributor, we want to make it very clear that +-there is no warranty for the free library. Also, if the library is +-modified by someone else and passed on, the recipients should know +-that what they have is not the original version, so that the original +-author's reputation will not be affected by problems that might be +-introduced by others. +- +- Finally, software patents pose a constant threat to the existence of +-any free program. We wish to make sure that a company cannot +-effectively restrict the users of a free program by obtaining a +-restrictive license from a patent holder. Therefore, we insist that +-any patent license obtained for a version of the library must be +-consistent with the full freedom of use specified in this license. +- +- Most GNU software, including some libraries, is covered by the +-ordinary GNU General Public License. This license, the GNU Lesser +-General Public License, applies to certain designated libraries, and +-is quite different from the ordinary General Public License. We use +-this license for certain libraries in order to permit linking those +-libraries into non-free programs. +- +- When a program is linked with a library, whether statically or using +-a shared library, the combination of the two is legally speaking a +-combined work, a derivative of the original library. The ordinary +-General Public License therefore permits such linking only if the +-entire combination fits its criteria of freedom. The Lesser General +-Public License permits more lax criteria for linking other code with +-the library. +- +- We call this license the "Lesser" General Public License because it +-does Less to protect the user's freedom than the ordinary General +-Public License. It also provides other free software developers Less +-of an advantage over competing non-free programs. These disadvantages +-are the reason we use the ordinary General Public License for many +-libraries. However, the Lesser license provides advantages in certain +-special circumstances. +- +- For example, on rare occasions, there may be a special need to +-encourage the widest possible use of a certain library, so that it becomes +-a de-facto standard. To achieve this, non-free programs must be +-allowed to use the library. A more frequent case is that a free +-library does the same job as widely used non-free libraries. In this +-case, there is little to gain by limiting the free library to free +-software only, so we use the Lesser General Public License. +- +- In other cases, permission to use a particular library in non-free +-programs enables a greater number of people to use a large body of +-free software. For example, permission to use the GNU C Library in +-non-free programs enables many more people to use the whole GNU +-operating system, as well as its variant, the GNU/Linux operating +-system. +- +- Although the Lesser General Public License is Less protective of the +-users' freedom, it does ensure that the user of a program that is +-linked with the Library has the freedom and the wherewithal to run +-that program using a modified version of the Library. +- +- The precise terms and conditions for copying, distribution and +-modification follow. Pay close attention to the difference between a +-"work based on the library" and a "work that uses the library". The +-former contains code derived from the library, whereas the latter must +-be combined with the library in order to run. +- +- GNU LESSER GENERAL PUBLIC LICENSE +- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +- +- 0. This License Agreement applies to any software library or other +-program which contains a notice placed by the copyright holder or +-other authorized party saying it may be distributed under the terms of +-this Lesser General Public License (also called "this License"). +-Each licensee is addressed as "you". +- +- A "library" means a collection of software functions and/or data +-prepared so as to be conveniently linked with application programs +-(which use some of those functions and data) to form executables. +- +- The "Library", below, refers to any such software library or work +-which has been distributed under these terms. A "work based on the +-Library" means either the Library or any derivative work under +-copyright law: that is to say, a work containing the Library or a +-portion of it, either verbatim or with modifications and/or translated +-straightforwardly into another language. (Hereinafter, translation is +-included without limitation in the term "modification".) +- +- "Source code" for a work means the preferred form of the work for +-making modifications to it. For a library, complete source code means +-all the source code for all modules it contains, plus any associated +-interface definition files, plus the scripts used to control compilation +-and installation of the library. +- +- Activities other than copying, distribution and modification are not +-covered by this License; they are outside its scope. The act of +-running a program using the Library is not restricted, and output from +-such a program is covered only if its contents constitute a work based +-on the Library (independent of the use of the Library in a tool for +-writing it). Whether that is true depends on what the Library does +-and what the program that uses the Library does. +- +- 1. You may copy and distribute verbatim copies of the Library's +-complete source code as you receive it, in any medium, provided that +-you conspicuously and appropriately publish on each copy an +-appropriate copyright notice and disclaimer of warranty; keep intact +-all the notices that refer to this License and to the absence of any +-warranty; and distribute a copy of this License along with the +-Library. +- +- You may charge a fee for the physical act of transferring a copy, +-and you may at your option offer warranty protection in exchange for a +-fee. +- +- 2. You may modify your copy or copies of the Library or any portion +-of it, thus forming a work based on the Library, and copy and +-distribute such modifications or work under the terms of Section 1 +-above, provided that you also meet all of these conditions: +- +- a) The modified work must itself be a software library. +- +- b) You must cause the files modified to carry prominent notices +- stating that you changed the files and the date of any change. +- +- c) You must cause the whole of the work to be licensed at no +- charge to all third parties under the terms of this License. +- +- d) If a facility in the modified Library refers to a function or a +- table of data to be supplied by an application program that uses +- the facility, other than as an argument passed when the facility +- is invoked, then you must make a good faith effort to ensure that, +- in the event an application does not supply such function or +- table, the facility still operates, and performs whatever part of +- its purpose remains meaningful. +- +- (For example, a function in a library to compute square roots has +- a purpose that is entirely well-defined independent of the +- application. Therefore, Subsection 2d requires that any +- application-supplied function or table used by this function must +- be optional: if the application does not supply it, the square +- root function must still compute square roots.) +- +-These requirements apply to the modified work as a whole. If +-identifiable sections of that work are not derived from the Library, +-and can be reasonably considered independent and separate works in +-themselves, then this License, and its terms, do not apply to those +-sections when you distribute them as separate works. But when you +-distribute the same sections as part of a whole which is a work based +-on the Library, the distribution of the whole must be on the terms of +-this License, whose permissions for other licensees extend to the +-entire whole, and thus to each and every part regardless of who wrote +-it. +- +-Thus, it is not the intent of this section to claim rights or contest +-your rights to work written entirely by you; rather, the intent is to +-exercise the right to control the distribution of derivative or +-collective works based on the Library. +- +-In addition, mere aggregation of another work not based on the Library +-with the Library (or with a work based on the Library) on a volume of +-a storage or distribution medium does not bring the other work under +-the scope of this License. +- +- 3. You may opt to apply the terms of the ordinary GNU General Public +-License instead of this License to a given copy of the Library. To do +-this, you must alter all the notices that refer to this License, so +-that they refer to the ordinary GNU General Public License, version 2, +-instead of to this License. (If a newer version than version 2 of the +-ordinary GNU General Public License has appeared, then you can specify +-that version instead if you wish.) Do not make any other change in +-these notices. +- +- Once this change is made in a given copy, it is irreversible for +-that copy, so the ordinary GNU General Public License applies to all +-subsequent copies and derivative works made from that copy. +- +- This option is useful when you wish to copy part of the code of +-the Library into a program that is not a library. +- +- 4. You may copy and distribute the Library (or a portion or +-derivative of it, under Section 2) in object code or executable form +-under the terms of Sections 1 and 2 above provided that you accompany +-it with the complete corresponding machine-readable source code, which +-must be distributed under the terms of Sections 1 and 2 above on a +-medium customarily used for software interchange. +- +- If distribution of object code is made by offering access to copy +-from a designated place, then offering equivalent access to copy the +-source code from the same place satisfies the requirement to +-distribute the source code, even though third parties are not +-compelled to copy the source along with the object code. +- +- 5. A program that contains no derivative of any portion of the +-Library, but is designed to work with the Library by being compiled or +-linked with it, is called a "work that uses the Library". Such a +-work, in isolation, is not a derivative work of the Library, and +-therefore falls outside the scope of this License. +- +- However, linking a "work that uses the Library" with the Library +-creates an executable that is a derivative of the Library (because it +-contains portions of the Library), rather than a "work that uses the +-library". The executable is therefore covered by this License. +-Section 6 states terms for distribution of such executables. +- +- When a "work that uses the Library" uses material from a header file +-that is part of the Library, the object code for the work may be a +-derivative work of the Library even though the source code is not. +-Whether this is true is especially significant if the work can be +-linked without the Library, or if the work is itself a library. The +-threshold for this to be true is not precisely defined by law. +- +- If such an object file uses only numerical parameters, data +-structure layouts and accessors, and small macros and small inline +-functions (ten lines or less in length), then the use of the object +-file is unrestricted, regardless of whether it is legally a derivative +-work. (Executables containing this object code plus portions of the +-Library will still fall under Section 6.) +- +- Otherwise, if the work is a derivative of the Library, you may +-distribute the object code for the work under the terms of Section 6. +-Any executables containing that work also fall under Section 6, +-whether or not they are linked directly with the Library itself. +- +- 6. As an exception to the Sections above, you may also combine or +-link a "work that uses the Library" with the Library to produce a +-work containing portions of the Library, and distribute that work +-under terms of your choice, provided that the terms permit +-modification of the work for the customer's own use and reverse +-engineering for debugging such modifications. +- +- You must give prominent notice with each copy of the work that the +-Library is used in it and that the Library and its use are covered by +-this License. You must supply a copy of this License. If the work +-during execution displays copyright notices, you must include the +-copyright notice for the Library among them, as well as a reference +-directing the user to the copy of this License. Also, you must do one +-of these things: +- +- a) Accompany the work with the complete corresponding +- machine-readable source code for the Library including whatever +- changes were used in the work (which must be distributed under +- Sections 1 and 2 above); and, if the work is an executable linked +- with the Library, with the complete machine-readable "work that +- uses the Library", as object code and/or source code, so that the +- user can modify the Library and then relink to produce a modified +- executable containing the modified Library. (It is understood +- that the user who changes the contents of definitions files in the +- Library will not necessarily be able to recompile the application +- to use the modified definitions.) +- +- b) Use a suitable shared library mechanism for linking with the +- Library. A suitable mechanism is one that (1) uses at run time a +- copy of the library already present on the user's computer system, +- rather than copying library functions into the executable, and (2) +- will operate properly with a modified version of the library, if +- the user installs one, as long as the modified version is +- interface-compatible with the version that the work was made with. +- +- c) Accompany the work with a written offer, valid for at +- least three years, to give the same user the materials +- specified in Subsection 6a, above, for a charge no more +- than the cost of performing this distribution. +- +- d) If distribution of the work is made by offering access to copy +- from a designated place, offer equivalent access to copy the above +- specified materials from the same place. +- +- e) Verify that the user has already received a copy of these +- materials or that you have already sent this user a copy. +- +- For an executable, the required form of the "work that uses the +-Library" must include any data and utility programs needed for +-reproducing the executable from it. However, as a special exception, +-the materials to be distributed need not include anything that is +-normally distributed (in either source or binary form) with the major +-components (compiler, kernel, and so on) of the operating system on +-which the executable runs, unless that component itself accompanies +-the executable. +- +- It may happen that this requirement contradicts the license +-restrictions of other proprietary libraries that do not normally +-accompany the operating system. Such a contradiction means you cannot +-use both them and the Library together in an executable that you +-distribute. +- +- 7. You may place library facilities that are a work based on the +-Library side-by-side in a single library together with other library +-facilities not covered by this License, and distribute such a combined +-library, provided that the separate distribution of the work based on +-the Library and of the other library facilities is otherwise +-permitted, and provided that you do these two things: +- +- a) Accompany the combined library with a copy of the same work +- based on the Library, uncombined with any other library +- facilities. This must be distributed under the terms of the +- Sections above. +- +- b) Give prominent notice with the combined library of the fact +- that part of it is a work based on the Library, and explaining +- where to find the accompanying uncombined form of the same work. +- +- 8. You may not copy, modify, sublicense, link with, or distribute +-the Library except as expressly provided under this License. Any +-attempt otherwise to copy, modify, sublicense, link with, or +-distribute the Library is void, and will automatically terminate your +-rights under this License. However, parties who have received copies, +-or rights, from you under this License will not have their licenses +-terminated so long as such parties remain in full compliance. +- +- 9. You are not required to accept this License, since you have not +-signed it. However, nothing else grants you permission to modify or +-distribute the Library or its derivative works. These actions are +-prohibited by law if you do not accept this License. Therefore, by +-modifying or distributing the Library (or any work based on the +-Library), you indicate your acceptance of this License to do so, and +-all its terms and conditions for copying, distributing or modifying +-the Library or works based on it. +- +- 10. Each time you redistribute the Library (or any work based on the +-Library), the recipient automatically receives a license from the +-original licensor to copy, distribute, link with or modify the Library +-subject to these terms and conditions. You may not impose any further +-restrictions on the recipients' exercise of the rights granted herein. +-You are not responsible for enforcing compliance by third parties with +-this License. +- +- 11. If, as a consequence of a court judgment or allegation of patent +-infringement or for any other reason (not limited to patent issues), +-conditions are imposed on you (whether by court order, agreement or +-otherwise) that contradict the conditions of this License, they do not +-excuse you from the conditions of this License. If you cannot +-distribute so as to satisfy simultaneously your obligations under this +-License and any other pertinent obligations, then as a consequence you +-may not distribute the Library at all. For example, if a patent +-license would not permit royalty-free redistribution of the Library by +-all those who receive copies directly or indirectly through you, then +-the only way you could satisfy both it and this License would be to +-refrain entirely from distribution of the Library. +- +-If any portion of this section is held invalid or unenforceable under any +-particular circumstance, the balance of the section is intended to apply, +-and the section as a whole is intended to apply in other circumstances. +- +-It is not the purpose of this section to induce you to infringe any +-patents or other property right claims or to contest validity of any +-such claims; this section has the sole purpose of protecting the +-integrity of the free software distribution system which is +-implemented by public license practices. Many people have made +-generous contributions to the wide range of software distributed +-through that system in reliance on consistent application of that +-system; it is up to the author/donor to decide if he or she is willing +-to distribute software through any other system and a licensee cannot +-impose that choice. +- +-This section is intended to make thoroughly clear what is believed to +-be a consequence of the rest of this License. +- +- 12. If the distribution and/or use of the Library is restricted in +-certain countries either by patents or by copyrighted interfaces, the +-original copyright holder who places the Library under this License may add +-an explicit geographical distribution limitation excluding those countries, +-so that distribution is permitted only in or among countries not thus +-excluded. In such case, this License incorporates the limitation as if +-written in the body of this License. +- +- 13. The Free Software Foundation may publish revised and/or new +-versions of the Lesser General Public License from time to time. +-Such new versions will be similar in spirit to the present version, +-but may differ in detail to address new problems or concerns. +- +-Each version is given a distinguishing version number. If the Library +-specifies a version number of this License which applies to it and +-"any later version", you have the option of following the terms and +-conditions either of that version or of any later version published by +-the Free Software Foundation. If the Library does not specify a +-license version number, you may choose any version ever published by +-the Free Software Foundation. +- +- 14. If you wish to incorporate parts of the Library into other free +-programs whose distribution conditions are incompatible with these, +-write to the author to ask for permission. For software which is +-copyrighted by the Free Software Foundation, write to the Free +-Software Foundation; we sometimes make exceptions for this. Our +-decision will be guided by the two goals of preserving the free status +-of all derivatives of our free software and of promoting the sharing +-and reuse of software generally. +- +- NO WARRANTY +- +- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. +- +- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +-DAMAGES. +- +- END OF TERMS AND CONDITIONS +- +- How to Apply These Terms to Your New Libraries +- +- If you develop a new library, and you want it to be of the greatest +-possible use to the public, we recommend making it free software that +-everyone can redistribute and change. You can do so by permitting +-redistribution under these terms (or, alternatively, under the terms of the +-ordinary General Public License). +- +- To apply these terms, attach the following notices to the library. It is +-safest to attach them to the start of each source file to most effectively +-convey the exclusion of warranty; and each file should have at least the +-"copyright" line and a pointer to where the full notice is found. +- +- +- Copyright (C) +- +- This library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- This library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with this library; if not, write to the Free Software +- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- +-Also add information on how to contact you by electronic and paper mail. +- +-You should also get your employer (if you work as a programmer) or your +-school, if any, to sign a "copyright disclaimer" for the library, if +-necessary. Here is a sample; alter the names: +- +- Yoyodyne, Inc., hereby disclaims all copyright interest in the +- library `Frob' (a library for tweaking knobs) written by James Random Hacker. +- +- , 1 April 1990 +- Ty Coon, President of Vice +- +-That's all there is to it! +- +- +diff --git a/utils/open-isns/ChangeLog b/utils/open-isns/ChangeLog +deleted file mode 100644 +index 36d6506..0000000 +--- a/utils/open-isns/ChangeLog ++++ /dev/null +@@ -1,50 +0,0 @@ +-Under development: +- +-2007-09-27: +- Fixed a serious interoperability bug +- Added SLP support (using openslp) +- Init script (courtesy Albert Pauw) +- +-2007-09-18: +- Fixed a number of bugs +- Added more test cases +- Implemented default DD +- Support autoconf, and building with/without openssl +- +-2007-08-24: +- Improved discovery domain handling +- Implemented DD deregistration +- Backward compat fixes for older openssl versions +- Made SCN more robust, SCN state now persists across server restarts +- More regression tests +- +-2007-07-27: +- Implemented SCN and ESI +- Created iSNS discovery daemon (isnsdd) +- Rewrote the policy handling a bit +- Started to write some regression test code +- Better manpages +- +-2007-07-12: +- DevGetNext support +- You can now define policies linking authentication +- to permitted storage node names, permitted +- entity names, etc. +- Implemented DDReg +- Queries and GetNext are now scoped to discovery domains +- Lots of little bits and pieces for RFC conformance +- +-2005-07-18: +- Public snapshot released +- DSA based authentication +- Deregistration +- Simple file backed storage for the iSNS database +- Entity Registration Period + Timestamp support (server side), +- and entity expiration +- isnsd now writes a pid file +- Improved manual pages +- DevGetNext support under development +- +-2007-05-11: +- First public release, supporting register/query +- +diff --git a/utils/open-isns/HACKING b/utils/open-isns/HACKING +deleted file mode 100644 +index 95b330c..0000000 +--- a/utils/open-isns/HACKING ++++ /dev/null +@@ -1,30 +0,0 @@ +- +-When hacking on open-isns, or when trying to locate a problem, +-the following information may be useful: +- +- - You can start the daemon using the -f option, which +- prevents it from backgrounding itself. Crucial if +- you want to run it in a debugger, or under strace. +- +- This option works for isnsd and isnsdd +- +- - All tools support the "-d" option to enable debugging. +- In general, you want to use "-d all" to turn on all +- debugging options. However, you can select individual +- debug facilities - check out the manpages and/or +- the source code in logging.c +- +- - If isnsd crashes, and you suspect memory corruption, +- you can compile open-isns with memory debugging enabled. Re-run +- the configure script and add the option --enable-memdebug. Then +- run "make clean all" to rebuild everything. +- +- Memory debugging can be chosen at run-time by setting the +- ISNS_MDEBUG environment variable, and re-starting the application: +- +- export ISNS_MDEBUG=1 +- ./isnsd -f -d all +- +- Memory debugging works for all memory allocations done by the +- Open-iSNS code, but does not affect memory allocations by other +- libraries (such as glibc or openssl). +diff --git a/utils/open-isns/Makefile.in b/utils/open-isns/Makefile.in +deleted file mode 100644 +index a27199c..0000000 +--- a/utils/open-isns/Makefile.in ++++ /dev/null +@@ -1,81 +0,0 @@ +-prefix = @prefix@ +-exec_prefix = @exec_prefix@ +-sbindir = @sbindir@ +-mandir = @mandir@ +-etcdir = /etc +-vardir = /var/lib/isns +- +-SBINDIR = $(INSTALL_ROOT)$(sbindir) +-ETCDIR = $(INSTALL_ROOT)$(etcdir) +-CFGDIR = $(ETCDIR)/isns +-MANDIR = $(INSTALL_ROOT)$(mandir) +-VARDIR = $(INSTALL_ROOT)$(vardir) +- +-CC = @CC@ +-CPPFLAGS= @CPPFLAGS@ +-CFLAGS = @CFLAGS@ -I. +-LDFLAGS = @LDFLAGS@ +- +-LIB = libisns.a +-LIBOBJS = server.o \ +- client.o \ +- objects.o \ +- callback.o \ +- timer.o \ +- vendor.o \ +- db.o \ +- db-file.o \ +- db-policy.o \ +- relation.o \ +- scope.o \ +- message.o \ +- security.o \ +- authblock.o \ +- policy.o \ +- register.o \ +- query.o \ +- getnext.o \ +- deregister.o \ +- esi.o \ +- scn.o \ +- dd.o \ +- entity.o \ +- portal-group.o \ +- storage-node.o \ +- domain.o \ +- simple.o \ +- tags.o \ +- attrs.o \ +- export.o \ +- socket.o \ +- slp.o \ +- error.o \ +- logging.o \ +- config.o \ +- parser.o \ +- buffer.o \ +- pidfile.o \ +- sysdep-unix.o \ +- util.o \ +- bitvector.o \ +- mdebug.o +-SECLINK = @SECLIBS@ +-SLPLINK = @SLPLIBS@ +-SLPLIN = @SLPLIBS@ +- +-all: $(LIB) +- +-clean distclean:: +- rm -f *.o $(LIB) *~ +- +-distclean:: +- rm -f config.h Makefile config.status config.log +- rm -rf autom4te.cache +- +-$(LIB): $(LIBOBJS) +- ar cr $@ $(LIBOBJS) +- +-depend: +- gcc $(CFLAGS) -M `ls *.c` > .depend +- +--include .depend +diff --git a/utils/open-isns/README b/utils/open-isns/README +deleted file mode 100644 +index acff29b..0000000 +--- a/utils/open-isns/README ++++ /dev/null +@@ -1,173 +0,0 @@ +- +-Welcome to Open-iSNS +-==================== +- +-This is a partial implementation of iSNS, according to RFC4171. +-The implementation is still somewhat incomplete, but I'm releasing +-it for your reading pleasure. +- +-The distribution comprises +- +- isnsd +- This is the iSNS server, supporting persistent storage +- of registrations in a file based database. +- +- isnsadm +- A command line utility for querying the iSNS database, +- and for registering/deregistering nodes and portals +- +- isnsdd +- An iSNS Discovery Daemon, which is still very much work +- in progress. The daemon is supposed to handle all the +- bit banging and server communications required to register +- a node, its portals, and to maintain the registration. +- It is also supposed to use the iSNS State Change Notification +- framework to learn of new targets or initiators coming online, +- and inform local services (such as the iSCSI initiator daemon) +- about these changes. +- +-Thanks! +-------- +- +-Many thanks to Albert Pauw for his fearless testing of snapshots, +-and his copious feedback! +- +-What works, after a fashion: +----------------------------- +- +- - For now, I've been focusing on getting the iSCSI part to +- work. There is some very basic support for FC objects, but +- this will be hardly useful yet. +- +- - Registration, deregistration, query, getnext +- You can use isnsadm to register iSCSI nodes, and portals. +- isnsadm also illustrates how this is supposed to be used from +- the client perspective. +- +- - Discovery domains are supported mostly. The administrator +- can create discovery domains using isnsadm, and place storage +- nodes in domains. Queries by clients are scoped by their +- discovery domains membership, so that they will be unable to +- see nodes not part of a shared DD. +- +- Open-iSNS currently does not allow clients to place themselves +- in a DD. +- +- Optionally, storage nodes that are not in any discovery domain +- will be placed in a "default DD" (see the DefaultDiscoveryDomain +- in isnsd.conf). +- +- - ESI, supported both by the server and the discovery daemon +- +- - SCN, supported by the server and the discovery daemon +- +-What is still missing +---------------------- +- +- - Better documentation (esp. a HOWTO on getting started with iSNS) +- - DD Sets +- - Various bits and pieces of the protocol +- - FC support +- +- +-Building Open-iSNS +------------------- +- +-The Open-iSNS build is now based on autoconf. The distributed tarball +-should include a configure script and a config.h.in file generated +-from configure.ac. If these are missing, you can generate them +-by running +- +- autoconf +- autoheader +- +-For most people, it should be sufficient to run configure without any +-arguments, or at most with the option --prefix. If run without --prefix, +-program files, manpages etc will be installed below /usr/local. To have +-everything installed /usr/bin, /usr/share/man etc, run it as +- +- ./configure --prefix=/usr +- +-Dependencies: +- +- - If you want to build Open-iSNS with support for authentication, +- you need the OpenSSL libraries and header files installed. +- +- The configure script should pick up the presence of these +- libraries, and enable security support automatically. To disable +- this explicitly in your build, pass the --without-security option +- to configure. +- +- - If you want to build Open-iSNS with SLP support, you need the +- OpenSLP library and header file installed. +- +- The configure script should pick up the presence of this library, +- and enable SLP support automatically. To disable this explicitly +- in your build, pass the --without-slp option to configure. +- +-When configure is run, it checks for a the presence of a number of +-headers and libraries in your system (the results of most of these checks +-are currently ignored :-). Then, it creates a Makefile and a config.h +-include file. With these in place, you can build the binaries and libraries: +- +- make +- make install +- +-Getting started +---------------- +- +-On the iSNS server, you need to generate a server key and install it. The +-simplest way is probably to use the isnssetup script included in the +-source package. +- +-For each client you wish to use, you should then +- +-iSNS Security +-------------- +- +-This implementation of iSNS supports authentication, as descibed in RFC +-4171. In order to use it, you have to create DSA keys for the server and +-all clients. +- +-iSNS uses conceptually the same security mechanism as SLP, and identifies +-principals by a "Security Parameter Index", which is essentially a string +-identifying a key. +- +-Open-iSNS fully supports DSA based security, and offers a flexible +-policy mechanism that ties an SPI to a network entity and the storage +-node names it is allowed to use. For an introduction to the security +-model used by Open-iSNS, refer to the isns_config(5) manual page. An +-overview on setting up the iSNS server for authentication is given in +-the EXAMPLES section of the isnsadm(8) manual page. +- +-Downloading Open-iSNS +---------------------- +- +-Open-iSNS is available for download from +- +- http://oss.oracle.com/~okir/open-isns +- +-You have to grab the latest tarball and compile it; fancy things such +-as RPMs are not available yet. +- +------------------------------------------------------------------- +- +- +- COPYRIGHT NOTICE +- +- Copyright (C) 2007 Olaf Kirch. +- +- This library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- This library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with this library; if not, write to the Free Software +- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- +diff --git a/utils/open-isns/TODO b/utils/open-isns/TODO +deleted file mode 100644 +index 2ddf008..0000000 +--- a/utils/open-isns/TODO ++++ /dev/null +@@ -1,100 +0,0 @@ +-Documentation: +- - Add HOWTO +- +-isnsd: +- - When registering a node, use the default EID given in its +- policy (avoid the isns.control trap) +- - make PGs children of the iSCSI storage node they're associated +- with? +- - Implement missing functions +- +-isnsadm: +- - support iSNS server discovery through DNS SRV +- records, and SLP +- +-isnsdd: +- - support iSNS server discovery through DNS SRV +- records, and SLP +- - At startup, query the server for the list of +- visible nodes/portals +- - When receiving an SCN, query for the node's +- portals, authmethod and such, and compare that +- to what we have cached +- - At regular intervals, repeat the query for +- all visible nodes/portals, and do a diff with +- our shadow DB +- - At regular intervals, check whether the portals +- we registered for ESI are seeing the server's +- ESI messages. +- +-DevAttrReg: +- - Refuse registration of nodes inside the CONTROL +- entity, unless it's a control node. +- - If the client uses REPLACE, is it okay for the +- entity's index to change? +- - security: optionally validate the IP addresses +- a client registers (either against a static policy, +- or using DNS). +- - relaxed security model: require privilege +- for registration of targets; anyone can register +- an initiator? +- - Gracefully handle registrations where the client +- specifies an index attribute, as long as it matches +- the next_index +- +-DevAttrQuery: +- - fix --local --query policy-index=iqn.1969-12.brummo +- and write test case +- - fix the way we enumerate related objects +- - ensure DD discovery works (5.6.5.2): +- DD membership can be discovered through the DevAttrQry message +- by including either DD member attributes (i.e., DD Member +- iSCSI Index, DD Member iSCSI Node, DD Member iFCP Node, DD +- Member Portal Index, DD Member Portal IP Addr, and DD Member +- Portal TCP/UDP) or the object key of the Storage Node or +- Portal (i.e., iSCSI Name, iSCSI Index, Portal IP Addr, Portal +- TCP/UDP Port, and Portal Index) in the Operating Attributes. +- Using DD member attributes SHALL return both registered and +- unregistered member Storage Nodes and/or Portals of a DD. +- DevAttrQry messages using the Storage Node and/or Portal +- object key SHALL return only member Storage Nodes or Portals +- that are currently registered in the iSNS database. +- +-DevAttrDereg: +- - PG Removal code: ignore nodes/portal that are dead +- - review security +- - cancel any SCN/ESI callbacks +- +-SCN: +- - Trigger a mgmt reg SCN when accepting a mgmt registration +- +-SCNEvent: +- - Implement +- +-ESI: +- - Right now the way we re-establish ESI state after database +- reload is awkward. +- +-DDReg: +- - Write test cases +- +-DDDereg: +- - Write test cases +- +-DDSReg/DDSDereg: +- - Implement +- +-Heartbeat: +- - Implement message send +- - Implement failover? +- +-Security: +- - Allow policies without key? +- - Implement simple default policies linking client IP + +- hostname (network entity) + storage node names +- +-Renaming +- - Add isns_ prefix to all visible functions +- +-Socket code: +- - impose upper limit on the reassembly buffer +diff --git a/utils/open-isns/aclocal/config.guess b/utils/open-isns/aclocal/config.guess +deleted file mode 100644 +index 6d71f75..0000000 +--- a/utils/open-isns/aclocal/config.guess ++++ /dev/null +@@ -1,1499 +0,0 @@ +-#! /bin/sh +-# Attempt to guess a canonical system name. +-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +-# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. +- +-timestamp='2005-05-27' +- +-# This file is free software; you can redistribute it and/or modify it +-# under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-# General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +-# 02110-1301, USA. +-# +-# As a special exception to the GNU General Public License, if you +-# distribute this file as part of a program that contains a +-# configuration script generated by Autoconf, you may include it under +-# the same distribution terms that you use for the rest of that program. +- +- +-# Originally written by Per Bothner . +-# Please send patches to . Submit a context +-# diff and a properly formatted ChangeLog entry. +-# +-# This script attempts to guess a canonical system name similar to +-# config.sub. If it succeeds, it prints the system name on stdout, and +-# exits with 0. Otherwise, it exits with 1. +-# +-# The plan is that this can be called by configure scripts if you +-# don't specify an explicit build system type. +- +-me=`echo "$0" | sed -e 's,.*/,,'` +- +-usage="\ +-Usage: $0 [OPTION] +- +-Output the configuration name of the system \`$me' is run on. +- +-Operation modes: +- -h, --help print this help, then exit +- -t, --time-stamp print date of last modification, then exit +- -v, --version print version number, then exit +- +-Report bugs and patches to ." +- +-version="\ +-GNU config.guess ($timestamp) +- +-Originally written by Per Bothner. +-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +-Free Software Foundation, Inc. +- +-This is free software; see the source for copying conditions. There is NO +-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." +- +-help=" +-Try \`$me --help' for more information." +- +-# Parse command line +-while test $# -gt 0 ; do +- case $1 in +- --time-stamp | --time* | -t ) +- echo "$timestamp" ; exit ;; +- --version | -v ) +- echo "$version" ; exit ;; +- --help | --h* | -h ) +- echo "$usage"; exit ;; +- -- ) # Stop option processing +- shift; break ;; +- - ) # Use stdin as input. +- break ;; +- -* ) +- echo "$me: invalid option $1$help" >&2 +- exit 1 ;; +- * ) +- break ;; +- esac +-done +- +-if test $# != 0; then +- echo "$me: too many arguments$help" >&2 +- exit 1 +-fi +- +-trap 'exit 1' 1 2 15 +- +-# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +-# compiler to aid in system detection is discouraged as it requires +-# temporary files to be created and, as you can see below, it is a +-# headache to deal with in a portable fashion. +- +-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +-# use `HOST_CC' if defined, but it is deprecated. +- +-# Portable tmp directory creation inspired by the Autoconf team. +- +-set_cc_for_build=' +-trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +-trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +-: ${TMPDIR=/tmp} ; +- { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || +- { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || +- { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || +- { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +-dummy=$tmp/dummy ; +-tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +-case $CC_FOR_BUILD,$HOST_CC,$CC in +- ,,) echo "int x;" > $dummy.c ; +- for c in cc gcc c89 c99 ; do +- if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then +- CC_FOR_BUILD="$c"; break ; +- fi ; +- done ; +- if test x"$CC_FOR_BUILD" = x ; then +- CC_FOR_BUILD=no_compiler_found ; +- fi +- ;; +- ,,*) CC_FOR_BUILD=$CC ;; +- ,*,*) CC_FOR_BUILD=$HOST_CC ;; +-esac ;' +- +-# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +-# (ghazi@noc.rutgers.edu 1994-08-24) +-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then +- PATH=$PATH:/.attbin ; export PATH +-fi +- +-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown +- +-# Note: order is significant - the case branches are not exclusive. +- +-case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in +- *:NetBSD:*:*) +- # NetBSD (nbsd) targets should (where applicable) match one or +- # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, +- # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently +- # switched to ELF, *-*-netbsd* would select the old +- # object file format. This provides both forward +- # compatibility and a consistent mechanism for selecting the +- # object file format. +- # +- # Note: NetBSD doesn't particularly care about the vendor +- # portion of the name. We always set it to "unknown". +- sysctl="sysctl -n hw.machine_arch" +- UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ +- /usr/sbin/$sysctl 2>/dev/null || echo unknown)` +- case "${UNAME_MACHINE_ARCH}" in +- armeb) machine=armeb-unknown ;; +- arm*) machine=arm-unknown ;; +- sh3el) machine=shl-unknown ;; +- sh3eb) machine=sh-unknown ;; +- *) machine=${UNAME_MACHINE_ARCH}-unknown ;; +- esac +- # The Operating System including object format, if it has switched +- # to ELF recently, or will in the future. +- case "${UNAME_MACHINE_ARCH}" in +- arm*|i386|m68k|ns32k|sh3*|sparc|vax) +- eval $set_cc_for_build +- if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ +- | grep __ELF__ >/dev/null +- then +- # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). +- # Return netbsd for either. FIX? +- os=netbsd +- else +- os=netbsdelf +- fi +- ;; +- *) +- os=netbsd +- ;; +- esac +- # The OS release +- # Debian GNU/NetBSD machines have a different userland, and +- # thus, need a distinct triplet. However, they do not need +- # kernel version information, so it can be replaced with a +- # suitable tag, in the style of linux-gnu. +- case "${UNAME_VERSION}" in +- Debian*) +- release='-gnu' +- ;; +- *) +- release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` +- ;; +- esac +- # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: +- # contains redundant information, the shorter form: +- # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. +- echo "${machine}-${os}${release}" +- exit ;; +- amd64:OpenBSD:*:*) +- echo x86_64-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- amiga:OpenBSD:*:*) +- echo m68k-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- cats:OpenBSD:*:*) +- echo arm-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- hp300:OpenBSD:*:*) +- echo m68k-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- luna88k:OpenBSD:*:*) +- echo m88k-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- mac68k:OpenBSD:*:*) +- echo m68k-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- macppc:OpenBSD:*:*) +- echo powerpc-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- mvme68k:OpenBSD:*:*) +- echo m68k-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- mvme88k:OpenBSD:*:*) +- echo m88k-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- mvmeppc:OpenBSD:*:*) +- echo powerpc-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- sgi:OpenBSD:*:*) +- echo mips64-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- sun3:OpenBSD:*:*) +- echo m68k-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- *:OpenBSD:*:*) +- echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} +- exit ;; +- *:ekkoBSD:*:*) +- echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} +- exit ;; +- macppc:MirBSD:*:*) +- echo powerppc-unknown-mirbsd${UNAME_RELEASE} +- exit ;; +- *:MirBSD:*:*) +- echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} +- exit ;; +- alpha:OSF1:*:*) +- case $UNAME_RELEASE in +- *4.0) +- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` +- ;; +- *5.*) +- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` +- ;; +- esac +- # According to Compaq, /usr/sbin/psrinfo has been available on +- # OSF/1 and Tru64 systems produced since 1995. I hope that +- # covers most systems running today. This code pipes the CPU +- # types through head -n 1, so we only detect the type of CPU 0. +- ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` +- case "$ALPHA_CPU_TYPE" in +- "EV4 (21064)") +- UNAME_MACHINE="alpha" ;; +- "EV4.5 (21064)") +- UNAME_MACHINE="alpha" ;; +- "LCA4 (21066/21068)") +- UNAME_MACHINE="alpha" ;; +- "EV5 (21164)") +- UNAME_MACHINE="alphaev5" ;; +- "EV5.6 (21164A)") +- UNAME_MACHINE="alphaev56" ;; +- "EV5.6 (21164PC)") +- UNAME_MACHINE="alphapca56" ;; +- "EV5.7 (21164PC)") +- UNAME_MACHINE="alphapca57" ;; +- "EV6 (21264)") +- UNAME_MACHINE="alphaev6" ;; +- "EV6.7 (21264A)") +- UNAME_MACHINE="alphaev67" ;; +- "EV6.8CB (21264C)") +- UNAME_MACHINE="alphaev68" ;; +- "EV6.8AL (21264B)") +- UNAME_MACHINE="alphaev68" ;; +- "EV6.8CX (21264D)") +- UNAME_MACHINE="alphaev68" ;; +- "EV6.9A (21264/EV69A)") +- UNAME_MACHINE="alphaev69" ;; +- "EV7 (21364)") +- UNAME_MACHINE="alphaev7" ;; +- "EV7.9 (21364A)") +- UNAME_MACHINE="alphaev79" ;; +- esac +- # A Pn.n version is a patched version. +- # A Vn.n version is a released version. +- # A Tn.n version is a released field test version. +- # A Xn.n version is an unreleased experimental baselevel. +- # 1.2 uses "1.2" for uname -r. +- echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` +- exit ;; +- Alpha\ *:Windows_NT*:*) +- # How do we know it's Interix rather than the generic POSIX subsystem? +- # Should we change UNAME_MACHINE based on the output of uname instead +- # of the specific Alpha model? +- echo alpha-pc-interix +- exit ;; +- 21064:Windows_NT:50:3) +- echo alpha-dec-winnt3.5 +- exit ;; +- Amiga*:UNIX_System_V:4.0:*) +- echo m68k-unknown-sysv4 +- exit ;; +- *:[Aa]miga[Oo][Ss]:*:*) +- echo ${UNAME_MACHINE}-unknown-amigaos +- exit ;; +- *:[Mm]orph[Oo][Ss]:*:*) +- echo ${UNAME_MACHINE}-unknown-morphos +- exit ;; +- *:OS/390:*:*) +- echo i370-ibm-openedition +- exit ;; +- *:z/VM:*:*) +- echo s390-ibm-zvmoe +- exit ;; +- *:OS400:*:*) +- echo powerpc-ibm-os400 +- exit ;; +- arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) +- echo arm-acorn-riscix${UNAME_RELEASE} +- exit ;; +- arm:riscos:*:*|arm:RISCOS:*:*) +- echo arm-unknown-riscos +- exit ;; +- SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) +- echo hppa1.1-hitachi-hiuxmpp +- exit ;; +- Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) +- # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. +- if test "`(/bin/universe) 2>/dev/null`" = att ; then +- echo pyramid-pyramid-sysv3 +- else +- echo pyramid-pyramid-bsd +- fi +- exit ;; +- NILE*:*:*:dcosx) +- echo pyramid-pyramid-svr4 +- exit ;; +- DRS?6000:unix:4.0:6*) +- echo sparc-icl-nx6 +- exit ;; +- DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) +- case `/usr/bin/uname -p` in +- sparc) echo sparc-icl-nx7; exit ;; +- esac ;; +- sun4H:SunOS:5.*:*) +- echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` +- exit ;; +- sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) +- echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` +- exit ;; +- i86pc:SunOS:5.*:*) +- echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` +- exit ;; +- sun4*:SunOS:6*:*) +- # According to config.sub, this is the proper way to canonicalize +- # SunOS6. Hard to guess exactly what SunOS6 will be like, but +- # it's likely to be more like Solaris than SunOS4. +- echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` +- exit ;; +- sun4*:SunOS:*:*) +- case "`/usr/bin/arch -k`" in +- Series*|S4*) +- UNAME_RELEASE=`uname -v` +- ;; +- esac +- # Japanese Language versions have a version number like `4.1.3-JL'. +- echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` +- exit ;; +- sun3*:SunOS:*:*) +- echo m68k-sun-sunos${UNAME_RELEASE} +- exit ;; +- sun*:*:4.2BSD:*) +- UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` +- test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 +- case "`/bin/arch`" in +- sun3) +- echo m68k-sun-sunos${UNAME_RELEASE} +- ;; +- sun4) +- echo sparc-sun-sunos${UNAME_RELEASE} +- ;; +- esac +- exit ;; +- aushp:SunOS:*:*) +- echo sparc-auspex-sunos${UNAME_RELEASE} +- exit ;; +- # The situation for MiNT is a little confusing. The machine name +- # can be virtually everything (everything which is not +- # "atarist" or "atariste" at least should have a processor +- # > m68000). The system name ranges from "MiNT" over "FreeMiNT" +- # to the lowercase version "mint" (or "freemint"). Finally +- # the system name "TOS" denotes a system which is actually not +- # MiNT. But MiNT is downward compatible to TOS, so this should +- # be no problem. +- atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) +- echo m68k-atari-mint${UNAME_RELEASE} +- exit ;; +- atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) +- echo m68k-atari-mint${UNAME_RELEASE} +- exit ;; +- *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) +- echo m68k-atari-mint${UNAME_RELEASE} +- exit ;; +- milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) +- echo m68k-milan-mint${UNAME_RELEASE} +- exit ;; +- hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) +- echo m68k-hades-mint${UNAME_RELEASE} +- exit ;; +- *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) +- echo m68k-unknown-mint${UNAME_RELEASE} +- exit ;; +- m68k:machten:*:*) +- echo m68k-apple-machten${UNAME_RELEASE} +- exit ;; +- powerpc:machten:*:*) +- echo powerpc-apple-machten${UNAME_RELEASE} +- exit ;; +- RISC*:Mach:*:*) +- echo mips-dec-mach_bsd4.3 +- exit ;; +- RISC*:ULTRIX:*:*) +- echo mips-dec-ultrix${UNAME_RELEASE} +- exit ;; +- VAX*:ULTRIX*:*:*) +- echo vax-dec-ultrix${UNAME_RELEASE} +- exit ;; +- 2020:CLIX:*:* | 2430:CLIX:*:*) +- echo clipper-intergraph-clix${UNAME_RELEASE} +- exit ;; +- mips:*:*:UMIPS | mips:*:*:RISCos) +- eval $set_cc_for_build +- sed 's/^ //' << EOF >$dummy.c +-#ifdef __cplusplus +-#include /* for printf() prototype */ +- int main (int argc, char *argv[]) { +-#else +- int main (argc, argv) int argc; char *argv[]; { +-#endif +- #if defined (host_mips) && defined (MIPSEB) +- #if defined (SYSTYPE_SYSV) +- printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); +- #endif +- #if defined (SYSTYPE_SVR4) +- printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); +- #endif +- #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) +- printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); +- #endif +- #endif +- exit (-1); +- } +-EOF +- $CC_FOR_BUILD -o $dummy $dummy.c && +- dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && +- SYSTEM_NAME=`$dummy $dummyarg` && +- { echo "$SYSTEM_NAME"; exit; } +- echo mips-mips-riscos${UNAME_RELEASE} +- exit ;; +- Motorola:PowerMAX_OS:*:*) +- echo powerpc-motorola-powermax +- exit ;; +- Motorola:*:4.3:PL8-*) +- echo powerpc-harris-powermax +- exit ;; +- Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) +- echo powerpc-harris-powermax +- exit ;; +- Night_Hawk:Power_UNIX:*:*) +- echo powerpc-harris-powerunix +- exit ;; +- m88k:CX/UX:7*:*) +- echo m88k-harris-cxux7 +- exit ;; +- m88k:*:4*:R4*) +- echo m88k-motorola-sysv4 +- exit ;; +- m88k:*:3*:R3*) +- echo m88k-motorola-sysv3 +- exit ;; +- AViiON:dgux:*:*) +- # DG/UX returns AViiON for all architectures +- UNAME_PROCESSOR=`/usr/bin/uname -p` +- if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] +- then +- if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ +- [ ${TARGET_BINARY_INTERFACE}x = x ] +- then +- echo m88k-dg-dgux${UNAME_RELEASE} +- else +- echo m88k-dg-dguxbcs${UNAME_RELEASE} +- fi +- else +- echo i586-dg-dgux${UNAME_RELEASE} +- fi +- exit ;; +- M88*:DolphinOS:*:*) # DolphinOS (SVR3) +- echo m88k-dolphin-sysv3 +- exit ;; +- M88*:*:R3*:*) +- # Delta 88k system running SVR3 +- echo m88k-motorola-sysv3 +- exit ;; +- XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) +- echo m88k-tektronix-sysv3 +- exit ;; +- Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) +- echo m68k-tektronix-bsd +- exit ;; +- *:IRIX*:*:*) +- echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` +- exit ;; +- ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. +- echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id +- exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' +- i*86:AIX:*:*) +- echo i386-ibm-aix +- exit ;; +- ia64:AIX:*:*) +- if [ -x /usr/bin/oslevel ] ; then +- IBM_REV=`/usr/bin/oslevel` +- else +- IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} +- fi +- echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} +- exit ;; +- *:AIX:2:3) +- if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then +- eval $set_cc_for_build +- sed 's/^ //' << EOF >$dummy.c +- #include +- +- main() +- { +- if (!__power_pc()) +- exit(1); +- puts("powerpc-ibm-aix3.2.5"); +- exit(0); +- } +-EOF +- if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` +- then +- echo "$SYSTEM_NAME" +- else +- echo rs6000-ibm-aix3.2.5 +- fi +- elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then +- echo rs6000-ibm-aix3.2.4 +- else +- echo rs6000-ibm-aix3.2 +- fi +- exit ;; +- *:AIX:*:[45]) +- IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` +- if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then +- IBM_ARCH=rs6000 +- else +- IBM_ARCH=powerpc +- fi +- if [ -x /usr/bin/oslevel ] ; then +- IBM_REV=`/usr/bin/oslevel` +- else +- IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} +- fi +- echo ${IBM_ARCH}-ibm-aix${IBM_REV} +- exit ;; +- *:AIX:*:*) +- echo rs6000-ibm-aix +- exit ;; +- ibmrt:4.4BSD:*|romp-ibm:BSD:*) +- echo romp-ibm-bsd4.4 +- exit ;; +- ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and +- echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to +- exit ;; # report: romp-ibm BSD 4.3 +- *:BOSX:*:*) +- echo rs6000-bull-bosx +- exit ;; +- DPX/2?00:B.O.S.:*:*) +- echo m68k-bull-sysv3 +- exit ;; +- 9000/[34]??:4.3bsd:1.*:*) +- echo m68k-hp-bsd +- exit ;; +- hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) +- echo m68k-hp-bsd4.4 +- exit ;; +- 9000/[34678]??:HP-UX:*:*) +- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` +- case "${UNAME_MACHINE}" in +- 9000/31? ) HP_ARCH=m68000 ;; +- 9000/[34]?? ) HP_ARCH=m68k ;; +- 9000/[678][0-9][0-9]) +- if [ -x /usr/bin/getconf ]; then +- sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` +- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` +- case "${sc_cpu_version}" in +- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 +- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 +- 532) # CPU_PA_RISC2_0 +- case "${sc_kernel_bits}" in +- 32) HP_ARCH="hppa2.0n" ;; +- 64) HP_ARCH="hppa2.0w" ;; +- '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 +- esac ;; +- esac +- fi +- if [ "${HP_ARCH}" = "" ]; then +- eval $set_cc_for_build +- sed 's/^ //' << EOF >$dummy.c +- +- #define _HPUX_SOURCE +- #include +- #include +- +- int main () +- { +- #if defined(_SC_KERNEL_BITS) +- long bits = sysconf(_SC_KERNEL_BITS); +- #endif +- long cpu = sysconf (_SC_CPU_VERSION); +- +- switch (cpu) +- { +- case CPU_PA_RISC1_0: puts ("hppa1.0"); break; +- case CPU_PA_RISC1_1: puts ("hppa1.1"); break; +- case CPU_PA_RISC2_0: +- #if defined(_SC_KERNEL_BITS) +- switch (bits) +- { +- case 64: puts ("hppa2.0w"); break; +- case 32: puts ("hppa2.0n"); break; +- default: puts ("hppa2.0"); break; +- } break; +- #else /* !defined(_SC_KERNEL_BITS) */ +- puts ("hppa2.0"); break; +- #endif +- default: puts ("hppa1.0"); break; +- } +- exit (0); +- } +-EOF +- (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` +- test -z "$HP_ARCH" && HP_ARCH=hppa +- fi ;; +- esac +- if [ ${HP_ARCH} = "hppa2.0w" ] +- then +- # avoid double evaluation of $set_cc_for_build +- test -n "$CC_FOR_BUILD" || eval $set_cc_for_build +- +- # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating +- # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler +- # generating 64-bit code. GNU and HP use different nomenclature: +- # +- # $ CC_FOR_BUILD=cc ./config.guess +- # => hppa2.0w-hp-hpux11.23 +- # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess +- # => hppa64-hp-hpux11.23 +- +- if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | +- grep __LP64__ >/dev/null +- then +- HP_ARCH="hppa2.0w" +- else +- HP_ARCH="hppa64" +- fi +- fi +- echo ${HP_ARCH}-hp-hpux${HPUX_REV} +- exit ;; +- ia64:HP-UX:*:*) +- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` +- echo ia64-hp-hpux${HPUX_REV} +- exit ;; +- 3050*:HI-UX:*:*) +- eval $set_cc_for_build +- sed 's/^ //' << EOF >$dummy.c +- #include +- int +- main () +- { +- long cpu = sysconf (_SC_CPU_VERSION); +- /* The order matters, because CPU_IS_HP_MC68K erroneously returns +- true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct +- results, however. */ +- if (CPU_IS_PA_RISC (cpu)) +- { +- switch (cpu) +- { +- case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; +- case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; +- case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; +- default: puts ("hppa-hitachi-hiuxwe2"); break; +- } +- } +- else if (CPU_IS_HP_MC68K (cpu)) +- puts ("m68k-hitachi-hiuxwe2"); +- else puts ("unknown-hitachi-hiuxwe2"); +- exit (0); +- } +-EOF +- $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && +- { echo "$SYSTEM_NAME"; exit; } +- echo unknown-hitachi-hiuxwe2 +- exit ;; +- 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) +- echo hppa1.1-hp-bsd +- exit ;; +- 9000/8??:4.3bsd:*:*) +- echo hppa1.0-hp-bsd +- exit ;; +- *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) +- echo hppa1.0-hp-mpeix +- exit ;; +- hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) +- echo hppa1.1-hp-osf +- exit ;; +- hp8??:OSF1:*:*) +- echo hppa1.0-hp-osf +- exit ;; +- i*86:OSF1:*:*) +- if [ -x /usr/sbin/sysversion ] ; then +- echo ${UNAME_MACHINE}-unknown-osf1mk +- else +- echo ${UNAME_MACHINE}-unknown-osf1 +- fi +- exit ;; +- parisc*:Lites*:*:*) +- echo hppa1.1-hp-lites +- exit ;; +- C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) +- echo c1-convex-bsd +- exit ;; +- C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) +- if getsysinfo -f scalar_acc +- then echo c32-convex-bsd +- else echo c2-convex-bsd +- fi +- exit ;; +- C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) +- echo c34-convex-bsd +- exit ;; +- C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) +- echo c38-convex-bsd +- exit ;; +- C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) +- echo c4-convex-bsd +- exit ;; +- CRAY*Y-MP:*:*:*) +- echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' +- exit ;; +- CRAY*[A-Z]90:*:*:*) +- echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ +- | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ +- -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ +- -e 's/\.[^.]*$/.X/' +- exit ;; +- CRAY*TS:*:*:*) +- echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' +- exit ;; +- CRAY*T3E:*:*:*) +- echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' +- exit ;; +- CRAY*SV1:*:*:*) +- echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' +- exit ;; +- *:UNICOS/mp:*:*) +- echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' +- exit ;; +- F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) +- FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` +- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` +- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` +- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" +- exit ;; +- 5000:UNIX_System_V:4.*:*) +- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` +- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` +- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" +- exit ;; +- i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) +- echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} +- exit ;; +- sparc*:BSD/OS:*:*) +- echo sparc-unknown-bsdi${UNAME_RELEASE} +- exit ;; +- *:BSD/OS:*:*) +- echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} +- exit ;; +- *:FreeBSD:*:*) +- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` +- exit ;; +- i*:CYGWIN*:*) +- echo ${UNAME_MACHINE}-pc-cygwin +- exit ;; +- i*:MINGW*:*) +- echo ${UNAME_MACHINE}-pc-mingw32 +- exit ;; +- i*:windows32*:*) +- # uname -m includes "-pc" on this system. +- echo ${UNAME_MACHINE}-mingw32 +- exit ;; +- i*:PW*:*) +- echo ${UNAME_MACHINE}-pc-pw32 +- exit ;; +- x86:Interix*:[34]*) +- echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' +- exit ;; +- [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) +- echo i${UNAME_MACHINE}-pc-mks +- exit ;; +- i*:Windows_NT*:* | Pentium*:Windows_NT*:*) +- # How do we know it's Interix rather than the generic POSIX subsystem? +- # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we +- # UNAME_MACHINE based on the output of uname instead of i386? +- echo i586-pc-interix +- exit ;; +- i*:UWIN*:*) +- echo ${UNAME_MACHINE}-pc-uwin +- exit ;; +- amd64:CYGWIN*:*:*) +- echo x86_64-unknown-cygwin +- exit ;; +- p*:CYGWIN*:*) +- echo powerpcle-unknown-cygwin +- exit ;; +- prep*:SunOS:5.*:*) +- echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` +- exit ;; +- *:GNU:*:*) +- # the GNU system +- echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` +- exit ;; +- *:GNU/*:*:*) +- # other systems with GNU libc and userland +- echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu +- exit ;; +- i*86:Minix:*:*) +- echo ${UNAME_MACHINE}-pc-minix +- exit ;; +- arm*:Linux:*:*) +- echo ${UNAME_MACHINE}-unknown-linux-gnu +- exit ;; +- cris:Linux:*:*) +- echo cris-axis-linux-gnu +- exit ;; +- crisv32:Linux:*:*) +- echo crisv32-axis-linux-gnu +- exit ;; +- frv:Linux:*:*) +- echo frv-unknown-linux-gnu +- exit ;; +- ia64:Linux:*:*) +- echo ${UNAME_MACHINE}-unknown-linux-gnu +- exit ;; +- m32r*:Linux:*:*) +- echo ${UNAME_MACHINE}-unknown-linux-gnu +- exit ;; +- m68*:Linux:*:*) +- echo ${UNAME_MACHINE}-unknown-linux-gnu +- exit ;; +- mips:Linux:*:*) +- eval $set_cc_for_build +- sed 's/^ //' << EOF >$dummy.c +- #undef CPU +- #undef mips +- #undef mipsel +- #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) +- CPU=mipsel +- #else +- #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) +- CPU=mips +- #else +- CPU= +- #endif +- #endif +-EOF +- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` +- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } +- ;; +- mips64:Linux:*:*) +- eval $set_cc_for_build +- sed 's/^ //' << EOF >$dummy.c +- #undef CPU +- #undef mips64 +- #undef mips64el +- #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) +- CPU=mips64el +- #else +- #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) +- CPU=mips64 +- #else +- CPU= +- #endif +- #endif +-EOF +- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` +- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } +- ;; +- ppc:Linux:*:*) +- echo powerpc-unknown-linux-gnu +- exit ;; +- ppc64:Linux:*:*) +- echo powerpc64-unknown-linux-gnu +- exit ;; +- alpha:Linux:*:*) +- case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in +- EV5) UNAME_MACHINE=alphaev5 ;; +- EV56) UNAME_MACHINE=alphaev56 ;; +- PCA56) UNAME_MACHINE=alphapca56 ;; +- PCA57) UNAME_MACHINE=alphapca56 ;; +- EV6) UNAME_MACHINE=alphaev6 ;; +- EV67) UNAME_MACHINE=alphaev67 ;; +- EV68*) UNAME_MACHINE=alphaev68 ;; +- esac +- objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null +- if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi +- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} +- exit ;; +- parisc:Linux:*:* | hppa:Linux:*:*) +- # Look for CPU level +- case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in +- PA7*) echo hppa1.1-unknown-linux-gnu ;; +- PA8*) echo hppa2.0-unknown-linux-gnu ;; +- *) echo hppa-unknown-linux-gnu ;; +- esac +- exit ;; +- parisc64:Linux:*:* | hppa64:Linux:*:*) +- echo hppa64-unknown-linux-gnu +- exit ;; +- s390:Linux:*:* | s390x:Linux:*:*) +- echo ${UNAME_MACHINE}-ibm-linux +- exit ;; +- sh64*:Linux:*:*) +- echo ${UNAME_MACHINE}-unknown-linux-gnu +- exit ;; +- sh*:Linux:*:*) +- echo ${UNAME_MACHINE}-unknown-linux-gnu +- exit ;; +- sparc:Linux:*:* | sparc64:Linux:*:*) +- echo ${UNAME_MACHINE}-unknown-linux-gnu +- exit ;; +- x86_64:Linux:*:*) +- echo x86_64-unknown-linux-gnu +- exit ;; +- i*86:Linux:*:*) +- # The BFD linker knows what the default object file format is, so +- # first see if it will tell us. cd to the root directory to prevent +- # problems with other programs or directories called `ld' in the path. +- # Set LC_ALL=C to ensure ld outputs messages in English. +- ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ +- | sed -ne '/supported targets:/!d +- s/[ ][ ]*/ /g +- s/.*supported targets: *// +- s/ .*// +- p'` +- case "$ld_supported_targets" in +- elf32-i386) +- TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" +- ;; +- a.out-i386-linux) +- echo "${UNAME_MACHINE}-pc-linux-gnuaout" +- exit ;; +- coff-i386) +- echo "${UNAME_MACHINE}-pc-linux-gnucoff" +- exit ;; +- "") +- # Either a pre-BFD a.out linker (linux-gnuoldld) or +- # one that does not give us useful --help. +- echo "${UNAME_MACHINE}-pc-linux-gnuoldld" +- exit ;; +- esac +- # Determine whether the default compiler is a.out or elf +- eval $set_cc_for_build +- sed 's/^ //' << EOF >$dummy.c +- #include +- #ifdef __ELF__ +- # ifdef __GLIBC__ +- # if __GLIBC__ >= 2 +- LIBC=gnu +- # else +- LIBC=gnulibc1 +- # endif +- # else +- LIBC=gnulibc1 +- # endif +- #else +- #ifdef __INTEL_COMPILER +- LIBC=gnu +- #else +- LIBC=gnuaout +- #endif +- #endif +- #ifdef __dietlibc__ +- LIBC=dietlibc +- #endif +-EOF +- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` +- test x"${LIBC}" != x && { +- echo "${UNAME_MACHINE}-pc-linux-${LIBC}" +- exit +- } +- test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } +- ;; +- i*86:DYNIX/ptx:4*:*) +- # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. +- # earlier versions are messed up and put the nodename in both +- # sysname and nodename. +- echo i386-sequent-sysv4 +- exit ;; +- i*86:UNIX_SV:4.2MP:2.*) +- # Unixware is an offshoot of SVR4, but it has its own version +- # number series starting with 2... +- # I am not positive that other SVR4 systems won't match this, +- # I just have to hope. -- rms. +- # Use sysv4.2uw... so that sysv4* matches it. +- echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} +- exit ;; +- i*86:OS/2:*:*) +- # If we were able to find `uname', then EMX Unix compatibility +- # is probably installed. +- echo ${UNAME_MACHINE}-pc-os2-emx +- exit ;; +- i*86:XTS-300:*:STOP) +- echo ${UNAME_MACHINE}-unknown-stop +- exit ;; +- i*86:atheos:*:*) +- echo ${UNAME_MACHINE}-unknown-atheos +- exit ;; +- i*86:syllable:*:*) +- echo ${UNAME_MACHINE}-pc-syllable +- exit ;; +- i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) +- echo i386-unknown-lynxos${UNAME_RELEASE} +- exit ;; +- i*86:*DOS:*:*) +- echo ${UNAME_MACHINE}-pc-msdosdjgpp +- exit ;; +- i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) +- UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` +- if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then +- echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} +- else +- echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} +- fi +- exit ;; +- i*86:*:5:[678]*) +- # UnixWare 7.x, OpenUNIX and OpenServer 6. +- case `/bin/uname -X | grep "^Machine"` in +- *486*) UNAME_MACHINE=i486 ;; +- *Pentium) UNAME_MACHINE=i586 ;; +- *Pent*|*Celeron) UNAME_MACHINE=i686 ;; +- esac +- echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} +- exit ;; +- i*86:*:3.2:*) +- if test -f /usr/options/cb.name; then +- UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then +- UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` +- (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 +- (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ +- && UNAME_MACHINE=i586 +- (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ +- && UNAME_MACHINE=i686 +- (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ +- && UNAME_MACHINE=i686 +- echo ${UNAME_MACHINE}-pc-sco$UNAME_REL +- else +- echo ${UNAME_MACHINE}-pc-sysv32 +- fi +- exit ;; +- pc:*:*:*) +- # Left here for compatibility: +- # uname -m prints for DJGPP always 'pc', but it prints nothing about +- # the processor, so we play safe by assuming i386. +- echo i386-pc-msdosdjgpp +- exit ;; +- Intel:Mach:3*:*) +- echo i386-pc-mach3 +- exit ;; +- paragon:*:*:*) +- echo i860-intel-osf1 +- exit ;; +- i860:*:4.*:*) # i860-SVR4 +- if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then +- echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 +- else # Add other i860-SVR4 vendors below as they are discovered. +- echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 +- fi +- exit ;; +- mini*:CTIX:SYS*5:*) +- # "miniframe" +- echo m68010-convergent-sysv +- exit ;; +- mc68k:UNIX:SYSTEM5:3.51m) +- echo m68k-convergent-sysv +- exit ;; +- M680?0:D-NIX:5.3:*) +- echo m68k-diab-dnix +- exit ;; +- M68*:*:R3V[5678]*:*) +- test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; +- 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) +- OS_REL='' +- test -r /etc/.relid \ +- && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` +- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ +- && { echo i486-ncr-sysv4.3${OS_REL}; exit; } +- /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ +- && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; +- 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) +- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ +- && { echo i486-ncr-sysv4; exit; } ;; +- m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) +- echo m68k-unknown-lynxos${UNAME_RELEASE} +- exit ;; +- mc68030:UNIX_System_V:4.*:*) +- echo m68k-atari-sysv4 +- exit ;; +- TSUNAMI:LynxOS:2.*:*) +- echo sparc-unknown-lynxos${UNAME_RELEASE} +- exit ;; +- rs6000:LynxOS:2.*:*) +- echo rs6000-unknown-lynxos${UNAME_RELEASE} +- exit ;; +- PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) +- echo powerpc-unknown-lynxos${UNAME_RELEASE} +- exit ;; +- SM[BE]S:UNIX_SV:*:*) +- echo mips-dde-sysv${UNAME_RELEASE} +- exit ;; +- RM*:ReliantUNIX-*:*:*) +- echo mips-sni-sysv4 +- exit ;; +- RM*:SINIX-*:*:*) +- echo mips-sni-sysv4 +- exit ;; +- *:SINIX-*:*:*) +- if uname -p 2>/dev/null >/dev/null ; then +- UNAME_MACHINE=`(uname -p) 2>/dev/null` +- echo ${UNAME_MACHINE}-sni-sysv4 +- else +- echo ns32k-sni-sysv +- fi +- exit ;; +- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort +- # says +- echo i586-unisys-sysv4 +- exit ;; +- *:UNIX_System_V:4*:FTX*) +- # From Gerald Hewes . +- # How about differentiating between stratus architectures? -djm +- echo hppa1.1-stratus-sysv4 +- exit ;; +- *:*:*:FTX*) +- # From seanf@swdc.stratus.com. +- echo i860-stratus-sysv4 +- exit ;; +- i*86:VOS:*:*) +- # From Paul.Green@stratus.com. +- echo ${UNAME_MACHINE}-stratus-vos +- exit ;; +- *:VOS:*:*) +- # From Paul.Green@stratus.com. +- echo hppa1.1-stratus-vos +- exit ;; +- mc68*:A/UX:*:*) +- echo m68k-apple-aux${UNAME_RELEASE} +- exit ;; +- news*:NEWS-OS:6*:*) +- echo mips-sony-newsos6 +- exit ;; +- R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) +- if [ -d /usr/nec ]; then +- echo mips-nec-sysv${UNAME_RELEASE} +- else +- echo mips-unknown-sysv${UNAME_RELEASE} +- fi +- exit ;; +- BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. +- echo powerpc-be-beos +- exit ;; +- BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. +- echo powerpc-apple-beos +- exit ;; +- BePC:BeOS:*:*) # BeOS running on Intel PC compatible. +- echo i586-pc-beos +- exit ;; +- SX-4:SUPER-UX:*:*) +- echo sx4-nec-superux${UNAME_RELEASE} +- exit ;; +- SX-5:SUPER-UX:*:*) +- echo sx5-nec-superux${UNAME_RELEASE} +- exit ;; +- SX-6:SUPER-UX:*:*) +- echo sx6-nec-superux${UNAME_RELEASE} +- exit ;; +- Power*:Rhapsody:*:*) +- echo powerpc-apple-rhapsody${UNAME_RELEASE} +- exit ;; +- *:Rhapsody:*:*) +- echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} +- exit ;; +- *:Darwin:*:*) +- UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown +- case $UNAME_PROCESSOR in +- *86) UNAME_PROCESSOR=i686 ;; +- unknown) UNAME_PROCESSOR=powerpc ;; +- esac +- echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} +- exit ;; +- *:procnto*:*:* | *:QNX:[0123456789]*:*) +- UNAME_PROCESSOR=`uname -p` +- if test "$UNAME_PROCESSOR" = "x86"; then +- UNAME_PROCESSOR=i386 +- UNAME_MACHINE=pc +- fi +- echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} +- exit ;; +- *:QNX:*:4*) +- echo i386-pc-qnx +- exit ;; +- NSE-?:NONSTOP_KERNEL:*:*) +- echo nse-tandem-nsk${UNAME_RELEASE} +- exit ;; +- NSR-?:NONSTOP_KERNEL:*:*) +- echo nsr-tandem-nsk${UNAME_RELEASE} +- exit ;; +- *:NonStop-UX:*:*) +- echo mips-compaq-nonstopux +- exit ;; +- BS2000:POSIX*:*:*) +- echo bs2000-siemens-sysv +- exit ;; +- DS/*:UNIX_System_V:*:*) +- echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} +- exit ;; +- *:Plan9:*:*) +- # "uname -m" is not consistent, so use $cputype instead. 386 +- # is converted to i386 for consistency with other x86 +- # operating systems. +- if test "$cputype" = "386"; then +- UNAME_MACHINE=i386 +- else +- UNAME_MACHINE="$cputype" +- fi +- echo ${UNAME_MACHINE}-unknown-plan9 +- exit ;; +- *:TOPS-10:*:*) +- echo pdp10-unknown-tops10 +- exit ;; +- *:TENEX:*:*) +- echo pdp10-unknown-tenex +- exit ;; +- KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) +- echo pdp10-dec-tops20 +- exit ;; +- XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) +- echo pdp10-xkl-tops20 +- exit ;; +- *:TOPS-20:*:*) +- echo pdp10-unknown-tops20 +- exit ;; +- *:ITS:*:*) +- echo pdp10-unknown-its +- exit ;; +- SEI:*:*:SEIUX) +- echo mips-sei-seiux${UNAME_RELEASE} +- exit ;; +- *:DragonFly:*:*) +- echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` +- exit ;; +- *:*VMS:*:*) +- UNAME_MACHINE=`(uname -p) 2>/dev/null` +- case "${UNAME_MACHINE}" in +- A*) echo alpha-dec-vms ; exit ;; +- I*) echo ia64-dec-vms ; exit ;; +- V*) echo vax-dec-vms ; exit ;; +- esac ;; +- *:XENIX:*:SysV) +- echo i386-pc-xenix +- exit ;; +- i*86:skyos:*:*) +- echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' +- exit ;; +-esac +- +-#echo '(No uname command or uname output not recognized.)' 1>&2 +-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 +- +-eval $set_cc_for_build +-cat >$dummy.c < +-# include +-#endif +-main () +-{ +-#if defined (sony) +-#if defined (MIPSEB) +- /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, +- I don't know.... */ +- printf ("mips-sony-bsd\n"); exit (0); +-#else +-#include +- printf ("m68k-sony-newsos%s\n", +-#ifdef NEWSOS4 +- "4" +-#else +- "" +-#endif +- ); exit (0); +-#endif +-#endif +- +-#if defined (__arm) && defined (__acorn) && defined (__unix) +- printf ("arm-acorn-riscix\n"); exit (0); +-#endif +- +-#if defined (hp300) && !defined (hpux) +- printf ("m68k-hp-bsd\n"); exit (0); +-#endif +- +-#if defined (NeXT) +-#if !defined (__ARCHITECTURE__) +-#define __ARCHITECTURE__ "m68k" +-#endif +- int version; +- version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; +- if (version < 4) +- printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); +- else +- printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); +- exit (0); +-#endif +- +-#if defined (MULTIMAX) || defined (n16) +-#if defined (UMAXV) +- printf ("ns32k-encore-sysv\n"); exit (0); +-#else +-#if defined (CMU) +- printf ("ns32k-encore-mach\n"); exit (0); +-#else +- printf ("ns32k-encore-bsd\n"); exit (0); +-#endif +-#endif +-#endif +- +-#if defined (__386BSD__) +- printf ("i386-pc-bsd\n"); exit (0); +-#endif +- +-#if defined (sequent) +-#if defined (i386) +- printf ("i386-sequent-dynix\n"); exit (0); +-#endif +-#if defined (ns32000) +- printf ("ns32k-sequent-dynix\n"); exit (0); +-#endif +-#endif +- +-#if defined (_SEQUENT_) +- struct utsname un; +- +- uname(&un); +- +- if (strncmp(un.version, "V2", 2) == 0) { +- printf ("i386-sequent-ptx2\n"); exit (0); +- } +- if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ +- printf ("i386-sequent-ptx1\n"); exit (0); +- } +- printf ("i386-sequent-ptx\n"); exit (0); +- +-#endif +- +-#if defined (vax) +-# if !defined (ultrix) +-# include +-# if defined (BSD) +-# if BSD == 43 +- printf ("vax-dec-bsd4.3\n"); exit (0); +-# else +-# if BSD == 199006 +- printf ("vax-dec-bsd4.3reno\n"); exit (0); +-# else +- printf ("vax-dec-bsd\n"); exit (0); +-# endif +-# endif +-# else +- printf ("vax-dec-bsd\n"); exit (0); +-# endif +-# else +- printf ("vax-dec-ultrix\n"); exit (0); +-# endif +-#endif +- +-#if defined (alliant) && defined (i860) +- printf ("i860-alliant-bsd\n"); exit (0); +-#endif +- +- exit (1); +-} +-EOF +- +-$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && +- { echo "$SYSTEM_NAME"; exit; } +- +-# Apollos put the system type in the environment. +- +-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } +- +-# Convex versions that predate uname can use getsysinfo(1) +- +-if [ -x /usr/convex/getsysinfo ] +-then +- case `getsysinfo -f cpu_type` in +- c1*) +- echo c1-convex-bsd +- exit ;; +- c2*) +- if getsysinfo -f scalar_acc +- then echo c32-convex-bsd +- else echo c2-convex-bsd +- fi +- exit ;; +- c34*) +- echo c34-convex-bsd +- exit ;; +- c38*) +- echo c38-convex-bsd +- exit ;; +- c4*) +- echo c4-convex-bsd +- exit ;; +- esac +-fi +- +-cat >&2 < in order to provide the needed +-information to handle your system. +- +-config.guess timestamp = $timestamp +- +-uname -m = `(uname -m) 2>/dev/null || echo unknown` +-uname -r = `(uname -r) 2>/dev/null || echo unknown` +-uname -s = `(uname -s) 2>/dev/null || echo unknown` +-uname -v = `(uname -v) 2>/dev/null || echo unknown` +- +-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +-/bin/uname -X = `(/bin/uname -X) 2>/dev/null` +- +-hostinfo = `(hostinfo) 2>/dev/null` +-/bin/universe = `(/bin/universe) 2>/dev/null` +-/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +-/bin/arch = `(/bin/arch) 2>/dev/null` +-/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` +- +-UNAME_MACHINE = ${UNAME_MACHINE} +-UNAME_RELEASE = ${UNAME_RELEASE} +-UNAME_SYSTEM = ${UNAME_SYSTEM} +-UNAME_VERSION = ${UNAME_VERSION} +-EOF +- +-exit 1 +- +-# Local variables: +-# eval: (add-hook 'write-file-hooks 'time-stamp) +-# time-stamp-start: "timestamp='" +-# time-stamp-format: "%:y-%02m-%02d" +-# time-stamp-end: "'" +-# End: +diff --git a/utils/open-isns/aclocal/config.sub b/utils/open-isns/aclocal/config.sub +deleted file mode 100644 +index 519f2cd..0000000 +--- a/utils/open-isns/aclocal/config.sub ++++ /dev/null +@@ -1,1570 +0,0 @@ +-#! /bin/sh +-# Configuration validation subroutine script. +-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +-# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. +- +-timestamp='2005-05-12' +- +-# This file is (in principle) common to ALL GNU software. +-# The presence of a machine in this file suggests that SOME GNU software +-# can handle that machine. It does not imply ALL GNU software can. +-# +-# This file is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +-# 02110-1301, USA. +-# +-# As a special exception to the GNU General Public License, if you +-# distribute this file as part of a program that contains a +-# configuration script generated by Autoconf, you may include it under +-# the same distribution terms that you use for the rest of that program. +- +- +-# Please send patches to . Submit a context +-# diff and a properly formatted ChangeLog entry. +-# +-# Configuration subroutine to validate and canonicalize a configuration type. +-# Supply the specified configuration type as an argument. +-# If it is invalid, we print an error message on stderr and exit with code 1. +-# Otherwise, we print the canonical config type on stdout and succeed. +- +-# This file is supposed to be the same for all GNU packages +-# and recognize all the CPU types, system types and aliases +-# that are meaningful with *any* GNU software. +-# Each package is responsible for reporting which valid configurations +-# it does not support. The user should be able to distinguish +-# a failure to support a valid configuration from a meaningless +-# configuration. +- +-# The goal of this file is to map all the various variations of a given +-# machine specification into a single specification in the form: +-# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +-# or in some cases, the newer four-part form: +-# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +-# It is wrong to echo any other type of specification. +- +-me=`echo "$0" | sed -e 's,.*/,,'` +- +-usage="\ +-Usage: $0 [OPTION] CPU-MFR-OPSYS +- $0 [OPTION] ALIAS +- +-Canonicalize a configuration name. +- +-Operation modes: +- -h, --help print this help, then exit +- -t, --time-stamp print date of last modification, then exit +- -v, --version print version number, then exit +- +-Report bugs and patches to ." +- +-version="\ +-GNU config.sub ($timestamp) +- +-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +-Free Software Foundation, Inc. +- +-This is free software; see the source for copying conditions. There is NO +-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." +- +-help=" +-Try \`$me --help' for more information." +- +-# Parse command line +-while test $# -gt 0 ; do +- case $1 in +- --time-stamp | --time* | -t ) +- echo "$timestamp" ; exit ;; +- --version | -v ) +- echo "$version" ; exit ;; +- --help | --h* | -h ) +- echo "$usage"; exit ;; +- -- ) # Stop option processing +- shift; break ;; +- - ) # Use stdin as input. +- break ;; +- -* ) +- echo "$me: invalid option $1$help" +- exit 1 ;; +- +- *local*) +- # First pass through any local machine types. +- echo $1 +- exit ;; +- +- * ) +- break ;; +- esac +-done +- +-case $# in +- 0) echo "$me: missing argument$help" >&2 +- exit 1;; +- 1) ;; +- *) echo "$me: too many arguments$help" >&2 +- exit 1;; +-esac +- +-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +-# Here we must recognize all the valid KERNEL-OS combinations. +-maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +-case $maybe_os in +- nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ +- kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) +- os=-$maybe_os +- basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` +- ;; +- *) +- basic_machine=`echo $1 | sed 's/-[^-]*$//'` +- if [ $basic_machine != $1 ] +- then os=`echo $1 | sed 's/.*-/-/'` +- else os=; fi +- ;; +-esac +- +-### Let's recognize common machines as not being operating systems so +-### that things like config.sub decstation-3100 work. We also +-### recognize some manufacturers as not being operating systems, so we +-### can provide default operating systems below. +-case $os in +- -sun*os*) +- # Prevent following clause from handling this invalid input. +- ;; +- -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ +- -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ +- -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ +- -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ +- -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ +- -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ +- -apple | -axis | -knuth | -cray) +- os= +- basic_machine=$1 +- ;; +- -sim | -cisco | -oki | -wec | -winbond) +- os= +- basic_machine=$1 +- ;; +- -scout) +- ;; +- -wrs) +- os=-vxworks +- basic_machine=$1 +- ;; +- -chorusos*) +- os=-chorusos +- basic_machine=$1 +- ;; +- -chorusrdb) +- os=-chorusrdb +- basic_machine=$1 +- ;; +- -hiux*) +- os=-hiuxwe2 +- ;; +- -sco5) +- os=-sco3.2v5 +- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` +- ;; +- -sco4) +- os=-sco3.2v4 +- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` +- ;; +- -sco3.2.[4-9]*) +- os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` +- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` +- ;; +- -sco3.2v[4-9]*) +- # Don't forget version if it is 3.2v4 or newer. +- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` +- ;; +- -sco*) +- os=-sco3.2v2 +- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` +- ;; +- -udk*) +- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` +- ;; +- -isc) +- os=-isc2.2 +- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` +- ;; +- -clix*) +- basic_machine=clipper-intergraph +- ;; +- -isc*) +- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` +- ;; +- -lynx*) +- os=-lynxos +- ;; +- -ptx*) +- basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` +- ;; +- -windowsnt*) +- os=`echo $os | sed -e 's/windowsnt/winnt/'` +- ;; +- -psos*) +- os=-psos +- ;; +- -mint | -mint[0-9]*) +- basic_machine=m68k-atari +- os=-mint +- ;; +-esac +- +-# Decode aliases for certain CPU-COMPANY combinations. +-case $basic_machine in +- # Recognize the basic CPU types without company name. +- # Some are omitted here because they have special meanings below. +- 1750a | 580 \ +- | a29k \ +- | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ +- | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ +- | am33_2.0 \ +- | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ +- | bfin \ +- | c4x | clipper \ +- | d10v | d30v | dlx | dsp16xx \ +- | fr30 | frv \ +- | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ +- | i370 | i860 | i960 | ia64 \ +- | ip2k | iq2000 \ +- | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ +- | mips | mipsbe | mipseb | mipsel | mipsle \ +- | mips16 \ +- | mips64 | mips64el \ +- | mips64vr | mips64vrel \ +- | mips64orion | mips64orionel \ +- | mips64vr4100 | mips64vr4100el \ +- | mips64vr4300 | mips64vr4300el \ +- | mips64vr5000 | mips64vr5000el \ +- | mipsisa32 | mipsisa32el \ +- | mipsisa32r2 | mipsisa32r2el \ +- | mipsisa64 | mipsisa64el \ +- | mipsisa64r2 | mipsisa64r2el \ +- | mipsisa64sb1 | mipsisa64sb1el \ +- | mipsisa64sr71k | mipsisa64sr71kel \ +- | mipstx39 | mipstx39el \ +- | mn10200 | mn10300 \ +- | msp430 \ +- | ns16k | ns32k \ +- | openrisc | or32 \ +- | pdp10 | pdp11 | pj | pjl \ +- | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ +- | pyramid \ +- | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ +- | sh64 | sh64le \ +- | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ +- | sparcv8 | sparcv9 | sparcv9b \ +- | strongarm \ +- | tahoe | thumb | tic4x | tic80 | tron \ +- | v850 | v850e \ +- | we32k \ +- | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ +- | z8k) +- basic_machine=$basic_machine-unknown +- ;; +- m6811 | m68hc11 | m6812 | m68hc12) +- # Motorola 68HC11/12. +- basic_machine=$basic_machine-unknown +- os=-none +- ;; +- m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) +- ;; +- +- # We use `pc' rather than `unknown' +- # because (1) that's what they normally are, and +- # (2) the word "unknown" tends to confuse beginning users. +- i*86 | x86_64) +- basic_machine=$basic_machine-pc +- ;; +- # Object if more than one company name word. +- *-*-*) +- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 +- exit 1 +- ;; +- # Recognize the basic CPU types with company name. +- 580-* \ +- | a29k-* \ +- | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ +- | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ +- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ +- | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ +- | avr-* \ +- | bfin-* | bs2000-* \ +- | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ +- | clipper-* | craynv-* | cydra-* \ +- | d10v-* | d30v-* | dlx-* \ +- | elxsi-* \ +- | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ +- | h8300-* | h8500-* \ +- | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ +- | i*86-* | i860-* | i960-* | ia64-* \ +- | ip2k-* | iq2000-* \ +- | m32r-* | m32rle-* \ +- | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ +- | m88110-* | m88k-* | maxq-* | mcore-* \ +- | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ +- | mips16-* \ +- | mips64-* | mips64el-* \ +- | mips64vr-* | mips64vrel-* \ +- | mips64orion-* | mips64orionel-* \ +- | mips64vr4100-* | mips64vr4100el-* \ +- | mips64vr4300-* | mips64vr4300el-* \ +- | mips64vr5000-* | mips64vr5000el-* \ +- | mipsisa32-* | mipsisa32el-* \ +- | mipsisa32r2-* | mipsisa32r2el-* \ +- | mipsisa64-* | mipsisa64el-* \ +- | mipsisa64r2-* | mipsisa64r2el-* \ +- | mipsisa64sb1-* | mipsisa64sb1el-* \ +- | mipsisa64sr71k-* | mipsisa64sr71kel-* \ +- | mipstx39-* | mipstx39el-* \ +- | mmix-* \ +- | msp430-* \ +- | none-* | np1-* | ns16k-* | ns32k-* \ +- | orion-* \ +- | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ +- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ +- | pyramid-* \ +- | romp-* | rs6000-* \ +- | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ +- | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ +- | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ +- | sparclite-* \ +- | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ +- | tahoe-* | thumb-* \ +- | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ +- | tron-* \ +- | v850-* | v850e-* | vax-* \ +- | we32k-* \ +- | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ +- | xstormy16-* | xtensa-* \ +- | ymp-* \ +- | z8k-*) +- ;; +- # Recognize the various machine names and aliases which stand +- # for a CPU type and a company and sometimes even an OS. +- 386bsd) +- basic_machine=i386-unknown +- os=-bsd +- ;; +- 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) +- basic_machine=m68000-att +- ;; +- 3b*) +- basic_machine=we32k-att +- ;; +- a29khif) +- basic_machine=a29k-amd +- os=-udi +- ;; +- abacus) +- basic_machine=abacus-unknown +- ;; +- adobe68k) +- basic_machine=m68010-adobe +- os=-scout +- ;; +- alliant | fx80) +- basic_machine=fx80-alliant +- ;; +- altos | altos3068) +- basic_machine=m68k-altos +- ;; +- am29k) +- basic_machine=a29k-none +- os=-bsd +- ;; +- amd64) +- basic_machine=x86_64-pc +- ;; +- amd64-*) +- basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` +- ;; +- amdahl) +- basic_machine=580-amdahl +- os=-sysv +- ;; +- amiga | amiga-*) +- basic_machine=m68k-unknown +- ;; +- amigaos | amigados) +- basic_machine=m68k-unknown +- os=-amigaos +- ;; +- amigaunix | amix) +- basic_machine=m68k-unknown +- os=-sysv4 +- ;; +- apollo68) +- basic_machine=m68k-apollo +- os=-sysv +- ;; +- apollo68bsd) +- basic_machine=m68k-apollo +- os=-bsd +- ;; +- aux) +- basic_machine=m68k-apple +- os=-aux +- ;; +- balance) +- basic_machine=ns32k-sequent +- os=-dynix +- ;; +- c90) +- basic_machine=c90-cray +- os=-unicos +- ;; +- convex-c1) +- basic_machine=c1-convex +- os=-bsd +- ;; +- convex-c2) +- basic_machine=c2-convex +- os=-bsd +- ;; +- convex-c32) +- basic_machine=c32-convex +- os=-bsd +- ;; +- convex-c34) +- basic_machine=c34-convex +- os=-bsd +- ;; +- convex-c38) +- basic_machine=c38-convex +- os=-bsd +- ;; +- cray | j90) +- basic_machine=j90-cray +- os=-unicos +- ;; +- craynv) +- basic_machine=craynv-cray +- os=-unicosmp +- ;; +- cr16c) +- basic_machine=cr16c-unknown +- os=-elf +- ;; +- crds | unos) +- basic_machine=m68k-crds +- ;; +- crisv32 | crisv32-* | etraxfs*) +- basic_machine=crisv32-axis +- ;; +- cris | cris-* | etrax*) +- basic_machine=cris-axis +- ;; +- crx) +- basic_machine=crx-unknown +- os=-elf +- ;; +- da30 | da30-*) +- basic_machine=m68k-da30 +- ;; +- decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) +- basic_machine=mips-dec +- ;; +- decsystem10* | dec10*) +- basic_machine=pdp10-dec +- os=-tops10 +- ;; +- decsystem20* | dec20*) +- basic_machine=pdp10-dec +- os=-tops20 +- ;; +- delta | 3300 | motorola-3300 | motorola-delta \ +- | 3300-motorola | delta-motorola) +- basic_machine=m68k-motorola +- ;; +- delta88) +- basic_machine=m88k-motorola +- os=-sysv3 +- ;; +- djgpp) +- basic_machine=i586-pc +- os=-msdosdjgpp +- ;; +- dpx20 | dpx20-*) +- basic_machine=rs6000-bull +- os=-bosx +- ;; +- dpx2* | dpx2*-bull) +- basic_machine=m68k-bull +- os=-sysv3 +- ;; +- ebmon29k) +- basic_machine=a29k-amd +- os=-ebmon +- ;; +- elxsi) +- basic_machine=elxsi-elxsi +- os=-bsd +- ;; +- encore | umax | mmax) +- basic_machine=ns32k-encore +- ;; +- es1800 | OSE68k | ose68k | ose | OSE) +- basic_machine=m68k-ericsson +- os=-ose +- ;; +- fx2800) +- basic_machine=i860-alliant +- ;; +- genix) +- basic_machine=ns32k-ns +- ;; +- gmicro) +- basic_machine=tron-gmicro +- os=-sysv +- ;; +- go32) +- basic_machine=i386-pc +- os=-go32 +- ;; +- h3050r* | hiux*) +- basic_machine=hppa1.1-hitachi +- os=-hiuxwe2 +- ;; +- h8300hms) +- basic_machine=h8300-hitachi +- os=-hms +- ;; +- h8300xray) +- basic_machine=h8300-hitachi +- os=-xray +- ;; +- h8500hms) +- basic_machine=h8500-hitachi +- os=-hms +- ;; +- harris) +- basic_machine=m88k-harris +- os=-sysv3 +- ;; +- hp300-*) +- basic_machine=m68k-hp +- ;; +- hp300bsd) +- basic_machine=m68k-hp +- os=-bsd +- ;; +- hp300hpux) +- basic_machine=m68k-hp +- os=-hpux +- ;; +- hp3k9[0-9][0-9] | hp9[0-9][0-9]) +- basic_machine=hppa1.0-hp +- ;; +- hp9k2[0-9][0-9] | hp9k31[0-9]) +- basic_machine=m68000-hp +- ;; +- hp9k3[2-9][0-9]) +- basic_machine=m68k-hp +- ;; +- hp9k6[0-9][0-9] | hp6[0-9][0-9]) +- basic_machine=hppa1.0-hp +- ;; +- hp9k7[0-79][0-9] | hp7[0-79][0-9]) +- basic_machine=hppa1.1-hp +- ;; +- hp9k78[0-9] | hp78[0-9]) +- # FIXME: really hppa2.0-hp +- basic_machine=hppa1.1-hp +- ;; +- hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) +- # FIXME: really hppa2.0-hp +- basic_machine=hppa1.1-hp +- ;; +- hp9k8[0-9][13679] | hp8[0-9][13679]) +- basic_machine=hppa1.1-hp +- ;; +- hp9k8[0-9][0-9] | hp8[0-9][0-9]) +- basic_machine=hppa1.0-hp +- ;; +- hppa-next) +- os=-nextstep3 +- ;; +- hppaosf) +- basic_machine=hppa1.1-hp +- os=-osf +- ;; +- hppro) +- basic_machine=hppa1.1-hp +- os=-proelf +- ;; +- i370-ibm* | ibm*) +- basic_machine=i370-ibm +- ;; +-# I'm not sure what "Sysv32" means. Should this be sysv3.2? +- i*86v32) +- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` +- os=-sysv32 +- ;; +- i*86v4*) +- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` +- os=-sysv4 +- ;; +- i*86v) +- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` +- os=-sysv +- ;; +- i*86sol2) +- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` +- os=-solaris2 +- ;; +- i386mach) +- basic_machine=i386-mach +- os=-mach +- ;; +- i386-vsta | vsta) +- basic_machine=i386-unknown +- os=-vsta +- ;; +- iris | iris4d) +- basic_machine=mips-sgi +- case $os in +- -irix*) +- ;; +- *) +- os=-irix4 +- ;; +- esac +- ;; +- isi68 | isi) +- basic_machine=m68k-isi +- os=-sysv +- ;; +- m88k-omron*) +- basic_machine=m88k-omron +- ;; +- magnum | m3230) +- basic_machine=mips-mips +- os=-sysv +- ;; +- merlin) +- basic_machine=ns32k-utek +- os=-sysv +- ;; +- mingw32) +- basic_machine=i386-pc +- os=-mingw32 +- ;; +- miniframe) +- basic_machine=m68000-convergent +- ;; +- *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) +- basic_machine=m68k-atari +- os=-mint +- ;; +- mips3*-*) +- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` +- ;; +- mips3*) +- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown +- ;; +- monitor) +- basic_machine=m68k-rom68k +- os=-coff +- ;; +- morphos) +- basic_machine=powerpc-unknown +- os=-morphos +- ;; +- msdos) +- basic_machine=i386-pc +- os=-msdos +- ;; +- mvs) +- basic_machine=i370-ibm +- os=-mvs +- ;; +- ncr3000) +- basic_machine=i486-ncr +- os=-sysv4 +- ;; +- netbsd386) +- basic_machine=i386-unknown +- os=-netbsd +- ;; +- netwinder) +- basic_machine=armv4l-rebel +- os=-linux +- ;; +- news | news700 | news800 | news900) +- basic_machine=m68k-sony +- os=-newsos +- ;; +- news1000) +- basic_machine=m68030-sony +- os=-newsos +- ;; +- news-3600 | risc-news) +- basic_machine=mips-sony +- os=-newsos +- ;; +- necv70) +- basic_machine=v70-nec +- os=-sysv +- ;; +- next | m*-next ) +- basic_machine=m68k-next +- case $os in +- -nextstep* ) +- ;; +- -ns2*) +- os=-nextstep2 +- ;; +- *) +- os=-nextstep3 +- ;; +- esac +- ;; +- nh3000) +- basic_machine=m68k-harris +- os=-cxux +- ;; +- nh[45]000) +- basic_machine=m88k-harris +- os=-cxux +- ;; +- nindy960) +- basic_machine=i960-intel +- os=-nindy +- ;; +- mon960) +- basic_machine=i960-intel +- os=-mon960 +- ;; +- nonstopux) +- basic_machine=mips-compaq +- os=-nonstopux +- ;; +- np1) +- basic_machine=np1-gould +- ;; +- nsr-tandem) +- basic_machine=nsr-tandem +- ;; +- op50n-* | op60c-*) +- basic_machine=hppa1.1-oki +- os=-proelf +- ;; +- or32 | or32-*) +- basic_machine=or32-unknown +- os=-coff +- ;; +- os400) +- basic_machine=powerpc-ibm +- os=-os400 +- ;; +- OSE68000 | ose68000) +- basic_machine=m68000-ericsson +- os=-ose +- ;; +- os68k) +- basic_machine=m68k-none +- os=-os68k +- ;; +- pa-hitachi) +- basic_machine=hppa1.1-hitachi +- os=-hiuxwe2 +- ;; +- paragon) +- basic_machine=i860-intel +- os=-osf +- ;; +- pbd) +- basic_machine=sparc-tti +- ;; +- pbb) +- basic_machine=m68k-tti +- ;; +- pc532 | pc532-*) +- basic_machine=ns32k-pc532 +- ;; +- pentium | p5 | k5 | k6 | nexgen | viac3) +- basic_machine=i586-pc +- ;; +- pentiumpro | p6 | 6x86 | athlon | athlon_*) +- basic_machine=i686-pc +- ;; +- pentiumii | pentium2 | pentiumiii | pentium3) +- basic_machine=i686-pc +- ;; +- pentium4) +- basic_machine=i786-pc +- ;; +- pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) +- basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` +- ;; +- pentiumpro-* | p6-* | 6x86-* | athlon-*) +- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` +- ;; +- pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) +- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` +- ;; +- pentium4-*) +- basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` +- ;; +- pn) +- basic_machine=pn-gould +- ;; +- power) basic_machine=power-ibm +- ;; +- ppc) basic_machine=powerpc-unknown +- ;; +- ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` +- ;; +- ppcle | powerpclittle | ppc-le | powerpc-little) +- basic_machine=powerpcle-unknown +- ;; +- ppcle-* | powerpclittle-*) +- basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` +- ;; +- ppc64) basic_machine=powerpc64-unknown +- ;; +- ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` +- ;; +- ppc64le | powerpc64little | ppc64-le | powerpc64-little) +- basic_machine=powerpc64le-unknown +- ;; +- ppc64le-* | powerpc64little-*) +- basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` +- ;; +- ps2) +- basic_machine=i386-ibm +- ;; +- pw32) +- basic_machine=i586-unknown +- os=-pw32 +- ;; +- rom68k) +- basic_machine=m68k-rom68k +- os=-coff +- ;; +- rm[46]00) +- basic_machine=mips-siemens +- ;; +- rtpc | rtpc-*) +- basic_machine=romp-ibm +- ;; +- s390 | s390-*) +- basic_machine=s390-ibm +- ;; +- s390x | s390x-*) +- basic_machine=s390x-ibm +- ;; +- sa29200) +- basic_machine=a29k-amd +- os=-udi +- ;; +- sb1) +- basic_machine=mipsisa64sb1-unknown +- ;; +- sb1el) +- basic_machine=mipsisa64sb1el-unknown +- ;; +- sei) +- basic_machine=mips-sei +- os=-seiux +- ;; +- sequent) +- basic_machine=i386-sequent +- ;; +- sh) +- basic_machine=sh-hitachi +- os=-hms +- ;; +- sh64) +- basic_machine=sh64-unknown +- ;; +- sparclite-wrs | simso-wrs) +- basic_machine=sparclite-wrs +- os=-vxworks +- ;; +- sps7) +- basic_machine=m68k-bull +- os=-sysv2 +- ;; +- spur) +- basic_machine=spur-unknown +- ;; +- st2000) +- basic_machine=m68k-tandem +- ;; +- stratus) +- basic_machine=i860-stratus +- os=-sysv4 +- ;; +- sun2) +- basic_machine=m68000-sun +- ;; +- sun2os3) +- basic_machine=m68000-sun +- os=-sunos3 +- ;; +- sun2os4) +- basic_machine=m68000-sun +- os=-sunos4 +- ;; +- sun3os3) +- basic_machine=m68k-sun +- os=-sunos3 +- ;; +- sun3os4) +- basic_machine=m68k-sun +- os=-sunos4 +- ;; +- sun4os3) +- basic_machine=sparc-sun +- os=-sunos3 +- ;; +- sun4os4) +- basic_machine=sparc-sun +- os=-sunos4 +- ;; +- sun4sol2) +- basic_machine=sparc-sun +- os=-solaris2 +- ;; +- sun3 | sun3-*) +- basic_machine=m68k-sun +- ;; +- sun4) +- basic_machine=sparc-sun +- ;; +- sun386 | sun386i | roadrunner) +- basic_machine=i386-sun +- ;; +- sv1) +- basic_machine=sv1-cray +- os=-unicos +- ;; +- symmetry) +- basic_machine=i386-sequent +- os=-dynix +- ;; +- t3e) +- basic_machine=alphaev5-cray +- os=-unicos +- ;; +- t90) +- basic_machine=t90-cray +- os=-unicos +- ;; +- tic54x | c54x*) +- basic_machine=tic54x-unknown +- os=-coff +- ;; +- tic55x | c55x*) +- basic_machine=tic55x-unknown +- os=-coff +- ;; +- tic6x | c6x*) +- basic_machine=tic6x-unknown +- os=-coff +- ;; +- tx39) +- basic_machine=mipstx39-unknown +- ;; +- tx39el) +- basic_machine=mipstx39el-unknown +- ;; +- toad1) +- basic_machine=pdp10-xkl +- os=-tops20 +- ;; +- tower | tower-32) +- basic_machine=m68k-ncr +- ;; +- tpf) +- basic_machine=s390x-ibm +- os=-tpf +- ;; +- udi29k) +- basic_machine=a29k-amd +- os=-udi +- ;; +- ultra3) +- basic_machine=a29k-nyu +- os=-sym1 +- ;; +- v810 | necv810) +- basic_machine=v810-nec +- os=-none +- ;; +- vaxv) +- basic_machine=vax-dec +- os=-sysv +- ;; +- vms) +- basic_machine=vax-dec +- os=-vms +- ;; +- vpp*|vx|vx-*) +- basic_machine=f301-fujitsu +- ;; +- vxworks960) +- basic_machine=i960-wrs +- os=-vxworks +- ;; +- vxworks68) +- basic_machine=m68k-wrs +- os=-vxworks +- ;; +- vxworks29k) +- basic_machine=a29k-wrs +- os=-vxworks +- ;; +- w65*) +- basic_machine=w65-wdc +- os=-none +- ;; +- w89k-*) +- basic_machine=hppa1.1-winbond +- os=-proelf +- ;; +- xbox) +- basic_machine=i686-pc +- os=-mingw32 +- ;; +- xps | xps100) +- basic_machine=xps100-honeywell +- ;; +- ymp) +- basic_machine=ymp-cray +- os=-unicos +- ;; +- z8k-*-coff) +- basic_machine=z8k-unknown +- os=-sim +- ;; +- none) +- basic_machine=none-none +- os=-none +- ;; +- +-# Here we handle the default manufacturer of certain CPU types. It is in +-# some cases the only manufacturer, in others, it is the most popular. +- w89k) +- basic_machine=hppa1.1-winbond +- ;; +- op50n) +- basic_machine=hppa1.1-oki +- ;; +- op60c) +- basic_machine=hppa1.1-oki +- ;; +- romp) +- basic_machine=romp-ibm +- ;; +- mmix) +- basic_machine=mmix-knuth +- ;; +- rs6000) +- basic_machine=rs6000-ibm +- ;; +- vax) +- basic_machine=vax-dec +- ;; +- pdp10) +- # there are many clones, so DEC is not a safe bet +- basic_machine=pdp10-unknown +- ;; +- pdp11) +- basic_machine=pdp11-dec +- ;; +- we32k) +- basic_machine=we32k-att +- ;; +- sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) +- basic_machine=sh-unknown +- ;; +- sh64) +- basic_machine=sh64-unknown +- ;; +- sparc | sparcv8 | sparcv9 | sparcv9b) +- basic_machine=sparc-sun +- ;; +- cydra) +- basic_machine=cydra-cydrome +- ;; +- orion) +- basic_machine=orion-highlevel +- ;; +- orion105) +- basic_machine=clipper-highlevel +- ;; +- mac | mpw | mac-mpw) +- basic_machine=m68k-apple +- ;; +- pmac | pmac-mpw) +- basic_machine=powerpc-apple +- ;; +- *-unknown) +- # Make sure to match an already-canonicalized machine name. +- ;; +- *) +- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 +- exit 1 +- ;; +-esac +- +-# Here we canonicalize certain aliases for manufacturers. +-case $basic_machine in +- *-digital*) +- basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` +- ;; +- *-commodore*) +- basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` +- ;; +- *) +- ;; +-esac +- +-# Decode manufacturer-specific aliases for certain operating systems. +- +-if [ x"$os" != x"" ] +-then +-case $os in +- # First match some system type aliases +- # that might get confused with valid system types. +- # -solaris* is a basic system type, with this one exception. +- -solaris1 | -solaris1.*) +- os=`echo $os | sed -e 's|solaris1|sunos4|'` +- ;; +- -solaris) +- os=-solaris2 +- ;; +- -svr4*) +- os=-sysv4 +- ;; +- -unixware*) +- os=-sysv4.2uw +- ;; +- -gnu/linux*) +- os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` +- ;; +- # First accept the basic system types. +- # The portable systems comes first. +- # Each alternative MUST END IN A *, to match a version number. +- # -sysv* is not here because it comes later, after sysvr4. +- -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ +- | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ +- | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ +- | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ +- | -aos* \ +- | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ +- | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ +- | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ +- | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ +- | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ +- | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ +- | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ +- | -chorusos* | -chorusrdb* \ +- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ +- | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ +- | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ +- | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ +- | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ +- | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ +- | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ +- | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* | -skyos*) +- # Remember, each alternative MUST END IN *, to match a version number. +- ;; +- -qnx*) +- case $basic_machine in +- x86-* | i*86-*) +- ;; +- *) +- os=-nto$os +- ;; +- esac +- ;; +- -nto-qnx*) +- ;; +- -nto*) +- os=`echo $os | sed -e 's|nto|nto-qnx|'` +- ;; +- -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ +- | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ +- | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) +- ;; +- -mac*) +- os=`echo $os | sed -e 's|mac|macos|'` +- ;; +- -linux-dietlibc) +- os=-linux-dietlibc +- ;; +- -linux*) +- os=`echo $os | sed -e 's|linux|linux-gnu|'` +- ;; +- -sunos5*) +- os=`echo $os | sed -e 's|sunos5|solaris2|'` +- ;; +- -sunos6*) +- os=`echo $os | sed -e 's|sunos6|solaris3|'` +- ;; +- -opened*) +- os=-openedition +- ;; +- -os400*) +- os=-os400 +- ;; +- -wince*) +- os=-wince +- ;; +- -osfrose*) +- os=-osfrose +- ;; +- -osf*) +- os=-osf +- ;; +- -utek*) +- os=-bsd +- ;; +- -dynix*) +- os=-bsd +- ;; +- -acis*) +- os=-aos +- ;; +- -atheos*) +- os=-atheos +- ;; +- -syllable*) +- os=-syllable +- ;; +- -386bsd) +- os=-bsd +- ;; +- -ctix* | -uts*) +- os=-sysv +- ;; +- -nova*) +- os=-rtmk-nova +- ;; +- -ns2 ) +- os=-nextstep2 +- ;; +- -nsk*) +- os=-nsk +- ;; +- # Preserve the version number of sinix5. +- -sinix5.*) +- os=`echo $os | sed -e 's|sinix|sysv|'` +- ;; +- -sinix*) +- os=-sysv4 +- ;; +- -tpf*) +- os=-tpf +- ;; +- -triton*) +- os=-sysv3 +- ;; +- -oss*) +- os=-sysv3 +- ;; +- -svr4) +- os=-sysv4 +- ;; +- -svr3) +- os=-sysv3 +- ;; +- -sysvr4) +- os=-sysv4 +- ;; +- # This must come after -sysvr4. +- -sysv*) +- ;; +- -ose*) +- os=-ose +- ;; +- -es1800*) +- os=-ose +- ;; +- -xenix) +- os=-xenix +- ;; +- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) +- os=-mint +- ;; +- -aros*) +- os=-aros +- ;; +- -kaos*) +- os=-kaos +- ;; +- -zvmoe) +- os=-zvmoe +- ;; +- -none) +- ;; +- *) +- # Get rid of the `-' at the beginning of $os. +- os=`echo $os | sed 's/[^-]*-//'` +- echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 +- exit 1 +- ;; +-esac +-else +- +-# Here we handle the default operating systems that come with various machines. +-# The value should be what the vendor currently ships out the door with their +-# machine or put another way, the most popular os provided with the machine. +- +-# Note that if you're going to try to match "-MANUFACTURER" here (say, +-# "-sun"), then you have to tell the case statement up towards the top +-# that MANUFACTURER isn't an operating system. Otherwise, code above +-# will signal an error saying that MANUFACTURER isn't an operating +-# system, and we'll never get to this point. +- +-case $basic_machine in +- *-acorn) +- os=-riscix1.2 +- ;; +- arm*-rebel) +- os=-linux +- ;; +- arm*-semi) +- os=-aout +- ;; +- c4x-* | tic4x-*) +- os=-coff +- ;; +- # This must come before the *-dec entry. +- pdp10-*) +- os=-tops20 +- ;; +- pdp11-*) +- os=-none +- ;; +- *-dec | vax-*) +- os=-ultrix4.2 +- ;; +- m68*-apollo) +- os=-domain +- ;; +- i386-sun) +- os=-sunos4.0.2 +- ;; +- m68000-sun) +- os=-sunos3 +- # This also exists in the configure program, but was not the +- # default. +- # os=-sunos4 +- ;; +- m68*-cisco) +- os=-aout +- ;; +- mips*-cisco) +- os=-elf +- ;; +- mips*-*) +- os=-elf +- ;; +- or32-*) +- os=-coff +- ;; +- *-tti) # must be before sparc entry or we get the wrong os. +- os=-sysv3 +- ;; +- sparc-* | *-sun) +- os=-sunos4.1.1 +- ;; +- *-be) +- os=-beos +- ;; +- *-ibm) +- os=-aix +- ;; +- *-knuth) +- os=-mmixware +- ;; +- *-wec) +- os=-proelf +- ;; +- *-winbond) +- os=-proelf +- ;; +- *-oki) +- os=-proelf +- ;; +- *-hp) +- os=-hpux +- ;; +- *-hitachi) +- os=-hiux +- ;; +- i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) +- os=-sysv +- ;; +- *-cbm) +- os=-amigaos +- ;; +- *-dg) +- os=-dgux +- ;; +- *-dolphin) +- os=-sysv3 +- ;; +- m68k-ccur) +- os=-rtu +- ;; +- m88k-omron*) +- os=-luna +- ;; +- *-next ) +- os=-nextstep +- ;; +- *-sequent) +- os=-ptx +- ;; +- *-crds) +- os=-unos +- ;; +- *-ns) +- os=-genix +- ;; +- i370-*) +- os=-mvs +- ;; +- *-next) +- os=-nextstep3 +- ;; +- *-gould) +- os=-sysv +- ;; +- *-highlevel) +- os=-bsd +- ;; +- *-encore) +- os=-bsd +- ;; +- *-sgi) +- os=-irix +- ;; +- *-siemens) +- os=-sysv4 +- ;; +- *-masscomp) +- os=-rtu +- ;; +- f30[01]-fujitsu | f700-fujitsu) +- os=-uxpv +- ;; +- *-rom68k) +- os=-coff +- ;; +- *-*bug) +- os=-coff +- ;; +- *-apple) +- os=-macos +- ;; +- *-atari*) +- os=-mint +- ;; +- *) +- os=-none +- ;; +-esac +-fi +- +-# Here we handle the case where we know the os, and the CPU type, but not the +-# manufacturer. We pick the logical manufacturer. +-vendor=unknown +-case $basic_machine in +- *-unknown) +- case $os in +- -riscix*) +- vendor=acorn +- ;; +- -sunos*) +- vendor=sun +- ;; +- -aix*) +- vendor=ibm +- ;; +- -beos*) +- vendor=be +- ;; +- -hpux*) +- vendor=hp +- ;; +- -mpeix*) +- vendor=hp +- ;; +- -hiux*) +- vendor=hitachi +- ;; +- -unos*) +- vendor=crds +- ;; +- -dgux*) +- vendor=dg +- ;; +- -luna*) +- vendor=omron +- ;; +- -genix*) +- vendor=ns +- ;; +- -mvs* | -opened*) +- vendor=ibm +- ;; +- -os400*) +- vendor=ibm +- ;; +- -ptx*) +- vendor=sequent +- ;; +- -tpf*) +- vendor=ibm +- ;; +- -vxsim* | -vxworks* | -windiss*) +- vendor=wrs +- ;; +- -aux*) +- vendor=apple +- ;; +- -hms*) +- vendor=hitachi +- ;; +- -mpw* | -macos*) +- vendor=apple +- ;; +- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) +- vendor=atari +- ;; +- -vos*) +- vendor=stratus +- ;; +- esac +- basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` +- ;; +-esac +- +-echo $basic_machine$os +-exit +- +-# Local variables: +-# eval: (add-hook 'write-file-hooks 'time-stamp) +-# time-stamp-start: "timestamp='" +-# time-stamp-format: "%:y-%02m-%02d" +-# time-stamp-end: "'" +-# End: +diff --git a/utils/open-isns/aclocal/install-sh b/utils/open-isns/aclocal/install-sh +deleted file mode 100644 +index 220abbf..0000000 +--- a/utils/open-isns/aclocal/install-sh ++++ /dev/null +@@ -1,251 +0,0 @@ +-#!/bin/sh +-# +-# install - install a program, script, or datafile +-# This comes from X11R5 (mit/util/scripts/install.sh). +-# +-# Copyright 1991 by the Massachusetts Institute of Technology +-# +-# Permission to use, copy, modify, distribute, and sell this software and its +-# documentation for any purpose is hereby granted without fee, provided that +-# the above copyright notice appear in all copies and that both that +-# copyright notice and this permission notice appear in supporting +-# documentation, and that the name of M.I.T. not be used in advertising or +-# publicity pertaining to distribution of the software without specific, +-# written prior permission. M.I.T. makes no representations about the +-# suitability of this software for any purpose. It is provided "as is" +-# without express or implied warranty. +-# +-# Calling this script install-sh is preferred over install.sh, to prevent +-# `make' implicit rules from creating a file called install from it +-# when there is no Makefile. +-# +-# This script is compatible with the BSD install script, but was written +-# from scratch. It can only install one file at a time, a restriction +-# shared with many OS's install programs. +- +- +-# set DOITPROG to echo to test this script +- +-# Don't use :- since 4.3BSD and earlier shells don't like it. +-doit="${DOITPROG-}" +- +- +-# put in absolute paths if you don't have them in your path; or use env. vars. +- +-mvprog="${MVPROG-mv}" +-cpprog="${CPPROG-cp}" +-chmodprog="${CHMODPROG-chmod}" +-chownprog="${CHOWNPROG-chown}" +-chgrpprog="${CHGRPPROG-chgrp}" +-stripprog="${STRIPPROG-strip}" +-rmprog="${RMPROG-rm}" +-mkdirprog="${MKDIRPROG-mkdir}" +- +-transformbasename="" +-transform_arg="" +-instcmd="$mvprog" +-chmodcmd="$chmodprog 0755" +-chowncmd="" +-chgrpcmd="" +-stripcmd="" +-rmcmd="$rmprog -f" +-mvcmd="$mvprog" +-src="" +-dst="" +-dir_arg="" +- +-while [ x"$1" != x ]; do +- case $1 in +- -c) instcmd="$cpprog" +- shift +- continue;; +- +- -d) dir_arg=true +- shift +- continue;; +- +- -m) chmodcmd="$chmodprog $2" +- shift +- shift +- continue;; +- +- -o) chowncmd="$chownprog $2" +- shift +- shift +- continue;; +- +- -g) chgrpcmd="$chgrpprog $2" +- shift +- shift +- continue;; +- +- -s) stripcmd="$stripprog" +- shift +- continue;; +- +- -t=*) transformarg=`echo $1 | sed 's/-t=//'` +- shift +- continue;; +- +- -b=*) transformbasename=`echo $1 | sed 's/-b=//'` +- shift +- continue;; +- +- *) if [ x"$src" = x ] +- then +- src=$1 +- else +- # this colon is to work around a 386BSD /bin/sh bug +- : +- dst=$1 +- fi +- shift +- continue;; +- esac +-done +- +-if [ x"$src" = x ] +-then +- echo "install: no input file specified" +- exit 1 +-else +- true +-fi +- +-if [ x"$dir_arg" != x ]; then +- dst=$src +- src="" +- +- if [ -d $dst ]; then +- instcmd=: +- chmodcmd="" +- else +- instcmd=mkdir +- fi +-else +- +-# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +-# might cause directories to be created, which would be especially bad +-# if $src (and thus $dsttmp) contains '*'. +- +- if [ -f $src -o -d $src ] +- then +- true +- else +- echo "install: $src does not exist" +- exit 1 +- fi +- +- if [ x"$dst" = x ] +- then +- echo "install: no destination specified" +- exit 1 +- else +- true +- fi +- +-# If destination is a directory, append the input filename; if your system +-# does not like double slashes in filenames, you may need to add some logic +- +- if [ -d $dst ] +- then +- dst="$dst"/`basename $src` +- else +- true +- fi +-fi +- +-## this sed command emulates the dirname command +-dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` +- +-# Make sure that the destination directory exists. +-# this part is taken from Noah Friedman's mkinstalldirs script +- +-# Skip lots of stat calls in the usual case. +-if [ ! -d "$dstdir" ]; then +-defaultIFS=' +-' +-IFS="${IFS-${defaultIFS}}" +- +-oIFS="${IFS}" +-# Some sh's can't handle IFS=/ for some reason. +-IFS='%' +-set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +-IFS="${oIFS}" +- +-pathcomp='' +- +-while [ $# -ne 0 ] ; do +- pathcomp="${pathcomp}${1}" +- shift +- +- if [ ! -d "${pathcomp}" ] ; +- then +- $mkdirprog "${pathcomp}" +- else +- true +- fi +- +- pathcomp="${pathcomp}/" +-done +-fi +- +-if [ x"$dir_arg" != x ] +-then +- $doit $instcmd $dst && +- +- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && +- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && +- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && +- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +-else +- +-# If we're going to rename the final executable, determine the name now. +- +- if [ x"$transformarg" = x ] +- then +- dstfile=`basename $dst` +- else +- dstfile=`basename $dst $transformbasename | +- sed $transformarg`$transformbasename +- fi +- +-# don't allow the sed command to completely eliminate the filename +- +- if [ x"$dstfile" = x ] +- then +- dstfile=`basename $dst` +- else +- true +- fi +- +-# Make a temp file name in the proper directory. +- +- dsttmp=$dstdir/#inst.$$# +- +-# Move or copy the file name to the temp name +- +- $doit $instcmd $src $dsttmp && +- +- trap "rm -f ${dsttmp}" 0 && +- +-# and set any options; do chmod last to preserve setuid bits +- +-# If any of these fail, we abort the whole thing. If we want to +-# ignore errors from any of these, just make sure not to ignore +-# errors from the above "$doit $instcmd $src $dsttmp" command. +- +- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && +- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && +- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && +- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && +- +-# Now rename the file to the real destination. +- +- $doit $rmcmd -f $dstdir/$dstfile && +- $doit $mvcmd $dsttmp $dstdir/$dstfile +- +-fi && +- +- +-exit 0 +diff --git a/utils/open-isns/attrs.c b/utils/open-isns/attrs.c +deleted file mode 100644 +index 12517c1..0000000 +--- a/utils/open-isns/attrs.c ++++ /dev/null +@@ -1,1618 +0,0 @@ +-/* +- * Handle iSNS attributes and attribute lists +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include "util.h" +-#include "vendor.h" +-#include "attrs.h" +-#include "isns.h" +- +-/* Implementation limit - sanity checking */ +-#define ISNS_ATTR_MAX_LEN 8192 +- +-static void __isns_attr_set_value(isns_attr_t *, const isns_value_t *); +- +-/* +- * Allocate an attribute +- */ +-isns_attr_t * +-isns_attr_alloc(uint32_t tag, const isns_tag_type_t *tag_type, const isns_value_t *value) +-{ +- isns_attr_t *attr; +- +- if (tag_type == NULL) +- tag_type = isns_tag_type_by_id(tag); +- +- attr = isns_calloc(1, sizeof(*attr)); +- if (!attr) +- isns_fatal("Out of memory!\n"); +- +- attr->ia_users = 1; +- attr->ia_tag_id = tag; +- attr->ia_tag = tag_type; +- +- __isns_attr_set_value(attr, value); +- return attr; +-} +- +-isns_attr_t * +-isns_attr_get(isns_attr_t *attr) +-{ +- if (attr) { +- isns_assert(attr->ia_users); +- attr->ia_users++; +- } +- return attr; +-} +- +-void +-isns_attr_release(isns_attr_t *attr) +-{ +- const isns_attr_type_t *type; +- +- isns_assert(attr->ia_users); +- if (--(attr->ia_users)) +- return; +- +- type = attr->ia_value.iv_type; +- if (type->it_destroy) +- type->it_destroy(&attr->ia_value); +- isns_free(attr); +-} +- +-/* +- * Assign a value to an attribute +- */ +-void +-__isns_attr_set_value(isns_attr_t *attr, const isns_value_t *new_value) +-{ +- const isns_attr_type_t *type, *old_type; +- isns_value_t *old_value; +- +- old_value = &attr->ia_value; +- if (old_value == new_value) +- return; +- +- old_type = old_value->iv_type; +- if (old_type && old_type->it_destroy) +- old_type->it_destroy(old_value); +- +- if (!new_value || !(type = new_value->iv_type)) +- type = attr->ia_tag->it_type; +- +- /* When assigning the value to the attr, check +- * whether it needs special attention. */ +- if (new_value) { +- if (type->it_assign) { +- type->it_assign(&attr->ia_value, new_value); +- } else { +- attr->ia_value = *new_value; +- } +- } +- attr->ia_value.iv_type = type; +-} +- +-/* +- * Compare two attributes. +- * Returns non-null when attributes are the same, else 0. +- */ +-int +-isns_attr_match(const isns_attr_t *a, const isns_attr_t *b) +-{ +- const isns_attr_type_t *type; +- +- if (a->ia_tag_id != b->ia_tag_id) +- return 0; +- +- /* NIL acts as a wildcard */ +- if (a->ia_value.iv_type == &isns_attr_type_nil +- || b->ia_value.iv_type == &isns_attr_type_nil) +- return 1; +- +- if (a->ia_value.iv_type != b->ia_value.iv_type) +- return 0; +- type = a->ia_value.iv_type; +- +- if (type->it_match) +- return type->it_match(&a->ia_value, &b->ia_value); +- +- return !memcmp(&a->ia_value, &b->ia_value, sizeof(isns_value_t)); +-} +- +-/* +- * Lexicographical comparison of two attributes. +- * Returns -1 when a is less than b, +1 when a is greater than +- * b, and 0 if equal. +- */ +-int +-isns_attr_compare(const isns_attr_t *a, const isns_attr_t *b) +-{ +- const isns_attr_type_t *type = a->ia_value.iv_type; +- +- isns_assert(a->ia_tag_id == b->ia_tag_id); +- +- if (type != b->ia_value.iv_type) { +- /* One of them must be NIL */ +- if (type == &isns_attr_type_nil) +- return -1; +- return 1; +- } +- +- /* If both are NIL, consider them equal */ +- if (type == &isns_attr_type_nil) +- return 0; +- +- /* A few types need special comparison functions, but +- * most don't. The reason is, we don't care whether the +- * ordering this creates is the "canonical" ordering for +- * this type, eg for integers. All that matters is that +- * there is some consistent ordering suitable for +- * DevGetNext. +- */ +- if (type->it_compare) +- return type->it_compare(&a->ia_value, &b->ia_value); +- +- return memcmp(&a->ia_value, &b->ia_value, sizeof(isns_value_t)); +-} +- +-/* +- * Convert a string to an attribute +- */ +-isns_attr_t * +-isns_attr_from_string(uint32_t tag, const char *string) +-{ +- const isns_tag_type_t *tag_type; +- int (*parse)(isns_value_t *, const char *); +- isns_value_t value; +- +- memset(&value, 0, sizeof(value)); +- +- tag_type = isns_tag_type_by_id(tag); +- if (!tag_type) +- return NULL; +- +- parse = tag_type->it_parse; +- if (parse == NULL) +- parse = tag_type->it_type->it_parse; +- +- if (!parse || !parse(&value, string)) +- return NULL; +- +- return isns_attr_alloc(tag, tag_type, &value); +-} +- +-/* +- * Initialize an attribute list. +- */ +-void +-isns_attr_list_init(isns_attr_list_t *list) +-{ +- memset(list, 0, sizeof(*list)); +-} +- +-static inline void +-__isns_attr_list_resize(isns_attr_list_t *list, unsigned int count) +-{ +- unsigned int max; +- +- max = (list->ial_count + 15) & ~15; +- if (count < max) +- return; +- +- count = (count + 15) & ~15; +- list->ial_data = isns_realloc(list->ial_data, count * sizeof(isns_attr_t *)); +- if (!list->ial_data) +- isns_fatal("Out of memory!\n"); +-} +- +-void +-isns_attr_list_append_list(isns_attr_list_t *dst, +- const isns_attr_list_t *src) +-{ +- unsigned int i, j; +- +- __isns_attr_list_resize(dst, dst->ial_count + src->ial_count); +- j = dst->ial_count; +- for (i = 0; i < src->ial_count; ++i, ++j) { +- isns_attr_t *attr = src->ial_data[i]; +- +- dst->ial_data[j] = attr; +- attr->ia_users++; +- } +- dst->ial_count = j; +-} +- +-void +-isns_attr_list_copy(isns_attr_list_t *dst, +- const isns_attr_list_t *src) +-{ +- isns_attr_list_destroy(dst); +- isns_attr_list_append_list(dst, src); +-} +- +-void +-isns_attr_list_destroy(isns_attr_list_t *list) +-{ +- unsigned int i; +- +- for (i = 0; i < list->ial_count; ++i) { +- isns_attr_t *attr = list->ial_data[i]; +- +- isns_attr_release(attr); +- } +- +- if (list->ial_data) +- isns_free(list->ial_data); +- memset(list, 0, sizeof(*list)); +-} +- +-int +-isns_attr_list_remove_tag(isns_attr_list_t *list, uint32_t tag) +-{ +- unsigned int i = 0, j = 0, removed = 0; +- +- for (i = 0; i < list->ial_count; ++i) { +- isns_attr_t *attr = list->ial_data[i]; +- +- if (attr->ia_tag_id == tag) { +- isns_attr_release(attr); +- removed++; +- } else { +- list->ial_data[j++] = attr; +- } +- } +- list->ial_count = j; +- return removed; +-} +- +-/* +- * Locate the given attribute in the list, remove it +- * and any following attributes that have a tag from the +- * @subordinate_tags list. This is used by the DDDereg +- * code to remove DD members. +- */ +-int +-isns_attr_list_remove_member(isns_attr_list_t *list, +- const isns_attr_t *match, +- const uint32_t *subordinate_tags) +-{ +- unsigned int i = 0, j = 0, k, removed = 0, purging = 0; +- +- while (i < list->ial_count) { +- isns_attr_t *attr = list->ial_data[i++]; +- +- if (purging && subordinate_tags) { +- for (k = 0; subordinate_tags[k]; ++k) { +- if (attr->ia_tag_id == subordinate_tags[k]) +- goto purge_attr; +- } +- } +- purging = 0; +- +- if (!isns_attr_match(attr, match)) { +- list->ial_data[j++] = attr; +- continue; +- } +- +-purge_attr: +- isns_attr_release(attr); +- purging = 1; +- removed++; +- } +- list->ial_count = j; +- return removed; +-} +- +-/* +- * Find the first attribute with the given tag +- */ +-static inline isns_attr_t * +-__isns_attr_list_find(const isns_attr_list_t *list, uint32_t tag) +-{ +- isns_attr_t *attr; +- unsigned int i; +- +- for (i = 0; i < list->ial_count; ++i) { +- attr = list->ial_data[i]; +- +- if (attr->ia_tag_id == tag) +- return attr; +- } +- +- return NULL; +-} +- +-/* +- * Add a new attribute at the end of the list +- */ +-static inline void +-__isns_attr_list_append_attr(isns_attr_list_t *list, isns_attr_t *attr) +-{ +- __isns_attr_list_resize(list, list->ial_count + 1); +- list->ial_data[list->ial_count++] = attr; +-} +- +-void +-isns_attr_list_append_attr(isns_attr_list_t *list, isns_attr_t *attr) +-{ +- attr->ia_users++; +- __isns_attr_list_append_attr(list, attr); +-} +- +-/* +- * Append an element to an attribute list +- */ +-static void +-__isns_attr_list_append(isns_attr_list_t *list, +- uint32_t tag, const isns_tag_type_t *tag_type, +- const isns_value_t *value) +-{ +- isns_attr_t *attr; +- +- if (tag_type == NULL) +- tag_type = isns_tag_type_by_id(tag); +- if (value->iv_type != &isns_attr_type_nil +- && value->iv_type != tag_type->it_type) { +- isns_warning("Using wrong type (%s) " +- "when encoding attribute %04x (%s) - should be %s\n", +- value->iv_type->it_name, +- tag, tag_type->it_name, +- tag_type->it_type->it_name); +- } +- +- attr = isns_attr_alloc(tag, tag_type, value); +- __isns_attr_list_append_attr(list, attr); +-} +- +-/* +- * Update an element to an attribute list +- */ +-static void +-__isns_attr_list_update(isns_attr_list_t *list, +- uint32_t tag, const isns_tag_type_t *tag_type, +- const isns_value_t *value) +-{ +- const isns_attr_type_t *type = value->iv_type; +- isns_attr_t *attr; +- +- if (tag_type == NULL) +- tag_type = isns_tag_type_by_id(tag); +- if (type != &isns_attr_type_nil +- && type != tag_type->it_type) { +- isns_warning("Using wrong type (%s) " +- "when encoding attribute %04x (%s) - should be %s\n", +- type->it_name, +- tag, tag_type->it_name, +- tag_type->it_type->it_name); +- } +- +- if (tag_type->it_multiple +- || (attr = __isns_attr_list_find(list, tag)) == NULL) { +- attr = isns_attr_alloc(tag, tag_type, NULL); +- __isns_attr_list_append_attr(list, attr); +- } +- +- __isns_attr_set_value(attr, value); +-} +- +-/* +- * Append an element to an attribute list - public interface +- */ +-void +-isns_attr_list_append_value(isns_attr_list_t *list, +- uint32_t tag, const isns_tag_type_t *tag_type, +- const isns_value_t *value) +-{ +- __isns_attr_list_append(list, tag, tag_type, value); +-} +- +-/* +- * Update an element of an attribute list - public interface +- */ +-void +-isns_attr_list_update_value(isns_attr_list_t *list, +- uint32_t tag, const isns_tag_type_t *tag_type, +- const isns_value_t *value) +-{ +- __isns_attr_list_update(list, tag, tag_type, value); +-} +- +-void +-isns_attr_list_update_attr(isns_attr_list_t *list, +- const isns_attr_t *attr) +-{ +- __isns_attr_list_update(list, attr->ia_tag_id, +- attr->ia_tag, &attr->ia_value); +-} +- +-/* +- * Replace an attribute on a list +- */ +-int +-isns_attr_list_replace_attr(isns_attr_list_t *list, +- isns_attr_t *attr) +-{ +- unsigned int i; +- +- for (i = 0; i < list->ial_count; ++i) { +- isns_attr_t *other = list->ial_data[i]; +- +- if (other->ia_tag_id == attr->ia_tag_id) { +- list->ial_data[i] = attr; +- attr->ia_users++; +- isns_attr_release(other); +- return 1; +- } +- } +- return 0; +-} +- +-/* +- * Retrieve an element of an attribute list +- */ +-int +-isns_attr_list_get_attr(const isns_attr_list_t *list, +- uint32_t tag, isns_attr_t **result) +-{ +- *result = __isns_attr_list_find(list, tag); +- return *result != NULL; +-} +- +-int +-isns_attr_list_get_value(const isns_attr_list_t *list, +- uint32_t tag, isns_value_t *value) +-{ +- isns_attr_t *attr; +- +- if (!(attr = __isns_attr_list_find(list, tag))) +- return 0; +- +- *value = attr->ia_value; +- return 1; +-} +- +-int +-isns_attr_list_get_uint32(const isns_attr_list_t *list, +- uint32_t tag, uint32_t *value) +-{ +- isns_attr_t *attr; +- +- if (!(attr = __isns_attr_list_find(list, tag)) +- || !ISNS_ATTR_IS_UINT32(attr)) +- return 0; +- +- *value = attr->ia_value.iv_uint32; +- return 1; +-} +- +-int +-isns_attr_list_get_ipaddr(const isns_attr_list_t *list, +- uint32_t tag, struct in6_addr *value) +-{ +- isns_attr_t *attr; +- +- if (!(attr = __isns_attr_list_find(list, tag)) +- || !ISNS_ATTR_IS_IPADDR(attr)) +- return 0; +- +- *value = attr->ia_value.iv_ipaddr; +- return 1; +-} +- +-int +-isns_attr_list_get_string(const isns_attr_list_t *list, +- uint32_t tag, const char **value) +-{ +- isns_attr_t *attr; +- +- if (!(attr = __isns_attr_list_find(list, tag)) +- || !ISNS_ATTR_IS_STRING(attr)) +- return 0; +- +- *value = attr->ia_value.iv_string; +- return 1; +-} +- +-int +-isns_attr_list_contains(const isns_attr_list_t *list, +- uint32_t tag) +-{ +- return __isns_attr_list_find(list, tag) != NULL; +-} +- +-/* +- * Some attribute types have an implied ordering, +- * which is needed for GetNext. This is used to +- * compare two lists. +- */ +- +-/* +- * Typed versions of isns_attr_list_append +- */ +-void +-isns_attr_list_append_nil(isns_attr_list_t *list, uint32_t tag) +-{ +- isns_value_t var = ISNS_VALUE_INIT(nil, 0); +- +- __isns_attr_list_append(list, tag, NULL, &var); +-} +- +-void +-isns_attr_list_append_string(isns_attr_list_t *list, +- uint32_t tag, const char *value) +-{ +- isns_value_t var = ISNS_VALUE_INIT(string, (char *) value); +- +- __isns_attr_list_append(list, tag, NULL, &var); +-} +- +-void +-isns_attr_list_append_uint32(isns_attr_list_t *list, +- uint32_t tag, uint32_t value) +-{ +- isns_value_t var = ISNS_VALUE_INIT(uint32, value); +- +- __isns_attr_list_append(list, tag, NULL, &var); +-} +- +-void +-isns_attr_list_append_int32(isns_attr_list_t *list, +- uint32_t tag, int32_t value) +-{ +- isns_value_t var = ISNS_VALUE_INIT(int32, value); +- +- __isns_attr_list_append(list, tag, NULL, &var); +-} +- +-void +-isns_attr_list_append_uint64(isns_attr_list_t *list, +- uint32_t tag, int64_t value) +-{ +- isns_value_t var = ISNS_VALUE_INIT(uint64, value); +- +- __isns_attr_list_append(list, tag, NULL, &var); +-} +- +-void +-isns_attr_list_append_ipaddr(isns_attr_list_t *list, +- uint32_t tag, const struct in6_addr *value) +-{ +- isns_value_t var = ISNS_VALUE_INIT(ipaddr, *value); +- +- __isns_attr_list_append(list, tag, NULL, &var); +-} +- +-/* +- * Untyped version of isns_attr_list_append and isns_attr_list_update. +- * The caller must make sure that the type of @data matches the tag's type. +- */ +-int +-isns_attr_list_append(isns_attr_list_t *list, uint32_t tag, const void *data) +-{ +- const isns_tag_type_t *tag_type; +- isns_value_t var; +- +- if (!(tag_type = isns_tag_type_by_id(tag))) +- return 0; +- +- var.iv_type = tag_type->it_type; +- if (!var.iv_type->it_set(&var, data)) +- return 0; +- +- __isns_attr_list_append(list, tag, tag_type, &var); +- return 1; +-} +- +-int +-isns_attr_list_update(isns_attr_list_t *list, uint32_t tag, const void *data) +-{ +- const isns_tag_type_t *tag_type; +- isns_attr_type_t *type; +- isns_value_t var; +- +- if (!(tag_type = isns_tag_type_by_id(tag))) +- return 0; +- +- type = tag_type->it_type; +- var.iv_type = type; +- if (!type->it_set(&var, data)) +- return 0; +- +- __isns_attr_list_update(list, tag, tag_type, &var); +- return 1; +-} +- +-/* +- * Validate the attribute list. +- */ +-int +-isns_attr_validate(const isns_attr_t *attr, +- const isns_policy_t *policy) +-{ +- const isns_tag_type_t *tag_type; +- +- tag_type = attr->ia_tag; +- if (tag_type->it_validate == NULL) +- return 1; +- return tag_type->it_validate(&attr->ia_value, policy); +-} +- +-int +-isns_attr_list_validate(const isns_attr_list_t *list, +- const isns_policy_t *policy, +- unsigned int function) +-{ +- DECLARE_BITMAP(seen, __ISNS_TAG_MAX); +- unsigned int i; +- +- for (i = 0; i < list->ial_count; ++i) { +- const isns_tag_type_t *tag_type; +- isns_attr_t *attr = list->ial_data[i]; +- uint32_t tag = attr->ia_tag_id; +- unsigned int bit; +- +- if (attr == NULL) +- return ISNS_INTERNAL_ERROR; +- +- tag_type = attr->ia_tag; +- if (tag_type == NULL) +- return ISNS_INTERNAL_ERROR; +- +- bit = tag; +- if (OPENISNS_IS_PRIVATE_ATTR(tag)) +- bit -= OPENISNS_VENDOR_PREFIX; +- if (bit >= __ISNS_TAG_MAX) +- goto invalid; +- +- if (attr->ia_value.iv_type == &isns_attr_type_nil) { +- if (test_bit(seen, bit)) +- goto invalid; +- } else +- if (attr->ia_value.iv_type == tag_type->it_type) { +- if (!tag_type->it_multiple && test_bit(seen, bit)) +- goto invalid; +- +- if (!isns_attr_validate(attr, policy)) +- goto invalid; +- } else { +- return ISNS_INTERNAL_ERROR; +- } +- +- if (function == ISNS_DEVICE_ATTRIBUTE_REGISTER +- && tag_type->it_readonly) +- goto invalid; +- +- set_bit(seen, bit); +- } +- +- return ISNS_SUCCESS; +- +-invalid: +- switch (function) { +- case ISNS_DEVICE_ATTRIBUTE_REGISTER: +- return ISNS_INVALID_REGISTRATION; +- +- case ISNS_DEVICE_DEREGISTER: +- return ISNS_INVALID_DEREGISTRATION; +- +- case ISNS_DEVICE_ATTRIBUTE_QUERY: +- case ISNS_DEVICE_GET_NEXT: +- return ISNS_INVALID_QUERY; +- } +- return ISNS_ATTRIBUTE_NOT_IMPLEMENTED; +-} +- +-/* +- * Debug helper: print attribute list +- */ +-void +-isns_attr_list_print(const isns_attr_list_t *list, isns_print_fn_t *fn) +-{ +- unsigned int i; +- +- for (i = 0; i < list->ial_count; ++i) +- isns_attr_print(list->ial_data[i], fn); +-} +- +-char * +-isns_attr_print_value(const isns_attr_t *attr, char *buffer, size_t size) +-{ +- const isns_tag_type_t *tag_type = attr->ia_tag; +- const isns_attr_type_t *type = attr->ia_value.iv_type; +- +- if (tag_type->it_print && type == tag_type->it_type) +- tag_type->it_print(&attr->ia_value, buffer, size); +- else +- type->it_print(&attr->ia_value, buffer, size); +- return buffer; +-} +- +-void +-isns_attr_print(const isns_attr_t *attr, isns_print_fn_t *fn) +-{ +- const isns_tag_type_t *tag_type = attr->ia_tag; +- const isns_attr_type_t *type = attr->ia_value.iv_type; +- uint32_t tag; +- char value[512], *vspec = ""; +- +- tag = attr->ia_tag_id; +- if (OPENISNS_IS_PRIVATE_ATTR(tag)) { +- tag -= OPENISNS_VENDOR_PREFIX; +- vspec = "v"; +- } +- +- fn(" %04x%1s %-12s: %s = %s\n", +- tag, vspec, +- type->it_name, +- tag_type? tag_type->it_name : "Unknown Attribute", +- isns_attr_print_value(attr, value, sizeof(value))); +-} +- +-/* +- * TLV encode a single attribute +- */ +-int +-isns_attr_encode(buf_t *bp, const isns_attr_t *attr) +-{ +- const isns_value_t *value = &attr->ia_value; +- const isns_attr_type_t *type = value->iv_type; +- +- if (!buf_put32(bp, attr->ia_tag_id) +- || !type->it_encode(bp, value)) +- return ISNS_INTERNAL_ERROR; +- +- return ISNS_SUCCESS; +-} +- +-/* +- * TLV decode a single attribute +- */ +-int +-isns_attr_decode(buf_t *bp, isns_attr_t **result) +-{ +- isns_attr_t *attr = NULL; +- isns_value_t *value; +- uint32_t tag, len; +- +- if (!buf_get32(bp, &tag) +- || !buf_get32(bp, &len)) +- goto msg_fmt_error; +- +- /* Attributes MUST be word aligned */ +- if (len & 3) +- goto msg_fmt_error; +- +- if (len > ISNS_ATTR_MAX_LEN) +- goto msg_fmt_error; +- +- /* Allocate the attribute */ +- attr = isns_attr_alloc(tag, NULL, NULL); +- +- value = &attr->ia_value; +- if (len == 0) +- value->iv_type = &isns_attr_type_nil; +- +- if (!value->iv_type->it_decode(bp, len, value)) +- goto msg_fmt_error; +- +- *result = attr; +- return ISNS_SUCCESS; +- +-msg_fmt_error: +- isns_error("Error decoding attribute, tag=0x%04x, len=%u\n", +- tag, len); +- if (attr) +- isns_attr_release(attr); +- return ISNS_MESSAGE_FORMAT_ERROR; +-} +- +- +-/* +- * Decode the list of TLV encoded attributes inside an +- * iSNS message. +- */ +-static int +-__isns_attr_list_decode(buf_t *bp, isns_attr_list_t *list, int delimited) +-{ +- int status; +- +- while (buf_avail(bp)) { +- isns_attr_t *attr; +- +- status = isns_attr_decode(bp, &attr); +- if (status != ISNS_SUCCESS) +- return status; +- +- if (delimited && attr->ia_tag_id == ISNS_TAG_DELIMITER) { +- isns_attr_release(attr); +- break; +- } +- +- __isns_attr_list_append_attr(list, attr); +- } +- +- return ISNS_SUCCESS; +-} +- +-int +-isns_attr_list_decode(buf_t *bp, isns_attr_list_t *list) +-{ +- return __isns_attr_list_decode(bp, list, 0); +-} +- +-int +-isns_attr_list_decode_delimited(buf_t *bp, isns_attr_list_t *list) +-{ +- return __isns_attr_list_decode(bp, list, 1); +-} +- +-/* +- * Remove all attributes from a list save those matching +- * the given tags. +- */ +-void +-isns_attr_list_prune(isns_attr_list_t *list, +- const uint32_t *tags, unsigned int num_tags) +-{ +- unsigned int i, j, k; +- +- for (i = j = 0; i < list->ial_count; ++i) { +- isns_attr_t *attr = list->ial_data[i]; +- +- for (k = 0; k < num_tags; ++k) { +- if (attr->ia_tag_id == tags[k]) { +- list->ial_data[j++] = attr; +- goto next; +- } +- } +- +- isns_attr_release(attr); +- +-next: ; +- } +- +- list->ial_count = j; +-} +- +-/* +- * TLV ecode the list of attributes to go with +- * iSNS message. +- */ +-int +-isns_attr_list_encode(buf_t *bp, const isns_attr_list_t *list) +-{ +- unsigned int i, status = ISNS_SUCCESS; +- +- for (i = 0; i < list->ial_count; ++i) { +- struct isns_attr *attr = list->ial_data[i]; +- +- status = isns_attr_encode(bp, attr); +- if (status) +- break; +- } +- return status; +-} +- +-/* +- * Encode the delimiter attribute +- */ +-int +-isns_encode_delimiter(buf_t *bp) +-{ +- uint32_t tag = 0, len = 0; +- +- if (!buf_put32(bp, tag) +- || !buf_put32(bp, len)) +- return ISNS_INTERNAL_ERROR; +- +- return ISNS_SUCCESS; +-} +- +-/* +- * Padded encoding +- */ +-static inline int +-isns_encode_padded(buf_t *bp, const void *ptr, size_t len) +-{ +- if (!buf_put(bp, ptr, len)) +- return 0; +- +- if ((len & 3) == 0) +- return 1; +- +- return buf_put(bp, "\0\0\0", 4 - (len & 3)); +-} +- +-/* +- * Helper functions to deal with portal information +- */ +-void +-isns_portal_init(isns_portal_info_t *portal, +- const struct sockaddr *saddr, int proto) +-{ +- const struct sockaddr_in *sin; +- +- memset(portal, 0, sizeof(*portal)); +- switch (saddr->sa_family) { +- case AF_INET6: +- portal->addr = *(const struct sockaddr_in6 *) saddr; +- break; +- +- case AF_INET: +- sin = (const struct sockaddr_in *) saddr; +- portal->addr.sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; +- portal->addr.sin6_port = sin->sin_port; +- portal->addr.sin6_family = AF_INET6; +- break; +- default: +- isns_warning("Unknown address family in isns_portal_init\n"); +- return; +- } +- +- portal->proto = proto; +-} +- +-int +-isns_portal_from_attr_list(isns_portal_info_t *portal, +- uint32_t addr_tag, uint32_t port_tag, +- const isns_attr_list_t *list) +-{ +- const isns_attr_t *addr_attr = NULL, *port_attr = NULL; +- unsigned int i; +- +- for (i = 0; i + 1 < list->ial_count; ++i) { +- const isns_attr_t *attr = list->ial_data[i]; +- +- if (!ISNS_ATTR_IS_IPADDR(attr)) +- continue; +- if (addr_tag && attr->ia_tag_id != addr_tag) +- continue; +- addr_attr = attr; +- if (port_tag == 0) { +- port_attr = list->ial_data[i + 1]; +- goto extract_portal; +- } +- break; +- } +- +- /* We have a specific port tag. */ +- while (++i < list->ial_count) { +- const isns_attr_t *attr = list->ial_data[i]; +- +- if (attr->ia_tag_id == port_tag) { +- port_attr = attr; +- goto extract_portal; +- } +- } +- +- return 0; +- +-extract_portal: +- return isns_portal_from_attr_pair(portal, +- addr_attr, port_attr); +-} +- +-int +-isns_portal_from_attr_pair(isns_portal_info_t *portal, +- const isns_attr_t *addr_attr, +- const isns_attr_t *port_attr) +-{ +- uint32_t portspec; +- +- memset(portal, 0, sizeof(*portal)); +- portal->addr.sin6_family = AF_INET6; +- +- if (!ISNS_ATTR_IS_IPADDR(addr_attr) +- || !ISNS_ATTR_IS_UINT32(port_attr)) +- return 0; +- +- portal->addr.sin6_addr = addr_attr->ia_value.iv_ipaddr; +- +- portspec = port_attr->ia_value.iv_uint32; +- portal->addr.sin6_port = htons(portspec & 0xffff); +- portal->proto = (portspec & ISNS_PORTAL_PORT_UDP_MASK)? IPPROTO_UDP : IPPROTO_TCP; +- +- return 1; +-} +- +-int +-isns_portal_to_attr_list(const isns_portal_info_t *portal, +- uint32_t addr_tag, uint32_t port_tag, +- isns_attr_list_t *list) +-{ +- uint32_t portspec; +- +- portspec = htons(portal->addr.sin6_port); +- if (portal->proto == IPPROTO_UDP) +- portspec |= ISNS_PORTAL_PORT_UDP_MASK; +- +- { +- isns_value_t addr_value = ISNS_VALUE_INIT(ipaddr, portal->addr.sin6_addr); +- isns_value_t port_value = ISNS_VALUE_INIT(uint32, portspec); +- +- isns_attr_list_update_value(list, addr_tag, NULL, &addr_value); +- isns_attr_list_update_value(list, port_tag, NULL, &port_value); +- } +- +- return 1; +-} +- +-const char * +-isns_portal_string(const isns_portal_info_t *portal) +-{ +- const struct sockaddr_in6 *six = &portal->addr; +- static char buffer[128]; +- char abuf[128]; +- +- inet_ntop(six->sin6_family, &six->sin6_addr, abuf, sizeof(abuf)); +- snprintf(buffer, sizeof(buffer), "[%s]:%d/%s", +- abuf, ntohs(six->sin6_port), +- (portal->proto == IPPROTO_UDP)? "udp" : "tcp"); +- return buffer; +-} +- +-int +-isns_portal_is_wildcard(const isns_portal_info_t *portal) +-{ +- return !memcmp(&portal->addr.sin6_addr, +- &in6addr_any, +- sizeof(struct in6_addr)); +-} +- +-int +-isns_portal_equal(const isns_portal_info_t *a, +- const isns_portal_info_t *b) +-{ +- if (a->proto != b->proto) +- return 0; +- return !memcmp(&a->addr, &b->addr, sizeof(a->addr)); +-} +- +-uint32_t +-isns_portal_tcpudp_port(const isns_portal_info_t *portal) +-{ +- uint32_t port; +- +- port = isns_addr_get_port((const struct sockaddr *) &portal->addr); +- if (portal->proto == IPPROTO_UDP) +- port |= ISNS_PORTAL_PORT_UDP_MASK; +- return port; +-} +- +-int +-isns_portal_parse(isns_portal_info_t *portal, +- const char *spec, +- const char *default_port) +-{ +- struct sockaddr_storage addr; +- char *copy, *psp; +- int alen, proto = IPPROTO_TCP, sock_type = SOCK_STREAM; +- +- if (spec[0] == '/') { +- isns_warning("%s: no AF_LOCAL addresses for portals!\n", +- __FUNCTION__); +- return 0; +- } +- +- /* Look at trailing /tcp or /udp */ +- copy = isns_strdup(spec); +- if ((psp = strrchr(copy, '/')) != NULL) { +- if (!strcasecmp(psp, "/udp")) { +- sock_type = SOCK_DGRAM; +- proto = IPPROTO_UDP; +- *psp = '\0'; +- } else +- if (!strcasecmp(psp, "/tcp")) { +- sock_type = SOCK_STREAM; +- proto = IPPROTO_TCP; +- *psp = '\0'; +- } +- } +- +- alen = isns_get_address(&addr, copy, default_port, 0, sock_type, 0); +- isns_free(copy); +- +- if (alen < 0) +- return 0; +- +- isns_portal_init(portal, (struct sockaddr *) &addr, proto); +- return 1; +-} +- +-/* +- * Attribute type NIL +- */ +-static int +-isns_attr_type_nil_encode(buf_t *bp, const isns_value_t *value) +-{ +- return buf_put32(bp, 0); +-} +- +-static int +-isns_attr_type_nil_decode(buf_t *bp, size_t len, isns_value_t *value) +-{ +- return len == 0; +-} +- +-static void +-isns_attr_type_nil_print(const isns_value_t *value, char *buf, size_t size) +-{ +- snprintf(buf, size, ""); +-} +- +-static int +-isns_attr_type_nil_parse(isns_value_t *value, const char *string) +-{ +- if (string && *string) +- return 0; +- return 1; +-} +- +-isns_attr_type_t isns_attr_type_nil = { +- .it_id = ISNS_ATTR_TYPE_NIL, +- .it_name = "nil", +- .it_encode = isns_attr_type_nil_encode, +- .it_decode = isns_attr_type_nil_decode, +- .it_print = isns_attr_type_nil_print, +- .it_parse = isns_attr_type_nil_parse, +-}; +- +-/* +- * Attribute type UINT32 +- */ +-static int +-isns_attr_type_uint32_encode(buf_t *bp, const isns_value_t *value) +-{ +- return buf_put32(bp, 4) && buf_put32(bp, value->iv_uint32); +-} +- +-static int +-isns_attr_type_uint32_decode(buf_t *bp, size_t len, isns_value_t *value) +-{ +- if (len != 4) +- return 0; +- return buf_get32(bp, &value->iv_uint32); +-} +- +-static void +-isns_attr_type_uint32_print(const isns_value_t *value, char *buf, size_t size) +-{ +- snprintf(buf, size, "%u", value->iv_uint32); +-} +- +-static int +-isns_attr_type_uint32_parse(isns_value_t *value, const char *string) +-{ +- char *end; +- +- value->iv_uint32 = strtoul(string, &end, 0); +- return *end == '\0'; +-} +- +-static void +-isns_attr_type_int32_print(const isns_value_t *value, char *buf, size_t size) +-{ +- snprintf(buf, size, "%d", value->iv_uint32); +-} +- +-static int +-isns_attr_type_int32_parse(isns_value_t *value, const char *string) +-{ +- char *end; +- +- value->iv_int32 = strtol(string, &end, 0); +- return *end == '\0'; +-} +- +-isns_attr_type_t isns_attr_type_uint32 = { +- .it_id = ISNS_ATTR_TYPE_UINT32, +- .it_name = "uint32", +- .it_encode = isns_attr_type_uint32_encode, +- .it_decode = isns_attr_type_uint32_decode, +- .it_print = isns_attr_type_uint32_print, +- .it_parse = isns_attr_type_uint32_parse, +-}; +- +-isns_attr_type_t isns_attr_type_int32 = { +- .it_id = ISNS_ATTR_TYPE_INT32, +- .it_name = "int32", +- .it_encode = isns_attr_type_uint32_encode, +- .it_decode = isns_attr_type_uint32_decode, +- .it_print = isns_attr_type_int32_print, +- .it_parse = isns_attr_type_int32_parse, +-}; +- +-/* +- * 16bit min/max +- */ +-static int +-isns_attr_type_range16_encode(buf_t *bp, const isns_value_t *value) +-{ +- uint32_t word; +- +- word = (value->iv_range.max << 16) | value->iv_range.min; +- return buf_put32(bp, 4) && buf_put32(bp, word); +-} +- +-static int +-isns_attr_type_range16_decode(buf_t *bp, size_t len, isns_value_t *value) +-{ +- uint32_t word; +- +- if (len != 4) +- return 0; +- if (!buf_get32(bp, &word)) +- return 0; +- value->iv_range.max = word >> 16; +- value->iv_range.min = word & 0xFFFF; +- return 1; +-} +- +-static void +-isns_attr_type_range16_print(const isns_value_t *value, char *buf, size_t size) +-{ +- snprintf(buf, size, "[%u, %u]", value->iv_range.min, value->iv_range.max); +-} +- +-isns_attr_type_t isns_attr_type_range16 = { +- .it_id = ISNS_ATTR_TYPE_RANGE16, +- .it_name = "range16", +- .it_encode = isns_attr_type_range16_encode, +- .it_decode = isns_attr_type_range16_decode, +- .it_print = isns_attr_type_range16_print, +-// .it_parse = isns_attr_type_range16_parse, +-}; +- +- +-/* +- * 64bit integers +- */ +-static int +-isns_attr_type_uint64_encode(buf_t *bp, const isns_value_t *value) +-{ +- return buf_put32(bp, 8) && buf_put64(bp, value->iv_uint64); +-} +- +-static int +-isns_attr_type_uint64_decode(buf_t *bp, size_t len, isns_value_t *value) +-{ +- if (len != 8) +- return 0; +- return buf_get64(bp, &value->iv_uint64); +-} +- +-static void +-isns_attr_type_uint64_print(const isns_value_t *value, char *buf, size_t size) +-{ +- snprintf(buf, size, "%Lu", (unsigned long long) value->iv_uint64); +-} +- +-static int +-isns_attr_type_uint64_parse(isns_value_t *value, const char *string) +-{ +- char *end; +- +- value->iv_uint64 = strtoull(string, &end, 0); +- return *end == '\0'; +-} +- +-isns_attr_type_t isns_attr_type_uint64 = { +- .it_id = ISNS_ATTR_TYPE_UINT64, +- .it_name = "uint64", +- .it_encode = isns_attr_type_uint64_encode, +- .it_decode = isns_attr_type_uint64_decode, +- .it_print = isns_attr_type_uint64_print, +- .it_parse = isns_attr_type_uint64_parse, +-}; +- +-/* +- * Attribute type STRING +- */ +-static void +-isns_attr_type_string_destroy(isns_value_t *value) +-{ +- isns_free(value->iv_string); +- value->iv_string = NULL; +-} +- +-static int +-isns_attr_type_string_match(const isns_value_t *a, const isns_value_t *b) +-{ +- if (a->iv_string && b->iv_string) +- return !strcmp(a->iv_string, b->iv_string); +- +- return a->iv_string == b->iv_string; +-} +- +-static int +-isns_attr_type_string_compare(const isns_value_t *a, const isns_value_t *b) +-{ +- if (a->iv_string && b->iv_string) +- return strcmp(a->iv_string, b->iv_string); +- +- return a->iv_string? 1 : -1; +-} +- +-static int +-isns_attr_type_string_encode(buf_t *bp, const isns_value_t *value) +-{ +- uint32_t len; +- +- len = value->iv_string? strlen(value->iv_string) + 1 : 0; +- +- if (!buf_put32(bp, ISNS_PAD(len))) +- return 0; +- +- if (len && !isns_encode_padded(bp, value->iv_string, len)) +- return 0; +- +- return 1; +-} +- +-static int +-isns_attr_type_string_decode(buf_t *bp, size_t len, isns_value_t *value) +-{ +- /* Is this legal? */ +- if (len == 0) +- return 1; +- +- /* The string should be NUL terminated, but +- * better be safe than sorry. */ +- value->iv_string = isns_malloc(len + 1); +- if (!buf_get(bp, value->iv_string, len)) { +- isns_free(value->iv_string); +- return 0; +- } +- value->iv_string[len] = '\0'; +- return 1; +-} +- +-static void +-isns_attr_type_string_print(const isns_value_t *value, char *buf, size_t size) +-{ +- if (!value->iv_string) +- snprintf(buf, size, "(empty)"); +- else +- snprintf(buf, size, "\"%s\"", value->iv_string); +-} +- +-static int +-isns_attr_type_string_parse(isns_value_t *value, const char *string) +-{ +- value->iv_string = isns_strdup(string); +- return 1; +-} +- +-static void +-isns_attr_type_string_assign(isns_value_t *value, const isns_value_t *new_value) +-{ +- isns_assert(!value->iv_string); +- if (new_value->iv_string) +- value->iv_string = isns_strdup(new_value->iv_string); +-} +- +-isns_attr_type_t isns_attr_type_string = { +- .it_id = ISNS_ATTR_TYPE_STRING, +- .it_name = "string", +- .it_assign = isns_attr_type_string_assign, +- .it_destroy = isns_attr_type_string_destroy, +- .it_match = isns_attr_type_string_match, +- .it_compare = isns_attr_type_string_compare, +- .it_encode = isns_attr_type_string_encode, +- .it_decode = isns_attr_type_string_decode, +- .it_print = isns_attr_type_string_print, +- .it_parse = isns_attr_type_string_parse, +-}; +- +-/* +- * Attribute type IPADDR +- */ +-static int +-isns_attr_type_ipaddr_encode(buf_t *bp, const isns_value_t *value) +-{ +- if (!buf_put32(bp, 16) +- || !buf_put(bp, &value->iv_ipaddr, 16)) +- return 0; +- +- return 1; +-} +- +-static int +-isns_attr_type_ipaddr_decode(buf_t *bp, size_t len, isns_value_t *value) +-{ +- if (len != 16) +- return 0; +- +- return buf_get(bp, &value->iv_ipaddr, 16); +-} +- +-static void +-isns_attr_type_ipaddr_print(const isns_value_t *value, char *buf, size_t size) +-{ +- const struct in6_addr *addr = &value->iv_ipaddr; +- char buffer[INET6_ADDRSTRLEN + 1]; +- +- /* The standard requires IPv4 mapping, but +- * some oldish implementations seem to use +- * IPv4 compatible addresss. */ +- if (IN6_IS_ADDR_V4MAPPED(addr) || IN6_IS_ADDR_V4COMPAT(addr)) { +- struct in_addr ipv4; +- +- ipv4.s_addr = addr->s6_addr32[3]; +- inet_ntop(AF_INET, &ipv4, buffer, sizeof(buffer)); +- } else { +- inet_ntop(AF_INET6, addr, buffer, sizeof(buffer)); +- } +- snprintf(buf, size, "%s", buffer); +-} +- +-static int +-isns_attr_type_ipaddr_parse(isns_value_t *value, const char *string) +-{ +- struct in_addr addr4; +- +- if (inet_pton(AF_INET, string, &addr4)) { +- value->iv_ipaddr = in6addr_any; +- value->iv_ipaddr.s6_addr32[3] = addr4.s_addr; +- return 1; +- } +- +- return inet_pton(AF_INET6, string, &value->iv_ipaddr); +-} +- +-isns_attr_type_t isns_attr_type_ipaddr = { +- .it_id = ISNS_ATTR_TYPE_IPADDR, +- .it_name = "ipaddr", +- .it_encode = isns_attr_type_ipaddr_encode, +- .it_decode = isns_attr_type_ipaddr_decode, +- .it_print = isns_attr_type_ipaddr_print, +- .it_parse = isns_attr_type_ipaddr_parse, +-}; +- +-/* +- * Attribute type OPAQUE +- */ +-static void +-isns_attr_type_opaque_assign(isns_value_t *value, const isns_value_t *new_value) +-{ +- size_t new_len = new_value->iv_opaque.len; +- isns_assert(value->iv_opaque.len == 0); +- if (new_len) { +- value->iv_opaque.ptr = isns_malloc(new_len); +- value->iv_opaque.len = new_len; +- memcpy(value->iv_opaque.ptr, +- new_value->iv_opaque.ptr, +- new_len); +- } +-} +- +-static void +-isns_attr_type_opaque_destroy(isns_value_t *value) +-{ +- isns_free(value->iv_opaque.ptr); +- value->iv_opaque.ptr = NULL; +- value->iv_opaque.len = 0; +-} +- +-static int +-isns_attr_type_opaque_match(const isns_value_t *a, const isns_value_t *b) +-{ +- if (a->iv_opaque.len != b->iv_opaque.len) +- return 0; +- return !memcmp(a->iv_opaque.ptr, b->iv_opaque.ptr, a->iv_opaque.len); +-} +- +-static int +-isns_attr_type_opaque_compare(const isns_value_t *a, const isns_value_t *b) +-{ +- long delta; +- +- delta = a->iv_opaque.len - b->iv_opaque.len; +- if (delta) +- return delta; +- +- return memcmp(a->iv_opaque.ptr, b->iv_opaque.ptr, a->iv_opaque.len); +-} +- +-static int +-isns_attr_type_opaque_encode(buf_t *bp, const isns_value_t *value) +-{ +- uint32_t len; +- +- len = value->iv_opaque.len; +- if (len & 3) +- return 0; +- +- if (!buf_put32(bp, len) +- || !buf_put(bp, value->iv_opaque.ptr, len)) +- return 0; +- +- return 1; +-} +- +-static int +-isns_attr_type_opaque_decode(buf_t *bp, size_t len, isns_value_t *value) +-{ +- value->iv_opaque.ptr = isns_malloc(len); +- if (!buf_get(bp, value->iv_opaque.ptr, len)) { +- isns_free(value->iv_opaque.ptr); +- return 0; +- } +- +- value->iv_opaque.len = len; +- return 1; +-} +- +-static void +-isns_attr_type_opaque_print(const isns_value_t *value, char *buf, size_t size) +-{ +- unsigned char *data = value->iv_opaque.ptr; +- unsigned int i, len; +- +- /* There must be room for "<...>\0" */ +- if (size < 6) +- return; +- size -= 6; +- +- if ((len = value->iv_opaque.len) > 20) +- len = 20; +- if (size < 3 * len) +- len = size / 3; +- +- *buf++ = '<'; +- for (i = 0; i < len; ++i) { +- if (i) +- *buf++ = ' '; +- sprintf(buf, "%02x", data[i]); +- buf += 2; +- } +- if (len < value->iv_opaque.len) { +- strcat(buf, "..."); +- buf += 4; +- } +- *buf++ = '>'; +- *buf++ = '\0'; +-} +- +-isns_attr_type_t isns_attr_type_opaque = { +- .it_id = ISNS_ATTR_TYPE_OPAQUE, +- .it_name = "opaque", +- .it_assign = isns_attr_type_opaque_assign, +- .it_destroy = isns_attr_type_opaque_destroy, +- .it_match = isns_attr_type_opaque_match, +- .it_compare = isns_attr_type_opaque_compare, +- .it_encode = isns_attr_type_opaque_encode, +- .it_decode = isns_attr_type_opaque_decode, +- .it_print = isns_attr_type_opaque_print, +-}; +- +-/* +- * Map attribute type IDs to attribute types +- */ +-static isns_attr_type_t * +-isns_attr_types_builtin[__ISNS_ATTR_TYPE_BUILTIN_MAX] = { +-[ISNS_ATTR_TYPE_NIL] = &isns_attr_type_nil, +-[ISNS_ATTR_TYPE_OPAQUE] = &isns_attr_type_opaque, +-[ISNS_ATTR_TYPE_STRING] = &isns_attr_type_string, +-[ISNS_ATTR_TYPE_INT32] = &isns_attr_type_int32, +-[ISNS_ATTR_TYPE_UINT32] = &isns_attr_type_uint32, +-[ISNS_ATTR_TYPE_UINT64] = &isns_attr_type_uint64, +-[ISNS_ATTR_TYPE_IPADDR] = &isns_attr_type_ipaddr, +-[ISNS_ATTR_TYPE_RANGE16] = &isns_attr_type_range16, +-}; +- +-const isns_attr_type_t * +-isns_attr_type_by_id(unsigned int id) +-{ +- if (id < __ISNS_ATTR_TYPE_BUILTIN_MAX) +- return isns_attr_types_builtin[id]; +- +- /* TODO: handle dynamic registration of attrtypes +- * for vendor extensions. */ +- return NULL; +-} +diff --git a/utils/open-isns/attrs.h b/utils/open-isns/attrs.h +deleted file mode 100644 +index 1d3667e..0000000 +--- a/utils/open-isns/attrs.h ++++ /dev/null +@@ -1,262 +0,0 @@ +-/* +- * iSNS object attributes +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#ifndef ISNS_ATTRS_H +-#define ISNS_ATTRS_H +- +-#include +-#include "buffer.h" +-#include "isns.h" +- +-/* +- * Type identifier +- */ +-enum { +- ISNS_ATTR_TYPE_NIL = 0, +- ISNS_ATTR_TYPE_OPAQUE, +- ISNS_ATTR_TYPE_STRING, +- ISNS_ATTR_TYPE_INT32, +- ISNS_ATTR_TYPE_UINT32, +- ISNS_ATTR_TYPE_UINT64, +- ISNS_ATTR_TYPE_IPADDR, +- ISNS_ATTR_TYPE_RANGE16, +- +- __ISNS_ATTR_TYPE_BUILTIN_MAX +-}; +- +-/* +- * Union holding an attribute value +- */ +-typedef struct isns_value { +- const struct isns_attr_type * iv_type; +- +- /* Data is stuffed into an anonymous union */ +- union { +- uint32_t iv_nil; +- struct __isns_opaque { +- void * ptr; +- size_t len; +- } iv_opaque; +- char * iv_string; +- int32_t iv_int32; +- uint32_t iv_uint32; +- uint64_t iv_uint64; +- struct in6_addr iv_ipaddr; +- struct { +- uint16_t min, max; +- } iv_range; +- }; +-} isns_value_t; +- +-#define __ISNS_ATTRTYPE(type) isns_attr_type_##type +-#define __ISNS_MEMBER(type) iv_##type +-#define ISNS_VALUE_INIT(type, value) \ +- (isns_value_t) { .iv_type = &__ISNS_ATTRTYPE(type), \ +- { .__ISNS_MEMBER(type) = (value) } } +- +-#define isns_attr_initialize(attrp, tag, type, value) do { \ +- isns_attr_t *__attr = (attrp); \ +- uint32_t __tag = (tag); \ +- __attr->ia_users = 1; \ +- __attr->ia_tag_id = (__tag); \ +- __attr->ia_tag = isns_tag_type_by_id(__tag); \ +- __attr->ia_value = ISNS_VALUE_INIT(type, value); \ +- } while (0) +-#define ISNS_ATTR_INIT(tag, type, value) (isns_attr_t) { \ +- .ia_users = 1, \ +- .ia_tag_id = (tag), \ +- .ia_tag = isns_tag_type_by_id(tag), \ +- .ia_value = ISNS_VALUE_INIT(type, value) \ +- } +- +-/* +- * Attribute type +- */ +-typedef struct isns_attr_type { +- uint32_t it_id; +- const char * it_name; +- +- void (*it_assign)(isns_value_t *, const isns_value_t *); +- int (*it_set)(isns_value_t *, const void *); +- int (*it_get)(isns_value_t *, void *); +- int (*it_match)(const isns_value_t *, const isns_value_t *); +- int (*it_compare)(const isns_value_t *, const isns_value_t *); +- int (*it_encode)(buf_t *, const isns_value_t *); +- int (*it_decode)(buf_t *, size_t, isns_value_t *); +- void (*it_destroy)(isns_value_t *); +- void (*it_print)(const isns_value_t *, char *, size_t); +- int (*it_parse)(isns_value_t *, const char *); +-} isns_attr_type_t; +- +-/* +- * Tag info: for each tag, provides a printable name, +- * and the attribute type associated with it. +- */ +-struct isns_tag_type { +- uint32_t it_id; +- const char * it_name; +- unsigned int it_multiple : 1, +- it_readonly : 1; +- isns_attr_type_t *it_type; +- +- int (*it_validate)(const isns_value_t *, +- const isns_policy_t *); +- void (*it_print)(const isns_value_t *, char *, size_t); +- int (*it_parse)(isns_value_t *, const char *); +- const char * (*it_help)(void); +-}; +- +-/* +- * Attribute +- */ +-struct isns_attr { +- unsigned int ia_users; +- uint32_t ia_tag_id; +- const isns_tag_type_t * ia_tag; +- isns_value_t ia_value; +-}; +- +-extern isns_attr_type_t isns_attr_type_nil; +-extern isns_attr_type_t isns_attr_type_opaque; +-extern isns_attr_type_t isns_attr_type_string; +-extern isns_attr_type_t isns_attr_type_int32; +-extern isns_attr_type_t isns_attr_type_uint32; +-extern isns_attr_type_t isns_attr_type_uint64; +-extern isns_attr_type_t isns_attr_type_ipaddr; +-extern isns_attr_type_t isns_attr_type_range16; +- +-extern isns_attr_t * isns_attr_alloc(uint32_t, const isns_tag_type_t *, +- const isns_value_t *); +- +-extern void isns_attr_list_append_value(isns_attr_list_t *, +- uint32_t tag, const isns_tag_type_t *, +- const isns_value_t *); +-extern void isns_attr_list_update_value(isns_attr_list_t *, +- uint32_t tag, const isns_tag_type_t *, +- const isns_value_t *); +-extern int isns_attr_list_get_value(const isns_attr_list_t *, +- uint32_t tag, +- isns_value_t *); +-extern int isns_attr_list_get_uint32(const isns_attr_list_t *, +- uint32_t tag, +- uint32_t *); +-extern int isns_attr_list_get_string(const isns_attr_list_t *, +- uint32_t tag, +- const char **); +- +-extern int isns_attr_list_validate(const isns_attr_list_t *, +- const isns_policy_t *, +- unsigned int function); +-extern int isns_attr_validate(const isns_attr_t *, +- const isns_policy_t *); +- +-extern void isns_attr_list_prune(isns_attr_list_t *, +- const uint32_t *, +- unsigned int); +-extern int isns_attr_list_remove_member(isns_attr_list_t *, +- const isns_attr_t *, +- const uint32_t *); +-extern void isns_attr_list_update_attr(isns_attr_list_t *, +- const isns_attr_t *); +- +-extern int isns_attr_decode(buf_t *, isns_attr_t **); +-extern int isns_attr_encode(buf_t *, const isns_attr_t *); +- +-extern int isns_attr_list_decode(buf_t *, isns_attr_list_t *); +-extern int isns_attr_list_decode_delimited(buf_t *, isns_attr_list_t *); +-extern int isns_attr_list_encode(buf_t *, const isns_attr_list_t *); +-extern int isns_encode_delimiter(buf_t *); +- +-extern const isns_tag_type_t *isns_tag_type_by_id(unsigned int); +-extern const isns_attr_type_t *isns_attr_type_by_id(unsigned int); +- +-typedef struct isns_quick_attr_list isns_quick_attr_list_t; +-struct isns_quick_attr_list { +- isns_attr_list_t iqa_list; +- isns_attr_t * iqa_attrs[1]; +- isns_attr_t iqa_attr; +-}; +-#define ISNS_QUICK_ATTR_LIST_DECLARE(qlist, tag, type, value) \ +- isns_quick_attr_list_t qlist = { \ +- .iqa_list = (isns_attr_list_t) { \ +- .ial_data = qlist.iqa_attrs, \ +- .ial_count = 1 \ +- }, \ +- .iqa_attrs = { &qlist.iqa_attr }, \ +- .iqa_attr = ISNS_ATTR_INIT(tag, type, value), \ +- } +- +-/* +- * The following is used to chop up an incoming attr list as +- * given in eg. a DevAttrReg message into separate chunks, +- * following the ordering constraints laid out in the RFC. +- * +- * isns_attr_list_scanner_init initializes the scanner state. +- * +- * isns_attr_list_scanner_next advances to the next object in +- * the list, returning the keys and attrs for one object. +- * +- * The isns_attr_list_scanner struct should really be opaque, but +- * we put it here so you can declare a scanner variable on the +- * stack. +- */ +-struct isns_attr_list_scanner { +- isns_source_t * source; +- isns_policy_t * policy; +- isns_object_t * key_obj; +- isns_attr_list_t orig_attrs; +- unsigned int pos; +- +- isns_attr_list_t keys; +- isns_attr_list_t attrs; +- isns_object_template_t *tmpl; +- unsigned int num_key_attrs; +- +- unsigned int entities; +- +- uint32_t pgt_next_attr; +- uint32_t pgt_value; +- const char * pgt_iscsi_name; +- isns_portal_info_t pgt_portal_info; +- isns_object_t * pgt_base_object; +- +- unsigned int index_acceptable : 1; +-}; +- +-extern void isns_attr_list_scanner_init(struct isns_attr_list_scanner *, +- isns_object_t *key_obj, +- const isns_attr_list_t *attrs); +-extern int isns_attr_list_scanner_next(struct isns_attr_list_scanner *); +-extern void isns_attr_list_scanner_destroy(struct isns_attr_list_scanner *); +- +-/* +- * The following is used to parse attribute lists given as +- * a bunch of strings. +- */ +-struct isns_attr_list_parser { +- struct isns_tag_prefix *prefix; +- const char * default_port; +- +- unsigned int multi_type_permitted : 1, +- nil_permitted : 1; +- +- isns_attr_t * (*load_key)(const char *); +- isns_attr_t * (*generate_key)(void); +-}; +- +-extern int isns_attr_list_split(char *line, char **argv, unsigned int argc_max); +-extern void isns_attr_list_parser_init(struct isns_attr_list_parser *, +- isns_object_template_t *); +-extern int isns_parse_attrs(unsigned int, char **, +- isns_attr_list_t *, struct isns_attr_list_parser *); +-extern int isns_parse_query_attrs(unsigned int, char **, +- isns_attr_list_t *, isns_attr_list_t *, +- struct isns_attr_list_parser *); +-extern void isns_attr_list_parser_help(struct isns_attr_list_parser *); +-extern isns_object_template_t *isns_attr_list_parser_context(const struct isns_attr_list_parser *); +-extern int isns_print_attrs(isns_object_t *, char **, unsigned int); +- +-#endif /* ISNS_ATTRS_H */ +diff --git a/utils/open-isns/authblock.c b/utils/open-isns/authblock.c +deleted file mode 100644 +index 76d35b4..0000000 +--- a/utils/open-isns/authblock.c ++++ /dev/null +@@ -1,62 +0,0 @@ +-/* +- * iSNS authentication functions +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include "isns.h" +-#include "attrs.h" +-#include "message.h" +-#include "util.h" +- +-/* We impose an artificial limit on the size of +- * the size of the authenticator +- */ +-#define ISNS_SPISTR_MAX 512 +- +-int +-isns_authblock_decode(buf_t *bp, struct isns_authblk *auth) +-{ +- unsigned int avail = buf_avail(bp); +- +- if (!buf_get32(bp, &auth->iab_bsd) +- || !buf_get32(bp, &auth->iab_length) +- || !buf_get64(bp, &auth->iab_timestamp) +- || !buf_get32(bp, &auth->iab_spi_len)) +- return 0; +- +- /* Make sure the length specified by the auth block +- * is reasonable. */ +- if (auth->iab_length < ISNS_AUTHBLK_SIZE +- || auth->iab_length > avail) +- return 0; +- +- /* This chops off any data trailing the auth block. +- * It also makes sure that we detect if iab_length +- * exceeds the amount of available data. */ +- if (!buf_truncate(bp, auth->iab_length - ISNS_AUTHBLK_SIZE)) +- return 0; +- +- auth->iab_spi = buf_head(bp); +- if (!buf_pull(bp, auth->iab_spi_len)) +- return 0; +- +- auth->iab_sig = buf_head(bp); +- auth->iab_sig_len = buf_avail(bp); +- return 1; +-} +- +-int +-isns_authblock_encode(buf_t *bp, const struct isns_authblk *auth) +-{ +- if (!buf_put32(bp, auth->iab_bsd) +- || !buf_put32(bp, auth->iab_length) +- || !buf_put64(bp, auth->iab_timestamp) +- || !buf_put32(bp, auth->iab_spi_len) +- || !buf_put(bp, auth->iab_spi, auth->iab_spi_len) +- || !buf_put(bp, auth->iab_sig, auth->iab_sig_len)) +- return 0; +- return 1; +-} +diff --git a/utils/open-isns/bitvector.c b/utils/open-isns/bitvector.c +deleted file mode 100644 +index 3e23f26..0000000 +--- a/utils/open-isns/bitvector.c ++++ /dev/null +@@ -1,651 +0,0 @@ +-/* +- * Handle bit vector as a run length encoded array of +- * 32bit words. +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include "isns.h" +-#include "util.h" +- +-struct isns_bitvector { +- unsigned int ib_count; +- uint32_t * ib_words; +-}; +- +-void +-isns_bitvector_init(isns_bitvector_t *bv) +-{ +- memset(bv, 0, sizeof(*bv)); +-} +- +-void +-isns_bitvector_destroy(isns_bitvector_t *bv) +-{ +- isns_free(bv->ib_words); +- memset(bv, 0, sizeof(*bv)); +-} +- +-isns_bitvector_t * +-isns_bitvector_alloc(void) +-{ +- return isns_calloc(1, sizeof(isns_bitvector_t)); +-} +- +-void +-isns_bitvector_free(isns_bitvector_t *bv) +-{ +- if (bv) { +- isns_free(bv->ib_words); +- memset(bv, 0xa5, sizeof(*bv)); +- isns_free(bv); +- } +-} +- +-/* +- * Helper function to locate bit +- */ +-uint32_t * +-__isns_bitvector_find_word(const isns_bitvector_t *bv, unsigned int bit) +-{ +- uint32_t *wp, *end; +- +- if (bv->ib_words == NULL) +- return NULL; +- +- wp = bv->ib_words; +- end = wp + bv->ib_count; +- while (wp < end) { +- unsigned int base, rlen; +- +- base = wp[0]; +- rlen = wp[1]; +- +- isns_assert(!(base % 32)); +- if (base <= bit && bit < base + rlen * 32) +- return wp + 2 + ((bit - base) / 32); +- +- wp += 2 + rlen; +- isns_assert(wp <= end); +- } +- +- return NULL; +-} +- +-/* +- * Insert words in the middle of the array +- */ +-static inline void +-__isns_bitvector_insert_words(isns_bitvector_t *bv, +- unsigned int offset, unsigned int count) +-{ +- bv->ib_words = isns_realloc(bv->ib_words, +- (bv->ib_count + count) * sizeof(uint32_t)); +- +- /* If we insert in the middle, shift out the tail +- * to make room for the new range. */ +- isns_assert(offset <= bv->ib_count); +- if (offset < bv->ib_count) { +- memmove(bv->ib_words + offset + count, +- bv->ib_words + offset, +- (bv->ib_count - offset) * sizeof(uint32_t)); +- } +- +- memset(bv->ib_words + offset, 0, count * sizeof(uint32_t)); +- bv->ib_count += count; +-} +- +-/* +- * Insert a new range +- */ +-static inline uint32_t * +-__isns_bitvector_insert_range(isns_bitvector_t *bv, +- unsigned int offset, unsigned int base) +-{ +- uint32_t *pos; +- +- __isns_bitvector_insert_words(bv, offset, 3); +- +- pos = bv->ib_words + offset; +- +- *pos++ = base & ~31; +- *pos++ = 1; +- +- return pos; +-} +- +-/* +- * Extend an existing range +- * @offset marks the beginning of the existing range. +- */ +-static inline uint32_t * +-__isns_bitvector_extend_range(isns_bitvector_t *bv, +- unsigned int offset, unsigned int count) +-{ +- uint32_t *pos, rlen; +- +- /* Find the end of the range */ +- pos = bv->ib_words + offset; +- rlen = pos[1]; +- +- __isns_bitvector_insert_words(bv, offset + 2 + rlen, count); +- +- pos = bv->ib_words + offset; +- pos[1] += count; +- +- /* Return pointer to the last word of the new range. */ +- return pos + 2 + rlen + count - 1; +-} +- +-/* +- * Find a suitable range for insertion +- */ +-static uint32_t * +-__isns_bitvector_find_insert_word(isns_bitvector_t *bv, unsigned int bit) +-{ +- uint32_t *wp, *end; +- +- if (bv->ib_words == NULL) +- return __isns_bitvector_insert_range(bv, 0, bit); +- +- wp = bv->ib_words; +- end = wp + bv->ib_count; +- while (wp < end) { +- unsigned int base, rlen, distance; +- +- base = wp[0]; +- rlen = wp[1]; +- +- isns_assert(!(base % 32)); +- +- if (bit < base) { +- return __isns_bitvector_insert_range(bv, +- wp - bv->ib_words, bit); +- } +- +- distance = (bit - base) / 32; +- if (distance < rlen) { +- /* This bit is within range */ +- return wp + 2 + distance; +- } +- +- /* Is it efficient to extend this range? +- * The break even point is if we have to add +- * 3 words to extend the range, because a new +- * range would be at least that much. +- */ +- if (distance + 1 <= rlen + 3) { +- return __isns_bitvector_extend_range(bv, +- wp - bv->ib_words, +- distance + 1 - rlen); +- } +- +- wp += 2 + rlen; +- isns_assert(wp <= end); +- } +- +- /* No suitable range found. Append one at the end */ +- return __isns_bitvector_insert_range(bv, +- bv->ib_count, bit); +-} +- +-/* +- * After clearing a bit, check if the bitvector can be +- * compacted. +- */ +-static void +-__isns_bitvector_compact(isns_bitvector_t *bv) +-{ +- uint32_t *src, *dst, *end; +- unsigned int dst_base = 0, dst_len = 0; +- +- if (bv->ib_words == NULL) +- return; +- +- src = dst = bv->ib_words; +- end = src + bv->ib_count; +- while (src < end) { +- unsigned int base, rlen; +- +- base = *src++; +- rlen = *src++; +- +- /* Consume leading NUL words */ +- while (rlen && *src == 0) { +- base += 32; +- src++; +- rlen--; +- } +- +- /* Consume trailing NUL words */ +- while (rlen && src[rlen-1] == 0) +- rlen--; +- +- if (rlen != 0) { +- if (dst_len && dst_base + 32 * dst_len == base) { +- /* We can extend the previous run */ +- } else { +- /* New run. Close off the previous one, +- * if we had one. */ +- if (dst_len != 0) { +- dst[0] = dst_base; +- dst[1] = dst_len; +- dst += 2 + dst_len; +- } +- +- dst_base = base; +- dst_len = 0; +- } +- +- while (rlen--) +- dst[2 + dst_len++] = *src++; +- } +- +- isns_assert(src <= end); +- } +- +- +- if (dst_len != 0) { +- dst[0] = dst_base; +- dst[1] = dst_len; +- dst += 2 + dst_len; +- } +- +- bv->ib_count = dst - bv->ib_words; +- if (bv->ib_count == 0) +- isns_bitvector_destroy(bv); +-} +- +-/* +- * Test the value of a single bit +- */ +-int +-isns_bitvector_test_bit(const isns_bitvector_t *bv, unsigned int bit) +-{ +- const uint32_t *pos; +- uint32_t mask; +- +- pos = __isns_bitvector_find_word(bv, bit); +- if (pos == NULL) +- return 0; +- +- mask = 1 << (bit % 32); +- return !!(*pos & mask); +-} +- +-int +-isns_bitvector_clear_bit(isns_bitvector_t *bv, unsigned int bit) +-{ +- uint32_t *pos, oldval, mask; +- +- pos = __isns_bitvector_find_word(bv, bit); +- if (pos == NULL) +- return 0; +- +- mask = 1 << (bit % 32); +- oldval = *pos; +- *pos &= ~mask; +- +- __isns_bitvector_compact(bv); +- return !!(oldval & mask); +-} +- +-int +-isns_bitvector_set_bit(isns_bitvector_t *bv, unsigned int bit) +-{ +- uint32_t *pos, oldval = 0, mask; +- +- mask = 1 << (bit % 32); +- +- pos = __isns_bitvector_find_insert_word(bv, bit); +- if (pos != NULL) { +- oldval = *pos; +- *pos |= mask; +- +- return !!(oldval & mask); +- } +- +- return 0; +-} +- +-int +-isns_bitvector_is_empty(const isns_bitvector_t *bv) +-{ +- uint32_t *wp, *end; +- +- if (bv == NULL || bv->ib_count == 0) +- return 1; +- +- /* In theory, we should never have a non-compacted +- * empty bitvector, as the only way to get one +- * is through clear_bit. +- * Better safe than sorry... +- */ +- +- wp = bv->ib_words; +- end = wp + bv->ib_count; +- while (wp < end) { +- unsigned int base, rlen; +- +- base = *wp++; +- rlen = *wp++; +- +- while (rlen--) { +- if (*wp++) +- return 0; +- } +- isns_assert(wp <= end); +- } +- +- return 1; +-} +- +-int +-isns_bitvector_intersect(const isns_bitvector_t *a, +- const isns_bitvector_t *b, +- isns_bitvector_t *result) +-{ +- const uint32_t *runa, *runb, *enda, *endb; +- const uint32_t *wpa = NULL, *wpb = NULL; +- uint32_t bita = 0, lena = 0, bitb = 0, lenb = 0; +- int found = -1; +- +- if (a == NULL || b == NULL) +- return -1; +- +- /* Returning the intersect is not implemented yet. */ +- isns_assert(result == NULL); +- +- runa = a->ib_words; +- enda = runa + a->ib_count; +- runb = b->ib_words; +- endb = runb + b->ib_count; +- +- while (1) { +- unsigned int skip; +- +- if (lena == 0) { +-next_a: +- if (runa >= enda) +- break; +- bita = *runa++; +- lena = *runa++; +- wpa = runa; +- runa += lena; +- lena *= 32; +- } +- +- if (lenb == 0) { +-next_b: +- if (runb >= endb) +- break; +- bitb = *runb++; +- lenb = *runb++; +- wpb = runb; +- runb += lenb; +- lenb *= 32; +- } +- +- if (bita < bitb) { +- skip = bitb - bita; +- +- /* range A ends before range B starts. +- * Proceed to next run in vector A. */ +- if (skip >= lena) +- goto next_a; +- +- bita += skip; +- lena -= skip; +- wpa += skip / 32; +- } else +- if (bitb < bita) { +- skip = bita - bitb; +- +- /* range B ends before range A starts. +- * Proceed to next run in vector B. */ +- if (skip >= lenb) +- goto next_b; +- +- bitb += skip; +- lenb -= skip; +- wpb += skip / 32; +- } +- +- isns_assert(bita == bitb); +- +- while (lena && lenb) { +- uint32_t intersect; +- +- intersect = *wpa & *wpb; +- +- if (!intersect) +- goto next_word; +- +- /* Find the bit */ +- if (found < 0) { +- uint32_t mask = intersect; +- +- found = bita; +- while (!(mask & 1)) { +- found++; +- mask >>= 1; +- } +- } +- +- if (result == NULL) +- return found; +- +- /* Append to result vector */ +- /* FIXME: TBD */ +- +-next_word: +- bita += 32; lena -= 32; wpa++; +- bitb += 32; lenb -= 32; wpb++; +- } +- } +- +- return found; +-} +- +-/* +- * Iterate over the bit vector +- */ +-void +-isns_bitvector_foreach(const isns_bitvector_t *bv, +- int (*cb)(uint32_t, void *), +- void *user_data) +-{ +- uint32_t *wp, *end; +- +- wp = bv->ib_words; +- end = wp + bv->ib_count; +- while (wp < end) { +- unsigned int base, rlen, bits; +- +- base = wp[0]; +- rlen = wp[1]; +- bits = rlen * 32; +- wp += 2; +- +- while (rlen--) { +- uint32_t mask, word; +- +- word = *wp++; +- for (mask = 1; mask; mask <<= 1, ++base) { +- if (word & mask) +- cb(base, user_data); +- } +- } +- isns_assert(wp <= end); +- } +-} +- +-void +-isns_bitvector_dump(const isns_bitvector_t *bv, isns_print_fn_t *fn) +-{ +- uint32_t *wp, *end; +- +- fn("Bit Vector %p (%u words):", bv, bv->ib_count); +- +- wp = bv->ib_words; +- end = wp + bv->ib_count; +- while (wp < end) { +- unsigned int base, rlen, bits; +- +- base = wp[0]; +- rlen = wp[1]; +- bits = rlen * 32; +- wp += 2; +- +- fn(" <%u:", base); +- while (rlen--) +- fn(" 0x%x", *wp++); +- fn(">"); +- +- isns_assert(wp <= end); +- } +- +- if (bv->ib_count == 0) +- fn(""); +- fn("\n"); +-} +- +-static inline void +-__isns_bitvector_print_next(uint32_t first, uint32_t last, +- isns_print_fn_t *fn) +-{ +- switch (last - first) { +- case 0: +- return; +- case 1: +- fn(", %u", last); +- break; +- default: +- fn("-%u", last); +- break; +- } +-} +- +-void +-isns_bitvector_print(const isns_bitvector_t *bv, +- isns_print_fn_t *fn) +-{ +- uint32_t *wp, *end, first = 0, next = 0; +- const char *sepa = ""; +- +- wp = bv->ib_words; +- end = wp + bv->ib_count; +- while (wp < end) { +- unsigned int base, rlen, bits; +- +- base = wp[0]; +- rlen = wp[1]; +- bits = rlen * 32; +- wp += 2; +- +- while (rlen--) { +- uint32_t mask, word; +- +- word = *wp++; +- for (mask = 1; mask; mask <<= 1, ++base) { +- if (word & mask) { +- if (next++) +- continue; +- fn("%s%u", sepa, base); +- sepa = ", "; +- first = base; +- next = base + 1; +- } else { +- if (next) +- __isns_bitvector_print_next(first, next - 1, fn); +- first = next = 0; +- } +- } +- } +- isns_assert(wp <= end); +- } +- +- if (next) +- __isns_bitvector_print_next(first, next - 1, fn); +- +- if (*sepa == '\0') +- fn(""); +- fn("\n"); +-} +- +-#ifdef TEST +-int +-main(void) +-{ +- isns_bitvector_t a, b; +- int i; +- +- isns_bitvector_init(&a); +- isns_bitvector_set_bit(&a, 0); +- isns_bitvector_dump(&a, isns_print_stdout); +- isns_bitvector_set_bit(&a, 1); +- isns_bitvector_set_bit(&a, 16); +- isns_bitvector_set_bit(&a, 32); +- isns_bitvector_set_bit(&a, 64); +- isns_bitvector_dump(&a, isns_print_stdout); +- isns_bitvector_set_bit(&a, 8192); +- isns_bitvector_set_bit(&a, 8196); +- isns_bitvector_set_bit(&a, 8194); +- isns_bitvector_dump(&a, isns_print_stdout); +- isns_bitvector_set_bit(&a, 2052); +- isns_bitvector_set_bit(&a, 2049); +- isns_bitvector_set_bit(&a, 2051); +- isns_bitvector_set_bit(&a, 2050); +- isns_bitvector_dump(&a, isns_print_stdout); +- isns_bitvector_print(&a, isns_print_stdout); +- isns_bitvector_destroy(&a); +- +- isns_bitvector_init(&a); +- for (i = 127; i >= 0; --i) +- isns_bitvector_set_bit(&a, i); +- isns_bitvector_dump(&a, isns_print_stdout); +- printf("[Compacting]\n"); +- __isns_bitvector_compact(&a); +- isns_bitvector_dump(&a, isns_print_stdout); +- isns_bitvector_print(&a, isns_print_stdout); +- isns_bitvector_destroy(&a); +- +- isns_bitvector_init(&a); +- for (i = 0; i < 128; ++i) +- isns_bitvector_set_bit(&a, i); +- isns_bitvector_dump(&a, isns_print_stdout); +- isns_bitvector_print(&a, isns_print_stdout); +- isns_bitvector_destroy(&a); +- +- isns_bitvector_init(&a); +- isns_bitvector_init(&b); +- isns_bitvector_set_bit(&a, 0); +- isns_bitvector_set_bit(&a, 77); +- isns_bitvector_set_bit(&a, 249); +- isns_bitvector_set_bit(&a, 102); +- +- isns_bitvector_set_bit(&b, 1); +- isns_bitvector_set_bit(&b, 76); +- isns_bitvector_set_bit(&b, 250); +- isns_bitvector_set_bit(&b, 102); +- i = isns_bitvector_intersect(&a, &b, NULL); +- if (i != 102) +- fprintf(stderr, "*** BAD: Intersect should return 102 (got %d)! ***\n", i); +- else +- printf("Intersect okay: %d\n", i); +- isns_bitvector_destroy(&a); +- isns_bitvector_destroy(&b); +- +- isns_bitvector_init(&a); +- isns_bitvector_set_bit(&a, 0); +- isns_bitvector_set_bit(&a, 1); +- isns_bitvector_clear_bit(&a, 1); +- isns_bitvector_clear_bit(&a, 0); +- isns_bitvector_dump(&a, isns_print_stdout); +- isns_bitvector_print(&a, isns_print_stdout); +- isns_bitvector_destroy(&a); +- return 0; +-} +-#endif +diff --git a/utils/open-isns/buffer.c b/utils/open-isns/buffer.c +deleted file mode 100644 +index 279ab76..0000000 +--- a/utils/open-isns/buffer.c ++++ /dev/null +@@ -1,407 +0,0 @@ +-/* +- * Buffer handling functions +- * +- * Copyright (C) 2003-2007, Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include /* ntohl&htonl */ +-#include "buffer.h" +-#include "util.h" /* htonll */ +- +-static int buf_drain(buf_t *bp); +- +-buf_t * +-buf_alloc(size_t size) +-{ +- buf_t *bp; +- +- bp = isns_calloc(1, sizeof(*bp)); +- buf_init_empty(bp, size); +- +- return bp; +-} +- +-buf_t * +-buf_open(const char *filename, int flags) +-{ +- static const unsigned int buflen = 4096; +- buf_t *bp; +- int oerr; +- +- if (!(bp = isns_calloc(1, sizeof(*bp) + buflen))) +- return NULL; +- buf_init(bp, (bp + 1), buflen); +- +- switch (flags & O_ACCMODE) { +- case O_RDONLY: +- bp->write_mode = 0; +- break; +- +- case O_WRONLY: +- bp->write_mode = 1; +- break; +- +- default: +- errno = EINVAL; +- goto failed; +- } +- +- if (!filename || !strcmp(filename, "-")) { +- bp->fd = dup(bp->write_mode? 1 : 0); +- } else { +- bp->fd = open(filename, flags, 0666); +- } +- +- if (bp->fd < 0) +- goto failed; +- +- return bp; +- +-failed: oerr = errno; +- isns_free(bp); +- errno = oerr; +- return NULL; +-} +- +-buf_t * +-buf_dup(const buf_t *src) +-{ +- buf_t *bp; +- +- bp = buf_alloc(src->max_size); +- buf_put(bp, src->base + src->head, src->tail - src->head); +- +- bp->addr = src->addr; +- bp->addrlen = src->addrlen; +- return bp; +-} +- +-void +-buf_close(buf_t *bp) +-{ +- if (bp->write_mode) +- buf_drain(bp); +- if (bp->fd >= 0) +- close(bp->fd); +- bp->fd = -1; +- isns_free(bp); +-} +- +-void +-buf_free(buf_t *bp) +-{ +- if (!bp) +- return; +- if (bp->allocated) +- isns_free(bp->base); +- isns_free(bp); +-} +- +-void +-buf_list_free(buf_t *bp) +-{ +- buf_t *next; +- +- while (bp) { +- next = bp->next; +- buf_free(bp); +- bp = next; +- } +-} +- +-void +-buf_init(buf_t *bp, void *mem, size_t len) +-{ +- memset(bp, 0, sizeof(*bp)); +- bp->base = (unsigned char *) mem; +- bp->size = len; +- bp->max_size = len; +- bp->fd = -1; +-} +- +-void +-buf_init_empty(buf_t *bp, size_t len) +-{ +- memset(bp, 0, sizeof(*bp)); +- bp->max_size = len; +- bp->fd = -1; +-} +- +-void +-buf_set(buf_t *bp, void *mem, size_t len) +-{ +- buf_init(bp, mem, len); +- bp->tail = len; +-} +- +-void +-buf_clear(buf_t *bp) +-{ +- bp->head = bp->tail = 0; +-} +- +-int +-buf_fill(buf_t *bp) +-{ +- int n; +- +- if (bp->head || bp->tail) +- buf_compact(bp); +- +- if (bp->write_mode || bp->fd < 0) +- return 0; +- +- n = read(bp->fd, bp->base + bp->tail, buf_tailroom(bp)); +- if (n < 0) { +- warn("read error"); +- return 0; +- } +- +- bp->tail += n; +- return n; +-} +- +-int +-buf_drain(buf_t *bp) +-{ +- int n; +- +- if (!bp->write_mode || bp->fd < 0) +- return 0; +- +- n = write(bp->fd, bp->base + bp->head, buf_avail(bp)); +- if (n < 0) { +- warn("write error"); +- return 0; +- } +- +- bp->head += n; +- return n; +-} +- +-int +-__buf_resize(buf_t *bp, size_t new_size) +-{ +- void *new_base; +- +- if (new_size > bp->max_size) +- return 0; +- isns_assert(bp->allocated || bp->base == NULL); +- +- new_size = (new_size + 127) & ~127; +- if (new_size > bp->max_size) +- new_size = bp->max_size; +- +- new_base = isns_realloc(bp->base, new_size); +- if (new_base == NULL) +- return 0; +- +- bp->base = new_base; +- bp->size = new_size; +- bp->allocated = 1; +- return new_size; +-} +- +-buf_t * +-buf_split(buf_t **to_split, size_t size) +-{ +- buf_t *old = *to_split, *new; +- size_t avail; +- +- avail = buf_avail(old); +- if (size > avail) +- return NULL; +- +- if (size == avail) { +- *to_split = NULL; +- return old; +- } +- +- new = buf_alloc(size); +- buf_put(new, buf_head(old), size); +- buf_pull(old, size); +- +- return new; +-} +- +-int +-buf_seek(buf_t *bp, off_t offset) +-{ +- if (bp->write_mode && !buf_drain(bp)) +- return 0; +- if (lseek(bp->fd, offset, SEEK_SET) < 0) { +- warn("cannot seek to offset %ld", (long) offset); +- return 0; +- } +- return 1; +-} +- +-int +-buf_get(buf_t *bp, void *mem, size_t len) +-{ +- caddr_t dst = (caddr_t) mem; +- unsigned int total = len, copy; +- +- while (len) { +- if ((copy = buf_avail(bp)) > len) +- copy = len; +- if (copy == 0) { +- if (!buf_fill(bp)) +- return 0; +- continue; +- } +- if (dst) { +- memcpy(dst, bp->base + bp->head, copy); +- dst += copy; +- } +- bp->head += copy; +- len -= copy; +- } +- return total; +-} +- +-int +-buf_get32(buf_t *bp, uint32_t *vp) +-{ +- if (!buf_get(bp, vp, 4)) +- return 0; +- *vp = ntohl(*vp); +- return 1; +-} +- +-int +-buf_get64(buf_t *bp, uint64_t *vp) +-{ +- if (!buf_get(bp, vp, 8)) +- return 0; +- *vp = ntohll(*vp); +- return 1; +-} +- +-int +-buf_gets(buf_t *bp, char *stringbuf, size_t size) +-{ +- uint32_t len, copy; +- +- if (size == 0) +- return 0; +- +- if (!buf_get32(bp, &len)) +- return 0; +- +- if ((copy = len) >= size) +- copy = size - 1; +- +- if (!buf_get(bp, stringbuf, copy)) +- return 0; +- stringbuf[copy] = '\0'; +- +- /* Pull remaining bytes */ +- if (copy != len && !buf_pull(bp, len - copy)) +- return 0; +- +- return copy + 1; +-} +- +-int +-buf_put(buf_t *bp, const void *mem, size_t len) +-{ +- caddr_t src = (caddr_t) mem; +- unsigned int total = len, copy; +- +- while (len) { +- if ((copy = bp->size - bp->tail) > len) +- copy = len; +- if (copy == 0) { +- if (buf_drain(bp)) { +- buf_compact(bp); +- continue; +- } +- if (__buf_resize(bp, bp->tail + len)) { +- buf_compact(bp); +- continue; +- } +- return 0; +- } +- if (src) { +- memcpy(bp->base + bp->tail, src, copy); +- src += copy; +- } +- bp->tail += copy; +- len -= copy; +- } +- return total; +-} +- +-int +-buf_putc(buf_t *bp, int byte) +-{ +- unsigned char c = byte; +- +- return buf_put(bp, &c, 1); +-} +- +-int +-buf_put32(buf_t *bp, uint32_t val) +-{ +- val = htonl(val); +- if (!buf_put(bp, &val, 4)) +- return 0; +- return 1; +-} +- +-int +-buf_put64(buf_t *bp, uint64_t val) +-{ +- val = htonll(val); +- return buf_put(bp, &val, 8); +-} +- +-int +-buf_puts(buf_t *bp, const char *sp) +-{ +- uint32_t len = 0; +- +- if (sp) +- len = strlen(sp); +- return buf_put32(bp, len) && buf_put(bp, sp, len); +-} +- +-void +-buf_compact(buf_t *bp) +-{ +- unsigned int count; +- +- if (bp->head == 0) +- return; +- +- count = bp->tail - bp->head; +- memmove(bp->base, bp->base + bp->head, count); +- bp->tail -= bp->head; +- bp->head = 0; +-} +- +-void +-buf_list_append(buf_t **list, buf_t *bp) +-{ +- bp->next = NULL; +- while (*list) +- list = &(*list)->next; +- *list = bp; +-} +- +-int +-buf_truncate(buf_t *bp, size_t len) +-{ +- if (bp->head + len > bp->tail) +- return 0; +- +- bp->tail = bp->head + len; +- return 1; +-} +diff --git a/utils/open-isns/buffer.h b/utils/open-isns/buffer.h +deleted file mode 100644 +index 75ba910..0000000 +--- a/utils/open-isns/buffer.h ++++ /dev/null +@@ -1,141 +0,0 @@ +-/* +- * Buffer handling functions +- * +- * Copyright (C) 2003-2006, Olaf Kirch +- */ +- +-#ifndef BUFFER_H +-#define BUFFER_H +- +-#include +-#include +-#include +- +-typedef struct isns_buf { +- struct isns_buf * next; +- unsigned char * base; +- unsigned int head, tail, size, max_size; +- unsigned int write_mode : 1, +- allocated : 1; +- int fd; +- +- /* Anonymous union for misc stuff */ +- union { +- struct { +- struct sockaddr_storage addr; +- socklen_t addrlen; +- }; +- }; +-} buf_t; +- +-extern buf_t * buf_open(const char *, int); +-extern buf_t * buf_alloc(size_t); +-extern buf_t * buf_dup(const buf_t *); +-extern void buf_init(buf_t *, void *, size_t); +-extern void buf_init_empty(buf_t *, size_t); +-extern void buf_set(buf_t *, void *, size_t); +- +-extern void buf_clear(buf_t *); +-extern void buf_close(buf_t *); +-extern void buf_destroy(buf_t *); +-extern void buf_free(buf_t *); +-extern void buf_list_free(buf_t *); +- +-extern int buf_get(buf_t *, void *, size_t); +-extern int buf_get32(buf_t *, uint32_t *); +-extern int buf_get64(buf_t *, uint64_t *); +-extern int buf_gets(buf_t *, char *, size_t); +-extern int buf_put(buf_t *, const void *, size_t); +-extern int buf_put32(buf_t *, uint32_t); +-extern int buf_put64(buf_t *, uint64_t); +-extern int buf_puts(buf_t *, const char *); +-extern int buf_putc(buf_t *, int); +-extern int buf_read(buf_t *, int); +-extern int buf_seek(buf_t *bp, off_t offset); +-extern int buf_truncate(buf_t *, size_t); +-extern void buf_compact(buf_t *); +-extern buf_t * buf_split(buf_t **to_split, size_t len); +-extern int __buf_resize(buf_t *, size_t); +- +-extern void buf_list_append(buf_t **, buf_t *); +- +-static inline size_t +-buf_avail(const buf_t *bp) +-{ +- return bp->tail - bp->head; +-} +- +-static inline size_t +-buf_tailroom(const buf_t *bp) +-{ +- return bp->max_size - bp->tail; +-} +- +-static inline size_t +-buf_size(const buf_t *bp) +-{ +- return bp->size; +-} +- +-static inline void * +-buf_head(const buf_t *bp) +-{ +- return bp->base + bp->head; +-} +- +-static inline void * +-buf_tail(const buf_t *bp) +-{ +- return bp->base + bp->tail; +-} +- +-static inline int +-buf_reserve(buf_t *bp, size_t len) +-{ +- if (bp->head != bp->tail) +- return 0; +- if (bp->max_size - bp->head < len) +- return 0; +- bp->head += len; +- bp->tail += len; +- return 1; +-} +- +-static inline int +-buf_pull(buf_t *bp, size_t len) +-{ +- if (len > buf_avail(bp)) +- return 0; +- bp->head += len; +- return 1; +-} +- +-static inline void * +-buf_push(buf_t *bp, size_t len) +-{ +- if (bp->max_size - bp->tail < len) +- return NULL; +- +- if (bp->tail + len > bp->size +- && !__buf_resize(bp, bp->tail + len)) +- return NULL; +- +- bp->tail += len; +- return bp->base + bp->tail - len; +-} +- +-static inline void * +-buf_push_head(buf_t *bp, size_t len) +-{ +- if (bp->head < len) +- return NULL; +- +- if (bp->tail > bp->size +- && !__buf_resize(bp, bp->tail)) +- return NULL; +- +- bp->head -= len; +- return bp->base + bp->head; +-} +- +-#endif /* BUFFER_H */ +diff --git a/utils/open-isns/callback.c b/utils/open-isns/callback.c +deleted file mode 100644 +index ecdabd7..0000000 +--- a/utils/open-isns/callback.c ++++ /dev/null +@@ -1,148 +0,0 @@ +-/* +- * iSNS object callbacks for SCN and other stuff +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include "isns.h" +-#include "objects.h" +-#include "vendor.h" +-#include "attrs.h" +-#include "util.h" +- +-typedef struct isns_object_notifier isns_object_notifier_t; +-struct isns_object_notifier { +- isns_list_t list; +- isns_db_callback_t * func; +- void * data; +-}; +- +-typedef struct isns_cb_event isns_cb_event_t; +-struct isns_cb_event { +- isns_list_t list; +- isns_db_event_t info; +-}; +- +-static ISNS_LIST_DECLARE(notifiers); +-static ISNS_LIST_DECLARE(events); +- +-static inline void +-__isns_db_event(isns_object_t *dst, +- isns_object_t *obj, +- unsigned int bits, +- isns_object_t *trigger) +-{ +- isns_cb_event_t *ev; +- +- ev = isns_calloc(1, sizeof(*ev)); +- ev->info.ie_recipient = isns_object_get(dst); +- ev->info.ie_object = isns_object_get(obj); +- ev->info.ie_bits = bits; +- ev->info.ie_trigger = isns_object_get(trigger); +- isns_list_append(&events, &ev->list); +-} +- +-void +-isns_object_event(isns_object_t *obj, +- unsigned int bits, +- isns_object_t *trigger) +-{ +- __isns_db_event(NULL, obj, bits, trigger); +-} +- +-void +-isns_unicast_event(isns_object_t *dst, +- isns_object_t *obj, +- unsigned int bits, +- isns_object_t *trigger) +-{ +- __isns_db_event(dst, obj, bits, trigger); +-} +- +-/* +- * Given an object pair and an event bitmask, +- * invoke all callbacks +- */ +-static inline void +-isns_call_callbacks(isns_db_event_t *ev) +-{ +- isns_object_t *obj = ev->ie_object; +- isns_list_t *pos, *next; +- +- ev->ie_bits |= obj->ie_scn_bits; +- if (ev->ie_bits == 0) +- return; +- isns_list_foreach(¬ifiers, pos, next) { +- isns_object_notifier_t *not; +- +- not = isns_list_item(isns_object_notifier_t, list, pos); +- not->func(ev, not->data); +- } +- obj->ie_scn_bits = 0; +-} +- +-void +-isns_flush_events(void) +-{ +- while (!isns_list_empty(&events)) { +- isns_cb_event_t *ev = isns_list_item(isns_cb_event_t, list, events.next); +- +- isns_call_callbacks(&ev->info); +- isns_object_release(ev->info.ie_recipient); +- isns_object_release(ev->info.ie_object); +- isns_object_release(ev->info.ie_trigger); +- isns_list_del(&ev->list); +- isns_free(ev); +- } +-} +- +-void +-isns_register_callback(isns_db_callback_t *func, +- void *user_data) +-{ +- isns_object_notifier_t *not; +- +- not = isns_calloc(1, sizeof(*not)); +- not->func = func; +- not->data = user_data; +- +- isns_list_append(¬ifiers, ¬->list); +-} +- +-const char * +-isns_event_string(unsigned int bits) +-{ +- static const char *names[16] = { +- [ISNS_SCN_DD_MEMBER_ADDED] = "member added", +- [ISNS_SCN_DD_MEMBER_REMOVED] = "member removed", +- [ISNS_SCN_OBJECT_UPDATED] = "updated", +- [ISNS_SCN_OBJECT_ADDED] = "added", +- [ISNS_SCN_OBJECT_REMOVED] = "removed", +- [ISNS_SCN_MANAGEMENT_REGISTRATION]= "mgmt registration", +- [ISNS_SCN_TARGET_AND_SELF_ONLY] = "target+self", +- [ISNS_SCN_INITIATOR_AND_SELF_ONLY]= "initiator+self", +- }; +- static char buffer[128]; +- unsigned int pos = 0, i; +- +- +- for (i = 0; i < 16; ++i, bits >>= 1) { +- if (!(bits & 1)) +- continue; +- +- if (names[i]) { +- snprintf(buffer + pos, sizeof(buffer) - pos, +- "%s%s", pos? ", " : "", names[i]); +- } else { +- snprintf(buffer + pos, sizeof(buffer) - pos, +- "%sevent %u", pos? ", " : "", i); +- } +- pos = strlen(buffer); +- } +- if (pos == 0) +- return ""; +- +- return buffer; +-} +diff --git a/utils/open-isns/client.c b/utils/open-isns/client.c +deleted file mode 100644 +index c470048..0000000 +--- a/utils/open-isns/client.c ++++ /dev/null +@@ -1,205 +0,0 @@ +-/* +- * Client functions +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include "security.h" +-#include "util.h" +-#include "internal.h" +-#include "config.h" +- +-static isns_client_t * +-__isns_create_default_client(isns_socket_t *sock, isns_security_t *ctx, +- const char *source_name) +-{ +- isns_client_t *clnt; +- +- clnt = isns_calloc(1, sizeof(*clnt)); +- +- if (!source_name) +- source_name = isns_config.ic_source_name; +- +- clnt->ic_source = isns_source_create_iscsi(source_name); +- clnt->ic_socket = sock; +- +- isns_socket_set_security_ctx(clnt->ic_socket, ctx); +- +- return clnt; +-} +- +-isns_client_t * +-isns_create_client(isns_security_t *ctx, const char *source_name) +-{ +- isns_socket_t *sock; +- const char *server_name; +- +- server_name = isns_config.ic_server_name; +- if (!strcasecmp(server_name, "SLP:") +- && !(server_name = isns_slp_find())) { +- isns_error("Unable to locate iSNS server through SLP\n"); +- return NULL; +- } +- +- sock = isns_create_bound_client_socket( +- isns_config.ic_bind_address, +- server_name, +- "isns", 0, SOCK_STREAM); +- if (sock == NULL) { +- isns_error("Unable to create socket for host \"%s\"\n", +- isns_config.ic_server_name); +- return NULL; +- } +- +- return __isns_create_default_client(sock, +- ctx? : isns_default_security_context(0), +- source_name); +-} +- +-isns_client_t * +-isns_create_default_client(isns_security_t *ctx) +-{ +- return isns_create_client(ctx, isns_config.ic_source_name); +-} +- +-isns_client_t * +-isns_create_local_client(isns_security_t *ctx, const char *source_name) +-{ +- isns_socket_t *sock; +- +- if (isns_config.ic_control_socket == NULL) +- isns_fatal("Cannot use local mode: no local control socket\n"); +- +- sock = isns_create_client_socket(isns_config.ic_control_socket, +- NULL, 0, SOCK_STREAM); +- if (sock == NULL) { +- isns_error("Unable to create control socket (%s)\n", +- isns_config.ic_control_socket); +- return NULL; +- } +- +- return __isns_create_default_client(sock, ctx, source_name); +-} +- +-int +-isns_client_call(isns_client_t *clnt, +- isns_simple_t **inout) +-{ +- return isns_simple_call(clnt->ic_socket, inout); +-} +- +-void +-isns_client_destroy(isns_client_t *clnt) +-{ +- if (clnt->ic_socket) +- isns_socket_free(clnt->ic_socket); +- if (clnt->ic_source) +- isns_source_release(clnt->ic_source); +- isns_free(clnt); +-} +- +-/* +- * Get the local address +- */ +-int +-isns_client_get_local_address(const isns_client_t *clnt, +- isns_portal_info_t *portal_info) +-{ +- return isns_socket_get_portal_info(clnt->ic_socket, portal_info); +-} +- +-/* +- * Create a security context +- */ +-static isns_security_t * +-__create_security_context(const char *name, const char *auth_key, +- const char *server_key) +-{ +-#ifdef WITH_SECURITY +- isns_security_t *ctx; +- isns_principal_t *princ; +-#endif /* WITH_SECURITY */ +- +- if (!isns_config.ic_security) +- return NULL; +- +-#ifndef WITH_SECURITY +- isns_error("Cannot create security context: security disabled at build time\n"); +- return NULL; +-#else /* WITH_SECURITY */ +- ctx = isns_create_dsa_context(); +- if (ctx == NULL) +- isns_fatal("Unable to create security context\n"); +- +- /* Load my own key */ +- princ = isns_security_load_privkey(ctx, auth_key); +- if (!princ) +- isns_fatal("Unable to load private key from %s\n", +- auth_key); +- +- isns_principal_set_name(princ, name); +- isns_security_set_identity(ctx, princ); +- +- if (server_key) { +- /* We're a client, and we want to load the +- * server's public key in order to authenticate +- * the server's responses. +- */ +- princ = isns_security_load_pubkey(ctx, server_key); +- if (!princ) +- isns_fatal("Unable to load public key from %s\n", +- server_key); +- +- /* Do *not* set a name for this principal - +- * this will be the default principal used when +- * verifying the server's reply, which is a good thing +- * because we don't know what SPI the server will +- * be using. */ +- isns_add_principal(ctx, princ); +- +- /* But set a policy for the server which allows it +- to send ESI and SCN messages */ +- isns_principal_set_policy(princ, isns_policy_server()); +- } +- +- return ctx; +-#endif /* WITH_SECURITY */ +-} +- +-/* +- * Create the default security context +- */ +-isns_security_t * +-isns_default_security_context(int server_only) +-{ +- static isns_security_t *ctx; +- +- if (ctx == NULL) +- ctx = __create_security_context(isns_config.ic_auth_name, +- isns_config.ic_auth_key_file, +- server_only? NULL : isns_config.ic_server_key_file); +- return ctx; +-} +- +-/* +- * Create the control security context +- */ +-isns_security_t * +-isns_control_security_context(int server_only) +-{ +- static isns_security_t *ctx; +- +- if (ctx == NULL) +- ctx = __create_security_context(isns_config.ic_control_name, +- isns_config.ic_control_key_file, +- server_only? NULL : isns_config.ic_server_key_file); +- return ctx; +-} +diff --git a/utils/open-isns/compat/my_getopt.c b/utils/open-isns/compat/my_getopt.c +deleted file mode 100644 +index 512b0ae..0000000 +--- a/utils/open-isns/compat/my_getopt.c ++++ /dev/null +@@ -1,271 +0,0 @@ +-/* +- * my_getopt.c - my re-implementation of getopt. +- * Copyright 1997, 2000, 2001, 2002, Benjamin Sittler +- * +- * Permission is hereby granted, free of charge, to any person +- * obtaining a copy of this software and associated documentation +- * files (the "Software"), to deal in the Software without +- * restriction, including without limitation the rights to use, copy, +- * modify, merge, publish, distribute, sublicense, and/or sell copies +- * of the Software, and to permit persons to whom the Software is +- * furnished to do so, subject to the following conditions: +- * +- * The above copyright notice and this permission notice shall be +- * included in all copies or substantial portions of the Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +- * DEALINGS IN THE SOFTWARE. +- */ +- +-#include +-#include +-#include +-#include +-#include "my_getopt.h" +- +-int my_optind=1, my_opterr=1, my_optopt=0; +-char *my_optarg=0; +- +-/* this is the plain old UNIX getopt, with GNU-style extensions. */ +-/* if you're porting some piece of UNIX software, this is all you need. */ +-/* this supports GNU-style permution and optional arguments */ +- +-int my_getopt(int argc, char * argv[], const char *opts) +-{ +- static int charind=0; +- const char *s; +- char mode, colon_mode; +- int off = 0, opt = -1; +- +- if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+'; +- else { +- if((colon_mode = *opts) == ':') off ++; +- if(((mode = opts[off]) == '+') || (mode == '-')) { +- off++; +- if((colon_mode != ':') && ((colon_mode = opts[off]) == ':')) +- off ++; +- } +- } +- my_optarg = 0; +- if(charind) { +- my_optopt = argv[my_optind][charind]; +- for(s=opts+off; *s; s++) if(my_optopt == *s) { +- charind++; +- if((*(++s) == ':') || ((my_optopt == 'W') && (*s == ';'))) { +- if(argv[my_optind][charind]) { +- my_optarg = &(argv[my_optind++][charind]); +- charind = 0; +- } else if(*(++s) != ':') { +- charind = 0; +- if(++my_optind >= argc) { +- if(my_opterr) fprintf(stderr, +- "%s: option requires an argument -- %c\n", +- argv[0], my_optopt); +- opt = (colon_mode == ':') ? ':' : '?'; +- goto my_getopt_ok; +- } +- my_optarg = argv[my_optind++]; +- } +- } +- opt = my_optopt; +- goto my_getopt_ok; +- } +- if(my_opterr) fprintf(stderr, +- "%s: illegal option -- %c\n", +- argv[0], my_optopt); +- opt = '?'; +- if(argv[my_optind][++charind] == '\0') { +- my_optind++; +- charind = 0; +- } +- my_getopt_ok: +- if(charind && ! argv[my_optind][charind]) { +- my_optind++; +- charind = 0; +- } +- } else if((my_optind >= argc) || +- ((argv[my_optind][0] == '-') && +- (argv[my_optind][1] == '-') && +- (argv[my_optind][2] == '\0'))) { +- my_optind++; +- opt = -1; +- } else if((argv[my_optind][0] != '-') || +- (argv[my_optind][1] == '\0')) { +- char *tmp; +- int i, j, k; +- +- if(mode == '+') opt = -1; +- else if(mode == '-') { +- my_optarg = argv[my_optind++]; +- charind = 0; +- opt = 1; +- } else { +- for(i=j=my_optind; i j) { +- tmp=argv[--i]; +- for(k=i; k+1 argc) my_optind = argc; +- return opt; +-} +- +-/* this is the extended getopt_long{,_only}, with some GNU-like +- * extensions. Implements _getopt_internal in case any programs +- * expecting GNU libc getopt call it. +- */ +- +-int _my_getopt_internal(int argc, char * argv[], const char *shortopts, +- const struct option *longopts, int *longind, +- int long_only) +-{ +- char mode, colon_mode = *shortopts; +- int shortoff = 0, opt = -1; +- +- if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+'; +- else { +- if((colon_mode = *shortopts) == ':') shortoff ++; +- if(((mode = shortopts[shortoff]) == '+') || (mode == '-')) { +- shortoff++; +- if((colon_mode != ':') && ((colon_mode = shortopts[shortoff]) == ':')) +- shortoff ++; +- } +- } +- my_optarg = 0; +- if((my_optind >= argc) || +- ((argv[my_optind][0] == '-') && +- (argv[my_optind][1] == '-') && +- (argv[my_optind][2] == '\0'))) { +- my_optind++; +- opt = -1; +- } else if((argv[my_optind][0] != '-') || +- (argv[my_optind][1] == '\0')) { +- char *tmp; +- int i, j, k; +- +- opt = -1; +- if(mode == '+') return -1; +- else if(mode == '-') { +- my_optarg = argv[my_optind++]; +- return 1; +- } +- for(i=j=my_optind; i j) { +- tmp=argv[--i]; +- for(k=i; k+1= argc) { +- opt = (colon_mode == ':') ? ':' : '?'; +- if(my_opterr) fprintf(stderr, +- "%s: option `--%s' requires an argument\n", +- argv[0], longopts[found].name); +- } else my_optarg = argv[my_optind]; +- } +- if(!opt) { +- if (longind) *longind = found; +- if(!longopts[found].flag) opt = longopts[found].val; +- else *(longopts[found].flag) = longopts[found].val; +- } +- my_optind++; +- } else if(!hits) { +- if(offset == 1) opt = my_getopt(argc, argv, shortopts); +- else { +- opt = '?'; +- if(my_opterr) fprintf(stderr, +- "%s: unrecognized option `%s'\n", +- argv[0], argv[my_optind++]); +- } +- } else { +- opt = '?'; +- if(my_opterr) fprintf(stderr, +- "%s: option `%s' is ambiguous\n", +- argv[0], argv[my_optind++]); +- } +- } +- if (my_optind > argc) my_optind = argc; +- return opt; +-} +- +-int my_getopt_long(int argc, char * argv[], const char *shortopts, +- const struct option *longopts, int *longind) +-{ +- return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 0); +-} +- +-int my_getopt_long_only(int argc, char * argv[], const char *shortopts, +- const struct option *longopts, int *longind) +-{ +- return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 1); +-} +diff --git a/utils/open-isns/compat/my_getopt.h b/utils/open-isns/compat/my_getopt.h +deleted file mode 100644 +index 34fcfe7..0000000 +--- a/utils/open-isns/compat/my_getopt.h ++++ /dev/null +@@ -1,69 +0,0 @@ +-/* +- * my_getopt.h - interface to my re-implementation of getopt. +- * Copyright 1997, 2000, 2001, 2002, Benjamin Sittler +- * +- * Permission is hereby granted, free of charge, to any person +- * obtaining a copy of this software and associated documentation +- * files (the "Software"), to deal in the Software without +- * restriction, including without limitation the rights to use, copy, +- * modify, merge, publish, distribute, sublicense, and/or sell copies +- * of the Software, and to permit persons to whom the Software is +- * furnished to do so, subject to the following conditions: +- * +- * The above copyright notice and this permission notice shall be +- * included in all copies or substantial portions of the Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +- * DEALINGS IN THE SOFTWARE. +- */ +- +-#ifndef MY_GETOPT_H_INCLUDED +-#define MY_GETOPT_H_INCLUDED +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-/* UNIX-style short-argument parser */ +-extern int my_getopt(int argc, char * argv[], const char *opts); +- +-extern int my_optind, my_opterr, my_optopt; +-extern char *my_optarg; +- +-struct option { +- const char *name; +- int has_arg; +- int *flag; +- int val; +-}; +- +-/* human-readable values for has_arg */ +-#undef no_argument +-#define no_argument 0 +-#undef required_argument +-#define required_argument 1 +-#undef optional_argument +-#define optional_argument 2 +- +-/* GNU-style long-argument parsers */ +-extern int my_getopt_long(int argc, char * argv[], const char *shortopts, +- const struct option *longopts, int *longind); +- +-extern int my_getopt_long_only(int argc, char * argv[], const char *shortopts, +- const struct option *longopts, int *longind); +- +-extern int _my_getopt_internal(int argc, char * argv[], const char *shortopts, +- const struct option *longopts, int *longind, +- int long_only); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* MY_GETOPT_H_INCLUDED */ +diff --git a/utils/open-isns/config.c b/utils/open-isns/config.c +deleted file mode 100644 +index cc470a4..0000000 +--- a/utils/open-isns/config.c ++++ /dev/null +@@ -1,278 +0,0 @@ +-/* +- * Config file reader +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +-#include +-#include +-#include +-#include +- +-#include "isns.h" +-#include "util.h" +-#include "paths.h" +- +-/* +- * iSNS configuration +- */ +-struct isns_config isns_config = { +- /* Security parameters */ +- .ic_security = -1, +- .ic_auth_key_file = ISNS_ETCDIR "/auth_key", +- .ic_server_key_file = ISNS_ETCDIR "/server_key.pub", +- .ic_client_keystore = "DB:", +- .ic_control_socket = ISNS_RUNDIR "/isnsctl", +- .ic_pidfile = ISNS_RUNDIR "/isnsd.pid", +- .ic_local_registry_file = ISNS_DEFAULT_LOCAL_REGISTRY, +- +- .ic_control_name = "isns.control", +- .ic_control_key_file = ISNS_ETCDIR "/control.key", +- +- .ic_registration_period = 3600, /* 1 hour */ +- .ic_scn_timeout = 60, +- .ic_scn_retries = 3, +- +- .ic_esi_max_interval = 600, /* 10 minutes */ +- .ic_esi_min_interval = 60, /* 1 minute */ +- .ic_esi_retries = 3, +- +- .ic_auth = { +- .replay_window = 300, /* 5 min clock skew */ +- .timestamp_jitter = 1, /* 1 sec timestamp jitter */ +- .allow_unknown_peers = 1, +- }, +- .ic_network = { +- .max_sockets = 1024, +- .connect_timeout = 5, +- .reconnect_timeout = 10, +- .call_timeout = 60, +- .udp_retrans_timeout = 10, +- .tcp_retrans_timeout = 60, +- .idle_timeout = 300, +- }, +- .ic_dsa = { +- .param_file = ISNS_ETCDIR "/dsa.params", +- }, +-}; +- +-/* +- * Default string values need to be dup'ed, +- * so that later assignment does't try to free +- * these strings. +- */ +-static inline void +-__isns_config_defaults(void) +-{ +- static int defaults_init = 1; +- +- if (!defaults_init) +- return; +- +-#define DUP(member) \ +- if (isns_config.member) \ +- isns_config.member = isns_strdup(isns_config.member) +- +- DUP(ic_source_name); +- DUP(ic_database); +- DUP(ic_server_name); +- DUP(ic_bind_address); +- DUP(ic_auth_key_file); +- DUP(ic_server_key_file); +- DUP(ic_client_keystore); +- DUP(ic_control_socket); +- DUP(ic_pidfile); +- DUP(ic_control_name); +- DUP(ic_control_key_file); +- DUP(ic_local_registry_file); +- DUP(ic_dsa.param_file); +- +-#undef DUP +- +- defaults_init = 0; +-} +- +-/* +- * Read the iSNS configuration file +- */ +-int +-isns_read_config(const char *filename) +-{ +- FILE *fp; +- char *name, *pos; +- +- __isns_config_defaults(); +- +- if ((fp = fopen(filename, "r")) == NULL) { +- perror(filename); +- return -1; +- } +- +- while ((pos = parser_get_next_line(fp)) != NULL) { +- pos[strcspn(pos, "#")] = '\0'; +- +- if (!(name = parser_get_next_word(&pos))) +- continue; +- +- isns_config_set(name, pos); +- } +- +- fclose(fp); +- +- /* Massage the config file */ +- if (isns_config.ic_security < 0) { +- /* By default, we will enable authentication +- * whenever we find our private key, and +- * the server's public key. */ +- if (access(isns_config.ic_auth_key_file, R_OK) == 0 +- && access(isns_config.ic_server_key_file, R_OK) == 0) +- isns_config.ic_security = 1; +- else +- isns_config.ic_security = 0; +- } +- +- isns_init_names(); +- +- return 0; +-} +- +-int +-isns_config_set(const char *name, char *pos) +-{ +- char *value; +- +- value = parser_get_rest_of_line(&pos); +- if (value) +- while (isspace(*value) || *value == '=') +- ++value; +- if (!strcasecmp(name, "HostName")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_host_name, value); +- } else if (!strcasecmp(name, "SourceName")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_source_name, value); +- } else if (!strcasecmp(name, "AuthName")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_auth_name, value); +- } else if (!strcasecmp(name, "Database")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_database, value); +- } else if (!strcasecmp(name, "ServerAddress")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_server_name, value); +- } else if (!strcasecmp(name, "BindAddress")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_bind_address, value); +- } else if (!strcasecmp(name, "ControlSocket")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_control_socket, value); +- } else if (!strcasecmp(name, "PIDFile")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_pidfile, value); +- } else if (!strcasecmp(name, "LocalRegistry")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_local_registry_file, value); +- } else if (!strcasecmp(name, "RegistrationPeriod")) { +- if (!value) +- goto no_value; +- isns_config.ic_registration_period = parse_timeout(value); +- } else if (!strcasecmp(name, "SCNTimeout")) { +- if (!value) +- goto no_value; +- isns_config.ic_scn_timeout = parse_timeout(value); +- } else if (!strcasecmp(name, "SCNRetries")) { +- if (!value) +- goto no_value; +- isns_config.ic_scn_retries = parse_int(value); +- } else if (!strcasecmp(name, "SCNCallout")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_scn_callout, value); +- } else if (!strcasecmp(name, "ESIMinInterval")) { +- if (!value) +- goto no_value; +- isns_config.ic_esi_min_interval = parse_timeout(value); +- } else if (!strcasecmp(name, "ESIMaxInterval")) { +- if (!value) +- goto no_value; +- isns_config.ic_esi_max_interval = parse_timeout(value); +- } else if (!strcasecmp(name, "ESIRetries")) { +- if (!value) +- goto no_value; +- isns_config.ic_esi_retries = parse_int(value); +- } else if (!strcasecmp(name, "DefaultDiscoveryDomain")) { +- if (!value) +- goto no_value; +- isns_config.ic_use_default_domain = parse_int(value); +- } else if (!strcasecmp(name, "SLPRegister")) { +- if (!value) +- goto no_value; +- isns_config.ic_slp_register = parse_int(value); +- } else if (!strcasecmp(name, "Security")) { +- if (!value) +- goto no_value; +- isns_config.ic_security = parse_int(value); +- } else if (!strcasecmp(name, "AuthKeyFile")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_auth_key_file, value); +- } else if (!strcasecmp(name, "ServerKeyFile")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_server_key_file, value); +- } else if (!strcasecmp(name, "ClientKeyStore") +- || !strcasecmp(name, "KeyStore")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_client_keystore, value); +- } else if (!strcasecmp(name, "Control.SourceName")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_control_name, value); +- } else if (!strcasecmp(name, "Control.AuthKeyFile")) { +- if (!value) +- goto no_value; +- isns_assign_string(&isns_config.ic_control_key_file, value); +- } else if (!strcasecmp(name, "Auth.ReplayWindow")) { +- if (!value) +- goto no_value; +- isns_config.ic_auth.replay_window = parse_timeout(value); +- } else if (!strcasecmp(name, "Auth.TimestampJitter")) { +- if (!value) +- goto no_value; +- isns_config.ic_auth.timestamp_jitter = parse_timeout(value); +- } else if (!strcasecmp(name, "Network.MaxSockets")) { +- if (!value) +- goto no_value; +- isns_config.ic_network.max_sockets = parse_timeout(value); +- } else if (!strcasecmp(name, "Network.ConnectTimeout")) { +- if (!value) +- goto no_value; +- isns_config.ic_network.connect_timeout = parse_timeout(value); +- } else if (!strcasecmp(name, "Network.ReconnectTimeout")) { +- if (!value) +- goto no_value; +- isns_config.ic_network.reconnect_timeout = parse_timeout(value); +- } else if (!strcasecmp(name, "Network.CallTimeout")) { +- if (!value) +- goto no_value; +- isns_config.ic_network.call_timeout = parse_timeout(value); +- } else { +- fprintf(stderr, "Unknown config item %s=%s\n", name, value); +- } +- return 0; +- +-no_value: +- fprintf(stderr, +- "*** Missing value in configuration assignment for %s ***\n", +- name); +- return -1; +-} +diff --git a/utils/open-isns/config.h.in b/utils/open-isns/config.h.in +deleted file mode 100644 +index b560bb0..0000000 +--- a/utils/open-isns/config.h.in ++++ /dev/null +@@ -1,103 +0,0 @@ +-/* config.h.in. Generated from configure.ac by autoheader. */ +- +-/* Define if building universal (internal helper macro) */ +-#undef AC_APPLE_UNIVERSAL_BUILD +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_ERRNO_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_FCNTL_H +- +-/* Define if you have the header file. */ +-#undef HAVE_GETOPT_H +- +-/* Define if you have the `getopt_long' function. */ +-#undef HAVE_GETOPT_LONG +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_INTTYPES_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_LOCALE_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_MALLOC_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_MEMORY_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_OPENSSL_CRYPTO_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_SLP_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_STDINT_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_STDLIB_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_STRINGS_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_STRING_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_SYS_STAT_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_SYS_TIME_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_SYS_TYPES_H +- +-/* Define to 1 if you have that is POSIX.1 compatible. */ +-#undef HAVE_SYS_WAIT_H +- +-/* Define to 1 if you have the header file. */ +-#undef HAVE_UNISTD_H +- +-/* Define to the address where bug reports for this package should be sent. */ +-#undef PACKAGE_BUGREPORT +- +-/* Define to the full name of this package. */ +-#undef PACKAGE_NAME +- +-/* Define to the full name and version of this package. */ +-#undef PACKAGE_STRING +- +-/* Define to the one symbol short name of this package. */ +-#undef PACKAGE_TARNAME +- +-/* Define to the version of this package. */ +-#undef PACKAGE_VERSION +- +-/* Define to 1 if you have the ANSI C header files. */ +-#undef STDC_HEADERS +- +-/* Define if you want to support iSNS authentication */ +-#undef WITH_SECURITY +- +-/* Define if you want to support SLP discovery */ +-#undef WITH_SLP +- +-/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most +- significant byte first (like Motorola and SPARC, unlike Intel). */ +-#if defined AC_APPLE_UNIVERSAL_BUILD +-# if defined __BIG_ENDIAN__ +-# define WORDS_BIGENDIAN 1 +-# endif +-#else +-# ifndef WORDS_BIGENDIAN +-# undef WORDS_BIGENDIAN +-# endif +-#endif +- +-/* Define to `__inline__' or `__inline' if that's what the C compiler +- calls it, or to nothing if 'inline' is not supported under any name. */ +-#ifndef __cplusplus +-#undef inline +-#endif +diff --git a/utils/open-isns/configure b/utils/open-isns/configure +deleted file mode 100755 +index 2d1054b..0000000 +--- a/utils/open-isns/configure ++++ /dev/null +@@ -1,6727 +0,0 @@ +-#! /bin/sh +-# Guess values for system-dependent variables and create Makefiles. +-# Generated by GNU Autoconf 2.63 for open-isns 0.90. +-# +-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +-# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +-# This configure script is free software; the Free Software Foundation +-# gives unlimited permission to copy, distribute and modify it. +-## --------------------- ## +-## M4sh Initialization. ## +-## --------------------- ## +- +-# Be more Bourne compatible +-DUALCASE=1; export DUALCASE # for MKS sh +-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +- emulate sh +- NULLCMD=: +- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which +- # is contrary to our usage. Disable this feature. +- alias -g '${1+"$@"}'='"$@"' +- setopt NO_GLOB_SUBST +-else +- case `(set -o) 2>/dev/null` in +- *posix*) set -o posix ;; +-esac +- +-fi +- +- +- +- +-# PATH needs CR +-# Avoid depending upon Character Ranges. +-as_cr_letters='abcdefghijklmnopqrstuvwxyz' +-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +-as_cr_Letters=$as_cr_letters$as_cr_LETTERS +-as_cr_digits='0123456789' +-as_cr_alnum=$as_cr_Letters$as_cr_digits +- +-as_nl=' +-' +-export as_nl +-# Printing a long string crashes Solaris 7 /usr/bin/printf. +-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +-if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then +- as_echo='printf %s\n' +- as_echo_n='printf %s' +-else +- if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then +- as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' +- as_echo_n='/usr/ucb/echo -n' +- else +- as_echo_body='eval expr "X$1" : "X\\(.*\\)"' +- as_echo_n_body='eval +- arg=$1; +- case $arg in +- *"$as_nl"*) +- expr "X$arg" : "X\\(.*\\)$as_nl"; +- arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; +- esac; +- expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" +- ' +- export as_echo_n_body +- as_echo_n='sh -c $as_echo_n_body as_echo' +- fi +- export as_echo_body +- as_echo='sh -c $as_echo_body as_echo' +-fi +- +-# The user is always right. +-if test "${PATH_SEPARATOR+set}" != set; then +- PATH_SEPARATOR=: +- (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { +- (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || +- PATH_SEPARATOR=';' +- } +-fi +- +-# Support unset when possible. +-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then +- as_unset=unset +-else +- as_unset=false +-fi +- +- +-# IFS +-# We need space, tab and new line, in precisely that order. Quoting is +-# there to prevent editors from complaining about space-tab. +-# (If _AS_PATH_WALK were called with IFS unset, it would disable word +-# splitting by setting IFS to empty value.) +-IFS=" "" $as_nl" +- +-# Find who we are. Look in the path if we contain no directory separator. +-case $0 in +- *[\\/]* ) as_myself=$0 ;; +- *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +-done +-IFS=$as_save_IFS +- +- ;; +-esac +-# We did not find ourselves, most probably we were run as `sh COMMAND' +-# in which case we are not to be found in the path. +-if test "x$as_myself" = x; then +- as_myself=$0 +-fi +-if test ! -f "$as_myself"; then +- $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 +- { (exit 1); exit 1; } +-fi +- +-# Work around bugs in pre-3.0 UWIN ksh. +-for as_var in ENV MAIL MAILPATH +-do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +-done +-PS1='$ ' +-PS2='> ' +-PS4='+ ' +- +-# NLS nuisances. +-LC_ALL=C +-export LC_ALL +-LANGUAGE=C +-export LANGUAGE +- +-# Required to use basename. +-if expr a : '\(a\)' >/dev/null 2>&1 && +- test "X`expr 00001 : '.*\(...\)'`" = X001; then +- as_expr=expr +-else +- as_expr=false +-fi +- +-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then +- as_basename=basename +-else +- as_basename=false +-fi +- +- +-# Name of the executable. +-as_me=`$as_basename -- "$0" || +-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ +- X"$0" : 'X\(//\)$' \| \ +- X"$0" : 'X\(/\)' \| . 2>/dev/null || +-$as_echo X/"$0" | +- sed '/^.*\/\([^/][^/]*\)\/*$/{ +- s//\1/ +- q +- } +- /^X\/\(\/\/\)$/{ +- s//\1/ +- q +- } +- /^X\/\(\/\).*/{ +- s//\1/ +- q +- } +- s/.*/./; q'` +- +-# CDPATH. +-$as_unset CDPATH +- +- +-if test "x$CONFIG_SHELL" = x; then +- if (eval ":") 2>/dev/null; then +- as_have_required=yes +-else +- as_have_required=no +-fi +- +- if test $as_have_required = yes && (eval ": +-(as_func_return () { +- (exit \$1) +-} +-as_func_success () { +- as_func_return 0 +-} +-as_func_failure () { +- as_func_return 1 +-} +-as_func_ret_success () { +- return 0 +-} +-as_func_ret_failure () { +- return 1 +-} +- +-exitcode=0 +-if as_func_success; then +- : +-else +- exitcode=1 +- echo as_func_success failed. +-fi +- +-if as_func_failure; then +- exitcode=1 +- echo as_func_failure succeeded. +-fi +- +-if as_func_ret_success; then +- : +-else +- exitcode=1 +- echo as_func_ret_success failed. +-fi +- +-if as_func_ret_failure; then +- exitcode=1 +- echo as_func_ret_failure succeeded. +-fi +- +-if ( set x; as_func_ret_success y && test x = \"\$1\" ); then +- : +-else +- exitcode=1 +- echo positional parameters were not saved. +-fi +- +-test \$exitcode = 0) || { (exit 1); exit 1; } +- +-( +- as_lineno_1=\$LINENO +- as_lineno_2=\$LINENO +- test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && +- test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +-") 2> /dev/null; then +- : +-else +- as_candidate_shells= +- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- case $as_dir in +- /*) +- for as_base in sh bash ksh sh5; do +- as_candidate_shells="$as_candidate_shells $as_dir/$as_base" +- done;; +- esac +-done +-IFS=$as_save_IFS +- +- +- for as_shell in $as_candidate_shells $SHELL; do +- # Try only shells that exist, to save several forks. +- if { test -f "$as_shell" || test -f "$as_shell.exe"; } && +- { ("$as_shell") 2> /dev/null <<\_ASEOF +-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +- emulate sh +- NULLCMD=: +- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which +- # is contrary to our usage. Disable this feature. +- alias -g '${1+"$@"}'='"$@"' +- setopt NO_GLOB_SUBST +-else +- case `(set -o) 2>/dev/null` in +- *posix*) set -o posix ;; +-esac +- +-fi +- +- +-: +-_ASEOF +-}; then +- CONFIG_SHELL=$as_shell +- as_have_required=yes +- if { "$as_shell" 2> /dev/null <<\_ASEOF +-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +- emulate sh +- NULLCMD=: +- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which +- # is contrary to our usage. Disable this feature. +- alias -g '${1+"$@"}'='"$@"' +- setopt NO_GLOB_SUBST +-else +- case `(set -o) 2>/dev/null` in +- *posix*) set -o posix ;; +-esac +- +-fi +- +- +-: +-(as_func_return () { +- (exit $1) +-} +-as_func_success () { +- as_func_return 0 +-} +-as_func_failure () { +- as_func_return 1 +-} +-as_func_ret_success () { +- return 0 +-} +-as_func_ret_failure () { +- return 1 +-} +- +-exitcode=0 +-if as_func_success; then +- : +-else +- exitcode=1 +- echo as_func_success failed. +-fi +- +-if as_func_failure; then +- exitcode=1 +- echo as_func_failure succeeded. +-fi +- +-if as_func_ret_success; then +- : +-else +- exitcode=1 +- echo as_func_ret_success failed. +-fi +- +-if as_func_ret_failure; then +- exitcode=1 +- echo as_func_ret_failure succeeded. +-fi +- +-if ( set x; as_func_ret_success y && test x = "$1" ); then +- : +-else +- exitcode=1 +- echo positional parameters were not saved. +-fi +- +-test $exitcode = 0) || { (exit 1); exit 1; } +- +-( +- as_lineno_1=$LINENO +- as_lineno_2=$LINENO +- test "x$as_lineno_1" != "x$as_lineno_2" && +- test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } +- +-_ASEOF +-}; then +- break +-fi +- +-fi +- +- done +- +- if test "x$CONFIG_SHELL" != x; then +- for as_var in BASH_ENV ENV +- do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +- done +- export CONFIG_SHELL +- exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +-fi +- +- +- if test $as_have_required = no; then +- echo This script requires a shell more modern than all the +- echo shells that I found on your system. Please install a +- echo modern shell, or manually run the script under such a +- echo shell if you do have one. +- { (exit 1); exit 1; } +-fi +- +- +-fi +- +-fi +- +- +- +-(eval "as_func_return () { +- (exit \$1) +-} +-as_func_success () { +- as_func_return 0 +-} +-as_func_failure () { +- as_func_return 1 +-} +-as_func_ret_success () { +- return 0 +-} +-as_func_ret_failure () { +- return 1 +-} +- +-exitcode=0 +-if as_func_success; then +- : +-else +- exitcode=1 +- echo as_func_success failed. +-fi +- +-if as_func_failure; then +- exitcode=1 +- echo as_func_failure succeeded. +-fi +- +-if as_func_ret_success; then +- : +-else +- exitcode=1 +- echo as_func_ret_success failed. +-fi +- +-if as_func_ret_failure; then +- exitcode=1 +- echo as_func_ret_failure succeeded. +-fi +- +-if ( set x; as_func_ret_success y && test x = \"\$1\" ); then +- : +-else +- exitcode=1 +- echo positional parameters were not saved. +-fi +- +-test \$exitcode = 0") || { +- echo No shell found that supports shell functions. +- echo Please tell bug-autoconf@gnu.org about your system, +- echo including any error possibly output before this message. +- echo This can help us improve future autoconf versions. +- echo Configuration will now proceed without shell functions. +-} +- +- +- +- as_lineno_1=$LINENO +- as_lineno_2=$LINENO +- test "x$as_lineno_1" != "x$as_lineno_2" && +- test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { +- +- # Create $as_me.lineno as a copy of $as_myself, but with $LINENO +- # uniformly replaced by the line number. The first 'sed' inserts a +- # line-number line after each line using $LINENO; the second 'sed' +- # does the real work. The second script uses 'N' to pair each +- # line-number line with the line containing $LINENO, and appends +- # trailing '-' during substitution so that $LINENO is not a special +- # case at line end. +- # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the +- # scripts with optimization help from Paolo Bonzini. Blame Lee +- # E. McMahon (1931-1989) for sed's syntax. :-) +- sed -n ' +- p +- /[$]LINENO/= +- ' <$as_myself | +- sed ' +- s/[$]LINENO.*/&-/ +- t lineno +- b +- :lineno +- N +- :loop +- s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ +- t loop +- s/-\n.*// +- ' >$as_me.lineno && +- chmod +x "$as_me.lineno" || +- { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 +- { (exit 1); exit 1; }; } +- +- # Don't try to exec as it changes $[0], causing all sort of problems +- # (the dirname of $[0] is not the place where we might find the +- # original and so on. Autoconf is especially sensitive to this). +- . "./$as_me.lineno" +- # Exit status is that of the last command. +- exit +-} +- +- +-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then +- as_dirname=dirname +-else +- as_dirname=false +-fi +- +-ECHO_C= ECHO_N= ECHO_T= +-case `echo -n x` in +--n*) +- case `echo 'x\c'` in +- *c*) ECHO_T=' ';; # ECHO_T is single tab character. +- *) ECHO_C='\c';; +- esac;; +-*) +- ECHO_N='-n';; +-esac +-if expr a : '\(a\)' >/dev/null 2>&1 && +- test "X`expr 00001 : '.*\(...\)'`" = X001; then +- as_expr=expr +-else +- as_expr=false +-fi +- +-rm -f conf$$ conf$$.exe conf$$.file +-if test -d conf$$.dir; then +- rm -f conf$$.dir/conf$$.file +-else +- rm -f conf$$.dir +- mkdir conf$$.dir 2>/dev/null +-fi +-if (echo >conf$$.file) 2>/dev/null; then +- if ln -s conf$$.file conf$$ 2>/dev/null; then +- as_ln_s='ln -s' +- # ... but there are two gotchas: +- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. +- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. +- # In both cases, we have to default to `cp -p'. +- ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || +- as_ln_s='cp -p' +- elif ln conf$$.file conf$$ 2>/dev/null; then +- as_ln_s=ln +- else +- as_ln_s='cp -p' +- fi +-else +- as_ln_s='cp -p' +-fi +-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +-rmdir conf$$.dir 2>/dev/null +- +-if mkdir -p . 2>/dev/null; then +- as_mkdir_p=: +-else +- test -d ./-p && rmdir ./-p +- as_mkdir_p=false +-fi +- +-if test -x / >/dev/null 2>&1; then +- as_test_x='test -x' +-else +- if ls -dL / >/dev/null 2>&1; then +- as_ls_L_option=L +- else +- as_ls_L_option= +- fi +- as_test_x=' +- eval sh -c '\'' +- if test -d "$1"; then +- test -d "$1/."; +- else +- case $1 in +- -*)set "./$1";; +- esac; +- case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in +- ???[sx]*):;;*)false;;esac;fi +- '\'' sh +- ' +-fi +-as_executable_p=$as_test_x +- +-# Sed expression to map a string onto a valid CPP name. +-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" +- +-# Sed expression to map a string onto a valid variable name. +-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" +- +- +- +-exec 7<&0 &1 +- +-# Name of the host. +-# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +-# so uname gets run too. +-ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` +- +-# +-# Initializations. +-# +-ac_default_prefix=/usr/local +-ac_clean_files= +-ac_config_libobj_dir=. +-LIBOBJS= +-cross_compiling=no +-subdirs= +-MFLAGS= +-MAKEFLAGS= +-SHELL=${CONFIG_SHELL-/bin/sh} +- +-# Identity of this package. +-PACKAGE_NAME='open-isns' +-PACKAGE_TARNAME='open-isns' +-PACKAGE_VERSION='0.90' +-PACKAGE_STRING='open-isns 0.90' +-PACKAGE_BUGREPORT='' +- +-ac_unique_file="isnsd.c" +-# Factoring default headers for most tests. +-ac_includes_default="\ +-#include +-#ifdef HAVE_SYS_TYPES_H +-# include +-#endif +-#ifdef HAVE_SYS_STAT_H +-# include +-#endif +-#ifdef STDC_HEADERS +-# include +-# include +-#else +-# ifdef HAVE_STDLIB_H +-# include +-# endif +-#endif +-#ifdef HAVE_STRING_H +-# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +-# include +-# endif +-# include +-#endif +-#ifdef HAVE_STRINGS_H +-# include +-#endif +-#ifdef HAVE_INTTYPES_H +-# include +-#endif +-#ifdef HAVE_STDINT_H +-# include +-#endif +-#ifdef HAVE_UNISTD_H +-# include +-#endif" +- +-ac_subst_vars='LTLIBOBJS +-LIBOBJS +-OPTIMIZE +-SLPLIBS +-SECLIBS +-GETOPTSRC +-SH +-SET_MAKE +-LN_S +-INSTALL_DATA +-INSTALL_SCRIPT +-INSTALL_PROGRAM +-EGREP +-GREP +-CPP +-host_os +-host_vendor +-host_cpu +-host +-build_os +-build_vendor +-build_cpu +-build +-OBJEXT +-EXEEXT +-ac_ct_CC +-CPPFLAGS +-LDFLAGS +-CFLAGS +-CC +-target_alias +-host_alias +-build_alias +-LIBS +-ECHO_T +-ECHO_N +-ECHO_C +-DEFS +-mandir +-localedir +-libdir +-psdir +-pdfdir +-dvidir +-htmldir +-infodir +-docdir +-oldincludedir +-includedir +-localstatedir +-sharedstatedir +-sysconfdir +-datadir +-datarootdir +-libexecdir +-sbindir +-bindir +-program_transform_name +-prefix +-exec_prefix +-PACKAGE_BUGREPORT +-PACKAGE_STRING +-PACKAGE_VERSION +-PACKAGE_TARNAME +-PACKAGE_NAME +-PATH_SEPARATOR +-SHELL' +-ac_subst_files='' +-ac_user_opts=' +-enable_option_checking +-with_security +-with_slp +-enable_memdebug +-' +- ac_precious_vars='build_alias +-host_alias +-target_alias +-CC +-CFLAGS +-LDFLAGS +-LIBS +-CPPFLAGS +-CPP' +- +- +-# Initialize some variables set by options. +-ac_init_help= +-ac_init_version=false +-ac_unrecognized_opts= +-ac_unrecognized_sep= +-# The variables have the same names as the options, with +-# dashes changed to underlines. +-cache_file=/dev/null +-exec_prefix=NONE +-no_create= +-no_recursion= +-prefix=NONE +-program_prefix=NONE +-program_suffix=NONE +-program_transform_name=s,x,x, +-silent= +-site= +-srcdir= +-verbose= +-x_includes=NONE +-x_libraries=NONE +- +-# Installation directory options. +-# These are left unexpanded so users can "make install exec_prefix=/foo" +-# and all the variables that are supposed to be based on exec_prefix +-# by default will actually change. +-# Use braces instead of parens because sh, perl, etc. also accept them. +-# (The list follows the same order as the GNU Coding Standards.) +-bindir='${exec_prefix}/bin' +-sbindir='${exec_prefix}/sbin' +-libexecdir='${exec_prefix}/libexec' +-datarootdir='${prefix}/share' +-datadir='${datarootdir}' +-sysconfdir='${prefix}/etc' +-sharedstatedir='${prefix}/com' +-localstatedir='${prefix}/var' +-includedir='${prefix}/include' +-oldincludedir='/usr/include' +-docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +-infodir='${datarootdir}/info' +-htmldir='${docdir}' +-dvidir='${docdir}' +-pdfdir='${docdir}' +-psdir='${docdir}' +-libdir='${exec_prefix}/lib' +-localedir='${datarootdir}/locale' +-mandir='${datarootdir}/man' +- +-ac_prev= +-ac_dashdash= +-for ac_option +-do +- # If the previous option needs an argument, assign it. +- if test -n "$ac_prev"; then +- eval $ac_prev=\$ac_option +- ac_prev= +- continue +- fi +- +- case $ac_option in +- *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; +- *) ac_optarg=yes ;; +- esac +- +- # Accept the important Cygnus configure options, so we can diagnose typos. +- +- case $ac_dashdash$ac_option in +- --) +- ac_dashdash=yes ;; +- +- -bindir | --bindir | --bindi | --bind | --bin | --bi) +- ac_prev=bindir ;; +- -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) +- bindir=$ac_optarg ;; +- +- -build | --build | --buil | --bui | --bu) +- ac_prev=build_alias ;; +- -build=* | --build=* | --buil=* | --bui=* | --bu=*) +- build_alias=$ac_optarg ;; +- +- -cache-file | --cache-file | --cache-fil | --cache-fi \ +- | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) +- ac_prev=cache_file ;; +- -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ +- | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) +- cache_file=$ac_optarg ;; +- +- --config-cache | -C) +- cache_file=config.cache ;; +- +- -datadir | --datadir | --datadi | --datad) +- ac_prev=datadir ;; +- -datadir=* | --datadir=* | --datadi=* | --datad=*) +- datadir=$ac_optarg ;; +- +- -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ +- | --dataroo | --dataro | --datar) +- ac_prev=datarootdir ;; +- -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ +- | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) +- datarootdir=$ac_optarg ;; +- +- -disable-* | --disable-*) +- ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` +- # Reject names that are not valid shell variable names. +- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && +- { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 +- { (exit 1); exit 1; }; } +- ac_useropt_orig=$ac_useropt +- ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` +- case $ac_user_opts in +- *" +-"enable_$ac_useropt" +-"*) ;; +- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" +- ac_unrecognized_sep=', ';; +- esac +- eval enable_$ac_useropt=no ;; +- +- -docdir | --docdir | --docdi | --doc | --do) +- ac_prev=docdir ;; +- -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) +- docdir=$ac_optarg ;; +- +- -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) +- ac_prev=dvidir ;; +- -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) +- dvidir=$ac_optarg ;; +- +- -enable-* | --enable-*) +- ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` +- # Reject names that are not valid shell variable names. +- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && +- { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 +- { (exit 1); exit 1; }; } +- ac_useropt_orig=$ac_useropt +- ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` +- case $ac_user_opts in +- *" +-"enable_$ac_useropt" +-"*) ;; +- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" +- ac_unrecognized_sep=', ';; +- esac +- eval enable_$ac_useropt=\$ac_optarg ;; +- +- -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ +- | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ +- | --exec | --exe | --ex) +- ac_prev=exec_prefix ;; +- -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ +- | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ +- | --exec=* | --exe=* | --ex=*) +- exec_prefix=$ac_optarg ;; +- +- -gas | --gas | --ga | --g) +- # Obsolete; use --with-gas. +- with_gas=yes ;; +- +- -help | --help | --hel | --he | -h) +- ac_init_help=long ;; +- -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) +- ac_init_help=recursive ;; +- -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) +- ac_init_help=short ;; +- +- -host | --host | --hos | --ho) +- ac_prev=host_alias ;; +- -host=* | --host=* | --hos=* | --ho=*) +- host_alias=$ac_optarg ;; +- +- -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) +- ac_prev=htmldir ;; +- -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ +- | --ht=*) +- htmldir=$ac_optarg ;; +- +- -includedir | --includedir | --includedi | --included | --include \ +- | --includ | --inclu | --incl | --inc) +- ac_prev=includedir ;; +- -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ +- | --includ=* | --inclu=* | --incl=* | --inc=*) +- includedir=$ac_optarg ;; +- +- -infodir | --infodir | --infodi | --infod | --info | --inf) +- ac_prev=infodir ;; +- -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) +- infodir=$ac_optarg ;; +- +- -libdir | --libdir | --libdi | --libd) +- ac_prev=libdir ;; +- -libdir=* | --libdir=* | --libdi=* | --libd=*) +- libdir=$ac_optarg ;; +- +- -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ +- | --libexe | --libex | --libe) +- ac_prev=libexecdir ;; +- -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ +- | --libexe=* | --libex=* | --libe=*) +- libexecdir=$ac_optarg ;; +- +- -localedir | --localedir | --localedi | --localed | --locale) +- ac_prev=localedir ;; +- -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) +- localedir=$ac_optarg ;; +- +- -localstatedir | --localstatedir | --localstatedi | --localstated \ +- | --localstate | --localstat | --localsta | --localst | --locals) +- ac_prev=localstatedir ;; +- -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ +- | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) +- localstatedir=$ac_optarg ;; +- +- -mandir | --mandir | --mandi | --mand | --man | --ma | --m) +- ac_prev=mandir ;; +- -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) +- mandir=$ac_optarg ;; +- +- -nfp | --nfp | --nf) +- # Obsolete; use --without-fp. +- with_fp=no ;; +- +- -no-create | --no-create | --no-creat | --no-crea | --no-cre \ +- | --no-cr | --no-c | -n) +- no_create=yes ;; +- +- -no-recursion | --no-recursion | --no-recursio | --no-recursi \ +- | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) +- no_recursion=yes ;; +- +- -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ +- | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ +- | --oldin | --oldi | --old | --ol | --o) +- ac_prev=oldincludedir ;; +- -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ +- | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ +- | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) +- oldincludedir=$ac_optarg ;; +- +- -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) +- ac_prev=prefix ;; +- -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) +- prefix=$ac_optarg ;; +- +- -program-prefix | --program-prefix | --program-prefi | --program-pref \ +- | --program-pre | --program-pr | --program-p) +- ac_prev=program_prefix ;; +- -program-prefix=* | --program-prefix=* | --program-prefi=* \ +- | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) +- program_prefix=$ac_optarg ;; +- +- -program-suffix | --program-suffix | --program-suffi | --program-suff \ +- | --program-suf | --program-su | --program-s) +- ac_prev=program_suffix ;; +- -program-suffix=* | --program-suffix=* | --program-suffi=* \ +- | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) +- program_suffix=$ac_optarg ;; +- +- -program-transform-name | --program-transform-name \ +- | --program-transform-nam | --program-transform-na \ +- | --program-transform-n | --program-transform- \ +- | --program-transform | --program-transfor \ +- | --program-transfo | --program-transf \ +- | --program-trans | --program-tran \ +- | --progr-tra | --program-tr | --program-t) +- ac_prev=program_transform_name ;; +- -program-transform-name=* | --program-transform-name=* \ +- | --program-transform-nam=* | --program-transform-na=* \ +- | --program-transform-n=* | --program-transform-=* \ +- | --program-transform=* | --program-transfor=* \ +- | --program-transfo=* | --program-transf=* \ +- | --program-trans=* | --program-tran=* \ +- | --progr-tra=* | --program-tr=* | --program-t=*) +- program_transform_name=$ac_optarg ;; +- +- -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) +- ac_prev=pdfdir ;; +- -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) +- pdfdir=$ac_optarg ;; +- +- -psdir | --psdir | --psdi | --psd | --ps) +- ac_prev=psdir ;; +- -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) +- psdir=$ac_optarg ;; +- +- -q | -quiet | --quiet | --quie | --qui | --qu | --q \ +- | -silent | --silent | --silen | --sile | --sil) +- silent=yes ;; +- +- -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) +- ac_prev=sbindir ;; +- -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ +- | --sbi=* | --sb=*) +- sbindir=$ac_optarg ;; +- +- -sharedstatedir | --sharedstatedir | --sharedstatedi \ +- | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ +- | --sharedst | --shareds | --shared | --share | --shar \ +- | --sha | --sh) +- ac_prev=sharedstatedir ;; +- -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ +- | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ +- | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ +- | --sha=* | --sh=*) +- sharedstatedir=$ac_optarg ;; +- +- -site | --site | --sit) +- ac_prev=site ;; +- -site=* | --site=* | --sit=*) +- site=$ac_optarg ;; +- +- -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) +- ac_prev=srcdir ;; +- -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) +- srcdir=$ac_optarg ;; +- +- -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ +- | --syscon | --sysco | --sysc | --sys | --sy) +- ac_prev=sysconfdir ;; +- -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ +- | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) +- sysconfdir=$ac_optarg ;; +- +- -target | --target | --targe | --targ | --tar | --ta | --t) +- ac_prev=target_alias ;; +- -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) +- target_alias=$ac_optarg ;; +- +- -v | -verbose | --verbose | --verbos | --verbo | --verb) +- verbose=yes ;; +- +- -version | --version | --versio | --versi | --vers | -V) +- ac_init_version=: ;; +- +- -with-* | --with-*) +- ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` +- # Reject names that are not valid shell variable names. +- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && +- { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 +- { (exit 1); exit 1; }; } +- ac_useropt_orig=$ac_useropt +- ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` +- case $ac_user_opts in +- *" +-"with_$ac_useropt" +-"*) ;; +- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" +- ac_unrecognized_sep=', ';; +- esac +- eval with_$ac_useropt=\$ac_optarg ;; +- +- -without-* | --without-*) +- ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` +- # Reject names that are not valid shell variable names. +- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && +- { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 +- { (exit 1); exit 1; }; } +- ac_useropt_orig=$ac_useropt +- ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` +- case $ac_user_opts in +- *" +-"with_$ac_useropt" +-"*) ;; +- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" +- ac_unrecognized_sep=', ';; +- esac +- eval with_$ac_useropt=no ;; +- +- --x) +- # Obsolete; use --with-x. +- with_x=yes ;; +- +- -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ +- | --x-incl | --x-inc | --x-in | --x-i) +- ac_prev=x_includes ;; +- -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ +- | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) +- x_includes=$ac_optarg ;; +- +- -x-libraries | --x-libraries | --x-librarie | --x-librari \ +- | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) +- ac_prev=x_libraries ;; +- -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ +- | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) +- x_libraries=$ac_optarg ;; +- +- -*) { $as_echo "$as_me: error: unrecognized option: $ac_option +-Try \`$0 --help' for more information." >&2 +- { (exit 1); exit 1; }; } +- ;; +- +- *=*) +- ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` +- # Reject names that are not valid shell variable names. +- expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && +- { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2 +- { (exit 1); exit 1; }; } +- eval $ac_envvar=\$ac_optarg +- export $ac_envvar ;; +- +- *) +- # FIXME: should be removed in autoconf 3.0. +- $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 +- expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && +- $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 +- : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} +- ;; +- +- esac +-done +- +-if test -n "$ac_prev"; then +- ac_option=--`echo $ac_prev | sed 's/_/-/g'` +- { $as_echo "$as_me: error: missing argument to $ac_option" >&2 +- { (exit 1); exit 1; }; } +-fi +- +-if test -n "$ac_unrecognized_opts"; then +- case $enable_option_checking in +- no) ;; +- fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2 +- { (exit 1); exit 1; }; } ;; +- *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; +- esac +-fi +- +-# Check all directory arguments for consistency. +-for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ +- datadir sysconfdir sharedstatedir localstatedir includedir \ +- oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ +- libdir localedir mandir +-do +- eval ac_val=\$$ac_var +- # Remove trailing slashes. +- case $ac_val in +- */ ) +- ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` +- eval $ac_var=\$ac_val;; +- esac +- # Be sure to have absolute directory names. +- case $ac_val in +- [\\/$]* | ?:[\\/]* ) continue;; +- NONE | '' ) case $ac_var in *prefix ) continue;; esac;; +- esac +- { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 +- { (exit 1); exit 1; }; } +-done +- +-# There might be people who depend on the old broken behavior: `$host' +-# used to hold the argument of --host etc. +-# FIXME: To remove some day. +-build=$build_alias +-host=$host_alias +-target=$target_alias +- +-# FIXME: To remove some day. +-if test "x$host_alias" != x; then +- if test "x$build_alias" = x; then +- cross_compiling=maybe +- $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. +- If a cross compiler is detected then cross compile mode will be used." >&2 +- elif test "x$build_alias" != "x$host_alias"; then +- cross_compiling=yes +- fi +-fi +- +-ac_tool_prefix= +-test -n "$host_alias" && ac_tool_prefix=$host_alias- +- +-test "$silent" = yes && exec 6>/dev/null +- +- +-ac_pwd=`pwd` && test -n "$ac_pwd" && +-ac_ls_di=`ls -di .` && +-ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || +- { $as_echo "$as_me: error: working directory cannot be determined" >&2 +- { (exit 1); exit 1; }; } +-test "X$ac_ls_di" = "X$ac_pwd_ls_di" || +- { $as_echo "$as_me: error: pwd does not report name of working directory" >&2 +- { (exit 1); exit 1; }; } +- +- +-# Find the source files, if location was not specified. +-if test -z "$srcdir"; then +- ac_srcdir_defaulted=yes +- # Try the directory containing this script, then the parent directory. +- ac_confdir=`$as_dirname -- "$as_myself" || +-$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ +- X"$as_myself" : 'X\(//\)[^/]' \| \ +- X"$as_myself" : 'X\(//\)$' \| \ +- X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +-$as_echo X"$as_myself" | +- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ +- s//\1/ +- q +- } +- /^X\(\/\/\)[^/].*/{ +- s//\1/ +- q +- } +- /^X\(\/\/\)$/{ +- s//\1/ +- q +- } +- /^X\(\/\).*/{ +- s//\1/ +- q +- } +- s/.*/./; q'` +- srcdir=$ac_confdir +- if test ! -r "$srcdir/$ac_unique_file"; then +- srcdir=.. +- fi +-else +- ac_srcdir_defaulted=no +-fi +-if test ! -r "$srcdir/$ac_unique_file"; then +- test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." +- { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 +- { (exit 1); exit 1; }; } +-fi +-ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +-ac_abs_confdir=`( +- cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2 +- { (exit 1); exit 1; }; } +- pwd)` +-# When building in place, set srcdir=. +-if test "$ac_abs_confdir" = "$ac_pwd"; then +- srcdir=. +-fi +-# Remove unnecessary trailing slashes from srcdir. +-# Double slashes in file names in object file debugging info +-# mess up M-x gdb in Emacs. +-case $srcdir in +-*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +-esac +-for ac_var in $ac_precious_vars; do +- eval ac_env_${ac_var}_set=\${${ac_var}+set} +- eval ac_env_${ac_var}_value=\$${ac_var} +- eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} +- eval ac_cv_env_${ac_var}_value=\$${ac_var} +-done +- +-# +-# Report the --help message. +-# +-if test "$ac_init_help" = "long"; then +- # Omit some internal or obsolete options to make the list less imposing. +- # This message is too long to be a string in the A/UX 3.1 sh. +- cat <<_ACEOF +-\`configure' configures open-isns 0.90 to adapt to many kinds of systems. +- +-Usage: $0 [OPTION]... [VAR=VALUE]... +- +-To assign environment variables (e.g., CC, CFLAGS...), specify them as +-VAR=VALUE. See below for descriptions of some of the useful variables. +- +-Defaults for the options are specified in brackets. +- +-Configuration: +- -h, --help display this help and exit +- --help=short display options specific to this package +- --help=recursive display the short help of all the included packages +- -V, --version display version information and exit +- -q, --quiet, --silent do not print \`checking...' messages +- --cache-file=FILE cache test results in FILE [disabled] +- -C, --config-cache alias for \`--cache-file=config.cache' +- -n, --no-create do not create output files +- --srcdir=DIR find the sources in DIR [configure dir or \`..'] +- +-Installation directories: +- --prefix=PREFIX install architecture-independent files in PREFIX +- [$ac_default_prefix] +- --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX +- [PREFIX] +- +-By default, \`make install' will install all the files in +-\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +-an installation prefix other than \`$ac_default_prefix' using \`--prefix', +-for instance \`--prefix=\$HOME'. +- +-For better control, use the options below. +- +-Fine tuning of the installation directories: +- --bindir=DIR user executables [EPREFIX/bin] +- --sbindir=DIR system admin executables [EPREFIX/sbin] +- --libexecdir=DIR program executables [EPREFIX/libexec] +- --sysconfdir=DIR read-only single-machine data [PREFIX/etc] +- --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] +- --localstatedir=DIR modifiable single-machine data [PREFIX/var] +- --libdir=DIR object code libraries [EPREFIX/lib] +- --includedir=DIR C header files [PREFIX/include] +- --oldincludedir=DIR C header files for non-gcc [/usr/include] +- --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] +- --datadir=DIR read-only architecture-independent data [DATAROOTDIR] +- --infodir=DIR info documentation [DATAROOTDIR/info] +- --localedir=DIR locale-dependent data [DATAROOTDIR/locale] +- --mandir=DIR man documentation [DATAROOTDIR/man] +- --docdir=DIR documentation root [DATAROOTDIR/doc/open-isns] +- --htmldir=DIR html documentation [DOCDIR] +- --dvidir=DIR dvi documentation [DOCDIR] +- --pdfdir=DIR pdf documentation [DOCDIR] +- --psdir=DIR ps documentation [DOCDIR] +-_ACEOF +- +- cat <<\_ACEOF +- +-System types: +- --build=BUILD configure for building on BUILD [guessed] +- --host=HOST cross-compile to build programs to run on HOST [BUILD] +-_ACEOF +-fi +- +-if test -n "$ac_init_help"; then +- case $ac_init_help in +- short | recursive ) echo "Configuration of open-isns 0.90:";; +- esac +- cat <<\_ACEOF +- +-Optional Features: +- --disable-option-checking ignore unrecognized --enable/--with options +- --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) +- --enable-FEATURE[=ARG] include FEATURE [ARG=yes] +- --enable-memdebug Enable malloc debugging +- +-Optional Packages: +- --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] +- --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) +- --with-security Enable iSNS authentication - requires OpenSSL +- --with-slp Enable SLP for server discovery - requires OpenSLP +- +-Some influential environment variables: +- CC C compiler command +- CFLAGS C compiler flags +- LDFLAGS linker flags, e.g. -L if you have libraries in a +- nonstandard directory +- LIBS libraries to pass to the linker, e.g. -l +- CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if +- you have headers in a nonstandard directory +- CPP C preprocessor +- +-Use these variables to override the choices made by `configure' or to help +-it to find libraries and programs with nonstandard names/locations. +- +-_ACEOF +-ac_status=$? +-fi +- +-if test "$ac_init_help" = "recursive"; then +- # If there are subdirs, report their specific --help. +- for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue +- test -d "$ac_dir" || +- { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || +- continue +- ac_builddir=. +- +-case "$ac_dir" in +-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +-*) +- ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` +- # A ".." for each directory in $ac_dir_suffix. +- ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` +- case $ac_top_builddir_sub in +- "") ac_top_builddir_sub=. ac_top_build_prefix= ;; +- *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; +- esac ;; +-esac +-ac_abs_top_builddir=$ac_pwd +-ac_abs_builddir=$ac_pwd$ac_dir_suffix +-# for backward compatibility: +-ac_top_builddir=$ac_top_build_prefix +- +-case $srcdir in +- .) # We are building in place. +- ac_srcdir=. +- ac_top_srcdir=$ac_top_builddir_sub +- ac_abs_top_srcdir=$ac_pwd ;; +- [\\/]* | ?:[\\/]* ) # Absolute name. +- ac_srcdir=$srcdir$ac_dir_suffix; +- ac_top_srcdir=$srcdir +- ac_abs_top_srcdir=$srcdir ;; +- *) # Relative name. +- ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix +- ac_top_srcdir=$ac_top_build_prefix$srcdir +- ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +-esac +-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix +- +- cd "$ac_dir" || { ac_status=$?; continue; } +- # Check for guested configure. +- if test -f "$ac_srcdir/configure.gnu"; then +- echo && +- $SHELL "$ac_srcdir/configure.gnu" --help=recursive +- elif test -f "$ac_srcdir/configure"; then +- echo && +- $SHELL "$ac_srcdir/configure" --help=recursive +- else +- $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 +- fi || ac_status=$? +- cd "$ac_pwd" || { ac_status=$?; break; } +- done +-fi +- +-test -n "$ac_init_help" && exit $ac_status +-if $ac_init_version; then +- cat <<\_ACEOF +-open-isns configure 0.90 +-generated by GNU Autoconf 2.63 +- +-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +-2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +-This configure script is free software; the Free Software Foundation +-gives unlimited permission to copy, distribute and modify it. +-_ACEOF +- exit +-fi +-cat >config.log <<_ACEOF +-This file contains any messages produced by compilers while +-running configure, to aid debugging if configure makes a mistake. +- +-It was created by open-isns $as_me 0.90, which was +-generated by GNU Autoconf 2.63. Invocation command line was +- +- $ $0 $@ +- +-_ACEOF +-exec 5>>config.log +-{ +-cat <<_ASUNAME +-## --------- ## +-## Platform. ## +-## --------- ## +- +-hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +-uname -m = `(uname -m) 2>/dev/null || echo unknown` +-uname -r = `(uname -r) 2>/dev/null || echo unknown` +-uname -s = `(uname -s) 2>/dev/null || echo unknown` +-uname -v = `(uname -v) 2>/dev/null || echo unknown` +- +-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +-/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` +- +-/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +-/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +-/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +-/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +-/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +-/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` +- +-_ASUNAME +- +-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- $as_echo "PATH: $as_dir" +-done +-IFS=$as_save_IFS +- +-} >&5 +- +-cat >&5 <<_ACEOF +- +- +-## ----------- ## +-## Core tests. ## +-## ----------- ## +- +-_ACEOF +- +- +-# Keep a trace of the command line. +-# Strip out --no-create and --no-recursion so they do not pile up. +-# Strip out --silent because we don't want to record it for future runs. +-# Also quote any args containing shell meta-characters. +-# Make two passes to allow for proper duplicate-argument suppression. +-ac_configure_args= +-ac_configure_args0= +-ac_configure_args1= +-ac_must_keep_next=false +-for ac_pass in 1 2 +-do +- for ac_arg +- do +- case $ac_arg in +- -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; +- -q | -quiet | --quiet | --quie | --qui | --qu | --q \ +- | -silent | --silent | --silen | --sile | --sil) +- continue ;; +- *\'*) +- ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; +- esac +- case $ac_pass in +- 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; +- 2) +- ac_configure_args1="$ac_configure_args1 '$ac_arg'" +- if test $ac_must_keep_next = true; then +- ac_must_keep_next=false # Got value, back to normal. +- else +- case $ac_arg in +- *=* | --config-cache | -C | -disable-* | --disable-* \ +- | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ +- | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ +- | -with-* | --with-* | -without-* | --without-* | --x) +- case "$ac_configure_args0 " in +- "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; +- esac +- ;; +- -* ) ac_must_keep_next=true ;; +- esac +- fi +- ac_configure_args="$ac_configure_args '$ac_arg'" +- ;; +- esac +- done +-done +-$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +-$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } +- +-# When interrupted or exit'd, cleanup temporary files, and complete +-# config.log. We remove comments because anyway the quotes in there +-# would cause problems or look ugly. +-# WARNING: Use '\'' to represent an apostrophe within the trap. +-# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +-trap 'exit_status=$? +- # Save into config.log some information that might help in debugging. +- { +- echo +- +- cat <<\_ASBOX +-## ---------------- ## +-## Cache variables. ## +-## ---------------- ## +-_ASBOX +- echo +- # The following way of writing the cache mishandles newlines in values, +-( +- for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do +- eval ac_val=\$$ac_var +- case $ac_val in #( +- *${as_nl}*) +- case $ac_var in #( +- *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 +-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; +- esac +- case $ac_var in #( +- _ | IFS | as_nl) ;; #( +- BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( +- *) $as_unset $ac_var ;; +- esac ;; +- esac +- done +- (set) 2>&1 | +- case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( +- *${as_nl}ac_space=\ *) +- sed -n \ +- "s/'\''/'\''\\\\'\'''\''/g; +- s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" +- ;; #( +- *) +- sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" +- ;; +- esac | +- sort +-) +- echo +- +- cat <<\_ASBOX +-## ----------------- ## +-## Output variables. ## +-## ----------------- ## +-_ASBOX +- echo +- for ac_var in $ac_subst_vars +- do +- eval ac_val=\$$ac_var +- case $ac_val in +- *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; +- esac +- $as_echo "$ac_var='\''$ac_val'\''" +- done | sort +- echo +- +- if test -n "$ac_subst_files"; then +- cat <<\_ASBOX +-## ------------------- ## +-## File substitutions. ## +-## ------------------- ## +-_ASBOX +- echo +- for ac_var in $ac_subst_files +- do +- eval ac_val=\$$ac_var +- case $ac_val in +- *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; +- esac +- $as_echo "$ac_var='\''$ac_val'\''" +- done | sort +- echo +- fi +- +- if test -s confdefs.h; then +- cat <<\_ASBOX +-## ----------- ## +-## confdefs.h. ## +-## ----------- ## +-_ASBOX +- echo +- cat confdefs.h +- echo +- fi +- test "$ac_signal" != 0 && +- $as_echo "$as_me: caught signal $ac_signal" +- $as_echo "$as_me: exit $exit_status" +- } >&5 +- rm -f core *.core core.conftest.* && +- rm -f -r conftest* confdefs* conf$$* $ac_clean_files && +- exit $exit_status +-' 0 +-for ac_signal in 1 2 13 15; do +- trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +-done +-ac_signal=0 +- +-# confdefs.h avoids OS command line length limits that DEFS can exceed. +-rm -f -r conftest* confdefs.h +- +-# Predefined preprocessor variables. +- +-cat >>confdefs.h <<_ACEOF +-#define PACKAGE_NAME "$PACKAGE_NAME" +-_ACEOF +- +- +-cat >>confdefs.h <<_ACEOF +-#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +-_ACEOF +- +- +-cat >>confdefs.h <<_ACEOF +-#define PACKAGE_VERSION "$PACKAGE_VERSION" +-_ACEOF +- +- +-cat >>confdefs.h <<_ACEOF +-#define PACKAGE_STRING "$PACKAGE_STRING" +-_ACEOF +- +- +-cat >>confdefs.h <<_ACEOF +-#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +-_ACEOF +- +- +-# Let the site file select an alternate cache file if it wants to. +-# Prefer an explicitly selected file to automatically selected ones. +-ac_site_file1=NONE +-ac_site_file2=NONE +-if test -n "$CONFIG_SITE"; then +- ac_site_file1=$CONFIG_SITE +-elif test "x$prefix" != xNONE; then +- ac_site_file1=$prefix/share/config.site +- ac_site_file2=$prefix/etc/config.site +-else +- ac_site_file1=$ac_default_prefix/share/config.site +- ac_site_file2=$ac_default_prefix/etc/config.site +-fi +-for ac_site_file in "$ac_site_file1" "$ac_site_file2" +-do +- test "x$ac_site_file" = xNONE && continue +- if test -r "$ac_site_file"; then +- { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +-$as_echo "$as_me: loading site script $ac_site_file" >&6;} +- sed 's/^/| /' "$ac_site_file" >&5 +- . "$ac_site_file" +- fi +-done +- +-if test -r "$cache_file"; then +- # Some versions of bash will fail to source /dev/null (special +- # files actually), so we avoid doing that. +- if test -f "$cache_file"; then +- { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5 +-$as_echo "$as_me: loading cache $cache_file" >&6;} +- case $cache_file in +- [\\/]* | ?:[\\/]* ) . "$cache_file";; +- *) . "./$cache_file";; +- esac +- fi +-else +- { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5 +-$as_echo "$as_me: creating cache $cache_file" >&6;} +- >$cache_file +-fi +- +-# Check that the precious variables saved in the cache have kept the same +-# value. +-ac_cache_corrupted=false +-for ac_var in $ac_precious_vars; do +- eval ac_old_set=\$ac_cv_env_${ac_var}_set +- eval ac_new_set=\$ac_env_${ac_var}_set +- eval ac_old_val=\$ac_cv_env_${ac_var}_value +- eval ac_new_val=\$ac_env_${ac_var}_value +- case $ac_old_set,$ac_new_set in +- set,) +- { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +-$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} +- ac_cache_corrupted=: ;; +- ,set) +- { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +-$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} +- ac_cache_corrupted=: ;; +- ,);; +- *) +- if test "x$ac_old_val" != "x$ac_new_val"; then +- # differences in whitespace do not lead to failure. +- ac_old_val_w=`echo x $ac_old_val` +- ac_new_val_w=`echo x $ac_new_val` +- if test "$ac_old_val_w" != "$ac_new_val_w"; then +- { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +-$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} +- ac_cache_corrupted=: +- else +- { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +-$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} +- eval $ac_var=\$ac_old_val +- fi +- { $as_echo "$as_me:$LINENO: former value: \`$ac_old_val'" >&5 +-$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} +- { $as_echo "$as_me:$LINENO: current value: \`$ac_new_val'" >&5 +-$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} +- fi;; +- esac +- # Pass precious variables to config.status. +- if test "$ac_new_set" = set; then +- case $ac_new_val in +- *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; +- *) ac_arg=$ac_var=$ac_new_val ;; +- esac +- case " $ac_configure_args " in +- *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. +- *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; +- esac +- fi +-done +-if $ac_cache_corrupted; then +- { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +- { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +-$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} +- { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +-$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} +- { (exit 1); exit 1; }; } +-fi +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +-ac_ext=c +-ac_cpp='$CPP $CPPFLAGS' +-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +-ac_compiler_gnu=$ac_cv_c_compiler_gnu +- +- +- +-ac_aux_dir= +-for ac_dir in aclocal "$srcdir"/aclocal; do +- if test -f "$ac_dir/install-sh"; then +- ac_aux_dir=$ac_dir +- ac_install_sh="$ac_aux_dir/install-sh -c" +- break +- elif test -f "$ac_dir/install.sh"; then +- ac_aux_dir=$ac_dir +- ac_install_sh="$ac_aux_dir/install.sh -c" +- break +- elif test -f "$ac_dir/shtool"; then +- ac_aux_dir=$ac_dir +- ac_install_sh="$ac_aux_dir/shtool install -c" +- break +- fi +-done +-if test -z "$ac_aux_dir"; then +- { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in aclocal \"$srcdir\"/aclocal" >&5 +-$as_echo "$as_me: error: cannot find install-sh or install.sh in aclocal \"$srcdir\"/aclocal" >&2;} +- { (exit 1); exit 1; }; } +-fi +- +-# These three variables are undocumented and unsupported, +-# and are intended to be withdrawn in a future Autoconf release. +-# They can cause serious problems if a builder's source tree is in a directory +-# whose full name contains unusual characters. +-ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +-ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +-ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. +- +- +- +-ac_config_headers="$ac_config_headers config.h" +- +- +-ac_ext=c +-ac_cpp='$CPP $CPPFLAGS' +-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +-ac_compiler_gnu=$ac_cv_c_compiler_gnu +-if test -n "$ac_tool_prefix"; then +- # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +-set dummy ${ac_tool_prefix}gcc; ac_word=$2 +-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +-$as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_CC+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- if test -n "$CC"; then +- ac_cv_prog_CC="$CC" # Let the user override the test. +-else +-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then +- ac_cv_prog_CC="${ac_tool_prefix}gcc" +- $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 +- break 2 +- fi +-done +-done +-IFS=$as_save_IFS +- +-fi +-fi +-CC=$ac_cv_prog_CC +-if test -n "$CC"; then +- { $as_echo "$as_me:$LINENO: result: $CC" >&5 +-$as_echo "$CC" >&6; } +-else +- { $as_echo "$as_me:$LINENO: result: no" >&5 +-$as_echo "no" >&6; } +-fi +- +- +-fi +-if test -z "$ac_cv_prog_CC"; then +- ac_ct_CC=$CC +- # Extract the first word of "gcc", so it can be a program name with args. +-set dummy gcc; ac_word=$2 +-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +-$as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- if test -n "$ac_ct_CC"; then +- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +-else +-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then +- ac_cv_prog_ac_ct_CC="gcc" +- $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 +- break 2 +- fi +-done +-done +-IFS=$as_save_IFS +- +-fi +-fi +-ac_ct_CC=$ac_cv_prog_ac_ct_CC +-if test -n "$ac_ct_CC"; then +- { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +-$as_echo "$ac_ct_CC" >&6; } +-else +- { $as_echo "$as_me:$LINENO: result: no" >&5 +-$as_echo "no" >&6; } +-fi +- +- if test "x$ac_ct_CC" = x; then +- CC="" +- else +- case $cross_compiling:$ac_tool_warned in +-yes:) +-{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +-ac_tool_warned=yes ;; +-esac +- CC=$ac_ct_CC +- fi +-else +- CC="$ac_cv_prog_CC" +-fi +- +-if test -z "$CC"; then +- if test -n "$ac_tool_prefix"; then +- # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +-set dummy ${ac_tool_prefix}cc; ac_word=$2 +-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +-$as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_CC+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- if test -n "$CC"; then +- ac_cv_prog_CC="$CC" # Let the user override the test. +-else +-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then +- ac_cv_prog_CC="${ac_tool_prefix}cc" +- $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 +- break 2 +- fi +-done +-done +-IFS=$as_save_IFS +- +-fi +-fi +-CC=$ac_cv_prog_CC +-if test -n "$CC"; then +- { $as_echo "$as_me:$LINENO: result: $CC" >&5 +-$as_echo "$CC" >&6; } +-else +- { $as_echo "$as_me:$LINENO: result: no" >&5 +-$as_echo "no" >&6; } +-fi +- +- +- fi +-fi +-if test -z "$CC"; then +- # Extract the first word of "cc", so it can be a program name with args. +-set dummy cc; ac_word=$2 +-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +-$as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_CC+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- if test -n "$CC"; then +- ac_cv_prog_CC="$CC" # Let the user override the test. +-else +- ac_prog_rejected=no +-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then +- if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then +- ac_prog_rejected=yes +- continue +- fi +- ac_cv_prog_CC="cc" +- $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 +- break 2 +- fi +-done +-done +-IFS=$as_save_IFS +- +-if test $ac_prog_rejected = yes; then +- # We found a bogon in the path, so make sure we never use it. +- set dummy $ac_cv_prog_CC +- shift +- if test $# != 0; then +- # We chose a different compiler from the bogus one. +- # However, it has the same basename, so the bogon will be chosen +- # first if we set CC to just the basename; use the full file name. +- shift +- ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" +- fi +-fi +-fi +-fi +-CC=$ac_cv_prog_CC +-if test -n "$CC"; then +- { $as_echo "$as_me:$LINENO: result: $CC" >&5 +-$as_echo "$CC" >&6; } +-else +- { $as_echo "$as_me:$LINENO: result: no" >&5 +-$as_echo "no" >&6; } +-fi +- +- +-fi +-if test -z "$CC"; then +- if test -n "$ac_tool_prefix"; then +- for ac_prog in cl.exe +- do +- # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +-set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +-$as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_CC+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- if test -n "$CC"; then +- ac_cv_prog_CC="$CC" # Let the user override the test. +-else +-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then +- ac_cv_prog_CC="$ac_tool_prefix$ac_prog" +- $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 +- break 2 +- fi +-done +-done +-IFS=$as_save_IFS +- +-fi +-fi +-CC=$ac_cv_prog_CC +-if test -n "$CC"; then +- { $as_echo "$as_me:$LINENO: result: $CC" >&5 +-$as_echo "$CC" >&6; } +-else +- { $as_echo "$as_me:$LINENO: result: no" >&5 +-$as_echo "no" >&6; } +-fi +- +- +- test -n "$CC" && break +- done +-fi +-if test -z "$CC"; then +- ac_ct_CC=$CC +- for ac_prog in cl.exe +-do +- # Extract the first word of "$ac_prog", so it can be a program name with args. +-set dummy $ac_prog; ac_word=$2 +-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +-$as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- if test -n "$ac_ct_CC"; then +- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +-else +-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then +- ac_cv_prog_ac_ct_CC="$ac_prog" +- $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 +- break 2 +- fi +-done +-done +-IFS=$as_save_IFS +- +-fi +-fi +-ac_ct_CC=$ac_cv_prog_ac_ct_CC +-if test -n "$ac_ct_CC"; then +- { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +-$as_echo "$ac_ct_CC" >&6; } +-else +- { $as_echo "$as_me:$LINENO: result: no" >&5 +-$as_echo "no" >&6; } +-fi +- +- +- test -n "$ac_ct_CC" && break +-done +- +- if test "x$ac_ct_CC" = x; then +- CC="" +- else +- case $cross_compiling:$ac_tool_warned in +-yes:) +-{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +-ac_tool_warned=yes ;; +-esac +- CC=$ac_ct_CC +- fi +-fi +- +-fi +- +- +-test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-{ { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +-See \`config.log' for more details." >&5 +-$as_echo "$as_me: error: no acceptable C compiler found in \$PATH +-See \`config.log' for more details." >&2;} +- { (exit 1); exit 1; }; }; } +- +-# Provide some information about the compiler. +-$as_echo "$as_me:$LINENO: checking for C compiler version" >&5 +-set X $ac_compile +-ac_compiler=$2 +-{ (ac_try="$ac_compiler --version >&5" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compiler --version >&5") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } +-{ (ac_try="$ac_compiler -v >&5" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compiler -v >&5") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } +-{ (ac_try="$ac_compiler -V >&5" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compiler -V >&5") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } +- +-cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-int +-main () +-{ +- +- ; +- return 0; +-} +-_ACEOF +-ac_clean_files_save=$ac_clean_files +-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +-# Try to create an executable without -o first, disregard a.out. +-# It will help us diagnose broken compilers, and finding out an intuition +-# of exeext. +-{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +-$as_echo_n "checking for C compiler default output file name... " >&6; } +-ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +- +-# The possible output files: +-ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" +- +-ac_rmfiles= +-for ac_file in $ac_files +-do +- case $ac_file in +- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; +- * ) ac_rmfiles="$ac_rmfiles $ac_file";; +- esac +-done +-rm -f $ac_rmfiles +- +-if { (ac_try="$ac_link_default" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link_default") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; then +- # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +-# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +-# in a Makefile. We should not override ac_cv_exeext if it was cached, +-# so that the user can short-circuit this test for compilers unknown to +-# Autoconf. +-for ac_file in $ac_files '' +-do +- test -f "$ac_file" || continue +- case $ac_file in +- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) +- ;; +- [ab].out ) +- # We found the default executable, but exeext='' is most +- # certainly right. +- break;; +- *.* ) +- if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; +- then :; else +- ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` +- fi +- # We set ac_cv_exeext here because the later test for it is not +- # safe: cross compilers may not add the suffix if given an `-o' +- # argument, so we may need to know it at that point already. +- # Even if this section looks crufty: it has the advantage of +- # actually working. +- break;; +- * ) +- break;; +- esac +-done +-test "$ac_cv_exeext" = no && ac_cv_exeext= +- +-else +- ac_file='' +-fi +- +-{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5 +-$as_echo "$ac_file" >&6; } +-if test -z "$ac_file"; then +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables +-See \`config.log' for more details." >&5 +-$as_echo "$as_me: error: C compiler cannot create executables +-See \`config.log' for more details." >&2;} +- { (exit 77); exit 77; }; }; } +-fi +- +-ac_exeext=$ac_cv_exeext +- +-# Check that the compiler produces executables we can run. If not, either +-# the compiler is broken, or we cross compile. +-{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +-$as_echo_n "checking whether the C compiler works... " >&6; } +-# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +-# If not cross compiling, check that we can run a simple program. +-if test "$cross_compiling" != yes; then +- if { ac_try='./$ac_file' +- { (case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_try") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then +- cross_compiling=no +- else +- if test "$cross_compiling" = maybe; then +- cross_compiling=yes +- else +- { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-{ { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs. +-If you meant to cross compile, use \`--host'. +-See \`config.log' for more details." >&5 +-$as_echo "$as_me: error: cannot run C compiled programs. +-If you meant to cross compile, use \`--host'. +-See \`config.log' for more details." >&2;} +- { (exit 1); exit 1; }; }; } +- fi +- fi +-fi +-{ $as_echo "$as_me:$LINENO: result: yes" >&5 +-$as_echo "yes" >&6; } +- +-rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +-ac_clean_files=$ac_clean_files_save +-# Check that the compiler produces executables we can run. If not, either +-# the compiler is broken, or we cross compile. +-{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +-$as_echo_n "checking whether we are cross compiling... " >&6; } +-{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5 +-$as_echo "$cross_compiling" >&6; } +- +-{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5 +-$as_echo_n "checking for suffix of executables... " >&6; } +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; then +- # If both `conftest.exe' and `conftest' are `present' (well, observable) +-# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +-# work properly (i.e., refer to `conftest.exe'), while it won't with +-# `rm'. +-for ac_file in conftest.exe conftest conftest.*; do +- test -f "$ac_file" || continue +- case $ac_file in +- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; +- *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` +- break;; +- * ) break;; +- esac +-done +-else +- { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +-See \`config.log' for more details." >&5 +-$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +-See \`config.log' for more details." >&2;} +- { (exit 1); exit 1; }; }; } +-fi +- +-rm -f conftest$ac_cv_exeext +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +-$as_echo "$ac_cv_exeext" >&6; } +- +-rm -f conftest.$ac_ext +-EXEEXT=$ac_cv_exeext +-ac_exeext=$EXEEXT +-{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5 +-$as_echo_n "checking for suffix of object files... " >&6; } +-if test "${ac_cv_objext+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-int +-main () +-{ +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.o conftest.obj +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; then +- for ac_file in conftest.o conftest.obj conftest.*; do +- test -f "$ac_file" || continue; +- case $ac_file in +- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; +- *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` +- break;; +- esac +-done +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +-See \`config.log' for more details." >&5 +-$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile +-See \`config.log' for more details." >&2;} +- { (exit 1); exit 1; }; }; } +-fi +- +-rm -f conftest.$ac_cv_objext conftest.$ac_ext +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +-$as_echo "$ac_cv_objext" >&6; } +-OBJEXT=$ac_cv_objext +-ac_objext=$OBJEXT +-{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +-$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +-if test "${ac_cv_c_compiler_gnu+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-int +-main () +-{ +-#ifndef __GNUC__ +- choke me +-#endif +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_compiler_gnu=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_compiler_gnu=no +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +-ac_cv_c_compiler_gnu=$ac_compiler_gnu +- +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +-$as_echo "$ac_cv_c_compiler_gnu" >&6; } +-if test $ac_compiler_gnu = yes; then +- GCC=yes +-else +- GCC= +-fi +-ac_test_CFLAGS=${CFLAGS+set} +-ac_save_CFLAGS=$CFLAGS +-{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +-$as_echo_n "checking whether $CC accepts -g... " >&6; } +-if test "${ac_cv_prog_cc_g+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- ac_save_c_werror_flag=$ac_c_werror_flag +- ac_c_werror_flag=yes +- ac_cv_prog_cc_g=no +- CFLAGS="-g" +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-int +-main () +-{ +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_cv_prog_cc_g=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- CFLAGS="" +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-int +-main () +-{ +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- : +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_c_werror_flag=$ac_save_c_werror_flag +- CFLAGS="-g" +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-int +-main () +-{ +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_cv_prog_cc_g=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +- ac_c_werror_flag=$ac_save_c_werror_flag +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +-$as_echo "$ac_cv_prog_cc_g" >&6; } +-if test "$ac_test_CFLAGS" = set; then +- CFLAGS=$ac_save_CFLAGS +-elif test $ac_cv_prog_cc_g = yes; then +- if test "$GCC" = yes; then +- CFLAGS="-g -O2" +- else +- CFLAGS="-g" +- fi +-else +- if test "$GCC" = yes; then +- CFLAGS="-O2" +- else +- CFLAGS= +- fi +-fi +-{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +-$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +-if test "${ac_cv_prog_cc_c89+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- ac_cv_prog_cc_c89=no +-ac_save_CC=$CC +-cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +-#include +-#include +-#include +-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +-struct buf { int x; }; +-FILE * (*rcsopen) (struct buf *, struct stat *, int); +-static char *e (p, i) +- char **p; +- int i; +-{ +- return p[i]; +-} +-static char *f (char * (*g) (char **, int), char **p, ...) +-{ +- char *s; +- va_list v; +- va_start (v,p); +- s = g (p, va_arg (v,int)); +- va_end (v); +- return s; +-} +- +-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has +- function prototypes and stuff, but not '\xHH' hex character constants. +- These don't provoke an error unfortunately, instead are silently treated +- as 'x'. The following induces an error, until -std is added to get +- proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an +- array size at least. It's necessary to write '\x00'==0 to get something +- that's true only with -std. */ +-int osf4_cc_array ['\x00' == 0 ? 1 : -1]; +- +-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters +- inside strings and character constants. */ +-#define FOO(x) 'x' +-int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; +- +-int test (int i, double x); +-struct s1 {int (*f) (int a);}; +-struct s2 {int (*f) (double a);}; +-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +-int argc; +-char **argv; +-int +-main () +-{ +-return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; +- ; +- return 0; +-} +-_ACEOF +-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ +- -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +-do +- CC="$ac_save_CC $ac_arg" +- rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_cv_prog_cc_c89=$ac_arg +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- +-fi +- +-rm -f core conftest.err conftest.$ac_objext +- test "x$ac_cv_prog_cc_c89" != "xno" && break +-done +-rm -f conftest.$ac_ext +-CC=$ac_save_CC +- +-fi +-# AC_CACHE_VAL +-case "x$ac_cv_prog_cc_c89" in +- x) +- { $as_echo "$as_me:$LINENO: result: none needed" >&5 +-$as_echo "none needed" >&6; } ;; +- xno) +- { $as_echo "$as_me:$LINENO: result: unsupported" >&5 +-$as_echo "unsupported" >&6; } ;; +- *) +- CC="$CC $ac_cv_prog_cc_c89" +- { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +-$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +-esac +- +- +-ac_ext=c +-ac_cpp='$CPP $CPPFLAGS' +-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +-ac_compiler_gnu=$ac_cv_c_compiler_gnu +- +-# Make sure we can run config.sub. +-$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || +- { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 +-$as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} +- { (exit 1); exit 1; }; } +- +-{ $as_echo "$as_me:$LINENO: checking build system type" >&5 +-$as_echo_n "checking build system type... " >&6; } +-if test "${ac_cv_build+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- ac_build_alias=$build_alias +-test "x$ac_build_alias" = x && +- ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +-test "x$ac_build_alias" = x && +- { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +-$as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;} +- { (exit 1); exit 1; }; } +-ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || +- { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 +-$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} +- { (exit 1); exit 1; }; } +- +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +-$as_echo "$ac_cv_build" >&6; } +-case $ac_cv_build in +-*-*-*) ;; +-*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 +-$as_echo "$as_me: error: invalid value of canonical build" >&2;} +- { (exit 1); exit 1; }; };; +-esac +-build=$ac_cv_build +-ac_save_IFS=$IFS; IFS='-' +-set x $ac_cv_build +-shift +-build_cpu=$1 +-build_vendor=$2 +-shift; shift +-# Remember, the first character of IFS is used to create $*, +-# except with old shells: +-build_os=$* +-IFS=$ac_save_IFS +-case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac +- +- +-{ $as_echo "$as_me:$LINENO: checking host system type" >&5 +-$as_echo_n "checking host system type... " >&6; } +-if test "${ac_cv_host+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- if test "x$host_alias" = x; then +- ac_cv_host=$ac_cv_build +-else +- ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || +- { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 +-$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} +- { (exit 1); exit 1; }; } +-fi +- +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +-$as_echo "$ac_cv_host" >&6; } +-case $ac_cv_host in +-*-*-*) ;; +-*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 +-$as_echo "$as_me: error: invalid value of canonical host" >&2;} +- { (exit 1); exit 1; }; };; +-esac +-host=$ac_cv_host +-ac_save_IFS=$IFS; IFS='-' +-set x $ac_cv_host +-shift +-host_cpu=$1 +-host_vendor=$2 +-shift; shift +-# Remember, the first character of IFS is used to create $*, +-# except with old shells: +-host_os=$* +-IFS=$ac_save_IFS +-case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac +- +- +- +-ac_ext=c +-ac_cpp='$CPP $CPPFLAGS' +-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +-ac_compiler_gnu=$ac_cv_c_compiler_gnu +-{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +-$as_echo_n "checking how to run the C preprocessor... " >&6; } +-# On Suns, sometimes $CPP names a directory. +-if test -n "$CPP" && test -d "$CPP"; then +- CPP= +-fi +-if test -z "$CPP"; then +- if test "${ac_cv_prog_CPP+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- # Double quotes because CPP needs to be expanded +- for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" +- do +- ac_preproc_ok=false +-for ac_c_preproc_warn_flag in '' yes +-do +- # Use a header file that comes with gcc, so configuring glibc +- # with a fresh cross-compiler works. +- # Prefer to if __STDC__ is defined, since +- # exists even on freestanding compilers. +- # On the NeXT, cc -E runs the code through the compiler's parser, +- # not just through cpp. "Syntax error" is here to catch this case. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#ifdef __STDC__ +-# include +-#else +-# include +-#endif +- Syntax error +-_ACEOF +-if { (ac_try="$ac_cpp conftest.$ac_ext" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } >/dev/null && { +- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || +- test ! -s conftest.err +- }; then +- : +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- # Broken: fails on valid input. +-continue +-fi +- +-rm -f conftest.err conftest.$ac_ext +- +- # OK, works on sane cases. Now check whether nonexistent headers +- # can be detected and how. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +-_ACEOF +-if { (ac_try="$ac_cpp conftest.$ac_ext" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } >/dev/null && { +- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || +- test ! -s conftest.err +- }; then +- # Broken: success on invalid input. +-continue +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- # Passes both tests. +-ac_preproc_ok=: +-break +-fi +- +-rm -f conftest.err conftest.$ac_ext +- +-done +-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +-rm -f conftest.err conftest.$ac_ext +-if $ac_preproc_ok; then +- break +-fi +- +- done +- ac_cv_prog_CPP=$CPP +- +-fi +- CPP=$ac_cv_prog_CPP +-else +- ac_cv_prog_CPP=$CPP +-fi +-{ $as_echo "$as_me:$LINENO: result: $CPP" >&5 +-$as_echo "$CPP" >&6; } +-ac_preproc_ok=false +-for ac_c_preproc_warn_flag in '' yes +-do +- # Use a header file that comes with gcc, so configuring glibc +- # with a fresh cross-compiler works. +- # Prefer to if __STDC__ is defined, since +- # exists even on freestanding compilers. +- # On the NeXT, cc -E runs the code through the compiler's parser, +- # not just through cpp. "Syntax error" is here to catch this case. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#ifdef __STDC__ +-# include +-#else +-# include +-#endif +- Syntax error +-_ACEOF +-if { (ac_try="$ac_cpp conftest.$ac_ext" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } >/dev/null && { +- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || +- test ! -s conftest.err +- }; then +- : +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- # Broken: fails on valid input. +-continue +-fi +- +-rm -f conftest.err conftest.$ac_ext +- +- # OK, works on sane cases. Now check whether nonexistent headers +- # can be detected and how. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +-_ACEOF +-if { (ac_try="$ac_cpp conftest.$ac_ext" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } >/dev/null && { +- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || +- test ! -s conftest.err +- }; then +- # Broken: success on invalid input. +-continue +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- # Passes both tests. +-ac_preproc_ok=: +-break +-fi +- +-rm -f conftest.err conftest.$ac_ext +- +-done +-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +-rm -f conftest.err conftest.$ac_ext +-if $ac_preproc_ok; then +- : +-else +- { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +-See \`config.log' for more details." >&5 +-$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +-See \`config.log' for more details." >&2;} +- { (exit 1); exit 1; }; }; } +-fi +- +-ac_ext=c +-ac_cpp='$CPP $CPPFLAGS' +-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +-ac_compiler_gnu=$ac_cv_c_compiler_gnu +- +- +-{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +-$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +-if test "${ac_cv_path_GREP+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- if test -z "$GREP"; then +- ac_path_GREP_found=false +- # Loop through the user's path and test for each of PROGNAME-LIST +- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- for ac_prog in grep ggrep; do +- for ac_exec_ext in '' $ac_executable_extensions; do +- ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" +- { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +-# Check for GNU ac_path_GREP and select it if it is found. +- # Check for GNU $ac_path_GREP +-case `"$ac_path_GREP" --version 2>&1` in +-*GNU*) +- ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +-*) +- ac_count=0 +- $as_echo_n 0123456789 >"conftest.in" +- while : +- do +- cat "conftest.in" "conftest.in" >"conftest.tmp" +- mv "conftest.tmp" "conftest.in" +- cp "conftest.in" "conftest.nl" +- $as_echo 'GREP' >> "conftest.nl" +- "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break +- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break +- ac_count=`expr $ac_count + 1` +- if test $ac_count -gt ${ac_path_GREP_max-0}; then +- # Best one so far, save it but keep looking for a better one +- ac_cv_path_GREP="$ac_path_GREP" +- ac_path_GREP_max=$ac_count +- fi +- # 10*(2^10) chars as input seems more than enough +- test $ac_count -gt 10 && break +- done +- rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +-esac +- +- $ac_path_GREP_found && break 3 +- done +- done +-done +-IFS=$as_save_IFS +- if test -z "$ac_cv_path_GREP"; then +- { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +-$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} +- { (exit 1); exit 1; }; } +- fi +-else +- ac_cv_path_GREP=$GREP +-fi +- +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +-$as_echo "$ac_cv_path_GREP" >&6; } +- GREP="$ac_cv_path_GREP" +- +- +-{ $as_echo "$as_me:$LINENO: checking for egrep" >&5 +-$as_echo_n "checking for egrep... " >&6; } +-if test "${ac_cv_path_EGREP+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 +- then ac_cv_path_EGREP="$GREP -E" +- else +- if test -z "$EGREP"; then +- ac_path_EGREP_found=false +- # Loop through the user's path and test for each of PROGNAME-LIST +- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- for ac_prog in egrep; do +- for ac_exec_ext in '' $ac_executable_extensions; do +- ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" +- { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +-# Check for GNU ac_path_EGREP and select it if it is found. +- # Check for GNU $ac_path_EGREP +-case `"$ac_path_EGREP" --version 2>&1` in +-*GNU*) +- ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +-*) +- ac_count=0 +- $as_echo_n 0123456789 >"conftest.in" +- while : +- do +- cat "conftest.in" "conftest.in" >"conftest.tmp" +- mv "conftest.tmp" "conftest.in" +- cp "conftest.in" "conftest.nl" +- $as_echo 'EGREP' >> "conftest.nl" +- "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break +- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break +- ac_count=`expr $ac_count + 1` +- if test $ac_count -gt ${ac_path_EGREP_max-0}; then +- # Best one so far, save it but keep looking for a better one +- ac_cv_path_EGREP="$ac_path_EGREP" +- ac_path_EGREP_max=$ac_count +- fi +- # 10*(2^10) chars as input seems more than enough +- test $ac_count -gt 10 && break +- done +- rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +-esac +- +- $ac_path_EGREP_found && break 3 +- done +- done +-done +-IFS=$as_save_IFS +- if test -z "$ac_cv_path_EGREP"; then +- { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +-$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} +- { (exit 1); exit 1; }; } +- fi +-else +- ac_cv_path_EGREP=$EGREP +-fi +- +- fi +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +-$as_echo "$ac_cv_path_EGREP" >&6; } +- EGREP="$ac_cv_path_EGREP" +- +- +-{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +-$as_echo_n "checking for ANSI C header files... " >&6; } +-if test "${ac_cv_header_stdc+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +-#include +-#include +-#include +- +-int +-main () +-{ +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_cv_header_stdc=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_cv_header_stdc=no +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +- +-if test $ac_cv_header_stdc = yes; then +- # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +- +-_ACEOF +-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | +- $EGREP "memchr" >/dev/null 2>&1; then +- : +-else +- ac_cv_header_stdc=no +-fi +-rm -f conftest* +- +-fi +- +-if test $ac_cv_header_stdc = yes; then +- # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +- +-_ACEOF +-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | +- $EGREP "free" >/dev/null 2>&1; then +- : +-else +- ac_cv_header_stdc=no +-fi +-rm -f conftest* +- +-fi +- +-if test $ac_cv_header_stdc = yes; then +- # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +- if test "$cross_compiling" = yes; then +- : +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +-#include +-#if ((' ' & 0x0FF) == 0x020) +-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +-#else +-# define ISLOWER(c) \ +- (('a' <= (c) && (c) <= 'i') \ +- || ('j' <= (c) && (c) <= 'r') \ +- || ('s' <= (c) && (c) <= 'z')) +-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +-#endif +- +-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +-int +-main () +-{ +- int i; +- for (i = 0; i < 256; i++) +- if (XOR (islower (i), ISLOWER (i)) +- || toupper (i) != TOUPPER (i)) +- return 2; +- return 0; +-} +-_ACEOF +-rm -f conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { ac_try='./conftest$ac_exeext' +- { (case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_try") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then +- : +-else +- $as_echo "$as_me: program exited with status $ac_status" >&5 +-$as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-( exit $ac_status ) +-ac_cv_header_stdc=no +-fi +-rm -rf conftest.dSYM +-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +-fi +- +- +-fi +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +-$as_echo "$ac_cv_header_stdc" >&6; } +-if test $ac_cv_header_stdc = yes; then +- +-cat >>confdefs.h <<\_ACEOF +-#define STDC_HEADERS 1 +-_ACEOF +- +-fi +- +-# On IRIX 5.3, sys/types and inttypes.h are conflicting. +- +- +- +- +- +- +- +- +- +-for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ +- inttypes.h stdint.h unistd.h +-do +-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +-$as_echo_n "checking for $ac_header... " >&6; } +-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then +- $as_echo_n "(cached) " >&6 +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-$ac_includes_default +- +-#include <$ac_header> +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- eval "$as_ac_Header=yes" +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- eval "$as_ac_Header=no" +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +-fi +-ac_res=`eval 'as_val=${'$as_ac_Header'} +- $as_echo "$as_val"'` +- { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +-$as_echo "$ac_res" >&6; } +-as_val=`eval 'as_val=${'$as_ac_Header'} +- $as_echo "$as_val"'` +- if test "x$as_val" = x""yes; then +- cat >>confdefs.h <<_ACEOF +-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +-_ACEOF +- +-fi +- +-done +- +- +- +- { $as_echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 +-$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +-if test "${ac_cv_c_bigendian+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- ac_cv_c_bigendian=unknown +- # See if we're dealing with a universal compiler. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#ifndef __APPLE_CC__ +- not a universal capable compiler +- #endif +- typedef int dummy; +- +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- +- # Check for potential -arch flags. It is not universal unless +- # there are some -arch flags. Note that *ppc* also matches +- # ppc64. This check is also rather less than ideal. +- case "${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS}" in #( +- *-arch*ppc*|*-arch*i386*|*-arch*x86_64*) ac_cv_c_bigendian=universal;; +- esac +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +- if test $ac_cv_c_bigendian = unknown; then +- # See if sys/param.h defines the BYTE_ORDER macro. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +- #include +- +-int +-main () +-{ +-#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ +- && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ +- && LITTLE_ENDIAN) +- bogus endian macros +- #endif +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- # It does; now see whether it defined to BIG_ENDIAN or not. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +- #include +- +-int +-main () +-{ +-#if BYTE_ORDER != BIG_ENDIAN +- not big endian +- #endif +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_cv_c_bigendian=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_cv_c_bigendian=no +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +- fi +- if test $ac_cv_c_bigendian = unknown; then +- # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +- +-int +-main () +-{ +-#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) +- bogus endian macros +- #endif +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- # It does; now see whether it defined to _BIG_ENDIAN or not. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +- +-int +-main () +-{ +-#ifndef _BIG_ENDIAN +- not big endian +- #endif +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_cv_c_bigendian=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_cv_c_bigendian=no +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +- fi +- if test $ac_cv_c_bigendian = unknown; then +- # Compile a test program. +- if test "$cross_compiling" = yes; then +- # Try to guess by grepping values from an object file. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-short int ascii_mm[] = +- { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; +- short int ascii_ii[] = +- { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; +- int use_ascii (int i) { +- return ascii_mm[i] + ascii_ii[i]; +- } +- short int ebcdic_ii[] = +- { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; +- short int ebcdic_mm[] = +- { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; +- int use_ebcdic (int i) { +- return ebcdic_mm[i] + ebcdic_ii[i]; +- } +- extern int foo; +- +-int +-main () +-{ +-return use_ascii (foo) == use_ebcdic (foo); +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then +- ac_cv_c_bigendian=yes +- fi +- if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then +- if test "$ac_cv_c_bigendian" = unknown; then +- ac_cv_c_bigendian=no +- else +- # finding both strings is unlikely to happen, but who knows? +- ac_cv_c_bigendian=unknown +- fi +- fi +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-$ac_includes_default +-int +-main () +-{ +- +- /* Are we little or big endian? From Harbison&Steele. */ +- union +- { +- long int l; +- char c[sizeof (long int)]; +- } u; +- u.l = 1; +- return u.c[sizeof (long int) - 1] == 1; +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { ac_try='./conftest$ac_exeext' +- { (case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_try") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then +- ac_cv_c_bigendian=no +-else +- $as_echo "$as_me: program exited with status $ac_status" >&5 +-$as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-( exit $ac_status ) +-ac_cv_c_bigendian=yes +-fi +-rm -rf conftest.dSYM +-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +-fi +- +- +- fi +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 +-$as_echo "$ac_cv_c_bigendian" >&6; } +- case $ac_cv_c_bigendian in #( +- yes) +- cat >>confdefs.h <<\_ACEOF +-#define WORDS_BIGENDIAN 1 +-_ACEOF +-;; #( +- no) +- ;; #( +- universal) +- +-cat >>confdefs.h <<\_ACEOF +-#define AC_APPLE_UNIVERSAL_BUILD 1 +-_ACEOF +- +- ;; #( +- *) +- { { $as_echo "$as_me:$LINENO: error: unknown endianness +- presetting ac_cv_c_bigendian=no (or yes) will help" >&5 +-$as_echo "$as_me: error: unknown endianness +- presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} +- { (exit 1); exit 1; }; } ;; +- esac +- +- +-ac_ext=c +-ac_cpp='$CPP $CPPFLAGS' +-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +-ac_compiler_gnu=$ac_cv_c_compiler_gnu +-{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +-$as_echo_n "checking how to run the C preprocessor... " >&6; } +-# On Suns, sometimes $CPP names a directory. +-if test -n "$CPP" && test -d "$CPP"; then +- CPP= +-fi +-if test -z "$CPP"; then +- if test "${ac_cv_prog_CPP+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- # Double quotes because CPP needs to be expanded +- for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" +- do +- ac_preproc_ok=false +-for ac_c_preproc_warn_flag in '' yes +-do +- # Use a header file that comes with gcc, so configuring glibc +- # with a fresh cross-compiler works. +- # Prefer to if __STDC__ is defined, since +- # exists even on freestanding compilers. +- # On the NeXT, cc -E runs the code through the compiler's parser, +- # not just through cpp. "Syntax error" is here to catch this case. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#ifdef __STDC__ +-# include +-#else +-# include +-#endif +- Syntax error +-_ACEOF +-if { (ac_try="$ac_cpp conftest.$ac_ext" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } >/dev/null && { +- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || +- test ! -s conftest.err +- }; then +- : +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- # Broken: fails on valid input. +-continue +-fi +- +-rm -f conftest.err conftest.$ac_ext +- +- # OK, works on sane cases. Now check whether nonexistent headers +- # can be detected and how. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +-_ACEOF +-if { (ac_try="$ac_cpp conftest.$ac_ext" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } >/dev/null && { +- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || +- test ! -s conftest.err +- }; then +- # Broken: success on invalid input. +-continue +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- # Passes both tests. +-ac_preproc_ok=: +-break +-fi +- +-rm -f conftest.err conftest.$ac_ext +- +-done +-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +-rm -f conftest.err conftest.$ac_ext +-if $ac_preproc_ok; then +- break +-fi +- +- done +- ac_cv_prog_CPP=$CPP +- +-fi +- CPP=$ac_cv_prog_CPP +-else +- ac_cv_prog_CPP=$CPP +-fi +-{ $as_echo "$as_me:$LINENO: result: $CPP" >&5 +-$as_echo "$CPP" >&6; } +-ac_preproc_ok=false +-for ac_c_preproc_warn_flag in '' yes +-do +- # Use a header file that comes with gcc, so configuring glibc +- # with a fresh cross-compiler works. +- # Prefer to if __STDC__ is defined, since +- # exists even on freestanding compilers. +- # On the NeXT, cc -E runs the code through the compiler's parser, +- # not just through cpp. "Syntax error" is here to catch this case. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#ifdef __STDC__ +-# include +-#else +-# include +-#endif +- Syntax error +-_ACEOF +-if { (ac_try="$ac_cpp conftest.$ac_ext" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } >/dev/null && { +- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || +- test ! -s conftest.err +- }; then +- : +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- # Broken: fails on valid input. +-continue +-fi +- +-rm -f conftest.err conftest.$ac_ext +- +- # OK, works on sane cases. Now check whether nonexistent headers +- # can be detected and how. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +-_ACEOF +-if { (ac_try="$ac_cpp conftest.$ac_ext" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } >/dev/null && { +- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || +- test ! -s conftest.err +- }; then +- # Broken: success on invalid input. +-continue +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- # Passes both tests. +-ac_preproc_ok=: +-break +-fi +- +-rm -f conftest.err conftest.$ac_ext +- +-done +-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +-rm -f conftest.err conftest.$ac_ext +-if $ac_preproc_ok; then +- : +-else +- { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +-See \`config.log' for more details." >&5 +-$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +-See \`config.log' for more details." >&2;} +- { (exit 1); exit 1; }; }; } +-fi +- +-ac_ext=c +-ac_cpp='$CPP $CPPFLAGS' +-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +-ac_compiler_gnu=$ac_cv_c_compiler_gnu +- +-# Find a good install program. We prefer a C program (faster), +-# so one script is as good as another. But avoid the broken or +-# incompatible versions: +-# SysV /etc/install, /usr/sbin/install +-# SunOS /usr/etc/install +-# IRIX /sbin/install +-# AIX /bin/install +-# AmigaOS /C/install, which installs bootblocks on floppy discs +-# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +-# AFS /usr/afsws/bin/install, which mishandles nonexistent args +-# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +-# OS/2's system install, which has a completely different semantic +-# ./install, which can be erroneously created by make from ./install.sh. +-# Reject install programs that cannot install multiple files. +-{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +-$as_echo_n "checking for a BSD-compatible install... " >&6; } +-if test -z "$INSTALL"; then +-if test "${ac_cv_path_install+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- # Account for people who put trailing slashes in PATH elements. +-case $as_dir/ in +- ./ | .// | /cC/* | \ +- /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ +- ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ +- /usr/ucb/* ) ;; +- *) +- # OSF1 and SCO ODT 3.0 have their own names for install. +- # Don't use installbsd from OSF since it installs stuff as root +- # by default. +- for ac_prog in ginstall scoinst install; do +- for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then +- if test $ac_prog = install && +- grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then +- # AIX install. It has an incompatible calling convention. +- : +- elif test $ac_prog = install && +- grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then +- # program-specific install script used by HP pwplus--don't use. +- : +- else +- rm -rf conftest.one conftest.two conftest.dir +- echo one > conftest.one +- echo two > conftest.two +- mkdir conftest.dir +- if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && +- test -s conftest.one && test -s conftest.two && +- test -s conftest.dir/conftest.one && +- test -s conftest.dir/conftest.two +- then +- ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" +- break 3 +- fi +- fi +- fi +- done +- done +- ;; +-esac +- +-done +-IFS=$as_save_IFS +- +-rm -rf conftest.one conftest.two conftest.dir +- +-fi +- if test "${ac_cv_path_install+set}" = set; then +- INSTALL=$ac_cv_path_install +- else +- # As a last resort, use the slow shell script. Don't cache a +- # value for INSTALL within a source directory, because that will +- # break other packages using the cache if that directory is +- # removed, or if the value is a relative name. +- INSTALL=$ac_install_sh +- fi +-fi +-{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5 +-$as_echo "$INSTALL" >&6; } +- +-# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +-# It thinks the first close brace ends the variable substitution. +-test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' +- +-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' +- +-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' +- +-{ $as_echo "$as_me:$LINENO: checking whether ln -s works" >&5 +-$as_echo_n "checking whether ln -s works... " >&6; } +-LN_S=$as_ln_s +-if test "$LN_S" = "ln -s"; then +- { $as_echo "$as_me:$LINENO: result: yes" >&5 +-$as_echo "yes" >&6; } +-else +- { $as_echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +-$as_echo "no, using $LN_S" >&6; } +-fi +- +-{ $as_echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +-$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +-set x ${MAKE-make} +-ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +-if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then +- $as_echo_n "(cached) " >&6 +-else +- cat >conftest.make <<\_ACEOF +-SHELL = /bin/sh +-all: +- @echo '@@@%%%=$(MAKE)=@@@%%%' +-_ACEOF +-# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +-case `${MAKE-make} -f conftest.make 2>/dev/null` in +- *@@@%%%=?*=@@@%%%*) +- eval ac_cv_prog_make_${ac_make}_set=yes;; +- *) +- eval ac_cv_prog_make_${ac_make}_set=no;; +-esac +-rm -f conftest.make +-fi +-if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then +- { $as_echo "$as_me:$LINENO: result: yes" >&5 +-$as_echo "yes" >&6; } +- SET_MAKE= +-else +- { $as_echo "$as_me:$LINENO: result: no" >&5 +-$as_echo "no" >&6; } +- SET_MAKE="MAKE=${MAKE-make}" +-fi +- +-# Extract the first word of "sh", so it can be a program name with args. +-set dummy sh; ac_word=$2 +-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +-$as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_path_SH+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- case $SH in +- [\\/]* | ?:[\\/]*) +- ac_cv_path_SH="$SH" # Let the user override the test with a path. +- ;; +- *) +- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then +- ac_cv_path_SH="$as_dir/$ac_word$ac_exec_ext" +- $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 +- break 2 +- fi +-done +-done +-IFS=$as_save_IFS +- +- ;; +-esac +-fi +-SH=$ac_cv_path_SH +-if test -n "$SH"; then +- { $as_echo "$as_me:$LINENO: result: $SH" >&5 +-$as_echo "$SH" >&6; } +-else +- { $as_echo "$as_me:$LINENO: result: no" >&5 +-$as_echo "no" >&6; } +-fi +- +- +- +-{ $as_echo "$as_me:$LINENO: checking for inline" >&5 +-$as_echo_n "checking for inline... " >&6; } +-if test "${ac_cv_c_inline+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- ac_cv_c_inline=no +-for ac_kw in inline __inline__ __inline; do +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#ifndef __cplusplus +-typedef int foo_t; +-static $ac_kw foo_t static_foo () {return 0; } +-$ac_kw foo_t foo () {return 0; } +-#endif +- +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_cv_c_inline=$ac_kw +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +- test "$ac_cv_c_inline" != no && break +-done +- +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 +-$as_echo "$ac_cv_c_inline" >&6; } +- +- +-case $ac_cv_c_inline in +- inline | yes) ;; +- *) +- case $ac_cv_c_inline in +- no) ac_val=;; +- *) ac_val=$ac_cv_c_inline;; +- esac +- cat >>confdefs.h <<_ACEOF +-#ifndef __cplusplus +-#define inline $ac_val +-#endif +-_ACEOF +- ;; +-esac +- +-if test "$GCC" = "yes"; then +- CFLAGS="-Wall -fno-strict-aliasing $CFLAGS" +- CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" +-fi +- +-{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +-$as_echo_n "checking for ANSI C header files... " >&6; } +-if test "${ac_cv_header_stdc+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +-#include +-#include +-#include +- +-int +-main () +-{ +- +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_cv_header_stdc=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_cv_header_stdc=no +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +- +-if test $ac_cv_header_stdc = yes; then +- # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +- +-_ACEOF +-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | +- $EGREP "memchr" >/dev/null 2>&1; then +- : +-else +- ac_cv_header_stdc=no +-fi +-rm -f conftest* +- +-fi +- +-if test $ac_cv_header_stdc = yes; then +- # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +- +-_ACEOF +-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | +- $EGREP "free" >/dev/null 2>&1; then +- : +-else +- ac_cv_header_stdc=no +-fi +-rm -f conftest* +- +-fi +- +-if test $ac_cv_header_stdc = yes; then +- # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +- if test "$cross_compiling" = yes; then +- : +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +-#include +-#if ((' ' & 0x0FF) == 0x020) +-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +-#else +-# define ISLOWER(c) \ +- (('a' <= (c) && (c) <= 'i') \ +- || ('j' <= (c) && (c) <= 'r') \ +- || ('s' <= (c) && (c) <= 'z')) +-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +-#endif +- +-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +-int +-main () +-{ +- int i; +- for (i = 0; i < 256; i++) +- if (XOR (islower (i), ISLOWER (i)) +- || toupper (i) != TOUPPER (i)) +- return 2; +- return 0; +-} +-_ACEOF +-rm -f conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { ac_try='./conftest$ac_exeext' +- { (case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_try") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then +- : +-else +- $as_echo "$as_me: program exited with status $ac_status" >&5 +-$as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-( exit $ac_status ) +-ac_cv_header_stdc=no +-fi +-rm -rf conftest.dSYM +-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +-fi +- +- +-fi +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +-$as_echo "$ac_cv_header_stdc" >&6; } +-if test $ac_cv_header_stdc = yes; then +- +-cat >>confdefs.h <<\_ACEOF +-#define STDC_HEADERS 1 +-_ACEOF +- +-fi +- +-{ $as_echo "$as_me:$LINENO: checking for sys/wait.h that is POSIX.1 compatible" >&5 +-$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } +-if test "${ac_cv_header_sys_wait_h+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include +-#include +-#ifndef WEXITSTATUS +-# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) +-#endif +-#ifndef WIFEXITED +-# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +-#endif +- +-int +-main () +-{ +- int s; +- wait (&s); +- s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_cv_header_sys_wait_h=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_cv_header_sys_wait_h=no +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5 +-$as_echo "$ac_cv_header_sys_wait_h" >&6; } +-if test $ac_cv_header_sys_wait_h = yes; then +- +-cat >>confdefs.h <<\_ACEOF +-#define HAVE_SYS_WAIT_H 1 +-_ACEOF +- +-fi +- +- +- +- +- +- +- +- +- +- +- +-for ac_header in errno.h fcntl.h malloc.h stdlib.h string.h strings.h sys/time.h unistd.h locale.h getopt.h +-do +-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then +- { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +-$as_echo_n "checking for $ac_header... " >&6; } +-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then +- $as_echo_n "(cached) " >&6 +-fi +-ac_res=`eval 'as_val=${'$as_ac_Header'} +- $as_echo "$as_val"'` +- { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +-$as_echo "$ac_res" >&6; } +-else +- # Is the header compilable? +-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +-$as_echo_n "checking $ac_header usability... " >&6; } +-cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-$ac_includes_default +-#include <$ac_header> +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_header_compiler=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_header_compiler=no +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +-$as_echo "$ac_header_compiler" >&6; } +- +-# Is the header present? +-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +-$as_echo_n "checking $ac_header presence... " >&6; } +-cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include <$ac_header> +-_ACEOF +-if { (ac_try="$ac_cpp conftest.$ac_ext" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } >/dev/null && { +- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || +- test ! -s conftest.err +- }; then +- ac_header_preproc=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_header_preproc=no +-fi +- +-rm -f conftest.err conftest.$ac_ext +-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +-$as_echo "$ac_header_preproc" >&6; } +- +-# So? What about this header? +-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in +- yes:no: ) +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} +- ac_header_preproc=yes +- ;; +- no:yes:* ) +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +-$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +-$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} +- +- ;; +-esac +-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +-$as_echo_n "checking for $ac_header... " >&6; } +-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then +- $as_echo_n "(cached) " >&6 +-else +- eval "$as_ac_Header=\$ac_header_preproc" +-fi +-ac_res=`eval 'as_val=${'$as_ac_Header'} +- $as_echo "$as_val"'` +- { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +-$as_echo "$ac_res" >&6; } +- +-fi +-as_val=`eval 'as_val=${'$as_ac_Header'} +- $as_echo "$as_val"'` +- if test "x$as_val" = x""yes; then +- cat >>confdefs.h <<_ACEOF +-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +-_ACEOF +- +-fi +- +-done +- +- +-# Check if socket() is in libsocket +-{ $as_echo "$as_me:$LINENO: checking for socket in -lsocket" >&5 +-$as_echo_n "checking for socket in -lsocket... " >&6; } +-if test "${ac_cv_lib_socket_socket+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- ac_check_lib_save_LIBS=$LIBS +-LIBS="-lsocket $LIBS" +-cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-/* Override any GCC internal prototype to avoid an error. +- Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-#ifdef __cplusplus +-extern "C" +-#endif +-char socket (); +-int +-main () +-{ +-return socket (); +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest$ac_exeext && { +- test "$cross_compiling" = yes || +- $as_test_x conftest$ac_exeext +- }; then +- ac_cv_lib_socket_socket=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_cv_lib_socket_socket=no +-fi +- +-rm -rf conftest.dSYM +-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ +- conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5 +-$as_echo "$ac_cv_lib_socket_socket" >&6; } +-if test "x$ac_cv_lib_socket_socket" = x""yes; then +- LIBS="$LIBS -lsocket" +-fi +- +- +- +- +-{ $as_echo "$as_me:$LINENO: checking for getopt_long" >&5 +-$as_echo_n "checking for getopt_long... " >&6; } +-if test "${ac_cv_func_getopt_long+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-/* Define getopt_long to an innocuous variant, in case declares getopt_long. +- For example, HP-UX 11i declares gettimeofday. */ +-#define getopt_long innocuous_getopt_long +- +-/* System header to define __stub macros and hopefully few prototypes, +- which can conflict with char getopt_long (); below. +- Prefer to if __STDC__ is defined, since +- exists even on freestanding compilers. */ +- +-#ifdef __STDC__ +-# include +-#else +-# include +-#endif +- +-#undef getopt_long +- +-/* Override any GCC internal prototype to avoid an error. +- Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-#ifdef __cplusplus +-extern "C" +-#endif +-char getopt_long (); +-/* The GNU C library defines this for functions which it implements +- to always fail with ENOSYS. Some functions are actually named +- something starting with __ and the normal name is an alias. */ +-#if defined __stub_getopt_long || defined __stub___getopt_long +-choke me +-#endif +- +-int +-main () +-{ +-return getopt_long (); +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest$ac_exeext && { +- test "$cross_compiling" = yes || +- $as_test_x conftest$ac_exeext +- }; then +- ac_cv_func_getopt_long=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_cv_func_getopt_long=no +-fi +- +-rm -rf conftest.dSYM +-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ +- conftest$ac_exeext conftest.$ac_ext +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_getopt_long" >&5 +-$as_echo "$ac_cv_func_getopt_long" >&6; } +-if test "x$ac_cv_func_getopt_long" = x""yes; then +- +-cat >>confdefs.h <<\_ACEOF +-#define HAVE_GETOPT_LONG 1 +-_ACEOF +- +-else +- GETOPTSRC="$GETOPTSRC \$(top_srcdir)/compat/my_getopt.c" +- CPPFLAGS="-I\$(top_srcdir)/compat/ $CPPFLAGS" +- +-cat >>confdefs.h <<\_ACEOF +-#define HAVE_GETOPT_H 1 +-_ACEOF +- +-fi +- +- +-WITH_SECURITY=maybe +- +-# Check whether --with-security was given. +-if test "${with_security+set}" = set; then +- withval=$with_security; +- if test "x$withval" = "xno" -o "x$withval" = "xyes"; then +- WITH_SECURITY=$withval +- else +- WITH_SECURITY=yes +- CPPFLAGS="$CPPFLAGS -I${withval}" +- LDFLAGS="$LDFLAGS -L${withval}" +- fi +- +- +-fi +- +- +-if test "x$WITH_SECURITY" != "xno" ; then +- # Check for openssl support - very primitive, we just +- # check for the presence of crypto.h +- +-for ac_header in openssl/crypto.h +-do +-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then +- { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +-$as_echo_n "checking for $ac_header... " >&6; } +-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then +- $as_echo_n "(cached) " >&6 +-fi +-ac_res=`eval 'as_val=${'$as_ac_Header'} +- $as_echo "$as_val"'` +- { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +-$as_echo "$ac_res" >&6; } +-else +- # Is the header compilable? +-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +-$as_echo_n "checking $ac_header usability... " >&6; } +-cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-$ac_includes_default +-#include <$ac_header> +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_header_compiler=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_header_compiler=no +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +-$as_echo "$ac_header_compiler" >&6; } +- +-# Is the header present? +-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +-$as_echo_n "checking $ac_header presence... " >&6; } +-cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include <$ac_header> +-_ACEOF +-if { (ac_try="$ac_cpp conftest.$ac_ext" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } >/dev/null && { +- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || +- test ! -s conftest.err +- }; then +- ac_header_preproc=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_header_preproc=no +-fi +- +-rm -f conftest.err conftest.$ac_ext +-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +-$as_echo "$ac_header_preproc" >&6; } +- +-# So? What about this header? +-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in +- yes:no: ) +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} +- ac_header_preproc=yes +- ;; +- no:yes:* ) +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +-$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +-$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} +- +- ;; +-esac +-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +-$as_echo_n "checking for $ac_header... " >&6; } +-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then +- $as_echo_n "(cached) " >&6 +-else +- eval "$as_ac_Header=\$ac_header_preproc" +-fi +-ac_res=`eval 'as_val=${'$as_ac_Header'} +- $as_echo "$as_val"'` +- { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +-$as_echo "$ac_res" >&6; } +- +-fi +-as_val=`eval 'as_val=${'$as_ac_Header'} +- $as_echo "$as_val"'` +- if test "x$as_val" = x""yes; then +- cat >>confdefs.h <<_ACEOF +-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +-_ACEOF +- +-else +- have_libcrypto=no +-fi +- +-done +- +- { $as_echo "$as_me:$LINENO: checking for EVP_PKEY_new in -lcrypto" >&5 +-$as_echo_n "checking for EVP_PKEY_new in -lcrypto... " >&6; } +-if test "${ac_cv_lib_crypto_EVP_PKEY_new+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- ac_check_lib_save_LIBS=$LIBS +-LIBS="-lcrypto $LIBS" +-cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-/* Override any GCC internal prototype to avoid an error. +- Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-#ifdef __cplusplus +-extern "C" +-#endif +-char EVP_PKEY_new (); +-int +-main () +-{ +-return EVP_PKEY_new (); +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest$ac_exeext && { +- test "$cross_compiling" = yes || +- $as_test_x conftest$ac_exeext +- }; then +- ac_cv_lib_crypto_EVP_PKEY_new=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_cv_lib_crypto_EVP_PKEY_new=no +-fi +- +-rm -rf conftest.dSYM +-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ +- conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_EVP_PKEY_new" >&5 +-$as_echo "$ac_cv_lib_crypto_EVP_PKEY_new" >&6; } +-if test "x$ac_cv_lib_crypto_EVP_PKEY_new" = x""yes; then +- SECLIBS="-lcrypto" +-else +- have_libcrypto=no +-fi +- +- +- if test "x$have_libcrypto" != "xno" ; then +- +-cat >>confdefs.h <<\_ACEOF +-#define WITH_SECURITY 1 +-_ACEOF +- +- else +- if test "x$WITH_SECURITY" = "xyes" ; then +- { { $as_echo "$as_me:$LINENO: error: Security requested, but unable to find libcrypto" >&5 +-$as_echo "$as_me: error: Security requested, but unable to find libcrypto" >&2;} +- { (exit 1); exit 1; }; } +- fi +- fi +-fi +- +- +-WITH_SLP=maybe +- +-# Check whether --with-slp was given. +-if test "${with_slp+set}" = set; then +- withval=$with_slp; +- if test "x$withval" = "xno" -o "x$withval" = "xyes"; then +- WITH_SLP=$withval +- else +- WITH_SLP=yes +- CPPFLAGS="$CPPFLAGS -I${withval}" +- LDFLAGS="$LDFLAGS -L${withval}" +- fi +- +- +-fi +- +- +-if test "x$WITH_SLP" != "xno" ; then +- # Check for openslp support - very primitive +- +-for ac_header in slp.h +-do +-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then +- { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +-$as_echo_n "checking for $ac_header... " >&6; } +-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then +- $as_echo_n "(cached) " >&6 +-fi +-ac_res=`eval 'as_val=${'$as_ac_Header'} +- $as_echo "$as_val"'` +- { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +-$as_echo "$ac_res" >&6; } +-else +- # Is the header compilable? +-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +-$as_echo_n "checking $ac_header usability... " >&6; } +-cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-$ac_includes_default +-#include <$ac_header> +-_ACEOF +-rm -f conftest.$ac_objext +-if { (ac_try="$ac_compile" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_compile") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest.$ac_objext; then +- ac_header_compiler=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_header_compiler=no +-fi +- +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +-$as_echo "$ac_header_compiler" >&6; } +- +-# Is the header present? +-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +-$as_echo_n "checking $ac_header presence... " >&6; } +-cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +-#include <$ac_header> +-_ACEOF +-if { (ac_try="$ac_cpp conftest.$ac_ext" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } >/dev/null && { +- test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || +- test ! -s conftest.err +- }; then +- ac_header_preproc=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_header_preproc=no +-fi +- +-rm -f conftest.err conftest.$ac_ext +-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +-$as_echo "$ac_header_preproc" >&6; } +- +-# So? What about this header? +-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in +- yes:no: ) +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} +- ac_header_preproc=yes +- ;; +- no:yes:* ) +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +-$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +-$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} +- { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} +- +- ;; +-esac +-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +-$as_echo_n "checking for $ac_header... " >&6; } +-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then +- $as_echo_n "(cached) " >&6 +-else +- eval "$as_ac_Header=\$ac_header_preproc" +-fi +-ac_res=`eval 'as_val=${'$as_ac_Header'} +- $as_echo "$as_val"'` +- { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +-$as_echo "$ac_res" >&6; } +- +-fi +-as_val=`eval 'as_val=${'$as_ac_Header'} +- $as_echo "$as_val"'` +- if test "x$as_val" = x""yes; then +- cat >>confdefs.h <<_ACEOF +-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +-_ACEOF +- +-else +- have_openslp=no +-fi +- +-done +- +- { $as_echo "$as_me:$LINENO: checking for SLPOpen in -lslp" >&5 +-$as_echo_n "checking for SLPOpen in -lslp... " >&6; } +-if test "${ac_cv_lib_slp_SLPOpen+set}" = set; then +- $as_echo_n "(cached) " >&6 +-else +- ac_check_lib_save_LIBS=$LIBS +-LIBS="-lslp $LIBS" +-cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-/* Override any GCC internal prototype to avoid an error. +- Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-#ifdef __cplusplus +-extern "C" +-#endif +-char SLPOpen (); +-int +-main () +-{ +-return SLPOpen (); +- ; +- return 0; +-} +-_ACEOF +-rm -f conftest.$ac_objext conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>conftest.er1 +- ac_status=$? +- grep -v '^ *+' conftest.er1 >conftest.err +- rm -f conftest.er1 +- cat conftest.err >&5 +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { +- test -z "$ac_c_werror_flag" || +- test ! -s conftest.err +- } && test -s conftest$ac_exeext && { +- test "$cross_compiling" = yes || +- $as_test_x conftest$ac_exeext +- }; then +- ac_cv_lib_slp_SLPOpen=yes +-else +- $as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +- ac_cv_lib_slp_SLPOpen=no +-fi +- +-rm -rf conftest.dSYM +-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ +- conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS +-fi +-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_slp_SLPOpen" >&5 +-$as_echo "$ac_cv_lib_slp_SLPOpen" >&6; } +-if test "x$ac_cv_lib_slp_SLPOpen" = x""yes; then +- SLPLIBS="-lslp" +-else +- have_openslp=no +-fi +- +- +- if test "x$have_openslp" != "xno" ; then +- +-cat >>confdefs.h <<\_ACEOF +-#define WITH_SLP 1 +-_ACEOF +- +- else +- if test "x$WITH_SLP" = "xyes" ; then +- { { $as_echo "$as_me:$LINENO: error: SLP requested, but unable to find openslp" >&5 +-$as_echo "$as_me: error: SLP requested, but unable to find openslp" >&2;} +- { (exit 1); exit 1; }; } +- fi +- fi +-fi +- +- +-MEMDEBUG= +-# Check whether --enable-memdebug was given. +-if test "${enable_memdebug+set}" = set; then +- enableval=$enable_memdebug; +- if test "x$enableval" = "xyes" ; then +- CPPFLAGS="$CPPFLAGS -DMEMDEBUG" +- fi +- +- +-fi +- +- +- +-ac_config_files="$ac_config_files Makefile" +- +-cat >confcache <<\_ACEOF +-# This file is a shell script that caches the results of configure +-# tests run on this system so they can be shared between configure +-# scripts and configure runs, see configure's option --config-cache. +-# It is not useful on other systems. If it contains results you don't +-# want to keep, you may remove or edit it. +-# +-# config.status only pays attention to the cache file if you give it +-# the --recheck option to rerun configure. +-# +-# `ac_cv_env_foo' variables (set or unset) will be overridden when +-# loading this file, other *unset* `ac_cv_foo' will be assigned the +-# following values. +- +-_ACEOF +- +-# The following way of writing the cache mishandles newlines in values, +-# but we know of no workaround that is simple, portable, and efficient. +-# So, we kill variables containing newlines. +-# Ultrix sh set writes to stderr and can't be redirected directly, +-# and sets the high bit in the cache file unless we assign to the vars. +-( +- for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do +- eval ac_val=\$$ac_var +- case $ac_val in #( +- *${as_nl}*) +- case $ac_var in #( +- *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 +-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; +- esac +- case $ac_var in #( +- _ | IFS | as_nl) ;; #( +- BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( +- *) $as_unset $ac_var ;; +- esac ;; +- esac +- done +- +- (set) 2>&1 | +- case $as_nl`(ac_space=' '; set) 2>&1` in #( +- *${as_nl}ac_space=\ *) +- # `set' does not quote correctly, so add quotes (double-quote +- # substitution turns \\\\ into \\, and sed turns \\ into \). +- sed -n \ +- "s/'/'\\\\''/g; +- s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" +- ;; #( +- *) +- # `set' quotes correctly as required by POSIX, so do not add quotes. +- sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" +- ;; +- esac | +- sort +-) | +- sed ' +- /^ac_cv_env_/b end +- t clear +- :clear +- s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ +- t end +- s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ +- :end' >>confcache +-if diff "$cache_file" confcache >/dev/null 2>&1; then :; else +- if test -w "$cache_file"; then +- test "x$cache_file" != "x/dev/null" && +- { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5 +-$as_echo "$as_me: updating cache $cache_file" >&6;} +- cat confcache >$cache_file +- else +- { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +-$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} +- fi +-fi +-rm -f confcache +- +-test "x$prefix" = xNONE && prefix=$ac_default_prefix +-# Let make expand exec_prefix. +-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' +- +-DEFS=-DHAVE_CONFIG_H +- +-ac_libobjs= +-ac_ltlibobjs= +-for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue +- # 1. Remove the extension, and $U if already installed. +- ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' +- ac_i=`$as_echo "$ac_i" | sed "$ac_script"` +- # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR +- # will be set to the directory where LIBOBJS objects are built. +- ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" +- ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +-done +-LIBOBJS=$ac_libobjs +- +-LTLIBOBJS=$ac_ltlibobjs +- +- +- +- +-: ${CONFIG_STATUS=./config.status} +-ac_write_fail=0 +-ac_clean_files_save=$ac_clean_files +-ac_clean_files="$ac_clean_files $CONFIG_STATUS" +-{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +-$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +-cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +-#! $SHELL +-# Generated by $as_me. +-# Run this file to recreate the current configuration. +-# Compiler output produced by configure, useful for debugging +-# configure, is in config.log if it exists. +- +-debug=false +-ac_cs_recheck=false +-ac_cs_silent=false +-SHELL=\${CONFIG_SHELL-$SHELL} +-_ACEOF +- +-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +-## --------------------- ## +-## M4sh Initialization. ## +-## --------------------- ## +- +-# Be more Bourne compatible +-DUALCASE=1; export DUALCASE # for MKS sh +-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +- emulate sh +- NULLCMD=: +- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which +- # is contrary to our usage. Disable this feature. +- alias -g '${1+"$@"}'='"$@"' +- setopt NO_GLOB_SUBST +-else +- case `(set -o) 2>/dev/null` in +- *posix*) set -o posix ;; +-esac +- +-fi +- +- +- +- +-# PATH needs CR +-# Avoid depending upon Character Ranges. +-as_cr_letters='abcdefghijklmnopqrstuvwxyz' +-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +-as_cr_Letters=$as_cr_letters$as_cr_LETTERS +-as_cr_digits='0123456789' +-as_cr_alnum=$as_cr_Letters$as_cr_digits +- +-as_nl=' +-' +-export as_nl +-# Printing a long string crashes Solaris 7 /usr/bin/printf. +-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +-if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then +- as_echo='printf %s\n' +- as_echo_n='printf %s' +-else +- if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then +- as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' +- as_echo_n='/usr/ucb/echo -n' +- else +- as_echo_body='eval expr "X$1" : "X\\(.*\\)"' +- as_echo_n_body='eval +- arg=$1; +- case $arg in +- *"$as_nl"*) +- expr "X$arg" : "X\\(.*\\)$as_nl"; +- arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; +- esac; +- expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" +- ' +- export as_echo_n_body +- as_echo_n='sh -c $as_echo_n_body as_echo' +- fi +- export as_echo_body +- as_echo='sh -c $as_echo_body as_echo' +-fi +- +-# The user is always right. +-if test "${PATH_SEPARATOR+set}" != set; then +- PATH_SEPARATOR=: +- (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { +- (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || +- PATH_SEPARATOR=';' +- } +-fi +- +-# Support unset when possible. +-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then +- as_unset=unset +-else +- as_unset=false +-fi +- +- +-# IFS +-# We need space, tab and new line, in precisely that order. Quoting is +-# there to prevent editors from complaining about space-tab. +-# (If _AS_PATH_WALK were called with IFS unset, it would disable word +-# splitting by setting IFS to empty value.) +-IFS=" "" $as_nl" +- +-# Find who we are. Look in the path if we contain no directory separator. +-case $0 in +- *[\\/]* ) as_myself=$0 ;; +- *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +-done +-IFS=$as_save_IFS +- +- ;; +-esac +-# We did not find ourselves, most probably we were run as `sh COMMAND' +-# in which case we are not to be found in the path. +-if test "x$as_myself" = x; then +- as_myself=$0 +-fi +-if test ! -f "$as_myself"; then +- $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 +- { (exit 1); exit 1; } +-fi +- +-# Work around bugs in pre-3.0 UWIN ksh. +-for as_var in ENV MAIL MAILPATH +-do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +-done +-PS1='$ ' +-PS2='> ' +-PS4='+ ' +- +-# NLS nuisances. +-LC_ALL=C +-export LC_ALL +-LANGUAGE=C +-export LANGUAGE +- +-# Required to use basename. +-if expr a : '\(a\)' >/dev/null 2>&1 && +- test "X`expr 00001 : '.*\(...\)'`" = X001; then +- as_expr=expr +-else +- as_expr=false +-fi +- +-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then +- as_basename=basename +-else +- as_basename=false +-fi +- +- +-# Name of the executable. +-as_me=`$as_basename -- "$0" || +-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ +- X"$0" : 'X\(//\)$' \| \ +- X"$0" : 'X\(/\)' \| . 2>/dev/null || +-$as_echo X/"$0" | +- sed '/^.*\/\([^/][^/]*\)\/*$/{ +- s//\1/ +- q +- } +- /^X\/\(\/\/\)$/{ +- s//\1/ +- q +- } +- /^X\/\(\/\).*/{ +- s//\1/ +- q +- } +- s/.*/./; q'` +- +-# CDPATH. +-$as_unset CDPATH +- +- +- +- as_lineno_1=$LINENO +- as_lineno_2=$LINENO +- test "x$as_lineno_1" != "x$as_lineno_2" && +- test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { +- +- # Create $as_me.lineno as a copy of $as_myself, but with $LINENO +- # uniformly replaced by the line number. The first 'sed' inserts a +- # line-number line after each line using $LINENO; the second 'sed' +- # does the real work. The second script uses 'N' to pair each +- # line-number line with the line containing $LINENO, and appends +- # trailing '-' during substitution so that $LINENO is not a special +- # case at line end. +- # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the +- # scripts with optimization help from Paolo Bonzini. Blame Lee +- # E. McMahon (1931-1989) for sed's syntax. :-) +- sed -n ' +- p +- /[$]LINENO/= +- ' <$as_myself | +- sed ' +- s/[$]LINENO.*/&-/ +- t lineno +- b +- :lineno +- N +- :loop +- s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ +- t loop +- s/-\n.*// +- ' >$as_me.lineno && +- chmod +x "$as_me.lineno" || +- { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 +- { (exit 1); exit 1; }; } +- +- # Don't try to exec as it changes $[0], causing all sort of problems +- # (the dirname of $[0] is not the place where we might find the +- # original and so on. Autoconf is especially sensitive to this). +- . "./$as_me.lineno" +- # Exit status is that of the last command. +- exit +-} +- +- +-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then +- as_dirname=dirname +-else +- as_dirname=false +-fi +- +-ECHO_C= ECHO_N= ECHO_T= +-case `echo -n x` in +--n*) +- case `echo 'x\c'` in +- *c*) ECHO_T=' ';; # ECHO_T is single tab character. +- *) ECHO_C='\c';; +- esac;; +-*) +- ECHO_N='-n';; +-esac +-if expr a : '\(a\)' >/dev/null 2>&1 && +- test "X`expr 00001 : '.*\(...\)'`" = X001; then +- as_expr=expr +-else +- as_expr=false +-fi +- +-rm -f conf$$ conf$$.exe conf$$.file +-if test -d conf$$.dir; then +- rm -f conf$$.dir/conf$$.file +-else +- rm -f conf$$.dir +- mkdir conf$$.dir 2>/dev/null +-fi +-if (echo >conf$$.file) 2>/dev/null; then +- if ln -s conf$$.file conf$$ 2>/dev/null; then +- as_ln_s='ln -s' +- # ... but there are two gotchas: +- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. +- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. +- # In both cases, we have to default to `cp -p'. +- ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || +- as_ln_s='cp -p' +- elif ln conf$$.file conf$$ 2>/dev/null; then +- as_ln_s=ln +- else +- as_ln_s='cp -p' +- fi +-else +- as_ln_s='cp -p' +-fi +-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +-rmdir conf$$.dir 2>/dev/null +- +-if mkdir -p . 2>/dev/null; then +- as_mkdir_p=: +-else +- test -d ./-p && rmdir ./-p +- as_mkdir_p=false +-fi +- +-if test -x / >/dev/null 2>&1; then +- as_test_x='test -x' +-else +- if ls -dL / >/dev/null 2>&1; then +- as_ls_L_option=L +- else +- as_ls_L_option= +- fi +- as_test_x=' +- eval sh -c '\'' +- if test -d "$1"; then +- test -d "$1/."; +- else +- case $1 in +- -*)set "./$1";; +- esac; +- case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in +- ???[sx]*):;;*)false;;esac;fi +- '\'' sh +- ' +-fi +-as_executable_p=$as_test_x +- +-# Sed expression to map a string onto a valid CPP name. +-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" +- +-# Sed expression to map a string onto a valid variable name. +-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" +- +- +-exec 6>&1 +- +-# Save the log message, to keep $[0] and so on meaningful, and to +-# report actual input values of CONFIG_FILES etc. instead of their +-# values after options handling. +-ac_log=" +-This file was extended by open-isns $as_me 0.90, which was +-generated by GNU Autoconf 2.63. Invocation command line was +- +- CONFIG_FILES = $CONFIG_FILES +- CONFIG_HEADERS = $CONFIG_HEADERS +- CONFIG_LINKS = $CONFIG_LINKS +- CONFIG_COMMANDS = $CONFIG_COMMANDS +- $ $0 $@ +- +-on `(hostname || uname -n) 2>/dev/null | sed 1q` +-" +- +-_ACEOF +- +-case $ac_config_files in *" +-"*) set x $ac_config_files; shift; ac_config_files=$*;; +-esac +- +-case $ac_config_headers in *" +-"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +-esac +- +- +-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +-# Files that config.status was made for. +-config_files="$ac_config_files" +-config_headers="$ac_config_headers" +- +-_ACEOF +- +-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +-ac_cs_usage="\ +-\`$as_me' instantiates files from templates according to the +-current configuration. +- +-Usage: $0 [OPTION]... [FILE]... +- +- -h, --help print this help, then exit +- -V, --version print version number and configuration settings, then exit +- -q, --quiet, --silent +- do not print progress messages +- -d, --debug don't remove temporary files +- --recheck update $as_me by reconfiguring in the same conditions +- --file=FILE[:TEMPLATE] +- instantiate the configuration file FILE +- --header=FILE[:TEMPLATE] +- instantiate the configuration header FILE +- +-Configuration files: +-$config_files +- +-Configuration headers: +-$config_headers +- +-Report bugs to ." +- +-_ACEOF +-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +-ac_cs_version="\\ +-open-isns config.status 0.90 +-configured by $0, generated by GNU Autoconf 2.63, +- with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" +- +-Copyright (C) 2008 Free Software Foundation, Inc. +-This config.status script is free software; the Free Software Foundation +-gives unlimited permission to copy, distribute and modify it." +- +-ac_pwd='$ac_pwd' +-srcdir='$srcdir' +-INSTALL='$INSTALL' +-test -n "\$AWK" || AWK=awk +-_ACEOF +- +-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +-# The default lists apply if the user does not specify any file. +-ac_need_defaults=: +-while test $# != 0 +-do +- case $1 in +- --*=*) +- ac_option=`expr "X$1" : 'X\([^=]*\)='` +- ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` +- ac_shift=: +- ;; +- *) +- ac_option=$1 +- ac_optarg=$2 +- ac_shift=shift +- ;; +- esac +- +- case $ac_option in +- # Handling of the options. +- -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) +- ac_cs_recheck=: ;; +- --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) +- $as_echo "$ac_cs_version"; exit ;; +- --debug | --debu | --deb | --de | --d | -d ) +- debug=: ;; +- --file | --fil | --fi | --f ) +- $ac_shift +- case $ac_optarg in +- *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; +- esac +- CONFIG_FILES="$CONFIG_FILES '$ac_optarg'" +- ac_need_defaults=false;; +- --header | --heade | --head | --hea ) +- $ac_shift +- case $ac_optarg in +- *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; +- esac +- CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'" +- ac_need_defaults=false;; +- --he | --h) +- # Conflict between --help and --header +- { $as_echo "$as_me: error: ambiguous option: $1 +-Try \`$0 --help' for more information." >&2 +- { (exit 1); exit 1; }; };; +- --help | --hel | -h ) +- $as_echo "$ac_cs_usage"; exit ;; +- -q | -quiet | --quiet | --quie | --qui | --qu | --q \ +- | -silent | --silent | --silen | --sile | --sil | --si | --s) +- ac_cs_silent=: ;; +- +- # This is an error. +- -*) { $as_echo "$as_me: error: unrecognized option: $1 +-Try \`$0 --help' for more information." >&2 +- { (exit 1); exit 1; }; } ;; +- +- *) ac_config_targets="$ac_config_targets $1" +- ac_need_defaults=false ;; +- +- esac +- shift +-done +- +-ac_configure_extra_args= +- +-if $ac_cs_silent; then +- exec 6>/dev/null +- ac_configure_extra_args="$ac_configure_extra_args --silent" +-fi +- +-_ACEOF +-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +-if \$ac_cs_recheck; then +- set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +- shift +- \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 +- CONFIG_SHELL='$SHELL' +- export CONFIG_SHELL +- exec "\$@" +-fi +- +-_ACEOF +-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +-exec 5>>config.log +-{ +- echo +- sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +-## Running $as_me. ## +-_ASBOX +- $as_echo "$ac_log" +-} >&5 +- +-_ACEOF +-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +-_ACEOF +- +-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +- +-# Handling of arguments. +-for ac_config_target in $ac_config_targets +-do +- case $ac_config_target in +- "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; +- "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; +- +- *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +-$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;} +- { (exit 1); exit 1; }; };; +- esac +-done +- +- +-# If the user did not use the arguments to specify the items to instantiate, +-# then the envvar interface is used. Set only those that are not. +-# We use the long form for the default assignment because of an extremely +-# bizarre bug on SunOS 4.1.3. +-if $ac_need_defaults; then +- test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +- test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +-fi +- +-# Have a temporary directory for convenience. Make it in the build tree +-# simply because there is no reason against having it here, and in addition, +-# creating and moving files from /tmp can sometimes cause problems. +-# Hook for its removal unless debugging. +-# Note that there is a small window in which the directory will not be cleaned: +-# after its creation but before its name has been assigned to `$tmp'. +-$debug || +-{ +- tmp= +- trap 'exit_status=$? +- { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +-' 0 +- trap '{ (exit 1); exit 1; }' 1 2 13 15 +-} +-# Create a (secure) tmp directory for tmp files. +- +-{ +- tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && +- test -n "$tmp" && test -d "$tmp" +-} || +-{ +- tmp=./conf$$-$RANDOM +- (umask 077 && mkdir "$tmp") +-} || +-{ +- $as_echo "$as_me: cannot create a temporary directory in ." >&2 +- { (exit 1); exit 1; } +-} +- +-# Set up the scripts for CONFIG_FILES section. +-# No need to generate them if there are no CONFIG_FILES. +-# This happens for instance with `./config.status config.h'. +-if test -n "$CONFIG_FILES"; then +- +- +-ac_cr=' ' +-ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +-if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then +- ac_cs_awk_cr='\\r' +-else +- ac_cs_awk_cr=$ac_cr +-fi +- +-echo 'BEGIN {' >"$tmp/subs1.awk" && +-_ACEOF +- +- +-{ +- echo "cat >conf$$subs.awk <<_ACEOF" && +- echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && +- echo "_ACEOF" +-} >conf$$subs.sh || +- { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +-$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} +- { (exit 1); exit 1; }; } +-ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +-ac_delim='%!_!# ' +-for ac_last_try in false false false false false :; do +- . ./conf$$subs.sh || +- { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +-$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} +- { (exit 1); exit 1; }; } +- +- ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` +- if test $ac_delim_n = $ac_delim_num; then +- break +- elif $ac_last_try; then +- { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +-$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} +- { (exit 1); exit 1; }; } +- else +- ac_delim="$ac_delim!$ac_delim _$ac_delim!! " +- fi +-done +-rm -f conf$$subs.sh +- +-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +-cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +-_ACEOF +-sed -n ' +-h +-s/^/S["/; s/!.*/"]=/ +-p +-g +-s/^[^!]*!// +-:repl +-t repl +-s/'"$ac_delim"'$// +-t delim +-:nl +-h +-s/\(.\{148\}\).*/\1/ +-t more1 +-s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +-p +-n +-b repl +-:more1 +-s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +-p +-g +-s/.\{148\}// +-t nl +-:delim +-h +-s/\(.\{148\}\).*/\1/ +-t more2 +-s/["\\]/\\&/g; s/^/"/; s/$/"/ +-p +-b +-:more2 +-s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +-p +-g +-s/.\{148\}// +-t delim +-' >$CONFIG_STATUS || ac_write_fail=1 +-rm -f conf$$subs.awk +-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +-_ACAWK +-cat >>"\$tmp/subs1.awk" <<_ACAWK && +- for (key in S) S_is_set[key] = 1 +- FS = "" +- +-} +-{ +- line = $ 0 +- nfields = split(line, field, "@") +- substed = 0 +- len = length(field[1]) +- for (i = 2; i < nfields; i++) { +- key = field[i] +- keylen = length(key) +- if (S_is_set[key]) { +- value = S[key] +- line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) +- len += length(value) + length(field[++i]) +- substed = 1 +- } else +- len += 1 + keylen +- } +- +- print line +-} +- +-_ACAWK +-_ACEOF +-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +-if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then +- sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +-else +- cat +-fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ +- || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5 +-$as_echo "$as_me: error: could not setup config files machinery" >&2;} +- { (exit 1); exit 1; }; } +-_ACEOF +- +-# VPATH may cause trouble with some makes, so we remove $(srcdir), +-# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +-# trailing colons and then remove the whole line if VPATH becomes empty +-# (actually we leave an empty line to preserve line numbers). +-if test "x$srcdir" = x.; then +- ac_vpsub='/^[ ]*VPATH[ ]*=/{ +-s/:*\$(srcdir):*/:/ +-s/:*\${srcdir}:*/:/ +-s/:*@srcdir@:*/:/ +-s/^\([^=]*=[ ]*\):*/\1/ +-s/:*$// +-s/^[^=]*=[ ]*$// +-}' +-fi +- +-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +-fi # test -n "$CONFIG_FILES" +- +-# Set up the scripts for CONFIG_HEADERS section. +-# No need to generate them if there are no CONFIG_HEADERS. +-# This happens for instance with `./config.status Makefile'. +-if test -n "$CONFIG_HEADERS"; then +-cat >"$tmp/defines.awk" <<\_ACAWK || +-BEGIN { +-_ACEOF +- +-# Transform confdefs.h into an awk script `defines.awk', embedded as +-# here-document in config.status, that substitutes the proper values into +-# config.h.in to produce config.h. +- +-# Create a delimiter string that does not exist in confdefs.h, to ease +-# handling of long lines. +-ac_delim='%!_!# ' +-for ac_last_try in false false :; do +- ac_t=`sed -n "/$ac_delim/p" confdefs.h` +- if test -z "$ac_t"; then +- break +- elif $ac_last_try; then +- { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5 +-$as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;} +- { (exit 1); exit 1; }; } +- else +- ac_delim="$ac_delim!$ac_delim _$ac_delim!! " +- fi +-done +- +-# For the awk script, D is an array of macro values keyed by name, +-# likewise P contains macro parameters if any. Preserve backslash +-# newline sequences. +- +-ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +-sed -n ' +-s/.\{148\}/&'"$ac_delim"'/g +-t rset +-:rset +-s/^[ ]*#[ ]*define[ ][ ]*/ / +-t def +-d +-:def +-s/\\$// +-t bsnl +-s/["\\]/\\&/g +-s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +-D["\1"]=" \3"/p +-s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +-d +-:bsnl +-s/["\\]/\\&/g +-s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +-D["\1"]=" \3\\\\\\n"\\/p +-t cont +-s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +-t cont +-d +-:cont +-n +-s/.\{148\}/&'"$ac_delim"'/g +-t clear +-:clear +-s/\\$// +-t bsnlc +-s/["\\]/\\&/g; s/^/"/; s/$/"/p +-d +-:bsnlc +-s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +-b cont +-' >$CONFIG_STATUS || ac_write_fail=1 +- +-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +- for (key in D) D_is_set[key] = 1 +- FS = "" +-} +-/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { +- line = \$ 0 +- split(line, arg, " ") +- if (arg[1] == "#") { +- defundef = arg[2] +- mac1 = arg[3] +- } else { +- defundef = substr(arg[1], 2) +- mac1 = arg[2] +- } +- split(mac1, mac2, "(") #) +- macro = mac2[1] +- prefix = substr(line, 1, index(line, defundef) - 1) +- if (D_is_set[macro]) { +- # Preserve the white space surrounding the "#". +- print prefix "define", macro P[macro] D[macro] +- next +- } else { +- # Replace #undef with comments. This is necessary, for example, +- # in the case of _POSIX_SOURCE, which is predefined and required +- # on some systems where configure will not decide to define it. +- if (defundef == "undef") { +- print "/*", prefix defundef, macro, "*/" +- next +- } +- } +-} +-{ print } +-_ACAWK +-_ACEOF +-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +- { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5 +-$as_echo "$as_me: error: could not setup config headers machinery" >&2;} +- { (exit 1); exit 1; }; } +-fi # test -n "$CONFIG_HEADERS" +- +- +-eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +-shift +-for ac_tag +-do +- case $ac_tag in +- :[FHLC]) ac_mode=$ac_tag; continue;; +- esac +- case $ac_mode$ac_tag in +- :[FHL]*:*);; +- :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5 +-$as_echo "$as_me: error: invalid tag $ac_tag" >&2;} +- { (exit 1); exit 1; }; };; +- :[FH]-) ac_tag=-:-;; +- :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; +- esac +- ac_save_IFS=$IFS +- IFS=: +- set x $ac_tag +- IFS=$ac_save_IFS +- shift +- ac_file=$1 +- shift +- +- case $ac_mode in +- :L) ac_source=$1;; +- :[FH]) +- ac_file_inputs= +- for ac_f +- do +- case $ac_f in +- -) ac_f="$tmp/stdin";; +- *) # Look for the file first in the build tree, then in the source tree +- # (if the path is not absolute). The absolute path cannot be DOS-style, +- # because $ac_f cannot contain `:'. +- test -f "$ac_f" || +- case $ac_f in +- [\\/$]*) false;; +- *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; +- esac || +- { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +-$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} +- { (exit 1); exit 1; }; };; +- esac +- case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac +- ac_file_inputs="$ac_file_inputs '$ac_f'" +- done +- +- # Let's still pretend it is `configure' which instantiates (i.e., don't +- # use $as_me), people would be surprised to read: +- # /* config.h. Generated by config.status. */ +- configure_input='Generated from '` +- $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' +- `' by configure.' +- if test x"$ac_file" != x-; then +- configure_input="$ac_file. $configure_input" +- { $as_echo "$as_me:$LINENO: creating $ac_file" >&5 +-$as_echo "$as_me: creating $ac_file" >&6;} +- fi +- # Neutralize special characters interpreted by sed in replacement strings. +- case $configure_input in #( +- *\&* | *\|* | *\\* ) +- ac_sed_conf_input=`$as_echo "$configure_input" | +- sed 's/[\\\\&|]/\\\\&/g'`;; #( +- *) ac_sed_conf_input=$configure_input;; +- esac +- +- case $ac_tag in +- *:-:* | *:-) cat >"$tmp/stdin" \ +- || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +-$as_echo "$as_me: error: could not create $ac_file" >&2;} +- { (exit 1); exit 1; }; } ;; +- esac +- ;; +- esac +- +- ac_dir=`$as_dirname -- "$ac_file" || +-$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ +- X"$ac_file" : 'X\(//\)[^/]' \| \ +- X"$ac_file" : 'X\(//\)$' \| \ +- X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +-$as_echo X"$ac_file" | +- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ +- s//\1/ +- q +- } +- /^X\(\/\/\)[^/].*/{ +- s//\1/ +- q +- } +- /^X\(\/\/\)$/{ +- s//\1/ +- q +- } +- /^X\(\/\).*/{ +- s//\1/ +- q +- } +- s/.*/./; q'` +- { as_dir="$ac_dir" +- case $as_dir in #( +- -*) as_dir=./$as_dir;; +- esac +- test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { +- as_dirs= +- while :; do +- case $as_dir in #( +- *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( +- *) as_qdir=$as_dir;; +- esac +- as_dirs="'$as_qdir' $as_dirs" +- as_dir=`$as_dirname -- "$as_dir" || +-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ +- X"$as_dir" : 'X\(//\)[^/]' \| \ +- X"$as_dir" : 'X\(//\)$' \| \ +- X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +-$as_echo X"$as_dir" | +- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ +- s//\1/ +- q +- } +- /^X\(\/\/\)[^/].*/{ +- s//\1/ +- q +- } +- /^X\(\/\/\)$/{ +- s//\1/ +- q +- } +- /^X\(\/\).*/{ +- s//\1/ +- q +- } +- s/.*/./; q'` +- test -d "$as_dir" && break +- done +- test -z "$as_dirs" || eval "mkdir $as_dirs" +- } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +-$as_echo "$as_me: error: cannot create directory $as_dir" >&2;} +- { (exit 1); exit 1; }; }; } +- ac_builddir=. +- +-case "$ac_dir" in +-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +-*) +- ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` +- # A ".." for each directory in $ac_dir_suffix. +- ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` +- case $ac_top_builddir_sub in +- "") ac_top_builddir_sub=. ac_top_build_prefix= ;; +- *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; +- esac ;; +-esac +-ac_abs_top_builddir=$ac_pwd +-ac_abs_builddir=$ac_pwd$ac_dir_suffix +-# for backward compatibility: +-ac_top_builddir=$ac_top_build_prefix +- +-case $srcdir in +- .) # We are building in place. +- ac_srcdir=. +- ac_top_srcdir=$ac_top_builddir_sub +- ac_abs_top_srcdir=$ac_pwd ;; +- [\\/]* | ?:[\\/]* ) # Absolute name. +- ac_srcdir=$srcdir$ac_dir_suffix; +- ac_top_srcdir=$srcdir +- ac_abs_top_srcdir=$srcdir ;; +- *) # Relative name. +- ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix +- ac_top_srcdir=$ac_top_build_prefix$srcdir +- ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +-esac +-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix +- +- +- case $ac_mode in +- :F) +- # +- # CONFIG_FILE +- # +- +- case $INSTALL in +- [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; +- *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; +- esac +-_ACEOF +- +-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +-# If the template does not know about datarootdir, expand it. +-# FIXME: This hack should be removed a few years after 2.60. +-ac_datarootdir_hack=; ac_datarootdir_seen= +- +-ac_sed_dataroot=' +-/datarootdir/ { +- p +- q +-} +-/@datadir@/p +-/@docdir@/p +-/@infodir@/p +-/@localedir@/p +-/@mandir@/p +-' +-case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +-*datarootdir*) ac_datarootdir_seen=yes;; +-*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) +- { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +-$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +-_ACEOF +-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +- ac_datarootdir_hack=' +- s&@datadir@&$datadir&g +- s&@docdir@&$docdir&g +- s&@infodir@&$infodir&g +- s&@localedir@&$localedir&g +- s&@mandir@&$mandir&g +- s&\\\${datarootdir}&$datarootdir&g' ;; +-esac +-_ACEOF +- +-# Neutralize VPATH when `$srcdir' = `.'. +-# Shell code in configure.ac might set extrasub. +-# FIXME: do we really want to maintain this feature? +-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +-ac_sed_extra="$ac_vpsub +-$extrasub +-_ACEOF +-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +-:t +-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +-s|@configure_input@|$ac_sed_conf_input|;t t +-s&@top_builddir@&$ac_top_builddir_sub&;t t +-s&@top_build_prefix@&$ac_top_build_prefix&;t t +-s&@srcdir@&$ac_srcdir&;t t +-s&@abs_srcdir@&$ac_abs_srcdir&;t t +-s&@top_srcdir@&$ac_top_srcdir&;t t +-s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +-s&@builddir@&$ac_builddir&;t t +-s&@abs_builddir@&$ac_abs_builddir&;t t +-s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +-s&@INSTALL@&$ac_INSTALL&;t t +-$ac_datarootdir_hack +-" +-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ +- || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +-$as_echo "$as_me: error: could not create $ac_file" >&2;} +- { (exit 1); exit 1; }; } +- +-test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && +- { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && +- { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && +- { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +-which seems to be undefined. Please make sure it is defined." >&5 +-$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +-which seems to be undefined. Please make sure it is defined." >&2;} +- +- rm -f "$tmp/stdin" +- case $ac_file in +- -) cat "$tmp/out" && rm -f "$tmp/out";; +- *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; +- esac \ +- || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +-$as_echo "$as_me: error: could not create $ac_file" >&2;} +- { (exit 1); exit 1; }; } +- ;; +- :H) +- # +- # CONFIG_HEADER +- # +- if test x"$ac_file" != x-; then +- { +- $as_echo "/* $configure_input */" \ +- && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" +- } >"$tmp/config.h" \ +- || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +-$as_echo "$as_me: error: could not create $ac_file" >&2;} +- { (exit 1); exit 1; }; } +- if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then +- { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +-$as_echo "$as_me: $ac_file is unchanged" >&6;} +- else +- rm -f "$ac_file" +- mv "$tmp/config.h" "$ac_file" \ +- || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +-$as_echo "$as_me: error: could not create $ac_file" >&2;} +- { (exit 1); exit 1; }; } +- fi +- else +- $as_echo "/* $configure_input */" \ +- && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ +- || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5 +-$as_echo "$as_me: error: could not create -" >&2;} +- { (exit 1); exit 1; }; } +- fi +- ;; +- +- +- esac +- +-done # for ac_tag +- +- +-{ (exit 0); exit 0; } +-_ACEOF +-chmod +x $CONFIG_STATUS +-ac_clean_files=$ac_clean_files_save +- +-test $ac_write_fail = 0 || +- { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5 +-$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;} +- { (exit 1); exit 1; }; } +- +- +-# configure is writing to config.log, and then calls config.status. +-# config.status does its own redirection, appending to config.log. +-# Unfortunately, on DOS this fails, as config.log is still kept open +-# by configure, so config.status won't be able to write to it; its +-# output is simply discarded. So we exec the FD to /dev/null, +-# effectively closing config.log, so it can be properly (re)opened and +-# appended to by config.status. When coming back to configure, we +-# need to make the FD available again. +-if test "$no_create" != yes; then +- ac_cs_success=: +- ac_config_status_args= +- test "$silent" = yes && +- ac_config_status_args="$ac_config_status_args --quiet" +- exec 5>/dev/null +- $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false +- exec 5>>config.log +- # Use ||, not &&, to avoid exiting from the if with $? = 1, which +- # would make configure fail if this is the last instruction. +- $ac_cs_success || { (exit 1); exit 1; } +-fi +-if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then +- { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +-$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +-fi +- +diff --git a/utils/open-isns/configure.ac b/utils/open-isns/configure.ac +deleted file mode 100644 +index a02915b..0000000 +--- a/utils/open-isns/configure.ac ++++ /dev/null +@@ -1,118 +0,0 @@ +-AC_INIT(open-isns, [0.90]) +-AC_CONFIG_SRCDIR([isnsd.c]) +-AC_CONFIG_AUX_DIR([aclocal]) +- +-AC_CONFIG_HEADER(config.h) +- +-AC_PROG_CC +-AC_CANONICAL_HOST +-AC_C_BIGENDIAN +- +-AC_PROG_CPP +-AC_PROG_INSTALL +-AC_PROG_LN_S +-AC_PROG_MAKE_SET +-AC_PATH_PROG(SH, sh) +- +-dnl C Compiler features +-AC_C_INLINE +-if test "$GCC" = "yes"; then +- CFLAGS="-Wall -fno-strict-aliasing $CFLAGS" +- CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" +-fi +- +-dnl Checks for header files. +-AC_HEADER_STDC +-AC_HEADER_SYS_WAIT +-AC_CHECK_HEADERS([errno.h fcntl.h malloc.h stdlib.h string.h strings.h sys/time.h unistd.h locale.h getopt.h]) +- +-# Check if socket() is in libsocket +-AC_CHECK_LIB(socket, socket, [LIBS="$LIBS -lsocket"]) +- +- +-AC_SUBST(GETOPTSRC) +-AC_CHECK_FUNC(getopt_long, AC_DEFINE(HAVE_GETOPT_LONG, 1, [Define if you have the `getopt_long' function.]), +- [GETOPTSRC="$GETOPTSRC \$(top_srcdir)/compat/my_getopt.c" +- CPPFLAGS="-I\$(top_srcdir)/compat/ $CPPFLAGS" +- AC_DEFINE(HAVE_GETOPT_H, 1, [Define if you have the header file.])]) +- +-WITH_SECURITY=maybe +-AC_ARG_WITH(security, +- [ --with-security Enable iSNS authentication - requires OpenSSL], +- [ +- if test "x$withval" = "xno" -o "x$withval" = "xyes"; then +- WITH_SECURITY=$withval +- else +- WITH_SECURITY=yes +- CPPFLAGS="$CPPFLAGS -I${withval}" +- LDFLAGS="$LDFLAGS -L${withval}" +- fi +- ] +-) +- +-if test "x$WITH_SECURITY" != "xno" ; then +- # Check for openssl support - very primitive, we just +- # check for the presence of crypto.h +- AC_CHECK_HEADERS([openssl/crypto.h], +- , +- [have_libcrypto=no]) +- AC_CHECK_LIB(crypto, EVP_PKEY_new, +- [SECLIBS="-lcrypto"], +- [have_libcrypto=no]) +- +- if test "x$have_libcrypto" != "xno" ; then +- AC_DEFINE(WITH_SECURITY, 1, +- [Define if you want to support iSNS authentication]) +- else +- if test "x$WITH_SECURITY" = "xyes" ; then +- AC_MSG_ERROR([Security requested, but unable to find libcrypto]) +- fi +- fi +-fi +-AC_SUBST(SECLIBS) +- +-WITH_SLP=maybe +-AC_ARG_WITH(slp, +- [ --with-slp Enable SLP for server discovery - requires OpenSLP], +- [ +- if test "x$withval" = "xno" -o "x$withval" = "xyes"; then +- WITH_SLP=$withval +- else +- WITH_SLP=yes +- CPPFLAGS="$CPPFLAGS -I${withval}" +- LDFLAGS="$LDFLAGS -L${withval}" +- fi +- ] +-) +- +-if test "x$WITH_SLP" != "xno" ; then +- # Check for openslp support - very primitive +- AC_CHECK_HEADERS([slp.h],, +- [have_openslp=no]) +- AC_CHECK_LIB(slp, SLPOpen, +- [SLPLIBS="-lslp"], +- [have_openslp=no]) +- +- if test "x$have_openslp" != "xno" ; then +- AC_DEFINE(WITH_SLP, 1, +- [Define if you want to support SLP discovery]) +- else +- if test "x$WITH_SLP" = "xyes" ; then +- AC_MSG_ERROR([SLP requested, but unable to find openslp]) +- fi +- fi +-fi +-AC_SUBST(SLPLIBS) +- +-MEMDEBUG= +-AC_ARG_ENABLE(memdebug, +- [ --enable-memdebug Enable malloc debugging], +- [ +- if test "x$enableval" = "xyes" ; then +- CPPFLAGS="$CPPFLAGS -DMEMDEBUG" +- fi +- ] +-) +-AC_SUBST(OPTIMIZE) +- +-AC_OUTPUT(Makefile) +diff --git a/utils/open-isns/db-file.c b/utils/open-isns/db-file.c +deleted file mode 100644 +index 98c08db..0000000 +--- a/utils/open-isns/db-file.c ++++ /dev/null +@@ -1,615 +0,0 @@ +-/* +- * iSNS object database +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "isns.h" +-#include "objects.h" +-#include "message.h" +-#include "util.h" +-#include "db.h" +- +-#define DBE_FILE_VERSION 1 +- +-struct isns_db_file_info { +- uint32_t db_version; +- uint32_t db_last_eid; +- uint32_t db_last_index; +-}; +- +-struct isns_db_object_info { +- uint32_t db_version; +- char db_type[64]; +- uint32_t db_parent; +- uint32_t db_state; +- uint32_t db_flags; +- uint32_t db_scn_mask; +- /* reserved bytes */ +- uint32_t __db_reserved[15]; +-}; +- +-static int isns_dbe_file_sync(isns_db_t *); +-static int isns_dbe_file_reload(isns_db_t *); +-static int isns_dbe_file_store(isns_db_t *, +- const isns_object_t *); +-static int isns_dbe_file_remove(isns_db_t *, +- const isns_object_t *); +-static int __dbe_file_load_all(const char *, +- isns_object_list_t *); +- +-/* +- * Helper functions +- */ +-static const char * +-__path_concat(const char *dirname, const char *basename) +-{ +- static char pathname[PATH_MAX]; +- +- snprintf(pathname, sizeof(pathname), "%s/%s", +- dirname, basename); +- return pathname; +-} +- +-static const char * +-__print_index(uint32_t index) +-{ +- static char namebuf[32]; +- +- snprintf(namebuf, sizeof(namebuf), "%08x", index); +- return namebuf; +-} +- +-static int +-__get_index(const char *name, uint32_t *result) +-{ +- char *end; +- +- *result = strtoul(name, &end, 16); +- if (*end) +- return ISNS_INTERNAL_ERROR; +- return ISNS_SUCCESS; +-} +- +-/* +- * Build path names for an object +- */ +-static const char * +-__dbe_file_object_path(const char *dirname, const isns_object_t *obj) +-{ +- return __path_concat(dirname, __print_index(obj->ie_index)); +-} +- +-/* +- * Build a path name for a temporary file. +- * Cannot use __path_concat, because we need both names +- * when storing objects +- */ +-static const char * +-__dbe_file_object_temp(const char *dirname, const isns_object_t *obj) +-{ +- static char pathname[PATH_MAX]; +- +- snprintf(pathname, sizeof(pathname), "%s/.%s", +- dirname, __print_index(obj->ie_index)); +- return pathname; +-} +- +-/* +- * Recursively create a directory +- */ +-static int +-__dbe_mkdir_path(const char *dirname) +-{ +- unsigned int true_len = strlen(dirname); +- char *copy, *s; +- +- copy = isns_strdup(dirname); +- +- /* Walk up until we find a directory that exists */ +- while (1) { +- s = strrchr(copy, '/'); +- if (s == NULL) +- break; +- +- *s = '\0'; +- if (access(copy, F_OK) == 0) +- break; +- } +- +- while (strcmp(dirname, copy)) { +- unsigned int len = strlen(copy); +- +- /* Better safe than sorry */ +- isns_assert(len < true_len); +- +- /* Put the next slash back in */ +- copy[len] = '/'; +- +- /* and try to create the directory */ +- if (mkdir(copy, 0700) < 0) +- return -1; +- } +- +- return 0; +-} +- +-/* +- * Write an object to a file +- */ +-static int +-__dbe_file_store_object(const char *dirname, const isns_object_t *obj) +-{ +- struct isns_db_object_info info; +- const char *path = __dbe_file_object_path(dirname, obj); +- const char *temp = __dbe_file_object_temp(dirname, obj); +- buf_t *bp = NULL; +- int status = ISNS_INTERNAL_ERROR; +- +- isns_debug_state("DB: Storing object %u -> %s\n", obj->ie_index, path); +- if (access(dirname, F_OK) < 0 +- && (errno != ENOENT || __dbe_mkdir_path(dirname) < 0)) { +- isns_error("DB: Unable to create %s: %m\n", +- dirname); +- goto out; +- } +- +- bp = buf_open(temp, O_CREAT|O_TRUNC|O_WRONLY); +- if (bp == NULL) { +- isns_error("Unable to open %s: %m\n", temp); +- goto out; +- } +- +- /* Encode the header info ... */ +- memset(&info, 0, sizeof(info)); +- info.db_version = htonl(DBE_FILE_VERSION); +- info.db_state = htonl(obj->ie_state); +- info.db_flags = htonl(obj->ie_flags); +- info.db_scn_mask = htonl(obj->ie_scn_mask); +- strcpy(info.db_type, obj->ie_template->iot_name); +- if (obj->ie_container) +- info.db_parent = htonl(obj->ie_container->ie_index); +- +- if (!buf_put(bp, &info, sizeof(info))) +- goto out; +- +- /* ... and attributes */ +- status = isns_attr_list_encode(bp, &obj->ie_attrs); +- if (status != ISNS_SUCCESS) +- goto out; +- +- /* Renaming an open file. NFS will hate this */ +- if (rename(temp, path) < 0) { +- isns_error("Cannot rename %s -> %s: %m\n", +- temp, path); +- unlink(temp); +- status = ISNS_INTERNAL_ERROR; +- } +- +-out: +- if (bp) +- buf_close(bp); +- return status; +-} +- +-/* +- * Store all children of an object +- */ +-static int +-__dbe_file_store_children(const char *dirname, const isns_object_t *obj) +-{ +- int status = ISNS_SUCCESS; +- unsigned int i; +- +- for (i = 0; i < obj->ie_children.iol_count; ++i) { +- isns_object_t *child; +- +- child = obj->ie_children.iol_data[i]; +- status = __dbe_file_store_object(dirname, child); +- if (status) +- break; +- status = __dbe_file_store_children(dirname, child); +- if (status) +- break; +- } +- +- return status; +-} +- +-/* +- * Remove object and children +- */ +-static int +-__dbe_file_remove_object(const char *dirname, const isns_object_t *obj) +-{ +- const char *path = __dbe_file_object_path(dirname, obj); +- +- isns_debug_state("DB: Purging object %u (%s)\n", obj->ie_index, path); +- if (unlink(path) < 0) +- isns_error("DB: Cannot remove %s: %m\n", path); +- return ISNS_SUCCESS; +-} +- +-static int +-__dbe_file_remove_children(const char *dirname, const isns_object_t *obj) +-{ +- const isns_object_list_t *list = &obj->ie_children; +- unsigned int i; +- +- for (i = 0; i < list->iol_count; ++i) +- __dbe_file_remove_object(dirname, list->iol_data[i]); +- +- return ISNS_SUCCESS; +-} +- +-/* +- * Load an object from file +- */ +-static int +-__dbe_file_load_object(const char *filename, const char *basename, +- isns_object_list_t *result) +-{ +- struct isns_db_object_info info; +- isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; +- isns_object_template_t *tmpl; +- isns_object_t *obj = NULL; +- buf_t *bp = NULL; +- uint32_t index; +- int status; +- +- bp = buf_open(filename, O_RDONLY); +- if (bp == NULL) { +- isns_error("Unable to open %s: %m\n", filename); +- goto internal_error; +- } +- +- /* Decode the header ... */ +- if (!buf_get(bp, &info, sizeof(info))) +- goto internal_error; +- if (info.db_version != htonl(DBE_FILE_VERSION)) { +- /* If we ever have to deal with a DB version +- * upgrade, we could do it here. */ +- isns_fatal("Found iSNS database version %u; not supported\n", +- ntohl(info.db_version)); +- } +- +- /* ... and attributes */ +- status = isns_attr_list_decode(bp, &attrs); +- if (status != ISNS_SUCCESS) +- goto out; +- +- /* Get the index from the file name */ +- status = __get_index(basename, &index); +- if (status != ISNS_SUCCESS) +- goto out; +- +- tmpl = isns_object_template_by_name(info.db_type); +- if (tmpl == NULL) { +- isns_error("DB: Bad type name \"%s\" in object file\n", +- info.db_type); +- goto internal_error; +- } +- +- obj = isns_create_object(tmpl, &attrs, NULL); +- if (obj == NULL) +- goto internal_error; +- +- obj->ie_state = ntohl(info.db_state); +- obj->ie_flags = ntohl(info.db_flags) & ~(ISNS_OBJECT_DIRTY); +- obj->ie_scn_mask = ntohl(info.db_scn_mask); +- obj->ie_index = index; +- +- /* Stash away the parent's index; we resolve them later on +- * once we've loaded all objects */ +- obj->ie_container_idx = ntohl(info.db_parent); +- +- isns_object_list_append(result, obj); +- +-out: +- if (bp) +- buf_close(bp); +- if (obj) +- isns_object_release(obj); +- isns_attr_list_destroy(&attrs); +- return status; +- +-internal_error: +- isns_error("Unable to load %s: Internal error\n", +- filename); +- status = ISNS_INTERNAL_ERROR; +- goto out; +-} +- +-/* +- * Load contents of directory into our database. +- * +- * We take two passes over the directory. In the first pass, we load +- * all regular files containing objects. The file names correspond to +- * the DB index. +- * +- * In the second pass, we load all directories, containing children of +- * an object. The directories names are formed by the object's index, +- * with ".d" appended to it. +- */ +-static int +-__dbe_file_load_all(const char *dirpath, isns_object_list_t *result) +-{ +- struct dirent *dp; +- DIR *dir; +- int status = ISNS_SUCCESS; +- +- if ((dir = opendir(dirpath)) == NULL) { +- isns_error("DB: cannot open %s: %m\n", dirpath); +- return ISNS_INTERNAL_ERROR; +- } +- +- while ((dp = readdir(dir)) != NULL) { +- struct stat stb; +- const char *path; +- +- if (dp->d_name[0] == '.' +- || !strcmp(dp->d_name, "DB")) +- continue; +- +- path = __path_concat(dirpath, dp->d_name); +- if (lstat(path, &stb) < 0) { +- isns_error("DB: cannot stat %s: %m\n", path); +- status = ISNS_INTERNAL_ERROR; +- } else +- if (S_ISREG(stb.st_mode)) { +- status = __dbe_file_load_object(path, +- dp->d_name, result); +- } else { +- isns_debug_state("DB: ignoring %s\n", path); +- } +- +- if (status != ISNS_SUCCESS) +- break; +- } +- +- closedir(dir); +- return status; +-} +- +-/* +- * Load and store DB metadata +- */ +-static int +-__dbe_file_write_info(isns_db_t *db) +-{ +- isns_db_backend_t *back = db->id_backend; +- const char *path; +- buf_t *bp; +- int status = ISNS_INTERNAL_ERROR; +- +- path = __path_concat(back->idb_name, "DB"); +- if ((bp = buf_open(path, O_CREAT|O_TRUNC|O_WRONLY)) == NULL) { +- isns_error("Unable to write %s: %m\n", path); +- goto out; +- } +- +- if (buf_put32(bp, DBE_FILE_VERSION) +- && buf_put32(bp, db->id_last_eid) +- && buf_put32(bp, db->id_last_index)) +- status = ISNS_SUCCESS; +- +-out: +- if (bp) +- buf_close(bp); +- return status; +-} +- +-static int +-__dbe_file_load_info(isns_db_t *db) +-{ +- isns_db_backend_t *back = db->id_backend; +- struct isns_db_file_info info; +- const char *path; +- buf_t *bp = NULL; +- int status; +- +- path = __path_concat(back->idb_name, "DB"); +- if ((bp = buf_open(path, O_RDONLY)) == NULL) { +- status = ISNS_NO_SUCH_ENTRY; +- goto out; +- } +- +- status = ISNS_INTERNAL_ERROR; +- if (!buf_get32(bp, &info.db_version)) +- goto out; +- +- if (info.db_version != DBE_FILE_VERSION) { +- isns_error("DB file from unsupported version %04x\n", +- info.db_version); +- goto out; +- } +- +- if (buf_get32(bp, &info.db_last_eid) +- && buf_get32(bp, &info.db_last_index)) { +- db->id_last_eid = info.db_last_eid; +- db->id_last_index = info.db_last_index; +- status = ISNS_SUCCESS; +- } +- +-out: +- if (bp) +- buf_close(bp); +- return status; +-} +- +-/* +- * Find object with the given index. +- */ +-static isns_object_t * +-__dbe_find_object(isns_object_list_t *list, uint32_t index) +-{ +- unsigned int i; +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- +- if (obj->ie_index == index) +- return obj; +- } +- return NULL; +-} +- +-int +-isns_dbe_file_reload(isns_db_t *db) +-{ +- isns_db_backend_t *back = db->id_backend; +- int status; +- unsigned int i; +- +- isns_debug_state("DB: loading all objects from %s\n", +- back->idb_name); +- +- if (access(back->idb_name, R_OK) < 0) { +- if (errno == ENOENT) { +- /* Empty database is okay */ +- return ISNS_NO_SUCH_ENTRY; +- } +- isns_error("Cannot open database %s: %m\n", back->idb_name); +- return ISNS_INTERNAL_ERROR; +- } +- +- status = __dbe_file_load_info(db); +- if (status) +- return status; +- +- status = __dbe_file_load_all(back->idb_name, db->id_objects); +- if (status) +- return status; +- +- /* Resolve parent/child relationship for all nodes */ +- for (i = 0; i < db->id_objects->iol_count; ++i) { +- isns_object_t *obj = db->id_objects->iol_data[i]; +- uint32_t index = obj->ie_container_idx; +- isns_object_t *parent; +- +- if (index == 0) +- continue; +- +- obj->ie_container = NULL; +- +- parent = __dbe_find_object(db->id_objects, index); +- if (parent == NULL) { +- isns_warning("DB: object %u references " +- "unknown container %u\n", +- obj->ie_index, +- index); +- } else { +- isns_object_attach(obj, parent); +- } +- } +- +- /* Add objects to the appropriate lists */ +- for (i = 0; i < db->id_objects->iol_count; ++i) { +- isns_object_template_t *tmpl; +- isns_object_t *obj = db->id_objects->iol_data[i]; +- +- switch (obj->ie_state) { +- case ISNS_OBJECT_STATE_MATURE: +- isns_scope_add(db->id_global_scope, obj); +- obj->ie_references++; +- +- tmpl = obj->ie_template; +- if (tmpl->iot_build_relation +- && !tmpl->iot_build_relation(db, obj, NULL)) +- isns_warning("DB: cannot build relation for " +- "object %u\n", +- obj->ie_index); +- +- if (obj->ie_relation) +- isns_relation_add(db->id_relations, +- obj->ie_relation); +- +- if (ISNS_IS_ENTITY(obj)) +- isns_esi_register(obj); +- break; +- +- case ISNS_OBJECT_STATE_LIMBO: +- isns_object_list_append(&db->id_limbo, obj); +- break; +- +- default: +- isns_error("Unexpected object state %d in object %u " +- "loaded from %s\n", +- obj->ie_state, obj->ie_index, +- back->idb_name); +- } +- +- /* Clear the dirty flag, which will be set when the +- object is created. */ +- obj->ie_flags &= ~ISNS_OBJECT_DIRTY; +- } +- +- return ISNS_SUCCESS; +-} +- +-int +-isns_dbe_file_sync(isns_db_t *db) +-{ +- return __dbe_file_write_info(db); +-} +- +-int +-isns_dbe_file_store(isns_db_t *db, const isns_object_t *obj) +-{ +- isns_db_backend_t *back = db->id_backend; +- int status; +- +- if (obj->ie_index == 0) { +- isns_error("DB: Refusing to store object with index 0\n"); +- return ISNS_INTERNAL_ERROR; +- } +- +- status = __dbe_file_store_object(back->idb_name, obj); +- if (status == ISNS_SUCCESS) +- status = __dbe_file_store_children(back->idb_name, obj); +- +- return status; +-} +- +-int +-isns_dbe_file_remove(isns_db_t *db, const isns_object_t *obj) +-{ +- isns_db_backend_t *back = db->id_backend; +- int status; +- +- status = __dbe_file_remove_object(back->idb_name, obj); +- if (status == ISNS_SUCCESS) +- status = __dbe_file_remove_children(back->idb_name, obj); +- +- return status; +-} +- +-/* +- * Create the file backend +- */ +-isns_db_backend_t * +-isns_create_file_db_backend(const char *pathname) +-{ +- isns_db_backend_t *back; +- +- isns_debug_state("Creating file DB backend (%s)\n", pathname); +- +- back = isns_calloc(1, sizeof(*back)); +- back->idb_name = isns_strdup(pathname); +- back->idb_reload = isns_dbe_file_reload; +- back->idb_sync = isns_dbe_file_sync; +- back->idb_store = isns_dbe_file_store; +- back->idb_remove = isns_dbe_file_remove; +- +- return back; +-} +- +diff --git a/utils/open-isns/db-policy.c b/utils/open-isns/db-policy.c +deleted file mode 100644 +index a85a436..0000000 +--- a/utils/open-isns/db-policy.c ++++ /dev/null +@@ -1,187 +0,0 @@ +-/* +- * Use database as policy and keystore +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#ifdef WITH_SECURITY +-#include +-#include +-#endif +-#include "isns.h" +-#include "security.h" +-#include "objects.h" +-#include "vendor.h" +-#include "util.h" +-#include "config.h" +- +-/* +- * DB keystore +- */ +-typedef struct isns_db_keystore isns_db_keystore_t; +-struct isns_db_keystore { +- isns_keystore_t sd_base; +- isns_db_t * sd_db; +- isns_object_t * sd_control; +-}; +- +-/* +- * Look up the policy object given its SPI +- */ +-isns_object_t * +-__isns_db_keystore_lookup(isns_db_keystore_t *store, +- const char *name, size_t namelen) +-{ +- isns_attr_list_t keys = ISNS_ATTR_LIST_INIT; +- char namebuf[256]; +- +- if (namelen >= sizeof(namebuf)) +- return NULL; +- memcpy(namebuf, name, namelen); +- namebuf[namelen] = '\0'; +- +- isns_attr_list_append_string(&keys, +- OPENISNS_TAG_POLICY_SPI, +- namebuf); +- return isns_db_lookup(store->sd_db, NULL, &keys); +-} +- +-/* +- * Load a DSA key from the DB store +- */ +-static EVP_PKEY * +-__isns_db_keystore_find(isns_keystore_t *store_base, +- const char *name, size_t namelen) +-{ +-#ifdef WITH_SECURITY +- isns_db_keystore_t *store = (isns_db_keystore_t *) store_base; +- isns_object_t *obj; +- const void *key_data; +- size_t key_size; +- +- obj = __isns_db_keystore_lookup(store, name, namelen); +- if (obj == NULL) +- return NULL; +- +- if (!isns_object_get_opaque(obj, OPENISNS_TAG_POLICY_KEY, +- &key_data, &key_size)) +- return NULL; +- +- return isns_dsa_decode_public(key_data, key_size); +-#else +- return NULL; +-#endif +-} +- +-/* +- * Retrieve policy from database +- */ +-static void +-__isns_db_keystore_copy_policy_string(isns_object_t *obj, +- uint32_t tag, char **var) +-{ +- const char *value; +- +- if (!isns_object_get_string(obj, tag, &value)) +- return; +- isns_assign_string(var, value); +-} +- +-static void +-__isns_db_keystore_copy_policy_strings(isns_object_t *obj, +- uint32_t tag, struct string_array *array) +-{ +- isns_attr_list_t *attrs = &obj->ie_attrs; +- unsigned int i; +- +- for (i = 0; i < attrs->ial_count; ++i) { +- isns_attr_t *attr = attrs->ial_data[i]; +- +- if (attr->ia_tag_id != tag +- || !ISNS_ATTR_IS_STRING(attr)) +- continue; +- isns_string_array_append(array, attr->ia_value.iv_string); +- } +-} +- +-static isns_policy_t * +-__isns_db_keystore_get_policy(isns_keystore_t *store_base, +- const char *name, size_t namelen) +-{ +- isns_db_keystore_t *store = (isns_db_keystore_t *) store_base; +- isns_policy_t *policy; +- isns_object_t *obj; +- uint32_t intval; +- +- obj = __isns_db_keystore_lookup(store, name, namelen); +- if (obj == NULL) +- return NULL; +- +- policy = __isns_policy_alloc(name, namelen); +- +- /* retrieve policy bits from object */ +-#if 0 +- __isns_db_keystore_copy_policy_string(obj, +- OPENISNS_TAG_POLICY_SOURCE_NAME, +- &policy->ip_source); +-#endif +- __isns_db_keystore_copy_policy_string(obj, +- OPENISNS_TAG_POLICY_ENTITY, +- &policy->ip_entity); +- __isns_db_keystore_copy_policy_string(obj, +- OPENISNS_TAG_POLICY_DEFAULT_DD, +- &policy->ip_dd_default); +- __isns_db_keystore_copy_policy_strings(obj, +- OPENISNS_TAG_POLICY_NODE_NAME, +- &policy->ip_node_names); +- +- if (isns_object_get_uint32(obj, OPENISNS_TAG_POLICY_OBJECT_TYPE, &intval)) +- policy->ip_object_types = intval; +- if (isns_object_get_uint32(obj, OPENISNS_TAG_POLICY_NODE_TYPE, &intval)) +- policy->ip_node_types = intval; +- if (isns_object_get_uint32(obj, OPENISNS_TAG_POLICY_FUNCTIONS, &intval)) +- policy->ip_functions = intval; +- +- return policy; +-} +- +-void +-__isns_db_keystore_change_notify(const isns_db_event_t *ev, void *handle) +-{ +- isns_db_keystore_t *store = handle; +- isns_object_t *obj = ev->ie_object; +- +- if (isns_object_get_entity(obj) == store->sd_control) { +- isns_debug_auth("DB keystore: policy data was modified\n"); +- store->sd_base.ic_generation++; +- } +-} +- +-isns_keystore_t * +-isns_create_db_keystore(isns_db_t *db) +-{ +- isns_db_keystore_t *store; +- isns_object_t *entity; +- +- isns_debug_auth("Creating DB keystore\n"); +- if (!(entity = isns_db_get_control(db))) { +- isns_error("Could not create control entity in database\n"); +- return NULL; +- } +- isns_debug_auth("Control entity is 0x%08x\n", entity->ie_index); +- +- store = isns_calloc(1, sizeof(*store)); +- store->sd_base.ic_name = "database key store"; +- store->sd_base.ic_find = __isns_db_keystore_find; +- store->sd_base.ic_get_policy = __isns_db_keystore_get_policy; +- store->sd_control = entity; +- store->sd_db = db; +- +- isns_register_callback(__isns_db_keystore_change_notify, store); +- +- return (isns_keystore_t *) store; +-} +- +diff --git a/utils/open-isns/db.c b/utils/open-isns/db.c +deleted file mode 100644 +index c66dfbb..0000000 +--- a/utils/open-isns/db.c ++++ /dev/null +@@ -1,994 +0,0 @@ +-/* +- * iSNS object database +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +- +-#include "isns.h" +-#include "objects.h" +-#include "db.h" +-#include "util.h" +- +-enum { +- IDT_INSERT, +- IDT_REMOVE, +- IDT_UPDATE +-}; +-struct isns_db_trans { +- struct isns_db_trans * idt_next; +- int idt_action; +- isns_object_t * idt_object; +-}; +- +-/* Internal helpers */ +-static int isns_db_sanity_check(isns_db_t *); +-static int isns_db_get_key_tags(const isns_attr_list_t *, +- uint32_t *, unsigned int); +-static int isns_db_keyed_compare(const isns_object_t *, +- const isns_attr_list_t *, +- const uint32_t *, unsigned int); +- +-/* +- * Open a database +- */ +-static isns_db_t * +-isns_db_create(isns_db_backend_t *backend) +-{ +- isns_db_t *db; +- +- db = isns_calloc(1, sizeof(*db)); +- db->id_last_index = 1; +- db->id_last_eid = 1; +- db->id_backend = backend; +- db->id_global_scope = isns_scope_alloc(db); +- db->id_relations = isns_relation_soup_alloc(); +- db->id_objects = &db->__id_objects; +- +- if (backend && backend->idb_reload) { +- int status; +- +- status = backend->idb_reload(db); +- /* "No such entry" is returned when the DB +- * is still empty. */ +- if (status != ISNS_SUCCESS +- && status != ISNS_NO_SUCH_ENTRY) { +- isns_error("Error loading database: %s\n", +- isns_strerror(status)); +- /* FIXME: isns_db_free(db); */ +- return NULL; +- } +- +- isns_db_sanity_check(db); +- } +- +- return db; +-} +- +-isns_db_t * +-isns_db_open(const char *location) +-{ +- isns_db_backend_t *backend; +- +- if (location == NULL) { +- isns_debug_state("Using in-memory DB\n"); +- return isns_db_create(NULL); +- } +- +- if (location[0] == '/') { +- backend = isns_create_file_db_backend(location); +- } else +- if (!strncmp(location, "file:", 5)) { +- backend = isns_create_file_db_backend(location + 5); +- } else { +- isns_error("Unsupported database type \"%s\"\n", +- location); +- return NULL; +- } +- +- return isns_db_create(backend); +-} +- +-isns_db_t * +-isns_db_open_shadow(isns_object_list_t *list) +-{ +- isns_db_t *db; +- +- if ((db = isns_db_create(NULL)) != NULL) +- db->id_objects = list; +- return db; +-} +- +-int +-isns_db_sanity_check(isns_db_t *db) +-{ +- unsigned int i; +- +- i = 0; +- while (i < db->id_objects->iol_count) { +- isns_object_t *obj = db->id_objects->iol_data[i]; +- +- switch (obj->ie_state) { +- case ISNS_OBJECT_STATE_MATURE: +- /* Nothing yet. */ +- break; +- +- case ISNS_OBJECT_STATE_LIMBO: +- if (!ISNS_IS_ISCSI_NODE(obj) +- && !ISNS_IS_PORTAL(obj)) { +- isns_error("Unexpected object %u (%s) in limbo\n", +- obj->ie_index, +- obj->ie_template->iot_name); +- isns_db_remove(db, obj); +- } +- break; +- +- default: +- isns_error("Unexpected object state %d in object %u (%s)\n", +- obj->ie_state, obj->ie_index, +- obj->ie_template->iot_name); +- isns_db_remove(db, obj); +- break; +- } +- +- i += 1; +- } +- +- return 1; +-} +- +-isns_object_t * +-isns_db_lookup(isns_db_t *db, +- isns_object_template_t *tmpl, +- const isns_attr_list_t *keys) +-{ +- return isns_object_list_lookup(db->id_objects, tmpl, keys); +-} +- +-int +-isns_db_gang_lookup(isns_db_t *db, +- isns_object_template_t *tmpl, +- const isns_attr_list_t *keys, +- isns_object_list_t *result) +-{ +- return isns_object_list_gang_lookup(db->id_objects, +- tmpl, keys, result); +-} +- +-/* +- * Look up the storage node for the given source. +- */ +-isns_object_t * +-isns_db_lookup_source_node(isns_db_t *db, +- const isns_source_t *source) +-{ +- isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; +- isns_object_t *node; +- +- isns_attr_list_append_attr(&attrs, isns_source_attr(source)); +- node = isns_db_lookup(db, NULL, &attrs); +- isns_attr_list_destroy(&attrs); +- +- return node; +-} +- +-isns_object_t * +-isns_db_vlookup(isns_db_t *db, +- isns_object_template_t *tmpl, +- ...) +-{ +- isns_attr_list_t keys = ISNS_ATTR_LIST_INIT; +- isns_object_t *obj = NULL; +- va_list ap; +- +- va_start(ap, tmpl); +- while (1) { +- const isns_tag_type_t *tag_type; +- isns_value_t value; +- uint32_t tag; +- +- tag = va_arg(ap, unsigned int); +- if (tag == 0) +- break; +- +- tag_type = isns_tag_type_by_id(tag); +- if (tag_type == NULL) { +- isns_error("isns_db_vlookup: unknown tag %u\n", tag); +- goto out; +- } +- +- memset(&value, 0, sizeof(value)); +- value.iv_type = tag_type->it_type; +- switch (tag_type->it_type->it_id) { +- case ISNS_ATTR_TYPE_STRING: +- value.iv_string = va_arg(ap, char *); +- break; +- +- case ISNS_ATTR_TYPE_INT32: +- value.iv_int32 = va_arg(ap, int32_t); +- break; +- +- case ISNS_ATTR_TYPE_UINT32: +- value.iv_int32 = va_arg(ap, uint32_t); +- break; +- +- case ISNS_ATTR_TYPE_IPADDR: +- value.iv_ipaddr = *va_arg(ap, struct in6_addr *); +- break; +- +- default: +- isns_error("isns_db_vlookup: unsupported tag type %s\n", +- value.iv_type->it_name); +- goto out; +- } +- +- isns_attr_list_append_value(&keys, tag, tag_type, &value); +- } +- +- obj = isns_db_lookup(db, tmpl, &keys); +- +-out: +- isns_attr_list_destroy(&keys); +- va_end(ap); +- return obj; +-} +- +-/* +- * Find the next matching object +- * +- * This implementation could be a lot simpler if the +- * RFC didn't make things so awfully complicated. +- * It could simply have mandated the use of the object +- * index attribute, period. +- */ +-isns_object_t * +-__isns_db_get_next(const isns_object_list_t *list, +- isns_object_template_t *tmpl, +- const isns_attr_list_t *current, +- const isns_attr_list_t *scope) +-{ +- isns_object_t *next = NULL; +- uint32_t tags[16]; +- unsigned int i; +- int num_tags; +- +- if (!tmpl) +- return NULL; +- +- /* Get the search attribute tags, and sort them. +- * Note, these don't have to be the standard key +- * attributes for a given object type; the RFC +- * also permits index attributes. +- */ +- num_tags = isns_db_get_key_tags(current, tags, 16); +- if (num_tags < 0) +- return NULL; +- +- /* +- * 5.6.5.3. +- * If the TLV length of the Message Key Attribute(s) is zero, +- * then the first object entry in the iSNS database matching the +- * Message Key type SHALL be returned in the Message Key of the +- * corresponding DevGetNextRsp message. +- */ +- for (i = 0; i < current->ial_count; ++i) { +- isns_attr_t *attr = current->ial_data[i]; +- +- if (!ISNS_ATTR_IS_NIL(attr)) +- goto non_nil; +- } +- current = NULL; +-non_nil: +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- +- if (obj->ie_template != tmpl) +- continue; +- if (scope && !isns_object_match(obj, scope)) +- continue; +- +- /* compare returns -1 if the first list +- * is "before" the second list, in terms of +- * implicit ordering. */ +- if (current +- && isns_db_keyed_compare(obj, current, tags, num_tags) <= 0) { +- /* obj less than or equal to current */ +- continue; +- } +- +- if (next == NULL +- || isns_db_keyed_compare(obj, &next->ie_attrs, tags, num_tags) < 0) +- next = obj; +- } +- +- if (next) +- isns_object_get(next); +- return next; +-} +- +-isns_object_t * +-isns_db_get_next(isns_db_t *db, +- isns_object_template_t *tmpl, +- const isns_attr_list_t *current, +- const isns_attr_list_t *scope, +- const isns_source_t *source) +-{ +- return __isns_db_get_next(db->id_objects, +- tmpl, current, scope); +-} +- +-/* +- * Get the search key tags +- */ +-static int +-isns_db_get_key_tags(const isns_attr_list_t *keys, +- uint32_t *tags, unsigned int max_tags) +-{ +- unsigned int i; +- +- /* Get the search attribute tags, and sort them */ +- for (i = 0; i < keys->ial_count; ++i) { +- if (i >= 16) +- return -1; +- tags[i] = keys->ial_data[i]->ia_tag_id; +- } +- +- /* FIXME: qsort the list */ +- return i; +-} +- +-/* +- * Helper function for GetNext +- */ +-static int +-isns_db_keyed_compare(const isns_object_t *obj, +- const isns_attr_list_t *attrs, +- const uint32_t *tags, unsigned int num_tags) +-{ +- int ind = 0; +- unsigned int i; +- +- for (i = 0; i < num_tags; ++i) { +- isns_attr_t *attr1, *attr2; +- uint32_t tag = tags[i]; +- +- if (!isns_attr_list_get_attr(&obj->ie_attrs, tag, &attr1)) +- attr1 = NULL; +- if (!isns_attr_list_get_attr(attrs, tag, &attr2)) +- attr2 = NULL; +- if (attr1 == attr2) { +- ind = 0; +- } else if (attr1 && attr2) { +- ind = isns_attr_compare(attr1, attr2); +- } else if (attr1 == NULL) { +- ind = -1; +- } else { +- ind = 1; +- } +- if (ind) +- break; +- } +- return ind; +-} +- +-uint32_t +-isns_db_allocate_index(isns_db_t *db) +-{ +- return db->id_last_index++; +-} +- +-/* +- * Insert an object into the database. +- */ +-void +-__isns_db_insert(isns_db_t *db, isns_object_t *obj, unsigned int state) +-{ +- uint32_t idx_tag = obj->ie_template->iot_index; +- +- switch (obj->ie_state) { +- case ISNS_OBJECT_STATE_LIMBO: +- /* The object was in limbo; now it goes +- * live (again). It should have an index, +- * and it should be on the global id_objects +- * list too. +- */ +- isns_assert(state == ISNS_OBJECT_STATE_MATURE); +- isns_assert(obj->ie_index); +- isns_assert(obj->ie_users > 1); +- isns_object_list_remove(&db->id_limbo, obj); +- break; +- +- case ISNS_OBJECT_STATE_DEAD: +- /* A DevAttrReg with the F_REPLACE bit set will cause +- * the key object to be removed from the DB, which may +- * kill it for good. +- * The subsequent call to db_insert will assign a new +- * index, and re-add it to the database. +- */ +- +- case ISNS_OBJECT_STATE_LARVAL: +- /* Larval objects can go either to mature or +- * limbo state. */ +- obj->ie_index = db->id_last_index++; +- +- if (idx_tag) +- isns_object_set_uint32(obj, +- idx_tag, +- obj->ie_index); +- +- isns_object_list_append(db->id_objects, obj); +- break; +- +- case ISNS_OBJECT_STATE_MATURE: +- /* If we call db_insert on a mature object, treat +- this as a NOP. */ +- isns_assert(state == ISNS_OBJECT_STATE_MATURE); +- return; +- +- default: +- isns_error("Internal error: unexpected object %u (%s) " +- "state %u in db_insert\n", +- obj->ie_index, +- obj->ie_template->iot_name, +- obj->ie_state); +- return; +- } +- +- obj->ie_state = state; +- +- /* Add it to the global scope */ +- if (state == ISNS_OBJECT_STATE_MATURE) { +- isns_scope_add(db->id_global_scope, obj); +- obj->ie_references++; +- +- /* See if this object represents a relationship +- * (eg a portal group). */ +- if (obj->ie_template->iot_relation_type) { +- if (!obj->ie_relation) { +- isns_warning("DB: inserting %s object " +- "without relation\n", +- obj->ie_template->iot_name); +- } else { +- isns_relation_add(db->id_relations, +- obj->ie_relation); +- } +- } +- +- isns_mark_object(obj, ISNS_SCN_OBJECT_ADDED); +- } +- +- isns_debug_state("DB: added object %u (%s) state %u\n", +- obj->ie_index, +- obj->ie_template->iot_name, +- obj->ie_state); +- +- if (db->id_backend) { +- db->id_backend->idb_store(db, obj); +- db->id_backend->idb_sync(db); +- } +-} +- +-void +-isns_db_insert(isns_db_t *db, isns_object_t *obj) +-{ +- __isns_db_insert(db, obj, ISNS_OBJECT_STATE_MATURE); +-} +- +-void +-isns_db_insert_limbo(isns_db_t *db, isns_object_t *obj) +-{ +- isns_assert(obj->ie_state == ISNS_OBJECT_STATE_LARVAL); +- __isns_db_insert(db, obj, ISNS_OBJECT_STATE_LIMBO); +-} +- +-/* +- * Save an object after updating it +- */ +-void +-isns_db_sync(isns_db_t *db) +-{ +- isns_object_list_t *list = db->id_objects; +- unsigned int i, saved = 0; +- +- if (!db->id_backend) +- return; +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- +- if (obj->ie_flags & ISNS_OBJECT_DIRTY) { +- db->id_backend->idb_store(db, obj); +- obj->ie_flags &= ~ISNS_OBJECT_DIRTY; +- saved++; +- } +- } +- if (saved) +- db->id_backend->idb_sync(db); +-} +- +-/* +- * Remove an object from the database. +- * This is slow and inefficient, due to the use +- * of an object array. We should at least use +- * a linked list, or maybe even a hash one day. +- */ +-static void +-__isns_db_prepare_removal(isns_db_t *db, isns_object_t *obj) +-{ +- isns_object_t *child; +- +- obj->ie_flags |= ISNS_OBJECT_DEAD; +- isns_object_get(obj); +- +- /* The node is dead; it's no longer interested in SCNs */ +- obj->ie_scn_mask = 0; +- +- /* Trigger an SCN event. */ +- if (obj->ie_state == ISNS_OBJECT_STATE_MATURE) +- isns_mark_object(obj, ISNS_SCN_OBJECT_REMOVED); +- +- /* If the object represents a relation between +- * two other objects, sever that relationship. +- */ +- if (obj->ie_relation) { +- isns_relation_remove(db->id_relations, +- obj->ie_relation); +- isns_relation_sever(obj->ie_relation); +- isns_relation_release(obj->ie_relation); +- obj->ie_relation = NULL; +- } +- +- /* Detach the object from its container */ +- isns_object_detach(obj); +- +- /* Remove it from the database */ +- if (isns_scope_remove(db->id_global_scope, obj)) { +- obj->ie_references--; +- } else { +- isns_warning("Unable to remove object from scope\n"); +- } +- +- /* Recursively remove all children */ +- while (obj->ie_children.iol_count) { +- child = obj->ie_children.iol_data[0]; +- __isns_db_prepare_removal(db, child); +- } +- +- isns_debug_state("DB: removed object %u (%s)\n", +- obj->ie_index, +- obj->ie_template->iot_name); +- +- isns_object_list_append(&db->id_deferred, obj); +- isns_object_release(obj); +-} +- +-int +-isns_db_remove(isns_db_t *db, isns_object_t *obj) +-{ +- isns_object_t *entity; +- unsigned int i; +- +- /* Don't even bother if the object was never added */ +- if (obj->ie_index == 0) +- goto out; +- +- /* Obtain the containing entity before removal */ +- entity = isns_object_get_entity(obj); +- +- /* We don't remove the object for real yet; +- * this will happen later during db_purge */ +- __isns_db_prepare_removal(db, obj); +- +- /* +- * 5.6.5.4. +- * If all Nodes and Portals associated with a Network Entity are +- * deregistered, then the Network Entity SHALL also be removed. +- * +- * If both the Portal and iSCSI Storage Node objects associated +- * with a Portal Group object are removed, then that Portal Group +- * object SHALL also be removed. The Portal Group object SHALL +- * remain registered as long as either of its associated Portal +- * or iSCSI Storage Node objects remain registered. If a deleted +- * Storage Node or Portal object is subsequently re-registered, +- * then a relationship between the re- registered object and +- * an existing Portal or Storage Node object registration, +- * indicated by the PG object, SHALL be restored. +- */ +- if (ISNS_IS_ENTITY(obj)) +- goto out; +- +- if (entity == NULL || !ISNS_IS_ENTITY(entity)) +- goto out; +- +- /* Don't do this for the CONTROL entity. */ +- if (entity->ie_flags & ISNS_OBJECT_PRIVATE) +- goto out; +- +- /* Step 1: Purge all relationship objects (read: portal groups) +- * where both referenced objects are dead. +- */ +- for (i = 0; i < entity->ie_children.iol_count; ) { +- isns_object_t *child = entity->ie_children.iol_data[i]; +- +- if (child->ie_relation +- && isns_relation_is_dead(child->ie_relation)) { +- __isns_db_prepare_removal(db, child); +- continue; +- } +- +- i += 1; +- } +- +- /* Step 2: If all portals, nodes and PGs have been unregistered, +- * the list of children should be empty. */ +- if (entity->ie_children.iol_count == 0) { +- isns_debug_state("Last portal/node unregistered, removing entity\n"); +- __isns_db_prepare_removal(db, entity); +- } +- +-out: +- return ISNS_SUCCESS; +-} +- +-/* +- * Purge deregistered objects. +- * If we find they're still part of some discovery +- * domain, they're moved to id_limbo; otherwise we'll +- * destroy them for good. +- */ +-void +-isns_db_purge(isns_db_t *db) +-{ +- isns_object_list_t *list = &db->id_deferred; +- unsigned int i; +- +- while (list->iol_count) { +- isns_object_t *obj = list->iol_data[0]; +- +- if (obj->ie_references == 0) { +- isns_debug_state("DB: destroying object %u (%s)\n", +- obj->ie_index, +- obj->ie_template->iot_name); +- +- if (db->id_backend) { +- db->id_backend->idb_remove(db, obj); +- /* db->id_backend->idb_sync(db); */ +- } +- +- isns_object_list_remove(db->id_objects, obj); +- obj->ie_state = ISNS_OBJECT_STATE_DEAD; +- } else if (obj->ie_state != ISNS_OBJECT_STATE_LIMBO) { +- isns_debug_state("DB: moving object %u (%s) to purgatory - " +- "%u references left\n", +- obj->ie_index, +- obj->ie_template->iot_name, +- obj->ie_references); +- +- isns_object_list_append(&db->id_limbo, obj); +- obj->ie_state = ISNS_OBJECT_STATE_LIMBO; +- isns_object_prune_attrs(obj); +- +- if (db->id_backend) { +- db->id_backend->idb_store(db, obj); +- db->id_backend->idb_sync(db); +- } +- } +- +- isns_object_list_remove(list, obj); +- } +- +- /* Brute force - look at all objects in limbo and kill those +- * that went out of scope */ +- for (i = 0; i < db->id_limbo.iol_count; ) { +- isns_object_t *obj = db->id_limbo.iol_data[i]; +- +- if (obj->ie_references == 0) { +- isns_debug_state("DB: destroying object %u (%s)\n", +- obj->ie_index, +- obj->ie_template->iot_name); +- +- if (db->id_backend) { +- db->id_backend->idb_remove(db, obj); +- /* db->id_backend->idb_sync(db); */ +- } +- +- obj->ie_state = ISNS_OBJECT_STATE_DEAD; +- isns_object_list_remove(&db->id_limbo, obj); +- isns_object_list_remove(db->id_objects, obj); +- continue; +- } +- +- i += 1; +- } +-} +- +-/* +- * Expire old entities +- * +- * This code is still rather simple, but once we start +- * using ESI things get rather complex quickly. +- */ +-time_t +-isns_db_expire(isns_db_t *db) +-{ +- isns_object_list_t *list = db->id_objects; +- time_t now = time(NULL), next_timeout; +- unsigned int i = 0; +- +- next_timeout = now + 3600; +- if (isns_config.ic_registration_period == 0) +- return next_timeout; +- +- while (i < list->iol_count) { +- isns_object_t *obj; +- uint64_t stamp; +- uint32_t period; +- +- obj = list->iol_data[i]; +- if (!ISNS_IS_ENTITY(obj)) +- goto next; +- +- if (!isns_object_get_uint32(obj, +- ISNS_TAG_REGISTRATION_PERIOD, +- &period)) { +- isns_debug_state("No registration period for entity %u\n", +- obj->ie_index); +- goto next; +- } +- +- if (!isns_object_get_uint64(obj, +- ISNS_TAG_TIMESTAMP, +- &stamp)) { +- isns_debug_state("No timestamp for entity %u\n", +- obj->ie_index); +- goto next; +- } +- +- stamp += period; +- if (stamp <= now) { +- /* removing the object will move one +- * object from the tail to the free +- * slot in the list. So don't increment +- * the index here. */ +- isns_debug_state("Expiring entity %u\n", obj->ie_index); +- isns_db_remove(db, obj); +- goto next; +- } else { +- isns_debug_state("Entity %u will expire in %u sec\n", +- obj->ie_index, (int) (stamp - now)); +- if (stamp < next_timeout) +- next_timeout = stamp; +- } +- +-next: +- i += 1; +- } +- +- /* Send out SCN notifications. +- * This makes sure we won't have extraneous references +- * on expired objects when we reach db_purge. */ +- isns_flush_events(); +- +- return next_timeout; +-} +- +-/* +- * Very special function to make sure we always have a +- * CONTROL entity. +- */ +-isns_object_t * +-isns_db_get_control(isns_db_t *db) +-{ +- isns_attr_list_t keys = ISNS_ATTR_LIST_INIT; +- isns_object_list_t *list = db->id_objects; +- isns_object_t *found = NULL; +- unsigned int i; +- +- isns_attr_list_append_string(&keys, +- ISNS_TAG_ENTITY_IDENTIFIER, +- ISNS_ENTITY_CONTROL); +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj; +- +- obj = list->iol_data[i]; +- if (!ISNS_IS_ENTITY(obj)) +- continue; +- if (isns_object_match(obj, &keys)) { +- obj->ie_users++; +- found = obj; +- goto done; +- } +- } +- +- found = isns_create_object(&isns_entity_template, +- &keys, NULL); +- found->ie_flags |= ISNS_OBJECT_PRIVATE; +- isns_db_insert(db, found); +- isns_db_sync(db); +- +-done: +- return found; +-} +- +-void +-isns_db_get_domainless(isns_db_t *db, +- isns_object_template_t *tmpl, +- isns_object_list_t *result) +-{ +- isns_object_list_t *list = db->id_objects; +- unsigned int i; +- +- if (!tmpl) +- return; +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- +- if (obj->ie_template == tmpl +- && isns_bitvector_is_empty(obj->ie_membership)) +- isns_object_list_append(result, obj); +- } +-} +- +-/* +- * Create a relationship and store it in the DB +- */ +-void +-isns_db_create_relation(isns_db_t *db, +- isns_object_t *relating_object, +- unsigned int relation_type, +- isns_object_t *subordinate_object1, +- isns_object_t *subordinate_object2) +-{ +- isns_relation_t *rel; +- +- rel = isns_create_relation(relating_object, +- relation_type, +- subordinate_object1, +- subordinate_object2); +- if (rel) { +- isns_relation_add(db->id_relations, rel); +- isns_relation_release(rel); +- } +-} +- +-/* +- * Get all objects related to @left through a relation +- * of type @type. +- */ +-void +-isns_db_get_relationship_objects(isns_db_t *db, +- const isns_object_t *left, +- unsigned int relation_type, +- isns_object_list_t *result) +-{ +- isns_relation_get_edge_objects(db->id_relations, +- left, relation_type, +- result); +-} +- +-/* +- * Get the object relating left and right. +- * Usually called to find the portal group connecting +- * a portal and a storage node, or a DD connecting +- * two storage nodes. +- */ +-isns_object_t * +-isns_db_get_relationship_object(isns_db_t *db, +- const isns_object_t *left, +- const isns_object_t *right, +- unsigned int relation_type) +-{ +- isns_relation_t *rel; +- +- /* Find a relation of the given type, connecting +- * the two objects. */ +- rel = isns_relation_find_edge(db->id_relations, +- left, right, relation_type); +- +- if (rel == NULL) +- return NULL; +- +- return isns_object_get(rel->ir_object); +-} +- +-/* +- * See if a relationship exists +- */ +-int +-isns_db_relation_exists(isns_db_t *db, +- const isns_object_t *relating_object, +- const isns_object_t *left, +- const isns_object_t *right, +- unsigned int relation_type) +-{ +- return isns_relation_exists(db->id_relations, +- relating_object, +- left, right, relation_type); +-} +- +-/* +- * Debug helper +- */ +-void +-isns_db_print(isns_db_t *db, isns_print_fn_t *fn) +-{ +- const isns_object_list_t *list = db->id_objects; +- unsigned int i; +- +- fn("Dumping database contents\n" +- "Backend: %s\n" +- "Last EID: %u\n" +- "Last Index: %u\n" +- , +- db->id_backend->idb_name, +- db->id_last_eid, +- db->id_last_index); +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- +- fn("--------------\n" +- "Object: index=%u type=<%s> state=%s", +- obj->ie_index, +- obj->ie_template->iot_name, +- isns_object_state_string(obj->ie_state)); +- if (obj->ie_container) +- fn(" parent=%u", obj->ie_container->ie_index); +- if (obj->ie_flags & ISNS_OBJECT_DIRTY) +- fn(" DIRTY"); +- if (obj->ie_flags & ISNS_OBJECT_PRIVATE) +- fn(" PRIVATE"); +- fn("\n"); +- isns_attr_list_print(&obj->ie_attrs, fn); +- } +-} +- +-/* +- * Generate a "random" entity identifier. This is used when +- * a DevAttrReg request does not specify an entity, and the +- * client's policy doesn't specify one either. +- */ +-const char * +-isns_db_generate_eid(isns_db_t *db, char *buf, size_t size) +-{ +- snprintf(buf, size, "isns.entity.%04d", db->id_last_eid); +- db->id_last_eid++; +- return buf; +-} +- +-/* +- * Highly primitive transaction handling. +- * This is really just a hack for the iSNS server code, +- * which wants to go along creating objects, and back out +- * if something goes wrong. +- */ +-void +-isns_db_begin_transaction(isns_db_t *db) +-{ +- if (db->id_in_transaction) { +- isns_error("isns_db_begin_transaction: running into pending transaction\n"); +- isns_db_rollback(db); +- } +- db->id_in_transaction = 1; +-} +- +-void +-isns_db_commit(isns_db_t *db) +-{ +- /* Nothing yet */ +- db->id_in_transaction = 0; +-} +- +-void +-isns_db_rollback(isns_db_t *db) +-{ +- /* Nothing yet */ +- db->id_in_transaction = 0; +-} +diff --git a/utils/open-isns/db.h b/utils/open-isns/db.h +deleted file mode 100644 +index 148d930..0000000 +--- a/utils/open-isns/db.h ++++ /dev/null +@@ -1,147 +0,0 @@ +-/* +- * iSNS object database +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#ifndef ISNS_DB_H +-#define ISNS_DB_H +- +-#include "attrs.h" +- +-typedef struct isns_db_backend isns_db_backend_t; +- +-/* +- * In-memory portion of object database. +- * Stable storage is provided by different +- * backends. +- */ +-struct isns_db { +- isns_object_list_t * id_objects; +- isns_object_list_t __id_objects; +- +- isns_relation_soup_t * id_relations; +- +- uint32_t id_last_eid; +- uint32_t id_last_index; +- +- isns_scope_t * id_global_scope; +- isns_scope_t * id_default_scope; +- +- isns_db_backend_t * id_backend; +- +- unsigned int id_in_transaction : 1; +- struct isns_db_trans * id_transact; +- +- /* This is for objects in limbo. When a client +- * calls DevAttrDereg, the object will first be +- * placed on the id_deferred list. +- * When we're done processing the message, we +- * invoke isns_db_purge, which looks at these +- * objects. +- * - if the reference count is 1, the object +- * is deleted. +- * - otherwise, we assume the object is referenced +- * by a discovery domain. In this case, we prune +- * the attribute list down to the key attr(s) +- * plus the index attribute, and move it to +- * the id_limbo list. +- */ +- isns_object_list_t id_deferred; +- isns_object_list_t id_limbo; +-}; +- +- +-struct isns_db_backend { +- char * idb_name; +- +- int (*idb_reload)(isns_db_t *); +- int (*idb_sync)(isns_db_t *); +- int (*idb_store)(isns_db_t *, +- const isns_object_t *); +- int (*idb_remove)(isns_db_t *, +- const isns_object_t *); +-}; +- +-extern isns_db_backend_t *isns_create_file_db_backend(const char *); +-extern isns_object_t * __isns_db_get_next(const isns_object_list_t *, +- isns_object_template_t *, +- const isns_attr_list_t *, +- const isns_attr_list_t *); +- +-extern isns_relation_soup_t *isns_relation_soup_alloc(void); +-extern isns_relation_t *isns_create_relation(isns_object_t *relating_object, +- unsigned int relation_type, +- isns_object_t *subordinate_object1, +- isns_object_t *subordinate_object2); +-extern void isns_relation_sever(isns_relation_t *); +-extern void isns_relation_release(isns_relation_t *); +-extern void isns_relation_add(isns_relation_soup_t *, +- isns_relation_t *); +-extern void isns_relation_remove(isns_relation_soup_t *, +- isns_relation_t *); +-extern isns_object_t * isns_relation_get_other(const isns_relation_t *, +- const isns_object_t *); +-extern isns_relation_t *isns_relation_find_edge(isns_relation_soup_t *, +- const isns_object_t *, +- const isns_object_t *, +- unsigned int); +-extern void isns_relation_halfspace(isns_relation_soup_t *, +- const isns_object_t *, +- unsigned int, +- isns_object_list_t *); +-extern void isns_relation_get_edge_objects(isns_relation_soup_t *, +- const isns_object_t *, +- unsigned int, +- isns_object_list_t *); +-extern int isns_relation_exists(isns_relation_soup_t *, +- const isns_object_t *relating_object, +- const isns_object_t *left, +- const isns_object_t *right, +- unsigned int relation_type); +-extern int isns_relation_is_dead(const isns_relation_t *); +- +-extern void isns_db_create_relation(isns_db_t *db, +- isns_object_t *relating_object, +- unsigned int relation_type, +- isns_object_t *subordinate_object1, +- isns_object_t *subordinate_object2); +-extern void isns_db_get_relationship_objects(isns_db_t *, +- const isns_object_t *, +- unsigned int relation_type, +- isns_object_list_t *); +-extern isns_object_t * isns_db_get_relationship_object(isns_db_t *, +- const isns_object_t *, +- const isns_object_t *, +- unsigned int relation_type); +-extern int isns_db_relation_exists(isns_db_t *db, +- const isns_object_t *relating_object, +- const isns_object_t *left, +- const isns_object_t *right, +- unsigned int relation_type); +-extern int isns_db_create_pg_relation(isns_db_t *, +- isns_object_t *); +- +-extern isns_scope_t * isns_scope_for_call(isns_db_t *, const isns_simple_t *); +-extern isns_scope_t * isns_scope_alloc(isns_db_t *); +-extern void isns_scope_release(isns_scope_t *); +-extern void isns_scope_add(isns_scope_t *, +- isns_object_t *); +-extern int isns_scope_remove(isns_scope_t *, +- isns_object_t *); +-extern int isns_scope_gang_lookup(isns_scope_t *, +- isns_object_template_t *, +- const isns_attr_list_t *, +- isns_object_list_t *); +-extern isns_object_t * isns_scope_get_next(isns_scope_t *, +- isns_object_template_t *, +- const isns_attr_list_t *current, +- const isns_attr_list_t *scope); +-extern void isns_scope_get_related(isns_scope_t *, +- const isns_object_t *, +- unsigned int, +- isns_object_list_t *); +-extern isns_db_t * isns_scope_get_db(const isns_scope_t *); +- +- +-#endif /* ISNS_DB_H */ +diff --git a/utils/open-isns/dd.c b/utils/open-isns/dd.c +deleted file mode 100644 +index b392036..0000000 +--- a/utils/open-isns/dd.c ++++ /dev/null +@@ -1,1307 +0,0 @@ +-/* +- * Handle DD registration/deregistration +- * +- * Discovery domains are weird, even in the context of +- * iSNS. For once thing, all other objects have unique +- * attributes; DDs attributes can appear several times. +- * They should really have made each DD member an object +- * in its own right. +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include "isns.h" +-#include "attrs.h" +-#include "objects.h" +-#include "message.h" +-#include "security.h" +-#include "util.h" +-#include "db.h" +- +-#define DD_DEBUG +- +-enum { +- ISNS_DD_MEMBER_ISCSI_NODE = 1, +- ISNS_DD_MEMBER_IFCP_NODE, +- ISNS_DD_MEMBER_PORTAL, +-}; +-/* Must be zero/one: */ +-enum { +- NOTIFY_MEMBER_ADDED = 0, +- NOTIFY_MEMBER_REMOVED = 1 +-}; +- +-typedef struct isns_dd isns_dd_t; +-typedef struct isns_dd_list isns_dd_list_t; +-typedef struct isns_dd_member isns_dd_member_t; +- +-struct isns_dd { +- uint32_t dd_id; +- char * dd_name; +- uint32_t dd_features; +- isns_dd_member_t * dd_members; +- +- unsigned int dd_inserted : 1; +- +- isns_object_t * dd_object; +-}; +- +-struct isns_dd_member { +- isns_dd_member_t * ddm_next; +- unsigned int ddm_type; +- isns_object_ref_t ddm_object; +- +- unsigned int ddm_added : 1; +- union { +- uint32_t ddm_index; +- +- /* Index must be first in all structs below. +- * Yeah, I know. Aliasing is bad. */ +- struct isns_dd_portal { +- uint32_t index; +- isns_portal_info_t info; +- } ddm_portal; +- struct isns_dd_iscsi_node { +- uint32_t index; +- char * name; +- } ddm_iscsi_node; +- struct isns_dd_ifcp_node { +- uint32_t index; +- char * name; +- } ddm_ifcp_node; +- }; +-}; +- +-struct isns_dd_list { +- unsigned int ddl_count; +- isns_dd_t ** ddl_data; +-}; +- +-/* +- * List of all discovery domains. +- * This duplicates the DD information from the database, +- * but unfortunately this can't be helped - we need to +- * have fast algorithms to compute the membership of a +- * node, and the relative visibility of two nodes. +- */ +-static int isns_dd_list_initialized = 0; +-static isns_dd_list_t isns_dd_list; +-static uint32_t isns_dd_next_id = 1; +- +-static isns_dd_t * isns_dd_alloc(void); +-static isns_dd_t * isns_dd_clone(const isns_dd_t *); +-static void isns_dd_release(isns_dd_t *); +-static int isns_dd_parse_attrs(isns_dd_t *, +- isns_db_t *, const isns_attr_list_t *, +- const isns_dd_t *, int); +-static int isns_dd_remove_members(isns_dd_t *, +- isns_db_t *, +- isns_dd_t *); +-static void isns_dd_notify(const isns_dd_t *, +- isns_dd_member_t *, +- isns_dd_member_t *, +- int); +-static void isns_dd_add_members(isns_dd_t *, +- isns_db_t *, +- isns_dd_t *); +-static void isns_dd_store(isns_db_t *, const isns_dd_t *, int); +-static void isns_dd_destroy(isns_db_t *, isns_dd_t *); +-static void isns_dd_insert(isns_dd_t *); +-static isns_dd_t * isns_dd_by_id(uint32_t); +-static isns_dd_t * isns_dd_by_name(const char *); +-static isns_dd_member_t * isns_dd_create_member(isns_object_t *); +-static inline void isns_dd_member_free(isns_dd_member_t *); +-static int isns_dd_remove_member(isns_dd_t *, isns_object_t *); +-static void isns_dd_list_resize(isns_dd_list_t *, unsigned int); +-static void isns_dd_list_insert(isns_dd_list_t *, isns_dd_t *); +-static void isns_dd_list_remove(isns_dd_list_t *, isns_dd_t *); +- +-static isns_object_t * isns_dd_get_member_object(isns_db_t *, +- const isns_attr_t *, const isns_attr_t *, +- int); +- +-/* +- * Create DDReg messages +- */ +-isns_simple_t * +-isns_create_dd_registration(isns_client_t *clnt, const isns_attr_list_t *attrs) +-{ +- isns_simple_t *msg; +- isns_attr_t *id_attr; +- +- msg = isns_simple_create(ISNS_DD_REGISTER, clnt->ic_source, NULL); +- if (msg == NULL) +- return NULL; +- +- /* If the caller specified a DD_ID, use it in the +- * message key. */ +- if (isns_attr_list_get_attr(attrs, ISNS_TAG_DD_ID, &id_attr)) +- isns_attr_list_append_attr(&msg->is_message_attrs, id_attr); +- +- isns_attr_list_copy(&msg->is_operating_attrs, attrs); +- return msg; +-} +- +-isns_simple_t * +-isns_create_dd_deregistration(isns_client_t *clnt, +- uint32_t dd_id, const isns_attr_list_t *attrs) +-{ +- isns_simple_t *msg; +- +- msg = isns_simple_create(ISNS_DD_DEREGISTER, clnt->ic_source, NULL); +- if (msg == NULL) +- return NULL; +- +- isns_attr_list_append_uint32(&msg->is_message_attrs, +- ISNS_TAG_DD_ID, dd_id); +- +- isns_attr_list_copy(&msg->is_operating_attrs, attrs); +- return msg; +-} +- +-/* +- * Process a DD registration +- */ +-int +-isns_process_dd_registration(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) +-{ +- isns_simple_t *reply = NULL; +- isns_attr_list_t *keys = &call->is_message_attrs; +- isns_attr_list_t *attrs = &call->is_operating_attrs; +- isns_db_t *db = srv->is_db; +- isns_dd_t *dd = NULL, *temp_dd = NULL; +- isns_attr_t *attr; +- uint32_t id = 0; +- int status; +- +- /* +- * 5.6.5.9. +- * The Message Key, if used, contains the DD_ID of the Discovery +- * Domain to be registered. If the Message Key contains a DD_ID +- * of an existing DD entry in the iSNS database, then the DDReg +- * message SHALL attempt to update the existing entry. If the +- * DD_ID in the Message Key (if used) does not match an existing +- * DD entry, then the iSNS server SHALL reject the DDReg message +- * with a status code of 3 (Invalid Registration). +- */ +- switch (keys->ial_count) { +- case 0: +- /* Security: check if the client is allowed to +- * create a discovery domain */ +- if (!isns_policy_validate_object_creation(call->is_policy, +- call->is_source, +- &isns_dd_template, +- keys, attrs, +- call->is_function)) +- goto unauthorized; +- break; +- +- case 1: +- attr = keys->ial_data[0]; +- if (attr->ia_tag_id != ISNS_TAG_DD_ID) +- goto reject; +- if (ISNS_ATTR_IS_NIL(attr)) +- break; +- if (!ISNS_ATTR_IS_UINT32(attr)) +- goto reject; +- +- id = attr->ia_value.iv_uint32; +- if (id == 0) +- goto reject; +- +- dd = isns_dd_by_id(id); +- if (dd == NULL) { +- isns_debug_state("DDReg for unknown ID=%u\n", id); +- goto reject; +- } +- +- /* Security: check if the client is allowed to +- * mess with this DD. */ +- isns_assert(dd->dd_object); +- if (!isns_policy_validate_object_update(call->is_policy, +- call->is_source, +- dd->dd_object, attrs, +- call->is_function)) +- goto unauthorized; +- +- break; +- +- default: +- goto reject; +- } +- +- temp_dd = isns_dd_alloc(); +- +- /* Parse the attributes and build a DD object. */ +- status = isns_dd_parse_attrs(temp_dd, db, attrs, dd, 1); +- if (status != ISNS_SUCCESS) +- goto out; +- +- if (dd == NULL) { +- /* Create the DD, and copy the general information +- * such asn features and symbolic name from temp_dd */ +- dd = isns_dd_clone(temp_dd); +- +- /* Don't assign the attrs to the DD right away. +- * First and foremost, they may be unsorted. Second, +- * we really want to hand-pick through them due to +- * the weird semantics mandated by the RFC. */ +- dd->dd_object = isns_create_object(&isns_dd_template, NULL, NULL); +- if (dd->dd_object == NULL) +- goto reject; +- +- /* Insert new domain into database */ +- isns_db_insert(db, dd->dd_object); +- +- /* Add it to the internal list. Assign DD_ID and +- * symbolic name if none were given. +- */ +- isns_dd_insert(dd); +- } else { +- if (!dd->dd_id) +- dd->dd_id = temp_dd->dd_id; +- dd->dd_features = temp_dd->dd_features; +- isns_assign_string(&dd->dd_name, temp_dd->dd_name); +- } +- +- /* Send notifications. This must be done before merging +- * the list of new members into the DD. +- */ +- isns_dd_notify(dd, dd->dd_members, temp_dd->dd_members, +- NOTIFY_MEMBER_ADDED); +- +- /* Update the DD */ +- isns_dd_add_members(dd, db, temp_dd); +- +- /* And add it to the database. */ +- isns_dd_store(db, dd, 0); +- +- reply = isns_simple_create(ISNS_DD_REGISTER, srv->is_source, NULL); +- isns_object_extract_all(dd->dd_object, &reply->is_operating_attrs); +- +- status = ISNS_SUCCESS; +- +-out: +- isns_dd_release(temp_dd); +- isns_dd_release(dd); +- *result = reply; +- return status; +- +-reject: +- status = ISNS_INVALID_REGISTRATION; +- goto out; +- +-unauthorized: +- status = ISNS_SOURCE_UNAUTHORIZED; +- goto out; +-} +- +-/* +- * Process a DD deregistration +- */ +-int +-isns_process_dd_deregistration(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) +-{ +- isns_simple_t *reply = NULL; +- isns_attr_list_t *keys = &call->is_message_attrs; +- isns_attr_list_t *attrs = &call->is_operating_attrs; +- isns_db_t *db = srv->is_db; +- isns_dd_t *dd = NULL, *temp_dd = NULL; +- isns_attr_t *attr; +- uint32_t id = 0; +- int status; +- +- /* +- * 5.6.5.10. +- * The Message Key Attribute for a DDDereg message is the DD +- * ID for the Discovery Domain being removed or having members +- * removed. +- */ +- if (keys->ial_count != 1) +- goto reject; +- +- attr = keys->ial_data[0]; +- if (attr->ia_tag_id != ISNS_TAG_DD_ID +- || ISNS_ATTR_IS_NIL(attr) +- || !ISNS_ATTR_IS_UINT32(attr)) +- goto reject; +- +- id = attr->ia_value.iv_uint32; +- if (id == 0) +- goto reject; +- +- dd = isns_dd_by_id(id); +- if (dd == NULL) +- goto reject; +- +- /* Security: check if the client is permitted to +- * modify the DD object. +- */ +- if (!isns_policy_validate_object_update(call->is_policy, +- call->is_source, +- dd->dd_object, attrs, +- call->is_function)) +- goto unauthorized; +- +- /* +- * 5.6.5.10. +- * If the DD ID matches an existing DD and there are +- * no Operating Attributes, then the DD SHALL be removed and a +- * success Status Code returned. Any existing members of that +- * DD SHALL remain in the iSNS database without membership in +- * the just-removed DD. +- */ +- if (attrs->ial_count == 0) { +- isns_dd_member_t *mp; +- +- /* Zap the membership bit */ +- for (mp = dd->dd_members; mp; mp = mp->ddm_next) { +- isns_object_t *obj = mp->ddm_object.obj; +- +- isns_object_clear_membership(obj, dd->dd_id); +- } +- +- /* Notify all DD members that they will lose the other +- * nodes. */ +- isns_dd_notify(dd, NULL, dd->dd_members, NOTIFY_MEMBER_REMOVED); +- +- isns_dd_destroy(db, dd); +- } else { +- /* Parse the attributes and build a temporary DD object. */ +- temp_dd = isns_dd_alloc(); +- status = isns_dd_parse_attrs(temp_dd, db, attrs, dd, 0); +- if (status != ISNS_SUCCESS) +- goto out; +- +- /* Update the DD object */ +- status = isns_dd_remove_members(dd, db, temp_dd); +- if (status != ISNS_SUCCESS) +- goto out; +- +- /* Send notifications. This must be done before after +- * updating the DD. +- */ +- isns_dd_notify(dd, dd->dd_members, temp_dd->dd_members, +- NOTIFY_MEMBER_REMOVED); +- +- /* Store it in the database. */ +- isns_dd_store(db, dd, 1); +- } +- +- reply = isns_simple_create(ISNS_DD_DEREGISTER, srv->is_source, NULL); +- status = ISNS_SUCCESS; +- +-out: +- isns_dd_release(temp_dd); +- isns_dd_release(dd); +- *result = reply; +- return status; +- +-reject: +- status = ISNS_INVALID_DEREGISTRATION; +- goto out; +- +-unauthorized: +- status = ISNS_SOURCE_UNAUTHORIZED; +- goto out; +-} +- +-static isns_dd_t * +-isns_dd_alloc(void) +-{ +- return isns_calloc(1, sizeof(isns_dd_t)); +-} +- +-/* +- * Allocate a clone of the orig_dd, but without +- * copying the members. +- */ +-static isns_dd_t * +-isns_dd_clone(const isns_dd_t *orig_dd) +-{ +- isns_dd_t *dd; +- +- dd = isns_dd_alloc(); +- +- dd->dd_id = orig_dd->dd_id; +- dd->dd_features = orig_dd->dd_features; +- dd->dd_object = isns_object_get(orig_dd->dd_object); +- isns_assign_string(&dd->dd_name, orig_dd->dd_name); +- +- return dd; +-} +- +-static void +-isns_dd_release(isns_dd_t *dd) +-{ +- isns_dd_member_t *member; +- +- if (dd == NULL || dd->dd_inserted) +- return; +- +- while ((member = dd->dd_members) != NULL) { +- dd->dd_members = member->ddm_next; +- isns_dd_member_free(member); +- } +- +- if (dd->dd_object) +- isns_object_release(dd->dd_object); +- +- isns_free(dd->dd_name); +- isns_free(dd); +-} +- +-static isns_dd_member_t * +-isns_dd_create_member(isns_object_t *obj) +-{ +- isns_dd_member_t *new; +- +- new = isns_calloc(1, sizeof(*new)); +- new->ddm_added = 1; +- +- if (ISNS_IS_ISCSI_NODE(obj)) +- new->ddm_type = ISNS_DD_MEMBER_ISCSI_NODE; +- else if (ISNS_IS_PORTAL(obj)) +- new->ddm_type = ISNS_DD_MEMBER_PORTAL; +- else if (ISNS_IS_FC_NODE(obj)) +- new->ddm_type = ISNS_DD_MEMBER_IFCP_NODE; +- else { +- isns_free(new); +- return NULL; +- } +- +- isns_object_reference_set(&new->ddm_object, obj); +- return new; +-} +- +-static inline void +-isns_dd_member_free(isns_dd_member_t *member) +-{ +- switch (member->ddm_type) { +- case ISNS_DD_MEMBER_ISCSI_NODE: +- isns_free(member->ddm_iscsi_node.name); +- break; +- +- case ISNS_DD_MEMBER_IFCP_NODE: +- isns_free(member->ddm_ifcp_node.name); +- break; +- } +- +- isns_object_reference_drop(&member->ddm_object); +- isns_free(member); +-} +- +-void +-isns_dd_get_members(uint32_t dd_id, isns_object_list_t *list, int active_only) +-{ +- isns_dd_t *dd; +- isns_dd_member_t *mp; +- +- dd = isns_dd_by_id(dd_id); +- if (dd == NULL) +- return; +- +- for (mp = dd->dd_members; mp; mp = mp->ddm_next) { +- isns_object_t *obj = mp->ddm_object.obj; +- +- if (active_only +- && obj->ie_state != ISNS_OBJECT_STATE_MATURE) +- continue; +- +- isns_object_list_append(list, obj); +- } +-} +- +-/* +- * Helper function to remove a member referencing the given object +- */ +-static int +-isns_dd_remove_member(isns_dd_t *dd, isns_object_t *obj) +-{ +- isns_dd_member_t *mp, **pos; +- +- pos = &dd->dd_members; +- while ((mp = *pos) != NULL) { +- if (mp->ddm_object.obj == obj) { +- *pos = mp->ddm_next; +- isns_dd_member_free(mp); +- return 1; +- } else { +- pos = &mp->ddm_next; +- } +- } +- +- return 0; +-} +- +-static void +-isns_dd_insert(isns_dd_t *dd) +-{ +- if (dd->dd_inserted) +- return; +- +- if (dd->dd_id == 0) { +- uint32_t id = isns_dd_next_id; +- unsigned int i; +- +- for (i = 0; i < isns_dd_list.ddl_count; ++i) { +- isns_dd_t *cur = isns_dd_list.ddl_data[i]; +- +- if (cur->dd_id > id) +- break; +- if (cur->dd_id == id) +- ++id; +- } +- isns_debug_state("Allocated new DD_ID %d\n", id); +- dd->dd_id = id; +- isns_dd_next_id = id + 1; +- } +- +- /* +- * When creating a new DD, if the DD_Symbolic_Name is +- * not included in the Operating Attributes, or if it +- * is included with a zero-length TLV, then the iSNS +- * server SHALL provide a unique DD_Symbolic_Name value +- * for the created DD. The assigned DD_Symbolic_Name +- * value SHALL be returned in the DDRegRsp message. +- */ +- if (dd->dd_name == NULL) { +- char namebuf[64]; +- +- snprintf(namebuf, sizeof(namebuf), "isns.dd%u", dd->dd_id); +- isns_assign_string(&dd->dd_name, namebuf); +- } +- +- isns_dd_list_insert(&isns_dd_list, dd); +- dd->dd_inserted = 1; +- +-#ifdef DD_DEBUG +- /* Safety first - make sure domains are sorted by DD_ID */ +- { +- unsigned int i, prev_id = 0; +- +- for (i = 0; i < isns_dd_list.ddl_count; ++i) { +- isns_dd_t *cur = isns_dd_list.ddl_data[i]; +- +- isns_assert(cur->dd_id > prev_id); +- prev_id = cur->dd_id; +- } +- } +-#endif +-} +- +-/* +- * Resize the DD list +- */ +-#define LIST_SIZE(n) (((n) + 15) & ~15) +-void +-isns_dd_list_resize(isns_dd_list_t *list, unsigned int last_index) +-{ +- unsigned int new_size, cur_size; +- isns_dd_t **new_data; +- +- cur_size = LIST_SIZE(list->ddl_count); +- new_size = LIST_SIZE(last_index + 1); +- if (new_size < list->ddl_count) +- return; +- +- /* We don't use realloc here because we need +- * to zero the new pointers anyway. */ +- new_data = isns_calloc(new_size, sizeof(void *)); +- isns_assert(new_data); +- +- memcpy(new_data, list->ddl_data, +- list->ddl_count * sizeof(void *)); +- isns_free(list->ddl_data); +- +- list->ddl_data = new_data; +- list->ddl_count = last_index + 1; +-} +- +-/* +- * Find the insert position for a given DD ID. +- * returns true iff the DD was found in the list. +- */ +-static int +-__isns_dd_list_find_pos(isns_dd_list_t *list, unsigned int id, +- unsigned int *where) +-{ +- unsigned int hi, lo, md; +- +- lo = 0; +- hi = list->ddl_count; +- +- /* binary search */ +- while (lo < hi) { +- isns_dd_t *cur; +- +- md = (lo + hi) / 2; +- cur = list->ddl_data[md]; +- +- if (id == cur->dd_id) { +- *where = md; +- return 1; +- } +- +- if (id < cur->dd_id) { +- hi = md; +- } else { +- lo = md + 1; +- } +- } +- +- *where = hi; +- return 0; +-} +- +-/* +- * In-order insert +- */ +-static void +-isns_dd_list_insert(isns_dd_list_t *list, isns_dd_t *dd) +-{ +- unsigned int pos; +- +- if (__isns_dd_list_find_pos(list, dd->dd_id, &pos)) { +- isns_error("Internal error in %s: DD already listed\n", +- __FUNCTION__); +- return; +- } +- +- isns_dd_list_resize(list, list->ddl_count); +- /* Shift the tail of the list to make room for new entry. */ +- memmove(list->ddl_data + pos + 1, +- list->ddl_data + pos, +- (list->ddl_count - pos - 1) * sizeof(void *)); +- list->ddl_data[pos] = dd; +-} +- +-/* +- * Remove DD from list +- */ +-void +-isns_dd_list_remove(isns_dd_list_t *list, isns_dd_t *dd) +-{ +- unsigned int pos; +- +- if (!__isns_dd_list_find_pos(list, dd->dd_id, &pos)) +- return; +- +- /* Shift the tail of the list */ +- memmove(list->ddl_data + pos, +- list->ddl_data + pos + 1, +- (list->ddl_count - pos - 1) * sizeof(void *)); +- list->ddl_count -= 1; +-} +- +-isns_dd_t * +-isns_dd_by_id(uint32_t id) +-{ +- unsigned int i; +- +- for (i = 0; i < isns_dd_list.ddl_count; ++i) { +- isns_dd_t *dd = isns_dd_list.ddl_data[i]; +- +- if (dd && dd->dd_id == id) +- return dd; +- } +- +- return NULL; +-} +- +-static isns_dd_t * +-isns_dd_by_name(const char *name) +-{ +- unsigned int i; +- +- for (i = 0; i < isns_dd_list.ddl_count; ++i) { +- isns_dd_t *dd = isns_dd_list.ddl_data[i]; +- +- if (dd && !strcmp(dd->dd_name, name)) +- return dd; +- } +- +- return NULL; +-} +- +-/* +- * Validate the operating attributes, which is surprisingly +- * tedious for DDs. It appears as if the whole DD/DDset +- * stuff has been slapped onto iSNS as an afterthought. +- * +- * DDReg has some funky rules about how eg iSCSI nodes +- * can be identified by either name or index, and how they +- * relate to each other. Unfortunately, the RFC is very vague +- * in describing how to treat DDReg message that mix these +- * two types of identification, except by saying they +- * need to be consistent. +- */ +-static int +-isns_dd_parse_attrs(isns_dd_t *dd, isns_db_t *db, +- const isns_attr_list_t *attrs, +- const isns_dd_t *orig_dd, +- int is_registration) +-{ +- isns_dd_member_t **tail; +- const isns_dd_t *conflict; +- unsigned int i; +- int rv = ISNS_SUCCESS; +- +- if (orig_dd) { +- dd->dd_id = orig_dd->dd_id; +- dd->dd_features = orig_dd->dd_features; +- isns_assign_string(&dd->dd_name, orig_dd->dd_name); +- } +- +- isns_assert(dd->dd_members == NULL); +- tail = &dd->dd_members; +- +- for (i = 0; i < attrs->ial_count; ++i) { +- isns_object_t *obj = NULL; +- isns_attr_t *attr, *next = NULL; +- const char *name; +- uint32_t id; +- +- attr = attrs->ial_data[i]; +- +- if (!isns_object_attr_valid(&isns_dd_template, attr->ia_tag_id)) +- return ISNS_INVALID_REGISTRATION; +- +- switch (attr->ia_tag_id) { +- case ISNS_TAG_DD_ID: +- /* Ignore this attribute in DDDereg messages */ +- if (!is_registration) +- continue; +- +- /* +- * 5.6.5.9. +- * A DDReg message with no Message Key SHALL result +- * in the attempted creation of a new Discovery Domain +- * (DD). If the DD_ID attribute (with non-zero length) +- * is included among the Operating Attributes in the +- * DDReg message, then the new Discovery Domain SHALL be +- * assigned the value contained in that DD_ID attribute. +- * +- * If the DD_ID is included in both the Message +- * Key and Operating Attributes, then the DD_ID +- * value in the Message Key MUST be the same as +- * the DD_ID value in the Operating Attributes. +- * +- * Implementer's note: It's not clear why the standard +- * makes an exception for the DD_ID, while all other +- * index attributes are read-only. +- */ +- if (ISNS_ATTR_IS_NIL(attr)) +- break; +- +- id = attr->ia_value.iv_uint32; +- if (dd->dd_id != 0) { +- if (dd->dd_id != id) +- goto invalid; +- } else if ((conflict = isns_dd_by_id(id)) != NULL) { +- isns_debug_state("DDReg: requested ID %d " +- "clashes with existing DD (%s)\n", +- id, conflict->dd_name); +- goto invalid; +- } +- dd->dd_id = id; +- break; +- +- case ISNS_TAG_DD_SYMBOLIC_NAME: +- /* Ignore this attribute in DDDereg messages */ +- if (!is_registration) +- continue; +- +- /* +- * If the DD_Symbolic_Name is an operating +- * attribute and its value is unique (i.e., it +- * does not match the registered DD_Symbolic_Name +- * for another DD), then the value SHALL be stored +- * in the iSNS database as the DD_Symbolic_Name +- * for the specified Discovery Domain. If the +- * value for the DD_Symbolic_Name is not unique, +- * then the iSNS server SHALL reject the attempted +- * DD registration with a status code of 3 +- * (Invalid Registration). +- */ +- if (ISNS_ATTR_IS_NIL(attr)) +- break; +- +- name = attr->ia_value.iv_string; +- if (dd->dd_name && strcmp(name, dd->dd_name)) { +- isns_debug_state("DDReg: symbolic name conflict: " +- "id=%d name=%s requested=%s\n", +- dd->dd_id, dd->dd_name, name); +- goto invalid; +- } +- if (dd->dd_name) +- break; +- +- if ((conflict = isns_dd_by_name(name)) != NULL) { +- isns_debug_state("DDReg: requested symbolic name (%s) " +- "clashes with existing DD (id=%d)\n", +- name, conflict->dd_id); +- goto invalid; +- } +- isns_assign_string(&dd->dd_name, name); +- break; +- +- case ISNS_TAG_DD_FEATURES: +- /* Ignore this attribute in DDDereg messages */ +- if (!is_registration) +- continue; +- +- /* +- * When creating a new DD, if the DD_Features +- * attribute is not included in the Operating +- * Attributes, then the iSNS server SHALL assign +- * the default value. The default value for +- * DD_Features is 0. +- */ +- if (ISNS_ATTR_IS_UINT32(attr)) +- dd->dd_features = attr->ia_value.iv_uint32; +- break; +- +- case ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR: +- /* portal address must be followed by port */ +- if (i + 1 >= attrs->ial_count) +- goto invalid; +- +- next = attrs->ial_data[i + 1]; +- if (next->ia_tag_id != ISNS_TAG_DD_MEMBER_PORTAL_TCP_UDP_PORT) +- goto invalid; +- i += 1; +- /* fallthru to normal case */ +- +- case ISNS_TAG_DD_MEMBER_PORTAL_INDEX: +- case ISNS_TAG_DD_MEMBER_ISCSI_INDEX: +- case ISNS_TAG_DD_MEMBER_ISCSI_NAME: +- case ISNS_TAG_DD_MEMBER_FC_PORT_NAME: +- if (ISNS_ATTR_IS_NIL(attr)) +- goto invalid; +- +- obj = isns_dd_get_member_object(db, +- attr, next, +- is_registration); +- /* For a DD deregistration, it's okay if the +- * object does not exist. */ +- if (obj == NULL && is_registration) +- goto invalid; +- break; +- +- invalid: +- rv = ISNS_INVALID_REGISTRATION; +- continue; +- +- } +- +- if (obj) { +- if (is_registration +- && isns_object_test_membership(obj, dd->dd_id)) { +- /* Duplicates are ignored */ +- isns_debug_state("Ignoring duplicate DD registration " +- "for %s %u\n", +- obj->ie_template->iot_name, +- obj->ie_index); +- } else { +- /* This just adds the member to the temporary DD object, +- * without changing any state in the database. */ +- isns_dd_member_t *new; +- +- new = isns_dd_create_member(obj); +- if (new) { +- *tail = new; +- tail = &new->ddm_next; +- } +- } +- isns_object_release(obj); +- } +- } +- +- return rv; +-} +- +-/* +- * Helper function: extract live nodes from the DD member list +- */ +-static inline void +-isns_dd_get_member_nodes(isns_dd_member_t *members, isns_object_list_t *result) +-{ +- isns_dd_member_t *mp; +- +- /* Extract iSCSI nodes from both list. */ +- for (mp = members; mp; mp = mp->ddm_next) { +- isns_object_t *obj = mp->ddm_object.obj; +- +- if (ISNS_IS_ISCSI_NODE(obj) +- && obj->ie_state == ISNS_OBJECT_STATE_MATURE) +- isns_object_list_append(result, obj); +- } +-} +- +-void +-isns_dd_notify(const isns_dd_t *dd, isns_dd_member_t *unchanged, +- isns_dd_member_t *changed, int removed) +-{ +- isns_object_list_t dd_objects = ISNS_OBJECT_LIST_INIT; +- isns_object_list_t changed_objects = ISNS_OBJECT_LIST_INIT; +- unsigned int i, j, event; +- +- /* Extract iSCSI nodes from both list. */ +- isns_dd_get_member_nodes(unchanged, &dd_objects); +- isns_dd_get_member_nodes(changed, &changed_objects); +- +- /* Send a management SCN multicast to all +- * control nodes that care. */ +- event = removed? ISNS_SCN_DD_MEMBER_REMOVED_MASK : ISNS_SCN_DD_MEMBER_ADDED_MASK; +- for (i = 0; i < changed_objects.iol_count; ++i) { +- isns_object_t *obj = changed_objects.iol_data[i]; +- +- isns_object_event(obj, +- event | ISNS_SCN_MANAGEMENT_REGISTRATION_MASK, +- dd->dd_object); +- } +- +-#ifdef notagoodidea +- /* Not sure - it may be good to send OBJECT ADDED/REMOVED instead +- * of the DD membership messages. However, right now the SCN code +- * will nuke all SCN registrations for a node when it sees a +- * REMOVE event for it. +- */ +- event = removed? ISNS_SCN_OBJECT_REMOVED_MASK : ISNS_SCN_OBJECT_ADDED_MASK; +-#endif +- +- /* If we added an iscsi node, loop over all members +- * and send unicast events to each iscsi node, +- * informing them that a new member has been added/removed. +- */ +- for (j = 0; j < changed_objects.iol_count; ++j) { +- isns_object_t *changed = changed_objects.iol_data[j]; +- +- for (i = 0; i < dd_objects.iol_count; ++i) { +- isns_object_t *obj = dd_objects.iol_data[i]; +- +- /* For member removal, do not send notifications +- * if the two nodes are still visible to each +- * other through a different discovery domain */ +- if (removed && isns_object_test_visibility(obj, changed)) +- continue; +- +- /* Inform the old node that the new node was +- * added/removed. */ +- isns_unicast_event(obj, changed, event, NULL); +- +- /* Inform the new node that the old node became +- * (in)accessible to it. */ +- isns_unicast_event(changed, obj, event, NULL); +- } +- +- /* Finally, inform each changed node of the other +- * DD members that became (in)accessible to it. */ +- for (i = 0; i < changed_objects.iol_count; ++i) { +- isns_object_t *obj = changed_objects.iol_data[i]; +- +- if (obj == changed) +- continue; +- +- if (removed && isns_object_test_visibility(obj, changed)) +- continue; +- +- isns_unicast_event(changed, obj, event, NULL); +- } +- } +-} +- +-void +-isns_dd_add_members(isns_dd_t *dd, isns_db_t *db, isns_dd_t *new_dd) +-{ +- isns_dd_member_t *mp, **tail; +- +- for (mp = new_dd->dd_members; mp; mp = mp->ddm_next) { +- const char *node_name; +- isns_object_t *obj = mp->ddm_object.obj; +- +- /* +- * If the Operating Attributes contain a DD +- * Member iSCSI Name value for a Storage Node +- * that is currently not registered in the iSNS +- * database, then the iSNS server MUST allocate an +- * unused iSCSI Node Index for that Storage Node. +- * The assigned iSCSI Node Index SHALL be returned +- * in the DDRegRsp message as the DD Member iSCSI +- * Node Index. The allocated iSCSI Node Index +- * value SHALL be assigned to the Storage Node +- * if and when it registers in the iSNS database. +- * [And likewise for portals] +- */ +- if (obj->ie_index == 0) +- isns_db_insert_limbo(db, obj); +- mp->ddm_index = obj->ie_index; +- +- /* Record the fact that the object is a member of +- * this DD */ +- isns_object_mark_membership(obj, dd->dd_id); +- +- switch (mp->ddm_type) { +- case ISNS_DD_MEMBER_ISCSI_NODE: +- if (isns_object_get_string(obj, ISNS_TAG_ISCSI_NAME, &node_name)) +- isns_assign_string(&mp->ddm_iscsi_node.name, node_name); +- +- break; +- +- case ISNS_DD_MEMBER_IFCP_NODE: +- if (isns_object_get_string(obj, ISNS_TAG_FC_PORT_NAME_WWPN, &node_name)) +- isns_assign_string(&mp->ddm_ifcp_node.name, node_name); +- +- break; +- +- case ISNS_DD_MEMBER_PORTAL: +- isns_portal_from_object(&mp->ddm_portal.info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- obj); +- break; +- } +- } +- +- /* Find the tail of the DD member list */ +- tail = &dd->dd_members; +- while ((mp = *tail) != NULL) +- tail = &mp->ddm_next; +- +- /* Append the new list of members */ +- *tail = new_dd->dd_members; +- new_dd->dd_members = NULL; +-} +- +-/* +- * Remove members from a DD +- */ +-int +-isns_dd_remove_members(isns_dd_t *dd, isns_db_t *db, isns_dd_t *temp_dd) +-{ +- isns_dd_member_t *mp; +- +- for (mp = temp_dd->dd_members; mp; mp = mp->ddm_next) { +- isns_object_t *obj = mp->ddm_object.obj; +- +- /* Clear the membership bit. If the object wasn't in this +- * DD to begin with, bail out right away. */ +- if (!isns_object_clear_membership(obj, dd->dd_id)) { +- isns_debug_state("DD dereg: object %d is not in this DD\n", +- obj->ie_index); +- continue; +- } +- +- if (!isns_dd_remove_member(dd, obj)) +- isns_error("%s: DD member not found in internal list\n", +- __FUNCTION__); +- } +- +- return ISNS_SUCCESS; +-} +- +-void +-isns_dd_store(isns_db_t *db, const isns_dd_t *dd, int rewrite) +-{ +- isns_object_t *obj = dd->dd_object; +- isns_dd_member_t *member; +- +- if (rewrite) +- isns_object_prune_attrs(obj); +- +- isns_object_set_uint32(obj, ISNS_TAG_DD_ID, dd->dd_id); +- isns_object_set_string(obj, ISNS_TAG_DD_SYMBOLIC_NAME, dd->dd_name); +- isns_object_set_uint32(obj, ISNS_TAG_DD_FEATURES, dd->dd_features); +- +- for (member = dd->dd_members; member; member = member->ddm_next) { +- struct isns_dd_iscsi_node *node; +- struct isns_dd_portal *portal; +- +- if (!member->ddm_added && !rewrite) +- continue; +- +- switch (member->ddm_type) { +- case ISNS_DD_MEMBER_ISCSI_NODE: +- node = &member->ddm_iscsi_node; +- +- isns_object_set_uint32(obj, +- ISNS_TAG_DD_MEMBER_ISCSI_INDEX, +- node->index); +- if (node->name) +- isns_object_set_string(obj, +- ISNS_TAG_DD_MEMBER_ISCSI_NAME, +- node->name); +- break; +- +- case ISNS_DD_MEMBER_PORTAL: +- portal = &member->ddm_portal; +- +- isns_object_set_uint32(obj, +- ISNS_TAG_DD_MEMBER_PORTAL_INDEX, +- portal->index); +- if (portal->info.addr.sin6_family != AF_UNSPEC) { +- isns_portal_to_object(&portal->info, +- ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR, +- ISNS_TAG_DD_MEMBER_PORTAL_TCP_UDP_PORT, +- obj); +- } +- break; +- } +- +- member->ddm_added = 0; +- } +-} +- +-/* +- * Destroy a DD +- * The caller should call isns_dd_release to free the DD object. +- */ +-void +-isns_dd_destroy(isns_db_t *db, isns_dd_t *dd) +-{ +- isns_db_remove(db, dd->dd_object); +- isns_dd_list_remove(&isns_dd_list, dd); +- dd->dd_inserted = 0; +-} +- +-int +-isns_dd_load_all(isns_db_t *db) +-{ +- isns_object_list_t list = ISNS_OBJECT_LIST_INIT; +- unsigned int i; +- int rc; +- +- if (isns_dd_list_initialized) +- return ISNS_SUCCESS; +- +- rc = isns_db_gang_lookup(db, &isns_dd_template, NULL, &list); +- if (rc != ISNS_SUCCESS) +- return rc; +- +- for (i = 0; i < list.iol_count; ++i) { +- isns_object_t *obj = list.iol_data[i]; +- isns_dd_t *dd = NULL, *temp_dd = NULL; +- isns_dd_member_t *mp; +- +- temp_dd = isns_dd_alloc(); +- +- rc = isns_dd_parse_attrs(temp_dd, db, &obj->ie_attrs, NULL, 1); +- if (rc) { +- if (temp_dd->dd_id == 0) { +- isns_error("Problem converting DD object (index 0x%x). No DD_ID\n", +- obj->ie_index); +- goto next; +- } +- isns_error("Problem converting DD %u. Proceeding anyway.\n", +- temp_dd->dd_id); +- } else { +- isns_debug_state("Loaded DD %d from database\n", temp_dd->dd_id); +- } +- +- dd = isns_dd_clone(temp_dd); +- +- dd->dd_object = isns_object_get(obj); +- +- isns_dd_insert(dd); +- isns_dd_add_members(dd, db, temp_dd); +- +- /* Clear the ddm_added flag for all members, to +- * prevent all information from being duplicated +- * to the DB on the next DD modification. */ +- for (mp = dd->dd_members; mp; mp = mp->ddm_next) +- mp->ddm_added = 0; +- +-next: +- isns_dd_release(temp_dd); +- } +- +- isns_object_list_destroy(&list); +- isns_dd_list_initialized = 1; +- return ISNS_SUCCESS; +-} +- +-isns_object_t * +-isns_dd_get_member_object(isns_db_t *db, const isns_attr_t *key1, +- const isns_attr_t *key2, +- int create) +-{ +- isns_attr_list_t query = ISNS_ATTR_LIST_INIT; +- isns_object_template_t *tmpl = NULL; +- isns_object_t *obj; +- isns_portal_info_t portal_info; +- const char *key_string = NULL; +- uint32_t key_index = 0; +- +- switch (key1->ia_tag_id) { +- case ISNS_TAG_DD_MEMBER_ISCSI_INDEX: +- key_index = key1->ia_value.iv_uint32; +- isns_attr_list_append_uint32(&query, +- ISNS_TAG_ISCSI_NODE_INDEX, +- key_index); +- tmpl = &isns_iscsi_node_template; +- break; +- +- case ISNS_TAG_DD_MEMBER_ISCSI_NAME: +- key_string = key1->ia_value.iv_string; +- isns_attr_list_append_string(&query, +- ISNS_TAG_ISCSI_NAME, +- key_string); +- tmpl = &isns_iscsi_node_template; +- break; +- +- case ISNS_TAG_DD_MEMBER_FC_PORT_NAME: +- key_string = key1->ia_value.iv_string; +- isns_attr_list_append_string(&query, +- ISNS_TAG_FC_PORT_NAME_WWPN, +- key_string); +- tmpl = &isns_fc_port_template; +- break; +- +- case ISNS_TAG_DD_MEMBER_PORTAL_INDEX: +- key_index = key1->ia_value.iv_uint32; +- isns_attr_list_append_uint32(&query, +- ISNS_TAG_PORTAL_INDEX, +- key_index); +- tmpl = &isns_portal_template; +- break; +- +- case ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR: +- if (!isns_portal_from_attr_pair(&portal_info, key1, key2) +- || !isns_portal_to_attr_list(&portal_info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- &query)) +- return NULL; +- +- key_string = isns_portal_string(&portal_info); +- tmpl = &isns_portal_template; +- break; +- +- default: +- return NULL; +- } +- +- obj = isns_db_lookup(db, tmpl, &query); +- if (!obj && create) { +- if (!key_string) { +- isns_debug_state("Attempt to register %s DD member " +- "with unknown index %u\n", +- tmpl->iot_name, key_index); +- goto out; +- } +- +- obj = isns_create_object(tmpl, &query, NULL); +- if (obj != NULL) +- isns_debug_state("Created limbo object for " +- "%s DD member %s\n", +- tmpl->iot_name, key_string); +- } +- +-out: +- isns_attr_list_destroy(&query); +- return obj; +- +-} +diff --git a/utils/open-isns/deregister.c b/utils/open-isns/deregister.c +deleted file mode 100644 +index 3a7b7a6..0000000 +--- a/utils/open-isns/deregister.c ++++ /dev/null +@@ -1,271 +0,0 @@ +-/* +- * Handle iSNS Device Deregistration +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include "isns.h" +-#include "attrs.h" +-#include "objects.h" +-#include "message.h" +-#include "security.h" +-#include "util.h" +-#include "db.h" +- +-extern isns_source_t * isns_server_source; +- +- +-/* +- * Create a registration, and set the source name +- */ +-static isns_simple_t * +-__isns_create_deregistration(isns_source_t *source, const isns_attr_list_t *attrs) +-{ +- isns_simple_t *simp; +- +- simp = isns_simple_create(ISNS_DEVICE_DEREGISTER, source, NULL); +- if (simp && attrs) +- isns_attr_list_copy(&simp->is_operating_attrs, attrs); +- return simp; +-} +- +-isns_simple_t * +-isns_create_deregistration(isns_client_t *clnt, const isns_attr_list_t *attrs) +-{ +- return __isns_create_deregistration(clnt->ic_source, attrs); +-} +- +-/* +- * Get the next object identified by the operating attrs. +- */ +-static int +-isns_deregistration_get_next_object(isns_db_t *db, +- struct isns_attr_list_scanner *st, +- isns_object_list_t *result) +-{ +- isns_object_t *current; +- int status; +- +- status = isns_attr_list_scanner_next(st); +- if (status) +- return status; +- +- /* +- * 5.6.5.4. +- * Valid Operating Attributes for DevDereg +- * --------------------------------------- +- * Entity Identifier +- * Portal IP-Address & Portal TCP/UDP Port +- * Portal Index +- * iSCSI Name +- * iSCSI Index +- * FC Port Name WWPN +- * FC Node Name WWNN +- * +- * In other words, deregistration is restricted to Entity, +- * portal, and node +- */ +- if (st->tmpl != &isns_entity_template +- && st->tmpl != &isns_iscsi_node_template +- && st->tmpl != &isns_portal_template) +- return ISNS_INVALID_DEREGISTRATION; +- +- /* Only key attrs allowed */ +- if (st->attrs.ial_count) { +- /* MS Initiators send the Entity protocol along +- * with the Entity Identifier. */ +- isns_debug_protocol("Client included invalid operating attrs " +- "with %s:\n", st->tmpl->iot_name); +- isns_attr_list_print(&st->attrs, isns_debug_protocol); +- /* return ISNS_INVALID_DEREGISTRATION; */ +- } +- +- /* +- * 5.6.5.4 +- * Attempted deregistration of non-existing entries SHALL not +- * be considered an isns_error. +- */ +- current = isns_db_lookup(db, st->tmpl, &st->keys); +- if (current != NULL) { +- isns_object_list_append(result, current); +- isns_object_release(current); +- } +- +- return ISNS_SUCCESS; +-} +- +-/* +- * Extract the list of objects to be deregistered from +- * the list of operating attributes. +- */ +-static int +-isns_deregistration_get_objects(isns_simple_t *reg, isns_db_t *db, +- isns_object_list_t *result) +-{ +- struct isns_attr_list_scanner state; +- int status = ISNS_SUCCESS; +- +- isns_attr_list_scanner_init(&state, NULL, ®->is_operating_attrs); +- state.index_acceptable = 1; +- state.source = reg->is_source; +- +- while (state.pos < state.orig_attrs.ial_count) { +- status = isns_deregistration_get_next_object(db, +- &state, result); +- +- if (status == 0) +- continue; +- +- /* Translate error codes */ +- if (status == ISNS_NO_SUCH_ENTRY) +- status = ISNS_SUCCESS; +- else +- if (status == ISNS_INVALID_REGISTRATION) +- status = ISNS_INVALID_DEREGISTRATION; +- break; +- } +- +- isns_attr_list_scanner_destroy(&state); +- return status; +-} +- +-/* +- * Process a deregistration +- * +- * Normally, you would expect that a deregistration removes the +- * object from the database, and that's the end of the story. +- * Unfortunately, someone added Discovery Domains to the protocol, +- * requiring _some_ information to survive as long as an object +- * is referenced by a discovery domain. Specifically, we need to +- * retain the relationship between key attributes (eg iscsi node +- * name) and the object index. +- * +- * Thus, deregistration consists of the following steps +- * - the object is removed from the database's global scope, +- * so that it's no longer visible to DB lookups. +- * +- * - the object is detached from its containing Network +- * Entity. +- * +- * - all attributes except the key attr(s) and the index +- * attribute are removed. +- */ +-int +-isns_process_deregistration(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) +-{ +- isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; +- isns_simple_t *reply = NULL; +- isns_db_t *db = srv->is_db; +- int status, dereg_status; +- unsigned int i; +- +- /* Get the objects to deregister */ +- status = isns_deregistration_get_objects(call, db, &objects); +- if (status != ISNS_SUCCESS) +- goto done; +- +- /* +- * 5.6.5.4 +- * +- * For messages that change the contents of the iSNS database, +- * the iSNS server MUST verify that the Source Attribute +- * identifies either a Control Node or a Storage Node that is +- * a part of the Network Entity containing the added, deleted, +- * or modified objects. +- */ +- /* +- * Implementation note: this can be implemented either by +- * explicitly checking the object's owner in isns_db_remove +- * (which is what we do right now), or by matching only +- * those objects that have the right owner anyway. +- * +- * The latter sounds like a better choice if the client +- * uses NIL attributes, because it limits the scope of +- * the operation; but then the RFC doesn't say whether +- * this kind of deregistration would be valid at all. +- */ +- +- /* Success: create a new simple message, and +- * send it in our reply. */ +- reply = __isns_create_deregistration(srv->is_source, NULL); +- if (reply == NULL) { +- status = ISNS_INTERNAL_ERROR; +- goto done; +- } +- +- dereg_status = ISNS_SUCCESS; +- for (i = 0; i < objects.iol_count; ++i) { +- isns_object_t *obj = objects.iol_data[i]; +- +- /* Policy: check that the client is permitted +- * to deregister this object */ +- if (!isns_policy_validate_object_access(call->is_policy, +- call->is_source, obj, +- call->is_function)) +- status = ISNS_SOURCE_UNAUTHORIZED; +- +- if (status == ISNS_SUCCESS) +- status = isns_db_remove(db, obj); +- if (status != ISNS_SUCCESS) { +- /* +- * 5.7.5.4 +- * +- * In the event of an error, this response message +- * contains the appropriate status code as well +- * as a list of objects from the original DevDereg +- * message that were not successfully deregistered +- * from the iSNS database. This list of objects +- * is contained in the Operating Attributes +- * of the DevDeregRsp message. Note that an +- * attempted deregistration of a non-existent +- * object does not constitute an isns_error, and +- * non-existent entries SHALL not be returned +- * in the DevDeregRsp message. +- */ +- /* +- * Implementation: right now this doesn't work +- * at all, because isns_msg_set_error will +- * discard the entire message except for the +- * status word. +- */ +- isns_debug_message("Failed to deregister object: %s (0x%04x)\n", +- isns_strerror(status), status); +- +- isns_object_extract_all(obj, &reply->is_operating_attrs); +- dereg_status = status; +- continue; +- } +- +- /* +- * 5.7.5.4 +- * If all Nodes and Portals associated with a Network +- * Entity are deregistered, then the Network Entity +- * SHALL also be removed. +- * [...] +- * If both the Portal and iSCSI Storage Node objects +- * associated with a Portal Group object are removed, +- * then that Portal Group object SHALL also be removed. +- * The Portal Group object SHALL remain registered +- * as long as either of its associated Portal or +- * iSCSI Storage Node objects remain registered. If a +- * deleted Storage Node or Portal object is subsequently +- * re-registered, then a relationship between the re- +- * registered object and an existing Portal or Storage +- * Node object registration, indicated by the PG object, +- * SHALL be restored. +- */ +- /* isns_db_remove takes care of removing dead entities, +- * and dead portal groups. +- */ +- } +- +- if (status == ISNS_SUCCESS) +- status = dereg_status; +- +-done: +- isns_object_list_destroy(&objects); +- *result = reply; +- return status; +-} +diff --git a/utils/open-isns/doc/isns_config.5 b/utils/open-isns/doc/isns_config.5 +deleted file mode 100644 +index 5fbd26e..0000000 +--- a/utils/open-isns/doc/isns_config.5 ++++ /dev/null +@@ -1,387 +0,0 @@ +-.TH ISNS_CONFIG 8 "11 May 2007" +-.SH NAME +-isns_config - iSNS configuration file +-.SH SYNOPSIS +-.B /etc/isns/isnsadm.conf +-.br +-.B /etc/isns/isnsd.conf +-.br +-.B /etc/isns/isnsdd.conf +- +-.SH DESCRIPTION +-All Open-iSNS utilities read their configuration +-from a file in +-.BR /etc/isns . +-There is a separate configuration file for each application, +-.BR isnsd ", " isnsadm ", and " isnsdd . +-The syntax and the set of supported options is identical, +-even though some options are specific to e.g. the server. +-Unless indicated, options are applicable to all utilities. +-.PP +-An Open-iSNS configuration file contains keyword-argument pairs, +-one per line. All keywords are case insensitive. +-.PP +-A +-.B # +-character introduces a comment, which extends until the +-end of the line. Empty lines are ignored. +-.PP +-There are no line continuations, and you cannot use quotes +-around arguments. +-.PP +-Some options specify timeout values, which are given in +-units of seconds by default. You can specify an explicit +-unit, however, such as +-.BR d " (days), +-.BR h " (hours), +-.BR m " (minutes), or +-.BR s " (seconds). +-.\" ------------------------------------------------------------------ +-.SS Generic Options +-.TP +-.BR HostName +-By default, Open-iSNS applications will retrieve the machine's +-hostname using the +-.BR gethostname (3) +-system call, and use a DNS lookup to look up the canonical name. +-Using the +-.BR HostName +-option, you can overried this. This option is rarely needed. +-.TP +-.BR SourceName +-This option is mandatory for all Open-iSNS applications. +-This should be a name which identifies the client uniquely. +-There are two readings of RFC 4171; one requires that this +-is an iSCSI qualified name such as +-.BR iqn.2001-04.com.example.host , +-whereas other language in the RFC suggests that this is +-pretty much a free-format string that just has to be +-unique (using e.g. the client's fully qualified domain name). +-.IP +-When using DSA authentication, Open-iSNS currently requires the source +-name to match the key identifier (SPI) of the client's public +-key. +-.IP +-If left empty, the source name is derived from the client's hostname. +-.TP +-.BR ServerAddress " (client): +-This options specifies the host name or address of +-the iSNS server to talk to. It can optionally be followed +-by a colon, and a port number. +-.IP +-Instead of a hostname, IPv4 or IPv6 addresses can be used. +-In order to avoid ambiguities, literal +-IPv6 addresses must be surrounded by square brackets, +-as in +-.BR [2001:4e5f::1] . +-.IP +-When specifying a port number, you can use either the +-numeric port, or a string name to be looked up in +-.BR /etc/services . +-When the port is omitted, it defaults to 3205, the IANA +-assigned port number of iSNS. +-.IP +-If the special string +-.B SLP: +-is used, the client will try to locate the iSNS server +-through SLP. +-.TP +-.BR SLPRegister " (server): +-If set to 1, the iSNS daemon will register itself will +-the SLP service. This allows clients to contact the +-server without having to configure its address +-statically. +-.TP +-.BR PIDFile " (server): +-This specifies the name of the server's PID file, which is +-.B /var/run/isnsd.pid +-by default. +-.\" ------------------------------------------------------------------ +-.SS Database Related Options +-These options apply to the iSNS server only, and control operation +-of the iSNS database. +-.TP +-.BR Database +-This option is used to specify how the database is stored. +-Setting this to an absolute path name will make +-.B isnsd +-keep its database in the specified directory. +-.IP +-If you leave this empty, +-.B isnsd +-will keep its database in memory. +-This is also the default setting. +-.TP +-.BR DefaultDiscoveryDomain +-iSNS scopes visibility of other nodes using so-called +-Discovery Domains. A storage node A will only "see" +-storage node B, if both are members of the same +-discovery domain. +-.IP +-So if a storage node is registered which is not part of +-any discovery domain, it will not see any other nodes. +-.IP +-By setting +-.BR DefaultDiscoveryDomain=1 , +-you can tell isnsd to create a virtual "default discovery domain", which +-holds all nodes that are not part of any administratively configured +-discovery domain. +-.IP +-By default, there is no default discovery domain. +-.TP +-.BR RegistrationPeriod +-The iSNS server can purge registered entities after a certain period +-of inactivity. This is called the registration period. Clients who +-register objects are supposed to refresh their registration within +-this period. +-.IP +-The default value is 1 hour. Setting it to 0 disables expiry +-of entities from the database. +-.TP +-.BR ESIRetries +-Open-iSNS is able to monitor the reachability of storage nodes +-and their portals by using a protocol feature called ESI +-(Entity status inquiry). Clients request ESI monitoring by +-registering an ESI port along with each portal. The server +-will send ESI messages to these portals at regular intervals. +-If the portal fails to reply several times in a row, it is +-considered dead, and will be removed from the database. +-.IP +-.B ESIRetries +-specifies the maximum number of attempts the server will make +-at contacting the portal before pronouncing it dead. If set +-to 0, the server will disable ESI and reject any registrations +-that specify an ESI port with an error code of "ESI not +-supported". +-.IP +-The default value is 3. +-.TP +-.BR ESIMinInterval +-This timeout value specifies the minimum ESI interval. +-If a client requests an ESI interval less than this value, +-it is silently rounded up. +-.IP +-The default value is 60 seconds. +-.TP +-.BR ESIMaxInterval +-This timeout value specifies the maximum ESI interval. +-If a client requests an ESI interval greater than this value, +-it is silently rounded down. +-.IP +-The default value is 10 minutes. +-.IP +-The maximum ESI interval must not exceed half the value +-of the registration period. +-.TP +-.B SCNRetries +-iSNS clients can register to receive State Change Notification +-(SCN) messages to learn about changes in the iSNS database. +-This value specifies how often the server will try to retransmit +-an SCN message until giving up. +-.IP +-The default value is 3. +-.TP +-.B SCNCallout +-This is the path name of a helper program that +-.B isnsdd +-will invoke whenever it processes a state change notification from the +-server. The helper program will be invoked with an argument indicating +-the type of event, being one of +-.BR add ", " update ", or " remove . +-This is followed by a list of attributes in +-.IB name = value +-notation, using the names and conventions described in +-.BR isnsadm (8). +-.\" ------------------------------------------------------------------ +-.SS Security Related Options +-The iSNS standard defines an authentication method based on +-the DSA algorithm. Participants in a message exchange authenticate +-messages by adding an "authentication block" containing a time stamp, +-a string identifying the key used, and a digital signature of the +-message. The same method is also used by SLP, the Service Location +-Protocol. +-.PP +-The string contained in the authentication block is referred to +-as the +-.IR "Security Policy Index" (SPI). +-This string can be used by the server to look up the client's public +-key by whatever mechanism; so the string could be used as the name of +-a public key file in a directory, or to retrieve an X509 certificate +-from LDAP. +-.PP +-From the perspective of Open-iSNS client applications, there are +-only two keys: the client's own (private) key, used to sign the +-messages it sends to the server, and the server's public key, +-used to verify the signatures of incoming server messages. +-.PP +-The iSNS server needs, in addition to its own private key, access to all +-public keys of clients that will communicate to it. The latter are kept +-in what is called a key store. Key stores and their operation will +-be discussed in section +-.B Key Stores and Policy +-below. +-.PP +-The following configuration options control authentication: +-.TP +-.BR Security +-This enables or disables DSA authentication. +-When set to 1, the client will sign all messages, and expect all server +-messages to be signed. +-.IP +-When enabling security in the server, incoming messages are checked +-for the presence of an auth block. If none is present, or if the server +-cannot find a public key corresponding to the SPI, the message is treated +-as originating from an anonymous source. If the SPI is known but the +-signature is incorrect, the message is dropped silently. +-.IP +-Messages from an anonymous source will be assigned a very restrictive +-policy that allows database queries only. +-.IP +-Setting this option to 0 will turn off authentication. +-.IP +-The default value is -1, which tells iSNS to use authentication +-if the required keys are installed, and use unauthenticated iSNS +-otherwise. +-.TP +-.BR AuthName +-This is the string that will be used as the SPI in all outgoing +-messages that have an auth block. It defaults to the host name +-(please refer to option +-.BR HostName ). +-.TP +-.BR AuthKeyFile +-This is the path name of a file containing a PEM encoded DSA key. +-This key is used to sign outgoing messages. +-The default is +-.BR /etc/isns/auth_key . +-.TP +-.BR ServerKeyFile +-This option is used by client applications only, and specifies +-the path name of a file containing a PEM encoded DSA key. +-This key is used to authenticate the server's replies. +-The default is +-.BR /etc/isns/server_key.pub . +-.TP +-.BR KeyStore +-This server-side option specifies the key store to use, +-described in the next section. +-.PP +-The following two options control how iSNS will verify the +-time stamp contained in the authentication block, which +-is supposed to prevent replay attacks. +-.TP +-.B Auth.ReplayWindow +-In order to compensate for clock drift between two hosts exchanging +-iSNS messages, Open-iSNS will apply a little fuzz when comparing +-the time stamp contained in the message +-to the local system time. If the difference between +-time stamp and local system time is less than the number of seconds +-given by this option, the message is acceptable. Otherwise, it is +-rejected. +-.IP +-The default value is +-.BR 5m . +-.TP +-.B Auth.TimestampJitter +-When verifying incoming messages, Open-iSNS checks that the time +-stamps sent by the peer are increasing monotonically. In order to +-compensate for the reordering of messages by the network (eg when +-using UDP as transport), a certain time stamp jitter is accepted. +-If the time stamp of an incoming messages is no earlier than +-.B TimestampJitter +-seconds before the last time stamp received, then the message is acceptable. +-Otherwise, it is rejected. +-.IP +-The default value is +-.BR 1s . +-.\" ------------------------------------------------------------------ +-.SS Key Stores and Policy +-The current implementation supports two types of key stores. +-.PP +-The simple key store uses a flat directory to store public keys, each +-key in a file of its own. The file is expected to hold the client's +-PEM-encoded public key, and it must use the client's SPI as the name. +-This type of key store is not really recommended, as it does not +-store any policy information. +-.PP +-A simple key store can be configured by setting the +-.B KeyStore +-option to the path name of the directory. +-.PP +-The recommended approach is to use the database as key store. This +-uses vendor-specific policy objects to tie SPI string, public key, +-entity name, source name and other bits of policy together, and +-store them in a persistent way. +-.PP +-The database key store is configured by setting the +-.B KeyStore +-option to the reserved value +-.BR DB: , +-which is also the default. +-.PP +-Currently, Open-iSNS policy objects have the following attributes, +-besides the SPI: +-.TP +-Source: +-This is the source node name the client must use. It defaults to +-the SPI string. +-.TP +-Functions: +-This is a bitmap detailing which functions the client is permitted +-to invoke. The bit names correspond to the shorthand names used in +-RFC 4711, such as +-.BR DevAttrReg , +-.BR DevAttrQry , +-etc. The default is to allow registration, query and deregistration, +-as well as SCNRegister. +-.TP +-Entity name: +-This is the entity name assigned to the client. If set, a registration +-by the client is not permitted to use a different entity name. If +-the client sends a registration without Entity identifier, the +-server will assign the entity name given in the policy. +-The default is to not restrict the entity name. +-.TP +-Object access: +-This is a bitfield describing access permissions for each object type. +-For each object type, you can grant Read and/or Write permissions. +-Read access applies to the Query and GetNext calls; all other operations +-require write permission. +-The default grants read and write access to objects of type Entity, Storage +-Node, Portal and Portal Group; and read access to Discovery Domains. +-.TP +-Node types: +-This bitfield describes which types of storage nodes a client is +-allowed to register; the valid bit names are +-.BR target ", " initiator " and " control . +-The default is to restrict nodes to register initiators only. +-.\" ------------------------------------------------------------------ +-.SS Network Related Options +-.TP +-.BR Network.MaxSockets +-This is the number of incoming connections accepted, and defaults to +-1024. This usually applies to server side only, but is relevant if you +-create a passive TCP socket for ESI or SCN. +-.TP +-.BR Network.ConnectTimeout +-This is a timeout value, which specifies the time to wait for a TCP +-connection to be established. It defaults to +-.BR 60s . +-.TP +-.BR Network.ReconnectTimeout +-When a connection attempt failed, we wait for a short time before we +-try connecting again. This is intended to take the pressure off +-overloaded servers. The default value is +-.BR 10s . +-.TP +-.BR Network.CallTimeout +-Total amount of time to wait before timing out a call to the iSNS server. +-The default value is +-.BR 60s . +-.\" ------------------------------------------------------------------ +-.SH SEE ALSO +-RFC 4171, +-.BR isnsd (8), +-.BR isnsadm (8). +-.SH AUTHORS +-Olaf Kirch +diff --git a/utils/open-isns/doc/isnsadm.8 b/utils/open-isns/doc/isnsadm.8 +deleted file mode 100644 +index c3e2b83..0000000 +--- a/utils/open-isns/doc/isnsadm.8 ++++ /dev/null +@@ -1,672 +0,0 @@ +-'\" t +-.TH ISNSADM 8 "11 May 2007" +-.SH NAME +-isnsadm \- iSNS client utility +-.SH SYNOPSIS +-.B isnsadm +-.RI [ options... ] +-.RI --register " object... +-.PP +-.B isnsadm +-.RB [ ... ] +-.RI --query " attr" [= value ] +-.PP +-.B isnsadm +-.RB [ ... ] +-.RI --deregister " attr=value +-.PP +-.B isnsadm +-.RB [ ... ] +-.RI --list " type attr=value +-.PP +-.B isnsadm +-.RB [ ... ] +-.RI --dd-register " attr=value +-.PP +-.B isnsadm +-.RB [ ... ] +-.RI --enroll " client-name attr=value +-.PP +-.B isnsadm +-.RB [ ... ] +-.RI --edit-policy " attr=value +- +-.SH DESCRIPTION +-.B Isnsadm +-is a command line utility for interacting with an iSNS +-server. It operates in one of several modes, which are +-mutually exclusive. +-Currently, +-.B isnsadm +-supports registration, query, and deregistration. +-.SH OPTIONS +-By default, +-.B isnsadm +-will take most of its settings from the configuration +-file +-.BR /etc/isns/isnsadm.conf , +-with the exception of the following options: +-.TP +-.BI \--config " filename\fR, " \-c " filename +-This option overrides the default configuration file. +-.TP +-.BI \--debug " facility\fR, " \-d " facility +-enables debugging. Valid facilities are +-.PP +-.TS +-tab(,),box,center; +-lb|lr. +-socket,network send/receive +-auth,authentication and security related information +-message,iSNS protocol layer +-state,database state +-scn,SCN (state change notification) messages +-esi,ESI (entity status inquiry) messages +-all,all of the above +-.TE +-.PP +-.TP +-.BI \--local +-makes +-.B isnsadm +-use a Local (aka Unix) socket when talking to the iSNS +-server. This can be used by the administrator to perform +-management tasks, such as enrolling new clients, editing +-access control and so on. Local mode is only available +-to the super user. +-.TP +-.BI \--control +-makes +-.B isnsadm +-assume the identity of a control node. Control nodes are +-special in that they have more rights in accessing and +-modifying the database than normal storage nodes have. +-.PP +-When using this option, +-.B isnsadm +-will use the source name and DSA key specified by the +-.BR Control.SourceName " and " Control.AuthKeyFile +-configuration options, respectively. +-.PP +-.TP +-.BI \--key " attr" = value +-This option is recognized in registration mode only, and +-lets you specify an object key. For a more detailed explanation, +-refer to section +-.BR "Registration mode" . +-.TP +-.BI \--keyfile= filename +-When creating a policy for a new iSNS client, +-.B isnsadm +-is able to generate a DSA key for the client. The public +-part of the key is stored in a policy object in the iSNS +-server's database, whereas the private portion is stored in the +-file specified by the +-.B keyfile +-option. +-.B +-.TP +-.BI \--help +-This will print a help message and exit. +-.\"--------------------------- +-.SS Built-in help +-.B Isnsadm +-has built-in help functions. When invoked with +-.BR \--help , +-it will print a general help message showing all supported +-command modes, and exit. Specific help on an individual +-command mode is available by invoking that mode with a +-single argument of +-.BR help , +-like this: +-.PP +-.B isnsadm --register help +-.PP +-This will print a help message describing how to use this +-command mode, followed by a list of attributes this command supports +-and a help text describing the attribute. +-.\"--------------------------- +-.SS Supported attributes +-Most command modes take a list of attributes as arguments on the +-command line. The naming and syntax of these attributes as +-the same for all commands modes, however certain modes support +-only a limited set of attributes. +-.PP +-Attributes are usually given as +-.IB name = value +-pairs. Where empty (or NIL) attributes are supported, the +-attribute name by itself can be given. +-.PP +-The syntax of attribute +-.I value +-depends on the attribute type. For strings and numeric values, +-no special conventions apply, but bitfields have a special syntax +-described below. +-.PP +-The attribute name is usually preceded by the object +-type it applies to (such as +-.BR entity ), +-followed by a hyphen and the name itself. However, where the +-context clearly determines a specific object type, the prefix +-can be omitted. For instance, when editing a policy object +-using +-.BR \--edit-policy , +-it is acceptable to use +-.B node-type +-as shorthand for +-.BR policy-node-type . +-.PP +-Likewise, in a query command, it is not permitted to mix attributes +-from different object types. Thus, the first attribute of a +-query string establishes a type context, so that the following +-two invocations are equivalent: +-.PP +-.B isnsadm --query pg-name=iqn.com.foo pg-addr=10.1.1.1 pg-port=860/tcp +-.br +-.B isnsadm --query pg-name=iqn.com.foo addr=10.1.1.1 port=860/tcp +-.PP +-.B Isnsadm +-currently supports the following attributes: +-.PP +-.TS +-tab(,),box,center; +-li|lilili +-lt|lbrlb. +-Context,Attribute,iSNS tag,Aliases +-_ +-Network Entity,entity-id,1,eid +-\^,entity-prot,2 +-\^,entity-index,7 +-iSCSI Storage Node,iscsi-name,32 +-\^,iscsi-node-type,33 +-\^,iscsi-alias,34 +-\^,iscsi-idx,36 +-\^,iscsi-authmethod,42 +-Portal,portal-addr,16 +-\^,portal-port,17 +-\^,portal-name,18 +-\^,portal-esi-port,20 +-\^,portal-esi-interval,21 +-\^,portal-idx,22 +-\^,portal-scn-port,23 +-Portal Group,portal-group-index,52 +-\^,pg-name,48 +-\^,pg-addr,49 +-\^,pg-port,50 +-\^,pg-tag,51,pgt +-\^,pg-idx,52 +-Discovery Domain,dd-id,2065 +-\^,dd-name,2066 +-\^,dd-member-iscsi-idx,2067 +-\^,dd-member-name,2068 +-\^,dd-member-fc-name,2069, +-\^,dd-member-portal-idx,2070, +-\^,dd-member-addr,2071, +-\^,dd-member-port,2072, +-\^,dd-features,2078, +-Policy Object,policy-name,-,spi +-\^,policy-key,- +-\^,policy-entity,- +-\^,policy-node-type,- +-\^,policy-object-type,- +-\^,policy-functions,- +-.TE +-.PP +-.\"--------------------------- +-.SS Portal attributes +-Portal information is conveyed by two separate attributes +-in iSNS; an address attribute holding the IP address, and +-a TCP/UDP port attribute holding the port number and an indication +-of the protocol to be used (TCP or UDP). +-.PP +-When parsing a TCP/UDP port, Open-iSNS will expect a port number, +-optionally followed by a slash and the protocol. Port names +-such as "iscsi-target" are not supported. +-.PP +-As a convenience, +-.B isnsadm +-supports a notation representing a portal as one pseudo-attribute. +-Separating address and port by a colon. Thus, the following two +-are equivalent, with the latter being the shorthand representation +-of the former: +-.PP +-.BI addr=
" port=" [/ protocol ] \fR. +-.BI portal= : port [/ protocol ] +-.PP +-This notation can be used in any context where an +-.BR addr / port +-attribute pair can appear, and may be prefixed by a type name, +-as in +-.BR pg-portal=... . +-.PP +-When using literal IPv6 addresses, the address has to be surrounded +-by square brackets, otherwise the embedded colons would create +-ambiguity: +-.BR portal=[2001:5c0:0:2::24]:860/tcp +-.PP +-.\"--------------------------- +-.SS Bitfield attributes +-Some iSNS attributes are words representing a bit field. +-.B Isnsadm +-displays and parses these attributes in human-readable form +-rather than using the numerical value. The names of the bit +-values are displayed by built-in help facilities. When specifying +-a bitfield attribute on the command line, you can combine them +-using the plus (\fB+\fP) or comma (\fB,\fR) character, like this: +-.PP +-.B node-type=control+initiator +-.PP +-.\"--------------------------- +-.SS Registration mode +-Registration mode is selected by using the +-.B --register +-option, followed by a list of one or more objects +-to register with the iSNS server. +-By default, this will create a network entity for the +-client (if none exists), and place the new objects inside +-it. Usually, you register all objects for +-a network entity in one operation, rather than each +-one separately. +-.PP +-Each object is specified as a type, optionally followed +-by a comma-separated list of attributes, such as +-this: +-.PP +-.B target=iqn.2005-01.org.open-iscsi.foo:disk1,alias=disk1 +-.PP +-The following object types are currently supported: +-.TP +-.BI entity= name +-Tells the server to group all objects in the specified +-Network Entity container object. +-Normally, the iSNS server will automatically assign an +-entity name that is in line with its policies, and there is +-no need to specify it explicitly. +-.TP +-.BI initiator[= name ] +-This will register an iSCSI storage node of type initiator. +-By default, the name is set to the iSNS source name. +-.IP +-This can be followed by any number of iSCSI storage node +-attributes. +-.TP +-.BI target[= name ] +-This will register an iSCSI storage node of type target. +-By default, the name is set to the iSNS source name. +-.IP +-This object accepts the same set of attributes as +-.BR initiator . +-.TP +-.BI control[= name ] +-This will register an iSCSI storage node of type control. +-By default, the name is set to the iSNS source name. +-Only management nodes should be registered as control +-nodes, as this gives a node complete control over the +-iSNS database. +-.IP +-This object accepts the same set of attributes as +-.BR initiator . +-.TP +-.BI portal=[ address:port/proto ] +-This will register a portal using the given address, +-port and protocol triple. If the triple is omitted, +-.B isnsadm +-will use the client host's IP address. If the portal +-is preceded by an initiator registration (on the command +-line), the port defaults to 860/tcp; if it is preceded by +-a target registration, the port defaults to 3260/tcp. +-For multi-homed hosts, the choice of address is +-implementation dependant. +-.IP +-This can be followed by any number of portal attributes. +-.TP +-.B pg +-This will register a portal group joining the preceding +-portal and node. Portal groups can be used to describe +-the preferred portals for a given node; please refer +-to RFC 4711 for details. +-.IP +-This can be followed by any number of portal group attributes. +-The attribute list must specify a portal group tag (PGT) +-via the +-.BR pgt +-attribute. +-.PP +-There are two additional command line options of interest, +-which are used exclusively with Registration mode. One is +-.BR \--replace . +-Normally, registration mode will +-.I add +-new objects to the network entity associated with the client +-host. If you specify +-.B \--replace +-on the command line, the server will wipe the network +-entity completely, and remove all portals and storage +-nodes it contained. Then it will create a new network +-entity, and place the portals and storage nodes provided +-by the caller inside. +-.PP +-In addition, it is possible to replace just parts of a +-network entity. This is achieved by using the command line +-option +-.B \--key +-to specify the object that should be replaced. +-.PP +-For instance, assume a network entity +-contains the portal +-.BR 10.1.1.1:860 , +-and the client's network address changed to +-.BR 10.2.7.7 . +-Then the following command will atomically update the +-database, replacing just the portal without touching the +-registered storage nodes: +-.PP +-.B " isnsadm --replace --key portal=10.1.1.1:860 portal=10.2.7.7:860 +-.PP +-The +-.B \--key +-option recognizes only a subset of the usual attributes: +-.RS +-.TS +-tab(,),box; +-li|li +-lb|lb. +-Object type,Syntax +-_ +-Entity,eid=\fIidentifier +-Portal,portal=\fIaddress\fP:\fPport +-iSCSI Node,iscsi-name=\fIname +-.TE +-.RE +-.PP +-To get a list of supported attributes, invoke +-.BR "isnsadm --register help" . +-.\"--------------------------- +-.SS Query mode +-Query mode is selected by using the +-.B --query +-option. A query consists of a list of +-.BR attr = \fI value +-pairs. All attributes must belong to the same object type, +-i.e. queries that mix a Network Entity attribute with e.g. +-a Portal attribute will be rejected. +-.PP +-It is also possible to specify an attribute name without +-value (i.e. just +-.BR attr ), +-which will +-will match any object that has such an attribute, regardless +-of its value. This is useful when you want to query for all +-objects of a given type. +-.PP +-To obtain a list of supported attributes, invoke +-.BR "isnsadm --query help" . +-.\"--------------------------- +-.SS List Mode +-In this mode, +-.B isnsadm +-will display all objects of a given type, optionally +-restricted to those matching certain attribute values. +-.PP +-The arguments to list mode are a +-.IR "type name" , +-optionally followed by one or more +-.IB attr = value +-pairs. Only attributes pertaining to the given +-type are permitted; for instance, if you specify a +-type name of +-.BR portals , +-only portal attributes are permitted. +-.PP +-Possible type names are: +-.BR entities , +-.BR nodes , +-.BR portals , +-.BR dds , +-.BR ddsets , +-.BR portal-groups ", and " +-.BR policies . +-.PP +-Additional information is available via +-.BR "isnsadm --list help" . +-.\"--------------------------- +-.SS Deregistration mode +-In this mode, you can deregister objects previously registered. +-Only the node which registered an entity in the first place is +-permitted to remove it, or any of its child objects. (Control +-nodes are not bound by this restriction). +-.PP +-In deregistration mode, the argument list consists of a list of +-.IB attr = value +-pairs. Deregistration supports the same set of attributes as +-query mode. +-.\"--------------------------- +-.SS Discovery Domain Registration +-This mode, allows to register a discovery domain or to add +-new members to an existing discovery domain. Again, attributes +-are specified as a list of +-.IB attr = value +-pairs. Only discovery domain attributes are recognized. +-.PP +-Note, in order to add members to an existing domain, you must +-specify the domain's numeric ID. The domain's symbolic name +-is not a valid handle when referring to a discovery domain. +-.\"--------------------------- +-.SS Client Enrollment +-This mode only works when the server recognizes the client +-as having control node capabilities, which is possible in +-two ways: +-.TP +-Invoke +-.B isnsadm \--local +-as super user on the host +-.B isnsd +-is running on. The +-.B \--local +-options tells it to communicate with the server through +-the local control socket. +-.TP +-Invoke +-.BR "isnsadm \--control" , +-which tells it to assume the identity of a control node. +-When given this option, +-.B isnsadm +-will use the source name and DSA key specified by the +-.BR Control.SourceName " and " Control.AuthKeyFile +-configuration options, respectively. +-The server must be configured to grant this identity +-control node status. +-.PP +-To enroll a client, use the +-.B \--enroll +-option, followed by the (source) name of the client to enroll. +-This string will be used as the name of the security policy +-the client will use to identify itself. +-.PP +-This is followed by a list of attribute/value pairs, where the +-following set of attributes is supported: +-.PP +-.TS +-tab(,),box,center; +-li|lilili +-lb|lrlb. +-Attribute,Description,Aliases +-_ +-name,Policy Name,spi +-key,Client's DSA public key +-entity,Assigned Entity Identifier +-node-type,Permitted node type(s) +-node-name,Permitted node name(s) +-functions,Bitmap of permitted functions +-object-type,Object access mask +-.TE +-.PP +-The +-.B key +-attribute is used to specify the DSA +-public key that the server should use to authenticate +-messages from this client. You can either provide a +-file name; in which case +-.B isnsadm +-will try to read the PEM encoded public key from that file. +-If no +-.B key +-attribute is given, or when using +-.BR key=gen ", " isnsadm +-will generate a DSA key. The private portion of the newly +-generated key will be stored in the file specified by +-.BI --keyfile= filename \fR. +-.PP +-The +-.B object-type +-attribute is used to specify which object types the client +-is permitted to access. This is a comma separated list of +-.IB type : perm +-pairs, where +-.I type +-can be any of +-.BR entity ", " iscsi-node ", " portal ", " portal-group ", " dd ", " ddset ", and " policy . +-The permissions can be either +-.BR rw ", or " r . +-.PP +-The +-.B functions +-attribute can be used to restrict which functions the client is +-permitted to invoke. This is a bitfield, using the standard function +-names from RFC 4171, such as +-.BR DevAttrReg ", " DevAttrQry ", etc." +-.PP +-For a description of the open-isns security model +-and policies, please refer to the +-.BR isns_config (5) +-manual page. +-.PP +-.BR "Important note" : +-In order to generate a DSA key, you have to have a set of DSA +-parameters installed. By default, +-.B isnsadm +-expects to find them in +-.BR /etc/isns/dsa.params . +-These parameters are created by calling +-.B isnsd \--init +-once on the server machine. Alternatively, you can use +-the following command: +-.PP +-.ti +8 +-openssl dsaparam 1024 -out /etc/isns/dsa.params +-.ti -8 +-.PP +-where 1024 is the chosen DSA key size, in bits. +-.SH EXAMPLES +-If you want to use Open-iSNS in authenticated mode, +-you first need to initialize the server's DSA key and +-DSA parameters. This can be done conveniently by using +-.PP +-.B isnsd --init +-.PP +-This will create the server's private and public key, +-and place them in +-.B /etc/isns/auth_key +-and +-.BR auth_key.pub , +-respectively. +-.PP +-The following command will create a policy object for a +-node named +-.B isns.control , +-and grant it control privileges: +-.PP +-.B isnsadm --local --keyfile=control.key +-.B --enroll isns.control \(rs +-.br +-.B " node-type=ALL functions=ALL object-type=ALL +-.PP +-In the process of entrolling the client, this will generate +-a DSA key pair, and place the private key portion in the +-file +-.BR control.key . +-This file must be installed as +-.BR /etc/isns/control.key +-on the host you wish to use as an iSNS management station. +-.PP +-Next, you need to create a storage node object for the +-management station: +-.PP +-.B isnsadm --local --register control +-.PP +-On the management station, you can then enroll additional +-hosts: +-.PP +-.B isnsadm --control --keyfile=somehost.key +-.B --enroll iqn.2005-01.org.open-iscsi.somehost \(rs +-.br +-.B " node-type=target+initiator +-.PP +-Again, this will generate a DSA key pair and store the private +-key portion in auth_key. Note the use of the +-.B \--control +-option that tells +-.B isnsadm +-to use the identity of the control node instead of the default +-key and source name. +-.PP +-You then need to copy +-.B somehost.key +-to the client host and install it as +-.BR /etc/isns/auth_key . +-Likewise, the server's public key (which resides in +-.BR /etc/isns/auth_key.pub +-on the server) needs to be copied to the client machine, +-and placed in +-.BR /etc/isns/server_key.pub . +-.PP +-By default, when a client registers a storage node (be +-it initiator or target) with iSNS, the client will not be +-able to see any other storage nodes. In order for targets +-to be visible to a given initiator, you need to create +-so-called Discovery Domains (or DDs for short). +-.PP +-Currently, domain membership operations require administrator +-privilege. Future extensions may allow iSNS clients to +-add themselves to one or more DDs upon registration. +-.PP +-To create a discovery domain, and add nodes to it, you can +-use +-.PP +-.B isnsadm --control --dd-register dd-name=mydomain \(rs +-.br +-.B " member-name=iqn.org.bozo.client iqn.org.bozo.jbod ... +-.PP +-In order to add members to an existing DD, you have to +-specify the numeric domain ID - using the DD name is not +-sufficient, unfortunately (this is a requirement of the +-RFC, not an implementation issue): +-.PP +-.B isnsadm --control --dd-register dd-id=42 \(rs +-.br +-.B " member-name=iqn.com.foo member-name=iqn.com.bar +-.PP +-The DD ID can be obtained by doing a query for the DD name: +-.PP +-.B isnsadm --control --query dd-name=mydomain +-.PP +-In management mode, you can also register and deregister +-nodes and portals manually, in case you want to fix up +-an inconsisteny in the database. For instance, this will +-register a node and portal on a host named client.bozo.org: +-.PP +-.B isnsadm --control --register entity=client.bozo.org \(rs +-.br +-.B " initiator=iqn.org.bozo.client portal=191.168.7.1:860 +-.PP +-Note that this registration explicitly specifies the network +-entity in which to place the new objects. If you omit this, +-the new objects will be placed in an entity named +-.BR CONTROL , +-which is decidedly not what you want. +-.SH SEE ALSO +-RFC 4171, +-.BR isnsd (8), +-.BR isns_config (5). +-.SH AUTHORS +-Olaf Kirch +diff --git a/utils/open-isns/doc/isnsd.8 b/utils/open-isns/doc/isnsd.8 +deleted file mode 100644 +index 84b3913..0000000 +--- a/utils/open-isns/doc/isnsd.8 ++++ /dev/null +@@ -1,93 +0,0 @@ +-.TH ISNSD 8 "11 May 2007" +-.SH NAME +-isnsd \- iSNS server daemon +-.SH SYNOPSIS +-.B isnsd +-.RB [ "\-f" ] +-.RB [ "\-4" ] +-.RB [ "\-6" ] +-.RB [ "\-c \fIfilename" ] +-.RB [ "\-d \fIdebug-facility" ] +-.RB [ \--dump-db ] +-.RB [ \--init ] +- +-.SH DESCRIPTION +-.B Isnsd +-implements the iSNS protocol as defined in RFC 4171. +-iSNS is a discovery protocol for iSCSI and iFCP. +-.SH OPTIONS +-By default, +-.B isnsd +-will take most of its settings from the configuration +-file +-.BR /etc/isns/isnsd.conf , +-with the exception of the following options: +-.TP +-.BI \--config " filename\fR, " \-c " filename +-This option overrides the default configuration file. +-.TP +-.BR \--foreground , \-f +-By default, +-.B isnsd +-will put itself into the background. By specifying this option, you can +-tell it to run in the foreground. Any error messages or debug output +-will be printed to the console rather than being sent to syslog. +-.TP +-.BI \-4 +-tells +-.B isnsd +-to create an IPv4 socket only. Normally, it defaults +-to IPv6 (which will accept both IPv4 and IPv6 connections). +-.TP +-.BI \-6 +-tells +-.B isnsd +-explicitly +-to create an IPv6 socket only. Since it defaults +-to IPv6 anyway, this is really a no-op. +-.TP +-.BI \--debug " facility\fR, " \-d " facility +-enables debugging. Valid facilities are +-.PP +-.TS +-tab(,),box,center; +-lb|lr. +-socket,network send/receive +-auth,authentication and security related information +-message,iSNS protocol layer +-state,database state +-scn,SCN (state change notification) messages +-esi,ESI (entity status inquiry) messages +-all,all of the above +-.TE +-.PP +-.TP +-.B \--dump-db +-This is a helper function that will read the database from the +-file system, and display it in human readable form. When using +-this option, +-.B isnsd +-will not open any sockets, and terminate immediately after display +-the database. +-.IP +-This option is intended to be used by the administrator when suspecting +-that the database contains bad/inconsistent information. +-.TP +-.B \--init +-This option will create the server's authentication key, and +-the required DSA parameters. The private key is stored in the +-file specified by the +-.B AuthKey +-option (usually +-.BR /etc/isns/auth_key ). +-The public portion of the key is written to same directory, +-with the suffix +-.B .pub +-appended to the key file name. +-.SH SEE ALSO +-RFC 4171, +-.BR isnsadm (8), +-.BR isnsdd (8), +-.BR isns_config (5). +-.SH AUTHORS +-Olaf Kirch +diff --git a/utils/open-isns/doc/isnsdd.8 b/utils/open-isns/doc/isnsdd.8 +deleted file mode 100644 +index 6088e28..0000000 +--- a/utils/open-isns/doc/isnsdd.8 ++++ /dev/null +@@ -1,75 +0,0 @@ +-.TH ISNSDD 8 "11 May 2007" +-.SH NAME +-isnsdd \- iSNS discovery daemon +-.SH SYNOPSIS +-.B isnsdd +-.RB [ "\-f" ] +-.RB [ "\-c \fIfilename" ] +-.RB [ "\-d \fIdebug-facility" ] +- +-.SH DESCRIPTION +-.B Isnsdd +-is a client side daemon for iSNS. It registers storage +-nodes and portals with the iSNS service, and refreshes +-these registrations in a timely manner. +-.PP +-The daemon also registers itself to receive SCN notifications, +-and processes these. It can be configured to invoke an +-external helper application for each status notification +-received. The path name of the helper application can be +-specified via the +-.B SCNCallout +-option in the configuration file. +-.SH OPTIONS +-By default, +-.B isnsd +-will take most of its settings from the configuration +-file +-.BR /etc/isns/isnsdd.conf , +-with the addition of the following command line options: +-.TP +-.BI \--config " filename\fR, " \-c " filename +-This option overrides the default configuration file. +-.TP +-.BR \--foreground , \-f +-By default, +-.B isnsd +-will put itself into the background. By specifying this option, you can +-tell it to run in the foreground. Any error messages or debug output +-will be printed to the console rather than being sent to syslog. +-.TP +-.BI \--role " role +-This tells the discovery daemon in which capacity is should register itself +-with the iSNS server. +-.I Role +-can be either +-.BR initiator ", or " control . +-The default is to register as an initiator. +-.IP +-Registering target nodes needs to use a different mechanism, as +-the iSCSI target server needs to inform the discovery daemon +-about each exported target separately. This is not implemented +-yet. +-.TP +-.BI \--debug " facility\fR, " \-d " facility +-enables debugging. Valid facilities are +-.PP +-.TS +-tab(,),box,center; +-lb|lr. +-socket,network send/receive +-auth,authentication and security related information +-message,iSNS protocol layer +-state,database state +-scn,SCN (state change notification) messages +-esi,ESI (entity status inquiry) messages +-all,all of the above +-.TE +-.PP +-.SH SEE ALSO +-RFC 4171, +-.BR isnsd (8), +-.BR isnsadm (8), +-.BR isns_config (5). +-.SH AUTHORS +-Olaf Kirch +diff --git a/utils/open-isns/domain.c b/utils/open-isns/domain.c +deleted file mode 100644 +index 3b848ac..0000000 +--- a/utils/open-isns/domain.c ++++ /dev/null +@@ -1,208 +0,0 @@ +-/* +- * iSNS object model - discovery domain specific code +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include "isns.h" +-#include "objects.h" +-#include "util.h" +- +-static int +-__isns_default_dd_rebuild(isns_object_t *obj, isns_db_t *db) +-{ +- isns_object_list_t list = ISNS_OBJECT_LIST_INIT; +- unsigned int i; +- +- isns_object_prune_attrs(obj); +- +- isns_db_get_domainless(db, &isns_iscsi_node_template, &list); +- for (i = 0; i < list.iol_count; ++i) { +- isns_object_t *node = list.iol_data[i]; +- const char *name; +- uint32_t type; +- +- if (!isns_object_get_uint32(node, +- ISNS_TAG_ISCSI_NODE_TYPE, +- &type)) +- continue; +- if (type & ISNS_ISCSI_CONTROL_MASK) +- continue; +- if (!isns_object_get_string(node, +- ISNS_TAG_ISCSI_NAME, +- &name)) +- continue; +- isns_object_set_string(obj, +- ISNS_TAG_DD_MEMBER_ISCSI_NAME, +- name); +- } +- +- return ISNS_SUCCESS; +-} +- +-/* +- * Create the default domain +- */ +-isns_object_t * +-isns_create_default_domain(void) +-{ +- isns_object_t *obj; +- +- obj = isns_create_object(&isns_dd_template, NULL, NULL); +- if (!obj) +- return NULL; +- +- isns_object_set_uint32(obj, ISNS_TAG_DD_ID, 0); +- obj->ie_rebuild = __isns_default_dd_rebuild; +- return obj; +-} +- +-/* +- * Check object type +- */ +-int +-isns_object_is_dd(const isns_object_t *obj) +-{ +- return ISNS_IS_DD(obj); +-} +- +-int +-isns_object_is_ddset(const isns_object_t *obj) +-{ +- return ISNS_IS_DDSET(obj); +-} +- +-/* +- * Keep track of DD membership through a bit vector +- */ +-int +-isns_object_mark_membership(isns_object_t *obj, uint32_t id) +-{ +- if (!obj->ie_membership) +- obj->ie_membership = isns_bitvector_alloc(); +- +- return isns_bitvector_set_bit(obj->ie_membership, id); +-} +- +-int +-isns_object_test_membership(const isns_object_t *obj, uint32_t id) +-{ +- if (!obj->ie_membership) +- return 0; +- +- return isns_bitvector_test_bit(obj->ie_membership, id); +-} +- +-int +-isns_object_clear_membership(isns_object_t *obj, uint32_t id) +-{ +- if (!obj->ie_membership) +- return 0; +- +- return isns_bitvector_clear_bit(obj->ie_membership, id); +-} +- +-/* +- * Check whether the two objects share a discovery domain, +- * and if so, return the DD_ID. +- * Returns -1 otherwise. +- */ +-int +-isns_object_test_visibility(const isns_object_t *a, const isns_object_t *b) +-{ +- /* The admin can tell isnsd to put all nodes which are *not* +- * in any discovery domain, into the so-called default domain */ +- if (isns_config.ic_use_default_domain +- && a->ie_template == b->ie_template +- && isns_bitvector_is_empty(a->ie_membership) +- && isns_bitvector_is_empty(b->ie_membership)) +- return 1; +- +- return isns_bitvector_intersect(a->ie_membership, b->ie_membership, NULL) >= 0; +-} +- +-/* +- * Return all visible nodes and portals +- */ +-static int +-__isns_object_vis_callback(uint32_t dd_id, void *ptr) +-{ +- isns_object_list_t *list = ptr; +- +- /* Get all active members */ +- isns_dd_get_members(dd_id, list, 1); +- return 0; +-} +- +-void +-isns_object_get_visible(const isns_object_t *obj, +- isns_db_t *db, +- isns_object_list_t *result) +-{ +- if (isns_bitvector_is_empty(obj->ie_membership)) { +- /* Get all other nodes not in any DD */ +- if (isns_config.ic_use_default_domain) +- isns_db_get_domainless(db, +- obj->ie_template, +- result); +- return; +- } +- +- isns_bitvector_foreach(obj->ie_membership, +- __isns_object_vis_callback, +- result); +-} +- +-/* +- * Object templates +- */ +-static uint32_t discovery_domain_attrs[] = { +- ISNS_TAG_DD_ID, +- ISNS_TAG_DD_SYMBOLIC_NAME, +- ISNS_TAG_DD_MEMBER_ISCSI_INDEX, +- ISNS_TAG_DD_MEMBER_ISCSI_NAME, +- ISNS_TAG_DD_MEMBER_FC_PORT_NAME, +- ISNS_TAG_DD_MEMBER_PORTAL_INDEX, +- ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR, +- ISNS_TAG_DD_MEMBER_PORTAL_TCP_UDP_PORT, +- ISNS_TAG_DD_FEATURES, +-}; +- +-static uint32_t discovery_domain_key_attrs[] = { +- ISNS_TAG_DD_ID, +-}; +- +-isns_object_template_t isns_dd_template = { +- .iot_name = "Discovery Domain", +- .iot_handle = ISNS_OBJECT_TYPE_DD, +- .iot_attrs = discovery_domain_attrs, +- .iot_num_attrs = array_num_elements(discovery_domain_attrs), +- .iot_keys = discovery_domain_key_attrs, +- .iot_num_keys = array_num_elements(discovery_domain_key_attrs), +- .iot_index = ISNS_TAG_DD_ID, +- .iot_next_index = ISNS_TAG_DD_NEXT_ID, +-}; +- +-static uint32_t dd_set_attrs[] = { +- ISNS_TAG_DD_SET_ID, +- ISNS_TAG_DD_SET_SYMBOLIC_NAME, +- ISNS_TAG_DD_SET_STATUS, +-}; +- +-static uint32_t dd_set_key_attrs[] = { +- ISNS_TAG_DD_SET_ID, +-}; +- +-isns_object_template_t isns_ddset_template = { +- .iot_name = "Discovery Domain Set", +- .iot_handle = ISNS_OBJECT_TYPE_DDSET, +- .iot_attrs = dd_set_attrs, +- .iot_num_attrs = array_num_elements(dd_set_attrs), +- .iot_keys = dd_set_key_attrs, +- .iot_num_keys = array_num_elements(dd_set_key_attrs), +- .iot_next_index = ISNS_TAG_DD_SET_NEXT_ID, +-}; +- +diff --git a/utils/open-isns/entity.c b/utils/open-isns/entity.c +deleted file mode 100644 +index cd45e1f..0000000 +--- a/utils/open-isns/entity.c ++++ /dev/null +@@ -1,127 +0,0 @@ +-/* +- * iSNS object model - network entity specific code +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include "isns.h" +-#include "objects.h" +-#include "util.h" +- +-/* +- * Create a network entity +- */ +-isns_object_t * +-isns_create_entity(int protocol, const char *name) +-{ +- isns_object_t *obj; +- +- obj = isns_create_object(&isns_entity_template, NULL, NULL); +- isns_object_set_string(obj, +- ISNS_TAG_ENTITY_IDENTIFIER, +- name); +- isns_object_set_uint32(obj, +- ISNS_TAG_ENTITY_PROTOCOL, +- protocol); +- +- return obj; +-} +- +-isns_object_t * +-isns_create_entity_for_source(const isns_source_t *source, +- const char *eid) +-{ +- switch (isns_source_type(source)) { +- case ISNS_TAG_ISCSI_NAME: +- return isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, eid); +- +- case ISNS_TAG_FC_PORT_NAME_WWPN: +- return isns_create_entity(ISNS_ENTITY_PROTOCOL_IFCP, eid); +- } +- +- return NULL; +-} +- +-const char * +-isns_entity_name(const isns_object_t *node) +-{ +- const isns_attr_t *attr; +- +- if (node->ie_attrs.ial_count == 0) +- return NULL; +- attr = node->ie_attrs.ial_data[0]; +- if (attr->ia_value.iv_type != &isns_attr_type_string +- || attr->ia_tag_id != ISNS_TAG_ENTITY_IDENTIFIER) +- return NULL; +- +- return attr->ia_value.iv_string; +- +-} +- +-int +-isns_object_is_entity(const isns_object_t *obj) +-{ +- return ISNS_IS_ENTITY(obj); +-} +- +-/* +- * 6.2.4. Entity Registration Timestamp +- * +- * This field indicates the most recent time when the Network Entity +- * registration occurred or when an associated object attribute was +- * updated or queried by the iSNS client registering the Network Entity. +- * The time format is, in seconds, the update period since the standard +- * base time of 00:00:00 GMT on January 1, 1970. This field cannot be +- * explicitly registered. This timestamp TLV format is also used in +- * the SCN and ESI messages. +- * +- * Implementer's note: we consider any kind of activity from +- * the client an indication that it is still alive. +- * Only exception is the pseudo-entity that holds the access control +- * information; we never assign it a timestamp so it is never subject +- * to expiry. +- */ +-void +-isns_entity_touch(isns_object_t *obj) +-{ +- /* Do not add a timestamp to entity CONTROL */ +- if (obj == NULL +- || (obj->ie_flags & ISNS_OBJECT_PRIVATE) +- || obj->ie_template != &isns_entity_template) +- return; +- isns_object_set_uint64(obj, ISNS_TAG_TIMESTAMP, time(NULL)); +-} +- +-/* +- * Object template +- */ +-static uint32_t entity_attrs[] = { +- ISNS_TAG_ENTITY_IDENTIFIER, +- ISNS_TAG_ENTITY_PROTOCOL, +- ISNS_TAG_MGMT_IP_ADDRESS, +- ISNS_TAG_TIMESTAMP, +- ISNS_TAG_PROTOCOL_VERSION_RANGE, +- ISNS_TAG_REGISTRATION_PERIOD, +- ISNS_TAG_ENTITY_INDEX, +- ISNS_TAG_ENTITY_ISAKMP_PHASE_1, +- ISNS_TAG_ENTITY_CERTIFICATE, +-}; +- +-static uint32_t entity_key_attrs[] = { +- ISNS_TAG_ENTITY_IDENTIFIER, +-}; +- +-isns_object_template_t isns_entity_template = { +- .iot_name = "Network Entity", +- .iot_handle = ISNS_OBJECT_TYPE_ENTITY, +- .iot_attrs = entity_attrs, +- .iot_num_attrs = array_num_elements(entity_attrs), +- .iot_keys = entity_key_attrs, +- .iot_num_keys = array_num_elements(entity_key_attrs), +- .iot_index = ISNS_TAG_ENTITY_INDEX, +- .iot_next_index = ISNS_TAG_ENTITY_NEXT_INDEX, +-}; +- +diff --git a/utils/open-isns/error.c b/utils/open-isns/error.c +deleted file mode 100644 +index 0d365e8..0000000 +--- a/utils/open-isns/error.c ++++ /dev/null +@@ -1,65 +0,0 @@ +-/* +- * iSNS error strings etc. +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include "isns.h" +- +-const char * +-isns_strerror(enum isns_status status) +-{ +- switch (status) { +- case ISNS_SUCCESS: +- return "Success"; +- case ISNS_UNKNOWN_ERROR: +- return "Unknown error"; +- case ISNS_MESSAGE_FORMAT_ERROR: +- return "Message format error"; +- case ISNS_INVALID_REGISTRATION: +- return "Invalid registration"; +- case ISNS_INVALID_QUERY: +- return "Invalid query"; +- case ISNS_SOURCE_UNKNOWN: +- return "Source unknown"; +- case ISNS_SOURCE_ABSENT: +- return "Source absent"; +- case ISNS_SOURCE_UNAUTHORIZED: +- return "Source unauthorized"; +- case ISNS_NO_SUCH_ENTRY: +- return "No such entry"; +- case ISNS_VERSION_NOT_SUPPORTED: +- return "Version not supported"; +- case ISNS_INTERNAL_ERROR: +- return "Internal error"; +- case ISNS_BUSY: +- return "Busy"; +- case ISNS_OPTION_NOT_UNDERSTOOD: +- return "Option not understood"; +- case ISNS_INVALID_UPDATE: +- return "Invalid update"; +- case ISNS_MESSAGE_NOT_SUPPORTED: +- return "Message not supported"; +- case ISNS_SCN_EVENT_REJECTED: +- return "SCN event rejected"; +- case ISNS_SCN_REGISTRATION_REJECTED: +- return "SCN registration rejected"; +- case ISNS_ATTRIBUTE_NOT_IMPLEMENTED: +- return "Attribute not implemented"; +- case ISNS_FC_DOMAIN_ID_NOT_AVAILABLE: +- return "FC domain id not available"; +- case ISNS_FC_DOMAIN_ID_NOT_ALLOCATED: +- return "FC domain id not allocated"; +- case ISNS_ESI_NOT_AVAILABLE: +- return "ESI not available"; +- case ISNS_INVALID_DEREGISTRATION: +- return "Invalid deregistration"; +- case ISNS_REGISTRATION_FEATURE_NOT_SUPPORTED: +- return "Registration feature not supported"; +- default: +- break; +- } +- +- return "Unknown iSNS status code"; +-} +- +diff --git a/utils/open-isns/esi.c b/utils/open-isns/esi.c +deleted file mode 100644 +index 47d52c6..0000000 +--- a/utils/open-isns/esi.c ++++ /dev/null +@@ -1,576 +0,0 @@ +-/* +- * Handle ESI events +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include "isns.h" +-#include "attrs.h" +-#include "objects.h" +-#include "message.h" +-#include "security.h" +-#include "util.h" +-#include "db.h" +- +-#define ESI_RETRANS_TIMEOUT 60 +- +-typedef struct isns_esi isns_esi_t; +-typedef struct isns_esi_portal isns_esi_portal_t; +- +-struct isns_esi { +- isns_list_t esi_list; +- isns_object_t * esi_object; +- isns_list_t esi_portals; +- +- unsigned int esi_update : 1; +-}; +- +-struct isns_esi_portal { +- isns_list_t esp_list; +- isns_object_t * esp_object; +- isns_portal_info_t esp_portal; +- unsigned int esp_interval; +- isns_portal_info_t esp_dest; +- +- isns_socket_t * esp_socket; +- unsigned int esp_retries; +- unsigned int esp_timeout; +- time_t esp_start; +- time_t esp_next_xmit; +- uint32_t esp_xid; +-}; +- +-int isns_esi_enabled = 0; +-static isns_server_t * isns_esi_server = NULL; +-static ISNS_LIST_DECLARE(isns_esi_list); +- +-static void isns_esi_transmit(void *); +-static void isns_esi_sendto(isns_esi_t *, isns_esi_portal_t *); +-static void isns_process_esi_response(uint32_t, int, +- isns_simple_t *); +-static void isns_esi_disconnect(isns_esi_portal_t *); +-static void isns_esi_restart(isns_esi_portal_t *); +-static void isns_esi_drop_portal(isns_esi_portal_t *, isns_db_t *, int); +-static void isns_esi_drop_entity(isns_esi_t *, isns_db_t *, int); +-static int isns_esi_update(isns_esi_t *); +-static void isns_esi_schedule(int); +-static void isns_esi_callback(const isns_db_event_t *, void *); +- +-void +-isns_esi_init(isns_server_t *srv) +-{ +- if (isns_config.ic_esi_retries == 0) { +- isns_debug_esi("ESI disabled by administrator\n"); +- } else { +- unsigned int max_interval; +- +- isns_register_callback(isns_esi_callback, NULL); +- isns_esi_schedule(0); +- +- max_interval = isns_config.ic_registration_period / 2; +- if (isns_config.ic_esi_max_interval > max_interval) { +- isns_warning("Max ESI interval adjusted to %u sec " +- "to match registration period\n", +- max_interval); +- isns_config.ic_esi_max_interval = max_interval; +- if (isns_config.ic_esi_min_interval > max_interval) +- isns_config.ic_esi_min_interval = max_interval; +- } +- isns_esi_server = srv; +- isns_esi_enabled = 1; +- } +-} +- +-/* +- * Timer callback to send out ESI messages. +- */ +-void +-isns_esi_transmit(void *ptr) +-{ +- isns_db_t *db = isns_esi_server->is_db; +- isns_list_t *esi_pos, *esi_next; +- time_t now; +- isns_object_t *obj; +- time_t next_timeout; +- +- now = time(NULL); +- next_timeout = now + 3600; +- +- isns_list_foreach(&isns_esi_list, esi_pos, esi_next) { +- isns_list_t *esp_pos, *esp_next; +- isns_esi_t *esi = isns_list_item(isns_esi_t, esi_list, esi_pos); +- +- if (esi->esi_update) { +- esi->esi_update = 0; +- if (!isns_esi_update(esi)) +- continue; +- } +- +- isns_list_foreach(&esi->esi_portals, esp_pos, esp_next) { +- isns_esi_portal_t *esp = isns_list_item(isns_esi_portal_t, +- esp_list, esp_pos); +- +- /* Check whether the portal object still exist */ +- obj = esp->esp_object; +- if (obj->ie_state != ISNS_OBJECT_STATE_MATURE) { +- isns_esi_drop_portal(esp, db, 0); +- continue; +- } +- +- if (esp->esp_next_xmit <= now) { +- if (esp->esp_retries == 0) { +- isns_debug_esi("No ESI response from %s - dropping\n", +- isns_portal_string(&esp->esp_dest)); +- isns_esi_drop_portal(esp, db, 1); +- continue; +- } +- +- esp->esp_retries -= 1; +- esp->esp_next_xmit = now + esp->esp_timeout; +- isns_esi_sendto(esi, esp); +- } +- if (esp->esp_next_xmit < next_timeout) +- next_timeout = esp->esp_next_xmit; +- } +- +- if (isns_list_empty(&esi->esi_portals)) +- isns_esi_drop_entity(esi, db, 1); +- } +- +- isns_debug_esi("Next ESI message in %d seconds\n", next_timeout - now); +- isns_esi_schedule(next_timeout - now); +-} +- +-/* +- * Send an ESI message +- */ +-void +-isns_esi_sendto(isns_esi_t *esi, isns_esi_portal_t *esp) +-{ +- isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; +- isns_socket_t *sock; +- isns_simple_t *msg; +- +- /* For TCP portals, kill the TCP socket every time. */ +- if (esp->esp_dest.proto == IPPROTO_TCP) +- isns_esi_disconnect(esp); +- +- if (esp->esp_socket == NULL) { +- sock = isns_connect_to_portal(&esp->esp_dest); +- if (sock == NULL) +- return; +- +- isns_socket_set_security_ctx(sock, +- isns_default_security_context(0)); +- /* sock->is_disconnect_fatal = 1; */ +- esp->esp_socket = sock; +- } +- +- isns_attr_list_append_uint64(&attrs, +- ISNS_TAG_TIMESTAMP, +- time(NULL)); +- /* The following will extract the ENTITY IDENTIFIER */ +- isns_object_extract_keys(esi->esi_object, &attrs); +- isns_portal_to_attr_list(&esp->esp_portal, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- &attrs); +- +- msg = isns_simple_create(ISNS_ENTITY_STATUS_INQUIRY, +- NULL, &attrs); +- if (msg == NULL) +- return; +- +- isns_debug_esi("*** Sending ESI message to %s (xid=0x%x); %u retries left\n", +- isns_portal_string(&esp->esp_dest), +- msg->is_xid, esp->esp_retries); +- isns_simple_transmit(esp->esp_socket, msg, +- NULL, esp->esp_timeout - 1, +- isns_process_esi_response); +- esp->esp_xid = msg->is_xid; +- isns_simple_free(msg); +-} +- +-/* +- * A new entity was added. See if it uses ESI, and create +- * portals and such. +- */ +-static void +-isns_esi_add_entity(isns_object_t *obj) +-{ +- isns_esi_t *esi; +- +- isns_debug_esi("Enable ESI monitoring for entity %u\n", obj->ie_index); +- esi = isns_calloc(1, sizeof(*esi)); +- esi->esi_object = isns_object_get(obj); +- esi->esi_update = 1; +- isns_list_init(&esi->esi_list); +- isns_list_init(&esi->esi_portals); +- +- isns_list_append(&isns_esi_list, &esi->esi_list); +-} +- +-/* +- * Given an entity, see if we can find ESI state for it. +- */ +-static isns_esi_t * +-isns_esi_find(isns_object_t *obj) +-{ +- isns_list_t *pos, *next; +- +- isns_list_foreach(&isns_esi_list, pos, next) { +- isns_esi_t *esi = isns_list_item(isns_esi_t, esi_list, pos); +- +- if (esi->esi_object == obj) +- return esi; +- } +- return NULL; +-} +- +-/* +- * Update the ESI state after an entity has changed +- */ +-static int +-isns_esi_update(isns_esi_t *esi) +-{ +- isns_object_t *entity = esi->esi_object; +- ISNS_LIST_DECLARE(hold); +- isns_esi_portal_t *esp; +- unsigned int i; +- +- isns_debug_esi("Updating ESI state for entity %u\n", entity->ie_index); +- +- isns_list_move(&hold, &esi->esi_portals); +- for (i = 0; i < entity->ie_children.iol_count; ++i) { +- isns_object_t *child = entity->ie_children.iol_data[i]; +- isns_portal_info_t esi_portal, portal_info; +- uint32_t esi_interval; +- isns_list_t *pos, *next; +- int changed = 0; +- +- if (!ISNS_IS_PORTAL(child)) +- continue; +- +- if (!isns_portal_from_object(&portal_info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- child) +- || !isns_portal_from_object(&esi_portal, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_ESI_PORT, +- child) +- || !isns_object_get_uint32(child, +- ISNS_TAG_ESI_INTERVAL, +- &esi_interval)) +- continue; +- +- isns_list_foreach(&hold, pos, next) { +- esp = isns_list_item(isns_esi_portal_t, esp_list, pos); +- +- if (esp->esp_object == child) { +- isns_debug_esi("Updating ESI state for %s\n", +- isns_portal_string(&portal_info)); +- isns_list_del(&esp->esp_list); +- goto update; +- } +- } +- +- isns_debug_esi("Creating ESI state for %s\n", +- isns_portal_string(&portal_info)); +- esp = isns_calloc(1, sizeof(*esp)); +- esp->esp_object = isns_object_get(child); +- isns_list_init(&esp->esp_list); +- changed = 1; +- +-update: +- if (!isns_portal_equal(&esp->esp_portal, &portal_info)) { +- esp->esp_portal = portal_info; +- changed++; +- } +- if (!isns_portal_equal(&esp->esp_dest, &esi_portal)) { +- isns_esi_disconnect(esp); +- esp->esp_dest = esi_portal; +- changed++; +- } +- if (esp->esp_interval != esi_interval) { +- esp->esp_interval = esi_interval; +- changed++; +- } +- +- isns_esi_restart(esp); +- +- isns_list_append(&esi->esi_portals, &esp->esp_list); +- } +- +- /* Destroy any old ESI portals */ +- while (!isns_list_empty(&hold)) { +- esp = isns_list_item(isns_esi_portal_t, esp_list, hold.next); +- +- isns_esi_drop_portal(esp, NULL, 0); +- } +- +- /* If the client explicitly unregistered all ESI portals, +- * stop monitoring it but *without* destroying the entity. */ +- if (isns_list_empty(&esi->esi_portals)) { +- isns_esi_drop_entity(esi, NULL, 0); +- return 0; +- } +- +- return 1; +-} +- +-void +-isns_esi_restart(isns_esi_portal_t *esp) +-{ +- unsigned int timeo; +- +- isns_esi_disconnect(esp); +- +- esp->esp_start = time(NULL); +- esp->esp_retries = isns_config.ic_esi_retries; +- esp->esp_next_xmit = esp->esp_start + esp->esp_interval; +- esp->esp_xid = 0; +- +- timeo = esp->esp_interval / esp->esp_retries; +- if (timeo == 0) +- timeo = 1; +- else if (timeo > ESI_RETRANS_TIMEOUT) +- timeo = ESI_RETRANS_TIMEOUT; +- esp->esp_timeout = timeo; +-} +- +-void +-isns_esi_disconnect(isns_esi_portal_t *esp) +-{ +- if (esp->esp_socket) +- isns_socket_free(esp->esp_socket); +- esp->esp_socket = NULL; +-} +- +-/* +- * Generic wrapper to dropping an object +- */ +-static inline void +-__isns_esi_drop_object(isns_db_t *db, isns_object_t *obj, unsigned int dead) +-{ +- if (db && obj && obj->ie_state == ISNS_OBJECT_STATE_MATURE && dead) +- isns_db_remove(db, obj); +- isns_object_release(obj); +-} +- +-/* +- * Portal did not respond in time. Drop it +- */ +-void +-isns_esi_drop_portal(isns_esi_portal_t *esp, isns_db_t *db, int dead) +-{ +- isns_debug_esi("ESI: dropping portal %s\n", +- isns_portal_string(&esp->esp_portal)); +- +- isns_list_del(&esp->esp_list); +- isns_esi_disconnect(esp); +- __isns_esi_drop_object(db, esp->esp_object, dead); +- isns_free(esp); +-} +- +-/* +- * We ran out of ESI portals for this entity. +- */ +-void +-isns_esi_drop_entity(isns_esi_t *esi, isns_db_t *db, int dead) +-{ +- isns_debug_esi("ESI: dropping entity %u\n", +- esi->esi_object->ie_index); +- +- isns_list_del(&esi->esi_list); +- __isns_esi_drop_object(db, esi->esi_object, dead); +- +- while (!isns_list_empty(&esi->esi_portals)) { +- isns_esi_portal_t *esp; +- +- esp = isns_list_item(isns_esi_portal_t, esp_list, +- esi->esi_portals.next); +- isns_esi_drop_portal(esp, db, dead); +- } +- isns_free(esi); +-} +- +-/* +- * When receiving an ESI response, find the portal we sent the +- * original message to. +- */ +-static isns_esi_portal_t * +-isns_esi_get_msg_portal(uint32_t xid, isns_esi_t **esip) +-{ +- isns_list_t *esi_pos, *esi_next; +- +- isns_list_foreach(&isns_esi_list, esi_pos, esi_next) { +- isns_esi_t *esi = isns_list_item(isns_esi_t, esi_list, esi_pos); +- isns_list_t *esp_pos, *esp_next; +- +- isns_list_foreach(&esi->esi_portals, esp_pos, esp_next) { +- isns_esi_portal_t *esp = isns_list_item(isns_esi_portal_t, +- esp_list, esp_pos); +- +- if (esp->esp_xid == xid) { +- *esip = esi; +- return esp; +- } +- } +- } +- +- return NULL; +-} +- +-/* +- * Handle incoming ESI request +- */ +-int +-isns_process_esi(isns_server_t *srv, isns_simple_t *call, isns_simple_t **reply) +-{ +- const isns_attr_list_t *attrs = &call->is_message_attrs; +- isns_object_t *portal = NULL; +- +- /* We just echo back the attributes sent to us by the server, +- * without further checking. */ +- *reply = isns_simple_create(ISNS_ENTITY_STATUS_INQUIRY, +- srv->is_source, attrs); +- +- /* Look up the portal and update its mtime. +- * This can help the application find out if a portal has +- * seen ESIs recently, and react. +- */ +- if (srv->is_db && attrs->ial_count == 4) { +- const isns_attr_t *addr_attr, *port_attr; +- +- addr_attr = attrs->ial_data[2]; +- port_attr = attrs->ial_data[3]; +- if (addr_attr->ia_tag_id == ISNS_TAG_PORTAL_IP_ADDRESS +- && port_attr->ia_tag_id == ISNS_TAG_PORTAL_TCP_UDP_PORT) { +- isns_attr_list_t key; +- +- key.ial_count = 2; +- key.ial_data = attrs->ial_data + 2; +- portal = isns_db_lookup(srv->is_db, +- &isns_portal_template, +- &key); +- } +- +- if (portal) +- portal->ie_mtime = time(NULL); +- } +- return ISNS_SUCCESS; +-} +- +-void +-isns_process_esi_response(uint32_t xid, int status, isns_simple_t *msg) +-{ +- isns_portal_info_t portal_info; +- isns_esi_portal_t *esp; +- isns_esi_t *esi; +- +- if (msg == NULL) { +- isns_debug_esi("ESI call 0x%x timed out\n", xid); +- return; +- } +- +- /* FIXME: As a matter of security, we should probably +- * verify that the ESI response originated from the +- * portal we sent it to; or at least that it was authenticated +- * by the client we think we're talking to. */ +- +- /* Get the portal */ +- if (!isns_portal_from_attr_list(&portal_info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- &msg->is_message_attrs)) { +- isns_debug_esi("Ignoring unintelligible ESI response\n"); +- return; +- } +- +- if (!(esp = isns_esi_get_msg_portal(xid, &esi))) { +- isns_debug_esi("Ignoring unmatched ESI reply\n"); +- return; +- } +- +- if (!isns_portal_equal(&esp->esp_portal, &portal_info)) { +- isns_warning("Faked ESI response for portal %s\n", +- isns_portal_string(&portal_info)); +- return; +- } +- +- isns_debug_esi("Good ESI response from %s\n", +- isns_portal_string(&portal_info)); +- isns_esi_restart(esp); +- +- /* Refresh the entity's registration timestamp */ +- isns_object_set_uint64(esi->esi_object, +- ISNS_TAG_TIMESTAMP, +- time(NULL)); +- isns_db_sync(isns_esi_server->is_db); +-} +- +-/* +- * Helper function to schedule the next timeout +- */ +-static void +-isns_esi_schedule(int timeout) +-{ +- isns_cancel_timer(isns_esi_transmit, NULL); +- isns_add_oneshot_timer(timeout, isns_esi_transmit, NULL); +-} +- +-/* +- * Register an entity for ESI monitoring. +- * This is called when reloading the database. +- */ +-void +-isns_esi_register(isns_object_t *obj) +-{ +- if (!isns_esi_find(obj)) +- isns_esi_add_entity(obj); +- /* We do not call esi_schedule(0) here; that happens in +- * isns_esi_init already. */ +-} +- +-/* +- * This callback is invoked whenever an object is added/removed/modified. +- * We use this to keep track of ESI portals and such. +- */ +-void +-isns_esi_callback(const isns_db_event_t *ev, void *ptr) +-{ +- isns_object_t *obj, *entity; +- isns_esi_t *esi; +- uint32_t event; +- +- obj = ev->ie_object; +- event = ev->ie_bits; +- +- if (obj->ie_flags & ISNS_OBJECT_PRIVATE) +- return; +- +- isns_debug_esi("isns_esi_callback(%p, 0x%x)\n", obj, event); +- +- if (ISNS_IS_ENTITY(obj) +- && (event & ISNS_SCN_OBJECT_ADDED_MASK)) { +- if (!isns_esi_find(obj)) +- isns_esi_add_entity(obj); +- /* Schedule an immediate ESI timer run */ +- isns_esi_schedule(0); +- return; +- } +- +- if (!(entity = isns_object_get_entity(obj))) +- return; +- +- esi = isns_esi_find(entity); +- if (esi != NULL) +- esi->esi_update = 1; +- +- /* Schedule an immediate ESI timer run */ +- isns_esi_schedule(0); +-} +diff --git a/utils/open-isns/etc/isnsadm.conf b/utils/open-isns/etc/isnsadm.conf +deleted file mode 100644 +index e7ee681..0000000 +--- a/utils/open-isns/etc/isnsadm.conf ++++ /dev/null +@@ -1,73 +0,0 @@ +-# +-# Sample iSNS client configuration file +-# +- +-# The source name. This is an iSCSI qualified name, +-# and identifies the client uniquely. +-# +-# If left empty, the source name is derived from +-# the client's hostname. +-# +-#SourceName = iqn.2006-01.com.example.host1 +- +-# Name and port of the iSNS server. +-# Possible formats: +-# foo.example.com +-# foo.example.com:3205 +-# 192.168.1.7:isns +-# [2001:4e5f::1]:isns +-# SLP: +-# If the special string "SLP:" is given, Open-iSNS will +-# query the SLP directory service to find the iSNS server. +-#ServerAddress = isns.example.com +- +- +-# Authentication enable/disable. +-# When set to 1, the client will sign +-# all messages, and expect all server messages +-# to be signed. +-# +-# Authentication requires a valid private DSA +-# key in AuthKeyFile, and the server's DSA public +-# key in ServerKeyFile. +-# +-# The default is to use authentication if the +-# requires keys are installed, and use unauthenticated +-# iSNS otherwise. +-#Security = 1 +- +-# Location of the client's private key. +-# The file must contain a PEM encoded DSA key. +-# The default is /etc/isns/auth_key +-#AuthKeyFile = /etc/isns/auth_key +- +-# Location of the servers's public key. +-# The file must contain a PEM encoded DSA key. +-# The default is /etc/isns/server_key.pub +-#ServerKeyFile = /etc/isns/server_key.pub +- +-# In order to prevent replay attacks, the +-# authentication blocks carried by iSNS +-# include a time stamp. The following two +-# parameters control how we verify the +-# time stamp +-Auth.ReplayWindow = 2m +-Auth.TimeStampJitter = 1s +- +-# Maximum number of incoming connections +-# accepted. This usually applies to server +-# side only, but is relevant if you create +-# a passive TCP socket for ESI or SCN. +-# Network.MaxSockets = 1024 +- +-# Time to wait for a TCP connection to be +-# established. +-# Network.ConnectTimeout = 60 +- +-# When a connection attempt failed, we wait +-# before we try connecting again. +-# Network.ReonnectTimeout = 10 +- +-# Total amount of time to wait before timing +-# out a call to the iSNS server. +-# Network.CallTimeout = 60 +diff --git a/utils/open-isns/etc/isnsd.conf b/utils/open-isns/etc/isnsd.conf +deleted file mode 100644 +index bc90f40..0000000 +--- a/utils/open-isns/etc/isnsd.conf ++++ /dev/null +@@ -1,129 +0,0 @@ +-# +-# Sample iSNS Server configuration file +-# +- +-# The source name. This is an iSCSI qualified name, +-# and identifies the client uniquely. +-# +-# If left empty, the source name is derived from +-# the client's hostname. +-# +-#SourceName = iqn.2006-01.com.example.host1 +- +-# Where to store the database. +-# If you leave this empty, isnsd will keep its +-# database in memory. +-# Setting this to an absolute path name will +-# make isnsd keep its database in a directory +-# hierarchy below that directory. +-Database = /var/lib/isns +- +-# The iSNS server can purge registered entities +-# after a certain period of inactivity. This is +-# called the registration period. +-# Clients who register objects are supposed to +-# refresh their registration within this period. +-# +-# The default value is 0, which disables this +-# feature. +-RegistrationPeriod = 10m +- +-# iSNS scopes visibility of other nodes using so-called +-# Discovery Domains. A storage node A will only "see" +-# storage node B, if both are members of the same +-# discovery domain. +-# +-# So if a storage node is registered which is not part of +-# any discovery domain, it will not see any other nodes. +-# +-# By setting DefaultDiscoveryDomain=1, you can tell isnsd to +-# create a virtual "default discovery domain", which +-# holds all nodes that are not part of any administratively +-# configured discovery domain. +-DefaultDiscoveryDomain = 1 +- +-# Make the iSNS server register itself with SLP. +-# Clients will be able to discover the server by +-# querying for service type "iscsi:sms", and a query +-# of "(protocols=isns)" +-SLPRegister = 1 +- +-# Authentication enable/disable. +-# When set to 1, the client will sign +-# all messages, and expect all server messages +-# to be signed. +-# +-# Authentication requires a valid private DSA +-# key in AuthKeyFile, and the server's DSA public +-# key in ServerKeyFile. +-# +-# The default is to use authentication if the +-# requires keys are installed, and use unauthenticated +-# iSNS otherwise. +-#Security = 1 +- +-# Location of the client's private key. +-# The file must contain a PEM encoded DSA key. +-# The default is /etc/isns/auth_key +-#AuthKeyFile = /etc/isns/auth_key +- +-# Location of the servers's public key. +-# The file must contain a PEM encoded DSA key. +-# The default is /etc/isns/server_key.pub +-#ServerKeyFile = /etc/isns/server_key.pub +- +-# This describes where the iSNS server stores +-# authentication keys and policy information. +-# Two options are currently supported: a +-# simple key store (flat directory with public +-# keys in PEM encoded files), and the iSNS +-# database itself +-#ClientKeyStore = /etc/isns/keystores +-ClientKeyStore = DB: +- +-# When transmitting State Change Notification, +-# we expect the client to ack them. If the +-# ACK doesn't arrive in due time, we retransmit +-# for a limited number of attempts, cycling +-# through the available portals. +-SCNTimeout = 60 +-SCNRetries = 3 +- +-# Configuration of ESI. +-# Defaults are +-# ESIMaxInterval = 1h +-# ESIMinInterval = 60s +-# ESIRetries = 3 +-# Setting ESIRetries to 0 disables ESI support, and makes +-# the server reject any portal registrations that specify +-# an ESI portal. +-ESIMinInterval = 1m +-ESIMaxInterval = 2m +-ESIRetries = 3 +- +-# In order to prevent replay attacks, the +-# authentication blocks carried by iSNS +-# include a time stamp. The following two +-# parameters control how we verify the +-# time stamp +-Auth.ReplayWindow = 2m +-Auth.TimeStampJitter = 1s +- +-# Maximum number of incoming connections +-# accepted. +-# Network.MaxSockets = 1024 +- +-# Time to wait for a TCP connection to be +-# established. +-# (Client only) +-# Network.ConnectTimeout = 60 +- +-# When a connection attempt failed, we wait +-# before we try connecting again. +-# (Client only) +-# Network.ReonnectTimeout = 10 +- +-# Total amount of time to wait before timing +-# out a call to the iSNS server. +-# (Client only) +-# Network.CallTimeout = 60 +diff --git a/utils/open-isns/etc/isnsdd.conf b/utils/open-isns/etc/isnsdd.conf +deleted file mode 100644 +index d751c3d..0000000 +--- a/utils/open-isns/etc/isnsdd.conf ++++ /dev/null +@@ -1,72 +0,0 @@ +-# +-# Sample iSNS Discovery Daemon configuration file +-# +- +-# The source name. This is an iSCSI qualified name, +-# and identifies the client uniquely. +-# +-# If left empty, the source name is derived from +-# the client's hostname. +-# +-#SourceName = iqn.2006-01.com.example.host1:monitor +- +-# Name and port of the iSNS server. +-# Possible formats: +-# foo.example.com +-# foo.example.com:3205 +-# 192.168.1.7:isns +-# [2001:4e5f::1]:isns +-# SLP: +-# If the special string "SLP:" is given, Open-iSNS will +-# query the SLP directory service to find the iSNS server. +-#ServerAddress = isns.example.com +- +-# Authentication enable/disable. +-# When set to 1, the client will sign +-# all messages, and expect all server messages +-# to be signed. +-# +-# Authentication requires a valid private DSA +-# key in AuthKeyFile, and the server's DSA public +-# key in ServerKeyFile. +-# +-# The default is to use authentication if the +-# required keys are installed, and use unauthenticated +-# iSNS otherwise. +-#Security = 1 +- +-# Location of the client's private key. +-# The file must contain a PEM encoded DSA key. +-# The default is /etc/isns/auth_key +-#AuthKeyFile = /etc/isns/auth_key +- +-# Location of the servers's public key. +-# The file must contain a PEM encoded DSA key. +-# The default is /etc/isns/server_key.pub +-#ServerKeyFile = /etc/isns/server_key.pub +- +-# In order to prevent replay attacks, the +-# authentication blocks carried by iSNS +-# include a time stamp. The following two +-# parameters control how we verify the +-# time stamp +-Auth.ReplayWindow = 2m +-Auth.TimeStampJitter = 1s +- +-# Maximum number of incoming connections +-# accepted. This usually applies to server +-# side only, but is relevant if you create +-# a passive TCP socket for ESI or SCN. +-# Network.MaxSockets = 1024 +- +-# Time to wait for a TCP connection to be +-# established. +-# Network.ConnectTimeout = 60 +- +-# When a connection attempt failed, we wait +-# before we try connecting again. +-# Network.ReonnectTimeout = 10 +- +-# Total amount of time to wait before timing +-# out a call to the iSNS server. +-# Network.CallTimeout = 60 +diff --git a/utils/open-isns/etc/openisns.init b/utils/open-isns/etc/openisns.init +deleted file mode 100644 +index 7c03778..0000000 +--- a/utils/open-isns/etc/openisns.init ++++ /dev/null +@@ -1,71 +0,0 @@ +-#!/bin/sh +-# +-# Init script for Open-iSNS. +-# +-# Copyright (C) 2007 Albert Pauw +-# +-# chkconfig: 345 13 89 +-# description: Starts and stops the iSCSI isns server +-# +-# processname: isnsd +-# pidfile: /var/run/isnsd.pid +-# config: /etc/isns/isnsd.conf +- +-# Source function library. +-. /etc/init.d/functions +- +-PATH=/sbin:/bin:/usr/sbin:/usr/bin +-#OPTIONS="-4 -d all" +-CONFIG="-c /etc/isns/isnsd.conf" +-RETVAL=0 +- +-start() +-{ +- echo -n "Starting iSCSI isns service: " +- daemon isnsd $OPTIONS $CONFIG +- RETVAL=$? +- success +- echo +- [ $RETVAL -eq 0 ] || return +- touch /var/lock/subsys/open-isns +-} +- +-stop() +-{ +- echo -n "Stopping iSCSI isns service: " +- killproc isnsd +- [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/open-isns +- success +- echo +- +-} +- +-restart() +-{ +- stop +- start +-} +- +-case "$1" in +-start) +- start +- ;; +-stop) +- stop +- ;; +-restart) +- restart +- ;; +-status) +- status isnsd +- RETVAL=$? +- ;; +-condrestart) +- [ -f /var/lock/subsys/open-isns ] && restart +- ;; +-*) +- echo $"Usage: $0 {start|stop|restart|status|condrestart}" +- exit 1 +-esac +- +-exit $RETVAL +diff --git a/utils/open-isns/export.c b/utils/open-isns/export.c +deleted file mode 100644 +index fa4c278..0000000 +--- a/utils/open-isns/export.c ++++ /dev/null +@@ -1,547 +0,0 @@ +-/* +- * Helper functions to represent iSNS objects as text, +- * and/or to parse objects represented in textual form. +- * These functions can be used by command line utilities +- * such as isnsadm, as well as applications like iscsid +- * or stgtd when talking to the iSNS discovery daemon. +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#include "isns.h" +-#include "util.h" +-#include "vendor.h" +-#include "attrs.h" +-#include "security.h" +-#include "objects.h" +-#include "paths.h" +- +-#define MAX_ALIASES 4 +- +-struct isns_tag_prefix { +- const char * name; +- unsigned int name_len; +- isns_object_template_t *context; +-}; +- +-struct tag_name { +- const char * name; +- uint32_t tag; +- struct isns_tag_prefix *prefix; +- const char * alias[MAX_ALIASES]; +-}; +- +-static struct isns_tag_prefix all_prefixes[__ISNS_OBJECT_TYPE_MAX] = { +-[ISNS_OBJECT_TYPE_ENTITY] = { "entity-", 7, &isns_entity_template }, +-[ISNS_OBJECT_TYPE_NODE] = { "iscsi-", 6, &isns_iscsi_node_template }, +-[ISNS_OBJECT_TYPE_PORTAL] = { "portal-", 7, &isns_portal_template }, +-[ISNS_OBJECT_TYPE_PG] = { "pg-", 3, &isns_iscsi_pg_template }, +-[ISNS_OBJECT_TYPE_DD] = { "dd-", 3, &isns_dd_template }, +-[ISNS_OBJECT_TYPE_POLICY] = { "policy-", 7, &isns_policy_template }, +-}; +- +-static struct tag_name all_attrs[] = { +-{ "id", ISNS_TAG_ENTITY_IDENTIFIER, +- .alias = { "eid", }, +-}, +-{ "prot", ISNS_TAG_ENTITY_PROTOCOL }, +-{ "idx", ISNS_TAG_ENTITY_INDEX }, +- +-{ "name", ISNS_TAG_ISCSI_NAME }, +-{ "node-type", ISNS_TAG_ISCSI_NODE_TYPE }, +-{ "alias", ISNS_TAG_ISCSI_ALIAS }, +-{ "authmethod", ISNS_TAG_ISCSI_AUTHMETHOD }, +-{ "idx", ISNS_TAG_ISCSI_NODE_INDEX }, +- +-{ "addr", ISNS_TAG_PORTAL_IP_ADDRESS }, +-{ "port", ISNS_TAG_PORTAL_TCP_UDP_PORT }, +-{ "name", ISNS_TAG_PORTAL_SYMBOLIC_NAME }, +-{ "esi-port", ISNS_TAG_ESI_PORT }, +-{ "esi-interval", ISNS_TAG_ESI_INTERVAL }, +-{ "scn-port", ISNS_TAG_SCN_PORT }, +-{ "idx", ISNS_TAG_PORTAL_INDEX }, +- +-{ "name", ISNS_TAG_PG_ISCSI_NAME }, +-{ "addr", ISNS_TAG_PG_PORTAL_IP_ADDR }, +-{ "port", ISNS_TAG_PG_PORTAL_TCP_UDP_PORT }, +-{ "tag", ISNS_TAG_PG_TAG }, +-{ "pgt", ISNS_TAG_PG_TAG }, +-{ "idx", ISNS_TAG_PG_INDEX }, +- +-{ "id", ISNS_TAG_DD_ID }, +-{ "name", ISNS_TAG_DD_SYMBOLIC_NAME }, +-{ "member-name", ISNS_TAG_DD_MEMBER_ISCSI_NAME }, +-{ "member-iscsi-idx", ISNS_TAG_DD_MEMBER_ISCSI_INDEX }, +-{ "member-fc-name", ISNS_TAG_DD_MEMBER_FC_PORT_NAME }, +-{ "member-portal-idx", ISNS_TAG_DD_MEMBER_PORTAL_INDEX }, +-{ "member-addr", ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR }, +-{ "member-port", ISNS_TAG_DD_MEMBER_PORTAL_TCP_UDP_PORT }, +-{ "features", ISNS_TAG_DD_FEATURES }, +- +-{ "name", OPENISNS_TAG_POLICY_SPI, +- .alias = { "spi" }, +-}, +-{ "key", OPENISNS_TAG_POLICY_KEY }, +-{ "entity", OPENISNS_TAG_POLICY_ENTITY }, +-{ "object-type", OPENISNS_TAG_POLICY_OBJECT_TYPE }, +-{ "node-type", OPENISNS_TAG_POLICY_NODE_TYPE }, +-{ "node-name", OPENISNS_TAG_POLICY_NODE_NAME }, +-{ "functions", OPENISNS_TAG_POLICY_FUNCTIONS }, +- +-{ NULL } +-}; +- +-/* +- * Initialize tag array +- */ +-static void +-init_tags(void) +-{ +- struct tag_name *t; +- +- for (t = all_attrs; t->name; ++t) { +- isns_object_template_t *tmpl; +- +- tmpl = isns_object_template_for_tag(t->tag); +- if (tmpl == NULL) +- isns_fatal("Bug: cannot find object type for tag %s\n", +- t->name); +- t->prefix = &all_prefixes[tmpl->iot_handle]; +- } +-} +- +-/* +- * Match prefix +- */ +-static struct isns_tag_prefix * +-find_prefix(const char *name) +-{ +- struct isns_tag_prefix *p; +- unsigned int i; +- +- for (i = 0, p = all_prefixes; i < __ISNS_OBJECT_TYPE_MAX; ++i, ++p) { +- if (p->name && !strncmp(name, p->name, p->name_len)) +- return p; +- } +- return NULL; +-} +- +-/* +- * Look up the tag for a given attribute name. +- * By default, attr names come with a disambiguating +- * prefix that defines the object type the attribute applies +- * to, such as "entity-" or "portal-". Once a context has +- * been established (ie we know the object type subsequent +- * attributes apply to), specifying the prefix is optional. +- * +- * For instance, in a portal context, "addr=10.1.1.1 port=616 name=foo" +- * specifies three portal related attributes. Whereas in a portal +- * group context, the same string would specify three portal group +- * related attributes. To disambiguate, the first attribute in +- * this list should be prefixed by "portal-" or "pg-", respectively. +- */ +-static uint32_t +-tag_by_name(const char *name, struct isns_attr_list_parser *st) +-{ +- const char *orig_name = name; +- unsigned int nmatch = 0, i; +- struct tag_name *t, *match[8]; +- struct isns_tag_prefix *specific = NULL; +- +- if (all_attrs[0].prefix == NULL) +- init_tags(); +- +- specific = find_prefix(name); +- if (specific != NULL) { +- if (st->prefix +- && st->prefix != specific +- && !st->multi_type_permitted) { +- isns_error("Cannot mix attributes of different types\n"); +- return 0; +- } +- name += specific->name_len; +- st->prefix = specific; +- } +- +- for (t = all_attrs; t->name; ++t) { +- if (specific && t->prefix != specific) +- continue; +- if (!st->multi_type_permitted +- && st->prefix && t->prefix != st->prefix) +- continue; +- if (!strcmp(name, t->name)) +- goto match; +- for (i = 0; i < MAX_ALIASES && t->alias[i]; ++i) { +- if (!strcmp(name, t->alias[i])) +- goto match; +- } +- continue; +- +-match: +- if (nmatch < 8) +- match[nmatch++] = t; +- } +- +- if (nmatch > 1) { +- char conflict[128]; +- unsigned int i; +- +- conflict[0] = '\0'; +- for (i = 0; i < nmatch; ++i) { +- if (i) +- strcat(conflict, ", "); +- t = match[i]; +- strcat(conflict, t->prefix->name); +- strcat(conflict, t->name); +- } +- isns_error("tag name \"%s\" not unique in this context " +- "(could be one of %s)\n", +- orig_name, conflict); +- return 0; +- } +- +- if (nmatch == 0) { +- isns_error("tag name \"%s\" not known in this context\n", +- orig_name); +- return 0; +- } +- +- st->prefix = match[0]->prefix; +- return match[0]->tag; +-} +- +-static const char * +-name_by_tag(uint32_t tag, struct isns_attr_list_parser *st) +-{ +- struct tag_name *t; +- +- for (t = all_attrs; t->name; ++t) { +- if (st->prefix && t->prefix != st->prefix) +- continue; +- if (t->tag == tag) +- return t->name; +- } +- return NULL; +-} +- +-static int +-parse_one_attr(const char *name, const char *value, +- isns_attr_list_t *attrs, +- struct isns_attr_list_parser *st) +-{ +- isns_attr_t *attr; +- uint32_t tag; +- +- /* Special case: "portal=" is translated to +- * addr=
port= +- * If no context has been set, assume portal context. +- */ +- if (!strcasecmp(name, "portal")) { +- isns_portal_info_t portal_info; +- uint32_t addr_tag, port_tag; +- +- if (st->prefix == NULL) { +- addr_tag = tag_by_name("portal-addr", st); +- port_tag = tag_by_name("portal-port", st); +- } else { +- addr_tag = tag_by_name("addr", st); +- port_tag = tag_by_name("port", st); +- } +- +- if (!addr_tag || !port_tag) { +- isns_error("portal=... not supported in this context\n"); +- return 0; +- } +- if (value == NULL) { +- isns_attr_list_append_nil(attrs, addr_tag); +- isns_attr_list_append_nil(attrs, port_tag); +- return 1; +- } +- if (!isns_portal_parse(&portal_info, value, st->default_port)) +- return 0; +- isns_portal_to_attr_list(&portal_info, addr_tag, port_tag, attrs); +- return 1; +- } +- +- if (!(tag = tag_by_name(name, st))) +- return 0; +- +- /* Special handling for key objects */ +- if (tag == OPENISNS_TAG_POLICY_KEY) { +- if (!value || !strcasecmp(value, "gen")) { +- if (st->generate_key == NULL) { +- isns_error("Key generation not supported in this context\n"); +- return 0; +- } +- attr = st->generate_key(); +- } else { +- if (st->load_key == NULL) { +- isns_error("Policy-key attribute not supported in this context\n"); +- return 0; +- } +- attr = st->load_key(value); +- } +- goto append_attr; +- } +- +- if (value == NULL) { +- isns_attr_list_append_nil(attrs, tag); +- return 1; +- } +- +- attr = isns_attr_from_string(tag, value); +- if (!attr) +- return 0; +- +-append_attr: +- isns_attr_list_append_attr(attrs, attr); +- return 1; +-} +- +-void +-isns_attr_list_parser_init(struct isns_attr_list_parser *st, +- isns_object_template_t *tmpl) +-{ +- if (all_attrs[0].prefix == NULL) +- init_tags(); +- +- memset(st, 0, sizeof(*st)); +- if (tmpl) +- st->prefix = &all_prefixes[tmpl->iot_handle]; +-} +- +-int +-isns_attr_list_split(char *line, char **argv, unsigned int argc_max) +-{ +- char *src = line; +- unsigned int argc = 0, quoted = 0; +- +- if (!line) +- return 0; +- +- while (1) { +- char *dst; +- +- while (isspace(*src)) +- ++src; +- if (!*src) +- break; +- +- argv[argc] = dst = src; +- while (*src) { +- char cc = *src++; +- +- if (cc == '"') { +- quoted = !quoted; +- continue; +- } +- if (!quoted && isspace(cc)) { +- *dst = '\0'; +- break; +- } +- *dst++ = cc; +- } +- +- if (quoted) { +- isns_error("%s: Unterminated quoted string: \"%s\"\n", +- __FUNCTION__, argv[argc]); +- return -1; +- } +- argc++; +- } +- +- return argc; +-} +- +-int +-isns_parse_attrs(unsigned int argc, char **argv, +- isns_attr_list_t *attrs, +- struct isns_attr_list_parser *st) +-{ +- unsigned int i; +- +- for (i = 0; i < argc; ++i) { +- char *name, *value; +- +- name = argv[i]; +- if ((value = strchr(name, '=')) != NULL) +- *value++ = '\0'; +- +- if (!value && !st->nil_permitted) { +- isns_error("Missing value for atribute %s\n", name); +- return 0; +- } +- +- if (!parse_one_attr(name, value, attrs, st)) { +- isns_error("Unable to parse %s=%s\n", name, value); +- return 0; +- } +- } +- +- return 1; +-} +- +-/* +- * Query strings may contain a mix of query keys (foo=bar), +- * and requested attributes (?foo). The former are used by +- * the server in its object search, whereas the latter instruct +- * it which attributes to return. +- */ +-int +-isns_parse_query_attrs(unsigned int argc, char **argv, +- isns_attr_list_t *keys, +- isns_attr_list_t *requested_attrs, +- struct isns_attr_list_parser *st) +-{ +- struct isns_attr_list_parser query_state; +- unsigned int i; +- +- query_state = *st; +- query_state.multi_type_permitted = 1; +- +- for (i = 0; i < argc; ++i) { +- char *name, *value; +- +- name = argv[i]; +- if ((value = strchr(name, '=')) != NULL) +- *value++ = '\0'; +- +- if (name[0] == '?') { +- uint32_t tag; +- +- if (value) { +- isns_error("No value allowed for query attribute %s\n", +- name); +- return 0; +- } +- +- if ((tag = tag_by_name(name + 1, &query_state)) != 0) { +- isns_attr_list_append_nil(requested_attrs, tag); +- continue; +- } +- } else { +- if (!value && !st->nil_permitted) { +- isns_error("Missing value for atribute %s\n", name); +- return 0; +- } +- +- if (parse_one_attr(name, value, keys, st)) +- continue; +- } +- +- isns_error("Unable to parse %s=%s\n", name, value); +- return 0; +- } +- +- return 1; +-} +- +-void +-isns_attr_list_parser_help(struct isns_attr_list_parser *st) +-{ +- isns_object_template_t *tmpl, *current = NULL; +- struct tag_name *t; +- +- if (all_attrs[0].prefix == NULL) +- init_tags(); +- +- for (t = all_attrs; t->name; ++t) { +- const isns_tag_type_t *tag_type; +- char namebuf[64]; +- const char *help; +- unsigned int i; +- +- if (st && !st->multi_type_permitted +- && st->prefix && t->prefix != st->prefix) +- continue; +- +- tmpl = t->prefix->context; +- if (tmpl != current) { +- printf("\nAttributes for object type %s; using prefix %s\n", +- tmpl->iot_name, t->prefix->name); +- current = tmpl; +- } +- +- snprintf(namebuf, sizeof(namebuf), "%s%s", t->prefix->name, t->name); +- printf(" %-20s ", namebuf); +- +- tag_type = isns_tag_type_by_id(t->tag); +- if (tag_type == NULL) { +- printf("Unknown\n"); +- continue; +- } +- printf("%s (%s", tag_type->it_name, +- tag_type->it_type->it_name); +- +- if (tag_type->it_readonly) +- printf("; readonly"); +- if (tag_type->it_multiple) +- printf("; multiple instances"); +- printf(")"); +- +- help = NULL; +- if (t->tag == OPENISNS_TAG_POLICY_KEY) { +- help = "name of key file, or \"gen\" for key generation"; +- } else +- if (tag_type->it_help) +- help = tag_type->it_help(); +- +- if (help) { +- if (strlen(help) < 20) +- printf(" [%s]", help); +- else +- printf("\n%25s[%s]", "", help); +- } +- printf("\n"); +- +- if (t->alias[0]) { +- printf("%25sAliases:", ""); +- for (i = 0; i < MAX_ALIASES && t->alias[i]; ++i) +- printf(" %s", t->alias[i]); +- printf("\n"); +- } +- } +-} +- +-isns_object_template_t * +-isns_attr_list_parser_context(const struct isns_attr_list_parser *st) +-{ +- if (st->prefix) +- return st->prefix->context; +- return NULL; +-} +- +-int +-isns_print_attrs(isns_object_t *obj, char **argv, unsigned int argsmax) +-{ +- struct isns_attr_list_parser st; +- unsigned int i, argc = 0; +- +- isns_attr_list_parser_init(&st, obj->ie_template); +- +- for (i = 0; i < obj->ie_attrs.ial_count; ++i) { +- isns_attr_t *attr = obj->ie_attrs.ial_data[i]; +- char argbuf[512], value[512]; +- const char *name; +- +- name = name_by_tag(attr->ia_tag_id, &st); +- if (name == NULL) +- continue; +- if (argc + 1 >= argsmax) +- break; +- +- snprintf(argbuf, sizeof(argbuf), "%s%s=%s", +- st.prefix->name, name, +- isns_attr_print_value(attr, value, sizeof(value))); +- argv[argc++] = isns_strdup(argbuf); +- } +- +- argv[argc] = NULL; +- return argc; +-} +diff --git a/utils/open-isns/getnext.c b/utils/open-isns/getnext.c +deleted file mode 100644 +index 916ee80..0000000 +--- a/utils/open-isns/getnext.c ++++ /dev/null +@@ -1,257 +0,0 @@ +-/* +- * Handle iSNS DevGetNext +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include "isns.h" +-#include "attrs.h" +-#include "message.h" +-#include "security.h" +-#include "objects.h" +-#include "db.h" +-#include "util.h" +- +-/* +- * Create a GetNext query, and set the source name +- */ +-static isns_simple_t * +-__isns_create_getnext(isns_source_t *source, +- const isns_attr_list_t *key, +- const isns_attr_list_t *scope) +-{ +- isns_simple_t *simp; +- +- simp = isns_simple_create(ISNS_DEVICE_GET_NEXT, source, key); +- if (simp && scope) +- isns_attr_list_copy(&simp->is_operating_attrs, +- scope); +- return simp; +-} +- +-isns_simple_t * +-isns_create_getnext(isns_client_t *clnt, +- isns_object_template_t *tmpl, +- const isns_attr_list_t *scope) +-{ +- isns_simple_t *simp; +- unsigned int i; +- +- simp = __isns_create_getnext(clnt->ic_source, NULL, scope); +- if (simp == NULL) +- return NULL; +- +- for (i = 0; i < tmpl->iot_num_keys; ++i) { +- isns_attr_list_append_nil(&simp->is_message_attrs, +- tmpl->iot_keys[i]); +- } +- return simp; +-} +- +-isns_simple_t * +-isns_create_getnext_followup(isns_client_t *clnt, +- const isns_simple_t *resp, +- const isns_attr_list_t *scope) +-{ +- return __isns_create_getnext(clnt->ic_source, +- &resp->is_message_attrs, scope); +-} +- +-/* +- * Get the list of objects matching this query +- */ +-static int +-isns_getnext_get_object(isns_simple_t *qry, isns_db_t *db, +- isns_object_t **result) +-{ +- isns_scope_t *scope; +- isns_attr_list_t *keys = &qry->is_message_attrs, match; +- isns_object_template_t *tmpl; +- unsigned int i; +- +- /* +- * 5.6.5.3. +- * The Message Key Attribute may be an Entity Identifier (EID), +- * iSCSI Name, iSCSI Index, Portal IP Address and TCP/UDP Port, +- * Portal Index, PG Index, FC Node Name WWNN, or FC Port Name +- * WWPN. +- * +- * Implementer's comment: In other words, it must be the +- * key attr(s) of a specific object type, or an index attribute. +- */ +- if ((tmpl = isns_object_template_for_key_attrs(keys)) != NULL) { +- if (keys->ial_count != tmpl->iot_num_keys) +- return ISNS_INVALID_QUERY; +- } else if (keys->ial_count == 1) { +- isns_attr_t *attr = keys->ial_data[0]; +- +- tmpl = isns_object_template_for_index_tag(attr->ia_tag_id); +- } +- if (tmpl == NULL) +- return ISNS_INVALID_QUERY; +- +- /* Verify whether the client is permitted to retrieve +- * objects of the given type. */ +- if (!isns_policy_validate_object_type(qry->is_policy, tmpl, +- qry->is_function)) +- return ISNS_SOURCE_UNAUTHORIZED; +- +- /* +- * 5.6.5.3. +- * The Operating Attributes can be used to specify the scope +- * of the DevGetNext request, and to specify the attributes of +- * the next object, which are to be returned in the DevGetNext +- * response message. All Operating Attributes MUST be attributes +- * of the object type identified by the Message Key. +- */ +- match = qry->is_operating_attrs; +- for (i = 0; i < match.ial_count; ++i) { +- isns_attr_t *attr = match.ial_data[i]; +- +- if (tmpl != isns_object_template_for_tag(attr->ia_tag_id)) +- return ISNS_INVALID_QUERY; +- } +- +- /* +- * 5.6.5.3. +- * Non-zero-length TLV attributes in the Operating Attributes +- * are used to scope the DevGetNext message. +- * [...] +- * Zero-length TLV attributes MUST be listed after non-zero-length +- * attributes in the Operating Attributes of the DevGetNext +- * request message. +- */ +- for (i = 0; i < match.ial_count; ++i) { +- if (ISNS_ATTR_IS_NIL(match.ial_data[i])) { +- match.ial_count = i; +- break; +- } +- } +- +- /* Get the scope for the originating node. */ +- scope = isns_scope_for_call(db, qry); +- +- *result = isns_scope_get_next(scope, tmpl, keys, &match); +- +- isns_scope_release(scope); +- +- if (*result == NULL) +- return ISNS_NO_SUCH_ENTRY; +- return ISNS_SUCCESS; +-} +- +-/* +- * Create a Query Response +- */ +-static isns_simple_t * +-isns_create_getnext_response(isns_source_t *source, +- const isns_simple_t *qry, isns_object_t *obj) +-{ +- const isns_attr_list_t *req_attrs = NULL; +- isns_attr_list_t requested; +- isns_simple_t *resp; +- unsigned int i; +- +- resp = __isns_create_getnext(source, NULL, NULL); +- +- /* +- * 5.7.5.3. Device Get Next Response (DevGetNextRsp) +- * The Message Key Attribute field returns the object keys +- * for the next object after the Message Key Attribute in the +- * original DevGetNext message. +- * +- * Implementer's note: slightly convoluted English here. +- * I *think* this means the key attributes of the object +- * we matched. +- */ +- if (!isns_object_get_key_attrs(obj, &resp->is_message_attrs)) +- return NULL; +- +- /* +- * 5.7.5.3. +- * The Operating Attribute field returns the Operating Attributes +- * of the next object as requested in the original DevGetNext +- * message. The values of the Operating Attributes are those +- * associated with the object identified by the Message Key +- * Attribute field of the DevGetNextRsp message. +- * +- * Implementer's note: the RFC doesn't say clearly what to +- * do when the list of operating attributes does not +- * contain any NIL TLVs. Let's default to the same +- * behavior as elsewhere, and return all attributes +- * in this case. +- */ +- req_attrs = &qry->is_operating_attrs; +- for (i = 0; i < req_attrs->ial_count; ++i) { +- if (ISNS_ATTR_IS_NIL(req_attrs->ial_data[i])) +- break; +- } +- requested.ial_count = req_attrs->ial_count - i; +- requested.ial_data = req_attrs->ial_data + i; +- if (requested.ial_count) +- req_attrs = &requested; +- else +- req_attrs = NULL; +- +- isns_object_get_attrlist(obj, +- &resp->is_operating_attrs, +- req_attrs); +- return resp; +-} +- +-/* +- * Process a GetNext request +- */ +-int +-isns_process_getnext(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) +-{ +- isns_simple_t *reply = NULL; +- isns_object_t *obj = NULL; +- isns_db_t *db = srv->is_db; +- int status; +- +- /* Get the next object */ +- status = isns_getnext_get_object(call, db, &obj); +- if (status != ISNS_SUCCESS) +- goto done; +- +- /* If it's a virtual object, rebuild it */ +- if (obj->ie_rebuild) +- obj->ie_rebuild(obj, srv->is_db); +- +- /* Success: create a new simple message, and +- * send it in our reply. */ +- reply = isns_create_getnext_response(srv->is_source, call, obj); +- if (reply == NULL) +- status = ISNS_INTERNAL_ERROR; +- +-done: +- if (obj) +- isns_object_release(obj); +- *result = reply; +- return status; +-} +- +-/* +- * Parse the object in a getnext response +- */ +-int +-isns_getnext_response_get_object(isns_simple_t *qry, +- isns_object_t **result) +-{ +- isns_object_template_t *tmpl; +- +- tmpl = isns_object_template_for_key_attrs(&qry->is_operating_attrs); +- if (tmpl == NULL) { +- isns_error("Cannot determine object type in GetNext response\n"); +- return ISNS_ATTRIBUTE_NOT_IMPLEMENTED; +- } +- +- *result = isns_create_object(tmpl, +- &qry->is_operating_attrs, +- NULL); +- return ISNS_SUCCESS; +-} +- +diff --git a/utils/open-isns/internal.h b/utils/open-isns/internal.h +deleted file mode 100644 +index fb80b48..0000000 +--- a/utils/open-isns/internal.h ++++ /dev/null +@@ -1,16 +0,0 @@ +-/* +- * iSNS implementation - internal functions and types +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#ifndef ISNS_INTERNAL_H +-#define ISNS_INTERNAL_H +- +-extern char * isns_slp_build_url(uint16_t); +-extern int isns_slp_register(const char *); +-extern int isns_slp_unregister(const char *); +-extern char * isns_slp_find(void); +- +-#endif /* ISNS_INTERNAL_H */ +- +diff --git a/utils/open-isns/isns-proto.h b/utils/open-isns/isns-proto.h +deleted file mode 100644 +index fbc3376..0000000 +--- a/utils/open-isns/isns-proto.h ++++ /dev/null +@@ -1,259 +0,0 @@ +-/* +- * iSNS protocol definitions +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#ifndef ISNS_PROTO_H +-#define ISNS_PROTO_H +- +-#include +- +-struct isns_hdr { +- uint16_t i_version; +- uint16_t i_function; +- uint16_t i_length; +- uint16_t i_flags; +- uint16_t i_xid; +- uint16_t i_seq; +-}; +- +-#define ISNS_VERSION 0x0001 +-#define ISNS_MAX_PDU_SIZE 65535 +-#define ISNS_DEFAULT_PORT 3205 +- +-/* +- * Values for the i_flags field: +- */ +-#define ISNS_F_CLIENT 0x8000 +-#define ISNS_F_SERVER 0x4000 +-#define ISNS_F_AUTHBLK_PRESENT 0x2000 +-#define ISNS_F_REPLACE 0x1000 +-#define ISNS_F_LAST_PDU 0x0800 +-#define ISNS_F_FIRST_PDU 0x0400 +- +-/* +- * Function values +- */ +-enum isns_function { +- ISNS_DEVICE_ATTRIBUTE_REGISTER = 1, +- ISNS_DEVICE_ATTRIBUTE_QUERY = 2, +- ISNS_DEVICE_GET_NEXT = 3, +- ISNS_DEVICE_DEREGISTER = 4, +- ISNS_SCN_REGISTER = 5, +- ISNS_SCN_DEREGISTER = 6, +- ISNS_SCN_EVENT = 7, +- ISNS_STATE_CHANGE_NOTIFICATION = 8, +- ISNS_DD_REGISTER = 9, +- ISNS_DD_DEREGISTER = 10, +- ISNS_DDS_REGISTER = 11, +- ISNS_DDS_DEREGISTER = 12, +- ISNS_ENTITY_STATUS_INQUIRY = 13, +- ISNS_HEARTBEAT = 14, +-}; +- +-/* +- * iSNS status codes: +- */ +-enum isns_status { +- ISNS_SUCCESS = 0, +- ISNS_UNKNOWN_ERROR, +- ISNS_MESSAGE_FORMAT_ERROR, +- ISNS_INVALID_REGISTRATION, +- __ISNS_RESERVED_STATUS, +- ISNS_INVALID_QUERY, +- ISNS_SOURCE_UNKNOWN, +- ISNS_SOURCE_ABSENT, +- ISNS_SOURCE_UNAUTHORIZED, +- ISNS_NO_SUCH_ENTRY, +- ISNS_VERSION_NOT_SUPPORTED, +- ISNS_INTERNAL_ERROR, +- ISNS_BUSY, +- ISNS_OPTION_NOT_UNDERSTOOD, +- ISNS_INVALID_UPDATE, +- ISNS_MESSAGE_NOT_SUPPORTED, +- ISNS_SCN_EVENT_REJECTED, +- ISNS_SCN_REGISTRATION_REJECTED, +- ISNS_ATTRIBUTE_NOT_IMPLEMENTED, +- ISNS_FC_DOMAIN_ID_NOT_AVAILABLE, +- ISNS_FC_DOMAIN_ID_NOT_ALLOCATED, +- ISNS_ESI_NOT_AVAILABLE, +- ISNS_INVALID_DEREGISTRATION, +- ISNS_REGISTRATION_FEATURE_NOT_SUPPORTED, +-}; +- +-enum isns_tag { +- ISNS_TAG_DELIMITER = 0, +- ISNS_TAG_ENTITY_IDENTIFIER = 1, +- ISNS_TAG_ENTITY_PROTOCOL = 2, +- ISNS_TAG_MGMT_IP_ADDRESS = 3, +- ISNS_TAG_TIMESTAMP = 4, +- ISNS_TAG_PROTOCOL_VERSION_RANGE = 5, +- ISNS_TAG_REGISTRATION_PERIOD = 6, +- ISNS_TAG_ENTITY_INDEX = 7, +- ISNS_TAG_ENTITY_NEXT_INDEX = 8, +- ISNS_TAG_ENTITY_ISAKMP_PHASE_1 = 11, +- ISNS_TAG_ENTITY_CERTIFICATE = 12, +- ISNS_TAG_PORTAL_IP_ADDRESS = 16, +- ISNS_TAG_PORTAL_TCP_UDP_PORT = 17, +- ISNS_TAG_PORTAL_SYMBOLIC_NAME = 18, +- ISNS_TAG_ESI_INTERVAL = 19, +- ISNS_TAG_ESI_PORT = 20, +- ISNS_TAG_PORTAL_INDEX = 22, +- ISNS_TAG_SCN_PORT = 23, +- ISNS_TAG_PORTAL_NEXT_INDEX = 24, +- ISNS_TAG_PORTAL_SECURITY_BITMAP = 27, +- ISNS_TAG_PORTAL_ISAKMP_PHASE_1 = 28, +- ISNS_TAG_PORTAL_ISAKMP_PHASE_2 = 29, +- ISNS_TAG_PORTAL_CERTIFICATE = 31, +- ISNS_TAG_ISCSI_NAME = 32, +- ISNS_TAG_ISCSI_NODE_TYPE = 33, +- ISNS_TAG_ISCSI_ALIAS = 34, +- ISNS_TAG_ISCSI_SCN_BITMAP = 35, +- ISNS_TAG_ISCSI_NODE_INDEX = 36, +- ISNS_TAG_WWNN_TOKEN = 37, +- ISNS_TAG_ISCSI_NODE_NEXT_INDEX = 38, +- ISNS_TAG_ISCSI_AUTHMETHOD = 42, +- ISNS_TAG_PG_ISCSI_NAME = 48, +- ISNS_TAG_PG_PORTAL_IP_ADDR = 49, +- ISNS_TAG_PG_PORTAL_TCP_UDP_PORT = 50, +- ISNS_TAG_PG_TAG = 51, +- ISNS_TAG_PG_INDEX = 52, +- ISNS_TAG_PG_NEXT_INDEX = 53, +- ISNS_TAG_FC_PORT_NAME_WWPN = 64, +- ISNS_TAG_PORT_ID = 65, +- ISNS_TAG_FC_PORT_TYPE = 66, +- ISNS_TAG_SYMBOLIC_PORT_NAME = 67, +- ISNS_TAG_FABRIC_PORT_NAME = 68, +- ISNS_TAG_HARD_ADDRESS = 69, +- ISNS_TAG_PORT_IP_ADDRESS = 70, +- ISNS_TAG_CLASS_OF_SERVICE = 71, +- ISNS_TAG_FC4_TYPES = 72, +- ISNS_TAG_FC4_DESCRIPTOR = 73, +- ISNS_TAG_FC4_FEATURES = 74, +- ISNS_TAG_IFCP_SCN_BITMAP = 75, +- ISNS_TAG_PORT_ROLE = 76, +- ISNS_TAG_PERMANENT_PORT_NAME = 77, +- ISNS_TAG_FC4_TYPE_CODE = 95, +- ISNS_TAG_FC_NODE_NAME_WWNN = 96, +- ISNS_TAG_SYMBOLIC_NODE_NAME = 97, +- ISNS_TAG_NODE_IP_ADDRESS = 98, +- ISNS_TAG_NODE_IPA = 99, +- ISNS_TAG_PROXY_ISCSI_NAME = 101, +- ISNS_TAG_SWITCH_NAME = 128, +- ISNS_TAG_PREFERRED_ID = 129, +- ISNS_TAG_ASSIGNED_ID = 130, +- ISNS_TAG_VIRTUAL_FABRIC_ID = 131, +- ISNS_TAG_SERVER_VENDOR_OUI = 256, +- ISNS_TAG_DD_SET_ID = 2049, +- ISNS_TAG_DD_SET_SYMBOLIC_NAME = 2050, +- ISNS_TAG_DD_SET_STATUS = 2051, +- ISNS_TAG_DD_SET_NEXT_ID = 2052, +- ISNS_TAG_DD_ID = 2065, +- ISNS_TAG_DD_SYMBOLIC_NAME = 2066, +- ISNS_TAG_DD_MEMBER_ISCSI_INDEX = 2067, +- ISNS_TAG_DD_MEMBER_ISCSI_NAME = 2068, +- ISNS_TAG_DD_MEMBER_FC_PORT_NAME = 2069, +- ISNS_TAG_DD_MEMBER_PORTAL_INDEX = 2070, +- ISNS_TAG_DD_MEMBER_PORTAL_IP_ADDR = 2071, +- ISNS_TAG_DD_MEMBER_PORTAL_TCP_UDP_PORT = 2072, +- ISNS_TAG_DD_FEATURES = 2078, +- ISNS_TAG_DD_NEXT_ID = 2079, +- +- __ISNS_TAG_MAX, +- +- ISNS_VENDOR_SPECIFIC_SERVER_BASE = 257, /* end 384 */ +- ISNS_VENDOR_SPECIFIC_ENTITY_BASE = 385, /* end 512 */ +- ISNS_VENDOR_SPECIFIC_PORTAL_BASE = 513, /* end 640 */ +- ISNS_VENDOR_SPECIFIC_NODE_BASE = 641, /* end 768 */ +- ISNS_VENDOR_SPECIFIC_DD_BASE = 1024, /* end 1280 */ +- ISNS_VENDOR_SPECIFIC_DDSET_BASE = 1281, /* end 1536 */ +- ISNS_VENDOR_SPECIFIC_OTHER_BASE = 1537, /* end 2048 */ +-}; +- +-typedef enum isns_entity_protocol { +- ISNS_ENTITY_PROTOCOL_NONE = 1, +- ISNS_ENTITY_PROTOCOL_ISCSI = 2, +- ISNS_ENTITY_PROTOCOL_IFCP = 3, +-} isns_entity_protocol_t; +- +-enum isns_iscsi_node_type_bits { +- ISNS_ISCSI_NODE_TYPE_TARGET = 0, +- ISNS_ISCSI_NODE_TYPE_INITIATOR = 1, +- ISNS_ISCSI_NODE_TYPE_CONTROL = 2, +-}; +-#define ISNS_ISCSI_INITIATOR_MASK (1 << ISNS_ISCSI_NODE_TYPE_INITIATOR) +-#define ISNS_ISCSI_TARGET_MASK (1 << ISNS_ISCSI_NODE_TYPE_TARGET) +-#define ISNS_ISCSI_CONTROL_MASK (1 << ISNS_ISCSI_NODE_TYPE_CONTROL) +- +-enum isns_portal_port_bits { +- ISNS_PORTAL_PORT_UDP = 16, +-}; +-#define ISNS_PORTAL_PORT_UDP_MASK (1 << ISNS_PORTAL_PORT_UDP) +- +-enum isns_portal_security_bits { +- ISNS_PORTAL_SEC_BITMAP_VALID = 0, +- ISNS_PORTAL_SEC_IPSEC_ENABLED = 1, +- ISNS_PORTAL_SEC_MAIN_MODE_ENABLED = 2, +- ISNS_PORTAL_SEC_AGGR_MODE_ENABLED = 3, +- ISNS_PORTAL_SEC_PFS_ENABLED = 4, +- ISNS_PORTAL_SEC_TRANSPORT_MODE_PREFERRED = 5, +- ISNS_PORTAL_SEC_TUNNEL_MODE_PREFERRED = 6, +-}; +-#define ISNS_PORTAL_SEC_BITMAP_VALID_MASK (1 << ISNS_PORTAL_SEC_BITMAP_VALID) +-#define ISNS_PORTAL_SEC_IPSEC_ENABLED_MASK (1 << ISNS_PORTAL_SEC_IPSEC_ENABLED) +-#define ISNS_PORTAL_SEC_MAIN_MODE_ENABLED_MASK (1 << ISNS_PORTAL_SEC_MAIN_MODE_ENABLED) +-#define ISNS_PORTAL_SEC_AGGR_MODE_ENABLED_MASK (1 << ISNS_PORTAL_SEC_AGGR_MODE_ENABLED) +-#define ISNS_PORTAL_SEC_PFS_ENABLED_MASK (1 << ISNS_PORTAL_SEC_PFS_ENABLED) +-#define ISNS_PORTAL_SEC_TRANSPORT_MODE_PREFERRED_MASK (1 << ISNS_PORTAL_SEC_TRANSPORT_MODE_PREFERRED) +-#define ISNS_PORTAL_SEC_TUNNEL_MODE_PREFERRED_MASK (1 << ISNS_PORTAL_SEC_TUNNEL_MODE_PREFERRED) +- +-enum isns_scn_bits { +- ISNS_SCN_DD_MEMBER_ADDED = 0, +- ISNS_SCN_DD_MEMBER_REMOVED = 1, +- ISNS_SCN_OBJECT_UPDATED = 2, +- ISNS_SCN_OBJECT_ADDED = 3, +- ISNS_SCN_OBJECT_REMOVED = 4, +- ISNS_SCN_MANAGEMENT_REGISTRATION = 5, +- ISNS_SCN_TARGET_AND_SELF_ONLY = 6, +- ISNS_SCN_INITIATOR_AND_SELF_ONLY = 7, +-}; +-#define ISNS_SCN_DD_MEMBER_ADDED_MASK (1 << ISNS_SCN_DD_MEMBER_ADDED) +-#define ISNS_SCN_DD_MEMBER_REMOVED_MASK (1 << ISNS_SCN_DD_MEMBER_REMOVED) +-#define ISNS_SCN_OBJECT_UPDATED_MASK (1 << ISNS_SCN_OBJECT_UPDATED) +-#define ISNS_SCN_OBJECT_ADDED_MASK (1 << ISNS_SCN_OBJECT_ADDED) +-#define ISNS_SCN_OBJECT_REMOVED_MASK (1 << ISNS_SCN_OBJECT_REMOVED) +-#define ISNS_SCN_MANAGEMENT_REGISTRATION_MASK (1 << ISNS_SCN_MANAGEMENT_REGISTRATION) +-#define ISNS_SCN_TARGET_AND_SELF_ONLY_MASK (1 << ISNS_SCN_TARGET_AND_SELF_ONLY) +-#define ISNS_SCN_INITIATOR_AND_SELF_ONLY_MASK (1 << ISNS_SCN_INITIATOR_AND_SELF_ONLY) +- +-enum isns_dds_status_bits { +- ISNS_DDS_ENABLED = 0, +-}; +-#define ISNS_DDS_ENABLED_MASK (1 << ISNS_DDS_ENABLED) +- +-enum isns_dd_feature_bits { +- ISNS_DD_BOOT_LIST_ENABLED = 0, +-}; +-#define ISNS_DD_BOOT_LIST_ENABLED_MASK (1 << ISN_BOOT_LIST_DDS_ENABLED) +- +-#define ISNS_PAD(len) (((len) + 3) & ~3UL) +- +-/* +- * iSNS auth block +- */ +-#define ISNS_AUTHBLK_SIZE 20 +-struct isns_authblk { +- uint32_t iab_bsd; /* 16bit in SLP */ +- uint32_t iab_length; /* 16bit in SLP */ +- uint64_t iab_timestamp; /* 32bit in SLP */ +- uint32_t iab_spi_len; /* 16bit in SLP */ +- +- char * iab_spi; +- void * iab_sig; +- uint32_t iab_sig_len; +-} __attribute__((packed)); +- +-#define ISNS_AUTH_TYPE_SHA1_DSA 0x0002 +- +-#endif /* ISNS_PROTO_H */ +diff --git a/utils/open-isns/isns.h b/utils/open-isns/isns.h +deleted file mode 100644 +index 53c22d5..0000000 +--- a/utils/open-isns/isns.h ++++ /dev/null +@@ -1,673 +0,0 @@ +-/* +- * iSNS implementation - library header file. +- * +- * Copyright (C) 2007 Olaf Kirch +- * +- * This file contains all declarations and definitions +- * commonly required by users of libisns. +- */ +- +-#ifndef ISNS_H +-#define ISNS_H +- +-#include +-#include +-#include +- +-#include +-#include "types.h" +- +-#define ISNS_MAX_BUFFER 8192 +-#define ISNS_MAX_MESSAGE 8192 +- +- +-/* +- * Client handle +- */ +-typedef struct isns_client isns_client_t; +-struct isns_client { +- isns_source_t * ic_source; +- isns_socket_t * ic_socket; +-}; +- +-/* +- * Server operations +- */ +-typedef int isns_service_fn_t(isns_server_t *, isns_simple_t *, isns_simple_t **); +-typedef void isns_scn_callback_fn_t(isns_db_t *, uint32_t scn_bits, +- isns_object_template_t *node_type, +- const char *node_name, +- const char *recipient); +-struct isns_service_ops { +- isns_service_fn_t * process_registration; +- isns_service_fn_t * process_query; +- isns_service_fn_t * process_getnext; +- isns_service_fn_t * process_deregistration; +- isns_service_fn_t * process_scn_registration; +- isns_service_fn_t * process_scn_deregistration; +- isns_service_fn_t * process_scn_event; +- isns_service_fn_t * process_scn; +- isns_service_fn_t * process_dd_registration; +- isns_service_fn_t * process_dd_deregistration; +- isns_service_fn_t * process_esi; +- isns_service_fn_t * process_heartbeat; +-}; +- +-extern struct isns_service_ops isns_default_service_ops; +-extern struct isns_service_ops isns_callback_service_ops; +- +-/* +- * Output function +- */ +-void isns_print_stdout(const char *, ...); +- +-/* +- * Database events +- */ +-struct isns_db_event { +- isns_object_t * ie_recipient; /* Recipient node or NULL */ +- isns_object_t * ie_object; /* Affected object */ +- isns_object_t * ie_trigger; /* Triggering object */ +- unsigned int ie_bits; /* SCN bitmask */ +-}; +-typedef void isns_db_callback_t(const isns_db_event_t *, +- void *user_data); +- +-/* +- * Handling of client objects +- */ +-extern isns_client_t * isns_create_default_client(isns_security_t *); +-extern isns_client_t * isns_create_client(isns_security_t *, +- const char *source_name); +-extern isns_client_t * isns_create_local_client(isns_security_t *, +- const char *source_name); +-extern int isns_client_call(isns_client_t *, +- isns_simple_t **inout); +-extern void isns_client_destroy(isns_client_t *); +-extern int isns_client_get_local_address(const isns_client_t *, +- isns_portal_info_t *); +- +-/* +- * Handling of server objects +- */ +-extern isns_server_t * isns_create_server(isns_source_t *, +- isns_db_t *, +- struct isns_service_ops *); +-extern void isns_server_set_scn_callback(isns_server_t *, +- isns_scn_callback_fn_t *); +- +- +-/* +- * Handling of source names +- */ +-extern int isns_init_names(void); +-extern const char * isns_default_source_name(void); +-extern isns_source_t * isns_source_create(isns_attr_t *); +-extern isns_source_t * isns_source_create_iscsi(const char *name); +-extern isns_source_t * isns_source_create_ifcp(const char *name); +-extern uint32_t isns_source_type(const isns_source_t *); +-extern const char * isns_source_name(const isns_source_t *); +-extern isns_attr_t * isns_source_attr(const isns_source_t *); +-extern isns_source_t * isns_source_get(isns_source_t *); +-extern isns_source_t * isns_source_from_object(const isns_object_t *); +-extern void isns_source_release(isns_source_t *); +-extern int isns_source_match(const isns_source_t *, +- const isns_source_t *); +- +-extern void isns_server_set_source(isns_source_t *); +-extern isns_message_t * isns_process_message(isns_server_t *, isns_message_t *); +- +-extern void isns_simple_print(isns_simple_t *, +- isns_print_fn_t *); +-extern int isns_simple_call(isns_socket_t *, +- isns_simple_t **); +-extern int isns_simple_transmit(isns_socket_t *, +- isns_simple_t *, +- const isns_portal_info_t *, +- unsigned int, +- void (*callback)(uint32_t, int, +- isns_simple_t *)); +-extern void isns_simple_free(isns_simple_t *); +-extern const isns_attr_list_t *isns_simple_get_attrs(isns_simple_t *); +- +-extern isns_simple_t * isns_create_query(isns_client_t *clnt, +- const isns_attr_list_t *query_key); +-extern isns_simple_t * isns_create_query2(isns_client_t *clnt, +- const isns_attr_list_t *query_key, +- isns_source_t *source); +-extern int isns_query_request_attr_tag(isns_simple_t *, +- uint32_t); +-extern int isns_query_request_attr(isns_simple_t *, +- isns_attr_t *); +-extern int isns_query_response_get_objects(isns_simple_t *qry, +- isns_object_list_t *result); +- +-extern isns_simple_t * isns_create_registration(isns_client_t *clnt, +- isns_object_t *key_object); +-extern isns_simple_t * isns_create_registration2(isns_client_t *clnt, +- isns_object_t *key_object, +- isns_source_t *source); +-extern void isns_registration_set_replace(isns_simple_t *, int); +-extern void isns_registration_add_object(isns_simple_t *, +- isns_object_t *object); +-extern void isns_registration_add_object_list(isns_simple_t *, +- isns_object_list_t *); +-extern int isns_registration_response_get_objects(isns_simple_t *, +- isns_object_list_t *); +- +-extern isns_simple_t * isns_create_getnext(isns_client_t *, +- isns_object_template_t *, +- const isns_attr_list_t *); +-extern int isns_getnext_response_get_object(isns_simple_t *, +- isns_object_t **); +-extern isns_simple_t * isns_create_getnext_followup(isns_client_t *, +- const isns_simple_t *, +- const isns_attr_list_t *); +- +-extern isns_simple_t * isns_create_deregistration(isns_client_t *clnt, +- const isns_attr_list_t *); +- +-extern isns_simple_t * isns_create_scn_registration(isns_client_t *clnt, +- unsigned int); +-extern isns_simple_t * isns_create_scn_registration2(isns_client_t *clnt, +- unsigned int, +- isns_source_t *); +- +-extern int isns_dd_load_all(isns_db_t *); +-extern void isns_dd_get_members(uint32_t, isns_object_list_t *, int); +-extern isns_simple_t * isns_create_dd_registration(isns_client_t *, +- const isns_attr_list_t *); +-extern isns_simple_t * isns_create_dd_deregistration(isns_client_t *, +- uint32_t, const isns_attr_list_t *); +- +-extern isns_object_t * isns_create_object(isns_object_template_t *, +- const isns_attr_list_t *, +- isns_object_t *); +-extern isns_object_t * isns_create_entity(int, const char *); +-extern isns_object_t * isns_create_entity_for_source(const isns_source_t *, +- const char *); +-extern const char * isns_entity_name(const isns_object_t *); +-extern isns_object_t * isns_create_portal(const isns_portal_info_t *, +- isns_object_t *parent); +-extern isns_object_t * isns_create_storage_node(const char *name, +- uint32_t type_mask, +- isns_object_t *parent); +-extern isns_object_t * isns_create_storage_node2(const isns_source_t *, +- uint32_t type_mask, +- isns_object_t *parent); +-extern isns_object_t * isns_create_iscsi_initiator(const char *name, +- isns_object_t *parent); +-extern isns_object_t * isns_create_iscsi_target(const char *name, +- isns_object_t *parent); +-extern const char * isns_storage_node_name(const isns_object_t *); +-extern isns_attr_t * isns_storage_node_key_attr(const isns_object_t *); +-extern isns_object_t * isns_create_portal_group(isns_object_t *portal, +- isns_object_t *iscsi_node, uint32_t pg_tag); +-extern isns_object_t * isns_create_default_portal_group(isns_db_t *, +- isns_object_t *portal, +- isns_object_t *node); +-extern void isns_get_portal_groups(isns_object_t *portal, +- isns_object_t *node, +- isns_object_list_t *result); +- +-extern const char * isns_object_template_name(isns_object_template_t *); +-extern int isns_object_set_attr(isns_object_t *, isns_attr_t *); +-extern int isns_object_set_attrlist(isns_object_t *, const isns_attr_list_t *); +-extern isns_object_t * isns_object_get(isns_object_t *); +-extern int isns_object_get_attrlist(isns_object_t *obj, +- isns_attr_list_t *result, +- const isns_attr_list_t *requested_attrs); +-extern int isns_object_get_key_attrs(isns_object_t *, +- isns_attr_list_t *); +-extern int isns_object_get_attr(const isns_object_t *, uint32_t, +- isns_attr_t **); +-extern void isns_object_get_related(isns_db_t *, +- isns_object_t *, isns_object_list_t *); +-extern void isns_object_get_descendants(const isns_object_t *, +- isns_object_template_t *, +- isns_object_list_t *); +-extern void isns_object_release(isns_object_t *); +-extern int isns_object_match(const isns_object_t *, +- const isns_attr_list_t *); +-extern isns_object_t * isns_object_get_entity(isns_object_t *); +-extern int isns_object_attr_valid(isns_object_template_t *, uint32_t); +-extern int isns_object_contains(const isns_object_t *, const isns_object_t *); +-extern int isns_object_delete_attr(isns_object_t *, uint32_t); +-extern int isns_object_is(const isns_object_t *, +- isns_object_template_t *); +-extern int isns_object_is_entity(const isns_object_t *); +-extern int isns_object_is_iscsi_node(const isns_object_t *); +-extern int isns_object_is_fc_port(const isns_object_t *); +-extern int isns_object_is_fc_node(const isns_object_t *); +-extern int isns_object_is_portal(const isns_object_t *); +-extern int isns_object_is_pg(const isns_object_t *); +-extern int isns_object_is_policy(const isns_object_t *); +-extern int isns_object_is_dd(const isns_object_t *); +-extern int isns_object_is_ddset(const isns_object_t *); +-extern void isns_object_print(isns_object_t *, +- isns_print_fn_t *); +-extern time_t isns_object_last_modified(const isns_object_t *); +-extern int isns_object_mark_membership(isns_object_t *, uint32_t); +-extern int isns_object_clear_membership(isns_object_t *, uint32_t); +-extern int isns_object_test_membership(const isns_object_t *, uint32_t); +-extern int isns_object_test_visibility(const isns_object_t *, +- const isns_object_t *); +-extern void isns_object_get_visible(const isns_object_t *, +- isns_db_t *, isns_object_list_t *); +-extern void isns_entity_touch(isns_object_t *); +-extern int isns_object_extract_keys(const isns_object_t *, +- isns_attr_list_t *); +-extern int isns_object_extract_all(const isns_object_t *, +- isns_attr_list_t *); +-extern int isns_object_extract_writable(const isns_object_t *, +- isns_attr_list_t *); +- +- +-extern int isns_object_set_nil(isns_object_t *obj, +- uint32_t tag); +-extern int isns_object_set_string(isns_object_t *obj, +- uint32_t tag, +- const char *value); +-extern int isns_object_set_uint32(isns_object_t *obj, +- uint32_t tag, +- uint32_t value); +-extern int isns_object_set_uint64(isns_object_t *obj, +- uint32_t tag, +- uint64_t value); +-extern int isns_object_set_ipaddr(isns_object_t *obj, +- uint32_t tag, +- const struct in6_addr *value); +- +-extern int isns_object_get_string(const isns_object_t *, +- uint32_t, +- const char **); +-extern int isns_object_get_ipaddr(const isns_object_t *, +- uint32_t, +- struct in6_addr *); +-extern int isns_object_get_uint32(const isns_object_t *, +- uint32_t, +- uint32_t *); +-extern int isns_object_get_uint64(const isns_object_t *, +- uint32_t, +- uint64_t *); +-extern int isns_object_get_opaque(const isns_object_t *, +- uint32_t, +- const void **, size_t *); +- +- +-extern int isns_object_find_descendants(isns_object_t *obj, +- isns_object_template_t *, +- const isns_attr_list_t *keys, +- isns_object_list_t *result); +-extern isns_object_t * isns_object_find_descendant(isns_object_t *obj, +- const isns_attr_list_t *keys); +-extern int isns_object_detach(isns_object_t *); +-extern int isns_object_attach(isns_object_t *, isns_object_t *); +-extern void isns_object_prune_attrs(isns_object_t *); +-extern void isns_mark_object(isns_object_t *, unsigned int); +- +-extern int isns_get_entity_identifier(isns_object_t *, const char **); +-extern int isns_get_entity_protocol(isns_object_t *, isns_entity_protocol_t *); +-extern int isns_get_entity_index(isns_object_t *, uint32_t *); +- +-extern int isns_get_portal_ipaddr(isns_object_t *, struct in6_addr *); +-extern int isns_get_portal_tcpudp_port(isns_object_t *, +- int *ipprotocol, uint16_t *port); +-extern int isns_get_portal_index(isns_object_t *, uint32_t *); +- +-extern int isns_get_address(struct sockaddr_storage *, +- const char *, const char *, int, int, int); +-extern char * isns_get_canon_name(const char *); +- +-extern isns_db_t * isns_db_open(const char *location); +-extern isns_db_t * isns_db_open_shadow(isns_object_list_t *); +-extern isns_object_t * isns_db_lookup(isns_db_t *, +- isns_object_template_t *, +- const isns_attr_list_t *); +-extern isns_object_t * isns_db_vlookup(isns_db_t *, +- isns_object_template_t *, +- ...); +-extern int isns_db_gang_lookup(isns_db_t *, +- isns_object_template_t *, +- const isns_attr_list_t *, +- isns_object_list_t *); +-extern isns_object_t * isns_db_get_next(isns_db_t *, +- isns_object_template_t *, +- const isns_attr_list_t *current, +- const isns_attr_list_t *scope, +- const isns_source_t *source); +-extern isns_object_t * isns_db_lookup_source_node(isns_db_t *, +- const isns_source_t *); +-extern void isns_db_get_domainless(isns_db_t *, +- isns_object_template_t *, +- isns_object_list_t *); +-extern uint32_t isns_db_allocate_index(isns_db_t *); +-extern void isns_db_insert(isns_db_t *, isns_object_t *); +-extern void isns_db_insert_limbo(isns_db_t *, isns_object_t *); +-extern int isns_db_remove(isns_db_t *, isns_object_t *); +-extern time_t isns_db_expire(isns_db_t *); +-extern void isns_db_purge(isns_db_t *); +-extern void isns_db_sync(isns_db_t *); +-extern const char * isns_db_generate_eid(isns_db_t *, char *, size_t); +-extern isns_object_t * isns_db_get_control(isns_db_t *); +-extern void isns_db_print(isns_db_t *, +- isns_print_fn_t *); +- +-extern void isns_db_begin_transaction(isns_db_t *); +-extern void isns_db_commit(isns_db_t *); +-extern void isns_db_rollback(isns_db_t *); +- +-extern void isns_object_event(isns_object_t *obj, +- unsigned int bits, +- isns_object_t *trigger); +-extern void isns_unicast_event(isns_object_t *dst, +- isns_object_t *obj, +- unsigned int bits, +- isns_object_t *trigger); +-extern void isns_register_callback(isns_db_callback_t *, +- void *); +-extern void isns_flush_events(void); +-extern const char * isns_event_string(unsigned int); +- +-extern void isns_add_timer(unsigned int, +- isns_timer_callback_t *, void *); +-extern void isns_add_oneshot_timer(unsigned int, +- isns_timer_callback_t *, void *); +-extern void isns_cancel_timer(isns_timer_callback_t *, void *); +-extern time_t isns_run_timers(void); +- +-extern void isns_object_list_init(isns_object_list_t *); +-extern void isns_object_list_destroy(isns_object_list_t *); +-extern int isns_object_list_contains(const isns_object_list_t *, +- isns_object_t *); +-extern void isns_object_list_append(isns_object_list_t *, +- isns_object_t *); +-extern void isns_object_list_append_list(isns_object_list_t *, +- const isns_object_list_t *); +-extern isns_object_t * isns_object_list_lookup(const isns_object_list_t *, +- isns_object_template_t *, +- const isns_attr_list_t *); +-extern int isns_object_list_gang_lookup(const isns_object_list_t *, +- isns_object_template_t *, +- const isns_attr_list_t *, +- isns_object_list_t *); +-extern int isns_object_list_remove(isns_object_list_t *, +- isns_object_t *); +-extern void isns_object_list_uniq(isns_object_list_t *); +-extern void isns_object_list_print(const isns_object_list_t *, +- isns_print_fn_t *); +- +-isns_object_template_t *isns_object_template_for_key_attrs(const isns_attr_list_t *); +-isns_object_template_t *isns_object_template_for_tag(uint32_t); +-isns_object_template_t *isns_object_template_for_index_tag(uint32_t); +-isns_object_template_t *isns_object_template_find(uint32_t); +- +-extern int isns_attr_set(isns_attr_t *, const void *); +-extern isns_attr_t * isns_attr_get(isns_attr_t *); +-extern void isns_attr_release(isns_attr_t *); +-extern void isns_attr_print(const isns_attr_t *, +- isns_print_fn_t *); +-extern char * isns_attr_print_value(const isns_attr_t *, +- char *, size_t); +-extern int isns_attr_match(const isns_attr_t *, +- const isns_attr_t *); +-extern int isns_attr_compare(const isns_attr_t *, +- const isns_attr_t *); +-extern isns_attr_t * isns_attr_from_string(uint32_t, const char *); +- +-extern void isns_attr_list_print(const isns_attr_list_t *, +- isns_print_fn_t *); +- +-extern void isns_attr_list_init(isns_attr_list_t *); +-extern void isns_attr_list_copy(isns_attr_list_t *, +- const isns_attr_list_t *); +-extern void isns_attr_list_destroy(isns_attr_list_t *); +-extern int isns_attr_list_remove_tag(isns_attr_list_t *, +- uint32_t); +- +-extern void isns_attr_list_append_attr(isns_attr_list_t *, +- isns_attr_t *); +-extern void isns_attr_list_append_list(isns_attr_list_t *, +- const isns_attr_list_t *); +-extern int isns_attr_list_replace_attr(isns_attr_list_t *, +- isns_attr_t *); +-/* Warning: this does *NOT* return a reference to the attribute */ +-extern int isns_attr_list_get_attr(const isns_attr_list_t *, +- uint32_t tag, +- isns_attr_t **); +- +-extern void isns_attr_list_append_nil(isns_attr_list_t *, +- uint32_t tag); +-extern void isns_attr_list_append_string(isns_attr_list_t *, +- uint32_t tag, const char *value); +-extern void isns_attr_list_append_uint32(isns_attr_list_t *, +- uint32_t tag, uint32_t value); +-extern void isns_attr_list_append_uint64(isns_attr_list_t *, +- uint32_t, int64_t); +-extern void isns_attr_list_append_int32(isns_attr_list_t *, +- uint32_t tag, int32_t value); +-extern void isns_attr_list_append_opaque(isns_attr_list_t *, +- uint32_t tag, const void *ptr, size_t len); +-extern void isns_attr_list_append_ipaddr(isns_attr_list_t *, +- uint32_t tag, const struct in6_addr *); +- +-extern int isns_attr_list_append(isns_attr_list_t *, +- uint32_t tag, const void *); +-extern int isns_attr_list_update(isns_attr_list_t *, +- uint32_t tag, const void *); +- +-extern int isns_attr_list_contains(const isns_attr_list_t *, +- uint32_t tag); +-extern int isns_attr_list_compare(const isns_attr_list_t *, +- const isns_attr_list_t *); +- +-/* +- * Helper macros +- */ +-#define ISNS_ATTR_TYPE_CHECK(attr, type) \ +- ((attr)->ia_value.iv_type == &isns_attr_type_##type) +-#define ISNS_ATTR_IS_NIL(attr) \ +- ISNS_ATTR_TYPE_CHECK(attr, nil) +-#define ISNS_ATTR_IS_STRING(attr) \ +- ISNS_ATTR_TYPE_CHECK(attr, string) +-#define ISNS_ATTR_IS_IPADDR(attr) \ +- ISNS_ATTR_TYPE_CHECK(attr, ipaddr) +-#define ISNS_ATTR_IS_UINT32(attr) \ +- ISNS_ATTR_TYPE_CHECK(attr, uint32) +-#define ISNS_ATTR_IS_UINT64(attr) \ +- ISNS_ATTR_TYPE_CHECK(attr, uint64) +-#define ISNS_ATTR_IS_OPAQUE(attr) \ +- ISNS_ATTR_TYPE_CHECK(attr, opaque) +- +- +- +-extern isns_socket_t * isns_create_server_socket(const char *hostname, const char *portname, +- int af_hint, int sock_type); +-extern isns_socket_t * isns_create_client_socket(const char *hostname, const char *portname, +- int af_hint, int sock_type); +-extern isns_socket_t * isns_create_bound_client_socket(const char *myaddr, +- const char *hostname, const char *portname, +- int af_hint, int sock_type); +-extern isns_socket_t * isns_connect_to_portal(const isns_portal_info_t *); +-extern void isns_socket_set_report_failure(isns_socket_t *); +-extern void isns_socket_set_disconnect_fatal(isns_socket_t *); +-extern int isns_socket_get_local_addr(const isns_socket_t *, +- struct sockaddr_storage *); +-extern int isns_socket_get_portal_info(const isns_socket_t *, +- isns_portal_info_t *); +-extern void isns_socket_set_security_ctx(isns_socket_t *, +- isns_security_t *); +-extern isns_message_t * isns_recv_message(struct timeval *timeout); +-extern isns_message_t * isns_socket_call(isns_socket_t *, isns_message_t *, long); +-extern int isns_socket_send(isns_socket_t *, isns_message_t *); +-extern void isns_socket_free(isns_socket_t *); +-extern int isns_addr_get_port(const struct sockaddr *); +-extern void isns_addr_set_port(struct sockaddr *, unsigned int); +-extern isns_socket_t * isns_socket_find_server(const isns_portal_info_t *); +- +-extern isns_message_t * isns_create_message(uint16_t function, uint16_t flags); +-extern isns_message_t * isns_create_reply(const isns_message_t *); +-extern int isns_message_init(isns_message_t *, +- uint16_t, uint16_t, size_t); +-extern int isns_message_status(isns_message_t *); +-extern void isns_message_release(isns_message_t *); +-extern unsigned int isns_message_function(const isns_message_t *); +-extern isns_socket_t * isns_message_socket(const isns_message_t *); +-extern void isns_message_set_error(isns_message_t *, uint32_t); +- +-extern const char * isns_strerror(enum isns_status); +-extern const char * isns_function_name(unsigned int); +- +-/* +- * Security related functions +- */ +-extern int isns_security_init(void); +-extern isns_principal_t *isns_security_load_privkey(isns_security_t *, +- const char *filename); +-extern isns_principal_t *isns_security_load_pubkey(isns_security_t *, +- const char *filename); +-extern isns_security_t *isns_default_security_context(int server_only); +-extern isns_security_t *isns_control_security_context(int server_only); +-extern isns_security_t *isns_create_dsa_context(void); +-extern void isns_security_set_identity(isns_security_t *, isns_principal_t *); +-extern void isns_principal_free(isns_principal_t *); +-extern void isns_add_principal(isns_security_t *, isns_principal_t *); +-extern isns_keystore_t *isns_create_keystore(const char *); +-extern void isns_security_set_keystore(isns_security_t *, +- isns_keystore_t *); +-extern void isns_principal_set_name(isns_principal_t *, const char *); +-extern const char * isns_principal_name(const isns_principal_t *); +- +-extern isns_object_template_t isns_entity_template; +-extern isns_object_template_t isns_portal_template; +-extern isns_object_template_t isns_iscsi_node_template; +-extern isns_object_template_t isns_fc_port_template; +-extern isns_object_template_t isns_fc_node_template; +-extern isns_object_template_t isns_iscsi_pg_template; +-extern isns_object_template_t isns_dd_template; +-extern isns_object_template_t isns_ddset_template; +- +-/* +- * Config file parser +- */ +-struct isns_config { +- char * ic_host_name; +- char * ic_auth_name; +- char * ic_source_name; +- char * ic_source_suffix; +- char * ic_entity_name; +- +- char * ic_server_name; +- char * ic_bind_address; +- char * ic_database; +- char * ic_auth_key_file; +- char * ic_server_key_file; +- char * ic_client_keystore; +- char * ic_control_socket; +- char * ic_pidfile; +- char * ic_local_registry_file; +- int ic_security; +- int ic_slp_register; +- +- char * ic_control_name; +- char * ic_control_key_file; +- +- unsigned int ic_registration_period; +- unsigned int ic_scn_timeout; +- unsigned int ic_scn_retries; +- char * ic_scn_callout; +- +- unsigned int ic_esi_max_interval; +- unsigned int ic_esi_min_interval; +- unsigned int ic_esi_retries; +- +- unsigned int ic_use_default_domain; +- +- struct { +- unsigned int policy; +- unsigned int replay_window; +- unsigned int timestamp_jitter; +- int allow_unknown_peers; +- } ic_auth; +- struct { +- unsigned int max_sockets; +- unsigned int connect_timeout; +- unsigned int reconnect_timeout; +- unsigned int call_timeout; +- unsigned int udp_retrans_timeout; +- unsigned int tcp_retrans_timeout; +- unsigned int idle_timeout; +- } ic_network; +- struct { +- char * param_file; +- unsigned int key_bits; +- } ic_dsa; +- +-}; +- +-extern struct isns_config isns_config; +-extern int isns_read_config(const char *); +-extern int isns_config_set(const char *, char *); +- +-/* +- * Reserved entity name for Policy information +- */ +-#define ISNS_ENTITY_CONTROL "CONTROL" +- +- +-/* +- * Helpers to deal with portal information +- */ +-struct isns_portal_info { +- struct sockaddr_in6 addr; +- int proto; +-}; +- +-extern void isns_portal_init(isns_portal_info_t *, +- const struct sockaddr *, int); +-extern int isns_portal_parse(isns_portal_info_t *portal, +- const char *addr_spec, +- const char *default_port); +-extern int isns_portal_from_attr_list(isns_portal_info_t *, +- uint32_t addr_tag, uint32_t port_tag, +- const isns_attr_list_t *); +-extern int isns_portal_from_attr_pair(isns_portal_info_t *, +- const isns_attr_t *, +- const isns_attr_t *); +-extern int isns_portal_from_object(isns_portal_info_t *, +- uint32_t addr_tag, uint32_t port_tag, +- const isns_object_t *); +-extern int isns_portal_from_sockaddr(isns_portal_info_t *, +- const struct sockaddr_storage *); +-extern int isns_portal_to_sockaddr(const isns_portal_info_t *, +- struct sockaddr_storage *); +-extern int isns_portal_to_attr_list(const isns_portal_info_t *, +- uint32_t addr_tag, uint32_t port_tag, +- isns_attr_list_t *); +-extern int isns_portal_to_object(const isns_portal_info_t *, +- uint32_t addr_tag, uint32_t port_tag, +- isns_object_t *); +-extern int isns_portal_is_wildcard(const isns_portal_info_t *); +-extern uint32_t isns_portal_tcpudp_port(const isns_portal_info_t *); +-extern const char * isns_portal_string(const isns_portal_info_t *); +-extern int isns_portal_equal(const isns_portal_info_t *, +- const isns_portal_info_t *); +-extern int isns_enumerate_portals(isns_portal_info_t *, +- unsigned int); +-extern int isns_get_nr_portals(void); +- +-/* Local registry stuff */ +-extern int isns_local_registry_load(const char *, pid_t, isns_object_list_t *); +-extern int isns_local_registry_store(const char *, pid_t, const isns_object_list_t *); +-extern int isns_local_registry_purge(const char *, pid_t); +- +-/* Should go somwhere else .*/ +-extern int isns_esi_enabled; +- +-extern void isns_esi_init(isns_server_t *); +-extern void isns_esi_register(isns_object_t *); +- +-extern void isns_scn_init(isns_server_t *); +-extern time_t isns_scn_transmit_all(void); +- +-#endif /* ISNS_H */ +diff --git a/utils/open-isns/isnsadm.c b/utils/open-isns/isnsadm.c +deleted file mode 100644 +index fadd87d..0000000 +--- a/utils/open-isns/isnsadm.c ++++ /dev/null +@@ -1,1149 +0,0 @@ +-/* +- * isnsadm - helper utility +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "isns.h" +-#include "util.h" +-#include "vendor.h" +-#include "attrs.h" +-#include "security.h" +-#include "objects.h" +-#include "paths.h" +-#include "config.h" +- +-#define ISNS_DEFAULT_PORT_INITIATOR 860 +-#define ISNS_DEFAULT_PORT_TARGET 3260 +- +- +-enum { +- DO_REGISTER = 1024, +- DO_QUERY, +- DO_QUERY_EID, +- DO_LIST, +- DO_DEREGISTER, +- DO_DD_REGISTER, +- DO_DD_DEREGISTER, +- DO_ENROLL, +- DO_EDIT_POLICY, +- DO_DELETE_POLICY, +-}; +- +-static struct option options[] = { +- { "help", no_argument, NULL, 'h' }, +- { "config", required_argument, NULL, 'c' }, +- { "debug", required_argument, NULL, 'd' }, +- { "keyfile", required_argument, NULL, 'K', }, +- { "key", required_argument, NULL, 'k', }, +- { "local", no_argument, NULL, 'l' }, +- { "control", no_argument, NULL, 'C' }, +- { "replace", no_argument, NULL, 'r' }, +- { "query", no_argument, NULL, DO_QUERY }, +- { "query-eid", no_argument, NULL, DO_QUERY_EID }, +- { "list", no_argument, NULL, DO_LIST }, +- { "register", no_argument, NULL, DO_REGISTER }, +- { "deregister", no_argument, NULL, DO_DEREGISTER }, +- { "dd-register", no_argument, NULL, DO_DD_REGISTER }, +- { "dd-deregister", no_argument, NULL, DO_DD_DEREGISTER}, +- +- { "enroll", no_argument, NULL, DO_ENROLL }, +- { "edit-policy", no_argument, NULL, DO_EDIT_POLICY }, +- { "delete-policy", no_argument, NULL, DO_DELETE_POLICY }, +- +- { "version", no_argument, NULL, 'V' }, +- { NULL } +-}; +- +- +-static const char * opt_configfile = ISNS_DEFAULT_ISNSADM_CONFIG; +-static int opt_af = AF_UNSPEC; +-static int opt_action = 0; +-static int opt_local = 0; +-static int opt_control = 0; +-static int opt_replace = 0; +-static const char * opt_keyfile = NULL; +-static char * opt_key = NULL; +-static struct sockaddr_storage opt_myaddr; +- +-static void usage(int, const char *); +- +-static int register_objects(isns_client_t *, int, char **); +-static int query_objects(isns_client_t *, int, char **); +-static int query_entity_id(isns_client_t *, int, char **); +-static int list_objects(isns_client_t *, int, char **); +-static int deregister_objects(isns_client_t *, int, char **); +-static int register_domain(isns_client_t *, int, char **); +-static int deregister_domain(isns_client_t *, int, char **); +-static int enroll_client(isns_client_t *, int, char **); +-static int edit_policy(isns_client_t *, int, char **); +- +-static isns_attr_t * load_key_callback(const char *); +-static isns_attr_t * generate_key_callback(void); +- +-int +-main(int argc, char **argv) +-{ +- isns_client_t *clnt; +- isns_security_t *security = NULL; +- int c, status; +- +- while ((c = getopt_long(argc, argv, "46Cc:d:hK:k:l", options, NULL)) != -1) { +- switch (c) { +- case '4': +- opt_af = AF_INET; +- break; +- +- case '6': +- opt_af = AF_INET6; +- break; +- +- case 'C': +- opt_control = 1; +- break; +- +- case 'c': +- opt_configfile = optarg; +- break; +- +- case 'd': +- isns_enable_debugging(optarg); +- break; +- +- case 'h': +- usage(0, NULL); +- break; +- +- case 'K': +- opt_keyfile = optarg; +- break; +- +- case 'k': +- opt_key = optarg; +- break; +- +- case 'l': +- opt_local = 1; +- break; +- +- case 'r': +- opt_replace = 1; +- break; +- +- case 'V': +- printf("Open-iSNS version %s\n" +- "Copyright (C) 2007, Olaf Kirch \n", +- OPENISNS_VERSION_STRING); +- return 0; +- +- case DO_REGISTER: +- case DO_QUERY: +- case DO_QUERY_EID: +- case DO_LIST: +- case DO_DEREGISTER: +- case DO_DD_REGISTER: +- case DO_DD_DEREGISTER: +- case DO_ENROLL: +- case DO_EDIT_POLICY: +- case DO_DELETE_POLICY: +- if (opt_action) +- usage(1, "You cannot specify more than one mode\n"); +- opt_action = c; +- break; +- +- default: +- usage(1, "Unknown option"); +- } +- } +- +- isns_read_config(opt_configfile); +- +- if (!isns_config.ic_source_name) +- usage(1, "Please specify an iSNS source name"); +- if (!isns_config.ic_server_name) +- usage(1, "Please specify an iSNS server name"); +- if (!opt_action) +- usage(1, "Please specify an operating mode"); +- +- if (opt_control) { +- if (!isns_config.ic_security) +- isns_fatal("Cannot use control mode, security disabled\n"); +- security = isns_control_security_context(0); +- if (!security) +- isns_fatal("Unable to create control security context\n"); +- +- /* Create a networked client, using isns.control as +- * the source name */ +- clnt = isns_create_client(security, isns_config.ic_control_name); +- } else if (opt_local) { +- /* Create a local client, using isns.control as +- * the source name */ +- clnt = isns_create_local_client(security, +- isns_config.ic_control_name); +- } else { +- /* Create a networked client, using the configured +- * source name */ +- clnt = isns_create_default_client(security); +- } +- +- if (clnt == NULL) +- return 1; +- +- /* We're an interactive app, and don't want to retry +- * forever if the server refuses us. */ +- isns_socket_set_disconnect_fatal(clnt->ic_socket); +- +- /* Get the IP address we use to talk to the iSNS server */ +- if (opt_myaddr.ss_family == AF_UNSPEC && !opt_local) { +- if (!isns_socket_get_local_addr(clnt->ic_socket, &opt_myaddr)) +- isns_fatal("Unable to obtain my IP address\n"); +- isns_addr_set_port((struct sockaddr *) &opt_myaddr, 860); +- } +- +- argv += optind; argc -= optind; +- switch (opt_action) { +- case DO_REGISTER: +- status = register_objects(clnt, argc, argv); +- break; +- +- case DO_QUERY: +- status = query_objects(clnt, argc, argv); +- break; +- +- case DO_QUERY_EID: +- status = query_entity_id(clnt, argc, argv); +- break; +- +- case DO_LIST: +- status = list_objects(clnt, argc, argv); +- break; +- +- case DO_DEREGISTER: +- status = deregister_objects(clnt, argc, argv); +- break; +- +- case DO_DD_REGISTER: +- status = register_domain(clnt, argc, argv); +- break; +- +- case DO_DD_DEREGISTER: +- status = deregister_domain(clnt, argc, argv); +- break; +- +- +- case DO_ENROLL: +- status = enroll_client(clnt, argc, argv); +- break; +- +- case DO_EDIT_POLICY: +- status = edit_policy(clnt, argc, argv); +- break; +- +- // case DO_DELETE_POLICY: +- +- default: +- isns_fatal("Not yet implemented\n"); +- status = 1; /* compiler food */ +- } +- +- return status != ISNS_SUCCESS; +-} +- +-void +-usage(int exval, const char *msg) +-{ +- if (msg) +- fprintf(stderr, "Error: %s\n", msg); +- fprintf(stderr, +- "Usage: isnsadm [options] --action ...\n" +- " --config Specify alternative config fille\n" +- " --debug Enable debugging (list of debug flags)\n" +- " --keyfile Where to store newly generated private key\n" +- " --local Use local Unix socket to talk to isnsd\n" +- " --control Assume control node identity for authentication\n" +- " --replace Use replace mode (--register only)\n" +- "\nThe following actions are supported:\n" +- " --register Register one or more objects\n" +- " --deregister Deregister an object (and children)\n" +- " --query Query iSNS server for objects\n" +- " --list List all objects of a given type\n" +- " --enroll Create a new policy object for a client\n" +- " --edit-policy Edit a policy object\n" +- " --delete-policy Edit a policy object\n" +- " --help Display this message\n" +- "\nUse \"--query help\" to get help on e.g. the query action\n" +- ); +- exit(exval); +-} +- +-int +-parse_registration(char **argv, int argc, isns_object_list_t *objs, isns_object_t *key_obj) +-{ +- struct sockaddr_storage def_addr; +- isns_object_t *entity = NULL, *last_portal = NULL, *last_node = NULL; +- const char *def_port = NULL; +- int i; +- +- if (argc == 1 && !strcmp(argv[0], "help")) { +- printf("Object registration:\n" +- " isnsadm [-key attr=value] --register type,attr=value,... type,attr=value,...\n" +- "Where type can be one of:\n" +- " entity create/update network entity\n" +- " initiator create iSCSI initiator storage node\n" +- " target create iSCSI target storage node\n" +- " control create control node\n" +- " portal create portal\n" +- " pg create portal group\n" +- "\nThe following attributes are recognized:\n"); +- +- isns_attr_list_parser_help(NULL); +- exit(0); +- } +- +- if (argc == 0) +- usage(1, "Missing object list\n"); +- +- if (key_obj) { +- //isns_object_list_append(objs, key_obj); +- if (isns_object_is_entity(key_obj)) +- entity = key_obj; +- } +- +- def_addr = opt_myaddr; +- +- for (i = 0; i < argc; ++i) { +- isns_attr_list_t attrlist = ISNS_ATTR_LIST_INIT; +- struct isns_attr_list_parser state; +- isns_object_t *obj; +- char *type, *name, *value, *next_attr; +- char *attrs[128]; +- unsigned int nattrs = 0; +- +- name = argv[i]; +- +- if ((next_attr = strchr(name, ',')) != NULL) +- *next_attr++ = '\0'; +- +- while (next_attr && *next_attr) { +- if (nattrs > 128) +- isns_fatal("Too many attributes\n"); +- +- /* Show mercy with fat fingered +- * people,,,,who,cannot,,,type,properly */ +- if (next_attr[0] != ',') +- attrs[nattrs++] = next_attr; +- if ((next_attr = strchr(next_attr, ',')) != NULL) +- *next_attr++ = '\0'; +- } +- +- if ((value = strchr(name, '=')) != NULL) +- *value++ = '\0'; +- +- type = name; +- if (!strcmp(name, "entity")) { +- if (entity == NULL) { +- isns_error("Cannot create entity object " +- "within this key object\n"); +- return 0; +- } +- +- if (value != NULL) +- isns_object_set_string(entity, +- ISNS_TAG_ENTITY_IDENTIFIER, +- value); +- obj = isns_object_get(entity); +- goto handle_attributes; +- } else +- if (!strcmp(name, "node") +- || !strcmp(name, "initiator")) { +- const char *node_name; +- +- node_name = isns_config.ic_source_name; +- if (value) +- node_name = value; +- +- obj = isns_create_storage_node(node_name, +- ISNS_ISCSI_INITIATOR_MASK, +- entity); +- last_node = obj; +- +- isns_addr_set_port((struct sockaddr *) &def_addr, +- ISNS_DEFAULT_PORT_INITIATOR); +- def_port = "iscsi"; +- } else +- if (!strcmp(name, "target")) { +- const char *node_name; +- +- node_name = isns_config.ic_source_name; +- if (value) +- node_name = value; +- obj = isns_create_storage_node(node_name, +- ISNS_ISCSI_TARGET_MASK, +- entity); +- last_node = obj; +- +- isns_addr_set_port((struct sockaddr *) &def_addr, +- ISNS_DEFAULT_PORT_TARGET); +- def_port = "iscsi-target"; +- } else +- if (!strcmp(name, "control")) { +- const char *node_name; +- +- node_name = isns_config.ic_control_name; +- if (value) +- node_name = value; +- obj = isns_create_storage_node(node_name, +- ISNS_ISCSI_CONTROL_MASK, +- entity); +- last_node = obj; +- +- def_port = NULL; +- } else +- if (!strcmp(name, "portal")) { +- isns_portal_info_t portal_info; +- +- if (value == NULL) { +- if (def_port == NULL) +- isns_fatal("portal must follow initiator or target\n"); +- isns_portal_init(&portal_info, +- (struct sockaddr *) &def_addr, +- IPPROTO_TCP); +- } else +- if (!isns_portal_parse(&portal_info, value, def_port)) +- isns_fatal("Unable to parse portal=%s\n", value); +- obj = isns_create_portal(&portal_info, entity); +- last_portal = obj; +- } else +- if (!strcmp(name, "pg")) { +- if (value) +- isns_fatal("Unexpected value for portal group\n"); +- if (!last_portal || !last_node) +- isns_fatal("Portal group registration must follow portal and node\n"); +- obj = isns_create_portal_group(last_portal, last_node, 10); +- } else { +- isns_error("Unknown object type \"%s\"\n", name); +- return 0; +- } +- +- if (obj == NULL) { +- isns_error("Failure to create %s object\n", name); +- return 0; +- } +- isns_object_list_append(objs, obj); +- +-handle_attributes: +- isns_attr_list_parser_init(&state, obj->ie_template); +- state.default_port = def_port; +- +- if (!isns_parse_attrs(nattrs, attrs, &attrlist, &state) +- || !isns_object_set_attrlist(obj, &attrlist)) { +- isns_error("Failure to set all %s attributes\n", name); +- isns_attr_list_destroy(&attrlist); +- return 0; +- } +- +- isns_attr_list_destroy(&attrlist); +- isns_object_release(obj); +- } +- +- return 1; +-} +- +-static int +-__register_objects(isns_client_t *clnt, +- isns_object_t *key_obj, +- const isns_object_list_t *objects) +-{ +- isns_source_t *source = NULL; +- isns_simple_t *reg; +- uint32_t status; +- unsigned int i; +- +- for (i = 0; i < objects->iol_count && !source; ++i) { +- isns_object_t *obj = objects->iol_data[i]; +- +- if (!isns_object_is_iscsi_node(obj)) +- continue; +- source = isns_source_from_object(obj); +- } +- +- reg = isns_create_registration2(clnt, key_obj, source); +- isns_registration_set_replace(reg, opt_replace); +- +- /* Add all objects to be registered */ +- for (i = 0; i < objects->iol_count; ++i) +- isns_registration_add_object(reg, objects->iol_data[i]); +- +- status = isns_client_call(clnt, ®); +- isns_simple_free(reg); +- +- if (status == ISNS_SUCCESS) +- printf("Successfully registered object(s)\n"); +- else +- isns_error("Failed to register object(s): %s\n", +- isns_strerror(status)); +- +- if (source) +- isns_source_release(source); +- return status; +-} +- +-int +-register_objects(isns_client_t *clnt, +- int argc, char **argv) +-{ +- isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; +- isns_object_t *key_obj = NULL; +- uint32_t status; +- +- if (opt_key != NULL) { +- isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; +- struct isns_attr_list_parser state; +- +- isns_attr_list_parser_init(&state, NULL); +- +- if (!isns_parse_attrs(1, &opt_key, &key_attrs, &state)) { +- isns_error("Cannot parse registration key \"%s\"\n", +- opt_key); +- return 0; +- } +- +- key_obj = isns_create_object(isns_attr_list_parser_context(&state), +- &key_attrs, NULL); +- isns_attr_list_destroy(&key_attrs); +- +- if (!key_obj) { +- isns_error("Cannot create registration key object\n"); +- return 0; +- } +- } else { +- /* If the user does not provide a key object, +- * create/update an entity. +- */ +- key_obj = isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, NULL); +- } +- +- if (!parse_registration(argv, argc, &objects, key_obj)) +- isns_fatal("Unable to parse registration\n"); +- +- status = __register_objects(clnt, key_obj, &objects); +- isns_object_list_destroy(&objects); +- +- isns_object_release(key_obj); +- return status; +-} +- +-/* +- * Parse the query string given by the user +- * +- * 5.6.5.2 +- * The Message Key may contain key or non-key attributes or no +- * attributes at all. If multiple attributes are used as the +- * Message Key, then they MUST all be from the same object type +- * (e.g., IP address and TCP/UDP Port are attributes of the +- * Portal object type). +- */ +-int +-parse_query(char **argv, int argc, isns_attr_list_t *keys, isns_attr_list_t *query) +-{ +- struct isns_attr_list_parser state; +- +- isns_attr_list_parser_init(&state, NULL); +- state.nil_permitted = 1; +- +- if (argc == 1 && !strcmp(argv[0], "help")) { +- printf("Object query:\n" +- " isnsadm --query attr=value attr=value ... ?query-attr ?query-attr ...\n" +- "All key attributes must refer to a common object type.\n" +- "Query attributes specify the attributes the server should return," +- "and can refer to any object type.\n" +- "The following attributes are recognized:\n"); +- isns_attr_list_parser_help(&state); +- exit(0); +- } +- +- if (argc == 0) +- isns_fatal("Missing query attributes\n"); +- +- return isns_parse_query_attrs(argc, argv, keys, query, &state); +-} +- +-int +-query_objects(isns_client_t *clnt, int argc, char **argv) +-{ +- isns_attr_list_t query_key = ISNS_ATTR_LIST_INIT; +- isns_attr_list_t oper_attrs = ISNS_ATTR_LIST_INIT; +- isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; +- uint32_t status; +- isns_simple_t *qry; +- unsigned int i; +- +- if (!parse_query(argv, argc, &query_key, &oper_attrs)) +- isns_fatal("Unable to parse query\n"); +- +- qry = isns_create_query(clnt, &query_key); +- isns_attr_list_destroy(&query_key); +- +- /* Add the list of attributes we request */ +- for (i = 0; i < oper_attrs.ial_count; ++i) +- isns_query_request_attr(qry, oper_attrs.ial_data[i]); +- isns_attr_list_destroy(&oper_attrs); +- +- status = isns_client_call(clnt, &qry); +- if (status != ISNS_SUCCESS) { +- isns_error("Query failed: %s\n", isns_strerror(status)); +- return status; +- } +- +- status = isns_query_response_get_objects(qry, &objects); +- if (status) { +- isns_error("Unable to extract object list from query response: %s\n", +- isns_strerror(status), status); +- return status; +- } +- +- isns_object_list_print(&objects, isns_print_stdout); +- isns_object_list_destroy(&objects); +- isns_simple_free(qry); +- +- return status; +-} +- +-int +-query_entity_id(isns_client_t *clnt, int argc, char **argv) +-{ +- isns_attr_list_t query_key = ISNS_ATTR_LIST_INIT; +- isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; +- uint32_t status; +- isns_simple_t *qry; +- const char *eid; +- +- if (argc == 1 && !strcmp(argv[0], "help")) { +- printf("Query iSNS for own entity ID.\n" +- "No arguments allowed\n"); +- exit(0); +- } +- if (argc != 0) +- isns_fatal("EID query - no arguments accepted\n"); +- +- isns_attr_list_append_string(&query_key, +- ISNS_TAG_ISCSI_NAME, +- isns_config.ic_source_name); +- qry = isns_create_query(clnt, &query_key); +- isns_attr_list_destroy(&query_key); +- +- isns_query_request_attr_tag(qry, ISNS_TAG_ENTITY_IDENTIFIER); +- +- status = isns_client_call(clnt, &qry); +- if (status != ISNS_SUCCESS) { +- isns_error("Query failed: %s\n", isns_strerror(status)); +- return status; +- } +- +- status = isns_query_response_get_objects(qry, &objects); +- if (status) { +- isns_error("Unable to extract object list from query response: %s\n", +- isns_strerror(status), status); +- return status; +- } +- +- status = ISNS_NO_SUCH_ENTRY; +- if (objects.iol_count == 0) { +- isns_error("Node %s not registered with iSNS\n", +- isns_config.ic_source_name); +- } else +- if (!isns_object_get_string(objects.iol_data[0], +- ISNS_TAG_ENTITY_IDENTIFIER, &eid)) { +- isns_error("Query for %s returned an object without EID\n", +- isns_config.ic_source_name); +- } else { +- printf("%s\n", eid); +- status = ISNS_SUCCESS; +- } +- +- isns_object_list_destroy(&objects); +- isns_simple_free(qry); +- +- return status; +-} +- +-/* +- * Parse the list query string given by the user +- */ +-int +-parse_list(int argc, char **argv, isns_object_template_t **type_p, isns_attr_list_t *keys) +-{ +- struct isns_attr_list_parser state; +- isns_object_template_t *query_type = NULL; +- char *type_name; +- +- if (argc == 0) +- usage(1, "Missing object type"); +- +- if (argc == 1 && !strcmp(argv[0], "help")) { +- printf("Object query:\n" +- " isnsadm --list type attr=value attr=value ...\n" +- "Possible value for :\n" +- " entities - list all network entites\n" +- " nodes - list all storage nodes\n" +- " portals - list all portals\n" +- " portal-groups - list all portal groups\n" +- " dds - list all discovery domains\n" +- " ddsets - list all discovery domains sets\n" +- " policies - list all policies (privileged)\n" +- "Additional attributes can be specified to scope the\n" +- "search. They must match the specified object type.\n" +- "\nThe following attributes are recognized:\n"); +- isns_attr_list_parser_help(NULL); +- exit(0); +- } +- +- type_name = *argv++; --argc; +- if (!strcasecmp(type_name, "entities")) +- query_type = &isns_entity_template; +- else +- if (!strcasecmp(type_name, "nodes")) +- query_type = &isns_iscsi_node_template; +- else +- if (!strcasecmp(type_name, "portals")) +- query_type = &isns_portal_template; +- else +- if (!strcasecmp(type_name, "portal-groups")) +- query_type = &isns_iscsi_pg_template; +- else +- if (!strcasecmp(type_name, "dds")) +- query_type = &isns_dd_template; +- else +- if (!strcasecmp(type_name, "ddsets")) +- query_type = &isns_ddset_template; +- else +- if (!strcasecmp(type_name, "policies")) +- query_type = &isns_policy_template; +- else { +- isns_error("Unknown object type \"%s\"\n", +- type_name); +- return 0; +- } +- +- *type_p = query_type; +- +- isns_attr_list_parser_init(&state, query_type); +- state.nil_permitted = 1; +- +- return isns_parse_attrs(argc, argv, keys, &state); +-} +- +-int +-list_objects(isns_client_t *clnt, int argc, char **argv) +-{ +- isns_attr_list_t query_keys = ISNS_ATTR_LIST_INIT; +- isns_object_template_t *query_type = NULL; +- isns_simple_t *simp; +- int status, count = 0; +- +- if (!parse_list(argc, argv, &query_type, &query_keys)) +- isns_fatal("Unable to parse parameters\n"); +- +- simp = isns_create_getnext(clnt, query_type, &query_keys); +- while (1) { +- isns_object_t *obj = NULL; +- isns_simple_t *followup; +- +- status = isns_client_call(clnt, &simp); +- if (status) +- break; +- +- status = isns_getnext_response_get_object(simp, &obj); +- if (status) +- break; +- +- printf("Object %u:\n", count++); +- isns_object_print(obj, isns_print_stdout); +- isns_object_release(obj); +- +- followup = isns_create_getnext_followup(clnt, +- simp, &query_keys); +- isns_simple_free(simp); +- simp = followup; +- } +- +- if (status == ISNS_SOURCE_UNAUTHORIZED +- && query_type == &isns_policy_template +- && !opt_local) +- isns_warning("Please use --local trying to list policies\n"); +- +- if (status != ISNS_NO_SUCH_ENTRY) { +- isns_error("GetNext call failed: %s\n", +- isns_strerror(status)); +- return status; +- } +- return ISNS_SUCCESS; +-} +- +-/* +- * Parse the deregistration string given by the user +- * +- * 5.6.5.2 +- * The Message Key may contain key or non-key attributes or no +- * attributes at all. If multiple attributes are used as the +- * Message Key, then they MUST all be from the same object type +- * (e.g., IP address and TCP/UDP Port are attributes of the +- * Portal object type). +- */ +-int +-parse_deregistration(char **argv, int argc, isns_attr_list_t *keys) +-{ +- struct isns_attr_list_parser state; +- +- isns_attr_list_parser_init(&state, NULL); +- state.multi_type_permitted = 1; +- state.nil_permitted = 1; +- +- if (argc == 1 && !strcmp(argv[0], "help")) { +- printf("Object deregistration:\n" +- " isnsadm --deregister attr=value attr=value ...\n" +- "All attributes must refer to a common object type.\n" +- "\nThe following attributes are recognized:\n"); +- isns_attr_list_parser_help(&state); +- exit(0); +- } +- +- return isns_parse_attrs(argc, argv, keys, &state); +-} +- +-int +-deregister_objects(isns_client_t *clnt, int argc, char **argv) +-{ +- isns_attr_list_t query_key = ISNS_ATTR_LIST_INIT; +- isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; +- isns_simple_t *dereg; +- uint32_t status; +- +- if (!parse_deregistration(argv, argc, &query_key)) +- isns_fatal("Unable to parse unregistration\n"); +- +- dereg = isns_create_deregistration(clnt, &query_key); +- isns_attr_list_destroy(&query_key); +- +- status = isns_client_call(clnt, &dereg); +- if (status != ISNS_SUCCESS) { +- isns_error("Deregistration failed: %s\n", +- isns_strerror(status)); +- return status; +- } +- +-#if 0 +- status = isns_dereg_msg_response_get_objects(dereg, &objects); +- if (status) { +- isns_error("Unable to extract object list from deregistration response: %s\n", +- isns_strerror(status), status); +- goto done; +- } +- isns_object_list_print(&objects, isns_print_stdout); +-#endif +- +- isns_object_list_destroy(&objects); +- isns_simple_free(dereg); +- +- return status; +-} +- +-/* +- * Handle discovery domain registration/deregistration +- */ +-int +-parse_dd_registration(char **argv, int argc, isns_attr_list_t *keys) +-{ +- struct isns_attr_list_parser state; +- +- isns_attr_list_parser_init(&state, &isns_dd_template); +- if (argc == 1 && !strcmp(argv[0], "help")) { +- printf("Object query:\n" +- " isnsadm --dd-register attr=value attr=value ...\n" +- "You cannot specify more than one domain.\n" +- "If you want to modify an existing domain, you must specify its ID.\n" +- "The following attributes are recognized:\n"); +- isns_attr_list_parser_help(&state); +- exit(0); +- } +- +- return isns_parse_attrs(argc, argv, keys, &state); +-} +- +-int +-register_domain(isns_client_t *clnt, int argc, char **argv) +-{ +- isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; +- isns_simple_t *msg; +- uint32_t status; +- +- if (!parse_dd_registration(argv, argc, &attrs)) +- isns_fatal("Unable to parse DD registration\n"); +- +- msg = isns_create_dd_registration(clnt, &attrs); +- isns_attr_list_destroy(&attrs); +- +- if (msg == NULL) { +- isns_error("Cannot create message\n"); +- return ISNS_INTERNAL_ERROR; +- } +- +- status = isns_client_call(clnt, &msg); +- if (status != ISNS_SUCCESS) { +- isns_error("Registration failed: %s\n", +- isns_strerror(status)); +- return status; +- } +- +- if (status == ISNS_SUCCESS) { +- printf("Registered DD:\n"); +- isns_attr_list_print( +- isns_simple_get_attrs(msg), +- isns_print_stdout); +- } +- isns_simple_free(msg); +- +- return status; +-} +- +-int +-parse_dd_deregistration(char **argv, int argc, +- uint32_t *dd_id, isns_attr_list_t *keys) +-{ +- struct isns_attr_list_parser state; +- +- isns_attr_list_parser_init(&state, &isns_dd_template); +- if (argc == 0 || (argc == 1 && !strcmp(argv[0], "help"))) { +- printf("DD deregistration:\n" +- " isnsadm --dd-deregister dd-id attr=value attr=value ...\n" +- "You cannot specify more than one domain.\n" +- "The following attributes are recognized:\n"); +- isns_attr_list_parser_help(&state); +- exit(0); +- } +- +- *dd_id = parse_count(argv[0]); +- +- return isns_parse_attrs(argc - 1, argv + 1, keys, &state); +-} +- +-int +-deregister_domain(isns_client_t *clnt, int argc, char **argv) +-{ +- isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; +- isns_simple_t *msg; +- uint32_t dd_id, status; +- +- if (!parse_dd_deregistration(argv, argc, &dd_id, &attrs)) +- isns_fatal("Unable to parse DD registration\n"); +- +- msg = isns_create_dd_deregistration(clnt, dd_id, &attrs); +- isns_attr_list_destroy(&attrs); +- +- if (msg == NULL) { +- isns_error("Cannot create message\n"); +- return ISNS_INTERNAL_ERROR; +- } +- +- status = isns_client_call(clnt, &msg); +- if (status != ISNS_SUCCESS) { +- isns_error("Deregistration failed: %s\n", +- isns_strerror(status)); +- return status; +- } +- +- isns_simple_free(msg); +- return status; +-} +- +-/* +- * Parse a policy +- */ +-int +-parse_policy(int argc, char **argv, isns_attr_list_t *attrs, +- const char *help_title, const char *help_action) +-{ +- struct isns_attr_list_parser state; +- +- isns_attr_list_parser_init(&state, &isns_policy_template); +- state.nil_permitted = 0; +- state.load_key = load_key_callback; +- state.generate_key = generate_key_callback; +- +- if (argc == 1 && !strcmp(argv[0], "help")) { +- printf("%s:\n" +- " isnsadm %s attr=value attr=value ...\n" +- "Specifying a Security Policy Index is mandatory.\n" +- "\nThe following attributes are recognized:\n", +- help_title, help_action); +- isns_attr_list_parser_help(&state); +- exit(0); +- } +- +- return isns_parse_attrs(argc, argv, attrs, &state); +-} +- +-static int +-__create_policy(isns_client_t *clnt, const isns_attr_list_t *attrs) +-{ +- isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; +- isns_object_t *obj; +- int status; +- +- obj = isns_create_object(&isns_policy_template, attrs, NULL); +- if (!obj) +- isns_fatal("Cannot create policy object\n"); +- isns_object_list_append(&objects, obj); +- +- status = __register_objects(clnt, NULL, &objects); +- isns_object_list_destroy(&objects); +- return status; +-} +- +-/* +- * Enroll a new client +- */ +-int +-enroll_client(isns_client_t *clnt, int argc, char **argv) +-{ +- isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; +- const char *client_name; +- int status; +- +- if (argc == 0) +- usage(1, "Missing client name"); +- +- client_name = *argv++; --argc; +- +- isns_attr_list_append_string(&attrs, +- OPENISNS_TAG_POLICY_SPI, +- client_name); +-#if 0 +- isns_attr_list_append_string(&attrs, +- OPENISNS_TAG_POLICY_SOURCE_NAME, +- client_name); +-#endif +- +- if (!opt_keyfile) { +- static char namebuf[PATH_MAX]; +- +- snprintf(namebuf, sizeof(namebuf), "%s.key", client_name); +- opt_keyfile = namebuf; +- } +- +- if (argc && !parse_policy(argc, argv, &attrs, +- "Enroll an iSNS client", +- "--enroll hostname")) +- isns_fatal("Cannot parse policy\n"); +- +- /* If no key is given, generate one */ +- if (!isns_attr_list_contains(&attrs, OPENISNS_TAG_POLICY_KEY)) { +- printf("No key given, generating one\n"); +- isns_attr_list_append_attr(&attrs, +- generate_key_callback()); +- } +- +- status = __create_policy(clnt, &attrs); +- isns_attr_list_destroy(&attrs); +- return status; +-} +- +- +-/* +- * Create a new policy +- */ +-int +-edit_policy(isns_client_t *clnt, int argc, char **argv) +-{ +- isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; +- int status; +- +- if (!parse_policy(argc, argv, &attrs, +- "Edit an existing policy", +- "--edit-policy")) +- isns_fatal("Cannot parse policy\n"); +- +- status = __create_policy(clnt, &attrs); +- isns_attr_list_destroy(&attrs); +- +- return status; +-} +- +-#ifdef WITH_SECURITY +-static isns_attr_t * +-__key_to_attr(EVP_PKEY *pkey) +-{ +- struct __isns_opaque key; +- isns_value_t value; +- isns_attr_t *attr = NULL; +- +- if (!isns_dsa_encode_public(pkey, &key.ptr, &key.len)) +- goto out; +- +- /* Must pad key. This means we may end up encoding a few +- * bytes of trash. Oh well. */ +- key.len = ISNS_PAD(key.len); +- +- value = ISNS_VALUE_INIT(opaque, key); +- attr = isns_attr_alloc(OPENISNS_TAG_POLICY_KEY, NULL, &value); +- +- isns_free(key.ptr); +- +-out: +- EVP_PKEY_free(pkey); +- return attr; +-} +- +-isns_attr_t * +-generate_key_callback(void) +-{ +- EVP_PKEY *pkey; +- +- if (opt_keyfile == NULL) +- isns_fatal("Key generation requires --keyfile option\n"); +- +- if (!(pkey = isns_dsa_generate_key())) +- isns_fatal("Key generation failed\n"); +- +- if (!isns_dsa_store_private(opt_keyfile, pkey)) +- isns_fatal("Unable to write private key to %s\n", +- opt_keyfile); +- +- printf("Stored DSA private key in %s\n", opt_keyfile); +- return __key_to_attr(pkey); +-} +- +-isns_attr_t * +-load_key_callback(const char *pathname) +-{ +- EVP_PKEY *pkey; +- +- if (!(pkey = isns_dsa_load_public(pathname))) +- isns_fatal("Unable to load public key from file %s\n", pathname); +- +- return __key_to_attr(pkey); +-} +- +-#else /* WITH_SECURITY */ +-isns_attr_t * +-generate_key_callback(void) +-{ +- isns_fatal("Authentication disabled in this build\n"); +- return NULL; +-} +- +-isns_attr_t * +-load_key_callback(const char *pathname) +-{ +- isns_fatal("Authentication disabled in this build\n"); +- return NULL; +-} +- +-#endif +diff --git a/utils/open-isns/isnsd.c b/utils/open-isns/isnsd.c +deleted file mode 100644 +index 3f983d6..0000000 +--- a/utils/open-isns/isnsd.c ++++ /dev/null +@@ -1,299 +0,0 @@ +-/* +- * isnsd - the iSNS Daemon +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#ifdef MTRACE +-# include +-#endif +- +-#include +-#include "security.h" +-#include "util.h" +-#include "paths.h" +-#include "internal.h" +- +-enum { +- MODE_NORMAL, +- MODE_DUMP_DB, +- MODE_INIT, +-}; +- +-static const char * opt_configfile = ISNS_DEFAULT_ISNSD_CONFIG; +-static int opt_af = AF_UNSPEC; +-static int opt_mode = MODE_NORMAL; +-static int opt_foreground = 0; +- +-static char * slp_url; +- +-static int init_server(void); +-static void run_server(isns_server_t *, isns_db_t *); +-static void usage(int, const char *); +-static void cleanup(int); +- +-static struct option options[] = { +- { "config", required_argument, NULL, 'c' }, +- { "debug", required_argument, NULL, 'd' }, +- { "foreground", no_argument, NULL, 'f' }, +- { "init", no_argument, NULL, MODE_INIT }, +- { "dump-db", no_argument, NULL, MODE_DUMP_DB }, +- { "help", no_argument, NULL, 'h' }, +- { "version", no_argument, NULL, 'V' }, +- { NULL } +-}; +- +-int +-main(int argc, char **argv) +-{ +- isns_server_t *server; +- isns_source_t *source; +- isns_db_t *db; +- int c; +- +-#ifdef MTRACE +- mtrace(); +-#endif +- +- while ((c = getopt_long(argc, argv, "46c:d:fh", options, NULL)) != -1) { +- switch (c) { +- case '4': +- opt_af = AF_INET; +- break; +- +- case '6': +- opt_af = AF_INET6; +- break; +- +- case 'c': +- opt_configfile = optarg; +- break; +- +- case 'd': +- isns_enable_debugging(optarg); +- break; +- +- case 'f': +- opt_foreground = 1; +- break; +- +- case MODE_DUMP_DB: +- case MODE_INIT: +- opt_mode = c; +- break; +- +- case 'h': +- usage(0, NULL); +- +- case 'V': +- printf("Open-iSNS version %s\n" +- "Copyright (C) 2007, Olaf Kirch \n", +- OPENISNS_VERSION_STRING); +- return 0; +- +- default: +- usage(1, "Unknown option"); +- } +- } +- +- if (optind != argc) +- usage(1, NULL); +- +- isns_read_config(opt_configfile); +- +- if (!isns_config.ic_source_name) +- usage(1, "Please specify an iSNS source name"); +- source = isns_source_create_iscsi(isns_config.ic_source_name); +- +- if (opt_mode == MODE_INIT) +- return !init_server(); +- +- if (opt_mode == MODE_NORMAL) +- isns_write_pidfile(isns_config.ic_pidfile); +- +- db = isns_db_open(isns_config.ic_database); +- if (db == NULL) +- isns_fatal("Unable to open database\n"); +- +- if (opt_mode == MODE_DUMP_DB) { +- isns_db_print(db, isns_print_stdout); +- exit(0); +- } +- +- if (!opt_foreground) { +- if (daemon(0, 0) < 0) +- isns_fatal("Unable to background server process\n"); +- isns_log_background(); +- isns_update_pidfile(isns_config.ic_pidfile); +- } +- +- signal(SIGTERM, cleanup); +- signal(SIGINT, cleanup); +- +- server = isns_create_server(source, db, &isns_default_service_ops); +- +- run_server(server, db); +- return 0; +-} +- +-void +-usage(int exval, const char *msg) +-{ +- if (msg) +- fprintf(stderr, "Error: %s\n", msg); +- fprintf(stderr, +- "Usage: isnsd [options]\n\n" +- " --config Specify alternative config fille\n" +- " --foreground Do not put daemon in the background\n" +- " --debug Enable debugging (list of debug flags)\n" +- " --init Initialize the server (key generation etc)\n" +- " --dump-db Display the database contents and exit\n" +- " --help Print this message\n" +- ); +- exit(exval); +-} +- +-void +-cleanup(int sig) +-{ +- isns_remove_pidfile(isns_config.ic_pidfile); +- exit(1); +-} +- +-static void +-slp_cleanup(void) +-{ +- char *url = slp_url; +- +- slp_url = NULL; +- if (url) { +- isns_slp_unregister(url); +- isns_free(url); +- } +-} +- +-/* +- * Initialize server +- */ +-int +-init_server(void) +-{ +- if (!isns_security_init()) +- return 0; +- +- /* Anything else? */ +- +- return 1; +-} +- +-/* +- * Server main loop +- */ +-void +-run_server(isns_server_t *server, isns_db_t *db) +-{ +- isns_socket_t *sock; +- isns_security_t *ctx = NULL; +- isns_message_t *msg, *resp; +- int status; +- +- if (isns_config.ic_security) { +- const char *ksname; +- isns_keystore_t *ks; +- +- ctx = isns_default_security_context(1); +- if (!(ksname = isns_config.ic_client_keystore)) +- isns_fatal("config problem: no key store specified\n"); +- if (!strcasecmp(ksname, "db:")) +- ks = isns_create_db_keystore(db); +- else +- ks = isns_create_keystore(ksname); +- if (ks == NULL) +- isns_fatal("Unable to create keystore %s\n", ksname); +- isns_security_set_keystore(ctx, ks); +- } +- +- status = isns_dd_load_all(db); +- if (status != ISNS_SUCCESS) +- isns_fatal("Problem loading Discovery Domains from database\n"); +- +- if (isns_config.ic_control_socket) { +- sock = isns_create_server_socket(isns_config.ic_control_socket, +- NULL, AF_UNSPEC, SOCK_STREAM); +- if (sock == NULL) +- isns_fatal("Unable to create control socket\n"); +- /* +- isns_socket_set_security_ctx(sock, ctx); +- */ +- } +- +- sock = isns_create_server_socket(isns_config.ic_bind_address, +- "isns", opt_af, SOCK_STREAM); +- if (sock == NULL) +- isns_fatal("Unable to create server socket\n"); +- isns_socket_set_security_ctx(sock, ctx); +- +- if (isns_config.ic_slp_register) { +- slp_url = isns_slp_build_url(0); +- isns_slp_register(slp_url); +- +- atexit(slp_cleanup); +- } +- +- isns_esi_init(server); +- isns_scn_init(server); +- +- while (1) { +- struct timeval timeout = { 0, 0 }; +- time_t now, then, next_timeout = time(NULL) + 3600; +- +- /* Expire entities that haven't seen any activity +- * for a while. */ +- if (isns_config.ic_registration_period) { +- then = isns_db_expire(db); +- if (then && then < next_timeout) +- next_timeout = then; +- } +- +- /* Run any timers (eg for ESI) */ +- then = isns_run_timers(); +- if (then && then < next_timeout) +- next_timeout = then; +- +- /* There may be pending SCNs, push them out now */ +- then = isns_scn_transmit_all(); +- if (then && then < next_timeout) +- next_timeout = then; +- +- /* Purge any objects that have been marked for removal +- * from the DB (deleting them, or moving them to limbo +- * state). */ +- isns_db_purge(db); +- +- /* Determine how long we can sleep before working +- * the ESI queues and DB expiry again. */ +- now = time(NULL); +- if (next_timeout <= now) +- continue; +- timeout.tv_sec = next_timeout - now; +- +- if ((msg = isns_recv_message(&timeout)) == NULL) +- continue; +- +- if ((resp = isns_process_message(server, msg)) != NULL) { +- isns_socket_t *sock = isns_message_socket(msg); +- +- isns_socket_send(sock, resp); +- isns_message_release(resp); +- } +- +- isns_message_release(msg); +- } +-} +diff --git a/utils/open-isns/isnsdd.c b/utils/open-isns/isnsdd.c +deleted file mode 100644 +index e4e212d..0000000 +--- a/utils/open-isns/isnsdd.c ++++ /dev/null +@@ -1,1153 +0,0 @@ +-/* +- * isnsdd - the iSNS Discovery Daemon +- * +- * Copyright (C) 2007 Olaf Kirch +- * +- * The way isnsdd communicates with local services (initiator, +- * target) is via a set of files and signals. That sounds rather +- * awkward, but it's a lot simpler to add to these services +- * than another socket based communication mechanism I guess. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#ifdef MTRACE +-# include +-#endif +- +-#include +-#include "security.h" +-#include "util.h" +-#include "isns-proto.h" +-#include "paths.h" +-#include "attrs.h" +- +-enum { +- ROLE_INITIATOR = 1, +- ROLE_MONITOR = 2, +-}; +- +-#define ISNSDD_REG_NAME "isns" +-#define ISNSDD_PGT_OFFSET 10000 +-#define MAX_RETRY_TIMEOUT 300 +- +-typedef struct isns_proxy isns_proxy_t; +-struct isns_proxy { +- isns_list_t ip_list; +- char * ip_eid; +- isns_object_t * ip_entity; +- isns_client_t * ip_client; +- isns_object_list_t ip_objects; +- time_t ip_last_registration; +-}; +- +-static const char * opt_configfile = ISNS_DEFAULT_ISNSDD_CONFIG; +-static int opt_af = AF_INET6; +-static int opt_foreground = 0; +-static int opt_role = ROLE_INITIATOR; +-static int opt_scn_bits = ISNS_SCN_OBJECT_UPDATED_MASK | +- ISNS_SCN_OBJECT_ADDED_MASK | +- ISNS_SCN_OBJECT_REMOVED_MASK | +- ISNS_SCN_TARGET_AND_SELF_ONLY_MASK; +-static unsigned int opt_retry_timeout = 10; +-static int opt_esi = 1; +- +-static isns_socket_t * server_socket; +-static ISNS_LIST_DECLARE(proxies); +-static isns_object_list_t local_registry = ISNS_OBJECT_LIST_INIT; +-static isns_object_list_t local_portals = ISNS_OBJECT_LIST_INIT; +-static isns_object_list_t visible_nodes = ISNS_OBJECT_LIST_INIT; +-static unsigned int esi_interval; +-static int should_reexport; +- +-static void run_discovery(isns_server_t *srv); +-static void scn_callback(isns_db_t *, uint32_t, +- isns_object_template_t *, +- const char *, const char *); +-static void refresh_registration(void *); +-static void retry_registration(void *); +-static void load_exported_objects(void); +-static void store_imported_objects(void); +-static void usage(int, const char *); +- +-static void install_sighandler(int, void (*func)(int)); +-static void sig_cleanup(int); +-static void sig_reread(int); +- +-static struct option options[] = { +- { "config", required_argument, NULL, 'c' }, +- { "debug", required_argument, NULL, 'd' }, +- { "foreground", no_argument, NULL, 'f' }, +- { "role", required_argument, NULL, 'r' }, +- { "no-esi", no_argument, NULL, 'E' }, +- { "help", no_argument, NULL, 'h' }, +- { "version", no_argument, NULL, 'V' }, +- { NULL } +-}; +- +-int +-main(int argc, char **argv) +-{ +- isns_server_t *server; +- isns_source_t *source; +- isns_db_t *db; +- int c; +- +-#ifdef MTRACE +- mtrace(); +-#endif +- +- while ((c = getopt_long(argc, argv, "46c:d:Efhr:", options, NULL)) != -1) { +- switch (c) { +- case '4': +- opt_af = AF_INET; +- break; +- +- case '6': +- opt_af = AF_INET6; +- break; +- +- case 'c': +- opt_configfile = optarg; +- break; +- +- case 'd': +- isns_enable_debugging(optarg); +- break; +- +- case 'E': +- opt_esi = 0; +- break; +- +- case 'f': +- opt_foreground = 1; +- break; +- +- case 'h': +- usage(0, NULL); +- +- case 'r': +- if (!strcasecmp(optarg, "initiator")) +- opt_role = ROLE_INITIATOR; +- else +- if (!strcasecmp(optarg, "control") +- || !strcasecmp(optarg, "monitor")) +- opt_role = ROLE_MONITOR; +- else { +- isns_error("Unknown role \"%s\"\n", optarg); +- usage(1, NULL); +- } +- break; +- +- case 'V': +- printf("Open-iSNS version %s\n" +- "Copyright (C) 2007, Olaf Kirch \n", +- OPENISNS_VERSION_STRING); +- return 0; +- +- default: +- usage(1, "Unknown option"); +- } +- } +- +- if (optind != argc) +- usage(1, NULL); +- +- /* If the config code derives the source name +- * automatically, we want it to be distinct from +- * any other source name (chosen by eg the iSCSI +- * initiator). Adding a suffix of ":isns" is a +- * somewhat lame attempt. +- */ +- isns_config.ic_source_suffix = "isns"; +- +- isns_read_config(opt_configfile); +- +- if (!isns_config.ic_source_name) +- usage(1, "Please specify an iSNS source name"); +- source = isns_source_create_iscsi(isns_config.ic_source_name); +- +- isns_write_pidfile(isns_config.ic_pidfile); +- +- if (!opt_foreground) { +- if (daemon(0, 0) < 0) +- isns_fatal("Unable to background server process\n"); +- isns_log_background(); +- isns_update_pidfile(isns_config.ic_pidfile); +- } +- +- install_sighandler(SIGTERM, sig_cleanup); +- install_sighandler(SIGINT, sig_cleanup); +- install_sighandler(SIGUSR2, sig_reread); +- +- /* Create a DB object that shadows our portal list. This is for ESI - +- * when an ESI comes in, the library will look up the portal in this +- * database, and update its mtime. By checking the mtime at regular +- * intervals, we can verify whether the server's ESIs actually +- * reach us. +- */ +- db = isns_db_open_shadow(&local_portals); +- +- server = isns_create_server(source, db, &isns_callback_service_ops); +- isns_server_set_scn_callback(server, scn_callback); +- +- run_discovery(server); +- return 0; +-} +- +-void +-usage(int exval, const char *msg) +-{ +- if (msg) +- fprintf(stderr, "Error: %s\n", msg); +- fprintf(stderr, +- "Usage: isnsdd [options]\n\n" +- " --role Specify role (one of initiator, control)\n" +- " --config Specify alternative config fille\n" +- " --foreground Do not put daemon in the background\n" +- " --no-esi Do not try to register an portals for ESI status inquiries\n" +- " --debug Enable debugging (list of debug flags)\n" +- " --help Print this message\n" +- ); +- exit(exval); +-} +- +-void +-install_sighandler(int signo, void (*func)(int)) +-{ +- struct sigaction act; +- +- memset(&act, 0, sizeof(act)); +- act.sa_handler = func; +- sigaction(signo, &act, NULL); +-} +- +-void +-sig_reread(int sig) +-{ +- should_reexport = 1; +-} +- +-void +-sig_cleanup(int sig) +-{ +- isns_remove_pidfile(isns_config.ic_pidfile); +- exit(1); +-} +- +-/* +- * Proxy handling functions +- */ +-static isns_proxy_t * +-isns_create_proxy(const char *eid) +-{ +- isns_proxy_t *proxy; +- +- proxy = calloc(1, sizeof(*proxy)); +- isns_list_init(&proxy->ip_list); +- proxy->ip_eid = strdup(eid); +- return proxy; +-} +- +-static isns_proxy_t * +-__isns_proxy_find(isns_list_t *head, const char *eid) +-{ +- isns_list_t *pos, *next; +- +- isns_list_foreach(head, pos, next) { +- isns_proxy_t *proxy = isns_list_item(isns_proxy_t, ip_list, pos); +- +- if (!strcmp(proxy->ip_eid, eid)) +- return proxy; +- } +- return NULL; +-} +- +-static isns_proxy_t * +-isns_proxy_by_entity(const isns_object_t *entity) +-{ +- isns_list_t *pos, *next; +- +- isns_list_foreach(&proxies, pos, next) { +- isns_proxy_t *proxy = isns_list_item(isns_proxy_t, ip_list, pos); +- +- if (proxy->ip_entity == entity) +- return proxy; +- } +- return NULL; +-} +- +-static void +-isns_proxy_erase(isns_proxy_t *proxy) +-{ +- isns_object_list_destroy(&proxy->ip_objects); +- if (proxy->ip_client) { +- isns_client_destroy(proxy->ip_client); +- proxy->ip_client = NULL; +- } +- if (proxy->ip_entity) { +- isns_object_release(proxy->ip_entity); +- proxy->ip_entity = NULL; +- } +- isns_cancel_timer(refresh_registration, proxy); +-} +- +-static void +-isns_proxy_free(isns_proxy_t *proxy) +-{ +- isns_proxy_erase(proxy); +- isns_list_del(&proxy->ip_list); +- free(&proxy->ip_eid); +- free(proxy); +-} +- +-/* +- * Force a re-registration of the whole object set. +- */ +-static void +-force_reregistration(isns_proxy_t *proxy) +-{ +- isns_cancel_timer(refresh_registration, proxy); +- isns_add_oneshot_timer(0, retry_registration, proxy); +-} +- +-/* +- * Refresh the registration by calling DevAttrQry +- */ +-static void +-refresh_registration(void *ptr) +-{ +- isns_proxy_t *proxy = ptr; +- isns_client_t *clnt = proxy->ip_client; +- isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; +- isns_attr_list_t query_key = ISNS_ATTR_LIST_INIT; +- isns_simple_t *qry = NULL; +- uint32_t status; +- +- isns_debug_state("Refreshing registration for %s\n", proxy->ip_eid); +- isns_attr_list_append_string(&query_key, +- ISNS_TAG_ENTITY_IDENTIFIER, +- proxy->ip_eid); +- +- qry = isns_create_query(clnt, &query_key); +- isns_attr_list_destroy(&query_key); +- +- /* We should have an async call mechanism. If the server +- * is wedged, we'll block here, unable to service any other +- * functions. +- */ +- status = isns_simple_call(clnt->ic_socket, &qry); +- if (status != ISNS_SUCCESS) { +- isns_error("Query failed: %s\n", isns_strerror(status)); +- goto re_register; +- } +- +- status = isns_query_response_get_objects(qry, &objects); +- isns_simple_free(qry); +- +- if (status == ISNS_SUCCESS) { +- if (objects.iol_count != 0) +- return; +- } else { +- isns_error("Unable to parse query response\n"); +- } +- +-re_register: +- isns_warning("Lost registration, trying to re-register\n"); +- force_reregistration(proxy); +-} +- +-/* +- * Check if all portals have seen ESI messages from the server +- */ +-static void +-check_portal_registration(void *ptr) +-{ +- isns_object_list_t bad_portals = ISNS_OBJECT_LIST_INIT; +- unsigned int i, need_reregister = 0, good_portals = 0; +- time_t now; +- +- isns_debug_state("%s()\n", __FUNCTION__); +- now = time(NULL); +- for (i = 0; i < local_portals.iol_count; ++i) { +- isns_object_t *obj = local_portals.iol_data[i]; +- isns_portal_info_t portal_info; +- isns_proxy_t *proxy; +- time_t last_modified; +- uint32_t interval; +- +- if (!isns_object_get_uint32(obj, ISNS_TAG_ESI_INTERVAL, &interval)) +- continue; +- +- last_modified = isns_object_last_modified(obj); +- if (last_modified + 2 * interval > now) { +- good_portals++; +- continue; +- } +- +- isns_portal_from_object(&portal_info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- obj); +- +- isns_notice("Portal %s did not receive ESIs within %u seconds - " +- "server may have lost us.\n", +- isns_portal_string(&portal_info), +- now - last_modified); +- +- proxy = isns_proxy_by_entity(isns_object_get_entity(obj)); +- if (!proxy) +- continue; +- +- /* If we haven't received ANY ESIs, ever, the portal +- * may be using a non-routable IP */ +- if (last_modified <= proxy->ip_last_registration) +- isns_object_list_append(&bad_portals, obj); +- +- force_reregistration(proxy); +- need_reregister++; +- } +- +- for (i = 0; i < bad_portals.iol_count; ++i) +- isns_object_list_remove(&local_portals, bad_portals.iol_data[i]); +- isns_object_list_destroy(&bad_portals); +- +- if (need_reregister && local_portals.iol_count == 0) { +- /* Force a re-registration from scratch. +- * This time without ESI. +- */ +- isns_notice("Suspiciously little ESI traffic - server may be broken\n"); +- isns_notice("Disabling ESI\n"); +- opt_esi = 0; +- } +-} +- +-static void +-setup_esi_watchdog(void) +-{ +- unsigned int i; +- +- isns_cancel_timer(check_portal_registration, NULL); +- esi_interval = 0; +- +- for (i = 0; i < local_portals.iol_count; ++i) { +- isns_object_t *obj = local_portals.iol_data[i]; +- uint32_t interval; +- +- /* should always succeed */ +- if (isns_object_get_uint32(obj, ISNS_TAG_ESI_INTERVAL, &interval)) +- continue; +- +- if (!esi_interval || interval < esi_interval) +- esi_interval = interval; +- } +- +- if (esi_interval) { +- isns_debug_state("Setting up timer to check for ESI reachability\n"); +- isns_add_timer(esi_interval * 4 / 5, +- check_portal_registration, +- NULL); +- } +-} +- +-static void +-load_exported_objects(void) +-{ +- isns_debug_state("Reading list of exported objects\n"); +- isns_object_list_destroy(&local_registry); +- if (!isns_local_registry_load("!" ISNSDD_REG_NAME, 0, &local_registry)) { +- isns_warning("Unable to obtain locally registered objects\n"); +- return; +- } +-} +- +-static void +-store_imported_objects(void) +-{ +- if (!isns_local_registry_store(ISNSDD_REG_NAME, 0, &visible_nodes)) +- isns_warning("Unable to store discovered objects\n"); +-} +- +-/* +- * Given the DevAttrReg response, extract the entity ID we +- * have been assigned. +- */ +-static int +-extract_entity_id(isns_proxy_t *proxy, isns_simple_t *resp) +-{ +- isns_object_list_t resp_objects = ISNS_OBJECT_LIST_INIT; +- isns_object_t *entity = NULL; +- int status; +- unsigned int i; +- +- status = isns_query_response_get_objects(resp, &resp_objects); +- if (status) { +- isns_error("Unable to extract object list from " +- "registration response: %s\n", +- isns_strerror(status), status); +- goto out; +- } +- +- for (i = 0; i < resp_objects.iol_count; ++i) { +- isns_object_t *obj = resp_objects.iol_data[i]; +- uint32_t interval; +- +- if (!isns_object_is_entity(obj)) +- continue; +- +- if (entity) { +- isns_error("Server returns more than one entity " +- "in registration response. What a weirdo.\n"); +- continue; +- } +- entity = obj; +- +- if (!isns_object_get_uint32(obj, +- ISNS_TAG_REGISTRATION_PERIOD, +- &interval)) +- continue; +- +- if (interval == 0) { +- isns_error("Server returns a registration period of 0\n"); +- continue; +- } +- +- isns_debug_state("Setting up timer for registration refresh\n"); +- isns_add_timer(interval / 2, +- refresh_registration, +- proxy); +- } +- +- for (i = 0; i < resp_objects.iol_count; ++i) { +- isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; +- isns_object_t *obj = resp_objects.iol_data[i]; +- uint32_t interval; +- +- if (!isns_object_is_portal(obj) +- || !isns_object_get_uint32(obj, ISNS_TAG_ESI_INTERVAL, &interval)) +- continue; +- +- if (interval == 0) { +- isns_error("Server returns an ESI interval of 0\n"); +- continue; +- } +- +- isns_object_get_key_attrs(obj, &key_attrs); +- if (!(obj = isns_object_list_lookup(&proxy->ip_objects, NULL, &key_attrs))) { +- isns_error("Server response includes a portal we never registered\n"); +- continue; +- } +- +- isns_object_set_uint32(obj, ISNS_TAG_ESI_INTERVAL, interval); +- +- /* Server enabled ESI for this portal, so add it to +- * the list of local portals we regularly check for +- * incoming ESI messages. */ +- isns_object_list_append(&local_portals, obj); +- } +- +- proxy->ip_last_registration = time(NULL); +-out: +- isns_object_list_destroy(&resp_objects); +- return status; +-} +- +-static inline void +-__add_release_object(isns_object_list_t *objects, isns_object_t *cur) +-{ +- if (cur == NULL) +- return; +- isns_object_list_append(objects, cur); +- isns_object_release(cur); +-} +- +-/* +- * Rebuild the list of proxies given the set of entities +- */ +-void +-rebuild_proxy_list(isns_object_list_t *entities, isns_list_t *old_list) +-{ +- isns_proxy_t *proxy; +- unsigned int i; +- +- isns_list_move(old_list, &proxies); +- +- for (i = 0; i < entities->iol_count; ++i) { +- isns_object_t *entity = entities->iol_data[i]; +- isns_object_t *node; +- const char *eid; +- +- eid = isns_entity_name(entity); +- if (eid == NULL) { +- isns_error("Whoopee, entity without name\n"); +- continue; +- } +- +- proxy = __isns_proxy_find(old_list, eid); +- if (proxy == NULL) { +- proxy = isns_create_proxy(eid); +- } else { +- isns_proxy_erase(proxy); +- } +- +- isns_object_list_append(&proxy->ip_objects, entity); +- isns_object_get_descendants(entity, NULL, &proxy->ip_objects); +- +- node = isns_object_list_lookup(&proxy->ip_objects, +- &isns_iscsi_node_template, +- NULL); +- if (node == NULL) { +- isns_warning("Service %s did not register any " +- "storage nodes - skipped\n", eid); +- continue; +- } +- +- proxy->ip_client = isns_create_client(NULL, +- isns_storage_node_name(node)); +- proxy->ip_entity = isns_object_get(entity); +- +- isns_list_del(&proxy->ip_list); +- isns_list_append(&proxies, &proxy->ip_list); +- } +-} +- +-/* +- * Unregister old proxies +- */ +-static void +-unregister_entities(isns_list_t *list) +-{ +- while (!isns_list_empty(list)) { +- isns_proxy_t *proxy = isns_list_item(isns_proxy_t, ip_list, list->next); +- +- /* XXX send a DevDereg */ +- isns_proxy_free(proxy); +- } +-} +- +-/* +- * The local registry creates fake entities to group objects +- * registered by the same service. We use this to perform +- * several registration calls, each with a different EID +- */ +-static int +-register_entity(isns_proxy_t *proxy) +-{ +- isns_client_t *clnt = proxy->ip_client; +- isns_simple_t *call = NULL; +- int status; +- +- call = isns_create_registration(clnt, proxy->ip_entity); +- isns_registration_set_replace(call, 1); +- isns_registration_add_object_list(call, &proxy->ip_objects); +- +- status = isns_simple_call(clnt->ic_socket, &call); +- if (status == ISNS_SUCCESS) { +- /* Extract the EID and registration period */ +- extract_entity_id(proxy, call); +- } +- +- isns_simple_free(call); +- return status; +-} +- +-static int +-register_exported_entities(void) +-{ +- int status = ISNS_SUCCESS; +- isns_list_t *pos, *next; +- +- isns_list_foreach(&proxies, pos, next) { +- isns_proxy_t *proxy = isns_list_item(isns_proxy_t, ip_list, pos); +- +- status = register_entity(proxy); +- if (status != ISNS_SUCCESS) +- break; +- } +- +- setup_esi_watchdog(); +- return status; +-} +- +-static void +-all_objects_set(isns_object_list_t *list, uint32_t tag, uint32_t value) +-{ +- unsigned int i; +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- +- isns_object_set_uint32(obj, tag, value); +- } +-} +- +-static void +-all_objects_unset(isns_object_list_t *list, uint32_t tag) +-{ +- unsigned int i; +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- +- isns_object_delete_attr(obj, tag); +- } +-} +- +-static int +-register_exported_objects(isns_client_t *clnt) +-{ +- isns_portal_info_t portal_info; +- isns_object_list_t entities = ISNS_OBJECT_LIST_INIT; +- isns_object_list_t portals = ISNS_OBJECT_LIST_INIT; +- isns_simple_t *call = NULL; +- int status, with_esi; +- unsigned int i, my_port; +- isns_list_t old_proxies; +- +- if (!isns_socket_get_portal_info(server_socket, &portal_info)) +- isns_fatal("Unable to get portal info\n"); +- my_port = isns_portal_tcpudp_port(&portal_info); +- +- /* Look up all entites and portals */ +- isns_object_list_gang_lookup(&local_registry, +- &isns_entity_template, NULL, +- &entities); +- isns_object_list_gang_lookup(&local_registry, +- &isns_portal_template, NULL, +- &portals); +- +- isns_list_init(&old_proxies); +- rebuild_proxy_list(&entities, &old_proxies); +- unregister_entities(&old_proxies); +- +- /* Enable SCN on all portals we're about to register */ +- all_objects_set(&portals, ISNS_TAG_SCN_PORT, my_port); +- +- /* Try ESI first. If the server doesn't support it, or doesn't +- * have the resources to serve us, fall back to normal +- * registration refresh. */ +- if (opt_esi) { +- all_objects_set(&portals, +- ISNS_TAG_ESI_INTERVAL, +- isns_config.ic_esi_min_interval); +- all_objects_set(&portals, +- ISNS_TAG_ESI_PORT, +- my_port); +- } +- +- for (with_esi = opt_esi; 1; with_esi--) { +- status = register_exported_entities(); +- +- /* At some point, we need to add these portals +- * to the local_portals list so that ESI works +- * properly. +- * Right now, we extract the portals from the response +- * and add those. The down side of this is that we no +- * longer use the same object (pointer) to refer to the +- * same thing. The up side is that the information returned +- * by the server reflects the correct ESI interval. +- */ +- if (status == ISNS_SUCCESS) +- break; +- +- if (status != ISNS_ESI_NOT_AVAILABLE || with_esi == 0) { +- isns_error("Failed to register object(s): %s\n", +- isns_strerror(status)); +- goto out; +- } +- +- /* Continue and retry without ESI */ +- all_objects_unset(&portals, ISNS_TAG_ESI_INTERVAL); +- all_objects_unset(&portals, ISNS_TAG_ESI_PORT); +- } +- +- for (i = 0; i < local_registry.iol_count; ++i) { +- isns_object_t *obj = local_registry.iol_data[i]; +- isns_source_t *source; +- int status; +- +- if (!isns_object_is_iscsi_node(obj) +- && !isns_object_is_fc_port(obj)) +- continue; +- +- if (!(source = isns_source_from_object(obj))) +- continue; +- call = isns_create_scn_registration2(clnt, opt_scn_bits, source); +- status = isns_simple_call(clnt->ic_socket, &call); +- if (status != ISNS_SUCCESS) { +- isns_error("SCN registration for %s failed: %s\n", +- isns_storage_node_name(obj), +- isns_strerror(status)); +- } +- isns_source_release(source); +- } +- +-out: +- if (call) +- isns_simple_free(call); +- isns_object_list_destroy(&entities); +- isns_object_list_destroy(&portals); +- return status; +-} +- +-static void +-retry_registration(void *ptr) +-{ +- isns_proxy_t *proxy = ptr; +- static unsigned int timeout = 0; +- int status; +- +- status = register_exported_objects(proxy->ip_client); +- if (status) { +- if (timeout == 0) +- timeout = opt_retry_timeout; +- else if (timeout >= MAX_RETRY_TIMEOUT) +- timeout = MAX_RETRY_TIMEOUT; +- +- isns_debug_state("Retrying to register in %u seconds\n", timeout); +- isns_add_oneshot_timer(timeout, retry_registration, proxy); +- +- /* Exponential backoff */ +- timeout <<= 1; +- } +-} +- +-/* +- * Get a list of all visible storage nodes +- */ +-static int +-get_objects_from_query(isns_simple_t *resp) +-{ +- isns_object_list_t resp_objects = ISNS_OBJECT_LIST_INIT; +- unsigned int i; +- int status; +- +- status = isns_query_response_get_objects(resp, &resp_objects); +- if (status) { +- isns_error("Unable to extract object list from " +- "query response: %s\n", +- isns_strerror(status)); +- return status; +- } +- +- isns_debug_state("Initial query returned %u object(s)\n", resp_objects.iol_count); +- for (i = 0; i < resp_objects.iol_count; ++i) { +- isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; +- isns_object_t *obj = resp_objects.iol_data[i]; +- isns_object_t *found; +- +- if (!isns_object_extract_keys(obj, &key_attrs)) +- continue; +- +- /* Don't add an object twice, and don't add objects +- * that *we* registered. +- * This still leaves any default PGs created by the server, +- * but we cannot help that (for now). +- */ +- found = isns_object_list_lookup(&visible_nodes, NULL, &key_attrs); +- if (!found) +- found = isns_object_list_lookup(&local_registry, NULL, &key_attrs); +- if (found) { +- isns_object_release(found); +- } else { +- isns_object_list_append(&visible_nodes, obj); +- } +- isns_attr_list_destroy(&key_attrs); +- } +- +- isns_object_list_destroy(&resp_objects); +- return status; +-} +- +-static int +-query_storage_node(isns_source_t *source, const char *name) +-{ +- isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; +- isns_simple_t *call; +- uint32_t tag; +- int status; +- isns_client_t *clnt; +- +- if (isns_source_type(source) != ISNS_TAG_ISCSI_NAME) { +- isns_error("FC source node - doesn't work yet\n"); +- return ISNS_SUCCESS; +- } +- clnt = isns_create_client(NULL, isns_source_name(source)); +- +- tag = isns_source_type(source); +- if (name) { +- isns_attr_list_append_string(&key_attrs, tag, name); +- } else { +- /* Query for visible nodes */ +- isns_attr_list_append_nil(&key_attrs, tag); +- } +- +- call = isns_create_query2(clnt, &key_attrs, source); +- isns_attr_list_destroy(&key_attrs); +- +- isns_query_request_attr_tag(call, tag); +- switch (tag) { +- case ISNS_TAG_ISCSI_NAME: +- isns_query_request_attr_tag(call, ISNS_TAG_ISCSI_NODE_TYPE); +- isns_query_request_attr_tag(call, ISNS_TAG_ISCSI_ALIAS); +- isns_query_request_attr_tag(call, ISNS_TAG_ISCSI_NODE_INDEX); +- +- isns_query_request_attr_tag(call, ISNS_TAG_PORTAL_IP_ADDRESS); +- isns_query_request_attr_tag(call, ISNS_TAG_PORTAL_TCP_UDP_PORT); +- isns_query_request_attr_tag(call, ISNS_TAG_PORTAL_INDEX); +- +- isns_query_request_attr_tag(call, ISNS_TAG_PG_ISCSI_NAME); +- isns_query_request_attr_tag(call, ISNS_TAG_PG_PORTAL_IP_ADDR); +- isns_query_request_attr_tag(call, ISNS_TAG_PG_PORTAL_TCP_UDP_PORT); +- isns_query_request_attr_tag(call, ISNS_TAG_PG_TAG); +- isns_query_request_attr_tag(call, ISNS_TAG_PG_INDEX); +- break; +- +- default: ; +- } +- +- status = isns_simple_call(clnt->ic_socket, &call); +- if (status == ISNS_SUCCESS) +- status = get_objects_from_query(call); +- +- isns_simple_free(call); +- isns_client_destroy(clnt); +- return status; +-} +- +-/* +- * Query for visible iscsi nodes +- */ +-static int +-query_visible(void) +-{ +- unsigned int i; +- +- for (i = 0; i < local_registry.iol_count; ++i) { +- isns_object_t *obj = local_registry.iol_data[i]; +- isns_source_t *source; +- int status; +- +- if (!isns_object_is_iscsi_node(obj) +- && !isns_object_is_fc_port(obj)) +- continue; +- +- if (isns_object_is_fc_port(obj)) { +- isns_error("FC source node - sorry, won't work yet\n"); +- continue; +- } +- +- if (!(source = isns_source_from_object(obj))) +- continue; +- status = query_storage_node(source, NULL); +- if (status != ISNS_SUCCESS) { +- isns_warning("Unable to run query on behalf of %s: %s\n", +- isns_storage_node_name(obj), +- isns_strerror(status)); +- } +- isns_source_release(source); +- } +- return ISNS_SUCCESS; +-} +- +-/* +- * Invoke the registered callout program +- */ +-static void +-callout(const char *how, isns_object_t *obj, unsigned int bitmap) +-{ +- char *argv[128]; +- int fargc, argc = 0; +- pid_t pid; +- +- if (!isns_config.ic_scn_callout) +- return; +- +- argv[argc++] = isns_config.ic_scn_callout; +- argv[argc++] = (char *) how; +- fargc = argc; +- +- argc += isns_print_attrs(obj, argv + argc, 128 - argc); +- +- pid = fork(); +- if (pid == 0) { +- execv(argv[0], argv); +- isns_fatal("Cannot execute %s: %m\n", argv[0]); +- } +- +- while (fargc < argc) +- isns_free(argv[fargc++]); +- +- if (pid < 0) { +- isns_error("fork: %m\n"); +- return; +- } +- +- while (waitpid(pid, NULL, 0) < 0) +- ; +-} +- +-/* +- * This is called when we receive a State Change Notification +- */ +-static void +-scn_callback(isns_db_t *db, uint32_t bitmap, +- isns_object_template_t *node_type, +- const char *node_name, +- const char *dst_name) +-{ +- isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; +- uint32_t key_tag; +- isns_object_t *node = NULL, *recipient = NULL; +- +- isns_notice("%s \"%s\" %s\n", +- isns_object_template_name(node_type), +- node_name, isns_event_string(bitmap)); +- +- /* This is either an iSCSI node or a FC node - in +- both cases the storage node name is the key attr */ +- if (node_type == &isns_iscsi_node_template) { +- key_tag = ISNS_TAG_ISCSI_NAME; +- } else if (node_type == &isns_fc_node_template) { +- key_tag = ISNS_TAG_FC_PORT_NAME_WWPN; +- } else +- return; +- +- isns_attr_list_append_string(&key_attrs, key_tag, dst_name); +- recipient = isns_object_list_lookup(&local_registry, node_type, &key_attrs); +- if (recipient == NULL) { +- isns_error("Received SCN for unknown recipient \"%s\"\n", +- dst_name); +- goto out; +- } +- isns_attr_list_destroy(&key_attrs); +- +- isns_attr_list_append_string(&key_attrs, key_tag, node_name); +- node = isns_object_list_lookup(&visible_nodes, node_type, &key_attrs); +- +- if (bitmap & (ISNS_SCN_OBJECT_REMOVED_MASK|ISNS_SCN_DD_MEMBER_REMOVED_MASK)) { +- if (node) { +- isns_object_list_remove(&visible_nodes, node); +- /* FIXME: We also want to remove any PGs associated with +- * this node. */ +- } +- store_imported_objects(); +- callout("remove", node, bitmap); +- } else +- if (bitmap & (ISNS_SCN_OBJECT_ADDED_MASK|ISNS_SCN_OBJECT_UPDATED_MASK|ISNS_SCN_DD_MEMBER_ADDED_MASK)) { +- const char *how = "add"; +- isns_source_t *source; +- +- if (bitmap & ISNS_SCN_OBJECT_UPDATED_MASK) +- how = "update"; +- if (!node) { +- node = isns_create_object(node_type, &key_attrs, NULL); +- if (!node) +- goto out; +- isns_object_list_append(&visible_nodes, node); +- } +- +- /* Query the server for information on this node */ +- source = isns_source_from_object(recipient); +- query_storage_node(source, node_name); +- isns_source_release(source); +- +- store_imported_objects(); +- callout(how, node, bitmap); +- +- } +- +-out: +- if (node) +- isns_object_release(node); +- if (recipient) +- isns_object_release(recipient); +- isns_attr_list_destroy(&key_attrs); +-} +- +-/* +- * Server main loop +- */ +-void +-run_discovery(isns_server_t *server) +-{ +- isns_client_t *clnt; +- isns_security_t *ctx = NULL; +- isns_message_t *msg, *resp; +- +- /* Create the server socket */ +- ctx = isns_default_security_context(0); +- server_socket = isns_create_server_socket(isns_config.ic_bind_address, +- NULL, opt_af, SOCK_DGRAM); +- if (server_socket == NULL) +- isns_fatal("Unable to create server socket\n"); +- isns_socket_set_security_ctx(server_socket, ctx); +- +- /* Create the client socket */ +- clnt = isns_create_default_client(NULL); +- if (clnt == NULL) +- isns_fatal("Cannot connect to server\n"); +- +- /* Load all objects registered by local services */ +- should_reexport = 1; +- +- while (1) { +- struct timeval timeout = { 0, 0 }; +- time_t now, then, next_timeout; +- unsigned int function; +- +- next_timeout = time(NULL) + 3600; +- +- /* Run timers */ +- then = isns_run_timers(); +- if (then && then < next_timeout) +- next_timeout = then; +- +- /* Determine how long we can sleep */ +- now = time(NULL); +- if (next_timeout <= now) +- continue; +- timeout.tv_sec = next_timeout - now; +- +- if (should_reexport) { +- load_exported_objects(); +- +- if (register_exported_objects(clnt)) +- isns_error("Failed to register exported objects.\n"); +- +- /* Prime the list of visible storage nodes */ +- if (query_visible()) +- isns_error("Unable to query list of visible nodes.\n"); +- store_imported_objects(); +- +- should_reexport = 0; +- } +- +- if ((msg = isns_recv_message(&timeout)) == NULL) +- continue; +- +- function = isns_message_function(msg); +- if (function != ISNS_STATE_CHANGE_NOTIFICATION +- && function != ISNS_ENTITY_STATUS_INQUIRY) { +- isns_warning("Discarding unexpected %s message\n", +- isns_function_name(function)); +- isns_message_release(msg); +- continue; +- } +- +- if ((resp = isns_process_message(server, msg)) != NULL) { +- isns_socket_t *sock = isns_message_socket(msg); +- +- isns_socket_send(sock, resp); +- isns_message_release(resp); +- } +- +- isns_message_release(msg); +- } +-} +diff --git a/utils/open-isns/isnssetup b/utils/open-isns/isnssetup +deleted file mode 100644 +index df0bd00..0000000 +--- a/utils/open-isns/isnssetup ++++ /dev/null +@@ -1,52 +0,0 @@ +-#!/bin/sh +-# +-# isnssetup - bootstrap open-isns server +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This is a very simple script to bootstrap an iSNS server. +-# It creates the necessary keys, enrolls a control node, +-# and enrolls the local host as target and initiator. +- +-hostname=`hostname -f` +- +-if [ -f isnsd -a -d isnsadm ]; then +- PATH=.:$PATH +-fi +- +-# Massage the configuration file +-for f in isnsadm.conf isnsdd.conf; do +- etcfile=/etc/isns/$f +- sed -e 's/^#*\(ServerAddress[[:space:]]*=\).*/\1 localhost/' \ +- -e 's/^#*\(Security[[:space:]]*=\).*/\1 1/' \ +- $etcfile > $etcfile.tmp +- mv $etcfile.tmp $etcfile +-done +- +-echo "*** Initializing server security ***" +-isnsd --init +-cp /etc/isns/auth_key.pub /etc/isns/server_key.pub +- +-if ps ax|grep isnsd | grep -qv grep; then +- killall -TERM isnsd +- sleep 1 +-fi +-isnsd +-sleep 1 +- +-echo "*** Registering control node policy ***" +-rm -f /etc/isns/control.key +-isnsadm --local \ +- --keyfile=/etc/isns/control.key \ +- --enroll isns.control \ +- node-type=ALL functions=ALL object-type=ALL +- +-echo "*** Registering control node ***" +-isnsadm --local \ +- --register control +- +-echo "*** Registering policy for server ***" +-isnsadm --control \ +- --enroll $hostname \ +- key=/etc/isns/auth_key.pub \ +- node-type=target+initiator +diff --git a/utils/open-isns/local.c b/utils/open-isns/local.c +deleted file mode 100644 +index 4bc1cb1..0000000 +--- a/utils/open-isns/local.c ++++ /dev/null +@@ -1,353 +0,0 @@ +-/* +- * Local iSNS registration +- * +- * Copyright (C) 2007 Olaf Kirch +- * +- * The way isnsdd communicates with local services (initiator, +- * target) is via a file and signals. That sounds rather +- * awkward, but it's a lot simpler to add to these services +- * than another socket based communication mechanism I guess. +- * +- * The file format is simple: +- * owner= +- * owner= +- * ... +- * +- * identifies the service owning these entries. +- * This is a service name, such as iscsid, tgtd, isnsdd, +- * optionally followed by a colon and a PID. This allows +- * removal of all entries created by one service in one go. +- * +- * is the description of one iSNS object, using the +- * syntax used by all other open-isns apps. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include "security.h" +-#include "util.h" +-#include "isns-proto.h" +-#include "paths.h" +-#include "attrs.h" +-#include "util.h" +- +-typedef int __isns_local_registry_cb_fn_t(const char *line, +- int argc, char **argv, +- void *user_data); +- +-/* +- * Build the owner=: tag +- */ +-static const char * +-__isns_local_registry_make_owner(const char *svcname, pid_t pid) +-{ +- static char owner[128]; +- +- if (pid == 0) { +- return svcname; +- } +- snprintf(owner, sizeof(owner), "%s:%u", svcname, pid); +- return owner; +-} +- +-/* +- * Read the registry file, match each entry against the given owner= tag, +- * and invoke the callback function. +- * This is used for both reading the registry, and rewriting it. +- */ +-static int +-__isns_local_registry_read(const char *match_owner, +- __isns_local_registry_cb_fn_t handle_matching, +- __isns_local_registry_cb_fn_t handle_nonmatching, +- void *user_data) +-{ +- const char *filename = isns_config.ic_local_registry_file; +- char *line, *copy = NULL; +- FILE *fp; +- int rv = 0, owner_len; +- +- if (!(fp = fopen(filename, "r"))) { +- if (errno == ENOENT) { +- isns_debug_state("Unable to open %s: %m\n", filename); +- return 1; +- } +- isns_error("Unable to open %s: %m\n", filename); +- return 0; +- } +- +- owner_len = match_owner? strlen(match_owner) : 0; +- while ((line = parser_get_next_line(fp)) != NULL) { +- __isns_local_registry_cb_fn_t *cb; +- char *argv[256], *owner; +- int argc = 0; +- +- isns_assign_string(©, line); +- +- argc = isns_attr_list_split(line, argv, 255); +- if (argc <= 0) +- continue; +- +- /* Last attr should be owner */ +- if (strncasecmp(argv[argc-1], "owner=", 6)) { +- isns_error("%s: syntax error (missing owner field)\n", +- filename); +- goto out; +- } +- owner = argv[argc-1] + 6; +- +- if (!strncasecmp(owner, match_owner, owner_len) +- && (owner[owner_len] == '\0' || owner[owner_len] == ':')) +- cb = handle_matching; +- else +- cb = handle_nonmatching; +- +- if (cb && !cb(copy, argc, argv, user_data)) +- goto out; +- +- } +- rv = 1; +- +-out: +- free(copy); +- fclose(fp); +- return rv; +-} +- +-/* +- * Open and lock the registry file for writing. Returns an +- * open stream and the name of the lock file. +- * Follow up with _finish_write when done. +- */ +-static FILE * +-__isns_local_registry_open_write(char **lock_name) +-{ +- char lock_path[PATH_MAX]; +- FILE *fp; +- int fd, retry; +- +- snprintf(lock_path, sizeof(lock_path), "%s.lock", +- isns_config.ic_local_registry_file); +- +- for (retry = 0; retry < 5; ++retry) { +- fd = open(lock_path, O_RDWR|O_CREAT|O_EXCL, 0644); +- if (fd >= 0) +- break; +- if (errno != EEXIST) { +- isns_error("Unable to create %s: %m\n", +- lock_path); +- return NULL; +- } +- isns_error("Cannot lock %s - retry in 1 sec\n", +- isns_config.ic_local_registry_file); +- sleep(1); +- } +- +- if (!(fp = fdopen(fd, "w"))) { +- isns_error("fdopen failed: %m\n"); +- close(fd); +- return NULL; +- } +- isns_assign_string(lock_name, lock_path); +- return fp; +-} +- +-/* +- * We're done with (re)writing the registry. Commit the changes, +- * or discard them. +- * Also frees the lock_name returned by registry_open_write. +- */ +-static int +-__isns_local_registry_finish_write(FILE *fp, char *lock_name, int commit) +-{ +- int rv = 1; +- +- fclose(fp); +- if (!commit) { +- if (unlink(lock_name)) +- isns_error("Failed to unlink %s: %m\n", lock_name); +- } else +- if (rename(lock_name, isns_config.ic_local_registry_file)) { +- isns_error("Failed to rename %s to %s: %m\n", +- lock_name, isns_config.ic_local_registry_file); +- rv = 0; +- } +- +- free(lock_name); +- return rv; +-} +- +-/* +- * Get the entity name for this service +- */ +-static char * +-__isns_local_registry_entity_name(const char *owner) +-{ +- static char namebuf[1024]; +- +- snprintf(namebuf, sizeof(namebuf), "%s:%s", +- isns_config.ic_entity_name, +- owner); +- return namebuf; +-} +- +-/* +- * Callback function which builds an iSNS object from the +- * list of attr=tag values. +- */ +-static int +-__isns_local_registry_load_object(const char *line, +- int argc, char **argv, void *user_data) +-{ +- isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; +- struct isns_attr_list_parser state; +- isns_object_list_t *list = user_data; +- isns_object_t *obj, *entity = NULL; +- +- for (; argc > 0; --argc) { +- char *attr = argv[argc-1]; +- +- if (!strncasecmp(attr, "owner=", 6)) { +- char *eid = __isns_local_registry_entity_name(attr + 6); +- ISNS_QUICK_ATTR_LIST_DECLARE(key_attrs, +- ISNS_TAG_ENTITY_IDENTIFIER, +- string, eid); +- +- if (entity) { +- isns_error("Duplicate owner entry in registry\n"); +- continue; +- } +- isns_attr_print(&key_attrs.iqa_attr, isns_print_stdout); +- entity = isns_object_list_lookup(list, +- &isns_entity_template, +- &key_attrs.iqa_list); +- if (entity != NULL) +- continue; +- +- isns_debug_state("Creating fake entity %s\n", eid); +- entity = isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, eid); +- isns_object_list_append(list, entity); +- } else { +- break; +- } +- } +- +- isns_attr_list_parser_init(&state, NULL); +- if (!isns_parse_attrs(argc, argv, &attrs, &state)) { +- isns_error("Unable to parse attrs\n"); +- isns_attr_list_destroy(&attrs); +- return 0; +- } +- +- obj = isns_create_object(isns_attr_list_parser_context(&state), +- &attrs, entity); +- isns_attr_list_destroy(&attrs); +- +- if (obj == NULL) { +- isns_error("Unable to create object\n"); +- return 0; +- } +- +- isns_object_list_append(list, obj); +- return 1; +-} +- +-/* +- * Callback function that simply writes out the line as-is +- */ +-static int +-__isns_local_registry_rewrite_object(const char *line, +- int argc, char **argv, void *user_data) +-{ +- FILE *ofp = user_data; +- +- fprintf(ofp, "%s\n", line); +- return 1; +-} +- +-/* +- * Load all objects owner by a specific service from the local registry. +- * If the svcname starts with "!", all entries except those matching this +- * particular service are returned. +- */ +-int +-isns_local_registry_load(const char *svcname, pid_t pid, isns_object_list_t *objs) +-{ +- __isns_local_registry_cb_fn_t *if_matching = NULL, *if_nonmatching = NULL; +- +- if (svcname == NULL) { +- isns_error("%s: no svcname given\n", __FUNCTION__); +- return 0; +- } +- if (*svcname == '!') { +- if_nonmatching = __isns_local_registry_load_object; +- svcname++; +- } else { +- if_matching = __isns_local_registry_load_object; +- } +- +- return __isns_local_registry_read( +- __isns_local_registry_make_owner(svcname, pid), +- if_matching, if_nonmatching, objs); +-} +- +-/* +- * Store the given list of objects in the registry. +- * This replaces all objects previously registered by this service. +- */ +-int +-isns_local_registry_store(const char *svcname, pid_t pid, const isns_object_list_t *objs) +-{ +- const char *owner = __isns_local_registry_make_owner(svcname, pid); +- char *lock_name = NULL; +- FILE *ofp; +- +- if (!(ofp = __isns_local_registry_open_write(&lock_name))) { +- isns_error("%s: could not open registry for writing\n", __FUNCTION__); +- return 0; +- } +- +- /* First, purge all entries previously belonging to this owner */ +- if (!__isns_local_registry_read(owner, NULL, __isns_local_registry_rewrite_object, ofp)) +- goto failed; +- +- if (objs) { +- unsigned int i; +- +- for (i = 0; i < objs->iol_count; ++i) { +- isns_object_t *obj = objs->iol_data[i]; +- char *argv[256]; +- int i, argc; +- +- argc = isns_print_attrs(obj, argv, 256); +- for (i = 0; i < argc; ++i) +- fprintf(ofp, "%s ", argv[i]); +- fprintf(ofp, "owner=%s\n", owner); +- } +- } +- +- return __isns_local_registry_finish_write(ofp, lock_name, 1); +- +-failed: +- isns_error("%s: error rewriting registry file\n", __FUNCTION__); +- __isns_local_registry_finish_write(ofp, lock_name, 0); +- return 0; +-} +- +-/* +- * Purge the local registry of all objects owned by the +- * given service. +- */ +-int +-isns_local_registry_purge(const char *svcname, pid_t pid) +-{ +- return isns_local_registry_store(svcname, pid, NULL); +-} +diff --git a/utils/open-isns/logging.c b/utils/open-isns/logging.c +deleted file mode 100644 +index 63ebbef..0000000 +--- a/utils/open-isns/logging.c ++++ /dev/null +@@ -1,228 +0,0 @@ +-/* +- * Logging related utility functions. +- * +- * Copyright (C) 2004-2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#include "util.h" +- +-static unsigned int log_stdout = 1; +-static unsigned int debugging = 0; +- +-/* +- * When backgrounding, any logging output should +- * go to syslog instead of stdout +- */ +-void +-isns_log_background(void) +-{ +- log_stdout = 0; +-} +- +-/* +- * For output to syslog, sanitize the format string +- * by removing newlines. +- */ +-static const char * +-sanitize_format(const char *fmt) +-{ +- static char __fmt[1024]; +- unsigned int len; +- +- /* Don't bother unless there's a newline */ +- if (!strchr(fmt, '\n')) +- return fmt; +- +- len = strlen(fmt); +- +- /* Decline if the buffer would overflow */ +- if (len >= sizeof(__fmt)) +- return fmt; +- +- strcpy(__fmt, fmt); +- while (len-- && __fmt[len] == '\n') +- __fmt[len] = '\0'; +- +- while (len) { +- if (__fmt[len] == '\n') +- __fmt[len] = ' '; +- --len; +- } +- +- return __fmt; +-} +- +-/* +- * Output to stderr or syslog +- */ +-static void +-voutput(int severity, const char *fmt, va_list ap) +-{ +- if (log_stdout) { +- switch (severity) { +- case LOG_ERR: +- fprintf(stderr, "Error: "); +- break; +- case LOG_WARNING: +- fprintf(stderr, "Warning: "); +- break; +- case LOG_DEBUG: +- fprintf(stderr, " "); +- break; +- } +- vfprintf(stderr, fmt, ap); +- } else { +- fmt = sanitize_format(fmt); +- if (!fmt || !*fmt) +- return; +- vsyslog(severity, fmt, ap); +- } +-} +- +-void +-isns_assert_failed(const char *condition, const char *file, unsigned int line) +-{ +- isns_error("Assertion failed (%s:%d): %s\n", +- file, line, condition); +- abort(); +-} +- +-void +-isns_fatal(const char *fmt, ...) +-{ +- va_list ap; +- +- va_start(ap, fmt); +- if (log_stdout) +- fprintf(stderr, "** FATAL ERROR **\n"); +- voutput(LOG_ERR, fmt, ap); +- va_end(ap); +- exit(1); +-} +- +-void +-isns_error(const char *fmt, ...) +-{ +- va_list ap; +- +- va_start(ap, fmt); +- voutput(LOG_WARNING, fmt, ap); +- va_end(ap); +-} +- +-void +-isns_warning(const char *fmt, ...) +-{ +- va_list ap; +- +- va_start(ap, fmt); +- voutput(LOG_NOTICE, fmt, ap); +- va_end(ap); +-} +- +-void +-isns_notice(const char *fmt, ...) +-{ +- va_list ap; +- +- va_start(ap, fmt); +- voutput(LOG_INFO, fmt, ap); +- va_end(ap); +-} +- +-void +-isns_enable_debugging(const char *what) +-{ +- char *copy, *s, *next; +- +- if (!strcmp(what, "all")) { +- debugging = ~0U; +- return; +- } +- +- copy = isns_strdup(what); +- +- for (s = copy; s; s = next) { +- if ((next = strchr(s, ',')) != NULL) +- *next++ = '\0'; +- +- if (!strcmp(s, "general")) +- debugging |= (1 << DBG_GENERAL); +- else if (!strcmp(s, "socket")) +- debugging |= (1 << DBG_SOCKET); +- else if (!strcmp(s, "protocol")) +- debugging |= (1 << DBG_PROTOCOL); +- else if (!strcmp(s, "state")) +- debugging |= (1 << DBG_STATE); +- else if (!strcmp(s, "message")) +- debugging |= (1 << DBG_MESSAGE); +- else if (!strcmp(s, "auth")) +- debugging |= (1 << DBG_AUTH); +- else if (!strcmp(s, "scn")) +- debugging |= (1 << DBG_SCN); +- else if (!strcmp(s, "esi")) +- debugging |= (1 << DBG_ESI); +- else { +- isns_error("Ignoring unknown isns_debug facility <<%s>>\n", +- s); +- } +- } +- isns_free(copy); +-} +- +-#define DEFINE_DEBUG_FUNC(name, NAME) \ +-void \ +-isns_debug_##name(const char *fmt, ...) \ +-{ \ +- va_list ap; \ +- \ +- if (!(debugging & (1 << DBG_##NAME))) \ +- return; \ +- \ +- va_start(ap, fmt); \ +- voutput(LOG_DEBUG, fmt, ap); \ +- va_end(ap); \ +-} +-DEFINE_DEBUG_FUNC(general, GENERAL) +-DEFINE_DEBUG_FUNC(socket, SOCKET) +-DEFINE_DEBUG_FUNC(protocol, PROTOCOL) +-DEFINE_DEBUG_FUNC(message, MESSAGE) +-DEFINE_DEBUG_FUNC(auth, AUTH) +-DEFINE_DEBUG_FUNC(state, STATE) +-DEFINE_DEBUG_FUNC(scn, SCN) +-DEFINE_DEBUG_FUNC(esi, ESI) +- +-int +-isns_debug_enabled(int fac) +-{ +- return (debugging & (1 << fac)) != 0; +-} +- +-/* +- * Misc isns_print_fn_t implementations +- */ +-void +-isns_print_stdout(const char *fmt, ...) +-{ +- va_list ap; +- +- va_start(ap, fmt); +- vfprintf(stdout, fmt, ap); +- va_end(ap); +-} +- +-void +-isns_print_stderr(const char *fmt, ...) +-{ +- va_list ap; +- +- va_start(ap, fmt); +- vfprintf(stderr, fmt, ap); +- va_end(ap); +-} +diff --git a/utils/open-isns/mdebug.c b/utils/open-isns/mdebug.c +deleted file mode 100644 +index 90dcaf0..0000000 +--- a/utils/open-isns/mdebug.c ++++ /dev/null +@@ -1,295 +0,0 @@ +-/* +- * Stupid malloc debugger. I think I wrote something like +- * this a couple of times already. Where does all the old +- * source code go? +- */ +- +-#ifdef MDEBUG +- +-#include +-#include +-#include "util.h" +- +-static void * isns_malloc_default(size_t, const char *, unsigned int); +-static void * isns_calloc_default(unsigned int, size_t, +- const char *, unsigned int); +-static void * isns_realloc_default(void *, size_t, +- const char *, unsigned int); +-static char * isns_strdup_default(const char *, const char *, unsigned int); +-static void isns_free_default(void *, const char *, unsigned int); +- +-/* +- * These are the function pointers used to redirect malloc and such. +- */ +-void * (*isns_malloc_fn)(size_t, const char *, unsigned int) = isns_malloc_default; +-void * (*isns_calloc_fn)(unsigned int, size_t, +- const char *, unsigned int) = isns_calloc_default; +-void * (*isns_realloc_fn)(void *, size_t, +- const char *, unsigned int) = isns_realloc_default; +-char * (*isns_strdup_fn)(const char *, const char *, unsigned int) = isns_strdup_default; +-void (*isns_free_fn)(void *, const char *, unsigned int) = isns_free_default; +- +-#define H_MAGIC 0xfeedbeef +-#define T_MAGIC 0xbadf00d +-#define CHUNK_OVERHEAD (sizeof(struct m_header) + sizeof(struct m_trailer)) +- +-struct m_header { +- struct isns_list h_list; +- uint32_t h_magic; +- size_t h_size; +- +- const char * h_file; +- unsigned int h_line; +-}; +- +-struct m_trailer { +- uint32_t t_magic[8]; +- size_t t_size; +-}; +- +-static ISNS_LIST_DECLARE(m_list); +-static void * m_low_addr; +-static void * m_high_addr; +-static int m_init = 0; +- +-static void +-__isns_check_chunk(const struct m_header *head) +-{ +- const struct m_trailer *tail; +- int i; +- +- if ((void *) head < m_low_addr +- || (void *) head > m_high_addr) { +- isns_error("%s: m_list corrupted!\n", __FUNCTION__); +- abort(); +- } +- +- if (head->h_magic != H_MAGIC) { +- isns_error("%s: m_list item %p with bad header magic %08x\n", +- __FUNCTION__, head, head->h_magic); +- isns_error(" Allocated from %s:%u\n", +- head->h_file, head->h_line); +- abort(); +- } +- +- tail = ((void *) head) + sizeof(*head) + head->h_size; +- for (i = 0; i < 8; ++i) { +- if (tail->t_magic[i] == T_MAGIC) +- continue; +- +- isns_error("%s: m_list item %p with bad trailer magic[%d] %08x\n", +- __FUNCTION__, head, i, tail->t_magic[i]); +- isns_error(" Allocated from %s:%u\n", +- head->h_file, head->h_line); +- abort(); +- } +- +- if (tail->t_size != head->h_size) { +- isns_error("%s: m_list item %p size mismatch; head=%u tail=%u\n", +- __FUNCTION__, head, +- head->h_size, tail->t_size); +- isns_error(" Allocated from %s:%u\n", +- head->h_file, head->h_line); +- abort(); +- } +-} +- +-static void +-__isns_verify_all(void) +-{ +- struct isns_list *pos, *next; +- +- isns_list_foreach(&m_list, pos, next) { +- __isns_check_chunk(isns_list_item(struct m_header, h_list, pos)); +- } +-} +- +-void * +-__isns_malloc(size_t size, const char *file, unsigned int line) +-{ +- struct m_header *head; +- struct m_trailer *tail; +- size_t true_size; +- void *ptr; +- int i; +- +- __isns_verify_all(); +- +- true_size = size + sizeof(*head) + sizeof(*tail); +- isns_assert(size < true_size); +- +- ptr = malloc(true_size); +- if (!ptr) +- return NULL; +- +- if (!m_low_addr) { +- m_low_addr = m_high_addr = ptr; +- } else if (ptr < m_low_addr) { +- m_low_addr = ptr; +- } else if (ptr > m_high_addr) { +- m_high_addr = ptr; +- } +- +- head = ptr; +- head->h_magic = H_MAGIC; +- head->h_size = size; +- head->h_file = file; +- head->h_line = line; +- isns_list_append(&m_list, &head->h_list); +- +- ptr += sizeof(*head); +- +- tail = ptr + size; +- for (i = 0; i < 8; ++i) +- tail->t_magic[i] = T_MAGIC; +- tail->t_size = size; +- +- return ptr; +-} +- +-void * +-__isns_calloc(unsigned int nele, size_t size, +- const char *file, unsigned int line) +-{ +- void *ptr; +- +- ptr = __isns_malloc(nele * size, file, line); +- if (ptr) +- memset(ptr, 0, nele * size); +- return ptr; +-} +- +-void * +-__isns_realloc(void *old, size_t new_size, +- const char *file, unsigned int line) +-{ +- struct m_header *old_head = NULL; +- void *new; +- +- if (old) { +- old_head = (old - sizeof(struct m_header)); +- __isns_check_chunk(old_head); +- } +- +- new = __isns_malloc(new_size, file, line); +- if (new && old) { +- memcpy(new, old, old_head->h_size); +- isns_free_fn(old, file, line); +- } +- +- return new; +-} +- +- +-char * +-__isns_strdup(const char *s, const char *file, unsigned int line) +-{ +- size_t len; +- char *ptr; +- +- len = s? strlen(s) : 0; +- ptr = __isns_malloc(len + 1, file, line); +- if (ptr) { +- memcpy(ptr, s, len); +- ptr[len] = '\0'; +- } +- return ptr; +-} +- +-void +-__isns_free(void *ptr, const char *file, unsigned int line) +-{ +- struct m_header *head; +- size_t true_size; +- +- if (ptr == NULL) +- return; +- +- head = ptr - sizeof(struct m_header); +- __isns_check_chunk(head); +- +- /* +- printf("__isns_free(%u from %s:%u): freed by %s:%u\n", +- head->h_size, head->h_file, head->h_line, +- file, line); +- */ +- true_size = head->h_size + CHUNK_OVERHEAD; +- isns_list_del(&head->h_list); +- +- memset(head, 0xa5, true_size); +- free(head); +- +- __isns_verify_all(); +-} +- +-/* +- * Enable memory debugging +- */ +-static void +-__isns_mdebug_init(void) +-{ +- const char *tracefile; +- +- tracefile = getenv("ISNS_MTRACE"); +- if (tracefile) +- isns_error("MTRACE not yet supported\n"); +- +- if (getenv("ISNS_MDEBUG")) { +- isns_malloc_fn = __isns_malloc; +- isns_calloc_fn = __isns_calloc; +- isns_realloc_fn = __isns_realloc; +- isns_strdup_fn = __isns_strdup; +- isns_free_fn = __isns_free; +- isns_notice("Enabled memory debugging\n"); +- } +- +- m_init = 1; +-} +- +-static inline void +-isns_mdebug_init(void) +-{ +- if (!m_init) +- __isns_mdebug_init(); +-} +- +-/* +- * Default implementations of malloc and friends +- */ +-static void * +-isns_malloc_default(size_t size, const char *file, unsigned int line) +-{ +- isns_mdebug_init(); +- return malloc(size); +-} +- +-static void * +-isns_calloc_default(unsigned int nele, size_t size, +- const char *file, unsigned int line) +-{ +- isns_mdebug_init(); +- return calloc(nele, size); +-} +- +-static void * +-isns_realloc_default(void *old, size_t size, +- const char *file, unsigned int line) +-{ +- isns_mdebug_init(); +- return realloc(old, size); +-} +- +-static char * +-isns_strdup_default(const char *s, const char *file, unsigned int line) +-{ +- isns_mdebug_init(); +- return strdup(s); +-} +- +-static void +-isns_free_default(void *ptr, const char *file, unsigned int line) +-{ +- isns_mdebug_init(); +- return free(ptr); +-} +-#endif +diff --git a/utils/open-isns/message.c b/utils/open-isns/message.c +deleted file mode 100644 +index 4cd40c3..0000000 +--- a/utils/open-isns/message.c ++++ /dev/null +@@ -1,681 +0,0 @@ +-/* +- * iSNS message handling functions +- * +- * Copyright (C) 2007 Olaf Kirch +- * +- * +- */ +- +-#include +-#include +-#include /* for timercmp */ +-#include /* gethostname */ +-#include +-#include "isns.h" +-#include "attrs.h" +-#include "message.h" +-#include "socket.h" +-#include "util.h" +- +-/* iSCSI qualified names include the year and +- * month in which the domain was assigned. +- * See RFC 3720, section 3.2.6.3.1. +- * That's one of these wonderful committee +- * type of ideas that makes it hard for everyone, +- * from coder to sysadmin. +- * Since we have no way of finding out here, +- * we fake it by assigning a date before the +- * dawn of time. +- */ +-#define DUMMY_IQN_PREFIX "iqn.1967-12." +- +-static uint32_t isns_xid = 1; +- +-/* +- * Initialize a message object +- */ +-isns_message_t * +-__isns_alloc_message(uint32_t xid, size_t size, void (*destroy)(isns_message_t *)) +-{ +- isns_message_t *msg; +- +- isns_assert(size >= sizeof(*msg)); +- msg = isns_calloc(1, size); +- +- isns_list_init(&msg->im_list); +- msg->im_users = 1; +- msg->im_xid = xid; +- msg->im_destroy = destroy; +- +- return msg; +-} +- +-static int +-__isns_message_init(isns_message_t *msg, +- uint16_t function, uint16_t flags, +- size_t payload_len) +-{ +- struct isns_hdr *hdr = &msg->im_header; +- +- /* Pad to multiple of 4 octets */ +- payload_len = (payload_len + 3) & ~3UL; +- +- /* For now, we don't do segmentation */ +- if (payload_len > ISNS_MAX_PDU_SIZE) +- return 0; +- +- /* msg->im_header is in host byte order */ +- hdr->i_version = ISNS_VERSION; +- hdr->i_function = function; +- hdr->i_flags = flags; +- hdr->i_length = payload_len; +- hdr->i_xid = msg->im_xid; +- hdr->i_seq = 0; +- +- /* Allocate buffer and reserve room for header */ +- msg->im_payload = buf_alloc(sizeof(*hdr) + payload_len); +- buf_push(msg->im_payload, sizeof(*hdr)); +- +- return 1; +-} +- +-/* +- * Allocate a message object. +- */ +-static isns_message_t * +-__isns_create_message(uint32_t xid, uint16_t function, uint16_t flags) +-{ +- isns_message_t *msg; +- +- msg = __isns_alloc_message(xid, sizeof(*msg), NULL); +- __isns_message_init(msg, function, flags, ISNS_MAX_MESSAGE); +- +- return msg; +-} +- +-/* +- * Allocate a request message +- */ +-isns_message_t * +-isns_create_message(uint16_t function, uint16_t flags) +-{ +- return __isns_create_message(isns_xid++, function, flags); +-} +- +-/* +- * Allocate a response message +- */ +-isns_message_t * +-isns_create_reply(const isns_message_t *msg) +-{ +- uint16_t function = msg->im_header.i_function;; +- isns_message_t *resp; +- +- resp = __isns_create_message(msg->im_xid, function | 0x8000, ISNS_F_SERVER); +- resp->im_addr = msg->im_addr; +- resp->im_addrlen = msg->im_addrlen; +- +- /* Default to ISNS_SUCCESS */ +- buf_put32(resp->im_payload, ISNS_SUCCESS); +- +- return resp; +-} +- +-/* +- * Delete a message +- */ +-void +-isns_message_release(isns_message_t *msg) +-{ +- if (msg == NULL) +- return; +- +- isns_assert(msg->im_users); +- if (--(msg->im_users)) +- return; +- +- if (msg->im_destroy) +- msg->im_destroy(msg); +- if (msg->im_payload) +- buf_free(msg->im_payload); +- isns_principal_free(msg->im_security); +- +- isns_list_del(&msg->im_list); +- isns_free(msg); +-} +- +-/* +- * Extract the status from a reply message +- */ +-int +-isns_message_status(isns_message_t *msg) +-{ +- uint32_t status; +- +- if (!(msg->im_header.i_function & 0x8000) +- || !buf_get32(msg->im_payload, &status)) +- return ISNS_MESSAGE_FORMAT_ERROR; +- return status; +-} +- +-/* +- * Obtain the socket on which the message was received. +- */ +-isns_socket_t * +-isns_message_socket(const isns_message_t *msg) +-{ +- return msg->im_socket; +-} +- +-/* +- * Obtain the message's security context +- */ +-isns_security_t * +-isns_message_security(const isns_message_t *msg) +-{ +- if (!msg->im_socket) +- return NULL; +- return msg->im_socket->is_security; +-} +- +-unsigned int +-isns_message_function(const isns_message_t *msg) +-{ +- return msg->im_header.i_function; +-} +- +-/* +- * Reset the response message, and encode isns_error +- * status +- */ +-void +-isns_message_set_error(isns_message_t *msg, uint32_t status) +-{ +- /* Clear the buffer. This just resets head + tail */ +- buf_clear(msg->im_payload); +- +- /* Now move past the header, and overwrite the +- * status word. */ +- buf_push(msg->im_payload, sizeof(struct isns_hdr)); +- buf_put32(msg->im_payload, status); +-} +- +-/* +- * Message queue handling. Most related functions are +- * in message.h +- */ +-void +-isns_message_queue_move(isns_message_queue_t *dstq, +- isns_message_t *msg) +-{ +- unsigned int src_ref = 0; +- +- /* If the message was on a different queue, +- * the source queue will hold a reference +- * to it. Account for that and fix up the +- * refcount after we've appended it to the +- * destination queue. */ +- if (isns_message_unlink(msg)) +- src_ref = 1; +- +- isns_message_queue_append(dstq, msg); +- msg->im_users -= src_ref; +-} +- +-/* +- * Insert a messsage into a queue sorted by resend timeout +- */ +-void +-isns_message_queue_insert_sorted(isns_message_queue_t *q, +- int sort, isns_message_t *msg) +-{ +- isns_list_t *pos; +- isns_message_t *__m; +- +- isns_assert(msg->im_queue == NULL); +- if (sort == ISNS_MQ_SORT_RESEND_TIMEOUT) { +- isns_message_queue_foreach(q, pos, __m) { +- if (timercmp(&msg->im_resend_timeout, +- &__m->im_resend_timeout, <)) +- break; +- } +- } else { +- isns_message_queue_append(q, msg); +- return; +- } +- +- /* Insert before pos */ +- __isns_list_insert(pos->prev, &msg->im_list, pos); +- q->imq_count++; +- +- msg->im_queue = q; +- msg->im_users++; +-} +- +-/* +- * Message queue handling +- */ +-void +-isns_message_queue_destroy(isns_message_queue_t *q) +-{ +- isns_message_t *msg; +- +- while ((msg = isns_message_dequeue(q)) != NULL) +- isns_message_release(msg); +-} +- +-/* +- * Find a message with matching xid and address. +- * (address, alen) may be NULL. +- */ +-isns_message_t * +-isns_message_queue_find(isns_message_queue_t *q, uint32_t xid, +- const struct sockaddr_storage *addr, socklen_t alen) +-{ +- isns_message_t *msg; +- isns_list_t *pos; +- +- isns_message_queue_foreach(q, pos, msg) { +- if (msg->im_xid != xid) +- continue; +- if (alen == 0) +- return msg; +- +- if (msg->im_addrlen == alen +- && !memcmp(&msg->im_addr, addr, alen)) +- return msg; +- } +- +- return NULL; +-} +- +-/* +- * Convert a hostname into an iSCSI qualified name +- * We omit the dismbiguating YYYY-MM infix because +- * we have no way of finding out, short of bothering +- * whois. +- */ +-static char * +-__revert_fqdn(const char *prefix, const char *__fqdn, const char *suffix) +-{ +- static char namebuf[1024] = { '\0' }; +- char *fqdn, *result = NULL; +- int pos, count = 0; +- +- if (prefix) +- strcpy(namebuf, prefix); +- pos = strlen(namebuf); +- +- fqdn = isns_strdup(__fqdn); +- while (1) { +- char *dot, *comp; +- int comp_len; +- +- if ((dot = strrchr(fqdn, '.')) != NULL) { +- *dot++ = '\0'; +- comp = dot; +- } else { +- comp = fqdn; +- } +- +- if (*comp == '\0') +- continue; +- comp_len = strlen(comp); +- if (pos + comp_len + 2 > sizeof(namebuf)) { +- isns_error("%s: FQDN too long\n", __FUNCTION__); +- goto out; +- } +- if (count++) +- namebuf[pos++] = '.'; +- strcpy(namebuf + pos, comp); +- pos += comp_len; +- +- if (dot == NULL) +- break; +- } +- +- if (suffix) { +- int sfx_len = strlen(suffix); +- +- if (pos + sfx_len + 2 > sizeof(namebuf)) { +- isns_error("%s: name too long\n", __FUNCTION__); +- goto out; +- } +- namebuf[pos++] = ':'; +- strcpy(namebuf + pos, suffix); +- pos += sfx_len; +- } +- +- result = isns_strdup(namebuf); +- +-out: isns_free(fqdn); +- return result; +-} +- +-/* +- * Initialize all names +- */ +-int +-isns_init_names(void) +-{ +- if (isns_config.ic_host_name == NULL) { +- char namebuf[1024], *fqdn; +- +- if (gethostname(namebuf, sizeof(namebuf)) < 0) { +- isns_error("gehostname: %m\n"); +- return 0; +- } +- fqdn = isns_get_canon_name(namebuf); +- if (fqdn == NULL) { +- /* FIXME: we could get some unique value here +- * such as the IP address, and concat that +- * with iqn.2005-01.org.open-iscsi.ip for the +- * source name. +- */ +- isns_error("Unable to get fully qualified hostname\n"); +- return 0; +- } +- isns_config.ic_host_name = fqdn; +- } +- +- if (isns_config.ic_auth_name == NULL) { +- isns_config.ic_auth_name = isns_config.ic_host_name; +- } +- +- if (isns_config.ic_entity_name == NULL) { +- isns_config.ic_entity_name = isns_config.ic_auth_name; +- } +- +- if (isns_config.ic_source_name == NULL) { +- isns_config.ic_source_name = __revert_fqdn(DUMMY_IQN_PREFIX, +- isns_config.ic_host_name, +- isns_config.ic_source_suffix); +- if (isns_config.ic_source_name == NULL) { +- isns_error("Unable to build source name\n"); +- return 0; +- } +- } +- +- return 1; +-} +- +-/* +- * Match a source name to a pattern (which is really just +- * the entity identifier, usually). +- * +- * If the pattern is of the form "match:rev-fqdn", the +- * source name must match +- * iqn.[YYYY-MM.] +- * optionally followed by dot, colon or hyphen and arbitrary +- * text. +- * +- * If the pattern does not start with "match:", the source name +- * must match the pattern literally (case insensitively). +- */ +-int +-isns_source_pattern_match(const char *pattern, const char *source) +-{ +- unsigned int rev_len; +- +- isns_debug_message("%s(%s, %s)\n", +- __FUNCTION__, pattern, source); +- +- if (!strcmp(pattern, "*")) +- return 1; +- +- if (strncmp(pattern, "match:", 6)) +- return !strcasecmp(pattern, source); +- pattern += 6; +- +- if (strncasecmp(source, "iqn.", 4)) +- return 0; +- source += 4; +- +- rev_len = strlen(pattern); +- if (strncasecmp(source, pattern, rev_len)) { +- /* See if the next component is YYYY-MM */ +- if (!(isdigit(source[0]) +- && isdigit(source[1]) +- && isdigit(source[2]) +- && isdigit(source[3]) +- && source[4] == '-' +- && isdigit(source[5]) +- && isdigit(source[6]) +- && source[7] == '.')) +- return 0; +- source += 8; +- +- if (strncasecmp(source, pattern, rev_len)) +- return 0; +- } +- +- source += rev_len; +- if (source[0] != '.' +- && source[0] != ':' +- && source[0] != '-' +- && source[0] != '\0') +- return 0; +- +- return 1; +-} +- +-/* +- * This really just reverts the FQDN so it can +- * be used in isns_source_entity_match +- */ +-char * +-isns_build_source_pattern(const char *fqdn) +-{ +- return __revert_fqdn("match:", fqdn, NULL); +-} +- +-/* +- * Manage source objects +- */ +-static isns_source_t * +-__isns_source_create(isns_attr_t *name_attr) +-{ +- isns_source_t *source = isns_calloc(1, sizeof(*source)); +- +- source->is_users = 1; +- source->is_attr = name_attr; +- return source; +-} +- +-isns_source_t * +-isns_source_create(isns_attr_t *name_attr) +-{ +- if (name_attr->ia_tag_id != ISNS_TAG_ISCSI_NAME +- && name_attr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN) +- return NULL; +- +- name_attr->ia_users++; +- return __isns_source_create(name_attr); +-} +- +-isns_source_t * +-isns_source_from_object(const isns_object_t *node) +-{ +- isns_attr_t *attr; +- +- if (!(attr = isns_storage_node_key_attr(node))) +- return NULL; +- return isns_source_create(attr); +-} +- +-isns_source_t * +-isns_source_create_iscsi(const char *name) +-{ +- isns_value_t var = ISNS_VALUE_INIT(string, (char *) name); +- isns_attr_t *attr; +- +- attr = isns_attr_alloc(ISNS_TAG_ISCSI_NAME, NULL, &var); +- return __isns_source_create(attr); +-} +- +-/* +- * This is used to attach a dummy source to iSNS responses +- * until I fixed up all the code that relies on msg->is_source +- * to be valid all the time. +- */ +-isns_source_t * +-isns_source_dummy(void) +-{ +- static isns_source_t *dummy = NULL; +- +- if (!dummy) +- dummy = isns_source_create_iscsi(".dummy."); +- return isns_source_get(dummy); +-} +- +-uint32_t +-isns_source_type(const isns_source_t *source) +-{ +- return source->is_attr->ia_tag_id; +-} +- +-const char * +-isns_source_name(const isns_source_t *source) +-{ +- return source->is_attr->ia_value.iv_string; +-} +- +-isns_attr_t * +-isns_source_attr(const isns_source_t *source) +-{ +- return source->is_attr; +-} +- +-/* +- * Obtain an additional reference on the source object +- */ +-isns_source_t * +-isns_source_get(isns_source_t *source) +-{ +- if (source) +- source->is_users++; +- return source; +-} +- +-/* +- * Look up the node corresponding to this source name +- * When we get here, we have already verified that the +- * client is permitted (by policy) to use this source node. +- */ +-int +-isns_source_set_node(isns_source_t *source, isns_db_t *db) +-{ +- isns_object_t *node, *entity; +- uint32_t node_type; +- +- if (source->is_node) +- return 1; +- +- if (db == NULL) +- return 0; +- +- node = isns_db_lookup_source_node(db, source); +- if (node == NULL) +- return 0; +- +- if (!isns_object_get_uint32(node, ISNS_TAG_ISCSI_NODE_TYPE, &node_type)) +- node_type = 0; +- +- source->is_node = node; +- source->is_node_type = node_type; +- +- if ((entity = isns_object_get_entity(node)) != NULL) +- source->is_entity = isns_object_get(entity); +- return 1; +-} +- +-void +-isns_source_set_entity(isns_source_t *source, isns_object_t *obj) +-{ +- if (obj) +- isns_object_get(obj); +- isns_object_release(source->is_entity); +- source->is_entity = obj; +-} +- +-/* +- * Release a reference on the source object +- */ +-void +-isns_source_release(isns_source_t *source) +-{ +- if (source && --source->is_users == 0) { +- isns_attr_release(source->is_attr); +- isns_object_release(source->is_node); +- isns_object_release(source->is_entity); +- memset(source, 0xa5, sizeof(*source)); +- isns_free(source); +- } +-} +- +-/* +- * Compare two source objects +- */ +-int +-isns_source_match(const isns_source_t *a, +- const isns_source_t *b) +-{ +- if (a && b) +- return isns_attr_match(a->is_attr, b->is_attr); +- return 0; +-} +- +-/* +- * Encode/decode source object +- */ +-int +-isns_source_encode(buf_t *bp, const isns_source_t *source) +-{ +- if (source == NULL) { +- isns_attr_t nil = ISNS_ATTR_INIT(ISNS_TAG_DELIMITER, nil, 0); +- +- return isns_attr_encode(bp, &nil); +- } +- return isns_attr_encode(bp, source->is_attr); +-} +- +-int +-isns_source_decode(buf_t *bp, isns_source_t **result) +-{ +- isns_attr_t *attr; +- int status; +- +- status = isns_attr_decode(bp, &attr); +- if (status == ISNS_SUCCESS) { +- /* +- * 5.6.1 +- * The Source Attribute uniquely identifies the source of the +- * message. Valid Source Attribute types are shown below. +- * +- * Valid Source Attributes +- * ----------------------- +- * iSCSI Name +- * FC Port Name WWPN +- */ +- switch (attr->ia_tag_id) { +-#if 0 +- case ISNS_TAG_DELIMITER: +- *result = NULL; +- break; +-#endif +- +- case ISNS_TAG_ISCSI_NAME: +- *result = __isns_source_create(attr); +- break; +- +- case ISNS_TAG_FC_PORT_NAME_WWPN: +- *result = __isns_source_create(attr); +- break; +- +- default: +- isns_attr_release(attr); +- return ISNS_SOURCE_UNKNOWN; +- } +- } +- return status; +-} +diff --git a/utils/open-isns/message.h b/utils/open-isns/message.h +deleted file mode 100644 +index f1f4ed6..0000000 +--- a/utils/open-isns/message.h ++++ /dev/null +@@ -1,196 +0,0 @@ +-/* +- * iSNS message definitions and functions +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#ifndef ISNS_MESSAGE_H +-#define ISNS_MESSAGE_H +- +-#include "attrs.h" +-#include "source.h" +-#include "util.h" +- +-typedef struct isns_message_queue isns_message_queue_t; +- +-struct isns_simple { +- uint32_t is_function; +- isns_source_t * is_source; +- isns_policy_t * is_policy; +- uint16_t is_xid; +- +- unsigned int is_replace : 1; +- +- isns_attr_list_t is_message_attrs; +- isns_attr_list_t is_operating_attrs; +-}; +- +-struct isns_message { +- unsigned int im_users; +- isns_list_t im_list; +- struct sockaddr_storage im_addr; +- socklen_t im_addrlen; +- uint32_t im_xid; +- struct isns_hdr im_header; +- struct isns_buf * im_payload; +- isns_socket_t * im_socket; +- isns_principal_t * im_security; +- struct ucred * im_creds; +- +- isns_message_queue_t * im_queue; +- +- /* When to retransmit */ +- struct timeval im_resend_timeout; +- struct timeval im_timeout; +- +- void (*im_destroy)(isns_message_t *); +- void (*im_callback)(isns_message_t *, +- isns_message_t *); +- void * im_calldata; +-}; +- +-enum { +- ISNS_MQ_SORT_NONE, +- ISNS_MQ_SORT_RESEND_TIMEOUT, +-}; +- +-struct isns_message_queue { +- isns_list_t imq_list; +- size_t imq_count; +-}; +- +-struct isns_server { +- isns_source_t * is_source; +- isns_db_t * is_db; +- +- isns_scn_callback_fn_t *is_scn_callback; +- struct isns_service_ops *is_ops; +-}; +- +-extern isns_message_t * __isns_alloc_message(uint32_t, size_t, void (*)(isns_message_t *)); +-extern isns_security_t *isns_message_security(const isns_message_t *); +- +-extern isns_message_t * isns_message_queue_find(isns_message_queue_t *, uint32_t, +- const struct sockaddr_storage *, socklen_t); +-extern void isns_message_queue_insert_sorted(isns_message_queue_t *, +- int, isns_message_t *); +-extern void isns_message_queue_move(isns_message_queue_t *, +- isns_message_t *); +-extern void isns_message_queue_destroy(isns_message_queue_t *); +- +-extern isns_simple_t * isns_simple_create(uint32_t, +- isns_source_t *, +- const isns_attr_list_t *); +-extern void isns_simple_free(isns_simple_t *); +-extern int isns_simple_encode(isns_simple_t *, +- isns_message_t **result); +-extern int isns_simple_decode(isns_message_t *, +- isns_simple_t **); +-extern int isns_simple_encode_response(isns_simple_t *, +- const isns_message_t *, isns_message_t **); +-extern int isns_simple_response_get_objects(isns_simple_t *, +- isns_object_list_t *); +-extern const char * isns_function_name(uint32_t); +- +-extern isns_source_t * isns_simple_get_source(isns_simple_t *); +- +-extern int isns_process_registration(isns_server_t *, isns_simple_t *, isns_simple_t **); +-extern int isns_process_query(isns_server_t *, isns_simple_t *, isns_simple_t **); +-extern int isns_process_getnext(isns_server_t *, isns_simple_t *, isns_simple_t **); +-extern int isns_process_deregistration(isns_server_t *, isns_simple_t *, isns_simple_t **); +-extern int isns_process_scn_register(isns_server_t *, isns_simple_t *, isns_simple_t **); +-extern int isns_process_scn_deregistration(isns_server_t *, isns_simple_t *, isns_simple_t **); +-extern int isns_process_dd_registration(isns_server_t *, isns_simple_t *, isns_simple_t **); +-extern int isns_process_dd_deregistration(isns_server_t *, isns_simple_t *, isns_simple_t **); +-extern int isns_process_esi(isns_server_t *, isns_simple_t *, isns_simple_t **); +-extern int isns_process_scn(isns_server_t *, isns_simple_t *, isns_simple_t **); +- +-/* +- * Inline functions for message queues. +- */ +-static inline void +-isns_message_queue_init(isns_message_queue_t *q) +-{ +- isns_list_init(&q->imq_list); +- q->imq_count = 0; +-} +- +-static inline isns_message_t * +-isns_message_queue_head(const isns_message_queue_t *q) +-{ +- isns_list_t *pos = q->imq_list.next; +- +- if (pos == &q->imq_list) +- return NULL; +- return isns_list_item(isns_message_t, im_list, pos); +-} +- +-static inline void +-isns_message_queue_append(isns_message_queue_t *q, isns_message_t *msg) +-{ +- isns_assert(msg->im_queue == NULL); +- isns_list_append(&q->imq_list, &msg->im_list); +- q->imq_count++; +- +- msg->im_queue = q; +- msg->im_users++; +-} +- +-static inline isns_message_t * +-isns_message_queue_remove(isns_message_queue_t *q, isns_message_t *msg) +-{ +- isns_assert(msg->im_queue == q); +- isns_list_del(&msg->im_list); +- msg->im_queue = NULL; +- q->imq_count--; +- +- return msg; +-} +- +-static inline isns_message_t * +-isns_message_unlink(isns_message_t *msg) +-{ +- if (msg->im_queue) +- return isns_message_queue_remove(msg->im_queue, msg); +- return NULL; +-} +- +-static inline isns_message_t * +-isns_message_dequeue(isns_message_queue_t *q) +-{ +- isns_message_t *msg; +- +- if ((msg = isns_message_queue_head(q)) != NULL) { +- isns_list_del(&msg->im_list); +- msg->im_queue = NULL; +- q->imq_count--; +- } +- return msg; +-} +- +-/* +- * Iterator for looping over all messages in a queue +- */ +-static inline void +-isns_message_queue_begin(isns_message_queue_t *q, isns_list_t **pos) +-{ +- *pos = q->imq_list.next; +-} +- +-static inline isns_message_t * +-isns_message_queue_next(isns_message_queue_t *q, isns_list_t **pos) +-{ +- isns_list_t *next = *pos; +- +- if (next == &q->imq_list) +- return NULL; +- *pos = next->next; +- return isns_list_item(isns_message_t, im_list, next); +-} +- +-#define isns_message_queue_foreach(q, pos, item) \ +- for (isns_message_queue_begin(q, &pos); \ +- (item = isns_message_queue_next(q, &pos)) != NULL; \ +- ) +- +-#endif /* ISNS_MESSAGE_H */ +diff --git a/utils/open-isns/objects.c b/utils/open-isns/objects.c +deleted file mode 100644 +index 1504026..0000000 +--- a/utils/open-isns/objects.c ++++ /dev/null +@@ -1,1320 +0,0 @@ +-/* +- * iSNS object model +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include "isns.h" +-#include "objects.h" +-#include "source.h" +-#include "vendor.h" +-#include "attrs.h" +-#include "util.h" +- +-/* For relationship stuff - should go */ +-#include "db.h" +- +-static isns_object_template_t * isns_object_templates[] = { +- &isns_entity_template, +- &isns_portal_template, +- &isns_iscsi_node_template, +- &isns_fc_port_template, +- &isns_fc_node_template, +- &isns_iscsi_pg_template, +- &isns_dd_template, +- &isns_ddset_template, +- +- /* vendor-specific templates */ +- &isns_policy_template, +- +- NULL +-}; +- +-/* +- * Quick lookup of (key) tag to template +- */ +-#define MAX_QUICK_TAG 2100 +-static isns_object_template_t * isns_object_template_key_map[MAX_QUICK_TAG]; +-static isns_object_template_t * isns_object_template_any_map[MAX_QUICK_TAG]; +-static isns_object_template_t * isns_object_template_idx_map[MAX_QUICK_TAG]; +-static int isns_object_maps_inizialized = 0; +- +- +-static void +-__isns_object_maps_init(void) +-{ +- isns_object_template_t *tmpl; +- uint32_t i, j, tag; +- +- isns_object_maps_inizialized = 1; +- +- for (i = 0; (tmpl = isns_object_templates[i]) != NULL; ++i) { +- if (tmpl->iot_vendor_specific) +- continue; +- +- tag = tmpl->iot_keys[0]; +- isns_assert(tag < MAX_QUICK_TAG); +- isns_object_template_key_map[tag] = tmpl; +- +- for (j = 0; j < tmpl->iot_num_attrs; ++j) { +- tag = tmpl->iot_attrs[j]; +- isns_assert(tag < MAX_QUICK_TAG); +- isns_object_template_any_map[tag] = tmpl; +- } +- +- if ((tag = tmpl->iot_index) != 0) +- isns_object_template_idx_map[tag] = tmpl; +- } +-} +- +-static void +-isns_object_maps_init(void) +-{ +- if (!isns_object_maps_inizialized) +- __isns_object_maps_init(); +-} +- +-/* +- * Based on a given key attribute, find the corresponding +- * object type. +- */ +-isns_object_template_t * +-isns_object_template_find(uint32_t key_tag) +-{ +- isns_object_template_t *tmpl; +- unsigned int i; +- +- isns_object_maps_init(); +- if (key_tag < MAX_QUICK_TAG) +- return isns_object_template_key_map[key_tag]; +- +- for (i = 0; (tmpl = isns_object_templates[i]) != NULL; ++i) { +- if (tmpl->iot_keys[0] == key_tag) +- return tmpl; +- } +- +- return NULL; +-} +- +-/* +- * Given a set of attributes, find the corresponding +- * object type. +- * Any attributes in the list in *addition to* the keys +- * attributes are ignored. +- */ +-isns_object_template_t * +-isns_object_template_for_key_attrs(const isns_attr_list_t *attrs) +-{ +- isns_object_template_t *tmpl; +- const isns_attr_t *attr; +- unsigned int i; +- +- if (attrs->ial_count == 0) +- return NULL; +- attr = attrs->ial_data[0]; +- +- tmpl = isns_object_template_find(attr->ia_tag_id); +- if (tmpl == NULL) +- return NULL; +- +- /* +- * 5.6.4. +- * +- * Some objects are keyed by more than one object key attribute +- * value. For example, the Portal object is keyed by attribute +- * tags 16 and 17. When describing an object keyed by more than one +- * key attribute, every object key attribute of that object MUST be +- * listed sequentially by tag value in the message before non-key +- * attributes of that object and key attributes of the next object. +- * A group of key attributes of this kind is treated as a single +- * logical key attribute when identifying an object. +- */ +- for (i = 1; i < tmpl->iot_num_keys; ++i) { +- attr = attrs->ial_data[i]; +- +- if (attr->ia_tag_id != tmpl->iot_keys[i]) +- return NULL; +- } +- +- return tmpl; +-} +- +-isns_object_template_t * +-isns_object_template_for_tag(uint32_t tag) +-{ +- isns_object_template_t *tmpl; +- unsigned int i, j; +- +- isns_object_maps_init(); +- if (tag < MAX_QUICK_TAG) +- return isns_object_template_any_map[tag]; +- +- for (i = 0; (tmpl = isns_object_templates[i]) != NULL; ++i) { +- for (j = 0; j < tmpl->iot_num_attrs; ++j) { +- if (tmpl->iot_attrs[j] == tag) +- return tmpl; +- } +- } +- +- return NULL; +-} +- +-isns_object_template_t * +-isns_object_template_for_index_tag(uint32_t tag) +-{ +- isns_object_maps_init(); +- if (tag >= MAX_QUICK_TAG) +- return NULL; +- +- return isns_object_template_idx_map[tag]; +-} +- +-isns_object_template_t * +-isns_object_template_by_name(const char *name) +-{ +- isns_object_template_t **pp, *tmpl; +- +- pp = isns_object_templates; +- while ((tmpl = *pp++) != NULL) { +- if (!strcasecmp(tmpl->iot_name, name)) +- return tmpl; +- } +- return NULL; +-} +- +-const char * +-isns_object_template_name(isns_object_template_t *tmpl) +-{ +- if (!tmpl) +- return NULL; +- return tmpl->iot_name; +-} +- +-/* +- * Notify any listeners that the object has changed, +- * and mark it dirty. +- * dd_or_dds is used for DD_MEMBER_ADDED and +- * DD_MEMBER_REMOVED events, and refers to the +- * domain or domain set the object was added to or +- * removed from. +- */ +-void +-isns_mark_object(isns_object_t *obj, unsigned int how) +-{ +- obj->ie_flags |= ISNS_OBJECT_DIRTY; +- obj->ie_mtime = time(NULL); +- obj->ie_scn_bits |= (1 << how); +- isns_object_event(obj, 0, NULL); +-} +- +-static void +-__isns_mark_object(isns_object_t *obj) +-{ +- obj->ie_flags |= ISNS_OBJECT_DIRTY; +- obj->ie_mtime = time(NULL); +-} +- +-/* +- * Create an object given its object template +- */ +-isns_object_t * +-isns_create_object(isns_object_template_t *tmpl, +- const isns_attr_list_t *attrs, +- isns_object_t *parent) +-{ +- isns_object_t *obj; +- unsigned int i; +- +- /* Enforce containment rules. */ +- if (parent) +- isns_assert(tmpl->iot_container == parent->ie_template); +- +-#ifdef notdef +- /* This check is somewhat costly: */ +- if (attrs && tmpl != isns_object_template_for_key_attrs(attrs)) +- return NULL; +-#endif +- +- obj = isns_calloc(1, sizeof(*obj)); +- +- obj->ie_users = 1; +- obj->ie_template = tmpl; +- isns_attr_list_init(&obj->ie_attrs); +- +- if (parent) +- isns_object_attach(obj, parent); +- +- if (attrs == NULL) { +- /* Make sure that all key attrs are instantiated +- * and in sequence. */ +- for (i = 0; i < tmpl->iot_num_keys; ++i) +- isns_attr_list_append_nil(&obj->ie_attrs, +- tmpl->iot_keys[i]); +- } else { +- /* We rely on the caller to ensure that +- * attributes are in proper sequence. */ +- isns_attr_list_copy(&obj->ie_attrs, attrs); +- } +- +- /* Just mark it dirty, but do not schedule a +- * SCN event. */ +- __isns_mark_object(obj); +- +- return obj; +-} +- +-/* +- * Obtain an additional reference on the object +- */ +-isns_object_t * +-isns_object_get(isns_object_t *obj) +-{ +- if (obj) { +- isns_assert(obj->ie_users); +- obj->ie_users++; +- } +- return obj; +-} +- +-/* +- * Release a reference on the object +- */ +-void +-isns_object_release(isns_object_t *obj) +-{ +- unsigned int i; +- isns_object_t *child; +- +- if (!obj) +- return; +- +- isns_assert(obj->ie_users); +- if (--(obj)->ie_users != 0) +- return; +- +- /* Must not have any live references to it */ +- isns_assert(obj->ie_references == 0); +- +- /* Must be detached from parent */ +- isns_assert(obj->ie_container == NULL); +- +- /* Release all children. We explicitly clear +- * ie_container because the destructor +- * checks for this (in order to catch +- * refcounting bugs) */ +- for (i = 0; i < obj->ie_children.iol_count; ++i) { +- child = obj->ie_children.iol_data[i]; +- child->ie_container = NULL; +- } +- isns_object_list_destroy(&obj->ie_children); +- +- isns_attr_list_destroy(&obj->ie_attrs); +- +- isns_bitvector_free(obj->ie_membership); +- isns_free(obj); +-} +- +-/* +- * Get the topmost container (ie Network Entity) +- * for the given object +- */ +-isns_object_t * +-isns_object_get_entity(isns_object_t *obj) +-{ +- if (obj == NULL) +- return NULL; +- while (obj->ie_container) +- obj = obj->ie_container; +- if (!ISNS_IS_ENTITY(obj)) +- return NULL; +- return obj; +-} +- +-int +-isns_object_contains(const isns_object_t *ancestor, +- const isns_object_t *descendant) +-{ +- while (descendant) { +- if (descendant == ancestor) +- return 1; +- descendant = descendant->ie_container; +- } +- return 0; +-} +- +-/* +- * Get all children of the specified type +- */ +-void +-isns_object_get_descendants(const isns_object_t *obj, +- isns_object_template_t *tmpl, +- isns_object_list_t *result) +-{ +- isns_object_t *child; +- unsigned int i; +- +- for (i = 0; i < obj->ie_children.iol_count; ++i) { +- child = obj->ie_children.iol_data[i]; +- if (!tmpl || child->ie_template == tmpl) +- isns_object_list_append(result, child); +- } +-} +- +-/* +- * Attach an object to a new container +- */ +-int +-isns_object_attach(isns_object_t *obj, isns_object_t *parent) +-{ +- isns_assert(obj->ie_container == NULL); +- +- if (parent) { +- /* Copy the owner (ie source) from the parent +- * object. +- * Make sure the parent object type is a valid +- * container for this object. +- */ +- if (parent->ie_template != obj->ie_template->iot_container) { +- isns_error("You are not allowed to add a %s object " +- "to a %s!\n", +- obj->ie_template->iot_name, +- parent->ie_template->iot_name); +- return 0; +- } +- obj->ie_flags = parent->ie_flags & ISNS_OBJECT_PRIVATE; +- isns_object_list_append(&parent->ie_children, obj); +- } +- obj->ie_container = parent; +- return 1; +-} +- +-int +-isns_object_is_valid_container(const isns_object_t *container, +- isns_object_template_t *child_type) +-{ +- return child_type->iot_container == container->ie_template; +-} +- +-/* +- * Detach an object from its container +- */ +-int +-isns_object_detach(isns_object_t *obj) +-{ +- isns_object_t *parent; +- +- /* Detach from parent */ +- if ((parent = obj->ie_container) != NULL) { +- int removed; +- +- obj->ie_container = NULL; +- removed = isns_object_list_remove( +- &parent->ie_children, obj); +- +- isns_assert(removed != 0); +- } +- +- return 0; +-} +- +-/* +- * Check the type of an object +- */ +-int +-isns_object_is(const isns_object_t *obj, +- isns_object_template_t *tmpl) +-{ +- return obj->ie_template == tmpl; +-} +- +-int +-isns_object_is_iscsi_node(const isns_object_t *obj) +-{ +- return ISNS_IS_ISCSI_NODE(obj); +-} +- +-int +-isns_object_is_fc_port(const isns_object_t *obj) +-{ +- return ISNS_IS_FC_PORT(obj); +-} +- +-int +-isns_object_is_fc_node(const isns_object_t *obj) +-{ +- return ISNS_IS_FC_NODE(obj); +-} +- +-int +-isns_object_is_portal(const isns_object_t *obj) +-{ +- return ISNS_IS_PORTAL(obj); +-} +- +-int +-isns_object_is_pg(const isns_object_t *obj) +-{ +- return ISNS_IS_PG(obj); +-} +- +-int +-isns_object_is_policy(const isns_object_t *obj) +-{ +- return ISNS_IS_POLICY(obj); +-} +- +-/* +- * Match an object against a list of attributes. +- */ +-int +-isns_object_match(const isns_object_t *obj, +- const isns_attr_list_t *attrs) +-{ +- isns_object_template_t *tmpl = obj->ie_template; +- isns_attr_t *self, *match; +- unsigned int i, j, from = 0; +- uint32_t tag; +- +- /* Fast path: try to compare in-order */ +- while (from < attrs->ial_count) { +- match = attrs->ial_data[from]; +- self = obj->ie_attrs.ial_data[from]; +- +- if (match->ia_tag_id != self->ia_tag_id) +- goto slow_path; +- +- if (!isns_attr_match(self, match)) +- return 0; +- +- from++; +- } +- +- return 1; +- +-slow_path: +- for (i = from; i < attrs->ial_count; ++i) { +- isns_attr_t *found = NULL; +- +- match = attrs->ial_data[i]; +- +- /* +- * 5.6.5.2 +- * A Message Key with zero-length TLV(s) is scoped to +- * every object of the type indicated by the zero-length +- * TLV(s) +- */ +- if (match->ia_value.iv_type == &isns_attr_type_nil) { +- tag = match->ia_tag_id; +- if (isns_object_attr_valid(tmpl, tag)) +- continue; +- return 0; +- } +- +- for (j = from; j < obj->ie_attrs.ial_count; ++j) { +- self = obj->ie_attrs.ial_data[j]; +- +- if (match->ia_tag_id == self->ia_tag_id) { +- found = self; +- break; +- } +- } +- +- if (found == NULL) +- return 0; +- +- if (!isns_attr_match(self, match)) +- return 0; +- } +- return 1; +-} +- +-/* +- * Find descendant object matching the given key +- */ +-isns_object_t * +-isns_object_find_descendant(isns_object_t *obj, const isns_attr_list_t *keys) +-{ +- isns_object_list_t list = ISNS_OBJECT_LIST_INIT; +- isns_object_t *found; +- +- if (!isns_object_find_descendants(obj, NULL, keys, &list)) +- return NULL; +- +- found = isns_object_get(list.iol_data[0]); +- isns_object_list_destroy(&list); +- +- return found; +-} +- +-int +-isns_object_find_descendants(isns_object_t *obj, +- isns_object_template_t *tmpl, +- const isns_attr_list_t *keys, +- isns_object_list_t *result) +-{ +- isns_object_t *child; +- unsigned int i; +- +- if ((tmpl == NULL || tmpl == obj->ie_template) +- && (keys == NULL || isns_object_match(obj, keys))) +- isns_object_list_append(result, obj); +- +- for (i = 0; i < obj->ie_children.iol_count; ++i) { +- child = obj->ie_children.iol_data[i]; +- isns_object_find_descendants(child, tmpl, keys, result); +- } +- +- return result->iol_count; +-} +- +-/* +- * Return the object's modification time stamp +- */ +-time_t +-isns_object_last_modified(const isns_object_t *obj) +-{ +- return obj->ie_mtime; +-} +- +-/* +- * Set the SCN bitmap +- */ +-void +-isns_object_set_scn_mask(isns_object_t *obj, uint32_t bitmap) +-{ +- obj->ie_scn_mask = bitmap; +- __isns_mark_object(obj); +-} +- +-/* +- * Debugging utility: print the object +- */ +-void +-isns_object_print(isns_object_t *obj, isns_print_fn_t *fn) +-{ +- isns_attr_list_print(&obj->ie_attrs, fn); +-} +- +-/* +- * Return a string representing the object state +- */ +-const char * +-isns_object_state_string(unsigned int state) +-{ +- switch (state) { +- case ISNS_OBJECT_STATE_LARVAL: +- return "larval"; +- case ISNS_OBJECT_STATE_MATURE: +- return "mature"; +- case ISNS_OBJECT_STATE_LIMBO: +- return "limbo"; +- case ISNS_OBJECT_STATE_DEAD: +- return "dead"; +- } +- return "UNKNOWN"; +-} +- +-/* +- * This is needed when deregistering an object. +- * Remove all attributes except the key and index attrs. +- */ +-void +-isns_object_prune_attrs(isns_object_t *obj) +-{ +- isns_object_template_t *tmpl = obj->ie_template; +- uint32_t tags[16]; +- unsigned int i; +- +- isns_assert(tmpl->iot_num_keys + 1 <= 16); +- for (i = 0; i < tmpl->iot_num_keys; ++i) +- tags[i] = tmpl->iot_keys[i]; +- if (tmpl->iot_index) +- tags[i++] = tmpl->iot_index; +- isns_attr_list_prune(&obj->ie_attrs, tags, i); +-} +- +-/* +- * Convenience functions +- */ +- +-/* +- * Create a portal object. +- * For now, always assume TCP. +- */ +-isns_object_t * +-isns_create_portal(const isns_portal_info_t *info, +- isns_object_t *parent) +-{ +- isns_object_t *obj; +- +- obj = isns_create_object(&isns_portal_template, NULL, parent); +- isns_portal_to_object(info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- obj); +- return obj; +-} +- +-/* +- * Extract all key attrs and place them +- * in the attribute list. +- */ +-int +-isns_object_extract_keys(const isns_object_t *obj, +- isns_attr_list_t *list) +-{ +- isns_object_template_t *tmpl = obj->ie_template; +- const isns_attr_list_t *src = &obj->ie_attrs; +- unsigned int i; +- +- for (i = 0; i < tmpl->iot_num_keys; ++i) { +- isns_attr_t *attr; +- +- if (!isns_attr_list_get_attr(src, tmpl->iot_keys[i], &attr)) +- return 0; +- isns_attr_list_append_attr(list, attr); +- } +- +- return 1; +-} +- +-/* +- * Extract all attributes we are permitted to overwrite and place them +- * in the attribute list. +- */ +-int +-isns_object_extract_writable(const isns_object_t *obj, +- isns_attr_list_t *list) +-{ +- const isns_attr_list_t *src = &obj->ie_attrs; +- unsigned int i; +- +- for (i = 0; i < src->ial_count; ++i) { +- isns_attr_t *attr = src->ial_data[i]; +- +- if (attr->ia_tag->it_readonly) +- continue; +- isns_attr_list_append_attr(list, attr); +- } +- +- return 1; +-} +- +-/* +- * Extract all attrs and place them +- * in the attribute list. We copy the attributes +- * as they appear inside the object; which allows +- * duplicate attributes (eg inside a discovery domain). +- */ +-int +-isns_object_extract_all(const isns_object_t *obj, isns_attr_list_t *list) +-{ +- isns_attr_list_append_list(list, &obj->ie_attrs); +- return 1; +-} +- +-/* +- * Check if the given object is valid +- */ +-int +-isns_object_attr_valid(isns_object_template_t *tmpl, uint32_t tag) +-{ +- const uint32_t *attr_tags = tmpl->iot_attrs; +- unsigned int i; +- +- for (i = 0; i < tmpl->iot_num_attrs; ++i) { +- if (*attr_tags == tag) +- return 1; +- ++attr_tags; +- } +- return 0; +-} +- +-/* +- * Set an object attribute +- */ +-static int +-__isns_object_set_attr(isns_object_t *obj, uint32_t tag, +- const isns_attr_type_t *type, +- const isns_value_t *value) +-{ +- const isns_tag_type_t *tag_type; +- +- if (!isns_object_attr_valid(obj->ie_template, tag)) +- return 0; +- +- tag_type = isns_tag_type_by_id(tag); +- if (type != &isns_attr_type_nil +- && type != tag_type->it_type) { +- isns_warning("application bug: cannot set attr %s(id=%u, " +- "type=%s) to a value of type %s\n", +- tag_type->it_name, tag, +- tag_type->it_type->it_name, +- type->it_name); +- return 0; +- } +- +- isns_attr_list_update_value(&obj->ie_attrs, +- tag, tag_type, value); +- +- /* Timestamp updates should just be written out, but we +- * do not want to trigger SCN messages and such. */ +- if (tag != ISNS_TAG_TIMESTAMP) +- isns_mark_object(obj, ISNS_SCN_OBJECT_UPDATED); +- else +- __isns_mark_object(obj); +- return 1; +-} +- +-/* +- * Copy an attribute to the object +- */ +-int +-isns_object_set_attr(isns_object_t *obj, isns_attr_t *attr) +-{ +- isns_attr_list_t *list = &obj->ie_attrs; +- uint32_t tag = attr->ia_tag_id; +- +- /* If this attribute exists within the object, +- * and it cannot occur multiple times, replace it. */ +- if (!attr->ia_tag->it_multiple +- && isns_attr_list_replace_attr(list, attr)) +- goto done; +- +- /* It doesn't exist; make sure it's a valid +- * attribute. */ +- if (!isns_object_attr_valid(obj->ie_template, tag)) +- return 0; +- +- isns_attr_list_append_attr(list, attr); +- +-done: +- isns_mark_object(obj, ISNS_SCN_OBJECT_UPDATED); +- return 1; +-} +- +-int +-isns_object_set_attrlist(isns_object_t *obj, const isns_attr_list_t *attrs) +-{ +- unsigned int i; +- +- for (i = 0; i < attrs->ial_count; ++i) { +- isns_attr_t *attr = attrs->ial_data[i]; +- if (!isns_object_set_attr(obj, attr)) +- return 0; +- } +- isns_mark_object(obj, ISNS_SCN_OBJECT_UPDATED); +- return 1; +-} +- +-/* +- * Untyped version of isns_object_set. +- * Any type checking must be done by the caller; +- * failure to do so will result in the end of the world. +- */ +-int +-isns_object_set_value(isns_object_t *obj, uint32_t tag, const void *data) +-{ +- return isns_attr_list_update(&obj->ie_attrs, tag, data); +-} +- +-/* +- * Typed versions of isns_object_set +- */ +-int +-isns_object_set_nil(isns_object_t *obj, uint32_t tag) +-{ +- return __isns_object_set_attr(obj, tag, +- &isns_attr_type_nil, NULL); +-} +- +-int +-isns_object_set_string(isns_object_t *obj, uint32_t tag, +- const char *value) +-{ +- isns_value_t var = ISNS_VALUE_INIT(string, (char *) value); +- int rc; +- +- rc = __isns_object_set_attr(obj, tag, +- &isns_attr_type_string, &var); +- return rc; +-} +- +-int +-isns_object_set_uint32(isns_object_t *obj, uint32_t tag, +- uint32_t value) +-{ +- isns_value_t var = ISNS_VALUE_INIT(uint32, value); +- +- return __isns_object_set_attr(obj, tag, +- &isns_attr_type_uint32, &var); +-} +- +-int +-isns_object_set_uint64(isns_object_t *obj, +- uint32_t tag, +- uint64_t value) +-{ +- isns_value_t var = ISNS_VALUE_INIT(uint64, value); +- +- return __isns_object_set_attr(obj, tag, +- &isns_attr_type_uint64, &var); +-} +- +-int +-isns_object_set_ipaddr(isns_object_t *obj, uint32_t tag, +- const struct in6_addr *value) +-{ +- isns_value_t var = ISNS_VALUE_INIT(ipaddr, *value); +- +- return __isns_object_set_attr(obj, tag, +- &isns_attr_type_ipaddr, &var); +-} +- +-/* +- * Query object attributes +- */ +-int +-isns_object_get_attr(const isns_object_t *obj, uint32_t tag, +- isns_attr_t **result) +-{ +- return isns_attr_list_get_attr(&obj->ie_attrs, tag, result); +-} +- +-int +-isns_object_get_attrlist(isns_object_t *obj, +- isns_attr_list_t *result, +- const isns_attr_list_t *req_attrs) +-{ +- isns_attr_list_t *attrs = &obj->ie_attrs; +- isns_attr_t *attr; +- unsigned int i; +- +- if (req_attrs == NULL) { +- /* Retrieve all attributes */ +- isns_attr_list_append_list(result, attrs); +- } else { +- for (i = 0; i < req_attrs->ial_count; ++i) { +- uint32_t tag = req_attrs->ial_data[i]->ia_tag_id; +- +- if (tag == obj->ie_template->iot_next_index) { +- /* FIXME: for now, we fake this value. +- * We need the DB object at this point +- * to find out what the next unused +- * index is. +- */ +- isns_attr_list_append_uint32(result, +- tag, 0); +- } else +- if (isns_attr_list_get_attr(attrs, tag, &attr)) +- isns_attr_list_append_attr(result, attr); +- } +- } +- return 1; +-} +- +-int +-isns_object_get_key_attrs(isns_object_t *obj, +- isns_attr_list_t *result) +-{ +- isns_object_template_t *tmpl = obj->ie_template; +- isns_attr_list_t *attrs = &obj->ie_attrs; +- isns_attr_t *attr; +- unsigned int i; +- +- for (i = 0; i < tmpl->iot_num_keys; ++i) { +- uint32_t tag = tmpl->iot_keys[i]; +- +- if (!isns_attr_list_get_attr(attrs, tag, &attr)) { +- isns_error("%s: %s object is missing key attr %u\n", +- __FUNCTION__, +- tmpl->iot_name, +- tag); +- return 0; +- } +- isns_attr_list_append_attr(result, attr); +- } +- return 1; +-} +- +-int +-isns_object_get_string(const isns_object_t *obj, uint32_t tag, +- const char **result) +-{ +- isns_attr_t *attr; +- +- if (!isns_object_get_attr(obj, tag, &attr) +- || !ISNS_ATTR_IS_STRING(attr)) +- return 0; +- +- *result = attr->ia_value.iv_string; +- return 1; +-} +- +-int +-isns_object_get_ipaddr(const isns_object_t *obj, uint32_t tag, +- struct in6_addr *result) +-{ +- isns_attr_t *attr; +- +- if (!isns_object_get_attr(obj, tag, &attr) +- || !ISNS_ATTR_IS_IPADDR(attr)) +- return 0; +- +- *result = attr->ia_value.iv_ipaddr; +- return 1; +-} +- +-int +-isns_object_get_uint32(const isns_object_t *obj, uint32_t tag, +- uint32_t *result) +-{ +- isns_attr_t *attr; +- +- if (!isns_object_get_attr(obj, tag, &attr) +- || !ISNS_ATTR_IS_UINT32(attr)) +- return 0; +- +- *result = attr->ia_value.iv_uint32; +- return 1; +-} +- +-int +-isns_object_get_uint64(const isns_object_t *obj, uint32_t tag, +- uint64_t *result) +-{ +- isns_attr_t *attr; +- +- if (!isns_object_get_attr(obj, tag, &attr) +- || !ISNS_ATTR_IS_UINT64(attr)) +- return 0; +- +- *result = attr->ia_value.iv_uint64; +- return 1; +-} +- +-int +-isns_object_get_opaque(const isns_object_t *obj, uint32_t tag, +- const void **ptr, size_t *len) +-{ +- isns_attr_t *attr; +- +- if (!isns_object_get_attr(obj, tag, &attr) +- || !ISNS_ATTR_IS_OPAQUE(attr)) +- return 0; +- +- *ptr = attr->ia_value.iv_opaque.ptr; +- *len = attr->ia_value.iv_opaque.len; +- return 1; +-} +- +-int +-isns_object_delete_attr(isns_object_t *obj, uint32_t tag) +-{ +- return isns_attr_list_remove_tag(&obj->ie_attrs, tag); +-} +- +-int +-isns_object_remove_member(isns_object_t *obj, +- const isns_attr_t *attr, +- const uint32_t *subordinate_tags) +-{ +- return isns_attr_list_remove_member(&obj->ie_attrs, +- attr, subordinate_tags); +-} +- +-/* +- * Object list functions +- */ +-void +-isns_object_list_init(isns_object_list_t *list) +-{ +- memset(list, 0, sizeof(*list)); +-} +- +-static inline void +-__isns_object_list_resize(isns_object_list_t *list, unsigned int count) +-{ +- unsigned int max; +- +- max = (list->iol_count + 15) & ~15; +- if (count < max) +- return; +- +- count = (count + 15) & ~15; +- list->iol_data = isns_realloc(list->iol_data, count * sizeof(isns_object_t *)); +- if (!list->iol_data) +- isns_fatal("Out of memory!\n"); +-} +- +-void +-isns_object_list_append(isns_object_list_t *list, isns_object_t *obj) +-{ +- __isns_object_list_resize(list, list->iol_count + 1); +- list->iol_data[list->iol_count++] = obj; +- obj->ie_users++; +-} +- +-void +-isns_object_list_append_list(isns_object_list_t *dst, +- const isns_object_list_t *src) +-{ +- unsigned int i, j; +- +- __isns_object_list_resize(dst, dst->iol_count + src->iol_count); +- j = dst->iol_count; +- for (i = 0; i < src->iol_count; ++i, ++j) { +- isns_object_t *obj = src->iol_data[i]; +- +- dst->iol_data[j] = obj; +- obj->ie_users++; +- } +- dst->iol_count = j; +-} +- +-int +-isns_object_list_contains(const isns_object_list_t *list, +- isns_object_t *obj) +-{ +- unsigned int i; +- +- for (i = 0; i < list->iol_count; ++i) { +- if (obj == list->iol_data[i]) +- return 1; +- } +- return 0; +-} +- +-isns_object_t * +-isns_object_list_lookup(const isns_object_list_t *list, +- isns_object_template_t *tmpl, +- const isns_attr_list_t *keys) +-{ +- unsigned int i; +- +- if (!tmpl && !keys) +- return NULL; +- +- if (!tmpl && !(tmpl = isns_object_template_for_key_attrs(keys))) +- return NULL; +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- +- if (obj->ie_template != tmpl) +- continue; +- if (keys && !isns_object_match(obj, keys)) +- continue; +- +- obj->ie_users++; +- return obj; +- } +- +- return NULL; +-} +- +- +-int +-isns_object_list_gang_lookup(const isns_object_list_t *list, +- isns_object_template_t *tmpl, +- const isns_attr_list_t *keys, +- isns_object_list_t *result) +-{ +- unsigned int i; +- +- if (!tmpl && !keys) +- return ISNS_INVALID_QUERY; +- +- if (!tmpl && !(tmpl = isns_object_template_for_key_attrs(keys))) +- return ISNS_INVALID_QUERY; +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- +- if (obj->ie_template != tmpl) +- continue; +- if (keys && !isns_object_match(obj, keys)) +- continue; +- +- isns_object_list_append(result, obj); +- } +- +- return ISNS_SUCCESS; +-} +- +- +-void +-isns_object_list_destroy(isns_object_list_t *list) +-{ +- unsigned int i; +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- +- isns_object_release(obj); +- } +- +- isns_free(list->iol_data); +- memset(list, 0, sizeof(*list)); +-} +- +-int +-isns_object_list_remove(isns_object_list_t *list, isns_object_t *tbr) +-{ +- unsigned int i, last; +- +- last = list->iol_count - 1; +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- +- if (obj == tbr) { +- list->iol_data[i] = list->iol_data[last]; +- list->iol_count--; +- isns_object_release(tbr); +- return 1; +- } +- } +- return 0; +-} +- +-static int +-isns_object_compare_id(const void *pa, const void *pb) +-{ +- const isns_object_t *a = *(const isns_object_t **) pa; +- const isns_object_t *b = *(const isns_object_t **) pb; +- +- return (int) a->ie_index - (int) b->ie_index; +-} +- +-void +-isns_object_list_sort(isns_object_list_t *list) +-{ +- if (list->iol_count == 0) +- return; +- +- qsort(list->iol_data, list->iol_count, +- sizeof(void *), isns_object_compare_id); +-} +- +-void +-isns_object_list_uniq(isns_object_list_t *list) +-{ +- isns_object_t *prev = NULL, *this; +- unsigned int i, j; +- +- isns_object_list_sort(list); +- for (i = j = 0; i < list->iol_count; i++) { +- this = list->iol_data[i]; +- if (this != prev) +- list->iol_data[j++] = this; +- prev = this; +- } +- list->iol_count = j; +-} +- +-void +-isns_object_list_print(const isns_object_list_t *list, isns_print_fn_t *fn) +-{ +- unsigned int i; +- +- if (list->iol_count == 0) { +- fn("(Object list empty)\n"); +- return; +- } +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj; +- +- obj = list->iol_data[i]; +- fn("object[%u] = <%s>\n", i, +- obj->ie_template->iot_name); +- isns_object_print(obj, fn); +- } +-} +- +-/* +- * Handle object references +- */ +-void +-isns_object_reference_set(isns_object_ref_t *ref, isns_object_t *obj) +-{ +- isns_object_t *old; +- +- if (obj) { +- isns_assert(obj->ie_users); +- obj->ie_references++; +- obj->ie_users++; +- } +- if ((old = ref->obj) != NULL) { +- isns_assert(old->ie_references); +- old->ie_references--; +- isns_object_release(old); +- } +- ref->obj = obj; +-} +- +-void +-isns_object_reference_drop(isns_object_ref_t *ref) +-{ +- isns_object_reference_set(ref, NULL); +-} +- +-/* +- * Helper function for portal/object conversion +- */ +-int +-isns_portal_from_object(isns_portal_info_t *portal, +- uint32_t addr_tag, uint32_t port_tag, +- const isns_object_t *obj) +-{ +- return isns_portal_from_attr_list(portal, +- addr_tag, port_tag, &obj->ie_attrs); +-} +- +-int +-isns_portal_to_object(const isns_portal_info_t *portal, +- uint32_t addr_tag, uint32_t port_tag, +- isns_object_t *obj) +-{ +- return isns_portal_to_attr_list(portal, +- addr_tag, port_tag, +- &obj->ie_attrs); +-} +- +-/* +- * Portal +- */ +-static uint32_t portal_attrs[] = { +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- ISNS_TAG_PORTAL_SYMBOLIC_NAME, +- ISNS_TAG_ESI_INTERVAL, +- ISNS_TAG_ESI_PORT, +- ISNS_TAG_PORTAL_INDEX, +- ISNS_TAG_SCN_PORT, +- ISNS_TAG_PORTAL_NEXT_INDEX, +- ISNS_TAG_PORTAL_SECURITY_BITMAP, +- ISNS_TAG_PORTAL_ISAKMP_PHASE_1, +- ISNS_TAG_PORTAL_ISAKMP_PHASE_2, +- ISNS_TAG_PORTAL_CERTIFICATE, +-}; +- +-static uint32_t portal_key_attrs[] = { +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +-}; +- +-isns_object_template_t isns_portal_template = { +- .iot_name = "Portal", +- .iot_handle = ISNS_OBJECT_TYPE_PORTAL, +- .iot_attrs = portal_attrs, +- .iot_num_attrs = array_num_elements(portal_attrs), +- .iot_keys = portal_key_attrs, +- .iot_num_keys = array_num_elements(portal_key_attrs), +- .iot_index = ISNS_TAG_PORTAL_INDEX, +- .iot_next_index = ISNS_TAG_PORTAL_NEXT_INDEX, +- .iot_container = &isns_entity_template, +-}; +diff --git a/utils/open-isns/objects.h b/utils/open-isns/objects.h +deleted file mode 100644 +index 8cc40c6..0000000 +--- a/utils/open-isns/objects.h ++++ /dev/null +@@ -1,168 +0,0 @@ +-/* +- * iSNS object model +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#ifndef ISNS_OBJECTS_H +-#define ISNS_OBJECTS_H +- +-#include "isns.h" +-#include "attrs.h" +- +-enum isns_object_id { +- ISNS_OBJECT_TYPE_ENTITY = 1, +- ISNS_OBJECT_TYPE_NODE, +- ISNS_OBJECT_TYPE_PORTAL, +- ISNS_OBJECT_TYPE_PG, +- ISNS_OBJECT_TYPE_DD, +- ISNS_OBJECT_TYPE_DDSET, +- ISNS_OBJECT_TYPE_POLICY, +- ISNS_OBJECT_TYPE_FC_PORT, +- ISNS_OBJECT_TYPE_FC_NODE, +- +- __ISNS_OBJECT_TYPE_MAX +-}; +- +- +-struct isns_object_template { +- const char * iot_name; +- unsigned int iot_handle; /* internal handle */ +- unsigned int iot_num_attrs; +- unsigned int iot_num_keys; +- uint32_t * iot_attrs; +- uint32_t * iot_keys; +- uint32_t iot_index; +- uint32_t iot_next_index; +- +- isns_object_template_t *iot_container; +- +- unsigned int iot_relation_type; +- isns_relation_t * (*iot_build_relation)(isns_db_t *, +- isns_object_t *, +- const isns_object_list_t *); +- +- unsigned int iot_vendor_specific : 1; +-}; +- +-struct isns_object { +- /* There are two kinds of users of an object +- * - Temporary references that result from the +- * object being examined; being on a list, +- * etc. The main purpose of these references +- * is to make sure the object doesn't go away +- * while being used. +- * +- * These are accounted for by ie_users. +- * +- * - Permanent references that result from the +- * object being references by other objects +- * (usually relations) such as a Portal Group, +- * or a Discovery Domain. +- * +- * These are accounted for by ie_references. +- * +- * The main purpose of these references is to +- * model some of the weirder life cycle states +- * described in RFC 4711. +- * +- * Every reference via ie_references implies a +- * reference via ie_users. +- */ +- unsigned int ie_users; +- unsigned int ie_references; +- +- uint32_t ie_index; +- +- unsigned int ie_state; +- unsigned int ie_flags; +- time_t ie_mtime; +- +- uint32_t ie_scn_mask; /* Events this node listens for */ +- uint32_t ie_scn_bits; /* Current event bits */ +- +- isns_attr_list_t ie_attrs; +- isns_object_t * ie_container; +- uint32_t ie_container_idx; +- isns_object_template_t *ie_template; +- +- isns_relation_t * ie_relation; +- isns_object_list_t ie_children; +- +- /* Bit vector describing DD membership */ +- isns_bitvector_t * ie_membership; +- +- /* Support for virtual objects */ +- int (*ie_rebuild)(isns_object_t *, isns_db_t *); +-}; +- +-typedef struct isns_object_ref { +- isns_object_t * obj; +-} isns_object_ref_t; +- +-enum { +- ISNS_RELATION_NONE = 0, +- ISNS_RELATION_PORTAL_GROUP, +-}; +- +-struct isns_relation { +- unsigned int ir_type; +- unsigned int ir_users; +- isns_object_t * ir_object; +- isns_object_ref_t ir_subordinate[2]; +-}; +- +-typedef struct isns_relation_soup isns_relation_soup_t; +- +-typedef struct isns_relation_list isns_relation_list_t; +-struct isns_relation_list { +- unsigned int irl_count; +- isns_relation_t ** irl_data; +-}; +-#define ISNS_RELATION_LIST_INIT { .irl_count = 0, .irl_data = NULL } +- +-#define ISNS_OBJECT_DIRTY 0x0001 +-#define ISNS_OBJECT_PRIVATE 0x0002 +-#define ISNS_OBJECT_DEAD 0x0004 +- +-enum { +- ISNS_OBJECT_STATE_LARVAL, +- ISNS_OBJECT_STATE_MATURE, +- ISNS_OBJECT_STATE_LIMBO, +- ISNS_OBJECT_STATE_DEAD, +-}; +- +-extern int isns_object_remove_member(isns_object_t *obj, +- const isns_attr_t *attr, +- const uint32_t *subordinate_tags); +- +-extern void isns_object_reference_set(isns_object_ref_t *ref, +- isns_object_t *obj); +-extern void isns_object_reference_drop(isns_object_ref_t *ref); +- +-extern const char *isns_object_state_string(unsigned int); +- +-extern isns_object_template_t *isns_object_template_by_name(const char *); +-extern int isns_object_is_valid_container(const isns_object_t *, +- isns_object_template_t *); +- +-extern void isns_object_set_scn_mask(isns_object_t *, uint32_t); +- +-extern isns_object_t *isns_create_default_domain(void); +- +-/* +- * Helper macros for object type check +- */ +-#define __ISNS_OBJECT_TYPE_CHECK(obj, type) \ +- ((obj)->ie_template == &isns_##type##_template) +-#define ISNS_IS_ENTITY(obj) __ISNS_OBJECT_TYPE_CHECK(obj, entity) +-#define ISNS_IS_ISCSI_NODE(obj) __ISNS_OBJECT_TYPE_CHECK(obj, iscsi_node) +-#define ISNS_IS_FC_PORT(obj) __ISNS_OBJECT_TYPE_CHECK(obj, fc_port) +-#define ISNS_IS_FC_NODE(obj) __ISNS_OBJECT_TYPE_CHECK(obj, fc_node) +-#define ISNS_IS_PORTAL(obj) __ISNS_OBJECT_TYPE_CHECK(obj, portal) +-#define ISNS_IS_PG(obj) __ISNS_OBJECT_TYPE_CHECK(obj, iscsi_pg) +-#define ISNS_IS_POLICY(obj) __ISNS_OBJECT_TYPE_CHECK(obj, policy) +-#define ISNS_IS_DD(obj) __ISNS_OBJECT_TYPE_CHECK(obj, dd) +-#define ISNS_IS_DDSET(obj) __ISNS_OBJECT_TYPE_CHECK(obj, ddset) +- +-#endif /* ISNS_OBJECTS_H */ +diff --git a/utils/open-isns/parser.c b/utils/open-isns/parser.c +deleted file mode 100644 +index 378f2c8..0000000 +--- a/utils/open-isns/parser.c ++++ /dev/null +@@ -1,134 +0,0 @@ +-/* +- * parser.c - simple line based parser +- * +- * Copyright (C) 2006, 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include "util.h" +- +-/* +- * By default, the parser will recognize any white space +- * as "word" separators. +- * If you need additional separators, you can put them +- * here. +- */ +-const char * parser_separators = NULL; +-const char * parser_punctuation = "="; +- +-char * +-parser_get_next_line(FILE *fp) +-{ +- static char buffer[8192]; +- unsigned int n = 0, count = 0; +- int c, continuation = 0; +- +- while (n < sizeof(buffer) - 1) { +- c = fgetc(fp); +- if (c == EOF) +- break; +- +- count++; +- if (c == '\r') +- continue; +- /* Discard all blanks +- * following a backslash-newline +- */ +- if (continuation) { +- if (c == ' ' || c == '\t') +- continue; +- continuation = 0; +- } +- +- if (c == '\n') { +- if (n && buffer[n-1] == '\\') { +- buffer[--n] = '\0'; +- continuation = 1; +- } +- while (n && isspace(buffer[n-1])) +- buffer[--n] = '\0'; +- if (!continuation) +- break; +- buffer[n++] = ' '; +- continue; +- } +- +- buffer[n++] = c; +- } +- +- if (count == 0) +- return NULL; +- +- buffer[n] = '\0'; +- return buffer; +-} +- +-static inline int +-is_separator(char c) +-{ +- if (isspace(c)) +- return 1; +- return parser_separators && c && strchr(parser_separators, c); +-} +- +-static inline int +-is_punctuation(char c) +-{ +- return parser_punctuation && c && strchr(parser_punctuation, c); +-} +- +-char * +-parser_get_next_word(char **sp) +-{ +- static char buffer[512]; +- char *s = *sp, *p = buffer; +- +- while (is_separator(*s)) +- ++s; +- +- if (*s == '\0') +- goto done; +- +- if (is_punctuation(*s)) { +- *p++ = *s++; +- goto done; +- } +- +- while (*s && !is_separator(*s) && !is_punctuation(*s)) +- *p++ = *s++; +- +-done: +- *p++ = '\0'; +- *sp = s; +- return buffer[0]? buffer : NULL; +-} +- +-int +-parser_split_line(char *line, unsigned int argsmax, char **argv) +-{ +- unsigned int argc = 0; +- char *s; +- +- while (argc < argsmax && (s = parser_get_next_word(&line))) +- argv[argc++] = strdup(s); +- return argc; +-} +- +-char * +-parser_get_rest_of_line(char **sp) +-{ +- char *s = *sp, *res = NULL; +- +- while (is_separator(*s)) +- ++s; +- +- *sp = ""; +- if (*s != '\0') +- res = s; +- return res; +-} +diff --git a/utils/open-isns/paths.h b/utils/open-isns/paths.h +deleted file mode 100644 +index b54612c..0000000 +--- a/utils/open-isns/paths.h ++++ /dev/null +@@ -1,22 +0,0 @@ +-/* +- * Compile time configuration. +- * For now, let's keep it simple and ignore autoconf... +- * +- * Copyright (C) 2006, 2007 Olaf Kirch +- */ +- +-#ifndef ISNS_CONFIG_H +-#define ISNS_CONFIG_H +- +-#define __OPENISNS_MKVERSION(maj, min) (((maj) << 8) + (min)) +-#define OPENISNS_VERSION __OPENISNS_MKVERSION(0, 90); +-#define OPENISNS_VERSION_STRING "0.90" +- +-#define ISNS_ETCDIR "/etc/isns" +-#define ISNS_RUNDIR "/var/run" +-#define ISNS_DEFAULT_ISNSD_CONFIG ISNS_ETCDIR "/isnsd.conf" +-#define ISNS_DEFAULT_ISNSDD_CONFIG ISNS_ETCDIR "/isnsdd.conf" +-#define ISNS_DEFAULT_ISNSADM_CONFIG ISNS_ETCDIR "/isnsadm.conf" +-#define ISNS_DEFAULT_LOCAL_REGISTRY ISNS_RUNDIR "/isns.registry" +- +-#endif /* ISNS_CONFIG_H */ +diff --git a/utils/open-isns/pidfile.c b/utils/open-isns/pidfile.c +deleted file mode 100644 +index 3384373..0000000 +--- a/utils/open-isns/pidfile.c ++++ /dev/null +@@ -1,98 +0,0 @@ +-/* +- * write pidfile +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "util.h" +- +-static void +-__update_pidfile(int fd) +-{ +- char pidbuf[32]; +- +- snprintf(pidbuf, sizeof(pidbuf), "%u\n", getpid()); +- if (write(fd, pidbuf, strlen(pidbuf)) < 0) +- isns_fatal("Error writing pid file: %m\n"); +- close(fd); +-} +- +-static pid_t +-__read_pidfile(const char *filename) +-{ +- char pidbuf[32]; +- FILE *fp; +- pid_t pid = -1; +- +- fp = fopen(filename, "r"); +- if (fp != NULL) { +- if (fgets(pidbuf, sizeof(pidbuf), fp)) +- pid = strtoul(pidbuf, NULL, 0); +- fclose(fp); +- } +- return pid; +-} +- +-void +-isns_write_pidfile(const char *filename) +-{ +- int fd; +- pid_t pid; +- +- fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, 0644); +- if (fd >= 0) { +- __update_pidfile(fd); +- return; +- } +- +- if (errno != EEXIST) +- isns_fatal("Error creating pid file %s: %m\n", +- filename); +- +- /* If the pid file is stale, remove it. +- * Not really needed in real life, but +- * highly convenient for debugging :) */ +- if ((pid = __read_pidfile(filename)) > 0 +- && kill(pid, 0) < 0 +- && errno == ESRCH) { +- isns_debug_general( +- "Removing stale PID file %s\n", +- filename); +- unlink(filename); +- } +- +- /* Try again */ +- fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, 0644); +- if (fd < 0) +- isns_fatal("PID file exists; another daemon " +- "seems to be running\n"); +- +- __update_pidfile(fd); +-} +- +-void +-isns_update_pidfile(const char *filename) +-{ +- int fd; +- +- fd = open(filename, O_WRONLY); +- if (fd < 0) { +- isns_fatal("Error opening pid file %s: %m\n", +- filename); +- } +- +- __update_pidfile(fd); +-} +- +-void +-isns_remove_pidfile(const char *filename) +-{ +- unlink(filename); +-} +diff --git a/utils/open-isns/pki.c b/utils/open-isns/pki.c +deleted file mode 100644 +index f3af922..0000000 +--- a/utils/open-isns/pki.c ++++ /dev/null +@@ -1,536 +0,0 @@ +-/* +- * PKI related functions +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "isns.h" +-#include "security.h" +-#include "util.h" +-#include "config.h" +- +-#ifdef WITH_SECURITY +- +-/* versions prior to 9.6.8 didn't seem to have these */ +-#if OPADDRCONFIGENSSL_VERSION_NUMBER < 0x00906080L +-# define EVP_MD_CTX_init(c) do { } while (0) +-# define EVP_MD_CTX_cleanup(c) do { } while (0) +-#endif +-#if OPADDRCONFIGENSSL_VERSION_NUMBER < 0x00906070L +-# define i2d_DSA_PUBKEY i2d_DSA_PUBKEY_backwards +- +-static int i2d_DSA_PUBKEY_backwards(DSA *, unsigned char **); +-#endif +- +-static int isns_openssl_init = 0; +- +-static int isns_dsasig_verify(isns_security_t *ctx, +- isns_principal_t *peer, +- buf_t *pdu, +- const struct isns_authblk *); +-static int isns_dsasig_sign(isns_security_t *ctx, +- isns_principal_t *peer, +- buf_t *pdu, +- struct isns_authblk *); +-static EVP_PKEY *isns_dsasig_load_private_pem(isns_security_t *ctx, +- const char *filename); +-static EVP_PKEY *isns_dsasig_load_public_pem(isns_security_t *ctx, +- const char *filename); +-static DSA * isns_dsa_load_params(const char *); +- +- +-/* +- * Create a DSA security context +- */ +-isns_security_t * +-isns_create_dsa_context(void) +-{ +- isns_security_t *ctx; +- +- if (!isns_openssl_init) { +- ERR_load_crypto_strings(); +- OpenSSL_add_all_algorithms(); +- OpenSSL_add_all_ciphers(); +- OpenSSL_add_all_digests(); +- isns_openssl_init = 1; +- } +- +- ctx = isns_calloc(1, sizeof(*ctx)); +- +- ctx->is_name = "DSA"; +- ctx->is_type = ISNS_AUTH_TYPE_SHA1_DSA; +- ctx->is_replay_window = isns_config.ic_auth.replay_window; +- ctx->is_timestamp_jitter = isns_config.ic_auth.timestamp_jitter; +- +- ctx->is_verify = isns_dsasig_verify; +- ctx->is_sign = isns_dsasig_sign; +- ctx->is_load_private = isns_dsasig_load_private_pem; +- ctx->is_load_public = isns_dsasig_load_public_pem; +- +- isns_debug_auth("Created DSA authentication context\n"); +- return ctx; +-} +- +-/* +- * DSA signature generation and verification +- */ +-static void +-isns_message_digest(EVP_MD_CTX *md, const buf_t *pdu, +- const struct isns_authblk *blk) +-{ +- uint64_t stamp; +- +- EVP_DigestUpdate(md, buf_head(pdu), buf_avail(pdu)); +- +- /* The RFC doesn't say which pieces of the +- * message should be hashed. +- * We make an educated guess. +- */ +- stamp = htonll(blk->iab_timestamp); +- EVP_DigestUpdate(md, &stamp, sizeof(stamp)); +-} +- +-static void +-isns_dsasig_report_errors(const char *msg, isns_print_fn_t *fn) +-{ +- unsigned long code; +- +- fn("%s - OpenSSL errors follow:\n", msg); +- while ((code = ERR_get_error()) != 0) +- fn("> %s: %s\n", +- ERR_func_error_string(code), +- ERR_reason_error_string(code)); +-} +- +-int +-isns_dsasig_sign(isns_security_t *ctx, +- isns_principal_t *peer, +- buf_t *pdu, +- struct isns_authblk *blk) +-{ +- static unsigned char signature[1024]; +- unsigned int sig_len = sizeof(signature); +- EVP_MD_CTX md_ctx; +- EVP_PKEY *pkey; +- int err; +- +- if ((pkey = peer->is_key) == NULL) +- return 0; +- +- if (pkey->type != EVP_PKEY_DSA) { +- isns_debug_message( +- "Incompatible public key (spi=%s)\n", +- peer->is_name); +- return 0; +- } +- if (EVP_PKEY_size(pkey) > sizeof(signature)) { +- isns_error("isns_dsasig_sign: signature buffer too small\n"); +- return 0; +- } +- if (pkey->pkey.dsa->priv_key == NULL) { +- isns_error("isns_dsasig_sign: oops, seems to be a public key\n"); +- return 0; +- } +- +- isns_debug_auth("Signing messages with spi=%s, DSA/%u\n", +- peer->is_name, EVP_PKEY_bits(pkey)); +- +- EVP_MD_CTX_init(&md_ctx); +- EVP_SignInit(&md_ctx, EVP_dss1()); +- isns_message_digest(&md_ctx, pdu, blk); +- err = EVP_SignFinal(&md_ctx, +- signature, &sig_len, +- pkey); +- EVP_MD_CTX_cleanup(&md_ctx); +- +- if (err == 0) { +- isns_dsasig_report_errors("EVP_SignFinal failed", isns_error); +- return 0; +- } +- +- blk->iab_sig = signature; +- blk->iab_sig_len = sig_len; +- return 1; +-} +- +-int +-isns_dsasig_verify(isns_security_t *ctx, +- isns_principal_t *peer, +- buf_t *pdu, +- const struct isns_authblk *blk) +-{ +- EVP_MD_CTX md_ctx; +- EVP_PKEY *pkey; +- int err; +- +- if ((pkey = peer->is_key) == NULL) +- return 0; +- +- if (pkey->type != EVP_PKEY_DSA) { +- isns_debug_message( +- "Incompatible public key (spi=%s)\n", +- peer->is_name); +- return 0; +- } +- +- EVP_MD_CTX_init(&md_ctx); +- EVP_VerifyInit(&md_ctx, EVP_dss1()); +- isns_message_digest(&md_ctx, pdu, blk); +- err = EVP_VerifyFinal(&md_ctx, +- blk->iab_sig, blk->iab_sig_len, +- pkey); +- EVP_MD_CTX_cleanup(&md_ctx); +- +- if (err == 0) { +- isns_debug_auth("*** Incorrect signature ***\n"); +- return 0; +- } +- if (err < 0) { +- isns_dsasig_report_errors("EVP_VerifyFinal failed", isns_error); +- return 0; +- } +- +- isns_debug_message("Good signature from %s\n", +- peer->is_name?: ""); +- return 1; +-} +- +-EVP_PKEY * +-isns_dsasig_load_private_pem(isns_security_t *ctx, const char *filename) +-{ +- EVP_PKEY *pkey; +- FILE *fp; +- +- if (!(fp = fopen(filename, "r"))) { +- isns_error("Unable to open DSA keyfile %s: %m\n", +- filename); +- return 0; +- } +- +- pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL); +- fclose(fp); +- return pkey; +-} +- +-EVP_PKEY * +-isns_dsasig_load_public_pem(isns_security_t *ctx, const char *filename) +-{ +- EVP_PKEY *pkey; +- FILE *fp; +- +- if (!(fp = fopen(filename, "r"))) { +- isns_error("Unable to open DSA keyfile %s: %m\n", +- filename); +- return 0; +- } +- +- pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL); +- if (pkey == NULL) { +- isns_dsasig_report_errors("Error loading DSA public key", +- isns_error); +- } +- +- fclose(fp); +- return pkey; +-} +- +-EVP_PKEY * +-isns_dsa_decode_public(const void *ptr, size_t len) +-{ +- const unsigned char *der = ptr; +- EVP_PKEY *evp; +- DSA *dsa; +- +- /* Assigning ptr to a temporary variable avoids a silly +- * compiled warning about type-punning. */ +- dsa = d2i_DSA_PUBKEY(NULL, &der, len); +- if (dsa == NULL) +- return NULL; +- +- evp = EVP_PKEY_new(); +- EVP_PKEY_assign_DSA(evp, dsa); +- return evp; +-} +- +-int +-isns_dsa_encode_public(EVP_PKEY *pkey, void **ptr, size_t *len) +-{ +- int bytes; +- +- *ptr = NULL; +- bytes = i2d_DSA_PUBKEY(pkey->pkey.dsa, (unsigned char **) ptr); +- if (bytes < 0) +- return 0; +- +- *len = bytes; +- return 1; +-} +- +-EVP_PKEY * +-isns_dsa_load_public(const char *name) +-{ +- return isns_dsasig_load_public_pem(NULL, name); +-} +- +-int +-isns_dsa_store_private(const char *name, EVP_PKEY *key) +-{ +- FILE *fp; +- int rv, fd; +- +- if ((fd = open(name, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) { +- isns_error("Cannot save DSA key to %s: %m\n", name); +- return 0; +- } +- +- if (!(fp = fdopen(fd, "w"))) { +- isns_error("fdopen(%s): %m\n", name); +- close(fd); +- return 0; +- } +- +- rv = PEM_write_PrivateKey(fp, key, NULL, NULL, 0, 0, NULL); +- fclose(fp); +- +- if (rv == 0) +- isns_dsasig_report_errors("Failed to store private key", +- isns_error); +- +- return rv; +-} +- +-int +-isns_dsa_store_public(const char *name, EVP_PKEY *key) +-{ +- FILE *fp; +- int rv; +- +- if (!(fp = fopen(name, "w"))) { +- isns_error("Unable to open %s: %m\n", name); +- return 0; +- } +- +- rv = PEM_write_PUBKEY(fp, key); +- fclose(fp); +- +- if (rv == 0) +- isns_dsasig_report_errors("Failed to store public key", +- isns_error); +- +- return rv; +-} +- +- +-/* +- * DSA key generation +- */ +-EVP_PKEY * +-isns_dsa_generate_key(void) +-{ +- EVP_PKEY *pkey; +- DSA *dsa = NULL; +- +- if (!(dsa = isns_dsa_load_params(isns_config.ic_dsa.param_file))) +- goto failed; +- +- if (!DSA_generate_key(dsa)) { +- isns_dsasig_report_errors("Failed to generate DSA key", +- isns_error); +- goto failed; +- } +- +- pkey = EVP_PKEY_new(); +- EVP_PKEY_assign_DSA(pkey, dsa); +- return pkey; +- +-failed: +- if (dsa) +- DSA_free(dsa); +- return NULL; +-} +- +-DSA * +-isns_dsa_load_params(const char *filename) +-{ +- FILE *fp; +- DSA *dsa; +- +- if (!filename) { +- isns_error("Cannot generate key - no DSA parameter file\n"); +- return NULL; +- } +- if (!(fp = fopen(filename, "r"))) { +- isns_error("Unable to open %s: %m\n", filename); +- return NULL; +- } +- +- dsa = PEM_read_DSAparams(fp, NULL, NULL, NULL); +- fclose(fp); +- +- if (dsa == NULL) { +- isns_dsasig_report_errors("Error loading DSA parameters", +- isns_error); +- } +- +- return dsa; +-} +- +-static void +-isns_dsa_param_gen_callback(int stage, int index, void *dummy) +-{ +- if (stage == 0) +- write(1, "+", 1); +- else if (stage == 1) +- write(1, ".", 1); +- else if (stage == 2) +- write(1, "/", 1); +-} +- +-int +-isns_dsa_init_params(const char *filename) +-{ +- FILE *fp; +- DSA *dsa; +- +- if (access(filename, R_OK) == 0) +- return 1; +- +- isns_mkdir_recursive(isns_dirname(filename)); +- if (!(fp = fopen(filename, "w"))) { +- isns_error("Unable to open %s: %m\n", filename); +- return 0; +- } +- +- isns_notice("Generating DSA parameters; this may take a while\n"); +- dsa = DSA_generate_parameters(1024, NULL, 0, +- NULL, NULL, isns_dsa_param_gen_callback, NULL); +- write(1, "\n", 1); +- +- if (dsa == NULL) { +- isns_dsasig_report_errors("Error generating DSA parameters", +- isns_error); +- fclose(fp); +- return 0; +- } +- +- if (!PEM_write_DSAparams(fp, dsa)) { +- isns_dsasig_report_errors("Error writing DSA parameters", +- isns_error); +- DSA_free(dsa); +- fclose(fp); +- return 0; +- } +- DSA_free(dsa); +- fclose(fp); +- return 1; +-} +- +-/* +- * Make sure the authentication key is present. +- */ +-int +-isns_dsa_init_key(const char *filename) +-{ +- char pubkey_path[1024]; +- EVP_PKEY *pkey; +- +- isns_mkdir_recursive(isns_dirname(filename)); +- snprintf(pubkey_path, sizeof(pubkey_path), +- "%s.pub", filename); +- if (access(filename, R_OK) == 0 +- && access(pubkey_path, R_OK) == 0) +- return 1; +- +- if (!(pkey = isns_dsa_generate_key())) { +- isns_error("Failed to generate AuthKey\n"); +- return 0; +- } +- +- if (!isns_dsa_store_private(filename, pkey)) { +- isns_error("Unable to write private key to %s\n", filename); +- return 0; +- } +- isns_notice("Stored private key in %s\n", filename); +- +- if (!isns_dsa_store_public(pubkey_path, pkey)) { +- isns_error("Unable to write public key to %s\n", pubkey_path); +- return 0; +- } +- isns_notice("Stored private key in %s\n", pubkey_path); +- +- return 1; +-} +- +-/* +- * Simple keystore - this is a flat directory, with +- * public key files using the SPI as their name. +- */ +-typedef struct isns_simple_keystore isns_simple_keystore_t; +-struct isns_simple_keystore { +- isns_keystore_t sc_base; +- char * sc_dirpath; +-}; +- +-/* +- * Load a DSA key from the cert store +- * In fact, this will load RSA keys as well. +- */ +-static EVP_PKEY * +-__isns_simple_keystore_find(isns_keystore_t *store_base, +- const char *name, size_t namelen) +-{ +- isns_simple_keystore_t *store = (isns_simple_keystore_t *) store_base; +- char pathname[PATH_MAX]; +- +- /* Refuse to open key files with names +- * that refer to parent directories */ +- if (memchr(name, '/', namelen) || name[0] == '.') +- return NULL; +- +- snprintf(pathname, sizeof(pathname), +- "%s/%.*s", store->sc_dirpath, +- (int) namelen, name); +- if (access(pathname, R_OK) < 0) +- return NULL; +- return isns_dsasig_load_public_pem(NULL, pathname); +-} +- +-isns_keystore_t * +-isns_create_simple_keystore(const char *dirname) +-{ +- isns_simple_keystore_t *store; +- +- store = isns_calloc(1, sizeof(*store)); +- store->sc_base.ic_name = "simple key store"; +- store->sc_base.ic_find = __isns_simple_keystore_find; +- store->sc_dirpath = isns_strdup(dirname); +- +- return (isns_keystore_t *) store; +-} +- +-#if OPADDRCONFIGENSSL_VERSION_NUMBER < 0x00906070L +-#undef i2d_DSA_PUBKEY +- +-int +-i2d_DSA_PUBKEY_backwards(DSA *dsa, unsigned char **ptr) +-{ +- unsigned char *buf; +- int len; +- +- len = i2d_DSA_PUBKEY(dsa, NULL); +- if (len < 0) +- return 0; +- +- *ptr = buf = OPENSSL_malloc(len); +- return i2d_DSA_PUBKEY(dsa, &buf); +-} +-#endif +- +-#endif /* WITH_SECURITY */ +diff --git a/utils/open-isns/policy.c b/utils/open-isns/policy.c +deleted file mode 100644 +index 46de15b..0000000 +--- a/utils/open-isns/policy.c ++++ /dev/null +@@ -1,577 +0,0 @@ +-/* +- * Open-iSNS policy engine +- * +- * Copyright (C) 2007 Olaf Kirch +- * +- * For now, policy is static. We can make it configurable +- * later. +- */ +- +-#include +-#include "isns.h" +-#include "security.h" +-#include "objects.h" +-#include "message.h" +-#include "util.h" +- +-/* +- A brief discussion of policy +- +- For now, a principal's name (ie its SPI string) *must* match +- the iSNS source name it uses. +- +- Special care needs to be taken to restrict which principals +- are permitted to act as a control node. For now, we don't +- implement control node semantics. +- +- */ +- +-static unsigned int isns_policy_gen = 0; +- +-/* +- * Administrative policy (everything allowed, +- * talks to entity "CONTROL" +- */ +-static isns_policy_t isns_superhero_powers = { +- .ip_name = "administrator", +- .ip_users = 1, +- .ip_gen = 0, +- +- .ip_entity = ISNS_ENTITY_CONTROL, +- .ip_functions = ~0, +- .ip_object_types = ~0, +- .ip_node_types = ~0, +-}; +- +-/* +- * Policy for anon user +- */ +-static isns_policy_t isns_dweeb_powers = { +- .ip_name = "anonymous", +- .ip_users = 1, +- .ip_gen = 0, +- +- .ip_functions = 1 << ISNS_DEVICE_ATTRIBUTE_QUERY, +- .ip_object_types = 0, +- .ip_node_types = 0, +-}; +- +-#define IS_ANON_POLICY(p) ((p) == &isns_dweeb_powers) +- +-/* +- * These are used when security is turned off. +- * Essentially the same as superhero, except +- * no eid specified. +- */ +-static isns_policy_t isns_flyingpigs_powers = { +- .ip_name = "insecure", +- .ip_users = 1, +- .ip_gen = 0, +- +- .ip_functions = ~0, +- .ip_object_types = ~0, +- .ip_node_types = ~0, +-}; +- +- +-isns_policy_t * +-isns_policy_bind(const isns_message_t *msg) +-{ +- isns_policy_t *policy = NULL; +- isns_principal_t *princ = NULL; +- +- /* When the admin turns off gravity, +- * pigs can fly, too. */ +- if (isns_config.ic_security == 0) { +- policy = &isns_flyingpigs_powers; +- goto found; +- } +- +- /* If the caller is the local root user, s/he can +- * do anything. */ +- if (msg->im_creds && msg->im_creds->uid == 0) { +- policy = &isns_superhero_powers; +- goto found; +- } +- +- /* Tie the SPI given in the auth block to a +- * source name. +- * For now, the names have to match. Down the road, +- * there may be more flexible schemes. +- */ +- if ((princ = msg->im_security) != NULL) { +- if ((policy = princ->is_policy) != NULL) +- goto found; +- +- isns_error("Internal error - no policy for " +- "principal %s!\n", +- princ->is_name); +- } +- +- policy = &isns_dweeb_powers; +- +-found: +- policy->ip_users++; +- return policy; +-} +- +-/* +- * Check whether the call is permitted. +- * This is particularly useful to prevent rogue +- * clients from messing with Discovery Domains. +- */ +-int +-isns_policy_validate_function(const isns_policy_t *policy, +- const isns_message_t *msg) +-{ +- uint32_t function = msg->im_header.i_function; +- int rv = 0; +- +- if (function >= 32) { +- isns_debug_auth("Bad function code %08x\n", function); +- return 0; +- } +- +- if (!(policy->ip_functions & (1 << function))) +- goto reject; +- +- rv = 1; +- +-reject: +- isns_debug_auth(":: policy %s function %s (%04x) %s\n", +- policy->ip_name, +- isns_function_name(function), function, +- rv? "permitted" : "DENIED"); +- return rv; +-} +- +-/* +- * Helper function to validate node names and source names +- */ +-static int +-__validate_node_name(const isns_policy_t *policy, const char *name) +-{ +- const struct string_array *ap; +- unsigned int i; +- +- /* Control nodes get to do everything */ +- if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK) +- return 1; +- +- ap = &policy->ip_node_names; +- for (i = 0; i < ap->count; ++i) { +- const char *s; +- +- s = ap->list[i]; +- if (s == NULL) +- continue; +- if (isns_source_pattern_match(s, name)) +- return 1; +- } +- return 0; +-} +- +-/* +- * Validate the source of a message +- */ +-int +-isns_policy_validate_source(const isns_policy_t *policy, +- const isns_source_t *source) +-{ +- const char *src_name = isns_source_name(source); +- int rv = 0; +- +- if (!__validate_node_name(policy, src_name)) +- goto reject; +- +- rv = 1; +- +-reject: +- isns_debug_auth(":: policy %s source %s %s\n", +- policy->ip_name, src_name, +- rv? "permitted" : "DENIED"); +- return rv; +-} +- +-/* +- * Check whether the entity name specified by the client +- * is actually his to use. +- */ +-int +-isns_policy_validate_entity(const isns_policy_t *policy, +- const char *eid) +-{ +- int rv = 0, eidlen; +- +- /* Control nodes get to do everything */ +- if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK) +- goto accept; +- +- /* For anonymous clients, refuse any attempt to +- * create an entity */ +- if (IS_ANON_POLICY(policy)) +- goto reject; +- +- /* If no entity is assigned, this means the client +- * is not permitted to specify its own entity name, +- * and accept what we assign it. +- */ +- if (policy->ip_entity == NULL) +- goto reject; +- +- eidlen = strlen(policy->ip_entity); +- if (strncasecmp(policy->ip_entity, eid, eidlen) +- && (eid[eidlen] == ':' || eid[eidlen] == '\0')) +- goto reject; +- +-accept: rv = 1; +- +-reject: +- isns_debug_auth(":: policy %s entity ID %s %s\n", +- policy->ip_name, eid, +- rv? "permitted" : "DENIED"); +- return rv; +-} +- +-const char * +-isns_policy_default_entity(const isns_policy_t *policy) +-{ +- return policy->ip_entity; +-} +- +-int +-isns_policy_validate_node_name(const isns_policy_t *policy, +- const char *node_name) +-{ +- int rv = 0; +- +- /* Control nodes get to do everything */ +- if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK) +- goto accept; +- +- if (!__validate_node_name(policy, node_name)) +- goto reject; +- +-accept: rv = 1; +-reject: +- isns_debug_auth(":: policy %s storage node name %s %s\n", +- policy->ip_name, node_name, +- rv? "permitted" : "DENIED"); +- return rv; +-} +- +-/* +- * Check whether the client is allowed to access +- * the given object in a particular way. +- */ +-static int +-__isns_policy_validate_object_access(const isns_policy_t *policy, +- const isns_source_t *source, +- const isns_object_t *obj, +- isns_object_template_t *tmpl, +- unsigned int function) +-{ +- uint32_t mask, perm = ISNS_PERMISSION_WRITE; +- int rv = 0; +- +- /* Control nodes get to do everything */ +- if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK) +- goto accept; +- +- if (function == ISNS_DEVICE_ATTRIBUTE_QUERY +- || function == ISNS_DEVICE_GET_NEXT) +- perm = ISNS_PERMISSION_READ; +- +- /* +- * 5.6.1. Source Attribute +- * +- * For messages that change the contents of the iSNS +- * database, the iSNS server MUST verify that the Source +- * Attribute identifies either a Control Node or a Storage +- * Node that is a part of the Network Entity containing +- * the added, deleted, or modified objects. +- * +- * Note: this statement makes sense for nodes, portals +- * etc, but not for discovery domains, which are not +- * part of any network entity (but the Control Node clause +- * above still applies). +- */ +- if (perm == ISNS_PERMISSION_WRITE && obj != NULL) { +- const isns_object_t *entity; +- +- entity = obj->ie_container; +- if (entity && entity != source->is_entity) +- goto refuse; +- +- /* You're not allowed to modify virtual objects */ +- if (obj->ie_rebuild) +- goto refuse; +- } +- +- /* Check whether the client is permitted +- to access such an object */ +- mask = ISNS_ACCESS(tmpl->iot_handle, perm); +- if (!(policy->ip_object_types & mask)) +- goto refuse; +- +- if (source->is_untrusted && (obj->ie_flags & ISNS_OBJECT_PRIVATE)) +- goto refuse; +- +-accept: +- rv = 1; +- +-refuse: +- if (obj) { +- isns_debug_auth(":: policy %s operation %s on object %08x (%s) %s\n", +- policy->ip_name, +- isns_function_name(function), +- obj->ie_index, +- tmpl->iot_name, +- rv? "permitted" : "DENIED"); +- } else { +- isns_debug_auth(":: policy %s operation %s on %s object %s\n", +- policy->ip_name, +- isns_function_name(function), +- tmpl->iot_name, +- rv? "permitted" : "DENIED"); +- } +- return rv; +-} +- +-/* +- * Check whether the client is allowed to access +- * the given object. This is called for read functions. +- */ +-int +-isns_policy_validate_object_access(const isns_policy_t *policy, +- const isns_source_t *source, +- const isns_object_t *obj, +- unsigned int function) +-{ +- return __isns_policy_validate_object_access(policy, source, +- obj, obj->ie_template, +- function); +-} +- +-/* +- * Check whether the client is allowed to update +- * the given object. +- */ +-int +-isns_policy_validate_object_update(const isns_policy_t *policy, +- const isns_source_t *source, +- const isns_object_t *obj, +- const isns_attr_list_t *attrs, +- unsigned int function) +-{ +- return __isns_policy_validate_object_access(policy, source, +- obj, obj->ie_template, +- function); +-} +- +-/* +- * Check whether the client is allowed to create an object +- * with the given attrs. +- */ +-int +-isns_policy_validate_object_creation(const isns_policy_t *policy, +- const isns_source_t *source, +- isns_object_template_t *tmpl, +- const isns_attr_list_t *keys, +- const isns_attr_list_t *attrs, +- unsigned int function) +-{ +- const char *name = NULL; +- +- if (tmpl == &isns_entity_template) { +- /* DevReg messages may contain an empty EID +- * string, which means the server should select +- * one. */ +- if (isns_attr_list_get_string(keys, +- ISNS_TAG_ENTITY_IDENTIFIER, &name) +- && !isns_policy_validate_entity(policy, name)) +- return 0; +- } +- +- if (tmpl == &isns_iscsi_node_template) { +- if (isns_attr_list_get_string(keys, +- ISNS_TAG_ISCSI_NAME, &name) +- && !isns_policy_validate_node_name(policy, name)) +- return 0; +- } +- +- /* Should we also include the permitted portals +- * in the policy? */ +- +- return __isns_policy_validate_object_access(policy, source, +- NULL, tmpl, function); +-} +- +-/* +- * Check whether the client is permitted to access +- * or create an object of this type. +- * FIXME: Pass R/W permission bit +- */ +-int +-isns_policy_validate_object_type(const isns_policy_t *policy, +- isns_object_template_t *tmpl, +- unsigned int function) +-{ +- uint32_t mask; +- int rv = 0; +- +- /* Control nodes get to do everything */ +- if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK) +- goto accept; +- +- mask = ISNS_ACCESS_R(tmpl->iot_handle); +- if (!(policy->ip_object_types & mask)) +- goto reject; +- +-accept: rv = 1; +- +-reject: +- isns_debug_auth(":: policy %s operation %s on object type %s %s\n", +- policy->ip_name, +- isns_function_name(function), +- tmpl->iot_name, +- rv? "permitted" : "DENIED"); +- return rv; +-} +- +-int +-isns_policy_validate_node_type(const isns_policy_t *policy, uint32_t type) +-{ +- int rv = 0; +- +- if ((~policy->ip_node_types & type) == 0) +- rv = 1; +- +- isns_debug_auth(":: policy %s registration of node type 0x%x %s\n", +- policy->ip_name, type, +- rv? "permitted" : "DENIED"); +- return rv; +-} +- +-/* +- * 6.4.4. +- * Management SCNs provide information about all changes to the network, +- * regardless of discovery domain membership. Registration for management +- * SCNs is indicated by setting bit 26 to 1. Only Control Nodes may +- * register for management SCNs. Bits 30 and 31 may only be enabled if +- * bit 26 is set to 1. +- */ +-int +-isns_policy_validate_scn_bitmap(const isns_policy_t *policy, +- uint32_t bitmap) +-{ +- int rv = 1; +- +- if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK) +- goto accept; +- +- if (!(bitmap & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK)) { +- if (bitmap & (ISNS_SCN_DD_MEMBER_ADDED_MASK | +- ISNS_SCN_DD_MEMBER_REMOVED_MASK)) +- goto reject; +- goto accept; +- } +- +-reject: +- rv = 0; +- +-accept: +- isns_debug_auth(":: policy %s scn bitmap 0x%x %s\n", +- policy->ip_name, bitmap, +- rv? "permitted" : "DENIED"); +- return rv; +-} +- +-/* +- * Create the default policy for a given SPI +- */ +-isns_policy_t * +-isns_policy_default(const char *spi, size_t len) +-{ +- return __isns_policy_alloc(spi, len); +-} +- +-/* +- * Create the policy object for the server we're +- * talking to. The server is allowed to send us +- * ESI and SCN messages, and that's about it. +- */ +-isns_policy_t * +-isns_policy_server(void) +-{ +- isns_policy_t *policy; +- +- policy = __isns_policy_alloc("", 8); +- +- policy->ip_functions = +- (1 << ISNS_ENTITY_STATUS_INQUIRY) | +- (1 << ISNS_STATE_CHANGE_NOTIFICATION); +- policy->ip_node_types = 0; +- policy->ip_object_types = 0; +- isns_string_array_append(&policy->ip_node_names, "*"); +- return policy; +-} +- +-/* +- * Allocate an empty policy object +- */ +-isns_policy_t * +-__isns_policy_alloc(const char *spi, size_t len) +-{ +- isns_policy_t *policy; +- +- policy = isns_calloc(1, sizeof(*policy)); +- policy->ip_name = isns_malloc(len + 1); +- policy->ip_users = 1; +- policy->ip_gen = isns_policy_gen; +- +- memcpy(policy->ip_name, spi, len); +- policy->ip_name[len] = '\0'; +- +- /* Only register/query allowed */ +- policy->ip_functions = +- (1 << ISNS_DEVICE_ATTRIBUTE_REGISTER) | +- (1 << ISNS_DEVICE_ATTRIBUTE_QUERY) | +- (1 << ISNS_DEVICE_GET_NEXT) | +- (1 << ISNS_DEVICE_DEREGISTER) | +- (1 << ISNS_SCN_REGISTER); +- +- /* Can only register initiator node(s) */ +- policy->ip_node_types = +- ISNS_ISCSI_INITIATOR_MASK; +- +- /* Can only view/modify standard objects */ +- policy->ip_object_types = ISNS_DEFAULT_OBJECT_ACCESS; +- +- return policy; +-} +- +-/* +- * Release a policy object +- */ +-void +-isns_policy_release(isns_policy_t *policy) +-{ +- if (!policy) +- return; +- +- isns_assert(policy->ip_users); +- if (--(policy->ip_users)) +- return; +- +- isns_assert(policy != &isns_superhero_powers); +- isns_assert(policy != &isns_flyingpigs_powers); +- isns_assert(policy != &isns_dweeb_powers); +- +- isns_free(policy->ip_name); +- isns_free(policy->ip_entity); +- isns_free(policy->ip_dd_default); +- isns_string_array_destroy(&policy->ip_node_names); +- +- isns_free(policy); +-} +diff --git a/utils/open-isns/portal-group.c b/utils/open-isns/portal-group.c +deleted file mode 100644 +index 647bbde..0000000 +--- a/utils/open-isns/portal-group.c ++++ /dev/null +@@ -1,307 +0,0 @@ +-/* +- * iSNS object model - portal group specific code +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include "isns.h" +-#include "objects.h" +-#include "vendor.h" +-#include "attrs.h" +-#include "util.h" +- +-/* For relationship stuff - should go */ +-#include "db.h" +- +- +-/* +- * Retrieve attribute @old_tag from object @obj, create a copy with +- * tag @new_tag, and append it to list @dst. +- * (Helper function for the portal group stuff) +- */ +-static int +-__isns_object_translate_attr(isns_object_t *obj, +- uint32_t old_tag, uint32_t new_tag, +- isns_attr_list_t *dst) +-{ +- isns_value_t value; +- +- if (!isns_attr_list_get_value(&obj->ie_attrs, old_tag, &value)) +- return 0; +- isns_attr_list_append_value(dst, new_tag, NULL, &value); +- return 1; +-} +- +- +-/* +- * Portal Group +- */ +-static isns_object_t * +-__isns_pg_create(const isns_attr_list_t *attrs, uint32_t pg_tag, +- isns_object_t *portal, isns_object_t *node) +-{ +- isns_object_t *obj; +- +- obj = isns_create_object(&isns_iscsi_pg_template, attrs, +- isns_object_get_entity(portal)); +- +- /* +- * 3.4 +- * +- * Each Portal and iSCSI Storage Node registered in an Entity can +- * be associated using a Portal Group (PG) object. The PG Tag +- * (PGT), if non-NULL, indicates that the associated Portal +- * provides access to the associated iSCSI Storage Node in +- * the Entity. All Portals that have the same PGT value for +- * a specific iSCSI Storage Node allow coordinated access to +- * that node. +- * +- * 5.6.5.2 +- * +- * If the PGT of the Portal Group is not NULL, then a relationship +- * exists between the indicated Storage Node and Portal; if the +- * PGT is NULL, then no relationship exists. +- */ +- if (pg_tag != 0) { +- isns_object_set_uint32(obj, +- ISNS_TAG_PG_TAG, pg_tag); +- } else { +- /* A NULL PGT indicates that the +- * storage node cannot be accessed through +- * this portal. */ +- isns_object_set_nil(obj, ISNS_TAG_PG_TAG); +- } +- +- /* This object represents a relationship between portal +- and storage node. Create a relation. */ +- obj->ie_relation = isns_create_relation(obj, +- ISNS_RELATION_PORTAL_GROUP, +- portal, node); +- +- return obj; +-} +- +-/* +- * Find the portal for a given portal group +- */ +-static isns_object_t * +-__isns_pg_find_portal(isns_db_t *db, isns_object_t *pg, +- const isns_object_list_t *extra_objs) +-{ +- isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; +- isns_object_t *obj = NULL; +- +- /* FIXME: ISNS_TAG_PG_PORTAL_IP_ADDR -> ...ADDRESS */ +- if (!__isns_object_translate_attr(pg, +- ISNS_TAG_PG_PORTAL_IP_ADDR, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- &key_attrs)) +- goto out; +- if (!__isns_object_translate_attr(pg, +- ISNS_TAG_PG_PORTAL_TCP_UDP_PORT, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- &key_attrs)) +- goto out; +- +- obj = isns_db_lookup(db, &isns_portal_template, &key_attrs); +- if (!obj && extra_objs) +- obj = isns_object_list_lookup(extra_objs, +- &isns_portal_template, &key_attrs); +- +-out: +- isns_attr_list_destroy(&key_attrs); +- return obj; +-} +- +-/* +- * Find the node for a given portal group +- */ +-static isns_object_t * +-__isns_pg_find_node(isns_db_t *db, isns_object_t *pg, +- const isns_object_list_t *extra_objs) +-{ +- isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; +- isns_object_t *obj = NULL; +- +- if (!__isns_object_translate_attr(pg, +- ISNS_TAG_PG_ISCSI_NAME, +- ISNS_TAG_ISCSI_NAME, +- &key_attrs)) +- goto out; +- +- obj = isns_db_lookup(db, &isns_iscsi_node_template, &key_attrs); +- if (!obj && extra_objs) +- obj = isns_object_list_lookup(extra_objs, +- &isns_iscsi_node_template, &key_attrs); +- +-out: +- isns_attr_list_destroy(&key_attrs); +- return obj; +-} +- +-/* +- * When creating a portal group, it must not connect nodes and +- * portals from other entities. However, it is perfectly fine to +- * link objects in limbo. +- */ +-static inline int +-__isns_pg_may_relate(isns_object_t *entity, isns_object_t *subordinate) +-{ +- isns_object_t *other; +- +- other = isns_object_get_entity(subordinate); +- return other == NULL || other == entity; +-} +- +-/* +- * Given a portal group object, create the relationship +- */ +-isns_relation_t * +-isns_db_build_pg_relation(isns_db_t *db, isns_object_t *pg, +- const isns_object_list_t *extra_objs) +-{ +- isns_object_t *entity, *node = NULL, *portal = NULL; +- +- entity = isns_object_get_entity(pg); +- +- node = __isns_pg_find_node(db, pg, extra_objs); +- if (node == NULL) { +- isns_error("Trying to register PG for non-existant node\n"); +- goto failed; +- } +- if (!__isns_pg_may_relate(entity, node)) { +- isns_error("Trying to register PG for node in other entity\n"); +- goto failed; +- } +- +- portal = __isns_pg_find_portal(db, pg, extra_objs); +- if (portal == NULL) { +- isns_error("Trying to register PG for non-existant portal\n"); +- goto failed; +- } +- if (!__isns_pg_may_relate(entity, portal)) { +- isns_error("Trying to register PG for portal in other entity\n"); +- goto failed; +- } +- +- pg->ie_relation = isns_create_relation(pg, +- ISNS_RELATION_PORTAL_GROUP, +- node, portal); +- isns_object_release(portal); +- isns_object_release(node); +- +- return pg->ie_relation; +- +-failed: +- if (portal) +- isns_object_release(portal); +- if (node) +- isns_object_release(node); +- return NULL; +-} +- +-/* +- * Create a portal group given node, portal and PGT +- */ +-isns_object_t * +-isns_create_portal_group(isns_object_t *portal, +- isns_object_t *node, uint32_t pg_tag) +-{ +- isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; +- isns_object_t *obj = NULL; +- +- if (portal == NULL || node == NULL) +- return NULL; +- +- if (node->ie_container != portal->ie_container) { +- isns_error("Refusing to create portal group " +- "linking objects from different entities\n"); +- return NULL; +- } +- +- if (__isns_object_translate_attr(node, +- ISNS_TAG_ISCSI_NAME, +- ISNS_TAG_PG_ISCSI_NAME, +- &key_attrs) +- && __isns_object_translate_attr(portal, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PG_PORTAL_IP_ADDR, +- &key_attrs) +- && __isns_object_translate_attr(portal, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- ISNS_TAG_PG_PORTAL_TCP_UDP_PORT, +- &key_attrs)) { +- obj = __isns_pg_create(&key_attrs, pg_tag, portal, node); +- } +- +- isns_attr_list_destroy(&key_attrs); +- return obj; +-} +- +-/* +- * 5.6.5.1 +- * New PG objects are registered when an associated Portal or +- * iSCSI Node object is registered. An explicit PG object +- * registration MAY follow a Portal or iSCSI Node object +- * registration in a DevAttrReg message. +- * [...] +- * If the PGT value is not included in the Storage Node or +- * Portal object registration, and if a PGT value was not +- * previously registered for the relationship, then the PGT for +- * the corresponding PG object SHALL be registered with a value +- * of 0x00000001. +- * +- * We return non-NULL if the object was created. +- */ +-isns_object_t * +-isns_create_default_portal_group(isns_db_t *db, +- isns_object_t *portal, isns_object_t *node) +-{ +- isns_object_t *obj; +- +- if (portal == NULL || node == NULL) +- return 0; +- +- /* See if there is a PG already */ +- obj = isns_db_get_relationship_object(db, node, portal, +- ISNS_RELATION_PORTAL_GROUP); +- if (obj != NULL) { +- isns_object_release(obj); +- return NULL; +- } +- +- return isns_create_portal_group(portal, node, 1); +-} +- +-static uint32_t iscsi_pg_attrs[] = { +- ISNS_TAG_PG_ISCSI_NAME, +- ISNS_TAG_PG_PORTAL_IP_ADDR, +- ISNS_TAG_PG_PORTAL_TCP_UDP_PORT, +- ISNS_TAG_PG_TAG, +- ISNS_TAG_PG_INDEX, +-}; +- +-static uint32_t iscsi_pg_key_attrs[] = { +- ISNS_TAG_PG_ISCSI_NAME, +- ISNS_TAG_PG_PORTAL_IP_ADDR, +- ISNS_TAG_PG_PORTAL_TCP_UDP_PORT, +-}; +- +-isns_object_template_t isns_iscsi_pg_template = { +- .iot_name = "iSCSI Portal Group", +- .iot_handle = ISNS_OBJECT_TYPE_PG, +- .iot_attrs = iscsi_pg_attrs, +- .iot_num_attrs = array_num_elements(iscsi_pg_attrs), +- .iot_keys = iscsi_pg_key_attrs, +- .iot_num_keys = array_num_elements(iscsi_pg_key_attrs), +- .iot_attrs = iscsi_pg_attrs, +- .iot_keys = iscsi_pg_key_attrs, +- .iot_index = ISNS_TAG_PG_INDEX, +- .iot_next_index = ISNS_TAG_PG_NEXT_INDEX, +- .iot_container = &isns_entity_template, +- .iot_relation_type = ISNS_RELATION_PORTAL_GROUP, +- .iot_build_relation = isns_db_build_pg_relation, +-}; +- +diff --git a/utils/open-isns/query.c b/utils/open-isns/query.c +deleted file mode 100644 +index b2cfbc9..0000000 +--- a/utils/open-isns/query.c ++++ /dev/null +@@ -1,238 +0,0 @@ +-/* +- * Handle iSNS Device Attribute Query +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include "isns.h" +-#include "attrs.h" +-#include "message.h" +-#include "security.h" +-#include "objects.h" +-#include "db.h" +-#include "util.h" +- +-/* +- * Create a query, and set the source name +- */ +-static isns_simple_t * +-__isns_create_query(isns_source_t *source, const isns_attr_list_t *key) +-{ +- return isns_simple_create(ISNS_DEVICE_ATTRIBUTE_QUERY, source, key); +-} +- +-isns_simple_t * +-isns_create_query(isns_client_t *clnt, const isns_attr_list_t *key) +-{ +- return __isns_create_query(clnt->ic_source, key); +-} +- +-isns_simple_t * +-isns_create_query2(isns_client_t *clnt, const isns_attr_list_t *key, isns_source_t *source) +-{ +- return __isns_create_query(source?: clnt->ic_source, key); +-} +- +-int +-isns_query_request_attr_tag(isns_simple_t *qry, uint32_t tag) +-{ +- isns_attr_list_append_nil(&qry->is_operating_attrs, tag); +- return ISNS_SUCCESS; +-} +- +-int +-isns_query_request_attr(isns_simple_t *qry, isns_attr_t *attr) +-{ +- if (!ISNS_ATTR_IS_NIL(attr)) { +- isns_error("Query operating attribute must be NIL\n"); +- return ISNS_INVALID_QUERY; +- } +- isns_attr_list_append_attr(&qry->is_operating_attrs, attr); +- return ISNS_SUCCESS; +-} +- +-static unsigned int +-isns_query_get_requested_types(const isns_attr_list_t *attrs) +-{ +- unsigned int i, mask = 0; +- +- for (i = 0; i < attrs->ial_count; ++i) { +- uint32_t tag = attrs->ial_data[i]->ia_tag_id; +- isns_object_template_t *tmpl; +- +- tmpl = isns_object_template_find(tag); +- /* Ignore unknown tags */ +- if (tmpl == NULL) +- continue; +- +- mask |= 1 << tmpl->iot_handle; +- } +- return mask; +-} +- +-/* +- * Get the list of objects matching this query +- */ +-static int +-isns_query_get_objects(isns_simple_t *qry, isns_db_t *db, isns_object_list_t *result) +-{ +- isns_scope_t *scope = NULL; +- isns_object_list_t matching = ISNS_OBJECT_LIST_INIT; +- isns_attr_list_t *keys = &qry->is_message_attrs; +- isns_object_template_t *query_type = NULL; +- unsigned int i, qry_mask = 0; +- int status; +- +- /* 5.6.5.2 +- * If multiple attributes are used as the Message Key, then they +- * MUST all be from the same object type (e.g., IP address and +- * TCP/UDP Port are attributes of the Portal object type). +- */ +- for (i = 0; i < keys->ial_count; ++i) { +- isns_object_template_t *tmpl; +- uint32_t tag = keys->ial_data[i]->ia_tag_id; +- +- tmpl = isns_object_template_for_tag(tag); +- if (tmpl == NULL) +- return ISNS_ATTRIBUTE_NOT_IMPLEMENTED; +- if (query_type == NULL) +- query_type = tmpl; +- else if (tmpl != query_type) +- return ISNS_INVALID_QUERY; +- } +- +- /* +- * 5.6.5.2 +- * An empty Message Key field indicates the query is scoped to +- * the entire database accessible by the source Node. +- */ +- if (keys->ial_count == 0) { +- query_type = &isns_entity_template; +- keys = NULL; +- } +- +- /* Policy: check whether the client is allowed to +- * query this type of object. */ +- if (!isns_policy_validate_object_type(qry->is_policy, +- query_type, qry->is_function)) +- return ISNS_SOURCE_UNAUTHORIZED; +- +- /* No scope means that the source is not part of +- * any discovery domain, and there's no default DD. +- * Just return an empty reply. */ +- scope = isns_scope_for_call(db, qry); +- if (scope == NULL) +- return ISNS_SUCCESS; +- +- status = isns_scope_gang_lookup(scope, query_type, keys, &matching); +- if (status != ISNS_SUCCESS) +- goto out; +- +- /* Extract the mask of requested objects */ +- qry_mask = isns_query_get_requested_types(&qry->is_operating_attrs); +- +- /* +- * 5.6.5.2 +- * The DevAttrQry response message returns attributes of objects +- * listed in the Operating Attributes that are related to the +- * Message Key of the original DevAttrQry message. +- */ +- for (i = 0; i < matching.iol_count; ++i) { +- isns_object_t *obj = matching.iol_data[i]; +- +- if (!isns_policy_validate_object_access(qry->is_policy, +- qry->is_source, obj, +- qry->is_function)) +- continue; +- +- if (obj->ie_container) +- isns_object_list_append(result, obj->ie_container); +- isns_object_list_append(result, obj); +- isns_scope_get_related(scope, obj, qry_mask, result); +- } +- +-out: +- isns_object_list_destroy(&matching); +- isns_scope_release(scope); +- return status; +-} +- +-/* +- * Create a Query Response +- */ +-static isns_simple_t * +-isns_create_query_response(isns_server_t *srv, +- const isns_simple_t *qry, const isns_object_list_t *objects) +-{ +- const isns_attr_list_t *req_attrs = NULL; +- isns_simple_t *resp; +- unsigned int i; +- +- resp = __isns_create_query(srv->is_source, &qry->is_message_attrs); +- +- /* +- * 5.7.5.2. +- * If no Operating Attributes are included in the original +- * query, then all Operating Attributes SHALL be returned +- * in the response. +- */ +- if (qry->is_operating_attrs.ial_count != 0) +- req_attrs = &qry->is_operating_attrs; +- +- for (i = 0; i < objects->iol_count; ++i) { +- isns_object_t *obj = objects->iol_data[i]; +- +- if (obj->ie_rebuild) +- obj->ie_rebuild(obj, srv->is_db); +- isns_object_get_attrlist(obj, +- &resp->is_operating_attrs, +- req_attrs); +- } +- return resp; +-} +- +-int +-isns_process_query(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) +-{ +- isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; +- isns_simple_t *reply = NULL; +- isns_db_t *db = srv->is_db; +- int status; +- +- /* Get the objects matching the query */ +- status = isns_query_get_objects(call, db, &objects); +- if (status != ISNS_SUCCESS) +- goto done; +- +- /* Success: build the response */ +- reply = isns_create_query_response(srv, call, &objects); +- if (reply == NULL) { +- status = ISNS_INTERNAL_ERROR; +- goto done; +- } +- +- /* There's nothing in the spec that tells us what to +- * return if the query matches no object. +- */ +- if (objects.iol_count == 0) { +- status = ISNS_NO_SUCH_ENTRY; +- goto done; +- } +- +-done: +- isns_object_list_destroy(&objects); +- *result = reply; +- return status; +-} +- +-/* +- * Parse the list of objects in a query response +- */ +-int +-isns_query_response_get_objects(isns_simple_t *qry, +- isns_object_list_t *result) +-{ +- return isns_simple_response_get_objects(qry, result); +-} +diff --git a/utils/open-isns/register.c b/utils/open-isns/register.c +deleted file mode 100644 +index 120deae..0000000 +--- a/utils/open-isns/register.c ++++ /dev/null +@@ -1,934 +0,0 @@ +-/* +- * Handle iSNS Device Attribute Registration +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include "isns.h" +-#include "attrs.h" +-#include "objects.h" +-#include "message.h" +-#include "security.h" +-#include "util.h" +-#include "db.h" +- +- +-static int isns_create_default_pgs_for_object(isns_db_t *, isns_object_t *); +- +-/* +- * Create a registration, and set the source name +- */ +-static isns_simple_t * +-__isns_create_registration(isns_source_t *source, isns_object_t *key_obj) +-{ +- isns_simple_t *reg; +- +- reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, source, NULL); +- if (reg == NULL) +- return NULL; +- +- /* +- * When sending a registration, you can either specify +- * the object to be modified in the key attrs, or leave +- * the key empty. +- */ +- if (key_obj == NULL) +- return reg; +- +- /* User gave us a key object. We need to put the key +- * attributes into the message attrs, and *all* attrs +- * into the operating attrs. */ +- if (!isns_object_extract_keys(key_obj, ®->is_message_attrs)) { +- /* bummer - seems the object is missing some +- * vital organs. */ +- isns_warning("%s: object not fully specified, key attrs missing\n", +- __FUNCTION__); +- goto failed; +- } +- +- /* +- * The Message Key identifies the object the DevAttrReg message +- * acts upon. [...] The key attribute(s) identifying this object +- * MUST also be included among the Operating Attributes. +- * +- * We do not enforce this here, we rely on the caller to get this +- * right. +- */ +-#if 0 +- if (!isns_object_extract_all(key_obj, ®->is_operating_attrs)) { +- isns_warning("%s: unable to extract attrs from key objects\n", +- __FUNCTION__); +- goto failed; +- } +-#endif +- +- return reg; +- +-failed: +- isns_simple_free(reg); +- return NULL; +-} +- +-isns_simple_t * +-isns_create_registration(isns_client_t *clnt, isns_object_t *key_obj) +-{ +- return __isns_create_registration(clnt->ic_source, key_obj); +-} +- +-isns_simple_t * +-isns_create_registration2(isns_client_t *clnt, isns_object_t *key_obj, +- isns_source_t *source) +-{ +- return __isns_create_registration(source?: clnt->ic_source, key_obj); +-} +- +-/* +- * Set the replace flag +- */ +-void +-isns_registration_set_replace(isns_simple_t *reg, int replace) +-{ +- reg->is_replace = !!replace; +-} +- +-/* +- * Add an object to the registration +- */ +-void +-isns_registration_add_object(isns_simple_t *reg, isns_object_t *obj) +-{ +- isns_object_extract_writable(obj, ®->is_operating_attrs); +-} +- +-void +-isns_registration_add_object_list(isns_simple_t *reg, isns_object_list_t *list) +-{ +- unsigned int i; +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_extract_writable(list->iol_data[i], +- ®->is_operating_attrs); +- } +-} +- +-/* +- * Get the key object given in this message +- * +- * It doesn't say anywhere explicitly in the RFC, but +- * the message key can contain both key and non-key +- * attributes. For instance, you can search by +- * Portal Group Index (section 3.4). +- */ +-static int +-isns_registration_get_key(isns_simple_t *reg, isns_db_t *db, isns_object_t **key_obj) +-{ +- isns_attr_list_t *keys = ®->is_message_attrs; +- isns_attr_list_t dummy_keys = ISNS_ATTR_LIST_INIT; +- isns_attr_t *attr; +- isns_object_t *obj = NULL; +- const char *eid = NULL; +- char eidbuf[128]; +- int status = ISNS_SUCCESS; +- int obj_must_exist = 0; +- +- /* +- * 5.6.5.1 +- * If the Message Key is not present, then the DevAttrReg message +- * implicitly registers a new Network Entity. In this case, +- * the replace bit SHALL be ignored; a new Network Entity SHALL +- * be created. +- * +- * Note that some clients seem to leave the message key +- * empty, but hide the entity identifier in the operating +- * attrs. +- */ +- if (keys->ial_count != 0) { +- attr = keys->ial_data[0]; +- +- /* +- * 5.6.5.1 +- * If the Message Key does not contain an EID, and no +- * pre-existing objects match the Message Key, then the +- * DevAttrReg message SHALL be rejected with a status +- * code of 3 (Invalid Registration). +- */ +- if (keys->ial_count != 1 +- || attr->ia_tag_id != ISNS_TAG_ENTITY_IDENTIFIER) +- obj_must_exist = 1; +- } else { +- /* Empty message key. But the client may have hidden +- * the EID in the operating attrs :-/ +- */ +- if (reg->is_operating_attrs.ial_count == 0) +- goto create_entity; +- +- attr = reg->is_operating_attrs.ial_data[0]; +- if (attr->ia_tag_id != ISNS_TAG_ENTITY_IDENTIFIER) +- goto create_entity; +- +- isns_attr_list_append_attr(&dummy_keys, attr); +- keys = &dummy_keys; +- } +- +- /* If the caller specifies an EID, extract it while +- * we know what we're doing :-) */ +- if (attr->ia_tag_id == ISNS_TAG_ENTITY_IDENTIFIER +- && ISNS_ATTR_IS_STRING(attr)) +- eid = attr->ia_value.iv_string; +- +- /* Look up the object identified by the keys. +- * We do not scope the lookup, as the client +- * may want to add nodes to an entity that's +- * currently empty - and hence not visible to +- * any DD. */ +- if (!ISNS_ATTR_IS_NIL(attr)) +- obj = isns_db_lookup(db, NULL, keys); +- +- if (obj == NULL && obj_must_exist) +- goto err_invalid; +- +- if (obj != NULL) { +- /* +- * Policy: verify that the client is permitted +- * to access this object. +- * +- * This includes +- * - the client node must be the object owner, +- * or a control node. +- * - the policy must allow modification of +- * this object type. +- */ +- if (!isns_policy_validate_object_access(reg->is_policy, +- reg->is_source, +- obj, reg->is_function)) +- goto err_unauthorized; +- +-found_object: +- if (reg->is_replace) { +- isns_object_t *container = NULL; +- +- if (!ISNS_IS_ENTITY(obj)) { +- container = isns_object_get_entity(obj); +- if (container == NULL) { +- isns_error("Trying to replace %s (id %u) " +- "which has no container\n", +- obj->ie_template->iot_name, +- obj->ie_index); +- goto err_invalid; +- } +- } +- +- isns_debug_state("Replacing %s (id %u)\n", +- obj->ie_template->iot_name, +- obj->ie_index); +- isns_db_remove(db, obj); +- isns_object_release(obj); +- +- /* Purge the deleted objects from the database now */ +- isns_db_purge(db); +- +- /* We need to flush pending SCNs because the +- * objects may be resurrected from limbo, +- * and we might be looking at stale data. */ +- isns_scn_transmit_all(); +- +- /* It's an entity. Nuke it and create +- * a new one. */ +- if (container == NULL) { +- isns_source_set_entity(reg->is_source, NULL); +- goto create_entity; +- } +- +- obj = isns_object_get(container); +- } +- +- goto out; +- } +- +- /* +- * If the Message Key contains an EID and no pre-existing objects +- * match the Message Key, then the DevAttrReg message SHALL create a +- * new Entity with the specified EID and any new object(s) specified +- * by the Operating Attributes. The replace bit SHALL be ignored. +- * +- * Implementer's note: the EID attribute may be empty, in which case +- * we also create a new entity. +- */ +- +-create_entity: +- if (!isns_policy_validate_object_creation(reg->is_policy, +- reg->is_source, +- &isns_entity_template, keys, NULL, +- reg->is_function)) +- goto err_unauthorized; +- +- /* +- * 5.6.5.1 +- * A registration message that creates a new Network Entity object +- * MUST contain at least one Portal or one Storage Node. If the +- * message does not, then it SHALL be considered invalid and result +- * in a response with Status Code of 3 (Invalid Registration). +- */ +- /* FIXME: Implement this check */ +- +- /* We try to play nice with lazy clients and attempt to +- * look up the network entity given the source name. +- * But we don't do this if a non-NULL EID was given, +- * because the client may explicitly want to specify more +- * than one Network Entity. +- */ +- if (eid == NULL) { +- obj = reg->is_source->is_entity; +- if (obj != NULL) { +- isns_object_get(obj); +- goto found_object; +- } +- +- /* The policy may define a default entity name. +- * If that is the case, use it. +- */ +- eid = isns_policy_default_entity(reg->is_policy); +- if (eid) { +- obj = isns_db_vlookup(db, &isns_entity_template, +- ISNS_TAG_ENTITY_IDENTIFIER, eid, +- 0); +- if (obj) { +- reg->is_source->is_entity = isns_object_get(obj); +- goto found_object; +- } +- } +- } +- +- /* +- * 5.6.5.1 +- * If the Message Key and Operating Attributes do not contain +- * an EID attribute, or if the EID attribute has a length of 0, +- * then a new Network Entity object SHALL be created and the iSNS +- * server SHALL supply a unique EID value for it. +- */ +- if (eid == NULL) +- eid = isns_db_generate_eid(db, eidbuf, sizeof(eidbuf)); +- +- /* +- * 6.2.2. Entity Protocol +- * +- * This attribute is required during initial registration of +- * the Network Entity. +- * +- * Implementer's note: we don't rely on this. Instead, the +- * Entity Protocol is selected based on the source type. +- * If the client specifies the protocol, the auto-selected +- * value is overwritten. +- */ +- obj = isns_create_entity_for_source(reg->is_source, eid); +- if (obj == NULL) +- goto err_invalid; +- +- isns_source_set_entity(reg->is_source, obj); +- +- /* +- * 6.2.6 +- * If a Registration Period is not requested by the iSNS +- * client and Entity Status Inquiry (ESI) messages are not +- * enabled for that client, then the Registration Period +- * SHALL be set to a non-zero value by the iSNS server. +- * This implementation-specific value for the Registration +- * Period SHALL be returned in the registration response to the +- * iSNS client. The Registration Period may be set to zero, +- * indicating its non-use, only if ESI messages are enabled for +- * that Network Entity. +- * +- * Implementer's note: we diverge from this in two ways: +- * - the admin may choose to disable registration timeout, +- * by setting RegistrationPeriod=0 in the config file +- * +- * - When a new entity is created, we always set the +- * registration interval because we cannot know yet +- * whether the client will subsequently enable ESI or +- * not. +- * +- * - The control entity (holding policy objects) will +- * not expire. +- */ +- if (isns_config.ic_registration_period +- && strcasecmp(eid, ISNS_ENTITY_CONTROL)) { +- isns_object_set_uint32(obj, +- ISNS_TAG_REGISTRATION_PERIOD, +- isns_config.ic_registration_period); +- isns_object_set_uint64(obj, +- ISNS_TAG_TIMESTAMP, +- time(NULL)); +- } +- +- /* Insert into database, and set the object's owner */ +- isns_db_insert(db, obj); +- +- reg->is_replace = 0; +- +-out: +- *key_obj = obj; +- isns_attr_list_destroy(&dummy_keys); +- return ISNS_SUCCESS; +- +-error: +- if (obj) +- isns_object_release(obj); +- isns_attr_list_destroy(&dummy_keys); +- return status; +- +-err_unauthorized: +- status = ISNS_SOURCE_UNAUTHORIZED; +- goto error; +- +-err_invalid: +- status = ISNS_INVALID_REGISTRATION; +- goto error; +-} +- +-static int +-isns_registration_get_next_object(isns_db_t *db, +- struct isns_attr_list_scanner *st, +- isns_object_list_t *result) +-{ +- isns_object_t *current; +- int status, esi = 0; +- +- status = isns_attr_list_scanner_next(st); +- /* We get here if the registration has a trailing PGT */ +- if (status == ISNS_NO_SUCH_ENTRY) +- return ISNS_SUCCESS; +- if (status) +- return status; +- +- /* +- * Validate the attrlist. +- * This makes sure the client does not include +- * duplicate attributes, readonly attributes +- * such as Registration Timestamp, Index and Next Index, +- * or privileged data (such as marking a storage node as +- * control node). +- */ +- status = isns_attr_list_validate(&st->attrs, +- st->policy, +- ISNS_DEVICE_ATTRIBUTE_REGISTER); +- if (status) { +- isns_debug_protocol("invalid attr in message\n"); +- return status; +- } +- +- /* +- * 6.3.4. Entity Status Inquiry Interval +- * +- * If the iSNS server is unable to support ESI messages +- * or the ESI Interval requested, it SHALL [...] reject +- * the ESI request by returning an "ESI Not Available" +- * Status Code [...] +- * +- * Implementer's note: In section 5.7.5.1, the RFC talks +- * about modifying the requested ESI interval; so it seems +- * it's okay to be liberal about the ESI intervals we accept, +- * and update them quietly. +- */ +- if (isns_attr_list_contains(&st->attrs, ISNS_TAG_ESI_PORT)) { +- if (!isns_esi_enabled) { +- isns_debug_esi("Refusing to accept portal " +- "registration with ESI port\n"); +- return ISNS_ESI_NOT_AVAILABLE; +- } +- esi = 1; +- } +- +- /* +- * Override any registration period specified by the client. +- */ +- if (isns_attr_list_contains(&st->attrs, ISNS_TAG_REGISTRATION_PERIOD)) { +- isns_value_t value = ISNS_VALUE_INIT(uint32, +- isns_config.ic_registration_period); +- +- isns_attr_list_update_value(&st->attrs, +- ISNS_TAG_REGISTRATION_PERIOD, NULL, +- &value); +- } +- +- if (st->tmpl == &isns_entity_template) { +- /* +- * 5.6.5.1. +- * A maximum of one Network Entity object can be +- * created or updated with a single DevAttrReg +- * message. Consequently, the Operating Attributes +- * MUST NOT contain more than one Network Entity +- * object. +- */ +- if (st->entities++) { +- isns_debug_protocol("More than one entity in DevAttrReg msg\n"); +- return ISNS_INVALID_REGISTRATION; +- } +- +- /* This should be the key object. +- * The EID specified by by the client may be +- * empty, so don't overwrite the value we +- * assigned with something else. +- */ +- if (!isns_object_match(st->key_obj, &st->keys)) { +- isns_debug_protocol("Entity mismatch in message vs. operating attrs\n"); +- return ISNS_INVALID_REGISTRATION; +- } +- current = isns_object_get(st->key_obj); +- } else +- if (st->tmpl == &isns_dd_template || st->tmpl == &isns_ddset_template) { +- isns_debug_protocol("DevAttrReg of type %s not allowed\n", +- st->tmpl->iot_name); +- return ISNS_INVALID_REGISTRATION; +- } else { +- /* This will also catch objects in limbo. */ +- current = isns_db_lookup(db, st->tmpl, &st->keys); +- } +- +- if (current != NULL) { +- /* +- * If the replace bit is not set, then the message updates +- * the attributes of the object identified by the Message Key +- * and its subordinate objects. Existing object containment +- * relationships MUST NOT be changed. For existing objects, +- * key attributes MUST NOT be modified, but new subordinate +- * objects MAY be added. +- */ +- +- /* +- * [...] +- * If the Node identified by the Source Attribute is +- * not a Control Node, then the objects in the operating +- * attributes MUST be members of the same Network Entity +- * as the Source Node. +- */ +- if (!isns_policy_validate_object_update(st->policy, +- st->source, current, &st->attrs, +- ISNS_DEVICE_ATTRIBUTE_REGISTER)) { +- isns_object_release(current); +- return ISNS_SOURCE_UNAUTHORIZED; +- } +- +- /* We shouldn't allow messages affecting one Entity +- * to modify objects owned by a different Entity. +- * +- * However, there may be orphan objects (created +- * while populating discovery domains). These will +- * not be associated with any Network Entity, so +- * they're up for grabs. +- */ +- if (st->key_obj == current +- || st->key_obj == current->ie_container) { +- /* All is well. The current object is the +- * key object itself, or a direct descendant of the +- * key object. */ +- /* FIXME: with FC we can get deeper nesting; +- * this needs work. */ +- } else +- if (!isns_object_is_valid_container(st->key_obj, st->tmpl)) { +- isns_error("Client attempts to add %s object to a %s - tsk tsk.\n", +- st->tmpl->iot_name, +- st->key_obj->ie_template->iot_name); +- goto invalid_registration; +- } else if (current->ie_container) { +- /* We shouldn't get here in authenticated mode, +- * but in insecure mode we still may. */ +- isns_error("Client attempts to move %s %u to a different %s\n", +- current->ie_template->iot_name, +- current->ie_index, +- st->key_obj->ie_template->iot_name); +- goto invalid_registration; +- } +- } else { +- if (!isns_object_is_valid_container(st->key_obj, st->tmpl)) { +- isns_error("Client attempts to add %s object to a %s - tsk tsk.\n", +- st->tmpl->iot_name, +- st->key_obj->ie_template->iot_name); +- goto invalid_registration; +- } +- +- if (!isns_policy_validate_object_creation(st->policy, +- st->source, st->tmpl, +- &st->keys, &st->attrs, +- ISNS_DEVICE_ATTRIBUTE_REGISTER)) { +- return ISNS_SOURCE_UNAUTHORIZED; +- } +- current = isns_create_object(st->tmpl, &st->keys, +- isns_object_get_entity(st->key_obj)); +- +- /* We do not insert the new object into the database yet. +- * That happens after we're done with parsing *all* +- * objects. */ +- } +- +- if (!isns_object_set_attrlist(current, &st->attrs)) { +- isns_debug_state("Error updating object's attrlist\n"); +- isns_object_release(current); +- return ISNS_INTERNAL_ERROR; +- } +- +- /* If the client specifies an ESI port, make sure the +- * ESI interval is set and within bounds. */ +- if (esi) { +- uint32_t esi_interval; +- +- if (!isns_object_get_uint32(current, +- ISNS_TAG_ESI_INTERVAL, &esi_interval)) { +- esi_interval = isns_config.ic_esi_min_interval; +- } else +- if (esi_interval < isns_config.ic_esi_min_interval) { +- esi_interval = isns_config.ic_esi_min_interval; +- } else +- if (esi_interval > isns_config.ic_esi_max_interval) { +- esi_interval = isns_config.ic_esi_max_interval; +- } else { +- esi_interval = 0; +- } +- +- if (esi_interval) +- isns_object_set_uint32(current, +- ISNS_TAG_ESI_INTERVAL, esi_interval); +- } +- +- /* Append it to the result list. +- * We do not return the key object, otherwise +- * we end up putting it into the response twice. +- */ +- if (current != st->key_obj) +- isns_object_list_append(result, current); +- +- /* +- * When a Portal is registered, the Portal attributes MAY immediately be +- * followed by a PGT attribute. +- * [...] +- * When an iSCSI Storage Node is registered, the Storage Node attributes +- * MAY immediately be followed by a PGT attribute. +- */ +- if (st->tmpl == &isns_portal_template +- || st->tmpl == &isns_iscsi_node_template) { +- st->pgt_next_attr = ISNS_TAG_PG_TAG; +- st->pgt_base_object = current; +- } else if (st->tmpl != &isns_iscsi_pg_template) { +- st->pgt_next_attr = 0; +- st->pgt_base_object = NULL; +- } +- +- isns_object_release(current); +- return ISNS_SUCCESS; +- +-invalid_registration: +- if (current) +- isns_object_release(current); +- return ISNS_INVALID_REGISTRATION; +-} +- +-/* +- * Extract the list of objects to be registered from +- * the list of operating attributes. +- */ +-static int +-isns_registration_get_objects(isns_simple_t *reg, isns_db_t *db, +- isns_object_t *key_obj, +- isns_object_list_t *result) +-{ +- struct isns_attr_list_scanner state; +- int status = ISNS_SUCCESS; +- +- isns_attr_list_scanner_init(&state, key_obj, ®->is_operating_attrs); +- state.source = reg->is_source; +- state.policy = reg->is_policy; +- +- /* +- * 5.6.4. +- * The ordering of Operating Attributes in the message is +- * important for determining the relationships among objects +- * and their ownership of non-key attributes. iSNS protocol +- * messages that violate these ordering rules SHALL be rejected +- * with the Status Code of 2 (Message Format Error). +- */ +- /* FIXME: Implement this check */ +- +- while (state.pos < state.orig_attrs.ial_count) { +- status = isns_registration_get_next_object(db, +- &state, result); +- +- if (status) +- break; +- } +- +- isns_attr_list_scanner_destroy(&state); +- return status; +-} +- +-/* +- * 5.6.5.1 +- * New PG objects are registered when an associated Portal or +- * iSCSI Node object is registered. An explicit PG object +- * registration MAY follow a Portal or iSCSI Node object +- * registration in a DevAttrReg message. +- * [...] +- * If the PGT value is not included in the Storage Node or +- * Portal object registration, and if a PGT value was not +- * previously registered for the relationship, then the PGT for +- * the corresponding PG object SHALL be registered with a value +- * of 0x00000001. +- */ +-static int +-isns_create_registration_pgs(isns_db_t *db, +- const isns_object_list_t *list) +-{ +- unsigned int i, num_created = 0; +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- +- if (ISNS_IS_ISCSI_NODE(obj) || ISNS_IS_PORTAL(obj)) +- num_created += isns_create_default_pgs_for_object(db, obj); +- } +- return num_created; +-} +- +-static int +-isns_create_default_pgs_for_object(isns_db_t *db, isns_object_t *this) +-{ +- isns_object_template_t *match_tmpl; +- isns_object_t *entity; +- unsigned int i, num_created = 0; +- +- if (ISNS_IS_ISCSI_NODE(this)) +- match_tmpl = &isns_portal_template; +- else +- match_tmpl = &isns_iscsi_node_template; +- +- entity = isns_object_get_entity(this); +- for (i = 0; i < entity->ie_children.iol_count; ++i) { +- isns_object_t *that = entity->ie_children.iol_data[i], *pg; +- +- if (that->ie_template != match_tmpl) +- continue; +- +- /* Create the portal group if it does not +- * exist. +- * Note: we do not return these implicitly +- * created portal groups - that's a matter +- * of sheer laziness. We would have to +- * splice these into the list in the +- * appropriate location, and I guess it's +- * not really worth the hassle. +- */ +- if (ISNS_IS_ISCSI_NODE(this)) +- pg = isns_create_default_portal_group(db, that, this); +- else +- pg = isns_create_default_portal_group(db, this, that); +- +- /* There already is a PG linking these two +- * objects. */ +- if (pg == NULL) +- continue; +- +- isns_db_insert(db, pg); +- +- isns_debug_message("--Created default PG:--\n"); +- isns_object_print(pg, isns_debug_message); +- +- isns_object_release(pg); +- num_created++; +- } +- +- return num_created; +-} +- +-/* +- * Commit all changes to the DB +- */ +-static int +-isns_commit_registration(isns_db_t *db, isns_object_t *key_obj, isns_object_list_t *list) +-{ +- unsigned int i; +- +- /* +- * If there are any Portal Groups in this registration, build +- * the relationship handle: +- * +- * 3.4 +- * A new PG object can only be registered by referencing +- * its associated iSCSI Storage Node or Portal object. +- * A pre-existing PG object can be modified or queried +- * by using its Portal Group Index as message key, or +- * by referencing its associated iSCSI Storage Node or +- * Portal object. +- * +- * Implementation note: isns_db_create_pg_relation +- * checks whether the referenced node and portal exist, +- * and belong to the same entity as the PG. If this is +- * not the case, NULL is returned, and no relation is +- * defined. +- */ +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- isns_object_template_t *tmpl; +- +- tmpl = obj->ie_template; +- if (tmpl->iot_build_relation && !obj->ie_relation +- && !tmpl->iot_build_relation(db, obj, list)) { +- isns_debug_protocol("Unable to build relation for new %s\n", +- tmpl->iot_name); +- return ISNS_INVALID_REGISTRATION; +- } +- } +- +- for (i = 0; i < list->iol_count; ++i) { +- isns_object_t *obj = list->iol_data[i]; +- isns_object_template_t *tmpl; +- +- tmpl = obj->ie_template; +- if (key_obj != obj && !obj->ie_container) { +- if (!isns_object_attach(obj, key_obj)) { +- /* This should not fail any longer */ +- isns_debug_protocol("Unable to attach %s %u to %s\n", +- tmpl->iot_name, obj->ie_index, +- key_obj->ie_template->iot_name); +- return ISNS_INVALID_REGISTRATION; +- } +- } +- +- if (obj->ie_state != ISNS_OBJECT_STATE_MATURE) +- isns_db_insert(db, obj); +- } +- +- return ISNS_SUCCESS; +-} +- +-/* +- * Process a registration +- */ +-int +-isns_process_registration(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) +-{ +- isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; +- isns_simple_t *reply = NULL; +- isns_object_t *key_obj = NULL; +- isns_db_t *db = srv->is_db; +- int status; +- unsigned int i; +- +- /* +- * 5.6.1 +- * For messages that change the contents of the iSNS database, +- * the iSNS server MUST verify that the Source Attribute +- * identifies either a Control Node or a Storage Node that is +- * a part of the Network Entity containing the added, deleted, +- * or modified objects. +- * +- * This check happens in isns_registration_get_key by calling +- * isns_policy_validate_object_access. +- */ +- +- /* Get the key object (usually a Network Entity) */ +- status = isns_registration_get_key(call, db, &key_obj); +- if (status) +- goto done; +- +- /* Get the objects to register */ +- status = isns_registration_get_objects(call, db, key_obj, &objects); +- if (status != ISNS_SUCCESS) +- goto done; +- +- /* We parsed the request alright; all semantic checks passed. +- * Now insert the modified/new objects. +- * We do this in two passes, by first committing all nodes and +- * portals, and then committing the portal groups. +- */ +- status = isns_commit_registration(db, key_obj, &objects); +- if (status != ISNS_SUCCESS) +- goto done; +- +- /* The client may have registered a bunch of storage nodes, +- * and created an entity in the process. However, there's the +- * odd chance that the source node name it used was not +- * registered. However, we need to be able to later find +- * the entity it registered based on its source name. +- * So we implicitly create a dummy storage node with the given +- * source name and attach it. +- */ +-#if 1 +- if (ISNS_IS_ENTITY(key_obj) +- && !isns_source_set_node(call->is_source, db)) { +- isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; +- isns_source_t *source = call->is_source; +- isns_object_t *obj; +- +- isns_attr_list_append_attr(&attrs, isns_source_attr(source)); +- isns_attr_list_append_uint32(&attrs, +- ISNS_TAG_ISCSI_NODE_TYPE, +- 0); +- obj = isns_create_object(&isns_iscsi_node_template, +- &attrs, key_obj); +- if (obj) { +- isns_db_insert(db, obj); +- } else { +- isns_warning("Unable to create dummy storage node " +- "for source %s\n", +- isns_source_name(source)); +- } +- isns_attr_list_destroy(&attrs); +- } +-#endif +- +- /* +- * 5.6.5.1 +- * New PG objects are registered when an associated Portal or +- * iSCSI Node object is registered. An explicit PG object +- * registration MAY follow a Portal or iSCSI Node object +- * registration in a DevAttrReg message. +- * [...] +- * If the PGT value is not included in the Storage Node or +- * Portal object registration, and if a PGT value was not +- * previously registered for the relationship, then the PGT for +- * the corresponding PG object SHALL be registered with a value +- * of 0x00000001. +- */ +- isns_create_registration_pgs(db, &objects); +- +- /* Success: create a new registration message, and +- * send it in our reply. */ +- reply = __isns_create_registration(srv->is_source, key_obj); +- if (reply == NULL) { +- status = ISNS_INTERNAL_ERROR; +- goto done; +- } +- +- /* If the key object was modified (or created) +- * include it in the response. +- * We really ought to restrict ourselves to the +- * key attrs plus those that were modified by this +- * registration. But right now have no way of +- * finding out. +- */ +- if (key_obj->ie_flags & ISNS_OBJECT_DIRTY) +- isns_registration_add_object(reply, key_obj); +- +- for (i = 0; i < objects.iol_count; ++i) { +- isns_registration_add_object(reply, +- objects.iol_data[i]); +- } +- +- +-done: +- isns_object_list_destroy(&objects); +- isns_object_release(key_obj); +- *result = reply; +- return status; +-} +- +-/* +- * Extract the list of objects from the DevAttrReg response +- */ +-int +-isns_registration_response_get_objects(isns_simple_t *reg, +- isns_object_list_t *result) +-{ +- return isns_simple_response_get_objects(reg, result); +-} +diff --git a/utils/open-isns/relation.c b/utils/open-isns/relation.c +deleted file mode 100644 +index caac38b..0000000 +--- a/utils/open-isns/relation.c ++++ /dev/null +@@ -1,281 +0,0 @@ +-/* +- * iSNS object relationships +- * +- * Relations are used to express a connection between two +- * objects. Currently, two relationship types are implemented: +- * +- * - portal group: this relates a storage node and a portal +- * - visibility: this relates a nodes nodes that share a +- * common discovery domain. +- * +- * Relation objects are nice for portals groups, but kind of +- * awkward for DDs. A better way of expressing DD membership +- * (which also allows for a fast visibility check) could be +- * to store a [bit] vector of DD IDs in each storage node. +- * A visibility check would amount to just doing the bitwise +- * AND of two vectors, and checking for NULL. The only thing +- * to take care of would be to make sure a DD object takes a +- * reference on its members (this is necessary so that objects +- * maintain their ID/name associations even when removed from +- * the database). +- * +- * Aug 22 2007 - changed DD code to use bit vectors. A lot +- * of code in this file is now obsolete. +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +- +-#include "isns.h" +-#include "objects.h" +-#include "util.h" +-#include "db.h" +- +-struct isns_relation_soup { +- /* For now, use one plain list. For better +- * scalability, we'll need a hash table or +- * something similar later. */ +- isns_relation_list_t irs_data; +-}; +- +-static void isns_relation_list_append(isns_relation_list_t *, +- isns_relation_t *); +-static int isns_relation_list_remove(isns_relation_list_t *, +- isns_relation_t *); +- +-isns_relation_soup_t * +-isns_relation_soup_alloc(void) +-{ +- return isns_calloc(1, sizeof(isns_relation_soup_t)); +-} +- +-void +-isns_relation_add(isns_relation_soup_t *soup, +- isns_relation_t *rp) +-{ +- isns_relation_list_append(&soup->irs_data, rp); +-} +- +-isns_relation_t * +-isns_relation_find_edge(isns_relation_soup_t *soup, +- const isns_object_t *left, +- const isns_object_t *right, +- unsigned int relation_type) +-{ +- isns_relation_list_t *list = &soup->irs_data; +- unsigned int i; +- +- for (i = 0; i < list->irl_count; ++i) { +- isns_relation_t *rp = list->irl_data[i]; +- +- if (rp->ir_type != relation_type) +- continue; +- if (rp->ir_subordinate[0].obj == left +- && rp->ir_subordinate[1].obj == right) +- return rp; +- if (rp->ir_subordinate[0].obj == right +- && rp->ir_subordinate[1].obj == left) +- return rp; +- } +- return NULL; +-} +- +-void +-isns_relation_get_edge_objects(isns_relation_soup_t *soup, +- const isns_object_t *left, +- unsigned int relation_type, +- isns_object_list_t *result) +-{ +- isns_relation_list_t *list = &soup->irs_data; +- unsigned int i; +- +- for (i = 0; i < list->irl_count; ++i) { +- isns_relation_t *rp = list->irl_data[i]; +- +- if (rp->ir_type != relation_type) +- continue; +- if (rp->ir_object == NULL) +- continue; +- if (rp->ir_subordinate[0].obj == left +- || rp->ir_subordinate[1].obj == left) { +- isns_object_list_append(result, +- rp->ir_object); +- } +- } +-} +- +- +- +-void +-isns_relation_halfspace(isns_relation_soup_t *soup, +- const isns_object_t *left, +- unsigned int relation_type, +- isns_object_list_t *result) +-{ +- isns_relation_list_t *list = &soup->irs_data; +- unsigned int i; +- +- for (i = 0; i < list->irl_count; ++i) { +- isns_relation_t *rp = list->irl_data[i]; +- +- if (rp->ir_type != relation_type) +- continue; +- if (rp->ir_subordinate[0].obj == left) { +- isns_object_list_append(result, +- rp->ir_subordinate[1].obj); +- } else +- if (rp->ir_subordinate[1].obj == left) { +- isns_object_list_append(result, +- rp->ir_subordinate[0].obj); +- } +- } +-} +- +-int +-isns_relation_exists(isns_relation_soup_t *soup, +- const isns_object_t *relating_object, +- const isns_object_t *left, +- const isns_object_t *right, +- unsigned int relation_type) +-{ +- isns_relation_list_t *list = &soup->irs_data; +- unsigned int i; +- +- for (i = 0; i < list->irl_count; ++i) { +- isns_relation_t *rp = list->irl_data[i]; +- +- if (rp->ir_type != relation_type) +- continue; +- if (rp->ir_object != relating_object) +- continue; +- if (rp->ir_subordinate[0].obj == left +- && rp->ir_subordinate[1].obj == right) +- return 1; +- if (rp->ir_subordinate[0].obj == right +- && rp->ir_subordinate[1].obj == left) +- return 1; +- } +- return 0; +-} +- +-isns_object_t * +-isns_relation_get_other(const isns_relation_t *rp, +- const isns_object_t *this) +-{ +- if (rp->ir_subordinate[0].obj == this) +- return rp->ir_subordinate[1].obj; +- if (rp->ir_subordinate[1].obj == this) +- return rp->ir_subordinate[0].obj; +- return NULL; +-} +- +-void +-isns_relation_remove(isns_relation_soup_t *soup, +- isns_relation_t *rp) +-{ +- isns_object_release(rp->ir_object); +- rp->ir_object = NULL; +- +- isns_relation_list_remove(&soup->irs_data, rp); +-} +- +-isns_relation_t * +-isns_create_relation(isns_object_t *relating_object, +- unsigned int relation_type, +- isns_object_t *subordinate_object1, +- isns_object_t *subordinate_object2) +-{ +- isns_relation_t *rp; +- +- rp = isns_calloc(1, sizeof(*rp)); +- rp->ir_type = relation_type; +- rp->ir_users = 1; +- rp->ir_object = isns_object_get(relating_object); +- isns_object_reference_set(&rp->ir_subordinate[0], subordinate_object1); +- isns_object_reference_set(&rp->ir_subordinate[1], subordinate_object2); +- +-#if 0 +- if (relating_object) { +- relating_object->ie_relation = rp; +- rp->ir_users++; +- } +-#endif +- +- return rp; +-} +- +-void +-isns_relation_sever(isns_relation_t *rp) +-{ +- isns_object_release(rp->ir_object); +- rp->ir_object = NULL; +- +- isns_object_reference_drop(&rp->ir_subordinate[0]); +- isns_object_reference_drop(&rp->ir_subordinate[1]); +-} +- +-void +-isns_relation_release(isns_relation_t *rp) +-{ +- if (--(rp->ir_users)) +- return; +- +- isns_relation_sever(rp); +- isns_free(rp); +-} +- +-/* +- * Check whether the relation references two dead/limbo objects. +- * This is used for dead PG removal. +- */ +-int +-isns_relation_is_dead(const isns_relation_t *rel) +-{ +- isns_object_t *left, *right; +- +- left = rel->ir_subordinate[0].obj; +- right = rel->ir_subordinate[1].obj; +- if ((left->ie_flags & ISNS_OBJECT_DEAD) +- && (right->ie_flags & ISNS_OBJECT_DEAD)) +- return 1; +- +- return 0; +-} +- +-void +-isns_relation_list_append(isns_relation_list_t *list, +- isns_relation_t *rp) +-{ +- if ((list->irl_count % 128) == 0) { +- list->irl_data = isns_realloc(list->irl_data, +- (list->irl_count + 128) * sizeof(void *)); +- if (list->irl_data == NULL) +- isns_fatal("out of memory!\n"); +- } +- +- list->irl_data[list->irl_count++] = rp; +- rp->ir_users++; +-} +- +-int +-isns_relation_list_remove(isns_relation_list_t *list, +- isns_relation_t *rp) +-{ +- unsigned int i, count = list->irl_count; +- +- for (i = 0; i < count; ++i) { +- if (list->irl_data[i] != rp) +- continue; +- if (i < count - 1) +- list->irl_data[i] = list->irl_data[count-1]; +- isns_relation_release(rp); +- list->irl_count -= 1; +- return 1; +- } +- +- return 0; +-} +diff --git a/utils/open-isns/scn.c b/utils/open-isns/scn.c +deleted file mode 100644 +index 51fcba3..0000000 +--- a/utils/open-isns/scn.c ++++ /dev/null +@@ -1,926 +0,0 @@ +-/* +- * Handle SCN registration/deregistration/events +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include "isns.h" +-#include "attrs.h" +-#include "objects.h" +-#include "message.h" +-#include "security.h" +-#include "util.h" +-#include "db.h" +- +-typedef struct isns_scn isns_scn_t; +-typedef struct isns_scn_funnel isns_scn_funnel_t; +- +-struct isns_scn { +- isns_scn_t * scn_next; +- char * scn_name; +- isns_object_t * scn_entity; +- isns_object_t * scn_owner; +- isns_attr_t * scn_attr; +- +- isns_simple_t * scn_message; +- isns_simple_t * scn_pending; +- unsigned int scn_retries; +- time_t scn_timeout; +- uint16_t scn_xid; +- +- time_t scn_last_update; +- isns_scn_funnel_t * scn_current_funnel; +- isns_scn_funnel_t * scn_funnels; +-}; +- +-struct isns_scn_funnel { +- isns_scn_funnel_t * scn_next; +- isns_portal_info_t scn_portal; +- isns_socket_t * scn_socket; +- unsigned int scn_bad; +-}; +- +-static isns_server_t * isns_scn_server = NULL; +-static isns_scn_t * isns_scn_list; +- +-static isns_scn_t * isns_scn_create_scn(isns_object_t *, uint32_t, isns_db_t *); +-static void isns_scn_delete_scn(isns_object_t *); +-static isns_scn_t * isns_scn_setup(isns_scn_t *, isns_object_t *); +-static void isns_scn_callback(const isns_db_event_t *, void *); +-static void isns_scn_free(isns_scn_t *); +- +-/* +- * Initialize SCN machinery +- */ +-void +-isns_scn_init(isns_server_t *srv) +-{ +- isns_db_t *db = srv->is_db; +- isns_object_list_t nodes = ISNS_OBJECT_LIST_INIT; +- isns_scn_t **tail; +- unsigned int i; +- +- isns_scn_server = srv; +- isns_register_callback(isns_scn_callback, db); +- +- /* Recover SCN state. */ +- isns_db_gang_lookup(db, &isns_iscsi_node_template, NULL, &nodes); +-#ifdef notyet +- isns_db_gang_lookup(db, &isns_fc_node_template, NULL, &nodes); +-#endif +- +- tail = &isns_scn_list; +- for (i = 0; i < nodes.iol_count; ++i) { +- isns_object_t *node = nodes.iol_data[i]; +- isns_scn_t *scn; +- +- if (!node->ie_scn_mask) +- continue; +- +- isns_debug_state("Recovering SCN state for %s %u\n", +- node->ie_template->iot_name, +- node->ie_index); +- scn = isns_scn_setup(NULL, node); +- if (scn) { +- *tail = scn; +- tail = &scn->scn_next; +- } +- } +-} +- +-/* +- * Support for SCNRegister calls +- */ +-isns_simple_t * +-isns_create_scn_registration2(isns_client_t *clnt, unsigned int bitmap, isns_source_t *source) +-{ +- isns_simple_t *call; +- +- if (!source) +- source = clnt->ic_source; +- call = isns_simple_create(ISNS_SCN_REGISTER, source, NULL); +- if (call) { +- isns_attr_list_append_attr(&call->is_message_attrs, +- isns_source_attr(source)); +- isns_attr_list_append_uint32(&call->is_operating_attrs, +- ISNS_TAG_ISCSI_SCN_BITMAP, +- bitmap); +- } +- return call; +-} +- +-isns_simple_t * +-isns_create_scn_registration(isns_client_t *clnt, unsigned int bitmap) +-{ +- return isns_create_scn_registration2(clnt, bitmap, clnt->ic_source); +-} +- +-/* +- * Create an SCN +- */ +-isns_simple_t * +-isns_create_scn(isns_source_t *source, isns_attr_t *nodeattr, isns_attr_t *tsattr) +-{ +- isns_simple_t *call; +- +- call = isns_simple_create(ISNS_STATE_CHANGE_NOTIFICATION, source, NULL); +- if (call && nodeattr) +- isns_attr_list_append_attr(&call->is_message_attrs, nodeattr); +- if (call && tsattr) +- isns_attr_list_append_attr(&call->is_message_attrs, tsattr); +- return call; +-} +- +-static void +-isns_scn_add_event(isns_simple_t *call, uint32_t scn_bits, +- const isns_object_t *obj, +- const isns_object_t *dd) +-{ +- isns_attr_list_t *attrs = &call->is_message_attrs; +- +- isns_attr_list_append_uint32(attrs, +- ISNS_TAG_ISCSI_SCN_BITMAP, +- scn_bits); +- isns_object_extract_keys(obj, attrs); +- if (dd) +- isns_object_extract_keys(dd, attrs); +-} +- +-/* +- * Process a SCN registration +- */ +-int +-isns_process_scn_register(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) +-{ +- isns_attr_list_t *keys = &call->is_message_attrs; +- isns_attr_list_t *attrs = &call->is_operating_attrs; +- isns_db_t *db = srv->is_db; +- isns_attr_t *attr; +- isns_object_t *node = NULL; +- uint32_t scn_bitmap; +- isns_scn_t *scn; +- int status = ISNS_SUCCESS; +- +- /* +- * 5.6.5.5 +- * The SCNReg request PDU Payload contains a Source Attribute, a Message +- * Key Attribute, and an Operating Attribute. Valid Message Key +- * Attributes for a SCNReg are shown below: +- * +- * Valid Message Key Attributes for SCNReg +- * --------------------------------------- +- * iSCSI Name +- * FC Port Name WWPN +- */ +- if (keys->ial_count != 1 || attrs->ial_count != 1) +- return ISNS_SCN_REGISTRATION_REJECTED; +- +- attr = keys->ial_data[0]; +- if (attr->ia_tag_id != ISNS_TAG_ISCSI_NAME && +- attr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN) +- return ISNS_SCN_REGISTRATION_REJECTED; +- +- /* Look up the storage node for this source. If it does +- * not exist, reject the message. */ +- node = isns_db_lookup(db, NULL, keys); +- if (node == NULL) +- return ISNS_SOURCE_UNKNOWN; +- +- /* +- * Policy: verify that the client is permitted +- * to access this entity. +- * +- * This includes +- * - the client node must be the object owner, +- * or a control node. +- * - the policy must allow monitoring of +- * this object type. +- */ +- if (!isns_policy_validate_object_access(call->is_policy, +- call->is_source, +- node, call->is_function)) +- goto unauthorized; +- +- /* +- * 5.6.5.5 +- * The SCN Bitmap is the only operating attribute of this message +- * [...] +- * Control Nodes MAY conduct registrations for management SCNs; +- * iSNS clients that are not supporting Control Nodes MUST NOT +- * conduct registrations for management SCNs. +- * +- * Implementer's note: for iFCP sources, we should check for +- * ISNS_TAG_IFCP_SCN_BITMAP. +- */ +- attr = attrs->ial_data[0]; +- if (attr->ia_tag_id != ISNS_TAG_ISCSI_SCN_BITMAP +- || !ISNS_ATTR_IS_UINT32(attr)) +- goto rejected; +- +- scn_bitmap = attr->ia_value.iv_uint32; +- if (!isns_policy_validate_scn_bitmap(call->is_policy, scn_bitmap)) +- goto unauthorized; +- +- /* +- * 5.6.5.5 +- * If no SCN Port fields of any Portals of the Storage Node are +- * registered to receive SCN messages, then the SCNReg message SHALL +- * be rejected with Status Code 17 (SCN Registration Rejected). +- */ +- if (!(scn = isns_scn_create_scn(node, scn_bitmap, db))) +- goto rejected; +- +- *result = isns_simple_create(ISNS_SCN_REGISTER, srv->is_source, NULL); +- status = ISNS_SUCCESS; +- +-out: +- if (node) +- isns_object_release(node); +- +- return status; +- +-rejected: +- status = ISNS_SCN_REGISTRATION_REJECTED; +- goto out; +- +-unauthorized: +- status = ISNS_SOURCE_UNAUTHORIZED; +- goto out; +-} +- +-/* +- * Process a SCNDereg message +- */ +-int +-isns_process_scn_deregistration(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) +-{ +- isns_attr_list_t *keys = &call->is_message_attrs; +- isns_db_t *db = srv->is_db; +- isns_attr_t *attr; +- isns_object_t *node = NULL; +- int status = ISNS_SUCCESS; +- +- /* +- * 5.6.5.6 +- * The SCNDereg request message PDU Payload contains a Source Attribute +- * and Message Key Attribute(s). Valid Message Key Attributes for a +- * SCNDereg are shown below: +- * +- * Valid Message Key Attributes for SCNDereg +- * ----------------------------------------- +- * iSCSI Name +- * FC Port Name WWPN +- * +- * There are no Operating Attributes in the SCNDereg message. +- */ +- +- if (keys->ial_count != 1) +- return ISNS_SCN_REGISTRATION_REJECTED; +- +- attr = keys->ial_data[0]; +- if (attr->ia_tag_id != ISNS_TAG_ISCSI_NAME && +- attr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN) +- return ISNS_SCN_REGISTRATION_REJECTED; +- +- /* Look up the storage node for this source. If it does +- * not exist, reject the message. */ +- node = isns_db_lookup(db, NULL, keys); +- if (node == NULL) +- return ISNS_SUCCESS; +- +- /* +- * Policy: verify that the client is permitted +- * to access this entity. +- * +- * This includes +- * - the client node must be the object owner, +- * or a control node. +- * - the policy must allow monitoring of +- * this object type. +- */ +- if (!isns_policy_validate_object_access(call->is_policy, +- call->is_source, +- node, call->is_function)) +- goto unauthorized; +- +- isns_object_set_scn_mask(node, 0); +- isns_scn_delete_scn(node); +- +- *result = isns_simple_create(ISNS_SCN_DEREGISTER, srv->is_source, NULL); +- status = ISNS_SUCCESS; +- +-out: +- if (node) +- isns_object_release(node); +- +- return status; +- +-unauthorized: +- status = ISNS_SOURCE_UNAUTHORIZED; +- goto out; +-} +- +-/* +- * Set up the SCN object. +- */ +-static isns_scn_t * +-isns_scn_setup(isns_scn_t *scn, isns_object_t *node) +-{ +- isns_object_list_t portals = ISNS_OBJECT_LIST_INIT; +- isns_object_t *entity; +- unsigned int i; +- +- entity = isns_object_get_entity(node); +- if (entity == NULL +- || !isns_object_find_descendants(entity, +- &isns_portal_template, NULL, &portals)) +- return NULL; +- +- for (i = 0; i < portals.iol_count; ++i) { +- isns_object_t *portal = portals.iol_data[i]; +- isns_portal_info_t info; +- isns_scn_funnel_t *funnel; +- +- /* Extract address and SCN port from portal */ +- if (!isns_portal_from_object(&info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_SCN_PORT, +- portal)) +- continue; +- +- /* We know where to send our notifications! */ +- if (scn == NULL) { +- isns_attr_t *attr; +- +- if (!isns_object_get_attr(node, ISNS_TAG_ISCSI_NAME, &attr) +- && !isns_object_get_attr(node, ISNS_TAG_FC_PORT_NAME_WWPN, &attr)) { +- isns_error("Attempt to set up SCN for strange node type\n"); +- return NULL; +- } +- +- scn = isns_calloc(1, sizeof(*scn)); +- scn->scn_entity = isns_object_get(entity); +- scn->scn_owner = isns_object_get(node); +- scn->scn_attr = isns_attr_get(attr); +- scn->scn_name = isns_strdup(attr->ia_value.iv_string); +- } +- +- funnel = isns_calloc(1, sizeof(*funnel)); +- funnel->scn_portal = info; +- funnel->scn_next = scn->scn_funnels; +- scn->scn_funnels = funnel; +- } +- +- isns_object_list_destroy(&portals); +- return scn; +-} +- +-/* +- * See if an SCN object exists for the given target; +- * if it doesn't, then create one. +- */ +-static isns_scn_t * +-isns_scn_create_scn(isns_object_t *node, uint32_t bitmap, isns_db_t *db) +-{ +- isns_scn_t *scn; +- +- for (scn = isns_scn_list; scn; scn = scn->scn_next) { +- if (scn->scn_owner == node) +- goto done; +- } +- +- /* Not found - create it */ +- scn = isns_scn_setup(NULL, node); +- if (scn == NULL) +- return NULL; +- +- scn->scn_next = isns_scn_list; +- isns_scn_list = scn; +- +-done: +- /* We're all set - update the bitmap */ +- isns_object_set_scn_mask(node, bitmap); +- return scn; +-} +- +-static void +-isns_scn_delete_scn(isns_object_t *node) +-{ +- isns_scn_t *scn, **pos; +- +- pos = &isns_scn_list; +- while ((scn = *pos) != NULL) { +- if (scn->scn_owner == node) { +- isns_debug_scn("Deregistering SCN for node %u\n", +- node->ie_index); +- *pos = scn->scn_next; +- isns_scn_free(scn); +- return; +- } +- pos = &scn->scn_next; +- } +-} +- +-static void +-isns_scn_release_funnels(isns_scn_t *scn) +-{ +- isns_scn_funnel_t *funnel; +- +- while ((funnel = scn->scn_funnels) != NULL) { +- scn->scn_funnels = funnel->scn_next; +- if (funnel->scn_socket) +- isns_socket_free(funnel->scn_socket); +- isns_free(funnel); +- } +-} +- +-static void +-isns_scn_free(isns_scn_t *scn) +-{ +- isns_scn_release_funnels(scn); +- isns_object_release(scn->scn_owner); +- isns_object_release(scn->scn_entity); +- isns_attr_release(scn->scn_attr); +- isns_free(scn->scn_name); +- isns_free(scn); +-} +- +-/* +- * Check whether we should send an event to the target +- */ +-static inline int +-isns_scn_match(isns_scn_t *scn, uint32_t event, +- const isns_object_t *node, +- uint32_t node_type) +-{ +- if (event == 0) +- return 0; +- +- if (node->ie_scn_mask & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK) +- return event | ISNS_SCN_MANAGEMENT_REGISTRATION_MASK; +- +-#if 0 +- /* This is a normal (non-control) node. Check whether the object +- * is in the scope of this client. */ +- if (!isns_object_in_scope(scn->scn_owner, node)) +- return 0; +-#endif +- +- if (node->ie_scn_mask & ISNS_SCN_TARGET_AND_SELF_ONLY_MASK) { +- if (node != scn->scn_owner && !(node_type & ISNS_ISCSI_TARGET_MASK)) +- return 0; +- } +- if (node->ie_scn_mask & ISNS_SCN_INITIATOR_AND_SELF_ONLY_MASK) { +- if (node != scn->scn_owner && !(node_type & ISNS_ISCSI_INITIATOR_MASK)) +- return 0; +- } +- +- return event; +-} +- +-/* +- * Helper to create time stamp attr +- */ +-static isns_attr_t * +-isns_create_timestamp_attr(void) +-{ +- isns_value_t value = ISNS_VALUE_INIT(uint64, time(NULL)); +- +- return isns_attr_alloc(ISNS_TAG_TIMESTAMP, NULL, &value); +-} +- +-/* +- * This function is invoked whenever someone changes the +- * database. +- * +- * SCNs are another area where the RFC is fabulously wishy washy. +- * It is not entirely clear when DD/DDS information should be +- * included in a management SCN - one *reasonable* interpretation +- * would be that this happens for DDReg/DDDereg/DDSReg/DDSDereg +- * events only. But some sections make it sound as if DD +- * information is included for all management SCNs. +- */ +-void +-isns_scn_callback(const isns_db_event_t *ev, void *ptr) +-{ +- isns_object_t *obj = ev->ie_object; +- isns_scn_t *scn, **pos; +- isns_attr_t *timestamp; +- uint32_t node_type; +- +- /* Never send out notifications for policy objects and the like. */ +- if (obj->ie_flags & ISNS_OBJECT_PRIVATE) +- return; +- +- /* When an entity is nuked, remove all SCNs to nodes +- * that registered from there */ +- if (ISNS_IS_ENTITY(obj) && (ev->ie_bits & ISNS_SCN_OBJECT_REMOVED_MASK)) { +- pos = &isns_scn_list; +- while ((scn = *pos) != NULL) { +- if (scn->scn_entity != obj) { +- pos = &scn->scn_next; +- continue; +- } +- isns_debug_scn("Deleting SCN registration for %s\n", +- scn->scn_name); +- *pos = scn->scn_next; +- isns_scn_free(scn); +- } +- return; +- } +- +- /* For now we handle iSCSI nodes only. Maybe later we'll +- * do iFC nodes as well. */ +- if (!ISNS_IS_ISCSI_NODE(obj)) +- return; +- if (!isns_object_get_uint32(obj, ISNS_TAG_ISCSI_NODE_TYPE, &node_type)) +- return; +- +- if (ev->ie_recipient) { +- isns_object_t *dst = ev->ie_recipient; +- +- isns_debug_scn("SCN unicast <%s %u, %s> -> %s %u\n", +- obj->ie_template->iot_name, obj->ie_index, +- isns_event_string(ev->ie_bits), +- dst->ie_template->iot_name, dst->ie_index); +- } else { +- isns_debug_scn("SCN multicast <%s %u, %s>\n", +- obj->ie_template->iot_name, obj->ie_index, +- isns_event_string(ev->ie_bits)); +- } +- timestamp = isns_create_timestamp_attr(); +- +- pos = &isns_scn_list; +- while ((scn = *pos) != NULL) { +- unsigned int scn_bits, management; +- isns_object_t *recipient, *dd = NULL; +- isns_simple_t *call; +- +- recipient = scn->scn_owner; +- +- /* Check if the node has gone away completely. */ +- if (recipient->ie_scn_mask == 0) { +- *pos = scn->scn_next; +- isns_scn_free(scn); +- continue; +- } +- +- if (recipient->ie_container == NULL) { +- isns_warning("Internal bug - SCN recipient without container\n"); +- /* Clear the bitmask and loop over - this will remove it */ +- recipient->ie_scn_mask = 0; +- continue; +- } +- +- /* See if portals were added/removed. +- * This does not catch updates that modified *just* +- * the SCN port */ +- if (recipient->ie_container->ie_mtime != scn->scn_last_update) { +- /* Rebuild the list of SCN portals */ +- isns_scn_release_funnels(scn); +- scn->scn_last_update = 0; +- } +- pos = &scn->scn_next; +- +- /* Check for unicast events (triggered for DD addition/removal). +- * For unicast events, we do not mask the SCN bits, so that +- * clients who have registered for non-management events +- * will see the membership events for their DDs nevertheless. */ +- if (ev->ie_recipient == NULL) { +- scn_bits = ev->ie_bits & recipient->ie_scn_mask; +- if (scn_bits == 0) +- continue; +- /* Management SCNs should not be delivered to nodes +- * that have not registered for them. */ +- if ((ev->ie_bits & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK) +- && !(recipient->ie_scn_mask & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK)) +- continue; +- } else if (recipient == ev->ie_recipient) { +- scn_bits = ev->ie_bits; +- } else { +- /* No match, skip this recipient */ +- continue; +- } +- +- if (scn->scn_last_update == 0) { +- scn->scn_last_update = recipient->ie_container->ie_mtime; +- isns_scn_setup(scn, recipient); +- } +- +- /* We check for SCN capable portals when processing +- * the SCN registration. But the portals may go away +- * in the meantime. */ +- if (scn->scn_funnels == NULL) +- continue; +- +- /* Check SCN bitmask. This will modify the event bits. */ +- scn_bits = isns_scn_match(scn, scn_bits, obj, node_type); +- if (scn_bits == 0) +- continue; +- management = !!(scn_bits & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK); +- +- /* +- * 2.2.3 +- * A regular SCN registration indicates that the +- * Discovery Domain Service SHALL be used to control the +- * distribution of SCN messages. Receipt of regular +- * SCNs is limited to the discovery domains in which +- * the SCN-triggering event takes place. Regular SCNs +- * do not contain information about discovery domains. +- * +- * Implementer's note: We override check for unicast events. +- * The reason is that DDDereg will sever the +- * relationship, and we would never send an SCN for that +- * event. +- */ +- if (!management && !ev->ie_recipient) { +- if (!isns_object_test_visibility(obj, recipient)) +- continue; +- } +- +- isns_debug_scn("preparing to send SCN to %s\n", +- scn->scn_name); +- +- if ((call = scn->scn_message) == NULL) { +- call = isns_create_scn(isns_scn_server->is_source, +- scn->scn_attr, +- timestamp); +- if (call == NULL) +- continue; +- scn->scn_message = call; +- } +- +- /* +- * If the SCN is a Management SCN, then the SCN message +- * SHALL also list the DD_ID and/or DDS_ID of the +- * Discovery Domains and Discovery Domain Sets (if any) +- * that caused the change in state for that Storage Node. +- * These additional attributes (i.e., DD_ID and/or DDS_ID) +- * shall immediately follow the iSCSI Name or FC Port +- * Name and precede the next SCN bitmap for the next +- * notification message (if any). +- */ +- if (management && ev->ie_trigger) +- dd = ev->ie_trigger; +- +- isns_scn_add_event(call, scn_bits, obj, dd); +- +- } +- +- isns_attr_release(timestamp); +-} +- +-/* +- * Obtain a socket to talk to this guy. +- * Not entirely trivial - this can be both an established +- * (incoming) connection, or one that we should establish. +- * +- * Note, we do not support transmission on the incoming +- * connection yet. +- */ +-static isns_socket_t * +-isns_scn_get_socket(isns_scn_t *scn) +-{ +- isns_scn_funnel_t *f, *best = NULL; +- isns_socket_t *sock; +- unsigned int worst = 0, loops = 0, nfunnels; +- +- /* Keep it simple for now */ +- if ((f = scn->scn_current_funnel) != NULL && f->scn_socket) { +- if (!f->scn_bad) +- return f->scn_socket; +- /* Oops, we've seen timeouts on this socket. */ +- isns_socket_free(f->scn_socket); +- f->scn_socket = NULL; +- } +- +-again: +- nfunnels = 0; +- for (f = scn->scn_funnels; f; f = f->scn_next) { +- unsigned int badness = f->scn_bad; +- +- if (!best || badness < best->scn_bad) +- best = f; +- if (badness > worst) +- worst = badness; +- nfunnels++; +- } +- +- if (!best) +- return NULL; +- +- sock = isns_connect_to_portal(&best->scn_portal); +- if (sock == NULL) { +- /* Make sure we try each funnel exactly once */ +- best->scn_bad = worst + 1; +- if (++loops < nfunnels) +- goto again; +- return NULL; +- } +- +- /* Set the security context */ +- isns_socket_set_security_ctx(sock, +- isns_default_security_context(1)); +- +- isns_debug_scn("SCN: %s using portal %s\n", +- scn->scn_name, +- isns_portal_string(&best->scn_portal)); +- scn->scn_current_funnel = best; +- best->scn_socket = sock; +- return sock; +-} +- +-/* +- * This is the callback function invoked when the SCN message reply +- * comes in, or when the message timed out. +- */ +-static void +-isns_process_scn_response(uint32_t xid, int status, isns_simple_t *msg) +-{ +- isns_scn_t *scn; +- +- if (msg == NULL) { +- isns_debug_scn("SCN timed out\n"); +- return; +- } +- +- isns_debug_scn("Received an SCN response\n"); +- for (scn = isns_scn_list; scn; scn = scn->scn_next) { +- if (scn->scn_pending && scn->scn_xid == xid) { +- isns_debug_scn("SCN: %s acknowledged notification\n", +- scn->scn_name); +- isns_simple_free(scn->scn_pending); +- scn->scn_pending = NULL; +- +- if (scn->scn_current_funnel) +- scn->scn_current_funnel->scn_bad = 0; +- } +- } +-} +-/* +- * Transmit all pending SCN messages +- * +- * 2.9.2 +- * If a Network Entity has multiple Portals with registered SCN UDP Ports, +- * then SCN messages SHALL be delivered to each Portal registered to +- * receive such messages. +- * +- * FIXME: we should make this timer based just as the ESI code. +- */ +-time_t +-isns_scn_transmit_all(void) +-{ +- time_t now = time(NULL), next_timeout; +- isns_scn_t *scn; +- +- for (scn = isns_scn_list; scn; scn = scn->scn_next) { +- isns_simple_t *call; +- isns_socket_t *sock; +- +- /* We do not allow more than one outstanding +- * notification for now. */ +- if ((call = scn->scn_pending) != NULL) { +- if (scn->scn_timeout > now) +- continue; +- scn->scn_current_funnel->scn_bad++; +- if (--(scn->scn_retries)) +- goto retry; +- isns_warning("SCN for %s timed out\n", +- scn->scn_name); +- isns_simple_free(call); +- scn->scn_pending = NULL; +- } +- +- if ((call = scn->scn_message) == NULL) +- continue; +- +- isns_debug_scn("SCN: transmit pending message for %s\n", +- scn->scn_name); +- scn->scn_retries = isns_config.ic_scn_retries; +- scn->scn_pending = call; +- scn->scn_message = NULL; +- +-retry: +- if ((sock = isns_scn_get_socket(scn)) == NULL) { +- /* Sorry, no can do. */ +- isns_warning("SCN for %s dropped - no portal\n", +- scn->scn_name); +- scn->scn_pending = NULL; +- isns_simple_free(call); +- continue; +- } +- +- isns_simple_transmit(sock, call, NULL, +- isns_config.ic_scn_timeout, +- isns_process_scn_response); +- scn->scn_xid = call->is_xid; +- scn->scn_timeout = now + isns_config.ic_scn_timeout; +- } +- +- next_timeout = now + 3600; +- for (scn = isns_scn_list; scn; scn = scn->scn_next) { +- if (scn->scn_pending && scn->scn_timeout < next_timeout) +- next_timeout = scn->scn_timeout; +- } +- +- return next_timeout; +-} +- +-/* +- * Process an incoming State Change Notification +- */ +-int +-isns_process_scn(isns_server_t *srv, isns_simple_t *call, isns_simple_t **reply) +-{ +- isns_attr_list_t *list = &call->is_message_attrs; +- isns_attr_t *dstattr, *tsattr; +- const char *dst_name; +- unsigned int i; +- +- /* The first attribute is the destination, and should match +- * our source name. Don't bother checking. The second is the +- * time stamp. +- */ +- if (list->ial_count < 2) +- goto rejected; +- +- dstattr = list->ial_data[0]; +- if (dstattr->ia_tag_id != ISNS_TAG_ISCSI_NAME +- && dstattr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN) +- goto rejected; +- if (!ISNS_ATTR_IS_STRING(dstattr)) +- goto rejected; +- dst_name = dstattr->ia_value.iv_string; +- +- tsattr = list->ial_data[1]; +- if (tsattr->ia_tag_id != ISNS_TAG_TIMESTAMP) +- return ISNS_SCN_EVENT_REJECTED; +- +- for (i = 2; i < list->ial_count; ) { +- isns_object_template_t *tmpl; +- isns_attr_t *bmattr, *srcattr; +- const char *node_name; +- uint32_t bitmap; +- +- if (i + 1 >= list->ial_count) +- goto rejected; +- +- bmattr = list->ial_data[i++]; +- srcattr = list->ial_data[i++]; +- +- /* Validate that bitmap and node type match */ +- switch (bmattr->ia_tag_id) { +- case ISNS_TAG_ISCSI_SCN_BITMAP: +- if (srcattr->ia_tag_id != ISNS_TAG_ISCSI_NAME) +- goto rejected; +- tmpl = &isns_iscsi_node_template; +- break; +- +- case ISNS_TAG_IFCP_SCN_BITMAP: +- if (srcattr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN) +- goto rejected; +- tmpl = &isns_fc_port_template; +- break; +- +- default: +- goto rejected; +- } +- +- /* Skip over and DD_ID or DDS_ID attrs */ +- while (i < list->ial_count) { +- isns_attr_t *ddattr = list->ial_data[i]; +- +- if (ddattr->ia_tag_id == ISNS_TAG_ISCSI_SCN_BITMAP +- || ddattr->ia_tag_id == ISNS_TAG_IFCP_SCN_BITMAP) +- break; +- ++i; +- } +- +- if (!ISNS_ATTR_IS_UINT32(bmattr)) +- goto rejected; +- bitmap = bmattr->ia_value.iv_uint32; +- +- if (!ISNS_ATTR_IS_STRING(srcattr)) +- goto rejected; +- node_name = srcattr->ia_value.iv_string; +- +- if (srv->is_scn_callback) +- srv->is_scn_callback(srv->is_db, bitmap, tmpl, node_name, dst_name); +- } +- +- /* +- * 5.7.5.8. SCN Response (SCNRsp) +- * The SCNRsp response contains the SCN Destination Attribute +- * representing the Node identifier that received the SCN. +- */ +- *reply = isns_create_scn(srv->is_source, +- list->ial_data[0], +- NULL); +- return ISNS_SUCCESS; +- +-rejected: +- return ISNS_SCN_EVENT_REJECTED; +-} +diff --git a/utils/open-isns/scope.c b/utils/open-isns/scope.c +deleted file mode 100644 +index 9ee7f9a..0000000 +--- a/utils/open-isns/scope.c ++++ /dev/null +@@ -1,513 +0,0 @@ +-/* +- * Handle object visibility and scope. +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include "isns.h" +-#include "attrs.h" +-#include "objects.h" +-#include "message.h" +-#include "security.h" +-#include "util.h" +-#include "db.h" +- +-struct isns_scope { +- isns_db_t * ic_db; +- unsigned int ic_users; +- isns_object_t * ic_source_node; +- +- isns_object_template_t * ic_query_class; +- +- isns_object_list_t ic_dd_nodes; +- isns_object_list_t ic_dd_portals; +- isns_object_list_t ic_objects; +-}; +- +-static int __isns_scope_collect_dd(uint32_t, void *); +- +-/* +- * Allocate an empty scope +- */ +-isns_scope_t * +-isns_scope_alloc(isns_db_t *db) +-{ +- isns_scope_t *scope; +- +- scope = isns_calloc(1, sizeof(*scope)); +- +- scope->ic_db = db; +- scope->ic_users = 1; +- return scope; +-} +- +-isns_scope_t * +-isns_scope_get(isns_scope_t *scope) +-{ +- if (scope) { +- isns_assert(scope->ic_users); +- scope->ic_users++; +- } +- return scope; +-} +- +-void +-isns_scope_release(isns_scope_t *scope) +-{ +- if (!scope) +- return; +- +- isns_assert(scope->ic_users); +- if (--(scope->ic_users)) +- return; +- +- isns_object_release(scope->ic_source_node); +- isns_object_list_destroy(&scope->ic_dd_nodes); +- isns_object_list_destroy(&scope->ic_dd_portals); +- isns_object_list_destroy(&scope->ic_objects); +- isns_free(scope); +-} +- +-/* +- * Get the scope for this operation +- */ +-isns_scope_t * +-isns_scope_for_call(isns_db_t *db, const isns_simple_t *call) +-{ +- isns_source_t *source = call->is_source; +- isns_object_t *node; +- isns_scope_t *scope; +- uint32_t node_type; +- +- /* FIXME use source->is_node and source->is_node_type */ +- +- /* When we get here, we already know that the client +- * represents the specified source node. */ +- node = isns_db_lookup_source_node(db, source); +- +- /* Allow unknown nodes to query the DB */ +- if (node == NULL) { +- node = isns_create_storage_node2(source, 0, NULL); +- if (node == NULL) +- return NULL; +- source->is_untrusted = 1; +- } +- +- if (isns_object_get_uint32(node, ISNS_TAG_ISCSI_NODE_TYPE, &node_type) +- && (node_type & ISNS_ISCSI_CONTROL_MASK)) { +- isns_object_release(node); +- return isns_scope_get(db->id_global_scope); +- } +- +- scope = isns_scope_alloc(db); +- scope->ic_source_node = node; +- +- { +- isns_object_list_t members = ISNS_OBJECT_LIST_INIT; +- unsigned int i; +- +- isns_object_get_visible(node, db, &members); +- isns_object_list_uniq(&members); +- +- /* If the node is not a member of any DD, allow it +- * to at least talk to itself. */ +- if (members.iol_count == 0) +- isns_object_list_append(&members, node); +- +- /* Sort DD members into nodes and portals */ +- for (i = 0; i < members.iol_count; ++i) { +- isns_object_t *obj = members.iol_data[i]; +- +- if (obj->ie_state != ISNS_OBJECT_STATE_MATURE) +- continue; +- if (!isns_policy_validate_object_access(call->is_policy, +- source, obj, +- call->is_function)) +- continue; +- if (ISNS_IS_ISCSI_NODE(obj)) +- isns_object_list_append(&scope->ic_dd_nodes, obj); +- else +- if (ISNS_IS_PORTAL(obj)) +- isns_object_list_append(&scope->ic_dd_portals, obj); +- } +- isns_object_list_destroy(&members); +- } +- +- return scope; +-} +- +-/* +- * Add an object to a scope +- */ +-void +-isns_scope_add(isns_scope_t *scope, isns_object_t *obj) +-{ +- isns_object_list_append(&scope->ic_objects, obj); +-} +- +-int +-isns_scope_remove(isns_scope_t *scope, isns_object_t *obj) +-{ +- return isns_object_list_remove(&scope->ic_objects, obj); +-} +- +-/* +- * Get all objects related through a portal group, optionally +- * including the portal group objects themselves +- */ +-static void +-__isns_scope_get_pg_related(isns_scope_t *scope, +- const isns_object_t *obj, +- isns_object_list_t *result) +-{ +- isns_object_list_t temp = ISNS_OBJECT_LIST_INIT; +- unsigned int i; +- +- /* Get all portal groups related to this object */ +- isns_db_get_relationship_objects(scope->ic_db, +- obj, ISNS_RELATION_PORTAL_GROUP, &temp); +- +- /* Include all portals/nodes that we can reach. */ +- for (i = 0; i < temp.iol_count; ++i) { +- isns_object_t *pg, *other; +- uint32_t pgt; +- +- pg = temp.iol_data[i]; +- +- /* Skip any portal group objects with a PG tag of 0; +- * these actually deny access. */ +- if (!isns_object_get_uint32(pg, ISNS_TAG_PG_TAG, &pgt) +- || pgt == 0) +- continue; +- +- /* Get the other object. +- * Note that isns_relation_get_other doesn't +- * bump the reference count, so there's no need +- * to call isns_object_release(other). */ +- other = isns_relation_get_other(pg->ie_relation, obj); +- if (other->ie_state != ISNS_OBJECT_STATE_MATURE) +- continue; +- +- isns_object_list_append(result, other); +- isns_object_list_append(result, pg); +- } +- +- isns_object_list_destroy(&temp); +-} +- +-/* +- * Get all portals related to the given node. +- * +- * 2.2.2 +- * Placing Portals of a Network Entity into Discovery Domains allows +- * administrators to indicate the preferred IP Portal interface through +- * which storage traffic should access specific Storage Nodes of that +- * Network Entity. If no Portals of a Network Entity have been placed +- * into a DD, then queries scoped to that DD SHALL report all Portals of +- * that Network Entity. If one or more Portals of a Network Entity have +- * been placed into a DD, then queries scoped to that DD SHALL report +- * only those Portals that have been explicitly placed in the DD. +- */ +-static void +-__isns_scope_get_portals(isns_scope_t *scope, +- const isns_object_t *node, +- isns_object_list_t *portals, +- isns_object_list_t *pgs, +- int unique) +-{ +- isns_object_list_t related = ISNS_OBJECT_LIST_INIT; +- unsigned int i, specific = 0; +- +- /* Get all portals and portal groups related to the +- * given node. This will put pairs of (portal, portal-group) +- * on the list. +- */ +- __isns_scope_get_pg_related(scope, node, &related); +- +- /* If we're querying for our own portals, don't limit +- * visibility. */ +- if (node == scope->ic_source_node) +- goto report_all_portals; +- +- /* Check if any of the portals is mentioned in the DD +- * FIXME: There is some ambiguity over what the right +- * answer is when you have two nodes (initiator, target), +- * and two discovery domains linking the two. One +- * DD mentions a specific portal through which target +- * should be accessed; the other DD does not (allowing +- * use of any portal in that entity). Which portals +- * to return here? +- * We go for the strict interpretation, ie if *any* DD +- * restricts access to certain portals, we report only +- * those. +- */ +- for (i = 0; i < related.iol_count; i += 2) { +- isns_object_t *portal = related.iol_data[i]; +- +- if (isns_object_list_contains(&scope->ic_dd_portals, portal)) { +- if (portals +- && !(unique || isns_object_list_contains(portals, portal))) +- isns_object_list_append(portals, portal); +- if (pgs) +- isns_object_list_append(pgs, +- related.iol_data[i + 1]); +- specific++; +- } +- } +- +- if (specific) +- goto out; +- +-report_all_portals: +- /* No specific portal given for this node. Add them all. */ +- for (i = 0; i < related.iol_count; i += 2) { +- isns_object_t *portal = related.iol_data[i]; +- +- if (portals +- && !(unique && isns_object_list_contains(portals, portal))) +- isns_object_list_append(portals, portal); +- if (pgs) +- isns_object_list_append(pgs, +- related.iol_data[i + 1]); +- } +- +-out: +- isns_object_list_destroy(&related); +-} +- +-/* +- * Get all nodes reachable through a given portal +- * This is really the same as __isns_scope_get_portals +- * minus the special casing for preferred portals. +- * Still, let's put this into it's own function - the whole +- * thing is already complex enough already. +- */ +-static void +-__isns_scope_get_nodes(isns_scope_t *scope, +- const isns_object_t *portal, +- isns_object_list_t *nodes, +- isns_object_list_t *pgs, +- int unique) +-{ +- isns_object_list_t related = ISNS_OBJECT_LIST_INIT; +- unsigned int i; +- +- /* Get all nodes and portal groups related to the +- * given node. This will put pairs of (nodes, portal-group) +- * on the list. +- */ +- __isns_scope_get_pg_related(scope, portal, &related); +- +- for (i = 0; i < related.iol_count; i += 2) { +- isns_object_t *node = related.iol_data[i]; +- +- if (nodes +- && !(unique && isns_object_list_contains(nodes, node))) +- isns_object_list_append(nodes, node); +- if (pgs) +- isns_object_list_append(pgs, +- related.iol_data[i + 1]); +- } +- +- isns_object_list_destroy(&related); +-} +- +-static void +-__isns_scope_get_default_dd(isns_scope_t *scope) +-{ +- isns_object_t *obj; +- +- if (isns_config.ic_use_default_domain) { +- obj = isns_create_default_domain(); +- isns_object_list_append(&scope->ic_objects, obj); +- isns_object_release(obj); +- } +-} +- +- +-/* +- * Scope the query +- */ +-static void +-__isns_scope_prepare_query(isns_scope_t *scope, +- isns_object_template_t *tmpl) +-{ +- isns_object_list_t *nodes; +- unsigned int i; +- +- /* Global and default scope have no source node; they're just +- * a list of objects. +- */ +- if (scope->ic_source_node == NULL) +- return; +- +- if (scope->ic_query_class) { +- if (scope->ic_query_class == tmpl) +- return; +- isns_object_list_destroy(&scope->ic_objects); +- } +- scope->ic_query_class = tmpl; +- +- nodes = &scope->ic_dd_nodes; +- if (tmpl == &isns_entity_template) { +- for (i = 0; i < nodes->iol_count; ++i) { +- isns_object_t *obj = nodes->iol_data[i]; +- +- if (obj->ie_container) +- isns_object_list_append(&scope->ic_objects, +- obj->ie_container); +- } +- } else +- if (tmpl == &isns_iscsi_node_template) { +- for (i = 0; i < nodes->iol_count; ++i) { +- isns_object_t *obj = nodes->iol_data[i]; +- +- isns_object_list_append(&scope->ic_objects, obj); +- } +- } else +- if (tmpl == &isns_portal_template) { +- for (i = 0; i < nodes->iol_count; ++i) { +- isns_object_t *obj = nodes->iol_data[i]; +- +- __isns_scope_get_portals(scope, obj, +- &scope->ic_objects, NULL, 0); +- } +- } else +- if (tmpl == &isns_iscsi_pg_template) { +- for (i = 0; i < nodes->iol_count; ++i) { +- isns_object_t *obj = nodes->iol_data[i]; +- +- __isns_scope_get_portals(scope, obj, +- NULL, &scope->ic_objects, 0); +- } +- } else +- if (tmpl == &isns_dd_template) { +- isns_object_t *node = scope->ic_source_node; +- +- if (node && !isns_bitvector_is_empty(node->ie_membership)) +- isns_bitvector_foreach(node->ie_membership, +- __isns_scope_collect_dd, +- scope); +- else +- __isns_scope_get_default_dd(scope); +- } +- +- isns_object_list_uniq(&scope->ic_objects); +-} +- +-static int +-__isns_scope_collect_dd(uint32_t dd_id, void *ptr) +-{ +- isns_scope_t *scope = ptr; +- isns_object_t *dd; +- +- dd = isns_db_vlookup(scope->ic_db, &isns_dd_template, +- ISNS_TAG_DD_ID, dd_id, +- 0); +- if (dd) { +- isns_object_list_append(&scope->ic_objects, dd); +- isns_object_release(dd); +- } +- +- return 0; +-} +- +-/* +- * Lookup functions for scope +- */ +-int +-isns_scope_gang_lookup(isns_scope_t *scope, +- isns_object_template_t *tmpl, +- const isns_attr_list_t *match, +- isns_object_list_t *result) +-{ +- isns_assert(tmpl); +- +- if (!scope) +- return 0; +- +- __isns_scope_prepare_query(scope, tmpl); +- return isns_object_list_gang_lookup(&scope->ic_objects, +- tmpl, match, result); +-} +- +-/* +- * Get related objects. +- * This is used by the query code. +- */ +-void +-isns_scope_get_related(isns_scope_t *scope, +- const isns_object_t *origin, +- unsigned int type_mask, +- isns_object_list_t *result) +-{ +- isns_object_template_t *tmpl = origin->ie_template; +- isns_object_list_t nodes_result = ISNS_OBJECT_LIST_INIT; +- isns_object_list_t portals_result = ISNS_OBJECT_LIST_INIT; +- isns_object_list_t *members = &scope->ic_dd_nodes; +- unsigned int i; +- +- if (tmpl == &isns_entity_template) { +- /* Entity: include all storage nodes contained, +- * the portals through which to reach them, and +- * the portal groups for those. */ +- for (i = 0; i < members->iol_count; ++i) { +- isns_object_t *obj = members->iol_data[i]; +- +- if (obj->ie_container != origin) +- continue; +- +- isns_object_list_append(&nodes_result, obj); +- __isns_scope_get_portals(scope, obj, +- &portals_result, +- &portals_result, 1); +- } +- } else +- if (tmpl == &isns_iscsi_node_template) { +- /* Storage node: include all portals through +- * which it can be reached, and the portal +- * groups for those. */ +- __isns_scope_get_portals(scope, origin, +- &portals_result, +- &portals_result, 1); +- /* FIXME: Include all discovery domains the +- * node is a member of. */ +- } else +- if (tmpl == &isns_portal_template) { +- /* Portal: include all storage nodes which can +- * be reached through it, and the portal groups +- * for those. */ +- __isns_scope_get_nodes(scope, origin, +- &portals_result, +- &portals_result, 1); +- } else +- if (tmpl == &isns_iscsi_pg_template) { +- /* Portal group: PGs *are* a relationship, but +- * unclear how this should be handled. +- * Return nothing for now. */ +- } else +- if (tmpl == &isns_dd_template) { +- /* Discovery domain: no related objects. */ +- } +- +- isns_object_list_append_list(result, &nodes_result); +- isns_object_list_append_list(result, &portals_result); +- +- isns_object_list_destroy(&nodes_result); +- isns_object_list_destroy(&portals_result); +-} +- +-isns_object_t * +-isns_scope_get_next(isns_scope_t *scope, +- isns_object_template_t *tmpl, +- const isns_attr_list_t *current, +- const isns_attr_list_t *match) +-{ +- if (!tmpl || !scope) +- return NULL; +- +- __isns_scope_prepare_query(scope, tmpl); +- return __isns_db_get_next(&scope->ic_objects, tmpl, current, match); +-} +diff --git a/utils/open-isns/security.c b/utils/open-isns/security.c +deleted file mode 100644 +index 548ce18..0000000 +--- a/utils/open-isns/security.c ++++ /dev/null +@@ -1,437 +0,0 @@ +-/* +- * Security functions for iSNS +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include "isns.h" +-#include "security.h" +-#include "source.h" +-#include "util.h" +-#include "config.h" +- +-#ifdef WITH_SECURITY +- +-/* +- * Allocate a security peer +- */ +-static isns_principal_t * +-isns_create_principal(const char *spi, size_t spi_len, EVP_PKEY *pk) +-{ +- char keydesc[32]; +- isns_principal_t *peer; +- +- peer = isns_calloc(1, sizeof(*peer)); +- peer->is_users = 1; +- if (spi) { +- peer->is_name = isns_malloc(spi_len + 1); +- memcpy(peer->is_name, spi, spi_len); +- peer->is_name[spi_len] = '\0'; +- peer->is_namelen = spi_len; +- } +- +- peer->is_key = pk; +- if (pk) { +- const char *algo; +- +- switch (pk->type) { +- case EVP_PKEY_DSA: algo = "DSA"; break; +- case EVP_PKEY_RSA: algo = "RSA"; break; +- default: algo = "unknown"; break; +- } +- +- snprintf(keydesc, sizeof(keydesc), " (%s/%u)", +- algo, EVP_PKEY_bits(pk)); +- } +- +- isns_debug_auth("Created security principal \"%s\"%s\n", +- peer->is_name, keydesc); +- return peer; +-} +- +-static void +-isns_principal_set_key(isns_principal_t *princ, EVP_PKEY *key) +-{ +- if (princ->is_key == key) +- return; +- if (princ->is_key) +- EVP_PKEY_free(princ->is_key); +- princ->is_key = key; +-} +- +-void +-isns_principal_free(isns_principal_t *peer) +-{ +- if (!peer) +- return; +- +- isns_assert(peer->is_users); +- if (--(peer->is_users)) +- return; +- +- if (peer->is_name) +- isns_free(peer->is_name); +- if (peer->is_key) +- EVP_PKEY_free(peer->is_key); +- isns_policy_release(peer->is_policy); +- isns_free(peer); +-} +- +-/* +- * Set the principal's name +- */ +-void +-isns_principal_set_name(isns_principal_t *princ, const char *spi) +-{ +- isns_assign_string(&princ->is_name, spi); +- isns_debug_auth("Setting principal name to \"%s\"\n", spi); +-} +- +-const char * +-isns_principal_name(const isns_principal_t *princ) +-{ +- return princ->is_name; +-} +- +-/* +- * Cache policy in the principal object. +- */ +-void +-isns_principal_set_policy(isns_principal_t *princ, +- isns_policy_t *policy) +-{ +- if (policy) +- policy->ip_users++; +- isns_policy_release(princ->is_policy); +- princ->is_policy = policy; +-} +- +-/* +- * Key management functions for a security context. +- */ +-isns_principal_t * +-isns_security_load_privkey(isns_security_t *ctx, const char *filename) +-{ +- EVP_PKEY *pkey; +- +- isns_debug_auth("Loading private %s key from %s\n", +- ctx->is_name, filename); +- if (!ctx->is_load_private) +- return NULL; +- if (!(pkey = ctx->is_load_private(ctx, filename))) { +- isns_error("Unable to load private %s key from %s\n", +- ctx->is_name, filename); +- return NULL; +- } +- +- return isns_create_principal(NULL, 0, pkey); +-} +- +-isns_principal_t * +-isns_security_load_pubkey(isns_security_t *ctx, const char *filename) +-{ +- EVP_PKEY *pkey; +- +- isns_debug_auth("Loading public %s key from %s\n", +- ctx->is_name, filename); +- if (!ctx->is_load_public) +- return NULL; +- if (!(pkey = ctx->is_load_public(ctx, filename))) { +- isns_error("Unable to load public %s key from %s\n", +- ctx->is_name, filename); +- return NULL; +- } +- +- return isns_create_principal(NULL, 0, pkey); +-} +- +-void +-isns_security_set_identity(isns_security_t *ctx, isns_principal_t *princ) +-{ +- if (princ) +- princ->is_users++; +- if (ctx->is_self) +- isns_principal_free(ctx->is_self); +- ctx->is_self = princ; +-} +- +-void +-isns_add_principal(isns_security_t *ctx, isns_principal_t *princ) +-{ +- if (princ) +- princ->is_users++; +- princ->is_next = ctx->is_peers; +- ctx->is_peers = princ; +-} +- +-isns_principal_t * +-isns_get_principal(isns_security_t *ctx, const char *spi, size_t spi_len) +-{ +- isns_principal_t *princ; +- isns_policy_t *policy; +- isns_keystore_t *ks; +- EVP_PKEY *pk; +- +- ks = ctx->is_peer_keys; +- +- for (princ = ctx->is_peers; princ; princ = princ->is_next) { +- /* In a client socket, we set the (expected) +- * public key of the peer through +- * isns_security_set_peer_key, which will +- * just put it on the peers list. +- * This key usually has no name. +- */ +- if (princ->is_name == NULL) { +- princ->is_users++; +- return princ; +- } +- if (spi_len == princ->is_namelen +- && !memcmp(princ->is_name, spi, spi_len)) { +- /* Check whether the cached key and policy +- * might be stale. */ +- if (ks && ks->ic_generation != princ->is_generation) { +- pk = ks->ic_find(ks, spi, spi_len); +- if (pk == NULL) { +- isns_debug_auth("Unable to refresh key " +- "for principal %.*s - probably deleted\n", +- spi_len, spi); +- return NULL; +- } +- isns_debug_auth("Refresh key for principal %.*s\n", +- spi_len, spi); +- isns_principal_set_key(princ, pk); +- princ->is_users++; +- goto refresh_policy; +- } +- princ->is_users++; +- return princ; +- } +- } +- +- if ((ks = ctx->is_peer_keys) == NULL) +- return NULL; +- +- if (!(pk = ks->ic_find(ks, spi, spi_len))) +- return NULL; +- princ = isns_create_principal(spi, spi_len, pk); +- +- /* Add it to the list */ +- princ->is_next = ctx->is_peers; +- ctx->is_peers = princ; +- princ->is_users++; +- +- /* Bind the policy for this peer */ +-refresh_policy: +- if (!ks->ic_get_policy +- || !(policy = ks->ic_get_policy(ks, spi, spi_len))) +- policy = isns_policy_default(spi, spi_len); +- +- /* If no entity is set, use the SPI */ +- if (policy->ip_entity == NULL) +- isns_assign_string(&policy->ip_entity, policy->ip_name); +- +- /* If the list of permitted node names is empty, +- * default to the standard pattern derived from +- * the reversed entity name */ +- if (policy->ip_node_names.count == 0) { +- char *pattern; +- +- pattern = isns_build_source_pattern(policy->ip_entity); +- if (pattern != NULL) +- isns_string_array_append(&policy->ip_node_names, +- pattern); +- isns_free(pattern); +- } +- +- isns_principal_set_policy(princ, policy); +- isns_policy_release(policy); +- +- /* Remember the keystore generation number */ +- princ->is_generation = ks->ic_generation; +- +- return princ; +-} +- +-/* +- * Create a keystore for a security context. +- * Key stores let the server side retrieve the +- * keys associated with a given SPI. +- * +- * For now, we support just simple key stores, +- * but this could be extended to support +- * URLs such as ldaps://ldap.example.com +- */ +-isns_keystore_t * +-isns_create_keystore(const char *spec) +-{ +- if (*spec != '/') +- return NULL; +- +- return isns_create_simple_keystore(spec); +-} +- +-/* +- * Attach the keystore to the security context +- */ +-void +-isns_security_set_keystore(isns_security_t *ctx, +- isns_keystore_t *ks) +-{ +- ctx->is_peer_keys = ks; +-} +- +-/* +- * Check that the client supplied time stamp is within a +- * certain window. +- */ +-static int +-isns_security_check_timestamp(isns_security_t *ctx, +- isns_principal_t *peer, +- uint64_t timestamp) +-{ +- int64_t delta; +- +- /* The time stamp must not be earlier than timestamp_jitter +- * before the last message received. */ +- if (peer->is_timestamp) { +- delta = timestamp - peer->is_timestamp; +- if (delta < -(int64_t) ctx->is_timestamp_jitter) +- return 0; +- } +- +- /* We allow the client's clock to diverge from ours, within +- * certain limits. */ +- if (ctx->is_replay_window != 0) { +- time_t now = time(NULL); +- +- delta = timestamp - now; +- if (delta < 0) +- delta = -delta; +- if (delta > ctx->is_replay_window) +- return 0; +- } +- +- peer->is_timestamp = timestamp; +- return 1; +-} +- +-int +-isns_security_sign(isns_security_t *ctx, isns_principal_t *peer, +- buf_t *bp, struct isns_authblk *auth) +-{ +- if (!ctx->is_sign) { +- isns_debug_auth("isns_security_sign: auth context without " +- "sign handler.\n"); +- return 0; +- } +- if (!ctx->is_sign(ctx, peer, bp, auth)) { +- isns_debug_auth("Failed to sign message, spi=%s\n", +- peer->is_name); +- return 0; +- } +- +- return 1; +-} +- +-int +-isns_security_verify(isns_security_t *ctx, isns_principal_t *peer, +- buf_t *bp, struct isns_authblk *auth) +-{ +- if (!isns_security_check_timestamp(ctx, peer, auth->iab_timestamp)) { +- isns_debug_auth("Possible replay attack (bad timestamp) " +- "from spi=%s\n", peer->is_name); +- return 0; +- } +- +- if (!ctx->is_verify) { +- isns_debug_auth("isns_security_verify: auth context without " +- "verify handler.\n"); +- return 0; +- } +- if (!ctx->is_verify(ctx, peer, bp, auth)) { +- isns_debug_auth("Failed to authenticate message, spi=%s\n", +- peer->is_name); +- return 0; +- } +- +- return 1; +-} +- +-/* +- * Initialize security services. +- */ +-int +-isns_security_init(void) +-{ +- if (!isns_config.ic_dsa.param_file) { +- isns_error("No DSA parameter file - please edit configuration\n"); +- return 0; +- } +- +- if (!isns_dsa_init_params(isns_config.ic_dsa.param_file)) +- return 0; +- +- if (!isns_config.ic_auth_key_file) { +- isns_error("No AuthKey specified; please edit configuration\n"); +- return 0; +- } +- +- if (!isns_dsa_init_key(isns_config.ic_auth_key_file)) +- return 0; +- +- return 1; +-} +- +-#else /* WITH_SECURITY */ +- +-static void +-isns_no_security(void) +-{ +- static int complain = 0; +- +- if (complain++ < 5) +- isns_error("iSNS authentication disabled in this build\n"); +-} +- +-int +-isns_security_init(void) +-{ +- isns_no_security(); +- return 0; +-} +- +-isns_keystore_t * +-isns_create_keystore(const char *spec) +-{ +- isns_no_security(); +- return NULL; +-} +- +-void +-isns_security_set_keystore(isns_security_t *ctx, +- isns_keystore_t *ks) +-{ +- isns_no_security(); +-} +- +-void +-isns_principal_free(isns_principal_t *peer) +-{ +-} +- +-isns_principal_t * +-isns_get_principal(isns_security_t *ctx, const char *spi, size_t spi_len) +-{ +- return NULL; +-} +- +-const char * +-isns_principal_name(const isns_principal_t *princ) +-{ +- return NULL; +-} +- +-#endif /* WITH_SECURITY */ +diff --git a/utils/open-isns/security.h b/utils/open-isns/security.h +deleted file mode 100644 +index 4b928ff..0000000 +--- a/utils/open-isns/security.h ++++ /dev/null +@@ -1,185 +0,0 @@ +-/* +- * Security functions for iSNS +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#ifndef ISNS_SECURITY_H +-#define ISNS_SECURITY_H +-#include "buffer.h" +-#include "util.h" +- +- +-#ifdef WITH_SECURITY +-#include +-#else +-#define EVP_PKEY void +-#endif +- +-/* +- * Security context +- */ +-struct isns_security { +- const char * is_name; +- unsigned int is_type; +- unsigned int is_replay_window; +- unsigned int is_timestamp_jitter; +- +- /* Our own key and identity */ +- isns_principal_t * is_self; +- +- /* Key store for peer keys */ +- isns_principal_t * is_peers; +- isns_keystore_t * is_peer_keys; +- +- EVP_PKEY * (*is_load_private)(isns_security_t *ctx, +- const char *filename); +- EVP_PKEY * (*is_load_public)(isns_security_t *ctx, +- const char *filename); +- int (*is_verify)(isns_security_t *ctx, +- isns_principal_t *peer, +- buf_t *pdu, +- const struct isns_authblk *); +- int (*is_sign)(isns_security_t *ctx, +- isns_principal_t *peer, +- buf_t *pdu, +- struct isns_authblk *); +-}; +- +-struct isns_principal { +- unsigned int is_users; +- isns_principal_t * is_next; +- char * is_name; +- unsigned int is_namelen; +- EVP_PKEY * is_key; +- unsigned int is_generation; +- uint64_t is_timestamp; +- +- isns_policy_t * is_policy; +-}; +- +-struct isns_policy { +- unsigned int ip_users; +- unsigned int ip_gen; +- +- /* SPI */ +- char * ip_name; +- +- /* The client's entity name. This is usually +- * the FQDN. */ +- char * ip_entity; +- +- /* Bitmap of functions the client is +- * permitted to call. */ +- unsigned int ip_functions; +- +- /* Bitmap of object types the client is +- * permitted to register (uses iot_handle) */ +- unsigned int ip_object_types; +- +- /* Names of storage nodes the client is permitted +- * to register. */ +- struct string_array ip_node_names; +- +- /* Storage node types the client is permitted +- * to read or modify. */ +- unsigned int ip_node_types; +- +- /* The client's default Discovery Domain */ +- char * ip_dd_default; +-}; +- +-#define ISNS_PERMISSION_READ 0x01 +-#define ISNS_PERMISSION_WRITE 0x02 +-#define ISNS_ACCESS(t, p) ((p) << (2 * (t))) +-#define ISNS_ACCESS_W(t) ISNS_ACCESS(t, ISNS_PERMISSION_WRITE) +-#define ISNS_ACCESS_R(t) ISNS_ACCESS(t, ISNS_PERMISSION_READ) +-#define ISNS_ACCESS_RW(t) ISNS_ACCESS(t, ISNS_PERMISSION_READ|ISNS_PERMISSION_WRITE) +- +-#define ISNS_DEFAULT_OBJECT_ACCESS \ +- ISNS_ACCESS_RW(ISNS_OBJECT_TYPE_ENTITY) | \ +- ISNS_ACCESS_RW(ISNS_OBJECT_TYPE_NODE) | \ +- ISNS_ACCESS_RW(ISNS_OBJECT_TYPE_FC_PORT) | \ +- ISNS_ACCESS_RW(ISNS_OBJECT_TYPE_FC_NODE) | \ +- ISNS_ACCESS_RW(ISNS_OBJECT_TYPE_PORTAL) | \ +- ISNS_ACCESS_RW(ISNS_OBJECT_TYPE_PG) | \ +- ISNS_ACCESS_R(ISNS_OBJECT_TYPE_DD) +- +-struct isns_keystore { +- char * ic_name; +- unsigned int ic_generation; +- EVP_PKEY * (*ic_find)(isns_keystore_t *, +- const char *, size_t); +- isns_policy_t * (*ic_get_policy)(isns_keystore_t *, +- const char *, size_t); +-}; +- +-extern isns_principal_t * isns_get_principal(isns_security_t *, +- const char *, size_t); +-extern int isns_security_sign(isns_security_t *, +- isns_principal_t *, buf_t *, +- struct isns_authblk *); +-extern int isns_security_verify(isns_security_t *, +- isns_principal_t *, buf_t *, +- struct isns_authblk *); +-extern int isns_security_protected_entity(isns_security_t *, +- const char *); +- +-extern isns_keystore_t * isns_create_keystore(const char *); +-extern isns_keystore_t * isns_create_simple_keystore(const char *); +-extern isns_keystore_t * isns_create_db_keystore(isns_db_t *); +- +-extern int isns_authblock_encode(buf_t *, +- const struct isns_authblk *); +-extern int isns_authblock_decode(buf_t *, +- struct isns_authblk *); +- +-extern isns_policy_t * __isns_policy_alloc(const char *, size_t); +-extern isns_policy_t * isns_policy_bind(const isns_message_t *); +-extern void isns_principal_set_policy(isns_principal_t *, +- isns_policy_t *); +-extern void isns_policy_release(isns_policy_t *); +-extern int isns_policy_validate_function(const isns_policy_t *, +- const isns_message_t *); +-extern int isns_policy_validate_source(const isns_policy_t *, +- const isns_source_t *); +-extern int isns_policy_validate_object_access(const isns_policy_t *, +- const isns_source_t *, +- const isns_object_t *, +- unsigned int); +-extern int isns_policy_validate_object_update(const isns_policy_t *, +- const isns_source_t *, +- const isns_object_t *, +- const isns_attr_list_t *, +- unsigned int); +-extern int isns_policy_validate_object_creation(const isns_policy_t *, +- const isns_source_t *, +- isns_object_template_t *, +- const isns_attr_list_t *, +- const isns_attr_list_t *, +- unsigned int); +-extern int isns_policy_validate_object_type(const isns_policy_t *, +- isns_object_template_t *, +- unsigned int function); +-extern int isns_policy_validate_node_type(const isns_policy_t *, +- uint32_t type); +-extern int isns_policy_validate_entity(const isns_policy_t *, +- const char *); +-extern int isns_policy_validate_node_name(const isns_policy_t *, +- const char *); +-extern int isns_policy_validate_scn_bitmap(const isns_policy_t *, +- uint32_t); +-extern const char * isns_policy_default_entity(const isns_policy_t *); +-extern isns_policy_t * isns_policy_default(const char *, size_t); +-extern isns_policy_t * isns_policy_server(void); +- +-extern EVP_PKEY * isns_dsa_decode_public(const void *, size_t); +-extern int isns_dsa_encode_public(EVP_PKEY *, +- void **, size_t *); +-extern EVP_PKEY * isns_dsa_load_public(const char *); +-extern int isns_dsa_store_private(const char *, EVP_PKEY *); +-extern EVP_PKEY * isns_dsa_generate_key(void); +-extern int isns_dsa_init_params(const char *); +-extern int isns_dsa_init_key(const char *); +- +-#endif /* ISNS_SECURITY_H */ +diff --git a/utils/open-isns/server.c b/utils/open-isns/server.c +deleted file mode 100644 +index 0f1c937..0000000 +--- a/utils/open-isns/server.c ++++ /dev/null +@@ -1,236 +0,0 @@ +-/* +- * iSNS server side functions +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include "isns.h" +-#include "util.h" +-#include "security.h" +-#include "message.h" +- +-static int isns_not_supported(isns_server_t *, isns_simple_t *, isns_simple_t **); +- +-struct isns_service_ops isns_default_service_ops = { +- .process_registration = isns_process_registration, +- .process_query = isns_process_query, +- .process_getnext = isns_process_getnext, +- .process_deregistration = isns_process_deregistration, +- .process_scn_registration = isns_process_scn_register, +- .process_scn_deregistration = isns_process_scn_deregistration, +- .process_scn_event = isns_not_supported, +- .process_dd_registration = isns_process_dd_registration, +- .process_dd_deregistration= isns_process_dd_deregistration, +-}; +- +-struct isns_service_ops isns_callback_service_ops = { +- .process_esi = isns_process_esi, +- .process_scn = isns_process_scn, +-}; +- +-/* +- * Create a server object +- */ +-isns_server_t * +-isns_create_server(isns_source_t *source, isns_db_t *db, +- struct isns_service_ops *ops) +-{ +- isns_server_t *srv; +- +- if (source == NULL) { +- isns_error("%s: source name not set\n", __FUNCTION__); +- return NULL; +- } +- +- srv = isns_calloc(1, sizeof(*srv)); +- srv->is_source = isns_source_get(source); +- srv->is_db = db; +- srv->is_ops = ops; +- +- return srv; +-} +- +-void +-isns_server_set_scn_callback(isns_server_t *srv, isns_scn_callback_fn_t *func) +-{ +- srv->is_scn_callback = func; +-} +- +-/* +- * Try to handle transactions safely. +- * This isn't perfect, because there's state outside the DB (for instance +- * the DD information) +- */ +-static int +-isns_begin_write_operation(isns_server_t *srv, isns_simple_t *msg, int *status) +-{ +- isns_db_begin_transaction(srv->is_db); +- return 1; +-} +- +-static void +-isns_end_write_operation(isns_server_t *srv, isns_simple_t *msg, int *status) +-{ +- if (*status == ISNS_SUCCESS) +- isns_db_commit(srv->is_db); +- else +- isns_db_rollback(srv->is_db); +-} +- +-static inline int +-isns_begin_read_operation(isns_server_t *srv, isns_simple_t *msg, int *status) +-{ +- return 1; +-} +- +-static void +-isns_end_read_operation(isns_server_t *srv, isns_simple_t *msg, int *status) +-{ +-} +- +-/* +- * Process an incoming message +- */ +-isns_message_t * +-isns_process_message(isns_server_t *srv, isns_message_t *msg) +-{ +- struct isns_service_ops *ops = srv->is_ops; +- uint16_t function = msg->im_header.i_function; +- int status = ISNS_SUCCESS; +- isns_simple_t *call = NULL, *reply = NULL; +- isns_message_t *res_msg = NULL; +- isns_db_t *db = srv->is_db; +- +- status = isns_simple_decode(msg, &call); +- if (status) { +- isns_debug_message("Failed to decode %s request: %s\n", +- isns_function_name(msg->im_header.i_function), +- isns_strerror(status)); +- goto reply; +- } +- +- isns_simple_print(call, isns_debug_message); +- +- /* Set policy and privileges based on the +- * sender's identity. */ +- if (!(call->is_policy = isns_policy_bind(msg))) +- goto err_unauthorized; +- +- if (!isns_policy_validate_function(call->is_policy, msg)) +- goto err_unauthorized; +- +- /* Checks related to the message source. +- * Note - some messages do not use a source. +- */ +- if (call->is_source) { +- /* Validate the message source. This checks whether the client +- * is permitted to use this source node name. +- * Beware - not all messages include a source. +- */ +- if (!isns_policy_validate_source(call->is_policy, call->is_source)) +- goto err_unauthorized; +- +- /* This may fail if the source node isn't in the DB yet. */ +- isns_source_set_node(call->is_source, db); +- +- /* +- * 6.2.6. Registration Period +- * +- * The registration SHALL be removed from the iSNS database +- * if an iSNS Protocol message is not received from the +- * iSNS client before the registration period has expired. +- * Receipt of any iSNS Protocol message from the iSNS client +- * automatically refreshes the Entity Registration Period and +- * Entity Registration Timestamp. To prevent a registration +- * from expiring, the iSNS client should send an iSNS Protocol +- * message to the iSNS server at intervals shorter than the +- * registration period. Such a message can be as simple as a +- * query for one of its own attributes, using its associated +- * iSCSI Name or FC Port Name WWPN as the Source attribute. +- */ +- /* Thusly, we update the timestamps of all entities +- * registered by this source. */ +- isns_entity_touch(call->is_source->is_entity); +- } +- +- /* Handle the requested function. If the function vector is +- * NULL, silently discard the message. */ +- switch (function) { +-#define DO(rw, FUNCTION, __function) \ +- case FUNCTION: \ +- if (!ops->__function) \ +- goto no_reply; \ +- \ +- if (!isns_begin_##rw##_operation(srv, call, &status)) \ +- break; \ +- status = ops->__function(srv, call, &reply); \ +- isns_end_##rw##_operation(srv, call, &status); \ +- break +- +- DO(write, ISNS_DEVICE_ATTRIBUTE_REGISTER, process_registration); +- DO(read, ISNS_DEVICE_ATTRIBUTE_QUERY, process_query); +- DO(read, ISNS_DEVICE_GET_NEXT, process_getnext); +- DO(write, ISNS_DEVICE_DEREGISTER, process_deregistration); +- DO(write, ISNS_DD_REGISTER, process_dd_registration); +- DO(write, ISNS_DD_DEREGISTER, process_dd_deregistration); +- DO(read, ISNS_SCN_REGISTER, process_scn_registration); +- DO(read, ISNS_SCN_DEREGISTER, process_scn_deregistration); +- DO(read, ISNS_SCN_EVENT, process_scn_event); +- DO(read, ISNS_STATE_CHANGE_NOTIFICATION, process_scn); +- DO(read, ISNS_ENTITY_STATUS_INQUIRY, process_esi); +- DO(read, ISNS_HEARTBEAT, process_heartbeat); +-#undef DO +- +- default: +- isns_error("Function %s not supported\n", +- isns_function_name(function)); +- status = ISNS_MESSAGE_NOT_SUPPORTED; +- break; +- } +- +-reply: +- /* Commit any changes to the DB before we reply */ +- if (db) +- isns_db_sync(db); +- +- /* Send out SCN notifications */ +- isns_flush_events(); +- +- if (reply != NULL) { +- reply->is_function |= 0x8000; +- isns_simple_print(reply, isns_debug_message); +- +- /* Encode the whole thing */ +- status = isns_simple_encode_response(reply, msg, &res_msg); +- } +- +- /* No reply, or error when encoding it: +- * just send the error, nothing else. */ +- if (res_msg == NULL) { +- res_msg = isns_create_reply(msg); +- if (status == ISNS_SUCCESS) +- status = ISNS_INTERNAL_ERROR; +- } +- +- isns_debug_message("response status 0x%04x (%s)\n", +- status, isns_strerror(status)); +- +- if (status != ISNS_SUCCESS) +- isns_message_set_error(res_msg, status); +- +-no_reply: +- isns_simple_free(call); +- if (reply) +- isns_simple_free(reply); +- return res_msg; +- +-err_unauthorized: +- status = ISNS_SOURCE_UNAUTHORIZED; +- goto reply; +-} +- +-int +-isns_not_supported(isns_server_t *srv, isns_simple_t *call, isns_simple_t **replyp) +-{ +- return ISNS_MESSAGE_NOT_SUPPORTED; +-} +diff --git a/utils/open-isns/simple.c b/utils/open-isns/simple.c +deleted file mode 100644 +index 1af89fd..0000000 +--- a/utils/open-isns/simple.c ++++ /dev/null +@@ -1,727 +0,0 @@ +-/* +- * Common handling for iSNS message parsing +- * +- * Copyright (C) 2007 Olaf Kirch +- * +- */ +- +-#include +-#include +-#include "isns.h" +-#include "attrs.h" +-#include "message.h" +-#include "objects.h" +-#include "security.h" +-#include "socket.h" +-#include "util.h" +- +-typedef void isns_simple_callback_fn_t(uint32_t, int status, isns_simple_t *); +- +-static int isns_attr_list_scanner_get_pg(struct isns_attr_list_scanner *st); +- +-/* +- * Allocate an empty simple message +- */ +-static isns_simple_t * +-__isns_alloc_simple(void) +-{ +- isns_simple_t *simp; +- +- simp = isns_calloc(1, sizeof(*simp)); +- +- isns_attr_list_init(&simp->is_message_attrs); +- isns_attr_list_init(&simp->is_operating_attrs); +- +- return simp; +-} +- +-/* +- * Create a simple message, and set the source name +- */ +-isns_simple_t * +-isns_simple_create(uint32_t function, isns_source_t *source, +- const isns_attr_list_t *key) +-{ +- isns_simple_t *simp; +- +- simp = __isns_alloc_simple(); +- simp->is_function = function; +- simp->is_source = source; +- if (source != NULL) +- source->is_users++; +- +- if (key) +- isns_attr_list_copy(&simp->is_message_attrs, key); +- +- return simp; +-} +- +-/* +- * Perform a call to the server, waiting for the response. +- */ +-int +-isns_simple_call(isns_socket_t *sock, isns_simple_t **inout) +-{ +- isns_simple_t *simp = *inout; +- isns_message_t *msg, *resp; +- int status; +- +- isns_simple_print(simp, isns_debug_message); +- +- status = isns_simple_encode(simp, &msg); +- if (status != ISNS_SUCCESS) { +- isns_error("Unable to encode %s: %s\n", +- isns_function_name(simp->is_function), +- isns_strerror(status)); +- return status; +- } +- +- isns_debug_message("Sending request, len=%d\n", +- buf_avail(msg->im_payload)); +- +- resp = isns_socket_call(sock, msg, +- isns_config.ic_network.call_timeout); +- isns_assert(msg->im_users == 1); +- isns_message_release(msg); +- +- if (resp == NULL) { +- isns_error("Timed out while waiting for reply\n"); +- return ISNS_INTERNAL_ERROR; +- } +- +- isns_debug_message("Received reply, len=%d\n", +- buf_avail(resp->im_payload)); +- isns_assert(resp->im_users == 1); +- +- status = isns_message_status(resp); +- if (status != ISNS_SUCCESS) { +- isns_message_release(resp); +- return status; +- } +- +- status = isns_simple_decode(resp, &simp); +- isns_message_release(resp); +- +- if (status) { +- isns_error("Unable to decode server response: %s (status 0x%04x)\n", +- isns_strerror(status), status); +- return status; +- } +- +- isns_simple_print(simp, isns_debug_message); +- +- isns_simple_free(*inout); +- *inout = simp; +- return ISNS_SUCCESS; +-} +- +-/* +- * This callback is invoked from the network layer when +- * we received a response to an async message +- */ +-static void +-isns_simple_recv_response(isns_message_t *cmsg, isns_message_t *rmsg) +-{ +- isns_simple_callback_fn_t *user_callback; +- isns_simple_t *resp = NULL; +- int status = ISNS_INTERNAL_ERROR; +- +- /* rmsg being NULL means the call timed out. */ +- if (rmsg == NULL) +- goto callback; +- +- status = isns_message_status(rmsg); +- if (status != ISNS_SUCCESS) { +- isns_error("Server flags error: %s (status 0x%04x)\n", +- isns_strerror(status), status); +- goto callback; +- } +- +- status = isns_simple_decode(rmsg, &resp); +- if (status) { +- isns_error("Unable to decode server response: %s (status 0x%04x)\n", +- isns_strerror(status), status); +- resp = NULL; +- goto callback; +- } +- +- isns_simple_print(resp, isns_debug_message); +- +-callback: +- user_callback = cmsg->im_calldata; +- if (user_callback) +- user_callback(cmsg->im_xid, status, resp); +- if (resp) +- isns_simple_free(resp); +-} +- +-/* +- * Transmit a call, without waiting for the response. +- */ +-int +-isns_simple_transmit(isns_socket_t *sock, isns_simple_t *call, +- const isns_portal_info_t *dest, +- unsigned int timeout, +- isns_simple_callback_fn_t *user_callback) +-{ +- isns_message_t *msg; +- int status; +- +- isns_simple_print(call, isns_debug_message); +- +- status = isns_simple_encode(call, &msg); +- if (status != ISNS_SUCCESS) { +- isns_error("Unable to encode %s: %s\n", +- isns_function_name(call->is_function), +- isns_strerror(status)); +- return status; +- } +- +- isns_debug_message("Sending message, len=%d\n", +- buf_avail(msg->im_payload)); +- +- if (user_callback) { +- msg->im_callback = isns_simple_recv_response; +- msg->im_calldata = user_callback; +- } +- +- if (!isns_socket_submit(sock, msg, timeout)) +- status = ISNS_INTERNAL_ERROR; +- isns_message_release(msg); +- return status; +-} +- +-/* +- * Delete the simple message object +- */ +-void +-isns_simple_free(isns_simple_t *simp) +-{ +- if (simp == NULL) +- return; +- +- isns_attr_list_destroy(&simp->is_message_attrs); +- isns_attr_list_destroy(&simp->is_operating_attrs); +- isns_source_release(simp->is_source); +- isns_policy_release(simp->is_policy); +- isns_free(simp); +-} +- +-/* +- * Get the source associated with this simple message +- */ +-isns_source_t * +-isns_simple_get_source(isns_simple_t *simp) +-{ +- return simp->is_source; +-} +- +-const isns_attr_list_t * +-isns_simple_get_attrs(isns_simple_t *simp) +-{ +- return &simp->is_operating_attrs; +-} +- +-/* +- * Determine whether message includes a source attr. +- */ +-static inline int +-isns_simple_include_source(uint16_t function) +-{ +- if (function & 0x8000) +- return 0; +- switch (function) { +- case ISNS_STATE_CHANGE_NOTIFICATION: +- case ISNS_ENTITY_STATUS_INQUIRY: +- return 0; +- } +- return 1; +-} +- +-/* +- * Decode a simple message +- */ +-int +-isns_simple_decode(isns_message_t *msg, isns_simple_t **result) +-{ +- isns_simple_t *simp = __isns_alloc_simple(); +- buf_t *bp = msg->im_payload; +- int status = ISNS_SUCCESS; +- +- simp->is_function = msg->im_header.i_function; +- simp->is_xid = msg->im_xid; +- +- if (isns_simple_include_source(simp->is_function)) { +- status = isns_source_decode(bp, &simp->is_source); +- if (status != ISNS_SUCCESS) +- goto out; +- } +- +- switch (simp->is_function & 0x7FFF) { +- case ISNS_ENTITY_STATUS_INQUIRY: +- case ISNS_STATE_CHANGE_NOTIFICATION: +- /* Server messages do not include a source */ +- status = isns_attr_list_decode(bp, +- &simp->is_message_attrs); +- break; +- +- default: +- status = isns_attr_list_decode_delimited(bp, +- &simp->is_message_attrs); +- if (status == ISNS_SUCCESS) +- status = isns_attr_list_decode(bp, +- &simp->is_operating_attrs); +- } +- +- if (msg->im_header.i_flags & ISNS_F_REPLACE) +- simp->is_replace = 1; +- +-out: +- if (status == ISNS_SUCCESS) { +- *result = simp; +- } else { +- isns_simple_free(simp); +- *result = NULL; +- } +- return status; +-} +- +-/* +- * Encode a simple message reply or response +- */ +-static int +-__isns_simple_encode(isns_simple_t *simp, buf_t *bp) +-{ +- int status = ISNS_SUCCESS; +- +- if (isns_simple_include_source(simp->is_function)) { +- if (simp->is_source == NULL) { +- isns_error("Cannot encode %s message - caller forgot to set source\n", +- isns_function_name(simp->is_function)); +- return ISNS_SOURCE_UNKNOWN; +- } +- status = isns_source_encode(bp, simp->is_source); +- } +- +- if (status == ISNS_SUCCESS) +- status = isns_attr_list_encode(bp, &simp->is_message_attrs); +- +- /* Some functions have just one set of attrs. */ +- switch (simp->is_function & 0x7fff) { +- /* It's not entirely clear which calls actually have the delimiter. +- * The spec is sometimes a little vague on this. */ +- case ISNS_SCN_DEREGISTER: +- case ISNS_ENTITY_STATUS_INQUIRY: +- case ISNS_STATE_CHANGE_NOTIFICATION: +- break; +- +- default: +- if (status == ISNS_SUCCESS) +- status = isns_encode_delimiter(bp); +- if (status == ISNS_SUCCESS) +- status = isns_attr_list_encode(bp, &simp->is_operating_attrs); +- break; +- } +- +- return status; +-} +- +-int +-isns_simple_encode(isns_simple_t *simp, isns_message_t **result) +-{ +- isns_message_t *msg; +- int status, flags; +- +- flags = ISNS_F_CLIENT; +- if (simp->is_replace) +- flags |= ISNS_F_REPLACE; +- msg = isns_create_message(simp->is_function, flags); +- +- /* FIXME: for UDP sockets, isns_simple_t may contain a +- destination address. */ +- +- status = __isns_simple_encode(simp, msg->im_payload); +- if (status != ISNS_SUCCESS) { +- isns_message_release(msg); +- msg = NULL; +- } +- +- /* Report the XID to the caller */ +- simp->is_xid = msg->im_xid; +- +- *result = msg; +- return status; +-} +- +-int +-isns_simple_encode_response(isns_simple_t *reg, +- const isns_message_t *request, isns_message_t **result) +-{ +- isns_message_t *msg; +- int status; +- +- msg = isns_create_reply(request); +- +- status = __isns_simple_encode(reg, msg->im_payload); +- if (status != ISNS_SUCCESS) { +- isns_message_release(msg); +- msg = NULL; +- } +- +- *result = msg; +- return status; +-} +- +-int +-isns_simple_decode_response(isns_message_t *resp, isns_simple_t **result) +-{ +- return isns_simple_decode(resp, result); +-} +- +-/* +- * Extract the list of objects from a DevAttrReg/DevAttrQry +- * response or similar. +- */ +-int +-isns_simple_response_get_objects(isns_simple_t *resp, +- isns_object_list_t *result) +-{ +- struct isns_attr_list_scanner state; +- int status = ISNS_SUCCESS; +- +- isns_attr_list_scanner_init(&state, NULL, &resp->is_operating_attrs); +- while (1) { +- isns_object_t *obj; +- +- status = isns_attr_list_scanner_next(&state); +- if (status == ISNS_NO_SUCH_ENTRY) { +- status = ISNS_SUCCESS; +- break; +- } +- if (status) +- break; +- +- obj = isns_create_object(state.tmpl, &state.keys, NULL); +- +- isns_object_set_attrlist(obj, &state.attrs); +- if (obj != state.key_obj) +- isns_object_list_append(result, obj); +- isns_object_release(obj); +- } +- +- isns_attr_list_scanner_destroy(&state); +- return status; +-} +- +-/* +- * Print a simple message object +- */ +-void +-isns_simple_print(isns_simple_t *simp, isns_print_fn_t *fn) +-{ +- char buffer[256]; +- +- if (fn == isns_debug_message +- && !isns_debug_enabled(DBG_MESSAGE)) +- return; +- +- fn("---%s%s---\n", +- isns_function_name(simp->is_function), +- simp->is_replace? "[REPLACE]" : ""); +- if (simp->is_source) { +- fn("Source:\n", buffer); +- isns_attr_print(simp->is_source->is_attr, fn); +- } else { +- fn("Source: \n"); +- } +- +- if (simp->is_message_attrs.ial_count == 0) { +- fn("Message attributes: \n"); +- } else { +- fn("Message attributes:\n"); +- isns_attr_list_print(&simp->is_message_attrs, fn); +- } +- if (simp->is_operating_attrs.ial_count == 0) { +- fn("Operating attributes: \n"); +- } else { +- fn("Operating attributes:\n"); +- isns_attr_list_print(&simp->is_operating_attrs, fn); +- } +-} +- +-/* +- * This set of functions analyzes the operating attrs of a registration, +- * or a query response, and chops it up into separate chunks, one +- * per objects. +- * +- * It always returns the keys and attrs for one object, +- * following the ordering constraints laid out in the RFC. +- */ +-void +-isns_attr_list_scanner_init(struct isns_attr_list_scanner *st, +- isns_object_t *key_obj, +- const isns_attr_list_t *attrs) +-{ +- memset(st, 0, sizeof(*st)); +- st->orig_attrs = *attrs; +- st->key_obj = key_obj; +-} +- +-void +-isns_attr_list_scanner_destroy(struct isns_attr_list_scanner *st) +-{ +- isns_attr_list_destroy(&st->keys); +- isns_attr_list_destroy(&st->attrs); +- memset(st, 0, sizeof(*st)); +-} +- +-int +-isns_attr_list_scanner_next(struct isns_attr_list_scanner *st) +-{ +- isns_attr_t *attr; +- unsigned int i, pos = st->pos; +- +- isns_attr_list_destroy(&st->keys); +- isns_attr_list_destroy(&st->attrs); +- +- if (st->orig_attrs.ial_count <= pos) +- return ISNS_NO_SUCH_ENTRY; +- +- attr = st->orig_attrs.ial_data[pos]; +- +- /* handle those funky inlined PGT definitions */ +- if (st->pgt_next_attr && attr->ia_tag_id == st->pgt_next_attr) +- return isns_attr_list_scanner_get_pg(st); +- +- /* This isn't really structured programming anymore */ +- if (st->index_acceptable +- && (st->tmpl = isns_object_template_for_index_tag(attr->ia_tag_id))) +- goto copy_attrs; +- +- /* +- * Find the object template for the given key attr(s). +- * This function also enforces restrictions on the +- * order of key attributes. +- */ +- st->tmpl = isns_object_template_find(attr->ia_tag_id); +- if (st->tmpl == NULL) { +- isns_debug_protocol("%s: attr %u is not a key attr\n", +- __FUNCTION__, attr->ia_tag_id); +- return ISNS_INVALID_REGISTRATION; +- } +- +- /* Copy the key attrs */ +- for (i = 0; i < st->tmpl->iot_num_keys; ++i, ++pos) { +- if (pos >= st->orig_attrs.ial_count) { +- isns_debug_protocol("%s: incomplete %s object " +- "(key attr %u missing)\n", +- __FUNCTION__, st->tmpl->iot_name, pos); +- return ISNS_INVALID_REGISTRATION; +- } +- attr = st->orig_attrs.ial_data[pos]; +- +- /* Make sure key attrs are complete and in order */ +- if (attr->ia_tag_id != st->tmpl->iot_keys[i]) { +- isns_debug_protocol("%s: incomplete %s object " +- "(key attr %u missing)\n", +- __FUNCTION__, st->tmpl->iot_name, pos); +- return ISNS_INVALID_REGISTRATION; +- } +- +- isns_attr_list_append_attr(&st->keys, attr); +- } +- +- /* +- * Consume all non-key attributes corresponding to the +- * object class. We stop whenever we hit another +- * key attribute, or an attribute that does not belong to +- * the object type (eg when a storage node is followed by +- * a PGT attribute, as described in section 5.6.5.1). +- */ +-copy_attrs: +- while (pos < st->orig_attrs.ial_count) { +- uint32_t tag; +- +- attr = st->orig_attrs.ial_data[pos]; +- tag = attr->ia_tag_id; +- +- if (!isns_object_attr_valid(st->tmpl, tag) +- || isns_object_template_find(tag) != NULL) +- break; +- +- pos++; +- isns_attr_list_append_attr(&st->attrs, attr); +- } +- st->pos = pos; +- +- return ISNS_SUCCESS; +-} +- +-int +-isns_attr_list_scanner_get_pg(struct isns_attr_list_scanner *st) +-{ +- isns_attr_t *attr, *next = NULL; +- unsigned int pos = st->pos; +- +- +- attr = st->orig_attrs.ial_data[st->pos++]; +- if (st->pgt_next_attr == ISNS_TAG_PG_TAG) { +- isns_object_t *base = st->pgt_base_object; +- +- if (ISNS_ATTR_IS_NIL(attr)) +- st->pgt_value = 0; +- else if (ISNS_ATTR_IS_UINT32(attr)) +- st->pgt_value = attr->ia_value.iv_uint32; +- else +- return ISNS_INVALID_REGISTRATION; +- +- if (ISNS_IS_PORTAL(base) +- && isns_portal_from_object(&st->pgt_portal_info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- base)) { +- st->pgt_next_attr = ISNS_TAG_PG_ISCSI_NAME; +- } else +- if (ISNS_IS_ISCSI_NODE(base) +- && isns_object_get_string(base, +- ISNS_TAG_ISCSI_NAME, +- &st->pgt_iscsi_name)) { +- st->pgt_next_attr = ISNS_TAG_PORTAL_IP_ADDRESS; +- } else { +- return ISNS_INTERNAL_ERROR; +- } +- +- /* Trailing PGT at end of list. Shrug. */ +- if (st->pos >= st->orig_attrs.ial_count) +- return ISNS_NO_SUCH_ENTRY; +- +- attr = st->orig_attrs.ial_data[st->pos++]; +- if (attr->ia_tag_id != st->pgt_next_attr) { +- /* Some clients may do this; catch them so +- * we can fix it. */ +- isns_error("Oops, client sends PGT followed by <%s>\n", +- attr->ia_tag->it_name); +- return ISNS_INVALID_REGISTRATION; +- } +- } +- +- st->tmpl = &isns_iscsi_pg_template; +- if (st->pgt_next_attr == ISNS_TAG_PG_ISCSI_NAME) { +- isns_attr_list_append_attr(&st->keys, attr); +- isns_portal_to_attr_list(&st->pgt_portal_info, +- ISNS_TAG_PG_PORTAL_IP_ADDR, +- ISNS_TAG_PG_PORTAL_TCP_UDP_PORT, +- &st->keys); +- } else +- if (st->pgt_next_attr == ISNS_TAG_PG_PORTAL_IP_ADDR) { +- if (st->pos >= st->orig_attrs.ial_count) +- return ISNS_INVALID_REGISTRATION; +- +- next = st->orig_attrs.ial_data[st->pos++]; +- if (next->ia_tag_id != ISNS_TAG_PORTAL_TCP_UDP_PORT) +- return ISNS_INVALID_REGISTRATION; +- +- isns_attr_list_append_string(&st->keys, +- ISNS_TAG_PG_ISCSI_NAME, +- st->pgt_iscsi_name); +- isns_attr_list_append_attr(&st->keys, attr); +- isns_attr_list_append_attr(&st->keys, next); +- } else { +- return ISNS_INTERNAL_ERROR; +- } +- +- isns_attr_list_append_uint32(&st->attrs, +- ISNS_TAG_PG_TAG, +- st->pgt_value); +- +- /* Copy other PG attributes if present */ +- for (pos = st->pos; pos < st->orig_attrs.ial_count; ++pos) { +- uint32_t tag; +- +- attr = st->orig_attrs.ial_data[pos]; +- tag = attr->ia_tag_id; +- +- /* +- * Additional sets of PGTs and PG iSCSI Names to be +- * associated to the registered Portal MAY follow. +- */ +- if (tag == ISNS_TAG_PG_TAG) { +- st->pgt_next_attr = tag; +- break; +- } +- +- if (tag == ISNS_TAG_PG_ISCSI_NAME +- || tag == ISNS_TAG_PG_PORTAL_IP_ADDR +- || tag == ISNS_TAG_PG_PORTAL_TCP_UDP_PORT +- || !isns_object_attr_valid(st->tmpl, tag)) +- break; +- +- isns_attr_list_append_attr(&st->attrs, attr); +- } +- st->pos = pos; +- +- return ISNS_SUCCESS; +-} +- +-/* +- * Get the name of a function +- */ +-#define __ISNS_MAX_FUNCTION 16 +-static const char * isns_req_function_names[__ISNS_MAX_FUNCTION] = { +-[ISNS_DEVICE_ATTRIBUTE_REGISTER]= "DevAttrReg", +-[ISNS_DEVICE_ATTRIBUTE_QUERY] = "DevAttrQry", +-[ISNS_DEVICE_GET_NEXT] = "DevGetNext", +-[ISNS_DEVICE_DEREGISTER] = "DevDereg", +-[ISNS_SCN_REGISTER] = "SCNReg", +-[ISNS_SCN_DEREGISTER] = "SCNDereg", +-[ISNS_SCN_EVENT] = "SCNEvent", +-[ISNS_STATE_CHANGE_NOTIFICATION]= "SCN", +-[ISNS_DD_REGISTER] = "DDReg", +-[ISNS_DD_DEREGISTER] = "DDDereg", +-[ISNS_DDS_REGISTER] = "DDSReg", +-[ISNS_DDS_DEREGISTER] = "DDSDereg", +-[ISNS_ENTITY_STATUS_INQUIRY] = "ESI", +-[ISNS_HEARTBEAT] = "Heartbeat", +-}; +-static const char * isns_resp_function_names[__ISNS_MAX_FUNCTION] = { +-[ISNS_DEVICE_ATTRIBUTE_REGISTER]= "DevAttrRegResp", +-[ISNS_DEVICE_ATTRIBUTE_QUERY] = "DevAttrQryResp", +-[ISNS_DEVICE_GET_NEXT] = "DevGetNextResp", +-[ISNS_DEVICE_DEREGISTER] = "DevDeregResp", +-[ISNS_SCN_REGISTER] = "SCNRegResp", +-[ISNS_SCN_DEREGISTER] = "SCNDeregResp", +-[ISNS_SCN_EVENT] = "SCNEventResp", +-[ISNS_STATE_CHANGE_NOTIFICATION]= "SCNResp", +-[ISNS_DD_REGISTER] = "DDRegResp", +-[ISNS_DD_DEREGISTER] = "DDDeregResp", +-[ISNS_DDS_REGISTER] = "DDSRegResp", +-[ISNS_DDS_DEREGISTER] = "DDSDeregResp", +-[ISNS_ENTITY_STATUS_INQUIRY] = "ESIRsp", +-/* No response code for heartbeat */ +-}; +- +-const char * +-isns_function_name(uint32_t function) +-{ +- static char namebuf[32]; +- const char **names, *name; +- unsigned int num = function; +- +- names = isns_req_function_names; +- if (num & 0x8000) { +- names = isns_resp_function_names; +- num &= 0x7fff; +- } +- name = NULL; +- if (num < __ISNS_MAX_FUNCTION) +- name = names[num]; +- if (name == NULL) { +- snprintf(namebuf, sizeof(namebuf), +- "", +- function); +- name = namebuf; +- } +- +- return name; +-} +- +diff --git a/utils/open-isns/slp.c b/utils/open-isns/slp.c +deleted file mode 100644 +index 43075b3..0000000 +--- a/utils/open-isns/slp.c ++++ /dev/null +@@ -1,242 +0,0 @@ +-/* +- * SLP registration and query of iSNS +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include "config.h" +-#include +-#ifdef HAVE_SLP_H +-# include +-#endif +- +-#include "isns.h" +-#include "util.h" +-#include "internal.h" +- +-#define ISNS_SLP_SERVICE_NAME "iscsi:sms" +-/* +- * RFC 4018 says we would use scope initiator-scope-list. +- * But don't we want targets to find the iSNS server, too? +- */ +-#define ISNS_SLP_SCOPE "initiator-scope-list" +- +-#ifdef WITH_SLP +- +-struct isns_slp_url_state { +- SLPError slp_err; +- char * slp_url; +-}; +- +-static void +-isns_slp_report(SLPHandle handle, SLPError err, void *cookie) +-{ +- *(SLPError *) cookie = err; +-} +- +-/* +- * Register a service with SLP +- */ +-int +-isns_slp_register(const char *url) +-{ +- SLPError err, callbackerr; +- SLPHandle handle = NULL; +- +- err = SLPOpen("en", SLP_FALSE, &handle); +- if(err != SLP_OK) { +- isns_error("Unable to obtain SLP handle (err %d)\n", err); +- return 0; +- } +- +- err = SLPReg(handle, url, SLP_LIFETIME_MAXIMUM, +- ISNS_SLP_SCOPE, +- "(description=iSNS Server),(protocols=isns)", +- SLP_TRUE, +- isns_slp_report, &callbackerr); +- +- SLPClose(handle); +- +- if (err == SLP_OK) +- err = callbackerr; +- if (err != SLP_OK) { +- isns_error("Failed to register with SLP (err %d)\n", err); +- return 0; +- } +- +- return 1; +-} +- +-/* +- * DeRegister a service +- */ +-int +-isns_slp_unregister(const char *url) +-{ +- SLPError err, callbackerr; +- SLPHandle handle = NULL; +- +- isns_debug_general("SLP: Unregistering \"%s\"\n", url); +- +- err = SLPOpen("en", SLP_FALSE, &handle); +- if(err != SLP_OK) { +- isns_error("Unable to obtain SLP handle (err %d)\n", err); +- return 0; +- } +- +- err = SLPDereg(handle, url, isns_slp_report, &callbackerr); +- +- SLPClose(handle); +- +- if (err == SLP_OK) +- err = callbackerr; +- if (err != SLP_OK) { +- isns_error("Failed to deregister with SLP (err %d)\n", err); +- return 0; +- } +- +- return 1; +-} +- +-/* +- * Find an iSNS server through SLP +- */ +-static SLPBoolean +-isns_slp_url_callback(SLPHandle handle, +- const char *url, unsigned short lifetime, +- SLPError err, void *cookie) +-{ +- struct isns_slp_url_state *sp = cookie; +- SLPSrvURL *parsed_url = NULL; +- int want_more = SLP_TRUE; +- char buffer[1024]; +- +- if (err != SLP_OK && err != SLP_LAST_CALL) +- return SLP_FALSE; +- +- if (!url) +- goto out; +- +- isns_debug_general("SLP: Found URL \"%s\"\n", url); +- err = SLPParseSrvURL(url, &parsed_url); +- if (err != SLP_OK) { +- isns_error("Error parsing SLP service URL \"%s\"\n", url); +- goto out; +- } +- +- if (parsed_url->s_pcNetFamily +- && parsed_url->s_pcNetFamily[0] +- && strcasecmp(parsed_url->s_pcNetFamily, "ip")) { +- isns_error("Ignoring SLP service URL \"%s\"\n", url); +- goto out; +- } +- +- if (parsed_url->s_iPort) { +- snprintf(buffer, sizeof(buffer), "%s:%u", +- parsed_url->s_pcHost, +- parsed_url->s_iPort); +- isns_assign_string(&sp->slp_url, buffer); +- } else { +- isns_assign_string(&sp->slp_url, +- parsed_url->s_pcHost); +- } +- want_more = SLP_FALSE; +- +-out: +- if (parsed_url) +- SLPFree(parsed_url); +- sp->slp_err = SLP_OK; +- +- return want_more; +-} +- +-/* +- * Locate the iSNS server using SLP. +- * This is not really an instantaneous process. Maybe we could +- * speed this up by using a cache. +- */ +-char * +-isns_slp_find(void) +-{ +- static struct isns_slp_url_state state; +- SLPHandle handle = NULL; +- SLPError err; +- +- if (state.slp_url) +- return state.slp_url; +- +- isns_debug_general("Using SLP to locate iSNS server\n"); +- +- err = SLPOpen("en", SLP_FALSE, &handle); +- if(err != SLP_OK) { +- isns_error("Unable to obtain SLP handle (err %d)\n", err); +- return NULL; +- } +- +- err = SLPFindSrvs(handle, ISNS_SLP_SERVICE_NAME, +- NULL, "(protocols=isns)", +- isns_slp_url_callback, &state); +- +- SLPClose(handle); +- +- if (err == SLP_OK) +- err = state.slp_err; +- if (err != SLP_OK) { +- isns_error("Failed to find service in SLP (err %d)\n", err); +- return NULL; +- } +- +- if (state.slp_url == NULL) { +- isns_error("Service %s not registered with SLP\n", +- ISNS_SLP_SERVICE_NAME); +- return NULL; +- +- } +- +- isns_debug_general("Using iSNS server at %s\n", state.slp_url); +- return state.slp_url; +-} +- +-#else /* WITH_SLP */ +- +-int +-isns_slp_register(const char *url) +-{ +- isns_error("SLP support disabled in this build\n"); +- return 0; +-} +- +-int +-isns_slp_unregister(const char *url) +-{ +- isns_error("SLP support disabled in this build\n"); +- return 0; +-} +- +-char * +-isns_slp_find(void) +-{ +- isns_error("SLP support disabled in this build\n"); +- return NULL; +-} +- +-#endif /* WITH_SLP */ +- +-char * +-isns_slp_build_url(uint16_t port) +-{ +- char buffer[1024]; +- +- if (port) +- snprintf(buffer, sizeof(buffer), +- "service:%s://%s:%u", +- ISNS_SLP_SERVICE_NAME, +- isns_config.ic_host_name, port); +- else +- snprintf(buffer, sizeof(buffer), +- "service:%s://%s", +- ISNS_SLP_SERVICE_NAME, +- isns_config.ic_host_name); +- return isns_strdup(buffer); +-} +- +diff --git a/utils/open-isns/socket.c b/utils/open-isns/socket.c +deleted file mode 100644 +index 47481c6..0000000 +--- a/utils/open-isns/socket.c ++++ /dev/null +@@ -1,2304 +0,0 @@ +-/* +- * Socket handling code +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "buffer.h" +-#include "isns.h" +-#include "socket.h" +-#include "security.h" +-#include "util.h" +-#include "config.h" +- +-#define SOCK_DEBUG_VERBOSE 0 +- +-#ifndef AI_ADDRCONFIG +-# define AI_ADDRCONFIG 0 +-#endif +-#ifndef AI_V4MAPPED +-# define AI_V4MAPPED 0 +-#endif +- +-enum { +- ISNS_MSG_DISCARD, +- ISNS_MSG_DONE, +- ISNS_MSG_RETURN +-}; +- +-static isns_socket_t *__isns_create_socket(struct addrinfo *src, +- struct addrinfo *dst, +- int sock_type); +-static struct addrinfo *isns_get_address_list(const char *, const char *, +- int, int, int); +-static void release_addrinfo(struct addrinfo *); +-static void isns_net_dgram_recv(isns_socket_t *); +-static void isns_net_dgram_xmit(isns_socket_t *); +-static void isns_net_stream_accept(isns_socket_t *); +-static void isns_net_stream_recv(isns_socket_t *); +-static void isns_net_stream_xmit(isns_socket_t *); +-static void isns_net_stream_hup(isns_socket_t *); +-static void isns_net_stream_error(isns_socket_t *, int); +-static void isns_net_stream_reconnect(isns_socket_t *); +-static void isns_net_stream_disconnect(isns_socket_t *); +-static isns_socket_t *isns_net_alloc(int); +-static int isns_socket_open(isns_socket_t *); +-static int isns_socket_queue_message(isns_socket_t *, isns_message_t *); +-static int isns_socket_retransmit_queued(isns_socket_t *); +- +-static ISNS_LIST_DECLARE(all_sockets); +- +-#define debug_verbose(args ...) do { \ +- if (SOCK_DEBUG_VERBOSE >= 1) isns_debug_socket(args); \ +-} while (0) +-#define debug_verbose2(args ...) do { \ +- if (SOCK_DEBUG_VERBOSE >= 2) isns_debug_socket(args); \ +-} while (0) +- +-/* +- * Helper function for looking at incoming PDUs +- */ +-static inline buf_t * +-isns_socket_next_pdu(isns_socket_t *sock) +-{ +- buf_t *bp = sock->is_recv_buf; +- unsigned int avail; +- struct isns_hdr *hdr; +- uint32_t pdu_len = 0; +- +- if (bp == NULL) +- return NULL; +- +- avail = buf_avail(bp); +- if (avail < sizeof(*hdr)) +- return NULL; +- hdr = buf_head(bp); +- pdu_len = sizeof(*hdr) + ntohs(hdr->i_length); +- +- if (avail < pdu_len) +- return NULL; +- +- /* Check for presence of authentication block */ +- if (hdr->i_flags & htons(ISNS_F_AUTHBLK_PRESENT)) { +- uint32_t *authblk, authlen; +- +- authblk = (uint32_t *) ((char *) hdr + pdu_len); +- if (avail < pdu_len + ISNS_AUTHBLK_SIZE) +- return NULL; +- +- authlen = ntohl(authblk[1]); +- if (authlen < 20 || authlen > ISNS_MAX_MESSAGE) { +- /* The authblock is garbage. +- * The only reliable way to signal such a problem +- * is by dropping the connection. +- */ +- isns_error("socket error: bad auth block\n"); +- sock->is_state = ISNS_SOCK_DEAD; +- return NULL; +- } +- +- pdu_len += authlen; +- if (avail < pdu_len) +- return NULL; +- } +- +- return buf_split(&sock->is_recv_buf, pdu_len); +-} +- +-/* +- * Try to assemble the message from PDUs +- */ +-static inline int +-isns_msg_complete(struct isns_partial_msg *msg) +-{ +- buf_t *msg_buf, **chain, *bp; +- +- /* Return if we haven't seen first and last frag */ +- if (((~msg->imp_flags) & (ISNS_F_FIRST_PDU|ISNS_F_LAST_PDU))) +- return 0; +- +- /* Simple - unfragmented case: just move +- * the PDU on the chain to the payload */ +- if (msg->imp_first_seq == msg->imp_last_seq) { +- msg->imp_payload = msg->imp_chain; +- buf_pull(msg->imp_payload, sizeof(struct isns_hdr)); +- msg->imp_chain = NULL; +- return 1; +- } +- +- /* Do we have all fragments? */ +- if (msg->imp_last_seq - msg->imp_first_seq + 1 +- != msg->imp_pdu_count) +- return 0; +- +- msg_buf = buf_alloc(msg->imp_msg_size); +- +- chain = &msg->imp_chain; +- while ((bp = *chain) != NULL) { +- /* Pull the header off */ +- buf_pull(bp, sizeof(struct isns_hdr)); +- buf_put(msg_buf, buf_head(bp), buf_avail(bp)); +- +- *chain = bp->next; +- buf_free(bp); +- } +- +- return 0; +-} +- +-/* +- * Clear the "partial" part of the message +- */ +-static void +-__isns_msg_clear_partial(struct isns_partial_msg *msg) +-{ +- buf_list_free(msg->imp_chain); +- msg->imp_chain = NULL; +-} +- +-/* +- * Add an authentication block to an outgoing PDU +- */ +-#ifdef WITH_SECURITY +-static int +-isns_pdu_seal(isns_security_t *ctx, buf_t *pdu) +-{ +- struct isns_authblk auth; +- isns_principal_t *self; +- +- if (!(self = ctx->is_self)) { +- isns_error("Cannot sign PDU: no sender identity for socket\n"); +- return 0; +- } +- +- auth.iab_bsd = ctx->is_type; +- auth.iab_timestamp = time(NULL); +- auth.iab_spi = self->is_name; +- auth.iab_spi_len = strlen(self->is_name); +- +- if (!isns_security_sign(ctx, self, pdu, &auth)) { +- isns_error("Cannot sign PDU: error creating signature\n"); +- return 0; +- } +- +- auth.iab_length = ISNS_AUTHBLK_SIZE + +- auth.iab_spi_len + +- auth.iab_sig_len; +- if (!isns_authblock_encode(pdu, &auth)) +- return 0; +- +- isns_debug_message("Successfully signed message (authlen=%u, spilen=%u, siglen=%u)\n", +- auth.iab_length, auth.iab_spi_len, auth.iab_sig_len); +- +- return 1; +-} +- +-/* +- * Authenticate a PDU +- * +- * The RFC is doing a bit of handwaving around the +- * authentication issue. For example, it never +- * spells out exactly which parts of the message +- * are included in the SHA1 hash to be signed. +- * +- * It also says that the auth block "is identical in format +- * to the SLP authentication block", but all fields +- * are twice as wide. +- * +- * There's not even an error code to tell the client +- * we were unable to authenticate him :-( +- * +- * Interoperability problems, here I come... +- */ +-static int +-isns_pdu_authenticate(isns_security_t *sec, +- struct isns_partial_msg *msg, buf_t *bp) +-{ +- struct isns_hdr *hdr = buf_head(bp); +- unsigned int pdu_len, avail; +- struct isns_authblk authblk; +- isns_principal_t * peer = NULL; +- buf_t auth_buf; +- +- isns_debug_auth("Message has authblock; trying to authenticate\n"); +- +- /* In the TCP path, we checked this before, but +- * better safe than sorry. */ +- avail = buf_avail(bp); +- pdu_len = sizeof(*hdr) + ntohs(hdr->i_length); +- if (avail < pdu_len + ISNS_AUTHBLK_SIZE) { +- isns_debug_auth("authblock truncated\n"); +- return 0; +- } +- +- /* Get the auth block */ +- buf_set(&auth_buf, buf_head(bp) + pdu_len, avail - pdu_len); +- if (!isns_authblock_decode(&auth_buf, &authblk)) { +- isns_debug_auth("error decoding authblock\n"); +- return 0; +- } +- +- /* Truncate the buffer (this just sets the +- * tail pointer, but doesn't free memory */ +- if (!buf_truncate(bp, pdu_len)) { +- isns_debug_auth("buf_truncate failed - cosmic particles?\n"); +- return 0; +- } +- +- /* If the socket doesn't have a security context, +- * just ignore the auth block. */ +- if (sec == NULL) { +- msg->imp_header.i_flags &= ~ISNS_F_AUTHBLK_PRESENT; +- return 1; +- } +- +- if (authblk.iab_bsd != sec->is_type) +- goto failed; +- +- peer = isns_get_principal(sec, authblk.iab_spi, authblk.iab_spi_len); +- if (peer == NULL) { +- /* If the admin allows unknown peers, we must make +- * sure, however, to not allow an unauthenticated +- * PDU to be inserted into an authenticated message. +- */ +- if (isns_config.ic_auth.allow_unknown_peers +- && msg->imp_security == NULL) { +- isns_debug_message( +- "Accepting unknown peer spi=\"%.*s\" as " +- "anonymous peer\n", +- authblk.iab_spi_len, authblk.iab_spi); +- return 1; +- } +- +- isns_debug_message( +- "Unable to create security peer for spi=%.*s\n", +- authblk.iab_spi_len, authblk.iab_spi); +- +- goto failed; +- } +- +- if (!isns_security_verify(sec, peer, bp, &authblk)) { +- /* Authentication failed */ +- goto failed; +- } +- +- /* The RFC doesn't say how to deal with fragmented +- * messages with different BSDs or SPIs. +- * kickban seems the right approach. +- * We discard this segment rather than failing +- * the entire message. +- */ +- if (msg->imp_chain == NULL) { +- msg->imp_security = peer; +- peer->is_users++; +- } else +- if (msg->imp_security != peer) { +- goto failed; +- } +- +- isns_principal_free(peer); +- return 1; +- +-failed: +- isns_principal_free(peer); +- return 0; +-} +-#else /* WITH_SECURITY */ +-static int +-isns_pdu_authenticate(isns_security_t *sec, +- struct isns_partial_msg *msg, buf_t *bp) +-{ +- return 0; +-} +- +-#endif +- +-/* +- * Enqueue an incoming PDU on the socket. +- * +- * A single iSNS message may be split up into +- * several PDUs, so we need to perform +- * reassembly here. +- * +- * This function also verifies the authentication +- * block, if present. +- */ +-static void +-isns_pdu_enqueue(isns_socket_t *sock, +- struct sockaddr_storage *addr, socklen_t alen, +- buf_t *segment, struct ucred *creds) +-{ +- isns_message_queue_t *q = &sock->is_partial; +- struct isns_partial_msg *msg; +- buf_t **chain, *bp; +- struct isns_hdr *hdr; +- uint32_t xid, seq, flags; +- +- hdr = (struct isns_hdr *) buf_head(segment); +- xid = ntohs(hdr->i_xid); +- seq = ntohs(hdr->i_seq); +- flags = ntohs(hdr->i_flags); +- +- isns_debug_socket("Incoming PDU xid=%04x seq=%u len=%u func=%s%s%s%s%s%s\n", +- xid, seq, ntohs(hdr->i_length), +- isns_function_name(ntohs(hdr->i_function)), +- (flags & ISNS_F_CLIENT)? " client" : "", +- (flags & ISNS_F_SERVER)? " server" : "", +- (flags & ISNS_F_AUTHBLK_PRESENT)? " authblk" : "", +- (flags & ISNS_F_FIRST_PDU)? " first" : "", +- (flags & ISNS_F_LAST_PDU)? " last" : ""); +- +- /* Find the message matching (addr, xid) */ +- msg = (struct isns_partial_msg *) isns_message_queue_find(q, xid, addr, alen); +- if (msg != NULL) { +- if (msg->imp_creds +- && (!creds || memcmp(msg->imp_creds, creds, sizeof(*creds)))) { +- isns_warning("socket: credentials mismatch! Dropping PDU\n"); +- goto drop; +- } +- hdr = &msg->imp_header; +- goto found; +- } +- +- msg = (struct isns_partial_msg *) __isns_alloc_message(xid, sizeof(*msg), +- (void (*)(isns_message_t *)) __isns_msg_clear_partial); +- memcpy(&msg->imp_addr, addr, alen); +- msg->imp_addrlen = alen; +- +- msg->imp_header = *hdr; +- msg->imp_header.i_seq = 0; +- +- isns_message_queue_append(q, &msg->imp_base); +- isns_message_release(&msg->imp_base); +- /* Message is owned by is_partial now */ +- +- /* Fix up the PDU header */ +- hdr = &msg->imp_header; +- hdr->i_version = ntohs(hdr->i_version); +- hdr->i_function = ntohs(hdr->i_function); +- hdr->i_length = ntohs(hdr->i_length); +- hdr->i_flags = ntohs(hdr->i_flags); +- hdr->i_xid = ntohs(hdr->i_xid); +- hdr->i_seq = ntohs(hdr->i_seq); +- +- if (creds) { +- msg->imp_credbuf = *creds; +- msg->imp_creds = &msg->imp_credbuf; +- } +- +-found: +- if (flags & ISNS_F_AUTHBLK_PRESENT) { +- /* When authentication fails - should we drop the +- * message or treat it as unauthenticated? +- * For now we drop it, but a more user friendly +- * approach might be to just treat it as +- * unauthenticated. +- */ +- if (!isns_pdu_authenticate(sock->is_security, msg, segment)) +- goto drop; +- } else +- if (msg->imp_header.i_flags & ISNS_F_AUTHBLK_PRESENT) { +- /* Oops, unauthenticated fragment in an +- * authenticated message. */ +- isns_debug_message( +- "Oops, unauthenticated fragment in an " +- "authenticated message!\n"); +- goto drop; +- } +- +- if ((flags & ISNS_F_FIRST_PDU) +- && !(msg->imp_flags & ISNS_F_FIRST_PDU)) { +- /* FIXME: first seq must be zero */ +- msg->imp_first_seq = seq; +- msg->imp_flags |= ISNS_F_FIRST_PDU; +- } +- if ((flags & ISNS_F_LAST_PDU) +- && !(msg->imp_flags & ISNS_F_LAST_PDU)) { +- msg->imp_last_seq = seq; +- msg->imp_flags |= ISNS_F_LAST_PDU; +- } +- +- chain = &msg->imp_chain; +- while ((bp = *chain) != NULL) { +- struct isns_hdr *ohdr = buf_head(bp); +- +- /* Duplicate? Drop it! */ +- if (seq == ohdr->i_seq) +- goto drop; +- if (seq < ohdr->i_seq) +- break; +- chain = &bp->next; +- } +- segment->next = *chain; +- *chain = segment; +- +- msg->imp_msg_size += buf_avail(segment) - sizeof(*hdr); +- msg->imp_pdu_count++; +- +- /* We received first and last PDU - check if the +- * chain is complete */ +- if (isns_msg_complete(msg)) { +- /* Remove from partial queue. +- * We clean the part of the message that is +- * not in imp_base, so that we can pass this +- * to the caller and have him call +- * isns_message_release on it. +- */ +- __isns_msg_clear_partial(msg); +- +- /* Move from partial queue to complete queue. */ +- isns_message_queue_move(&sock->is_complete, +- &msg->imp_base); +- msg->imp_base.im_socket = sock; +- } +- +- return; +- +-drop: +- buf_free(segment); +- return; +-} +- +-/* +- * Send side handling +- */ +-static void +-isns_send_update(isns_socket_t *sock) +-{ +- buf_t *bp = sock->is_xmit_buf; +- +- if (bp && buf_avail(bp) == 0) { +- sock->is_xmit_buf = bp->next; +- buf_free(bp); +- } +- +- if (sock->is_xmit_buf) +- sock->is_poll_mask |= POLLOUT; +- else +- sock->is_poll_mask &= ~POLLOUT; +-} +- +-/* +- * Close the socket +- */ +-static void +-isns_net_close(isns_socket_t *sock, int next_state) +-{ +- if (sock->is_desc >= 0) { +- close(sock->is_desc); +- sock->is_desc = -1; +- } +- sock->is_poll_mask &= ~(POLLIN|POLLOUT); +- sock->is_state = next_state; +- +- buf_list_free(sock->is_xmit_buf); +- sock->is_xmit_buf = NULL; +- +- buf_free(sock->is_recv_buf); +- sock->is_recv_buf = NULL; +- +- isns_message_queue_destroy(&sock->is_partial); +- isns_message_queue_destroy(&sock->is_complete); +-} +- +-static void +-isns_net_set_timeout(isns_socket_t *sock, +- void (*func)(isns_socket_t *), +- unsigned int timeout) +-{ +- gettimeofday(&sock->is_deadline, NULL); +- sock->is_deadline.tv_sec += timeout; +- sock->is_timeout = func; +-} +- +-static void +-isns_net_cancel_timeout(isns_socket_t *sock) +-{ +- timerclear(&sock->is_deadline); +-} +- +-void +-isns_net_error(isns_socket_t *sock, int err_code) +-{ +- if (sock->is_error) +- sock->is_error(sock, err_code); +-} +- +-/* +- * Create a passive socket (server side) +- */ +-isns_socket_t * +-isns_create_server_socket(const char *src_spec, const char *portspec, int af_hint, int sock_type) +-{ +- struct addrinfo *src; +- +- src = isns_get_address_list(src_spec, portspec, +- af_hint, sock_type, AI_PASSIVE); +- if (src == NULL) +- return NULL; +- +- return __isns_create_socket(src, NULL, sock_type); +-} +- +-/* +- * Accept incoming connections. +- */ +-void +-isns_net_stream_accept(isns_socket_t *sock) +-{ +- isns_socket_t *child; +- socklen_t optlen; +- int fd, passcred = 0; +- +- fd = accept(sock->is_desc, NULL, NULL); +- if (fd < 0) { +- if (errno != EINTR) +- isns_error("Error accepting connection: %m\n"); +- return; +- } +- +- optlen = sizeof(passcred); +- if (getsockopt(sock->is_desc, SOL_SOCKET, SO_PASSCRED, +- &passcred, &optlen) >= 0) { +- setsockopt(fd, SOL_SOCKET, SO_PASSCRED, +- &passcred, sizeof(passcred)); +- } +- +- child = isns_net_alloc(fd); +- child->is_type = SOCK_STREAM; +- child->is_autoclose = 1; +- child->is_disconnect_fatal = 1; +- child->is_poll_in = isns_net_stream_recv; +- child->is_poll_out = isns_net_stream_xmit; +- child->is_poll_hup = isns_net_stream_hup; +- child->is_error = isns_net_stream_error; +- child->is_poll_mask = POLLIN|POLLHUP; +- child->is_security = sock->is_security; +- +- if (isns_config.ic_network.idle_timeout) +- isns_net_set_timeout(child, +- isns_net_stream_disconnect, +- isns_config.ic_network.idle_timeout); +- +- isns_list_append(&all_sockets, &child->is_list); +-} +- +-/* +- * This is called from the socket code when it detects +- * an error condition. +- */ +-static void +-isns_net_stream_error(isns_socket_t *sock, int err_code) +-{ +- int timeo = 0, next_state = ISNS_SOCK_DEAD; +- +- if (err_code == EAGAIN) +- return; +- +- isns_debug_socket("isns_net_stream_error: %s\n", strerror(err_code)); +- +- switch (err_code) { +- case EINTR: /* ignored */ +- return; +- +- case ECONNREFUSED: +- case ECONNRESET: +- case EHOSTUNREACH: +- case ENETUNREACH: +- case ENOTCONN: +- case EPIPE: +- if (sock->is_disconnect_fatal) { +- isns_warning("socket disconnect, killing socket\n"); +- break; +- } +- +- /* fallthrough to disconnect */ +- timeo = isns_config.ic_network.reconnect_timeout; +- +- case ETIMEDOUT: +- /* Disconnect and try to reconnect */ +- if (sock->is_client) { +- /* FIXME: We don't want this warning for ESI and +- * SCN sockets on the server side. */ +- isns_warning("socket disconnect, retrying in %u sec\n", +- timeo); +- isns_net_set_timeout(sock, +- isns_net_stream_reconnect, +- timeo); +- next_state = ISNS_SOCK_DISCONNECTED; +- break; +- } +- +- /* fallthru */ +- +- default: +- isns_error("socket error: %s\n", strerror(err_code)); +- } +- +- /* Close the socket right away */ +- isns_net_close(sock, next_state); +-} +- +-/* +- * recvmsg wrapper handling SCM_CREDENTIALS passing +- */ +-static int +-isns_net_recvmsg(isns_socket_t *sock, +- void *buffer, size_t count, +- struct sockaddr *addr, socklen_t *alen, +- struct ucred **cred) +-{ +- static struct ucred cred_buf; +- unsigned int control[128]; +- struct cmsghdr *cmsg; +- struct msghdr msg; +- struct iovec iov; +- int len; +- +- *cred = NULL; +- +- iov.iov_base = buffer; +- iov.iov_len = count; +- +- memset(&msg, 0, sizeof(msg)); +- msg.msg_name = addr; +- msg.msg_namelen = *alen; +- msg.msg_iov = &iov; +- msg.msg_iovlen = 1; +- msg.msg_control = control; +- msg.msg_controllen = sizeof(control); +- +- len = recvmsg(sock->is_desc, &msg, MSG_DONTWAIT); +- +- if (len < 0) +- return len; +- +- cmsg = CMSG_FIRSTHDR(&msg); +- while (cmsg) { +- if (cmsg->cmsg_level == SOL_SOCKET +- && cmsg->cmsg_type == SCM_CREDENTIALS) { +- memcpy(&cred_buf, CMSG_DATA(cmsg), sizeof(cred_buf)); +- *cred = &cred_buf; +- break; +- } +- +- cmsg = CMSG_NXTHDR(&msg, cmsg); +- } +- +- *alen = msg.msg_namelen; +- return len; +-} +- +-void +-isns_net_stream_recv(isns_socket_t *sock) +-{ +- unsigned char buffer[ISNS_MAX_BUFFER]; +- struct sockaddr_storage addr; +- struct ucred *creds = NULL; +- socklen_t alen = sizeof(addr); +- buf_t *bp; +- size_t count, total = 0; +- int len; +- +-again: +- if ((bp = sock->is_recv_buf) == NULL) { +- bp = buf_alloc(ISNS_MAX_MESSAGE); +- sock->is_recv_buf = bp; +- } +- +- if ((count = buf_tailroom(bp)) > sizeof(buffer)) +- count = sizeof(buffer); +- +- if (count == 0) { +- /* Message too large */ +- isns_net_stream_error(sock, EMSGSIZE); +- return; +- } +- +-#if 0 +- len = recvfrom(sock->is_desc, buffer, count, MSG_DONTWAIT, +- (struct sockaddr *) &addr, &alen); +-#else +- len = isns_net_recvmsg(sock, buffer, count, +- (struct sockaddr *) &addr, &alen, +- &creds); +-#endif +- if (len < 0) { +- isns_net_stream_error(sock, errno); +- return; +- } +- if (len == 0) { +- if (total == 0) +- sock->is_poll_mask &= ~POLLIN; +- return; +- } +- +- /* We received some data from client, re-arm the +- * idle disconnect timer */ +- if (sock->is_autoclose +- && isns_config.ic_network.idle_timeout) +- isns_net_set_timeout(sock, +- isns_net_stream_disconnect, +- isns_config.ic_network.idle_timeout); +- +- buf_put(bp, buffer, len); +- total += len; +- +- /* Chop up the recv buffer into PDUs */ +- while ((bp = isns_socket_next_pdu(sock)) != NULL) { +- /* We have a full PDU; enqueue it */ +- /* We shouldn't have more than one partial message +- * on a TCP connection; we could check this here. +- */ +- isns_pdu_enqueue(sock, &addr, alen, bp, creds); +- } +- +- goto again; +-} +- +-void +-isns_net_stream_xmit(isns_socket_t *sock) +-{ +- unsigned int count; +- buf_t *bp = sock->is_xmit_buf; +- int len; +- +- /* If a connecting socket can send, it has +- * the TCP three-way handshake. */ +- if (sock->is_state == ISNS_SOCK_CONNECTING) { +- sock->is_state = ISNS_SOCK_IDLE; +- sock->is_poll_mask |= POLLIN; +- isns_net_cancel_timeout(sock); +- } +- +- if (bp == NULL) +- return; +- +- count = buf_avail(bp); +- len = send(sock->is_desc, buf_head(bp), count, MSG_DONTWAIT); +- if (len < 0) { +- isns_net_stream_error(sock, errno); +- return; +- } +- +- debug_verbose("isns_net_stream_xmit(%p, count=%u): transmitted %d\n", +- sock, count, len); +- buf_pull(bp, len); +- isns_send_update(sock); +-} +- +-void +-isns_net_stream_hup(isns_socket_t *sock) +-{ +- sock->is_poll_mask &= ~(POLLIN|POLLOUT); +- /* POLLHUP while connecting means we failed */ +- if (sock->is_state == ISNS_SOCK_CONNECTING) +- isns_net_stream_error(sock, ECONNREFUSED); +-} +- +-/* +- * Clone an addrinfo list +- */ +-static struct addrinfo * +-clone_addrinfo(const struct addrinfo *ai) +-{ +- struct addrinfo *res = NULL, **p; +- +- p = &res; +- for (; ai; ai = ai->ai_next) { +- struct addrinfo *new; +- +- if (ai->ai_addrlen > sizeof(struct sockaddr_storage)) +- continue; +- +- new = isns_calloc(1, sizeof(*new) + ai->ai_addrlen); +- new->ai_family = ai->ai_family; +- new->ai_socktype = ai->ai_socktype; +- new->ai_protocol = ai->ai_protocol; +- new->ai_addrlen = ai->ai_addrlen; +- new->ai_addr = (struct sockaddr *) (new + 1); +- memcpy(new->ai_addr, ai->ai_addr, new->ai_addrlen); +- +- *p = new; +- p = &new->ai_next; +- } +- +- return res; +-} +- +-static struct addrinfo * +-__make_addrinfo(const struct sockaddr *ap, socklen_t alen, int socktype) +-{ +- struct addrinfo *new; +- +- new = isns_calloc(1, sizeof(*new) + alen); +- new->ai_family = ap->sa_family; +- new->ai_socktype = socktype; +- new->ai_protocol = 0; +- new->ai_addrlen = alen; +- new->ai_addr = (struct sockaddr *) (new + 1); +- memcpy(new->ai_addr, ap, alen); +- +- return new; +-} +- +-static struct addrinfo * +-make_addrinfo_unix(const char *pathname, int socktype) +-{ +- unsigned int len = strlen(pathname); +- struct sockaddr_un sun; +- +- if (len + 1 > sizeof(sun.sun_path)) { +- isns_error("Can't set AF_LOCAL address: path too long!\n"); +- return NULL; +- } +- +- sun.sun_family = AF_LOCAL; +- strcpy(sun.sun_path, pathname); +- return __make_addrinfo((struct sockaddr *) &sun, SUN_LEN(&sun) + 1, socktype); +-} +- +-static struct addrinfo * +-make_addrinfo_any(int family, int socktype) +-{ +- struct sockaddr_storage addr = { .ss_family = AF_UNSPEC }; +- struct addrinfo *res; +- +- if (family != AF_UNSPEC) { +- addr.ss_family = family; +- res = __make_addrinfo((struct sockaddr *) &addr, sizeof(addr), socktype); +- } else { +- addr.ss_family = AF_INET6; +- res = __make_addrinfo((struct sockaddr *) &addr, sizeof(addr), socktype); +- addr.ss_family = AF_INET; +- res->ai_next = __make_addrinfo((struct sockaddr *) &addr, sizeof(addr), socktype); +- } +- +- return res; +-} +- +-/* +- * Release addrinfo created by functions above. +- * We cannot use freeaddrinfo, as we don't know how it +- * is implemented. +- */ +-static void +-release_addrinfo(struct addrinfo *ai) +-{ +- struct addrinfo *next; +- +- for (; ai; ai = next) { +- next = ai->ai_next; +- isns_free(ai); +- } +-} +- +-static void +-__isns_sockaddr_set_current(struct __isns_socket_addr *info, +- const struct addrinfo *ai) +-{ +- if (!ai) +- return; +- +- /* Cannot overflow; we check addrlen in clone_addrinfo */ +- memcpy(&info->addr, ai->ai_addr, ai->ai_addrlen); +- info->addrlen = ai->ai_addrlen; +-} +- +-static void +-isns_sockaddr_init(struct __isns_socket_addr *info, +- struct addrinfo *ai) +-{ +- if (ai == NULL) +- return; +- +- __isns_sockaddr_set_current(info, ai); +- +- /* keep a copy so that we can loop through +- * all addrs */ +- info->list = ai; +- +- /* Make the list circular */ +- while (ai->ai_next) +- ai = ai->ai_next; +- ai->ai_next = info->list; +-} +- +-static void +-isns_sockaddr_destroy(struct __isns_socket_addr *info) +-{ +- struct addrinfo *ai, *next; +- +- if ((ai = info->list) != NULL) { +- /* Break the circular list */ +- info->list = NULL; +- next = ai->ai_next; +- ai->ai_next = NULL; +- isns_assert(next); +- +- /* Can't use freeaddrinfo on homegrown +- * addrinfo lists. */ +- release_addrinfo(next); +- } +-} +- +-static int +-isns_sockaddr_set_next(struct __isns_socket_addr *info) +-{ +- struct addrinfo *ai; +- +- if (!(ai = info->list)) +- return 0; +- +- info->list = ai->ai_next; +- __isns_sockaddr_set_current(info, info->list); +- return 1; +-} +- +-/* +- * This function is used to pick a matching source address +- * when connecting to some server. +- */ +-static int +-isns_sockaddr_select(struct __isns_socket_addr *info, +- const struct sockaddr_storage *hint) +-{ +- struct addrinfo *head = info->list, *ai; +- +- if (info->list == NULL) +- return 0; +- +- if (hint->ss_family == AF_INET6) { +- struct addrinfo *good = NULL, *best = NULL; +- +- ai = head; +- do { +- if (ai->ai_family == AF_INET) { +- /* Possible improvement: when +- * destination is not a private network, +- * prefer non-private source. */ +- good = ai; +- } else +- if (ai->ai_family == AF_INET6) { +- /* Possible improvement: prefer IPv6 addr +- * with same address scope (local, global) +- */ +- best = ai; +- break; +- } +- +- ai = ai->ai_next; +- } while (ai != head); +- +- if (!best) +- best = good; +- if (best) { +- __isns_sockaddr_set_current(info, best); +- return 1; +- } +- } else +- if (hint->ss_family == AF_INET || hint->ss_family == AF_LOCAL) { +- ai = head; +- do { +- if (ai->ai_family == hint->ss_family) { +- __isns_sockaddr_set_current(info, ai); +- return 1; +- } +- ai = ai->ai_next; +- } while (ai != head); +- } +- +- return 0; +-} +- +-void +-isns_net_stream_reconnect(isns_socket_t *sock) +-{ +- struct sockaddr *addr = (struct sockaddr *) &sock->is_dst.addr; +- +- debug_verbose("isns_net_stream_reconnect(%p)\n", sock); +- +- /* If we timed out while connecting, close the socket +- * and try again. */ +- if (sock->is_state == ISNS_SOCK_CONNECTING) { +- isns_net_close(sock, ISNS_SOCK_DISCONNECTED); +- isns_sockaddr_set_next(&sock->is_dst); +- } +- +- if (!isns_socket_open(sock)) { +- isns_error("isns_net_stream_reconnect: cannot create socket\n"); +- sock->is_state = ISNS_SOCK_DEAD; +- return; +- } +- +- if (connect(sock->is_desc, addr, sock->is_dst.addrlen) >= 0) { +- sock->is_state = ISNS_SOCK_IDLE; +- sock->is_poll_mask |= POLLIN; +- } else +- if (errno == EINTR || errno == EINPROGRESS) { +- sock->is_state = ISNS_SOCK_CONNECTING; +- isns_net_set_timeout(sock, +- isns_net_stream_reconnect, +- isns_config.ic_network.connect_timeout); +- sock->is_poll_mask |= POLLOUT; +- } else { +- isns_net_stream_error(sock, errno); +- return; +- } +- +- /* We're connected, or in the process of doing so. +- * Check if there are any pending messages, and +- * retransmit them. */ +- isns_socket_retransmit_queued(sock); +-} +- +-void +-isns_net_stream_disconnect(isns_socket_t *sock) +-{ +- isns_debug_socket("Disconnecting idle socket\n"); +- isns_net_close(sock, ISNS_SOCK_DEAD); +-} +- +-/* +- * Datagram send/recv +- */ +-static int +-isns_net_dgram_connect(isns_socket_t *sock) +-{ +- return connect(sock->is_desc, +- (struct sockaddr *) &sock->is_dst.addr, +- sock->is_dst.addrlen); +-} +- +-void +-isns_net_dgram_recv(isns_socket_t *sock) +-{ +- unsigned char buffer[ISNS_MAX_BUFFER]; +- struct sockaddr_storage addr; +- socklen_t alen = sizeof(addr); +- buf_t *bp; +- int len; +- +- len = recvfrom(sock->is_desc, buffer, sizeof(buffer), +- MSG_DONTWAIT, (struct sockaddr *) &addr, &alen); +- if (len < 0) { +- isns_error("recv: %m\n"); +- return; +- } +- if (len == 0) +- return; +- +- bp = buf_alloc(len); +- if (bp == NULL) +- return; +- +- buf_put(bp, buffer, len); +- isns_pdu_enqueue(sock, &addr, alen, bp, NULL); +-} +- +-void +-isns_net_dgram_xmit(isns_socket_t *sock) +-{ +- unsigned int count; +- buf_t *bp = sock->is_xmit_buf; +- int len; +- +- count = buf_avail(bp); +- if (bp->addrlen) { +- len = sendto(sock->is_desc, buf_head(bp), count, MSG_DONTWAIT, +- (struct sockaddr *) &bp->addr, bp->addrlen); +- } else { +- len = sendto(sock->is_desc, buf_head(bp), count, MSG_DONTWAIT, +- NULL, 0); +- } +- +- /* Even if sendto failed, we will pull the pending buffer +- * off the send chain. Else we'll loop forever on an +- * unreachable host. */ +- if (len < 0) +- isns_error("send: %m\n"); +- +- buf_pull(bp, count); +- isns_send_update(sock); +-} +- +-/* +- * Bind socket to random port +- */ +-static int +-__isns_socket_bind_random(int fd, +- const struct sockaddr *orig_addr, +- socklen_t src_len) +-{ +- struct sockaddr_storage addr; +- struct sockaddr *src_addr; +- uint16_t min = 888, max = 1024; +- unsigned int loop = 0; +- +- /* Copy the address to a writable location */ +- isns_assert(src_len <= sizeof(addr)); +- memcpy(&addr, orig_addr, src_len); +- src_addr = (struct sockaddr *) &addr; +- +- /* Bind to a random port */ +- do { +- uint16_t port; +- +- port = random(); +- port = min + (port % (max - min)); +- +- isns_addr_set_port(src_addr, port); +- +- if (bind(fd, src_addr, src_len) == 0) +- return 1; +- +- if (errno == EACCES && min < 1024) { +- min = 1024; +- max = 65535; +- continue; +- } +- } while (errno == EADDRINUSE && ++loop < 128); +- +- isns_error("Unable to bind socket\n"); +- return 0; +-} +- +-/* +- * Create a socket +- */ +-isns_socket_t * +-__isns_create_socket(struct addrinfo *src, struct addrinfo *dst, int sock_type) +-{ +- isns_socket_t *sock; +- +- sock = isns_net_alloc(-1); +- sock->is_type = sock_type; +- +- /* Set address lists */ +- isns_sockaddr_init(&sock->is_dst, dst); +- isns_sockaddr_init(&sock->is_src, src); +- +- if (dst) { +- /* This is an outgoing connection. */ +- sock->is_client = 1; +- +- if (!isns_socket_open(sock)) +- goto failed; +- +- if (sock_type == SOCK_DGRAM) { +- sock->is_poll_in = isns_net_dgram_recv; +- sock->is_poll_out = isns_net_dgram_xmit; +- sock->is_poll_mask = POLLIN; +- +- sock->is_retrans_timeout = isns_config.ic_network.udp_retrans_timeout; +- +- while (isns_net_dgram_connect(sock) < 0) { +- if (isns_sockaddr_set_next(&sock->is_dst) +- && sock->is_dst.list != dst) +- continue; +- isns_error("Unable to connect: %m\n"); +- goto failed; +- } +- } else { +- /* Stream socket */ +- sock->is_poll_in = isns_net_stream_recv; +- sock->is_poll_out = isns_net_stream_xmit; +- sock->is_poll_hup = isns_net_stream_hup; +- sock->is_error = isns_net_stream_error; +- sock->is_poll_mask = POLLHUP; +- +- sock->is_retrans_timeout = isns_config.ic_network.tcp_retrans_timeout; +- +- isns_net_stream_reconnect(sock); +- } +- } else { +- if (!isns_socket_open(sock)) +- goto failed; +- +- if (sock_type == SOCK_DGRAM) { +- sock->is_poll_in = isns_net_dgram_recv; +- sock->is_poll_out = isns_net_dgram_xmit; +- sock->is_state = ISNS_SOCK_IDLE; +- } else { +- sock->is_poll_in = isns_net_stream_accept; +- sock->is_error = isns_net_stream_error; +- sock->is_state = ISNS_SOCK_LISTENING; +- } +- sock->is_poll_mask = POLLIN; +- } +- +- isns_list_append(&all_sockets, &sock->is_list); +- return sock; +- +-failed: +- isns_socket_free(sock); +- return NULL; +-} +- +-/* +- * Connect to the master process +- */ +-isns_socket_t * +-isns_create_bound_client_socket(const char *src_spec, const char *dst_spec, +- const char *portspec, int af_hint, int sock_type) +-{ +- struct addrinfo *src = NULL, *dst; +- +- if (src_spec) { +- src = isns_get_address_list(src_spec, NULL, af_hint, sock_type, 0); +- if (src == NULL) +- return NULL; +- } +- +- dst = isns_get_address_list(dst_spec, portspec, af_hint, sock_type, 0); +- if (dst == NULL) { +- release_addrinfo(src); +- return NULL; +- } +- +- return __isns_create_socket(src, dst, sock_type); +-} +- +-isns_socket_t * +-isns_create_client_socket(const char *dst_spec, const char *portspec, int af_hint, int sock_type) +-{ +- return isns_create_bound_client_socket(NULL, dst_spec, portspec, af_hint, sock_type); +-} +- +-static inline int +-isns_socket_type_from_portal(const isns_portal_info_t *info) +-{ +- switch (info->proto) { +- case IPPROTO_TCP: +- return SOCK_STREAM; +- case IPPROTO_UDP: +- return SOCK_DGRAM; +- default: +- isns_error("Unknown protocol %d in portal\n", info->proto); +- } +- return -1; +-} +- +-isns_socket_t * +-isns_connect_to_portal(const isns_portal_info_t *info) +-{ +- struct sockaddr_storage dst_addr; +- struct addrinfo *ai; +- int dst_alen, sock_type; +- +- if ((sock_type = isns_socket_type_from_portal(info)) < 0) +- return NULL; +- +- dst_alen = isns_portal_to_sockaddr(info, &dst_addr); +- ai = __make_addrinfo((struct sockaddr *) &dst_addr, dst_alen, sock_type); +- +- return __isns_create_socket(NULL, ai, sock_type); +-} +- +-/* +- * Make server side disconnects isns_fatal. +- * Nice for command line apps. +- */ +-void +-isns_socket_set_disconnect_fatal(isns_socket_t *sock) +-{ +- sock->is_disconnect_fatal = 1; +-} +- +-void +-isns_socket_set_report_failure(isns_socket_t *sock) +-{ +- sock->is_report_failure = 1; +-} +- +-/* +- * Set the socket's security context +- */ +-void +-isns_socket_set_security_ctx(isns_socket_t *sock, +- isns_security_t *ctx) +-{ +- sock->is_security = ctx; +-} +- +-/* +- * Create a socket +- */ +-static isns_socket_t * +-isns_net_alloc(int fd) +-{ +- isns_socket_t *new; +- +- new = isns_calloc(1, sizeof(*new)); +- new->is_desc = fd; +- if (fd >= 0) +- new->is_state = ISNS_SOCK_IDLE; +- else +- new->is_state = ISNS_SOCK_DISCONNECTED; +- +- isns_message_queue_init(&new->is_partial); +- isns_message_queue_init(&new->is_complete); +- isns_message_queue_init(&new->is_pending); +- isns_list_init(&new->is_list); +- +- return new; +-} +- +-/* +- * Open the socket +- */ +-static int +-isns_socket_open(isns_socket_t *sock) +-{ +- int af, fd, state = ISNS_SOCK_IDLE; +- +- if (sock->is_desc >= 0) +- return 1; +- +- af = sock->is_dst.addr.ss_family; +- if (af != AF_UNSPEC) { +- /* Select a matching source address */ +- if (sock->is_src.list +- && !isns_sockaddr_select(&sock->is_src, &sock->is_dst.addr)) { +- isns_warning("No matching source address for given destination\n"); +- return 0; +- } +- } else { +- af = sock->is_src.addr.ss_family; +- if (af == AF_UNSPEC) +- return 0; +- } +- +- if ((fd = socket(af, sock->is_type, 0)) < 0) { +- isns_error("Unable to create socket: %m\n"); +- return 0; +- } +- +- if (sock->is_src.addr.ss_family != AF_UNSPEC) { +- const struct sockaddr *src_addr; +- int src_len, on = 1, bound = 0; +- +- src_addr = (struct sockaddr *) &sock->is_src.addr; +- src_len = sock->is_src.addrlen; +- +- /* For debugging only! */ +- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { +- isns_error("setsockopt(SO_REUSEADDR) failed: %m\n"); +- goto failed; +- } +- +- switch (af) { +- case AF_LOCAL: +- unlink(((struct sockaddr_un *) src_addr)->sun_path); +- +- if (sock->is_type == SOCK_STREAM +- && setsockopt(fd, SOL_SOCKET, SO_PASSCRED, +- &on, sizeof(on)) < 0) { +- isns_error("setsockopt(SO_PASSCRED) failed: %m\n"); +- goto failed; +- } +- break; +- +- case AF_INET: +- case AF_INET6: +- if (isns_addr_get_port(src_addr) == 0) { +- if (!__isns_socket_bind_random(fd, src_addr, src_len)) +- goto failed; +- bound++; +- } +- break; +- } +- +- if (!bound && bind(fd, src_addr, src_len) < 0) { +- isns_error("Unable to bind socket: %m\n"); +- goto failed; +- } +- } +- +- if (sock->is_client) { +- /* Set to nonblocking behavior; makes the connect +- * call return instantly. */ +- fcntl(fd, F_SETFL, O_NONBLOCK); +- } else { +- if (sock->is_type == SOCK_STREAM) { +- if (listen(fd, 128) < 0) { +- isns_error("Unable to listen on socket: %m\n"); +- goto failed; +- } +- state = ISNS_SOCK_LISTENING; +- } +- } +- +- sock->is_desc = fd; +- sock->is_state = state; +- return 1; +- +-failed: +- close(fd); +- return 0; +-} +- +-/* +- * Destroy a socket +- */ +-static inline void +-isns_socket_destroy(isns_socket_t *sock) +-{ +- isns_sockaddr_destroy(&sock->is_dst); +- isns_sockaddr_destroy(&sock->is_src); +- isns_free(sock); +-} +- +-void +-isns_socket_free(isns_socket_t *sock) +-{ +- isns_net_close(sock, ISNS_SOCK_DEAD); +- isns_list_del(&sock->is_list); +- +- sock->is_destroy = 1; +- if (sock->is_users == 0) +- isns_socket_destroy(sock); +-} +- +-int +-isns_socket_release(isns_socket_t *sock) +-{ +- isns_assert(sock->is_users); +- sock->is_users -= 1; +- +- if (sock->is_destroy) { +- if (!sock->is_users) +- isns_socket_destroy(sock); +- return 0; +- } +- return 1; +-} +- +-/* +- * Display a socket +- */ +-#if SOCK_DEBUG_VERBOSE > 0 +-static const char * +-isns_socket_state_name(int state) +-{ +- static char xbuf[16]; +- +- switch (state) { +- case ISNS_SOCK_LISTENING: +- return "listening"; +- case ISNS_SOCK_CONNECTING: +- return "connecting"; +- case ISNS_SOCK_IDLE: +- return "idle"; +- case ISNS_SOCK_FAILED: +- return "failed"; +- case ISNS_SOCK_DISCONNECTED: +- return "disconnected"; +- case ISNS_SOCK_DEAD: +- return "dead"; +- } +- snprintf(xbuf, sizeof(xbuf), "<%u>", state); +- return xbuf; +-} +- +-static void +-isns_print_socket(const isns_socket_t *sock) +-{ +- isns_message_t *msg = NULL; +- char buffer[8192]; +- size_t pos = 0, size = sizeof(buffer); +- +- snprintf(buffer + pos, size - pos, +- "socket %p desc %d state %s", +- sock, sock->is_desc, +- isns_socket_state_name(sock->is_state)); +- pos = strlen(buffer); +- +- if (timerisset(&sock->is_deadline)) { +- snprintf(buffer + pos, size - pos, " deadline=%ldms", +- __timeout_millisec(NULL, &sock->is_deadline)); +- pos = strlen(buffer); +- } +- +- if ((msg = isns_message_queue_head(&sock->is_pending)) != NULL) { +- snprintf(buffer + pos, size - pos, " msg timeout=%ldms", +- __timeout_millisec(NULL, &msg->im_timeout)); +- pos = strlen(buffer); +- } +- +- isns_debug_socket("%s\n", buffer); +-} +-#else +-#define isns_print_socket(p) do { } while (0) +-#endif +- +-/* +- * Process incoming messages, and timeouts +- */ +-static int +-isns_net_validate(isns_socket_t *sock, isns_message_t *msg, +- const isns_message_t *check_msg) +-{ +- isns_message_t *orig = NULL; +- int verdict = ISNS_MSG_DISCARD; +- +- if (sock->is_security && !msg->im_security) { +- /* Rude server, or malicious man in the +- * middle. */ +- isns_debug_message("Ignoring unauthenticated message\n"); +- goto out; +- } +- +- /* If this is a request, return it. */ +- if (!(msg->im_header.i_function & 0x8000)) { +- if (check_msg == NULL) { +- verdict = ISNS_MSG_RETURN; +- } else { +- /* Else: see if there's a server attached to this +- * socket. */ +- } +- goto out; +- } +- +- orig = isns_message_queue_find(&sock->is_pending, msg->im_xid, NULL, 0); +- if (orig == NULL) { +- isns_debug_message("Ignoring spurious response message (xid=%04x)\n", +- msg->im_xid); +- goto out; +- } +- +- isns_message_unlink(orig); +- if (orig->im_header.i_function != (msg->im_header.i_function & 0x7FFF)) { +- isns_debug_message("Response message doesn't match function\n"); +- goto out; +- } +- +- if (check_msg == orig) { +- verdict = ISNS_MSG_RETURN; +- } else { +- isns_debug_message("Received response for pending message 0x%x\n", +- msg->im_xid); +- if (orig->im_callback) +- orig->im_callback(orig, msg); +- verdict = ISNS_MSG_DONE; +- } +- +-out: +- isns_message_release(orig); +- return verdict; +-} +- +-static void +-isns_net_timeout(isns_socket_t *sock, isns_message_t *msg) +-{ +- if (msg->im_callback) +- msg->im_callback(msg, NULL); +- isns_message_release(msg); +-} +- +-/* +- * Helper function to update timeout +- */ +-static inline void +-__set_timeout(struct timeval *end, unsigned long timeout) +-{ +- gettimeofday(end, NULL); +- end->tv_sec += timeout; +-} +- +-static inline int +-__timeout_expired(const struct timeval *now, const struct timeval *expires) +-{ +- /* FIXME: Should ignore sub-millisecond remainder */ +- return timercmp(now, expires, >=); +-} +- +-static long +-__timeout_millisec(const struct timeval *now, const struct timeval *expires) +-{ +- struct timeval __now, delta = { 0, 0 }; +- +- if (now == NULL) { +- gettimeofday(&__now, NULL); +- now = &__now; +- } +- +- timersub(expires, now, &delta); +- +- return delta.tv_sec * 1000 + delta.tv_usec / 1000; +-} +- +-static inline void +-__update_timeout(struct timeval *end, const struct timeval *timeout) +-{ +- if (!timerisset(end) || timercmp(timeout, end, <)) +- *end = *timeout; +-} +- +-/* +- * Get the next iSNS message +- */ +-isns_message_t * +-__isns_recv_message(const struct timeval *end_time, isns_message_t *watch_msg) +-{ +- isns_socket_t *sock, **sock_list; +- isns_list_t *pos, *next; +- struct pollfd *pfd; +- unsigned int i, count, max_sockets; +- struct timeval now, this_end; +- int r; +- +- max_sockets = isns_config.ic_network.max_sockets; +- sock_list = alloca(max_sockets * sizeof(sock_list[0])); +- pfd = alloca(max_sockets * sizeof(pfd[0])); +- +-again: +- timerclear(&this_end); +- gettimeofday(&now, NULL); +- +- if (end_time) { +- if (__timeout_expired(&now, end_time)) +- return NULL; +- this_end = *end_time; +- } +- +- i = 0; +- isns_list_foreach(&all_sockets, pos, next) { +- isns_socket_t *sock = isns_list_item(isns_socket_t, is_list, pos); +- isns_message_t *msg = NULL; +- +- /* We need to be a little careful here; callbacks may +- * mark the socket for destruction. +- * Bumping is_users while we're busy with the socket +- * prevents mayhem. */ +- sock->is_users++; +- +- while ((msg = isns_message_dequeue(&sock->is_complete)) != NULL) { +- switch (isns_net_validate(sock, msg, watch_msg)) { +- case ISNS_MSG_RETURN: +- isns_assert(!sock->is_destroy); +- isns_socket_release(sock); +- return msg; +- default: +- isns_message_release(msg); +- isns_socket_release(sock); +- return NULL; +- } +- } +- +- isns_print_socket(sock); +- +- /* This handles reconnect, idle disconnect etc. */ +- while (timerisset(&sock->is_deadline)) { +- if (__timeout_expired(&now, &sock->is_deadline)) { +- timerclear(&sock->is_deadline); +- sock->is_timeout(sock); +- isns_print_socket(sock); +- continue; +- } +- __update_timeout(&this_end, &sock->is_deadline); +- break; +- } +- +- /* No more input and output means closed&dead */ +- if (sock->is_state == ISNS_SOCK_IDLE +- && !(sock->is_poll_mask & (POLLIN|POLLOUT))) { +- isns_debug_socket("connection closed by peer, killing socket\n"); +- isns_net_close(sock, ISNS_SOCK_FAILED); +- } +- +- /* Check whether pending messages have timed out. */ +- while ((msg = isns_message_queue_head(&sock->is_pending)) != +- NULL) { +- if (__timeout_expired(&now, &msg->im_timeout)) { +- isns_debug_socket("sock %p message %04x timed out\n", +- sock, msg->im_xid); +- isns_message_unlink(msg); +- if (msg == watch_msg) { +- isns_message_release(msg); +- isns_socket_release(sock); +- return NULL; +- } +- +- isns_net_timeout(sock, msg); +- continue; +- } +- +- if (!__timeout_expired(&now, &msg->im_resend_timeout)) { +- __update_timeout(&this_end, +- &msg->im_resend_timeout); +- /* In odd configurations, the call_timeout +- * may be lower than the resend_timeout */ +- __update_timeout(&this_end, +- &msg->im_timeout); +- break; +- } +- +- isns_debug_socket("sock %p message %04x - " +- "minor timeout, resending.\n", +- sock, msg->im_xid); +- +- /* If a TCP socket times out, something is +- * fishy. Force a reconnect, which will resend +- * all pending messages. */ +- if (sock->is_type == SOCK_STREAM) { +- isns_net_close(sock, ISNS_SOCK_DISCONNECTED); +- isns_net_set_timeout(sock, +- isns_net_stream_reconnect, +- 0); +- break; +- } +- +- /* UDP socket - retransmit this one message */ +- isns_message_queue_remove(&sock->is_pending, msg); +- isns_socket_queue_message(sock, msg); +- isns_message_release(msg); +- } +- +- /* +- * If the socket on which we're waiting right +- * now got disconnected, or had any other kind of +- * error, return right away to let the caller know. +- */ +- if (sock->is_state == ISNS_SOCK_FAILED) { +- if (sock->is_disconnect_fatal) +- goto kill_socket; +- if (sock->is_report_failure) { +- isns_socket_release(sock); +- return NULL; +- } +- sock->is_state = ISNS_SOCK_DISCONNECTED; +- isns_socket_release(sock); +- continue; +- } +- +- if (sock->is_state == ISNS_SOCK_DEAD) { +-kill_socket: +- isns_list_del(&sock->is_list); +- if (sock->is_report_failure) { +- isns_socket_release(sock); +- return NULL; +- } +- if (!sock->is_client) +- isns_socket_free(sock); +- isns_socket_release(sock); +- continue; +- } +- +- /* This will return 0 if the socket was marked for +- * destruction. */ +- if (!isns_socket_release(sock)) +- continue; +- +- /* should not happen */ +- if (i >= max_sockets) +- break; +- +- pfd[i].fd = sock->is_desc; +- pfd[i].events = sock->is_poll_mask; +- sock_list[i] = sock; +- i++; +- } +- count = i; +- +- if (timerisset(&this_end)) { +- long millisec; +- +- /* timeval arithmetic can yield sub-millisecond timeouts. +- * Round up to prevent looping. */ +- millisec = __timeout_millisec(&now, &this_end); +- if (millisec == 0) +- millisec += 1; +- +- debug_verbose2("poll(%p, %u, %d)\n", pfd, count, millisec); +- r = poll(pfd, count, millisec); +- } else { +- r = poll(pfd, count, -1); +- } +- +- if (r < 0) { +- if (errno != EINTR) +- isns_error("poll returned error: %m\n"); +- return NULL; +- } +- +- /* Any new incoming connections will be added to the +- * head of the list. */ +- for (i = 0; i < count; ++i) { +- sock = sock_list[i]; +- if (pfd[i].revents & POLLIN) +- sock->is_poll_in(sock); +- if (pfd[i].revents & POLLOUT) +- sock->is_poll_out(sock); +- if (pfd[i].revents & POLLHUP) +- sock->is_poll_hup(sock); +- } +- +- goto again; +-} +- +-isns_message_t * +-isns_recv_message(struct timeval *timeout) +-{ +- isns_message_t *msg; +- struct timeval end; +- +- if (timeout == NULL) +- return __isns_recv_message(NULL, NULL); +- +- gettimeofday(&end, NULL); +- timeradd(&end, timeout, &end); +- msg = __isns_recv_message(&end, NULL); +- +- if (msg == NULL) +- return msg; +- isns_debug_socket("Next message xid=%04x\n", msg->im_xid); +- if (msg->im_security) { +- isns_debug_message("Received authenticated message from \"%s\"\n", +- isns_principal_name(msg->im_security)); +- } else if (isns_config.ic_security) { +- isns_debug_message("Received unauthenticated message\n"); +- } else { +- isns_debug_message("Received message\n"); +- } +- return msg; +-} +- +-int +-isns_socket_send(isns_socket_t *sock, isns_message_t *msg) +-{ +- struct isns_hdr *hdr; +- size_t pdu_len; +- buf_t *bp; +- +- /* If the socket is disconnected, and the +- * reconnect timeout is not set, force a +- * reconnect right away. */ +- if (sock->is_state == ISNS_SOCK_DISCONNECTED +- && !timerisset(&sock->is_deadline)) { +- isns_net_set_timeout(sock, +- isns_net_stream_reconnect, 0); +- } +- +- if (!(bp = msg->im_payload)) +- return 0; +- +- pdu_len = buf_avail(bp); +- if (pdu_len < sizeof(*hdr)) +- return 0; +- +- /* Pad PDU to multiple of 4 bytes, if needed */ +- if (pdu_len & 3) { +- unsigned int pad = 4 - (pdu_len & 3); +- +- if (!buf_put(bp, "\0\0\0", pad)) +- return 0; +- pdu_len += pad; +- } +- +- if (!(bp = buf_dup(bp))) +- return 0; +- +- hdr = buf_head(bp); +- +- hdr->i_version = htons(msg->im_header.i_version); +- hdr->i_function = htons(msg->im_header.i_function); +- hdr->i_flags = htons(msg->im_header.i_flags); +- hdr->i_length = htons(pdu_len - sizeof(*hdr)); +- hdr->i_xid = htons(msg->im_header.i_xid); +- hdr->i_seq = htons(msg->im_header.i_seq); +- +- /* For now, we deal with unfragmented messages only. */ +- hdr->i_flags |= htons(ISNS_F_FIRST_PDU|ISNS_F_LAST_PDU); +- +- if (sock->is_security) { +-#ifdef WITH_SECURITY +- hdr->i_flags |= htons(ISNS_F_AUTHBLK_PRESENT); +- if (!isns_pdu_seal(sock->is_security, bp)) { +- isns_debug_message("Error adding auth block to outgoing PDU\n"); +- goto error; +- } +-#else +- isns_debug_message("%s: Authentication not supported\n", +- __FUNCTION__); +- goto error; +-#endif +- } +- +- bp->addr = msg->im_addr; +- bp->addrlen = msg->im_addrlen; +- +- buf_list_append(&sock->is_xmit_buf, bp); +- sock->is_poll_mask |= POLLOUT; +- +- /* Set the retransmit timeout */ +- __set_timeout(&msg->im_resend_timeout, sock->is_retrans_timeout); +- return 1; +- +-error: +- buf_free(bp); +- return 0; +-} +- +-/* +- * Queue a message to a socket +- */ +-int +-isns_socket_queue_message(isns_socket_t *sock, isns_message_t *msg) +-{ +- if (!isns_socket_send(sock, msg)) +- return 0; +- +- /* Insert sorted by timeout. For now, this amounts to +- * appending at the end of the list, but that may change +- * if we implement exponential backoff for UDP */ +- isns_message_queue_insert_sorted(&sock->is_pending, +- ISNS_MQ_SORT_RESEND_TIMEOUT, msg); +- msg->im_socket = sock; +- return 1; +-} +- +-/* +- * Retransmit any queued messages +- */ +-int +-isns_socket_retransmit_queued(isns_socket_t *sock) +-{ +- isns_message_t *msg; +- isns_list_t *pos; +- +- isns_debug_socket("%s(%p)\n", __FUNCTION__, sock); +- isns_message_queue_foreach(&sock->is_pending, pos, msg) { +- if (!isns_socket_send(sock, msg)) +- isns_warning("Unable to retransmit message\n"); +- } +- return 1; +-} +- +-/* +- * Submit a message to the socket, for asynchronous calls +- */ +-int +-isns_socket_submit(isns_socket_t *sock, isns_message_t *msg, long timeout) +-{ +- if (timeout <= 0) +- timeout = isns_config.ic_network.call_timeout; +- +- __set_timeout(&msg->im_timeout, timeout); +- return isns_socket_queue_message(sock, msg); +-} +- +-/* +- * Transmit a message and wait for a response. +- */ +-isns_message_t * +-isns_socket_call(isns_socket_t *sock, isns_message_t *msg, long timeout) +-{ +- isns_message_t *resp; +- +- debug_verbose("isns_socket_call(sock=%p, msg=%p, timeout=%ld)\n", +- sock, msg, timeout); +- if (timeout <= 0) +- timeout = isns_config.ic_network.call_timeout; +- +- __set_timeout(&msg->im_timeout, timeout); +- if (!isns_socket_queue_message(sock, msg)) +- return NULL; +- +- sock->is_report_failure = 1; +- resp = __isns_recv_message(NULL, msg); +- sock->is_report_failure = 0; +- +- if (isns_message_unlink(msg)) { +- /* We can get here if __isns_recv_message returned +- * due to a fatal socket error. */ +- isns_debug_socket("%s: msg not unlinked!\n", __FUNCTION__); +- isns_message_release(msg); +- } +- +- if (resp == NULL && sock->is_type == SOCK_STREAM) +- isns_net_close(sock, ISNS_SOCK_DISCONNECTED); +- +- return resp; +-} +- +-/* +- * Resolve a hostname +- */ +-struct addrinfo * +-isns_get_address_list(const char *addrspec, const char *port, +- int af_hint, int sock_type, int flags) +-{ +- struct addrinfo hints, *found = NULL, *res = NULL; +- char *copy = NULL, *host = NULL, *s; +- int rv; +- +- memset(&hints, 0, sizeof(hints)); +- hints.ai_flags = AI_ADDRCONFIG; +- +- if (addrspec && addrspec[0] == '/') { +- if (af_hint != AF_LOCAL && af_hint != AF_UNSPEC) { +- isns_debug_socket("Path as address, but af_hint=%d\n", +- af_hint); +- goto bad_address; +- } +- +- res = make_addrinfo_unix(addrspec, SOCK_STREAM); +- goto out; +- } +- +- if (addrspec) { +- copy = host = isns_strdup(addrspec); +- if (*host == '[') { +- hints.ai_flags |= AI_NUMERICHOST; +- if ((s = strchr(host, ']')) == NULL) +- goto bad_address; +- +- *s++ = '\0'; +- if (*s == ':') +- port = ++s; +- else if (*s) +- goto bad_address; +- } else if ((s = strchr(host, ':')) != NULL) { +- *s++ = '\0'; +- if (!*s) +- goto bad_address; +- port = s; +- } +- +- if (*host == '\0') +- host = NULL; +- } else if (port == NULL) { +- /* Just wildcard */ +- res = make_addrinfo_any(af_hint, sock_type); +- goto out; +- } +- +- hints.ai_family = af_hint; +- hints.ai_flags |= flags; +- hints.ai_socktype = sock_type; +- if (af_hint == AF_INET6) +- hints.ai_flags |= AI_V4MAPPED; +- +- rv = getaddrinfo(host, port, &hints, &found); +- if (rv) { +- isns_error("Cannot resolve address \"%s\": %s\n", +- addrspec, gai_strerror(rv)); +- goto out; +- } +- +- if (found == NULL) { +- isns_error("No useable addresses returned.\n"); +- goto out; +- } +- +- res = clone_addrinfo(found); +- +-out: +- if (found) +- freeaddrinfo(found); +- isns_free(copy); +- return res; +- +-bad_address: +- isns_error("Cannot parse address spec \"%s\"\n", +- addrspec); +- goto out; +-} +- +-int +-isns_get_address(struct sockaddr_storage *result, +- const char *addrspec, +- const char *port, +- int af_hint, int sock_type, int flags) +-{ +- struct addrinfo *ai; +- int alen; +- +- if (!(ai = isns_get_address_list(addrspec, port, af_hint, sock_type, flags))) +- return -1; +- +- alen = ai->ai_addrlen; +- if (alen > sizeof(*result)) +- return -1; +- memcpy(result, ai->ai_addr, alen); +- release_addrinfo(ai); +- return alen; +-} +- +-/* +- * Get the canonical hostname +- */ +-char * +-isns_get_canon_name(const char *hostname) +-{ +- struct addrinfo hints, *res = NULL; +- char *fqdn = NULL; +- int rv; +- +- memset(&hints, 0, sizeof(hints)); +- hints.ai_flags = AI_CANONNAME; +- +- rv = getaddrinfo(hostname, NULL, &hints, &res); +- if (rv) { +- isns_error("Cannot resolve hostname \"%s\": %s\n", +- hostname, gai_strerror(rv)); +- goto out; +- } +- +- if (res == NULL) { +- isns_error("No useable addresses returned.\n"); +- goto out; +- } +- +- +- fqdn = isns_strdup(res->ai_canonname); +- +-out: +- if (res) +- freeaddrinfo(res); +- return fqdn; +-} +- +-int +-isns_socket_get_local_addr(const isns_socket_t *sock, +- struct sockaddr_storage *addr) +-{ +- socklen_t alen; +- +- if (sock->is_desc < 0) +- return 0; +- if (getsockname(sock->is_desc, +- (struct sockaddr *) addr, &alen) < 0) { +- isns_error("getsockname: %m\n"); +- return 0; +- } +- +- return 1; +-} +- +-int +-isns_socket_get_portal_info(const isns_socket_t *sock, +- isns_portal_info_t *portal) +-{ +- struct sockaddr_storage addr; +- socklen_t alen; +- int fd, success = 0; +- +- memset(portal, 0, sizeof(*portal)); +- +- /* If the socket is currently closed (eg because the +- * server shut down the connection), we cannot get the +- * local address easily. Create a temporary UDP socket, +- * connect it, and query that socket. */ +- if ((fd = sock->is_desc) < 0) { +- const struct sockaddr *daddr; +- +- daddr = (struct sockaddr *) &sock->is_dst.addr; +- fd = socket(daddr->sa_family, SOCK_DGRAM, 0); +- if (fd < 0) +- goto out; +- if (connect(fd, daddr, sizeof(sock->is_dst.addr)) < 0) +- goto out; +- } +- +- alen = sizeof(addr); +- if (getsockname(fd, (struct sockaddr *) &addr, &alen) < 0) { +- isns_error("getsockname: %m\n"); +- goto out; +- } +- +- if (!isns_portal_from_sockaddr(portal, &addr)) +- goto out; +- if (sock->is_type == SOCK_STREAM) +- portal->proto = IPPROTO_TCP; +- else +- portal->proto = IPPROTO_UDP; +- +- debug_verbose("socket_get_portal: %s\n", isns_portal_string(portal)); +- success = 1; +- +-out: +- /* If we used a temp UDP socket, close it */ +- if (fd >= 0 && fd != sock->is_desc) +- close(fd); +- return success; +-} +- +-isns_socket_t * +-isns_socket_find_server(const isns_portal_info_t *portal) +-{ +- struct sockaddr_storage bound_addr; +- int sock_type, addr_len; +- isns_list_t *pos, *next; +- +- addr_len = isns_portal_to_sockaddr(portal, &bound_addr); +- if ((sock_type = isns_socket_type_from_portal(portal)) < 0) +- return NULL; +- +- isns_list_foreach(&all_sockets, pos, next) { +- isns_socket_t *sock = isns_list_item(isns_socket_t, is_list, pos); +- +- if (!sock->is_client +- && sock->is_type == sock_type +- && sock->is_dst.addrlen == addr_len +- && !memcmp(&sock->is_dst.addr, &bound_addr, addr_len)) { +- sock->is_users++; +- return sock; +- } +- } +- +- return NULL; +-} +- +-int +-isns_addr_get_port(const struct sockaddr *addr) +-{ +- const struct sockaddr_in *sin; +- const struct sockaddr_in6 *six; +- +- switch (addr->sa_family) { +- case AF_INET: +- sin = (const struct sockaddr_in *) addr; +- return ntohs(sin->sin_port); +- +- case AF_INET6: +- six = (const struct sockaddr_in6 *) addr; +- return ntohs(six->sin6_port); +- } +- return 0; +-} +- +-void +-isns_addr_set_port(struct sockaddr *addr, unsigned int port) +-{ +- struct sockaddr_in *sin; +- struct sockaddr_in6 *six; +- +- switch (addr->sa_family) { +- case AF_INET: +- sin = (struct sockaddr_in *) addr; +- sin->sin_port = htons(port); +- break; +- +- case AF_INET6: +- six = (struct sockaddr_in6 *) addr; +- six->sin6_port = htons(port); +- break; +- } +-} +diff --git a/utils/open-isns/socket.h b/utils/open-isns/socket.h +deleted file mode 100644 +index cc63d23..0000000 +--- a/utils/open-isns/socket.h ++++ /dev/null +@@ -1,95 +0,0 @@ +-/* +- * iSNS network code +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#ifndef ISNS_SOCKET_H +-#define ISNS_SOCKET_H +- +-#include "isns.h" +-#include "buffer.h" +-#include "message.h" +- +-struct isns_partial_msg { +- isns_message_t imp_base; +- uint32_t imp_flags; +- uint32_t imp_first_seq; +- uint32_t imp_last_seq; +- unsigned int imp_pdu_count; +- unsigned int imp_msg_size; +- buf_t * imp_chain; +- +- struct ucred imp_credbuf; +-}; +- +-#define imp_users imp_base.im_users +-#define imp_list imp_base.im_list +-#define imp_xid imp_base.im_xid +-#define imp_header imp_base.im_header +-#define imp_addr imp_base.im_addr +-#define imp_addrlen imp_base.im_addrlen +-#define imp_header imp_base.im_header +-#define imp_payload imp_base.im_payload +-#define imp_security imp_base.im_security +-#define imp_creds imp_base.im_creds +- +-enum { +- ISNS_SOCK_LISTENING, +- ISNS_SOCK_CONNECTING, +- ISNS_SOCK_IDLE, +- ISNS_SOCK_FAILED, +- ISNS_SOCK_DISCONNECTED, +- ISNS_SOCK_DEAD, +-}; +- +-/* Helper class */ +-struct __isns_socket_addr { +- struct sockaddr_storage addr; +- socklen_t addrlen; +- struct addrinfo * list; +-}; +- +-struct isns_socket { +- isns_list_t is_list; +- int is_desc; +- int is_type; +- unsigned int is_client : 1, +- is_autoclose : 1, +- is_disconnect_fatal : 1, +- is_report_failure : 1, +- is_destroy : 1; +- unsigned int is_users; +- int is_poll_mask; +- int is_state; +- +- isns_security_t * is_security; +- +- struct __isns_socket_addr is_src, is_dst; +- +- unsigned int is_retrans_timeout; +- +- /* If we're past this time, is_timeout() is called. */ +- struct timeval is_deadline; +- +- buf_t * is_recv_buf; +- buf_t * is_xmit_buf; +- +- size_t is_queue_size; +- isns_message_queue_t is_partial; +- isns_message_queue_t is_complete; +- isns_message_queue_t is_pending; +- +- void (*is_poll_in)(isns_socket_t *); +- void (*is_poll_out)(isns_socket_t *); +- void (*is_poll_hup)(isns_socket_t *); +- void (*is_poll_err)(isns_socket_t *); +- void (*is_timeout)(isns_socket_t *); +- void (*is_error)(isns_socket_t *, int); +-}; +- +-extern int isns_socket_submit(isns_socket_t *, +- isns_message_t *, +- long); +- +-#endif /* ISNS_SOCKET_H */ +diff --git a/utils/open-isns/source.h b/utils/open-isns/source.h +deleted file mode 100644 +index 59fb662..0000000 +--- a/utils/open-isns/source.h ++++ /dev/null +@@ -1,32 +0,0 @@ +-/* +- * iSNS source attribute handling +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#ifndef ISNS_SOURCE_H +-#define ISNS_SOURCE_H +- +-#include "attrs.h" +- +-struct isns_source { +- unsigned int is_users; +- isns_attr_t * is_attr; +- unsigned int is_untrusted : 1; +- +- isns_object_t * is_node; +- unsigned int is_node_type; +- +- isns_object_t * is_entity; +-}; +- +-extern int isns_source_encode(buf_t *, const isns_source_t *); +-extern int isns_source_decode(buf_t *, isns_source_t **); +-extern int isns_source_set_node(isns_source_t *, isns_db_t *); +-extern void isns_source_set_entity(isns_source_t *, isns_object_t *); +-extern isns_source_t * isns_source_dummy(void); +- +-extern char * isns_build_source_pattern(const char *); +-extern int isns_source_pattern_match(const char *, const char *); +- +-#endif /* ISNS_SOURCE_H */ +diff --git a/utils/open-isns/storage-node.c b/utils/open-isns/storage-node.c +deleted file mode 100644 +index 97e54d1..0000000 +--- a/utils/open-isns/storage-node.c ++++ /dev/null +@@ -1,202 +0,0 @@ +-/* +- * iSNS object model - storage node +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include "isns.h" +-#include "objects.h" +-#include "util.h" +- +-isns_object_t * +-isns_create_storage_node(const char *name, uint32_t type, +- isns_object_t *parent) +-{ +- isns_object_t *obj; +- +- if (parent && !ISNS_IS_ENTITY(parent)) { +- isns_warning("Invalid container type \"%s\" for storage node: " +- "should be \"%s\"\n", +- parent->ie_template->iot_name, +- isns_entity_template.iot_name); +- return NULL; +- } +- +- obj = isns_create_object(&isns_iscsi_node_template, NULL, parent); +- isns_object_set_string(obj, +- ISNS_TAG_ISCSI_NAME, name); +- isns_object_set_uint32(obj, +- ISNS_TAG_ISCSI_NODE_TYPE, type); +- +- return obj; +-} +- +-isns_object_t * +-isns_create_storage_node2(const isns_source_t *source, +- uint32_t type, +- isns_object_t *parent) +-{ +- isns_attr_t *name_attr; +- isns_object_t *obj; +- +- if (parent && !ISNS_IS_ENTITY(parent)) { +- isns_warning("Invalid container type \"%s\" for storage node: " +- "should be \"%s\"\n", +- parent->ie_template->iot_name, +- isns_entity_template.iot_name); +- return NULL; +- } +- if ((name_attr = isns_source_attr(source)) == NULL) { +- isns_warning("No source attribute\n"); +- return NULL; +- } +- +- if (name_attr->ia_tag_id == ISNS_TAG_ISCSI_NAME) { +- obj = isns_create_object(&isns_iscsi_node_template, NULL, parent); +- isns_attr_list_update_attr(&obj->ie_attrs, name_attr); +- isns_object_set_uint32(obj, +- ISNS_TAG_ISCSI_NODE_TYPE, type); +- } else { +- /* No iFCP yet, sorry */ +- isns_warning("%s: source tag type %u not supported\n", +- __FUNCTION__); +- return NULL; +- } +- +- return obj; +-} +- +-isns_object_t * +-isns_create_iscsi_initiator(const char *name, +- isns_object_t *parent) +-{ +- return isns_create_storage_node(name, +- 1 << ISNS_ISCSI_NODE_TYPE_INITIATOR, +- parent); +-} +- +-isns_object_t * +-isns_create_iscsi_target(const char *name, +- isns_object_t *parent) +-{ +- return isns_create_storage_node(name, +- 1 << ISNS_ISCSI_NODE_TYPE_TARGET, +- parent); +-} +- +-const char * +-isns_storage_node_name(const isns_object_t *node) +-{ +- const isns_attr_t *attr; +- +- if (node->ie_attrs.ial_count == 0) +- return NULL; +- attr = node->ie_attrs.ial_data[0]; +- if (attr->ia_value.iv_type != &isns_attr_type_string) +- return NULL; +- +- switch (attr->ia_tag_id) { +- case ISNS_TAG_ISCSI_NAME: +- case ISNS_TAG_FC_PORT_NAME_WWPN: +- return attr->ia_value.iv_string; +- } +- +- return 0; +- +-} +- +-isns_attr_t * +-isns_storage_node_key_attr(const isns_object_t *node) +-{ +- if (node->ie_attrs.ial_count == 0) +- return NULL; +- return node->ie_attrs.ial_data[0]; +-} +- +-static uint32_t iscsi_node_attrs[] = { +- ISNS_TAG_ISCSI_NAME, +- ISNS_TAG_ISCSI_NODE_TYPE, +- ISNS_TAG_ISCSI_ALIAS, +- ISNS_TAG_ISCSI_SCN_BITMAP, +- ISNS_TAG_ISCSI_NODE_INDEX, +- ISNS_TAG_WWNN_TOKEN, +- ISNS_TAG_ISCSI_AUTHMETHOD, +- /* RFC 4171 lists a "iSCSI node certificate" +- * as an option attribute of an iSCSI +- * storage node, but doesn't define it anywhere +- * in the spec. +- */ +-}; +- +-static uint32_t iscsi_node_key_attrs[] = { +- ISNS_TAG_ISCSI_NAME, +-}; +- +-isns_object_template_t isns_iscsi_node_template = { +- .iot_name = "iSCSI Storage Node", +- .iot_handle = ISNS_OBJECT_TYPE_NODE, +- .iot_attrs = iscsi_node_attrs, +- .iot_num_attrs = array_num_elements(iscsi_node_attrs), +- .iot_keys = iscsi_node_key_attrs, +- .iot_num_keys = array_num_elements(iscsi_node_key_attrs), +- .iot_index = ISNS_TAG_ISCSI_NODE_INDEX, +- .iot_next_index = ISNS_TAG_ISCSI_NODE_NEXT_INDEX, +- .iot_container = &isns_entity_template, +-}; +- +-static uint32_t fc_port_attrs[] = { +- ISNS_TAG_FC_PORT_NAME_WWPN, +- ISNS_TAG_PORT_ID, +- ISNS_TAG_FC_PORT_TYPE, +- ISNS_TAG_SYMBOLIC_PORT_NAME, +- ISNS_TAG_FABRIC_PORT_NAME, +- ISNS_TAG_HARD_ADDRESS, +- ISNS_TAG_PORT_IP_ADDRESS, +- ISNS_TAG_CLASS_OF_SERVICE, +- ISNS_TAG_FC4_TYPES, +- ISNS_TAG_FC4_DESCRIPTOR, +- ISNS_TAG_FC4_FEATURES, +- ISNS_TAG_IFCP_SCN_BITMAP, +- ISNS_TAG_PORT_ROLE, +- ISNS_TAG_PERMANENT_PORT_NAME, +-}; +- +-static uint32_t fc_port_key_attrs[] = { +- ISNS_TAG_FC_PORT_NAME_WWPN, +-}; +- +-isns_object_template_t isns_fc_port_template = { +- .iot_name = "iFCP Port", +- .iot_handle = ISNS_OBJECT_TYPE_FC_PORT, +- .iot_attrs = fc_port_attrs, +- .iot_num_attrs = array_num_elements(fc_port_attrs), +- .iot_keys = fc_port_key_attrs, +- .iot_num_keys = array_num_elements(fc_port_key_attrs), +- .iot_container = &isns_entity_template, +-}; +- +-static uint32_t fc_node_attrs[] = { +- ISNS_TAG_FC_NODE_NAME_WWNN, +- ISNS_TAG_SYMBOLIC_NODE_NAME, +- ISNS_TAG_NODE_IP_ADDRESS, +- ISNS_TAG_NODE_IPA, +- ISNS_TAG_PROXY_ISCSI_NAME, +-}; +- +-static uint32_t fc_node_key_attrs[] = { +- ISNS_TAG_FC_NODE_NAME_WWNN, +-}; +- +-isns_object_template_t isns_fc_node_template = { +- .iot_name = "iFCP Device Node", +- .iot_handle = ISNS_OBJECT_TYPE_FC_NODE, +- .iot_attrs = fc_node_attrs, +- .iot_num_attrs = array_num_elements(fc_node_attrs), +- .iot_keys = fc_node_key_attrs, +- .iot_num_keys = array_num_elements(fc_node_key_attrs), +- .iot_container = &isns_fc_port_template, +-}; +- +diff --git a/utils/open-isns/sysdep-unix.c b/utils/open-isns/sysdep-unix.c +deleted file mode 100644 +index d2a9532..0000000 +--- a/utils/open-isns/sysdep-unix.c ++++ /dev/null +@@ -1,186 +0,0 @@ +-/* +- * System dependent stuff +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include "isns.h" +-#include "util.h" +- +-int isns_get_nr_portals(void) +-{ +- char buffer[8192], *end, *ptr; +- struct ifconf ifc; +- unsigned int nportals = 0; +- int fd = -1; +- +- if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { +- isns_error("%s: no socket - %m\n", __FUNCTION__); +- return 0; +- } +- +- ifc.ifc_buf = buffer; +- ifc.ifc_len = sizeof(buffer); +- if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { +- isns_error("ioctl(SIOCGIFCONF): %m\n"); +- goto out; +- } +- +- ptr = buffer; +- end = buffer + ifc.ifc_len; +- while (ptr < end) { +- struct ifreq ifr; +- struct sockaddr_storage ifaddr; +- int ifflags; +- +- memcpy(&ifr, ptr, sizeof(ifr)); +- ptr += sizeof(ifr); +- +- /* Get the interface addr */ +- memcpy(&ifaddr, &ifr.ifr_addr, sizeof(ifr.ifr_addr)); +- +- if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { +- isns_error("ioctl(%s, SIOCGIFFLAGS): %m\n", +- ifr.ifr_name); +- continue; +- } +- ifflags = ifr.ifr_flags; +- +- if ((ifflags & IFF_UP) == 0) +- continue; +- if ((ifflags & IFF_LOOPBACK) != 0) +- continue; +- +- if (ifaddr.ss_family == AF_INET6 || ifaddr.ss_family == AF_INET) +- nportals++; +- } +- +-out: +- if (fd >= 0) +- close(fd); +- return nportals; +-} +- +-int +-isns_enumerate_portals(isns_portal_info_t *result, unsigned int max) +-{ +- char buffer[8192], *end, *ptr; +- struct ifconf ifc; +- unsigned int nportals = 0; +- int fd = -1; +- +- if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { +- isns_error("%s: no socket - %m\n", __FUNCTION__); +- return 0; +- } +- +- ifc.ifc_buf = buffer; +- ifc.ifc_len = sizeof(buffer); +- if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { +- isns_error("ioctl(SIOCGIFCONF): %m\n"); +- goto out; +- } +- +- ptr = buffer; +- end = buffer + ifc.ifc_len; +- while (ptr < end) { +- struct ifreq ifr; +- struct sockaddr_storage ifaddr; +- isns_portal_info_t portal; +- int ifflags; +- +- memcpy(&ifr, ptr, sizeof(ifr)); +- ptr += sizeof(ifr); +- +- /* Get the interface addr */ +- memcpy(&ifaddr, &ifr.ifr_addr, sizeof(ifr.ifr_addr)); +- +- if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { +- isns_error("ioctl(%s, SIOCGIFFLAGS): %m\n", +- ifr.ifr_name); +- continue; +- } +- ifflags = ifr.ifr_flags; +- +- if ((ifflags & IFF_UP) == 0) +- continue; +- if ((ifflags & IFF_LOOPBACK) != 0) +- continue; +- +- if (!isns_portal_from_sockaddr(&portal, &ifaddr)) +- continue; +- +- isns_debug_socket("Got interface %u: %s %s\n", +- nportals, ifr.ifr_name, +- isns_portal_string(&portal)); +- if (nportals < max) +- result[nportals++] = portal; +- } +- +-out: +- if (fd >= 0) +- close(fd); +- return nportals; +-} +- +-int +-isns_portal_from_sockaddr(isns_portal_info_t *portal, +- const struct sockaddr_storage *addr) +-{ +- struct sockaddr_in6 *six; +- struct sockaddr_in *sin; +- +- memset(portal, 0, sizeof(*portal)); +- +- /* May have to convert AF_INET to AF_INET6 */ +- six = &portal->addr; +- switch (addr->ss_family) { +- case AF_INET6: +- memcpy(six, addr, sizeof(*six)); +- break; +- +- case AF_INET: +- sin = (struct sockaddr_in *) addr; +- six->sin6_family = AF_INET6; +- six->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; +- six->sin6_port = sin->sin_port; +- break; +- +- default: +- return 0; +- } +- +- return 1; +-} +- +-int +-isns_portal_to_sockaddr(const isns_portal_info_t *portal, +- struct sockaddr_storage *addr) +-{ +- const struct sockaddr_in6 *six = &portal->addr; +- struct sockaddr_in *sin; +- +- /* Check if this is really a v4 address is disguise. +- * If so, explicitly use an AF_INET socket - the +- * stack may not support IPv6. +- */ +- if (IN6_IS_ADDR_V4MAPPED(&six->sin6_addr) +- || IN6_IS_ADDR_V4COMPAT(&six->sin6_addr)) { +- sin = (struct sockaddr_in *) addr; +- +- memset(sin, 0, sizeof(*sin)); +- sin->sin_family = AF_INET; +- sin->sin_addr.s_addr = six->sin6_addr.s6_addr32[3]; +- sin->sin_port = six->sin6_port; +- +- return sizeof(*sin); +- } +- +- /* This is the genuine article */ +- memcpy(addr, six, sizeof(*six)); +- return sizeof(*six); +-} +diff --git a/utils/open-isns/tags.c b/utils/open-isns/tags.c +deleted file mode 100644 +index 7413cee..0000000 +--- a/utils/open-isns/tags.c ++++ /dev/null +@@ -1,740 +0,0 @@ +-/* +- * Define all iSNS tags with their types, etc. +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include "isns-proto.h" +-#include "vendor.h" +-#include "attrs.h" +-#include "security.h" +-#include "objects.h" +-#include "util.h" +- +-#define ISNS_MAX_BUILTIN_TAG 4096 +- +- +-static void print_bitfield(unsigned long, char **, char *, size_t); +-static int parse_bitfield( char **, const char *, uint32_t *); +-static const char *help_bitfield(char **); +- +-#define DECLARE_VALIDATOR(name) \ +-static int isns_##name##_validate(const isns_value_t *, const isns_policy_t *); +-#define DECLARE_ACCESSORS(name) \ +-static int isns_##name##_parse(isns_value_t *, const char *buf); \ +-static void isns_##name##_print(const isns_value_t *, char *buf, size_t size); \ +-static const char * isns_##name##_help(void) +-#define USE_VALIDATOR(name) \ +- .it_validate = isns_##name##_validate +-#define USE_ACCESSORS(name) \ +- .it_parse = isns_##name##_parse, \ +- .it_print = isns_##name##_print, \ +- .it_help = isns_##name##_help +- +-DECLARE_VALIDATOR(entity_protocol); +-DECLARE_ACCESSORS(entity_protocol); +-DECLARE_ACCESSORS(tcpudp_port); +-DECLARE_VALIDATOR(iscsi_node_type); +-DECLARE_ACCESSORS(iscsi_node_type); +-DECLARE_ACCESSORS(timestamp); +-DECLARE_ACCESSORS(portal_secbitmap); +-DECLARE_ACCESSORS(scn_bitmap); +-DECLARE_ACCESSORS(dd_features); +-DECLARE_ACCESSORS(policy_object_type); +-DECLARE_ACCESSORS(policy_function); +- +-static const char *isns_authmethod_help(void); +- +-#define TAG(ID, name, type, args...) \ +-[ISNS_TAG_##ID] = { \ +- .it_id = ISNS_TAG_##ID, \ +- .it_name = name, \ +- .it_type = &isns_attr_type_##type, \ +- args \ +-} +- +-static isns_tag_type_t isns_tags[ISNS_MAX_BUILTIN_TAG] = { +-TAG(DELIMITER, "Delimiter", nil), +-TAG(ENTITY_IDENTIFIER, "Entity identifier", string), +-TAG(ENTITY_PROTOCOL, "Entity protocol", uint32, +- USE_VALIDATOR(entity_protocol), +- USE_ACCESSORS(entity_protocol)), +-TAG(MGMT_IP_ADDRESS, "Mgmt IP address", ipaddr), +-TAG(TIMESTAMP, "Timestamp", uint64, +- USE_ACCESSORS(timestamp), +- .it_readonly = 1), +-TAG(PROTOCOL_VERSION_RANGE, "Protocol version range", range16), +-TAG(REGISTRATION_PERIOD, "Registration Period", uint32), +-TAG(ENTITY_INDEX, "Entity index", uint32, +- .it_readonly = 1), +-TAG(ENTITY_NEXT_INDEX, "Entity next index", uint32, +- .it_readonly = 1), +-TAG(PORTAL_IP_ADDRESS, "Portal IP address", ipaddr), +-TAG(PORTAL_TCP_UDP_PORT, "Portal TCP/UDP port", uint32, +- USE_ACCESSORS(tcpudp_port)), +-TAG(ESI_INTERVAL, "ESI interval", uint32), +-TAG(ESI_PORT, "ESI port", uint32, +- USE_ACCESSORS(tcpudp_port)), +-TAG(PORTAL_SYMBOLIC_NAME, "Portal name", string), +-TAG(PORTAL_INDEX, "Portal index", uint32), +-TAG(SCN_PORT, "SCN port", uint32, +- USE_ACCESSORS(tcpudp_port)), +-TAG(PORTAL_SECURITY_BITMAP, "Portal security bitmap", uint32, +- USE_ACCESSORS(portal_secbitmap)), +-TAG(PORTAL_NEXT_INDEX, "Portal next index", uint32, +- .it_readonly = 1), +- +-TAG(ISCSI_NAME, "iSCSI name", string), +-TAG(ISCSI_NODE_TYPE, "iSCSI node type", uint32, +- USE_VALIDATOR(iscsi_node_type), +- USE_ACCESSORS(iscsi_node_type)), +-TAG(ISCSI_ALIAS, "iSCSI alias", string), +-TAG(ISCSI_SCN_BITMAP, "iSCSI SCN bitmap", uint32, +- USE_ACCESSORS(scn_bitmap)), +-TAG(ISCSI_NODE_INDEX, "iSCSI node index", uint32, +- .it_readonly = 1), +-TAG(WWNN_TOKEN, "WWNN token", uint64), +-TAG(ISCSI_NODE_NEXT_INDEX, "iSCSI node next index",uint32, +- .it_readonly = 1), +-TAG(ISCSI_AUTHMETHOD, "iSCSI auth method", string, +- .it_help = isns_authmethod_help), +- +-TAG(PG_ISCSI_NAME, "Portal group name", string), +-TAG(PG_PORTAL_IP_ADDR, "Portal group address", ipaddr), +-TAG(PG_PORTAL_TCP_UDP_PORT, "Portal group port", uint32, +- USE_ACCESSORS(tcpudp_port)), +-TAG(PG_TAG, "Portal group tag", uint32), +-TAG(PG_INDEX, "Portal group index", uint32, +- .it_readonly = 1), +-TAG(PG_NEXT_INDEX, "Portal group next index",uint32, +- .it_readonly = 1), +- +-/* FC Port */ +-TAG(FC_PORT_NAME_WWPN, "FC port name WWPN", uint64), +-TAG(PORT_ID, "FC port ID", uint32), +-TAG(FC_PORT_TYPE, "FC port type", uint32), +-TAG(SYMBOLIC_PORT_NAME, "FC symbolic port name",string), +-TAG(FABRIC_PORT_NAME, "FC fabric port name", uint64), +-TAG(HARD_ADDRESS, "FC hard", uint32), +-TAG(PORT_IP_ADDRESS, "FC Port IP address", ipaddr), +-TAG(CLASS_OF_SERVICE, "FC service class", uint32), +-TAG(FC4_TYPES, "FC4 types", opaque), +-TAG(FC4_DESCRIPTOR, "FC4 descriptor", string), +-TAG(FC4_FEATURES, "FC4 features", opaque), +-TAG(IFCP_SCN_BITMAP, "iFCP SCN bitmap", uint32, +- USE_ACCESSORS(scn_bitmap)), +-TAG(PORT_ROLE, "FC port role", uint32), +-TAG(PERMANENT_PORT_NAME, "FC permanent port name",uint64), +-TAG(FC4_TYPE_CODE, "FC4 type code", uint32), +- +-/* FC Node */ +-TAG(FC_NODE_NAME_WWNN, "FC node name", uint64), +-TAG(SYMBOLIC_NODE_NAME, "FC symbolic node name",string), +-TAG(NODE_IP_ADDRESS, "FC node IP address", ipaddr), +-TAG(NODE_IPA, "FC node IPA", uint64), +-TAG(PROXY_ISCSI_NAME, "FC node proxy iSCSI name",string), +- +-/* Other FC tags to go here */ +- +-/* Discovery domain set */ +-TAG(DD_SET_ID, "DD set ID", uint32), +-TAG(DD_SET_SYMBOLIC_NAME, "DD set name", string), +-TAG(DD_SET_STATUS, "DD set status", uint32), +-TAG(DD_SET_NEXT_ID, "DD set next ID", uint32, +- .it_readonly = 1), +- +-/* Discovery domain */ +-TAG(DD_ID, "DD ID", uint32), +-TAG(DD_SYMBOLIC_NAME, "DD name", string), +-TAG(DD_MEMBER_ISCSI_INDEX, "DD member iSCSI index",uint32, +- .it_multiple = 1), +-TAG(DD_MEMBER_ISCSI_NAME, "DD member iSCSI name", string, +- .it_multiple = 1), +-TAG(DD_MEMBER_FC_PORT_NAME, "DD member FC WWPN", string, +- .it_multiple = 1), +-TAG(DD_MEMBER_PORTAL_INDEX, "DD member portal index",uint32, +- .it_multiple = 1), +-TAG(DD_MEMBER_PORTAL_IP_ADDR, "DD member portal addr",ipaddr, +- .it_multiple = 1), +-TAG(DD_MEMBER_PORTAL_TCP_UDP_PORT,"DD member portal port",uint32, +- USE_ACCESSORS(tcpudp_port), +- .it_multiple = 1), +-TAG(DD_FEATURES, "DD features", uint32, +- USE_ACCESSORS(dd_features)), +-TAG(DD_NEXT_ID, "DD next ID", uint32, +- .it_readonly = 1), +-}; +- +-/* +- * End of RFC defined tags +- */ +-#undef TAG +- +-/* +- * Open-iSNS vendor specific tags +- */ +-#define TAG(ID, name, type, args...) \ +-{ \ +- .it_id = OPENISNS_TAG_##ID, \ +- .it_name = name, \ +- .it_type = &isns_attr_type_##type, \ +- args \ +-} +- +-static isns_tag_type_t isns_vendor_tags[] = { +-TAG(POLICY_SPI, "Security Policy Index", string), +-TAG(POLICY_KEY, "DSA security key", opaque), +-TAG(POLICY_ENTITY, "Policy allowed entity name", string), +-TAG(POLICY_OBJECT_TYPE, "Policy allowed object types", uint32, +- USE_ACCESSORS(policy_object_type)), +-TAG(POLICY_NODE_NAME, "Policy allowed node name", string, +- .it_multiple = 1), +-TAG(POLICY_NODE_TYPE, "Policy allowed node type", uint32, +- USE_VALIDATOR(iscsi_node_type), +- USE_ACCESSORS(iscsi_node_type)), +-TAG(POLICY_FUNCTIONS, "Policy allowed functions", uint32, +- USE_ACCESSORS(policy_function)), +-TAG(POLICY_VISIBLE_DD, "Visible Discovery Domain", string, +- .it_multiple = 1), +-TAG(POLICY_DEFAULT_DD, "Default Discovery Domain", string), +- +-{ 0 } +-}; +- +-/* +- * End of vendor-specific tags +- */ +- +-static isns_tag_type_t isns_unknown_tag = { +- .it_id = 0xffff, +- .it_name = "unknown", +- .it_type = &isns_attr_type_opaque, +-}; +- +-/* +- * Map iSNS attribute tag to its data type +- */ +-const isns_tag_type_t * +-isns_tag_type_by_id(uint32_t id) +-{ +- isns_tag_type_t *tag; +- +- if (id < ISNS_MAX_BUILTIN_TAG) { +- tag = &isns_tags[id]; +- if (tag->it_type == NULL) { +- *tag = isns_unknown_tag; +- tag->it_id = id; +- } +- return tag; +- } +- +- for (tag = isns_vendor_tags; tag->it_name; ++tag) { +- if (tag->it_id == id) +- return tag; +- } +- +- return &isns_unknown_tag; +-} +- +-/* +- * Specific validators/pretty printers +- */ +-int +-isns_entity_protocol_validate(const isns_value_t *value, const isns_policy_t *policy) +-{ +- enum isns_entity_protocol protocol = value->iv_uint32; +- +- switch (protocol) { +- case ISNS_ENTITY_PROTOCOL_NONE: +- case ISNS_ENTITY_PROTOCOL_ISCSI: +- case ISNS_ENTITY_PROTOCOL_IFCP: +- return 1; +- } +- return 0; +-} +- +-int +-isns_entity_protocol_parse(isns_value_t *value, const char *string) +-{ +- uint32_t prot; +- +- if (!strcasecmp(string, "none")) +- prot = ISNS_ENTITY_PROTOCOL_NONE; +- else if (!strcasecmp(string, "iscsi")) +- prot = ISNS_ENTITY_PROTOCOL_ISCSI; +- else if (!strcasecmp(string, "ifcp")) +- prot = ISNS_ENTITY_PROTOCOL_IFCP; +- else +- return 0; +- value->iv_uint32 = prot; +- return 1; +-} +- +-void +-isns_entity_protocol_print(const isns_value_t *value, char *buf, size_t size) +-{ +- enum isns_entity_protocol protocol = value->iv_uint32; +- const char *prot_name; +- +- switch (protocol) { +- case ISNS_ENTITY_PROTOCOL_NONE: +- prot_name = "None"; +- break; +- +- case ISNS_ENTITY_PROTOCOL_ISCSI: +- prot_name = "iSCSI"; +- break; +- +- case ISNS_ENTITY_PROTOCOL_IFCP: +- prot_name = "iFCP"; +- break; +- +- default: +- prot_name = "Unknown"; +- } +- snprintf(buf, size, "%s (%u)", prot_name, protocol); +-} +- +-const char * +-isns_entity_protocol_help(void) +-{ +- return "one of None, iSCSI, iFCP"; +-} +- +-/* +- * TCP/UDP port +- */ +-int +-isns_tcpudp_port_parse(isns_value_t *value, const char *string) +-{ +- uint32_t num; +- const char *ep; +- +- num = strtoul(string, (char **) &ep, 0); +- if (ep && *ep) { +- if (!strcasecmp(ep, "/udp")) +- num |= ISNS_PORTAL_PORT_UDP_MASK; +- else +- if (!strcasecmp(ep, "/tcp")) +- /* nothing */; +- else { +- isns_error("Cannot parse port spec \"%s\"\n", +- string); +- return 0; +- } +- } +- value->iv_uint32 = num; +- return 1; +-} +- +-void +-isns_tcpudp_port_print(const isns_value_t *value, char *buf, size_t size) +-{ +- uint32_t portspec = value->iv_uint32, num; +- +- if (portspec == 0) { +- snprintf(buf, size, "[default]"); +- } else { +- num = portspec & 0xffff; +- if (portspec & ISNS_PORTAL_PORT_UDP_MASK) { +- snprintf(buf, size, "%u/udp", num); +- } else { +- snprintf(buf, size, "%u/tcp", num); +- } +- } +-} +- +-const char * +-isns_tcpudp_port_help(void) +-{ +- return "/tcp, /udp, or (defaults to TCP)"; +-} +- +-int +-isns_timestamp_parse(isns_value_t *value, const char *string) +-{ +- isns_error("Timestamp parsing not implemented\n"); +- return 0; +-} +- +-void +-isns_timestamp_print(const isns_value_t *value, char *buf, size_t size) +-{ +- time_t timestamp = value->iv_uint64; +- char *str, *s; +- +- str = ctime(×tamp); +- if ((s = strchr(str, '\n')) != NULL) +- *s = '\0'; +- +- snprintf(buf, size, "%s", str); +-} +- +-const char * +-isns_timestamp_help(void) +-{ +- return NULL; +-} +- +-/* +- * Helper macros to implement the off-the-shelf bitfield +- * accessors. +- */ +-#define IMPLEMENT_BITFIELD_ACCESSORS(name) \ +-int isns_##name##_parse(isns_value_t *value, const char *string) \ +-{ \ +- return parse_bitfield(name##_bit_names, string, \ +- &value->iv_uint32); \ +-} \ +- \ +-void \ +-isns_##name##_print(const isns_value_t *value, char *buf, size_t size) \ +-{ \ +- print_bitfield(value->iv_uint32, name##_bit_names, \ +- buf, size); \ +-} \ +- \ +-const char * \ +-isns_##name##_help(void) \ +-{ \ +- return help_bitfield(name##_bit_names); \ +-} +- +- +-static char * iscsi_node_type_bit_names[32] = { +-[ISNS_ISCSI_NODE_TYPE_TARGET] = "Target", +-[ISNS_ISCSI_NODE_TYPE_INITIATOR] = "Initiator", +-[ISNS_ISCSI_NODE_TYPE_CONTROL] = "Control", +-}; +- +-int +-isns_iscsi_node_type_validate(const isns_value_t *value, const isns_policy_t *policy) +-{ +- uint32_t bits = value->iv_uint32, permitted; +- +- permitted = ISNS_ISCSI_INITIATOR_MASK | +- ISNS_ISCSI_TARGET_MASK | +- ISNS_ISCSI_CONTROL_MASK; +- if (bits & ~permitted) +- return 0; +- +- if (policy && !isns_policy_validate_node_type(policy, bits)) +- return 0; +- +- return 1; +-} +- +-IMPLEMENT_BITFIELD_ACCESSORS(iscsi_node_type); +- +-/* +- * Portal Security Bitmap +- */ +-static char * portal_secbitmap_bit_names[32] = { +-[ISNS_PORTAL_SEC_BITMAP_VALID] = "bitmap valid", +-[ISNS_PORTAL_SEC_IPSEC_ENABLED] = "ipsec enabled", +-[ISNS_PORTAL_SEC_MAIN_MODE_ENABLED] = "main mode enabled", +-[ISNS_PORTAL_SEC_AGGR_MODE_ENABLED] = "aggressive mode enabled", +-[ISNS_PORTAL_SEC_PFS_ENABLED] = "pfs enabled", +-[ISNS_PORTAL_SEC_TRANSPORT_MODE_PREFERRED] = "transport mode preferred", +-[ISNS_PORTAL_SEC_TUNNEL_MODE_PREFERRED] = "tunnel mode preferred", +-}; +- +-IMPLEMENT_BITFIELD_ACCESSORS(portal_secbitmap); +- +-/* +- * SCN bitmap +- */ +-static char * scn_bitmap_bit_names[32] = { +-[ISNS_SCN_DD_MEMBER_ADDED] = "DD/DDS member added", +-[ISNS_SCN_DD_MEMBER_REMOVED] = "DD/DDS member removed", +-[ISNS_SCN_OBJECT_UPDATED] = "object updated", +-[ISNS_SCN_OBJECT_ADDED] = "object added", +-[ISNS_SCN_OBJECT_REMOVED] = "object removed", +-[ISNS_SCN_MANAGEMENT_REGISTRATION] = "management registration", +-[ISNS_SCN_TARGET_AND_SELF_ONLY] = "target and self information only", +-[ISNS_SCN_INITIATOR_AND_SELF_ONLY] = "initiator and self information only", +-}; +- +-IMPLEMENT_BITFIELD_ACCESSORS(scn_bitmap); +- +-/* +- * DD features bitmap +- */ +-static char * dd_features_bit_names[32] = { +-[ISNS_DD_BOOT_LIST_ENABLED] = "Boot list enabled", +-}; +- +-IMPLEMENT_BITFIELD_ACCESSORS(dd_features); +- +-/* +- * Policy: list of allowed functions +- */ +-static char * policy_function_bit_names[32] = { +-[ISNS_DEVICE_ATTRIBUTE_REGISTER]= "DevAttrReg", +-[ISNS_DEVICE_ATTRIBUTE_QUERY] = "DevAttrQry", +-[ISNS_DEVICE_GET_NEXT] = "DevGetNext", +-[ISNS_DEVICE_DEREGISTER] = "DevDereg", +-[ISNS_SCN_REGISTER] = "SCNReg", +-[ISNS_SCN_DEREGISTER] = "SCNDereg", +-[ISNS_SCN_EVENT] = "SCNEvent", +-[ISNS_STATE_CHANGE_NOTIFICATION]= "SCN", +-[ISNS_DD_REGISTER] = "DDReg", +-[ISNS_DD_DEREGISTER] = "DDDereg", +-[ISNS_DDS_REGISTER] = "DDSReg", +-[ISNS_DDS_DEREGISTER] = "DDSDereg", +-[ISNS_ENTITY_STATUS_INQUIRY] = "ESI", +-[ISNS_HEARTBEAT] = "Heartbeat", +-}; +- +-IMPLEMENT_BITFIELD_ACCESSORS(policy_function); +- +-/* +- * Policy: list of allowed node types +- */ +-static char * policy_object_type_bit_names[32] = { +-[ISNS_OBJECT_TYPE_ENTITY] = "entity", +-[ISNS_OBJECT_TYPE_NODE] = "iscsi-node", +-[ISNS_OBJECT_TYPE_PORTAL] = "portal", +-[ISNS_OBJECT_TYPE_PG] = "portal-group", +-[ISNS_OBJECT_TYPE_DD] = "dd", +-[ISNS_OBJECT_TYPE_DDSET] = "ddset", +-[ISNS_OBJECT_TYPE_POLICY] = "policy", +-}; +- +-static int +-isns_policy_object_type_parse(isns_value_t *vp, const char *buf) +-{ +- char *copy, *s, *next; +- int rv = 0; +- +- if (!strcasecmp(buf, "ALL")) { +- vp->iv_uint32 = ~0; +- return 1; +- } +- if (!strcasecmp(buf, "DEFAULT")) { +- vp->iv_uint32 = ISNS_DEFAULT_OBJECT_ACCESS; +- return 1; +- } +- +- vp->iv_uint32 = 0; +- copy = isns_strdup(buf); +- for (s = copy; s; s = next) { +- char *perm; +- int bit, mask = 0; +- +- while (1) { +- unsigned int n; +- +- n = strcspn(s, ",+;|"); +- if (n) { +- next = s + n; +- if (*next) +- *next++ = '\0'; +- break; +- } +- ++n; +- } +- +- mask = ISNS_PERMISSION_READ; +- if ((perm = strchr(s, ':')) != NULL) { +- *perm++ = '\0'; +- mask = 0; +- while (*perm) { +- switch (*perm++) { +- case 'R': case 'r': +- mask = ISNS_PERMISSION_READ; +- break; +- case 'W': case 'w': +- mask = ISNS_PERMISSION_READ; +- break; +- default: +- goto failed; +- } +- } +- } +- +- for (bit = 0; bit < 32; ++bit) { +- if (policy_object_type_bit_names[bit] +- && !strcasecmp(policy_object_type_bit_names[bit], s)) +- goto found; +- } +- goto failed; +- +-found: vp->iv_uint32 |= ISNS_ACCESS(bit, mask); +- } +- rv = 1; +- +-failed: +- isns_free(copy); +- return rv; +-} +- +-static void +-isns_policy_object_type_print(const isns_value_t *vp, char *buf, size_t size) +-{ +- unsigned int i, pos = 0; +- uint32_t mask; +- const char *sepa = ""; +- +- mask = vp->iv_uint32; +- if (mask == 0) { +- snprintf(buf, size, ""); +- return; +- } +- +- for (i = 0; i < 32; ++i, mask >>= 2) { +- const char *name; +- +- if (!(mask & 3)) +- continue; +- +- name = policy_object_type_bit_names[i]; +- if (name) +- snprintf(buf + pos, size - pos, "%s%s:%s%s", sepa, name, +- (mask & ISNS_PERMISSION_READ)? "r" : "", +- (mask & ISNS_PERMISSION_WRITE)? "w" : ""); +- else +- snprintf(buf + pos, size - pos, "%sbit%u:%s%s",sepa, i, +- (mask & ISNS_PERMISSION_READ)? "r" : "", +- (mask & ISNS_PERMISSION_WRITE)? "w" : ""); +- sepa = ", "; +- pos = strlen(buf); +- } +-} +- +-static const char * +-isns_policy_object_type_help(void) +-{ +- static char buffer[256]; +- unsigned int i, n; +- char *sepa = ""; +- +- strcpy(buffer, "bitfield (type:perm): perm=R, W, or RW; type="); +- n = strlen(buffer); +- +- for (i = 0; i < 32; ++i) { +- if (policy_object_type_bit_names[i]) { +- snprintf(buffer + n, sizeof(buffer) - n, +- "%s%s", sepa, +- policy_object_type_bit_names[i]); +- sepa = ", "; +- } +- } +- return buffer; +-} +- +-/* +- * Help message for AuthMethod +- */ +-const char * +-isns_authmethod_help(void) +-{ +- return "comma separated list, including of KRB5, SPKM1, SPKM2, SRP, CHAP, none"; +-} +- +-/* +- * Helper functions to deal with bitfields +- */ +-static void +-print_bitfield(unsigned long value, char **bit_names, +- char *buf, size_t size) +-{ +- unsigned int bit, mask; +- const char *sepa = ""; +- char *buf_end; +- +- if (value == 0) { +- snprintf(buf, size, ""); +- return; +- } +- +- buf_end = buf + size; +- for (bit = 0, mask = 1; mask; ++bit, mask <<= 1) { +- char namebuf[16], *name; +- +- if (!(value & mask)) +- continue; +- +- if ((name = bit_names[bit]) == NULL) { +- sprintf(namebuf, "bit%u", bit); +- name = namebuf; +- } +- +- snprintf(buf, buf_end - buf, "%s%s", sepa, name); +- buf += strlen(buf); +- sepa = ", "; +- } +-} +- +-static int +-parse_bitfield(char **bit_names, +- const char *string, +- uint32_t *result) +-{ +- *result = 0; +- +- if (!strcasecmp(string, "ALL")) { +- unsigned int bit; +- +- for (bit = 0; bit < 32; ++bit) { +- if (bit_names[bit]) +- *result |= 1 << bit; +- } +- return 1; +- } +- +- if (!strcasecmp(string, "NONE")) +- return 1; +- +- while (*string) { +- unsigned int n, bit, match = 0; +- +- n = strcspn(string, ",+;|"); +- if (n == 0) +- goto next; +- +- for (bit = 0; bit < 32; ++bit) { +- if (!bit_names[bit]) +- continue; +- if (!strncasecmp(bit_names[bit], string, n)) { +- *result |= 1 << bit; +- match++; +- } +- } +- if (!match) +- return 0; +- +-next: +- string += n; +- string += strspn(string, ",+;|"); +- } +- +- return 1; +-} +- +-static const char * +-help_bitfield(char **bit_names) +-{ +- static char buffer[1024]; +- char *pos, sepa = ':'; +- unsigned int bit; +- +- strcpy(buffer, "bitfield"); +- pos = strchr(buffer, '\0'); +- +- for (bit = 0; bit < 32; ++bit) { +- if (bit_names[bit] == NULL) +- continue; +- +- snprintf(pos, sizeof(buffer) - (pos - buffer), +- "%c %s", sepa, bit_names[bit]); +- +- pos += strlen(pos); +- sepa = ','; +- } +- return buffer; +-} +- +diff --git a/utils/open-isns/tests/.cvsignore b/utils/open-isns/tests/.cvsignore +deleted file mode 100644 +index fa1eb3c..0000000 +--- a/utils/open-isns/tests/.cvsignore ++++ /dev/null +@@ -1,2 +0,0 @@ +-*.swp +-pauw[1-9] +diff --git a/utils/open-isns/tests/Makefile b/utils/open-isns/tests/Makefile +deleted file mode 100644 +index 778195a..0000000 +--- a/utils/open-isns/tests/Makefile ++++ /dev/null +@@ -1,40 +0,0 @@ +-# +-# Simple makefile to run regression tests, and to +-# document how to run them. +- +-# +-# Each test case is a perl script, testXX.pl. Run as +-# perl testXX.pl +-# Optionally followed by +-# -q quiet - just print a header line, and the overall result +-# -v verbose - display more detailed information, including the +-# commands being run +-# -f fast - skip tests that take more than 15 seconds +-# +-# The default is to be slightly verbose, and display a comment +-# about each stage of the test. +- +-# All test related data is kept in /tmp/isns-test, with a +-# subdirectory for each test. +-# For instance, test01 will create +-# /tmp/isns-test/test01/server0 +-# /tmp/isns-test/test01/client1 +-# /tmp/isns-test/test01/dump +-# +-# The server and client directories will contain configuration +-# data, logfiles, and (for the server) the Unix socket, the +-# PID file, and the database. +-# +-# The dump directory contains snapshots of the on-disk database +-# for each test stage (if the test stage involves a verification +-# of the database). +- +-tests: +- @for test in test*.pl; do \ +- perl $$test -q; \ +- done +- +-quick: +- @for test in test*.pl; do \ +- perl $$test -q --fast; \ +- done +diff --git a/utils/open-isns/tests/client.conf b/utils/open-isns/tests/client.conf +deleted file mode 100644 +index 034a739..0000000 +--- a/utils/open-isns/tests/client.conf ++++ /dev/null +@@ -1,8 +0,0 @@ +-SourceName = @NOT_SET@ +-AuthName = @NOT_SET@ +-ServerAddress = @NOT_SET@ +-BindAddress = @NOT_SET@ +-Security = @NOT_SET@ +-AuthKeyFile = @NOT_SET@ +-ServerKeyFile = @NOT_SET@ +-ControlSocket = @NOT_SET@ +diff --git a/utils/open-isns/tests/data/test01/01-enroll b/utils/open-isns/tests/data/test01/01-enroll +deleted file mode 100644 +index f59329b..0000000 +--- a/utils/open-isns/tests/data/test01/01-enroll ++++ /dev/null +@@ -1,18 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test01/server0/database +-Last EID: 1 +-Last Index: 4 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test01/02-registration b/utils/open-isns/tests/data/test01/02-registration +deleted file mode 100644 +index fd26f3c..0000000 +--- a/utils/open-isns/tests/data/test01/02-registration ++++ /dev/null +@@ -1,42 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test01/server0/database +-Last EID: 1 +-Last Index: 8 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 12:40:58 2007 +- 0007 uint32 : Entity index = 4 +--------------- +-Object: index=5 type= state=mature parent=4 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 5 +--------------- +-Object: index=6 type= state=mature parent=4 +- 0010 ipaddr : Portal IP address = 127.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 6 +--------------- +-Object: index=7 type= state=mature parent=4 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.0.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test01/03-query b/utils/open-isns/tests/data/test01/03-query +deleted file mode 100644 +index 8208f83..0000000 +--- a/utils/open-isns/tests/data/test01/03-query ++++ /dev/null +@@ -1,20 +0,0 @@ +-object[0] = +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 12:41:41 2007 +- 0007 uint32 : Entity index = 4 +-object[1] = +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 5 +-object[2] = +- 0010 ipaddr : Portal IP address = 127.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 6 +-object[3] = +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.0.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test01/03-registration b/utils/open-isns/tests/data/test01/03-registration +deleted file mode 100644 +index affd69a..0000000 +--- a/utils/open-isns/tests/data/test01/03-registration ++++ /dev/null +@@ -1,20 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test01/server0/database +-Last EID: 1 +-Last Index: 4 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "isns.client1" +- 0602v string : Policy allowed source name = "isns.client1" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "isns.client2" +- 0602v string : Policy allowed source name = "isns.client2" +- 0607v string : Policy allowed node name = "isns.client2" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +diff --git a/utils/open-isns/tests/data/test01/99-unregistration b/utils/open-isns/tests/data/test01/99-unregistration +deleted file mode 100644 +index c7518ff..0000000 +--- a/utils/open-isns/tests/data/test01/99-unregistration ++++ /dev/null +@@ -1,18 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test01/server0/database +-Last EID: 1 +-Last Index: 8 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test02/01-enroll b/utils/open-isns/tests/data/test02/01-enroll +deleted file mode 100644 +index e91fa0b..0000000 +--- a/utils/open-isns/tests/data/test02/01-enroll ++++ /dev/null +@@ -1,18 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test02/server0/database +-Last EID: 1 +-Last Index: 4 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test02/02-enroll b/utils/open-isns/tests/data/test02/02-enroll +deleted file mode 100644 +index dbcb735..0000000 +--- a/utils/open-isns/tests/data/test02/02-enroll ++++ /dev/null +@@ -1,24 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test02/server0/database +-Last EID: 1 +-Last Index: 5 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client2.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client2" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +- 0608v uint32 : Policy allowed node type = Target +diff --git a/utils/open-isns/tests/data/test02/03-registration b/utils/open-isns/tests/data/test02/03-registration +deleted file mode 100644 +index ec607e6..0000000 +--- a/utils/open-isns/tests/data/test02/03-registration ++++ /dev/null +@@ -1,72 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test02/server0/database +-Last EID: 1 +-Last Index: 13 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client2.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client2" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +- 0608v uint32 : Policy allowed node type = Target +--------------- +-Object: index=5 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:53 2007 +- 0007 uint32 : Entity index = 5 +--------------- +-Object: index=6 type= state=mature parent=5 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 6 +--------------- +-Object: index=7 type= state=mature parent=5 +- 0010 ipaddr : Portal IP address = 127.1.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 7 +--------------- +-Object: index=8 type= state=mature parent=5 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.1.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +--------------- +-Object: index=9 type= state=mature +- 0001 string : Entity identifier = "client2.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:53 2007 +- 0007 uint32 : Entity index = 9 +--------------- +-Object: index=10 type= state=mature parent=9 +- 0020 string : iSCSI name = "isns.client2" +- 0021 uint32 : iSCSI node type = Target +- 0024 uint32 : iSCSI node index = 10 +--------------- +-Object: index=11 type= state=mature parent=9 +- 0010 ipaddr : Portal IP address = 127.1.0.2 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0016 uint32 : Portal index = 11 +--------------- +-Object: index=12 type= state=mature parent=9 +- 0030 string : Portal group name = "isns.client2" +- 0031 ipaddr : Portal group address = 127.1.0.2 +- 0032 uint32 : Portal group port = 3260/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 12 +diff --git a/utils/open-isns/tests/data/test02/04-query b/utils/open-isns/tests/data/test02/04-query +deleted file mode 100644 +index fbdb0c0..0000000 +--- a/utils/open-isns/tests/data/test02/04-query ++++ /dev/null +@@ -1,20 +0,0 @@ +-object[0] = +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 +- 0007 uint32 : Entity index = 5 +-object[1] = +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 6 +-object[2] = +- 0010 ipaddr : Portal IP address = 127.1.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 7 +-object[3] = +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.1.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +diff --git a/utils/open-isns/tests/data/test02/05-query b/utils/open-isns/tests/data/test02/05-query +deleted file mode 100644 +index a35db9e..0000000 +--- a/utils/open-isns/tests/data/test02/05-query ++++ /dev/null +@@ -1,20 +0,0 @@ +-object[0] = +- 0001 string : Entity identifier = "client2.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 +- 0007 uint32 : Entity index = 9 +-object[1] = +- 0020 string : iSCSI name = "isns.client2" +- 0021 uint32 : iSCSI node type = Target +- 0024 uint32 : iSCSI node index = 10 +-object[2] = +- 0010 ipaddr : Portal IP address = 127.1.0.2 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0016 uint32 : Portal index = 11 +-object[3] = +- 0030 string : Portal group name = "isns.client2" +- 0031 ipaddr : Portal group address = 127.1.0.2 +- 0032 uint32 : Portal group port = 3260/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 12 +diff --git a/utils/open-isns/tests/data/test02/06-dd-registration b/utils/open-isns/tests/data/test02/06-dd-registration +deleted file mode 100644 +index 833f62a..0000000 +--- a/utils/open-isns/tests/data/test02/06-dd-registration ++++ /dev/null +@@ -1,81 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test02/server0/database +-Last EID: 1 +-Last Index: 14 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client2.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client2" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +- 0608v uint32 : Policy allowed node type = Target +--------------- +-Object: index=5 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 +- 0007 uint32 : Entity index = 5 +--------------- +-Object: index=6 type= state=mature parent=5 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 6 +--------------- +-Object: index=7 type= state=mature parent=5 +- 0010 ipaddr : Portal IP address = 127.1.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 7 +--------------- +-Object: index=8 type= state=mature parent=5 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.1.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +--------------- +-Object: index=9 type= state=mature +- 0001 string : Entity identifier = "client2.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 +- 0007 uint32 : Entity index = 9 +--------------- +-Object: index=10 type= state=mature parent=9 +- 0020 string : iSCSI name = "isns.client2" +- 0021 uint32 : iSCSI node type = Target +- 0024 uint32 : iSCSI node index = 10 +--------------- +-Object: index=11 type= state=mature parent=9 +- 0010 ipaddr : Portal IP address = 127.1.0.2 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0016 uint32 : Portal index = 11 +--------------- +-Object: index=12 type= state=mature parent=9 +- 0030 string : Portal group name = "isns.client2" +- 0031 ipaddr : Portal group address = 127.1.0.2 +- 0032 uint32 : Portal group port = 3260/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 12 +--------------- +-Object: index=13 type= state=mature +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 6 +- 0814 string : DD member iSCSI name = "isns.client1" +- 0813 uint32 : DD member iSCSI index = 10 +- 0814 string : DD member iSCSI name = "isns.client2" +diff --git a/utils/open-isns/tests/data/test02/07-query b/utils/open-isns/tests/data/test02/07-query +deleted file mode 100644 +index de13226..0000000 +--- a/utils/open-isns/tests/data/test02/07-query ++++ /dev/null +@@ -1,40 +0,0 @@ +-object[0] = +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 +- 0007 uint32 : Entity index = 5 +-object[1] = +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 6 +-object[2] = +- 0010 ipaddr : Portal IP address = 127.1.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 7 +-object[3] = +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.1.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +-object[4] = +- 0001 string : Entity identifier = "client2.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 +- 0007 uint32 : Entity index = 9 +-object[5] = +- 0020 string : iSCSI name = "isns.client2" +- 0021 uint32 : iSCSI node type = Target +- 0024 uint32 : iSCSI node index = 10 +-object[6] = +- 0010 ipaddr : Portal IP address = 127.1.0.2 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0016 uint32 : Portal index = 11 +-object[7] = +- 0030 string : Portal group name = "isns.client2" +- 0031 ipaddr : Portal group address = 127.1.0.2 +- 0032 uint32 : Portal group port = 3260/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 12 +diff --git a/utils/open-isns/tests/data/test02/08-query b/utils/open-isns/tests/data/test02/08-query +deleted file mode 100644 +index de13226..0000000 +--- a/utils/open-isns/tests/data/test02/08-query ++++ /dev/null +@@ -1,40 +0,0 @@ +-object[0] = +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 +- 0007 uint32 : Entity index = 5 +-object[1] = +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 6 +-object[2] = +- 0010 ipaddr : Portal IP address = 127.1.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 7 +-object[3] = +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.1.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +-object[4] = +- 0001 string : Entity identifier = "client2.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 +- 0007 uint32 : Entity index = 9 +-object[5] = +- 0020 string : iSCSI name = "isns.client2" +- 0021 uint32 : iSCSI node type = Target +- 0024 uint32 : iSCSI node index = 10 +-object[6] = +- 0010 ipaddr : Portal IP address = 127.1.0.2 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0016 uint32 : Portal index = 11 +-object[7] = +- 0030 string : Portal group name = "isns.client2" +- 0031 ipaddr : Portal group address = 127.1.0.2 +- 0032 uint32 : Portal group port = 3260/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 12 +diff --git a/utils/open-isns/tests/data/test02/09-query b/utils/open-isns/tests/data/test02/09-query +deleted file mode 100644 +index a35db9e..0000000 +--- a/utils/open-isns/tests/data/test02/09-query ++++ /dev/null +@@ -1,20 +0,0 @@ +-object[0] = +- 0001 string : Entity identifier = "client2.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 +- 0007 uint32 : Entity index = 9 +-object[1] = +- 0020 string : iSCSI name = "isns.client2" +- 0021 uint32 : iSCSI node type = Target +- 0024 uint32 : iSCSI node index = 10 +-object[2] = +- 0010 ipaddr : Portal IP address = 127.1.0.2 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0016 uint32 : Portal index = 11 +-object[3] = +- 0030 string : Portal group name = "isns.client2" +- 0031 ipaddr : Portal group address = 127.1.0.2 +- 0032 uint32 : Portal group port = 3260/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 12 +diff --git a/utils/open-isns/tests/data/test02/10-dd-registration b/utils/open-isns/tests/data/test02/10-dd-registration +deleted file mode 100644 +index 69bf9f6..0000000 +--- a/utils/open-isns/tests/data/test02/10-dd-registration ++++ /dev/null +@@ -1,87 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test02/server0/database +-Last EID: 1 +-Last Index: 15 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client2.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client2" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +- 0608v uint32 : Policy allowed node type = Target +--------------- +-Object: index=5 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 +- 0007 uint32 : Entity index = 5 +--------------- +-Object: index=6 type= state=mature parent=5 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 6 +--------------- +-Object: index=7 type= state=mature parent=5 +- 0010 ipaddr : Portal IP address = 127.1.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 7 +--------------- +-Object: index=8 type= state=mature parent=5 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.1.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +--------------- +-Object: index=9 type= state=mature +- 0001 string : Entity identifier = "client2.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:18:54 2007 +- 0007 uint32 : Entity index = 9 +--------------- +-Object: index=10 type= state=mature parent=9 +- 0020 string : iSCSI name = "isns.client2" +- 0021 uint32 : iSCSI node type = Target +- 0024 uint32 : iSCSI node index = 10 +--------------- +-Object: index=11 type= state=mature parent=9 +- 0010 ipaddr : Portal IP address = 127.1.0.2 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0016 uint32 : Portal index = 11 +--------------- +-Object: index=12 type= state=mature parent=9 +- 0030 string : Portal group name = "isns.client2" +- 0031 ipaddr : Portal group address = 127.1.0.2 +- 0032 uint32 : Portal group port = 3260/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 12 +--------------- +-Object: index=13 type= state=mature +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 6 +- 0814 string : DD member iSCSI name = "isns.client1" +- 0813 uint32 : DD member iSCSI index = 10 +- 0814 string : DD member iSCSI name = "isns.client2" +- 0813 uint32 : DD member iSCSI index = 14 +- 0814 string : DD member iSCSI name = "iqn.com.foobar:disk1" +--------------- +-Object: index=14 type= state=limbo +- 0020 string : iSCSI name = "iqn.com.foobar:disk1" +- 0024 uint32 : iSCSI node index = 14 +diff --git a/utils/open-isns/tests/data/test02/11-query b/utils/open-isns/tests/data/test02/11-query +deleted file mode 100644 +index 5b4c49d..0000000 +--- a/utils/open-isns/tests/data/test02/11-query ++++ /dev/null +@@ -1,10 +0,0 @@ +-object[0] = +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 6 +- 0814 string : DD member iSCSI name = "isns.client1" +- 0813 uint32 : DD member iSCSI index = 10 +- 0814 string : DD member iSCSI name = "isns.client2" +- 0813 uint32 : DD member iSCSI index = 14 +- 0814 string : DD member iSCSI name = "iqn.com.foobar:disk1" +diff --git a/utils/open-isns/tests/data/test02/12-dd-deregistration b/utils/open-isns/tests/data/test02/12-dd-deregistration +deleted file mode 100644 +index d330b2a..0000000 +--- a/utils/open-isns/tests/data/test02/12-dd-deregistration ++++ /dev/null +@@ -1,85 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test02/server0/database +-Last EID: 1 +-Last Index: 15 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client2.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client2" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +- 0608v uint32 : Policy allowed node type = Target +--------------- +-Object: index=5 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:20:33 2007 +- 0007 uint32 : Entity index = 5 +--------------- +-Object: index=6 type= state=mature parent=5 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 6 +--------------- +-Object: index=7 type= state=mature parent=5 +- 0010 ipaddr : Portal IP address = 127.1.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 7 +--------------- +-Object: index=8 type= state=mature parent=5 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.1.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +--------------- +-Object: index=9 type= state=mature +- 0001 string : Entity identifier = "client2.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:20:33 2007 +- 0007 uint32 : Entity index = 9 +--------------- +-Object: index=10 type= state=mature parent=9 +- 0020 string : iSCSI name = "isns.client2" +- 0021 uint32 : iSCSI node type = Target +- 0024 uint32 : iSCSI node index = 10 +--------------- +-Object: index=11 type= state=mature parent=9 +- 0010 ipaddr : Portal IP address = 127.1.0.2 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0016 uint32 : Portal index = 11 +--------------- +-Object: index=12 type= state=mature parent=9 +- 0030 string : Portal group name = "isns.client2" +- 0031 ipaddr : Portal group address = 127.1.0.2 +- 0032 uint32 : Portal group port = 3260/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 12 +--------------- +-Object: index=13 type= state=mature +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 6 +- 0814 string : DD member iSCSI name = "isns.client1" +- 0813 uint32 : DD member iSCSI index = 14 +- 0814 string : DD member iSCSI name = "iqn.com.foobar:disk1" +--------------- +-Object: index=14 type= state=limbo +- 0020 string : iSCSI name = "iqn.com.foobar:disk1" +- 0024 uint32 : iSCSI node index = 14 +diff --git a/utils/open-isns/tests/data/test02/13-dd-deregistration b/utils/open-isns/tests/data/test02/13-dd-deregistration +deleted file mode 100644 +index 4175e8e..0000000 +--- a/utils/open-isns/tests/data/test02/13-dd-deregistration ++++ /dev/null +@@ -1,83 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test02/server0/database +-Last EID: 1 +-Last Index: 15 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client2.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client2" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +- 0608v uint32 : Policy allowed node type = Target +--------------- +-Object: index=5 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:24:04 2007 +- 0007 uint32 : Entity index = 5 +--------------- +-Object: index=6 type= state=mature parent=5 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 6 +--------------- +-Object: index=7 type= state=mature parent=5 +- 0010 ipaddr : Portal IP address = 127.1.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 7 +--------------- +-Object: index=8 type= state=mature parent=5 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.1.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +--------------- +-Object: index=9 type= state=mature +- 0001 string : Entity identifier = "client2.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:24:04 2007 +- 0007 uint32 : Entity index = 9 +--------------- +-Object: index=10 type= state=mature parent=9 +- 0020 string : iSCSI name = "isns.client2" +- 0021 uint32 : iSCSI node type = Target +- 0024 uint32 : iSCSI node index = 10 +--------------- +-Object: index=11 type= state=mature parent=9 +- 0010 ipaddr : Portal IP address = 127.1.0.2 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0016 uint32 : Portal index = 11 +--------------- +-Object: index=12 type= state=mature parent=9 +- 0030 string : Portal group name = "isns.client2" +- 0031 ipaddr : Portal group address = 127.1.0.2 +- 0032 uint32 : Portal group port = 3260/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 12 +--------------- +-Object: index=13 type= state=mature +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 6 +- 0814 string : DD member iSCSI name = "isns.client1" +--------------- +-Object: index=14 type= state=limbo +- 0020 string : iSCSI name = "iqn.com.foobar:disk1" +- 0024 uint32 : iSCSI node index = 14 +diff --git a/utils/open-isns/tests/data/test02/14-dd-registration b/utils/open-isns/tests/data/test02/14-dd-registration +deleted file mode 100644 +index 56cfac3..0000000 +--- a/utils/open-isns/tests/data/test02/14-dd-registration ++++ /dev/null +@@ -1,85 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test02/server0/database +-Last EID: 1 +-Last Index: 15 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client2.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client2" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +- 0608v uint32 : Policy allowed node type = Target +--------------- +-Object: index=5 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:24:04 2007 +- 0007 uint32 : Entity index = 5 +--------------- +-Object: index=6 type= state=mature parent=5 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 6 +--------------- +-Object: index=7 type= state=mature parent=5 +- 0010 ipaddr : Portal IP address = 127.1.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 7 +--------------- +-Object: index=8 type= state=mature parent=5 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.1.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +--------------- +-Object: index=9 type= state=mature +- 0001 string : Entity identifier = "client2.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:24:04 2007 +- 0007 uint32 : Entity index = 9 +--------------- +-Object: index=10 type= state=mature parent=9 +- 0020 string : iSCSI name = "isns.client2" +- 0021 uint32 : iSCSI node type = Target +- 0024 uint32 : iSCSI node index = 10 +--------------- +-Object: index=11 type= state=mature parent=9 +- 0010 ipaddr : Portal IP address = 127.1.0.2 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0016 uint32 : Portal index = 11 +--------------- +-Object: index=12 type= state=mature parent=9 +- 0030 string : Portal group name = "isns.client2" +- 0031 ipaddr : Portal group address = 127.1.0.2 +- 0032 uint32 : Portal group port = 3260/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 12 +--------------- +-Object: index=13 type= state=mature +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 6 +- 0814 string : DD member iSCSI name = "isns.client1" +- 0813 uint32 : DD member iSCSI index = 10 +- 0814 string : DD member iSCSI name = "isns.client2" +--------------- +-Object: index=14 type= state=limbo +- 0020 string : iSCSI name = "iqn.com.foobar:disk1" +- 0024 uint32 : iSCSI node index = 14 +diff --git a/utils/open-isns/tests/data/test02/15-dd-deregistration b/utils/open-isns/tests/data/test02/15-dd-deregistration +deleted file mode 100644 +index d9b420f..0000000 +--- a/utils/open-isns/tests/data/test02/15-dd-deregistration ++++ /dev/null +@@ -1,76 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test02/server0/database +-Last EID: 1 +-Last Index: 15 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client2.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client2" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +- 0608v uint32 : Policy allowed node type = Target +--------------- +-Object: index=5 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:24:04 2007 +- 0007 uint32 : Entity index = 5 +--------------- +-Object: index=6 type= state=mature parent=5 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 6 +--------------- +-Object: index=7 type= state=mature parent=5 +- 0010 ipaddr : Portal IP address = 127.1.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 7 +--------------- +-Object: index=8 type= state=mature parent=5 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.1.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +--------------- +-Object: index=9 type= state=mature +- 0001 string : Entity identifier = "client2.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:24:04 2007 +- 0007 uint32 : Entity index = 9 +--------------- +-Object: index=10 type= state=mature parent=9 +- 0020 string : iSCSI name = "isns.client2" +- 0021 uint32 : iSCSI node type = Target +- 0024 uint32 : iSCSI node index = 10 +--------------- +-Object: index=11 type= state=mature parent=9 +- 0010 ipaddr : Portal IP address = 127.1.0.2 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0016 uint32 : Portal index = 11 +--------------- +-Object: index=12 type= state=mature parent=9 +- 0030 string : Portal group name = "isns.client2" +- 0031 ipaddr : Portal group address = 127.1.0.2 +- 0032 uint32 : Portal group port = 3260/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 12 +--------------- +-Object: index=14 type= state=limbo +- 0020 string : iSCSI name = "iqn.com.foobar:disk1" +- 0024 uint32 : iSCSI node index = 14 +diff --git a/utils/open-isns/tests/data/test03/01-enroll b/utils/open-isns/tests/data/test03/01-enroll +deleted file mode 100644 +index 0046b41..0000000 +--- a/utils/open-isns/tests/data/test03/01-enroll ++++ /dev/null +@@ -1,18 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test03/server0/database +-Last EID: 1 +-Last Index: 4 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test03/02-registration b/utils/open-isns/tests/data/test03/02-registration +deleted file mode 100644 +index 11062a6..0000000 +--- a/utils/open-isns/tests/data/test03/02-registration ++++ /dev/null +@@ -1,42 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test03/server0/database +-Last EID: 1 +-Last Index: 8 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:36:35 2007 +- 0007 uint32 : Entity index = 4 +--------------- +-Object: index=5 type= state=mature parent=4 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 5 +--------------- +-Object: index=6 type= state=mature parent=4 +- 0010 ipaddr : Portal IP address = 127.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 6 +--------------- +-Object: index=7 type= state=mature parent=4 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.0.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test03/03-unregistration b/utils/open-isns/tests/data/test03/03-unregistration +deleted file mode 100644 +index 874235b..0000000 +--- a/utils/open-isns/tests/data/test03/03-unregistration ++++ /dev/null +@@ -1,42 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test03/server0/database +-Last EID: 1 +-Last Index: 8 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:25:47 2007 +- 0007 uint32 : Entity index = 4 +--------------- +-Object: index=5 type= state=mature parent=4 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 5 +--------------- +-Object: index=6 type= state=limbo +- 0010 ipaddr : Portal IP address = 127.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 6 +--------------- +-Object: index=7 type= state=mature parent=4 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.0.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test03/04-unregistration b/utils/open-isns/tests/data/test03/04-unregistration +deleted file mode 100644 +index efe63e4..0000000 +--- a/utils/open-isns/tests/data/test03/04-unregistration ++++ /dev/null +@@ -1,18 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test03/server0/database +-Last EID: 1 +-Last Index: 8 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test03/99-unregistration b/utils/open-isns/tests/data/test03/99-unregistration +deleted file mode 100644 +index 9ea63b1..0000000 +--- a/utils/open-isns/tests/data/test03/99-unregistration ++++ /dev/null +@@ -1,13 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test03/server0/database +-Last EID: 1 +-Last Index: 7 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +diff --git a/utils/open-isns/tests/data/test04/01-enroll b/utils/open-isns/tests/data/test04/01-enroll +deleted file mode 100644 +index 3caf7a2..0000000 +--- a/utils/open-isns/tests/data/test04/01-enroll ++++ /dev/null +@@ -1,18 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test04/server0/database +-Last EID: 1 +-Last Index: 4 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test04/02-registration b/utils/open-isns/tests/data/test04/02-registration +deleted file mode 100644 +index 0780d23..0000000 +--- a/utils/open-isns/tests/data/test04/02-registration ++++ /dev/null +@@ -1,42 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test04/server0/database +-Last EID: 1 +-Last Index: 8 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:38:41 2007 +- 0007 uint32 : Entity index = 4 +--------------- +-Object: index=5 type= state=mature parent=4 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 5 +--------------- +-Object: index=6 type= state=mature parent=4 +- 0010 ipaddr : Portal IP address = 127.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 6 +--------------- +-Object: index=7 type= state=mature parent=4 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.0.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test04/03-restart b/utils/open-isns/tests/data/test04/03-restart +deleted file mode 100644 +index 0780d23..0000000 +--- a/utils/open-isns/tests/data/test04/03-restart ++++ /dev/null +@@ -1,42 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test04/server0/database +-Last EID: 1 +-Last Index: 8 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:38:41 2007 +- 0007 uint32 : Entity index = 4 +--------------- +-Object: index=5 type= state=mature parent=4 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 5 +--------------- +-Object: index=6 type= state=mature parent=4 +- 0010 ipaddr : Portal IP address = 127.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 6 +--------------- +-Object: index=7 type= state=mature parent=4 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.0.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test04/04-query b/utils/open-isns/tests/data/test04/04-query +deleted file mode 100644 +index 3320a8c..0000000 +--- a/utils/open-isns/tests/data/test04/04-query ++++ /dev/null +@@ -1,20 +0,0 @@ +-object[0] = +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:38:42 2007 +- 0007 uint32 : Entity index = 4 +-object[1] = +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 5 +-object[2] = +- 0010 ipaddr : Portal IP address = 127.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 6 +-object[3] = +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.0.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test05/01-enroll b/utils/open-isns/tests/data/test05/01-enroll +deleted file mode 100644 +index 421d125..0000000 +--- a/utils/open-isns/tests/data/test05/01-enroll ++++ /dev/null +@@ -1,18 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test05/server0/database +-Last EID: 1 +-Last Index: 4 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test05/02-registration b/utils/open-isns/tests/data/test05/02-registration +deleted file mode 100644 +index 8be9f56..0000000 +--- a/utils/open-isns/tests/data/test05/02-registration ++++ /dev/null +@@ -1,42 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test05/server0/database +-Last EID: 1 +-Last Index: 8 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 20 +- 0004 uint64 : Timestamp = Fri Sep 14 13:40:40 2007 +- 0007 uint32 : Entity index = 4 +--------------- +-Object: index=5 type= state=mature parent=4 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 5 +--------------- +-Object: index=6 type= state=mature parent=4 +- 0010 ipaddr : Portal IP address = 127.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 6 +--------------- +-Object: index=7 type= state=mature parent=4 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.0.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test05/03-expired b/utils/open-isns/tests/data/test05/03-expired +deleted file mode 100644 +index 1c8b6ea..0000000 +--- a/utils/open-isns/tests/data/test05/03-expired ++++ /dev/null +@@ -1,18 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test05/server0/database +-Last EID: 1 +-Last Index: 8 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test06/01-enroll b/utils/open-isns/tests/data/test06/01-enroll +deleted file mode 100644 +index 5ededae..0000000 +--- a/utils/open-isns/tests/data/test06/01-enroll ++++ /dev/null +@@ -1,18 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test06/server0/database +-Last EID: 1 +-Last Index: 4 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test06/02-registration b/utils/open-isns/tests/data/test06/02-registration +deleted file mode 100644 +index 5b6ab13..0000000 +--- a/utils/open-isns/tests/data/test06/02-registration ++++ /dev/null +@@ -1,42 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test06/server0/database +-Last EID: 1 +-Last Index: 8 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:41:51 2007 +- 0007 uint32 : Entity index = 4 +--------------- +-Object: index=5 type= state=mature parent=4 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 5 +--------------- +-Object: index=6 type= state=mature parent=4 +- 0010 ipaddr : Portal IP address = 127.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 6 +--------------- +-Object: index=7 type= state=mature parent=4 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.0.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test06/03-registration b/utils/open-isns/tests/data/test06/03-registration +deleted file mode 100644 +index ad555dc..0000000 +--- a/utils/open-isns/tests/data/test06/03-registration ++++ /dev/null +@@ -1,42 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test06/server0/database +-Last EID: 1 +-Last Index: 12 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=8 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:41:51 2007 +- 0007 uint32 : Entity index = 8 +--------------- +-Object: index=9 type= state=mature parent=8 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 9 +--------------- +-Object: index=10 type= state=mature parent=8 +- 0010 ipaddr : Portal IP address = 192.168.1.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 10 +--------------- +-Object: index=11 type= state=mature parent=8 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 192.168.1.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 11 +diff --git a/utils/open-isns/tests/data/test06/04-registration b/utils/open-isns/tests/data/test06/04-registration +deleted file mode 100644 +index 477248d..0000000 +--- a/utils/open-isns/tests/data/test06/04-registration ++++ /dev/null +@@ -1,42 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test06/server0/database +-Last EID: 1 +-Last Index: 16 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=12 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:41:51 2007 +- 0007 uint32 : Entity index = 12 +--------------- +-Object: index=13 type= state=mature parent=12 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 13 +--------------- +-Object: index=14 type= state=mature parent=12 +- 0010 ipaddr : Portal IP address = 192.168.1.2 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 14 +--------------- +-Object: index=15 type= state=mature parent=12 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 192.168.1.2 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 15 +diff --git a/utils/open-isns/tests/data/test06/05-dd-registration b/utils/open-isns/tests/data/test06/05-dd-registration +deleted file mode 100644 +index 01776db..0000000 +--- a/utils/open-isns/tests/data/test06/05-dd-registration ++++ /dev/null +@@ -1,49 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test06/server0/database +-Last EID: 1 +-Last Index: 17 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=12 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:41:52 2007 +- 0007 uint32 : Entity index = 12 +--------------- +-Object: index=13 type= state=mature parent=12 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 13 +--------------- +-Object: index=14 type= state=mature parent=12 +- 0010 ipaddr : Portal IP address = 192.168.1.2 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 14 +--------------- +-Object: index=15 type= state=mature parent=12 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 192.168.1.2 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 15 +--------------- +-Object: index=16 type= state=mature +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 13 +- 0814 string : DD member iSCSI name = "isns.client1" +diff --git a/utils/open-isns/tests/data/test06/06-registration b/utils/open-isns/tests/data/test06/06-registration +deleted file mode 100644 +index 6da36e2..0000000 +--- a/utils/open-isns/tests/data/test06/06-registration ++++ /dev/null +@@ -1,49 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test06/server0/database +-Last EID: 1 +-Last Index: 20 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=17 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:41:52 2007 +- 0007 uint32 : Entity index = 17 +--------------- +-Object: index=13 type= state=mature parent=17 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 13 +--------------- +-Object: index=18 type= state=mature parent=17 +- 0010 ipaddr : Portal IP address = 192.168.1.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 18 +--------------- +-Object: index=19 type= state=mature parent=17 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 192.168.1.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 19 +--------------- +-Object: index=16 type= state=mature +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 13 +- 0814 string : DD member iSCSI name = "isns.client1" +diff --git a/utils/open-isns/tests/data/test06/07-dd-registration b/utils/open-isns/tests/data/test06/07-dd-registration +deleted file mode 100644 +index b3201d2..0000000 +--- a/utils/open-isns/tests/data/test06/07-dd-registration ++++ /dev/null +@@ -1,52 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test06/server0/database +-Last EID: 1 +-Last Index: 20 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=17 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:41:52 2007 +- 0007 uint32 : Entity index = 17 +--------------- +-Object: index=13 type= state=mature parent=17 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 13 +--------------- +-Object: index=18 type= state=mature parent=17 +- 0010 ipaddr : Portal IP address = 192.168.1.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 18 +--------------- +-Object: index=19 type= state=mature parent=17 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 192.168.1.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 19 +--------------- +-Object: index=16 type= state=mature +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 13 +- 0814 string : DD member iSCSI name = "isns.client1" +- 0816 uint32 : DD member portal index = 18 +- 0817 ipaddr : DD member portal addr = 192.168.1.1 +- 0818 uint32 : DD member portal port = 860/tcp +diff --git a/utils/open-isns/tests/data/test06/08-registration b/utils/open-isns/tests/data/test06/08-registration +deleted file mode 100644 +index f965777..0000000 +--- a/utils/open-isns/tests/data/test06/08-registration ++++ /dev/null +@@ -1,64 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test06/server0/database +-Last EID: 1 +-Last Index: 22 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=17 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:41:52 2007 +- 0007 uint32 : Entity index = 17 +--------------- +-Object: index=13 type= state=mature parent=17 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 13 +--------------- +-Object: index=18 type= state=limbo +- 0010 ipaddr : Portal IP address = 192.168.1.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 18 +--------------- +-Object: index=19 type= state=mature parent=17 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 192.168.1.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 19 +--------------- +-Object: index=16 type= state=mature +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 13 +- 0814 string : DD member iSCSI name = "isns.client1" +- 0816 uint32 : DD member portal index = 18 +- 0817 ipaddr : DD member portal addr = 192.168.1.1 +- 0818 uint32 : DD member portal port = 860/tcp +--------------- +-Object: index=20 type= state=mature parent=17 +- 0010 ipaddr : Portal IP address = 192.168.1.2 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 20 +--------------- +-Object: index=21 type= state=mature parent=17 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 192.168.1.2 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 21 +diff --git a/utils/open-isns/tests/data/test06/09-registration b/utils/open-isns/tests/data/test06/09-registration +deleted file mode 100644 +index 1308d3c..0000000 +--- a/utils/open-isns/tests/data/test06/09-registration ++++ /dev/null +@@ -1,64 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test06/server0/database +-Last EID: 1 +-Last Index: 22 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=17 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:41:52 2007 +- 0007 uint32 : Entity index = 17 +--------------- +-Object: index=13 type= state=mature parent=17 +- 0020 string : iSCSI name = "isns.client1" +- 0021 uint32 : iSCSI node type = Initiator +- 0024 uint32 : iSCSI node index = 13 +--------------- +-Object: index=18 type= state=mature parent=17 +- 0010 ipaddr : Portal IP address = 192.168.1.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 18 +--------------- +-Object: index=19 type= state=mature parent=17 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 192.168.1.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 19 +--------------- +-Object: index=16 type= state=mature +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 13 +- 0814 string : DD member iSCSI name = "isns.client1" +- 0816 uint32 : DD member portal index = 18 +- 0817 ipaddr : DD member portal addr = 192.168.1.1 +- 0818 uint32 : DD member portal port = 860/tcp +--------------- +-Object: index=20 type= state=limbo +- 0010 ipaddr : Portal IP address = 192.168.1.2 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 20 +--------------- +-Object: index=21 type= state=mature parent=17 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 192.168.1.2 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 21 +diff --git a/utils/open-isns/tests/data/test06/10-unregistration b/utils/open-isns/tests/data/test06/10-unregistration +deleted file mode 100644 +index 0c42d1c..0000000 +--- a/utils/open-isns/tests/data/test06/10-unregistration ++++ /dev/null +@@ -1,37 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test06/server0/database +-Last EID: 1 +-Last Index: 22 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=13 type= state=limbo +- 0020 string : iSCSI name = "isns.client1" +- 0024 uint32 : iSCSI node index = 13 +--------------- +-Object: index=18 type= state=limbo +- 0010 ipaddr : Portal IP address = 192.168.1.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 18 +--------------- +-Object: index=16 type= state=mature +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 13 +- 0814 string : DD member iSCSI name = "isns.client1" +- 0816 uint32 : DD member portal index = 18 +- 0817 ipaddr : DD member portal addr = 192.168.1.1 +- 0818 uint32 : DD member portal port = 860/tcp +diff --git a/utils/open-isns/tests/data/test06/11-registration b/utils/open-isns/tests/data/test06/11-registration +deleted file mode 100644 +index d8d03f8..0000000 +--- a/utils/open-isns/tests/data/test06/11-registration ++++ /dev/null +@@ -1,52 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test06/server0/database +-Last EID: 1 +-Last Index: 24 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b7 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=22 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 21 11:23:54 2007 +- 0007 uint32 : Entity index = 22 +--------------- +-Object: index=13 type= state=mature parent=22 +- 0020 string : iSCSI name = "isns.client1" +- 0024 uint32 : iSCSI node index = 13 +- 0021 uint32 : iSCSI node type = Initiator +--------------- +-Object: index=18 type= state=mature parent=22 +- 0010 ipaddr : Portal IP address = 192.168.1.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 18 +--------------- +-Object: index=23 type= state=mature parent=22 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 192.168.1.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 23 +--------------- +-Object: index=16 type= state=mature +- 0811 uint32 : DD ID = 1 +- 0812 string : DD name = "isns.dd1" +- 081e uint32 : DD features = +- 0813 uint32 : DD member iSCSI index = 13 +- 0814 string : DD member iSCSI name = "isns.client1" +- 0816 uint32 : DD member portal index = 18 +- 0817 ipaddr : DD member portal addr = 192.168.1.1 +- 0818 uint32 : DD member portal port = 860/tcp +diff --git a/utils/open-isns/tests/data/test07/01-enroll b/utils/open-isns/tests/data/test07/01-enroll +deleted file mode 100644 +index ad2eaf4..0000000 +--- a/utils/open-isns/tests/data/test07/01-enroll ++++ /dev/null +@@ -1,19 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test07/server0/database +-Last EID: 1 +-Last Index: 4 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +- 0004 uint64 : Timestamp = Fri Sep 14 13:42:57 2007 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test07/02-registration b/utils/open-isns/tests/data/test07/02-registration +deleted file mode 100644 +index da8962a..0000000 +--- a/utils/open-isns/tests/data/test07/02-registration ++++ /dev/null +@@ -1,45 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test07/server0/database +-Last EID: 1 +-Last Index: 8 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +- 0004 uint64 : Timestamp = Fri Sep 14 13:42:57 2007 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=4 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:42:57 2007 +- 0007 uint32 : Entity index = 4 +--------------- +-Object: index=5 type= state=mature parent=4 +- 0020 string : iSCSI name = "isns.client1" +- 0024 uint32 : iSCSI node index = 5 +- 0021 uint32 : iSCSI node type = Initiator +--------------- +-Object: index=6 type= state=mature parent=4 +- 0010 ipaddr : Portal IP address = 127.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 6 +- 0014 uint32 : ESI port = 65535/tcp +- 0013 uint32 : ESI interval = 5 +--------------- +-Object: index=7 type= state=mature parent=4 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.0.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 7 +diff --git a/utils/open-isns/tests/data/test07/03-expired b/utils/open-isns/tests/data/test07/03-expired +deleted file mode 100644 +index edb9ea4..0000000 +--- a/utils/open-isns/tests/data/test07/03-expired ++++ /dev/null +@@ -1,19 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test07/server0/database +-Last EID: 1 +-Last Index: 8 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +- 0004 uint64 : Timestamp = Fri Sep 14 13:42:57 2007 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test07/04-registration b/utils/open-isns/tests/data/test07/04-registration +deleted file mode 100644 +index de57cbd..0000000 +--- a/utils/open-isns/tests/data/test07/04-registration ++++ /dev/null +@@ -1,57 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test07/server0/database +-Last EID: 1 +-Last Index: 14 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +- 0004 uint64 : Timestamp = Fri Sep 14 13:43:12 2007 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +--------------- +-Object: index=8 type= state=mature +- 0001 string : Entity identifier = "client1.isns-test.eu" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 14 13:43:12 2007 +- 0007 uint32 : Entity index = 8 +--------------- +-Object: index=9 type= state=mature parent=8 +- 0020 string : iSCSI name = "isns.client1" +- 0024 uint32 : iSCSI node index = 9 +- 0021 uint32 : iSCSI node type = Initiator +--------------- +-Object: index=10 type= state=mature parent=8 +- 0010 ipaddr : Portal IP address = 127.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 860/tcp +- 0016 uint32 : Portal index = 10 +- 0014 uint32 : ESI port = 65535/tcp +- 0013 uint32 : ESI interval = 5 +--------------- +-Object: index=11 type= state=mature parent=8 +- 0010 ipaddr : Portal IP address = 127.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 1/tcp +- 0016 uint32 : Portal index = 11 +--------------- +-Object: index=12 type= state=mature parent=8 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.0.0.1 +- 0032 uint32 : Portal group port = 860/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 12 +--------------- +-Object: index=13 type= state=mature parent=8 +- 0030 string : Portal group name = "isns.client1" +- 0031 ipaddr : Portal group address = 127.0.0.1 +- 0032 uint32 : Portal group port = 1/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 13 +diff --git a/utils/open-isns/tests/data/test07/05-expired b/utils/open-isns/tests/data/test07/05-expired +deleted file mode 100644 +index fd51f78..0000000 +--- a/utils/open-isns/tests/data/test07/05-expired ++++ /dev/null +@@ -1,19 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test07/server0/database +-Last EID: 1 +-Last Index: 14 +--------------- +-Object: index=1 type= state=mature PRIVATE +- 0001 string : Entity identifier = "CONTROL" +- 0007 uint32 : Entity index = 1 +- 0004 uint64 : Timestamp = Fri Sep 14 13:43:12 2007 +--------------- +-Object: index=2 type= state=mature parent=1 PRIVATE +- 0601v string : Security Policy Index = "client1.isns-test.eu" +- 0607v string : Policy allowed node name = "isns.client1" +- 0603v opaque : DSA security key = <30 82 01 b6 30 82 01 2b 06 07 2a 86 48 ce 38 04 01 30 82 01... +--------------- +-Object: index=3 type= state=mature parent=1 PRIVATE +- 0020 string : iSCSI name = "isns.control" +- 0021 uint32 : iSCSI node type = +- 0024 uint32 : iSCSI node index = 3 +diff --git a/utils/open-isns/tests/data/test08/01-pauw1 b/utils/open-isns/tests/data/test08/01-pauw1 +deleted file mode 100644 +index 3de54da..0000000 +--- a/utils/open-isns/tests/data/test08/01-pauw1 ++++ /dev/null +@@ -1,100 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test08/server0/database +-Last EID: 1 +-Last Index: 15 +--------------- +-Object: index=1 type= state=mature +- 0001 string : Entity identifier = "cyan.pauw.homeunix.net" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Mon Sep 17 15:15:41 2007 +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0" +- 0024 uint32 : iSCSI node index = 2 +- 0021 uint32 : iSCSI node type = Target +- 0022 string : iSCSI alias = "Test (10 GB)" +- 002a string : iSCSI auth method = "None" +--------------- +-Object: index=3 type= state=mature parent=1 +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-1" +- 0024 uint32 : iSCSI node index = 3 +- 0021 uint32 : iSCSI node type = Target +- 0022 string : iSCSI alias = "160 GB disk (ntfs)" +- 002a string : iSCSI auth method = "None" +--------------- +-Object: index=4 type= state=mature parent=1 +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-2" +- 0024 uint32 : iSCSI node index = 4 +- 0021 uint32 : iSCSI node type = Target +- 0022 string : iSCSI alias = "160 GB disk (ext3)" +- 002a string : iSCSI auth method = "CHAP" +--------------- +-Object: index=5 type= state=mature parent=1 +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-3" +- 0024 uint32 : iSCSI node index = 5 +- 0021 uint32 : iSCSI node type = Target +- 0022 string : iSCSI alias = "Test (1 GB)" +- 002a string : iSCSI auth method = "None" +--------------- +-Object: index=6 type= state=mature parent=1 +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-4" +- 0024 uint32 : iSCSI node index = 6 +- 0021 uint32 : iSCSI node type = Target +- 0022 string : iSCSI alias = "Test (40 GB)" +- 002a string : iSCSI auth method = "CHAP" +--------------- +-Object: index=7 type= state=mature parent=1 +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-5" +- 0024 uint32 : iSCSI node index = 7 +- 0021 uint32 : iSCSI node type = Target +- 0022 string : iSCSI alias = "test" +- 002a string : iSCSI auth method = "None" +--------------- +-Object: index=8 type= state=mature parent=1 +- 0010 ipaddr : Portal IP address = 10.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0016 uint32 : Portal index = 8 +--------------- +-Object: index=9 type= state=mature parent=1 +- 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0" +- 0031 ipaddr : Portal group address = 10.0.0.1 +- 0032 uint32 : Portal group port = 3260/tcp +- 0034 uint32 : Portal group index = 9 +- 0033 uint32 : Portal group tag = 1 +--------------- +-Object: index=10 type= state=mature parent=1 +- 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-1" +- 0031 ipaddr : Portal group address = 10.0.0.1 +- 0032 uint32 : Portal group port = 3260/tcp +- 0034 uint32 : Portal group index = 10 +- 0033 uint32 : Portal group tag = 1 +--------------- +-Object: index=11 type= state=mature parent=1 +- 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-2" +- 0031 ipaddr : Portal group address = 10.0.0.1 +- 0032 uint32 : Portal group port = 3260/tcp +- 0034 uint32 : Portal group index = 11 +- 0033 uint32 : Portal group tag = 1 +--------------- +-Object: index=12 type= state=mature parent=1 +- 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-3" +- 0031 ipaddr : Portal group address = 10.0.0.1 +- 0032 uint32 : Portal group port = 3260/tcp +- 0034 uint32 : Portal group index = 12 +- 0033 uint32 : Portal group tag = 1 +--------------- +-Object: index=13 type= state=mature parent=1 +- 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-4" +- 0031 ipaddr : Portal group address = 10.0.0.1 +- 0032 uint32 : Portal group port = 3260/tcp +- 0034 uint32 : Portal group index = 13 +- 0033 uint32 : Portal group tag = 1 +--------------- +-Object: index=14 type= state=mature parent=1 +- 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-5" +- 0031 ipaddr : Portal group address = 10.0.0.1 +- 0032 uint32 : Portal group port = 3260/tcp +- 0034 uint32 : Portal group index = 14 +- 0033 uint32 : Portal group tag = 1 +diff --git a/utils/open-isns/tests/data/test09/01-pauw2 b/utils/open-isns/tests/data/test09/01-pauw2 +deleted file mode 100644 +index 9b0a814..0000000 +--- a/utils/open-isns/tests/data/test09/01-pauw2 ++++ /dev/null +@@ -1,31 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test09/server0/database +-Last EID: 1 +-Last Index: 9 +--------------- +-Object: index=5 type= state=mature +- 0001 string : Entity identifier = "blue.pauw.homeunix.net" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Mon Sep 17 15:18:04 2007 +- 0007 uint32 : Entity index = 5 +--------------- +-Object: index=6 type= state=mature parent=5 +- 0010 ipaddr : Portal IP address = 192.168.1.2 +- 0011 uint32 : Portal TCP/UDP port = 33849/tcp +- 0016 uint32 : Portal index = 6 +- 0014 uint32 : ESI port = 56288/tcp +- 0013 uint32 : ESI interval = 300 +--------------- +-Object: index=7 type= state=mature parent=5 +- 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" +- 0024 uint32 : iSCSI node index = 7 +- 0021 uint32 : iSCSI node type = Initiator +- 0022 string : iSCSI alias = "blue.pauw.homeunix.net" +--------------- +-Object: index=8 type= state=mature parent=5 +- 0030 string : Portal group name = "iqn.2005-03.org.open-iscsi:blue" +- 0031 ipaddr : Portal group address = 192.168.1.2 +- 0032 uint32 : Portal group port = 33849/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +diff --git a/utils/open-isns/tests/data/test10/01-pauw3 b/utils/open-isns/tests/data/test10/01-pauw3 +deleted file mode 100644 +index b7f3b10..0000000 +--- a/utils/open-isns/tests/data/test10/01-pauw3 ++++ /dev/null +@@ -1,31 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test10/server0/database +-Last EID: 1 +-Last Index: 9 +--------------- +-Object: index=5 type= state=mature +- 0001 string : Entity identifier = "blue.pauw.homeunix.net" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Mon Sep 17 16:34:30 2007 +- 0007 uint32 : Entity index = 5 +--------------- +-Object: index=6 type= state=mature parent=5 +- 0010 ipaddr : Portal IP address = 192.168.1.2 +- 0011 uint32 : Portal TCP/UDP port = 33849/tcp +- 0016 uint32 : Portal index = 6 +- 0014 uint32 : ESI port = 56288/tcp +- 0013 uint32 : ESI interval = 10 +--------------- +-Object: index=7 type= state=mature parent=5 +- 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" +- 0024 uint32 : iSCSI node index = 7 +- 0021 uint32 : iSCSI node type = Initiator +- 0022 string : iSCSI alias = "blue.pauw.homeunix.net" +--------------- +-Object: index=8 type= state=mature parent=5 +- 0030 string : Portal group name = "iqn.2005-03.org.open-iscsi:blue" +- 0031 ipaddr : Portal group address = 192.168.1.2 +- 0032 uint32 : Portal group port = 33849/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +diff --git a/utils/open-isns/tests/data/test10/02-expired b/utils/open-isns/tests/data/test10/02-expired +deleted file mode 100644 +index b7f3b10..0000000 +--- a/utils/open-isns/tests/data/test10/02-expired ++++ /dev/null +@@ -1,31 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test10/server0/database +-Last EID: 1 +-Last Index: 9 +--------------- +-Object: index=5 type= state=mature +- 0001 string : Entity identifier = "blue.pauw.homeunix.net" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Mon Sep 17 16:34:30 2007 +- 0007 uint32 : Entity index = 5 +--------------- +-Object: index=6 type= state=mature parent=5 +- 0010 ipaddr : Portal IP address = 192.168.1.2 +- 0011 uint32 : Portal TCP/UDP port = 33849/tcp +- 0016 uint32 : Portal index = 6 +- 0014 uint32 : ESI port = 56288/tcp +- 0013 uint32 : ESI interval = 10 +--------------- +-Object: index=7 type= state=mature parent=5 +- 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" +- 0024 uint32 : iSCSI node index = 7 +- 0021 uint32 : iSCSI node type = Initiator +- 0022 string : iSCSI alias = "blue.pauw.homeunix.net" +--------------- +-Object: index=8 type= state=mature parent=5 +- 0030 string : Portal group name = "iqn.2005-03.org.open-iscsi:blue" +- 0031 ipaddr : Portal group address = 192.168.1.2 +- 0032 uint32 : Portal group port = 33849/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +diff --git a/utils/open-isns/tests/data/test10/03-pauw3 b/utils/open-isns/tests/data/test10/03-pauw3 +deleted file mode 100644 +index 412c5b5..0000000 +--- a/utils/open-isns/tests/data/test10/03-pauw3 ++++ /dev/null +@@ -1,31 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test10/server0/database +-Last EID: 1 +-Last Index: 9 +--------------- +-Object: index=5 type= state=mature +- 0001 string : Entity identifier = "blue.pauw.homeunix.net" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Mon Sep 17 16:34:51 2007 +- 0007 uint32 : Entity index = 5 +--------------- +-Object: index=6 type= state=mature parent=5 +- 0010 ipaddr : Portal IP address = 192.168.1.2 +- 0011 uint32 : Portal TCP/UDP port = 33849/tcp +- 0016 uint32 : Portal index = 6 +- 0014 uint32 : ESI port = 56288/tcp +- 0013 uint32 : ESI interval = 10 +--------------- +-Object: index=7 type= state=mature parent=5 +- 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" +- 0024 uint32 : iSCSI node index = 7 +- 0021 uint32 : iSCSI node type = Initiator +- 0022 string : iSCSI alias = "blue.pauw.homeunix.net" +--------------- +-Object: index=8 type= state=mature parent=5 +- 0030 string : Portal group name = "iqn.2005-03.org.open-iscsi:blue" +- 0031 ipaddr : Portal group address = 192.168.1.2 +- 0032 uint32 : Portal group port = 33849/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +diff --git a/utils/open-isns/tests/data/test10/04-expired b/utils/open-isns/tests/data/test10/04-expired +deleted file mode 100644 +index 412c5b5..0000000 +--- a/utils/open-isns/tests/data/test10/04-expired ++++ /dev/null +@@ -1,31 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test10/server0/database +-Last EID: 1 +-Last Index: 9 +--------------- +-Object: index=5 type= state=mature +- 0001 string : Entity identifier = "blue.pauw.homeunix.net" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Mon Sep 17 16:34:51 2007 +- 0007 uint32 : Entity index = 5 +--------------- +-Object: index=6 type= state=mature parent=5 +- 0010 ipaddr : Portal IP address = 192.168.1.2 +- 0011 uint32 : Portal TCP/UDP port = 33849/tcp +- 0016 uint32 : Portal index = 6 +- 0014 uint32 : ESI port = 56288/tcp +- 0013 uint32 : ESI interval = 10 +--------------- +-Object: index=7 type= state=mature parent=5 +- 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" +- 0024 uint32 : iSCSI node index = 7 +- 0021 uint32 : iSCSI node type = Initiator +- 0022 string : iSCSI alias = "blue.pauw.homeunix.net" +--------------- +-Object: index=8 type= state=mature parent=5 +- 0030 string : Portal group name = "iqn.2005-03.org.open-iscsi:blue" +- 0031 ipaddr : Portal group address = 192.168.1.2 +- 0032 uint32 : Portal group port = 33849/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 8 +diff --git a/utils/open-isns/tests/data/test11/01-pauw4 b/utils/open-isns/tests/data/test11/01-pauw4 +deleted file mode 100644 +index 50c6b92..0000000 +--- a/utils/open-isns/tests/data/test11/01-pauw4 ++++ /dev/null +@@ -1,32 +0,0 @@ +-Dumping database contents +-Backend: /tmp/isns-test/test11/server0/database +-Last EID: 1 +-Last Index: 5 +--------------- +-Object: index=1 type= state=mature +- 0001 string : Entity identifier = "troopa.nki.nl" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 7200 +- 0004 uint64 : Timestamp = Fri Sep 21 09:37:10 2007 +- 0007 uint32 : Entity index = 1 +--------------- +-Object: index=2 type= state=mature parent=1 +- 0010 ipaddr : Portal IP address = 192.168.1.40 +- 0011 uint32 : Portal TCP/UDP port = 3229/tcp +- 0017 uint32 : SCN port = 3230/tcp +- 0014 uint32 : ESI port = 3230/tcp +- 0013 uint32 : ESI interval = 300 +- 0016 uint32 : Portal index = 2 +--------------- +-Object: index=3 type= state=mature parent=1 +- 0030 string : Portal group name = "iqn.1991-05.com.microsoft:orange" +- 0031 ipaddr : Portal group address = 192.168.1.40 +- 0032 uint32 : Portal group port = 3229/tcp +- 0033 uint32 : Portal group tag = 1 +- 0034 uint32 : Portal group index = 3 +--------------- +-Object: index=4 type= state=mature parent=1 +- 0020 string : iSCSI name = "iqn.1991-05.com.microsoft:orange" +- 0021 uint32 : iSCSI node type = Initiator +- 0022 string : iSCSI alias = "" +- 0024 uint32 : iSCSI node index = 4 +diff --git a/utils/open-isns/tests/genkey b/utils/open-isns/tests/genkey +deleted file mode 100644 +index 36c5eee..0000000 +--- a/utils/open-isns/tests/genkey ++++ /dev/null +@@ -1,175 +0,0 @@ +-#!/bin/bash +-# +-# This is a very simple script to generate a DSA +-# key pair for authenticated iSNS. +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This script is supposed to be run on the iSNS server. +-# For the first time, run as +-# isnsgenkey -s 1024 +-# This will generate a DSA params file, and a DSA private +-# and public key for the server. +-# +-# For each client, generate a key using +-# isnsgenkey +-# where is the fully qualified domain name. +-# This script will convert the FQDN to a valid iSNS +-# source name (isns.com.foobar.host) +- +-myname=`basename $0` +-etcdir=/etc/isns +-keystore=$etcdir/keystore +-dsa_parms=$etcdir/dsa.params +-dsa_bits=1024 +-opt_force=0 +-opt_server=0 +- +-function usage { +- cat <<-EOF >&2 +- $* +- Usage: +- $myname -s [-f] bits +- $myname clientname +- EOF +- exit 1 +-} +- +-function make_isns_name { +- OFS="$IFS" +- IFS=. +- set -- $* +- +- __result=$1; shift +- for part; do +- __result=$part.$__result +- done +- echo "isns.$__result" +- IFS="$OFS" +-} +- +-set -- `getopt b:fk:s $*` +-while [ $# -gt 0 ]; do +- opt=$1; shift +- case $opt in +- --) break;; +- -b) dsa_bits=$1; shift;; +- -f) opt_force=1;; +- -k) dsa_priv=$1; shift;; +- -s) opt_server=1;; +- *) usage "Unknown option $opt";; +- esac +-done +- +-if [ `id -un` != "root" -a $opt_force -eq 0 ]; then +- echo "$myname: should be run by super user only" >&2 +- exit 1 +-fi +- +-# All newly generated files should have restricted +-# access by default. +-umask 077 +- +-tmpdir=`mktemp -d /tmp/isnsgenkey.XXXXXX` +-trap "rm -rf $tmpdir" 0 1 2 15 +- +-if [ $opt_server -ne 0 ]; then +- [ $# -eq 1 ] || usage "Expected DSA key length" +- dsa_bits=$1 +- +- install -m 755 -d $etcdir +- if [ -z $dsa_priv ]; then +- dsa_priv=$etcdir/auth_key +- fi +- dsa_pub=$dsa_priv.pub +- dsa_copy= +-else +- [ $# -eq 1 ] || usage "Expected client name" +- client=`make_isns_name $1` +- +- mkdir -p $tmpdir$etcdir +- # build_client_conf $client > $tmpdir$etcdir/client.conf +- +- if [ -z $dsa_priv ]; then +- dsa_priv=$tmpdir$etcdir/auth_key +- fi +- dsa_pub=$dsa_priv.pub +- dsa_copy=$keystore/$client +-fi +- +-if [ -f $dsa_priv -a $opt_force -eq 0 ]; then +- cat <<-EOF +- +- ------------------------------------------------------------------ +- | There is already a DSA key installed in $dsa_priv. In order to +- | generate a new key, please specify the -f [force] option. +- ------------------------------------------------------------------ +- EOF +- exit 1 +-fi +- +-if [ ! -r $dsa_parms ]; then +- if [ $opt_server -eq 0 ]; then +- echo "Please run $myname in server-initialization mode first" >&2 +- exit 1 +- fi +- +- cat <<-EOF +- +- ------------------------------------------------------------------ +- | I will now try to generate a set of DSA parameters. This can be +- | a slow process, so please be patient. +- ------------------------------------------------------------------ +- EOF +- +- mkdir -p `dirname $dsa_parms` +- openssl dsaparam $dsa_bits -out $dsa_parms || +- exit 1 +- +- # DSA parameters are public +- chmod 644 $dsa_parms +-fi +- +-cat <&2 +- exit 1 +-fi +-if ! openssl dgst -dss1 -verify $dsa_pub -signature $tmpdir/test-sig /etc/hosts; then +- echo "DSA verification failed - aborting!" >&2 +- exit 1 +-fi +-od -tx1 $tmpdir/test-sig +- +-if [ $opt_server -eq 0 ]; then +- echo "Installing DSA public key as $dsa_copy" +- install -d -m 755 $keystore +- install -m 644 $dsa_pub $dsa_copy +- install -m 644 $etcdir/auth_key.pub $tmpdir$etcdir/server.pub +- +- tarball=auth-$client.tar.gz +- tar -C $tmpdir -czf $tarball .$etcdir +- +- cat <<-EOF +- ------------------------------------------------------------------ +- | Successfully packaged $tarball +- | Please copy this file to client $client and install +- ------------------------------------------------------------------ +- EOF +-fi +diff --git a/utils/open-isns/tests/harness.pl b/utils/open-isns/tests/harness.pl +deleted file mode 100644 +index d7ce025..0000000 +--- a/utils/open-isns/tests/harness.pl ++++ /dev/null +@@ -1,929 +0,0 @@ +-#!/usr/bin/perl +- +-use Getopt::Long; +- +-$__isns_verbose = 1; +-$__isns_security = 1; +- +-$__isns_bin = "../"; +-$__isns_seq = 0; +-$__isns_test_base = '/tmp/isns-test'; +-$__isns_test_dir = '/tmp/isns-test/test'; +-$__isns_stage = 1; +-$__isns_test_data = ''; +-$__isns_test_dump = ''; +-$__isns_passed = 0; +-$__isns_failed = 0; +-$__isns_warned = 0; +-@__isns_servers = (); +- +-%__isns_ignore_tag = ( +- "0004" => 1, # Timestamp +- "0603v" => 1, # DSA public key +-); +- +-sub isns_fail { +- +- print "*** FAILURE ***\n"; +- $__isns_failed++; +- +- my $line; +- foreach $line (@_) { +- print "*** $line ***\n"; +- } +-} +- +-sub isns_pass { +- +- print "*** SUCCESS ***\n" if ($__isns_verbose > 1); +- $__isns_passed++; +-} +- +-sub isns_warn { +- +- printf "*** WARNING: %s ***\n", join(' ', @_); +- $__isns_warned++; +-} +- +-sub isns_die { +- +- printf "*** TERMINAL FAILURE: %s ***\n", join(' ', @_); +- $__isns_failed++; +- +- &isns_finish; +- die "Test aborted\n"; +-} +- +-sub isns_finish { +- +- my $pid; +- foreach $pid (@__isns_servers) { +- kill 15, $pid or &isns_warn("Cannot kill server process (pid=$pid): $!\n"); +- } +- +- &isns_report; +-} +- +-sub isns_report { +- +- print "*** Test $__isns_test_name complete."; +- print " PASSED: $__isns_passed" if ($__isns_passed); +- print " FAILED: $__isns_failed" if ($__isns_failed); +- print " WARNINGS: $__isns_warned" if ($__isns_warned); +- print " ***\n"; +-} +- +-sub isns_info { +- +- print @_ if ($__isns_verbose > 1); +-} +- +-sub isns_notice { +- +- print @_ if ($__isns_verbose > 0); +-} +- +-sub isns_stage { +- +- local($name, @msg) = @_; +- +- if ($name =~ m/^[0-9]/o) { +- $__isns_stage_name = $name; +- } else { +- $__isns_stage_name = sprintf "%02d-%s", +- $__isns_stage++, $name; +- } +- &isns_notice("*** $__isns_stage_name: ", @msg, " ***\n"); +-} +- +-sub build_config { +- +- local($src_file, $dst_file, *__subst) = @_; +- my $key; +- my $okey; +- my $value; +- my $sepa; +- my %subst; +- +- &isns_info("*** Building $src_file -> $dst_file\n"); +- +- # Translate all keys to lower case. +- foreach $key (keys(%__subst)) { +- $value = $__subst{$key}; +- $key =~ tr/A-Z/a-z/; +- $subst{$key} = $value; +- } +-# foreach $key (keys(%subst)) { +-# printf " %s -> %s\n", $key, $subst{$key}; +-# } +- +- open IN, "<$src_file" or die "$src_file: $!\n"; +- open OUT, ">$dst_file" or die "$dst_file: $!\n"; +- +- while () { +- $line = $_; +- if (m:(\S+)(\s*=\s*)(.*):o) { +- ($okey, $sepa, $value) = ($1, $2, $3); +- +- $key = $okey; +- $key =~ tr/A-Z/a-z/; +- +- if ($subst{$key}) { +- $line = "$okey$sepa$subst{$key}\n"; +- } +- } +- +- # Ignore unconfigured lines. +- next if ($line =~ m/\@[A-Z_]*\@/o); +- print OUT $line; +- } +- close OUT; +- close IN; +-} +- +-sub get_config_value { +- local($cfg_file, $item_name) = @_; +- my $result; +- my $name; +- my $value; +- +- $item_name =~ tr/A-Z/a-z/; +- +- open IN, "<$cfg_file" or die "$cfg_file: $!\n"; +- while () { +- chop; +- ($name, $value) = split(/\s+=\s+/, $_); +- +- $name =~ tr/A-Z/a-z/; +- if ($name eq $item_name) { +- $result = $value; +- last; +- } +- } +- close IN; +- +- return $result; +-} +- +-sub create_key { +- +- local($keyfile) = @_; +- +- if ($__isns_security) { +- &isns_info("*** Creating key at $keyfile\n"); +- system "./genkey -fsk $keyfile 2048 >${keyfile}.log 2>&1"; +- } +- return $keyfile; +-} +- +-sub create_server { +- +- local(*override) = @_; +- my %local_config; +- my $my_dir; +- my $handle; +- my $config; +- +- $handle = sprintf "server%d", $__isns_seq++; +- $my_dir = "$__isns_test_dir/${handle}"; +- +- mkdir $my_dir, 0700 or die "Cannot create $my_dir: $!\n"; +- +- $server_addr = "127.0.0.1:7770" unless ($server_addr); +- +- $config = "$my_dir/config"; +- +- $local_config{"SourceName"} = "isns.$handle"; +- $local_config{"Database"} = "$my_dir/database"; +- $local_config{"BindAddress"} = "$server_addr"; +- $local_config{"PIDFile"} = "$my_dir/pid"; +- $local_config{"ControlSocket"} = "$my_dir/control"; +- $local_config{"Security"} = $__isns_security; +- $local_config{"AuthKeyFile"} = &create_key("$my_dir/auth_key"); +- +- foreach $key (keys(%override)) { +- $local_config{$key} = $override{$key}; +- } +- +- &build_config('server.conf', $config, \%local_config); +- return $config; +-} +- +-sub create_client { +- +- local($server_config, $client_address) = @_; +- my %local_config; +- my $server_key; +- my $control_socket; +- my $server_addr; +- my $my_dir; +- my $handle; +- my $config; +- +- $handle = sprintf "client%d", $__isns_seq++; +- $my_dir = "$__isns_test_dir/${handle}"; +- +- mkdir $my_dir, 0700 or die "Cannot create $my_dir: $!\n"; +- +- $control_socket = &get_config_value($server_config, "ControlSocket"); +- $server_addr = &get_config_value($server_config, "BindAddress"); +- $server_addr = "127.0.0.1" unless ($server_addr); +- +- $config = "$my_dir/config"; +- +- $local_config{"SourceName"} = "isns.$handle"; +- $local_config{"AuthName"} = "$handle.isns-test.eu"; +- $local_config{"ServerAddress"} = $server_addr; +- $local_config{"ControlSocket"} = $control_socket; +- $local_config{"BindAddress"} = $client_address if ($client_address); +- $local_config{"server_config"} = $server_config; +- $local_config{"Security"} = $__isns_security; +- $local_config{"AuthKeyFile"} = &create_key("$my_dir/auth_key"); +- $local_config{"ServerKeyFile"} = +- &get_config_value($server_config, "AuthKeyFile") . ".pub"; +- +- &build_config('client.conf', $config, \%local_config); +- +- $__isns_data{$config,"server_config"} = $server_config; +- $__isns_data{$config} = %local_config; +- return $config; +-} +- +-sub get_logfile { +- +- local($config) = @_; +- my $dir; +- +- $dir = $config; +- $dir =~ s|/+[^/]+$||o; +- +- return "$dir/logfile"; +-} +- +-sub run_command { +- +- local(@cmd) = @_; +- my $status; +- my $cmd; +- +- $cmd = join(' ', @cmd); +- &isns_info("$cmd\n"); +- +- system "$cmd"; +- +- $status = $?; +- if ($status) { +- &isns_warn("Command failed, exit status $status"); +- print "*** Command was: $cmd ***\n"; +- return undef; +- } +- +- return 1; +-} +- +-sub isns_start_server { +- +- local($server_config) = @_; +- my $logfile; +- my $pidfile; +- my $pid; +- +- die "restart_server: missing server config argument!\n" +- unless(-f $server_config); +- $logfile = &get_logfile($server_config); +- $pidfile = &get_config_value($server_config, "PIDFile"); +- +- &isns_info("*** Starting server (logging to $logfile)\n"); +- +- $pid = fork(); +- if ($pid) { +- my $retry; +- +- if ($pidfile) { +- for ($retry = 0; $retry < 5; $retry++) { +- last if (-f $pidfile); +- sleep 1; +- } +- $pid = `cat $pidfile` if ($pidfile); +- chop($pid); +- } +- &isns_info("*** Started server (pid=$pid) ***\n"); +- push(@__isns_servers, $pid); +- return $pid; +- } +- +- &isns_info("${__isns_bin}isnsd -c $server_config -f -d all\n"); +- exec "${__isns_bin}isnsd -c $server_config -f -d all >$logfile 2>&1 &" +- or die "Unable to run isnsd: $!\n"; +-} +- +-sub isns_stop_server { +- +- local($pid) = @_; +- my @list; +- my $p; +- +- kill 15, $pid or &isns_warn("Cannot kill server process (pid=$pid): $!\n"); +- foreach $p (@__isns_servers) { +- append(@list, $p) unless ($p == $pid); +- } +- @__isns_servers = @list; +-} +- +-sub isns_restart_server { +- +- local($pid, $server_config); +- +- if ($_[0] =~ m:^\d+$:o) { +- $pid = shift(@_); +- } else { +- if ($#__isns_servers < 0) { +- &isns_warn("isns_restart_server: no server running\n"); +- return 0; +- } +- $pid = $__isns_servers[0]; +- } +- $server_config = shift(@_); +- +- &isns_stop_server($pid); +- return &isns_start_server($server_config); +-} +- +-sub isns_verify_db { +- +- local($stage, $server_config); +- my $dump_file; +- my $data_file; +- +- if ($_[0] =~ m/^\d/o) { +- $stage = shift(@_); +- } else { +- $stage = $__isns_stage_name; +- } +- $server_config = shift(@_); +- +- die "Test case forgot to call test_prep" unless($__isns_test_data); +- +- $dump_file = "$__isns_test_dump/$stage"; +- unless (&run_command("${__isns_bin}/isnsd -c $server_config --dump-db > $dump_file")) { +- &isns_fail; +- return 0; +- } +- +- # See if the reference data file exists. If it +- # doesn't, this means we're priming the test case. +- # Just copy the dump file. +- $data_file = "$__isns_test_data/$stage"; +- unless (-f $data_file) { +- print "*** Saving database dump for stage $stage ***\n"; +- mkdir $__isns_test_data, 0755; +- system "cp $dump_file $data_file"; +- return 1; +- } +- +- &isns_info("*** Verifying database dump for stage $stage ***\n"); +- if (&verify_dump($stage, $data_file, $dump_file)) { +- &isns_pass; +- } else { +- if ($__isns_verbose > 1) { +- system("diff -u -ITimestamp -I'DSA security key' $data_file $dump_file"); +- } +- &isns_fail; +- } +- +- return 1; +-} +- +-sub verify_db { +- +- &isns_verify_db(@_); +-} +- +-sub verify_response { +- +- local($stage, $client_config) = @_; +- my $dump_file; +- my $data_file; +- +- die "Test case forgot to call test_prep" unless($__isns_test_data); +- +- $dump_file = &get_logfile($client_config); +- +- # See if the reference data file exists. If it +- # doesn't, this means we're priming the test case. +- # Just copy the dump file. +- $data_file = "$__isns_test_data/$stage"; +- unless (-f $data_file) { +- print "*** Saving data for stage $stage ***\n"; +- mkdir $__isns_test_data, 0755; +- system "cp $dump_file $data_file"; +- return 1; +- } +- +- &isns_info("*** Verifying data for stage $stage ***\n"); +- if (&verify_query($stage, $data_file, $dump_file)) { +- &isns_pass; +- } else { +- &isns_fail("Query response returns unexpected data"); +- system "cp $dump_file $__isns_test_dump/$stage"; +- print "*** Saved dump as $__isns_test_dump/$stage\n"; +- print "*** Reference data in $data_file\n"; +- if ($__isns_verbose > 1) { +- system("diff -u -ITimestamp -I'DSA security key' $data_file $dump_file"); +- } +- } +- +- return 1; +-} +- +-sub verify_dump { +- +- local($stage, $data_file, $dump_file) = @_; +- my $line; +- my @dump; +- my @data; +- my @obj1; +- my @obj2; +- +- @dump = &load_dump($dump_file); +- @data = &load_dump($data_file); +- +- &skip_header(\@dump); +- &skip_header(\@data); +- +- while (1) { +- $line++; +- +- @obj1 = &get_next_object(\@dump); +- @obj2 = &get_next_object(\@data); +- +- last unless(@obj1 || @obj2); +- +- unless (@obj1 && @obj2) { +- print STDERR "*** $stage: Excess data at end of dump\n"; +- return 0; +- } +- +- unless (&compare_objects(\@obj1, \@obj2)) { +- print STDERR "*** Object mismatch (object $line):\n"; +- print STDERR "Expected:\n "; +- print STDERR join("\n ", @obj2), "\n"; +- print STDERR "Got:\n "; +- print STDERR join("\n ", @obj1), "\n"; +- return 0; +- } +- } +- +- if (@data) { +- print STDERR "*** $stage: Unexpected end of dump at line $line\n"; +- return 0; +- } +- +- return 1; +-} +- +-sub skip_header { +- +- local(*list) = @_; +- local($_); +- +- while ($_ = shift(@list)) { +- last if (/^-/o); +- } +-} +- +-sub get_next_object { +- +- local(*list) = @_; +- local($_, $header, @result); +- my @tags; +- +- while ($_ = shift(@list)) { +- next if (/^-/o); +- if (/^\s+([0-9a-fv]+)\s+/o) { +- next if ($__isns_ignore_tag{$1}); +- push(@tags, $_); +- } else { +- if (@result) { +- unshift(@list, $_); +- last; +- } +- push(@result, $_); +- } +- #print "### $_\n"; +- } +- +- if (@tags) { +- push(@result, sort(@tags)); +- } +- return @result; +-} +- +-sub compare_objects { +- +- local(*a, *b) = @_; +- local($i); +- +- return 0 unless ($#a == $#b); +- for ($i = 0; $i <= $#a; $i++) { +- return 0 unless ($a[$i] eq $b[$i]); +- } +- +- return 1; +-} +- +- +-sub verify_query { +- +- local($stage, $data_file, $dump_file) = @_; +- my $line; +- my @dump; +- my @data; +- +- @dump = &load_dump($dump_file); +- @data = &load_dump($data_file); +- +- while (@dump) { +- $line++; +- unless (@data) { +- print STDERR "*** $stage: Excess data in dump at line $line\n"; +- return 0; +- } +- +- $a = shift(@dump); +- $b = shift(@data); +- if ($a =~ /^\S/o) { +- next if ($a eq $b); +- print STDERR "*** $stage: Mismatch at line $line ***\n"; +- print STDERR "*** Found: $a\n"; +- print STDERR "*** Expected: $b\n"; +- return 0; +- } +- +- ($nix, $a_tag, $a_value) = split(/\s+/, $a, 3); +- ($nix, $b_tag, $b_value) = split(/\s+/, $b, 3); +- if ($a_tag ne $b_tag) { +- print STDERR "*** $stage: Tag mismatch at line $line\n"; +- print STDERR "*** Found: $a\n"; +- print STDERR "*** Expected: $b\n"; +- return 0; +- } +- +- next if ($__isns_ignore_tag{$a_tag}); +- if ($a_value ne $b_value) { +- print STDERR "*** $stage: Value mismatch at line $line (tag $a_tag)\n"; +- print STDERR "*** Found: $a\n"; +- print STDERR "*** Expected: $b\n"; +- return 0; +- } +- } +- +- if (@data) { +- print STDERR "*** $stage: Unexpected end of dump at line $line\n"; +- return 0; +- } +- +- return 1; +-} +- +-sub load_dump { +- +- local($filename) = @_; +- my @result; +- +- open IN, $filename or die "Unable to open $filename: $!\n"; +- while () { +- chop; +- push(@result, $_); +- } +- close IN; +- return @result; +-} +- +- +-sub run_client { +- +- local($config, @args) = @_; +- my $logfile; +- my $cmd; +- +- $logfile = &get_logfile($config); +- +- $cmd = "${__isns_bin}/isnsadm -c $client_config " . join(' ', @args); +- if (&run_command("$cmd >$logfile")) { +- return $logfile; +- } +- return undef; +-} +- +-sub __isns_enroll_client { +- +- local($client_config, @extra_args) = @_; +- my $source_name; +- my $auth_name; +- my $auth_key; +- my @args; +- +- $source_name = &get_config_value($client_config, "SourceName"); +- $auth_name = &get_config_value($client_config, "AuthName"); +- $auth_key = &get_config_value($client_config, "AuthKeyFile"); +- +- push(@args, "--local --enroll $auth_name node-name=$source_name"); +- push(@args, " key=${auth_key}.pub") if ($auth_key); +- push(@args, @extra_args) if (@extra_args); +- +- &run_client($client_config, @args); +-} +- +-sub isns_enroll_client { +- +- local($client, @args) = @_; +- my $server; +- +- $server = $__isns_data{$client,"server_config"}; +- &isns_stage("enroll", "Enrolling client"); +- &__isns_enroll_client($client, @args); +- &verify_db($__isns_stage_name, $server); +-} +- +-sub enroll_client { +- +- print "*** Enrolling client ***\n"; +- &__isns_enroll_client(@_); +-} +- +-sub __isns_register_client { +- +- local($client_config, @extra_args) = @_; +- my @args; +- +- push(@args, "--register"); +- push(@args, @extra_args) if (@extra_args); +- +- &run_client($client_config, @args); +-} +- +-sub isns_register_client { +- +- local($client, @args) = @_; +- my $server; +- +- $server = $__isns_data{$client,"server_config"}; +- &isns_stage("registration", "Registering client " . join(' ', @args)); +- &__isns_register_client($client, @args); +- &verify_db($__isns_stage_name, $server); +-} +- +-sub register_client { +- +- print "*** Registering client ***\n"; +- &__isns_register_client(@_); +-} +- +-sub __isns_query_objects { +- +- local($client_config, @extra_args) = @_; +- my @args; +- +- push(@args, "--query"); +- push(@args, @extra_args) if (@extra_args); +- +- return &run_client($client_config, @args); +-} +- +-sub isns_query_objects { +- +- local($client, @args) = @_; +- +- &isns_stage("query", "Querying " . join(' ', @args)); +- &__isns_query_objects($client, @args); +- &verify_response($__isns_stage_name, $client); +-} +- +-sub query_objects { +- +- print "*** Querying objects ***\n"; +- __isns_query_objects(@_); +-} +- +-sub isns_query_eid { +- +- local($client_config, @extra_args) = @_; +- my $logfile; +- my @args; +- local($eid); +- +- push(@args, "--query-eid"); +- push(@args, @extra_args) if (@extra_args); +- +- &isns_info("*** Querying for EID ***\n"); +- $logfile = &run_client($client_config, @args); +- +- if ($logfile) { +- $eid = `cat $logfile`; +- unless ($eid) { +- &isns_fail("Server reports empty EID"); +- } +- chop($eid); +- } +- +- return $eid; +-} +- +-sub __isns_unregister_client { +- +- local($client_config, @extra_args) = @_; +- my @args; +- +- push(@args, "--deregister"); +- push(@args, @extra_args) if (@extra_args); +- +- &run_client($client_config, @args); +-} +- +-sub isns_unregister_client { +- +- my $stage = 0; +- my $client; +- my $server; +- my $eid; +- +- if ($_[0] =~ m/^\d/o) { +- &isns_stage(shift(@_), "Unregister client"); +- } else { +- &isns_stage("unregistration", "Unregister client"); +- } +- +- $client = shift(@_); +- +- unless (@_) { +- $eid = &isns_query_eid($client); +- push(@_, "eid=$eid"); +- } +- +- &__isns_unregister_client($client, @_); +- +- $server = $__isns_data{$client,"server_config"}; +- &verify_db($__isns_stage_name, $server); +-} +- +-sub unregister_client { +- +- &isns_info("*** Unregistering client ***\n"); +- &__isns_unregister_client(@_); +-} +- +-sub __isns_register_domain { +- +- local($client_config, @extra_args) = @_; +- my @args; +- +- push(@args, "--local --dd-register"); +- push(@args, @extra_args) if (@extra_args); +- +- &run_client($client_config, @args); +-} +- +-sub isns_register_domain { +- +- local($client, @args) = @_; +- my $server; +- +- &isns_stage("dd-registration", "Registering DD " . join(' ', @args)); +- &__isns_register_domain($client, @args); +- +- $server = $__isns_data{$client,"server_config"}; +- &isns_verify_db($server); +-} +- +-sub register_domain { +- +- &isns_info("*** Registering DD ***\n"); +- &__isns_register_domain(@_); +-} +- +-sub __isns_deregister_domain { +- +- local($client_config, @extra_args) = @_; +- my @args; +- +- push(@args, "--local --dd-deregister"); +- push(@args, @extra_args) if (@extra_args); +- +- &run_client($client_config, @args); +-} +- +-sub isns_deregister_domain { +- +- local($client, @args) = @_; +- my $server; +- +- &isns_stage("dd-deregistration", "Deregistering DD (members)" . join(' ', @args)); +- &__isns_deregister_domain($client, @args); +- +- $server = $__isns_data{$client,"server_config"}; +- &isns_verify_db($server); +-} +- +-sub isns_external_test { +- +- local($client, @args) = @_; +- my $logfile; +- my $stage; +- my $cmd; +- +- $logfile = &get_logfile($client); +- +- $cmd = shift(@args); +- $stage = $cmd; +- $stage =~ s:.*/::o; +- +- $cmd = "${__isns_bin}/$cmd -c $client " . join(' ', @args); +- +- &isns_stage($stage, "Running external $cmd " . join(' ', @args)); +- unless (&run_command("$cmd >$logfile")) { +- return undef; +- } +- +- $server = $__isns_data{$client,"server_config"}; +- &isns_verify_db($server); +-} +- +-sub __isns_prep_test { +- +- local($name, $duration, @ARGV) = @_; +- +- GetOptions('verbose+' => \$__isns_verbose, +- "quiet" => \$__isns_quiet, +- "fast" => \$__isns_quick, +- "insecure" => \$__isns_insecure); +- $__isns_verbose = 0 if ($__isns_quiet); +- $__isns_security = 0 if ($__isns_insecure); +- +- if ($__isns_quick && $duration > 15) { +- print "*** Skipping $name (duration ~ $duration seconds) ***\n"; +- exit(0); +- } +- +- print "*** Starting $name ***\n"; +- printf "*** This test case will take about %u sec ***\n", $duration +- if ($duration); +- $__isns_test_name = $name; +- $__isns_test_dir = "$__isns_test_base/$name"; +- $__isns_test_dump = "$__isns_test_dir/dump"; +- $__isns_test_data = "data/$name"; +- +- # Be careful when removing test dir +- system "rm -rf $__isns_test_dir" if ($__isns_test_dir =~ m:/tmp/:o); +- +- mkdir $__isns_test_base, 0700; +- mkdir $__isns_test_dir, 0700; +- mkdir $__isns_test_dump, 0700; +-} +- +-sub test_prep { +- +- local($name, @args) = @_; +- +- __isns_prep_test($name, 0, @args); +-} +- +-sub isns_prep_slow_test { +- +- __isns_prep_test(@_); +-} +- +-# Sleep for a few seconds, giving the user some dots to keep +-# him occupied. +-sub isns_idle { +- +- local($time) = @_; +- +- if ($__isns_verbose == 0) { +- sleep $time; +- return; +- } +- +- $| = 1; +- print "Snooze"; +- while ($time--) { +- print "."; +- sleep 1; +- } +- print "\n"; +- $| = 0; +-} +- +-sub main { +- +- my $server_config; +- my $client_config; +- +- &test_prep; +- +- $server_config = &create_server; +- $client_config = &create_client($server_config); +-} +- +-#&main; +-1; +diff --git a/utils/open-isns/tests/pauw1.c b/utils/open-isns/tests/pauw1.c +deleted file mode 100644 +index c3e66f7..0000000 +--- a/utils/open-isns/tests/pauw1.c ++++ /dev/null +@@ -1,179 +0,0 @@ +-/* +- * Test case, captured from a Wasabi Storage Builder +- * registering itself. +- */ +-#include +-#include +-#include +-#include +-#include +- +-int +-main(int argc, char **argv) +-{ +- const char *opt_configfile = ISNS_DEFAULT_ISNSADM_CONFIG; +- isns_client_t *clnt; +- isns_attr_list_t *attrs; +- isns_simple_t *reg; +- isns_portal_info_t portal_info; +- uint32_t status; +- int c; +- +- while ((c = getopt(argc, argv, "c:d:")) != -1) { +- switch (c) { +- case 'c': +- opt_configfile = optarg; +- break; +- +- case 'd': +- isns_enable_debugging(optarg); +- break; +- +- default: +- isns_fatal("Unknown option\n"); +- } +- } +- +- isns_read_config(opt_configfile); +- isns_assign_string(&isns_config.ic_source_name, +- "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0"); +- +- clnt = isns_create_default_client(NULL); +- +- reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, +- clnt->ic_source, NULL); +- +- attrs = ®->is_operating_attrs; +- +-#define ADD(type, tag, value) \ +- isns_attr_list_append_##type(attrs, ISNS_TAG_##tag, value) +-#define STR(tag, value) ADD(string, tag, value) +-#define U32(tag, value) ADD(uint32, tag, value) +-#define NIL(tag) isns_attr_list_append_nil(attrs, ISNS_TAG_##tag) +-#define TARGET(name, alias, auth) \ +- STR(ISCSI_NAME, name); \ +- U32(ISCSI_NODE_TYPE, ISNS_ISCSI_TARGET_MASK); \ +- STR(ISCSI_ALIAS, alias); \ +- STR(ISCSI_AUTHMETHOD, auth) +- +- STR(ENTITY_IDENTIFIER, "cyan.pauw.homeunix.net"); +- U32(ENTITY_PROTOCOL, 2); +- U32(REGISTRATION_PERIOD, 31536000); +- +- TARGET("iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0", +- "Test (10 GB)", +- "None"); +- TARGET("iqn.2000-05.com.wasabisystems.storagebuilder:cyan-1", +- "160 GB disk (ntfs)", +- "None"); +- TARGET("iqn.2000-05.com.wasabisystems.storagebuilder:cyan-2", +- "160 GB disk (ext3)", +- "CHAP"); +- TARGET("iqn.2000-05.com.wasabisystems.storagebuilder:cyan-3", +- "Test (1 GB)", +- "None"); +- TARGET("iqn.2000-05.com.wasabisystems.storagebuilder:cyan-4", +- "Test (40 GB)", +- "CHAP"); +- TARGET("iqn.2000-05.com.wasabisystems.storagebuilder:cyan-5", +- "test", +- "None"); +- +- isns_portal_parse(&portal_info, "10.0.0.1:3260/tcp", NULL); +- isns_portal_to_attr_list(&portal_info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- attrs); +- +- /* Mumbo jumbo encoding of portal groups */ +- U32(PG_TAG, 1); +- STR(PG_ISCSI_NAME, "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0"); +- STR(PG_ISCSI_NAME, "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-1"); +- STR(PG_ISCSI_NAME, "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-2"); +- STR(PG_ISCSI_NAME, "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-3"); +- STR(PG_ISCSI_NAME, "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-4"); +- STR(PG_ISCSI_NAME, "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-5"); +- +- /* Strictly speaking, a PGT not followed by any data is invalid. +- * +- * 5.6.5.1. +- * When a Portal is registered, the Portal attributes MAY +- * immediately be followed by a PGT attribute. The PGT attribute +- * SHALL be followed by the set of PG iSCSI Names representing +- * nodes that will be associated to the Portal using the indicated +- * PGT value. +- */ +- NIL(PG_TAG); +- +- isns_simple_print(reg, isns_print_stdout); +- +- status = isns_client_call(clnt, ®); +- +- if (status != ISNS_SUCCESS) +- isns_fatal("Unable to register object: %s\n", +- isns_strerror(status)); +- +- printf("Successfully registered object(s)\n"); +- isns_simple_print(reg, isns_print_stdout); +- +- return 0; +-} +- +-/* +- Creating file DB backend (/var/lib/isns) +- DB: loading all objects from /var/lib/isns +- Next ESI message in 3600 seconds +- Incoming PDU xid=0001 seq=0 len=1208 func=DevAttrReg client first last +- Next message xid=0001 +- Received message +- ---DevAttrReg--- +- Source: +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0" +- Message attributes: +- Operating attributes: +- 0001 string : Entity identifier = "cyan.pauw.homeunix.net" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0006 uint32 : Registration Period = 31536000 +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0" +- 0021 uint32 : iSCSI node type = Target +- 0022 string : iSCSI alias = "Test (10 GB)" +- 002a string : iSCSI auth method = "None" +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-1" +- 0021 uint32 : iSCSI node type = Target +- 0022 string : iSCSI alias = "160 GB disk (ntfs)" +- 002a string : iSCSI auth method = "None" +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-2" +- 0021 uint32 : iSCSI node type = Target +- 0022 string : iSCSI alias = "160 GB disk (ext3)" +- 002a string : iSCSI auth method = "CHAP" +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-3" +- 0021 uint32 : iSCSI node type = Target +- 0022 string : iSCSI alias = "Test (1 GB)" +- 002a string : iSCSI auth method = "None" +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-4" +- 0021 uint32 : iSCSI node type = Target +- 0022 string : iSCSI alias = "Test (40 GB)" +- 002a string : iSCSI auth method = "CHAP" +- 0020 string : iSCSI name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-5" +- 0021 uint32 : iSCSI node type = Target +- 0022 string : iSCSI alias = "test" +- 002a string : iSCSI auth method = "None" +- 0010 ipaddr : Portal IP address = 10.0.0.1 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0033 uint32 : Portal group tag = 1 +- 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0" +- 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-1" +- 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-2" +- 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-3" +- 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-4" +- 0030 string : Portal group name = "iqn.2000-05.com.wasabisystems.storagebuilder:cyan-5" +- 0033 nil : Portal group tag = +- :: policy insecure function DevAttrReg (0001) permitted +- :: policy insecure source +-iqn.2000-05.com.wasabisystems.storagebuilder:cyan-0 permitted +- :: policy insecure operation DevAttrReg on Network Entity object +-permitted +- DB: Storing object 00000001 -> /var/lib/isns/00000001 +- DB: added object 1 (Network Entity) state 1 +-Segmentation fault +- */ +diff --git a/utils/open-isns/tests/pauw2.c b/utils/open-isns/tests/pauw2.c +deleted file mode 100644 +index 29084b3..0000000 +--- a/utils/open-isns/tests/pauw2.c ++++ /dev/null +@@ -1,212 +0,0 @@ +-/* +- * Test case, captured from iscsi-target +- * registering itself. +- */ +-#include +-#include +-#include +-#include +-#include +- +-#define ADD(type, tag, value) \ +- isns_attr_list_append_##type(attrs, ISNS_TAG_##tag, value) +-#define STR(tag, value) ADD(string, tag, value) +-#define U32(tag, value) ADD(uint32, tag, value) +-#define NIL(tag) isns_attr_list_append_nil(attrs, ISNS_TAG_##tag) +-#define TARGET(name, alias, auth) \ +- STR(ISCSI_NAME, name); \ +- U32(ISCSI_NODE_TYPE, ISNS_ISCSI_TARGET_MASK); \ +- STR(ISCSI_ALIAS, alias); \ +- STR(ISCSI_AUTHMETHOD, auth) +- +-int +-main(int argc, char **argv) +-{ +- const char *opt_configfile = ISNS_DEFAULT_ISNSADM_CONFIG; +- isns_client_t *clnt; +- isns_attr_list_t *attrs; +- isns_simple_t *reg; +- isns_portal_info_t portal_info; +- uint32_t status; +- int c; +- +- while ((c = getopt(argc, argv, "c:d:")) != -1) { +- switch (c) { +- case 'c': +- opt_configfile = optarg; +- break; +- +- case 'd': +- isns_enable_debugging(optarg); +- break; +- +- default: +- isns_fatal("Unknown option\n"); +- } +- } +- +- isns_read_config(opt_configfile); +- +- /* +- ---DevAttrReg[REPLACE]--- +- Source: +- 0020 string : iSCSI name = "iqn.2007-03.com.example:stgt.disk" +- Message attributes: +- 0001 string : Entity identifier = "blue.pauw.homeunix.net" +- Operating attributes: +- 0001 string : Entity identifier = "blue.pauw.homeunix.net" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0010 ipaddr : Portal IP address = 192.168.1.2 +- 0011 uint32 : Portal TCP/UDP port = 3260/tcp +- 0017 uint32 : SCN port = 42138/tcp +- 0020 string : iSCSI name = "iqn.2007-03.com.example:stgt.disk" +- 0021 uint32 : iSCSI node type = Target +- */ +- isns_assign_string(&isns_config.ic_source_name, +- "iqn.2007-03.com.example:stgt.disk"); +- +- clnt = isns_create_default_client(NULL); +- reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, +- clnt->ic_source, NULL); +- reg->is_replace = 1; +- +- /* Message attributes */ +- attrs = ®->is_message_attrs; +- STR(ENTITY_IDENTIFIER, "blue.pauw.homeunix.net"); +- +- /* Operating attributes */ +- attrs = ®->is_operating_attrs; +- +- STR(ENTITY_IDENTIFIER, "blue.pauw.homeunix.net"); +- U32(ENTITY_PROTOCOL, 2); +- +- isns_portal_parse(&portal_info, "192.168.1.2:3260/tcp", NULL); +- isns_portal_to_attr_list(&portal_info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- attrs); +- +- U32(SCN_PORT, 42138); +- STR(ISCSI_NAME, "iqn.2007-03.com.example:stgt.disk"); +- U32(ISCSI_NODE_TYPE, ISNS_ISCSI_TARGET_MASK); +- isns_simple_print(reg, isns_print_stdout); +- +- status = isns_client_call(clnt, ®); +- +- if (status != ISNS_SUCCESS) +- isns_fatal("Unable to register object: %s\n", +- isns_strerror(status)); +- +- printf("Successfully registered object #1\n"); +- // isns_simple_print(reg, isns_print_stdout); +- isns_simple_free(reg); +- isns_client_destroy(clnt); +- +- /* +- ---DevAttrReg[REPLACE]--- +- Source: +- 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" +- Message attributes: +- 0001 string : Entity identifier = "blue.pauw.homeunix.net" +- Operating attributes: +- 0001 string : Entity identifier = "blue.pauw.homeunix.net" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0010 ipaddr : Portal IP address = 192.168.1.2 +- 0011 uint32 : Portal TCP/UDP port = 33849/tcp +- 0014 uint32 : ESI port = 56288/tcp +- 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" +- 0021 uint32 : iSCSI node type = Initiator +- 0022 string : iSCSI alias = "blue.pauw.homeunix.net" +- +- [...] +- response status 0x0003 (Invalid registration) +- +- This would fail because we got confused about EID in +- the replace case. +- */ +- isns_assign_string(&isns_config.ic_source_name, +- "iqn.2005-03.org.open-iscsi:blue"); +- +- clnt = isns_create_default_client(NULL); +- reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, +- clnt->ic_source, NULL); +- reg->is_replace = 1; +- +- /* Message attributes */ +- attrs = ®->is_message_attrs; +- STR(ENTITY_IDENTIFIER, "blue.pauw.homeunix.net"); +- +- /* Operating attributes */ +- attrs = ®->is_operating_attrs; +- +- STR(ENTITY_IDENTIFIER, "blue.pauw.homeunix.net"); +- U32(ENTITY_PROTOCOL, 2); +- +- isns_portal_parse(&portal_info, "192.168.1.2:33849/tcp", NULL); +- isns_portal_to_attr_list(&portal_info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- attrs); +- +- U32(ESI_PORT, 56288); +- STR(ISCSI_NAME, "iqn.2005-03.org.open-iscsi:blue"); +- U32(ISCSI_NODE_TYPE, ISNS_ISCSI_INITIATOR_MASK); +- STR(ISCSI_ALIAS, "blue.pauw.homeunix.net"); +- isns_simple_print(reg, isns_print_stdout); +- +- status = isns_client_call(clnt, ®); +- +- if (status != ISNS_SUCCESS) +- isns_fatal("Unable to register object: %s\n", +- isns_strerror(status)); +- +- printf("Successfully registered object #2\n"); +- // isns_simple_print(reg, isns_print_stdout); +- isns_simple_free(reg); +- isns_client_destroy(clnt); +- +- return 0; +-} +- +-/* +- Creating file DB backend (/var/lib/isns) +- DB: loading all objects from /var/lib/isns +- Next ESI message in 3600 seconds +- Incoming PDU xid=0001 seq=0 len=232 func=DevAttrReg client first last +- Next message xid=0001 +- Received message +- +- :: policy insecure function DevAttrReg (0001) permitted +- :: policy insecure source iqn.2005-03.org.open-iscsi:blue permitted +- :: policy insecure operation DevAttrReg on object 00000001 (Network +-Entity) permitted +- Replacing Network Entity (id 1) +- DB: removed object 2 (Portal) +- DB: removed object 4 (iSCSI Portal Group) +- DB: removed object 3 (iSCSI Storage Node) +- DB: removed object 1 (Network Entity) +- DB: destroying object 2 (Portal) +- DB: Purging object 2 (/var/lib/isns/00000002) +- DB: destroying object 1 (Network Entity) +- DB: Purging object 1 (/var/lib/isns/00000001) +- DB: destroying object 3 (iSCSI Storage Node) +- DB: Purging object 3 (/var/lib/isns/00000003) +- DB: destroying object 4 (iSCSI Portal Group) +- DB: Purging object 4 (/var/lib/isns/00000004) +- :: policy insecure entity ID blue.pauw.homeunix.net permitted +- :: policy insecure operation DevAttrReg on Network Entity object +-permitted +- DB: Storing object 5 -> /var/lib/isns/00000005 +- DB: added object 5 (Network Entity) state 1 +- DB: Storing object 5 -> /var/lib/isns/00000005 +- isns_esi_callback(0x9dee788, 0x10) +- Deleting SCN registration for iqn.2007-03.com.example:stgt.disk +- isns_esi_callback(0x9deeae0, 0x10) +- isns_esi_callback(0x9deea30, 0x10) +- isns_esi_callback(0x9deec80, 0x10) +- SCN multicast +- isns_scn_callback(0x9deec80, 0x10) +- isns_esi_callback(0x9def4b0, 0xc) +- Enable ESI monitoring for entity 5 +- +- */ +diff --git a/utils/open-isns/tests/pauw3.c b/utils/open-isns/tests/pauw3.c +deleted file mode 100644 +index 3be0baa..0000000 +--- a/utils/open-isns/tests/pauw3.c ++++ /dev/null +@@ -1,139 +0,0 @@ +-/* +- * This tests another problem reported by Albert, where a +- * re-registration shortly before ESI expiry would fail +- * to resurrect the registration properly. +- * +- * Usage: +- * pauw3 [options] timeout +- * +- * Where timeout is the delay until we try to re-register +- */ +- +-#include +-#include +- +-#include +-#include +-#include +-#include +- +-#define ADD(type, tag, value) \ +- isns_attr_list_append_##type(attrs, ISNS_TAG_##tag, value) +-#define STR(tag, value) ADD(string, tag, value) +-#define U32(tag, value) ADD(uint32, tag, value) +-#define NIL(tag) isns_attr_list_append_nil(attrs, ISNS_TAG_##tag) +-#define TARGET(name, alias, auth) \ +- STR(ISCSI_NAME, name); \ +- U32(ISCSI_NODE_TYPE, ISNS_ISCSI_TARGET_MASK); \ +- STR(ISCSI_ALIAS, alias); \ +- STR(ISCSI_AUTHMETHOD, auth) +- +-int +-main(int argc, char **argv) +-{ +- const char *opt_configfile = ISNS_DEFAULT_ISNSADM_CONFIG; +- isns_client_t *clnt; +- isns_attr_list_t *attrs; +- isns_simple_t *reg; +- isns_portal_info_t portal_info; +- uint32_t status; +- int opt_replace = 1; +- int c, n, timeout; +- +- while ((c = getopt(argc, argv, "c:d:n")) != -1) { +- switch (c) { +- case 'c': +- opt_configfile = optarg; +- break; +- +- case 'd': +- isns_enable_debugging(optarg); +- break; +- +- case 'n': +- opt_replace = 0; +- break; +- +- default: +- isns_fatal("Unknown option\n"); +- } +- } +- +- if (optind != argc - 1) +- isns_fatal("Need timeout argument\n"); +- timeout = parse_timeout(argv[optind]); +- +- isns_read_config(opt_configfile); +- +- /* +- ---DevAttrReg[REPLACE]--- +- Source: +- 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" +- Message attributes: +- 0001 string : Entity identifier = "blue.pauw.homeunix.net" +- Operating attributes: +- 0001 string : Entity identifier = "blue.pauw.homeunix.net" +- 0002 uint32 : Entity protocol = iSCSI (2) +- 0010 ipaddr : Portal IP address = 192.168.1.2 +- 0011 uint32 : Portal TCP/UDP port = 33849/tcp +- 0014 uint32 : ESI port = 56288/tcp +- 0020 string : iSCSI name = "iqn.2005-03.org.open-iscsi:blue" +- 0021 uint32 : iSCSI node type = Initiator +- 0022 string : iSCSI alias = "blue.pauw.homeunix.net" +- +- [...] +- response status 0x0003 (Invalid registration) +- +- This would fail because we got confused about EID in +- the replace case. +- */ +- isns_assign_string(&isns_config.ic_source_name, +- "iqn.2005-03.org.open-iscsi:blue"); +- +- for (n = 0; n < 2; ++n) { +- clnt = isns_create_default_client(NULL); +- reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, +- clnt->ic_source, NULL); +- reg->is_replace = opt_replace; +- +- /* Message attributes */ +- attrs = ®->is_message_attrs; +- STR(ENTITY_IDENTIFIER, "blue.pauw.homeunix.net"); +- +- /* Operating attributes */ +- attrs = ®->is_operating_attrs; +- +- STR(ENTITY_IDENTIFIER, "blue.pauw.homeunix.net"); +- U32(ENTITY_PROTOCOL, 2); +- +- isns_portal_parse(&portal_info, "192.168.1.2:33849/tcp", NULL); +- isns_portal_to_attr_list(&portal_info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- attrs); +- +- U32(ESI_PORT, 56288); +- STR(ISCSI_NAME, "iqn.2005-03.org.open-iscsi:blue"); +- U32(ISCSI_NODE_TYPE, ISNS_ISCSI_INITIATOR_MASK); +- STR(ISCSI_ALIAS, "blue.pauw.homeunix.net"); +- isns_simple_print(reg, isns_print_stdout); +- +- status = isns_client_call(clnt, ®); +- +- if (status != ISNS_SUCCESS) +- isns_fatal("Unable to register object: %s\n", +- isns_strerror(status)); +- +- printf("Successfully registered object\n"); +- // isns_simple_print(reg, isns_print_stdout); +- isns_simple_free(reg); +- isns_client_destroy(clnt); +- +- if (n == 0) { +- printf("Sleeping for %d seconds\n", timeout); +- sleep(timeout); +- } +- } +- +- return 0; +-} +diff --git a/utils/open-isns/tests/pauw4.c b/utils/open-isns/tests/pauw4.c +deleted file mode 100644 +index 9510ddd..0000000 +--- a/utils/open-isns/tests/pauw4.c ++++ /dev/null +@@ -1,137 +0,0 @@ +-/* +- * Test MS initiator registration. +- * The oddity about this is that the PG object precedes the +- * initiator object in the message. +- */ +- +-#include +-#include +- +-#include +-#include +-#include +-#include +- +-#define ADD(type, tag, value) \ +- isns_attr_list_append_##type(attrs, ISNS_TAG_##tag, value) +-#define STR(tag, value) ADD(string, tag, value) +-#define U32(tag, value) ADD(uint32, tag, value) +-#define NIL(tag) isns_attr_list_append_nil(attrs, ISNS_TAG_##tag) +-#define TARGET(name, alias, auth) \ +- STR(ISCSI_NAME, name); \ +- U32(ISCSI_NODE_TYPE, ISNS_ISCSI_TARGET_MASK); \ +- STR(ISCSI_ALIAS, alias); \ +- STR(ISCSI_AUTHMETHOD, auth) +- +-int +-main(int argc, char **argv) +-{ +- const char *opt_configfile = ISNS_DEFAULT_ISNSADM_CONFIG; +- isns_client_t *clnt; +- isns_attr_list_t *attrs; +- isns_simple_t *reg; +- isns_portal_info_t portal_info; +- uint32_t status; +- int opt_replace = 1; +- int c; +- +- while ((c = getopt(argc, argv, "c:d:n")) != -1) { +- switch (c) { +- case 'c': +- opt_configfile = optarg; +- break; +- +- case 'd': +- isns_enable_debugging(optarg); +- break; +- +- case 'n': +- opt_replace = 0; +- break; +- +- default: +- isns_fatal("Unknown option\n"); +- } +- } +- +- isns_read_config(opt_configfile); +- +- isns_assign_string(&isns_config.ic_source_name, +- "iqn.1991-05.com.microsoft:orange"); +- +- clnt = isns_create_default_client(NULL); +- +- reg = isns_simple_create(ISNS_SCN_DEREGISTER, clnt->ic_source, NULL); +- +- /* Message attributes */ +- attrs = ®->is_message_attrs; +- STR(ISCSI_NAME, "iqn.1991-05.com.microsoft:orange"); +- +- status = isns_client_call(clnt, ®); +- if (status != ISNS_SUCCESS) +- isns_error("SCNDereg failed: %s\n", isns_strerror(status)); +- isns_simple_free(reg); +- +- +- reg = isns_simple_create(ISNS_DEVICE_DEREGISTER, clnt->ic_source, NULL); +- +- attrs = ®->is_operating_attrs; +- STR(ENTITY_IDENTIFIER, "troopa.nki.nl"); +- U32(ENTITY_PROTOCOL, 2); +- +- isns_portal_parse(&portal_info, "192.168.1.40:3229/tcp", NULL); +- isns_portal_to_attr_list(&portal_info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- attrs); +- +- STR(ISCSI_NAME, "iqn.1991-05.com.microsoft:orange"); +- +- status = isns_client_call(clnt, ®); +- if (status != ISNS_SUCCESS) +- isns_fatal("DevDereg failed: %s\n", isns_strerror(status)); +- isns_simple_free(reg); +- +- reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, clnt->ic_source, NULL); +- reg->is_replace = opt_replace; +- +- attrs = ®->is_operating_attrs; +- STR(ENTITY_IDENTIFIER, "troopa.nki.nl"); +- U32(ENTITY_PROTOCOL, 2); +- +- isns_portal_parse(&portal_info, "192.168.1.40:3229/tcp", NULL); +- isns_portal_to_attr_list(&portal_info, +- ISNS_TAG_PORTAL_IP_ADDRESS, +- ISNS_TAG_PORTAL_TCP_UDP_PORT, +- attrs); +- +- U32(SCN_PORT, 3230); +- U32(ESI_PORT, 3230); +- +- U32(PG_TAG, 1); +- STR(PG_ISCSI_NAME, "iqn.1991-05.com.microsoft:orange"); +- +- STR(ISCSI_NAME, "iqn.1991-05.com.microsoft:orange"); +- U32(ISCSI_NODE_TYPE, ISNS_ISCSI_INITIATOR_MASK); +- STR(ISCSI_ALIAS, ""); +- +- status = isns_client_call(clnt, ®); +- if (status != ISNS_SUCCESS) +- isns_fatal("DevAttrReg failed: %s\n", isns_strerror(status)); +- isns_simple_free(reg); +- +- reg = isns_simple_create(ISNS_DEVICE_GET_NEXT, clnt->ic_source, NULL); +- attrs = ®->is_message_attrs; +- NIL(ISCSI_NAME); +- +- attrs = ®->is_operating_attrs; +- U32(ISCSI_NODE_TYPE, ISNS_ISCSI_TARGET_MASK); +- NIL(ISCSI_NODE_TYPE); +- +- status = isns_client_call(clnt, ®); +- if (status != ISNS_SUCCESS) +- isns_fatal("DevGetNext failed: %s\n", isns_strerror(status)); +- isns_simple_free(reg); +- +- return 0; +-} +diff --git a/utils/open-isns/tests/server.conf b/utils/open-isns/tests/server.conf +deleted file mode 100644 +index fc0bb5a..0000000 +--- a/utils/open-isns/tests/server.conf ++++ /dev/null +@@ -1,11 +0,0 @@ +-BindAddress = @SERVER_ADDRESS@ +-SourceName = @SOURCE_NAME@ +-Database = @DB_PATH@ +-RegistrationPeriod = 2h +-ESIMinInterval = 1m +-ESIMinInterval = 5m +-Security = @NOT_SET@ +-AuthKeyFile = @AUTH_KEY@ +-ClientKeyStore = DB: +-PIDFile = @MYDIR@/pid +-ControlSocket = @MYDIR@/control +diff --git a/utils/open-isns/tests/test01.pl b/utils/open-isns/tests/test01.pl +deleted file mode 100644 +index 258acff..0000000 +--- a/utils/open-isns/tests/test01.pl ++++ /dev/null +@@ -1,30 +0,0 @@ +-#!/usr/bin/perl +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This test case validates registration and simple query of +-# single client. +- +-push(@INC, "."); +-require "harness.pl"; +- +-&test_prep("test01", @ARGV); +- +-$server = &create_server; +-$client = &create_client($server); +- +-&isns_start_server($server); +- +-# 1: Enroll the test client +-&isns_enroll_client($client); +- +-# 2: Register an initiator with default portal +-&isns_register_client($client, "initiator portal"); +- +-# 3: Run a simple query +-&isns_query_objects($client, "eid"); +- +-# 99: Unregister client +-&isns_unregister_client("99-unregistration", $client); +- +-&isns_finish; +diff --git a/utils/open-isns/tests/test02.pl b/utils/open-isns/tests/test02.pl +deleted file mode 100644 +index 208bed5..0000000 +--- a/utils/open-isns/tests/test02.pl ++++ /dev/null +@@ -1,58 +0,0 @@ +-#!/usr/bin/perl +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This test case validates registration and simple query of +-# two clients, and simple DD functionality. +- +-push(@INC, "."); +-require "harness.pl"; +- +-&test_prep("test02", @ARGV); +- +-$server = &create_server; +-$client1 = &create_client($server, "127.1.0.1"); +-$client2 = &create_client($server, "127.1.0.2"); +- +-&isns_start_server($server); +- +-# 1: Enroll the client1 +-&isns_enroll_client($client1); +- +-# 2: Enroll the client1 +-&isns_enroll_client($client2, "node-type=target"); +- +-&isns_stage("registration", "Registering both clients"); +-&__isns_register_client($client1, "initiator portal"); +-&__isns_register_client($client2, "target portal"); +-&isns_verify_db($server); +- +-# Now each of the two clients should just see +-# itself +-&isns_query_objects($client1, "eid"); +-&isns_query_objects($client2, "eid"); +- +-# Register a DD linking the two nodes +-&isns_register_domain($client1, "member-name=isns.client1", "member-name=isns.client2"); +- +-# Now the clients should see each other +-&isns_query_objects($client1, "eid"); +-&isns_query_objects($client2, "eid"); +- +-# Initiator querying for target: +-&isns_query_objects($client1, "iscsi-node-type=Target"); +- +-# Add another member to this DD, and re-add client2 (making +-# sure the server doesn't generate dupes) +-&isns_register_domain($client1, "dd-id=1", "member-name=isns.client2", "member-name=iqn.com.foobar:disk1"); +- +-# Query the list of DDs we're a member of +-&isns_query_objects($client1, "dd-id"); +- +-# Remove some entries from the DD +-&isns_deregister_domain($client1, "1", "member-iscsi-idx=10"); +-&isns_deregister_domain($client1, "1", "member-name=iqn.com.foobar:disk1"); +-&isns_register_domain($client1, "dd-id=1", "member-name=isns.client2"); +-&isns_deregister_domain($client1, "1"); +- +-&isns_finish; +diff --git a/utils/open-isns/tests/test03.pl b/utils/open-isns/tests/test03.pl +deleted file mode 100644 +index 3cc0d71..0000000 +--- a/utils/open-isns/tests/test03.pl ++++ /dev/null +@@ -1,27 +0,0 @@ +-#!/usr/bin/perl +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This test case validates registration and unregistration. +- +-push(@INC, "."); +-require "harness.pl"; +- +-&test_prep("test03", @ARGV); +- +-$server = &create_server; +-$client = &create_client($server); +- +-&isns_start_server($server); +- +-&isns_enroll_client($client); +-&isns_register_client($client, "initiator portal"); +- +-# Unregistering the portal should leave the iscsi node and +-# portal group active, and move the portal to state limbo. +-&isns_unregister_client($client, "portal=127.0.0.1:860"); +- +-# As the iscsi node goes away, so should the whole entity +-&isns_unregister_client($client, "iscsi-name=isns.client1"); +- +-&isns_finish; +diff --git a/utils/open-isns/tests/test04.pl b/utils/open-isns/tests/test04.pl +deleted file mode 100644 +index 8181a4e..0000000 +--- a/utils/open-isns/tests/test04.pl ++++ /dev/null +@@ -1,30 +0,0 @@ +-#!/usr/bin/perl +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This test case verifies that the database remains intact +-# across server restarts. +- +-push(@INC, "."); +-require "harness.pl"; +- +-&test_prep("test04", @ARGV); +- +-$server = &create_server; +-$client = &create_client($server); +- +-&isns_start_server($server); +- +-&isns_enroll_client($client); +-&isns_register_client($client, "initiator portal"); +- +-# Restart the server, and make sure it still displays +-# the database properly +-&isns_stage("restart", "Restarting server process"); +-&isns_restart_server($server); +-&isns_verify_db($server); +- +-# Run a simple query +-&isns_query_objects($client, "iscsi-name"); +- +-&isns_finish; +diff --git a/utils/open-isns/tests/test05.pl b/utils/open-isns/tests/test05.pl +deleted file mode 100644 +index 694d7c3..0000000 +--- a/utils/open-isns/tests/test05.pl ++++ /dev/null +@@ -1,25 +0,0 @@ +-#!/usr/bin/perl +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This test case verifies entity expiry +- +-push(@INC, "."); +-require "harness.pl"; +- +-&isns_prep_slow_test("test05", 30, @ARGV); +- +-$server = &create_server({ "RegistrationPeriod" => "20s" }); +-$client = &create_client($server); +- +-&isns_start_server($server); +- +-&isns_enroll_client($client); +-&isns_register_client($client, "initiator portal"); +- +-&isns_stage("expired", "Waiting for registration period to expire (25s)"); +-&isns_idle(25); +-&isns_verify_db($server); +- +-&isns_finish; +- +diff --git a/utils/open-isns/tests/test06.pl b/utils/open-isns/tests/test06.pl +deleted file mode 100644 +index 6b6aa05..0000000 +--- a/utils/open-isns/tests/test06.pl ++++ /dev/null +@@ -1,50 +0,0 @@ +-#!/usr/bin/perl +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This test case validates DevAttrReg replace mode. +- +-push(@INC, "."); +-require "harness.pl"; +- +-&test_prep("test06", @ARGV); +- +-$server = &create_server; +-$client = &create_client($server); +- +-&isns_start_server($server); +- +-# 1: Enroll the client +-&isns_enroll_client($client); +- +-# 2: Register a simple initiator with one portal +-&isns_register_client($client, "initiator portal"); +- +-$eid = &isns_query_eid($client); +-unless ($eid) { +- &isns_die("Cannot obtain entity ID"); +-} +- +-# Now replace the portal with different values +-&isns_register_client($client, "--replace entity=$eid initiator portal=192.168.1.1:iscsi"); +-&isns_register_client($client, "--replace entity=$eid initiator portal=192.168.1.2:iscsi"); +- +-&isns_register_domain($client, "member-name=isns.client1"); +- +-# Replace our registration once more. Now the object index of the +-# initiator should not change, since it's a domain member now. +-&isns_register_client($client, "--replace entity=$eid initiator portal=192.168.1.1:iscsi"); +- +-# Make the portal a domain member too. Now even the portal index should stay +-# the same. Note that we do not replace the whole entity now, but just the +-# portal +-&isns_register_domain($client, "dd-id=1 member-addr=192.168.1.1 member-port=860"); +-&isns_register_client($client, "--replace --key portal=192.168.1.1:iscsi portal=192.168.1.2:iscsi"); +-&isns_register_client($client, "--replace --key portal=192.168.1.2:iscsi portal=192.168.1.1:iscsi"); +- +-# Now unregister the whole client, and re-register. +-# Portal and client index should remain the same +-&isns_unregister_client($client, "eid=$eid"); +-&isns_register_client($client, "initiator portal=192.168.1.1:iscsi"); +- +-&isns_finish; +diff --git a/utils/open-isns/tests/test07.pl b/utils/open-isns/tests/test07.pl +deleted file mode 100644 +index c13df11..0000000 +--- a/utils/open-isns/tests/test07.pl ++++ /dev/null +@@ -1,37 +0,0 @@ +-#!/usr/bin/perl +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This test case validates that the server discards portals +-# that do not respond to ESI messages +- +-push(@INC, "."); +-require "harness.pl"; +- +-&isns_prep_slow_test("test07", 30, @ARGV); +- +-$server = &create_server({ "ESIMinInterval" => "5s" }); +-$client = &create_client($server); +- +-&isns_start_server($server); +- +-# 1: Enroll the client +-&isns_enroll_client($client); +- +-# 2: Register a simple initiator with one portal +-&isns_register_client($client, "initiator portal,esi-port=65535,esi-interval=5"); +- +-&isns_stage("expired", "Waiting for ESI to expire (~15 sec)"); +-&isns_idle(15); +-&isns_verify_db($server); +- +-# 3: Register a simple initiator with two portals, one with ESI and one without. +-# When the ESI monitored portal expires, this should still take down +-# the whole network entity. +-&isns_register_client($client, "initiator portal,esi-port=65535,esi-interval=5 portal=127.0.0.1:1"); +- +-&isns_stage("expired", "Waiting for ESI to expire (~15 sec)"); +-&isns_idle(15); +-&isns_verify_db($server); +- +-&isns_finish; +diff --git a/utils/open-isns/tests/test08.pl b/utils/open-isns/tests/test08.pl +deleted file mode 100644 +index 1487532..0000000 +--- a/utils/open-isns/tests/test08.pl ++++ /dev/null +@@ -1,23 +0,0 @@ +-#!/usr/bin/perl +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This test case validates registration and simple query of +-# single client. +- +-push(@INC, "."); +-require "harness.pl"; +- +-# For now, this one will run w/o security only +-push(@ARGV, '-i'); +- +-&test_prep("test08", @ARGV); +- +-$server = &create_server; +-$client = &create_client($server); +- +-&isns_start_server($server); +- +-&isns_external_test($client, "tests/pauw1"); +- +-&isns_finish; +diff --git a/utils/open-isns/tests/test09.pl b/utils/open-isns/tests/test09.pl +deleted file mode 100644 +index bd2bd7f..0000000 +--- a/utils/open-isns/tests/test09.pl ++++ /dev/null +@@ -1,23 +0,0 @@ +-#!/usr/bin/perl +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This test case validates registration and simple query of +-# single client. +- +-push(@INC, "."); +-require "harness.pl"; +- +-# For now, this one will run w/o security only +-push(@ARGV, '-i'); +- +-&test_prep("test09", @ARGV); +- +-$server = &create_server; +-$client = &create_client($server); +- +-&isns_start_server($server); +- +-&isns_external_test($client, "tests/pauw2"); +- +-&isns_finish; +diff --git a/utils/open-isns/tests/test10.pl b/utils/open-isns/tests/test10.pl +deleted file mode 100644 +index 7286521..0000000 +--- a/utils/open-isns/tests/test10.pl ++++ /dev/null +@@ -1,33 +0,0 @@ +-#!/usr/bin/perl +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This test case validates registration and simple query of +-# single client. +- +-push(@INC, "."); +-require "harness.pl"; +- +-# For now, this one will run w/o security only +-push(@ARGV, '-i'); +- +-&isns_prep_slow_test("test10", 20, @ARGV); +- +-$server = &create_server({ "ESIMinInterval" => "10s" }); +-$client = &create_client($server); +- +-&isns_start_server($server); +- +-&isns_external_test($client, "tests/pauw3", "16"); +- +-&isns_stage("expired", "Waiting for ESI to come around"); +-&isns_idle(5); +-&isns_verify_db($server); +- +-&isns_external_test($client, "tests/pauw3", "-n", "16"); +- +-&isns_stage("expired", "Waiting for ESI to come around"); +-&isns_idle(5); +-&isns_verify_db($server); +- +-&isns_finish; +diff --git a/utils/open-isns/tests/test11.pl b/utils/open-isns/tests/test11.pl +deleted file mode 100644 +index 2745955..0000000 +--- a/utils/open-isns/tests/test11.pl ++++ /dev/null +@@ -1,23 +0,0 @@ +-#!/usr/bin/perl +-# +-# Copyright (C) 2007 Olaf Kirch +-# +-# This test case validates registration and simple query of +-# single client. +- +-push(@INC, "."); +-require "harness.pl"; +- +-# For now, this one will run w/o security only +-push(@ARGV, '-i'); +- +-&test_prep("test11", @ARGV); +- +-$server = &create_server; +-$client = &create_client($server); +- +-&isns_start_server($server); +- +-&isns_external_test($client, "tests/pauw4"); +- +-&isns_finish; +diff --git a/utils/open-isns/timer.c b/utils/open-isns/timer.c +deleted file mode 100644 +index ed8a23f..0000000 +--- a/utils/open-isns/timer.c ++++ /dev/null +@@ -1,126 +0,0 @@ +-/* +- * Timers (one-short and periodic) +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include "isns.h" +-#include "util.h" +- +-typedef struct isns_timer isns_timer_t; +-struct isns_timer { +- isns_list_t it_list; +- time_t it_when; +- unsigned int it_period; +- isns_timer_callback_t * it_func; +- void * it_data; +-}; +- +- +-static ISNS_LIST_DECLARE(timers); +- +-static void +-__isns_arm_timer(isns_timer_t *tm) +-{ +- isns_list_t *pos, *next; +- time_t when = tm->it_when; +- +- isns_list_foreach(&timers, pos, next) { +- isns_timer_t *cur = isns_list_item(isns_timer_t, it_list, pos); +- +- if (when < cur->it_when) +- break; +- } +- isns_item_insert_before(pos, &tm->it_list); +-} +- +-static isns_timer_t * +-__isns_create_timer(time_t when, +- unsigned int period, +- isns_timer_callback_t *fn, +- void *data) +-{ +- isns_timer_t *tm; +- +- tm = isns_calloc(1, sizeof(*tm)); +- tm->it_when = when; +- tm->it_period = period; +- tm->it_func = fn; +- tm->it_data = data; +- return tm; +-} +- +-void +-isns_add_timer(unsigned int period, +- isns_timer_callback_t *fn, +- void *data) +-{ +- isns_timer_t *tm; +- +- isns_assert(period); +- tm = __isns_create_timer(time(NULL) + period, period, fn, data); +- __isns_arm_timer(tm); +-} +- +-void +-isns_add_oneshot_timer(unsigned int expires, +- isns_timer_callback_t *fn, +- void *data) +-{ +- isns_timer_t *tm; +- +- tm = __isns_create_timer(time(NULL) + expires, 0, fn, data); +- __isns_arm_timer(tm); +-} +- +-void +-isns_cancel_timer(isns_timer_callback_t *fn, void *data) +-{ +- isns_list_t *pos, *next; +- +- isns_list_foreach(&timers, pos, next) { +- isns_timer_t *tm = isns_list_item(isns_timer_t, it_list, pos); +- +- if (tm->it_func == fn +- && (data == NULL || tm->it_data == data)) { +- isns_list_del(pos); +- isns_free(tm); +- } +- } +-} +- +-time_t +-isns_run_timers(void) +-{ +- +- while (!isns_list_empty(&timers)) { +- isns_timer_t *tm = isns_list_item(isns_timer_t, it_list, timers.next); +- isns_timer_callback_t *func; +- time_t expire; +- void *data; +- +- expire = tm->it_when; +- if (time(NULL) < expire) +- return expire; +- +- isns_list_del(&tm->it_list); +- func = tm->it_func; +- data = tm->it_data; +- expire = 0; +- +- /* If it's a periodic timer, rearm it now. This allows +- * the timer callback to cancel the timer. */ +- if (tm->it_period) { +- tm->it_when = time(NULL) + tm->it_period; +- __isns_arm_timer(tm); +- } else { +- isns_free(tm); +- } +- +- func(data); +- } +- +- return 0; +-} +diff --git a/utils/open-isns/types.h b/utils/open-isns/types.h +deleted file mode 100644 +index ddd153f..0000000 +--- a/utils/open-isns/types.h ++++ /dev/null +@@ -1,57 +0,0 @@ +-/* +- * Open-iSNS types +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#ifndef ISNS_TYPES_H +-#define ISNS_TYPES_H +- +-typedef struct isns_simple isns_simple_t; +-typedef struct isns_source isns_source_t; +-typedef struct isns_object isns_object_t; +-typedef struct isns_relation isns_relation_t; +-typedef struct isns_attr isns_attr_t; +-typedef struct isns_attr_list isns_attr_list_t; +-typedef struct isns_message isns_message_t; +-typedef struct isns_socket isns_socket_t; +-typedef struct isns_db isns_db_t; +-typedef struct isns_tag_type isns_tag_type_t; +-typedef const struct isns_object_template isns_object_template_t; +-typedef struct isns_authdata isns_authdata_t; +-typedef struct isns_security isns_security_t; +-typedef struct isns_principal isns_principal_t; +-typedef struct isns_policy isns_policy_t; +-typedef struct isns_keystore isns_keystore_t; +-typedef struct isns_scope isns_scope_t; +-typedef struct isns_portal_info isns_portal_info_t; +-typedef struct isns_server isns_server_t; +-typedef struct isns_db_event isns_db_event_t; +-typedef struct isns_bitvector isns_bitvector_t; +- +-typedef struct isns_object_list { +- unsigned int iol_count; +- isns_object_t ** iol_data; +-} isns_object_list_t; +- +-#define ISNS_OBJECT_LIST_INIT { .iol_count = 0, .iol_data = NULL } +- +-/* +- * An attribute list +- */ +-struct isns_attr_list { +- unsigned int ial_count; +- isns_attr_t ** ial_data; +-}; +-#define ISNS_ATTR_LIST_INIT { .ial_count = 0, .ial_data = NULL } +- +-/* +- * Function types. +- */ +-typedef void isns_print_fn_t(const char *, ...); +-typedef void isns_timer_callback_t(void *); +- +- +-#endif /* ISNS_TYPES_H */ +- +- +diff --git a/utils/open-isns/util.c b/utils/open-isns/util.c +deleted file mode 100644 +index 4c0a7b2..0000000 +--- a/utils/open-isns/util.c ++++ /dev/null +@@ -1,263 +0,0 @@ +-/* +- * util.c +- * +- * Misc utility functions +- * +- * Copyright (C) 2006, 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include "util.h" +- +-unsigned long +-parse_size(const char *arg) +-{ +- unsigned long mult = 1, ret; +- char *s; +- +- ret = strtol(arg, &s, 0); +- +- switch (*s++) { +- case 'g': +- case 'G': +- mult = 1024 * 1024 * 1024; +- break; +- case 'm': +- case 'M': +- mult = 1024 * 1024; +- break; +- case 'k': +- case 'K': +- mult = 1024; +- break; +- +- case '\0': +- return ret; +- +- default: +- bad: +- err(1, "parse_size: unknown unit in \"%s\"\n", arg); +- } +- +- if (*s != '\0') +- goto bad; +- +- return mult * ret; +-} +- +-char * +-print_size(unsigned long size) +-{ +- static char unit[] = "-kMG"; +- static char buffer[64]; +- unsigned int power = 0; +- +- while (size && !(size % 1024) && power < sizeof(unit)) { +- size /= 1024; +- power++; +- } +- +- if (!power) { +- snprintf(buffer, sizeof(buffer), "%lu", size); +- } else { +- snprintf(buffer, sizeof(buffer), "%lu%c", +- size, unit[power]); +- } +- return buffer; +-} +- +-unsigned int +-parse_count(const char *arg) +-{ +- unsigned long ret; +- char *s; +- +- ret = strtoul(arg, &s, 0); +- if (*s != '\0') +- err(1, "parse_count: unexpected character in \"%s\"\n", arg); +- +- return ret; +-} +- +-int +-parse_int(const char *arg) +-{ +- long ret; +- char *s; +- +- ret = strtol(arg, &s, 0); +- if (*s != '\0') +- err(1, "parse_count: unexpected character in \"%s\"\n", arg); +- +- return ret; +-} +- +-long long +-parse_longlong(const char *arg) +-{ +- long long ret; +- char *s; +- +- ret = strtoll(arg, &s, 0); +- if (*s != '\0') +- err(1, "parse_count: unexpected character in \"%s\"\n", arg); +- +- return ret; +-} +- +-double +-parse_double(const char *arg) +-{ +- double ret; +- char *s; +- +- ret = strtod(arg, &s); +- if (*s != '\0') +- err(1, "parse_count: unexpected character in \"%s\"\n", arg); +- +- return ret; +-} +- +-unsigned int +-parse_timeout(const char *arg) +-{ +- unsigned int v, ret = 0; +- char *s; +- +- do { +- v = strtoul(arg, &s, 10); +- switch (*s) { +- case '\0': +- ret += v; +- break; +- case 'd': +- v *= 24; +- case 'h': +- v *= 60; +- case 'm': +- v *= 60; +- case 's': +- ret += v; +- ++s; +- break; +- +- default: +- errx(1, "parse_timeout: unexpected character in \"%s\"\n", +- arg); +- } +- +- arg = s; +- } while (*arg); +- +- return ret; +-} +- +-void +-isns_string_array_append(struct string_array *array, const char *val) +-{ +- if (!(array->count % 32)) { +- array->list = isns_realloc(array->list, +- (array->count + 32) * sizeof(val)); +- } +- array->list[array->count++] = val? isns_strdup(val) : NULL; +-} +- +-void +-isns_string_array_destroy(struct string_array *array) +-{ +- unsigned int i; +- +- for (i = 0; i < array->count; ++i) +- isns_free(array->list[i]); +- isns_free(array->list); +- memset(array, 0, sizeof(*array)); +-} +- +-void +-isns_assign_string(char **var, const char *val) +-{ +- char *s = NULL; +- +- if (val && !(s = isns_strdup(val))) +- errx(1, "out of memory"); +- +- if (*var) +- isns_free(*var); +- *var = s; +-} +- +-/* +- * Recursively create a directory +- */ +-int +-isns_mkdir_recursive(const char *pathname) +-{ +- const char *orig_pathname = pathname; +- char *squirrel[64]; +- char *copy = NULL, *s; +- int ns = 0; +- +- if (!pathname || !strcmp(pathname, ".")) +- return 0; +- while (1) { +- if (mkdir(pathname, 0755) >= 0) { +- if (ns == 0) +- break; +- *squirrel[--ns] = '/'; +- continue; +- } +- +- if (errno == EEXIST) +- goto good; +- if (errno != ENOENT) +- goto bad; +- +- if (copy == NULL) { +- copy = isns_strdup(pathname); +- pathname = copy; +- } +- +- s = strrchr(copy, '/'); +- while (s > copy && s[-1] == '/') +- --s; +- *s = '\0'; +- +- isns_assert(ns < 64); +- squirrel[ns++] = s; +- +- if (s == copy) +- goto bad; +- } +- +-good: if (copy) +- isns_free(copy); +- errno = 0; +- return 0; +- +-bad: if (copy) +- isns_free(copy); +- perror(orig_pathname); +- return -1; +-} +- +-/* +- * This one differs from POSIX dirname; it does not +- * modify its argument +- */ +-const char * +-isns_dirname(const char *pathname) +-{ +- static char buffer[4096]; +- char *s; +- +- strcpy(buffer, pathname); +- if ((s = strrchr(buffer, '/')) != NULL) { +- *s = '\0'; +- return buffer; +- } +- return "."; +-} +diff --git a/utils/open-isns/util.h b/utils/open-isns/util.h +deleted file mode 100644 +index deecb24..0000000 +--- a/utils/open-isns/util.h ++++ /dev/null +@@ -1,289 +0,0 @@ +-/* +- * Utility functions +- * +- * Copyright (C) 2006, 2007 Olaf Kirch +- */ +- +-#ifndef UTIL_H +-#define UTIL_H +- +-#include +-#include +-#include +-#include +-#include +-#include // for strdup +-#include "types.h" +- +-#define array_num_elements(a) (sizeof(a) / sizeof((a)[0])) +- +-const char * isns_dirname(const char *); +-int isns_mkdir_recursive(const char *); +- +-extern const char *parser_separators; +-char * parser_get_next_line(FILE *); +-char * parser_get_next_word(char **); +-char * parser_get_rest_of_line(char **); +-int parser_split_line(char *, unsigned int, char **); +- +-unsigned long parse_size(const char *); +-unsigned int parse_count(const char *); +-int parse_int(const char *); +-long long parse_longlong(const char *); +-double parse_double(const char *); +-unsigned int parse_timeout(const char *); +- +-char * print_size(unsigned long); +- +-/* +- * Very simple and stupid string array. +- */ +-struct string_array { +- unsigned int count; +- char ** list; +-}; +- +-void isns_string_array_append(struct string_array *, const char *); +-void isns_string_array_destroy(struct string_array *); +- +-void isns_assign_string(char **, const char *); +- +-void isns_write_pidfile(const char *); +-void isns_update_pidfile(const char *); +-void isns_remove_pidfile(const char *); +- +-extern void isns_log_background(void); +-extern void isns_assert_failed(const char *, +- const char *, unsigned int); +-extern void isns_fatal(const char *, ...); +-extern void isns_warning(const char *, ...); +-extern void isns_error(const char *, ...); +-extern void isns_notice(const char *, ...); +-extern void isns_debug_general(const char *, ...); +-extern void isns_debug_socket(const char *, ...); +-extern void isns_debug_protocol(const char *, ...); +-extern void isns_debug_message(const char *, ...); +-extern void isns_debug_state(const char *, ...); +-extern void isns_debug_auth(const char *, ...); +-extern void isns_debug_scn(const char *, ...); +-extern void isns_debug_esi(const char *, ...); +-extern void isns_enable_debugging(const char *); +-extern int isns_debug_enabled(int); +- +-enum { +- DBG_GENERAL = 0, +- DBG_SOCKET, +- DBG_PROTOCOL, +- DBG_MESSAGE, +- DBG_STATE, +- DBG_AUTH, +- DBG_SCN, +- DBG_ESI, +-}; +- +-/* +- * There's no htonll yet +- */ +-#ifndef htonll +-# include +-# include +-# if __BYTE_ORDER == __BIG_ENDIAN +-# define htonll(x) (x) +-# define ntohll(x) (x) +-# elif __BYTE_ORDER == __LITTLE_ENDIAN +-# define htonll(x) __bswap_64(x) +-# define ntohll(x) __bswap_64(x) +-# endif +-#endif +- +-/* +- * One of the those eternal staples of C coding: +- */ +-#ifndef MIN +-# define MIN(a, b) ((a) < (b)? (a) : (b)) +-# define MAX(a, b) ((a) > (b)? (a) : (b)) +-#endif +- +-#define DECLARE_BITMAP(name, NBITS) \ +- uint32_t name[(NBITS+31) >> 5] = { 0 } +- +-#define __BIT_INDEX(nr) (nr >> 5) +-#define __BIT_MASK(nr) (1 << (nr & 31)) +- +-static inline void +-set_bit(uint32_t *map, unsigned int nr) +-{ +- map[__BIT_INDEX(nr)] |= __BIT_MASK(nr); +-} +- +-static inline void +-clear_bit(uint32_t *map, unsigned int nr) +-{ +- map[__BIT_INDEX(nr)] &= ~__BIT_MASK(nr); +-} +- +-static inline int +-test_bit(const uint32_t *map, unsigned int nr) +-{ +- return !!(map[__BIT_INDEX(nr)] & __BIT_MASK(nr)); +-} +- +-/* +- * Dynamically sized bit vector +- */ +-extern isns_bitvector_t *isns_bitvector_alloc(void); +-extern void isns_bitvector_init(isns_bitvector_t *); +-extern void isns_bitvector_destroy(isns_bitvector_t *); +-extern void isns_bitvector_free(isns_bitvector_t *); +-extern int isns_bitvector_test_bit(const isns_bitvector_t *, unsigned int); +-extern int isns_bitvector_set_bit(isns_bitvector_t *, unsigned int); +-extern int isns_bitvector_clear_bit(isns_bitvector_t *, unsigned int); +-extern int isns_bitvector_is_empty(const isns_bitvector_t *); +-extern int isns_bitvector_intersect(const isns_bitvector_t *a, +- const isns_bitvector_t *b, +- isns_bitvector_t *result); +-extern void isns_bitvector_print(const isns_bitvector_t *, +- isns_print_fn_t *); +-extern void isns_bitvector_foreach(const isns_bitvector_t *bv, +- int (*cb)(uint32_t, void *), +- void *user_data); +- +-/* +- * List manipulation primites +- */ +-typedef struct isns_list isns_list_t; +-struct isns_list { +- isns_list_t * next; +- isns_list_t * prev; +-}; +- +-#define ISNS_LIST_DECLARE(list) \ +- isns_list_t list = { &list, &list } +- +-static inline void +-isns_list_init(isns_list_t *head) +-{ +- head->next = head->prev = head; +-} +- +-static inline void +-__isns_list_insert(isns_list_t *prev, isns_list_t *item, isns_list_t *next) +-{ +- item->next = next; +- item->prev = prev; +- next->prev = item; +- prev->next = item; +-} +- +-static inline void +-isns_list_append(isns_list_t *head, isns_list_t *item) +-{ +- __isns_list_insert(head->prev, item, head); +-} +- +-static inline void +-isns_list_insert(isns_list_t *head, isns_list_t *item) +-{ +- __isns_list_insert(head, item, head->next); +-} +- +-static inline void +-isns_item_insert_before(isns_list_t *where, isns_list_t *item) +-{ +- __isns_list_insert(where->prev, item, where); +-} +- +-static inline void +-isns_item_insert_after(isns_list_t *where, isns_list_t *item) +-{ +- __isns_list_insert(where, item, where->next); +-} +- +-static inline void +-isns_list_del(isns_list_t *item) +-{ +- isns_list_t *prev = item->prev; +- isns_list_t *next = item->next; +- +- prev->next = next; +- next->prev = prev; +- item->next = item->prev = item; +-} +- +-static inline int +-isns_list_empty(const isns_list_t *head) +-{ +- return head == head->next; +-} +- +-static inline void +-isns_list_move(isns_list_t *dst, isns_list_t *src) +-{ +- isns_list_t *prev, *next; +- isns_list_t *head, *tail; +- +- if (isns_list_empty(src)) +- return; +- +- prev = dst->prev; +- next = dst; +- +- head = src->next; +- tail = src->prev; +- +- next->prev = tail; +- prev->next = head; +- head->prev = prev; +- tail->next = next; +- +- src->next = src->prev = src; +-} +- +-#define isns_list_item(type, member, ptr) \ +- container_of(type, member, ptr) +- +-#define isns_list_foreach(list, __pos, __next) \ +- for (__pos = (list)->next; \ +- (__pos != list) && (__next = __pos->next, 1); \ +- __pos = __next) +- +-#if 0 +-/* This is defined in stddef */ +-#define offsetof(type, member) ((unsigned long) &(((type *) 0)->member)) +-#endif +-#define container_of(type, member, ptr) \ +- ((type *) (((unsigned char *) ptr) - offsetof(type, member))) +- +-/* +- * Use isns_assert instead of libc's assert, so that the +- * message can be captured and sent to syslog. +- */ +-#define isns_assert(condition) do { \ +- if (!(condition)) \ +- isns_assert_failed(#condition, \ +- __FILE__, __LINE__); \ +-} while (0) +- +-#ifndef MDEBUG +-# define isns_malloc(size) malloc(size) +-# define isns_calloc(n, size) calloc(n, size) +-# define isns_realloc(p, size) realloc(p, size) +-# define isns_strdup(s) strdup(s) +-# define isns_free(p) free(p) +-#else +-# define isns_malloc(size) isns_malloc_fn(size, __FILE__, __LINE__) +-# define isns_calloc(n, size) isns_calloc_fn(n, size, __FILE__, __LINE__) +-# define isns_realloc(p, size) isns_realloc_fn(p, size, __FILE__, __LINE__) +-# define isns_strdup(s) isns_strdup_fn(s, __FILE__, __LINE__) +-# define isns_free(p) isns_free_fn(p, __FILE__, __LINE__) +- +-extern void * (*isns_malloc_fn)(size_t, const char *, unsigned int); +-extern void * (*isns_calloc_fn)(unsigned int, size_t, +- const char *, unsigned int); +-extern void * (*isns_realloc_fn)(void *, size_t, +- const char *, unsigned int); +-extern char * (*isns_strdup_fn)(const char *, const char *, unsigned int); +-extern void (*isns_free_fn)(void *, const char *, unsigned int); +-#endif +- +-#endif /* UTIL_H */ +diff --git a/utils/open-isns/vendor.c b/utils/open-isns/vendor.c +deleted file mode 100644 +index e24164d..0000000 +--- a/utils/open-isns/vendor.c ++++ /dev/null +@@ -1,41 +0,0 @@ +-/* +- * iSNS vendor specific objects +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#include +-#include +-#include "isns.h" +-#include "objects.h" +-#include "attrs.h" +-#include "vendor.h" +-#include "util.h" +- +-static uint32_t policy_attrs[] = { +- OPENISNS_TAG_POLICY_SPI, +- OPENISNS_TAG_POLICY_KEY, +- OPENISNS_TAG_POLICY_ENTITY, +- OPENISNS_TAG_POLICY_OBJECT_TYPE, +- OPENISNS_TAG_POLICY_NODE_NAME, +- OPENISNS_TAG_POLICY_NODE_TYPE, +- OPENISNS_TAG_POLICY_FUNCTIONS, +- OPENISNS_TAG_POLICY_VISIBLE_DD, +- OPENISNS_TAG_POLICY_DEFAULT_DD, +-}; +- +-static uint32_t policy_key_attrs[] = { +- OPENISNS_TAG_POLICY_SPI, +-}; +- +-isns_object_template_t isns_policy_template = { +- .iot_name = "Policy", +- .iot_handle = ISNS_OBJECT_TYPE_POLICY, +- .iot_attrs = policy_attrs, +- .iot_num_attrs = array_num_elements(policy_attrs), +- .iot_keys = policy_key_attrs, +- .iot_num_keys = array_num_elements(policy_key_attrs), +- .iot_container = &isns_entity_template, +- .iot_vendor_specific = 1, +-}; +- +diff --git a/utils/open-isns/vendor.h b/utils/open-isns/vendor.h +deleted file mode 100644 +index 49c6132..0000000 +--- a/utils/open-isns/vendor.h ++++ /dev/null +@@ -1,56 +0,0 @@ +-/* +- * iSNS "vendor-specific" protocol definitions +- * +- * Copyright (C) 2007 Olaf Kirch +- */ +- +-#ifndef ISNS_VENDOR_H +-#define ISNS_VENDOR_H +- +-#include "isns-proto.h" +- +-/* +- * We're poor, we don't own a OUI. Let's fake one. +- */ +-#define OPENISNS_VENDOR_OUI 0xFFFF00 +-#define OPENISNS_VENDOR_PREFIX (OPENISNS_VENDOR_OUI << 8) +-#define OPENISNS_IS_PRIVATE_ATTR(tag) (((tag) >> 16) == 0xFFFF) +- +-enum openisns_vendor_tag { +- /* Security Policy Identifier */ +- OPENISNS_TAG_POLICY_SPI = OPENISNS_VENDOR_PREFIX + ISNS_VENDOR_SPECIFIC_OTHER_BASE, +- +- __OPENISNS_TAG_POLICY_RESERVED, +- +- /* DSA signature key (public) */ +- OPENISNS_TAG_POLICY_KEY, +- +- /* Entity name to use */ +- OPENISNS_TAG_POLICY_ENTITY, +- +- /* Functions the client is permitted to invoke */ +- OPENISNS_TAG_POLICY_FUNCTIONS, +- +- /* Object types the client is permitted to see. */ +- OPENISNS_TAG_POLICY_OBJECT_TYPE, +- +- /* iSCSI node name the client is permitted to register. +- * This attribute may occur multiple times. +- * If absent, it defaults to POLICY_SOURCE_NAME +- */ +- OPENISNS_TAG_POLICY_NODE_NAME, +- +- /* Node type bitmap the client is permitted to register */ +- OPENISNS_TAG_POLICY_NODE_TYPE, +- +- /* Default discovery domain the client will be +- * placed in. +- * Not used yet. +- */ +- OPENISNS_TAG_POLICY_DEFAULT_DD, +- OPENISNS_TAG_POLICY_VISIBLE_DD, +-}; +- +-extern const struct isns_object_template isns_policy_template; +- +-#endif /* ISNS_VENDOR_H */ +diff --git a/utils/sysdeps/Makefile b/utils/sysdeps/Makefile +index 53c10e5..4299164 100644 +--- a/utils/sysdeps/Makefile ++++ b/utils/sysdeps/Makefile +@@ -1,6 +1,7 @@ + # This Makefile will work only with GNU make. + +-CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -O2 -fno-inline -Wall -Wstrict-prototypes -g ++CFLAGS ?= -O2 -fno-inline -g ++CFLAGS += $(WARNFLAGS) -Wall -Wstrict-prototypes + + SYSDEPS_OBJS=sysdeps.o + +-- +2.5.5 + diff --git a/SOURCES/open-iscsi-0002-ARP-table-too-small-when-switches-involved.patch b/SOURCES/open-iscsi-0002-ARP-table-too-small-when-switches-involved.patch new file mode 100644 index 00000000..022ae066 --- /dev/null +++ b/SOURCES/open-iscsi-0002-ARP-table-too-small-when-switches-involved.patch @@ -0,0 +1,44 @@ +From d6fdb1478fbee4abb45df12868b1c91ad295971d Mon Sep 17 00:00:00 2001 +From: Lee Duncan +Date: Wed, 1 Apr 2015 10:23:56 -0700 +Subject: [PATCH v2 2/9] ARP table too small when switches involved. + +The default uIP approach is to hae a super-small +memory foot print, but modern networks, with +switches, need more than 8 ARP entries, discovered +during IPv6 using, showing up as slow iscsiuio +response. +--- + iscsiuio/src/uip/ipv6.h | 2 +- + iscsiuio/src/uip/uipopt.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/iscsiuio/src/uip/ipv6.h b/iscsiuio/src/uip/ipv6.h +index bc63762..3586437 100644 +--- a/iscsiuio/src/uip/ipv6.h ++++ b/iscsiuio/src/uip/ipv6.h +@@ -270,7 +270,7 @@ struct ipv6_context { + struct ipv6_addr default_router; + struct ipv6_prefix_entry *addr_list; + u8_t hop_limit; +-#define UIP_ARPTAB_SIZE 8 ++#define UIP_ARPTAB_SIZE 16 + + struct uip_stack *ustack; + #define MAX_MCADDR_TABLE 5 +diff --git a/iscsiuio/src/uip/uipopt.h b/iscsiuio/src/uip/uipopt.h +index 946fce2..bcc8949 100644 +--- a/iscsiuio/src/uip/uipopt.h ++++ b/iscsiuio/src/uip/uipopt.h +@@ -341,7 +341,7 @@ + #ifdef UIP_CONF_ARPTAB_SIZE + #define UIP_ARPTAB_SIZE UIP_CONF_ARPTAB_SIZE + #else +-#define UIP_ARPTAB_SIZE 8 ++#define UIP_ARPTAB_SIZE 16 + #endif + + /** +-- +2.5.5 + diff --git a/SOURCES/open-iscsi-0003-Build-system-sort-object-file-lists.patch b/SOURCES/open-iscsi-0003-Build-system-sort-object-file-lists.patch new file mode 100644 index 00000000..48e93000 --- /dev/null +++ b/SOURCES/open-iscsi-0003-Build-system-sort-object-file-lists.patch @@ -0,0 +1,96 @@ +From 42b0b82a5dfd15966e8820a99d95c321d685d172 Mon Sep 17 00:00:00 2001 +From: Christian Seiler +Date: Sat, 13 Feb 2016 01:05:33 +0100 +Subject: [PATCH v2 3/9] Build system: sort object file lists + +Hi, + +Debian is currently working on making the entire archive build +reproducibly. is a good +resource describing the motivation behind this effort. + +There was one problem that was found in the open-iscsi package +build system that prevented builds from being reproducible: +the list of object files generated by the wildcard Makefile +function are not in a deterministic order, causing changes in +the output depending on the order in the underlying filesystem. + +I've attached a patch against the current git master that +sorts the list of object files within the Makefile, making the +order deterministic and allowing reproducible builds to be +made. See also: + + +It would be great if you could apply this patch upstream, so we +don't have to carry it in Debian. + +Thanks! + +Regards, +Christian + +-- +You received this message because you are subscribed to the Google Groups "open-iscsi" group. +To unsubscribe from this group and stop receiving emails from it, send an email to open-iscsi+unsubscribe@googlegroups.com. +To post to this group, send email to open-iscsi@googlegroups.com. +Visit this group at https://groups.google.com/group/open-iscsi. +For more options, visit https://groups.google.com/d/optout. + +From a919d214d10870a54c6a5e383a19a6e82e5f8a54 Mon Sep 17 00:00:00 2001 +From: Christian Seiler +Date: Sat, 13 Feb 2016 00:56:19 +0100 +Subject: [PATCH] Build system: sort object file lists + +The object file list generated by the wildcard Makefile function is not +deterministic, because it may change depending on the underlying file +system. + +Use the sort function to make the list deterministic in these cases, to +be able to build open-iscsi deterministically. See + +for further details. + +Signed-off-by: Christian Seiler +--- + usr/Makefile | 4 ++-- + utils/fwparam_ibft/Makefile | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/usr/Makefile b/usr/Makefile +index 5ac0726..277ac6a 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -34,7 +34,7 @@ CFLAGS += $(WARNFLAGS) -I../include -I. -D$(OSNAME) $(IPC_CFLAGS) + PROGRAMS = iscsid iscsiadm iscsistart + + # libc compat files +-SYSDEPS_SRCS = $(wildcard ../utils/sysdeps/*.o) ++SYSDEPS_SRCS = $(sort $(wildcard ../utils/sysdeps/*.o)) + # sources shared between iscsid, iscsiadm and iscsistart + ISCSI_LIB_SRCS = iscsi_util.o io.o auth.o iscsi_timer.o login.o log.o md5.o \ + sha1.o iface.o idbm.o sysfs.o host.o session_info.o iscsi_sysfs.o \ +@@ -45,7 +45,7 @@ ISCSI_LIB_SRCS = iscsi_util.o io.o auth.o iscsi_timer.o login.o log.o md5.o \ + INITIATOR_SRCS = initiator.o scsi.o actor.o event_poll.o mgmt_ipc.o kern_err_table.o + + # fw boot files +-FW_BOOT_SRCS = $(wildcard ../utils/fwparam_ibft/*.o) ++FW_BOOT_SRCS = $(sort $(wildcard ../utils/fwparam_ibft/*.o)) + + # core discovery files + DISCOVERY_SRCS = $(FW_BOOT_SRCS) strings.o discovery.o +diff --git a/utils/fwparam_ibft/Makefile b/utils/fwparam_ibft/Makefile +index 773d8eb..ade8a56 100644 +--- a/utils/fwparam_ibft/Makefile ++++ b/utils/fwparam_ibft/Makefile +@@ -21,7 +21,7 @@ + # "Prasanna Mumbai" + # + +-SYSDEPS_OBJS = $(wildcard ../sysdeps/*.o) ++SYSDEPS_OBJS = $(sort $(wildcard ../sysdeps/*.o)) + OBJS := fw_entry.o fwparam_sysfs.o $(SYSDEPS_OBJS) ../../usr/iscsi_net_util.o + OBJS += prom_lex.o prom_parse.tab.o fwparam_ppc.o + CLEANFILES = $(OBJS) *.output *~ +-- +2.5.5 + diff --git a/SOURCES/open-iscsi-0004-iscsi_tcp-set-SO_LINGER-to-abort-connection-for-e.patch b/SOURCES/open-iscsi-0004-iscsi_tcp-set-SO_LINGER-to-abort-connection-for-e.patch new file mode 100644 index 00000000..14bde909 --- /dev/null +++ b/SOURCES/open-iscsi-0004-iscsi_tcp-set-SO_LINGER-to-abort-connection-for-e.patch @@ -0,0 +1,50 @@ +From b104afd497502321765c2c1ed3f020b1fe4b400a Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Mon, 29 Feb 2016 14:13:27 -0800 +Subject: [PATCH v2 4/9] iscsi_tcp set SO_LINGER to abort connection for error + handling + +When requests are being failed it's important to abort the TCP +connection rather than let TCP wait and attempt a graceful shutdown. + +That can be accomplished by setting the SO_LINGER socket option with a +linger time of 0 to drop queued data and close the connection with a RST +instead of a FIN. + +Signed-off-by: Chris Leech +--- + usr/io.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/usr/io.c b/usr/io.c +index f552e1e..48b233c 100644 +--- a/usr/io.c ++++ b/usr/io.c +@@ -391,9 +391,24 @@ iscsi_io_tcp_poll(iscsi_conn_t *conn, int timeout_ms) + void + iscsi_io_tcp_disconnect(iscsi_conn_t *conn) + { ++ struct linger so_linger = { .l_onoff = 1, .l_linger = 0 }; ++ + if (conn->socket_fd >= 0) { + log_debug(1, "disconnecting conn %p, fd %d", conn, + conn->socket_fd); ++ ++ /* If the state is not IN_LOGOUT, this isn't a clean shutdown ++ * and there's some sort of error handling going on. In that ++ * case, set a 0 SO_LINGER to force an abortive close (RST) and ++ * free whatever is sitting in the TCP transmit queue. This is ++ * done to prevent stale data from being sent should the ++ * network connection be restored before TCP times out. ++ */ ++ if (conn->state != ISCSI_CONN_STATE_IN_LOGOUT) { ++ setsockopt(conn->socket_fd, SOL_SOCKET, SO_LINGER, ++ &so_linger, sizeof(so_linger)); ++ } ++ + close(conn->socket_fd); + conn->socket_fd = -1; + } +-- +2.5.5 + diff --git a/SOURCES/open-iscsi-0005-iscsiadm-fix-parallel-rescan-handling-of-exit-cod.patch b/SOURCES/open-iscsi-0005-iscsiadm-fix-parallel-rescan-handling-of-exit-cod.patch new file mode 100644 index 00000000..7b7f7af7 --- /dev/null +++ b/SOURCES/open-iscsi-0005-iscsiadm-fix-parallel-rescan-handling-of-exit-cod.patch @@ -0,0 +1,88 @@ +From bc5de4146b18cc6359a337c2cc044d136421c215 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Fri, 8 Apr 2016 10:55:46 -0700 +Subject: [PATCH v2 5/9] iscsiadm: fix parallel rescan handling of exit codes + +The parallel rescan patches work, in so much as the rescans happen, but +if a target is specified the non-matching cases cause warning to be +printed and a non-zero exit code. + +To reproduce: have more than one session to different targets, issue a +node mode rescan command to one of them (-m node -T -R). + +The problem is that while exit() takes an int, only the low byte is part +of the exit code and it's combined with other exit status information. +iscsiadm tries to use exit(-1) to indicate a non-match (not a fatal +error). The value retrieved with wait() after an exit(-1) is actually +65280. + +Fix this by making use of the wait.h macros for checking the exit code. +--- + include/iscsi_err.h | 2 ++ + usr/iscsi_err.c | 1 + + usr/iscsi_sysfs.c | 20 +++++++++++++++++--- + 3 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/include/iscsi_err.h b/include/iscsi_err.h +index 125f443..506bd8c 100644 +--- a/include/iscsi_err.h ++++ b/include/iscsi_err.h +@@ -66,6 +66,8 @@ enum { + ISCSI_ERR_AGAIN = 29, + /* unknown discovery type */ + ISCSI_ERR_UNKNOWN_DISCOVERY_TYPE = 30, ++ /* child process terminated */ ++ ISCSI_ERR_CHILD_TERMINATED = 31, + + /* Always last. Indicates end of error code space */ + ISCSI_MAX_ERR_VAL, +diff --git a/usr/iscsi_err.c b/usr/iscsi_err.c +index 11e0348..1ba9e64 100644 +--- a/usr/iscsi_err.c ++++ b/usr/iscsi_err.c +@@ -53,6 +53,7 @@ static char *iscsi_err_msgs[] = { + /* 28 */ "device or resource in use", + /* 29 */ "operation failed but retry may succeed", + /* 30 */ "unknown discovery type", ++ /* 31 */ "child process terminated", + }; + + char *iscsi_err_to_str(int err) +diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c +index 3a37a48..a8fe156 100644 +--- a/usr/iscsi_sysfs.c ++++ b/usr/iscsi_sysfs.c +@@ -1472,13 +1472,27 @@ int iscsi_sysfs_for_each_session(void *data, int *nr_found, + break; + } + +- if ((chldrc > 0) && (rc == 0)) { ++ if (!WIFEXITED(chldrc)) { + /* ++ * abnormal termination (signal, exception, etc.) ++ * + * The non-parallel code path returns the first + * error so this keeps the same semantics. + */ +- rc = chldrc; +- } else if (chldrc == 0) { ++ if (rc == 0) ++ rc = ISCSI_ERR_CHILD_TERMINATED; ++ } else if ((WEXITSTATUS(chldrc) != 0) && ++ (WEXITSTATUS(chldrc) != 255)) { ++ /* ++ * 0 is success ++ * 255 is a truncated return code from exit(-1) ++ * and means no match ++ * anything else (this case) is an error ++ */ ++ if (rc == 0) ++ rc = WEXITSTATUS(chldrc); ++ } else if (WEXITSTATUS(chldrc) == 0) { ++ /* success */ + (*nr_found)++; + } + } +-- +2.5.5 + diff --git a/SOURCES/open-iscsi-0006-iscsistart-support-booting-over-a-VLAN.patch b/SOURCES/open-iscsi-0006-iscsistart-support-booting-over-a-VLAN.patch new file mode 100644 index 00000000..435d25ea --- /dev/null +++ b/SOURCES/open-iscsi-0006-iscsistart-support-booting-over-a-VLAN.patch @@ -0,0 +1,199 @@ +From bea3e68d7a242ff50714332598fabaf4975712a2 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Wed, 17 Jun 2015 15:07:53 -0700 +Subject: [PATCH v2 6/9] iscsistart: support booting over a VLAN + +Adds code to check for VLAN devices if the boot configuration specifies +a VLAN ID. + +Does not create VLANs, they need to already be in place. +--- + include/iscsi_net_util.h | 3 +- + usr/iscsi_net_util.c | 78 +++++++++++++++++++++++++++++++++++++++++-- + utils/fwparam_ibft/fw_entry.c | 3 +- + 3 files changed, 78 insertions(+), 6 deletions(-) + +diff --git a/include/iscsi_net_util.h b/include/iscsi_net_util.h +index 31b80ad..cbf3637 100644 +--- a/include/iscsi_net_util.h ++++ b/include/iscsi_net_util.h +@@ -6,7 +6,8 @@ + extern int net_get_transport_name_from_netdev(char *netdev, char *transport); + extern int net_get_netdev_from_hwaddress(char *hwaddress, char *netdev); + extern int net_setup_netdev(char *netdev, char *local_ip, char *mask, +- char *gateway, char *remote_ip, int needs_bringup); ++ char *gateway, char *vlan, char *remote_ip, ++ int needs_bringup); + extern int net_ifup_netdev(char *netdev); + + #endif +diff --git a/usr/iscsi_net_util.c b/usr/iscsi_net_util.c +index 848b4c6..06df9b3 100644 +--- a/usr/iscsi_net_util.c ++++ b/usr/iscsi_net_util.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -27,6 +28,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include "sysdeps.h" + #include "ethtool-copy.h" +@@ -162,6 +166,45 @@ free_ifni: + return 0; + } + ++static char *find_vlan_dev(char *netdev, int vlan_id) { ++ struct ifreq if_hwaddr; ++ struct ifreq vlan_hwaddr; ++ struct vlan_ioctl_args vlanrq = { .cmd = GET_VLAN_VID_CMD, }; ++ struct if_nameindex *ifni; ++ char *vlan = NULL; ++ int sockfd, i, rc; ++ ++ sockfd = socket(AF_INET, SOCK_DGRAM, 0); ++ ++ strncpy(if_hwaddr.ifr_name, netdev, IFNAMSIZ); ++ ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr); ++ ++ if (if_hwaddr.ifr_hwaddr.sa_family != ARPHRD_ETHER) ++ return NULL; ++ ++ ifni = if_nameindex(); ++ for (i = 0; ifni[i].if_index && ifni[i].if_name; i++) { ++ strncpy(vlan_hwaddr.ifr_name, ifni[i].if_name, IFNAMSIZ); ++ ioctl(sockfd, SIOCGIFHWADDR, &vlan_hwaddr); ++ ++ if (vlan_hwaddr.ifr_hwaddr.sa_family != ARPHRD_ETHER) ++ continue; ++ ++ if (!memcmp(if_hwaddr.ifr_hwaddr.sa_data, vlan_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN)) { ++ strncpy(vlanrq.device1, ifni[i].if_name, IFNAMSIZ); ++ rc = ioctl(sockfd, SIOCGIFVLAN, &vlanrq); ++ if ((rc == 0) && (vlanrq.u.VID == vlan_id)) { ++ vlan = strdup(vlanrq.device1); ++ break; ++ } ++ } ++ } ++ if_freenameindex(ifni); ++ ++ close(sockfd); ++ return vlan; ++} ++ + /** + * net_setup_netdev - bring up NIC + * @netdev: network device name +@@ -175,7 +218,7 @@ free_ifni: + * to force iSCSI traffic through correct NIC. + */ + int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway, +- char *remote_ip, int needs_bringup) ++ char *vlan, char *remote_ip, int needs_bringup) + { + struct sockaddr_in sk_ipaddr = { .sin_family = AF_INET }; + struct sockaddr_in sk_netmask = { .sin_family = AF_INET }; +@@ -184,14 +227,29 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway, + struct sockaddr_in sk_tgt_ipaddr = { .sin_family = AF_INET }; + struct rtentry rt; + struct ifreq ifr; ++ char *physdev = NULL; + int sock; + int ret; ++ int vlan_id; + + if (!strlen(netdev)) { + log_error("No netdev name in fw entry."); + return EINVAL; + } + ++ vlan_id = atoi(vlan); ++ ++ if (vlan_id != 0) { ++ physdev = netdev; ++ netdev = find_vlan_dev(physdev, vlan_id); ++ } ++ ++ if (vlan_id && !netdev) { ++ /* TODO: create vlan if not found */ ++ log_error("No matching vlan found for fw entry."); ++ return EINVAL; ++ } ++ + /* Create socket for making networking changes */ + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + log_error("Could not open socket to manage network " +@@ -224,7 +282,19 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway, + + /* Only set IP/NM if this is a new interface */ + if (needs_bringup) { +- /* TODO: create vlan if strlen(vlan) */ ++ ++ if (physdev) { ++ /* Bring up interface */ ++ memset(&ifr, 0, sizeof(ifr)); ++ strlcpy(ifr.ifr_name, physdev, IFNAMSIZ); ++ ifr.ifr_flags = IFF_UP | IFF_RUNNING; ++ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) { ++ log_error("Could not bring up netdev %s (err %d - %s)", ++ physdev, errno, strerror(errno)); ++ ret = errno; ++ goto done; ++ } ++ } + + /* Bring up interface */ + memset(&ifr, 0, sizeof(ifr)); +@@ -246,7 +316,7 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway, + ret = errno; + goto done; + } +- ++ + /* Set netmask */ + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, netdev, IFNAMSIZ); +@@ -303,6 +373,8 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway, + + done: + close(sock); ++ if (vlan_id) ++ free(netdev); + return ret; + } + +diff --git a/utils/fwparam_ibft/fw_entry.c b/utils/fwparam_ibft/fw_entry.c +index f94a035..0a1b46b 100644 +--- a/utils/fwparam_ibft/fw_entry.c ++++ b/utils/fwparam_ibft/fw_entry.c +@@ -41,8 +41,6 @@ + /** + * fw_setup_nics - setup nics (ethXs) based on ibft net info + * +- * Currently does not support vlans. +- * + * If this is a offload card, this function does nothing. The + * net info is used by the iscsi iface settings for the iscsi + * function. +@@ -82,6 +80,7 @@ int fw_setup_nics(void) + + err = net_setup_netdev(context->iface, context->ipaddr, + context->mask, context->gateway, ++ context->vlan, + context->target_ipaddr, needs_bringup); + if (err) + ret = err; +-- +2.5.5 + diff --git a/SOURCES/open-iscsi-0007-iscsid-safe_logout-fix-device-path-canonicalizati.patch b/SOURCES/open-iscsi-0007-iscsid-safe_logout-fix-device-path-canonicalizati.patch new file mode 100644 index 00000000..b789857f --- /dev/null +++ b/SOURCES/open-iscsi-0007-iscsid-safe_logout-fix-device-path-canonicalizati.patch @@ -0,0 +1,51 @@ +From 3f1b9160dc8ffc6e7196a24885781e1ba82f9119 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 21 Jul 2015 16:15:30 -0700 +Subject: [PATCH v2 7/9] iscsid: safe_logout fix device path canonicalization + by using libmount cache + +Fix for the safe_logout options use of libmount. If the cache API isn't +used then device name canonicalization doesn't happen, and proper +detection of devices mounted by a label doesn't work. +--- + usr/initiator.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/usr/initiator.c b/usr/initiator.c +index 8cd1896..b0f0147 100644 +--- a/usr/initiator.c ++++ b/usr/initiator.c +@@ -2045,12 +2045,14 @@ static int session_unbind(struct iscsi_session *session) + } + + static struct libmnt_table *mtab, *swaps; ++static struct libmnt_cache *mntcache; + + static void libmount_cleanup(void) + { + mnt_free_table(mtab); + mnt_free_table(swaps); +- mtab = swaps = NULL; ++ mnt_free_cache(mntcache); ++ mtab = swaps = mntcache = NULL; + } + + static int libmount_init(void) +@@ -2058,10 +2060,13 @@ static int libmount_init(void) + mnt_init_debug(0); + mtab = mnt_new_table(); + swaps = mnt_new_table(); +- if (!mtab || !swaps) { ++ mntcache = mnt_new_cache(); ++ if (!mtab || !swaps || !mntcache) { + libmount_cleanup(); + return -ENOMEM; + } ++ mnt_table_set_cache(mtab, mntcache); ++ mnt_table_set_cache(swaps, mntcache); + mnt_table_parse_mtab(mtab, NULL); + mnt_table_parse_swaps(swaps, NULL); + return 0; +-- +2.5.5 + diff --git a/SOURCES/open-iscsi-0008-iscsid-make-safe_logut-session-checks-apply-for-f.patch b/SOURCES/open-iscsi-0008-iscsid-make-safe_logut-session-checks-apply-for-f.patch new file mode 100644 index 00000000..10d4c993 --- /dev/null +++ b/SOURCES/open-iscsi-0008-iscsid-make-safe_logut-session-checks-apply-for-f.patch @@ -0,0 +1,573 @@ +From 723e7b342ec311a59f92eb94936ce769e804b43d Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Fri, 24 Jul 2015 14:18:30 -0700 +Subject: [PATCH v2 8/9] iscsid: make safe_logut session checks apply for + flashnode session + +Make the safe_logout option work with flashnode sessions as well. +Moves the code into a new file shared between iscsid and iscsiadm. +--- + usr/Makefile | 8 +- + usr/initiator.c | 195 ----------------------------------------- + usr/initiator.h | 1 + + usr/initiator_common.c | 2 + + usr/iscsiadm.c | 23 +++++ + usr/iscsistart.c | 2 + + usr/mntcheck.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 265 insertions(+), 199 deletions(-) + create mode 100644 usr/mntcheck.c + +diff --git a/usr/Makefile b/usr/Makefile +index 277ac6a..c1866b6 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -53,15 +53,15 @@ DISCOVERY_SRCS = $(FW_BOOT_SRCS) strings.o discovery.o + all: $(PROGRAMS) + + iscsid: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(DISCOVERY_SRCS) \ +- iscsid.o session_mgmt.o discoveryd.o ++ iscsid.o session_mgmt.o discoveryd.o mntcheck.o + $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lisns -lcrypto -lrt -lmount + +-iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o +- $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lisns -lcrypto ++iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o mntcheck.o ++ $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lisns -lcrypto -lmount + + iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \ + iscsistart.o statics.o +- $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lrt -lmount ++ $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lrt + clean: + rm -f *.o $(PROGRAMS) .depend $(LIBSYS) + +diff --git a/usr/initiator.c b/usr/initiator.c +index b0f0147..072bcc9 100644 +--- a/usr/initiator.c ++++ b/usr/initiator.c +@@ -30,7 +30,6 @@ + #include + #include + #include +-#include + + #include "initiator.h" + #include "transport.h" +@@ -2044,200 +2043,6 @@ static int session_unbind(struct iscsi_session *session) + return err; + } + +-static struct libmnt_table *mtab, *swaps; +-static struct libmnt_cache *mntcache; +- +-static void libmount_cleanup(void) +-{ +- mnt_free_table(mtab); +- mnt_free_table(swaps); +- mnt_free_cache(mntcache); +- mtab = swaps = mntcache = NULL; +-} +- +-static int libmount_init(void) +-{ +- mnt_init_debug(0); +- mtab = mnt_new_table(); +- swaps = mnt_new_table(); +- mntcache = mnt_new_cache(); +- if (!mtab || !swaps || !mntcache) { +- libmount_cleanup(); +- return -ENOMEM; +- } +- mnt_table_set_cache(mtab, mntcache); +- mnt_table_set_cache(swaps, mntcache); +- mnt_table_parse_mtab(mtab, NULL); +- mnt_table_parse_swaps(swaps, NULL); +- return 0; +-} +- +-static int trans_filter(const struct dirent *d) +-{ +- if (!strcmp(".", d->d_name) || !strcmp("..", d->d_name)) +- return 0; +- return 1; +-} +- +-static int subdir_filter(const struct dirent *d) +-{ +- if (!(d->d_type & DT_DIR)) +- return 0; +- return trans_filter(d); +-} +- +-static int is_partition(const char *path) +-{ +- char *devtype; +- int rc = 0; +- +- devtype = sysfs_get_uevent_devtype(path); +- if (!devtype) +- return 0; +- if (strcmp(devtype, "partition") == 0) +- rc = 1; +- free(devtype); +- return rc; +-} +- +-static int blockdev_check_mnts(char *syspath) +-{ +- struct libmnt_fs *fs; +- char *devname = NULL; +- char *_devname = NULL; +- int rc = 0; +- +- devname = sysfs_get_uevent_devname(syspath); +- if (!devname) +- goto out; +- +- _devname = calloc(1, PATH_MAX); +- if (!_devname) +- goto out; +- snprintf(_devname, PATH_MAX, "/dev/%s", devname); +- +- fs = mnt_table_find_source(mtab, _devname, MNT_ITER_FORWARD); +- if (fs) { +- rc = 1; +- goto out; +- } +- fs = mnt_table_find_source(swaps, _devname, MNT_ITER_FORWARD); +- if (fs) +- rc = 1; +-out: +- free(devname); +- free(_devname); +- return rc; +-} +- +-static int count_device_users(char *syspath); +- +-static int blockdev_get_partitions(char *syspath) +-{ +- struct dirent **parts = NULL; +- int n, i; +- int count = 0; +- +- n = scandir(syspath, &parts, subdir_filter, alphasort); +- for (i = 0; i < n; i++) { +- char *newpath; +- +- newpath = calloc(1, PATH_MAX); +- if (!newpath) +- continue; +- snprintf(newpath, PATH_MAX, "%s/%s", syspath, parts[i]->d_name); +- free(parts[i]); +- if (is_partition(newpath)) { +- count += count_device_users(newpath); +- } +- free(newpath); +- } +- free(parts); +- return count; +-} +- +-static int blockdev_get_holders(char *syspath) +-{ +- char *path = NULL; +- struct dirent **holds = NULL; +- int n, i; +- int count = 0; +- +- path = calloc(1, PATH_MAX); +- if (!path) +- return 0; +- snprintf(path, PATH_MAX, "%s/holders", syspath); +- +- n = scandir(path, &holds, trans_filter, alphasort); +- for (i = 0; i < n; i++) { +- char *newpath; +- char *rp; +- +- newpath = calloc(1, PATH_MAX); +- if (!newpath) +- continue; +- snprintf(newpath, PATH_MAX, "%s/%s", path, holds[i]->d_name); +- +- free(holds[i]); +- rp = realpath(newpath, NULL); +- if (rp) +- count += count_device_users(rp); +- free(newpath); +- free(rp); +- } +- free(path); +- free(holds); +- return count; +-} +- +-static int count_device_users(char *syspath) +-{ +- int count = 0; +- count += blockdev_check_mnts(syspath); +- count += blockdev_get_partitions(syspath); +- count += blockdev_get_holders(syspath); +- return count; +-}; +- +-static void device_in_use(void *data, int host_no, int target, int lun) +-{ +- char *syspath = NULL; +- char *devname = NULL; +- int *count = data; +- +- devname = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun); +- if (!devname) +- goto out; +- syspath = calloc(1, PATH_MAX); +- if (!syspath) +- goto out; +- snprintf(syspath, PATH_MAX, "/sys/class/block/%s", devname); +- *count += count_device_users(syspath); +-out: +- free(syspath); +- free(devname); +-} +- +-static int session_in_use(int sid) +-{ +- int host_no = -1, err = 0; +- int count = 0; +- +- if (libmount_init()) { +- log_error("Failed to initialize libmount, " +- "not checking for active mounts on session [%d].", +- sid); +- return 0; +- } +- +- host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err); +- if (!err) +- iscsi_sysfs_for_each_device(&count, host_no, sid, device_in_use); +- +- libmount_cleanup(); +- return count; +-} +- + int session_logout_task(int sid, queue_task_t *qtask) + { + iscsi_session_t *session; +diff --git a/usr/initiator.h b/usr/initiator.h +index c11d77f..4f96d6b 100644 +--- a/usr/initiator.h ++++ b/usr/initiator.h +@@ -359,4 +359,5 @@ extern int iscsi_set_net_config(struct iscsi_transport *t, + struct iface_rec *iface); + extern void iscsi_session_init_params(struct iscsi_session *session); + ++extern int session_in_use(int sid); + #endif /* INITIATOR_H */ +diff --git a/usr/initiator_common.c b/usr/initiator_common.c +index c02643a..1d1d822 100644 +--- a/usr/initiator_common.c ++++ b/usr/initiator_common.c +@@ -23,6 +23,8 @@ + #include + #include + #include ++#include ++#include + + #include "initiator.h" + #include "transport.h" +diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c +index c6705bd..fc0c8bc 100644 +--- a/usr/iscsiadm.c ++++ b/usr/iscsiadm.c +@@ -1898,11 +1898,34 @@ exit_logout: + return rc; + } + ++static int iscsi_check_session_use_count(uint32_t sid) { ++ char *config_file; ++ char *safe_logout; ++ ++ config_file = get_config_file(); ++ if (!config_file) { ++ log_error("Could not get config file from iscsid"); ++ return 0; ++ } ++ ++ safe_logout = cfg_get_string_param(config_file, "iscsid.safe_logout"); ++ if (!safe_logout || strcmp(safe_logout, "Yes")) ++ return 0; ++ ++ return session_in_use(sid); ++} ++ + int iscsi_logout_flashnode_sid(struct iscsi_transport *t, uint32_t host_no, + uint32_t sid) + { + int fd, rc = 0; + ++ if (iscsi_check_session_use_count(sid)) { ++ log_error("Session is actively in use for mounted storage, " ++ "and iscsid.safe_logout is configured."); ++ return ISCSI_ERR_BUSY; ++ } ++ + fd = ipc->ctldev_open(); + if (fd < 0) { + log_error("Netlink open failed."); +diff --git a/usr/iscsistart.c b/usr/iscsistart.c +index 7ff2236..79d6622 100644 +--- a/usr/iscsistart.c ++++ b/usr/iscsistart.c +@@ -279,6 +279,8 @@ static int setup_session(void) + return rc; + } + ++int session_in_use(int sid) { return 0; } ++ + static void catch_signal(int signo) + { + log_warning("pid %d caught signal -%d", getpid(), signo); +diff --git a/usr/mntcheck.c b/usr/mntcheck.c +new file mode 100644 +index 0000000..6ae03e0 +--- /dev/null ++++ b/usr/mntcheck.c +@@ -0,0 +1,233 @@ ++/* ++ * Common code for checking sessions for mnt use ++ * ++ * Copyright (C) 2014 - 2015 Chris Leech ++ * Copyright (C) 2014 - 2015 Red Hat, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "initiator.h" ++#include "transport.h" ++#include "iscsid.h" ++#include "iscsi_ipc.h" ++#include "log.h" ++#include "iscsi_sysfs.h" ++#include "iscsi_settings.h" ++#include "iface.h" ++#include "host.h" ++#include "sysdeps.h" ++#include "iscsi_err.h" ++#include "iscsi_net_util.h" ++ ++static struct libmnt_table *mtab, *swaps; ++static struct libmnt_cache *mntcache; ++ ++static void libmount_cleanup(void) ++{ ++ mnt_free_table(mtab); ++ mnt_free_table(swaps); ++ mnt_free_cache(mntcache); ++ mtab = NULL; ++ swaps = NULL; ++ mntcache = NULL; ++} ++ ++static int libmount_init(void) ++{ ++ mnt_init_debug(0); ++ mtab = mnt_new_table(); ++ swaps = mnt_new_table(); ++ mntcache = mnt_new_cache(); ++ if (!mtab || !swaps || !mntcache) { ++ libmount_cleanup(); ++ return -ENOMEM; ++ } ++ mnt_table_set_cache(mtab, mntcache); ++ mnt_table_set_cache(swaps, mntcache); ++ mnt_table_parse_mtab(mtab, NULL); ++ mnt_table_parse_swaps(swaps, NULL); ++ return 0; ++} ++ ++static int trans_filter(const struct dirent *d) ++{ ++ if (!strcmp(".", d->d_name) || !strcmp("..", d->d_name)) ++ return 0; ++ return 1; ++} ++ ++static int subdir_filter(const struct dirent *d) ++{ ++ if (!(d->d_type & DT_DIR)) ++ return 0; ++ return trans_filter(d); ++} ++ ++static int is_partition(const char *path) ++{ ++ char *devtype; ++ int rc = 0; ++ ++ devtype = sysfs_get_uevent_devtype(path); ++ if (!devtype) ++ return 0; ++ if (strcmp(devtype, "partition") == 0) ++ rc = 1; ++ free(devtype); ++ return rc; ++} ++ ++static int blockdev_check_mnts(char *syspath) ++{ ++ struct libmnt_fs *fs; ++ char *devname = NULL; ++ char *_devname = NULL; ++ int rc = 0; ++ ++ devname = sysfs_get_uevent_devname(syspath); ++ if (!devname) ++ goto out; ++ ++ _devname = calloc(1, PATH_MAX); ++ if (!_devname) ++ goto out; ++ snprintf(_devname, PATH_MAX, "/dev/%s", devname); ++ ++ fs = mnt_table_find_source(mtab, _devname, MNT_ITER_FORWARD); ++ if (fs) { ++ rc = 1; ++ goto out; ++ } ++ fs = mnt_table_find_source(swaps, _devname, MNT_ITER_FORWARD); ++ if (fs) ++ rc = 1; ++out: ++ free(devname); ++ free(_devname); ++ return rc; ++} ++ ++static int count_device_users(char *syspath); ++ ++static int blockdev_get_partitions(char *syspath) ++{ ++ struct dirent **parts = NULL; ++ int n, i; ++ int count = 0; ++ ++ n = scandir(syspath, &parts, subdir_filter, alphasort); ++ for (i = 0; i < n; i++) { ++ char *newpath; ++ ++ newpath = calloc(1, PATH_MAX); ++ if (!newpath) ++ continue; ++ snprintf(newpath, PATH_MAX, "%s/%s", syspath, parts[i]->d_name); ++ free(parts[i]); ++ if (is_partition(newpath)) { ++ count += count_device_users(newpath); ++ } ++ free(newpath); ++ } ++ free(parts); ++ return count; ++} ++ ++static int blockdev_get_holders(char *syspath) ++{ ++ char *path = NULL; ++ struct dirent **holds = NULL; ++ int n, i; ++ int count = 0; ++ ++ path = calloc(1, PATH_MAX); ++ if (!path) ++ return 0; ++ snprintf(path, PATH_MAX, "%s/holders", syspath); ++ ++ n = scandir(path, &holds, trans_filter, alphasort); ++ for (i = 0; i < n; i++) { ++ char *newpath; ++ char *rp; ++ ++ newpath = calloc(1, PATH_MAX); ++ if (!newpath) ++ continue; ++ snprintf(newpath, PATH_MAX, "%s/%s", path, holds[i]->d_name); ++ ++ free(holds[i]); ++ rp = realpath(newpath, NULL); ++ if (rp) ++ count += count_device_users(rp); ++ free(newpath); ++ free(rp); ++ } ++ free(path); ++ free(holds); ++ return count; ++} ++ ++static int count_device_users(char *syspath) ++{ ++ int count = 0; ++ count += blockdev_check_mnts(syspath); ++ count += blockdev_get_partitions(syspath); ++ count += blockdev_get_holders(syspath); ++ return count; ++}; ++ ++static void device_in_use(void *data, int host_no, int target, int lun) ++{ ++ char *syspath = NULL; ++ char *devname = NULL; ++ int *count = data; ++ ++ devname = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun); ++ if (!devname) ++ goto out; ++ syspath = calloc(1, PATH_MAX); ++ if (!syspath) ++ goto out; ++ snprintf(syspath, PATH_MAX, "/sys/class/block/%s", devname); ++ *count += count_device_users(syspath); ++out: ++ free(syspath); ++ free(devname); ++} ++ ++int session_in_use(int sid) ++{ ++ int host_no = -1, err = 0; ++ int count = 0; ++ ++ if (libmount_init()) { ++ log_error("Failed to initialize libmount, " ++ "not checking for active mounts on session [%d].", sid); ++ return 0; ++ } ++ ++ host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err); ++ if (!err) ++ iscsi_sysfs_for_each_device(&count, host_no, sid, device_in_use); ++ ++ libmount_cleanup(); ++ return count; ++} +-- +2.5.5 + diff --git a/SOURCES/open-iscsi-0009-remove-sysfs-attr_list.patch b/SOURCES/open-iscsi-0009-remove-sysfs-attr_list.patch new file mode 100644 index 00000000..214a5340 --- /dev/null +++ b/SOURCES/open-iscsi-0009-remove-sysfs-attr_list.patch @@ -0,0 +1,223 @@ +From 62b1b734053a33af1aabac663dc52dfce0682904 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 16 Feb 2016 16:45:26 -0800 +Subject: [PATCH v2 9/9] remove sysfs attr_list + +The global cache is not well designed, it quickly can grow to the point +where lookups take much longer than just doing the sysfs read in the +first place. + +v2: initialized 'value' array in sysfs_attr_get_value to fix issue when + checking for an attr that doesn't exist + +v3: fix another behavior change when checking ofr non-existent attrs, + make sure we return NULL and not an empty string +--- + usr/host.c | 1 + + usr/session_info.c | 1 + + usr/sysfs.c | 65 ++++++++++++++---------------------------------------- + 3 files changed, 19 insertions(+), 48 deletions(-) + +diff --git a/usr/host.c b/usr/host.c +index f2052d3..6333490 100644 +--- a/usr/host.c ++++ b/usr/host.c +@@ -274,6 +274,7 @@ int host_info_print(int info_level, uint32_t host_no) + printf("iSCSI Transport Class version %s\n", + version); + printf("version %s\n", ISCSI_VERSION_STR); ++ free(version); + } + + flags |= SESSION_INFO_SCSI_DEVS; +diff --git a/usr/session_info.c b/usr/session_info.c +index 2f48e65..89422d8 100644 +--- a/usr/session_info.c ++++ b/usr/session_info.c +@@ -390,6 +390,7 @@ int session_info_print(int info_level, struct session_info *info, int do_show) + printf("iSCSI Transport Class version %s\n", + version); + printf("version %s\n", ISCSI_VERSION_STR); ++ free(version); + } + + flags |= (SESSION_INFO_SCSI_DEVS | SESSION_INFO_HOST_DEVS); +diff --git a/usr/sysfs.c b/usr/sysfs.c +index 6520bf6..48f3825 100644 +--- a/usr/sysfs.c ++++ b/usr/sysfs.c +@@ -63,15 +63,6 @@ char sysfs_path[PATH_SIZE]; + /* device cache */ + static LIST_HEAD(dev_list); + +-/* attribute value cache */ +-static LIST_HEAD(attr_list); +- +-struct sysfs_attr { +- struct list_head node; +- char path[PATH_SIZE]; +- char *value; /* points to value_local if value is cached */ +- char value_local[NAME_SIZE]; +-}; + int sysfs_init(void) + { + const char *env; +@@ -85,22 +76,14 @@ int sysfs_init(void) + dbg("sysfs_path='%s'", sysfs_path); + + INIT_LIST_HEAD(&dev_list); +- INIT_LIST_HEAD(&attr_list); + return 0; + } + + void sysfs_cleanup(void) + { +- struct sysfs_attr *attr_loop; +- struct sysfs_attr *attr_temp; + struct sysfs_device *dev_loop; + struct sysfs_device *dev_temp; + +- list_for_each_entry_safe(attr_loop, attr_temp, &attr_list, node) { +- list_del_init(&attr_loop->node); +- free(attr_loop); +- } +- + list_for_each_entry_safe(dev_loop, dev_temp, &dev_list, node) { + list_del_init(&dev_loop->node); + free(dev_loop); +@@ -355,10 +338,7 @@ struct sysfs_device *sysfs_device_get_parent_with_subsystem(struct sysfs_device + char *sysfs_attr_get_value(const char *devpath, const char *attr_name) + { + char path_full[PATH_SIZE]; +- const char *path; +- char value[NAME_SIZE]; +- struct sysfs_attr *attr_loop; +- struct sysfs_attr *attr; ++ char value[NAME_SIZE] = { '\0', }; + struct stat statbuf; + int fd; + ssize_t size; +@@ -368,29 +348,10 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name) + sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full)); + if(sysfs_len >= sizeof(path_full)) + sysfs_len = sizeof(path_full) - 1; +- path = &path_full[sysfs_len]; + strlcat(path_full, devpath, sizeof(path_full)); + strlcat(path_full, "/", sizeof(path_full)); + strlcat(path_full, attr_name, sizeof(path_full)); + +- /* look for attribute in cache */ +- list_for_each_entry(attr_loop, &attr_list, node) { +- if (strcmp(attr_loop->path, path) == 0) { +- dbg("found in cache '%s'", attr_loop->path); +- return attr_loop->value; +- } +- } +- +- /* store attribute in cache (also negatives are kept in cache) */ +- dbg("new uncached attribute '%s'", path_full); +- attr = malloc(sizeof(struct sysfs_attr)); +- if (attr == NULL) +- return NULL; +- memset(attr, 0x00, sizeof(struct sysfs_attr)); +- strlcpy(attr->path, path, sizeof(attr->path)); +- dbg("add to cache '%s'", path_full); +- list_add(&attr->node, &attr_list); +- + if (lstat(path_full, &statbuf) != 0) { + dbg("stat '%s' failed: %s", path_full, strerror(errno)); + goto out; +@@ -408,8 +369,7 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name) + pos = strrchr(link_target, '/'); + if (pos != NULL) { + dbg("cache '%s' with link value '%s'", path_full, value); +- strlcpy(attr->value_local, &pos[1], sizeof(attr->value_local)); +- attr->value = attr->value_local; ++ strlcpy(value, &pos[1], NAME_SIZE); + } + } + goto out; +@@ -439,12 +399,11 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name) + /* got a valid value, store and return it */ + value[size] = '\0'; + remove_trailing_chars(value, '\n'); +- dbg("cache '%s' with attribute value '%s'", path_full, value); +- strlcpy(attr->value_local, value, sizeof(attr->value_local)); +- attr->value = attr->value_local; + + out: +- return attr->value; ++ if (value[0] == '\0') ++ return NULL; ++ return strdup(value); + } + + int sysfs_lookup_devpath_by_subsys_id(char *devpath_full, size_t len, const char *subsystem, const char *id) +@@ -567,8 +526,10 @@ char *sysfs_get_value(const char *id, char *subsys, char *param) + } + + if (!strncmp(sysfs_value, "", 6) || +- !strncmp(sysfs_value, "(null)", 6)) ++ !strncmp(sysfs_value, "(null)", 6)) { ++ free(sysfs_value); + return NULL; ++ } + + return sysfs_value; + } +@@ -585,6 +546,7 @@ int sysfs_get_uint(char *id, char *subsys, char *param, + + errno = 0; + *value = strtoul(sysfs_value, NULL, 0); ++ free(sysfs_value); + if (errno) + return errno; + return 0; +@@ -600,6 +562,7 @@ int sysfs_get_int(const char *id, char *subsys, char *param, int *value) + return EIO; + + *value = atoi(sysfs_value); ++ free(sysfs_value); + return 0; + } + +@@ -619,6 +582,7 @@ int sysfs_get_str(char *id, char *subsys, char *param, char *value, + sysfs_value[len - 1] = '\0'; + strncpy(value, sysfs_value, value_size); + value[value_size - 1] = '\0'; ++ free(sysfs_value); + return 0; + } + +@@ -631,8 +595,11 @@ int sysfs_get_uint64(char *id, char *subsys, char *param, uint64_t *value) + if (!sysfs_value) + return EIO; + +- if (sscanf(sysfs_value, "%" PRIu64 "\n", value) != 1) ++ if (sscanf(sysfs_value, "%" PRIu64 "\n", value) != 1) { ++ free(sysfs_value); + return EINVAL; ++ } ++ free(sysfs_value); + return 0; + } + +@@ -647,6 +614,7 @@ int sysfs_get_uint8(char *id, char *subsys, char *param, + return EIO; + + *value = (uint8_t)atoi(sysfs_value); ++ free(sysfs_value); + return 0; + } + +@@ -661,6 +629,7 @@ int sysfs_get_uint16(char *id, char *subsys, char *param, + return EIO; + + *value = (uint16_t)atoi(sysfs_value); ++ free(sysfs_value); + return 0; + } + +-- +2.5.5 + diff --git a/SOURCES/open-iscsi-2.0-873-safe-logout-flashnode.patch b/SOURCES/open-iscsi-2.0-873-safe-logout-flashnode.patch new file mode 100755 index 00000000..346a905c --- /dev/null +++ b/SOURCES/open-iscsi-2.0-873-safe-logout-flashnode.patch @@ -0,0 +1,585 @@ +From 4d3d30ea5bcb917fed58f1cb57154de5e6ce2349 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Fri, 24 Jul 2015 14:18:30 -0700 +Subject: [PATCH] share session use checks with iscsiadm, apply for flashnode + session + +--- + usr/Makefile | 8 +- + usr/initiator.c | 196 +---------------------------------------- + usr/initiator.h | 1 + + usr/initiator_common.c | 3 + + usr/iscsiadm.c | 23 +++++ + usr/iscsistart.c | 2 + + usr/mntcheck.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 268 insertions(+), 199 deletions(-) + create mode 100644 usr/mntcheck.c + +diff --git a/usr/Makefile b/usr/Makefile +index b2c1504..93b03d5 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -54,15 +54,15 @@ DISCOVERY_SRCS = $(FW_BOOT_SRCS) strings.o discovery.o + all: $(PROGRAMS) + + iscsid: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(DISCOVERY_SRCS) \ +- iscsid.o session_mgmt.o discoveryd.o ++ iscsid.o session_mgmt.o discoveryd.o mntcheck.o + $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lmount + +-iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o +- $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns ++iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o mntcheck.o ++ $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lmount + + iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \ + iscsistart.o statics.o +- $(CC) $(CFLAGS) -static $^ -o $@ -lmount ++ $(CC) $(CFLAGS) -static $^ -o $@ + clean: + rm -f *.o $(PROGRAMS) .depend $(LIBSYS) + +diff --git a/usr/initiator.c b/usr/initiator.c +index 1b4c90a..701b9a5 100644 +--- a/usr/initiator.c ++++ b/usr/initiator.c +@@ -30,7 +30,6 @@ + #include + #include + #include +-#include + + #include "initiator.h" + #include "transport.h" +@@ -2141,199 +2140,6 @@ static int session_unbind(struct iscsi_session *session) + return err; + } + +-static struct libmnt_table *mtab, *swaps; +-static struct libmnt_cache *mntcache; +- +-static void libmount_cleanup(void) +-{ +- mnt_free_table(mtab); +- mnt_free_table(swaps); +- mnt_free_cache(mntcache); +- mtab = swaps = mntcache = NULL; +-} +- +-static int libmount_init(void) +-{ +- mnt_init_debug(0); +- mtab = mnt_new_table(); +- swaps = mnt_new_table(); +- mntcache = mnt_new_cache(); +- if (!mtab || !swaps || !mntcache) { +- libmount_cleanup(); +- return -ENOMEM; +- } +- mnt_table_set_cache(mtab, mntcache); +- mnt_table_set_cache(swaps, mntcache); +- mnt_table_parse_mtab(mtab, NULL); +- mnt_table_parse_swaps(swaps, NULL); +- return 0; +-} +- +-static int trans_filter(const struct dirent *d) +-{ +- if (!strcmp(".", d->d_name) || !strcmp("..", d->d_name)) +- return 0; +- return 1; +-} +- +-static int subdir_filter(const struct dirent *d) +-{ +- if (!(d->d_type & DT_DIR)) +- return 0; +- return trans_filter(d); +-} +- +-static int is_partition(const char *path) +-{ +- char *devtype; +- int rc = 0; +- +- devtype = sysfs_get_uevent_devtype(path); +- if (!devtype) +- return 0; +- if (strcmp(devtype, "partition") == 0) +- rc = 1; +- free(devtype); +- return rc; +-} +- +-static int blockdev_check_mnts(char *syspath) +-{ +- struct libmnt_fs *fs; +- char *devname = NULL; +- char *_devname = NULL; +- int rc = 0; +- +- devname = sysfs_get_uevent_devname(syspath); +- if (!devname) +- goto out; +- +- _devname = calloc(1, PATH_MAX); +- if (!_devname) +- goto out; +- snprintf(_devname, PATH_MAX, "/dev/%s", devname); +- +- fs = mnt_table_find_source(mtab, _devname, MNT_ITER_FORWARD); +- if (fs) { +- rc = 1; +- goto out; +- } +- fs = mnt_table_find_source(swaps, _devname, MNT_ITER_FORWARD); +- if (fs) +- rc = 1; +-out: +- free(devname); +- free(_devname); +- return rc; +-} +- +-static int count_device_users(char *syspath); +- +-static int blockdev_get_partitions(char *syspath) +-{ +- struct dirent **parts = NULL; +- int n, i; +- int count = 0; +- +- n = scandir(syspath, &parts, subdir_filter, alphasort); +- for (i = 0; i < n; i++) { +- char *newpath; +- +- newpath = calloc(1, PATH_MAX); +- if (!newpath) +- continue; +- snprintf(newpath, PATH_MAX, "%s/%s", syspath, parts[i]->d_name); +- free(parts[i]); +- if (is_partition(newpath)) { +- count += count_device_users(newpath); +- } +- free(newpath); +- } +- free(parts); +- return count; +-} +- +-static int blockdev_get_holders(char *syspath) +-{ +- char *path = NULL; +- struct dirent **holds = NULL; +- int n, i; +- int count = 0; +- +- path = calloc(1, PATH_MAX); +- if (!path) +- return 0; +- snprintf(path, PATH_MAX, "%s/holders", syspath); +- +- n = scandir(path, &holds, trans_filter, alphasort); +- for (i = 0; i < n; i++) { +- char *newpath; +- char *rp; +- +- newpath = calloc(1, PATH_MAX); +- if (!newpath) +- continue; +- snprintf(newpath, PATH_MAX, "%s/%s", path, holds[i]->d_name); +- +- free(holds[i]); +- rp = realpath(newpath, NULL); +- if (rp) +- count += count_device_users(rp); +- free(newpath); +- free(rp); +- } +- free(path); +- free(holds); +- return count; +-} +- +-static int count_device_users(char *syspath) +-{ +- int count = 0; +- count += blockdev_check_mnts(syspath); +- count += blockdev_get_partitions(syspath); +- count += blockdev_get_holders(syspath); +- return count; +-}; +- +-static void device_in_use(void *data, int host_no, int target, int lun) +-{ +- char *syspath = NULL; +- char *devname = NULL; +- int *count = data; +- +- devname = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun); +- if (!devname) +- goto out; +- syspath = calloc(1, PATH_MAX); +- if (!syspath) +- goto out; +- snprintf(syspath, PATH_MAX, "/sys/class/block/%s", devname); +- *count += count_device_users(syspath); +-out: +- free(syspath); +- free(devname); +-} +- +-static int session_in_use(int sid) +-{ +- int host_no = -1, err = 0; +- int count = 0; +- +- if (libmount_init()) { +- log_error("Failed to initialize libmount, " +- "not checking for active mounts on session [%d].\n", sid); +- return 0; +- } +- +- host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err); +- if (!err) +- iscsi_sysfs_for_each_device(&count, host_no, sid, device_in_use); +- +- libmount_cleanup(); +- return count; +-} +- + int session_logout_task(int sid, queue_task_t *qtask) + { + iscsi_session_t *session; +@@ -2363,7 +2169,7 @@ invalid_state: + + if (dconfig->safe_logout && session_in_use(sid)) { + log_error("Session is actively in use for mounted storage, " +- "and iscsid.safe_logout is configured.\n"); ++ "and iscsid.safe_logout is configured."); + return ISCSI_ERR_BUSY; + } + +diff --git a/usr/initiator.h b/usr/initiator.h +index c34625b..e8bce45 100644 +--- a/usr/initiator.h ++++ b/usr/initiator.h +@@ -360,4 +360,5 @@ extern int iscsi_set_net_config(struct iscsi_transport *t, + struct iface_rec *iface); + extern void iscsi_session_init_params(struct iscsi_session *session); + ++extern int session_in_use(int sid); + #endif /* INITIATOR_H */ +diff --git a/usr/initiator_common.c b/usr/initiator_common.c +index 8ff993d..4e574b4 100644 +--- a/usr/initiator_common.c ++++ b/usr/initiator_common.c +@@ -23,6 +23,8 @@ + #include + #include + #include ++#include ++#include + + #include "initiator.h" + #include "transport.h" +@@ -741,3 +743,4 @@ int iscsi_host_set_net_params(struct iface_rec *iface, + } + return 0; + } ++ +diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c +index f886d39..d5d38b1 100644 +--- a/usr/iscsiadm.c ++++ b/usr/iscsiadm.c +@@ -1898,11 +1898,34 @@ exit_logout: + return rc; + } + ++static int iscsi_check_session_use_count(uint32_t sid) { ++ char *config_file; ++ char *safe_logout; ++ ++ config_file = get_config_file(); ++ if (!config_file) { ++ log_error("Could not get config file from iscsid"); ++ return 0; ++ } ++ ++ safe_logout = cfg_get_string_param(config_file, "iscsid.safe_logout"); ++ if (!safe_logout || strcmp(safe_logout, "Yes")) ++ return 0; ++ ++ return session_in_use(sid); ++} ++ + int iscsi_logout_flashnode_sid(struct iscsi_transport *t, uint32_t host_no, + uint32_t sid) + { + int fd, rc = 0; + ++ if (iscsi_check_session_use_count(sid)) { ++ log_error("Session is actively in use for mounted storage, " ++ "and iscsid.safe_logout is configured."); ++ return ISCSI_ERR_BUSY; ++ } ++ + fd = ipc->ctldev_open(); + if (fd < 0) { + log_error("Netlink open failed."); +diff --git a/usr/iscsistart.c b/usr/iscsistart.c +index 6924d49..26ba014 100644 +--- a/usr/iscsistart.c ++++ b/usr/iscsistart.c +@@ -279,6 +279,8 @@ static int setup_session(void) + return rc; + } + ++int session_in_use(int sid) { return 0; } ++ + static void catch_signal(int signo) + { + log_warning("pid %d caught signal -%d", getpid(), signo); +diff --git a/usr/mntcheck.c b/usr/mntcheck.c +new file mode 100644 +index 0000000..57bf007 +--- /dev/null ++++ b/usr/mntcheck.c +@@ -0,0 +1,234 @@ ++/* ++ * Common code for checking sessions for mnt use ++ * ++ * Copyright (C) 2014 - 2015 Chris Leech ++ * Copyright (C) 2014 - 2015 Red Hat, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "initiator.h" ++#include "transport.h" ++#include "iscsid.h" ++#include "iscsi_ipc.h" ++#include "log.h" ++#include "iscsi_sysfs.h" ++#include "iscsi_settings.h" ++#include "iface.h" ++#include "host.h" ++#include "sysdeps.h" ++#include "iscsi_err.h" ++#include "iscsi_net_util.h" ++ ++static struct libmnt_table *mtab, *swaps; ++static struct libmnt_cache *mntcache; ++ ++static void libmount_cleanup(void) ++{ ++ mnt_free_table(mtab); ++ mnt_free_table(swaps); ++ mnt_free_cache(mntcache); ++ mtab = NULL; ++ swaps = NULL; ++ mntcache = NULL; ++} ++ ++static int libmount_init(void) ++{ ++ mnt_init_debug(0); ++ mtab = mnt_new_table(); ++ swaps = mnt_new_table(); ++ mntcache = mnt_new_cache(); ++ if (!mtab || !swaps || !mntcache) { ++ libmount_cleanup(); ++ return -ENOMEM; ++ } ++ mnt_table_set_cache(mtab, mntcache); ++ mnt_table_set_cache(swaps, mntcache); ++ mnt_table_parse_mtab(mtab, NULL); ++ mnt_table_parse_swaps(swaps, NULL); ++ return 0; ++} ++ ++static int trans_filter(const struct dirent *d) ++{ ++ if (!strcmp(".", d->d_name) || !strcmp("..", d->d_name)) ++ return 0; ++ return 1; ++} ++ ++static int subdir_filter(const struct dirent *d) ++{ ++ if (!(d->d_type & DT_DIR)) ++ return 0; ++ return trans_filter(d); ++} ++ ++static int is_partition(const char *path) ++{ ++ char *devtype; ++ int rc = 0; ++ ++ devtype = sysfs_get_uevent_devtype(path); ++ if (!devtype) ++ return 0; ++ if (strcmp(devtype, "partition") == 0) ++ rc = 1; ++ free(devtype); ++ return rc; ++} ++ ++static int blockdev_check_mnts(char *syspath) ++{ ++ struct libmnt_fs *fs; ++ char *devname = NULL; ++ char *_devname = NULL; ++ int rc = 0; ++ ++ devname = sysfs_get_uevent_devname(syspath); ++ if (!devname) ++ goto out; ++ ++ _devname = calloc(1, PATH_MAX); ++ if (!_devname) ++ goto out; ++ snprintf(_devname, PATH_MAX, "/dev/%s", devname); ++ ++ fs = mnt_table_find_source(mtab, _devname, MNT_ITER_FORWARD); ++ if (fs) { ++ rc = 1; ++ goto out; ++ } ++ fs = mnt_table_find_source(swaps, _devname, MNT_ITER_FORWARD); ++ if (fs) ++ rc = 1; ++out: ++ free(devname); ++ free(_devname); ++ return rc; ++} ++ ++static int count_device_users(char *syspath); ++ ++static int blockdev_get_partitions(char *syspath) ++{ ++ struct dirent **parts = NULL; ++ int n, i; ++ int count = 0; ++ ++ n = scandir(syspath, &parts, subdir_filter, alphasort); ++ for (i = 0; i < n; i++) { ++ char *newpath; ++ ++ newpath = calloc(1, PATH_MAX); ++ if (!newpath) ++ continue; ++ snprintf(newpath, PATH_MAX, "%s/%s", syspath, parts[i]->d_name); ++ free(parts[i]); ++ if (is_partition(newpath)) { ++ count += count_device_users(newpath); ++ } ++ free(newpath); ++ } ++ free(parts); ++ return count; ++} ++ ++static int blockdev_get_holders(char *syspath) ++{ ++ char *path = NULL; ++ struct dirent **holds = NULL; ++ int n, i; ++ int count = 0; ++ ++ path = calloc(1, PATH_MAX); ++ if (!path) ++ return 0; ++ snprintf(path, PATH_MAX, "%s/holders", syspath); ++ ++ n = scandir(path, &holds, trans_filter, alphasort); ++ for (i = 0; i < n; i++) { ++ char *newpath; ++ char *rp; ++ ++ newpath = calloc(1, PATH_MAX); ++ if (!newpath) ++ continue; ++ snprintf(newpath, PATH_MAX, "%s/%s", path, holds[i]->d_name); ++ ++ free(holds[i]); ++ rp = realpath(newpath, NULL); ++ if (rp) ++ count += count_device_users(rp); ++ free(newpath); ++ free(rp); ++ } ++ free(path); ++ free(holds); ++ return count; ++} ++ ++static int count_device_users(char *syspath) ++{ ++ int count = 0; ++ count += blockdev_check_mnts(syspath); ++ count += blockdev_get_partitions(syspath); ++ count += blockdev_get_holders(syspath); ++ return count; ++}; ++ ++static void device_in_use(void *data, int host_no, int target, int lun) ++{ ++ char *syspath = NULL; ++ char *devname = NULL; ++ int *count = data; ++ ++ devname = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun); ++ if (!devname) ++ goto out; ++ syspath = calloc(1, PATH_MAX); ++ if (!syspath) ++ goto out; ++ snprintf(syspath, PATH_MAX, "/sys/class/block/%s", devname); ++ *count += count_device_users(syspath); ++out: ++ free(syspath); ++ free(devname); ++} ++ ++int session_in_use(int sid) ++{ ++ int host_no = -1, err = 0; ++ int count = 0; ++ ++ if (libmount_init()) { ++ log_error("Failed to initialize libmount, " ++ "not checking for active mounts on session [%d].\n", sid); ++ return 0; ++ } ++ ++ host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err); ++ if (!err) ++ iscsi_sysfs_for_each_device(&count, host_no, sid, device_in_use); ++ ++ libmount_cleanup(); ++ return count; ++} ++ +-- +2.1.0 + diff --git a/SOURCES/open-iscsi-2.0.873-125-iscsid-safe-session-logout.patch b/SOURCES/open-iscsi-2.0.873-125-iscsid-safe-session-logout.patch new file mode 100755 index 00000000..47c4904a --- /dev/null +++ b/SOURCES/open-iscsi-2.0.873-125-iscsid-safe-session-logout.patch @@ -0,0 +1,354 @@ +From 46ba8eed79fa13b32947b5c5b1bf0bc133b14c41 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 3 Feb 2015 16:28:15 -0800 +Subject: [PATCH] iscsid safe session logout + +Implement a safe logout option, which uses libmount from util-linux to +check for active mounts (and swaps) over devices, their partitions, and +any holders (like LVM and multipath device maps). When enabled iscsid +will refuse to logout of sessions actively being used for mounts, +returning a status of EBUSY to the ipc request. + +I've made it a configuration option (iscsid.safe_logout) that defaults +to "No" to preserve the existing behavior as the default, while making +it available for users that prefer a safety check. + +This does add a new dependency on libmount. + +Signed-off-by: Chris Leech +--- + etc/iscsid.conf | 3 + + usr/Makefile | 4 +- + usr/initiator.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + usr/sysfs.c | 40 ++++++++++++ + usr/sysfs.h | 4 ++ + 5 files changed, 248 insertions(+), 2 deletions(-) + +diff --git a/etc/iscsid.conf b/etc/iscsid.conf +index ef76dc0..6d9a5c0 100644 +--- a/etc/iscsid.conf ++++ b/etc/iscsid.conf +@@ -22,6 +22,9 @@ + # Default for upstream open-iscsi scripts (uncomment to activate). + iscsid.startup = /sbin/iscsid + ++# Check for active mounts on devices reachable through a session ++# and refuse to logout if there are any. Defaults to "No". ++# iscsid.safe_logout = Yes + + ############################# + # NIC/HBA and driver settings +diff --git a/usr/Makefile b/usr/Makefile +index 3d8ee22..b2c1504 100644 +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -55,14 +55,14 @@ all: $(PROGRAMS) + + iscsid: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(DISCOVERY_SRCS) \ + iscsid.o session_mgmt.o discoveryd.o +- $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns ++ $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lmount + + iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o + $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns + + iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \ + iscsistart.o statics.o +- $(CC) $(CFLAGS) -static $^ -o $@ ++ $(CC) $(CFLAGS) -static $^ -o $@ -lmount + clean: + rm -f *.o $(PROGRAMS) .depend $(LIBSYS) + +diff --git a/usr/initiator.c b/usr/initiator.c +index 9d02f47..ac1a3ac 100644 +--- a/usr/initiator.c ++++ b/usr/initiator.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + #include "initiator.h" + #include "transport.h" +@@ -2140,11 +2141,200 @@ static int session_unbind(struct iscsi_session *session) + return err; + } + ++static struct libmnt_table *mtab, *swaps; ++ ++static void libmount_cleanup(void) ++{ ++ mnt_free_table(mtab); ++ mnt_free_table(swaps); ++ mtab = swaps = NULL; ++} ++ ++static int libmount_init(void) ++{ ++ mnt_init_debug(0); ++ mtab = mnt_new_table(); ++ swaps = mnt_new_table(); ++ if (!mtab || !swaps) { ++ libmount_cleanup(); ++ return -ENOMEM; ++ } ++ mnt_table_parse_mtab(mtab, NULL); ++ mnt_table_parse_swaps(swaps, NULL); ++ return 0; ++} ++ ++static int trans_filter(const struct dirent *d) ++{ ++ if (!strcmp(".", d->d_name) || !strcmp("..", d->d_name)) ++ return 0; ++ return 1; ++} ++ ++static int subdir_filter(const struct dirent *d) ++{ ++ if (!(d->d_type & DT_DIR)) ++ return 0; ++ return trans_filter(d); ++} ++ ++static int is_partition(const char *path) ++{ ++ char *devtype; ++ int rc = 0; ++ ++ devtype = sysfs_get_uevent_devtype(path); ++ if (!devtype) ++ return 0; ++ if (strcmp(devtype, "partition") == 0) ++ rc = 1; ++ free(devtype); ++ return rc; ++} ++ ++static int blockdev_check_mnts(char *syspath) ++{ ++ struct libmnt_fs *fs; ++ char *devname = NULL; ++ char *_devname = NULL; ++ int rc = 0; ++ ++ devname = sysfs_get_uevent_devname(syspath); ++ if (!devname) ++ goto out; ++ ++ _devname = calloc(1, PATH_MAX); ++ if (!_devname) ++ goto out; ++ snprintf(_devname, PATH_MAX, "/dev/%s", devname); ++ ++ fs = mnt_table_find_source(mtab, _devname, MNT_ITER_FORWARD); ++ if (fs) { ++ rc = 1; ++ goto out; ++ } ++ fs = mnt_table_find_source(swaps, _devname, MNT_ITER_FORWARD); ++ if (fs) ++ rc = 1; ++out: ++ free(devname); ++ free(_devname); ++ return rc; ++} ++ ++static int count_device_users(char *syspath); ++ ++static int blockdev_get_partitions(char *syspath) ++{ ++ struct dirent **parts = NULL; ++ int n, i; ++ int count = 0; ++ ++ n = scandir(syspath, &parts, subdir_filter, alphasort); ++ for (i = 0; i < n; i++) { ++ char *newpath; ++ ++ newpath = calloc(1, PATH_MAX); ++ if (!newpath) ++ continue; ++ snprintf(newpath, PATH_MAX, "%s/%s", syspath, parts[i]->d_name); ++ free(parts[i]); ++ if (is_partition(newpath)) { ++ count += count_device_users(newpath); ++ } ++ free(newpath); ++ } ++ free(parts); ++ return count; ++} ++ ++static int blockdev_get_holders(char *syspath) ++{ ++ char *path = NULL; ++ struct dirent **holds = NULL; ++ int n, i; ++ int count = 0; ++ ++ path = calloc(1, PATH_MAX); ++ if (!path) ++ return 0; ++ snprintf(path, PATH_MAX, "%s/holders", syspath); ++ ++ n = scandir(path, &holds, trans_filter, alphasort); ++ for (i = 0; i < n; i++) { ++ char *newpath; ++ char *rp; ++ ++ newpath = calloc(1, PATH_MAX); ++ if (!newpath) ++ continue; ++ snprintf(newpath, PATH_MAX, "%s/%s", path, holds[i]->d_name); ++ ++ free(holds[i]); ++ rp = realpath(newpath, NULL); ++ if (rp) ++ count += count_device_users(rp); ++ free(newpath); ++ free(rp); ++ } ++ free(path); ++ free(holds); ++ return count; ++} ++ ++static int count_device_users(char *syspath) ++{ ++ int count = 0; ++ count += blockdev_check_mnts(syspath); ++ count += blockdev_get_partitions(syspath); ++ count += blockdev_get_holders(syspath); ++ return count; ++}; ++ ++static void device_in_use(void *data, int host_no, int target, int lun) ++{ ++ char *syspath = NULL; ++ char *devname = NULL; ++ int *count = data; ++ ++ devname = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun); ++ if (!devname) ++ goto out; ++ syspath = calloc(1, PATH_MAX); ++ if (!syspath) ++ goto out; ++ snprintf(syspath, PATH_MAX, "/sys/class/block/%s", devname); ++ *count += count_device_users(syspath); ++out: ++ free(syspath); ++ free(devname); ++} ++ ++static int session_in_use(int sid) ++{ ++ int host_no = -1, err = 0; ++ int count = 0; ++ ++ if (libmount_init()) { ++ log_error("Failed to initialize libmount, " ++ "not checking for active mounts on session [%d].\n", sid); ++ return 0; ++ } ++ ++ host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err); ++ if (!err) ++ iscsi_sysfs_for_each_device(&count, host_no, sid, device_in_use); ++ ++ libmount_cleanup(); ++ return count; ++} ++ + int session_logout_task(int sid, queue_task_t *qtask) + { + iscsi_session_t *session; + iscsi_conn_t *conn; + int rc = ISCSI_SUCCESS; ++ char *safe; + + session = session_find_by_sid(sid); + if (!session) { +@@ -2167,6 +2357,15 @@ invalid_state: + return ISCSI_ERR_INTERNAL; + } + ++ safe = cfg_get_string_param(dconfig->config_file, "iscsid.safe_logout"); ++ if (safe && !strcmp(safe, "Yes") && session_in_use(sid)) { ++ log_error("Session is actively in use for mounted storage, " ++ "and iscsid.safe_logout is configured.\n"); ++ free(safe); ++ return ISCSI_ERR_BUSY; ++ } ++ free(safe); ++ + /* FIXME: logout all active connections */ + conn = &session->conn[0]; + if (conn->logout_qtask) +diff --git a/usr/sysfs.c b/usr/sysfs.c +index d00c925..bbb00c0 100644 +--- a/usr/sysfs.c ++++ b/usr/sysfs.c +@@ -709,3 +709,43 @@ int sysfs_set_param(char *id, char *subsys, char *attr_name, + close(fd); + return rc; + } ++ ++char *sysfs_get_uevent_field(const char *path, const char *field) ++{ ++ char *uevent_path = NULL; ++ FILE *f = NULL; ++ char *line, buffer[1024]; ++ char *ff, *d; ++ char *out = NULL; ++ ++ uevent_path = calloc(1, PATH_MAX); ++ if (!uevent_path) ++ return NULL; ++ snprintf(uevent_path, PATH_MAX, "%s/uevent", path); ++ ++ f = fopen(uevent_path, "r"); ++ if (!f) ++ goto out; ++ while ((line = fgets(buffer, sizeof (buffer), f))) { ++ ff = strtok(line, "="); ++ d = strtok(NULL, "\n"); ++ if (strcmp(ff, field)) ++ continue; ++ out = strdup(d); ++ break; ++ } ++ fclose(f); ++out: ++ free(uevent_path); ++ return out; ++} ++ ++char *sysfs_get_uevent_devtype(const char *path) ++{ ++ return sysfs_get_uevent_field(path, "DEVTYPE"); ++} ++ ++char *sysfs_get_uevent_devname(const char *path) ++{ ++ return sysfs_get_uevent_field(path, "DEVNAME"); ++} +diff --git a/usr/sysfs.h b/usr/sysfs.h +index 304dbbf..462060e 100644 +--- a/usr/sysfs.h ++++ b/usr/sysfs.h +@@ -66,4 +66,8 @@ extern int sysfs_get_uint16(char *id, char *subsys, char *param, + extern int sysfs_set_param(char *id, char *subsys, char *attr_name, + char *write_buf, ssize_t buf_size); + ++extern char *sysfs_get_uevent_field(const char *path, const char *field); ++extern char *sysfs_get_uevent_devtype(const char *path); ++extern char *sysfs_get_uevent_devname(const char *path); ++ + #endif +-- +2.1.0 + diff --git a/SOURCES/open-iscsi-2.0.873-126-iscsid-don-t-re-read-config-file-for-every-session-l.patch b/SOURCES/open-iscsi-2.0.873-126-iscsid-don-t-re-read-config-file-for-every-session-l.patch new file mode 100755 index 00000000..51163da3 --- /dev/null +++ b/SOURCES/open-iscsi-2.0.873-126-iscsid-don-t-re-read-config-file-for-every-session-l.patch @@ -0,0 +1,82 @@ +From 006270c0f9a1fa1e78574a7eaa04bb9ae1ef62b6 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Thu, 12 Feb 2015 16:38:00 -0800 +Subject: [PATCH] iscsid: don't re-read config file for every session logout + +Follow up to the safe_logout feature patch. +Cache the safe_logout setting when iscsid is started. + +Signed-off-by: Chris Leech +--- + usr/initiator.c | 6 +----- + usr/iscsid.c | 6 ++++++ + usr/iscsid.h | 1 + + 3 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/usr/initiator.c b/usr/initiator.c +index 2f17882..b25ded8 100644 +--- a/usr/initiator.c ++++ b/usr/initiator.c +@@ -2333,7 +2333,6 @@ int session_logout_task(int sid, queue_task_t *qtask) + iscsi_session_t *session; + iscsi_conn_t *conn; + int rc = ISCSI_SUCCESS; +- char *safe; + + session = session_find_by_sid(sid); + if (!session) { +@@ -2356,14 +2355,11 @@ invalid_state: + return ISCSI_ERR_INTERNAL; + } + +- safe = cfg_get_string_param(dconfig->config_file, "iscsid.safe_logout"); +- if (safe && !strcmp(safe, "Yes") && session_in_use(sid)) { ++ if (dconfig->safe_logout && session_in_use(sid)) { + log_error("Session is actively in use for mounted storage, " + "and iscsid.safe_logout is configured.\n"); +- free(safe); + return ISCSI_ERR_BUSY; + } +- free(safe); + + /* FIXME: logout all active connections */ + conn = &session->conn[0]; +diff --git a/usr/iscsid.c b/usr/iscsid.c +index f4f4f38..033a71f 100644 +--- a/usr/iscsid.c ++++ b/usr/iscsid.c +@@ -341,6 +341,7 @@ int main(int argc, char *argv[]) + char *config_file = CONFIG_FILE; + char *initiatorname_file = INITIATOR_NAME_FILE; + char *pid_file = PID_FILE; ++ char *safe_logout; + int ch, longindex; + uid_t uid = 0; + struct sigaction sa_old; +@@ -520,6 +521,11 @@ int main(int argc, char *argv[]) + daemon_config.initiator_name : "NOT SET"); + log_debug(1, "InitiatorAlias=%s", daemon_config.initiator_alias); + ++ safe_logout = cfg_get_string_param(config_file, "iscsid.safe_logout"); ++ if (safe_logout && !strcmp(safe_logout, "Yes")) ++ daemon_config.safe_logout = 1; ++ free(safe_logout); ++ + pid = fork(); + if (pid == 0) { + int nr_found = 0; +diff --git a/usr/iscsid.h b/usr/iscsid.h +index 15f264f..b9f3d54 100644 +--- a/usr/iscsid.h ++++ b/usr/iscsid.h +@@ -29,6 +29,7 @@ struct iscsi_daemon_config { + char *pid_file; + char *initiator_name; + char *initiator_alias; ++ int safe_logout; + }; + extern struct iscsi_daemon_config *dconfig; + +-- +2.1.0 + diff --git a/SOURCES/open-iscsi-2.0.873-Revert-ISCSIUIO-Fixed-a-pthread-resc-leak-from-exces.patch b/SOURCES/open-iscsi-2.0.873-Revert-ISCSIUIO-Fixed-a-pthread-resc-leak-from-exces.patch new file mode 100644 index 00000000..0649dcd4 --- /dev/null +++ b/SOURCES/open-iscsi-2.0.873-Revert-ISCSIUIO-Fixed-a-pthread-resc-leak-from-exces.patch @@ -0,0 +1,238 @@ +From 2c50348a9f93ef81c30d898b5ab8f1e36b927003 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Thu, 18 Aug 2016 13:06:16 -0700 +Subject: [PATCH] Revert "ISCSIUIO: Fixed a pthread resc leak from excessive + session recovery" + +This reverts commit fabe160ee191fb57f826d991bcb433dd2467fdc9. +--- + iscsiuio/RELEASE.TXT | 12 ------------ + iscsiuio/src/unix/iscsid_ipc.c | 26 +++++++++++++------------- + iscsiuio/src/unix/main.c | 5 +---- + iscsiuio/src/unix/nic.c | 23 +++++++++++++++++++++-- + iscsiuio/src/unix/nic_utils.c | 5 +---- + 5 files changed, 36 insertions(+), 35 deletions(-) + +diff --git a/iscsiuio/RELEASE.TXT b/iscsiuio/RELEASE.TXT +index 44d67f9..19ef717 100644 +--- a/iscsiuio/RELEASE.TXT ++++ b/iscsiuio/RELEASE.TXT +@@ -11,18 +11,6 @@ + Copyright (c) 2014, QLogic Corporation + All rights reserved + +-uIP v0.7.10.2 (Feb 12, 2014) +-======================================================= +- Fixes +- ----- +- 1. Problem: Cont00072504 - ifconfig shows allocation failure after +- up/down few hours with iSCSI + L2 traffic +- Cause: A memory leak was discovered in the ongoing pthread creation +- destruction code during the connection recovery process +- Change: Fixed the pthread creation code +- Impact: All +- +- + uIP v0.7.8.2 (Dec 10, 2013) + ======================================================= + Fixes +diff --git a/iscsiuio/src/unix/iscsid_ipc.c b/iscsiuio/src/unix/iscsid_ipc.c +index a2a59a8..7790dc5 100644 +--- a/iscsiuio/src/unix/iscsid_ipc.c ++++ b/iscsiuio/src/unix/iscsid_ipc.c +@@ -396,9 +396,9 @@ static int parse_iface(void *arg, int do_ping) + char ipv6_buf_str[INET6_ADDRSTRLEN]; + int request_type = 0; + struct iface_rec *rec; ++ void *res; + struct iface_rec_decode ird; + struct in_addr src_match, dst_match; +- pthread_attr_t attr; + struct ping_conf *png_c; + + data = (iscsid_uip_broadcast_t *) arg; +@@ -665,9 +665,7 @@ static int parse_iface(void *arg, int do_ping) + + nic_iface->flags |= NIC_IFACE_PATHREQ_WAIT1; + if (nic->nl_process_thread == INVALID_THREAD) { +- pthread_attr_init(&attr); +- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); +- rc = pthread_create(&nic->nl_process_thread, &attr, ++ rc = pthread_create(&nic->nl_process_thread, NULL, + nl_process_handle_thread, nic); + if (rc != 0) { + LOG_ERR(PFX "%s: Could not create NIC NL " +@@ -818,16 +816,14 @@ enable_nic: + case NIC_STOPPED: + /* This thread will be thrown away when completed */ + if (nic->enable_thread != INVALID_THREAD) { +- rc = pthread_cancel(nic->enable_thread); ++ rc = pthread_join(nic->enable_thread, &res); + if (rc != 0) { +- LOG_INFO(PFX "%s: failed to cancel enable NIC " ++ LOG_INFO(PFX "%s: failed joining enable NIC " + "thread\n", nic->log_name); + goto eagain; + } + } +- pthread_attr_init(&attr); +- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); +- rc = pthread_create(&nic->enable_thread, &attr, ++ rc = pthread_create(&nic->enable_thread, NULL, + enable_nic_thread, (void *)nic); + if (rc != 0) + LOG_WARN(PFX "%s: failed starting enable NIC thread\n", +@@ -1169,12 +1165,9 @@ error: + */ + int iscsid_start() + { +- pthread_attr_t attr; + int rc; + +- pthread_attr_init(&attr); +- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); +- rc = pthread_create(&iscsid_opts.thread, &attr, iscsid_loop, NULL); ++ rc = pthread_create(&iscsid_opts.thread, NULL, iscsid_loop, NULL); + if (rc != 0) { + LOG_ERR(PFX "Could not start iscsid listening thread rc=%d", + rc); +@@ -1197,6 +1190,7 @@ error: + void iscsid_cleanup() + { + int rc; ++ void *res; + + if (iscsid_opts.fd != INVALID_FD) { + rc = pthread_cancel(iscsid_opts.thread); +@@ -1204,6 +1198,12 @@ void iscsid_cleanup() + LOG_ERR("Could not cancel iscsid listening thread: %s", + strerror(rc)); + } ++ ++ rc = pthread_join(iscsid_opts.thread, &res); ++ if (rc != 0) { ++ LOG_ERR("Could not wait for the iscsid listening " ++ "thread: %s", strerror(rc)); ++ } + } + + LOG_INFO(PFX "iscsid listening thread has shutdown"); +diff --git a/iscsiuio/src/unix/main.c b/iscsiuio/src/unix/main.c +index c1a72d8..bbf8f9c 100644 +--- a/iscsiuio/src/unix/main.c ++++ b/iscsiuio/src/unix/main.c +@@ -236,7 +236,6 @@ int main(int argc, char *argv[]) + int fd; + int foreground = 0; + pid_t pid; +- pthread_attr_t attr; + + /* Record the start time for the user space daemon */ + opt.start_time = time(NULL); +@@ -366,9 +365,7 @@ int main(int argc, char *argv[]) + rc = pthread_sigmask(SIG_SETMASK, &set, NULL); + + /* Spin off the signal handling thread */ +- pthread_attr_init(&attr); +- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); +- rc = pthread_create(&signal_thread, &attr, signal_handle_thread, NULL); ++ rc = pthread_create(&signal_thread, NULL, signal_handle_thread, NULL); + if (rc != 0) + LOG_ERR("Could not create signal handling thread"); + +diff --git a/iscsiuio/src/unix/nic.c b/iscsiuio/src/unix/nic.c +index 74b7c5e..0d4965d 100644 +--- a/iscsiuio/src/unix/nic.c ++++ b/iscsiuio/src/unix/nic.c +@@ -465,6 +465,7 @@ int nic_remove(nic_t *nic) + int rc; + nic_t *prev, *current; + struct stat file_stat; ++ void *res; + nic_interface_t *nic_iface, *next_nic_iface, *vlan_iface; + + pthread_mutex_lock(&nic->nic_mutex); +@@ -487,6 +488,12 @@ int nic_remove(nic_t *nic) + LOG_DEBUG(PFX "%s: Couldn't send cancel to nic enable " + "thread", nic->log_name); + ++ LOG_DEBUG(PFX "%s: Waiting to join nic enable thread", ++ nic->log_name); ++ rc = pthread_join(nic->enable_thread, &res); ++ if (rc != 0) ++ LOG_DEBUG(PFX "%s: Couldn't join to canceled enable " ++ "nic thread", nic->log_name); + nic->enable_thread = INVALID_THREAD; + LOG_DEBUG(PFX "%s: nic enable thread cleaned", nic->log_name); + } else { +@@ -502,6 +509,11 @@ int nic_remove(nic_t *nic) + LOG_DEBUG(PFX "%s: Couldn't send cancel to nic", + nic->log_name); + ++ LOG_DEBUG(PFX "%s: Waiting to join nic thread", nic->log_name); ++ rc = pthread_join(nic->thread, &res); ++ if (rc != 0) ++ LOG_DEBUG(PFX "%s: Couldn't join to canceled nic " ++ "thread", nic->log_name); + nic->thread = INVALID_THREAD; + LOG_DEBUG(PFX "%s: nic thread cleaned", nic->log_name); + } else { +@@ -516,6 +528,12 @@ int nic_remove(nic_t *nic) + LOG_DEBUG(PFX "%s: Couldn't send cancel to nic nl " + "thread", nic->log_name); + ++ LOG_DEBUG(PFX "%s: Waiting to join nic nl thread", ++ nic->log_name); ++ rc = pthread_join(nic->nl_process_thread, &res); ++ if (rc != 0) ++ LOG_DEBUG(PFX "%s: Couldn't join to canceled nic nl " ++ "thread", nic->log_name); + nic->nl_process_thread = INVALID_THREAD; + LOG_DEBUG(PFX "%s: nic nl thread cleaned", nic->log_name); + } else { +@@ -1236,6 +1254,7 @@ static int do_acquisition(nic_t *nic, nic_interface_t *nic_iface, + { + struct in_addr addr; + struct in6_addr addr6; ++ void *res; + char buf[INET6_ADDRSTRLEN]; + int rc = -1; + +@@ -1309,9 +1328,9 @@ static int do_acquisition(nic_t *nic, nic_interface_t *nic_iface, + if (nic->enable_thread == INVALID_THREAD) + goto dhcp_err; + +- rc = pthread_cancel(nic->enable_thread); ++ rc = pthread_join(nic->enable_thread, &res); + if (rc != 0) +- LOG_ERR(PFX "%s: Couldn't cancel " ++ LOG_ERR(PFX "%s: Couldn't join to canceled " + "enable nic thread", nic->log_name); + dhcp_err: + pthread_mutex_lock(&nic->nic_mutex); +diff --git a/iscsiuio/src/unix/nic_utils.c b/iscsiuio/src/unix/nic_utils.c +index 0daffd2..cbed986 100644 +--- a/iscsiuio/src/unix/nic_utils.c ++++ b/iscsiuio/src/unix/nic_utils.c +@@ -893,7 +893,6 @@ error: + + void prepare_nic_thread(nic_t *nic) + { +- pthread_attr_t attr; + int rc; + + pthread_mutex_lock(&nic->nic_mutex); +@@ -904,9 +903,7 @@ void prepare_nic_thread(nic_t *nic) + LOG_INFO(PFX "%s: spinning up thread for nic", nic->log_name); + + /* Try to spin up the nic thread */ +- pthread_attr_init(&attr); +- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); +- rc = pthread_create(&nic->thread, &attr, nic_loop, nic); ++ rc = pthread_create(&nic->thread, NULL, nic_loop, nic); + if (rc != 0) { + LOG_ERR(PFX "%s: Couldn't create thread for nic", + nic->log_name); +-- +2.5.5 + diff --git a/SOURCES/open-iscsi-2.0.873-fix-device-path-canonicalization-by-using-libmount-c.patch b/SOURCES/open-iscsi-2.0.873-fix-device-path-canonicalization-by-using-libmount-c.patch new file mode 100755 index 00000000..f00ded3d --- /dev/null +++ b/SOURCES/open-iscsi-2.0.873-fix-device-path-canonicalization-by-using-libmount-c.patch @@ -0,0 +1,47 @@ +From b6c9ebe86c45d0a318ec9bb42a6373b4f77a1ba7 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 21 Jul 2015 16:15:30 -0700 +Subject: [PATCH 1/1] fix device path canonicalization by using libmount cache + +--- + usr/initiator.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/usr/initiator.c b/usr/initiator.c +index 3b39c5d..0519d46 100644 +--- a/usr/initiator.c ++++ b/usr/initiator.c +@@ -2141,12 +2141,14 @@ static int session_unbind(struct iscsi_session *session) + } + + static struct libmnt_table *mtab, *swaps; ++static struct libmnt_cache *mntcache; + + static void libmount_cleanup(void) + { + mnt_free_table(mtab); + mnt_free_table(swaps); +- mtab = swaps = NULL; ++ mnt_free_cache(mntcache); ++ mtab = swaps = mntcache = NULL; + } + + static int libmount_init(void) +@@ -2154,10 +2156,13 @@ static int libmount_init(void) + mnt_init_debug(0); + mtab = mnt_new_table(); + swaps = mnt_new_table(); +- if (!mtab || !swaps) { ++ mntcache = mnt_new_cache(); ++ if (!mtab || !swaps || !mntcache) { + libmount_cleanup(); + return -ENOMEM; + } ++ mnt_table_set_cache(mtab, mntcache); ++ mnt_table_set_cache(swaps, mntcache); + mnt_table_parse_mtab(mtab, NULL); + mnt_table_parse_swaps(swaps, NULL); + return 0; +-- +2.1.0 + diff --git a/SOURCES/open-iscsi-2.0.874-1-iBFT-origin-is-an-enum-not-a-string.patch b/SOURCES/open-iscsi-2.0.874-1-iBFT-origin-is-an-enum-not-a-string.patch new file mode 100644 index 00000000..b688f2cf --- /dev/null +++ b/SOURCES/open-iscsi-2.0.874-1-iBFT-origin-is-an-enum-not-a-string.patch @@ -0,0 +1,29 @@ +From 3f15a2270a7efb1a6ee8ef555b01f3d8674818b9 Mon Sep 17 00:00:00 2001 +From: Lee Duncan +Date: Fri, 10 Jul 2015 11:58:55 -0700 +Subject: iBFT 'origin' is an enum, not a string + +A recent change, commit 4959a89f421fdebc, modified open-iscsi +to treat the "origin" field as an enum, not a character +string. But one spot was missed. +--- + utils/fwparam_ibft/fwparam_ibft_sysfs.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/utils/fwparam_ibft/fwparam_ibft_sysfs.c b/utils/fwparam_ibft/fwparam_ibft_sysfs.c +index 2dc6f6d5fe54..019fc19184bb 100644 +--- a/utils/fwparam_ibft/fwparam_ibft_sysfs.c ++++ b/utils/fwparam_ibft/fwparam_ibft_sysfs.c +@@ -201,8 +201,7 @@ static int fill_nic_context(char *id, struct boot_context *context) + sizeof(context->secondary_dns)); + sysfs_get_str(id, IBFT_SUBSYS, "dhcp", context->dhcp, + sizeof(context->dhcp)); +- sysfs_get_str(id, IBFT_SUBSYS, "origin", context->origin, +- sizeof(context->origin)); ++ sysfd_get_int(id, IBFT_SUBSYS, "origin", &context->origin); + return 0; + } + +-- +2.9.3 + diff --git a/SOURCES/open-iscsi-2.0.874-23-Fix-manual-LUN-scans-feature.patch b/SOURCES/open-iscsi-2.0.874-23-Fix-manual-LUN-scans-feature.patch new file mode 100644 index 00000000..b4b7aa6a --- /dev/null +++ b/SOURCES/open-iscsi-2.0.874-23-Fix-manual-LUN-scans-feature.patch @@ -0,0 +1,62 @@ +From d5483b0df96bd2a1cf86039cf4c6822ec7d7f609 Mon Sep 17 00:00:00 2001 +From: Gorka Eguileor +Date: Fri, 17 Mar 2017 16:00:11 +0100 +Subject: Fix manual LUN scans feature + +The newly introduced feature to disable automatic scans should not be +scanning *any* of the LUNs when the scan is set to manual, but it always +scans for LUN0. + +This patch fixes this by skipping the sysfs call altogether, as it +should have been doing from the start. +--- + usr/iscsi_sysfs.c | 13 +++++++------ + usr/iscsi_sysfs.h | 2 +- + 2 files changed, 8 insertions(+), 7 deletions(-) + +diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c +index 2f94b632baaa..0cc55b97bde9 100644 +--- a/usr/iscsi_sysfs.c ++++ b/usr/iscsi_sysfs.c +@@ -1883,18 +1883,19 @@ void iscsi_sysfs_rescan_device(void *data, int hostno, int target, int lun) + strlen(write_buf)); + } + +-pid_t iscsi_sysfs_scan_host(int hostno, int async, int full_scan) ++pid_t iscsi_sysfs_scan_host(int hostno, int async, int autoscan) + { + char id[NAME_SIZE]; +- char write_buf[6] = "- - 0"; ++ char *write_buf = "- - -"; + pid_t pid = 0; + +- if (full_scan) +- write_buf[4] = '-'; +- + if (async) + pid = fork(); +- if (pid == 0) { ++ ++ if (pid >= 0 && !autoscan) { ++ if (pid) ++ log_debug(4, "host%d in manual scan mode, skipping scan", hostno); ++ } else if (pid == 0) { + /* child */ + log_debug(4, "scanning host%d", hostno); + +diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h +index 3492ce6e033c..cdcefa65f683 100644 +--- a/usr/iscsi_sysfs.h ++++ b/usr/iscsi_sysfs.h +@@ -87,7 +87,7 @@ extern void iscsi_sysfs_get_negotiated_session_conf(int sid, + struct iscsi_session_operational_config *conf); + extern void iscsi_sysfs_get_negotiated_conn_conf(int sid, + struct iscsi_conn_operational_config *conf); +-extern pid_t iscsi_sysfs_scan_host(int hostno, int async, int full); ++extern pid_t iscsi_sysfs_scan_host(int hostno, int async, int autoscan); + extern int iscsi_sysfs_get_session_state(char *state, int sid); + extern int iscsi_sysfs_get_host_state(char *state, int host_no); + extern int iscsi_sysfs_get_device_state(char *state, int host_no, int target, +-- +2.9.3 + diff --git a/SOURCES/open-iscsi-2.0.874-27-iscsid-Add-qedi-ping-transport-hook.patch b/SOURCES/open-iscsi-2.0.874-27-iscsid-Add-qedi-ping-transport-hook.patch new file mode 100644 index 00000000..617db22b --- /dev/null +++ b/SOURCES/open-iscsi-2.0.874-27-iscsid-Add-qedi-ping-transport-hook.patch @@ -0,0 +1,28 @@ +From f910837dace250418cba4155a6708d47d45075cc Mon Sep 17 00:00:00 2001 +From: Nilesh Javili +Date: Thu, 27 Apr 2017 17:59:00 -0700 +Subject: iscsid: Add qedi ping transport hook + +iscsiuio ping is operational for qedi. +Add missing qedi transport hook for ping support. + +Signed-off-by: Nilesh Javali +--- + usr/transport.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/usr/transport.c b/usr/transport.c +index 533ba30a8846..3b7a00a2245e 100644 +--- a/usr/transport.c ++++ b/usr/transport.c +@@ -124,6 +124,7 @@ struct iscsi_transport_template qedi = { + .ep_poll = ktransport_ep_poll, + .ep_disconnect = ktransport_ep_disconnect, + .set_net_config = uip_broadcast_params, ++ .exec_ping = uip_broadcast_ping_req, + }; + + static struct iscsi_transport_template *iscsi_transport_templates[] = { +-- +2.9.3 + diff --git a/SOURCES/open-iscsi-2.0.874-30-isolate-iscsistart-socket-use.patch b/SOURCES/open-iscsi-2.0.874-30-isolate-iscsistart-socket-use.patch new file mode 100644 index 00000000..d5a73dbe --- /dev/null +++ b/SOURCES/open-iscsi-2.0.874-30-isolate-iscsistart-socket-use.patch @@ -0,0 +1,111 @@ +From 2a463c04a75726e811161f435e2f6736d70a66bd Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 20 Jun 2017 09:35:23 -0700 +Subject: isolate iscsistart socket use + +--- + usr/iscsid_req.c | 12 +++++++++++- + usr/iscsid_req.h | 3 +++ + usr/iscsistart.c | 6 ++++++ + usr/mgmt_ipc.c | 3 ++- + usr/mgmt_ipc.h | 1 - + 5 files changed, 22 insertions(+), 3 deletions(-) + +diff --git a/usr/iscsid_req.c b/usr/iscsid_req.c +index 2950d748c644..69351c6c61ea 100644 +--- a/usr/iscsid_req.c ++++ b/usr/iscsid_req.c +@@ -96,9 +96,19 @@ static int ipc_connect(int *fd, char *unix_sock_name, int start_iscsid) + return ISCSI_ERR_ISCSID_NOTCONN; + } + ++char iscsid_namespace[64] = ISCSIADM_NAMESPACE; ++ ++void iscsid_set_namespace(pid_t pid) { ++ if (pid) { ++ snprintf(iscsid_namespace, 64, ISCSIADM_NAMESPACE "-%d", pid); ++ } else { ++ snprintf(iscsid_namespace, 64, ISCSIADM_NAMESPACE); ++ } ++} ++ + static int iscsid_connect(int *fd, int start_iscsid) + { +- return ipc_connect(fd, ISCSIADM_NAMESPACE, start_iscsid); ++ return ipc_connect(fd, iscsid_namespace, start_iscsid); + } + + int iscsid_request(int *fd, iscsiadm_req_t *req, int start_iscsid) +diff --git a/usr/iscsid_req.h b/usr/iscsid_req.h +index 8cb4a922f46d..ba7b2357c729 100644 +--- a/usr/iscsid_req.h ++++ b/usr/iscsid_req.h +@@ -25,6 +25,9 @@ struct iscsiadm_req; + struct iscsiadm_rsp; + struct node_rec; + ++extern char iscsid_namespace[64]; ++extern void iscsid_set_namespace(pid_t); ++ + extern int iscsid_exec_req(struct iscsiadm_req *req, struct iscsiadm_rsp *rsp, + int iscsid_start); + extern int iscsid_req_wait(int cmd, int fd); +diff --git a/usr/iscsistart.c b/usr/iscsistart.c +index ecb256b3c2f6..538dd2f9d780 100644 +--- a/usr/iscsistart.c ++++ b/usr/iscsistart.c +@@ -458,6 +458,10 @@ int main(int argc, char *argv[]) + } else if (pid) { + int status, rc, rc2; + ++ /* make a special socket path for only this iscsistart instance */ ++ iscsid_set_namespace(pid); ++ sleep(1); ++ + rc = setup_session(); + rc2 = stop_event_loop(); + /* +@@ -475,6 +478,9 @@ int main(int argc, char *argv[]) + exit(0); + } + ++ pid = getpid(); ++ iscsid_set_namespace(pid); ++ + mgmt_ipc_fd = mgmt_ipc_listen(); + if (mgmt_ipc_fd < 0) { + log_error("Could not setup mgmt ipc"); +diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c +index c16bce962232..140d358ec5da 100644 +--- a/usr/mgmt_ipc.c ++++ b/usr/mgmt_ipc.c +@@ -37,6 +37,7 @@ + #include "iscsi_ipc.h" + #include "iscsi_err.h" + #include "iscsi_util.h" ++#include "iscsid_req.h" + + #define PEERUSER_MAX 64 + #define EXTMSG_MAX (64 * 1024) +@@ -60,7 +61,7 @@ mgmt_ipc_listen(void) + return fd; + } + +- addr_len = setup_abstract_addr(&addr, ISCSIADM_NAMESPACE); ++ addr_len = setup_abstract_addr(&addr, iscsid_namespace); + + if ((err = bind(fd, (struct sockaddr *) &addr, addr_len)) < 0 ) { + log_error("Can not bind IPC socket"); +diff --git a/usr/mgmt_ipc.h b/usr/mgmt_ipc.h +index 55972ed793a1..b6b836fc07c1 100644 +--- a/usr/mgmt_ipc.h ++++ b/usr/mgmt_ipc.h +@@ -115,5 +115,4 @@ int mgmt_ipc_listen(void); + int mgmt_ipc_systemd(void); + void mgmt_ipc_close(int fd); + void mgmt_ipc_handle(int accept_fd); +- + #endif /* MGMT_IPC_H */ +-- +2.9.4 + diff --git a/SOURCES/open-iscsi-2.0.874-4-iscsid-treat-SIGTERM-like-iscsiadm-k-0.patch b/SOURCES/open-iscsi-2.0.874-4-iscsid-treat-SIGTERM-like-iscsiadm-k-0.patch new file mode 100644 index 00000000..de2661e9 --- /dev/null +++ b/SOURCES/open-iscsi-2.0.874-4-iscsid-treat-SIGTERM-like-iscsiadm-k-0.patch @@ -0,0 +1,35 @@ +From c3122e9aedc4ebb49090df86e6f53806fed6cebc Mon Sep 17 00:00:00 2001 +From: Lee Duncan +Date: Wed, 23 Nov 2016 14:50:35 -0800 +Subject: iscsid: treat SIGTERM like "iscsiadm -k 0" + +The same code that is executed by iscsid +when iscsiadm sends the "immediate stop" +command should be executed when iscsid +receives a SIGTERM. + +Changes since v1: + * now just set the "event loop stop" flag + +Signed-off-by: Lee Duncan +--- + usr/iscsid.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/usr/iscsid.c b/usr/iscsid.c +index 0c2634448d09..81a14f259b5f 100644 +--- a/usr/iscsid.c ++++ b/usr/iscsid.c +@@ -313,8 +313,7 @@ static void catch_signal(int signo) + + switch (signo) { + case SIGTERM: +- iscsid_shutdown(); +- exit(0); ++ event_loop_exit(NULL); + break; + default: + break; +-- +2.9.3 + diff --git a/SOURCES/open-iscsi-2.0.874-5-Make-event_loop_stop-volatile-for-safer-access.patch b/SOURCES/open-iscsi-2.0.874-5-Make-event_loop_stop-volatile-for-safer-access.patch new file mode 100644 index 00000000..45ed088d --- /dev/null +++ b/SOURCES/open-iscsi-2.0.874-5-Make-event_loop_stop-volatile-for-safer-access.patch @@ -0,0 +1,33 @@ +From 3951c242d266689a8c856717b02b07c1fe193a31 Mon Sep 17 00:00:00 2001 +From: Lee Duncan +Date: Fri, 2 Dec 2016 09:22:02 -0800 +Subject: Make event_loop_stop volatile for safer access + +As suggested by Christian Seiler: +"Only minor thing is that you might want to mark +static int event_loop_stop; (usr/event_poll.c) +to be volatile, to be on the safe side when modifying it +from within a signal handler. Probably not really required +here (the compiler is not allowed to optimize out the +access anyway, since you call non-static functions within +the loop), but it doesn't hurt either, just in case... " +--- + usr/event_poll.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/usr/event_poll.c b/usr/event_poll.c +index 209ee0280c0a..ac2504404366 100644 +--- a/usr/event_poll.c ++++ b/usr/event_poll.c +@@ -123,7 +123,7 @@ static int shutdown_wait_pids(void) + #define POLL_ALARM 2 + #define POLL_MAX 3 + +-static int event_loop_stop; ++static volatile int event_loop_stop; + static queue_task_t *shutdown_qtask; + + void event_loop_exit(queue_task_t *qtask) +-- +2.9.3 + diff --git a/SOURCES/open-iscsi-2.0.874-7-Allow-disabling-auto-LUN-scans.patch b/SOURCES/open-iscsi-2.0.874-7-Allow-disabling-auto-LUN-scans.patch new file mode 100644 index 00000000..22930213 --- /dev/null +++ b/SOURCES/open-iscsi-2.0.874-7-Allow-disabling-auto-LUN-scans.patch @@ -0,0 +1,265 @@ +From 5e32aea95741a07d53153c658a0572588eae494d Mon Sep 17 00:00:00 2001 +From: Gorka Eguileor +Date: Tue, 21 Feb 2017 20:01:39 +0100 +Subject: Allow disabling auto LUN scans + +Existing behavior of auto scanning LUNs is problematic for some +deployments, particularly in cases where we are: + +- Accessing different LUNs from the same target on different machines + and we don't want the other LUNs automatically exposed in other + systems. + +- LUNs are constantly being created and removed from the target by + another machine and we don't want our systems polluted by no longer + available logical units, since default udev rules don't remove them + automatically from the system once they have been added automatically. + +This is a little more problematic when working with multipaths as we end +up with a lot of leftover device maps. + +This patch introduces a new configuration option at the session level +called "scan", with "auto" and "manual" as acceptable values, that +allows us to disable the autoscan in the following cases: + +- On iscsid start +- On login +- On AEN/AER messages reporting LUNs data has changed. + +For HW drivers all sessions will use the value defined in the +configuration file. + +Default value for this new option is "auto" to maintain existing +behavior. +--- + etc/iscsid.conf | 8 ++++++++ + usr/config.h | 1 + + usr/idbm.c | 14 +++++++++++++- + usr/idbm.h | 1 + + usr/idbm_fields.h | 1 + + usr/initiator.c | 5 +++-- + usr/iscsi_settings.h | 3 +++ + usr/iscsi_sysfs.c | 7 +++++-- + usr/iscsi_sysfs.h | 2 +- + usr/iscsiadm.c | 2 +- + usr/iscsid.c | 2 +- + usr/iscsistart.c | 3 +++ + 12 files changed, 41 insertions(+), 8 deletions(-) + +diff --git a/etc/iscsid.conf b/etc/iscsid.conf +index f7ecb6b3c2ab..cb77a777062d 100644 +--- a/etc/iscsid.conf ++++ b/etc/iscsid.conf +@@ -305,3 +305,11 @@ node.session.iscsi.FastAbort = Yes + # a task management function like an ABORT TASK or LOGICAL UNIT RESET, that + # it continue to respond to R2Ts. To enable this uncomment this line + # node.session.iscsi.FastAbort = No ++ ++# To prevent doing automatic scans that would add unwanted luns to the system ++# we can disable them and have sessions only do manually requested scans. ++# Automatic scans are performed on startup, on login, and on AEN/AER reception ++# on devices supporting it. For HW drivers all sessions will use the value ++# defined in the configuration file. This configuration option is independent ++# of scsi_mod scan parameter. (The default behavior is auto): ++node.session.scan = auto +diff --git a/usr/config.h b/usr/config.h +index 5b1bb1d624c5..3bcb93fe7322 100644 +--- a/usr/config.h ++++ b/usr/config.h +@@ -190,6 +190,7 @@ typedef struct session_rec { + int queue_depth; + int initial_login_retry_max; + int nr_sessions; ++ int scan; + struct iscsi_auth_config auth; + struct iscsi_session_timeout_config timeo; + struct iscsi_error_timeout_config err_timeo; +diff --git a/usr/idbm.c b/usr/idbm.c +index 3b8a5a20bec8..ff8d67f64c51 100644 +--- a/usr/idbm.c ++++ b/usr/idbm.c +@@ -462,6 +462,9 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) + session.iscsi.MaxOutstandingR2T, IDBM_SHOW, num, 1); + __recinfo_int(SESSION_ERL, ri, r, + session.iscsi.ERL, IDBM_SHOW, num, 1); ++ __recinfo_int_o2(SESSION_SCAN, ri, r, ++ session.scan, IDBM_SHOW, "manual", "auto", ++ num, 1); + + for (i = 0; i < ISCSI_CONN_MAX; i++) { + char key[NAME_MAXVAL]; +@@ -2490,7 +2493,7 @@ static void idbm_rm_disc_node_links(char *disc_dir) + log_debug(5, "disc removal removing link %s %s %s %s", + target, address, port, iface_id); + +- memset(rec, 0, sizeof(*rec)); ++ memset(rec, 0, sizeof(*rec)); + strlcpy(rec->name, target, TARGET_NAME_MAXLEN); + rec->tpgt = atoi(tpgt); + rec->conn[0].port = atoi(port); +@@ -2726,6 +2729,14 @@ idbm_slp_defaults(struct iscsi_slp_config *cfg) + sizeof(struct iscsi_slp_config)); + } + ++int ++idbm_session_autoscan(struct iscsi_session *session) ++{ ++ if (session) ++ return session->nrec.session.scan; ++ return db->nrec.session.scan; ++} ++ + struct user_param *idbm_alloc_user_param(char *name, char *value) + { + struct user_param *param; +@@ -2981,6 +2992,7 @@ void idbm_node_setup_defaults(node_rec_t *rec) + rec->session.info = NULL; + rec->session.sid = 0; + rec->session.multiple = 0; ++ rec->session.scan = DEF_INITIAL_SCAN; + idbm_setup_session_defaults(&rec->session.iscsi); + + for (i=0; ihostno, NULL); + break; + case ISCSI_ASYNC_MSG_REQUEST_LOGOUT: +diff --git a/usr/iscsi_settings.h b/usr/iscsi_settings.h +index 3d923c8ba029..296ff403b1e5 100644 +--- a/usr/iscsi_settings.h ++++ b/usr/iscsi_settings.h +@@ -45,3 +45,6 @@ + + /* login retries */ + #define DEF_INITIAL_LOGIN_RETRIES_MAX 4 ++ ++/* autoscan enabled */ ++#define DEF_INITIAL_SCAN 1 +diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c +index 8ca668fdb3bc..2f94b632baaa 100644 +--- a/usr/iscsi_sysfs.c ++++ b/usr/iscsi_sysfs.c +@@ -1883,12 +1883,15 @@ void iscsi_sysfs_rescan_device(void *data, int hostno, int target, int lun) + strlen(write_buf)); + } + +-pid_t iscsi_sysfs_scan_host(int hostno, int async) ++pid_t iscsi_sysfs_scan_host(int hostno, int async, int full_scan) + { + char id[NAME_SIZE]; +- char *write_buf = "- - -"; ++ char write_buf[6] = "- - 0"; + pid_t pid = 0; + ++ if (full_scan) ++ write_buf[4] = '-'; ++ + if (async) + pid = fork(); + if (pid == 0) { +diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h +index 9a56105165b3..3492ce6e033c 100644 +--- a/usr/iscsi_sysfs.h ++++ b/usr/iscsi_sysfs.h +@@ -87,7 +87,7 @@ extern void iscsi_sysfs_get_negotiated_session_conf(int sid, + struct iscsi_session_operational_config *conf); + extern void iscsi_sysfs_get_negotiated_conn_conf(int sid, + struct iscsi_conn_operational_config *conf); +-extern pid_t iscsi_sysfs_scan_host(int hostno, int async); ++extern pid_t iscsi_sysfs_scan_host(int hostno, int async, int full); + extern int iscsi_sysfs_get_session_state(char *state, int sid); + extern int iscsi_sysfs_get_host_state(char *state, int host_no); + extern int iscsi_sysfs_get_device_state(char *state, int host_no, int target, +diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c +index 4b2bd34cbb2e..90e2828bcb79 100644 +--- a/usr/iscsiadm.c ++++ b/usr/iscsiadm.c +@@ -773,7 +773,7 @@ static int rescan_portal(void *data, struct session_info *info) + iscsi_sysfs_for_each_device(NULL, host_no, info->sid, + iscsi_sysfs_rescan_device); + /* now scan for new devices */ +- iscsi_sysfs_scan_host(host_no, 0); ++ iscsi_sysfs_scan_host(host_no, 0, 1); + return 0; + } + +diff --git a/usr/iscsid.c b/usr/iscsid.c +index 81a14f259b5f..813eb3da940d 100644 +--- a/usr/iscsid.c ++++ b/usr/iscsid.c +@@ -216,7 +216,7 @@ static int sync_session(void *data, struct session_info *info) + iscsi_err_to_str(err)); + return 0; + } +- iscsi_sysfs_scan_host(host_no, 0); ++ iscsi_sysfs_scan_host(host_no, 0, idbm_session_autoscan(NULL)); + return 0; + } + +diff --git a/usr/iscsistart.c b/usr/iscsistart.c +index 5cf09721636b..67ac47515f23 100644 +--- a/usr/iscsistart.c ++++ b/usr/iscsistart.c +@@ -140,6 +140,7 @@ static int apply_params(struct node_rec *rec) + rec->session.initial_login_retry_max = -1; + rec->conn[0].timeo.noop_out_interval = -1; + rec->conn[0].timeo.noop_out_timeout = -1; ++ rec->session.scan = -1; + + list_for_each_entry(param, &user_params, list) { + /* +@@ -183,6 +184,8 @@ static int apply_params(struct node_rec *rec) + rec->conn[0].timeo.noop_out_interval = 0; + if (rec->conn[0].timeo.noop_out_timeout == -1) + rec->conn[0].timeo.noop_out_timeout = 0; ++ if (rec->session.scan == -1) ++ rec->session.scan = DEF_INITIAL_SCAN; + + return 0; + } +-- +2.9.3 + diff --git a/SOURCES/open-iscsi-2.0.874-7-iscsid-Changes-to-support-the-new-qedi-transport.patch b/SOURCES/open-iscsi-2.0.874-7-iscsid-Changes-to-support-the-new-qedi-transport.patch new file mode 100644 index 00000000..11e4272e --- /dev/null +++ b/SOURCES/open-iscsi-2.0.874-7-iscsid-Changes-to-support-the-new-qedi-transport.patch @@ -0,0 +1,73 @@ +From dc939e78d6dab78f3fcddfada581fa402604bb51 Mon Sep 17 00:00:00 2001 +From: Nilesh Javali +Date: Fri, 11 Nov 2016 08:17:50 +0200 +Subject: iscsid: Changes to support the new qedi transport + +Signed-off-by: Manish Rangankar +Signed-off-by: Adheer Chandravanshi +Signed-off-by: Nilesh Javali +--- + usr/initiator_common.c | 2 +- + usr/transport.c | 13 +++++++++++++ + usr/transport.h | 1 + + 3 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/usr/initiator_common.c b/usr/initiator_common.c +index 1d1d82251ad4..191e779bb942 100644 +--- a/usr/initiator_common.c ++++ b/usr/initiator_common.c +@@ -700,7 +700,7 @@ int iscsi_host_set_net_params(struct iface_rec *iface, + netdev = hinfo.iface.netdev; + } + +- if (net_ifup_netdev(netdev)) ++ if (!t->template->no_netdev && net_ifup_netdev(netdev)) + log_warning("Could not brining up netdev %s. Try running " + "'ifup %s' first if login fails.", netdev, netdev); + +diff --git a/usr/transport.c b/usr/transport.c +index 18b770464608..533ba30a8846 100644 +--- a/usr/transport.c ++++ b/usr/transport.c +@@ -114,6 +114,18 @@ struct iscsi_transport_template ocs = { + .ep_disconnect = ktransport_ep_disconnect, + }; + ++struct iscsi_transport_template qedi = { ++ .name = "qedi", ++ .set_host_ip = SET_HOST_IP_REQ, ++ .use_boot_info = 1, ++ .bind_ep_required = 1, ++ .no_netdev = 1, ++ .ep_connect = ktransport_ep_connect, ++ .ep_poll = ktransport_ep_poll, ++ .ep_disconnect = ktransport_ep_disconnect, ++ .set_net_config = uip_broadcast_params, ++}; ++ + static struct iscsi_transport_template *iscsi_transport_templates[] = { + &iscsi_tcp, + &iscsi_iser, +@@ -123,6 +135,7 @@ static struct iscsi_transport_template *iscsi_transport_templates[] = { + &qla4xxx, + &be2iscsi, + &ocs, ++ &qedi, + NULL + }; + +diff --git a/usr/transport.h b/usr/transport.h +index 4d3bdbff67f8..b67776b47288 100644 +--- a/usr/transport.h ++++ b/usr/transport.h +@@ -39,6 +39,7 @@ struct iscsi_transport_template { + uint8_t set_host_ip; + uint8_t use_boot_info; + uint8_t bind_ep_required; ++ uint8_t no_netdev; + int (*ep_connect) (struct iscsi_conn *conn, int non_blocking); + int (*ep_poll) (struct iscsi_conn *conn, int timeout_ms); + void (*ep_disconnect) (struct iscsi_conn *conn); +-- +2.9.3 + diff --git a/SOURCES/open-iscsi-2.0.874-8-iscsiuio-Add-support-for-the-new-qedi-transport.patch b/SOURCES/open-iscsi-2.0.874-8-iscsiuio-Add-support-for-the-new-qedi-transport.patch new file mode 100644 index 00000000..83234c97 --- /dev/null +++ b/SOURCES/open-iscsi-2.0.874-8-iscsiuio-Add-support-for-the-new-qedi-transport.patch @@ -0,0 +1,1665 @@ +From 264e48a0bda2d6cd5d0607acd2669894ee95b3b5 Mon Sep 17 00:00:00 2001 +From: Nilesh Javali +Date: Fri, 11 Nov 2016 08:17:51 +0200 +Subject: iscsiuio: Add support for the new qedi transport + +Signed-off-by: Manish Rangankar +Signed-off-by: Adheer Chandravanshi +Signed-off-by: Nilesh Javali +--- + iscsiuio/src/unix/libs/Makefile.am | 3 +- + iscsiuio/src/unix/libs/cnic.c | 9 + + iscsiuio/src/unix/libs/cnic.h | 2 + + iscsiuio/src/unix/libs/qedi.c | 1151 ++++++++++++++++++++++++++++++++++++ + iscsiuio/src/unix/libs/qedi.h | 159 +++++ + iscsiuio/src/unix/nic.c | 6 +- + iscsiuio/src/unix/nic.h | 1 + + iscsiuio/src/unix/nic_utils.c | 147 ++++- + iscsiuio/src/unix/nic_utils.h | 2 + + iscsiuio/src/unix/options.h | 1 + + 10 files changed, 1475 insertions(+), 6 deletions(-) + create mode 100644 iscsiuio/src/unix/libs/qedi.c + create mode 100644 iscsiuio/src/unix/libs/qedi.h + +diff --git a/iscsiuio/src/unix/libs/Makefile.am b/iscsiuio/src/unix/libs/Makefile.am +index 890415f5a79a..737546b04917 100644 +--- a/iscsiuio/src/unix/libs/Makefile.am ++++ b/iscsiuio/src/unix/libs/Makefile.am +@@ -10,4 +10,5 @@ noinst_LIBRARIES = lib_iscsiuio_hw_cnic.a + lib_iscsiuio_hw_cnic_a_SOURCES = ../build_date.c \ + cnic.c \ + bnx2.c \ +- bnx2x.c ++ bnx2x.c \ ++ qedi.c +diff --git a/iscsiuio/src/unix/libs/cnic.c b/iscsiuio/src/unix/libs/cnic.c +index 228c4b9e25b1..5d60f898ad57 100644 +--- a/iscsiuio/src/unix/libs/cnic.c ++++ b/iscsiuio/src/unix/libs/cnic.c +@@ -55,6 +55,7 @@ + #include + #include + #include ++#include + + #include "uip_arp.h" + #include "nic.h" +@@ -65,6 +66,7 @@ + #include "cnic.h" + #include "iscsi_if.h" + #include "ipv6_ndpc.h" ++#include "qedi.h" + + /******************************************************************************* + * Constants +@@ -81,6 +83,13 @@ const char bnx2i_library_transport_name[] = "bnx2i"; + const size_t bnx2i_library_transport_name_size = + sizeof(bnx2i_library_transport_name); + ++/******************************************************************************* ++ * Constants for qedi module ++ ******************************************************************************/ ++const char qedi_library_transport_name[] = "qedi"; ++const size_t qedi_library_transport_name_size = ++ sizeof(qedi_library_transport_name); ++ + /****************************************************************************** + * Netlink Functions + ******************************************************************************/ +diff --git a/iscsiuio/src/unix/libs/cnic.h b/iscsiuio/src/unix/libs/cnic.h +index 6244a94012c1..c86595c512b0 100644 +--- a/iscsiuio/src/unix/libs/cnic.h ++++ b/iscsiuio/src/unix/libs/cnic.h +@@ -44,6 +44,8 @@ + ******************************************************************************/ + extern const char bnx2i_library_transport_name[]; + extern const size_t bnx2i_library_transport_name_size; ++extern const char qedi_library_transport_name[]; ++extern const size_t qedi_library_transport_name_size; + + int cnic_nl_open(); + void cnic_nl_close(); +diff --git a/iscsiuio/src/unix/libs/qedi.c b/iscsiuio/src/unix/libs/qedi.c +new file mode 100644 +index 000000000000..c2096e59dad1 +--- /dev/null ++++ b/iscsiuio/src/unix/libs/qedi.c +@@ -0,0 +1,1151 @@ ++/* ++ * Copyright (c) 2016, Cavium Inc. ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * qedi.c - qedi user space driver ++ * This file handles different qedi NIC operations, ++ * qedi_open - initializes all hardware resources under NIC device ++ * qedi_close - closes the NIC device ++ * qedi_read - reads data to the hardware ++ * qedi_write - writes data to the hardware ++ * qedi_start_xmit - sends a pkt of data on NIC device ++ * qedi_get_tx_pkt - gets a Tx pkt from NIC ++ * qedi_clear_tx_intr - clears the Tx interrupt ++ * NOTE: nic_t is used as NIC device, ++ * qedi is not attached to netdev hence it is not mandatory ++ * for netdev to be upd ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "config.h" ++ ++#include "build_date.h" ++#include "bnx2x.h" ++#include "qedi.h" ++#include "cnic.h" ++#include "logger.h" ++#include "nic.h" ++#include "nic_id.h" ++#include "nic_utils.h" ++#include "options.h" ++ ++#define PFX "qedi " ++ ++extern int nl_sock; ++ ++/* Foward struct declarations */ ++struct nic_ops qedi_op; ++ ++/******************************************************************************* ++ * NIC Library Strings ++ ******************************************************************************/ ++static const char library_name[] = "qedi"; ++static const char library_version[] = PACKAGE_VERSION; ++static const char library_uio_name[] = "qedi_uio"; ++ ++/* The name that should be returned from /sys/class/uio/uio0/name */ ++static const char cnic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name"; ++static const char qedi_uio_sysfs_name[] = "qedi_uio"; ++static const char qedi_host_mac_template[] = ++ "/sys/class/iscsi_host/host%i/hwaddress"; ++ ++struct qedi_driver_version qedi_version = { ++ QEDI_UNKNOWN_MAJOR_VERSION, ++ QEDI_UNKNOWN_MINOR_VERSION, ++ QEDI_UNKNOWN_SUB_MINOR_VERSION, ++}; ++ ++static int qedi_clear_tx_intr(nic_t *nic); ++ ++/******************************************************************************* ++ * QEDI Library Functions ++ ******************************************************************************/ ++/** ++ * qedi_get_library_name() - Used to get the name of this NIC library ++ * @param name - This function will return the pointer to this NIC ++ * library name ++ * @param name_size ++ */ ++static void qedi_get_library_name(char **name, size_t *name_size) ++{ ++ *name = (char *)library_name; ++ *name_size = sizeof(library_name); ++} ++ ++/** ++ * qedi_get_library_version() - Used to get the version string of this ++ * NIC library ++ * @param version - This function will return the pointer to this NIC ++ * library version string ++ * @param version_size - This will be set with the version size ++ */ ++static void qedi_get_library_version(char **version, size_t *version_size) ++{ ++ *version = (char *)library_version; ++ *version_size = sizeof(library_version); ++} ++ ++/** ++ * qedi_get_build_date() - Used to get the build date string of this library ++ * @param version - This function will return the pointer to this NIC ++ * library build date string ++ * @param version_size - This will be set with the build date string size ++ */ ++static void qedi_get_build_date(char **build, size_t *build_size) ++{ ++ *build = (char *)build_date; ++ *build_size = sizeof(build_date); ++} ++ ++/** ++ * qedi_get_transport_name() - Used to get the transport name associated ++ * with this this NIC library ++ * @param transport_name - This function will return the pointer to this NIC ++ * library's associated transport string ++ * @param transport_name_size - This will be set with the transport name size ++ */ ++static void qedi_get_transport_name(char **transport_name, ++ size_t *transport_name_size) ++{ ++ *transport_name = (char *)qedi_library_transport_name; ++ *transport_name_size = qedi_library_transport_name_size; ++} ++ ++/** ++ * qedi_get_uio_name() - Used to get the uio name associated with this this ++ * NIC library ++ * @param uio_name - This function will return the pointer to this NIC ++ * library's associated uio string ++ * @param transport_name_size - This will be set with the uio name size ++ */ ++static void qedi_get_uio_name(char **uio_name, size_t *uio_name_size) ++{ ++ *uio_name = (char *)library_uio_name; ++ *uio_name_size = sizeof(library_uio_name); ++} ++ ++/** ++ * qedi_get_ops() - Used to get the NIC library op table ++ * @param op - The op table of this NIC library ++ */ ++struct nic_ops *qedi_get_ops() ++{ ++ return &qedi_op; ++} ++ ++/******************************************************************************* ++ * qedi Utility Functions ++ ******************************************************************************/ ++/******************************************************************************* ++ * Utility Functions Used to read register from the qedi device ++ ******************************************************************************/ ++static void qedi_set_drv_version_unknown(qedi_t *bp) ++{ ++ bp->version.major = QEDI_UNKNOWN_MAJOR_VERSION; ++ bp->version.minor = QEDI_UNKNOWN_MINOR_VERSION; ++ bp->version.sub_minor = QEDI_UNKNOWN_SUB_MINOR_VERSION; ++} ++ ++/* Return: 1 = Unknown, 0 = Known */ ++static int qedi_is_drv_version_unknown(struct qedi_driver_version *version) ++{ ++ if ((version->major == (uint16_t)QEDI_UNKNOWN_MAJOR_VERSION) && ++ (version->minor == (uint16_t)QEDI_UNKNOWN_MINOR_VERSION) && ++ (version->sub_minor == (uint16_t)QEDI_UNKNOWN_SUB_MINOR_VERSION)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/** ++ * qedi_get_drv_version() - Used to determine the driver version ++ * @param bp - Device used to determine qedi driver version ++ */ ++static int qedi_get_drv_version(qedi_t *bp) ++{ ++ nic_t *nic = bp->parent; ++ ++ /* ++ * CAPABILITIES: Get the iscsi driver version from qedi ++ * This may be obtained from sysfs ++ */ ++ LOG_INFO(PFX "%s: qedi driver using version %d.%d.%d", ++ nic->log_name, ++ bp->version.major, bp->version.minor, bp->version.sub_minor); ++ ++ return 0; ++} ++ ++/******************************************************************************/ ++ ++/** ++ * qedi_get_chip_id() - Used to retrieve the chip ID from the nic ++ * @param dev - Device used to determin NIC type ++ * @return Chip ID read from the MISC ID register ++ */ ++static int qedi_get_chip_id(qedi_t *bp) ++{ ++ /* int val, id; */ ++ ++ /* Get the chip revision id and number. */ ++ /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ ++ /* ++ * CAPABILITIES: Get the CHIP info from qedi through sysfs or uio struct. ++ */ ++ return 0; ++} ++ ++/** ++ * qedi_uio_verify() ++ * ++ */ ++static int qedi_uio_verify(nic_t *nic) ++{ ++ char *raw = NULL, *raw_tmp; ++ uint32_t raw_size = 0; ++ char temp_path[sizeof(cnic_uio_sysfs_name_tempate) + 8]; ++ int rc = 0; ++ ++ /* Build the path to determine uio name */ ++ snprintf(temp_path, sizeof(temp_path), ++ cnic_uio_sysfs_name_tempate, nic->uio_minor); ++ ++ rc = capture_file(&raw, &raw_size, temp_path); ++ if (rc != 0) ++ goto error; ++ ++ /* sanitize name string by replacing newline with null termination */ ++ raw_tmp = raw; ++ while (*raw_tmp != '\n') ++ raw_tmp++; ++ *raw_tmp = '\0'; ++ ++ if (strncmp(raw, qedi_uio_sysfs_name, ++ sizeof(qedi_uio_sysfs_name)) != 0) { ++ LOG_ERR(PFX "%s: uio names not equal: expecting %s got %s from %s", ++ nic->log_name, qedi_uio_sysfs_name, raw, temp_path); ++ rc = -EIO; ++ } ++ ++ free(raw); ++ ++ LOG_INFO(PFX "%s: Verified is a qedi_uio device", nic->log_name); ++ ++error: ++ return rc; ++} ++ ++static int qedi_get_mac_addr(qedi_t *bp) ++{ ++ nic_t *nic = bp->parent; ++ char *raw = NULL, *raw_tmp; ++ uint32_t raw_size = 0; ++ char temp_path[sizeof(qedi_host_mac_template) + 8]; ++ int rc = 0; ++ ++ /* Build the path to determine mac address */ ++ snprintf(temp_path, sizeof(temp_path), ++ qedi_host_mac_template, nic->host_no); ++ ++ rc = capture_file(&raw, &raw_size, temp_path); ++ if (rc != 0) ++ goto error; ++ ++ /* sanitize name string by replacing newline with null termination */ ++ raw_tmp = raw; ++ while (*raw_tmp != '\n') ++ raw_tmp++; ++ *raw_tmp = '\0'; ++ ++ rc = sscanf(raw, "%02x:%02x:%02x:%02x:%02x:%02x", ++ (uint32_t *)&nic->mac_addr[0], (uint32_t *)&nic->mac_addr[1], ++ (uint32_t *)&nic->mac_addr[2], (uint32_t *)&nic->mac_addr[3], ++ (uint32_t *)&nic->mac_addr[4], (uint32_t *)&nic->mac_addr[5]); ++ if (rc != 1) { ++ LOG_WARN(PFX "%s: Could not parse mac_addr", ++ nic->log_name); ++ rc = -ENODEV; ++ goto error; ++ } ++ ++error: ++ if (raw) ++ free(raw); ++ return rc; ++} ++ ++/******************************************************************************* ++ * qedi Utility Functions to get to the hardware consumer indexes ++ ******************************************************************************/ ++ ++static __u32 qedi_get_rx(qedi_t *bp) ++{ ++ return ((struct qedi_uio_ctrl *)bp->uctrl_map)->host_rx_cons; ++} ++ ++static __u32 qedi_get_tx(qedi_t *bp) ++{ ++ return ((struct qedi_uio_ctrl *)bp->uctrl_map)->hw_tx_cons; ++} ++ ++/** ++ * qedi_free() - Used to free a qedi structure ++ */ ++static void qedi_free(nic_t *nic) ++{ ++ if (nic->priv) ++ free(nic->priv); ++ nic->priv = NULL; ++} ++ ++/** ++ * qedi_alloc() - Used to allocate a qedi structure ++ */ ++static qedi_t *qedi_alloc(nic_t *nic) ++{ ++ qedi_t *bp = malloc(sizeof(*bp)); ++ ++ if (!bp) { ++ LOG_ERR(PFX "%s: Could not allocate QEDI space", ++ nic->log_name); ++ return NULL; ++ } ++ ++ /* Clear out the CNIC contents */ ++ memset(bp, 0, sizeof(*bp)); ++ ++ bp->parent = nic; ++ nic->priv = (void *)bp; ++ get_iscsi_transport_handle(nic, &nic->transport_handle); ++ qedi_set_drv_version_unknown(bp); ++ ++ return bp; ++} ++ ++int uio_get_map_offset(nic_t *nic, uint8_t map, uint32_t *offset) ++{ ++ char *raw = NULL; ++ uint32_t raw_size = 0; ++ ssize_t elements_read; ++ char temp_path[sizeof(UIO_OFFSET_TMPL) + 8]; ++ int rc = 0; ++ ++ /* Capture RX buffer size */ ++ snprintf(temp_path, sizeof(temp_path), ++ UIO_OFFSET_TMPL, nic->uio_minor, map); ++ ++ rc = capture_file(&raw, &raw_size, temp_path); ++ if (rc != 0) ++ goto error; ++ ++ elements_read = sscanf(raw, "0x%x", offset); ++ if (elements_read != 1) { ++ LOG_ERR(PFX "%s: Couldn't get the offset from %s", ++ nic->log_name, temp_path); ++ rc = -EIO; ++ goto error; ++ } ++ ++ rc = 0; ++error: ++ if (raw) ++ free(raw); ++ ++ return rc; ++} ++ ++int uio_get_map_info(nic_t *nic, uint8_t map, char *attr, uint32_t *val) ++{ ++ char *raw = NULL; ++ uint32_t raw_size = 0; ++ ssize_t elements_read; ++ char temp_path[sizeof(UIO_ATTR_TMPL) + 8]; ++ int rc = 0; ++ ++ /* Capture RX buffer size */ ++ snprintf(temp_path, sizeof(temp_path), ++ UIO_ATTR_TMPL, nic->uio_minor, map, attr); ++ ++ rc = capture_file(&raw, &raw_size, temp_path); ++ if (rc != 0) ++ goto error; ++ ++ elements_read = sscanf(raw, "0x%x", val); ++ if (elements_read != 1) { ++ LOG_ERR(PFX "%s: Couldn't get the offset from %s", ++ nic->log_name, temp_path); ++ rc = -EIO; ++ goto error; ++ } ++ ++ rc = 0; ++error: ++ if (raw) ++ free(raw); ++ ++ return rc; ++} ++ ++/** ++ * qedi_open() - This will initialize all the hardware resources underneath ++ * a struct cnic_uio device ++ * @param dev - The struct cnic_uio device to attach the hardware with ++ * @return 0 on success, on failure a errno will be returned ++ */ ++static int qedi_open(nic_t *nic) ++{ ++ qedi_t *bp = NULL; ++ struct stat uio_stat; ++ int i, rc; ++ int count; ++ uint32_t bus; ++ uint32_t slot; ++ uint32_t func; ++ uint32_t offset; ++ ++ /* Sanity Check: validate the parameters */ ++ if (!nic) { ++ LOG_ERR(PFX "nic == NULL"); ++ return -EINVAL; ++ } ++ ++ if ((nic->priv) != NULL && ++ (((qedi_t *)(nic->priv))->flags & QEDI_OPENED)) { ++ return 0; ++ } ++ ++ if (nic->host_no == INVALID_HOST_NO) { ++ rc = sscanf(nic->config_device_name, "host%d", &nic->host_no); ++ if (rc != 1) { ++ LOG_WARN(PFX "%s: Could not parse for host number", ++ nic->config_device_name); ++ rc = -ENODEV; ++ goto open_error; ++ } ++ } ++ ++ bp = qedi_alloc(nic); ++ if (!bp) ++ return -ENOMEM; ++ ++ if (qedi_is_drv_version_unknown(&qedi_version)) { ++ /* If version is unknown, go read from ethtool */ ++ rc = qedi_get_drv_version(bp); ++ if (rc) ++ goto open_error; ++ } else { ++ /* Version is not unknown, just use it */ ++ qedi_version.major = bp->version.major; ++ qedi_version.minor = bp->version.minor; ++ qedi_version.sub_minor = bp->version.sub_minor; ++ } ++ ++ count = 0; ++ while ((nic->fd < 0) && count < 15) { ++ /* udev might not have created the file yet */ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ sleep(1); ++ pthread_mutex_lock(&nic->nic_mutex); ++ ++ nic->fd = open(nic->uio_device_name, O_RDWR | O_NONBLOCK); ++ if (nic->fd != INVALID_FD) { ++ LOG_ERR(PFX "%s: uio device has been brought up via pid: %d on fd: %d", ++ nic->uio_device_name, getpid(), nic->fd); ++ ++ rc = qedi_uio_verify(nic); ++ if (rc != 0) ++ continue; ++ ++ break; ++ } else { ++ LOG_WARN(PFX "%s: Could not open device: %s, [%s]", ++ nic->log_name, nic->uio_device_name, ++ strerror(errno)); ++ ++ manually_trigger_uio_event(nic, nic->uio_minor); ++ ++ /* udev might not have created the file yet */ ++ pthread_mutex_unlock(&nic->nic_mutex); ++ sleep(1); ++ pthread_mutex_lock(&nic->nic_mutex); ++ ++ count++; ++ } ++ } ++ if (fstat(nic->fd, &uio_stat) < 0) { ++ LOG_ERR(PFX "%s: Could not fstat device", nic->log_name); ++ rc = -ENODEV; ++ goto open_error; ++ } ++ nic->uio_minor = minor(uio_stat.st_rdev); ++ ++ /* ++ * CAPABILITIES: acquire the rx buffer size and rx ring size from qedi ++ */ ++ ++ bp->rx_ring_size = RX_RING_SIZE; ++ bp->rx_buffer_size = PKT_BUF_SIZE; ++ ++ LOG_DEBUG(PFX "%s: using rx ring size: %d, rx buffer size: %d", ++ nic->log_name, bp->rx_ring_size, bp->rx_buffer_size); ++ ++ /* Determine the number of UIO events that have already occurred */ ++ rc = detemine_initial_uio_events(nic, &nic->intr_count); ++ if (rc != 0) { ++ LOG_ERR(PFX "Could not get the no. of initial UIO events"); ++ nic->intr_count = 0; ++ } ++ ++ /* Allocate space for rx pkt ring */ ++ bp->rx_pkt_ring = malloc(sizeof(void *) * bp->rx_ring_size); ++ if (!bp->rx_pkt_ring) { ++ LOG_ERR(PFX "%s: Could not allocate space for rx_pkt_ring", ++ nic->log_name); ++ rc = errno; ++ goto open_error; ++ } ++ ++ /* ++ * Map the uio struct and packet buffer ++ */ ++ offset = 0; ++ rc = uio_get_map_info(nic, QEDI_UCTRL_MAP_REG, "size", &offset); ++ if (rc) { ++ LOG_INFO(PFX "Failed to get the map size rc=%d", rc); ++ goto open_error; ++ } ++ LOG_INFO(PFX "uctrl map size=%u", offset); ++ ++ offset = 0; ++ rc = uio_get_map_info(nic, QEDI_RING_MAP_REG, "size", &offset); ++ if (rc) { ++ LOG_INFO(PFX "Failed to get the map size rc=%d", rc); ++ goto open_error; ++ } ++ LOG_INFO(PFX "ring map size=%u", offset); ++ ++ offset = 0; ++ rc = uio_get_map_info(nic, QEDI_BUF_MAP_REG, "size", &offset); ++ if (rc) { ++ LOG_INFO(PFX "Failed to get the map size rc=%d", rc); ++ goto open_error; ++ } ++ LOG_INFO(PFX "buf map size=%u", offset); ++ ++ offset = 0; ++ rc = uio_get_map_offset(nic, QEDI_UCTRL_MAP_REG, &offset); ++ if (rc) { ++ LOG_INFO(PFX "Failed to get the map offset rc=%d", rc); ++ goto open_error; ++ } ++ ++ bp->uctrl_map = mmap(NULL, sizeof(struct qedi_uio_ctrl), ++ PROT_READ | PROT_WRITE, ++ MAP_SHARED | MAP_LOCKED, ++ nic->fd, (off_t)0); ++ if (bp->uctrl_map == MAP_FAILED) { ++ LOG_INFO(PFX "%s: Could not mmap uio ctrl struct: %s", ++ nic->log_name, strerror(errno)); ++ bp->uctrl_map = NULL; ++ rc = errno; ++ goto open_error; ++ } ++ ++ bp->uctrl_map_offset = offset; ++ bp->uctrl_map += offset; ++ ++ bp->rx_comp_ring = mmap(NULL, nic->page_size, ++ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, ++ nic->fd, (off_t)nic->page_size); ++ if (bp->rx_comp_ring == MAP_FAILED) { ++ LOG_INFO(PFX "%s: Could not mmap rx_comp_ring: %s", ++ nic->log_name, strerror(errno)); ++ bp->rx_comp_ring = NULL; ++ rc = errno; ++ goto open_error; ++ } ++ ++ bp->bufs = mmap(NULL, (bp->rx_ring_size + 1) * bp->rx_buffer_size, ++ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, ++ nic->fd, (off_t)2 * nic->page_size); ++ if (bp->bufs == MAP_FAILED) { ++ LOG_INFO(PFX "%s: Could not mmap pkt buffers: %s", ++ nic->log_name, strerror(errno)); ++ bp->bufs = NULL; ++ rc = errno; ++ goto open_error; ++ } ++ ++ /* ++ * Get all CHIP related info from qedi ++ */ ++ bp->chip_id = qedi_get_chip_id(bp); ++ LOG_DEBUG(PFX "Chip ID: %x", bp->chip_id); ++ ++ rc = get_bus_slot_func_num(nic, &bus, &slot, &func); ++ if (rc != 0) { ++ LOG_INFO(PFX "%s: Couldn't determine bus:slot.func", ++ nic->log_name); ++ goto open_error; ++ } ++ ++ /* ++ * Get all function, pfid, client_id and cid info from qedi ++ */ ++ LOG_INFO(PFX "%s: func 0x%x, pfid 0x%x, client_id 0x%x, cid 0x%x", ++ nic->log_name, bp->func, bp->pfid, bp->client_id, bp->cid); ++ ++ bp->get_rx_cons = qedi_get_rx; ++ bp->get_tx_cons = qedi_get_tx; ++ bp->tx_cons = 0; ++ bp->tx_prod = 0; ++ bp->tx_bd_prod = 0; ++ bp->tx_pkt = bp->bufs; ++ bp->rx_pkts = bp->bufs + bp->rx_buffer_size; ++ ++ bp->rx_index = 0; ++ bp->rx_cons = 0; ++ bp->rx_bd_cons = 0; ++ bp->rx_prod = 127; ++ bp->rx_bd_prod = bp->rx_ring_size; ++ ++ for (i = 0; i < bp->rx_ring_size; i++) { ++ void *ptr = bp->bufs + (bp->rx_buffer_size * (i + 1)); ++ ++ bp->rx_pkt_ring[i] = ptr; ++ } ++ ++ qedi_get_mac_addr(bp); ++ LOG_INFO(PFX "%s: Using mac address: %02x:%02x:%02x:%02x:%02x:%02x", ++ nic->log_name, ++ nic->mac_addr[0], nic->mac_addr[1], nic->mac_addr[2], ++ nic->mac_addr[3], nic->mac_addr[4], nic->mac_addr[5]); ++ ++ qedi_get_library_name(&nic->library_name, (size_t *)&count); ++ LOG_INFO("%s: qedi initialized", nic->log_name); ++ ++ bp->flags |= QEDI_OPENED; ++ ++ return 0; ++ ++open_error: ++ ++ if (bp->bufs) { ++ munmap(bp->bufs, (bp->rx_ring_size + 1) * bp->rx_buffer_size); ++ bp->bufs = NULL; ++ } ++ ++ if (bp->rx_comp_ring) { ++ munmap(bp->rx_comp_ring, nic->page_size); ++ bp->rx_comp_ring = NULL; ++ } ++ ++ if (bp->uctrl_map) { ++ bp->uctrl_map -= bp->uctrl_map_offset; ++ munmap(bp->uctrl_map, sizeof(struct qedi_uio_ctrl)); ++ bp->uctrl_map = NULL; ++ } ++ ++ if (bp->rx_pkt_ring) { ++ free(bp->rx_pkt_ring); ++ bp->rx_pkt_ring = NULL; ++ } ++ ++ if (nic->fd != INVALID_FD) { ++ close(nic->fd); ++ nic->fd = INVALID_FD; ++ } ++ ++ qedi_free(nic); ++ ++ return rc; ++} ++ ++/** ++ * qedi_uio_close_resources() - Used to free resource for the NIC/CNIC ++ * @param nic - NIC device to free resource ++ * @param graceful - whether to wait to close gracefully ++ * @return 0 on success, <0 on failure ++ */ ++static int qedi_uio_close_resources(nic_t *nic, NIC_SHUTDOWN_T graceful) ++{ ++ qedi_t *bp = (qedi_t *)nic->priv; ++ int rc = 0; ++ ++ /* Check if there is an assoicated qedi device */ ++ if (!bp) { ++ LOG_WARN(PFX "%s: when closing resources there is no assoicated qedi", ++ nic->log_name); ++ return -EIO; ++ } ++ ++ /* Clean up allocated memory */ ++ ++ if (bp->rx_pkt_ring) { ++ free(bp->rx_pkt_ring); ++ bp->rx_pkt_ring = NULL; ++ } ++ ++ /* Clean up mapped registers */ ++ if (bp->bufs) { ++ rc = munmap(bp->bufs, ++ (bp->rx_ring_size + 1) * bp->rx_buffer_size); ++ if (rc != 0) ++ LOG_ERR(PFX "%s: Couldn't unmap bufs", nic->log_name); ++ bp->bufs = NULL; ++ } ++ ++ if (bp->rx_comp_ring) { ++ rc = munmap(bp->rx_comp_ring, nic->page_size); ++ if (rc != 0) ++ LOG_ERR(PFX "%s: Couldn't unmap ring", nic->log_name); ++ bp->rx_comp_ring = NULL; ++ } ++ ++ if (bp->uctrl_map) { ++ bp->uctrl_map -= bp->uctrl_map_offset; ++ rc = munmap(bp->uctrl_map, sizeof(struct qedi_uio_ctrl)); ++ if (rc != 0) { ++ LOG_ERR(PFX "%s: Couldn't unmap uio ctrl", ++ nic->log_name); ++ } ++ bp->uctrl_map = NULL; ++ } ++ ++ if (nic->fd != INVALID_FD) { ++ rc = close(nic->fd); ++ if (rc != 0) { ++ LOG_ERR(PFX ++ "%s: Couldn't close uio file descriptor: %d", ++ nic->log_name, nic->fd); ++ } else { ++ LOG_DEBUG(PFX "%s: Closed uio file descriptor: %d", ++ nic->log_name, nic->fd); ++ } ++ ++ nic->fd = INVALID_FD; ++ } else { ++ LOG_ERR(PFX "%s: Invalid uio file descriptor: %d", ++ nic->log_name, nic->fd); ++ } ++ ++ qedi_set_drv_version_unknown(bp); ++ ++ LOG_INFO(PFX "%s: Closed all resources", nic->log_name); ++ ++ return 0; ++} ++ ++/** ++ * qedi_close() - Used to close the NIC device ++ * @param nic - NIC device to close ++ * @param graceful - whether to wait to close gracefully ++ * @return 0 if successful, <0 if there is an error ++ */ ++static int qedi_close(nic_t *nic, NIC_SHUTDOWN_T graceful) ++{ ++ /* Sanity Check: validate the parameters */ ++ if (!nic) { ++ LOG_ERR(PFX "%s: nic == NULL", __func__); ++ return -EINVAL; ++ } ++ if (!nic->priv) { ++ LOG_ERR(PFX "%s: nic->priv == NULL", __func__); ++ return -EINVAL; ++ } ++ ++ LOG_INFO(PFX "Closing NIC device: %s", nic->log_name); ++ ++ qedi_uio_close_resources(nic, graceful); ++ qedi_free(nic); ++ ++ return 0; ++} ++ ++static void qedi_prepare_xmit_packet(nic_t *nic, ++ nic_interface_t *nic_iface, ++ struct packet *pkt) ++{ ++ qedi_t *bp = (qedi_t *)nic->priv; ++ struct uip_vlan_eth_hdr *eth_vlan = (struct uip_vlan_eth_hdr *)pkt->buf; ++ struct uip_eth_hdr *eth = (struct uip_eth_hdr *)bp->tx_pkt; ++ ++ if (eth_vlan->tpid == htons(UIP_ETHTYPE_8021Q)) { ++ memcpy(bp->tx_pkt, pkt->buf, sizeof(struct uip_eth_hdr)); ++ eth->type = eth_vlan->type; ++ pkt->buf_size -= (sizeof(struct uip_vlan_eth_hdr) - ++ sizeof(struct uip_eth_hdr)); ++ memcpy(bp->tx_pkt + sizeof(struct uip_eth_hdr), ++ pkt->buf + sizeof(struct uip_vlan_eth_hdr), ++ pkt->buf_size - sizeof(struct uip_eth_hdr)); ++ } else { ++ memcpy(bp->tx_pkt, pkt->buf, pkt->buf_size); ++ } ++ ++ msync(bp->tx_pkt, pkt->buf_size, MS_SYNC); ++} ++ ++/** ++ * qedi_get_tx_pkt() - This function is used to a TX packet from the NIC ++ * @param nic - The NIC device to send the packet ++ */ ++void *qedi_get_tx_pkt(nic_t *nic) ++{ ++ qedi_t *bp = (qedi_t *)nic->priv; ++ ++ return bp->tx_pkt; ++} ++ ++/** ++ * qedi_start_xmit() - This function is used to send a packet of data ++ * @param nic - The NIC device to send the packet ++ * @param len - the length of the TX packet ++ * ++ */ ++void qedi_start_xmit(nic_t *nic, size_t len, u16_t vlan_id) ++{ ++ qedi_t *bp = (qedi_t *)nic->priv; ++ uint8_t *ubuf; ++ struct iscsi_uevent *ev; ++ struct iscsi_path *path_data; ++ struct qedi_uio_ctrl *uctrl; ++ int rc = 0; ++ uint16_t buflen; ++ ++ uctrl = (struct qedi_uio_ctrl *)bp->uctrl_map; ++ ++ buflen = sizeof(struct iscsi_uevent) + sizeof(struct iscsi_path); ++ ubuf = calloc(1, NLMSG_SPACE(buflen)); ++ if (!ubuf) { ++ LOG_ERR(PFX "%s: alloc failed for uevent buf", __func__); ++ return; ++ } ++ ++ memset(ubuf, 0, NLMSG_SPACE(buflen)); ++ ++ /* prepare the iscsi_uevent buffer */ ++ ev = (struct iscsi_uevent *)ubuf; ++ ev->type = ISCSI_UEVENT_PATH_UPDATE; ++ ev->transport_handle = nic->transport_handle; ++ ev->u.set_path.host_no = nic->host_no; ++ ++ /* Prepare the iscsi_path buffer */ ++ path_data = (struct iscsi_path *)(ubuf + sizeof(struct iscsi_uevent)); ++ path_data->handle = QEDI_PATH_HANDLE; ++ path_data->vlan_id = vlan_id; ++ uctrl->host_tx_pkt_len = len; ++ ++ rc = __kipc_call(nl_sock, ev, buflen); ++ if (rc > 0) { ++ bp->tx_prod++; ++ uctrl->host_tx_prod++; ++ msync(uctrl, sizeof(struct qedi_uio_ctrl), MS_SYNC); ++ LOG_PACKET(PFX "%s: sent %d bytes using bp->tx_prod: %d", ++ nic->log_name, len, bp->tx_prod); ++ } else { ++ LOG_ERR(PFX "Pkt transmission failed: %d", rc); ++ pthread_mutex_unlock(&nic->xmit_mutex); ++ } ++ ++ free(ubuf); ++} ++ ++/** ++ * qedi_write() - Used to write the data to the hardware ++ * @param nic - NIC hardware to read from ++ * @param pkt - The packet which will hold the data to be sent on the wire ++ * @return 0 if successful, <0 if failed ++ */ ++int qedi_write(nic_t *nic, nic_interface_t *nic_iface, packet_t *pkt) ++{ ++ qedi_t *bp; ++ struct uip_stack *uip; ++ int i = 0; ++ ++ /* Sanity Check: validate the parameters */ ++ if (!nic || !nic_iface || !pkt) { ++ LOG_ERR(PFX "%s: qedi_write() nic == 0x%p || nic_iface == 0x%p || pkt == 0x%x", ++ nic, nic_iface, pkt); ++ return -EINVAL; ++ } ++ bp = (qedi_t *)nic->priv; ++ uip = &nic_iface->ustack; ++ ++ if (pkt->buf_size == 0) { ++ LOG_ERR(PFX "%s: Trying to transmitted 0 sized packet", ++ nic->log_name); ++ return -EINVAL; ++ } ++ ++ /* Try to wait for a TX completion */ ++ for (i = 0; i < 15; i++) { ++ struct timespec sleep_req = {.tv_sec = 0, .tv_nsec = 5000000 }, ++ sleep_rem; ++ ++ if (qedi_clear_tx_intr(nic) == 0) ++ break; ++ ++ nanosleep(&sleep_req, &sleep_rem); ++ } ++ ++ if (pthread_mutex_trylock(&nic->xmit_mutex) != 0) { ++ LOG_PACKET(PFX "%s: Dropped previous transmitted packet", ++ nic->log_name); ++ return -EINVAL; ++ } ++ ++ qedi_prepare_xmit_packet(nic, nic_iface, pkt); ++ qedi_start_xmit(nic, pkt->buf_size, ++ (nic_iface->vlan_priority << 12) | ++ nic_iface->vlan_id); ++ ++ /* bump up the tx stats */ ++ nic->stats.tx.packets++; ++ nic->stats.tx.bytes += uip->uip_len; ++ ++ LOG_PACKET(PFX "%s: transmitted %d bytes dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bd_prod:%d", ++ nic->log_name, pkt->buf_size, ++ bp->tx_cons, bp->tx_prod, bp->tx_bd_prod); ++ ++ return 0; ++} ++ ++/** ++ * qedi_read() - Used to read the data from the hardware ++ * @param nic - NIC hardware to read from ++ * @param pkt - The packet which will hold the data ++ * @return 0 if successful, < 0 if failed ++ */ ++static int qedi_read(nic_t *nic, packet_t *pkt) ++{ ++ qedi_t *bp; ++ void *rx_pkt; ++ int rc = 0; ++ uint32_t sw_cons, bd_cons; ++ uint32_t hw_prod; ++ uint32_t rx_pkt_idx; ++ int len; ++ struct qedi_rx_bd *rx_bd; ++ struct qedi_uio_ctrl *uctrl; ++ uint16_t vlan_id; ++ ++ /* Sanity Check: validate the parameters */ ++ if (!nic || !pkt) { ++ LOG_ERR(PFX "%s: qedi_read() nic == 0x%p || pkt == 0x%x", ++ nic, pkt); ++ return -EINVAL; ++ } ++ ++ bp = (qedi_t *)nic->priv; ++ msync(bp->uctrl_map, sizeof(struct qedi_uio_ctrl), MS_SYNC); ++ msync(bp->rx_comp_ring, nic->page_size, MS_SYNC); ++ uctrl = (struct qedi_uio_ctrl *)bp->uctrl_map; ++ hw_prod = uctrl->hw_rx_prod; ++ sw_cons = uctrl->host_rx_cons; ++ bd_cons = uctrl->host_rx_bd_cons; ++ rx_bd = bp->rx_comp_ring + (bd_cons * sizeof(*rx_bd)); ++ len = rx_bd->rx_pkt_len; ++ rx_pkt_idx = rx_bd->rx_pkt_index; ++ vlan_id = rx_bd->vlan_id; ++ ++ if (sw_cons != hw_prod) { ++ LOG_DEBUG(PFX "%s: clearing rx interrupt: %d %d", ++ nic->log_name, sw_cons, hw_prod); ++ rc = 1; ++ rx_pkt = bp->rx_pkts + (bp->rx_buffer_size * rx_pkt_idx); ++ ++ if (len > 0) { ++ msync(rx_pkt, len, MS_SYNC); ++ /* Copy the data */ ++ memcpy(pkt->buf, rx_pkt, len); ++ pkt->buf_size = len; ++ if (vlan_id) { ++ pkt->vlan_tag = vlan_id; ++ pkt->flags |= VLAN_TAGGED; ++ } else { ++ pkt->vlan_tag = 0; ++ } ++ ++ LOG_DEBUG(PFX "%s: processing packet length: %d", ++ nic->log_name, len); ++ ++ /* bump up the recv stats */ ++ nic->stats.rx.packets++; ++ nic->stats.rx.bytes += pkt->buf_size; ++ } else { ++ rc = 0; ++ } ++ ++ sw_cons = (sw_cons + 1) % RX_RING_SIZE; ++ bd_cons = (bd_cons + 1) % QEDI_NUM_RX_BD; ++ uctrl->host_rx_cons_cnt++; ++ } ++ ++ uctrl->host_rx_bd_cons = bd_cons; ++ uctrl->host_rx_cons = sw_cons; ++ ++ msync(uctrl, sizeof(struct qedi_uio_ctrl), MS_SYNC); ++ msync(bp->rx_comp_ring, nic->page_size, MS_SYNC); ++ return rc; ++} ++ ++/******************************************************************************* ++ * Clearing TX interrupts ++ ******************************************************************************/ ++/** ++ * qedi_clear_tx_intr() - This routine is called when a TX interrupt occurs ++ * @param nic - the nic the interrupt occurred on ++ * @return 0 on success ++ */ ++ ++static int qedi_clear_tx_intr(nic_t *nic) ++{ ++ qedi_t *bp; ++ uint32_t hw_cons; ++ struct qedi_uio_ctrl *uctrl; ++ ++ /* Sanity check: ensure the parameters passed in are valid */ ++ if (unlikely(!nic)) { ++ LOG_ERR(PFX "%s: nic == NULL", __func__); ++ return -EINVAL; ++ } ++ ++ bp = (qedi_t *)nic->priv; ++ uctrl = (struct qedi_uio_ctrl *)bp->uctrl_map; ++ msync(bp->uctrl_map, sizeof(struct qedi_uio_ctrl), MS_SYNC); ++ hw_cons = uctrl->hw_tx_cons; ++ ++ if (bp->tx_cons == hw_cons) { ++ if (bp->tx_cons == bp->tx_prod) { ++ /* Make sure the xmit_mutex lock is unlock */ ++ if (pthread_mutex_trylock(&nic->xmit_mutex)) ++ LOG_ERR(PFX "qedi tx lock with prod == cons"); ++ ++ pthread_mutex_unlock(&nic->xmit_mutex); ++ return 0; ++ } ++ return -EAGAIN; ++ } ++ ++ LOG_PACKET(PFX "%s: clearing tx interrupt [%d %d]", ++ nic->log_name, bp->tx_cons, hw_cons); ++ bp->tx_cons = hw_cons; ++ ++ /* There is a queued TX packet that needs to be sent out. The usual ++ * case is when stack will send an ARP packet out before sending the ++ * intended packet ++ */ ++ if (nic->tx_packet_queue) { ++ packet_t *pkt; ++ int i; ++ ++ LOG_PACKET(PFX "%s: sending queued tx packet", nic->log_name); ++ pkt = nic_dequeue_tx_packet(nic); ++ ++ /* Got a TX packet buffer of the TX queue and put it onto ++ * the hardware ++ */ ++ if (pkt) { ++ qedi_prepare_xmit_packet(nic, pkt->nic_iface, pkt); ++ ++ qedi_start_xmit(nic, pkt->buf_size, ++ (pkt->nic_iface->vlan_priority << 12) | ++ pkt->nic_iface->vlan_id); ++ ++ LOG_PACKET(PFX "%s: transmitted queued packet %d bytes, dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bd_prod:%d", ++ nic->log_name, pkt->buf_size, ++ bp->tx_cons, bp->tx_prod, bp->tx_bd_prod); ++ ++ return 0; ++ } ++ ++ /* Try to wait for a TX completion */ ++ for (i = 0; i < 15; i++) { ++ struct timespec sleep_req = {.tv_sec = 0, ++ .tv_nsec = 5000000 ++ }, sleep_rem; ++ ++ hw_cons = uctrl->hw_tx_cons; ++ if (bp->tx_cons != hw_cons) { ++ LOG_PACKET(PFX ++ "%s: clearing tx interrupt [%d %d]", ++ nic->log_name, bp->tx_cons, hw_cons); ++ bp->tx_cons = hw_cons; ++ ++ break; ++ } ++ ++ nanosleep(&sleep_req, &sleep_rem); ++ } ++ } ++ ++ pthread_mutex_unlock(&nic->xmit_mutex); ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * qedi NIC op's table ++ ******************************************************************************/ ++struct nic_ops qedi_op = { ++ .description = "qedi", ++ .open = qedi_open, ++ .close = qedi_close, ++ .write = qedi_write, ++ .get_tx_pkt = qedi_get_tx_pkt, ++ .start_xmit = qedi_start_xmit, ++ .read = qedi_read, ++ .clear_tx_intr = qedi_clear_tx_intr, ++ .handle_iscsi_path_req = cnic_handle_iscsi_path_req, ++ ++ .lib_ops = { ++ .get_library_name = qedi_get_library_name, ++ .get_library_version = qedi_get_library_version, ++ .get_build_date = qedi_get_build_date, ++ .get_transport_name = qedi_get_transport_name, ++ .get_uio_name = qedi_get_uio_name, ++ }, ++}; +diff --git a/iscsiuio/src/unix/libs/qedi.h b/iscsiuio/src/unix/libs/qedi.h +new file mode 100644 +index 000000000000..7e0140adb2ba +--- /dev/null ++++ b/iscsiuio/src/unix/libs/qedi.h +@@ -0,0 +1,159 @@ ++/* ++ * Copyright (c) 2016, Cavium Inc. ++ * ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. All advertising materials mentioning features or use of this software ++ * must display the following acknowledgement: ++ * This product includes software developed by Adam Dunkels. ++ * 4. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ++ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ++ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * qedi.h - qedi user space driver ++ * ++ */ ++#ifndef __QEDI_H__ ++#define __QEDI_H__ ++ ++#include "nic.h" ++ ++#define RX_RING_SIZE 15 ++#define PKT_BUF_SIZE 0X400 ++#define QEDI_PAGE_SIZE 4096 ++ ++#define QEDI_UNKNOWN_MAJOR_VERSION -1 ++#define QEDI_UNKNOWN_MINOR_VERSION -1 ++#define QEDI_UNKNOWN_SUB_MINOR_VERSION -1 ++struct qedi_driver_version { ++ uint16_t major; ++ uint16_t minor; ++ uint16_t sub_minor; ++}; ++ ++#define QEDI_UCTRL_MAP_REG 0 ++#define QEDI_RING_MAP_REG 1 ++#define QEDI_BUF_MAP_REG 2 ++#define UIO_ATTR_TMPL "/sys/class/uio/uio%u/maps/map%u/%s" ++#define UIO_ADDR_TMPL "/sys/class/uio/uio%u/maps/map%u/addr" ++#define UIO_OFFSET_TMPL "/sys/class/uio/uio%u/maps/map%u/offset" ++#define UIO_SIZE_TMPL "/sys/class/uio/uio%u/maps/map%u/size" ++ ++struct qedi_uio_ctrl { ++ /* meta data */ ++ __u32 uio_hsi_version; ++ ++ /* user writes */ ++ __u32 host_tx_prod; ++ __u32 host_rx_cons; ++ __u32 host_rx_bd_cons; ++ __u32 host_tx_pkt_len; ++ __u32 host_rx_cons_cnt; ++ ++ /* driver writes */ ++ __u32 hw_tx_cons; ++ __u32 hw_rx_prod; ++ __u32 hw_rx_bd_prod; ++ __u32 hw_rx_prod_cnt; ++ ++ /* other */ ++ __u8 mac_addr[6]; ++ __u8 reserve[2]; ++}; ++ ++struct qedi_rx_bd { ++ __u32 rx_pkt_index; ++ __u32 rx_pkt_len; ++ __u16 vlan_id; ++}; ++ ++#define QEDI_RX_DESC_CNT (QEDI_PAGE_SIZE / sizeof(struct qedi_rx_bd)) ++#define QEDI_MAX_RX_DESC_CNT (QEDI_RX_DESC_CNT - 1) ++#define QEDI_NUM_RX_BD (QEDI_RX_DESC_CNT * 1) ++#define QEDI_MAX_RX_BD (QEDI_NUM_RX_BD - 1) ++ ++#define QEDI_NEXT_RX_IDX(x) ((((x) & (QEDI_MAX_RX_DESC_CNT)) == \ ++ (QEDI_MAX_RX_DESC_CNT - 1)) ? \ ++ (x) + 2 : (x) + 1) ++ ++#define QEDI_PATH_HANDLE 0xFE0000000 ++ ++typedef struct qedi { ++ nic_t *parent; ++ ++ struct qedi_driver_version version; ++ ++ uint16_t flags; ++#define CNIC_UIO_UNITIALIZED 0x0001 ++#define CNIC_UIO_INITIALIZED 0x0002 ++#define CNIC_UIO_ENABLED 0x0004 ++#define CNIC_UIO_DISABLED 0x0008 ++#define CNIC_UIO_IPv6_ENABLED 0x0010 ++#define CNIC_UIO_ADDED_MULICAST 0x0020 ++#define CNIC_UIO_MSIX_ENABLED 0x0200 ++#define CNIC_UIO_TX_HAS_SENT 0x0400 ++#define QEDI_OPENED 0x0800 ++ ++ __u32 chip_id; ++ int func; ++ int port; ++ int pfid; ++ __u32 cid; ++ __u32 client_id; ++ ++ __u32 tx_prod; ++ __u32 tx_bd_prod; ++ __u32 tx_cons; ++ __u8 tx_vlan_tag_bit; ++ ++ __u32 rx_prod; ++ __u32 rx_bd_prod; ++ __u32 rx_cons; ++ __u32 rx_bd_cons; ++ __u32 rx_hw_prod; ++ ++ __u32 (*get_rx_cons)(struct qedi *); ++ __u32 (*get_tx_cons)(struct qedi *); ++ ++ /* RX ring parameters */ ++ uint32_t rx_ring_size; ++ uint32_t rx_buffer_size; ++ ++ void *bufs; /* Pointer to the mapped buffer space */ ++ void *uctrl_map; /* UIO control structure */ ++ uint32_t uctrl_map_offset; /* UIO control structure mmap offset */ ++ ++ uint32_t rx_index; ++ void *rx_comp_ring; ++ void **rx_pkt_ring; ++ void *tx_pkt; ++ void *rx_pkts; ++} qedi_t; ++ ++/****************************************************************************** ++ * qedi Function Declarations ++ ******************************************************************************/ ++void qedi_start_xmit(nic_t *nic, size_t len, u16_t vlan_id); ++struct nic_ops *qedi_get_ops(); ++ ++#endif /* __QEDI_H__ */ +diff --git a/iscsiuio/src/unix/nic.c b/iscsiuio/src/unix/nic.c +index 8825f00b7216..a5f714a91923 100644 +--- a/iscsiuio/src/unix/nic.c ++++ b/iscsiuio/src/unix/nic.c +@@ -65,6 +65,7 @@ + + #include "bnx2.h" + #include "bnx2x.h" ++#include "qedi.h" + #include "ipv6.h" + + /****************************************************************************** +@@ -180,7 +181,7 @@ error: + } + + static struct nic_ops *(*nic_get_ops[]) () = { +-bnx2_get_ops, bnx2x_get_ops,}; ++bnx2_get_ops, bnx2x_get_ops, qedi_get_ops}; + + int load_all_nic_libraries() + { +@@ -404,6 +405,7 @@ nic_t *nic_init() + memset(nic, 0, sizeof(*nic)); + nic->uio_minor = -1; + nic->fd = INVALID_FD; ++ nic->host_no = INVALID_HOST_NO; + nic->next = NULL; + nic->thread = INVALID_THREAD; + nic->enable_thread = INVALID_THREAD; +@@ -1070,6 +1072,8 @@ int process_packets(nic_t *nic, + } + nic_iface_present: + pkt->nic_iface = nic_iface; ++ LOG_DEBUG(PFX "%s: found nic iface, type=0x%x, bufsize=%d", ++ nic->log_name, type, pkt->buf_size); + + ustack = &nic_iface->ustack; + +diff --git a/iscsiuio/src/unix/nic.h b/iscsiuio/src/unix/nic.h +index ec157815a375..2c41e6e3c25a 100644 +--- a/iscsiuio/src/unix/nic.h ++++ b/iscsiuio/src/unix/nic.h +@@ -334,6 +334,7 @@ typedef struct nic { + + /* The thread used to perform ping */ + pthread_t ping_thread; ++ uint64_t transport_handle; + } nic_t; + + /****************************************************************************** +diff --git a/iscsiuio/src/unix/nic_utils.c b/iscsiuio/src/unix/nic_utils.c +index 0daffd2fcb6d..6e580f862eea 100644 +--- a/iscsiuio/src/unix/nic_utils.c ++++ b/iscsiuio/src/unix/nic_utils.c +@@ -81,6 +81,10 @@ static const char iscsi_host_path_netdev_template[] = + "/sys/class/iscsi_host/host%d/netdev"; + static const char cnic_uio_sysfs_resc_template[] = + "/sys/class/uio/uio%i/device/resource%i"; ++static const char iscsi_transport_handle_template[] = ++ "/sys/class/iscsi_transport/%s/handle"; ++static const char eth_pfx[] = "eth"; ++static const char host_pfx[] = "host"; + + /** + * manually_trigger_uio_event() - If the uio file node doesn't exist then +@@ -250,6 +254,7 @@ int nic_discover_iscsi_hosts() + strncpy(nic->eth_device_name, raw, raw_size); + nic->config_device_name = nic->eth_device_name; + nic->log_name = nic->eth_device_name; ++ nic->host_no = host_no; + + if (nic_fill_name(nic) != 0) { + free(nic); +@@ -557,6 +562,102 @@ error: + } + + /** ++ * from_uio_find_associated_host() - Given the uio minor number ++ * this function will try to find the assoicated iscsi host ++ * @param uio_minor - minor number of the UIO device ++ * @param name - char buffer which will be filled if successful ++ * @param name_size - size of the name buffer ++ * @return >0 minor number <0 an error ++ */ ++static int from_uio_find_associated_host(nic_t *nic, int uio_minor, ++ char *name, size_t name_size) ++{ ++ char *path; ++ int rc; ++ int count; ++ struct dirent **files; ++ char *parsed_name; ++ int i; ++ int path_iterator; ++ char *search_paths[] = { "/sys/class/uio/uio%i/device/" }; ++ int path_to[] = { 5, 1 }; ++ int (*search_filters[]) (const struct dirent *) = { filter_host_name, }; ++ char *(*extract_name[]) (struct dirent **files) = { extract_none, }; ++ int extract_name_offset[] = { 0 }; ++ ++ path = malloc(PATH_MAX); ++ if (!path) { ++ LOG_ERR(PFX "Could not allocate memory for path"); ++ rc = -ENOMEM; ++ goto error; ++ } ++ ++ for (path_iterator = 0; ++ path_iterator < sizeof(search_paths) / sizeof(search_paths[0]); ++ path_iterator++) { ++ /* Build the path to determine uio name */ ++ rc = sprintf(path, search_paths[path_iterator], uio_minor); ++ ++ wait_for_file_node_timed(nic, path, path_to[path_iterator]); ++ ++ count = scandir(path, &files, ++ search_filters[path_iterator], alphasort); ++ ++ switch (count) { ++ case 1: ++ parsed_name = (*extract_name[path_iterator]) (files); ++ if (!parsed_name) { ++ LOG_WARN(PFX "Couldn't find delimiter in: %s", ++ files[0]->d_name); ++ ++ break; ++ } ++ ++ strncpy(name, ++ parsed_name + ++ extract_name_offset[path_iterator], name_size); ++ ++ free(files[0]); ++ free(files); ++ ++ rc = 0; ++ break; ++ ++ case 0: ++ rc = -EINVAL; ++ break; ++ ++ case -1: ++ LOG_WARN(PFX "Error when scanning path: %s[%s]", ++ path, strerror(errno)); ++ rc = -EINVAL; ++ break; ++ ++ default: ++ LOG_WARN(PFX ++ "Too many entries when looking for device: %s", ++ path); ++ ++ /* Cleanup the scandir() call */ ++ for (i = 0; i < count; i++) ++ free(files[i]); ++ free(files); ++ ++ rc = -EINVAL; ++ break; ++ } ++ ++ if (rc == 0) ++ break; ++ } ++ ++error: ++ free(path); ++ ++ return rc; ++} ++ ++/** + * filter_uio_name() - This is the callback used by scandir when looking for + * the number of uio entries + */ +@@ -652,10 +753,16 @@ int from_phys_name_find_assoicated_uio_device(nic_t *nic) + continue; + } + +- rc = from_uio_find_associated_eth_device(nic, +- uio_minor, +- eth_name, +- sizeof(eth_name)); ++ if (!memcmp(host_pfx, nic->config_device_name, ++ strlen(host_pfx))) { ++ rc = from_uio_find_associated_host(nic, uio_minor, ++ eth_name, ++ sizeof(eth_name)); ++ } else { ++ rc = from_uio_find_associated_eth_device(nic, uio_minor, ++ eth_name, ++ sizeof(eth_name)); ++ } + if (rc != 0) { + LOG_WARN("uio minor: %d not valid [%D]", uio_minor, rc); + continue; +@@ -1124,6 +1231,38 @@ int detemine_initial_uio_events(nic_t *nic, uint32_t *num_of_events) + + rc = 0; + error: ++ if (raw) ++ free(raw); ++ ++ return rc; ++} ++ ++int get_iscsi_transport_handle(nic_t *nic, uint64_t *handle) ++{ ++ char *raw = NULL; ++ uint32_t raw_size = 0; ++ ssize_t elements_read; ++ char temp_path[sizeof(iscsi_transport_handle_template) + 8]; ++ int rc; ++ ++ /* Capture RX buffer size */ ++ snprintf(temp_path, sizeof(temp_path), ++ iscsi_transport_handle_template, nic->library_name); ++ ++ rc = capture_file(&raw, &raw_size, temp_path); ++ if (rc != 0) ++ goto error; ++ ++ elements_read = sscanf(raw, "%lu", handle); ++ if (elements_read != 1) { ++ LOG_ERR(PFX "%s: Couldn't parse transport handle from %s", ++ nic->log_name, temp_path); ++ rc = -EIO; ++ goto error; ++ } ++ ++ rc = 0; ++error: + if (raw != NULL) + free(raw); + +diff --git a/iscsiuio/src/unix/nic_utils.h b/iscsiuio/src/unix/nic_utils.h +index d5c1b580f340..e4cf5c13177e 100644 +--- a/iscsiuio/src/unix/nic_utils.h ++++ b/iscsiuio/src/unix/nic_utils.h +@@ -99,4 +99,6 @@ void dump_packet_to_log(struct nic_interface *iface, + int determine_file_size_read(const char *filepath); + int capture_file(char **raw, uint32_t *raw_size, const char *path); + ++int get_iscsi_transport_handle(nic_t *nic, uint64_t *handle); ++ + #endif /* __NIC_UTILS_H__ */ +diff --git a/iscsiuio/src/unix/options.h b/iscsiuio/src/unix/options.h +index df03255f7a87..63b86357aafa 100644 +--- a/iscsiuio/src/unix/options.h ++++ b/iscsiuio/src/unix/options.h +@@ -87,6 +87,7 @@ + + #define INVALID_FD -1 + #define INVALID_THREAD -1 ++#define INVALID_HOST_NO -1 + + struct options { + char debug; +-- +2.9.3 + diff --git a/SOURCES/open-iscsi-2.0.874-9-iscsiuio-v0.7.8.3.patch b/SOURCES/open-iscsi-2.0.874-9-iscsiuio-v0.7.8.3.patch new file mode 100644 index 00000000..ec17af93 --- /dev/null +++ b/SOURCES/open-iscsi-2.0.874-9-iscsiuio-v0.7.8.3.patch @@ -0,0 +1,84 @@ +From 13ade0423449530836ccb4c4d94ae36ce5257b56 Mon Sep 17 00:00:00 2001 +From: Nilesh Javali +Date: Fri, 11 Nov 2016 08:17:52 +0200 +Subject: iscsiuio: v0.7.8.3 + +Signed-off-by: Manish Rangankar +Signed-off-by: Adheer Chandravanshi +Signed-off-by: Nilesh Javali +--- + iscsiuio/README | 4 ++-- + iscsiuio/RELEASE.TXT | 20 ++++++++------------ + iscsiuio/configure.ac | 4 ++-- + 3 files changed, 12 insertions(+), 16 deletions(-) + +diff --git a/iscsiuio/README b/iscsiuio/README +index 9ae14111dd40..ca2da16a7342 100644 +--- a/iscsiuio/README ++++ b/iscsiuio/README +@@ -1,6 +1,6 @@ + Iscsiuio Userspace Tool +-Version 0.7.8.2 +-Dec 10, 2013 ++Version 0.7.8.3 ++Sept 28, 2016 + ------------------------------------------------------ + + This tool is to be used in conjunction with the QLogic NetXtreme II Linux +diff --git a/iscsiuio/RELEASE.TXT b/iscsiuio/RELEASE.TXT +index 44d67f9ceb84..69c5b5f6bd61 100644 +--- a/iscsiuio/RELEASE.TXT ++++ b/iscsiuio/RELEASE.TXT +@@ -1,7 +1,7 @@ + Release Notes + QLogic uIP Linux Driver +- Version 0.7.8.2 +- 12/10/2013 ++ Version 0.7.8.3 ++ 9/28/2016 + + QLogic Corporation + 26650 Aliso Viejo Pkwy, +@@ -11,17 +11,13 @@ + Copyright (c) 2014, QLogic Corporation + All rights reserved + +-uIP v0.7.10.2 (Feb 12, 2014) +-======================================================= +- Fixes +- ----- +- 1. Problem: Cont00072504 - ifconfig shows allocation failure after +- up/down few hours with iSCSI + L2 traffic +- Cause: A memory leak was discovered in the ongoing pthread creation +- destruction code during the connection recovery process +- Change: Fixed the pthread creation code +- Impact: All + ++uIP v0.7.8.3 (Sept 28, 2016) ++======================================================= ++ Enhancements ++ ------------ ++ 1. Change: Add support for the new qedi transport ++ Impact: 10/25/40/50GGbE Controller (iSCSI) + + uIP v0.7.8.2 (Dec 10, 2013) + ======================================================= +diff --git a/iscsiuio/configure.ac b/iscsiuio/configure.ac +index ed1499cdbba1..075d07d04f34 100644 +--- a/iscsiuio/configure.ac ++++ b/iscsiuio/configure.ac +@@ -12,9 +12,9 @@ dnl Benjamin Li (benli@broadcom.com) + dnl + + PACKAGE=iscsiuio +-VERSION=0.7.8.2 ++VERSION=0.7.8.3 + +-AC_INIT([iscsiuio], [0.7.8.2], [QLogic-Storage-Upstream@qlogic.com]) ++AC_INIT([iscsiuio], [0.7.8.3], [QLogic-Storage-Upstream@cavium.com]) + + AM_INIT_AUTOMAKE + AC_CONFIG_HEADER(config.h) +-- +2.9.3 + diff --git a/SOURCES/open-iscsi-2.0.874-iscsid-reset-head-on-wrap-when-buffer-empty.patch b/SOURCES/open-iscsi-2.0.874-iscsid-reset-head-on-wrap-when-buffer-empty.patch new file mode 100644 index 00000000..5925cec6 --- /dev/null +++ b/SOURCES/open-iscsi-2.0.874-iscsid-reset-head-on-wrap-when-buffer-empty.patch @@ -0,0 +1,27 @@ +From 2235c48bd993ead1d6e3de405b98b524d4bc0b61 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Tue, 28 Feb 2017 19:34:03 -0800 +Subject: iscsid: reset head on wrap when buffer empty + +Reported-By: David Jeffery +--- + usr/log.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/usr/log.c b/usr/log.c +index 26c61d847793..b730642779bf 100644 +--- a/usr/log.c ++++ b/usr/log.c +@@ -189,6 +189,9 @@ int log_enqueue (int prio, const char * fmt, va_list ap) + (len + sizeof(struct logmsg)) > (la->end - la->tail)) { + logdbg(stderr, "enqueue: rewind tail to %p\n", la->tail); + la->tail = la->start; ++ ++ if (la->empty) ++ la->head = lastmsg = la->tail; + } + + /* not enough space on head : drop msg */ +-- +2.9.3 + diff --git a/SPECS/iscsi-initiator-utils.spec b/SPECS/iscsi-initiator-utils.spec new file mode 100644 index 00000000..a7bd6961 --- /dev/null +++ b/SPECS/iscsi-initiator-utils.spec @@ -0,0 +1,485 @@ +%define open_iscsi_version 2.0 +%define open_iscsi_build 874 + +Summary: iSCSI daemon and utility programs +Name: iscsi-initiator-utils +Version: 6.%{open_iscsi_version}.%{open_iscsi_build} +Release: 7%{?dist} +Group: System Environment/Daemons +License: GPLv2+ +URL: http://www.open-iscsi.org + +Source0: https://github.com/open-iscsi/open-iscsi/archive/%{open_iscsi_version}.%{open_iscsi_build}.tar.gz#/open-iscsi-%{open_iscsi_version}.%{open_iscsi_build}.tar.gz +Source4: 04-iscsi +Source5: iscsi-tmpfiles.conf + +# upstream patches, post last tagged version +Patch1: open-iscsi-2.0.874-1-iBFT-origin-is-an-enum-not-a-string.patch +Patch2: open-iscsi-2.0.874-4-iscsid-treat-SIGTERM-like-iscsiadm-k-0.patch +Patch3: open-iscsi-2.0.874-5-Make-event_loop_stop-volatile-for-safer-access.patch +Patch4: open-iscsi-2.0.874-7-iscsid-Changes-to-support-the-new-qedi-transport.patch +Patch5: open-iscsi-2.0.874-8-iscsiuio-Add-support-for-the-new-qedi-transport.patch +Patch6: open-iscsi-2.0.874-9-iscsiuio-v0.7.8.3.patch +Patch7: open-iscsi-2.0.874-7-Allow-disabling-auto-LUN-scans.patch +Patch8: open-iscsi-2.0.874-23-Fix-manual-LUN-scans-feature.patch +Patch9: open-iscsi-2.0.874-27-iscsid-Add-qedi-ping-transport-hook.patch +Patch20: open-iscsi-2.0.874-30-isolate-iscsistart-socket-use.patch +# not (yet) upstream merged +Patch140: open-iscsi-2.0.874-iscsid-reset-head-on-wrap-when-buffer-empty.patch +Patch143: 0143-idmb_rec_write-check-for-tpgt-first.patch +Patch145: 0145-idbm_rec_write-seperate-old-and-new-style-writes.patch +Patch146: 0146-idbw_rec_write-pick-tpgt-from-existing-record.patch +Patch149: 0149-update-systemd-service-files-add-iscsi.service-for-s.patch +Patch150: 0150-iscsi-boot-related-service-file-updates.patch +# distro specific modifications +Patch151: 0151-update-initscripts-and-docs.patch +Patch152: 0152-use-var-for-config.patch +Patch153: 0153-use-red-hat-for-name.patch +Patch154: 0154-add-libiscsi.patch +Patch156: 0156-remove-the-offload-boot-supported-ifdef.patch +Patch159: 0159-iscsiuio-systemd-unit-files.patch +Patch160: 0160-use-systemctl-to-start-iscsid.patch +Patch161: 0161-resolve-565245-multilib-issues-caused-by-doxygen.patch +Patch162: 0162-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch +Patch164: 0164-libiscsi-fix-incorrect-strncpy-use.patch +Patch166: 0166-start-socket-listeners-on-iscsiadm-command.patch +Patch167: 0167-Revert-iscsiadm-return-error-when-login-fails.patch +Patch168: 0168-update-handling-of-boot-sessions.patch +Patch169: 0169-update-iscsi.service-for-boot-session-recovery.patch +Patch170: 0170-fix-systemd-unit-wants.patch +Patch172: 0172-move-cleanup-to-seperate-service.patch +Patch175: be2iscsi-vlan.patch +# upstream removed internal open-isns, but not taking that here just yet +# it requires repackaging isns-utils to provide a debug package +Patch198: keep-open-isns.patch +# version string, needs to be updated with each build +Patch199: 0199-use-Red-Hat-version-string-to-match-RPM-package-vers.patch + +BuildRequires: flex bison python-devel doxygen kmod-devel systemd-devel libmount-devel autoconf automake libtool +# For dir ownership +Requires: %{name}-iscsiuio >= %{version}-%{release} +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + +%global _hardened_build 1 +%global __provides_exclude_from ^(%{python_sitearch}/.*\\.so)$ + +%description +The iscsi package provides the server daemon for the iSCSI protocol, +as well as the utility programs used to manage it. iSCSI is a protocol +for distributed disk access using SCSI commands sent over Internet +Protocol networks. + +%package iscsiuio +Summary: Userspace configuration daemon required for some iSCSI hardware +Group: System Environment/Daemons +License: BSD +Requires: %{name} = %{version}-%{release} + +%description iscsiuio +The iscsiuio configuration daemon provides network configuration help +for some iSCSI offload hardware. + +%package devel +Summary: Development files for %{name} +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + +%prep +%autosetup -p1 -n open-iscsi-%{open_iscsi_version}.%{open_iscsi_build} + +# change exec_prefix, there's no easy way to override +%{__sed} -i -e 's|^exec_prefix = /$|exec_prefix = %{_exec_prefix}|' Makefile + +%build + +# configure sub-packages from here +# letting the top level Makefile do it will lose setting from rpm +cd iscsiuio +autoreconf --install +%{configure} +cd .. + +cd utils/open-isns +chmod +x ./configure +%{configure} --with-security=no --with-slp=no +cd ../.. + +%{__make} OPTFLAGS="%{optflags} %{?__global_ldflags} -DUSE_KMOD -lkmod" +pushd libiscsi +python setup.py build +touch -r libiscsi.doxy html/* +popd + + +%install +%{__make} DESTDIR=%{?buildroot} install_programs install_doc install_etc +# upstream makefile doesn't get everything the way we like it +rm $RPM_BUILD_ROOT%{_sbindir}/iscsi_discovery +rm $RPM_BUILD_ROOT%{_mandir}/man8/iscsi_discovery.8 +%{__install} -pm 755 usr/iscsistart $RPM_BUILD_ROOT%{_sbindir} +%{__install} -pm 644 doc/iscsistart.8 $RPM_BUILD_ROOT%{_mandir}/man8 +%{__install} -pm 644 doc/iscsi-iname.8 $RPM_BUILD_ROOT%{_mandir}/man8 +%{__install} -d $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d +%{__install} -pm 644 iscsiuio/iscsiuiolog $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d + +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/nodes +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/send_targets +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/static +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/isns +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/slp +%{__install} -d $RPM_BUILD_ROOT%{_sharedstatedir}/iscsi/ifaces + +# for %%ghost +%{__install} -d $RPM_BUILD_ROOT/var/lock/iscsi +touch $RPM_BUILD_ROOT/var/lock/iscsi/lock + + +%{__install} -d $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsi.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsi-shutdown.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsid.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsid.socket $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsiuio.service $RPM_BUILD_ROOT%{_unitdir} +%{__install} -pm 644 etc/systemd/iscsiuio.socket $RPM_BUILD_ROOT%{_unitdir} + +%{__install} -d $RPM_BUILD_ROOT%{_libexecdir} +%{__install} -pm 755 etc/systemd/iscsi-mark-root-nodes $RPM_BUILD_ROOT%{_libexecdir} + +%{__install} -d $RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d +%{__install} -pm 755 %{SOURCE4} $RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d + +%{__install} -d $RPM_BUILD_ROOT%{_tmpfilesdir} +%{__install} -pm 644 %{SOURCE5} $RPM_BUILD_ROOT%{_tmpfilesdir}/iscsi.conf + +%{__install} -d $RPM_BUILD_ROOT%{_libdir} +%{__install} -pm 755 libiscsi/libiscsi.so.0 $RPM_BUILD_ROOT%{_libdir} +%{__ln_s} libiscsi.so.0 $RPM_BUILD_ROOT%{_libdir}/libiscsi.so +%{__install} -d $RPM_BUILD_ROOT%{_includedir} +%{__install} -pm 644 libiscsi/libiscsi.h $RPM_BUILD_ROOT%{_includedir} + +%{__install} -d $RPM_BUILD_ROOT%{python_sitearch} +%{__install} -pm 755 libiscsi/build/lib.linux-*/libiscsimodule.so \ + $RPM_BUILD_ROOT%{python_sitearch} + + +%post +/sbin/ldconfig + +%systemd_post iscsi.service iscsi-shutdown.service iscsid.service iscsid.socket + +if [ $1 -eq 1 ]; then + if [ ! -f %{_sysconfdir}/iscsi/initiatorname.iscsi ]; then + echo "InitiatorName=`/usr/sbin/iscsi-iname`" > %{_sysconfdir}/iscsi/initiatorname.iscsi + fi + # enable socket activation and persistant session startup by default + /bin/systemctl enable iscsi.service >/dev/null 2>&1 || : + /bin/systemctl enable iscsid.socket >/dev/null 2>&1 || : + /bin/systemctl start iscsid.socket >/dev/null 2>&1 || : +fi + +%post iscsiuio +%systemd_post iscsiuio.service iscsiuio.socket + +if [ $1 -eq 1 ]; then + /bin/systemctl enable iscsiuio.socket >/dev/null 2>&1 || : + /bin/systemctl start iscsiuio.socket >/dev/null 2>&1 || : +fi + +%preun +%systemd_preun iscsi.service iscsi-shutdown.service iscsid.service iscsiuio.service iscsid.socket iscsiuio.socket + +%preun iscsiuio +%systemd_preun iscsiuio.service iscsiuio.socket + +%postun +/sbin/ldconfig +%systemd_postun + +%postun iscsiuio +%systemd_postun + +%triggerun -- iscsi-initiator-utils < 6.2.0.873-22 +# prior to 6.2.0.873-22 iscsi.service was missing a Wants=remote-fs-pre.target +# this forces remote-fs-pre.target active if needed for a clean shutdown/reboot +# after upgrading this package +if [ $1 -gt 0 ]; then + /usr/bin/systemctl -q is-active iscsi.service + if [ $? -eq 0 ]; then + /usr/bin/systemctl -q is-active remote-fs-pre.target + if [ $? -ne 0 ]; then + SRC=`/usr/bin/systemctl show --property FragmentPath remote-fs-pre.target | cut -d= -f2` + DST=/run/systemd/system/remote-fs-pre.target + if [ $SRC != $DST ]; then + cp $SRC $DST + fi + sed -i 's/RefuseManualStart=yes/RefuseManualStart=no/' $DST + /usr/bin/systemctl daemon-reload >/dev/null 2>&1 || : + /usr/bin/systemctl start remote-fs-pre.target >/dev/null 2>&1 || : + fi + fi +fi +# added in 6.2.0.873-26 +if [ $1 -gt 0 ]; then + systemctl start iscsi-shutdown.service >/dev/null 2>&1 || : +fi + +%files +%doc README +%dir %{_sharedstatedir}/iscsi +%dir %{_sharedstatedir}/iscsi/nodes +%dir %{_sharedstatedir}/iscsi/isns +%dir %{_sharedstatedir}/iscsi/static +%dir %{_sharedstatedir}/iscsi/slp +%dir %{_sharedstatedir}/iscsi/ifaces +%dir %{_sharedstatedir}/iscsi/send_targets +%ghost %{_var}/lock/iscsi +%ghost %{_var}/lock/iscsi/lock +%{_unitdir}/iscsi.service +%{_unitdir}/iscsi-shutdown.service +%{_unitdir}/iscsid.service +%{_unitdir}/iscsid.socket +%{_libexecdir}/iscsi-mark-root-nodes +%{_sysconfdir}/NetworkManager/dispatcher.d/04-iscsi +%{_tmpfilesdir}/iscsi.conf +%dir %{_sysconfdir}/iscsi +%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/iscsi/iscsid.conf +%{_sbindir}/iscsi-iname +%{_sbindir}/iscsiadm +%{_sbindir}/iscsid +%{_sbindir}/iscsistart +%{_libdir}/libiscsi.so.0 +%{python_sitearch}/libiscsimodule.so +%{_mandir}/man8/iscsi-iname.8.gz +%{_mandir}/man8/iscsiadm.8.gz +%{_mandir}/man8/iscsid.8.gz +%{_mandir}/man8/iscsistart.8.gz + +%files iscsiuio +%{_sbindir}/iscsiuio +%{_unitdir}/iscsiuio.service +%{_unitdir}/iscsiuio.socket +%config(noreplace) %{_sysconfdir}/logrotate.d/iscsiuiolog +%{_mandir}/man8/iscsiuio.8.gz + +%files devel +%doc libiscsi/html +%{_libdir}/libiscsi.so +%{_includedir}/libiscsi.h + +%changelog +* Thu Nov 30 2017 Chris Leech - 6.2.0.874-7 +- 1328694 keep vlan settings in sync for ipv4/ipv6 iface records with be2iscsi + +* Wed Nov 01 2017 Chris Leech - 6.2.0.874-6 +- 1507945 force start iscsiuio for boot session recovery with qedi +- 1457359 start systemd socket listeners, otherwise if iscsid is started + directly iscsiuio doesn't activate as expected + +* Tue Aug 15 2017 Chris Leech - 6.2.0.874-5 +- 1431622 fix default in iscsi-iname manpage to match Red Hat customization + +* Tue Jun 27 2017 Chris Leech - 6.2.0.874-4 +- 1450756 isolate iscsistart sockets + +* Fri Apr 28 2017 Chris Leech - 6.2.0.874-3 +- 1445686 add missing ping hook for the qedi transport driver + +* Tue Apr 11 2017 Chris Leech - 6.2.0.874-2 +- 1422941 allow disabling of auto scanning sessions, requested for OpenStack + +* Tue Feb 28 2017 Chris Leech - 6.2.0.874-1 +- 1384090 upstream 2.0.874+ with qedi support +- 1414819 iscsid reporting blank emerg messages + +* Thu Aug 18 2016 Chris Leech - 6.2.0.873-35 +- 1362590 Revert iscsiuio pthread changes that result in a race condition on shutdown + +* Tue Jun 14 2016 Chris Leech - 6.2.0.873-34 +- 1322000 ensure TCP abort on session failure to prevent data corruption with link flap +- 1294964, 1265073, 1213569 iscsiuio update, fix small ARP table issue +- 1309488 remove broken sysfs cache code to speed up login of many sessions +- 1330348 sync with upstream Open-iSCSI for minor fixes + +* Tue Apr 26 2016 Chris Leech - 6.2.0.873-33 +- 1275139 iscsiuio support for multi-function mode NetXtreme2 HBAs + +* Fri Jul 24 2015 Chris Leech - 6.2.0.873-32 +- 1235684 apply safe_logout setting to flashnode sessions as well + but only when logging out by session id, not by flashnode index + +* Tue Jul 21 2015 Chris Leech - 6.2.0.873-31 +- 1235684 fix safe logout DM name canonicalization, use libmount cache + +* Mon Jul 06 2015 Chris Leech - 6.2.0.873-30 +- 1235684 add iscsid safe logout option + +* Fri Jan 30 2015 Chris Leech - 6.2.0.873-29 +- 1166713 1187792 add missing ExecStart, only newer systemd lets that be optional for oneshot services + +* Thu Jan 15 2015 Chris Leech - 6.2.0.873-28 +- 1180100 scriptlets were never split out properly for the iscsiuio subpackage + +* Thu Jan 15 2015 Chris Leech - 6.2.0.873-27 +- 1168556 fix regression in network interface binding + +* Mon Jan 12 2015 Chris Leech - 6.2.0.873-26 +- 1166713 created iscsi-shutdown.service to ensure that session cleanup happens + +* Thu Dec 11 2014 Andy Grover - 6.2.0.873-25 +- Add --with-slp=no for #1088020 + +* Tue Nov 18 2014 Chris Leech - 6.2.0.873-24 +- 1040343 segfault from unexpected netlink event during discovery +- inhibit strict aliasing optimizations in iscsiuio, rpmdiff error + +* Tue Oct 21 2014 Chris Leech - 6.2.0.873-23 +- make sure to pass --with-security=no to isns configure (#1088020) + +* Wed Sep 24 2014 Chris Leech - 6.2.0.873-22 +- 1081798 retry login on host not found error +- 1111925 ignore iscsiadm return in iscsi.service +- 1126524 make sure systemd order against remote mounts is correct +- 963039 add discovery as a valid mode in iscsiadm.8 +- sync with upstream + +* Tue Mar 18 2014 Chris Leech - 6.2.0.873-21 +- 1069825 +- boot session handling improvements +- Fix iscsi-mark-root for changed iscsiadm output +- Make sure iscsiuio is running for boot session recovery when using the + bnx2i transport by forcing iscsiuio.service start +- Make NM dispatch triggered re-check for autostart sessions async +- Accept exit code 21, no records, from iscsiadm as success in + iscsi.service + +* Tue Feb 25 2014 Chris Leech - 6.2.0.873-20 +- 1049710 host0 being treated as an invalid in the host stats command +- 1015563 revert change to return code when calling login_portal for sessions + that already exist, as it impacts users scripting around iscsiadm + +* Mon Feb 17 2014 Chris Leech - 6.2.0.873-19 +- 1007388 fixes for iscsiadm to support qla4xxx +- refresh boot session info patches to final version from upstream, + fixes context issues with later patches +- 1006156, 1006161 Add/Update entries in chap table through Open-iSCSI +- 948134 extend support to set additional parameters for network configuration +- 1049710 update open-iscsi to support host statistics +- 1043019 iscsiuio fix for arp cache flush issue +- 1059332 Fix broken discovery sessions over iser +- 1017393 split out iscsiuio into a seperate sub-package + +* Fri Jan 24 2014 Daniel Mach - 6.2.0.873-18 +- Mass rebuild 2014-01-24 + +* Fri Dec 27 2013 Daniel Mach - 6.2.0.873-17 +- Mass rebuild 2013-12-27 + +* Mon Nov 25 2013 Chris Leech - 6.2.0.873-16 +- fix iscsiuio socket activation +- have systemd start socket units on iscsiadm use, if not already listening + +* Sun Sep 15 2013 Chris Leech - 6.2.0.873-15 +- move /sbin to /usr/sbin +- use rpm macros in install rules + +* Fri Sep 13 2013 Chris Leech - 6.2.0.873-14 +- fix iscsiuio hardened build and other compiler flags + +* Fri Aug 23 2013 Andy Grover - 6.2.0.873-13 +- Fix patch 0041 to check session != NULL before calling iscsi_sysfs_read_boot() + +* Tue Aug 20 2013 Chris Leech - 6.2.0.873-12 +- fix regression in last build, database records can't be accessed + +* Mon Aug 19 2013 Chris Leech - 6.2.0.873-11 +- iscsi boot related fixes + make sure iscsid gets started if there are any boot sessions running + add reload target to fix double session problem when restarting from NM + don't rely on session list passed from initrd, never got fully implemented + remove patches related to running iscsid from initrd, possible to revisit later + +* Sun Aug 18 2013 Chris Leech - 6.2.0.873-10 +- sync with upstream git, minor context fixes after rebase of out-of-tree patches +- iscsiuio is merged upstream, remove old source archive and patches +- spec cleanups to fix rpmlint issues + +* Sun Aug 4 2013 Peter Robinson 6.2.0.873-9 +- Fix FTBFS, cleanup spec + +* Sat Aug 03 2013 Fedora Release Engineering - 6.2.0.873-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Tue Jun 11 2013 Chris Leech - 6.2.0.873-7 +- Use the systemd tmpfiles service to recreate lockfiles in /var/lock +- 955167 build as a position independent executable +- 894576 fix order of setuid/setgid and drop additional groups + +* Tue May 28 2013 Chris Leech - 6.2.0.873-6 +- Don't have iscsiadm scan for autostart record if node db is empty (bug #951951) + +* Tue Apr 30 2013 Orion Poplawski - 6.2.0.873-5 +- Fix typo in NM dispatcher script (bug #917058) + +* Thu Feb 21 2013 Chris Leech - 6.2.0.873-4 +- build with libkmod support, instead of calling out to modprobe +- enable socket activation by default + +* Thu Jan 24 2013 Kalev Lember - 6.2.0.873-3 +- Fix the postun script to not use ldconfig as the interpreter + +* Wed Jan 23 2013 Chris Leech - 6.2.0.873-2 +- package iscsi_mark_root_nodes script, it's being referenced by the unit files + +* Tue Jan 22 2013 Chris Leech - 6.2.0.873-1 +- rebase to new upstream code +- systemd conversion +- 565245 Fix multilib issues caused by timestamp in doxygen footers + +* Thu Jul 19 2012 Fedora Release Engineering - 6.2.0.872-19 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue Feb 14 2012 Mike Christie 6.2.0.872.18 +- 789683 Fix boot slow down when the iscsi service is started + (regression added in 6.2.0.872.16 when the nm wait was added). + +* Mon Feb 6 2012 Mike Christie 6.2.0.872.17 +- 786174 Change iscsid/iscsi service startup, so it always starts + when called. + +* Sat Feb 4 2012 Mike Christie 6.2.0.872.16 +- 747479 Fix iscsidevs handling of network requirement + +* Fri Jan 13 2012 Fedora Release Engineering - 6.2.0.872-15 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Wed Nov 30 2011 Mike Christie 6.2.0.872.14 +- Fix version string to reflect fedora and not rhel. + +* Tue Oct 18 2011 Mike Christie 6.2.0.872.13 +- Update iscsi tools. + +* Sat Apr 30 2011 Hans de Goede - 6.2.0.872-12 +- Change iscsi init scripts to check for networking being actually up, rather + then for NetworkManager being started (#692230) + +* Tue Apr 26 2011 Hans de Goede - 6.2.0.872-11 +- Fix iscsid autostarting when upgrading from an older version + (add iscsid.startup key to iscsid.conf on upgrade) +- Fix printing of [ OK ] when successfully stopping iscsid +- systemd related fixes: + - Add Should-Start/Stop tgtd to iscsi init script to fix (re)boot from + hanging when using locally hosted targets + - %%ghost /var/lock/iscsi and contents (#656605) + +* Mon Apr 25 2011 Mike Christie 6.2.0.872-10 +- Fix iscsi init scripts check for networking being up (#692230) + +* Wed Feb 09 2011 Fedora Release Engineering - 6.2.0.872-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild