]> git.pld-linux.org Git - packages/open-iscsi.git/commitdiff
- updated to 2.1.4 + current Fedora patch set
authorJakub Bogusz <qboosh@pld-linux.org>
Mon, 16 May 2022 19:50:10 +0000 (21:50 +0200)
committerJakub Bogusz <qboosh@pld-linux.org>
Mon, 16 May 2022 19:50:10 +0000 (21:50 +0200)
- updated systemd patch
- removed obsolete git,build patches
- added libscsi patch, rename Fedora-provided libiscsi to libopeniscsi to resolve conflict with libiscsi.spec

34 files changed:
0001-Remove-dependences-from-iscsi-init.service.patch [new file with mode: 0644]
0001-unit-file-tweaks.patch [new file with mode: 0644]
0005-update-initscripts-and-docs.patch [new file with mode: 0644]
0008-libiscsi.patch [new file with mode: 0644]
0009-Add-macros-to-release-GIL-lock.patch [new file with mode: 0644]
0010-libiscsi-introduce-sessions-API.patch [new file with mode: 0644]
0011-libiscsi-fix-discovery-request-timeout-regression.patch [new file with mode: 0644]
0012-libiscsi-format-security-build-errors.patch [new file with mode: 0644]
0013-libiscsi-fix-build-to-use-libopeniscsiusr.patch [new file with mode: 0644]
0014-libiscsi-fix-build-against-latest-upstream-again.patch [new file with mode: 0644]
0015-remove-the-offload-boot-supported-ifdef.patch [new file with mode: 0644]
0016-Revert-iscsiadm-return-error-when-login-fails.patch [new file with mode: 0644]
0019-Coverity-scan-fixes.patch [new file with mode: 0644]
0020-fix-upstream-build-breakage-of-iscsiuio-LDFLAGS.patch [new file with mode: 0644]
0022-iscsi_if.h-replace-zero-length-array-with-flexible-a.patch [new file with mode: 0644]
0023-stop-using-Werror-for-now.patch [new file with mode: 0644]
0024-minor-service-file-updates.patch [new file with mode: 0644]
0044-iscsid-add-initrd-option-to-set-run-from-initrd-hint.patch [deleted file]
0047-iscsiadm-iscsid-newroot-command-to-survive-switch_ro.patch [deleted file]
0047-iscsiuio-systemd-socket-activation-support.patch [deleted file]
0048-iscsiadm-param-parsing-for-advanced-node-creation.patch [deleted file]
0049-update-systemd-service-files-add-iscsi.service-for-s.patch [deleted file]
0050-iscsi-boot-related-service-file-updates.patch [deleted file]
0058-iscsiuio-IPC-newroot-command.patch [deleted file]
0059-iscsiuio-systemd-unit-files.patch [deleted file]
0062-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch [deleted file]
0063-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch [deleted file]
0065-fix-hardened-build-of-iscsiuio.patch [deleted file]
0066-start-socket-listeners-on-iscsiadm-command.patch [deleted file]
open-iscsi-build.patch [deleted file]
open-iscsi-git.patch [deleted file]
open-iscsi-libiscsi.patch [new file with mode: 0644]
open-iscsi-systemd.patch
open-iscsi.spec

