+++ /dev/null
-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 *)ð->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,
-+ ð->src_mac);
-+
-+ /* Now check for the target address option and update that as
-+ well */
-+ if (link_opt->hdr.type == IPV6_ICMP_OPTION_TAR_ADDR) {
-+ tar_addr6 = (struct ipv6_addr *)((u8_t *)icmp +
-+ sizeof(struct icmpv6_hdr));
-+ LOG_DEBUG("IPV6: Target MAC "
-+ "%02x:%02x:%02x:%02x:%02x:%02x",
-+ link_opt->link_addr[0], link_opt->link_addr[1],
-+ link_opt->link_addr[2], link_opt->link_addr[3],
-+ link_opt->link_addr[4], link_opt->link_addr[5]);
-+ inet_ntop(AF_INET6, &tar_addr6->addr8, addr_str,
-+ sizeof(addr_str));
-+ LOG_DEBUG("IPv6: Target IP addr %s", addr_str);
-+ ipv6_update_arp_table(context, tar_addr6,
-+ (struct mac_address *)link_opt->link_addr);
-+ }
-+
-+ }
-+}
-+
-+static void ipv6_icmp_handle_nd_sol(struct ipv6_context *context)
-+{
-+ struct eth_hdr *eth =
-+ (struct eth_hdr *)context->ustack->data_link_layer;
-+ struct ipv6_hdr *ipv6 =
-+ (struct ipv6_hdr *)context->ustack->network_layer;
-+ struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
-+ sizeof(struct ipv6_hdr));
-+ struct icmpv6_opt_link_addr *link_opt =
-+ (struct icmpv6_opt_link_addr *)((u8_t *)icmp +
-+ sizeof(struct icmpv6_hdr) + sizeof(struct ipv6_addr));
-+ int icmpv6_opt_len = 0;
-+ struct ipv6_addr tmp;
-+ struct ipv6_addr *longest_match_addr, *tar_addr6;
-+
-+ LOG_DEBUG("IPv6: Handle nd sol");
-+
-+ if ((memcmp((char *)&context->mac_addr,
-+ (char *)ð->dest_mac, sizeof(struct mac_address)) != 0) &&
-+ (iscsiL2IsOurMcAddr(context, (struct mac_address *)ð->dest_mac)
-+ == FALSE)) {
-+ /* This packet is not for us to handle */
-+ LOG_DEBUG("IPv6: MAC not addressed to us "
-+ "%02x:%02x:%02x:%02x:%02x:%02x",
-+ eth->dest_mac.addr[0], eth->dest_mac.addr[1],
-+ eth->dest_mac.addr[2], eth->dest_mac.addr[3],
-+ eth->dest_mac.addr[4], eth->dest_mac.addr[5]);
-+ return;
-+ }
-+
-+ /* Also check for the icmpv6_data before generating the reply */
-+ if (ipv6_is_it_our_address(context,
-+ (struct ipv6_addr *) ((u8_t *) icmp +
-+ sizeof(struct icmpv6_hdr)))
-+ == FALSE) {
-+ /* This packet is not for us to handle */
-+ LOG_DEBUG("IPv6: IP not addressed to us");
-+ return;
-+ }
-+
-+ /* Copy source MAC to Destination MAC */
-+ memcpy((char *)ð->dest_mac,
-+ (char *)ð->src_mac, sizeof(struct mac_address));
-+
-+ /* Dest IP contains source IP */
-+ memcpy((char *)&tmp,
-+ (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr));
-+ memcpy((char *)&ipv6->ipv6_dst,
-+ (char *)&ipv6->ipv6_src, sizeof(struct ipv6_addr));
-+
-+ /* Examine the Neighbor Solicitation ICMPv6 target address field.
-+ If target address exist, use that to find best match src address
-+ for the reply */
-+ if (link_opt->hdr.type == IPV6_ICMP_OPTION_SRC_ADDR) {
-+ tar_addr6 = (struct ipv6_addr *)((u8_t *)icmp +
-+ sizeof(struct icmpv6_hdr));
-+ if (ipv6_is_it_our_link_local_address(context, tar_addr6)
-+ == TRUE) {
-+ LOG_DEBUG("IPv6: NA using link local");
-+ memcpy((char *)&ipv6->ipv6_src,
-+ (char *)&context->link_local_addr,
-+ sizeof(struct ipv6_addr));
-+ } else {
-+ longest_match_addr =
-+ ipv6_find_longest_match(context, tar_addr6);
-+ if (longest_match_addr) {
-+ LOG_DEBUG("IPv6: NA using longest match addr");
-+ memcpy((char *)&ipv6->ipv6_src,
-+ (char *)longest_match_addr,
-+ sizeof(struct ipv6_addr));
-+ } else {
-+ LOG_DEBUG("IPv6: NA using link local instead");
-+ memcpy((char *)&ipv6->ipv6_src,
-+ (char *)&context->link_local_addr,
-+ sizeof(struct ipv6_addr));
-+ }
-+ }
-+ } else {
-+ /* No target link address, just use whatever it sent to us */
-+ LOG_DEBUG("IPv6: NA use dst addr");
-+ memcpy((char *)&ipv6->ipv6_src,
-+ (char *)&tmp,
-+ sizeof(struct ipv6_addr));
-+ }
-+ ipv6->ipv6_hop_limit = 255;
-+ icmp->icmpv6_type = ICMPV6_NEIGH_ADV;
-+ icmp->icmpv6_code = 0;
-+ icmp->icmpv6_data = 0;
-+ icmp->icmpv6_cksum = 0;
-+ icmp->data.icmpv6_un_data8[0] =
-+ IPV6_NA_FLAG_SOLICITED | IPV6_NA_FLAG_OVERRIDE;
-+ memcpy((char *)((u8_t *)icmp + sizeof(struct icmpv6_hdr)),
-+ (char *)&ipv6->ipv6_src,
-+ sizeof(struct ipv6_addr));
-+
-+ /* Add the target link address option only for all solicitation */
-+ ipv6_icmp_init_link_option(context,
-+ (struct icmpv6_opt_link_addr *)((u8_t *)icmp +
-+ sizeof(struct icmpv6_hdr) +
-+ sizeof(struct ipv6_addr)),
-+ IPV6_ICMP_OPTION_TAR_ADDR);
-+ icmpv6_opt_len = sizeof(struct icmpv6_opt_link_addr);
-+ ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) +
-+ icmpv6_opt_len + sizeof(struct ipv6_addr)));
-+ LOG_DEBUG("IPv6: Send nd adv");
-+ ipv6_send(context,
-+ (u8_t *) icmp - (u8_t *) eth +
-+ sizeof(struct icmpv6_hdr) +
-+ sizeof(struct icmpv6_opt_link_addr) +
-+ sizeof(struct ipv6_addr));
-+ return;
-+}
-+
-+static void ipv6_icmp_handle_echo_request(struct ipv6_context *context)
-+{
-+ struct eth_hdr *eth =
-+ (struct eth_hdr *)context->ustack->data_link_layer;
-+ struct ipv6_hdr *ipv6 =
-+ (struct ipv6_hdr *)context->ustack->network_layer;
-+ struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
-+ sizeof(struct ipv6_hdr));
-+ struct ipv6_addr temp;
-+
-+ /* Copy source MAC to Destination MAC */
-+ memcpy((char *)ð->dest_mac,
-+ (char *)ð->src_mac, sizeof(struct mac_address));
-+
-+ memcpy((char *)&temp,
-+ (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr));
-+
-+ /* Dest IP contains source IP */
-+ memcpy((char *)&ipv6->ipv6_dst,
-+ (char *)&ipv6->ipv6_src, sizeof(struct ipv6_addr));
-+ /* Use Link-local as source address */
-+ memcpy((char *)&ipv6->ipv6_src,
-+ (char *)&temp, sizeof(struct ipv6_addr));
-+
-+ ipv6->ipv6_hop_limit = context->hop_limit;
-+ icmp->icmpv6_type = ICMPV6_ECHO_REPLY;
-+ icmp->icmpv6_code = 0;
-+ icmp->icmpv6_cksum = 0;
-+ LOG_DEBUG("IPv6: Send echo reply");
-+ ipv6_send(context, (u8_t *) icmp - (u8_t *) eth +
-+ sizeof(struct ipv6_hdr) + HOST_TO_NET16(ipv6->ipv6_plen));
-+ return;
-+}
-+
-+void ipv6_set_ip_params(struct ipv6_context *context,
-+ struct ipv6_addr *src_ip, u8_t prefix_len,
-+ struct ipv6_addr *default_gateway,
-+ struct ipv6_addr *linklocal)
-+{
-+ if (!(IPV6_IS_ADDR_UNSPECIFIED(src_ip))) {
-+ ipv6_add_prefix_entry(context, src_ip, prefix_len);
-+ /* Create the multi_dest address */
-+ memset(&context->multi_dest, 0, sizeof(struct ipv6_addr));
-+ context->multi_dest.addr8[0] = 0xff;
-+ context->multi_dest.addr8[1] = 0x02;
-+ context->multi_dest.addr8[11] = 0x01;
-+ context->multi_dest.addr8[12] = 0xff;
-+ context->multi_dest.addr8[13] = src_ip->addr8[13];
-+ context->multi_dest.addr16[7] = src_ip->addr16[7];
-+ /* Create the multi address */
-+ memset(&context->multi, 0, sizeof(struct ipv6_addr));
-+ context->multi.addr8[0] = 0xfc;
-+ context->multi.addr8[2] = 0x02;
-+ context->multi.addr16[7] = src_ip->addr16[7];
-+ }
-+
-+ if (!(IPV6_IS_ADDR_UNSPECIFIED(default_gateway))) {
-+ /* Override the default gateway addr */
-+ memcpy((char *)&context->default_router,
-+ (char *)default_gateway, sizeof(struct ipv6_addr));
-+ ipv6_add_prefix_entry(context, default_gateway,
-+ prefix_len);
-+ }
-+ if (!(IPV6_IS_ADDR_UNSPECIFIED(linklocal))) {
-+ /* Override the linklocal addr */
-+ memcpy((char *)&context->link_local_addr,
-+ (char *)linklocal, sizeof(struct ipv6_addr));
-+ context->link_local_multi.addr8[0] = 0xff;
-+ context->link_local_multi.addr8[1] = 0x02;
-+ context->link_local_multi.addr8[11] = 0x01;
-+ context->link_local_multi.addr8[12] = 0xff;
-+ context->link_local_multi.addr8[13] |=
-+ context->link_local_addr.addr8[13];
-+ context->link_local_multi.addr16[7] =
-+ context->link_local_addr.addr16[7];
-+
-+ /* Default Prefix length is 64 */
-+ /* Add Link local address to the head of the ipv6 address
-+ list */
-+ ipv6_add_prefix_entry(context,
-+ &context->link_local_addr, 64);
-+ }
-+}
-+
-+int ipv6_get_source_ip_addrs(struct ipv6_context *context,
-+ struct ipv6_addr_entry *addr_list)
-+{
-+ struct ipv6_prefix_entry *ipv6_prefix;
-+ int i;
-+
-+ for (i = 0, ipv6_prefix = context->addr_list; ipv6_prefix != NULL;
-+ ipv6_prefix = ipv6_prefix->next) {
-+ memcpy((char *)&addr_list->ip_addr,
-+ (char *)&ipv6_prefix->ip_addr,
-+ sizeof(struct ipv6_addr));
-+ addr_list->prefix_len = ipv6_prefix->prefix_len * 8;
-+
-+ i++;
-+ addr_list++;
-+ }
-+
-+ return i;
-+}
-+
-+int ipv6_get_default_router_ip_addrs(struct ipv6_context *context,
-+ struct ipv6_addr *ip_addr)
-+{
-+ /* This is a default router. */
-+ memcpy((char *)ip_addr,
-+ (char *)&context->default_router,
-+ sizeof(struct ipv6_addr));
-+
-+ return 1;
-+}
-+
-+static void ipv6_udp_rx(struct ipv6_context *context)
-+{
-+ struct eth_hdr *eth =
-+ (struct eth_hdr *)context->ustack->data_link_layer;
-+ struct ipv6_hdr *ipv6 =
-+ (struct ipv6_hdr *)context->ustack->network_layer;
-+ struct udp_hdr *udp = (struct udp_hdr *)((u8_t *)ipv6 +
-+ sizeof(struct ipv6_hdr));
-+ struct dhcpv6_context *dhcpv6c;
-+
-+ /*
-+ * We only care about DHCPv6 packets from the DHCPv6 server. We drop
-+ * all others.
-+ */
-+ if (!(context->flags & IPV6_FLAGS_DISABLE_DHCPV6)) {
-+ if ((udp->src_port == HOST_TO_NET16(DHCPV6_SERVER_PORT)) &&
-+ (udp->dest_port == HOST_TO_NET16(DHCPV6_CLIENT_PORT))) {
-+ dhcpv6c = context->dhcpv6_context;
-+ dhcpv6c->eth = eth;
-+ dhcpv6c->ipv6 = ipv6;
-+ dhcpv6c->udp = udp;
-+ ipv6_udp_handle_dhcp(dhcpv6c);
-+ }
-+ }
-+}
-+
-+struct mac_address *ipv6_get_link_addr(struct ipv6_context *context)
-+{
-+ return &context->mac_addr;
-+}
-+
-+u16_t ipv6_do_stateful_dhcpv6(struct ipv6_context *context, u32_t flags)
-+{
-+ u16_t task = 0;
-+ u16_t ra_flags;
-+
-+ ra_flags = context->flags &
-+ (IPV6_FLAGS_MANAGED_ADDR_CONFIG | IPV6_FLAGS_OTHER_STATEFUL_CONFIG);
-+
-+ if (!(context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED)) {
-+ LOG_DEBUG("IPv6: There is no IPv6 router on the network");
-+ ra_flags |=
-+ (IPV6_FLAGS_MANAGED_ADDR_CONFIG |
-+ IPV6_FLAGS_OTHER_STATEFUL_CONFIG);
-+ }
-+
-+ if ((flags & ISCSI_FLAGS_DHCP_TCPIP_CONFIG) &&
-+ (ra_flags & IPV6_FLAGS_MANAGED_ADDR_CONFIG))
-+ task |= DHCPV6_TASK_GET_IP_ADDRESS;
-+
-+ if ((flags & ISCSI_FLAGS_DHCP_ISCSI_CONFIG) &&
-+ (ra_flags & IPV6_FLAGS_OTHER_STATEFUL_CONFIG))
-+ task |= DHCPV6_TASK_GET_OTHER_PARAMS;
-+
-+ LOG_DEBUG("IPv6: Stateful flags = 0x%x, ra_flags = 0x%x, task = 0x%x",
-+ flags, ra_flags, task);
-+
-+ return task;
-+}
-+
-+void ipv6_add_solit_node_address(struct ipv6_context *context,
-+ struct ipv6_addr *ip_addr)
-+{
-+ struct mac_address mac_addr;
-+
-+ /*
-+ * Add Solicited Node Multicast Address for statically configured IPv6
-+ * address.
-+ */
-+ mac_addr.addr[0] = 0x33;
-+ mac_addr.addr[1] = 0x33;
-+ mac_addr.addr[2] = 0xff;
-+ mac_addr.addr[3] = ip_addr->addr8[13];
-+ mac_addr.addr[4] = ip_addr->addr8[14];
-+ mac_addr.addr[5] = ip_addr->addr8[15];
-+ iscsiL2AddMcAddr(context, (struct mac_address *)&mac_addr);
-+}
-+
-+void ipv6_cfg_link_local_addr(struct ipv6_context *context,
-+ struct ipv6_addr *ip_addr)
-+{
-+ memcpy((char *)&context->link_local_addr,
-+ (char *)ip_addr, sizeof(struct ipv6_addr));
-+}
-+
-+void ipv6_disable_dhcpv6(struct ipv6_context *context)
-+{
-+ context->flags |= IPV6_FLAGS_DISABLE_DHCPV6;
-+}
-diff --git a/iscsiuio/src/uip/ipv6.h b/iscsiuio/src/uip/ipv6.h
-new file mode 100644
-index 0000000..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(ð_addr_tmp, eth_hdr->src.addr, sizeof(eth_addr_tmp));
-+ memcpy(eth_hdr->src.addr, ustack->uip_ethaddr.addr,
-+ sizeof(eth_hdr->src.addr));
-+ memcpy(eth_hdr->dest.addr, ð_addr_tmp,
-+ sizeof(eth_hdr->dest.addr));
-+
-+ pthread_mutex_unlock(&ustack->lock);
-+ return;
-+ }
-+
-+ memcpy(eth_hdr->dest.addr, &e->mac_addr, sizeof(eth_hdr->dest.addr));
-+ memcpy(eth_hdr->src.addr, ustack->uip_ethaddr.addr,
-+ sizeof(eth_hdr->src.addr));
-+
-+ pthread_mutex_unlock(&ustack->lock);
-+}
-+
-+/*---------------------------------------------------------------------------*/
-diff --git a/iscsiuio/src/uip/uip-neighbor.h b/iscsiuio/src/uip/uip-neighbor.h
-new file mode 100644
-index 0000000..d10c57b
---- /dev/null
-+++ b/iscsiuio/src/uip/uip-neighbor.h
-@@ -0,0 +1,105 @@
-+/*
-+ * Copyright (c) 2006, Swedish Institute of Computer Science.
-+ * All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. Neither the name of the Institute nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
-+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
-+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-+ * SUCH DAMAGE.
-+ *
-+ * This file is part of the uIP TCP/IP stack
-+ *
-+ */
-+
-+/**
-+ * \file
-+ * Header file for database of link-local neighbors, used by
-+ * IPv6 code and to be used by future ARP code.
-+ * \author
-+ * Adam Dunkels <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, ð->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(ð->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(¤t_time, NULL)) {
-+ LOG_ERR(PFX "%s: Couldn't get current time for "
-+ "DHCP start", nic->log_name);
-+ return -EIO;
-+ }
-+
-+ if (timercmp(&total_time, ¤t_time, <)) {
-+ LOG_ERR(PFX "%s: timeout waiting for DHCP/NDP",
-+ nic->log_name);
-+ if (nic_iface->ustack.ip_config == IPV6_CONFIG_DHCP ||
-+ nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC)
-+ n->retry_count = IPV6_MAX_ROUTER_SOL_RETRY;
-+ return -EIO;
-+ }
-+ }
-+
-+ if (nic->flags & NIC_GOING_DOWN)
-+ return -EIO;
-+ else if (nic->flags & NIC_DISABLED)
-+ return -EINVAL;
-+ else
-+ return 0;
-+}
-+
-+/* Called with nic_mutex locked */
-+static int do_acquisition(nic_t *nic, nic_interface_t *nic_iface,
-+ struct timer *periodic_timer, struct timer *arp_timer)
-+{
-+ struct in_addr addr;
-+ struct in6_addr addr6;
-+ char buf[INET6_ADDRSTRLEN];
-+ int rc = -1;
-+
-+ /* New acquisition */
-+ uip_init(&nic_iface->ustack, nic->flags & NIC_IPv6_ENABLED);
-+ memcpy(&nic_iface->ustack.uip_ethaddr.addr, nic->mac_addr, ETH_ALEN);
-+
-+ LOG_INFO(PFX "%s: Initialized ip stack: VLAN: %d",
-+ nic->log_name, nic_iface->vlan_id);
-+
-+ LOG_INFO(PFX "%s: mac: %02x:%02x:%02x:%02x:%02x:%02x",
-+ nic->log_name,
-+ nic_iface->mac_addr[0],
-+ nic_iface->mac_addr[1],
-+ nic_iface->mac_addr[2],
-+ nic_iface->mac_addr[3],
-+ nic_iface->mac_addr[4],
-+ nic_iface->mac_addr[5]);
-+
-+ switch (nic_iface->ustack.ip_config) {
-+ case IPV4_CONFIG_STATIC:
-+ memcpy(&addr.s_addr, nic_iface->ustack.hostaddr,
-+ sizeof(addr.s_addr));
-+
-+ LOG_INFO(PFX "%s: Using IP address: %s",
-+ nic->log_name, inet_ntoa(addr));
-+
-+ memcpy(&addr.s_addr, nic_iface->ustack.netmask,
-+ sizeof(addr.s_addr));
-+
-+ LOG_INFO(PFX "%s: Using netmask: %s",
-+ nic->log_name, inet_ntoa(addr));
-+
-+ set_uip_stack(&nic_iface->ustack,
-+ &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(¤t_time, NULL)) {
-+ LOG_ERR(PFX "%s: Couldn't get current time for "
-+ "watching file: %s [%s]",
-+ nic->log_name, filepath, strerror(errno));
-+ return -EIO;
-+ }
-+
-+ /* Timeout has excceded return -ETIME */
-+ if (timercmp(&total_time, ¤t_time, <)) {
-+ LOG_ERR(PFX "%s: timeout waiting %d secs for file: %s",
-+ nic->log_name, seconds, filepath);
-+ return -ETIME;
-+ }
-+
-+ nanosleep(&sleep_req, &sleep_rem);
-+ }
-+}
-+
-+/******************************************************************************
-+ * Autodiscovery of iscsi_hosts
-+ *****************************************************************************/
-+static int filter_host_name(const struct dirent *entry)
-+{
-+ if ((memcmp(entry->d_name, "host", 4) == 0))
-+ return 1;
-+ else
-+ return 0;
-+}
-+
-+int nic_discover_iscsi_hosts()
-+{
-+ struct dirent **files;
-+ int count;
-+ int i;
-+ int rc;
-+
-+ count = scandir(base_iscsi_host_name, &files, filter_host_name,
-+ alphasort);
-+
-+ switch (count) {
-+ case 0:
-+ /* Currently there are no iSCSI hosts */
-+ rc = 0;
-+ break;
-+
-+ case -1:
-+ LOG_WARN(PFX "Error when scanning path: %s[%s]",
-+ base_iscsi_host_name, strerror(errno));
-+ rc = -EINVAL;
-+ break;
-+
-+ default:
-+ /* There are iSCSI hosts */
-+ pthread_mutex_lock(&nic_list_mutex);
-+ for (i = 0; i < count; i++) {
-+ int host_no;
-+ char *raw = NULL;
-+ uint32_t raw_size = 0;
-+ char temp_path[sizeof(iscsi_host_path_netdev_template) +
-+ 8];
-+ rc = sscanf(files[i]->d_name, host_template, &host_no);
-+ nic_t *nic;
-+
-+ LOG_INFO(PFX "Found host[%d]: %s",
-+ host_no, files[i]->d_name);
-+
-+ /* Build the path to determine netdev name */
-+ snprintf(temp_path, sizeof(temp_path),
-+ iscsi_host_path_netdev_template, host_no);
-+
-+ rc = capture_file(&raw, &raw_size, temp_path);
-+ if (rc != 0)
-+ continue;
-+
-+ rc = from_host_no_find_associated_eth_device(host_no,
-+ &nic);
-+ if (rc != 0) {
-+ /* Normalize the string */
-+ if (raw[raw_size - 1] == '\n')
-+ raw[raw_size - 1] = '\0';
-+
-+ nic = nic_init();
-+ if (nic == NULL) {
-+ LOG_ERR(PFX "Couldn't allocate "
-+ "space for NIC %s "
-+ "during scan", raw);
-+
-+ rc = -ENOMEM;
-+ break;
-+ }
-+
-+ strncpy(nic->eth_device_name, raw, raw_size);
-+ nic->config_device_name = nic->eth_device_name;
-+ nic->log_name = nic->eth_device_name;
-+
-+ if (nic_fill_name(nic) != 0) {
-+ free(nic);
-+ free(raw);
-+ rc = -EIO;
-+ continue;
-+ }
-+
-+ nic_add(nic);
-+
-+ LOG_INFO(PFX "NIC not found creating an "
-+ "instance for host_no: %d %s",
-+ host_no, nic->eth_device_name);
-+ } else
-+ LOG_INFO(PFX "%s: NIC found host_no: %d",
-+ nic->log_name, host_no);
-+
-+ free(raw);
-+ }
-+ pthread_mutex_unlock(&nic_list_mutex);
-+
-+ /* Cleanup the scandir() call */
-+ for (i = 0; i < count; i++)
-+ free(files[i]);
-+ free(files);
-+
-+ rc = 0;
-+ break;
-+ }
-+
-+ return rc;
-+}
-+
-+/******************************************************************************
-+ * Enable/Disable Multicast on physical interface
-+ *****************************************************************************/
-+static int nic_util_enable_disable_multicast(nic_t *nic, uint32_t cmd)
-+{
-+ int rc = 0;
-+ struct uip_eth_addr multicast_addr;
-+ int fd;
-+ struct ifreq ifr;
-+
-+ /* adding ethernet multicast address for IPv6 */
-+ memcpy(&multicast_addr, nic->mac_addr, ETH_ALEN);
-+ multicast_addr.addr[0] = 0x33;
-+ multicast_addr.addr[1] = 0x33;
-+ multicast_addr.addr[2] = 0xff;
-+
-+ /* Prepare the request */
-+ memset(&ifr, 0, sizeof(ifr));
-+ strncpy(ifr.ifr_name, nic->eth_device_name,
-+ sizeof(nic->eth_device_name));
-+ memcpy(ifr.ifr_hwaddr.sa_data, multicast_addr.addr, ETH_ALEN);
-+
-+ fd = socket(AF_INET, SOCK_DGRAM, 0);
-+ if (fd < 0) {
-+ LOG_ERR(PFX "%s: Couldn't create socket to %s "
-+ "multicast address: %s",
-+ nic->log_name,
-+ cmd == SIOCADDMULTI ? "added" : "delete",
-+ strerror(errno));
-+ return errno;
-+ }
-+
-+ rc = fcntl(fd, F_SETFL, O_NONBLOCK);
-+ if (rc != 0) {
-+ LOG_WARN("%s: Couldn't set to ethtool IOCTL to "
-+ "non-blocking [%s]", nic->log_name, strerror(errno));
-+ }
-+
-+ if (ioctl(fd, cmd, (char *)&ifr) != 0) {
-+ LOG_ERR("%s: Couldn't issue ioctl socket to %s "
-+ "multicast address: %s",
-+ nic->log_name,
-+ cmd == SIOCADDMULTI ? "add" : "delete",
-+ strerror(errno));
-+ rc = errno;
-+ goto error;
-+ }
-+
-+ LOG_INFO(PFX "%s: %s address %02x:%02x:%02x:%02x:%02x:%02x "
-+ "to multicast list",
-+ nic->log_name,
-+ cmd == SIOCADDMULTI ? "Added" : "Deleted",
-+ multicast_addr.addr[0], multicast_addr.addr[1],
-+ multicast_addr.addr[2], multicast_addr.addr[3],
-+ multicast_addr.addr[4], multicast_addr.addr[5]);
-+
-+ if (cmd == SIOCADDMULTI)
-+ nic->flags |= NIC_ADDED_MULICAST;
-+ else
-+ nic->flags &= ~NIC_ADDED_MULICAST;
-+
-+error:
-+ close(fd);
-+
-+ return rc;
-+}
-+
-+/**
-+ * enable_multicast() - This fuction is used to enable
-+ * the listening of multicast addresses for a given network interface
-+ * @param nic - NIC device to enable multicast on
-+ * @return 0 for success or <0 for failure
-+ */
-+int enable_multicast(nic_t *nic)
-+{
-+ return nic_util_enable_disable_multicast(nic, SIOCADDMULTI);
-+}
-+
-+/**
-+ * disable_multicast() - This fuction is used to disable
-+ * the listening of multicast addresses for a given network interface
-+ * @param dev - NIC device to disable multicast on
-+ * @return 0 for success or <0 for failure
-+ */
-+int disable_multicast(nic_t *nic)
-+{
-+ return nic_util_enable_disable_multicast(nic, SIOCDELMULTI);
-+}
-+
-+/*******************************************************************************
-+ * Finding associated UIO/physical network interfaces
-+ ******************************************************************************/
-+static int filter_net_name(const struct dirent *entry)
-+{
-+ if ((memcmp(entry->d_name, "net:", 4) == 0))
-+ return 1;
-+ else
-+ return 0;
-+}
-+
-+static char *extract_net_name(struct dirent **files)
-+{
-+ return strstr(files[0]->d_name, ":");
-+}
-+
-+static int filter_dot_out(const struct dirent *entry)
-+{
-+ if ((memcmp(entry->d_name, ".", 1) == 0))
-+ return 0;
-+ else
-+ return 1;
-+}
-+
-+static char *extract_none(struct dirent **files)
-+{
-+ return files[0]->d_name;
-+}
-+
-+/**
-+ * from_host_no_find_nic() - Given the host number
-+ * this function will try to find the assoicated nic interface
-+ * Must be called with nic_list_mutex lock
-+ * @param host_no - minor number of the UIO device
-+ * @param nic - pointer to the NIC will set if successful
-+ * @return 0 on success, <0 on error
-+ */
-+int from_host_no_find_associated_eth_device(int host_no, nic_t **nic)
-+{
-+ nic_t *current_nic = nic_list;
-+ char *raw = NULL, *raw_tmp;
-+ uint32_t raw_size = 0;
-+
-+ char temp_path[sizeof(iscsi_host_path_netdev_template) + 8];
-+ int rc = -EIO;
-+
-+ /* Build the path to determine uio name */
-+ snprintf(temp_path, sizeof(temp_path),
-+ iscsi_host_path_netdev_template, host_no);
-+
-+ rc = capture_file(&raw, &raw_size, temp_path);
-+ if (rc != 0)
-+ goto error;
-+
-+ /* sanitize name string by replacing newline with null termination */
-+ raw_tmp = raw;
-+ while (*raw_tmp != '\n' && raw_size--)
-+ raw_tmp++;
-+ *raw_tmp = '\0';
-+
-+ rc = -EIO;
-+
-+ current_nic = nic_list;
-+ while (current_nic != NULL) {
-+ if (strcmp(raw, current_nic->eth_device_name) == 0) {
-+ *nic = current_nic;
-+ rc = 0;
-+ break;
-+ }
-+
-+ current_nic = current_nic->next;
-+ }
-+
-+ free(raw);
-+
-+error:
-+ return rc;
-+}
-+
-+/*******************************************************************************
-+ * NIC packet handling functions
-+ ******************************************************************************/
-+/**
-+ * from_uio_find_associated_eth_device() - Given the uio minor number
-+ * this function will try to find the assoicated phyisical network
-+ * interface
-+ * @param uio_minor - minor number of the UIO device
-+ * @param name - char buffer which will be filled if successful
-+ * @param name_size - size of the name buffer
-+ * @return >0 minor number <0 an error
-+ */
-+static int from_uio_find_associated_eth_device(nic_t *nic,
-+ int uio_minor,
-+ char *name, size_t name_size)
-+{
-+ char *path;
-+ int rc;
-+ int count;
-+ struct dirent **files;
-+ char *parsed_name;
-+ int i;
-+ int path_iterator;
-+ char *search_paths[] = { "/sys/class/uio/uio%i/device/",
-+ "/sys/class/uio/uio%i/device/net"
-+ };
-+ int path_to[] = { 5, 1 };
-+ int (*search_filters[]) (const struct dirent *) = {
-+ filter_net_name, filter_dot_out,};
-+ char *(*extract_name[]) (struct dirent **files) = {
-+ extract_net_name, extract_none,};
-+ int extract_name_offset[] = { 1, 0 };
-+
-+ path = malloc(PATH_MAX);
-+ if (path == NULL) {
-+ LOG_ERR(PFX "Could not allocate memory for path");
-+ rc = -ENOMEM;
-+ goto error;
-+ }
-+
-+ for (path_iterator = 0;
-+ path_iterator < sizeof(search_paths) / sizeof(search_paths[0]);
-+ path_iterator++) {
-+ /* Build the path to determine uio name */
-+ rc = sprintf(path, search_paths[path_iterator], uio_minor);
-+
-+ wait_for_file_node_timed(nic, path, path_to[path_iterator]);
-+
-+ count = scandir(path, &files,
-+ search_filters[path_iterator], alphasort);
-+
-+ switch (count) {
-+ case 1:
-+ parsed_name = (*extract_name[path_iterator]) (files);
-+ if (parsed_name == NULL) {
-+ LOG_WARN(PFX "Couldn't find delimiter in: %s",
-+ files[0]->d_name);
-+
-+ break;
-+ }
-+
-+ strncpy(name,
-+ parsed_name +
-+ extract_name_offset[path_iterator], name_size);
-+
-+ free(files[0]);
-+ free(files);
-+
-+ rc = 0;
-+ break;
-+
-+ case 0:
-+ rc = -EINVAL;
-+ break;
-+
-+ case -1:
-+ LOG_WARN(PFX "Error when scanning path: %s[%s]",
-+ path, strerror(errno));
-+ rc = -EINVAL;
-+ break;
-+
-+ default:
-+ LOG_WARN(PFX
-+ "Too many entries when looking for device: %s",
-+ path);
-+
-+ /* Cleanup the scandir() call */
-+ for (i = 0; i < count; i++)
-+ free(files[i]);
-+ free(files);
-+
-+ rc = -EINVAL;
-+ break;
-+ }
-+
-+ if (rc == 0)
-+ break;
-+ }
-+
-+error:
-+ free(path);
-+
-+ return rc;
-+}
-+
-+/**
-+ * filter_uio_name() - This is the callback used by scandir when looking for
-+ * the number of uio entries
-+ */
-+static int filter_uio_name(const struct dirent *entry)
-+{
-+ /* Only return if the name of the file begins with 'uio' */
-+ if ((memcmp(entry->d_name, uio_name, sizeof(uio_name) - 1) == 0))
-+ return 1;
-+ else
-+ return 0;
-+}
-+
-+/**
-+ * from_netdev_name_find_nic() - This is used to find the NIC device given
-+ * the netdev name
-+ * @param interface_name - name of the interface to search on
-+ * @param nic - pointer of the pointer to the NIC
-+ * @return 0 on success, <0 on failure
-+ */
-+int from_netdev_name_find_nic(char *interface_name, nic_t **nic)
-+{
-+ nic_t *current_nic;
-+
-+ current_nic = nic_list;
-+ while (current_nic != NULL) {
-+ if (strcmp(interface_name, current_nic->eth_device_name) == 0)
-+ break;
-+
-+ current_nic = current_nic->next;
-+ }
-+
-+ if (current_nic == NULL)
-+ return -EINVAL;
-+
-+ *nic = current_nic;
-+ return 0;
-+}
-+
-+/**
-+ * from_phys_name_find_assoicated_uio_device() - This is used to find the
-+ * uio minor
-+ * when given a network interface name
-+ * @param interface_name - network interface name to search for
-+ * @return >0 minor number <0 an error
-+ */
-+int from_phys_name_find_assoicated_uio_device(nic_t *nic)
-+{
-+ char *path = NULL;
-+ int count;
-+ struct dirent **files;
-+ int i;
-+ int rc;
-+ char *interface_name = nic->config_device_name;
-+
-+ if (interface_name == NULL)
-+ interface_name = nic->eth_device_name;
-+
-+ /* Wait at least 10 seconds for uio sysfs entries to appear */
-+ rc = wait_for_file_node_timed(nic, (char *)base_uio_sysfs_name, 10);
-+ if (rc != 0)
-+ return rc;
-+
-+ count = scandir(base_uio_sysfs_name,
-+ &files, filter_uio_name, alphasort);
-+
-+ switch (count) {
-+ case 0:
-+ LOG_WARN(PFX "Couldn't find %s to determine uio minor",
-+ interface_name);
-+ return -EINVAL;
-+
-+ case -1:
-+ LOG_WARN(PFX "Error when scanning for %s in path: %s [%s]",
-+ interface_name, base_uio_sysfs_name, strerror(errno));
-+ return -EINVAL;
-+ }
-+
-+ path = malloc(PATH_MAX);
-+ if (path == NULL) {
-+ LOG_ERR(PFX "Could not allocate memory for path");
-+ return -ENOMEM;
-+ }
-+
-+ /* Run through the contents of the filtered files to see if the
-+ * network interface name matches that of the uio device */
-+ for (i = 0; i < count; i++) {
-+ int uio_minor;
-+ char eth_name[IFNAMSIZ];
-+
-+ rc = sscanf(files[i]->d_name, "uio%d", &uio_minor);
-+ if (rc != 1) {
-+ LOG_WARN("Could not parse: %s", files[i]->d_name);
-+ continue;
-+ }
-+
-+ rc = from_uio_find_associated_eth_device(nic,
-+ uio_minor,
-+ eth_name,
-+ sizeof(eth_name));
-+ if (rc != 0) {
-+ LOG_WARN("uio minor: %d not valid [%D]", uio_minor, rc);
-+ continue;
-+ }
-+
-+ if (strncmp(eth_name, interface_name, sizeof(eth_name)) == 0) {
-+ memcpy(nic->eth_device_name,
-+ eth_name, sizeof(nic->eth_device_name));
-+
-+ LOG_INFO(PFX "%s associated with uio%d",
-+ nic->eth_device_name, uio_minor);
-+
-+ rc = uio_minor;
-+ goto done;
-+ }
-+ }
-+
-+ LOG_WARN("Could not find assoicate uio device with %s", interface_name);
-+
-+ rc = -EINVAL;
-+done:
-+ if (path != NULL)
-+ free(path);
-+
-+ for (i = 0; i < count; i++)
-+ free(files[i]);
-+ free(files);
-+
-+ return rc;
-+
-+}
-+
-+/**
-+ * nic_verify_uio_sysfs_name() - Using the name entry in sysfs it will try to
-+ * match the NIC library name
-+ * @param nic - The NIC hardware to check
-+ *
-+ */
-+int nic_verify_uio_sysfs_name(nic_t *nic)
-+{
-+ char *raw = NULL, *raw_tmp;
-+ uint32_t raw_size = 0;
-+ char temp_path[sizeof(nic_uio_sysfs_name_tempate) + 8];
-+ int rc = 0;
-+
-+ /* 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, ¶m_count);
-+ if (rc) {
-+ log_error("Invalid username/password pair passed. Unable to determine the type of chap entry");
-+ rc = ISCSI_ERR_INVAL;
-+ goto free_info_rec;
-+ }
-+
-+ if (param_count > 2) {
-+ log_error("Only one pair of username/password can be passed.");
-+ rc = ISCSI_ERR;
-+ goto free_info_rec;
-+ }
-+
-+ memset(&crec, 0, sizeof(crec));
-+ rc = fill_host_chap_rec(params, &crec, chap_info, chap_index, type,
-+ ¶m_count);
-+ if (rc) {
-+ log_error("Unable to fill CHAP record");
-+ goto free_info_rec;
-+ }
-+
-+ /* +2 for event and nlmsghdr */
-+ param_count += 2;
-+ iovs = calloc((param_count * sizeof(struct iovec)),
-+ sizeof(char));
-+ if (!iovs) {
-+ log_error("Out of Memory.");
-+ rc = ISCSI_ERR_NOMEM;
-+ goto free_info_rec;
-+ }
-+
-+ /* param_used gives actual number of iovecs used for chap */
-+ param_used = chap_build_config(&crec, iovs);
-+ if (!param_used) {
-+ log_error("Build chap config failed.");
-+ rc = ISCSI_ERR;
-+ goto free_iovec;
-+ }
-+
-+ fd = ipc->ctldev_open();
-+ if (fd < 0) {
-+ rc = ISCSI_ERR_INTERNAL;
-+ log_error("Netlink open failed.");
-+ goto free_iovec;
-+ }
-+
-+ rc = ipc->set_chap(t->handle, host_no, iovs, param_count);
-+ if (rc < 0) {
-+ log_error("CHAP setting failed");
-+ if (rc == -EBUSY) {
-+ rc = ISCSI_ERR_BUSY;
-+ log_error("CHAP index %d is in use.",
-+ crec.chap_tbl_idx);
-+ } else {
-+ rc = ISCSI_ERR;
-+ }
-+
-+ goto exit_set_chap;
-+ }
-+
-+ ipc->ctldev_close();
-+
-+free_iovec:
-+ /* start at 2, because 0 is for nlmsghdr and 1 for event */
-+ iov = iovs + 2;
-+ for (i = 0; i < param_used; i++, iov++) {
-+ if (iov->iov_base)
-+ free(iov->iov_base);
-+ }
-+
-+ free(iovs);
-+
-+free_info_rec:
-+ if (chap_info)
-+ free(chap_info);
-+
-+exit_set_chap:
-+ return rc;
-+}
-+
-+static int delete_host_chap_info(uint32_t host_no, uint16_t chap_tbl_idx)
-+{
-+ struct iscsi_transport *t = NULL;
-+ int fd, rc = 0;
-+
-+ 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, ¶ms);
- break;
-+ case MODE_FLASHNODE:
-+ if (host_no > MAX_HOST_NO) {
-+ log_error("FLASHNODE mode requires host no");
-+ rc = ISCSI_ERR_INVAL;
-+ break;
-+ }
-+
-+ if (index == ULLONG_MAX)
-+ index = (uint64_t)MAX_FLASHNODE_IDX + 1;
-+
-+ rc = exec_flashnode_op(op, info_level, host_no,
-+ index, portal_type,
-+ ¶ms);
-+ break;
-+ case MODE_HOST_STATS:
-+ if (host_no > MAX_HOST_NO) {
-+ log_error("STATS mode requires host no");
-+ rc = ISCSI_ERR_INVAL;
-+ break;
-+ }
-+
-+ rc = exec_host_stats_op(op, info_level,
-+ host_no);
-+ break;
-+
- default:
- log_error("Invalid Sub Mode");
- break;
-diff --git a/usr/iscsid.c b/usr/iscsid.c
-index b4bb65b..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.