diff --git a/0001-Remove-dependences-from-iscsi-init.service.patch b/0001-Remove-dependences-from-iscsi-init.service.patch
new file mode 100644 (file)
index 0000000..66c4cc4
--- /dev/null
@@ -0,0 +1,28 @@
+From 432bbf979ee66ee29bb92e35fd6e3ffb948563e3 Mon Sep 17 00:00:00 2001
+From: Lee Duncan <lduncan@suse.com>
+Date: Wed, 29 Sep 2021 11:48:16 -0700
+Subject: [PATCH] Remove dependences from iscsi-init.service
+
+Since iscsid.service depends on it but disables
+default dependencies, iscsi-init.service must
+also disable default dependencies, or a dependency
+loop can be created.
+---
+ etc/systemd/iscsi-init.service | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/etc/systemd/iscsi-init.service b/etc/systemd/iscsi-init.service
+index e058ff0..eab4ff2 100644
+--- a/etc/systemd/iscsi-init.service
++++ b/etc/systemd/iscsi-init.service
+@@ -1,6 +1,7 @@
+ [Unit]
+ Description=One time configuration for iscsi.service
+ ConditionPathExists=!/etc/iscsi/initiatorname.iscsi
++DefaultDependencies=no
+ Before=iscsid.service
+ [Service]
+-- 
+2.33.0
+
diff --git a/0001-unit-file-tweaks.patch b/0001-unit-file-tweaks.patch
new file mode 100644 (file)
index 0000000..743dccd
--- /dev/null
@@ -0,0 +1,175 @@
+From fd538429be486d057b092e3b9c148add2c5ea9c2 Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Tue, 4 Jun 2019 13:23:32 -0700
+Subject: [PATCH 1/1] unit file tweaks
+
+---
+ etc/systemd/iscsi-mark-root-nodes  | 34 ++++++++++++++++++++++++++++++
+ etc/systemd/iscsi-onboot.service   | 15 +++++++++++++
+ etc/systemd/iscsi-shutdown.service | 15 +++++++++++++
+ etc/systemd/iscsi.service          | 16 +++++++-------
+ etc/systemd/iscsid.service         |  3 +--
+ etc/systemd/iscsiuio.service       |  4 +---
+ 6 files changed, 74 insertions(+), 13 deletions(-)
+ create mode 100755 etc/systemd/iscsi-mark-root-nodes
+ create mode 100644 etc/systemd/iscsi-onboot.service
+ create mode 100644 etc/systemd/iscsi-shutdown.service
+
+diff --git a/etc/systemd/iscsi-mark-root-nodes b/etc/systemd/iscsi-mark-root-nodes
+new file mode 100755
+index 0000000..9d48805
+--- /dev/null
++++ b/etc/systemd/iscsi-mark-root-nodes
+@@ -0,0 +1,34 @@
++#!/bin/bash
++
++ISCSIADM=/usr/sbin/iscsiadm
++start_iscsid=0
++start_iscsiuio=0
++
++while read t num p target flash; do
++  # strip tag number from portal, keep "ip:port"
++  portal=${p%,*}
++  transport=${t%:}
++
++  # use session number to find the iface name in use
++  num=${num#[}; num=${num%]}
++  iface=$(iscsiadm -m session -r $num | grep iface.iscsi_ifacename | cut -d= -f2)
++
++  $ISCSIADM -m node -p $portal -T $target -I $iface -o update -n node.startup -v onboot
++
++  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
++
+diff --git a/etc/systemd/iscsi-onboot.service b/etc/systemd/iscsi-onboot.service
+new file mode 100644
+index 0000000..42ced68
+--- /dev/null
++++ b/etc/systemd/iscsi-onboot.service
+@@ -0,0 +1,15 @@
++[Unit]
++Description=Special handling of early boot iSCSI sessions
++Documentation=man:iscsiadm(8) man:iscsid(8)
++DefaultDependencies=no
++RefuseManualStart=true
++Before=iscsi.service
++After=systemd-remount-fs.service
++ConditionDirectoryNotEmpty=/sys/class/iscsi_session
++
++[Service]
++Type=oneshot
++ExecStart=-/usr/libexec/iscsi-mark-root-nodes
++
++[Install]
++WantedBy=sysinit.target
+diff --git a/etc/systemd/iscsi-shutdown.service b/etc/systemd/iscsi-shutdown.service
+new file mode 100644
+index 0000000..caee933
+--- /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=-/usr/bin/true
++ExecStop=-/usr/sbin/iscsiadm -m node --logoutall=all
+diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service
+index 5e394b9..175cb2c 100644
+--- a/etc/systemd/iscsi.service
++++ b/etc/systemd/iscsi.service
+@@ -1,18 +1,18 @@
+ [Unit]
+ Description=Login and scanning of iSCSI devices
+ Documentation=man:iscsiadm(8) man:iscsid(8)
+-Before=remote-fs.target
+-After=network-online.target iscsid.service
+-Requires=iscsid.socket iscsi-init.service
+-Wants=network-online.target
++DefaultDependencies=no
++Before=remote-fs-pre.target
++After=network.target network-online.target iscsid.service iscsiuio.service systemd-remount-fs.service
++Wants=remote-fs-pre.target iscsi-shutdown.service
++ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes
+ [Service]
+ Type=oneshot
+-ExecStart=/sbin/iscsiadm -m node --loginall=automatic -W
+-ExecStop=/sbin/iscsiadm -m node --logoutall=automatic
+-ExecStop=/sbin/iscsiadm -m node --logoutall=manual
+-SuccessExitStatus=21 15
+ RemainAfterExit=true
++ExecStart=-/usr/sbin/iscsiadm -m node --loginall=automatic
++ExecReload=-/usr/sbin/iscsiadm -m node --loginall=automatic
++SuccessExitStatus=21
+ [Install]
+ WantedBy=remote-fs.target
+diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service
+index 3fd7dd3..324c593 100644
+--- a/etc/systemd/iscsid.service
++++ b/etc/systemd/iscsid.service
+@@ -4,13 +4,12 @@ Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8)
+ DefaultDependencies=no
+ After=network-online.target iscsiuio.service iscsi-init.service
+ Before=remote-fs-pre.target
+-Wants=remote-fs-pre.target
+ Requires=iscsi-init.service
+ [Service]
+ Type=notify
+ NotifyAccess=main
+-ExecStart=/sbin/iscsid -f
++ExecStart=/usr/sbin/iscsid -f
+ KillMode=mixed
+ Restart=on-failure
+diff --git a/etc/systemd/iscsiuio.service b/etc/systemd/iscsiuio.service
+index 923e019..fc0be93 100644
+--- a/etc/systemd/iscsiuio.service
++++ b/etc/systemd/iscsiuio.service
+@@ -2,17 +2,15 @@
+ 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
+-Wants=remote-fs-pre.target
+ [Service]
+ Type=notify
+ NotifyAccess=main
+-ExecStart=/sbin/iscsiuio -f
++ExecStart=/usr/sbin/iscsiuio -f
+ KillMode=mixed
+ Restart=on-failure
+-- 
+2.26.3
+
diff --git a/0005-update-initscripts-and-docs.patch b/0005-update-initscripts-and-docs.patch
new file mode 100644 (file)
index 0000000..7d487a5
--- /dev/null
@@ -0,0 +1,134 @@
+From 97b1242450df25648d203acf7cc297cd46d10e8c Mon Sep 17 00:00:00 2001
+From: Chris Leech <cleech@redhat.com>
+Date: Mon, 19 Nov 2012 16:37:13 -0800
+Subject: [PATCH] update initscripts and docs
+
+---
+ README          | 12 +++++-------
+ etc/iscsid.conf | 23 +++++++++++------------
+ usr/idbm.c      |  4 ++++
+ 3 files changed, 20 insertions(+), 19 deletions(-)
+
+diff --git a/README b/README
+index 508c9d7..b62a14e 100644
+--- a/README
++++ b/README
+@@ -77,11 +77,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:
+       https://github.com/gonzoleeman/open-isns/releases
+@@ -1163,11 +1158,11 @@ Red Hat or Fedora:
+ -----------------
+ To start open-iscsi in Red Hat/Fedora you can do:
+-      systemctl start open-iscsi
++      systemctl start iscsi
+ To get open-iscsi to automatically start at run time you may have to
+ run:
+-      systemctl enable open-iscsi
++      systemctl enable iscsi
+ And, to automatically mount a file system during startup
+ you must have the partition entry in /etc/fstab marked with the "_netdev"
+@@ -1370,6 +1365,9 @@ 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".
++
+ Examples
+ --------
+diff --git a/etc/iscsid.conf b/etc/iscsid.conf
+index f21ed3d..420145b 100644
+--- a/etc/iscsid.conf
++++ b/etc/iscsid.conf
+@@ -19,8 +19,8 @@
+ # the time then leave this attribute commented out.
+ #
+ # Default for Fedora and RHEL. (uncomment to activate).
+-# iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket
+-#
++iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket
++# 
+ # Default if you are not using systemd (uncomment to activate)
+ # iscsid.startup = /usr/bin/service start iscsid
+@@ -41,8 +41,8 @@
+ # 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
+@@ -271,28 +271,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 f1e5c88..0f0f17a 100644
+--- a/usr/idbm.c
++++ b/usr/idbm.c
+@@ -566,9 +566,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.26.2
+
diff --git a/0008-libiscsi.patch b/0008-libiscsi.patch
new file mode 100644 (file)
index 0000000..39d1a84
--- /dev/null
@@ -0,0 +1,4014 @@
+From 8b4da8007ef59bbc833fed882ddae57bbcd51f1c Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Mon, 26 Jan 2015 12:57:11 -0800
+Subject: [PATCH] libiscsi
+
+---
+ Makefile                                    |    2 +
+ libiscsi/Makefile                           |   65 +
+ libiscsi/libiscsi.c                         |  617 ++++++++
+ libiscsi/libiscsi.doxy                      | 1473 +++++++++++++++++++
+ libiscsi/libiscsi.h                         |  344 +++++
+ libiscsi/no_date_footer.html                |    6 +
+ libiscsi/pylibiscsi.c                       |  709 +++++++++
+ 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 +
+ 22 files changed, 3769 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/no_date_footer.html
+ 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 7b445a5..4ab091f 100644
+--- a/Makefile
++++ b/Makefile
+@@ -65,6 +65,7 @@ user: iscsiuio/Makefile
+       $(MAKE) -C usr
+       $(MAKE) -C utils
+       $(MAKE) -C iscsiuio
++      $(MAKE) -C libiscsi
+       @echo
+       @echo "Compilation complete                 Output file"
+       @echo "-----------------------------------  ----------------"
+@@ -85,6 +86,7 @@ iscsiuio/configure iscsiuio/Makefile.in: iscsiuio/configure.ac iscsiuio/Makefile
+ 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 0000000..53f9746
+--- /dev/null
++++ b/libiscsi/Makefile
+@@ -0,0 +1,65 @@
++# This Makefile will work only with GNU make.
++
++ifeq ($(TOPDIR),)
++      TOPDIR = ..
++endif
++
++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 $@ -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr
++      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 0000000..064e4b5
+--- /dev/null
++++ b/libiscsi/libiscsi.c
+@@ -0,0 +1,617 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
++ * 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <sys/syslog.h>
++#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(&params);
++      param = idbm_alloc_user_param(parameter, value);
++      if (!param) {
++              rc = ENOMEM;
++              goto leave;
++      }
++      list_add_tail(&params, &param->list);
++
++      CHECK(idbm_for_each_iface(&nr_found, &params, 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;
++      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;
++}
++
++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;
++
++      strlcpy(initiatorname, fw_entry.initiatorname, LIBISCSI_VALUE_MAXLEN);
++
++      return 0;
++}
+diff --git a/libiscsi/libiscsi.doxy b/libiscsi/libiscsi.doxy
+new file mode 100644
+index 0000000..7a5ff7f
+--- /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 <command> <input-file>, where <command> is the value of 
++# the FILE_VERSION_FILTER tag, and <input-file> 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 <filter> <input-file>, where <filter> 
++# is the value of the INPUT_FILTER tag, and <input-file> 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            = 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 
++# 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 
++# <a href="http://doc.trolltech.com/qthelpproject.html#namespace">Qt Help Project / Namespace</a>.
++
++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 
++# <a href="http://doc.trolltech.com/qthelpproject.html#virtual-folders">Qt Help Project / Virtual Folders</a>.
++
++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 0000000..756590e
+--- /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 <hdegoede@redhat.com>
++ * 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 <netdb.h>
++
++#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/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 @@
++<hr size="1"><address style="text-align: right;"><small>
++Generated for $projectname by <a href="http://www.doxygen.org/
++index.html"><img src="doxygen.png" alt="doxygen" align="middle" border="0"></a>
++$doxygenversion</small></address>
++</body>
++</html>
+diff --git a/libiscsi/pylibiscsi.c b/libiscsi/pylibiscsi.c
+new file mode 100644
+index 0000000..8800853
+--- /dev/null
++++ b/libiscsi/pylibiscsi.c
+@@ -0,0 +1,709 @@
++/*
++ * iSCSI Administration library
++ *
++ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
++ * 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 <Python.h>
++#include "libiscsi.h"
++
++#if PY_MAJOR_VERSION >= 3
++#define IS_PY3K
++#define MODINITERROR return NULL
++#define PYNUM_FROMLONG PyLong_FromLong
++#define PYSTR_FROMSTRING PyUnicode_FromString
++#else
++#define MODINITERROR return
++#define PYNUM_FROMLONG PyInt_FromLong
++#define PYSTR_FROMSTRING PyString_FromString
++#endif
++
++#define RET_TRUE_ELSE_FALSE { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; }
++#define CMP_TO_RICHCMP(cmpfunc) \
++      int comp_res = cmpfunc(self, other); \
++      switch (op) { \
++          case Py_LT: \
++              if (comp_res < 0) RET_TRUE_ELSE_FALSE \
++          case Py_LE: \
++              if (comp_res <= 0) RET_TRUE_ELSE_FALSE \
++          case Py_EQ: \
++              if (comp_res == 0) RET_TRUE_ELSE_FALSE \
++          case Py_NE: \
++              if (comp_res != 0) RET_TRUE_ELSE_FALSE \
++          case Py_GT: \
++              if (comp_res > 0) RET_TRUE_ELSE_FALSE \
++          default: \
++              if (comp_res >= 0) RET_TRUE_ELSE_FALSE \
++      }
++
++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 PYSTR_FROMSTRING(chap->info.chap.username);
++      } else if (!strcmp(attr, "password")) {
++              return PYSTR_FROMSTRING(chap->info.chap.password);
++      } else if (!strcmp(attr, "reverse_username")) {
++              return PYSTR_FROMSTRING(chap->info.chap.reverse_username);
++      } else if (!strcmp(attr, "reverse_password")) {
++              return PYSTR_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;
++}
++
++PyObject *PyIscsiChapAuthInfo_richcompare(PyIscsiChapAuthInfo *self,
++                                        PyIscsiChapAuthInfo *other,
++                                        int op)
++{
++      CMP_TO_RICHCMP(PyIscsiChapAuthInfo_compare)
++}
++
++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 PYSTR_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 = {
++      PyVarObject_HEAD_INIT(NULL, 0)
++      .tp_name = "libiscsi.chapAuthInfo",
++      .tp_basicsize = sizeof (PyIscsiChapAuthInfo),
++      .tp_getset = PyIscsiChapAuthInfo_getseters,
++      .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
++#ifndef IS_PY3K
++      // Py_TPFLAGS_CHECKTYPES is only needed on Python 2
++      |  Py_TPFLAGS_CHECKTYPES
++#endif
++      ,
++      .tp_richcompare = (richcmpfunc)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 PYSTR_FROMSTRING(node->node.name);
++      } else if (!strcmp(attr, "tpgt")) {
++              return PYNUM_FROMLONG(node->node.tpgt);
++      } else if (!strcmp(attr, "address")) {
++              return PYSTR_FROMSTRING(node->node.address);
++      } else if (!strcmp(attr, "port")) {
++              return PYNUM_FROMLONG(node->node.port);
++      } else if (!strcmp(attr, "iface")) {
++              return PYSTR_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;
++}
++
++PyObject *PyIscsiNode_richcompare(PyIscsiNode *self, PyIscsiNode *other, int op)
++{
++    CMP_TO_RICHCMP(PyIscsiNode_compare)
++}
++
++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 PYSTR_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,
++                                       &parameter, &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, &parameter))
++              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 = {
++      PyVarObject_HEAD_INIT(NULL, 0)
++      .tp_name = "libiscsi.node",
++      .tp_basicsize = sizeof (PyIscsiNode),
++      .tp_getset = PyIscsiNode_getseters,
++      .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
++#ifndef IS_PY3K
++      | Py_TPFLAGS_CHECKTYPES
++#endif
++      ,
++      .tp_methods = PyIscsiNode_methods,
++      .tp_richcompare = (richcmpfunc)PyIscsiNode_richcompare,
++      .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 PYSTR_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}
++};
++
++#ifdef IS_PY3K
++static struct PyModuleDef libiscsi_def = {
++      PyModuleDef_HEAD_INIT,
++      "libiscsi",
++      NULL,
++      -1,
++      pylibiscsi_functions,
++      NULL,
++      NULL,
++      NULL,
++      NULL
++};
++
++PyMODINIT_FUNC PyInit_libiscsi(void)
++#else
++PyMODINIT_FUNC initlibiscsi(void)
++#endif
++{
++      PyObject *m;
++
++      if (!context) /* We may be called more then once */
++              context = libiscsi_init();
++      if (!context)
++              MODINITERROR;
++
++      if (PyType_Ready(&PyIscsiChapAuthInfo_Type) < 0)
++              MODINITERROR;
++
++      if (PyType_Ready(&PyIscsiNode_Type) < 0)
++              MODINITERROR;
++
++#ifdef IS_PY3K
++      m = PyModule_Create(&libiscsi_def);
++#else
++      m = Py_InitModule("libiscsi", pylibiscsi_functions);
++#endif
++      Py_INCREF(&PyIscsiChapAuthInfo_Type);
++      PyModule_AddObject(m, "chapAuthInfo", (PyObject *) &PyIscsiChapAuthInfo_Type);
++      Py_INCREF(&PyIscsiNode_Type);
++      PyModule_AddObject(m, "node", (PyObject *) &PyIscsiNode_Type);
++#ifdef IS_PY3K
++      return m;
++#endif
++}
+diff --git a/libiscsi/setup.py b/libiscsi/setup.py
+new file mode 100644
+index 0000000..caa4e66
+--- /dev/null
++++ b/libiscsi/setup.py
+@@ -0,0 +1,9 @@
++from distutils.core import setup, Extension
++
++module1 = Extension('libiscsi',
++                    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 0000000..76e852a
+--- /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 <hdegoede@redhat.com>
++ * 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 0000000..1a3c12e
+--- /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 <hdegoede@redhat.com>
++ * 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 0000000..5e234da
+--- /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 <hdegoede@redhat.com>
++ * 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 0000000..997c053
+--- /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 <hdegoede@redhat.com>
++ * 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 0000000..2dedd61
+--- /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 <hdegoede@redhat.com>
++ * 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 0000000..3eb70d6
+--- /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 <hdegoede@redhat.com>
++ * 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 0000000..b734dca
+--- /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 <hdegoede@redhat.com>
++ * 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 <stdio.h>
++#include <stdlib.h>
++#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 0000000..d3223be
+--- /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 <hdegoede@redhat.com>
++ * 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 <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#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 0000000..a21f888
+--- /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 <hdegoede@redhat.com>
++ * 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 <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#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 21bb154..885243a 100644
+--- a/usr/Makefile
++++ b/usr/Makefile
+@@ -37,7 +37,7 @@ PKG_CONFIG = /usr/bin/pkg-config
+ CFLAGS ?= -O2 -g
+ WARNFLAGS ?= -Wall -Wextra -Werror -Wstrict-prototypes -fno-common
+ CFLAGS += $(WARNFLAGS) -I../include -I. -D_GNU_SOURCE \
+-        -I$(TOPDIR)/libopeniscsiusr
++        -I$(TOPDIR)/libopeniscsiusr -DISNS_ENABLE
+ CFLAGS += $(shell $(PKG_CONFIG) --cflags libkmod)
+ ISCSI_LIB = -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr
+ LDFLAGS += $(shell $(PKG_CONFIG) --libs libkmod)
+diff --git a/usr/discovery.c b/usr/discovery.c
+index 7dec696..2cf1838 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 <libisns/isns.h>
+ #include <libisns/paths.h>
+ #include <libisns/message.h>
++#endif
+ #ifdef SLP_ENABLE
+ #include "iscsi-slp-discovery.h"
+@@ -98,6 +101,7 @@ static int request_initiator_name(int tmo)
+       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,
+                __attribute__((unused))struct iface_rec *iface,
+diff --git a/usr/idbm.c b/usr/idbm.c
+index 27cad0a..2498a03 100644
+--- a/usr/idbm.c
++++ b/usr/idbm.c
+@@ -1825,9 +1825,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,
+-                             bool ruw_lock)
++int idbm_for_each_iface(int *found, void *data, idbm_iface_op_fn *fn,
++                      char *targetname, int tpgt, char *ip, int port,
++                      bool ruw_lock)
+ {
+       DIR *iface_dirfd;
+       struct dirent *iface_dent;
+diff --git a/usr/idbm.h b/usr/idbm.h
+index ce098b7..d1a7f63 100644
+--- a/usr/idbm.h
++++ b/usr/idbm.h
+@@ -105,6 +105,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,
++                              bool ruw_lock);
+ extern int idbm_for_each_portal(int *found, void *data, idbm_portal_op_fn *fn,
+                               char *targetname, bool ruw_lock);
+ extern int idbm_for_each_node(int *found, void *data,
+diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h
+index 47857dd..596543b 100644
+--- a/usr/iscsi_ipc.h
++++ b/usr/iscsi_ipc.h
+@@ -162,4 +162,6 @@ struct iscsi_ipc {
+                        char *host_stats);
+ };
++extern struct iscsi_ipc *ipc;
++
+ #endif /* ISCSI_IPC_H */
+-- 
+2.26.2
+
diff --git a/0009-Add-macros-to-release-GIL-lock.patch b/0009-Add-macros-to-release-GIL-lock.patch
new file mode 100644 (file)
index 0000000..e03b7ef
--- /dev/null
@@ -0,0 +1,56 @@
+From 676f48d6e70f8406b36a004669d923825db51e2f Mon Sep 17 00:00:00 2001
+From: Jiri Konecny <jkonecny@redhat.com>
+Date: Mon, 11 May 2015 13:16:26 +0200
+Subject: [PATCH] Add macros to release GIL lock
+
+Other threads are blocked when GIL is not released before the time consuming
+functions.
+---
+ libiscsi/pylibiscsi.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/libiscsi/pylibiscsi.c b/libiscsi/pylibiscsi.c
+index 8800853..40b5955 100644
+--- a/libiscsi/pylibiscsi.c
++++ b/libiscsi/pylibiscsi.c
+@@ -364,8 +364,13 @@ static PyObject *PyIscsiNode_str(PyObject *self)
+ static PyObject *PyIscsiNode_login(PyObject *self)
+ {
+       PyIscsiNode *node = (PyIscsiNode *)self;
++      int ret;
+-      if (libiscsi_node_login(context, &node->node)) {
++      Py_BEGIN_ALLOW_THREADS
++      ret = libiscsi_node_login(context, &node->node);
++      Py_END_ALLOW_THREADS
++
++      if (ret) {
+               PyErr_SetString(PyExc_IOError,
+                               libiscsi_get_error_string(context));
+               return NULL;
+@@ -551,6 +556,7 @@ static PyObject *pylibiscsi_discover_sendtargets(PyObject *self,
+       const struct libiscsi_auth_info *authinfo = NULL;
+       struct libiscsi_node *found_nodes;
+       PyObject* found_node_list;
++      int ret;
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|iO",
+                                       kwlist, &address, &port,
+@@ -570,8 +576,12 @@ static PyObject *pylibiscsi_discover_sendtargets(PyObject *self,
+               }
+       }
+-      if (libiscsi_discover_sendtargets(context, address, port, authinfo,
+-                                        &nr_found, &found_nodes)) {
++      Py_BEGIN_ALLOW_THREADS
++      ret = libiscsi_discover_sendtargets(context, address, port, authinfo,
++                                          &nr_found, &found_nodes);
++      Py_END_ALLOW_THREADS
++
++      if (ret) {
+               PyErr_SetString(PyExc_IOError,
+                               libiscsi_get_error_string(context));
+               return NULL;
+-- 
+2.26.2
+
diff --git a/0010-libiscsi-introduce-sessions-API.patch b/0010-libiscsi-introduce-sessions-API.patch
new file mode 100644 (file)
index 0000000..57ab58f
--- /dev/null
@@ -0,0 +1,290 @@
+From 2c28c620727e522f022689312d76f107eb8ef18f Mon Sep 17 00:00:00 2001
+From: Peter Hatina <phatina@redhat.com>
+Date: Mon, 5 Oct 2015 16:50:36 -0700
+Subject: [PATCH] libiscsi introduce sessions API
+
+---
+ libiscsi/libiscsi.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
+ libiscsi/libiscsi.h |  56 ++++++++++++++++++++
+ usr/iscsi_sysfs.c   |   6 +++
+ usr/iscsi_sysfs.h   |   2 +
+ 4 files changed, 189 insertions(+)
+
+diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c
+index 064e4b5..755c18c 100644
+--- a/libiscsi/libiscsi.c
++++ b/libiscsi/libiscsi.c
+@@ -3,6 +3,7 @@
+  *
+  * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
+  * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
++ * Copyright (C) 2015      Peter Hatina <phatina@redhat.com>
+  * maintained by open-iscsi@googlegroups.com
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -469,6 +470,130 @@ leave:
+       return rc;
+ }
++struct libiscsi_session_array {
++      int cnt;
++      int size;
++      struct libiscsi_session_info *data;
++};
++
++static void libiscsi_session_array_init(struct libiscsi_session_array *arr)
++{
++      arr->cnt = 0;
++      arr->size = 0;
++      arr->data = NULL;
++}
++
++static int libiscsi_session_array_grow(struct libiscsi_session_array *arr)
++{
++      if (arr->size == 0)
++              arr->size = 4;
++      else
++              arr->size *= 2;
++
++      arr->data = (struct libiscsi_session_info *) realloc(
++              arr->data,
++              arr->size * sizeof(struct libiscsi_session_info));
++
++      return arr->data ? 0 : 1;
++}
++
++static int libiscsi_session_array_grow_ondemand(struct libiscsi_session_array *arr)
++{
++      if (arr->size == arr->cnt)
++              return libiscsi_session_array_grow(arr);
++      return 0;
++}
++
++static int libiscsi_session_array_resize_precize(struct libiscsi_session_array *arr)
++{
++      arr->data = (struct libiscsi_session_info *) realloc(
++              arr->data,
++              arr->cnt * sizeof(struct libiscsi_session_info));
++      arr->size = arr->cnt;
++
++      return arr->data ? 0 : 1;
++}
++
++static void copy_session_info_to_libiscsi_session_info(
++      struct libiscsi_session_info *info,
++      struct session_info *s_info)
++{
++      /* Copy session info to public struct. */
++      info->sid = s_info->sid;
++      /* Timeouts */
++      memcpy(&info->tmo, &s_info->tmo, sizeof(struct libiscsi_session_timeout));
++      /* CHAP authentication information */
++      memcpy(&info->chap, &s_info->chap, sizeof(struct libiscsi_chap_auth_info));
++      /* Target information */
++      strncpy(info->targetname, s_info->targetname, LIBISCSI_VALUE_MAXLEN);
++      strncpy(info->address, s_info->address, NI_MAXHOST);
++      strncpy(info->persistent_address, s_info->persistent_address, NI_MAXHOST);
++      info->tpgt = s_info->tpgt;
++      info->persistent_port = s_info->persistent_port;
++}
++
++static int get_sessions_helper(void *data, struct session_info *s_info)
++{
++      struct libiscsi_session_array *arr = (struct libiscsi_session_array *) data;
++
++      if (libiscsi_session_array_grow_ondemand(arr) != 0)
++              return 1;
++
++      copy_session_info_to_libiscsi_session_info(&arr->data[arr->cnt++], s_info);
++
++      return 0;
++}
++
++int libiscsi_get_session_infos(struct libiscsi_context *context,
++      struct libiscsi_session_info **infos,
++      int *nr_sessions)
++{
++      int rc = 0;
++      int nr_found = 0;
++      struct libiscsi_session_array arr;
++
++      if (!context || !infos || !nr_sessions)
++              return 1;
++
++      libiscsi_session_array_init(&arr);
++
++      rc = iscsi_sysfs_for_each_session((void *) &arr, &nr_found,
++              get_sessions_helper, 0);
++      if (rc != 0 || nr_found == 0) {
++              strcpy(context->error_str, "No matching session");
++              return ENODEV;
++      }
++
++      if (libiscsi_session_array_resize_precize(&arr) != 0) {
++              strcpy(context->error_str, "Can't allocate memory for session infos");
++              return ENOMEM;
++      }
++
++      *infos = arr.data;
++      *nr_sessions = nr_found;
++
++      return 0;
++}
++
++int libiscsi_get_session_info_by_id(struct libiscsi_context *context,
++      struct libiscsi_session_info *info,
++      const char *session)
++{
++      struct session_info s_info;
++
++      if (!context || !info || !session)
++              return 1;
++
++      if (iscsi_sysfs_get_sessioninfo_by_id(&s_info, (char*) session) != 0) {
++              strcpy(context->error_str, "No matching session");
++              return ENODEV;
++      }
++
++      copy_session_info_to_libiscsi_session_info(info, &s_info);
++
++      return 0;
++}
++
+ int libiscsi_node_set_parameter(struct libiscsi_context *context,
+       const struct libiscsi_node *node,
+       const char *parameter, const char *value)
+diff --git a/libiscsi/libiscsi.h b/libiscsi/libiscsi.h
+index 756590e..a9891f4 100644
+--- a/libiscsi/libiscsi.h
++++ b/libiscsi/libiscsi.h
+@@ -3,6 +3,7 @@
+  *
+  * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
+  * Copyright (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
++ * Copyright (C) 2015      Peter Hatina <phatina@redhat.com>
+  * maintained by open-iscsi@googlegroups.com
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -56,6 +57,17 @@ enum libiscsi_auth_t {
+  */
+ struct libiscsi_context;
++/** \brief iSCSI session timeouts
++ *
++ * Struct holding session timeouts.
++ */
++struct libiscsi_session_timeout {
++    int abort_tmo;
++    int lu_reset_tmo;
++    int recovery_tmo;
++    int tgt_reset_tmo;
++};
++
+ /** \brief iSCSI node record
+  *
+  * Struct holding data uniquely identifying an iSCSI node.
+@@ -84,6 +96,24 @@ struct libiscsi_chap_auth_info {
+     char reverse_password[LIBISCSI_VALUE_MAXLEN] /** Reverse Password */;
+ };
++/** \brief iSCSI session
++ *
++ * Struct hoding iSCSI session information.
++ */
++struct libiscsi_session_info {
++    int sid;
++
++    struct libiscsi_session_timeout tmo;
++    struct libiscsi_chap_auth_info chap;
++
++    char targetname[LIBISCSI_VALUE_MAXLEN];
++    int tpgt;
++    char address[NI_MAXHOST];
++    int port;
++    char persistent_address[NI_MAXHOST];
++    int persistent_port;
++};
++
+ /** \brief generic libiscsi authentication information struct
+  *
+  * Struct holding authentication information for discovery and login.
+@@ -248,6 +278,32 @@ PUBLIC int libiscsi_node_login(struct libiscsi_context *context,
+ PUBLIC int libiscsi_node_logout(struct libiscsi_context *context,
+     const struct libiscsi_node *node);
++/** \brief Get an array of iSCSI sessions.
++ *
++ * Get the array containing iSCSI sessions' information.
++ *
++ * \param context       libiscsi context to operate on.
++ * \param infos         Array of iSCSI sessions' information.
++ *                      Release with free().
++ * \param nr_sessions   The number of elements in \e infos.
++ * \return              0 on success, otherwise a standard error code
++ *                      (from errno.h).
++ */
++PUBLIC int libiscsi_get_session_infos(struct libiscsi_context *context,
++    struct libiscsi_session_info **infos, int *nr_sessions);
++
++/** \brief Get session information by session ID.
++ *
++ * \param context       libiscsi context to operate on.
++ * \param info          iSCSI session information.
++ * \param session       Session name.
++ * \return              0 on success, otherwise a standard error code
++ *                      (from errno.h)
++ */
++PUBLIC int libiscsi_get_session_info_by_id(struct libiscsi_context *context,
++    struct libiscsi_session_info *info,
++    const char *session);
++
+ /** \brief Set an iSCSI parameter for the given node
+  *
+  * Set the given nodes iSCSI parameter named by \e parameter to value \e value.
+diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c
+index 435c576..e549afe 100644
+--- a/usr/iscsi_sysfs.c
++++ b/usr/iscsi_sysfs.c
+@@ -3,6 +3,7 @@
+  *
+  * Copyright (C) 2006 Mike Christie
+  * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2015      Peter Hatina <phatina@redhat.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
+@@ -1151,6 +1152,11 @@ free_info:
+       return rc;
+ }
++const char *iscsi_sysfs_get_session_path(void)
++{
++      return ISCSI_SESSION_DIR;
++}
++
+ int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no,
+                                      int *nr_found,
+                                      iscsi_sysfs_iface_op_fn *fn)
+diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h
+index 1d0377f..909db34 100644
+--- a/usr/iscsi_sysfs.h
++++ b/usr/iscsi_sysfs.h
+@@ -3,6 +3,7 @@
+  *
+  * Copyright (C) 2006 Mike Christie
+  * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
++ * Copyright (C) 2015      Peter Hatina <phatina@redhat.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
+@@ -47,6 +48,7 @@ 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 const char *iscsi_sysfs_get_session_path(void);
+ extern int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no,
+                                             int *nr_found,
+                                             iscsi_sysfs_iface_op_fn *fn);
+-- 
+2.26.2
+
diff --git a/0011-libiscsi-fix-discovery-request-timeout-regression.patch b/0011-libiscsi-fix-discovery-request-timeout-regression.patch
new file mode 100644 (file)
index 0000000..cddc17c
--- /dev/null
@@ -0,0 +1,32 @@
+From c53c576c09c5a3a1654b7a1f08fcc222a102499d Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Tue, 28 Feb 2017 09:00:41 -0800
+Subject: [PATCH] libiscsi: fix discovery request timeout regression
+
+---
+ libiscsi/libiscsi.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c
+index 755c18c..bb17dfc 100644
+--- a/libiscsi/libiscsi.c
++++ b/libiscsi/libiscsi.c
+@@ -136,6 +136,7 @@ int libiscsi_discover_sendtargets(struct libiscsi_context *context,
+       /* Fill the drec struct with all needed info */
+       memset(&drec, 0, sizeof drec);
++      drec.iscsid_req_tmo = -1;
+       idbm_sendtargets_defaults(&drec.u.sendtargets);
+       drec.type = DISCOVERY_TYPE_SENDTARGETS;
+       strlcpy(drec.address, address, sizeof(drec.address));
+@@ -228,6 +229,7 @@ int libiscsi_discover_firmware(struct libiscsi_context *context,
+       CHECK(iface_create_ifaces_from_boot_contexts(&ifaces, &targets));
+       memset(&drec, 0, sizeof(drec));
++      drec.iscsid_req_tmo = -1;
+       drec.type = DISCOVERY_TYPE_FW;
+       rc = idbm_bind_ifaces_to_nodes(discovery_fw, &drec, &ifaces, &rec_list);
+       if (rc) {
+-- 
+2.26.2
+
diff --git a/0012-libiscsi-format-security-build-errors.patch b/0012-libiscsi-format-security-build-errors.patch
new file mode 100644 (file)
index 0000000..421bc3b
--- /dev/null
@@ -0,0 +1,35 @@
+From cf4db608004f7c1f137ed556e3ba6b6f4d65da96 Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Tue, 28 Feb 2017 10:06:42 -0800
+Subject: [PATCH] libiscsi format-security build errors
+
+---
+ libiscsi/libiscsi.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c
+index bb17dfc..7003388 100644
+--- a/libiscsi/libiscsi.c
++++ b/libiscsi/libiscsi.c
+@@ -177,7 +177,8 @@ int libiscsi_discover_sendtargets(struct libiscsi_context *context,
+               *found_nodes = calloc(found, sizeof **found_nodes);
+               if (*found_nodes == NULL) {
+                       snprintf(context->error_str,
+-                               sizeof(context->error_str), strerror(ENOMEM));
++                               sizeof(context->error_str),
++                               "%s", strerror(ENOMEM));
+                       rc = ENOMEM;
+                       goto leave;
+               }
+@@ -634,7 +635,7 @@ static int get_parameter_helper(void *data, node_rec_t *rec)
+       info = idbm_recinfo_alloc(MAX_KEYS);
+       if (!info) {
+               snprintf(context->error_str, sizeof(context->error_str),
+-                       strerror(ENOMEM));
++                       "%s", strerror(ENOMEM));
+               return ENOMEM;
+       }
+-- 
+2.26.2
+
diff --git a/0013-libiscsi-fix-build-to-use-libopeniscsiusr.patch b/0013-libiscsi-fix-build-to-use-libopeniscsiusr.patch
new file mode 100644 (file)
index 0000000..9b3c34b
--- /dev/null
@@ -0,0 +1,36 @@
+From a86a677762cf5fd45a43029a4fd3dd83d1a87a98 Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Thu, 24 May 2018 15:17:05 -0700
+Subject: [PATCH] libiscsi fix build to use libopeniscsiusr
+
+---
+ libiscsi/Makefile | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/libiscsi/Makefile b/libiscsi/Makefile
+index 53f9746..f2cf248 100644
+--- a/libiscsi/Makefile
++++ b/libiscsi/Makefile
+@@ -8,7 +8,9 @@ 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
++              -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden \
++              -I../libopeniscsiusr
++LDFLAGS = -L../libopeniscsiusr -lopeniscsiusr
+ LIB = libiscsi.so.0
+ TESTS = tests/test_discovery_sendtargets tests/test_discovery_firmware
+ TESTS += tests/test_login tests/test_logout tests/test_params
+@@ -23,7 +25,7 @@ FW_PARAM_SRCS = fw_entry.o prom_lex.o prom_parse.tab.o fwparam_ppc.o fwparam_sys
+ # 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)
++USR_OBJS = $(patsubst %.o, usr-objs/%.o, $(ISCSI_LIB_SRCS) local_strings.o)
+ FW_OBJS = $(patsubst %.o, fw-objs/%.o, $(FW_PARAM_SRCS))
+ # Flags for the tests
+-- 
+2.26.2
+
diff --git a/0014-libiscsi-fix-build-against-latest-upstream-again.patch b/0014-libiscsi-fix-build-against-latest-upstream-again.patch
new file mode 100644 (file)
index 0000000..f9f8d07
--- /dev/null
@@ -0,0 +1,66 @@
+From 55af753f593243bcd1ab4c7e82620bdee432915b Mon Sep 17 00:00:00 2001
+From: Chris Leech <cleech@redhat.com>
+Date: Thu, 7 Nov 2019 09:16:17 -0800
+Subject: [PATCH] libiscsi: fix build against latest upstream, again
+
+---
+ libiscsi/Makefile   | 4 ++--
+ libiscsi/libiscsi.c | 6 +++---
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/libiscsi/Makefile b/libiscsi/Makefile
+index f2cf248..462d666 100644
+--- a/libiscsi/Makefile
++++ b/libiscsi/Makefile
+@@ -10,7 +10,7 @@ WARNFLAGS ?= -Wall -Wstrict-prototypes
+ CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I../include -I../usr \
+               -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden \
+               -I../libopeniscsiusr
+-LDFLAGS = -L../libopeniscsiusr -lopeniscsiusr
++LDFLAGS = -L../libopeniscsiusr -lopeniscsiusr -lkmod -lcrypto
+ LIB = libiscsi.so.0
+ TESTS = tests/test_discovery_sendtargets tests/test_discovery_firmware
+ TESTS += tests/test_login tests/test_logout tests/test_params
+@@ -19,7 +19,7 @@ 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
++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 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
+diff --git a/libiscsi/libiscsi.c b/libiscsi/libiscsi.c
+index 7003388..c598aee 100644
+--- a/libiscsi/libiscsi.c
++++ b/libiscsi/libiscsi.c
+@@ -429,7 +429,7 @@ int libiscsi_node_login(struct libiscsi_context *context,
+       CHECK(idbm_for_each_iface(&nr_found, (void*)node->iface, login_helper,
+               (char *)node->name, node->tpgt,
+-              (char *)node->address, node->port))
++              (char *)node->address, node->port, false))
+       if (nr_found == 0) {
+               strcpy(context->error_str, "No such node");
+               rc = ENODEV;
+@@ -615,7 +615,7 @@ int libiscsi_node_set_parameter(struct libiscsi_context *context,
+       CHECK(idbm_for_each_iface(&nr_found, &params, idbm_node_set_param,
+               (char *)node->name, node->tpgt,
+-              (char *)node->address, node->port))
++              (char *)node->address, node->port, false))
+       if (nr_found == 0) {
+               strcpy(context->error_str, "No such node");
+               rc = ENODEV;
+@@ -677,7 +677,7 @@ int libiscsi_node_get_parameter(struct libiscsi_context *context,
+          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))
++              (char *)node->address, node->port, false))
+       if (nr_found == 0) {
+               strcpy(context->error_str, "No such node");
+               rc = ENODEV;
+-- 
+2.26.2
+
diff --git a/0015-remove-the-offload-boot-supported-ifdef.patch b/0015-remove-the-offload-boot-supported-ifdef.patch
new file mode 100644 (file)
index 0000000..2466935
--- /dev/null
@@ -0,0 +1,45 @@
+From d410fe4b6eb2347f2160b8aaab24a639de99c23c Mon Sep 17 00:00:00 2001
+From: Chris Leech <cleech@redhat.com>
+Date: Mon, 19 Nov 2012 17:09:24 -0800
+Subject: [PATCH] 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 11f3d2a..65c1615 100644
+--- a/usr/iface.c
++++ b/usr/iface.c
+@@ -998,6 +998,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,
+@@ -1011,10 +1012,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 */
+@@ -1040,9 +1038,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;
+-- 
+2.26.2
+
diff --git a/0016-Revert-iscsiadm-return-error-when-login-fails.patch b/0016-Revert-iscsiadm-return-error-when-login-fails.patch
new file mode 100644 (file)
index 0000000..7cae8ab
--- /dev/null
@@ -0,0 +1,34 @@
+From 49dc2a687175f9671a159df38971a15287dae18c Mon Sep 17 00:00:00 2001
+From: Chris Leech <cleech@redhat.com>
+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 0500f15..1e1f2bc 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;
+       }
+-- 
+2.26.2
+
diff --git a/0019-Coverity-scan-fixes.patch b/0019-Coverity-scan-fixes.patch
new file mode 100644 (file)
index 0000000..1b3904e
--- /dev/null
@@ -0,0 +1,100 @@
+From 6de09f82e86db0500a59017a473c944877a80516 Mon Sep 17 00:00:00 2001
+From: Chris Leech <cleech@redhat.com>
+Date: Wed, 5 Jun 2019 09:08:39 -0700
+Subject: [PATCH 1/1] Coverity scan fixes
+
+---
+ iscsiuio/src/unix/libs/qedi.c |  2 +-
+ iscsiuio/src/unix/main.c      |  3 +++
+ libopeniscsiusr/idbm.c        | 11 +++++------
+ usr/idbm.c                    | 10 ++++------
+ usr/iscsid.c                  |  2 +-
+ 5 files changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/iscsiuio/src/unix/libs/qedi.c b/iscsiuio/src/unix/libs/qedi.c
+index 1af8d1b..9a814c6 100644
+--- a/iscsiuio/src/unix/libs/qedi.c
++++ b/iscsiuio/src/unix/libs/qedi.c
+@@ -1030,7 +1030,7 @@ static int qedi_read(nic_t *nic, packet_t *pkt)
+       LOG_DEBUG(PFX "%s:hw_prod %d bd_prod %d, rx_pkt_idx %d, rxlen %d",
+                 nic->log_name, hw_prod, bd_prod, rx_bd->rx_pkt_index, len);
+-      LOG_DEBUG(PFX "%s: sw_con %d bd_cons %d num BD %d",
++      LOG_DEBUG(PFX "%s: sw_con %d bd_cons %d num BD %lu",
+                 nic->log_name, sw_cons, bd_cons, QEDI_NUM_RX_BD);
+       if (bd_cons != bd_prod) {
+diff --git a/iscsiuio/src/unix/main.c b/iscsiuio/src/unix/main.c
+index 0c9ad49..f83f305 100644
+--- a/iscsiuio/src/unix/main.c
++++ b/iscsiuio/src/unix/main.c
+@@ -391,6 +391,9 @@ int main(int argc, char *argv[])
+       sigaddset(&set, SIGTERM);
+       sigaddset(&set, SIGUSR1);
+       rc = pthread_sigmask(SIG_SETMASK, &set, NULL);
++      if (rc != 0) {
++              LOG_ERR("Failed to set thread signal mask");
++      }
+       /*  Spin off the signal handling thread */
+       pthread_attr_init(&attr);
+diff --git a/libopeniscsiusr/idbm.c b/libopeniscsiusr/idbm.c
+index 0910c63..6213e62 100644
+--- a/libopeniscsiusr/idbm.c
++++ b/libopeniscsiusr/idbm.c
+@@ -321,12 +321,11 @@ int _idbm_lock(struct iscsi_context *ctx)
+               return 0;
+       }
+-      if (access(LOCK_DIR, F_OK) != 0) {
+-              if (mkdir(LOCK_DIR, 0770) != 0) {
+-                      _error(ctx, "Could not open %s: %d %s", LOCK_DIR, errno,
+-                              _strerror(errno, strerr_buff));
+-                      return LIBISCSI_ERR_IDBM;
+-              }
++      if (((mkdir(LOCK_DIR, 0770) != 0) && (errno != EEXIST)) ||
++          (access(LOCK_DIR, F_OK) != 0)) {
++              _error(ctx, "Could not open %s: %d %s", LOCK_DIR, errno,
++                      _strerror(errno, strerr_buff));
++              return LIBISCSI_ERR_IDBM;
+       }
+       fd = open(LOCK_FILE, O_RDWR | O_CREAT, 0666);
+diff --git a/usr/idbm.c b/usr/idbm.c
+index b33ae42..1ac0b73 100644
+--- a/usr/idbm.c
++++ b/usr/idbm.c
+@@ -1461,12 +1461,10 @@ int idbm_lock(void)
+               return 0;
+       }
+-      if (access(LOCK_DIR, F_OK) != 0) {
+-              if (mkdir(LOCK_DIR, 0770) != 0) {
+-                      log_error("Could not open %s: %s", LOCK_DIR,
+-                                strerror(errno));
+-                      return ISCSI_ERR_IDBM;
+-              }
++      if (((mkdir(LOCK_DIR, 0770) != 0) && (errno != EEXIST)) ||
++          (access(LOCK_DIR, F_OK) != 0)) {
++              log_error("Could not open %s: %s", LOCK_DIR, strerror(errno));
++              return ISCSI_ERR_IDBM;
+       }
+       fd = open(LOCK_FILE, O_RDWR | O_CREAT, 0666);
+diff --git a/usr/iscsid.c b/usr/iscsid.c
+index dc54fec..fde8894 100644
+--- a/usr/iscsid.c
++++ b/usr/iscsid.c
+@@ -510,8 +510,8 @@ int main(int argc, char *argv[])
+                               log_close(log_pid);
+                               exit(ISCSI_ERR);
+                       }
++                      close(fd);
+               }
+-              close(fd);
+               if ((control_fd = ipc->ctldev_open()) < 0) {
+                       log_close(log_pid);
+-- 
+2.26.3
+
diff --git a/0020-fix-upstream-build-breakage-of-iscsiuio-LDFLAGS.patch b/0020-fix-upstream-build-breakage-of-iscsiuio-LDFLAGS.patch
new file mode 100644 (file)
index 0000000..142fcde
--- /dev/null
@@ -0,0 +1,25 @@
+From b50ab4a08a12593985b14aece5f689e485647b1c Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Wed, 16 Oct 2019 23:17:20 -0700
+Subject: [PATCH 1/1] fix upstream build breakage of iscsiuio LDFLAGS
+
+---
+ iscsiuio/configure.ac | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/iscsiuio/configure.ac b/iscsiuio/configure.ac
+index 9b85448..5dc188b 100644
+--- a/iscsiuio/configure.ac
++++ b/iscsiuio/configure.ac
+@@ -72,7 +72,7 @@ AC_ARG_WITH([systemd],
+      *)   AC_MSG_ERROR([bad value $withval for --with-systemd]) ;;
+      esac],[with_libsystemd=auto])
+ AS_IF([test "$with_libsystemd" != no],[
+-    PKG_CHECK_MODULES([LIBSYSTEMD],[libsystemd],[LDFLAGS=$LIBSYSTEMD_LIBS],[
++    PKG_CHECK_MODULES([LIBSYSTEMD],[libsystemd],[LDFLAGS="$LDFLAGS $LIBSYSTEMD_LIBS"],[
+         if test "$with_libsystemd" = yes; then
+             AC_MSG_ERROR([could not find libsystemd using pkg-config])
+       else
+-- 
+2.26.3
+
diff --git a/0022-iscsi_if.h-replace-zero-length-array-with-flexible-a.patch b/0022-iscsi_if.h-replace-zero-length-array-with-flexible-a.patch
new file mode 100644 (file)
index 0000000..2318503
--- /dev/null
@@ -0,0 +1,44 @@
+From 84a8601fe7b9b5337af95835aaa5aae1bfd88d95 Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Tue, 11 Aug 2020 21:00:29 +0200
+Subject: [PATCH] iscsi_if.h replace zero-length array with flexible-array
+ member
+
+---
+ include/iscsi_if.h | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/include/iscsi_if.h b/include/iscsi_if.h
+index 5a1c614..e8cee0d 100644
+--- a/include/iscsi_if.h
++++ b/include/iscsi_if.h
+@@ -337,7 +337,7 @@ enum iscsi_param_type {
+ 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 */
++      uint8_t value[];        /* length sized value follows */
+ } __attribute__((__packed__));
+ struct iscsi_iface_param_info {
+@@ -346,7 +346,7 @@ struct iscsi_iface_param_info {
+       uint16_t param;         /* iscsi param value */
+       uint8_t iface_type;     /* IPv4 or IPv6 */
+       uint8_t param_type;     /* iscsi_param_type */
+-      uint8_t value[0];       /* length sized value follows */
++      uint8_t value[];        /* length sized value follows */
+ } __attribute__((__packed__));
+ /*
+@@ -723,7 +723,7 @@ enum iscsi_flashnode_param {
+ 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 */
++      uint8_t value[];        /* length sized value follows */
+ } __attribute__((__packed__));
+ enum iscsi_discovery_parent_type {
+-- 
+2.26.2
+
diff --git a/0023-stop-using-Werror-for-now.patch b/0023-stop-using-Werror-for-now.patch
new file mode 100644 (file)
index 0000000..624081c
--- /dev/null
@@ -0,0 +1,56 @@
+From af428f588f8023784c6f4b0a25d13b70fb7216ab Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Tue, 3 Mar 2020 10:35:40 -0800
+Subject: [PATCH] stop using Werror for now
+
+need to work through these warning that only appear on s390x
+Werror seems bad for release, makes packaging a nightmare when new
+compilers come around
+---
+ Makefile        | 2 +-
+ usr/Makefile    | 2 +-
+ usr/initiator.c | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index 7e6b734..0069e75 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
+diff --git a/usr/Makefile b/usr/Makefile
+index 885243a..1a743d1 100644
+--- a/usr/Makefile
++++ b/usr/Makefile
+@@ -35,7 +35,7 @@ endif
+ PKG_CONFIG = /usr/bin/pkg-config
+ CFLAGS ?= -O2 -g
+-WARNFLAGS ?= -Wall -Wextra -Werror -Wstrict-prototypes -fno-common
++WARNFLAGS ?= -Wall -Wextra -Wstrict-prototypes -fno-common
+ CFLAGS += $(WARNFLAGS) -I../include -I. -D_GNU_SOURCE \
+         -I$(TOPDIR)/libopeniscsiusr -DISNS_ENABLE
+ CFLAGS += $(shell $(PKG_CONFIG) --cflags libkmod)
+diff --git a/usr/initiator.c b/usr/initiator.c
+index 684647c..a5a9d08 100644
+--- a/usr/initiator.c
++++ b/usr/initiator.c
+@@ -580,7 +580,7 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop,
+                     int redirected)
+ {
+       iscsi_session_t *session = conn->session;
+-      uint32_t delay;
++      uint32_t delay = 0;
+       log_debug(1, "re-opening session %d (reopen_cnt %d)", session->id,
+                       session->reopen_cnt);
+-- 
+2.26.2
+
diff --git a/0024-minor-service-file-updates.patch b/0024-minor-service-file-updates.patch
new file mode 100644 (file)
index 0000000..be17752
--- /dev/null
@@ -0,0 +1,68 @@
+From b8c6c1f3bed0e5fcc0d02c56834fa60850a11b5f Mon Sep 17 00:00:00 2001
+From: Chris Leech <cleech@redhat.com>
+Date: Thu, 18 Feb 2021 14:04:32 -0800
+Subject: [PATCH 1/1] minor service file updates
+
+Intended use is with system presets to enable the following:
+  iscsi.service - login of automatic node records
+  iscsid.socket - start iscsid as needed for all iSCSI sessions
+  iscsiuio.socket - start iscsiuio as needed for bnx2i or qedi
+  iscsi-onboot.service - special handling of initramfs sessions
+
+The following are started automatically as needed:
+  iscsid.service - needed for all iSCSI sessions
+  iscsiuio.service - needed for bnx2i or qedi offload
+  iscsi-init.service - create an iSCSI name if missing before starting iscsid
+  iscsi-shutdown.service - ensure all non-boot sessions logout at shutdown
+---
+ etc/systemd/iscsi-init.service | 1 +
+ etc/systemd/iscsi.service      | 2 +-
+ etc/systemd/iscsid.service     | 3 +--
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/etc/systemd/iscsi-init.service b/etc/systemd/iscsi-init.service
+index e058ff0..c3370ec 100644
+--- a/etc/systemd/iscsi-init.service
++++ b/etc/systemd/iscsi-init.service
+@@ -1,6 +1,7 @@
+ [Unit]
+ Description=One time configuration for iscsi.service
+ ConditionPathExists=!/etc/iscsi/initiatorname.iscsi
++Before=iscsid.service
+ [Service]
+ Type=oneshot
+diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service
+index 175cb2c..6c542d2 100644
+--- a/etc/systemd/iscsi.service
++++ b/etc/systemd/iscsi.service
+@@ -4,7 +4,7 @@ Documentation=man:iscsiadm(8) man:iscsid(8)
+ DefaultDependencies=no
+ Before=remote-fs-pre.target
+ After=network.target network-online.target iscsid.service iscsiuio.service systemd-remount-fs.service
+-Wants=remote-fs-pre.target iscsi-shutdown.service
++Wants=remote-fs-pre.target
+ ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes
+ [Service]
+diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service
+index 324c593..df0bd83 100644
+--- a/etc/systemd/iscsid.service
++++ b/etc/systemd/iscsid.service
+@@ -4,7 +4,7 @@ Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8)
+ DefaultDependencies=no
+ After=network-online.target iscsiuio.service iscsi-init.service
+ Before=remote-fs-pre.target
+-Requires=iscsi-init.service
++Requires=iscsi-init.service iscsi-shutdown.service
+ [Service]
+ Type=notify
+@@ -15,4 +15,3 @@ Restart=on-failure
+ [Install]
+ WantedBy=multi-user.target
+-Also=iscsid.socket
+-- 
+2.26.3
+
diff --git a/0044-iscsid-add-initrd-option-to-set-run-from-initrd-hint.patch b/0044-iscsid-add-initrd-option-to-set-run-from-initrd-hint.patch
deleted file mode 100644 (file)
index 358b50c..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-From b1799fe84ed94a19bba6bcd7284ce8b038be4ffe Mon Sep 17 00:00:00 2001
-From: Chris Leech <cleech@redhat.com>
-Date: Mon, 10 Dec 2012 13:20:47 -0800
-Subject: iscsid: add --initrd option to set run from initrd hint for systemd
-
-See http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons
-
-Signed-off-by: Chris Leech <cleech@redhat.com>
----
- usr/iscsid.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/usr/iscsid.c b/usr/iscsid.c
-index b4bb65b..7d71085 100644
---- a/usr/iscsid.c
-+++ b/usr/iscsid.c
-@@ -61,6 +61,7 @@ static pid_t log_pid;
- static gid_t gid;
- static int daemonize = 1;
- static int mgmt_ipc_fd;
-+static int initrd = 0;
- static struct option const long_options[] = {
-       {"config", required_argument, NULL, 'c'},
-@@ -73,6 +74,7 @@ static struct option const long_options[] = {
-       {"pid", required_argument, NULL, 'p'},
-       {"help", no_argument, NULL, 'h'},
-       {"version", no_argument, NULL, 'v'},
-+      {"initrd", no_argument, &initrd, 1},
-       {NULL, 0, NULL, 0},
- };
-@@ -95,6 +97,7 @@ Open-iSCSI initiator daemon.\n\
-   -p, --pid=pidfile       use pid file (default " PID_FILE ").\n\
-   -h, --help              display this help and exit\n\
-   -v, --version           display version and exit\n\
-+  --initrd                run from initrd\n\
- ");
-       }
-       exit(status);
-@@ -383,12 +386,17 @@ int main(int argc, char *argv[])
-               case 'h':
-                       usage(0);
-                       break;
-+              case 0:
-+                      break;
-               default:
-                       usage(1);
-                       break;
-               }
-       }
-+      if (initrd)
-+              argv[0][0] = '@';
-+
-       /* initialize logger */
-       log_pid = log_init(program_name, DEFAULT_AREA_SIZE,
-                     daemonize ? log_do_log_daemon : log_do_log_std, NULL);
--- 
-1.7.11.7
-
diff --git a/0047-iscsiadm-iscsid-newroot-command-to-survive-switch_ro.patch b/0047-iscsiadm-iscsid-newroot-command-to-survive-switch_ro.patch
deleted file mode 100644 (file)
index 7020e65..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-From e5d7c7070358a5db8b849c8c5886e67881fe8906 Mon Sep 17 00:00:00 2001
-From: Chris Leech <cleech@redhat.com>
-Date: Fri, 7 Dec 2012 17:01:42 -0800
-Subject: [PATCH 47/47] iscsiadm, iscsid: newroot command to survive
- switch_root
-
-When started from initramfs, iscsid needs to be able to chroot itself
-to the runtime filesystem before the switch_root occurs.  In the
-initramfs "iscsiadm --newroot {root fs mount before switch}" should be
-called before the switch_root.
-
-Signed-off-by: Chris Leech <cleech@redhat.com>
----
- usr/iscsiadm.c | 30 ++++++++++++++++++++++++++++++
- usr/mgmt_ipc.c | 11 +++++++++++
- usr/mgmt_ipc.h |  6 +++++-
- 3 files changed, 46 insertions(+), 1 deletion(-)
-
-diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
-index da0a3ec..af6d607 100644
---- a/usr/iscsiadm.c
-+++ b/usr/iscsiadm.c
-@@ -117,6 +117,7 @@ static struct option const long_options[] =
-       {"interval", required_argument, NULL, 'i'},
-       {"flashnode_idx", optional_argument, NULL, 'x'},
-       {"portal_type", optional_argument, NULL, 'A'},
-+      {"newroot", required_argument, NULL, 0},
-       {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:ux:A:";
-@@ -137,6 +138,7 @@ iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P  printlevel] [ -r sessionid
- 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 [ -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 --newroot switch_root_path\n\
- iscsiadm -k priority\n");
-       }
-       exit(status);
-@@ -278,6 +280,22 @@ static void kill_iscsid(int priority)
-       }
- }
-+static void do_newroot(char *newroot)
-+{
-+      iscsiadm_req_t req;
-+      iscsiadm_rsp_t rsp;
-+      int rc;
-+
-+      memset(&req, 0, sizeof(req));
-+      req.command = MGMT_IPC_NEWROOT;
-+      strncpy(req.u.newroot.path, newroot, PATH_MAX);
-+      rc = iscsid_exec_req(&req, &rsp, 0);
-+      if (rc) {
-+              iscsi_err_print_msg(rc);
-+              log_error("Could not send NEWROOT command");
-+      }
-+}
-+
- /*
-  * TODO: we can display how the ifaces are related to node records.
-  * And we can add a scsi_host mode which would display how
-@@ -2800,6 +2818,7 @@ main(int argc, char **argv)
- {
-       char *ip = NULL, *name = NULL, *value = NULL;
-       char *targetname = NULL, *group_session_mgmt_mode = NULL;
-+      char *newroot = NULL;
-       int ch, longindex, mode=-1, port=-1, do_login=0, do_rescan=0;
-       int rc=0, sid=-1, op=OP_NOOP, type=-1, do_logout=0, do_stats=0;
-       int do_login_all=0, do_logout_all=0, info_level=-1, num_ifaces = 0;
-@@ -2837,6 +2856,12 @@ main(int argc, char **argv)
-       while ((ch = getopt_long(argc, argv, short_options,
-                                long_options, &longindex)) >= 0) {
-               switch (ch) {
-+              case 0:
-+                      if (long_options[longindex].flag != 0)
-+                              break;
-+                      if (!strcmp(long_options[longindex].name, "newroot"))
-+                              newroot = optarg;
-+                      break;
-               case 'k':
-                       killiscsid = atoi(optarg);
-                       if (killiscsid < 0) {
-@@ -2989,6 +3014,11 @@ main(int argc, char **argv)
-               goto free_ifaces;
-       }
-+      if (newroot) {
-+              do_newroot(newroot);
-+              goto free_ifaces;
-+      }
-+
-       if (mode < 0)
-               usage(ISCSI_ERR_INVAL);
-diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c
-index 87bd346..5cb7143 100644
---- a/usr/mgmt_ipc.c
-+++ b/usr/mgmt_ipc.c
-@@ -226,6 +226,16 @@ mgmt_ipc_immediate_stop(queue_task_t *qtask)
- }
- static int
-+mgmt_ipc_newroot(queue_task_t *qtask)
-+{
-+      char *newroot = qtask->req.u.newroot.path;
-+      if (chdir(newroot) || chroot(".") || chdir("/"))
-+              return ISCSI_ERR;
-+      mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS);
-+      return ISCSI_SUCCESS;
-+}
-+
-+static int
- mgmt_ipc_conn_remove(queue_task_t *qtask)
- {
-       return ISCSI_ERR;
-@@ -534,6 +544,7 @@ static mgmt_ipc_fn_t *     mgmt_ipc_functions[__MGMT_IPC_MAX_COMMAND] = {
- [MGMT_IPC_NOTIFY_DEL_NODE]    = mgmt_ipc_notify_del_node,
- [MGMT_IPC_NOTIFY_ADD_PORTAL]  = mgmt_ipc_notify_add_portal,
- [MGMT_IPC_NOTIFY_DEL_PORTAL]  = mgmt_ipc_notify_del_portal,
-+[MGMT_IPC_NEWROOT]            = mgmt_ipc_newroot,
- };
- void mgmt_ipc_handle(int accept_fd)
-diff --git a/usr/mgmt_ipc.h b/usr/mgmt_ipc.h
-index 55972ed..102ffff 100644
---- a/usr/mgmt_ipc.h
-+++ b/usr/mgmt_ipc.h
-@@ -22,6 +22,7 @@
- #include "types.h"
- #include "iscsi_if.h"
- #include "config.h"
-+#include "limits.h"
- #define ISCSIADM_NAMESPACE    "ISCSIADM_ABSTRACT_NAMESPACE"
- #define PEERUSER_MAX          64
-@@ -46,6 +47,7 @@ typedef enum iscsiadm_cmd {
-       MGMT_IPC_NOTIFY_DEL_NODE        = 17,
-       MGMT_IPC_NOTIFY_ADD_PORTAL      = 18,
-       MGMT_IPC_NOTIFY_DEL_PORTAL      = 19,
-+      MGMT_IPC_NEWROOT                = 20,
-       __MGMT_IPC_MAX_COMMAND
- } iscsiadm_cmd_e;
-@@ -75,8 +77,10 @@ typedef struct iscsiadm_req {
-                       int param;
-                       /* TODO: make this variable len to support */
-                       char value[IFNAMSIZ + 1];
--
-               } set_host_param;
-+              struct ipc_msg_newroot {
-+                      char path[PATH_MAX + 1];
-+              } newroot;
-       } u;
- } iscsiadm_req_t;
--- 
-1.8.1.4
-
diff --git a/0047-iscsiuio-systemd-socket-activation-support.patch b/0047-iscsiuio-systemd-socket-activation-support.patch
deleted file mode 100644 (file)
index 896eba9..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-From 8003178db245b43d04b27b559d5541ced24ec13f Mon Sep 17 00:00:00 2001
-From: Chris Leech <cleech@redhat.com>
-Date: Wed, 19 Dec 2012 21:39:06 -0800
-Subject: [PATCH] iscsiuio systemd socket activation support
-
----
- iscsiuio/src/unix/iscsid_ipc.c | 28 ++++++++++++++++++++++++++++
- 1 file changed, 28 insertions(+)
-
-diff --git a/iscsiuio/src/unix/iscsid_ipc.c b/iscsiuio/src/unix/iscsid_ipc.c
-index e22de0d..4908cb7 100644
---- a/iscsiuio/src/unix/iscsid_ipc.c
-+++ b/iscsiuio/src/unix/iscsid_ipc.c
-@@ -948,6 +948,30 @@ static void *iscsid_loop(void *arg)
-       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
-  ******************************************************************************/
-@@ -961,6 +985,10 @@ 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");
--- 
-1.8.3.1
-
diff --git a/0048-iscsiadm-param-parsing-for-advanced-node-creation.patch b/0048-iscsiadm-param-parsing-for-advanced-node-creation.patch
deleted file mode 100644 (file)
index a39833b..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-From b58f3b48a36821d10a3377acfcbf18113fba0c9d Mon Sep 17 00:00:00 2001
-From: Chris Leech <cleech@redhat.com>
-Date: Tue, 18 Dec 2012 11:27:00 -0800
-Subject: [PATCH 48/48] iscsiadm: --param parsing for advanced node creation
-
-Share parse_param and apply_param code from iscsistart, allow using multiple
---param options to set arbitrary fields in node mode.
-
-Signed-off-by: Chris Leech <cleech@redhat.com>
----
- usr/Makefile      |  2 +-
- usr/iscsi_param.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
- usr/iscsi_param.h |  7 ++++
- usr/iscsiadm.c    | 16 ++++++++--
- usr/iscsistart.c  | 91 ++--------------------------------------------------
- 5 files changed, 120 insertions(+), 91 deletions(-)
- create mode 100644 usr/iscsi_param.c
- create mode 100644 usr/iscsi_param.h
-
-diff --git a/usr/Makefile b/usr/Makefile
-index 3d8ee22..a7e80c0 100644
---- a/usr/Makefile
-+++ b/usr/Makefile
-@@ -40,7 +40,7 @@ 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 flashnode.o uip_mgmt_ipc.o \
-+      initiator_common.o iscsi_err.o iscsi_param.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
-diff --git a/usr/iscsi_param.c b/usr/iscsi_param.c
-new file mode 100644
-index 0000000..c075e8f
---- /dev/null
-+++ b/usr/iscsi_param.c
-@@ -0,0 +1,95 @@
-+#include <string.h>
-+#include "log.h"
-+#include "config.h"
-+#include "idbm.h"
-+#include "list.h"
-+#include "iface.h"
-+#include "idbm_fields.h"
-+#include "iscsi_err.h"
-+
-+int apply_params(struct list_head *user_params, struct node_rec *rec)
-+{
-+      struct user_param *param;
-+      int rc;
-+
-+      /* Must init this so we can check if user overrode them */
-+      rec->session.initial_login_retry_max = -1;
-+      rec->conn[0].timeo.noop_out_interval = -1;
-+      rec->conn[0].timeo.noop_out_timeout = -1;
-+
-+      list_for_each_entry(param, user_params, list) {
-+              /*
-+               * user may not have passed in all params that were set by
-+               * ibft/iscsi_boot, so clear out values that might conflict
-+               * with user overrides
-+               */
-+              if (!strcmp(param->name, IFACE_NETNAME)) {
-+                      /* overriding netname so MAC will be for old netdev */
-+                      memset(rec->iface.hwaddress, 0,
-+                              sizeof(rec->iface.hwaddress));
-+              } else if (!strcmp(param->name, IFACE_HWADDR)) {
-+                      /* overriding MAC so netdev will be for old MAC */
-+                      memset(rec->iface.netdev, 0, sizeof(rec->iface.netdev));
-+              } else if (!strcmp(param->name, IFACE_TRANSPORTNAME)) {
-+                      /*
-+                       * switching drivers so all old binding info is no
-+                       * longer valid. Old values were either for offload
-+                       * and we are switching to software or the reverse,
-+                       * or switching types of cards (bnx2i to cxgb3i).
-+                       */
-+                      memset(&rec->iface, 0, sizeof(rec->iface));
-+                      iface_setup_defaults(&rec->iface);
-+              }
-+      }
-+
-+      rc = idbm_node_set_rec_from_param(user_params, rec, 0);
-+      if (rc)
-+              return rc;
-+
-+      /*
-+       * For root boot we could not change this in older versions so
-+       * if user did not override then use the defaults.
-+       *
-+       * Increase to account for boot using static setup.
-+       */
-+      if (rec->session.initial_login_retry_max == -1)
-+              rec->session.initial_login_retry_max = 30;
-+      /* we used to not be able to answer so turn off */
-+      if (rec->conn[0].timeo.noop_out_interval == -1)
-+              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;
-+
-+      return 0;
-+}
-+
-+int parse_param(struct list_head *user_params, char *param_str)
-+{
-+      struct user_param *param;
-+      char *name, *value;
-+
-+      name = param_str;
-+
-+      value = strchr(param_str, '=');
-+      if (!value) {
-+              log_error("Invalid --param %s. Missing value.", param_str);
-+              return ISCSI_ERR_INVAL;
-+      }
-+      *value = '\0';
-+
-+      value++;
-+      if (!strlen(value)) {
-+              log_error("Invalid --param %s. Missing value.", param_str);
-+              return ISCSI_ERR_INVAL;
-+      }
-+
-+      param = idbm_alloc_user_param(name, value);
-+      if (!param) {
-+              log_error("Could not allocate memory for param.");
-+              return ISCSI_ERR_NOMEM;
-+      }
-+
-+      list_add(&param->list, user_params);
-+      return 0;
-+}
-+
-diff --git a/usr/iscsi_param.h b/usr/iscsi_param.h
-new file mode 100644
-index 0000000..8b7956c
---- /dev/null
-+++ b/usr/iscsi_param.h
-@@ -0,0 +1,7 @@
-+#ifndef ISCSI_PARAM_H
-+#define ISCSI_PARAM_H
-+
-+extern int parse_param(struct list_head *user_params, char *param_str);
-+extern int apply_params(struct list_head *user_params, struct node_rec *rec);
-+
-+#endif
-diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
-index af6d607..2003d48 100644
---- a/usr/iscsiadm.c
-+++ b/usr/iscsiadm.c
-@@ -53,6 +53,7 @@
- #include "iscsi_err.h"
- #include "iscsi_ipc.h"
- #include "iscsi_timer.h"
-+#include "iscsi_param.h"
- #include "flashnode.h"
- static char program_name[] = "iscsiadm";
-@@ -118,6 +119,7 @@ static struct option const long_options[] =
-       {"flashnode_idx", optional_argument, NULL, 'x'},
-       {"portal_type", optional_argument, NULL, 'A'},
-       {"newroot", required_argument, NULL, 0},
-+      {"param", required_argument, NULL, 0},
-       {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:ux:A:";
-@@ -133,7 +135,7 @@ iscsiadm -m discoverydb [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p
- [ -o operation ] [ -n name ] [ -v value ] [ -lD ] ] \n\
- iscsiadm -m discovery [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p ip:port -I ifaceN ... [ -l ] ] | [ [ -p ip:port ] [ -l | -D ] ] \n\
- iscsiadm -m node [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -L all,manual,automatic ] [ -U all,manual,automatic ] [ -S ] [ [ -T targetname -p ip:port -I ifaceN ] [ -l | -u | -R | -s] ] \
--[ [ -o  operation  ] [ -n name ] [ -v value ] ]\n\
-+[ [ -o  operation  ] [ -n name ] [ -v value ] ] [ --param=NAME=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 [ -d debug_level ] [ -l ]\n\
-@@ -2834,9 +2836,11 @@ main(int argc, char **argv)
-       uint32_t host_no = -1;
-       struct user_param *param;
-       struct list_head params;
-+      struct list_head user_params;
-       INIT_LIST_HEAD(&params);
-       INIT_LIST_HEAD(&ifaces);
-+      INIT_LIST_HEAD(&user_params);
-       /* do not allow ctrl-c for now... */
-       memset(&sa_old, 0, sizeof(struct sigaction));
-       memset(&sa_new, 0, sizeof(struct sigaction));
-@@ -2859,8 +2863,14 @@ main(int argc, char **argv)
-               case 0:
-                       if (long_options[longindex].flag != 0)
-                               break;
--                      if (!strcmp(long_options[longindex].name, "newroot"))
-+                      if (!strcmp(long_options[longindex].name, "newroot")) {
-                               newroot = optarg;
-+                              break;
-+                      }
-+                      if (!strcmp(long_options[longindex].name, "param")) {
-+                              parse_param(&user_params, optarg);
-+                              break;
-+                      }
-                       break;
-               case 'k':
-                       killiscsid = atoi(optarg);
-@@ -3169,6 +3179,8 @@ main(int argc, char **argv)
-                       goto out;
-               }
-+              apply_params(&user_params, rec);
-+
-               rc = exec_node_op(op, do_login, do_logout, do_show,
-                                 do_rescan, do_stats, info_level, rec,
-                                 &params);
-diff --git a/usr/iscsistart.c b/usr/iscsistart.c
-index 6924d49..85be35b 100644
---- a/usr/iscsistart.c
-+++ b/usr/iscsistart.c
-@@ -50,6 +50,7 @@
- #include "iscsid_req.h"
- #include "iscsi_err.h"
- #include "iface.h"
-+#include "iscsi_param.h"
- /* global config info */
- /* initiator needs initiator name/alias */
-@@ -131,99 +132,13 @@ static int stop_event_loop(void)
-       return rc;
- }
--static int apply_params(struct node_rec *rec)
--{
--      struct user_param *param;
--      int rc;
--
--      /* Must init this so we can check if user overrode them */
--      rec->session.initial_login_retry_max = -1;
--      rec->conn[0].timeo.noop_out_interval = -1;
--      rec->conn[0].timeo.noop_out_timeout = -1;
--
--      list_for_each_entry(param, &user_params, list) {
--              /*
--               * user may not have passed in all params that were set by
--               * ibft/iscsi_boot, so clear out values that might conflict
--               * with user overrides
--               */
--              if (!strcmp(param->name, IFACE_NETNAME)) {
--                      /* overriding netname so MAC will be for old netdev */
--                      memset(rec->iface.hwaddress, 0,
--                              sizeof(rec->iface.hwaddress));
--              } else if (!strcmp(param->name, IFACE_HWADDR)) {
--                      /* overriding MAC so netdev will be for old MAC */
--                      memset(rec->iface.netdev, 0, sizeof(rec->iface.netdev));
--              } else if (!strcmp(param->name, IFACE_TRANSPORTNAME)) {
--                      /*
--                       * switching drivers so all old binding info is no
--                       * longer valid. Old values were either for offload
--                       * and we are switching to software or the reverse,
--                       * or switching types of cards (bnx2i to cxgb3i).
--                       */
--                      memset(&rec->iface, 0, sizeof(rec->iface));
--                      iface_setup_defaults(&rec->iface);
--              }
--      }
--
--      rc = idbm_node_set_rec_from_param(&user_params, rec, 0);
--      if (rc)
--              return rc;
--
--      /*
--       * For root boot we could not change this in older versions so
--       * if user did not override then use the defaults.
--       *
--       * Increase to account for boot using static setup.
--       */
--      if (rec->session.initial_login_retry_max == -1)
--              rec->session.initial_login_retry_max = 30;
--      /* we used to not be able to answer so turn off */
--      if (rec->conn[0].timeo.noop_out_interval == -1)
--              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;
--
--      return 0;
--}
--
--static int parse_param(char *param_str)
--{
--      struct user_param *param;
--      char *name, *value;
--
--      name = param_str;
--
--      value = strchr(param_str, '=');
--      if (!value) {
--              log_error("Invalid --param %s. Missing value.", param_str);
--              return ISCSI_ERR_INVAL;
--      }
--      *value = '\0';
--
--      value++;
--      if (!strlen(value)) {
--              log_error("Invalid --param %s. Missing value.", param_str);
--              return ISCSI_ERR_INVAL;
--      }
--
--      param = idbm_alloc_user_param(name, value);
--      if (!param) {
--              log_error("Could not allocate memory for param.");
--              return ISCSI_ERR_NOMEM;
--      }
--
--      list_add(&param->list, &user_params);
--      return 0;
--}
--
- static int login_session(struct node_rec *rec)
- {
-       iscsiadm_req_t req;
-       iscsiadm_rsp_t rsp;
-       int rc, retries = 0;
--      rc = apply_params(rec);
-+      rc = apply_params(&user_params, rec);
-       if (rc)
-               return rc;
-@@ -426,7 +341,7 @@ int main(int argc, char *argv[])
-                       fw_free_targets(&targets);
-                       exit(0);
-               case 'P':
--                      err = parse_param(optarg);
-+                      err = parse_param(&user_params, optarg);
-                       if (err)
-                               exit(err);
-                       break;
--- 
-1.8.1.4
-
diff --git a/0049-update-systemd-service-files-add-iscsi.service-for-s.patch b/0049-update-systemd-service-files-add-iscsi.service-for-s.patch
deleted file mode 100644 (file)
index 966bb9f..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-From 1c3b1d23e0b3f17399ffd4463cafad813b0444d5 Mon Sep 17 00:00:00 2001
-From: Chris Leech <cleech@redhat.com>
-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 <cleech@redhat.com>
----
- 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/0050-iscsi-boot-related-service-file-updates.patch b/0050-iscsi-boot-related-service-file-updates.patch
deleted file mode 100644 (file)
index 19450ee..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-From 8f79529354b4023c371e00091f11bdd523497639 Mon Sep 17 00:00:00 2001
-From: Chris Leech <cleech@redhat.com>
-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/0058-iscsiuio-IPC-newroot-command.patch b/0058-iscsiuio-IPC-newroot-command.patch
deleted file mode 100644 (file)
index fa3f4c7..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-From 6e979154c9c51dedd54c91e46106e495a65ced43 Mon Sep 17 00:00:00 2001
-From: Chris Leech <cleech@redhat.com>
-Date: Wed, 2 Jan 2013 14:45:05 -0800
-Subject: [PATCH 58/58] iscsiuio IPC newroot command
-
----
- usr/mgmt_ipc.c     | 11 +++++++++++
- usr/transport.c    |  1 +
- usr/transport.h    |  1 +
- usr/uip_mgmt_ipc.c | 14 ++++++++++++++
- usr/uip_mgmt_ipc.h |  5 +++++
- 5 files changed, 32 insertions(+)
-
-diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c
-index 5cb7143..a8f8473 100644
---- a/usr/mgmt_ipc.c
-+++ b/usr/mgmt_ipc.c
-@@ -36,6 +36,7 @@
- #include "sysdeps.h"
- #include "iscsi_ipc.h"
- #include "iscsi_err.h"
-+#include "iscsi_sysfs.h"
- #define PEERUSER_MAX  64
- #define EXTMSG_MAX    (64 * 1024)
-@@ -229,8 +230,18 @@ static int
- mgmt_ipc_newroot(queue_task_t *qtask)
- {
-       char *newroot = qtask->req.u.newroot.path;
-+      struct iscsi_transport *t;
-+
-       if (chdir(newroot) || chroot(".") || chdir("/"))
-               return ISCSI_ERR;
-+
-+      /* if a registered transport has a separate userspace process,
-+       * notify it of the root change as well */
-+      list_for_each_entry(t, &transports, list) {
-+              if (t->template->newroot)
-+                      t->template->newroot(t, newroot);
-+      }
-+
-       mgmt_ipc_write_rsp(qtask, ISCSI_SUCCESS);
-       return ISCSI_SUCCESS;
- }
-diff --git a/usr/transport.c b/usr/transport.c
-index 4d030a8..e0488ad 100644
---- a/usr/transport.c
-+++ b/usr/transport.c
-@@ -83,6 +83,7 @@ struct iscsi_transport_template bnx2i = {
-       .ep_poll        = ktransport_ep_poll,
-       .ep_disconnect  = ktransport_ep_disconnect,
-       .set_net_config = uip_broadcast_params,
-+      .newroot        = uip_broadcast_newroot,
- };
- struct iscsi_transport_template be2iscsi = {
-diff --git a/usr/transport.h b/usr/transport.h
-index 388e4b1..d4d9ec7 100644
---- a/usr/transport.h
-+++ b/usr/transport.h
-@@ -39,6 +39,7 @@ struct iscsi_transport_template {
-       int (*set_net_config) (struct iscsi_transport *t,
-                              struct iface_rec *iface,
-                              struct iscsi_session *session);
-+      void (*newroot) (struct iscsi_transport *t, char *path);
- };
- /* represents data path provider */
-diff --git a/usr/uip_mgmt_ipc.c b/usr/uip_mgmt_ipc.c
-index f3074ee..d5d496a 100644
---- a/usr/uip_mgmt_ipc.c
-+++ b/usr/uip_mgmt_ipc.c
-@@ -39,3 +39,17 @@ int uip_broadcast_params(struct iscsi_transport *t,
-                            sizeof(iscsid_uip_broadcast_header_t) +
-                            sizeof(*iface));
- }
-+
-+int uip_broadcast_newroot(struct iscsi_transport *t, char *newroot)
-+{
-+      struct iscsid_uip_broadcast broadcast;
-+
-+      memset(&broadcast, 0, sizeof(broadcast));
-+
-+      broadcast.header.command = ISCSID_UIP_NEWROOT;
-+      strncpy(broadcast.u.newroot.path, newroot, PATH_MAX);
-+
-+      return uip_broadcast(&broadcast,
-+                           sizeof(iscsid_uip_broadcast_header_t) +
-+                           PATH_MAX + 1);
-+}
-diff --git a/usr/uip_mgmt_ipc.h b/usr/uip_mgmt_ipc.h
-index 29a4769..3ca4fb1 100644
---- a/usr/uip_mgmt_ipc.h
-+++ b/usr/uip_mgmt_ipc.h
-@@ -29,6 +29,7 @@
- typedef enum iscsid_uip_cmd {
-       ISCSID_UIP_IPC_UNKNOWN                  = 0,
-       ISCSID_UIP_IPC_GET_IFACE                = 1,
-+      ISCSID_UIP_NEWROOT                      = 2,
-       __ISCSID_UIP_IPC_MAX_COMMAND
- } iscsid_uip_cmd_e;
-@@ -47,6 +48,9 @@ typedef struct iscsid_uip_broadcast {
-               struct ipc_broadcast_iface_rec {
-                       struct iface_rec rec;
-               } iface_rec;
-+              struct ipc_broadcast_newroot {
-+                      char path[PATH_MAX + 1];
-+              } newroot;
-       } u;
- } iscsid_uip_broadcast_t;
-@@ -69,5 +73,6 @@ extern int uip_broadcast_params(struct iscsi_transport *t,
-                               struct iface_rec *iface,
-                               struct iscsi_session *session);
-+extern int uip_broadcast_newroot(struct iscsi_transport *t, char *path);
- #endif /* UIP_MGMT_IPC_H */
--- 
-1.8.1.4
-
diff --git a/0059-iscsiuio-systemd-unit-files.patch b/0059-iscsiuio-systemd-unit-files.patch
deleted file mode 100644 (file)
index 2d0e213..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-From 822b53e6c9ebb0fe7236ebd3b4c73b009100592d Mon Sep 17 00:00:00 2001
-From: Chris Leech <cleech@redhat.com>
-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/0062-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch b/0062-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch
deleted file mode 100644 (file)
index 684463f..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-From ab79bdb20e37216ca969e06d63a952acfd023963 Mon Sep 17 00:00:00 2001
-From: Chris Leech <cleech@redhat.com>
-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/0063-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch b/0063-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch
deleted file mode 100644 (file)
index cedb4e0..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-From 3cac85a3f97d0a22270166f428209f873b58c319 Mon Sep 17 00:00:00 2001
-From: Chris Leech <cleech@redhat.com>
-Date: Tue, 11 Jun 2013 11:25:27 -0700
-Subject: [PATCH] iscsid: fix order of setting uid/gid and drop supplementary
- groups
-
-If using the user and group ID settings together the existing order of
-calling setuid first will almost always cause the setgid call to fail,
-assuming the new effective user id does not have the CAP_SETGID
-capability.  The effective group ID needs to change first.
-
-While we're at it, if iscsid is started as root it should drop any
-inherited supplementary group permissions.
-
-And if anyone is actually using this to try and isolate capabilities,
-they probably care enough to want to known that it is failing.  Make
-iscsid startup fail instead of just calling perror.
-
-Signed-off-by: Chris Leech <cleech@redhat.com>
----
- usr/iscsid.c | 23 +++++++++++++++++++----
- 1 file changed, 19 insertions(+), 4 deletions(-)
-
-diff --git a/usr/iscsid.c b/usr/iscsid.c
-index b4bb65b..c0ea6fa 100644
---- a/usr/iscsid.c
-+++ b/usr/iscsid.c
-@@ -27,6 +27,7 @@
- #include <unistd.h>
- #include <string.h>
- #include <signal.h>
-+#include <grp.h>
- #include <sys/mman.h>
- #include <sys/utsname.h>
- #include <sys/types.h>
-@@ -477,11 +478,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\n", 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\n");
-+                      log_close(log_pid);
-+                      exit(ISCSI_ERR);
-+              }
-+      }
-+
-+      if (uid && setuid(uid) < 0) {
-+              log_error("Unable to setuid to %d\n", uid);
-+              log_close(log_pid);
-+              exit(ISCSI_ERR);
-+      }
-       memset(&daemon_config, 0, sizeof (daemon_config));
-       daemon_config.pid_file = pid_file;
--- 
-1.8.1.4
-
diff --git a/0065-fix-hardened-build-of-iscsiuio.patch b/0065-fix-hardened-build-of-iscsiuio.patch
deleted file mode 100644 (file)
index bcc43a4..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-From 436ac9074def43ae09d7ecc28eec6cdc77a9d0e2 Mon Sep 17 00:00:00 2001
-From: Chris Leech <cleech@redhat.com>
-Date: Fri, 13 Sep 2013 16:56:51 -0700
-Subject: [PATCH 65/65] fix hardened build of iscsiuio
-
-The new iscsiuio code sets CFLAGS in configure.ac, wiping out the
-environment setup by rpm.  Patch that out.
-
----
- Makefile              | 2 +-
- iscsiuio/configure    | 2 +-
- iscsiuio/configure.ac | 2 +-
- 3 files changed, 3 insertions(+), 3 deletions(-)
- mode change 100644 => 100755 iscsiuio/configure
-
-diff --git a/iscsiuio/configure.ac b/iscsiuio/configure.ac
-index e9a5e32..d9a6bdb 100644
---- a/iscsiuio/configure.ac
-+++ b/iscsiuio/configure.ac
-@@ -52,7 +52,7 @@ AC_LIBTOOL_DLOPEN
- # libtool stuff
- AC_PROG_LIBTOOL
--CFLAGS="-O2 -Wall"
-+CFLAGS="${CFLAGS} -O2 -Wall"
- ## check for --enable-debug first before checking CFLAGS before
- ## so that we don't mix -O and -g
- AC_ARG_ENABLE(debug,
--- 
-1.8.1.4
-
diff --git a/0066-start-socket-listeners-on-iscsiadm-command.patch b/0066-start-socket-listeners-on-iscsiadm-command.patch
deleted file mode 100644 (file)
index 039e8d4..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-From 89e9c2ff66d069b812fabcd4fefe453bbcea73e4 Mon Sep 17 00:00:00 2001
-From: Chris Leech <cleech@redhat.com>
-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 = /etc/rc.d/init.d/iscsid force-start
-+# 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/open-iscsi-build.patch b/open-iscsi-build.patch
deleted file mode 100644 (file)
index c9d63a2..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
---- oiscsi/usr/Makefile        2010-08-11 17:27:07.000000000 +0200
-+++ oiscsi/usr/Makefile        2010-11-10 14:26:59.085995691 +0100
-@@ -53,13 +53,13 @@
- 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 -lslp
- iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o
--      $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns
-+      $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lslp
- iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \
-               iscsistart.o statics.o
--      $(CC) $(CFLAGS) -static $^ -o $@
-+      $(CC) $(CFLAGS) -static $^ -o $@ -lslp
- clean:
-       rm -f *.o $(PROGRAMS) .depend $(LIBSYS)
---- a/iscsiuio/configure.ac
-+++ b/iscsiuio/configure.ac
-@@ -52,7 +52,7 @@ AC_LIBTOOL_DLOPEN
- # libtool stuff
- AC_PROG_LIBTOOL
--CFLAGS="${CFLAGS} -O2 -Wall"
-+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,
diff --git a/open-iscsi-git.patch b/open-iscsi-git.patch
deleted file mode 100644 (file)
index 3a06172..0000000
+++ /dev/null
@@ -1,35445 +0,0 @@
-diff --git a/Makefile b/Makefile
-index c5d9700..79bad84 100644
---- a/Makefile
-+++ b/Makefile
-@@ -14,8 +14,8 @@ 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
-@@ -26,24 +26,32 @@ IFACEFILES = etc/iface.example
- all: user
--user: utils/open-isns/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
-       $(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
-       @echo "Kernel Compilation complete          Output file"
-@@ -61,6 +69,7 @@ clean:
-       $(MAKE) -C utils clean
-       $(MAKE) -C usr clean
-       $(MAKE) -C kernel clean
-+      $(MAKE) -C iscsiuio clean
-       $(MAKE) -C utils/open-isns clean
-       $(MAKE) -C utils/open-isns distclean
-@@ -115,7 +124,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 +137,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..06d1b6f 100644
---- a/README
-+++ b/README
-@@ -159,15 +159,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 +393,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 +406,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 +991,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/doc/iscsiadm.8 b/doc/iscsiadm.8
-index 7c209f6..9a945d1 100644
---- a/doc/iscsiadm.8
-+++ b/doc/iscsiadm.8
-@@ -14,9 +14,9 @@ iscsiadm \- open-iscsi administration utility
- \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 ] ]
--\fBiscsiadm\fR \-m fw [\-l]
-+\fBiscsiadm\fR \-m fw [ \-d debug_level ] [\-l]
--\fBiscsiadm\fR \-m host [ \-P printlevel ] [ \-H hostno|MAC ] [ -C chap [ -o operation ] [ -v chap_tbl_idx ] ]
-+\fBiscsiadm\fR \-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 ] ]
- \fBiscsiadm\fR \-k priority
-@@ -47,6 +47,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.
-@@ -66,6 +72,14 @@ 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
-+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
- print debugging information. Valid values for debug_level are 0 to 8.
-@@ -170,8 +184,9 @@ 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 +196,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 +227,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 +281,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 +316,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.
-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..6563d68 100644
---- a/include/fw_context.h
-+++ b/include/fw_context.h
-@@ -30,6 +30,9 @@
- 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_port;
-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/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 `<wchar.h>' 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..a283116
---- /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 Broadcom NetXtreme II Linux
-+driver (Kernel module name: 'bnx2' and 'bnx2x'), Broadcom CNIC driver,
-+and the Broadcom iSCSI driver (Kernel module name: 'bnx2i').
-+This user space tool is used in conjunction with the following
-+Broadcom 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.  Broadcom CNIC driver (cnic)
-+1.  Broadcom iSCSI offload driver (bnx2i)
-+2.  Userspace I/O driver (uio)
-+
-+Directory Structure of this Package:
-+=======================================
-+
-+<root>
-+  |
-+  +-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 <iface name> --op=new
-+
-+2.  Discover the targets associated with the new iface
-+
-+     iscsiadm -m discovery -t st -p <iSCSI target IP address> -I <iface name>
-+
-+3.  Update the iface file:
-+
-+  To use a static IPv4 address:
-+      iscsiadm -m iface -I <iface name> --op=update --name=iface.ipaddress --value=<static IPv4 address ie: 192.168.0.1>
-+
-+  To use a DHCP address:
-+      iscsiadm -m iface -I <iface name> --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 <iface name> --op=update --name=iface.transport_name --value=bnx2i
-+
-+  To specify the network interface to offload with:
-+
-+  a.  Specify the physical network interface name <ie. eth0, eth1, eth2 ...>
-+      iscsiadm -m iface -I <iface name> --op=update --name=iface.net_ifacename --value=<network interface name>
-+
-+  b.  Specify the iSCSI MAC address of the iSCSI HBA
-+      iscsiadm -m iface -I <iface name> --op=update --name=iface.hwaddress --value=<MAC address of the iSCSI HBA>
-+
-+4.  Now all the settings should be set so that one could connect to their
-+    desired iSCSI target.
-+
-+      iscsiadm -m node -p <iSCSI target IP address> -T <target name> -I <iface name> --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 = <name of this iface file>
-+      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 <debug level>'
-+
-+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..48feedd
---- /dev/null
-+++ b/iscsiuio/RELEASE.TXT
-@@ -0,0 +1,2031 @@
-+                              Release Notes
-+                        Broadcom uIP Linux Driver
-+                            Version 0.7.8.2
-+                               12/10/2013
-+
-+                          Broadcom Corporation
-+                         5300 California Avenue,
-+                            Irvine, CA 92617
-+
-+               Copyright (c) 2004 - 2013 Broadcom 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 <shiyer@redhat.com>
-+
-+      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..4faee9e
---- /dev/null
-+++ b/iscsiuio/configure.ac
-@@ -0,0 +1,76 @@
-+dnl iscsiuio uIP user space stack configure.ac file
-+dnl
-+dnl Copyright (c) 2004-2013 Broadcom 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], [eddie.wai@broadcom.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 -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..3b50409
---- /dev/null
-+++ b/iscsiuio/docs/iscsiuio.8
-@@ -0,0 +1,86 @@
-+.\" Copyright (c) 2010-2013 Broadcom 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" "Broadcom 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 Broadcom NetXtreme II
-+BCM5706/5708/5709 series PCI/PCI-X Gigabit Ethernet Network Interface Card
-+(NIC) and for the Broadcom 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 <debug level>
-+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 <pidfile>
-+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
-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 <adam@sics.se>. 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..7979774
---- /dev/null
-+++ b/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c
-@@ -0,0 +1,88 @@
-+/*
-+ * Copyright (c) 2009-2011, Broadcom Corporation
-+ *
-+ * Written by:  Benjamin Li <benli@broadcom.com>
-+ *              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 <benli@broadcom.com>
-+ */
-+
-+/*
-+ * 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
-+ * <string.h>, since we use the memcpy() function in the code.
-+ */
-+#include "brcm_iscsi.h"
-+#include "uip.h"
-+#include <string.h>
-+#include <stdio.h>
-+
-+#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..f008471
---- /dev/null
-+++ b/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h
-@@ -0,0 +1,90 @@
-+/*
-+ * Copyright (c) 2009-2011, Broadcom Corporation
-+ *
-+ * Written by:  Benjamin Li <benli@broadcom.com>
-+ *              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 <benli@broadcom.com>
-+ */
-+
-+#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 <errno.h>
-+#include <pthread.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <stdlib.h>
-+#include <arpa/inet.h>
-+
-+#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 <time.h>
-+
-+#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..a92209a
---- /dev/null
-+++ b/iscsiuio/src/apps/dhcpc/dhcpv6.c
-@@ -0,0 +1,513 @@
-+/*
-+ * Copyright (c) 2011, Broadcom Corporation
-+ *
-+ * Written by:  Eddie Wai <eddie.wai@broadcom.com>
-+ *              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 <stdio.h>
-+#include <string.h>
-+
-+#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 =
-+          *((u32_t *) &context->our_mac_addr->addr[2]) & 0xffffffL;
-+
-+      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(*((u32_t *) &context->our_mac_addr->addr[2]));
-+      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..f82cfdb
---- /dev/null
-+++ b/iscsiuio/src/apps/dhcpc/dhcpv6.h
-@@ -0,0 +1,252 @@
-+/*
-+ * Copyright (c) 2011, Broadcom Corporation
-+ *
-+ * Written by:  Eddie Wai <eddie.wai@broadcom.com>
-+ *              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
-+
-+/* Broadcom 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 <adam@sics.se>
-+ *
-+ */
-+#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..9b00d82
---- /dev/null
-+++ b/iscsiuio/src/uip/icmpv6.h
-@@ -0,0 +1,301 @@
-+/*
-+ * Copyright (c) 2011, Broadcom 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..edaa2e9
---- /dev/null
-+++ b/iscsiuio/src/uip/ipv6.c
-@@ -0,0 +1,1296 @@
-+/*
-+ * Copyright (c) 2011, Broadcom 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 <stdio.h>
-+#include <string.h>
-+#include <arpa/inet.h>
-+#include "logger.h"
-+#include "uip.h"
-+#include "ipv6.h"
-+#include "ipv6_pkt.h"
-+#include "icmpv6.h"
-+#include "uipopt.h"
-+#include "dhcpv6.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 *)&eth->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));
-+
-+      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;
-+
-+      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,
-+                                    &eth->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 *)&eth->dest_mac, sizeof(struct mac_address)) != 0) &&
-+          (iscsiL2IsOurMcAddr(context, (struct mac_address *)&eth->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 *)&eth->dest_mac,
-+             (char *)&eth->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 *)&eth->dest_mac,
-+             (char *)&eth->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..91bfaa6
---- /dev/null
-+++ b/iscsiuio/src/uip/ipv6.h
-@@ -0,0 +1,346 @@
-+/*
-+ * Copyright (c) 2011, Broadcom 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 {
-+      u8_t addr[6];
-+};
-+
-+#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)           \
-+      ((*(u32_t *)(&(a)->addr8[0]) == 0) &&   \
-+       (*(u32_t *)(&(a)->addr8[4]) == 0) &&   \
-+       (*(u32_t *)(&(a)->addr8[8]) == 0) &&   \
-+       (*(u32_t *)(&(a)->addr8[12]) == 0))
-+
-+/* Loopback IPv6 address */
-+#define IPV6_IS_ADDR_LOOPBACK(a)              \
-+      ((*(u32_t *)(&(a)->addr8[0]) == 0) &&   \
-+       (*(u32_t *)(&(a)->addr8[4]) == 0) &&   \
-+       (*(u32_t *)(&(a)->addr8[8]) == 0) &&   \
-+       (*(u32_t *)(&(a)->addr8[12]) == 0x1))
-+
-+/* IPv4 compatible */
-+#define IPV6_IS_ADDR_IPV4_COMPAT(a)           \
-+      ((*(u32_t *)(&(a)->addr8[0]) == 0) &&   \
-+       (*(u32_t *)(&(a)->addr8[4]) == 0) &&   \
-+       (*(u32_t *)(&(a)->addr8[8]) == 0) &&   \
-+       (*(u32_t *)(&(a)->addr8[12]) != 0) &&  \
-+       (*(u32_t *)(&(a)->addr8[12]) != 0x1))
-+
-+/* Mapped IPv4-IPv6 address */
-+#define IPV6_IS_ADDR_IPV4_MAPPED(a)           \
-+      ((*(u32_t *)(&(a)->addr8[0]) == 0) &&   \
-+       (*(u32_t *)(&(a)->addr8[4]) == 0) &&   \
-+       (*(u32_t *)(&(a)->addr8[8]) == ntohl(0x0000ffff)))
-+
-+/* 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..6f965f4
---- /dev/null
-+++ b/iscsiuio/src/uip/ipv6_ndpc.c
-@@ -0,0 +1,426 @@
-+/*
-+ * Copyright (c) 2011, Broadcom 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 <errno.h>
-+#include <pthread.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <stdlib.h>
-+#include <arpa/inet.h>
-+
-+#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..1eaced9
---- /dev/null
-+++ b/iscsiuio/src/uip/ipv6_ndpc.h
-@@ -0,0 +1,97 @@
-+/*
-+ * Copyright (c) 2011, Broadcom 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 <time.h>
-+
-+#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..e0da018
---- /dev/null
-+++ b/iscsiuio/src/uip/ipv6_pkt.h
-@@ -0,0 +1,49 @@
-+/*
-+ * Copyright (c) 2011, Broadcom 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 <adam@sics.se>
-+ *
-+ */
-+
-+/**
-+ * \addtogroup lc
-+ * @{
-+ */
-+
-+/**
-+ * \file
-+ * Implementation of local continuations based on the "Labels as
-+ * values" feature of gcc
-+ * \author
-+ * Adam Dunkels <adam@sics.se>
-+ *
-+ * 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 <adam@sics.se>
-+ *
-+ */
-+
-+/**
-+ * \addtogroup lc
-+ * @{
-+ */
-+
-+/**
-+ * \file
-+ * Implementation of local continuations based on switch() statment
-+ * \author Adam Dunkels <adam@sics.se>
-+ *
-+ * 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 <adam@sics.se>
-+ *
-+ */
-+
-+/**
-+ * \addtogroup pt
-+ * @{
-+ */
-+
-+/**
-+ * \defgroup lc Local continuations
-+ * @{
-+ *
-+ * Local continuations form the basis for implementing protothreads. A
-+ * local continuation can be <i>set</i> in a specific function to
-+ * capture the state of the function. After a local continuation has
-+ * been set can be <i>resumed</i> 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 <adam@sics.se>
-+ *
-+ */
-+
-+#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 <b>not</b> 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 <adam@sics.se>
-+ *
-+ */
-+
-+#include <stdio.h>
-+#include <string.h>
-+
-+#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 <adam@sics.se>
-+ *
-+ */
-+
-+/**
-+ * \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 <adam@sics.se>
-+ *
-+ */
-+
-+#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..87465b4
---- /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 <adam@sics.se>
-+ *
-+ */
-+
-+/**
-+ * \addtogroup pt
-+ * @{
-+ */
-+
-+/**
-+ * \file
-+ * Protothreads implementation.
-+ * \author
-+ * Adam Dunkels <adam@sics.se>
-+ *
-+ */
-+
-+#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 = 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 <adam@sics.se>
-+ */
-+
-+/*
-+ * 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 <adam@sics.se>
-+ *
-+ */
-+
-+#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 <adam@sics.se>
-+ */
-+
-+/*
-+ * 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 <adam@sics.se>
-+ *
-+ */
-+#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 <adam@sics.se>
-+ */
-+
-+#include "logger.h"
-+#include "uip.h"
-+#include "uip-neighbor.h"
-+
-+#include <errno.h>
-+#include <string.h>
-+#include <arpa/inet.h>
-+
-+/*******************************************************************************
-+ * 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(&eth_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, &eth_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 <adam@sics.se>
-+ */
-+
-+#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..703cefc
---- /dev/null
-+++ b/iscsiuio/src/uip/uip.c
-@@ -0,0 +1,2405 @@
-+#include <netinet/in.h>
-+#include <netinet/ip6.h>
-+#include <netinet/icmp6.h>
-+#include <sys/types.h>
-+#include <arpa/inet.h>
-+#include "uip.h"
-+#include "dhcpc.h"
-+#include "ipv6_ndpc.h"
-+#include "brcm_iscsi.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 <adam@dunkels.com>
-+ */
-+
-+/*
-+ * 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 <string.h>
-+
-+/*******************************************************************************
-+ * 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)
-+{
-+      uip_sethostaddr4(ustack, ip);
-+      uip_setnetmask4(ustack, netmask);
-+      uip_setdraddr4(ustack, default_route);
-+      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;
-+}
-+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 = 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;
-+
-+              /* 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..0225f6a
---- /dev/null
-+++ b/iscsiuio/src/uip/uip.h
-@@ -0,0 +1,1569 @@
-+
-+/**
-+ * \addtogroup uip
-+ * @{
-+ */
-+
-+/**
-+ * \file
-+ * Header file for the uIP TCP/IP stack.
-+ * \author Adam Dunkels <adam@dunkels.com>
-+ *
-+ * 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 <netinet/in.h>
-+#include <pthread.h>
-+
-+#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;
-+};
-+
-+/* 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;
-+};
-+
-+/*******************************************************************************
-+ * 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);
-+
-+#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 <adam@dunkels.com>
-+ */
-+
-+/*
-+ * 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..a8de07f
---- /dev/null
-+++ b/iscsiuio/src/uip/uip_arp.c
-@@ -0,0 +1,481 @@
-+#include <errno.h>
-+#include <netinet/in.h>
-+#include <arpa/inet.h>
-+
-+#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 <adam@dunkels.com>
-+ *
-+ */
-+
-+/*
-+ * 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 <pthread.h>
-+#include <string.h>
-+
-+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, &eth->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 arp_hdr *arp;
-+      struct uip_eth_hdr *eth;
-+      struct ip_hdr *ip_buf;
-+
-+      arp = (struct arp_hdr *)ustack->network_layer;
-+      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(&eth->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 <adam@dunkels.com>
-+ */
-+
-+/*
-+ * 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..449616e
---- /dev/null
-+++ b/iscsiuio/src/uip/uip_eth.c
-@@ -0,0 +1,49 @@
-+/*
-+ * 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.
-+ *
-+ * 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 <adam@dunkels.com>
-+ *
-+ * 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..898691d
---- /dev/null
-+++ b/iscsiuio/src/unix/Makefile.am
-@@ -0,0 +1,39 @@
-+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
-+
-+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 <adam@sics.se>
-+ */
-+
-+#include "clock-arch.h"
-+#include <sys/time.h>
-+
-+/*---------------------------------------------------------------------------*/
-+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..0b9b18c
---- /dev/null
-+++ b/iscsiuio/src/unix/iscsid_ipc.c
-@@ -0,0 +1,1046 @@
-+/*
-+ * 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.
-+ *
-+ * iscsi_ipc.c - Generic NIC management/utility functions
-+ *
-+ */
-+
-+#include <errno.h>
-+#include <pthread.h>
-+#include <signal.h>
-+#include <string.h>
-+#include <stdio.h>
-+#include <unistd.h>
-+#include <arpa/inet.h>
-+#include <sys/socket.h>
-+#include <sys/time.h>
-+#include <sys/un.h>
-+
-+#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"
-+
-+/*  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 int parse_iface(void *arg)
-+{
-+      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;
-+
-+      data = (iscsid_uip_broadcast_t *) arg;
-+      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 = 0;
-+              sleep_req.tv_nsec = 100000;
-+              nanosleep(&sleep_req, &sleep_rem);
-+
-+              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);
-+
-+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);
-+
-+      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;
-+      }
-+
-+      switch (cmd) {
-+      case ISCSID_UIP_IPC_GET_IFACE:
-+              rc = parse_iface(data);
-+              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;
-+      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);
-+}
-+
-+/******************************************************************************
-+ *  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 = 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..30843fb
---- /dev/null
-+++ b/iscsiuio/src/unix/iscsid_ipc.h
-@@ -0,0 +1,51 @@
-+/*
-+ * 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.
-+ *
-+ * 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..91c44e5
---- /dev/null
-+++ b/iscsiuio/src/unix/libs/bnx2.c
-@@ -0,0 +1,1164 @@
-+/*
-+ * 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.
-+ *
-+ * bnx2.c - bnx2 user space driver
-+ *
-+ */
-+#include <errno.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <arpa/inet.h>
-+#include <sys/mman.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <sys/user.h>
-+#include <fcntl.h>
-+#include <unistd.h>
-+
-+#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[] = "Broadcom 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[] = "Broadcom NetXtreme II BCM5706 1000Base-SX";
-+static const char hp_NC370F[] =
-+      "HP NC370F Multifunction Gigabit Server Adapter";
-+static const char brcm_5708C[] = "Broadcom NetXtreme II BCM5708 1000Base-T";
-+static const char brcm_5708S[] = "Broadcom NetXtreme II BCM5708 1000Base-SX";
-+static const char brcm_5709C[] = "Broadcom NetXtreme II BCM5709 1000Base-T";
-+static const char brcm_5709S[] = "Broadcom NetXtreme II BCM5709 1000Base-SX";
-+static const char brcm_5716C[] = "Broadcom NetXtreme II BCM5716 1000Base-T";
-+static const char brcm_5716S[] = "Broadcom 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..c025542
---- /dev/null
-+++ b/iscsiuio/src/unix/libs/bnx2.h
-@@ -0,0 +1,303 @@
-+/*
-+ * 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.
-+ *
-+ * 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..748b59d
---- /dev/null
-+++ b/iscsiuio/src/unix/libs/bnx2x.c
-@@ -0,0 +1,1633 @@
-+/*
-+ * 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.c - bnx2x user space driver
-+ *
-+ */
-+#include <errno.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <arpa/inet.h>
-+#include <linux/types.h>      /* Needed for linux/ethtool.h on RHEL 5.x */
-+#include <linux/sockios.h>
-+#include <linux/ethtool.h>
-+#include <sys/mman.h>
-+#include <sys/ioctl.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <sys/user.h>
-+#include <fcntl.h>
-+#include <unistd.h>
-+
-+#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[] = "Broadcom NetXtreme II BCM57710 10-Gigabit";
-+static const char brcm_57711[] = "Broadcom NetXtreme II BCM57711 10-Gigabit";
-+static const char brcm_57711e[] = "Broadcom NetXtreme II BCM57711E 10-Gigabit";
-+static const char brcm_57712[] = "Broadcom NetXtreme II BCM57712 10-Gigabit";
-+static const char brcm_57712_MF[] = "Broadcom NetXtreme II BCM57712 MF "
-+                                  "10-Gigabit";
-+static const char brcm_57712_VF[] = "Broadcom NetXtreme II BCM57712 VF "
-+                                  "10-Gigabit";
-+static const char brcm_57713[] = "Broadcom NetXtreme II BCM57713 10-Gigabit";
-+static const char brcm_57713e[] = "Broadcom NetXtreme II BCM57713E 10-Gigabit";
-+static const char brcm_57800[] = "Broadcom NetXtreme II BCM57800 10-Gigabit";
-+static const char brcm_57800_MF[] = "Broadcom NetXtreme II BCM57800 MF "
-+                                  "10-Gigabit";
-+static const char brcm_57800_VF[] = "Broadcom NetXtreme II BCM57800 VF "
-+                                  "10-Gigabit";
-+static const char brcm_57810[] = "Broadcom NetXtreme II BCM57810 10-Gigabit";
-+static const char brcm_57810_MF[] = "Broadcom NetXtreme II BCM57810 MF "
-+                                  "10-Gigabit";
-+static const char brcm_57810_VF[] = "Broadcom NetXtreme II BCM57810 VF "
-+                                  "10-Gigabit";
-+static const char brcm_57811[] = "Broadcom NetXtreme II BCM57811 10-Gigabit";
-+static const char brcm_57811_MF[] = "Broadcom NetXtreme II BCM57811 MF "
-+                                  "10-Gigabit";
-+static const char brcm_57811_VF[] = "Broadcom NetXtreme II BCM57811 VF "
-+                                  "10-Gigabit";
-+static const char brcm_57840[] = "Broadcom NetXtreme II BCM57840 10-Gigabit";
-+static const char brcm_57840_MF[] = "Broadcom NetXtreme II BCM57840 MF "
-+                                  "10-Gigabit";
-+static const char brcm_57840_VF[] = "Broadcom NetXtreme II BCM57840 VF "
-+                                  "10-Gigabit";
-+static const char brcm_57840_4_10[] = "Broadcom NetXtreme II BCM57840 4x"
-+                                    "10-Gigabit";
-+static const char brcm_57840_2_20[] = "Broadcom NetXtreme II BCM57840 2x"
-+                                    "20-Gigabit";
-+
-+/*******************************************************************************
-+ * PCI ID constants
-+ ******************************************************************************/
-+#define PCI_VENDOR_ID_BROADCOM                        0x14e4
-+#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},
-+};
-+
-+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;
-+      }
-+
-+      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;
-+
-+      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;
-+
-+      /*  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 */
-+              val = bnx2x_rd32(bp, bp->shmem_base + 0x354);
-+              /* SI mode */
-+              if ((val & 0x700) == 0x300) {
-+                      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;
-+                      }
-+              } else if ((val & 0x700) == 0) {
-+                      __u32 proto_offset = 0x24 + (bp->func * 0x18);
-+                      __u32 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);
-+
-+              }
-+      }
-+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<<ME_REG_PF_NUM_SHIFT) /* Relative PF Num */
-+#define ME_REG_VF_VALID                       (1<<8)
-+#define ME_REG_VF_NUM_SHIFT           9
-+#define ME_REG_VF_NUM_MASK            (0x3f<<ME_REG_VF_NUM_SHIFT)
-+#define ME_REG_VF_ERR                 (0x1<<3)
-+#define ME_REG_ABS_PF_NUM_SHIFT               16
-+#define ME_REG_ABS_PF_NUM\
-+      (7L<<ME_REG_ABS_PF_NUM_SHIFT) /* Absolute PF Num */
-+
-+#define USTORM_RX_PRODS_OFFSET(port, client_id) \
-+      (IS_E1H_OFFSET ? (0x4000 + (port * 0x360) + (client_id * 0x30)) \
-+      :(0x1000 + (port * 0x680) + (client_id * 0x40)))
-+
-+struct iro {
-+      __u32 base;
-+      __u16 m1;
-+      __u16 m2;
-+      __u16 m3;
-+      __u16 size;
-+};
-+
-+#define IRO_ENT (bp->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..6ba8bce
---- /dev/null
-+++ b/iscsiuio/src/unix/libs/cnic.c
-@@ -0,0 +1,661 @@
-+/*
-+ * 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.
-+ *
-+ * cnic.c - CNIC UIO uIP user space stack
-+ *
-+ */
-+#include <errno.h>
-+#include <pthread.h>
-+#include <signal.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <unistd.h>
-+#include <arpa/inet.h>
-+#include <linux/limits.h>
-+#include <netinet/if_ether.h>
-+#include <netinet/in.h>
-+#include <netinet/ip6.h>
-+#include <netinet/icmp6.h>
-+#include <linux/netlink.h>
-+#include <sys/ioctl.h>
-+#include <sys/time.h>
-+#include <sys/types.h>
-+#include <sys/user.h>
-+#include <sys/socket.h>
-+
-+#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);
-+
-+      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);
-+
-+      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..3e53307
---- /dev/null
-+++ b/iscsiuio/src/unix/libs/cnic.h
-@@ -0,0 +1,54 @@
-+/*
-+ * 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.
-+ *
-+ * 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..1a65793
---- /dev/null
-+++ b/iscsiuio/src/unix/logger.c
-@@ -0,0 +1,180 @@
-+/*
-+ * 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.
-+ *
-+ * logger.c - Logging Utilities
-+ *
-+ */
-+#include <errno.h>
-+#include <string.h>
-+#include <time.h>
-+#include <stdarg.h>
-+#include <stdlib.h>
-+
-+#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..edf85ae
---- /dev/null
-+++ b/iscsiuio/src/unix/logger.h
-@@ -0,0 +1,128 @@
-+/*
-+ * 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.
-+ *
-+ * logger.h - Logging Utilities
-+ *
-+ */
-+#ifndef __LOGGER_H__
-+#define __LOGGER_H__
-+
-+#include <pthread.h>
-+#include <stdio.h>
-+#include <time.h>
-+#include <stdint.h>
-+#include <sys/types.h>
-+
-+/*******************************************************************************
-+ * 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..e33db04
---- /dev/null
-+++ b/iscsiuio/src/unix/main.c
-@@ -0,0 +1,400 @@
-+/*
-+ * 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 <dlfcn.h>
-+#include <errno.h>
-+#include <fcntl.h>
-+#include <string.h>
-+#include <signal.h>
-+#include <stdlib.h>
-+#include <getopt.h>
-+#include <unistd.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <sys/utsname.h>
-+#include <net/ethernet.h>
-+#include <arpa/inet.h>
-+#include <sys/mman.h>
-+
-+#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;
-+      int rc;
-+
-+      fd = open("/dev/null", O_RDWR);
-+      if (fd == -1)
-+              exit(-1);
-+
-+      dup2(fd, 0);
-+      dup2(fd, 1);
-+      dup2(fd, 2);
-+      setsid();
-+      rc = 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;
-+      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..18e3007
---- /dev/null
-+++ b/iscsiuio/src/unix/nic.c
-@@ -0,0 +1,1533 @@
-+/*
-+ * 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.
-+ *
-+ * nic.c - Generic NIC management/utility functions
-+ *
-+ */
-+#include <dlfcn.h>
-+#include <errno.h>
-+#include <pthread.h>
-+#include <signal.h>
-+#include <string.h>
-+#include <time.h>
-+#include <unistd.h>
-+#include <sys/socket.h>
-+#include <sys/time.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <netinet/in.h>
-+#include <arpa/inet.h>
-+
-+#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_pci_table == 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_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) {
-+                      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_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) {
-+                      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;
-+
-+              current->ops->lib_ops.get_pci_table(&pci_table, &entries);
-+
-+              /*  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));
-+
-+      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 */
-+      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;
-+}
-+
-+static 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);
-+              uip_build_arp_request(ustack, ipaddr);
-+              break;
-+      default:
-+              LOG_ERR("Unknown arp state");
-+              break;
-+      }
-+}
-+
-+static 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);
-+      }
-+}
-+
-+static 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;
-+              struct ip_hdr *ip;
-+              struct ipv6_hdr *ip6;
-+              void *dst_ip;
-+              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)) {
-+                      type = ntohs(ETH_BUF(pkt->buf)->type);
-+                      pkt->network_layer = pkt->data_link_layer +
-+                                           sizeof(struct uip_eth_hdr);
-+              } else {
-+                      type = ntohs(VLAN_ETH_BUF(pkt->buf)->type);
-+                      pkt->network_layer = pkt->data_link_layer +
-+                                           sizeof(struct uip_vlan_eth_hdr);
-+              }
-+
-+              switch (type) {
-+              case UIP_ETHTYPE_IPv6:
-+                      af_type = AF_INET6;
-+                      ip6 = (struct ipv6_hdr *) pkt->network_layer;
-+                      dst_ip = (void *)&ip6->ipv6_dst;
-+                      break;
-+              case UIP_ETHTYPE_IPv4:
-+              case UIP_ETHTYPE_ARP:
-+                      af_type = AF_INET;
-+                      ip = (struct ip_hdr *) pkt->network_layer;
-+                      dst_ip = (void *)&ip->destipaddr;
-+                      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(&current_time, NULL)) {
-+                      LOG_ERR(PFX "%s: Couldn't get current time for "
-+                              "DHCP start", nic->log_name);
-+                      return -EIO;
-+              }
-+
-+              if (timercmp(&total_time, &current_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,
-+                            &nic_iface->ustack.hostaddr,
-+                            &nic_iface->ustack.netmask,
-+                            &nic_iface->ustack.default_route_addr,
-+                            nic_iface->mac_addr);
-+              break;
-+
-+      case IPV4_CONFIG_DHCP:
-+              set_uip_stack(&nic_iface->ustack,
-+                            &nic_iface->ustack.hostaddr,
-+                            &nic_iface->ustack.netmask,
-+                            &nic_iface->ustack.default_route_addr,
-+                            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);
-+              pthread_mutex_unlock(&nic->nic_mutex);
-+
-+              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)) {
-+                      /*  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);
-+                      }
-+              }
-+
-+              LOG_INFO(PFX "%s: exited main processing loop", nic->log_name);
-+
-+dev_close_free:
-+              free_free_queue(nic);
-+dev_close:
-+              pthread_mutex_lock(&nic->nic_mutex);
-+
-+              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..7d1ae28
---- /dev/null
-+++ b/iscsiuio/src/unix/nic.h
-@@ -0,0 +1,383 @@
-+/*
-+ * 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.
-+ *
-+ * nic.h - NIC header file
-+ *
-+ */
-+
-+#include <errno.h>
-+
-+#ifndef __NIC_H__
-+#define __NIC_H__
-+
-+#include <stdint.h>
-+#include <netinet/if_ether.h>
-+#include <net/if.h>
-+#include <linux/limits.h>
-+#include <stdlib.h>
-+#include <pthread.h>
-+
-+#include "nic_nl.h"
-+#include "packet.h"
-+#include "uip.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];
-+} 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_LIBRARY_EXIST_T does_nic_library_exist(char *name);
-+
-+/*******************************************************************************
-+ *  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);
-+
-+#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..8f21ba9
---- /dev/null
-+++ b/iscsiuio/src/unix/nic_id.c
-@@ -0,0 +1,361 @@
-+/*
-+ * 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.
-+ *
-+ * nic_id.c - Using sysfs to determine the PCI vendor, device, subvendor and
-+ *            subdevice ID's
-+ *
-+ */
-+#include <errno.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <unistd.h>
-+#include <sys/socket.h>
-+
-+#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;
-+
-+      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;
-+
-+      return 0;
-+}
-diff --git a/iscsiuio/src/unix/nic_id.h b/iscsiuio/src/unix/nic_id.h
-new file mode 100644
-index 0000000..8d1e1db
---- /dev/null
-+++ b/iscsiuio/src/unix/nic_id.h
-@@ -0,0 +1,46 @@
-+/*
-+ * 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.
-+ *
-+ * 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..3ab4eb9
---- /dev/null
-+++ b/iscsiuio/src/unix/nic_nl.c
-@@ -0,0 +1,677 @@
-+/*
-+ * 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.
-+ *
-+ * nic_nl.c - NIC uIP NetLink user space stack
-+ *
-+ */
-+#include <errno.h>
-+#include <pthread.h>
-+#include <signal.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <unistd.h>
-+#include <arpa/inet.h>
-+#include <linux/limits.h>
-+#include <netinet/if_ether.h>
-+#include <netinet/in.h>
-+#include <linux/netlink.h>
-+#include <iscsi_if.h>
-+#include <sys/ioctl.h>
-+#include <sys/poll.h>
-+#include <sys/types.h>
-+#include <sys/user.h>
-+#include <sys/socket.h>
-+
-+#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..90f76be
---- /dev/null
-+++ b/iscsiuio/src/unix/nic_nl.h
-@@ -0,0 +1,53 @@
-+/*
-+ * 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.
-+ *
-+ * nic_nl.h - NIC uIP NetLink user space stack
-+ *
-+ */
-+
-+#ifndef __NIC_NL_H__
-+#define __NIC_NL_H__
-+
-+#include <pthread.h>
-+
-+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..fee9a4b
---- /dev/null
-+++ b/iscsiuio/src/unix/nic_utils.c
-@@ -0,0 +1,1631 @@
-+/*
-+ * 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.
-+ *
-+ * nic_util.c - shared NIC utility functions
-+ *
-+ */
-+#include <dirent.h>
-+#include <errno.h>
-+#include <fcntl.h>
-+#define _GNU_SOURCE
-+#include <stdio.h>
-+#include <string.h>
-+#include <time.h>
-+#include <unistd.h>
-+#include <arpa/inet.h>
-+#include <linux/sockios.h>
-+#include <sys/ioctl.h>
-+#include <sys/types.h>
-+#include <sys/socket.h>
-+#include <sys/stat.h>
-+#include <sys/time.h>
-+
-+#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(&current_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, &current_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;
-+
-+      /*  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 library name */
-+      if (nic->nic_library == NULL) {
-+              NIC_LIBRARY_EXIST_T exist;
-+
-+              exist = does_nic_uio_name_exist(raw);
-+              if (exist == NIC_LIBRARY_DOESNT_EXIST) {
-+                      LOG_ERR(PFX "%s: could not find library: %s ",
-+                              nic->log_name, raw);
-+                      rc = -EIO;
-+              }
-+      } else {
-+              char *library_name;
-+              size_t library_name_size;
-+
-+              /*  Get the string name from the NIC library */
-+              (*nic->ops->lib_ops.get_library_name) (&library_name,
-+                                                     &library_name_size);
-+
-+              if (strcmp(raw, library_name) != 0) {
-+                      LOG_ERR(PFX "%s: uio names not equal: "
-+                              "expecting %s got %s from %s",
-+                              nic->log_name, library_name, raw, temp_path);
-+                      rc = -EIO;
-+              }
-+      }
-+
-+      free(raw);
-+
-+      LOG_INFO(PFX "%s: Verified is a cnic_uio device", nic->log_name);
-+
-+error:
-+      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_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);
-+              if (exist == NIC_LIBRARY_DOESNT_EXIST) {
-+                      LOG_ERR(PFX "NIC library doesn't exists: %s",
-+                              nic->library_name);
-+                      goto error;
-+              }
-+      }
-+
-+      /*  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 '%s'", nic->log_name, nic->pci_id->device_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 0 on success, <0 on failure
-+ */
-+int 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);
-+              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);
-+              pthread_mutex_unlock(&nic->nic_mutex);
-+
-+              LOG_DEBUG(PFX "%s: device disabled", nic->log_name);
-+
-+              return 0;
-+      } else {
-+              LOG_WARN(PFX "%s: device already disabled: "
-+                       "flag: 0x%x state: 0x%x",
-+                       nic->log_name, nic->flags, nic->state);
-+              return -EALREADY;
-+      }
-+}
-+
-+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..2644e43
---- /dev/null
-+++ b/iscsiuio/src/unix/nic_utils.h
-@@ -0,0 +1,101 @@
-+/*
-+ * 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.
-+ *
-+ * 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);
-+int 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..d371ec5
---- /dev/null
-+++ b/iscsiuio/src/unix/nic_vlan.c
-@@ -0,0 +1,336 @@
-+/*
-+ * 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.
-+ *
-+ * nic_vlan.c - uIP user space stack VLAN utilities
-+ *
-+ */
-+#define _GNU_SOURCE
-+#include <errno.h>
-+#include <fcntl.h>
-+#include <pthread.h>
-+#include <string.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <sys/stat.h>
-+
-+#include <arpa/inet.h>
-+#include <sys/types.h>
-+#include <sys/socket.h>
-+#include <sys/un.h>
-+
-+#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..f7293d4
---- /dev/null
-+++ b/iscsiuio/src/unix/nic_vlan.h
-@@ -0,0 +1,88 @@
-+/*
-+ * 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.
-+ *
-+ * nic_vlan.h - uIP user space stack VLAN utilities
-+ *
-+ */
-+#ifndef __NIC_VLAN_H__
-+#define __NIC_VLAN_H__
-+
-+#include <sys/types.h>
-+
-+/*  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..9691c4e
---- /dev/null
-+++ b/iscsiuio/src/unix/options.h
-@@ -0,0 +1,116 @@
-+/*
-+ * 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.
-+ *
-+ * options.h - CNIC UIO uIP user space stack
-+ *
-+ */
-+#ifndef __OPTIONS_H__
-+#define __OPTIONS_H__
-+
-+#include <byteswap.h>
-+#include <time.h>
-+#include <sys/types.h>
-+
-+/******************************************************************************
-+ * 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..1657d73
---- /dev/null
-+++ b/iscsiuio/src/unix/packet.c
-@@ -0,0 +1,145 @@
-+/*
-+ * 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.
-+ *
-+ * packet.c - packet management
-+ *
-+ */
-+#include <errno.h>
-+#include <stdio.h>
-+
-+#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;
-+      }
-+
-+      priv = malloc(priv_size);
-+      if (priv == NULL) {
-+              LOG_ERR("Could not allocate any memory for private structure");
-+              goto free_pkt;
-+      }
-+
-+      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 rc, 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) {
-+                      rc = i;
-+                      goto done;
-+              }
-+
-+              reset_packet(pkt);
-+
-+              pkt->next = nic->free_packet_queue;
-+              nic->free_packet_queue = pkt;
-+      }
-+
-+      rc = num_of_packets;
-+
-+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..f62b685
---- /dev/null
-+++ b/iscsiuio/src/unix/packet.h
-@@ -0,0 +1,75 @@
-+/*
-+ * 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.
-+ *
-+ * packet.h - packet definitions
-+ *
-+ */
-+#include <errno.h>
-+
-+#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/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 <adam@sics.se>
-+ */
-+
-+#ifndef __UIP_CONF_H__
-+#define __UIP_CONF_H__
-+
-+#include <inttypes.h>
-+
-+/**
-+ * 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..3d8ee22 100644
---- a/usr/Makefile
-+++ b/usr/Makefile
-@@ -40,7 +40,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
-diff --git a/usr/auth.c b/usr/auth.c
-index c924545..4ff0425 100644
---- a/usr/auth.c
-+++ b/usr/auth.c
-@@ -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);
-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..635ec8d 100644
---- a/usr/discovery.c
-+++ b/usr/discovery.c
-@@ -1403,6 +1403,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\n", __FUNCTION__);
-+              rc = iscsi_session_set_params(conn);
-+              if (rc) {
-+                      log_error("Could not set iscsi params for conn %d:%d "
-+                                "(err %d)\n", session->id, conn->id, rc);
-+                      rc = ISCSI_ERR_INTERNAL;
-+                      goto login_failed;
-+              }
-+      }
-+
-       if ((session->t->caps & CAP_LOGIN_OFFLOAD))
-               goto start_conn;
-@@ -1509,8 +1520,8 @@ 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\n", __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);
-diff --git a/usr/event_poll.c b/usr/event_poll.c
-index f36fec1..939f1a2 100644
---- a/usr/event_poll.c
-+++ b/usr/event_poll.c
-@@ -165,8 +165,11 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd)
-                                         "exiting", res, errno);
-                               break;
-                       }
--              } else
-+              }
-+
-+              if (res >= 0)
-                       actor_poll();
-+
-               reap_proc();
-               /*
-                * flush sysfs cache since kernel objs may
-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 <errno.h>
-+#include <stdlib.h>
-+#include <stdio.h>
-+#include <unistd.h>
-+#include <string.h>
-+#include <sys/stat.h>
-+#include <arpa/inet.h>
-+
-+#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 <sys/types.h>
-+#include <netdb.h>
-+#include <net/if.h>
-+
-+#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..1ade099 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);
-@@ -255,21 +269,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 +280,119 @@ 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_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_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 +526,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 +537,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 +545,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 +657,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 +672,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 +857,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 +987,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 +1044,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;
- }
-@@ -880,6 +1247,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, '.'))
-@@ -2569,6 +2942,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..870dba0 100644
---- a/usr/iface.c
-+++ b/usr/iface.c
-@@ -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, "."))
-@@ -476,11 +478,8 @@ static int iface_setup_binding_from_kern_iface(void *data,
-       }
-       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))
-@@ -910,6 +1010,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 +1019,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) {
-@@ -957,6 +1063,11 @@ int iface_setup_from_boot_context(struct iface_rec *iface,
-               sizeof(iface->hwaddress));
-       strlcpy(iface->ipaddress, context->ipaddr,
-               sizeof(iface->ipaddress));
-+      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 "\n", iface_str(iface));
-       return 1;
- }
-@@ -1016,6 +1127,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 +1218,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 +1236,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 +1253,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 +1375,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->vlan_id)
--                                              /* For vlan value */
--                                              count++;
--                              } else
--                                      /* vlan_state disabled */
-+                              if (iface->traffic_class)
-+                                      count++;
-+
-+                              if (iface->hop_limit)
-+                                      count++;
-+
-+                              if (iface->nd_reachable_tmo)
-+                                      count++;
-+
-+                              if (iface->nd_rexmit_time)
-                                       count++;
--                              if (iface->mtu)
-+                              if (iface->nd_stale_tmo)
-                                       count++;
--                              if (iface->port)
-+                              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;
-@@ -1213,58 +1445,68 @@ int iface_get_param_count(struct iface_rec *iface, int iface_all)
-       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)
-+      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_PORT;
-+      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;
--      if (iface->port)
--              port = iface->port;
--      memcpy(net_param->value, &port, net_param->len);
--      return 0;
--}
-+      net_param->param_type = param_type;
-+      switch (param_len) {
-+      case 1:
-+              val8 = (uint8_t)param_val;
-+              val = (char *)&val8;
-+              break;
--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;
-+      case 2:
-+              val16 = (uint16_t)param_val;
-+              val = (char *)&val16;
-+              break;
--      len = sizeof(struct iscsi_iface_param_info) + 2;
--      iov->iov_base = iscsi_nla_alloc(ISCSI_NET_PARAM_MTU, len);
--      if (!(iov->iov_base))
--              return 1;
--      attr = iov->iov_base;
--      iov->iov_len = NLA_ALIGN(attr->nla_len);
-+      case 4:
-+              val32 = (uint32_t)param_val;
-+              val = (char *)&val32;
-+              break;
--      net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr);
--      net_param->param = ISCSI_NET_PARAM_MTU;
--      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);
-+      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 +1543,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;
--      len = sizeof(struct iscsi_iface_param_info) + 1;
--      iov->iov_base = iscsi_nla_alloc(ISCSI_NET_PARAM_VLAN_ENABLED, len);
--      if (!(iov->iov_base))
-+      if (!param_val[0])
-               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->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;
--      return 0;
--}
--
--/* 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);
-+      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_IFACE_ENABLE;
--      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->state, "disable"))
--              net_param->value[0] = ISCSI_IFACE_DISABLE;
--      else /* Assume enabled */
--              net_param->value[0] = ISCSI_IFACE_ENABLE;
-+      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;
-+}
-+
-+#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 +1708,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 +1726,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 +1746,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 +1775,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 +1790,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 +1857,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 +1887,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 +1915,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 +2073,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 +2097,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 +2119,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 +2132,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;
- }
-diff --git a/usr/initiator.c b/usr/initiator.c
-index 79ca32c..05a5b19 100644
---- a/usr/initiator.c
-+++ b/usr/initiator.c
-@@ -45,6 +45,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"
-@@ -383,17 +384,7 @@ __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) {
-@@ -557,6 +548,48 @@ static int iscsi_conn_connect(struct iscsi_conn *conn, queue_task_t *qtask)
-       return 0;
- }
-+static void iscsi_uio_poll_login_timedout(void *data)
-+{
-+      struct queue_task *qtask = data;
-+      struct iscsi_conn *conn = qtask->conn;
-+      iscsi_session_t *session = conn->session;
-+
-+      log_debug(3, "timeout waiting for UIO ...\n");
-+      mgmt_ipc_write_rsp(qtask, ISCSI_ERR_TRANS_TIMEOUT);
-+      conn_delete_timers(conn);
-+      __session_destroy(session);
-+}
-+
-+static int iscsi_sched_uio_poll(queue_task_t *qtask)
-+{
-+      struct iscsi_conn *conn = qtask->conn;
-+      struct iscsi_session *session = conn->session;
-+      struct iscsi_transport *t = session->t;
-+      struct iscsi_ev_context *ev_context;
-+
-+      if (!t->template->set_net_config)
-+              return 0;
-+
-+      ev_context = iscsi_ev_context_get(conn, 0);
-+      if (!ev_context) {
-+              /* while reopening the recv pool should be full */
-+              log_error("BUG: __session_conn_reopen could "
-+                        "not get conn context for recv.");
-+              return -ENOMEM;
-+      }
-+
-+      ev_context->data = qtask;
-+      conn->state = ISCSI_CONN_STATE_XPT_WAIT;
-+
-+      iscsi_sched_ev_context(ev_context, conn, 0, EV_UIO_POLL);
-+
-+      log_debug(3, "Setting login UIO poll timer %p timeout %d",
-+                &conn->login_timer, conn->login_timeout);
-+      actor_timer(&conn->login_timer, conn->login_timeout * 1000,
-+                  iscsi_uio_poll_login_timedout, qtask);
-+      return -EAGAIN;
-+}
-+
- static void
- __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop,
-                     int redirected)
-@@ -598,6 +631,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;
-@@ -993,7 +1031,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 +1048,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;
-       }
-@@ -1469,6 +1502,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;
-@@ -1580,6 +1618,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 +1666,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
-@@ -1667,6 +1718,53 @@ failed_login:
- }
-+static void session_conn_uio_poll(void *data)
-+{
-+      struct iscsi_ev_context *ev_context = data;
-+      iscsi_conn_t *conn = ev_context->conn;
-+      struct iscsi_session *session = conn->session;
-+      queue_task_t *qtask = ev_context->data;
-+      int rc;
-+
-+      log_debug(4, "retrying uio poll");
-+      rc = iscsi_set_net_config(session->t, session,
-+                                &conn->session->nrec.iface);
-+      if (rc != 0) {
-+              if (rc == ISCSI_ERR_AGAIN) {
-+                      ev_context->data = qtask;
-+                      iscsi_sched_ev_context(ev_context, conn, 2,
-+                                             EV_UIO_POLL);
-+                      return;
-+              } else {
-+                      log_error("session_conn_uio_poll() "
-+                                "connection failure [0x%x]", rc);
-+                      actor_delete(&conn->login_timer);
-+                      iscsi_login_eh(conn, qtask, ISCSI_ERR_INTERNAL);
-+                      iscsi_ev_context_put(ev_context);
-+                      return;
-+              }
-+      }
-+
-+      iscsi_ev_context_put(ev_context);
-+      actor_delete(&conn->login_timer);
-+      log_debug(4, "UIO ready trying connect");
-+
-+      /*  uIP is ready try to connect */
-+      if (gettimeofday(&conn->initial_connect_time, NULL))
-+              log_error("Could not get initial connect time. If "
-+                        "login errors iscsid may give up the initial "
-+                        "login early. You should manually login.");
-+
-+      conn->state = ISCSI_CONN_STATE_XPT_WAIT;
-+      if (iscsi_conn_connect(conn, qtask)) {
-+              int delay = ISCSI_CONN_ERR_REOPEN_DELAY;
-+
-+              log_debug(4, "Waiting %u seconds before trying to reconnect.\n",
-+                        delay);
-+              queue_delayed_reopen(qtask, delay);
-+      }
-+}
-+
- static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
-                                 struct iscsi_conn *conn, unsigned long tmo,
-                                 int event)
-@@ -1708,6 +1806,11 @@ static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
-                         ev_context);
-               actor_schedule(&ev_context->actor);
-               break;
-+      case EV_UIO_POLL:
-+              actor_new(&ev_context->actor, session_conn_uio_poll,
-+                        ev_context);
-+              actor_schedule(&ev_context->actor);
-+              break;
-       case EV_CONN_LOGOUT_TIMER:
-               actor_timer(&ev_context->actor, tmo * 1000,
-                           iscsi_logout_timedout, ev_context);
-@@ -1752,7 +1855,8 @@ 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;
-@@ -1841,7 +1945,17 @@ 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) {
-+              iscsi_sched_uio_poll(qtask);
-+              /*
-+               * Cannot block iscsid, so caller is going to internally
-+               * retry the operation.
-+               */
-+              qtask->rsp.command = MGMT_IPC_SESSION_LOGIN;
-+              qtask->rsp.err = ISCSI_SUCCESS;
-+              return ISCSI_SUCCESS;
-+      } else if (rc) {
-               __session_destroy(session);
-               return ISCSI_ERR_LOGIN;
-       }
-diff --git a/usr/initiator.h b/usr/initiator.h
-index b45caab..c34625b 100644
---- a/usr/initiator.h
-+++ b/usr/initiator.h
-@@ -83,6 +83,7 @@ typedef enum iscsi_event_e {
-       EV_CONN_LOGOUT_TIMER,
-       EV_CONN_STOP,
-       EV_CONN_LOGIN,
-+      EV_UIO_POLL,
- } iscsi_event_e;
- struct queue_task;
-@@ -343,6 +344,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 +355,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..109e8d7 100644
---- a/usr/initiator_common.c
-+++ b/usr/initiator_common.c
-@@ -324,12 +324,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 +357,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,
-@@ -414,15 +434,58 @@ int iscsi_session_set_params(struct iscsi_conn *conn)
-                       .type = ISCSI_INT,
-                       .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 +555,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 +637,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.\n");
-+                      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)
- {
-@@ -600,6 +705,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/iscsi_ipc.h b/usr/iscsi_ipc.h
-index db5f1f0..9d26d54 100644
---- a/usr/iscsi_ipc.h
-+++ b/usr/iscsi_ipc.h
-@@ -143,8 +143,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_sysfs.c b/usr/iscsi_sysfs.c
-index 123dde3..c916ed8 100644
---- a/usr/iscsi_sysfs.c
-+++ b/usr/iscsi_sysfs.c
-@@ -24,11 +24,13 @@
- #include <dirent.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-+#include <sys/wait.h>
- #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.
-@@ -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
-@@ -567,6 +839,9 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no,
-               }
-       }
-+      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\n", session);
-+              exit(1);
-       }
-       if (!S_ISDIR(statb.st_mode) && !S_ISLNK(statb.st_mode)) {
-@@ -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++)
-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..9dbfbfd 100644
---- a/usr/iscsi_util.c
-+++ b/usr/iscsi_util.c
-@@ -25,16 +25,28 @@
- #include <string.h>
- #include <errno.h>
- #include <ctype.h>
-+#include <sys/socket.h>
-+#include <sys/un.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/resource.h>
-+#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));
-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..389f4b8 100644
---- a/usr/iscsiadm.c
-+++ b/usr/iscsiadm.c
-@@ -53,6 +53,7 @@
- #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;
-@@ -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",
-@@ -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;
--      }
--
--      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);
-+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\n", drec->type);
-+              return ISCSI_ERR_UNKNOWN_DISCOVERY_TYPE;
-       }
--
--      return rc;
- }
-+
- static int
- verify_mode_params(int argc, char **argv, char *allowed, int skip_m)
- {
-@@ -1373,18 +1430,192 @@ 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;
--      int fd, rc = 0;
--      uint16_t chap_tbl_idx;
-+      struct iscsi_chap_rec crec;
-+      recinfo_t *chap_info = NULL;
-+      struct iovec *iovs = NULL;
-+      struct iovec *iov = NULL;
-+      int type;
-+      int param_count;
-+      int param_used;
-+      int rc = 0;
-+      int fd, i = 0;
--      if (!value) {
--              log_error("CHAP deletion requires --value=table_index.");
--              return ISCSI_ERR_INVAL;
-+      if (list_empty(params)) {
-+              log_error("Chap username/password not provided.");
-+              goto exit_set_chap;
-       }
--      chap_tbl_idx = (uint16_t)atoi(value);
-+      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, &param_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,
-+                              &param_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;
-+
-+      if (chap_tbl_idx > MAX_CHAP_ENTRIES) {
-+              log_error("Invalid chap table index.");
-+              goto exit_delete_chap;
-+      }
-       t = iscsi_sysfs_get_transport_by_hba(host_no);
-       if (!t) {
-@@ -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,589 @@ 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;
-+      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:
-+      if (req_buf)
-+              free(req_buf);
-+      return rc;
-+}
-+
- static int verify_iface_params(struct list_head *params, struct node_rec *rec)
- {
-       struct user_param *param;
-@@ -1473,7 +2291,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 +2412,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 +2425,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 +2436,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 +2529,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;
-       }
-@@ -1999,15 +2817,9 @@ 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,
--                                  0);
--              break;
-       case DISCOVERY_TYPE_ISNS:
--              rc = do_isns(drec, ifaces, info_level, do_login, op);
-+              rc = do_target_discovery(drec, ifaces, info_level, do_login, op,
-+                                  0);
-               break;
-       default:
-               log_error("Unsupported discovery type.");
-@@ -2140,8 +2952,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 +2975,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 +3008,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 +3048,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 +3064,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;
-@@ -2403,12 +3220,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 +3370,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 +3414,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 +3434,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 +3443,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, &params);
-                               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,
-+                                                     &params);
-+                              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..d1756ef 100644
---- a/usr/iscsid.c
-+++ b/usr/iscsid.c
-@@ -111,9 +111,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);
-@@ -238,6 +236,7 @@ static int sync_session(void *data, struct session_info *info)
-               log_warning("Could not read data from db. Using default and "
-                           "currently negotiated values\n");
-               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 +250,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 */
-@@ -511,7 +509,8 @@ int main(int argc, char *argv[])
-       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"
-diff --git a/usr/iscsid_req.c b/usr/iscsid_req.c
-index 0902011..0e91dee 100644
---- a/usr/iscsid_req.c
-+++ b/usr/iscsid_req.c
-@@ -22,6 +22,7 @@
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
-+#include <fcntl.h>
- #include <sys/un.h>
- #include <sys/types.h>
- #include <sys/socket.h>
-@@ -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,82 @@ 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 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;
-+      err = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-+      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 3
-+      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\n", buf_len,
-+                                   rsp.command, rsp.err);
-+                      err = 0;
-+                      break;
-+              } else if ((err == -1) && (errno == EAGAIN)) {
-+                      usleep(250000);
-+                      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;
-+      } else if (rsp.err != ISCSID_UIP_MGMT_IPC_DEVICE_UP) {
-+              log_debug(3, "Device is not ready\n");
-+              err = ISCSI_ERR_AGAIN;
-+      }
-+
-+      close(fd);
-+      return err;
-+}
-diff --git a/usr/iscsid_req.h b/usr/iscsid_req.h
-index 68f5256..4fff43d 100644
---- a/usr/iscsid_req.h
-+++ b/usr/iscsid_req.h
-@@ -33,4 +33,6 @@ 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);
-+
- #endif
-diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c
-index 5c39c2e..a82c063 100644
---- a/usr/mgmt_ipc.c
-+++ b/usr/mgmt_ipc.c
-@@ -39,25 +39,29 @@
- #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 +76,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)
- {
-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..532d9ef 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) {
-@@ -1228,6 +1232,30 @@ 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, ev_len;
-+      struct iscsi_uevent ev;
-+      struct iovec *iov = iovs + 1;
-+
-+      log_debug(8, "in %s", __func__);
-+
-+      ev_len = sizeof(ev);
-+      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 +1280,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;
-@@ -1296,10 +1529,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);
-@@ -1382,8 +1615,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 +1775,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..87b8e00 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;
-       }
-@@ -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/transport.c b/usr/transport.c
-index e6e3dfc..2f38519 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"
-@@ -76,9 +77,11 @@ struct iscsi_transport_template cxgb4i = {
- struct iscsi_transport_template bnx2i = {
-       .name           = "bnx2i",
-       .set_host_ip    = 1,
-+      .use_boot_info  = 1,
-       .ep_connect     = ktransport_ep_connect,
-       .ep_poll        = ktransport_ep_poll,
-       .ep_disconnect  = ktransport_ep_disconnect,
-+      .set_net_config = uip_broadcast_params,
- };
- struct iscsi_transport_template be2iscsi = {
-@@ -97,6 +100,13 @@ struct iscsi_transport_template qla4xxx = {
-       .ep_disconnect  = ktransport_ep_disconnect,
- };
-+struct iscsi_transport_template ocs = {
-+      .name           = "ocs",
-+      .ep_connect     = ktransport_ep_connect,
-+      .ep_poll        = ktransport_ep_poll,
-+      .ep_disconnect  = ktransport_ep_disconnect,
-+};
-+
- static struct iscsi_transport_template *iscsi_transport_templates[] = {
-       &iscsi_tcp,
-       &iscsi_iser,
-@@ -105,6 +115,7 @@ static struct iscsi_transport_template *iscsi_transport_templates[] = {
-       &bnx2i,
-       &qla4xxx,
-       &be2iscsi,
-+      &ocs,
-       NULL
- };
-diff --git a/usr/transport.h b/usr/transport.h
-index 672561b..388e4b1 100644
---- a/usr/transport.h
-+++ b/usr/transport.h
-@@ -31,10 +31,14 @@ struct iscsi_transport_template {
-        * the host's ip address.
-        */
-       uint8_t set_host_ip;
-+      uint8_t use_boot_info;
-       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);
- };
- /* 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 <netinet/in.h>
- #include <stdint.h>
- #include <sys/types.h>
-+#include <limits.h>
- /*
-  * 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..f3074ee
---- /dev/null
-+++ b/usr/uip_mgmt_ipc.c
-@@ -0,0 +1,41 @@
-+/*
-+ * 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 <string.h>
-+
-+#include "log.h"
-+#include "uip_mgmt_ipc.h"
-+#include "iscsid_req.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\n");
-+
-+      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));
-+}
-diff --git a/usr/uip_mgmt_ipc.h b/usr/uip_mgmt_ipc.h
-new file mode 100644
-index 0000000..29a4769
---- /dev/null
-+++ b/usr/uip_mgmt_ipc.h
-@@ -0,0 +1,73 @@
-+/*
-+ * 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_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;
-+      } 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;
-+} iscsid_uip_rsp_t;
-+
-+extern int uip_broadcast_params(struct iscsi_transport *t,
-+                              struct iface_rec *iface,
-+                              struct iscsi_session *session);
-+
-+
-+#endif /* UIP_MGMT_IPC_H */
-diff --git a/utils/fwparam_ibft/fwparam_sysfs.c b/utils/fwparam_ibft/fwparam_sysfs.c
-index 3997363..2f37b59 100644
---- a/utils/fwparam_ibft/fwparam_sysfs.c
-+++ b/utils/fwparam_ibft/fwparam_sysfs.c
-@@ -200,6 +200,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,
-@@ -224,6 +227,8 @@ 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)
-@@ -240,6 +245,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.
diff --git a/open-iscsi-libiscsi.patch b/open-iscsi-libiscsi.patch
new file mode 100644 (file)
index 0000000..6d65275
--- /dev/null
@@ -0,0 +1,20 @@
+--- open-iscsi-2.1.4/libiscsi/Makefile.orig    2022-05-16 21:07:19.280763434 +0200
++++ open-iscsi-2.1.4/libiscsi/Makefile 2022-05-16 21:12:22.995784736 +0200
+@@ -11,7 +11,7 @@ CFLAGS = $(OPTFLAGS) $(WARNFLAGS) -I../i
+               -D$(OSNAME) -fPIC -D_GNU_SOURCE -fvisibility=hidden \
+               -I../libopeniscsiusr
+ LDFLAGS = -L../libopeniscsiusr -lopeniscsiusr -lkmod -lcrypto
+-LIB = libiscsi.so.0
++LIB = libopeniscsi.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
+@@ -49,7 +49,7 @@ fw-objs/%.o: ../utils/fwparam_ibft/%.c
+       $(CC) $(CFLAGS) -c $< -o $@
+ $(LIB): $(COMMON_OBJS) $(FW_OBJS) $(USR_OBJS) libiscsi.o
+-      $(CC) $(CFLAGS) -shared -Wl,-soname,$(LIB) $^ -o $@ -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr
++      $(CC) $(CFLAGS) -shared -Wl,-soname,$(LIB) $^ -o $@ -L$(TOPDIR)/libopeniscsiusr -lopeniscsiusr -lkmod -lcrypto
+       ln -s -f $(LIB) libiscsi.so
+ $(TESTS): $(FW_OBJS) $(COMMON_OBJS) $(USR_OBJS) $(LIB)
index 25ea03c4bda0c58ed4c256a0253e041af1f52514..41751c34a6f414075dedd08b6002022eb845cfdc 100644 (file)
@@ -1,59 +1,73 @@
---- open-iscsi-2.0-873/etc/systemd/iscsi-mark-root-nodes~      2014-04-01 12:17:50.000000000 +0200
-+++ open-iscsi-2.0-873/etc/systemd/iscsi-mark-root-nodes       2014-04-01 12:19:04.118355255 +0200
-@@ -1,13 +1,12 @@
--#!/bin/bash
-+#!/bin/sh
- 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
-+      ip=${i%:*}
-+      $ISCSIADM -m node -p $ip -T $target -o update -n node.startup -v onboot
- done
--systemctl start iscsid.service
--
-+/bin/systemctl start iscsid.service
---- open-iscsi-2.0-873/etc/systemd/iscsi.service~      2014-04-01 12:17:50.000000000 +0200
-+++ open-iscsi-2.0-873/etc/systemd/iscsi.service       2014-04-01 12:19:26.975255123 +0200
-@@ -5,12 +5,12 @@
- Conflicts=shutdown.target
- After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service
+--- open-iscsi-2.1.4/etc/systemd/iscsi.service.orig    2022-05-15 21:39:53.531578661 +0200
++++ open-iscsi-2.1.4/etc/systemd/iscsi.service 2022-05-15 21:43:54.510273168 +0200
+@@ -5,7 +5,7 @@ DefaultDependencies=no
  Before=remote-fs-pre.target
+ After=network.target network-online.target iscsid.service iscsiuio.service systemd-remount-fs.service
+ Wants=remote-fs-pre.target
 -ConditionDirectoryNotEmpty=/var/lib/iscsi/nodes
 +ConditionDirectoryNotEmpty=/etc/iscsi/nodes
  
  [Service]
  Type=oneshot
- RemainAfterExit=true
--ExecStart=/usr/libexec/iscsi-mark-root-nodes
-+ExecStart=/lib/systemd/pld-helpers.d/iscsi-mark-root-nodes
- ExecStart=/sbin/iscsiadm -m node --loginall=automatic
- ExecStop=/bin/sync
- ExecStop=/sbin/iscsiadm -m node --logoutall=automatic
---- open-iscsi-2.0-873/etc/systemd/iscsid.service~     2014-04-01 12:17:50.000000000 +0200
-+++ open-iscsi-2.0-873/etc/systemd/iscsid.service      2014-04-01 12:20:05.375647813 +0200
-@@ -9,7 +9,7 @@
+--- open-iscsi-2.1.4/etc/systemd/iscsid.service.orig   2022-05-15 21:39:53.531578661 +0200
++++ open-iscsi-2.1.4/etc/systemd/iscsid.service        2022-05-15 21:44:16.530153876 +0200
+@@ -9,7 +9,7 @@ Requires=iscsi-init.service iscsi-shutdo
  [Service]
- Type=forking
- PIDFile=/var/run/iscsid.pid
--ExecStart=/usr/sbin/iscsid
-+ExecStart=/sbin/iscsid -u iscsi -g iscsi
- ExecStop=/sbin/iscsiadm -k 0 2
+ Type=notify
+ NotifyAccess=main
+-ExecStart=/usr/sbin/iscsid -f
++ExecStart=/sbin/iscsid -f -u iscsi -g iscsi
+ KillMode=mixed
+ Restart=on-failure
+--- open-iscsi-2.1.4/etc/systemd/iscsiuio.service.orig 2022-05-15 21:39:53.531578661 +0200
++++ open-iscsi-2.1.4/etc/systemd/iscsiuio.service      2022-05-15 21:44:41.373352622 +0200
+@@ -10,7 +10,7 @@ Before=remote-fs-pre.target iscsid.servi
+ [Service]
+ Type=notify
+ NotifyAccess=main
+-ExecStart=/usr/sbin/iscsiuio -f
++ExecStart=/sbin/iscsiuio -f
+ KillMode=mixed
+ Restart=on-failure
+--- open-iscsi-2.1.4/Makefile.orig     2022-05-15 21:56:37.309474063 +0200
++++ open-iscsi-2.1.4/Makefile  2022-05-15 22:08:13.275703691 +0200
+@@ -7,7 +7,7 @@
+ DESTDIR ?=
+ prefix = /usr
+-exec_prefix = /usr
++exec_prefix = /
+ sbindir = $(exec_prefix)/sbin
+ bindir = $(exec_prefix)/bin
+ mandir = $(prefix)/share/man
+--- open-iscsi-2.1.4/etc/systemd/iscsi-init.service.orig       2022-05-15 22:26:26.836446030 +0200
++++ open-iscsi-2.1.4/etc/systemd/iscsi-init.service    2022-05-16 20:43:43.358434144 +0200
+@@ -7,4 +7,4 @@ Before=iscsid.service
+ [Service]
+ Type=oneshot
+ RemainAfterExit=no
+-ExecStart=/usr/bin/sh -c 'echo "InitiatorName=`/usr/sbin/iscsi-iname`" > /etc/iscsi/initiatorname.iscsi'
++ExecStart=/bin/sh -c 'echo "InitiatorName=`/sbin/iscsi-iname`" > /etc/iscsi/initiatorname.iscsi'
+--- open-iscsi-2.1.4/etc/systemd/iscsi-onboot.service.orig     2022-05-15 22:26:25.683118945 +0200
++++ open-iscsi-2.1.4/etc/systemd/iscsi-onboot.service  2022-05-16 20:50:19.019623997 +0200
+@@ -9,7 +9,7 @@ ConditionDirectoryNotEmpty=/sys/class/is
  
- [Install]
---- open-iscsi-2.0-873/etc/systemd/iscsiuio.service~   2014-04-01 12:54:05.000000000 +0200
-+++ open-iscsi-2.0-873/etc/systemd/iscsiuio.service    2014-04-04 12:11:04.361786827 +0200
-@@ -11,7 +11,7 @@
  [Service]
- Type=forking
- PIDFile=/var/run/iscsiuio.pid
--ExecStart=/usr/sbin/iscsiuio
-+ExecStart=/sbin/iscsiuio
+ Type=oneshot
+-ExecStart=-/usr/libexec/iscsi-mark-root-nodes
++ExecStart=-/lib/systemd/pld-helpers.d/iscsi-mark-root-nodes
  
  [Install]
- WantedBy=multi-user.target
+ WantedBy=sysinit.target
+--- open-iscsi-2.1.4/etc/systemd/iscsi-shutdown.service.orig   2022-05-15 22:26:25.683118945 +0200
++++ open-iscsi-2.1.4/etc/systemd/iscsi-shutdown.service        2022-05-16 20:50:36.799527675 +0200
+@@ -11,5 +11,5 @@ RefuseManualStop=yes
+ [Service]
+ Type=oneshot
+ RemainAfterExit=true
+-ExecStart=-/usr/bin/true
+-ExecStop=-/usr/sbin/iscsiadm -m node --logoutall=all
++ExecStart=-/bin/true
++ExecStop=-/sbin/iscsiadm -m node --logoutall=all
index f0637fc777428b477d04ae16242bea611aa98dca..1bc271dcd3da4ddc84244cf6d5a1de5704ef06b5 100644 (file)
@@ -1,50 +1,58 @@
-# Conditional build:
-%bcond_without dynamic         # link utilities dynamically
 #
-%define                ver     2.0
-%define                subver  873
+# Conditional build:
+%bcond_without python2 # CPython 2.x module
+%bcond_without python3 # CPython 3.x module
+
 Summary:       iSCSI - SCSI over IP
 Summary(pl.UTF-8):     iSCSI - SCSI po IP
 Name:          open-iscsi
-Version:       %{ver}.%{subver}
-Release:       5
+Version:       2.1.4
+Release:       1
 License:       GPL v2
 Group:         Networking/Daemons
-Source0:       http://www.open-iscsi.org/bits/%{name}-%{ver}-%{subver}.tar.gz
-# Source0-md5: 8b8316d7c9469149a6cc6234478347f7
+#Source0Download: https://github.com/open-iscsi/open-iscsi/releases
+Source0:       https://github.com/open-iscsi/open-iscsi/archive/%{version}/%{name}-%{version}.tar.gz
+# Source0-md5: e17f1924c1d64342773eae630e15c519
 Source1:       %{name}.init
 Source2:       %{name}.sysconfig
 Source3:       %{name}-devices.init
 Source4:       iscsiuio.logrotate
-Patch0:                %{name}-git.patch
-Patch1:                %{name}-build.patch
-Patch2:                %{name}-systemd.patch
-Patch32:       0044-iscsid-add-initrd-option-to-set-run-from-initrd-hint.patch
-Patch35:       0047-iscsiadm-iscsid-newroot-command-to-survive-switch_ro.patch
-Patch36:       0047-iscsiuio-systemd-socket-activation-support.patch
-Patch37:       0048-iscsiadm-param-parsing-for-advanced-node-creation.patch
-Patch38:       0049-update-systemd-service-files-add-iscsi.service-for-s.patch
-Patch39:       0050-iscsi-boot-related-service-file-updates.patch
-Patch40:       0058-iscsiuio-IPC-newroot-command.patch
-Patch41:       0059-iscsiuio-systemd-unit-files.patch
-Patch42:       0062-Don-t-check-for-autostart-sessions-if-iscsi-is-not-u.patch
-Patch43:       0063-fix-order-of-setting-uid-gid-and-drop-supplementary-.patch
-Patch44:       0065-fix-hardened-build-of-iscsiuio.patch
-Patch45:       0066-start-socket-listeners-on-iscsiadm-command.patch
-URL:           http://www.open-iscsi.org/
+# Fedora patches
+Patch1:                0001-unit-file-tweaks.patch
+# idmb_rec_write refactoring skipped, see 75c46b011d7485a4b5676d824c7f3cdea2076f49
+Patch5:                0005-update-initscripts-and-docs.patch
+# use-var-for-config, use-red-hat-for-name skipped
+Patch8:                0008-libiscsi.patch
+Patch9:                0009-Add-macros-to-release-GIL-lock.patch
+Patch10:       0010-libiscsi-introduce-sessions-API.patch
+Patch11:       0011-libiscsi-fix-discovery-request-timeout-regression.patch
+Patch12:       0012-libiscsi-format-security-build-errors.patch
+Patch13:       0013-libiscsi-fix-build-to-use-libopeniscsiusr.patch
+Patch14:       0014-libiscsi-fix-build-against-latest-upstream-again.patch
+Patch15:       0015-remove-the-offload-boot-supported-ifdef.patch
+Patch16:       0016-Revert-iscsiadm-return-error-when-login-fails.patch
+# dont-install-scripts, use-var-lib-iscsi-in-libopeniscsiusr skipped
+Patch19:       0019-Coverity-scan-fixes.patch
+Patch20:       0020-fix-upstream-build-breakage-of-iscsiuio-LDFLAGS.patch
+# use-Red-Hat-version-string-to-match-RPM-package-vers skipped
+Patch22:       0022-iscsi_if.h-replace-zero-length-array-with-flexible-a.patch
+Patch23:       0023-stop-using-Werror-for-now.patch
+Patch24:       0024-minor-service-file-updates.patch
+Patch25:       0001-Remove-dependences-from-iscsi-init.service.patch
+# PLD specific
+Patch100:      %{name}-systemd.patch
+Patch101:      %{name}-libiscsi.patch
+URL:           https://www.open-iscsi.com/
 BuildRequires: kmod-devel
+BuildRequires: open-isns-devel
 BuildRequires: openssl-devel
-BuildRequires: rpmbuild(macros) >= 1.671
-%if %{with dynamic}
-BuildRequires: openslp-devel
-BuildRequires: sed >= 4.0
-Requires:      openslp >= 2.0.0
-%else
-BuildRequires: glibc-static
-BuildRequires: openslp-static
-%endif
+%{?with_python2:BuildRequires: python-devel >= 1:2.5}
+%{?with_python3:BuildRequires: python3-devel >= 1:3.2}
+BuildRequires: rpm-pythonprov
+BuildRequires: rpmbuild(macros) >= 1.714
 Requires(post,preun):  /sbin/chkconfig
 Requires(post,preun,postun):   systemd-units >= 38
+Requires:      %{name}-libs = %{version}-%{release}
 Requires:      rc-scripts
 Requires:      systemd-units >= 38
 Suggests:      multipath-tools
@@ -70,27 +78,74 @@ Protokół iSCSI jest zdefiniowany przez IETF do składowania IP. Więcej
 informacji o protokole iSCSI znajduje się w standardach IETF na
 <http://www.ietf.org/>.
 
+%package libs
+Summary:       Open-iSCSI shared libraries
+Summary(pl.UTF-8):     Biblioteki współdzielone Open-iSCSI
+Group:         Libraries
+
+%description libs
+Open-iSCSI shared libraries.
+
+%description libs -l pl.UTF-8
+Biblioteki współdzielone Open-iSCSI.
+
+%package devel
+Summary:       Header files for Open-iSCSI libraries
+Summary(pl.UTF-8):     Pliki nagłówkowe bibliotek Open-iSCSI
+Group:         Development/Libraries
+Requires:      %{name}-libs = %{version}-%{release}
+
+%description devel
+Header files for Open-iSCSI libraries.
+
+%description devel -l pl.UTF-8
+Pliki nagłówkowe bibliotek Open-iSCSI.
+
+%package -n python-pyiscsi
+Summary:       Python 2 interface to Open-iSCSI library
+Summary(pl.UTF-8):     Interfejs Pythona 2 do biblioteki Open-iSCSI
+Group:         Libraries/Python
+Requires:      %{name}-libs = %{version}-%{release}
+
+%description -n python-pyiscsi
+Python 2 interface to Open-iSCSI library.
+
+%description -n python-pyiscsi -l pl.UTF-8
+Interfejs Pythona 2 do biblioteki Open-iSCSI.
+
+%package -n python3-pyiscsi
+Summary:       Python 3 interface to Open-iSCSI library
+Summary(pl.UTF-8):     Interfejs Pythona 3 do biblioteki Open-iSCSI
+Group:         Libraries/Python
+Requires:      %{name}-libs = %{version}-%{release}
+
+%description -n python3-pyiscsi
+Python 3 interface to Open-iSCSI library.
+
+%description -n python3-pyiscsi -l pl.UTF-8
+Interfejs Pythona 3 do biblioteki Open-iSCSI.
+
 %prep
-%setup -q -n %{name}-%{ver}-%{subver}
-%patch0 -p1
-%patch32 -p1
-%patch35 -p1
-%patch36 -p1
-%patch37 -p1
-%patch38 -p1
-%patch39 -p1
-%patch40 -p1
-%patch41 -p1
-%patch42 -p1
-%patch43 -p1
-%patch44 -p1
-%patch45 -p1
+%setup -q
 %patch1 -p1
-%patch2 -p1
-
-%if %{with dynamic}
-sed -i -e 's/-static //' usr/Makefile
-%endif
+%patch5 -p1
+%patch8 -p1
+%patch9 -p1
+%patch10 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
+%patch15 -p1
+%patch16 -p1
+%patch19 -p1
+%patch20 -p1
+%patch22 -p1
+%patch23 -p1
+%patch24 -p1
+%patch25 -p1
+%patch100 -p1
+%patch101 -p1
 
 %build
 cd iscsiuio
@@ -100,47 +155,67 @@ cd iscsiuio
 %{__autoheader}
 %{__automake}
 %configure
+cd ..
 
-cd ../utils/open-isns
-%configure \
-       --with-slp \
-       --without-security
-cd ../..
 %{__make} \
        CC="%{__cc}" \
-       OPTFLAGS="%{rpmcflags} %{rpmcppflags} -DUSE_KMOD -lkmod" \
-       IPC_FLAGS="-DNETLINK_ISCSI=8 -D_GNU_SOURCE" \
+       OPTFLAGS="%{rpmcflags} %{rpmcppflags}" \
+       SED=sed \
        KSUBLEVEL=0
 
+cd libiscsi
+%if %{with python2}
+%py_build
+%endif
+%if %{with python3}
+%py3_build
+%endif
+
 %install
 rm -rf $RPM_BUILD_ROOT
 install -d $RPM_BUILD_ROOT%{_sysconfdir}/iscsi/{nodes,send_targets,static,isns,slp,ifaces} \
        $RPM_BUILD_ROOT/etc/{rc.d/init.d,sysconfig,logrotate.d} \
        $RPM_BUILD_ROOT%{systemdunitdir} \
-       $RPM_BUILD_ROOT/lib/systemd/pld-helpers.d
+       $RPM_BUILD_ROOT{/sbin,/lib/systemd/pld-helpers.d}
 
-%{__make} install_programs install_doc install_etc \
+%{__make} -j1 install_programs install_doc install_etc install_libopeniscsiusr \
        DESTDIR=$RPM_BUILD_ROOT
 
 :> $RPM_BUILD_ROOT%{_sysconfdir}/iscsi/initiatorname.iscsi
 
 install %{SOURCE1} $RPM_BUILD_ROOT/etc/rc.d/init.d/iscsid
-install %{SOURCE2} $RPM_BUILD_ROOT/etc/sysconfig/iscsi
+cp -p %{SOURCE2} $RPM_BUILD_ROOT/etc/sysconfig/iscsi
 install %{SOURCE3} $RPM_BUILD_ROOT/etc/rc.d/init.d/iscsi
-install %{SOURCE4} $RPM_BUILD_ROOT/etc/logrotate.d/iscsiuio
+cp -p %{SOURCE4} $RPM_BUILD_ROOT/etc/logrotate.d/iscsiuio
 
 install usr/iscsistart $RPM_BUILD_ROOT%{_sbindir}
-install doc/iscsistart.8 $RPM_BUILD_ROOT%{_mandir}/man8
-install doc/iscsi-iname.8 $RPM_BUILD_ROOT%{_mandir}/man8
+cp -p doc/iscsistart.8 $RPM_BUILD_ROOT%{_mandir}/man8
+#install doc/iscsi-iname.8 $RPM_BUILD_ROOT%{_mandir}/man8
 
-install etc/systemd/iscsi.service $RPM_BUILD_ROOT%{systemdunitdir}
-install etc/systemd/iscsid.service $RPM_BUILD_ROOT%{systemdunitdir}
-install etc/systemd/iscsid.socket $RPM_BUILD_ROOT%{systemdunitdir}
-install etc/systemd/iscsiuio.service $RPM_BUILD_ROOT%{systemdunitdir}
-install etc/systemd/iscsiuio.socket $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsi.service $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsi-init.service $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsi-onboot.service $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsi-shutdown.service $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsid.service $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsid.socket $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsiuio.service $RPM_BUILD_ROOT%{systemdunitdir}
+cp -p etc/systemd/iscsiuio.socket $RPM_BUILD_ROOT%{systemdunitdir}
 
 install etc/systemd/iscsi-mark-root-nodes $RPM_BUILD_ROOT/lib/systemd/pld-helpers.d
 
+# rename to resolve conflict with already existing libiscsi from libiscsi.spec
+install -p libiscsi/libopeniscsi.so.0 $RPM_BUILD_ROOT%{_libdir}
+ln -sf libopeniscsi.so.0 $RPM_BUILD_ROOT%{_libdir}/libopeniscsi.so
+cp -p libiscsi/libiscsi.h $RPM_BUILD_ROOT%{_includedir}/libopeniscsi.h
+
+cd libiscsi
+%if %{with python2}
+%py_install
+%endif
+%if %{with python3}
+%py3_install
+%endif
+
 %clean
 rm -rf $RPM_BUILD_ROOT
 
@@ -155,7 +230,7 @@ fi
 /sbin/chkconfig --add iscsi
 /sbin/chkconfig --add iscsid
 NORESTART=1
-%systemd_post iscsi.service iscsid.service iscsiuio.service iscsid.socket iscsiuio.socket
+%systemd_post iscsi.service iscsid.service iscsiuio.service iscsid.socket iscsiuio.socket iscsi-onboot.service iscsi-init.service iscsi-shutdown.service
 
 %preun
 if [ "$1" = "0" ]; then
@@ -164,7 +239,7 @@ if [ "$1" = "0" ]; then
        /sbin/chkconfig --del iscsid
        /sbin/chkconfig --del iscsi
 fi
-%systemd_preun iscsi.service iscsid.service iscsiuio.service iscsid.socket iscsiuio.socket
+%systemd_preun iscsi.service iscsid.service iscsiuio.service iscsid.socket iscsiuio.socket iscsi-onboot.service iscsi-init.service iscsi-shutdown.service
 
 %postun
 if [ "$1" = "0" ]; then
@@ -178,9 +253,12 @@ fi
 /bin/systemctl --quiet enable iscsid.socket || :
 /bin/systemctl --quiet enable iscsiuio.socket || :
 
+%post  libs -p /sbin/ldconfig
+%postun        libs -p /sbin/ldconfig
+
 %files
 %defattr(644,root,root,755)
-%doc Changelog README THANKS
+%doc Changelog README THANKS TODO
 %dir %{_sysconfdir}/iscsi
 %dir %{_sysconfdir}/iscsi/ifaces
 %dir %{_sysconfdir}/iscsi/isns
@@ -195,20 +273,55 @@ fi
 %attr(754,root,root) /etc/rc.d/init.d/iscsi
 %attr(754,root,root) /etc/rc.d/init.d/iscsid
 %{systemdunitdir}/iscsi.service
+%{systemdunitdir}/iscsi-init.service
+%{systemdunitdir}/iscsi-onboot.service
+%{systemdunitdir}/iscsi-shutdown.service
 %{systemdunitdir}/iscsid.service
 %{systemdunitdir}/iscsid.socket
 %{systemdunitdir}/iscsiuio.service
 %{systemdunitdir}/iscsiuio.socket
 %attr(755,root,root) /lib/systemd/pld-helpers.d/iscsi-mark-root-nodes
+%attr(755,root,root) %{_sbindir}/iscsi-gen-initiatorname
 %attr(755,root,root) %{_sbindir}/iscsi-iname
+%attr(755,root,root) %{_sbindir}/iscsi_discovery
+%attr(755,root,root) %{_sbindir}/iscsi_fw_login
+%attr(755,root,root) %{_sbindir}/iscsi_offload
 %attr(755,root,root) %{_sbindir}/iscsiadm
 %attr(755,root,root) %{_sbindir}/iscsid
 %attr(755,root,root) %{_sbindir}/iscsistart
-%attr(755,root,root) %{_sbindir}/iscsi_discovery
 %attr(755,root,root) %{_sbindir}/iscsiuio
 %{_mandir}/man8/iscsi-iname.8*
 %{_mandir}/man8/iscsi_discovery.8*
+%{_mandir}/man8/iscsi_fw_login.8*
 %{_mandir}/man8/iscsiadm.8*
 %{_mandir}/man8/iscsid.8*
 %{_mandir}/man8/iscsistart.8*
 %{_mandir}/man8/iscsiuio.8*
+
+%files libs
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libopeniscsi.so.0
+%attr(755,root,root) %{_libdir}/libopeniscsiusr.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libopeniscsiusr.so.0
+
+%files devel
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libopeniscsi.so
+%attr(755,root,root) %{_libdir}/libopeniscsiusr.so
+%{_includedir}/libopeniscsi.h
+%{_includedir}/libopeniscsiusr*.h
+%{_pkgconfigdir}/libopeniscsiusr.pc
+
+%if %{with python2}
+%files -n python-pyiscsi
+%defattr(644,root,root,755)
+%attr(755,root,root) %{py_sitedir}/libiscsi.so
+%{py_sitedir}/PyIscsi-1.0-py*.egg-info
+%endif
+
+%if %{with python3}
+%files -n python3-pyiscsi
+%defattr(644,root,root,755)
+%attr(755,root,root) %{py3_sitedir}/libiscsi.cpython-*.so
+%{py3_sitedir}/PyIscsi-1.0-py*.egg-info
+%endif
This page took 1.760007 seconds and 4 git commands to generate.