From 602db466741748f9f51c674b6ed9ccb420e6ec90 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Wed, 10 Oct 2012 12:59:40 -0700 Subject: [PATCH] Resolves: #826300 --- iscsi-initiator-utils-sync-uio-0.7.4.3.patch | 5690 ++++++++++++++++++ iscsi-initiator-utils.spec | 8 +- 2 files changed, 5697 insertions(+), 1 deletion(-) create mode 100644 iscsi-initiator-utils-sync-uio-0.7.4.3.patch diff --git a/iscsi-initiator-utils-sync-uio-0.7.4.3.patch b/iscsi-initiator-utils-sync-uio-0.7.4.3.patch new file mode 100644 index 0000000..f612d27 --- /dev/null +++ b/iscsi-initiator-utils-sync-uio-0.7.4.3.patch @@ -0,0 +1,5690 @@ +diff --git a/iscsiuio/README b/iscsiuio/README +index 5c36dec..a716263 100644 +--- a/iscsiuio/README ++++ b/iscsiuio/README +@@ -1,6 +1,6 @@ +-Iscsiuio Userspace Tool +-Version 0.7.2.1 +-Mar 05, 2012 ++iscsiuio Userspace Tool ++Version 0.7.4.3 ++Aug 16, 2012 + ------------------------------------------------------ + + This tool is to be used in conjunction with the Broadcom NetXtreme II Linux +@@ -189,10 +189,11 @@ To run the daemon in debug mode please pass the parameter '-d ' + + where the following debug levels are defined: + +-DEBUG 4 - Print all messages +-INFO 3 - Print messages needed to follow the uIP code (default) +-WARN 2 - Print warning messages +-ERROR 1 - Only print critical errors ++PACKET 5 - Print all messages ++DEBUG 4 - Print debug 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: + +diff --git a/iscsiuio/RELEASE.TXT b/iscsiuio/RELEASE.TXT +index d4a00b6..cb1d470 100644 +--- a/iscsiuio/RELEASE.TXT ++++ b/iscsiuio/RELEASE.TXT +@@ -1,7 +1,7 @@ + Release Notes + Broadcom uIP Linux Driver +- Version 0.7.2.1 +- 03/05/2012 ++ Version 0.7.4.3 ++ 08/16/2012 + + Broadcom Corporation + 5300 California Avenue, +@@ -10,6 +10,228 @@ + Copyright (c) 2004 - 2012 Broadcom Corporation + All rights reserved + ++ ++uIP v0.7.4.3 (Aug 16, 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 ++ ++ 3. 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 ++ ++ 4. 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 ++ ++ 5. 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 ++ ++ 6. 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 ++ ++ 7. 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 ++ ++ 8. 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 ++ ++ 9. 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 ++ ++ 10. 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 ++ ++ 11. 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 ++ ++ 12. 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 ++ ++ 13. 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 ++ ++ 14. 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 ++ ++ 15. Problem: Cont00063443 - Compilation error on SLES11sp1 ++ Cause: The iface_num field was not defined ++ Change: Fixed all references to iface_num ++ Impact: SLES11sp1 ++ ++ 16. 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 ++ ++ 17. 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 ++ ++ 18. 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 ++ ++ 19. 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 ++ ++ 20. 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 ++ ++ 21. 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 ++ ++ 22. 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 ++ ++ 23. 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 ++ ++ 24. 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 ++ ++ 25. 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 ++ ++ 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 ++ ++ 4. Updated README ++ ++ 5. Added support for the new iface_num field in the iscsi_uevent ++ path ++ ++ 6. Fixed bug in the nic_iface search engine based on iface_num ++ ++ 7. Allow VLAN tag = 1 (router management) to connect offload ++ ++ 8. Added support for jumbo MTU (independent from the L2 MTU) ++ ++ + uIP v0.7.2.1 (Mar 05, 2012) + ======================================================= + Fixes +@@ -47,7 +269,7 @@ uIP v0.7.2.1 (Mar 05, 2012) + ------------ + 1. Change: Default iscsiuio logging to off. Use the '-d' + option to enable +- 2. Change: Disable HP SD mode ++ 2. Change: Disable HP SD mode (NOT) + 3. Change: Updated README + + +diff --git a/iscsiuio/configure b/iscsiuio/configure +index 4879fb9..6ff2e68 100644 +--- a/iscsiuio/configure ++++ b/iscsiuio/configure +@@ -1,6 +1,6 @@ + #! /bin/sh + # Guess values for system-dependent variables and create Makefiles. +-# Generated by GNU Autoconf 2.59 for iscsiuio 0.7.2.1. ++# Generated by GNU Autoconf 2.59 for iscsiuio 0.7.4.3. + # + # Report bugs to . + # +@@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} + # Identity of this package. + PACKAGE_NAME='iscsiuio' + PACKAGE_TARNAME='iscsiuio' +-PACKAGE_VERSION='0.7.2.1' +-PACKAGE_STRING='iscsiuio 0.7.2.1' ++PACKAGE_VERSION='0.7.4.3' ++PACKAGE_STRING='iscsiuio 0.7.4.3' + PACKAGE_BUGREPORT='eddie.wai@broadcom.com' + + # Factoring default headers for most tests. +@@ -954,7 +954,7 @@ if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +-\`configure' configures iscsiuio 0.7.2.1 to adapt to many kinds of systems. ++\`configure' configures iscsiuio 0.7.4.3 to adapt to many kinds of systems. + + Usage: $0 [OPTION]... [VAR=VALUE]... + +@@ -1020,7 +1020,7 @@ fi + + if test -n "$ac_init_help"; then + case $ac_init_help in +- short | recursive ) echo "Configuration of iscsiuio 0.7.2.1:";; ++ short | recursive ) echo "Configuration of iscsiuio 0.7.4.3:";; + esac + cat <<\_ACEOF + +@@ -1161,7 +1161,7 @@ fi + test -n "$ac_init_help" && exit 0 + if $ac_init_version; then + cat <<\_ACEOF +-iscsiuio configure 0.7.2.1 ++iscsiuio configure 0.7.4.3 + generated by GNU Autoconf 2.59 + + Copyright (C) 2003 Free Software Foundation, Inc. +@@ -1175,7 +1175,7 @@ cat >&5 <<_ACEOF + This file contains any messages produced by compilers while + running configure, to aid debugging if configure makes a mistake. + +-It was created by iscsiuio $as_me 0.7.2.1, which was ++It was created by iscsiuio $as_me 0.7.4.3, which was + generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ +@@ -21726,7 +21726,7 @@ _ASBOX + } >&5 + cat >&5 <<_CSEOF + +-This file was extended by iscsiuio $as_me 0.7.2.1, which was ++This file was extended by iscsiuio $as_me 0.7.4.3, which was + generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES +@@ -21789,7 +21789,7 @@ _ACEOF + + cat >>$CONFIG_STATUS <<_ACEOF + ac_cs_version="\\ +-iscsiuio config.status 0.7.2.1 ++iscsiuio config.status 0.7.4.3 + configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +diff --git a/iscsiuio/configure.ac b/iscsiuio/configure.ac +index 3b7a880..0b1e7f1 100644 +--- a/iscsiuio/configure.ac ++++ b/iscsiuio/configure.ac +@@ -1,6 +1,6 @@ + dnl iscsiuio uIP user space stack configure.ac file + dnl +-dnl Copyright (c) 2004-2011 Broadcom Corporation ++dnl Copyright (c) 2004-2012 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 +@@ -11,9 +11,9 @@ dnl Maintained by: Eddie Wai (eddie.wai@broadcom.com) + dnl + + PACKAGE=iscsiuio +-VERSION=0.7.2.1 ++VERSION=0.7.4.3 + +-AC_INIT(iscsiuio, 0.7.2.1, eddie.wai@broadcom.com) ++AC_INIT(iscsiuio, 0.7.4.3, eddie.wai@broadcom.com) + + AM_INIT_AUTOMAKE($PACKAGE, $VERSION) + AC_CONFIG_HEADER(config.h) +diff --git a/iscsiuio/docs/iscsiuio.8 b/iscsiuio/docs/iscsiuio.8 +index 3307b1e..4bf26df 100644 +--- a/iscsiuio/docs/iscsiuio.8 ++++ b/iscsiuio/docs/iscsiuio.8 +@@ -3,9 +3,9 @@ + .\" modify it under the terms of the GNU General Public License as + .\" published by the Free Software Foundation. + .\" +-.\" bnx2.4,v 0.7.2.1 ++.\" bnx2.4,v 0.7.4.3 + .\" +-.TH iscsiuio 8 "03/05/2012" "Broadcom Corporation" ++.TH iscsiuio 8 "08/16/2012" "Broadcom Corporation" + .\" + .\" NAME part + .\" +diff --git a/iscsiuio/include/iscsi_if.h b/iscsiuio/include/iscsi_if.h +index a9ac145..1944abd 100644 +--- a/iscsiuio/include/iscsi_if.h ++++ b/iscsiuio/include/iscsi_if.h +@@ -207,6 +207,7 @@ struct iscsi_uevent { + } ep_connect_ret; + struct msg_req_path { + uint32_t host_no; ++ uint32_t iface_num; + } req_path; + struct msg_notify_if_down { + uint32_t host_no; +@@ -234,6 +235,8 @@ struct iscsi_path { + struct in6_addr v6_addr; + } dst; + uint16_t vlan_id; ++#define IFACE_NUM_PRESENT (1<<0) ++#define IFACE_NUM_INVALID -1 + uint16_t pmtu; + } __attribute__ ((aligned (sizeof(uint64_t)))); + +diff --git a/iscsiuio/src/apps/dhcpc/dhcpc.c b/iscsiuio/src/apps/dhcpc/dhcpc.c +index 88d75c3..afec601 100644 +--- a/iscsiuio/src/apps/dhcpc/dhcpc.c ++++ b/iscsiuio/src/apps/dhcpc/dhcpc.c +@@ -334,7 +334,7 @@ static PT_THREAD(handle_dhcp(struct uip_stack *ustack)) + (uint8_t *) s->mac_addr); + + /* Put the stack thread back into a long sleep */ +- s->nic->state |= NIC_LONG_SLEEP; ++ s->nic->flags |= NIC_LONG_SLEEP; + + /* timer_stop(&s.timer); */ + +@@ -343,7 +343,7 @@ static PT_THREAD(handle_dhcp(struct uip_stack *ustack)) + 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->state &= ~NIC_LONG_SLEEP; ++ s->nic->flags &= ~NIC_LONG_SLEEP; + PT_RESTART(&s->pt); + + /* +@@ -397,7 +397,7 @@ int dhcpc_init(nic_t * nic, struct uip_stack *ustack, + ustack->dhcpc = s; + + /* Let the RX poll value take over */ +- nic->state &= ~NIC_LONG_SLEEP; ++ nic->flags &= ~NIC_LONG_SLEEP; + + PT_INIT(&s->pt); + +diff --git a/iscsiuio/src/apps/dhcpc/dhcpv6.c b/iscsiuio/src/apps/dhcpc/dhcpv6.c +index b7ae631..273cce0 100644 +--- a/iscsiuio/src/apps/dhcpc/dhcpv6.c ++++ b/iscsiuio/src/apps/dhcpc/dhcpv6.c +@@ -86,10 +86,6 @@ int dhcpv6_do_discovery(pDHCPV6_CONTEXT dhcpv6_context) + (pIPV6_HDR) dhcpv6_context->ipv6_context->ustack->network_layer; + dhcpv6_context->udp = + (pUDP_HDR) ((u8_t *) dhcpv6_context->ipv6 + sizeof(IPV6_HDR)); +- LOG_INFO("dhcpv6: ipv6c=%p, ustack=%p eth=%p ipv6=%p udp=%p", +- dhcpv6_context->ipv6_context, +- dhcpv6_context->ipv6_context->ustack, dhcpv6_context->eth, +- dhcpv6_context->ipv6, dhcpv6_context->udp); + + /* Send out DHCPv6 Solicit packet. */ + dhcpv6_send_solicit_packet(dhcpv6_context); +@@ -176,8 +172,10 @@ STATIC u16_t dhcpv6_init_packet(pDHCPV6_CONTEXT dhcpv6_context, u8_t type) + opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_CLIENTID); + opt->hdr.length = HOST_TO_NET16(sizeof(DHCPV6_OPT_CLIENT_ID)); + opt->type.client_id.duid_type = +- HOST_TO_NET16(DHCPV6_DUID_TYPE_LINK_LAYER); ++ 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 __FAR__ *)&opt->type.client_id.link_layer_addr, + (char __FAR__ *)dhcpv6_context->our_mac_addr, sizeof(MAC_ADDR)); + pkt_len += sizeof(DHCPV6_OPT_CLIENT_ID) + sizeof(DHCPV6_OPT_HDR); +diff --git a/iscsiuio/src/apps/dhcpc/dhcpv6.h b/iscsiuio/src/apps/dhcpc/dhcpv6.h +index 917cf35..d8e03e5 100644 +--- a/iscsiuio/src/apps/dhcpc/dhcpv6.h ++++ b/iscsiuio/src/apps/dhcpc/dhcpv6.h +@@ -164,7 +164,7 @@ typedef struct DHCPV6_OPT_CLIENT_ID { + #define DHCPV6_DUID_TYPE_LINK_LAYER 3 + u16_t hw_type; + #define DHCPV6_HW_TYPE_ETHERNET 1 +-// u32_t time; ++ u32_t time; + MAC_ADDR link_layer_addr; + } DHCPV6_OPT_CLIENT_ID, *pDHCPV6_OPT_CLIENT_ID; + +diff --git a/iscsiuio/src/uip/ipv6.c b/iscsiuio/src/uip/ipv6.c +index 594495a..a8eed71 100644 +--- a/iscsiuio/src/uip/ipv6.c ++++ b/iscsiuio/src/uip/ipv6.c +@@ -38,6 +38,7 @@ + */ + #include + #include ++#include + #include "logger.h" + #include "uip.h" + #include "ipv6.h" +@@ -78,7 +79,7 @@ STATIC void ipv6_udp_rx(pIPV6_CONTEXT ipv6_context); + + int iscsiL2Send(pIPV6_CONTEXT ipv6_context, int pkt_len) + { +- LOG_DEBUG("IPV6: iscsiL2Send"); ++ LOG_DEBUG("IPv6: iscsiL2Send"); + uip_send(ipv6_context->ustack, + (void *)ipv6_context->ustack->data_link_layer, pkt_len); + +@@ -103,7 +104,8 @@ int iscsiL2AddMcAddr(pIPV6_CONTEXT ipv6_context, MAC_ADDR * new_mc_addr) + (char __FAR__ *)&all_zeroes_mc, sizeof(MAC_ADDR))) { + memcpy((char __FAR__ *)mc_addr, + (char __FAR__ *)new_mc_addr, sizeof(MAC_ADDR)); +- LOG_DEBUG("IPV6: mc_addr added %x:%x:%x:%x:%x:%x", ++ 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), +@@ -150,10 +152,11 @@ void ipv6_init(struct ndpc_state *ndp, int cfg) + ipv6_arp_table = &ipv6_context->ipv6_arp_table[0]; + ipv6_prefix_table = &ipv6_context->ipv6_prefix_table[0]; + +- memset((char __FAR__ *)ipv6_arp_table, 0, sizeof(ipv6_arp_table)); +- memset((char __FAR__ *)ipv6_prefix_table, 0, sizeof(ipv6_prefix_table)); +- memcpy((char __FAR__ *)&ipv6_context->mac_addr, +- (char __FAR__ *)mac_addr, sizeof(MAC_ADDR)); ++ memset((char __FAR__*)ipv6_arp_table, 0, sizeof(*ipv6_arp_table)); ++ memset((char __FAR__*)ipv6_prefix_table, 0, ++ sizeof(*ipv6_prefix_table)); ++ memcpy((char __FAR__*)&ipv6_context->mac_addr, ++ (char __FAR__*)mac_addr, sizeof(MAC_ADDR)); + /* + * Per RFC 2373. + * There are two types of local-use unicast addresses defined. These +@@ -167,33 +170,34 @@ void ipv6_init(struct ndpc_state *ndp, int cfg) + * |1111111010| 0 | interface ID | + * +----------+-------------------------+----------------------------+ + */ +- ipv6_context->link_local_addr.addr8[0] = 0xfe; +- ipv6_context->link_local_addr.addr8[1] = 0x80; +- /* Bit 1 is 1 to indicate universal scope. */ +- ipv6_context->link_local_addr.addr8[8] = mac_addr[0] | 0x2; +- ipv6_context->link_local_addr.addr8[9] = mac_addr[1]; +- ipv6_context->link_local_addr.addr8[10] = mac_addr[2]; +- ipv6_context->link_local_addr.addr8[11] = 0xff; +- ipv6_context->link_local_addr.addr8[12] = 0xfe; +- ipv6_context->link_local_addr.addr8[13] = mac_addr[3]; +- ipv6_context->link_local_addr.addr8[14] = mac_addr[4]; +- ipv6_context->link_local_addr.addr8[15] = mac_addr[5]; +- +- ipv6_context->link_local_multi.addr8[0] = 0xff; +- ipv6_context->link_local_multi.addr8[1] = 0x02; +- ipv6_context->link_local_multi.addr8[11] = 0x01; +- ipv6_context->link_local_multi.addr8[12] = 0xff; +- ipv6_context->link_local_multi.addr8[13] |= +- ipv6_context->link_local_addr.addr8[13]; +- ipv6_context->link_local_multi.addr16[7] = +- ipv6_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(ipv6_context, +- &ipv6_context->link_local_addr, 64); +- ++ if (ipv6_context->ustack->linklocal_autocfg != IPV6_LL_AUTOCFG_OFF) { ++ ipv6_context->link_local_addr.addr8[0] = 0xfe; ++ ipv6_context->link_local_addr.addr8[1] = 0x80; ++ /* Bit 1 is 1 to indicate universal scope. */ ++ ipv6_context->link_local_addr.addr8[8] = mac_addr[0] | 0x2; ++ ipv6_context->link_local_addr.addr8[9] = mac_addr[1]; ++ ipv6_context->link_local_addr.addr8[10] = mac_addr[2]; ++ ipv6_context->link_local_addr.addr8[11] = 0xff; ++ ipv6_context->link_local_addr.addr8[12] = 0xfe; ++ ipv6_context->link_local_addr.addr8[13] = mac_addr[3]; ++ ipv6_context->link_local_addr.addr8[14] = mac_addr[4]; ++ ipv6_context->link_local_addr.addr8[15] = mac_addr[5]; ++ ++ ipv6_context->link_local_multi.addr8[0] = 0xff; ++ ipv6_context->link_local_multi.addr8[1] = 0x02; ++ ipv6_context->link_local_multi.addr8[11] = 0x01; ++ ipv6_context->link_local_multi.addr8[12] = 0xff; ++ ipv6_context->link_local_multi.addr8[13] |= ++ ipv6_context->link_local_addr.addr8[13]; ++ ipv6_context->link_local_multi.addr16[7] = ++ ipv6_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(ipv6_context, ++ &ipv6_context->link_local_addr, 64); ++ } + /* + * Convert Multicast IP address to Multicast MAC adress per + * RFC 2464: Transmission of IPv6 Packets over Ethernet Networks +@@ -257,6 +261,7 @@ int ipv6_add_prefix_entry(pIPV6_CONTEXT ipv6_context, + int i; + pIPV6_PREFIX_ENTRY prefix_entry; + pIPV6_PREFIX_ENTRY ipv6_prefix_table = ipv6_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++) { +@@ -287,21 +292,13 @@ int ipv6_add_prefix_entry(pIPV6_CONTEXT ipv6_context, + + prefix_entry->prefix_len = prefix_len / 8; + +- memcpy((char __FAR__ *)&prefix_entry->address, +- (char __FAR__ *)ipv6_addr, sizeof(IPV6_ADDR)); +- +- +- LOG_DEBUG("IPV6: add prefix ip addr " +- "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " +- "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", +- prefix_entry->address.addr8[0], prefix_entry->address.addr8[1], +- prefix_entry->address.addr8[2], prefix_entry->address.addr8[3], +- prefix_entry->address.addr8[4], prefix_entry->address.addr8[5], +- prefix_entry->address.addr8[6], prefix_entry->address.addr8[7], +- prefix_entry->address.addr8[8], prefix_entry->address.addr8[9], +- prefix_entry->address.addr8[10], prefix_entry->address.addr8[11], +- prefix_entry->address.addr8[12], prefix_entry->address.addr8[13], +- prefix_entry->address.addr8[14], prefix_entry->address.addr8[15]); ++ memcpy((char __FAR__*)&prefix_entry->address, ++ (char __FAR__*)ipv6_addr, sizeof(IPV6_ADDR)); ++ ++ inet_ntop(AF_INET6, &prefix_entry->address.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 (ipv6_context->addr_list != NULL) { +@@ -419,7 +416,7 @@ int ipv6_discover_address(pIPV6_CONTEXT ipv6_context) + sizeof(IPV6_ADDR)); + + icmp->icmpv6_cksum = 0; +- LOG_DEBUG("IPV6: Send rtr sol"); ++ LOG_DEBUG("IPv6: Send rtr sol"); + ipv6_send(ipv6_context, (u8_t *) icmp - (u8_t *) eth + + sizeof(ICMPV6_HDR) + sizeof(ICMPV6_OPT_LINK_ADDR)); + return rc; +@@ -650,7 +647,7 @@ STATIC void ipv6_update_arp_table(pIPV6_CONTEXT ipv6_context, + int i; + pIPV6_ARP_ENTRY ipv6_arp_table = ipv6_context->ipv6_arp_table; + +- LOG_DEBUG("IPV6: ARP update"); ++ 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 +@@ -710,6 +707,7 @@ int ipv6_send_nd_solicited_packet(pIPV6_CONTEXT ipv6_context, pETH_HDR eth, + pICMPV6_HDR icmp; + int pkt_len = 0; + pIPV6_ADDR longest_match_addr; ++ char addr_str[INET6_ADDRSTRLEN]; + + ipv6->ipv6_nxt_hdr = IPPROTO_ICMPV6; + +@@ -719,7 +717,7 @@ int ipv6_send_nd_solicited_packet(pIPV6_CONTEXT ipv6_context, pETH_HDR eth, + /* Use Link-local as source address */ + if (ipv6_is_it_our_link_local_address(ipv6_context, &ipv6->ipv6_dst) == + TRUE) { +- LOG_DEBUG("IPV6: NS using link local"); ++ LOG_DEBUG("IPv6: NS using link local"); + memcpy((char __FAR__ *)&ipv6->ipv6_src, + (char __FAR__ *)&ipv6_context->link_local_addr, + sizeof(IPV6_ADDR)); +@@ -727,12 +725,12 @@ int ipv6_send_nd_solicited_packet(pIPV6_CONTEXT ipv6_context, pETH_HDR eth, + longest_match_addr = + ipv6_find_longest_match(ipv6_context, &ipv6->ipv6_dst); + if (longest_match_addr) { +- LOG_DEBUG("IPV6: NS using longest match addr"); ++ LOG_DEBUG("IPv6: NS using longest match addr"); + memcpy((char __FAR__ *)&ipv6->ipv6_src, + (char __FAR__ *)longest_match_addr, + sizeof(IPV6_ADDR)); + } else { +- LOG_DEBUG("IPV6: NS using link local instead"); ++ LOG_DEBUG("IPv6: NS using link local instead"); + memcpy((char __FAR__ *)&ipv6->ipv6_src, + (char __FAR__ *)&ipv6_context->link_local_addr, + sizeof(IPV6_ADDR)); +@@ -740,17 +738,8 @@ int ipv6_send_nd_solicited_packet(pIPV6_CONTEXT ipv6_context, pETH_HDR eth, + } + icmp = (pICMPV6_HDR) ((u8_t *) ipv6 + sizeof(IPV6_HDR)); + +- LOG_DEBUG +- ("IPV6: NS host ip addr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x" +- " %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", +- ipv6->ipv6_src.addr8[0], ipv6->ipv6_src.addr8[1], +- ipv6->ipv6_src.addr8[2], ipv6->ipv6_src.addr8[3], +- ipv6->ipv6_src.addr8[4], ipv6->ipv6_src.addr8[5], +- ipv6->ipv6_src.addr8[6], ipv6->ipv6_src.addr8[7], +- ipv6->ipv6_src.addr8[8], ipv6->ipv6_src.addr8[9], +- ipv6->ipv6_src.addr8[10], ipv6->ipv6_src.addr8[11], +- ipv6->ipv6_src.addr8[12], ipv6->ipv6_src.addr8[13], +- ipv6->ipv6_src.addr8[14], ipv6->ipv6_src.addr8[15]); ++ 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. +@@ -839,6 +828,7 @@ STATIC void ipv6_icmp_handle_router_adv(pIPV6_CONTEXT ipv6_context) + pICMPV6_OPT_HDR icmp_opt; + u16_t opt_len; + u16_t len; ++ char addr_str[INET6_ADDRSTRLEN]; + + if (ipv6_context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED) + return; +@@ -868,7 +858,7 @@ STATIC void ipv6_icmp_handle_router_adv(pIPV6_CONTEXT ipv6_context) + } + + if (ipv6_context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED) { +- LOG_DEBUG("IPV6: RTR ADV nd_ra_flags=0x%x", ++ LOG_DEBUG("IPv6: RTR ADV nd_ra_flags = 0x%x", + icmp->nd_ra_flags_reserved); + if (icmp->nd_ra_curhoplimit > 0) + ipv6_context->hop_limit = icmp->nd_ra_curhoplimit; +@@ -880,21 +870,17 @@ STATIC void ipv6_icmp_handle_router_adv(pIPV6_CONTEXT ipv6_context) + ipv6_context->flags |= IPV6_FLAGS_OTHER_STATEFUL_CONFIG; + + if (icmp->nd_ra_router_lifetime != 0) { +- /* This is a default router. */ +- memcpy((char __FAR__ *)&ipv6_context->default_router, +- (char __FAR__ *)&ipv6->ipv6_src, +- sizeof(IPV6_ADDR)); +- LOG_DEBUG("IPV6: def router " +- "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " +- "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", +- ipv6->ipv6_src.addr8[0], ipv6->ipv6_src.addr8[1], +- ipv6->ipv6_src.addr8[2], ipv6->ipv6_src.addr8[3], +- ipv6->ipv6_src.addr8[4], ipv6->ipv6_src.addr8[5], +- ipv6->ipv6_src.addr8[6], ipv6->ipv6_src.addr8[7], +- ipv6->ipv6_src.addr8[8], ipv6->ipv6_src.addr8[9], +- ipv6->ipv6_src.addr8[10], ipv6->ipv6_src.addr8[11], +- ipv6->ipv6_src.addr8[12], ipv6->ipv6_src.addr8[13], +- ipv6->ipv6_src.addr8[14], ipv6->ipv6_src.addr8[15]); ++ /* There is a default router. */ ++ if (ipv6_context->ustack->router_autocfg != ++ IPV6_RTR_AUTOCFG_OFF) ++ memcpy( ++ (char __FAR__*)&ipv6_context->default_router, ++ (char __FAR__*)&ipv6->ipv6_src, ++ sizeof(IPV6_ADDR)); ++ inet_ntop(AF_INET6, &ipv6_context->default_router, ++ addr_str, sizeof(addr_str)); ++ LOG_DEBUG("IPV6: Got default router IP addr: %s", ++ addr_str); + } + } + } +@@ -903,6 +889,7 @@ STATIC void ipv6_icmp_process_prefix(pIPV6_CONTEXT ipv6_context, + pICMPV6_OPT_PREFIX icmp_prefix) + { + 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)) +@@ -917,6 +904,8 @@ STATIC void ipv6_icmp_process_prefix(pIPV6_CONTEXT ipv6_context, + (char __FAR__ *)&icmp_prefix->prefix, 8); + memcpy((char __FAR__ *)&addr.addr8[8], + &ipv6_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(ipv6_context, &addr, 64); + } + } +@@ -929,11 +918,12 @@ STATIC void ipv6_icmp_handle_nd_adv(pIPV6_CONTEXT ipv6_context) + pICMPV6_OPT_LINK_ADDR link_opt = (pICMPV6_OPT_LINK_ADDR)((u8_t *)icmp + + sizeof(ICMPV6_HDR) + sizeof(IPV6_ADDR)); + pIPV6_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"); ++ LOG_DEBUG("IPv6: Handle nd adv"); + if ((ipv6_is_it_our_address(ipv6_context, &ipv6->ipv6_dst) == TRUE) || + (memcmp((char __FAR__ *)&ipv6_context->link_local_multi, + (char __FAR__ *)&ipv6->ipv6_dst, sizeof(IPV6_ADDR)) == 0) || +@@ -951,21 +941,14 @@ STATIC void ipv6_icmp_handle_nd_adv(pIPV6_CONTEXT ipv6_context) + if (link_opt->hdr.type == IPV6_ICMP_OPTION_TAR_ADDR) { + tar_addr6 = (pIPV6_ADDR)((u8_t *)icmp + + sizeof(ICMPV6_HDR)); +- LOG_DEBUG("IPV6: tar mac %x:%x:%x:%x:%x:%x", ++ 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]); +- LOG_DEBUG("IPV6: tar addr " +- "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " +- "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", +- tar_addr6->addr8[0], tar_addr6->addr8[1], +- tar_addr6->addr8[2], tar_addr6->addr8[3], +- tar_addr6->addr8[4], tar_addr6->addr8[5], +- tar_addr6->addr8[6], tar_addr6->addr8[7], +- tar_addr6->addr8[8], tar_addr6->addr8[9], +- tar_addr6->addr8[10], tar_addr6->addr8[11], +- tar_addr6->addr8[12], tar_addr6->addr8[13], +- tar_addr6->addr8[14], tar_addr6->addr8[15]); ++ 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(ipv6_context, tar_addr6, + (MAC_ADDR *)link_opt->link_addr); + } +@@ -985,14 +968,15 @@ STATIC void ipv6_icmp_handle_nd_sol(pIPV6_CONTEXT ipv6_context) + pIPV6_ADDR longest_match_addr; + pIPV6_ADDR tar_addr6; + +- LOG_DEBUG("IPV6: Handle nd sol"); ++ LOG_DEBUG("IPv6: Handle nd sol"); + + if ((memcmp((char __FAR__ *)&ipv6_context->mac_addr, + (char __FAR__ *)eth->dest_mac, sizeof(MAC_ADDR)) != 0) && + (iscsiL2IsOurMcAddr(ipv6_context, (pMAC_ADDRESS) & eth->dest_mac) == + FALSE)) { + /* This packet is not for us to handle */ +- LOG_DEBUG("IPV6: MAC not addressed to us %x:%x:%x:%x:%x:%x", ++ LOG_DEBUG("IPv6: MAC not addressed to us " ++ "%02x:%02x:%02x:%02x:%02x:%02x", + eth->dest_mac[0], eth->dest_mac[1], + eth->dest_mac[2], eth->dest_mac[3], + eth->dest_mac[4], eth->dest_mac[5]); +@@ -1005,7 +989,7 @@ STATIC void ipv6_icmp_handle_nd_sol(pIPV6_CONTEXT ipv6_context) + sizeof(ICMPV6_HDR))) + == FALSE) { + /* This packet is not for us to handle */ +- LOG_DEBUG("IPV6: IP not addressed to us"); ++ LOG_DEBUG("IPv6: IP not addressed to us"); + return; + } + +@@ -1026,7 +1010,7 @@ STATIC void ipv6_icmp_handle_nd_sol(pIPV6_CONTEXT ipv6_context) + tar_addr6 = (pIPV6_ADDR)((u8_t *)icmp + sizeof(ICMPV6_HDR)); + if (ipv6_is_it_our_link_local_address(ipv6_context, tar_addr6) + == TRUE) { +- LOG_DEBUG("IPV6: NA using link local"); ++ LOG_DEBUG("IPv6: NA using link local"); + memcpy((char __FAR__ *)&ipv6->ipv6_src, + (char __FAR__ *)&ipv6_context->link_local_addr, + sizeof(IPV6_ADDR)); +@@ -1034,12 +1018,12 @@ STATIC void ipv6_icmp_handle_nd_sol(pIPV6_CONTEXT ipv6_context) + longest_match_addr = + ipv6_find_longest_match(ipv6_context, tar_addr6); + if (longest_match_addr) { +- LOG_DEBUG("IPV6: NA using longest match addr"); ++ LOG_DEBUG("IPv6: NA using longest match addr"); + memcpy((char __FAR__ *)&ipv6->ipv6_src, + (char __FAR__ *)longest_match_addr, + sizeof(IPV6_ADDR)); + } else { +- LOG_DEBUG("IPV6: NA using link local instead"); ++ LOG_DEBUG("IPv6: NA using link local instead"); + memcpy((char __FAR__ *)&ipv6->ipv6_src, + (char __FAR__ *)&ipv6_context->link_local_addr, + sizeof(IPV6_ADDR)); +@@ -1047,7 +1031,7 @@ STATIC void ipv6_icmp_handle_nd_sol(pIPV6_CONTEXT ipv6_context) + } + } else { + /* No target link address, just use whatever it sent to us */ +- LOG_DEBUG("IPV6: NA use dst addr"); ++ LOG_DEBUG("IPv6: NA use dst addr"); + memcpy((char __FAR__ *)&ipv6->ipv6_src, + (char __FAR__ *)&tmp, + sizeof(IPV6_ADDR)); +@@ -1085,7 +1069,7 @@ STATIC void ipv6_icmp_handle_nd_sol(pIPV6_CONTEXT ipv6_context) + */ + ipv6->ipv6_plen = HOST_TO_NET16((sizeof(ICMPV6_HDR) + + icmpv6_opt_len + sizeof(IPV6_ADDR))); +- LOG_DEBUG("IPV6: Send nd adv"); ++ LOG_DEBUG("IPv6: Send nd adv"); + ipv6_send(ipv6_context, + (u8_t *) icmp - (u8_t *) eth + + sizeof(ICMPV6_HDR) + +@@ -1118,7 +1102,7 @@ STATIC void ipv6_icmp_handle_echo_request(pIPV6_CONTEXT ipv6_context) + icmp->icmpv6_type = ICMPV6_ECHO_REPLY; + icmp->icmpv6_code = 0; + icmp->icmpv6_cksum = 0; +- LOG_DEBUG("IPV6: Send echo reply"); ++ LOG_DEBUG("IPv6: Send echo reply"); + ipv6_send(ipv6_context, (u8_t *) icmp - (u8_t *) eth + + sizeof(IPV6_HDR) + HOST_TO_NET16(ipv6->ipv6_plen)); + return; +@@ -1126,7 +1110,8 @@ STATIC void ipv6_icmp_handle_echo_request(pIPV6_CONTEXT ipv6_context) + + void ipv6_set_ip_params(pIPV6_CONTEXT ipv6_context, + pIPV6_ADDR src_ip, u8_t prefix_len, +- pIPV6_ADDR default_gateway) ++ pIPV6_ADDR default_gateway, ++ pIPV6_ADDR linklocal) + { + if (!(IPV6_IS_ADDR_UNSPECIFIED(src_ip))) { + ipv6_add_prefix_entry(ipv6_context, src_ip, prefix_len); +@@ -1146,9 +1131,30 @@ void ipv6_set_ip_params(pIPV6_CONTEXT ipv6_context, + } + + if (!(IPV6_IS_ADDR_UNSPECIFIED(default_gateway))) { +- /* This is a default router. */ +- memcpy((char __FAR__ *)&ipv6_context->default_router, +- (char __FAR__ *)default_gateway, sizeof(IPV6_ADDR)); ++ /* Override the default gateway addr */ ++ memcpy((char __FAR__*)&ipv6_context->default_router, ++ (char __FAR__*)default_gateway, sizeof(IPV6_ADDR)); ++ ipv6_add_prefix_entry(ipv6_context, default_gateway, ++ prefix_len); ++ } ++ if (!(IPV6_IS_ADDR_UNSPECIFIED(linklocal))) { ++ /* Override the linklocal addr */ ++ memcpy((char __FAR__*)&ipv6_context->link_local_addr, ++ (char __FAR__*)linklocal, sizeof(IPV6_ADDR)); ++ ipv6_context->link_local_multi.addr8[0] = 0xff; ++ ipv6_context->link_local_multi.addr8[1] = 0x02; ++ ipv6_context->link_local_multi.addr8[11] = 0x01; ++ ipv6_context->link_local_multi.addr8[12] = 0xff; ++ ipv6_context->link_local_multi.addr8[13] |= ++ ipv6_context->link_local_addr.addr8[13]; ++ ipv6_context->link_local_multi.addr16[7] = ++ ipv6_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(ipv6_context, ++ &ipv6_context->link_local_addr, 64); + } + } + +@@ -1220,7 +1226,7 @@ u16_t ipv6_do_stateful_dhcpv6(pIPV6_CONTEXT ipv6_context, u32_t flags) + (IPV6_FLAGS_MANAGED_ADDR_CONFIG | IPV6_FLAGS_OTHER_STATEFUL_CONFIG); + + if (!(ipv6_context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED)) { +- LOG_DEBUG("IPV6: There is no IPv6 router on the network"); ++ LOG_DEBUG("IPv6: There is no IPv6 router on the network"); + ra_flags |= + (IPV6_FLAGS_MANAGED_ADDR_CONFIG | + IPV6_FLAGS_OTHER_STATEFUL_CONFIG); +@@ -1234,7 +1240,7 @@ u16_t ipv6_do_stateful_dhcpv6(pIPV6_CONTEXT ipv6_context, u32_t flags) + (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, ++ LOG_DEBUG("IPv6: Stateful flags=0x%x, ra_flags=0x%x, task=0x%x", flags, + ra_flags, task); + + return task; +diff --git a/iscsiuio/src/uip/ipv6.h b/iscsiuio/src/uip/ipv6.h +index 167f5f6..ed2f3a4 100644 +--- a/iscsiuio/src/uip/ipv6.h ++++ b/iscsiuio/src/uip/ipv6.h +@@ -343,7 +343,8 @@ int ipv6_add_prefix_entry(pIPV6_CONTEXT ipv6_context, + IPV6_ADDR * ipv6_addr, u8_t prefix_len); + void ipv6_set_ip_params(pIPV6_CONTEXT ipv6_context, + pIPV6_ADDR src_ip, u8_t prefix_len, +- pIPV6_ADDR default_gateway); ++ pIPV6_ADDR default_gateway, ++ pIPV6_ADDR linklocal); + void ipv6_set_host_addr(pIPV6_CONTEXT ipv6_context, pIPV6_ADDR src_ip); + int ipv6_get_default_router_ip_addrs(pIPV6_CONTEXT ipv6_context, + pIPV6_ADDR ip_addr); +diff --git a/iscsiuio/src/uip/ipv6_ndpc.c b/iscsiuio/src/uip/ipv6_ndpc.c +index 6d101ce..89dbd5e 100644 +--- a/iscsiuio/src/uip/ipv6_ndpc.c ++++ b/iscsiuio/src/uip/ipv6_ndpc.c +@@ -65,6 +65,7 @@ static PT_THREAD(handle_ndp(struct uip_stack *ustack, int force)) + pIPV6_CONTEXT ipv6c; + pDHCPV6_CONTEXT dhcpv6c = NULL; + u16_t task = 0; ++ char buf[INET6_ADDRSTRLEN]; + + s = ustack->ndpc; + if (s == NULL) { +@@ -86,6 +87,9 @@ static PT_THREAD(handle_ndp(struct uip_stack *ustack, int force)) + 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; +@@ -97,7 +101,7 @@ static PT_THREAD(handle_ndp(struct uip_stack *ustack, int force)) + ipv6_autoconfig(s->ipv6_context); + + timer_set(&s->timer, s->ticks); +- wait_rtr: ++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); +@@ -134,10 +138,12 @@ no_rtr_adv: + s->state = NDPC_STATE_RTR_ADV; + + rtr_adv: +- /* Both Static IPv6 and DHCPv6 comes here */ ++ 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 && (ustack->ip_config == IPV6_CONFIG_DHCP)) { ++ if (task) { + /* Run the DHCPv6 engine */ + + if (!dhcpv6c) +@@ -187,6 +193,7 @@ wait_dhcp: + } + } 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 */ +@@ -197,28 +204,25 @@ wait_dhcp: + s->nic->log_name); + PT_RESTART(&s->pt); + } +- IPV6_ADDR tmp, tmp2; +- char buf[INET6_ADDRSTRLEN]; +- ++staticv6: + ipv6_disable_dhcpv6(ipv6c); +- memcpy(&tmp.addr8, &ustack->hostaddr6, sizeof(IPV6_ADDR)); +- LOG_DEBUG("%s: host ip addr %02x:%02x:%02x:%02x:%02x:%02x:" +- "%02x:%02x", s->nic->log_name, +- ustack->hostaddr6[0], ustack->hostaddr6[1], +- ustack->hostaddr6[2], ustack->hostaddr6[3], +- ustack->hostaddr6[4], ustack->hostaddr6[5], +- ustack->hostaddr6[6], ustack->hostaddr6[7]); +- memset(&tmp2, 0, sizeof(tmp2)); +- ipv6_set_ip_params(ipv6c, &tmp, +- ustack->prefix_len, &tmp2); +- +- ipv6_add_solit_node_address(ipv6c, &tmp); +- +- inet_ntop(AF_INET6, &tmp.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(&ustack->default_route_addr6, ++ &ipv6c->default_router, sizeof(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(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; +@@ -249,6 +253,8 @@ int ndpc_init(nic_t * nic, struct uip_stack *ustack, + pIPV6_CONTEXT ipv6c; + pDHCPV6_CONTEXT dhcpv6c; + struct ndpc_state *s = ustack->ndpc; ++ IPV6_ADDR src, gw, ll; ++ char buf[INET6_ADDRSTRLEN]; + + if (s) { + LOG_DEBUG("NDP: NDP context already allocated"); +@@ -315,9 +321,30 @@ init2: + + if (ustack->ip_config == IPV6_CONFIG_DHCP) { + /* DHCPv6 specific */ ++ memset(&src, 0, sizeof(src)); + } else { + /* Static v6 specific */ ++ memcpy(&src.addr8, &ustack->hostaddr6, sizeof(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(IPV6_ADDR)); ++ else ++ memset(&gw, 0, sizeof(gw)); ++ ++ if (ustack->linklocal_autocfg == IPV6_LL_AUTOCFG_OFF) ++ memcpy(&ll.addr8, &ustack->linklocal6, ++ sizeof(IPV6_ADDR)); ++ else ++ memset(&ll, 0, sizeof(ll)); ++ ipv6_set_ip_params(ipv6c, &src, ++ ustack->prefix_len, &gw, &ll); + + return 0; + error2: +@@ -367,16 +394,14 @@ int ndpc_request(struct uip_stack *ustack, void *in, void *out, int request) + //LOG_DEBUG("%s: NDP - Request %d", s->nic->log_name, request); + + while (s->state != NDPC_STATE_BACKGROUND_LOOP) { +- LOG_DEBUG("%s: ndpc state not in background loop, run handler", +- s->nic->log_name); ++ 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: +- LOG_DEBUG("nd sol: in=%p in->eth=%p in->ipv6=%p", in, in, +- (u8_t *) in + 4); + *(int *)out = ipv6_send_nd_solicited_packet(ipv6c, + (pETH_HDR) ((pNDPC_REQPTR)in)->eth, + (pIPV6_HDR) ((pNDPC_REQPTR)in)->ipv6); +@@ -385,12 +410,6 @@ int ndpc_request(struct uip_stack *ustack, void *in, void *out, int request) + *(int *)out = ipv6_is_it_our_link_local_address(ipv6c, + (pIPV6_ADDR)in); + break; +- case GET_LINK_LOCAL_ADDR: +- *(pIPV6_ADDR *) out = &ipv6c->link_local_addr; +- break; +- case GET_DEFAULT_ROUTER_ADDR: +- *(pIPV6_ADDR *)out = &ipv6c->default_router; +- break; + case CHECK_ARP_TABLE: + *(int *)out = ipv6_ip_in_arp_table(ipv6c, + (pIPV6_ADDR) ((pNDPC_REQPTR)in)->ipv6, +@@ -399,7 +418,9 @@ int ndpc_request(struct uip_stack *ustack, void *in, void *out, int request) + case GET_HOST_ADDR: + *(pIPV6_ADDR *)out = ipv6_find_longest_match(ipv6c, + (pIPV6_ADDR)in); ++ break; + default: ++ ret = -EINVAL; + break; + } + return ret; +diff --git a/iscsiuio/src/uip/uip.c b/iscsiuio/src/uip/uip.c +index 9c79e07..d03b92e 100644 +--- a/iscsiuio/src/uip/uip.c ++++ b/iscsiuio/src/uip/uip.c +@@ -1403,8 +1403,6 @@ void uip_process(struct uip_stack *ustack, u8_t flag) + #endif /* UIP_UDP */ + + /* This is IPv6 ICMPv6 processing code. */ +- LOG_DEBUG(PFX "icmp6_input: length %d", ustack->uip_len); +- + if (ipv6_hdr->ip6_nxt != UIP_PROTO_ICMP6) { + /* We only allow ICMPv6 packets from here. */ + ++ustack->stats.ip.drop; +@@ -2344,7 +2342,7 @@ tcp_send: + uip_ip6addr_copy(IPv6_BUF(ustack)->srcipaddr, + ustack->hostaddr6); + uip_ip6addr_copy(IPv6_BUF(ustack)->destipaddr, +- uip_connr->ripaddr); ++ uip_connr->ripaddr6); + } else { + tcp_ipv4_hdr->proto = UIP_PROTO_TCP; + uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr); +diff --git a/iscsiuio/src/uip/uip.h b/iscsiuio/src/uip/uip.h +index 2b5f88c..ccac680 100644 +--- a/iscsiuio/src/uip/uip.h ++++ b/iscsiuio/src/uip/uip.h +@@ -1031,6 +1031,7 @@ extern u16_t uip_urglen, uip_surglen; + */ + 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. */ +@@ -1564,6 +1565,7 @@ struct uip_stack { + 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 +@@ -1573,8 +1575,24 @@ struct uip_stack { + u8_t ip_config; + + uip_ip4addr_t hostaddr, netmask, default_route_addr; +- uip_ip6addr_t hostaddr6, netmask6, default_route_addr6; ++ 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]; +@@ -1586,7 +1604,6 @@ struct uip_stack { + pthread_mutex_t lock; + + /* IPv6 support */ +- + #define UIP_SUPPORT_IPv6_ENABLED 0x01 + #define UIP_SUPPORT_IPv6_DISABLED 0x02 + u8_t enable_IPv6; +diff --git a/iscsiuio/src/uip/uip_arp.c b/iscsiuio/src/uip/uip_arp.c +index 321281c..3ef3b07 100644 +--- a/iscsiuio/src/uip/uip_arp.c ++++ b/iscsiuio/src/uip/uip_arp.c +@@ -265,10 +265,14 @@ uip_arp_arpin(nic_interface_t * nic_iface, + arp->sipaddr[0] = ustack->hostaddr[0]; + arp->sipaddr[1] = ustack->hostaddr[1]; + +- if (nic_iface->vlan_id == 0) ++ if (nic_iface->vlan_id == 0) { + eth->type = htons(UIP_ETHTYPE_ARP); +- else ++ 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); ++ } + pkt->buf_size = sizeof(*arp) + sizeof(*eth); + } + break; +diff --git a/iscsiuio/src/unix/iscsid_ipc.c b/iscsiuio/src/unix/iscsid_ipc.c +index 6bc5c11..d7372fc 100644 +--- a/iscsiuio/src/unix/iscsid_ipc.c ++++ b/iscsiuio/src/unix/iscsid_ipc.c +@@ -70,20 +70,34 @@ struct iscsid_options { + pthread_t thread; + }; + +-struct ip_addr_mask { +- int ip_type; +- union { +- struct in_addr addr4; +- struct in6_addr addr6; +- } addr; +- union { +- struct in_addr nm4; +- struct in6_addr nm6; +- } netmask; +-#define addr4 addr.addr4 +-#define addr6 addr.addr6 +-#define nm4 netmask.nm4 +-#define nm6 netmask.nm6 ++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; + }; + + /****************************************************************************** +@@ -119,8 +133,7 @@ static void *enable_nic_thread(void *data) + pthread_exit(NULL); + } + +-static int decode_cidr(char *in_ipaddr_str, struct ip_addr_mask *ipam, +- int *prefix_len) ++static int decode_cidr(char *in_ipaddr_str, struct iface_rec_decode *ird) + { + int rc = 0, i; + char *tmp, *tok; +@@ -130,7 +143,6 @@ static int decode_cidr(char *in_ipaddr_str, struct ip_addr_mask *ipam, + struct in_addr ia; + struct in6_addr ia6; + +- memset(ipam, 0, sizeof(struct ip_addr_mask)); + if (strlen(in_ipaddr_str) > NI_MAXHOST) + strncpy(ipaddr_str, in_ipaddr_str, NI_MAXHOST); + else +@@ -149,16 +161,16 @@ static int decode_cidr(char *in_ipaddr_str, struct ip_addr_mask *ipam, + + /* Determine if the IP address passed from the iface file is + * an IPv4 or IPv6 address */ +- rc = inet_pton(AF_INET, ipaddr_str, &ipam->addr6); ++ 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, &ipam->addr6); ++ 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; + } +- ipam->ip_type = AF_INET6; ++ ird->ip_type = AF_INET6; + if (keepbits > 128) { + LOG_ERR(PFX "CIDR netmask > 128 for IPv6: %d(%s)", + keepbits, tmp); +@@ -166,15 +178,15 @@ static int decode_cidr(char *in_ipaddr_str, struct ip_addr_mask *ipam, + } + if (!keepbits) { + /* Default prefix mask to 64 */ +- memcpy(&ipam->nm6.s6_addr, all_zeroes_addr6, ++ memcpy(&ird->ipv6_subnet_mask.s6_addr, all_zeroes_addr6, + sizeof(struct in6_addr)); ++ ird->prefix_len = 64; + for (i = 0; i < 2; i++) +- ipam->nm6.s6_addr32[i] = 0xffffffff; ++ ird->ipv6_subnet_mask.s6_addr32[i] = 0xffffffff; + goto out; + } +- *prefix_len = keepbits; +- memcpy(&ia6.s6_addr, all_zeroes_addr6, +- sizeof(struct in6_addr)); ++ 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 ? +@@ -184,12 +196,12 @@ static int decode_cidr(char *in_ipaddr_str, struct ip_addr_mask *ipam, + ia6.s6_addr32[i] = 0xFFFFFFFF; + keepbits -= 32; + } +- ipam->nm6 = ia6; ++ ird->ipv6_subnet_mask = ia6; + if (inet_ntop(AF_INET6, &ia6, str, sizeof(str))) + LOG_INFO(PFX "Using netmask: %s", str); + } else { +- ipam->ip_type = AF_INET; +- rc = inet_pton(AF_INET, ipaddr_str, &ipam->addr4); ++ 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)", +@@ -197,54 +209,153 @@ static int decode_cidr(char *in_ipaddr_str, struct ip_addr_mask *ipam, + goto out; + } + ia.s_addr = keepbits > 0 ? 0x00 - (1 << (32 - keepbits)) : 0; +- ipam->nm4.s_addr = htonl(ia.s_addr); +- LOG_INFO(PFX "Using netmask: %s", inet_ntoa(ipam->nm4)); ++ 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_INET, 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; ++ int rc, i; + nic_t *nic = NULL; +- nic_interface_t *nic_iface, *vlan_iface, *base_nic_iface; ++ nic_interface_t *nic_iface; + char *transport_name; + size_t transport_name_size; + nic_lib_handle_t *handle; + iscsid_uip_broadcast_t *data; +- short int vlan; + char ipv6_buf_str[INET6_ADDRSTRLEN]; + int request_type = 0; +- struct in_addr netmask; +- int i, prefix_len = 64; +- struct ip_addr_mask ipam; + struct iface_rec *rec; + void *res; ++ struct iface_rec_decode ird; ++ struct in_addr src_match, dst_match; + + 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); +- +- vlan = rec->vlan_id; +- if (vlan && valid_vlan(vlan) == 0) { +- LOG_ERR(PFX "Invalid VLAN tag: %d", rec->vlan_id); ++ "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; + } +- +- /* Detect for CIDR notation and strip off the netmask if present */ +- rc = decode_cidr(rec->ipaddress, &ipam, &prefix_len); +- if (rc && !ipam.ip_type) { +- LOG_ERR(PFX "decode_cidr: rc=%d, ipam.ip_type=%d", +- rc, ipam.ip_type) +- goto early_exit; +- } +- if (ipam.ip_type == AF_INET6) +- inet_ntop(AF_INET6, &ipam.addr6, ipv6_buf_str, +- sizeof(ipv6_buf_str)); ++ 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; +@@ -258,11 +369,13 @@ static int parse_iface(void *arg) + } + + if (i >= 10) { +- LOG_WARN(PFX "Could not aquire nic_list_mutex lock"); ++ 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); +@@ -298,21 +411,22 @@ static int parse_iface(void *arg) + 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 to timeout */ ++ /* If we retry too many times allow iscsid to timeout */ + if (nic->pending_count > 1000) { +- LOG_WARN(PFX "%s: pending count excceded 1000", nic->log_name); +- +- pthread_mutex_lock(&nic->nic_mutex); + 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; + } +@@ -320,18 +434,19 @@ static int parse_iface(void *arg) + 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); + +- pthread_mutex_lock(&nic->nic_mutex); +- nic->pending_count++; +- pthread_mutex_unlock(&nic->nic_mutex); +- + LOG_INFO(PFX "%s: enabled pending", nic->log_name); ++ + rc = -EAGAIN; + goto done; + } ++ pthread_mutex_unlock(&nic->nic_mutex); + + prepare_library(nic); + +@@ -359,66 +474,9 @@ static int parse_iface(void *arg) + LOG_INFO(PFX "%s library set using transport_name %s", + nic->log_name, transport_name); + +- /* Create the base network interface if it doesn't exist */ +- nic_iface = nic_find_nic_iface_protocol(nic, 0, ipam.ip_type); +- if (nic_iface == NULL) { +- LOG_INFO(PFX "%s couldn't find interface with " +- "ip_type: 0x%x creating it", +- nic->log_name, ipam.ip_type); +- +- /* Create the nic interface */ +- nic_iface = nic_iface_init(); +- +- if (nic_iface == NULL) { +- LOG_ERR(PFX "Couldn't allocate nic_iface", nic_iface); +- goto done; +- } +- +- nic_iface->protocol = ipam.ip_type; +- nic_add_nic_iface(nic, nic_iface); +- +- persist_all_nic_iface(nic); +- +- LOG_INFO(PFX "%s: created network interface", nic->log_name); +- } else { +- LOG_INFO(PFX "%s: using existing network interface", +- nic->log_name); +- } +- +- set_nic_iface(nic, nic_iface); +- +- /* Find the vlan nic_interface */ +- if (vlan) { +- vlan_iface = nic_find_vlan_iface_protocol(nic, nic_iface, vlan, +- ipam.ip_type); +- if (vlan_iface == NULL) { +- LOG_INFO(PFX "%s couldn't find interface with VLAN = %d" +- "ip_type: 0x%x creating it", +- nic->log_name, vlan, ipam.ip_type); +- +- /* Create the nic interface */ +- vlan_iface = nic_iface_init(); +- +- if (vlan_iface == NULL) { +- LOG_ERR(PFX "Couldn't allocate nic_iface for " +- "VLAN: %d", vlan_iface, vlan); +- goto done; +- } +- +- vlan_iface->protocol = ipam.ip_type; +- vlan_iface->vlan_id = vlan; +- nic_add_vlan_iface(nic, nic_iface, vlan_iface); +- } else { +- LOG_INFO(PFX "%s: using existing vlan interface", +- nic->log_name); +- } +- base_nic_iface = nic_iface; +- nic_iface = vlan_iface; +- } +- + /* Determine how to configure the IP address */ +- if (ipam.ip_type == AF_INET) { +- if (memcmp(&ipam.addr4, ++ 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); +@@ -428,51 +486,161 @@ static int parse_iface(void *arg) + "static IP address", nic->log_name); + request_type = IPV4_CONFIG_STATIC; + } +- } else if (ipam.ip_type == AF_INET6) { +- if (memcmp(&ipam.addr6, +- all_zeroes_addr6, sizeof(uip_ip6addr_t)) == 0) { +- LOG_INFO(PFX +- "%s: requesting configuration using DHCPv6", +- nic->log_name); ++ } 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; +- } else { +- LOG_INFO(PFX "%s: request configuration using static " +- "IPv6 address: '%s'", +- nic->log_name, ipv6_buf_str); ++ 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, ipam.ip_type); ++ 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) { ++ rc = pthread_create(&nic->nl_process_thread, NULL, ++ nl_process_handle_thread, nic); ++ if (rc != 0) { ++ LOG_ERR(PFX "%s: Could not create NIC NL " ++ "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, &ipam.addr4, ++ if (memcmp(nic_iface->ustack.hostaddr, &ird.ipv4_addr, + sizeof(struct in_addr))) +- goto diff; ++ goto reacquire; + } else if (request_type == IPV6_CONFIG_STATIC) { +- if (memcmp(nic_iface->ustack.hostaddr6, &ipam.addr6, ++ if (memcmp(nic_iface->ustack.hostaddr6, &ird.ipv6_addr, + sizeof(struct in6_addr))) +- goto diff; ++ 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); +- goto enable_nic; +-diff: +- /* Disable the NIC */ +- nic_disable(nic, 0); +- } else { +- if (request_type == IPV4_CONFIG_DHCP +- || request_type == IPV6_CONFIG_DHCP) +- nic->flags |= NIC_RESET_UIP; ++ /* No need to acquire the IP address */ ++ inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str, ++ sizeof(ipv6_buf_str)); + +- /* Disable the NIC */ +- nic_disable(nic, 0); ++ 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 +@@ -485,97 +653,96 @@ diff: + 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, &ipam.addr4, ++ 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(ipam.addr4)); +- netmask.s_addr = ipam.nm4.s_addr; +- if (!netmask.s_addr) +- netmask.s_addr = +- calculate_default_netmask(ipam.addr4.s_addr); +- memcpy(nic_iface->ustack.netmask, +- &netmask, sizeof(netmask.s_addr)); +- LOG_INFO(PFX " netmask :%s", inet_ntoa(netmask)); +- ++ 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 = prefix_len; +- if (ipam.nm6.s6_addr[0] | ipam.nm6.s6_addr[1] | +- ipam.nm6.s6_addr[2] | ipam.nm6.s6_addr[3] | +- ipam.nm6.s6_addr[4] | ipam.nm6.s6_addr[5] | +- ipam.nm6.s6_addr[6] | ipam.nm6.s6_addr[7]) ++ 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, +- &ipam.nm6, sizeof(struct in6_addr)); ++ &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, &ipam.addr6, ++ 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; + +- nic_iface->ustack.prefix_len = prefix_len; +- if (ipam.nm6.s6_addr[0] | ipam.nm6.s6_addr[1] | +- ipam.nm6.s6_addr[2] | ipam.nm6.s6_addr[3] | +- ipam.nm6.s6_addr[4] | ipam.nm6.s6_addr[5] | +- ipam.nm6.s6_addr[6] | ipam.nm6.s6_addr[7]) ++ if (memcmp(&ird.ipv6_subnet_mask, all_zeroes_addr6, ++ sizeof(struct in6_addr))) + memcpy(nic_iface->ustack.netmask6, +- &ipam.nm6, sizeof(struct in6_addr)); +- ++ &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); + + } + +- /* Configuration changed, do VLAN WA */ +- vlan_iface = nic_iface->vlan_next; +- while (vlan_iface) { +- /* TODO: When VLAN support is placed in the iface file +- * revisit this code */ +- if (vlan_iface->ustack.ip_config) { +- 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.hostaddr6, +- nic_iface->ustack.hostaddr6, +- sizeof(nic_iface->ustack.hostaddr6)); +- memcpy(vlan_iface->ustack.netmask6, +- nic_iface->ustack.netmask6, +- sizeof(nic_iface->ustack.netmask6)); +- } +- vlan_iface = vlan_iface->vlan_next; +- } +- + enable_nic: +- if (nic->state & NIC_STOPPED) { +- pthread_mutex_lock(&nic->nic_mutex); +- if (nic->flags & NIC_ENABLED_PENDING) { +- /* Still waiting */ +- pthread_mutex_unlock(&nic->nic_mutex); +- rc = 0; +- goto enable_out; +- } +- nic->flags |= NIC_ENABLED_PENDING; +- pthread_mutex_unlock(&nic->nic_mutex); +- ++ switch (nic->state) { ++ case NIC_STOPPED: + /* This thread will be thrown away when completed */ + if (nic->enable_thread != INVALID_THREAD) { + rc = pthread_join(nic->enable_thread, &res); +@@ -592,19 +759,27 @@ enable_nic: + nic->log_name); + eagain: + rc = -EAGAIN; +- } else { ++ 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; + } +-enable_out: ++ + 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, +- (ipam.ip_type == AF_INET) ? inet_ntoa(ipam.addr4) : ++ (ird.ip_type == AF_INET) ? inet_ntoa(ird.ipv4_addr) : + ipv6_buf_str, +- vlan, rec->transport_name); ++ ird.vlan_id, rec->transport_name); + + done: + pthread_mutex_unlock(&nic_list_mutex); +@@ -638,12 +813,13 @@ int process_iscsid_broadcast(int s2) + data = (iscsid_uip_broadcast_t *) calloc(1, sizeof(*data)); + if (data == NULL) { + LOG_ERR(PFX "Couldn't allocate memory for iface data"); +- return -ENOMEM; ++ rc = -ENOMEM; ++ goto error; + } + memset(data, 0, sizeof(*data)); + + size = fread(data, sizeof(iscsid_uip_broadcast_header_t), 1, fd); +- if (size == -1) { ++ if (!size) { + LOG_ERR(PFX "Could not read request: %d(%s)", + errno, strerror(errno)); + rc = ferror(fd); +@@ -657,7 +833,7 @@ int process_iscsid_broadcast(int s2) + cmd, payload_len); + + size = fread(&data->u.iface_rec, payload_len, 1, fd); +- if (size == -1) { ++ if (!size) { + LOG_ERR(PFX "Could not read data: %d(%s)", + errno, strerror(errno)); + goto error; +diff --git a/iscsiuio/src/unix/libs/bnx2.c b/iscsiuio/src/unix/libs/bnx2.c +index 112d570..a8300c2 100644 +--- a/iscsiuio/src/unix/libs/bnx2.c ++++ b/iscsiuio/src/unix/libs/bnx2.c +@@ -295,7 +295,7 @@ static int bnx2_uio_verify(nic_t * nic) + + LOG_INFO(PFX "%s: Verified is a cnic_uio device", nic->log_name); + +- error: ++error: + return rc; + } + +@@ -395,7 +395,7 @@ static void bnx2_free(nic_t *nic) + /** + * bnx2_alloc() - Used to allocate a bnx2 structure + */ +-static bnx2_t *bnx2_alloc(nic_t * nic) ++static bnx2_t *bnx2_alloc(nic_t *nic) + { + bnx2_t *bp = malloc(sizeof(*bp)); + if (bp == NULL) { +@@ -468,12 +468,14 @@ static int bnx2_open(nic_t * nic) + 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); +- rc = -ENODEV; ++ errno = -ENODEV; + goto error_alloc_rx_ring; + } + nic->uio_minor = minor(uio_stat.st_rdev); +@@ -483,7 +485,7 @@ static int bnx2_open(nic_t * nic) + if (bp->bar0_fd < 0) { + LOG_ERR(PFX "%s: Could not open %s", nic->log_name, + sysfs_resc_path); +- rc = -ENODEV; ++ errno = -ENODEV; + goto error_alloc_rx_ring; + } + +@@ -506,6 +508,7 @@ static int bnx2_open(nic_t * nic) + 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); +@@ -515,6 +518,7 @@ static int bnx2_open(nic_t * nic) + 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); +@@ -677,9 +681,10 @@ static int bnx2_open(nic_t * nic) + bnx2_wr32(bp, BNX2_RPM_SORT_USER2, val | BNX2_RPM_SORT_USER2_ENA); + + rc = enable_multicast(nic); +- if (rc != 0) ++ if (rc != 0) { ++ errno = rc; + goto error_bufs; +- ++ } + msync(bp->reg, 0x12800, MS_SYNC); + LOG_INFO("%s: bnx2 uio initialized", nic->log_name); + +@@ -707,6 +712,10 @@ error_alloc_rx_pkt_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; +@@ -878,8 +887,8 @@ void bnx2_start_xmit(nic_t * nic, size_t len, u16_t vlan_id) + rxbd = (struct rx_bd *)(((__u8 *) bp->tx_ring) + getpagesize()); + + if ((rxbd->rx_bd_haddr_hi == 0) && (rxbd->rx_bd_haddr_lo == 0)) { +- LOG_DEBUG(PFX "%s: trying to transmit when device is closed", +- nic->log_name); ++ LOG_PACKET(PFX "%s: trying to transmit when device is closed", ++ nic->log_name); + pthread_mutex_unlock(&nic->xmit_mutex); + return; + } +@@ -905,8 +914,8 @@ void bnx2_start_xmit(nic_t * nic, size_t len, u16_t vlan_id) + bnx2_reg_sync(bp, bp->tx_bidx_io, sizeof(__u16)); + bnx2_reg_sync(bp, bp->tx_bseq_io, sizeof(__u32)); + +- LOG_DEBUG(PFX "%s: sent %d bytes using dev->tx_prod: %d", +- nic->log_name, len, bp->tx_prod); ++ LOG_PACKET(PFX "%s: sent %d bytes using dev->tx_prod: %d", ++ nic->log_name, len, bp->tx_prod); + } + + /** +@@ -917,8 +926,8 @@ void bnx2_start_xmit(nic_t * nic, size_t len, u16_t vlan_id) + */ + int bnx2_write(nic_t * nic, nic_interface_t * nic_iface, packet_t * pkt) + { +- bnx2_t *bp = (bnx2_t *) nic->priv; +- struct uip_stack *uip = &nic_iface->ustack; ++ bnx2_t *bp; ++ struct uip_stack *uip; + + /* Sanity Check: validate the parameters */ + if (nic == NULL || nic_iface == NULL || pkt == NULL) { +@@ -927,6 +936,8 @@ int bnx2_write(nic_t * nic, nic_interface_t * nic_iface, packet_t * pkt) + " 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", +@@ -935,22 +946,24 @@ int bnx2_write(nic_t * nic, nic_interface_t * nic_iface, packet_t * pkt) + } + + if (pthread_mutex_trylock(&nic->xmit_mutex) != 0) { +- LOG_DEBUG(PFX "%s: Dropped previous transmitted packet", +- nic->log_name); ++ 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_id); ++ 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_DEBUG(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); ++ 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; + } +@@ -963,7 +976,7 @@ int bnx2_write(nic_t * nic, nic_interface_t * nic_iface, packet_t * pkt) + */ + static int bnx2_read(nic_t * nic, packet_t * pkt) + { +- bnx2_t *bp = (bnx2_t *) nic->priv; ++ bnx2_t *bp; + int rc = 0; + uint16_t hw_cons, sw_cons; + +@@ -973,6 +986,7 @@ static int bnx2_read(nic_t * nic, packet_t * pkt) + " pkt == 0x%x", nic, pkt); + return -EINVAL; + } ++ bp = (bnx2_t *)nic->priv; + + hw_cons = bp->get_rx_cons(bp); + sw_cons = bp->rx_cons; +@@ -984,8 +998,8 @@ static int bnx2_read(nic_t * nic, packet_t * pkt) + int len; + uint16_t errors; + +- LOG_DEBUG(PFX "%s: clearing rx interrupt: %d %d %d", +- nic->log_name, sw_cons, hw_cons, rx_index); ++ 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); +@@ -1033,8 +1047,8 @@ static int bnx2_read(nic_t * nic, packet_t * pkt) + + rc = 1; + +- LOG_DEBUG(PFX "%s: processing packet " +- "length: %d", nic->log_name, len); ++ 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 */ +@@ -1073,21 +1087,23 @@ static int bnx2_read(nic_t * nic, packet_t * pkt) + */ + static int bnx2_clear_tx_intr(nic_t * nic) + { +- bnx2_t *bp = (bnx2_t *) nic->priv; +- uint16_t hw_cons = bp->get_tx_cons(bp); ++ 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_DEBUG(PFX "%s: clearing tx interrupt [%d %d]", +- nic->log_name, 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; + +@@ -1097,7 +1113,7 @@ static int bnx2_clear_tx_intr(nic_t * nic) + if (nic->tx_packet_queue != NULL) { + packet_t *pkt; + +- LOG_DEBUG(PFX "%s: sending queued tx packet", nic->log_name); ++ 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 +@@ -1106,13 +1122,14 @@ static int bnx2_clear_tx_intr(nic_t * nic) + 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_DEBUG(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); ++ 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; + } +diff --git a/iscsiuio/src/unix/libs/bnx2x.c b/iscsiuio/src/unix/libs/bnx2x.c +index fa32fbc..5e33420 100644 +--- a/iscsiuio/src/unix/libs/bnx2x.c ++++ b/iscsiuio/src/unix/libs/bnx2x.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2009-2011, Broadcom Corporation ++ * Copyright (c) 2009-2012, Broadcom Corporation + * + * Written by: Benjamin Li (benli@broadcom.com) + * +@@ -288,11 +288,12 @@ static void bnx2x_set_drv_version_unknown(bnx2x_t * bp) + 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 == BNX2X_UNKNOWN_MAJOR_VERSION) && +- (version->minor == BNX2X_UNKNOWN_MINOR_VERSION) && +- (version->sub_minor == BNX2X_UNKNOWN_SUB_MINOR_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; + } + +@@ -595,7 +596,7 @@ static void bnx2x_free(nic_t *nic) + /** + * bnx2x_alloc() - Used to allocate a bnx2x structure + */ +-static bnx2x_t *bnx2x_alloc(nic_t * nic) ++static bnx2x_t *bnx2x_alloc(nic_t *nic) + { + bnx2x_t *bp = malloc(sizeof(*bp)); + +@@ -652,9 +653,13 @@ static int bnx2x_open(nic_t * nic) + if (bp == NULL) + return -ENOMEM; + +- if (!bnx2x_is_drv_version_unknown(&bnx2x_version)) +- bnx2x_get_drv_version(bp); +- else { ++ 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, jsut use it */ + bnx2x_version.major = bp->version.major; + bnx2x_version.minor = bp->version.minor; + bnx2x_version.sub_minor = bp->version.sub_minor; +@@ -663,7 +668,9 @@ static int bnx2x_open(nic_t * nic) + 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) { +@@ -684,7 +691,9 @@ static int bnx2x_open(nic_t * nic) + 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++; + } +@@ -820,7 +829,15 @@ static int bnx2x_open(nic_t * nic) + 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; + +@@ -976,9 +993,12 @@ static int bnx2x_open(nic_t * nic) + val = bnx2x_rd32(bp, mf_cfg_addr + ovtag_offset); + val &= 0xffff; + /* SD mode, check for valid outer VLAN */ +- if (val == 0xffff) +- goto open_error; +- ++ 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) +@@ -995,10 +1015,9 @@ static int bnx2x_open(nic_t * nic) + 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], +@@ -1053,6 +1072,10 @@ open_error: + 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; +@@ -1165,9 +1188,12 @@ static int bnx2x_uio_close_resources(nic_t * nic, NIC_SHUTDOWN_T graceful) + static int bnx2x_close(nic_t * nic, NIC_SHUTDOWN_T graceful) + { + /* Sanity Check: validate the parameters */ +- if (nic == NULL || nic->priv == NULL) { +- LOG_ERR(PFX "bnx2x_close(): nic == %p, bp == %p", nic, +- nic->priv); ++ 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; + } + +@@ -1227,8 +1253,8 @@ void bnx2x_start_xmit(nic_t * nic, size_t len, u16_t vlan_id) + rx_bd = (struct eth_rx_bd *)(((__u8 *) bp->tx_ring) + getpagesize()); + + if ((rx_bd->addr_hi == 0) && (rx_bd->addr_lo == 0)) { +- LOG_DEBUG(PFX "%s: trying to transmit when device is closed", +- nic->log_name); ++ LOG_PACKET(PFX "%s: trying to transmit when device is closed", ++ nic->log_name); + pthread_mutex_unlock(&nic->xmit_mutex); + return; + } +@@ -1251,7 +1277,7 @@ void bnx2x_start_xmit(nic_t * nic, size_t len, u16_t vlan_id) + bp->tx_bd_prod = BNX2X_NEXT_TX_BD(bp->tx_bd_prod); + + barrier(); +- if (nl_process_if_down == 0) { ++ 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); +@@ -1262,8 +1288,8 @@ void bnx2x_start_xmit(nic_t * nic, size_t len, u16_t vlan_id) + */ + pthread_mutex_unlock(&nic->xmit_mutex); + } +- LOG_DEBUG(PFX "%s: sent %d bytes using bp->tx_prod: %d", +- nic->log_name, len, bp->tx_prod); ++ LOG_PACKET(PFX "%s: sent %d bytes using bp->tx_prod: %d", ++ nic->log_name, len, bp->tx_prod); + } + + /** +@@ -1274,8 +1300,8 @@ void bnx2x_start_xmit(nic_t * nic, size_t len, u16_t vlan_id) + */ + int bnx2x_write(nic_t * nic, nic_interface_t * nic_iface, packet_t * pkt) + { +- bnx2x_t *bp = (bnx2x_t *) nic->priv; +- struct uip_stack *uip = &nic_iface->ustack; ++ bnx2x_t *bp; ++ struct uip_stack *uip; + int i = 0; + + /* Sanity Check: validate the parameters */ +@@ -1285,6 +1311,8 @@ int bnx2x_write(nic_t * nic, nic_interface_t * nic_iface, packet_t * pkt) + " 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", +@@ -1304,22 +1332,24 @@ int bnx2x_write(nic_t * nic, nic_interface_t * nic_iface, packet_t * pkt) + } + + if (pthread_mutex_trylock(&nic->xmit_mutex) != 0) { +- LOG_DEBUG(PFX "%s: Dropped previous transmitted packet", +- nic->log_name); ++ 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_id); ++ 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_DEBUG(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); ++ 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; + } +@@ -1348,7 +1378,7 @@ static inline int bnx2x_get_rx_pad(bnx2x_t * bp, union eth_rx_cqe *cqe) + */ + static int bnx2x_read(nic_t * nic, packet_t * pkt) + { +- bnx2x_t *bp = (bnx2x_t *) nic->priv; ++ bnx2x_t *bp; + int rc = 0; + uint16_t hw_cons, sw_cons, bd_cons, bd_prod; + +@@ -1358,6 +1388,7 @@ static int bnx2x_read(nic_t * nic, packet_t * pkt) + " pkt == 0x%x", nic, pkt); + return -EINVAL; + } ++ bp = (bnx2x_t *) nic->priv; + + hw_cons = bp->get_rx_cons(bp); + sw_cons = bp->rx_cons; +@@ -1383,8 +1414,8 @@ static int bnx2x_read(nic_t * nic, packet_t * pkt) + } + cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; + +- LOG_DEBUG(PFX "%s: clearing rx interrupt: %d %d", +- nic->log_name, sw_cons, hw_cons); ++ LOG_PACKET(PFX "%s: clearing rx interrupt: %d %d", ++ nic->log_name, sw_cons, hw_cons); + + msync(cqe, cqe_size, MS_SYNC); + +@@ -1416,9 +1447,9 @@ static int bnx2x_read(nic_t * nic, packet_t * pkt) + pkt->vlan_tag = 0; + } + +- LOG_DEBUG(PFX +- "%s: processing packet length: %d", +- nic->log_name, len); ++ LOG_PACKET(PFX ++ "%s: processing packet length: %d", ++ nic->log_name, len); + + /* bump the cnic dev recv statistics */ + nic->stats.rx.packets++; +@@ -1453,14 +1484,16 @@ static int bnx2x_read(nic_t * nic, packet_t * pkt) + */ + static int bnx2x_clear_tx_intr(nic_t * nic) + { +- bnx2x_t *bp = (bnx2x_t *) nic->priv; +- uint16_t hw_cons = bp->get_tx_cons(bp); ++ 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) { +@@ -1473,8 +1506,8 @@ static int bnx2x_clear_tx_intr(nic_t * nic) + return -EAGAIN; + } + +- LOG_DEBUG(PFX "%s: clearing tx interrupt [%d %d]", +- nic->log_name, 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; + + /* There is a queued TX packet that needs to be sent out. The usual +@@ -1484,7 +1517,7 @@ static int bnx2x_clear_tx_intr(nic_t * nic) + packet_t *pkt; + int i; + +- LOG_DEBUG(PFX "%s: sending queued tx packet", nic->log_name); ++ 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 +@@ -1493,13 +1526,14 @@ static int bnx2x_clear_tx_intr(nic_t * nic) + 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_DEBUG(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); ++ 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; + } +@@ -1512,9 +1546,9 @@ static int bnx2x_clear_tx_intr(nic_t * nic) + + hw_cons = bp->get_tx_cons(bp); + if (bp->tx_cons != hw_cons) { +- LOG_DEBUG(PFX +- "%s: clearing tx interrupt [%d %d]", +- nic->log_name, 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; +diff --git a/iscsiuio/src/unix/libs/bnx2x.h b/iscsiuio/src/unix/libs/bnx2x.h +index 8e923b9..b758179 100644 +--- a/iscsiuio/src/unix/libs/bnx2x.h ++++ b/iscsiuio/src/unix/libs/bnx2x.h +@@ -467,6 +467,18 @@ struct client_init_general_data { + #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<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)); +@@ -166,15 +167,6 @@ static int cnic_neigh_soliciation_send(nic_t * nic, + memcpy(ipv6_hdr->ip6_dst.s6_addr, addr6_dst->s6_addr, + sizeof(struct in6_addr)); + +- LOG_DEBUG(PFX "dst ip addr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", +- ipv6_hdr->ip6_dst.s6_addr16[0], +- ipv6_hdr->ip6_dst.s6_addr16[1], +- ipv6_hdr->ip6_dst.s6_addr16[2], +- ipv6_hdr->ip6_dst.s6_addr16[3], +- ipv6_hdr->ip6_dst.s6_addr16[4], +- ipv6_hdr->ip6_dst.s6_addr16[5], +- ipv6_hdr->ip6_dst.s6_addr16[6], +- ipv6_hdr->ip6_dst.s6_addr16[7]); + 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; +@@ -196,6 +188,7 @@ static int cnic_neigh_soliciation_send(nic_t * nic, + 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", +@@ -261,12 +254,7 @@ static int cnic_nl_neigh_rsp(nic_t * nic, int fd, + } + if (ret) { + /* Get link local IPv6 address */ +- if (ndpc_request(&nic_iface->ustack, NULL, +- &src_ipv6, GET_LINK_LOCAL_ADDR)) { +- src_ipv6 = (u8_t *)all_zeroes_addr6; +- LOG_DEBUG(PFX "RSP Get LL failed"); +- goto src_done; +- } ++ src_ipv6 = (u8_t *)&nic_iface->ustack.linklocal6; + } else { + if (ndpc_request(&nic_iface->ustack, + &path_req->dst.v6_addr, +@@ -288,16 +276,18 @@ src_done: + addr_dst_str, sizeof(addr_dst_str)); + } + memcpy(path_rsp->mac_addr, mac_addr, 6); +- path_rsp->vlan_id = path_req->vlan_id; +- path_rsp->pmtu = path_req->pmtu; ++ 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", ++ "%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]); ++ 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); +@@ -323,67 +313,18 @@ const static struct timeval tp_wait = { + */ + int cnic_handle_ipv4_iscsi_path_req(nic_t * nic, int fd, + struct iscsi_uevent *ev, +- struct iscsi_path *path) ++ struct iscsi_path *path, ++ nic_interface_t *nic_iface) + { +- nic_interface_t *nic_iface, *vlan_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; +- +- memset(mac_addr, 0, sizeof(mac_addr)); +- +- pthread_mutex_lock(&nic_list_mutex); +- +- /* Find the proper interface via VLAN id */ +- nic_iface = nic_find_nic_iface_protocol(nic, 0, AF_INET); +- if (nic_iface == NULL) { +- pthread_mutex_unlock(&nic_list_mutex); +- LOG_ERR(PFX "%s: Couldn't find net_iface vlan_id: %d", +- nic->log_name, path->vlan_id); +- return -EINVAL; +- } +- if (path->vlan_id) { +- vlan_iface = nic_find_vlan_iface_protocol(nic, nic_iface, +- path->vlan_id, +- AF_INET); +- if (vlan_iface == NULL) { +- LOG_INFO(PFX "%s couldn't find interface with VLAN = %d" +- "ip_type: 0x%x creating it", +- nic->log_name, path->vlan_id, AF_INET); +- +- /* Create the nic interface */ +- vlan_iface = nic_iface_init(); +- +- if (vlan_iface == NULL) { +- LOG_ERR(PFX "Couldn't allocate nic_iface for " +- "VLAN: %d", vlan_iface, +- path->vlan_id); +- return -EINVAL; +- } +- +- vlan_iface->protocol = nic_iface->protocol; +- vlan_iface->vlan_id = path->vlan_id; +- 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)); +- nic_add_vlan_iface(nic, nic_iface, vlan_iface); +- } else { +- LOG_INFO(PFX "%s: using existing vlan interface", +- nic->log_name); +- } +- nic_iface = vlan_iface; +- } +- + #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)); + +@@ -445,20 +386,15 @@ int cnic_handle_ipv4_iscsi_path_req(nic_t * nic, int fd, + ts.tv_sec = tp_abs.tv_sec; + ts.tv_nsec = tp_abs.tv_usec * 1000; + +- pthread_mutex_unlock(&nic_list_mutex); ++ /* Wait 1s for if_down */ ++ pthread_mutex_lock(&nic->nl_process_mutex); + rc = pthread_cond_timedwait +- (&nl_process_if_down_cond, +- &nl_process_mutex, &ts); ++ (&nic->nl_process_if_down_cond, ++ &nic->nl_process_mutex, &ts); + + if (rc == ETIMEDOUT) { +- pthread_mutex_unlock(&nl_process_mutex); +- +- if (pthread_mutex_trylock +- (&nic_list_mutex) != 0) { +- arp_retry = MAX_ARP_RETRY; +- goto done; +- +- } ++ pthread_mutex_unlock ++ (&nic->nl_process_mutex); + + rc = uip_lookup_arp_entry(dst_addr. + s_addr, +@@ -466,8 +402,9 @@ int cnic_handle_ipv4_iscsi_path_req(nic_t * nic, int fd, + if (rc == 0) + goto done; + } else { +- nl_process_if_down = 0; +- pthread_mutex_unlock(&nl_process_mutex); ++ nic->nl_process_if_down = 0; ++ pthread_mutex_unlock ++ (&nic->nl_process_mutex); + + arp_retry = MAX_ARP_RETRY; + goto done; +@@ -491,9 +428,6 @@ done: + + cnic_nl_neigh_rsp(nic, fd, ev, path, mac_addr, + nic_iface, status, AF_INET); +- +- pthread_mutex_unlock(&nic_list_mutex); +- + return rc; + } + +@@ -507,9 +441,9 @@ done: + */ + int cnic_handle_ipv6_iscsi_path_req(nic_t * nic, int fd, + struct iscsi_uevent *ev, +- struct iscsi_path *path) ++ struct iscsi_path *path, ++ nic_interface_t *nic_iface) + { +- nic_interface_t *nic_iface, *vlan_iface; + __u8 mac_addr[6]; + int rc, i; + uint16_t neighbor_retry; +@@ -525,52 +459,6 @@ int cnic_handle_ipv6_iscsi_path_req(nic_t * nic, int fd, + inet_ntop(AF_INET6, &path->dst.v6_addr, + addr_dst_str, sizeof(addr_dst_str)); + +- pthread_mutex_lock(&nic_list_mutex); +- +- /* Find the proper interface via VLAN id */ +- nic_iface = nic_find_nic_iface_protocol(nic, 0, AF_INET6); +- if (nic_iface == NULL) { +- pthread_mutex_unlock(&nic_list_mutex); +- LOG_ERR(PFX "%s: Couldn't find net_iface vlan_id: %d", +- nic->log_name, path->vlan_id); +- return -EINVAL; +- } +- if (path->vlan_id) { +- vlan_iface = nic_find_vlan_iface_protocol(nic, nic_iface, +- path->vlan_id, +- AF_INET6); +- if (vlan_iface == NULL) { +- LOG_INFO(PFX "%s couldn't find interface with VLAN = %d" +- "ip_type: 0x%x creating it", +- nic->log_name, path->vlan_id, AF_INET6); +- +- /* Create the nic interface */ +- vlan_iface = nic_iface_init(); +- +- if (vlan_iface == NULL) { +- LOG_ERR(PFX "Couldn't allocate nic_iface for " +- "VLAN: %d", vlan_iface, +- path->vlan_id); +- return -EINVAL; +- } +- vlan_iface->protocol = nic_iface->protocol; +- vlan_iface->vlan_id = path->vlan_id; +- vlan_iface->ustack.ip_config = +- nic_iface->ustack.ip_config; +- memcpy(vlan_iface->ustack.hostaddr6, +- nic_iface->ustack.hostaddr6, +- sizeof(nic_iface->ustack.hostaddr6)); +- memcpy(vlan_iface->ustack.netmask6, +- nic_iface->ustack.netmask6, +- sizeof(nic_iface->ustack.netmask6)); +- nic_add_vlan_iface(nic, nic_iface, vlan_iface); +- } else { +- LOG_INFO(PFX "%s: using existing vlan interface", +- nic->log_name); +- } +- nic_iface = vlan_iface; +- } +- + /* 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 */ +@@ -584,12 +472,7 @@ int cnic_handle_ipv6_iscsi_path_req(nic_t * nic, int fd, + if (rc) { + LOG_DEBUG(PFX "Use LL"); + /* Get link local IPv6 address */ +- if (ndpc_request(&nic_iface->ustack, NULL, +- &addr, GET_LINK_LOCAL_ADDR)) { +- neighbor_retry = MAX_ARP_RETRY; +- LOG_DEBUG(PFX "Use LL failed"); +- goto done; +- } ++ addr = (struct in6_addr *)&nic_iface->ustack.linklocal6; + } else { + LOG_DEBUG(PFX "Use Best matched"); + if (ndpc_request(&nic_iface->ustack, +@@ -618,21 +501,15 @@ int cnic_handle_ipv6_iscsi_path_req(nic_t * nic, int fd, + memcpy(&netmask.s6_addr, all_zeroes_addr6, + sizeof(struct in6_addr)); + +- LOG_DEBUG(PFX "src addr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", +- src_addr.s6_addr16[0], src_addr.s6_addr16[1], +- src_addr.s6_addr16[2], src_addr.s6_addr16[3], +- src_addr.s6_addr16[4], src_addr.s6_addr16[5], +- src_addr.s6_addr16[6], src_addr.s6_addr16[7]); +- LOG_DEBUG(PFX "dst addr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", +- dst_addr.s6_addr16[0], dst_addr.s6_addr16[1], +- dst_addr.s6_addr16[2], dst_addr.s6_addr16[3], +- dst_addr.s6_addr16[4], dst_addr.s6_addr16[5], +- dst_addr.s6_addr16[6], dst_addr.s6_addr16[7]); +- LOG_DEBUG(PFX "nm addr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", +- netmask.s6_addr16[0], netmask.s6_addr16[1], +- netmask.s6_addr16[2], netmask.s6_addr16[3], +- netmask.s6_addr16[4], netmask.s6_addr16[5], +- netmask.s6_addr16[6], netmask.s6_addr16[7]); ++ 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] & +@@ -642,24 +519,22 @@ int cnic_handle_ipv6_iscsi_path_req(nic_t * nic, int fd, + if (src_matching_addr.s6_addr32[i] != + dst_matching_addr.s6_addr32[i]) { + /* No match with the prefix mask, use default route */ +- if (ndpc_request(&nic_iface->ustack, NULL, &addr, +- GET_DEFAULT_ROUTER_ADDR)) { +- neighbor_retry = MAX_ARP_RETRY; +- goto done; +- } +- if (memcmp(addr, all_zeroes_addr6, sizeof(*addr))) +- memcpy(&dst_addr, addr, sizeof(dst_addr)); +- else { ++ 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; + } + } + } +- LOG_DEBUG(PFX "dst addr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", +- dst_addr.s6_addr16[0], dst_addr.s6_addr16[1], +- dst_addr.s6_addr16[2], dst_addr.s6_addr16[3], +- dst_addr.s6_addr16[4], dst_addr.s6_addr16[5], +- dst_addr.s6_addr16[6], dst_addr.s6_addr16[7]); + + #define MAX_ARP_RETRY 4 + neighbor_retry = 0; +@@ -672,6 +547,8 @@ int cnic_handle_ipv6_iscsi_path_req(nic_t * nic, int fd, + 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); +@@ -703,20 +580,14 @@ int cnic_handle_ipv6_iscsi_path_req(nic_t * nic, int fd, + ts.tv_sec = tp_abs.tv_sec; + ts.tv_nsec = tp_abs.tv_usec * 1000; + +- pthread_mutex_unlock(&nic_list_mutex); ++ pthread_mutex_lock(&nic->nl_process_mutex); + rc = pthread_cond_timedwait +- (&nl_process_if_down_cond, +- &nl_process_mutex, &ts); ++ (&nic->nl_process_if_down_cond, ++ &nic->nl_process_mutex, &ts); + + if (rc == ETIMEDOUT) { +- pthread_mutex_unlock(&nl_process_mutex); +- +- if (pthread_mutex_trylock +- (&nic_list_mutex) != 0) { +- neighbor_retry = MAX_ARP_RETRY; +- goto done; +- +- } ++ pthread_mutex_unlock ++ (&nic->nl_process_mutex); + + req_ptr.eth = (void *)mac_addr; + req_ptr.ipv6 = (void *)&dst_addr; +@@ -730,8 +601,9 @@ int cnic_handle_ipv6_iscsi_path_req(nic_t * nic, int fd, + if (rc) + goto done; + } else { +- nl_process_if_down = 0; +- pthread_mutex_unlock(&nl_process_mutex); ++ nic->nl_process_if_down = 0; ++ pthread_mutex_unlock ++ (&nic->nl_process_mutex); + + neighbor_retry = MAX_ARP_RETRY; + goto done; +@@ -752,9 +624,6 @@ done: + + cnic_nl_neigh_rsp(nic, fd, ev, path, mac_addr, + nic_iface, status, AF_INET6); +- +- pthread_mutex_unlock(&nic_list_mutex); +- + return rc; + } + +@@ -764,11 +633,12 @@ done: + * @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 +- * @param buf_len - The private message buffer length ++ * @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) ++ struct iscsi_path *path, ++ nic_interface_t *nic_iface) + { + + LOG_DEBUG(PFX "%s: Netlink message with VLAN ID: %d, path MTU: %d " +@@ -777,9 +647,11 @@ int cnic_handle_iscsi_path_req(nic_t * nic, int fd, struct iscsi_uevent *ev, + path->ip_addr_len); + + if (path->ip_addr_len == 4) +- return cnic_handle_ipv4_iscsi_path_req(nic, fd, ev, path); ++ 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); ++ 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); +diff --git a/iscsiuio/src/unix/libs/cnic.h b/iscsiuio/src/unix/libs/cnic.h +index 738deb8..679dab8 100644 +--- a/iscsiuio/src/unix/libs/cnic.h ++++ b/iscsiuio/src/unix/libs/cnic.h +@@ -48,6 +48,7 @@ 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); ++ struct iscsi_path *path, ++ nic_interface_t *nic_iface); + + #endif /* __CNIC_NL_H__ */ +diff --git a/iscsiuio/src/unix/main.c b/iscsiuio/src/unix/main.c +index 4f548e9..2008913 100644 +--- a/iscsiuio/src/unix/main.c ++++ b/iscsiuio/src/unix/main.c +@@ -141,7 +141,6 @@ signal_wait: + break; + case SIGUSR1: + LOG_INFO("Caught SIGUSR1 signal, rotate log"); +-retry: + fini_logger(SHUTDOWN_LOGGER); + rc = init_logger(main_log.log_file); + if (rc != 0) +diff --git a/iscsiuio/src/unix/nic.c b/iscsiuio/src/unix/nic.c +index 0934b56..0b3c538 100644 +--- a/iscsiuio/src/unix/nic.c ++++ b/iscsiuio/src/unix/nic.c +@@ -64,6 +64,7 @@ + + #include "bnx2.h" + #include "bnx2x.h" ++#include "ipv6.h" + + /****************************************************************************** + * Constants +@@ -118,7 +119,7 @@ static void free_nic_library_handle(nic_lib_handle_t * handle) + * @param handle - This is the library handle to load + * @return 0 = Success; <0 = failure + */ +-static int load_nic_library(nic_lib_handle_t * handle) ++static int load_nic_library(nic_lib_handle_t *handle) + { + int rc; + char *library_name; +@@ -172,7 +173,7 @@ static int load_nic_library(nic_lib_handle_t * handle) + + return 0; + +- error: ++error: + pthread_mutex_unlock(&handle->mutex); + + return rc; +@@ -197,9 +198,10 @@ int load_all_nic_libraries() + handle->ops = (*nic_get_ops[i]) (); + + rc = load_nic_library(handle); +- if (rc != 0) ++ 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); + +@@ -270,7 +272,7 @@ NIC_LIBRARY_EXIST_T does_nic_uio_name_exist(char *name) + + rc = NIC_LIBRARY_DOESNT_EXIST; + +- done: ++done: + pthread_mutex_unlock(&nic_lib_list_mutex); + return rc; + } +@@ -300,7 +302,7 @@ NIC_LIBRARY_EXIST_T does_nic_library_exist(char *name) + + rc = NIC_LIBRARY_DOESNT_EXIST; + +- done: ++done: + pthread_mutex_unlock(&nic_lib_list_mutex); + return rc; + } +@@ -366,7 +368,7 @@ int find_nic_lib_using_pci_id(uint32_t vendor, uint32_t device, + } + rc = -EINVAL; + +- done: ++done: + pthread_mutex_unlock(&nic_lib_list_mutex); + + return rc; +@@ -393,13 +395,14 @@ nic_t *nic_init() + nic->next = NULL; + nic->thread = INVALID_THREAD; + nic->enable_thread = INVALID_THREAD; +- nic->flags |= NIC_UNITIALIZED | NIC_DISABLED; +- nic->state |= NIC_STOPPED; ++ 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_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); +@@ -411,6 +414,15 @@ nic_t *nic_init() + + 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; + } + +@@ -432,7 +444,6 @@ void nic_add(nic_t * nic) + + /** + * nic_remove() - Used to remove the NIC for the nic list +- nic_list_mutex must be taken + * @param nic - the nic to remove + */ + int nic_remove(nic_t * nic) +@@ -451,41 +462,66 @@ int nic_remove(nic_t * nic) + nic->ops->close(nic, 0); + + nic->state = NIC_EXIT; +- pthread_mutex_unlock(&nic->nic_mutex); + + if (nic->enable_thread != INVALID_THREAD) { +- LOG_ERR(PFX "%s: Canceling nic enable thread", nic->log_name); ++ LOG_DEBUG(PFX "%s: Canceling nic enable thread", nic->log_name); + + rc = pthread_cancel(nic->enable_thread); + if (rc != 0) +- LOG_ERR(PFX "%s: Couldn't send cancel to nic enable " +- "thread", nic->log_name); ++ LOG_DEBUG(PFX "%s: Couldn't send cancel to nic enable " ++ "thread", nic->log_name); + +- LOG_ERR(PFX "%s: Waiting to join nic enable thread", +- nic->log_name); ++ LOG_DEBUG(PFX "%s: Waiting to join nic enable thread", ++ nic->log_name); + rc = pthread_join(nic->enable_thread, &res); + if (rc != 0) +- LOG_ERR(PFX "%s: Couldn't join to canceled enable nic " +- "thread", nic->log_name); ++ LOG_DEBUG(PFX "%s: Couldn't join to canceled enable " ++ "nic thread", nic->log_name); + nic->enable_thread = INVALID_THREAD; ++ LOG_DEBUG(PFX "%s: nic enable thread cleaned", nic->log_name); ++ } else { ++ LOG_DEBUG(PFX "%s: NIC enable thread already canceled", ++ nic->log_name); + } ++ + if (nic->thread != INVALID_THREAD) { +- LOG_ERR(PFX "%s: Canceling nic thread", nic->log_name); ++ LOG_DEBUG(PFX "%s: Canceling nic thread", nic->log_name); + + rc = pthread_cancel(nic->thread); + if (rc != 0) +- LOG_ERR(PFX "%s: Couldn't send cancel to nic", +- nic->log_name); ++ LOG_DEBUG(PFX "%s: Couldn't send cancel to nic", ++ nic->log_name); + +- LOG_ERR(PFX "%s: Waiting to join nic thread", nic->log_name); ++ LOG_DEBUG(PFX "%s: Waiting to join nic thread", nic->log_name); + rc = pthread_join(nic->thread, &res); + if (rc != 0) +- LOG_ERR(PFX "%s: Couldn't join to canceled nic thread", +- nic->log_name); +- ++ LOG_DEBUG(PFX "%s: Couldn't join to canceled nic " ++ "thread", nic->log_name); + nic->thread = INVALID_THREAD; ++ LOG_DEBUG(PFX "%s: nic thread cleaned", nic->log_name); ++ } else { ++ 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); ++ ++ LOG_DEBUG(PFX "%s: Waiting to join nic nl thread", ++ nic->log_name); ++ rc = pthread_join(nic->nl_process_thread, &res); ++ if (rc != 0) ++ LOG_DEBUG(PFX "%s: Couldn't join to canceled nic nl " ++ "thread", nic->log_name); ++ nic->nl_process_thread = INVALID_THREAD; ++ LOG_DEBUG(PFX "%s: nic nl thread cleaned", nic->log_name); + } else { +- LOG_ERR(PFX "%s: NIC thread already canceled", nic->log_name); ++ LOG_DEBUG(PFX "%s: NIC nl thread already canceled", ++ nic->log_name); + } + + current = prev = nic_list; +@@ -505,7 +541,7 @@ int nic_remove(nic_t * nic) + + /* Before freeing the nic, must free all the associated + nic_iface */ +- nic_iface = nic->nic_iface; ++ nic_iface = current->nic_iface; + while (nic_iface != NULL) { + vlan_iface = nic_iface->vlan_next; + while (vlan_iface != NULL) { +@@ -608,7 +644,7 @@ error: + } + + /** +- * net_iface_init() - This function is used to add an interface to the ++ * nic_iface_init() - This function is used to add an interface to the + * structure cnic_uio + * @return 0 on success, <0 on failure + */ +@@ -623,6 +659,8 @@ nic_interface_t *nic_iface_init() + 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; + } +@@ -630,112 +668,57 @@ nic_interface_t *nic_iface_init() + /** + * 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) ++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; ++ } + +- pthread_mutex_lock(&nic->nic_mutex); +- +- /* Add the nic_interface */ +- if (nic->nic_iface == NULL) { +- nic->nic_iface = nic_iface; +- } else { +- nic_interface_t *current = nic->nic_iface; +- +- /* Check to see if this interface already exists via 2 +- * conditions: 1) VLAN 2) protocol */ +- while (current != NULL) { +- if ((current->protocol == nic_iface->protocol) && +- (current->vlan_id == nic_iface->vlan_id)) { +- LOG_WARN(PFX "%s: nic interface alread exists" +- "for VLAN: %d, protocol: %d", +- nic->log_name, current->vlan_id, +- current->protocol); +- goto error; +- } +- current = current->next; +- } +- +- /* This interface doesn't exists, we can safely add +- * this nic interface */ +- current = nic->nic_iface; +- while (current->next != NULL) { +- current = current->next; ++ 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; + } +- +- current->next = nic_iface; ++ 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); + +-error: +- pthread_mutex_unlock(&nic->nic_mutex); +- + return 0; + } + +-/** +- * nic_add_vlan_iface() - This function is used to add a vlan interface to the +- * nic structure +- * @param nic - struct nic device to add the interface to +- * @param nic_iface - network interface to be added to +- * @param vlan_iface - vlan interface used to add to the nic_iface +- * @return 0 on success, <0 on failure +- */ +-int nic_add_vlan_iface(nic_t *nic, nic_interface_t *nic_iface, +- nic_interface_t *vlan_iface) +-{ +- pthread_mutex_lock(&nic->nic_mutex); +- +- /* Add the nic_interface */ +- if (nic_iface == NULL) +- goto error; +- else { +- nic_interface_t *current = nic_iface->vlan_next; +- +- /* Check to see if this interface already exists via 2 +- * conditions: 1) VLAN 2) protocol */ +- while (current != NULL) { +- if ((current->protocol == vlan_iface->protocol) && +- (current->vlan_id == vlan_iface->vlan_id)) { +- LOG_WARN(PFX "%s: vlan interface already exists" +- "for VLAN: %d, protocol: %d", +- nic->log_name, current->vlan_id, +- current->protocol); +- goto error; +- } +- current = current->vlan_next; +- } +- +- /* This interface doesn't exists, we can safely add +- * this nic interface */ +- current = nic_iface; +- while (current->vlan_next != NULL) +- current = current->vlan_next; +- +- current->vlan_next = vlan_iface; +- } +- +- /* Set nic_interface common fields */ +- vlan_iface->parent = nic; +- nic->num_of_nic_iface++; +- +- LOG_INFO(PFX "%s: Added vlan interface for VLAN: %d, protocol: %d", +- nic->log_name, vlan_iface->vlan_id, vlan_iface->protocol); +- +-error: +- pthread_mutex_unlock(&nic->nic_mutex); +- +- return 0; +-} + /****************************************************************************** + * Routine to process interrupts from the NIC device + ******************************************************************************/ +@@ -752,13 +735,13 @@ int nic_process_intr(nic_t * nic, int discard_check) + struct timeval tv; + + /* Simple sanity checks */ +- if ((discard_check != 1) && (nic->state & NIC_RUNNING) != NIC_RUNNING) { ++ 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)) { ++ if (discard_check != 1 && nic->fd == INVALID_FD) { + LOG_ERR(PFX "%s: NIC fd not valid", nic->log_name); + return -EIO; + } +@@ -767,11 +750,12 @@ int nic_process_intr(nic_t * nic, int discard_check) + FD_SET(nic->fd, &fdset); + + tv.tv_sec = 0; +- if (nic->state & NIC_LONG_SLEEP) { ++ pthread_mutex_lock(&nic->nic_mutex); ++ if (nic->flags & NIC_LONG_SLEEP) + tv.tv_usec = 1000; +- } else { ++ 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); +@@ -796,20 +780,20 @@ int nic_process_intr(nic_t * nic, int discard_check) + pthread_mutex_lock(&nic->nic_mutex); + if (ret > 0) { + nic->stats.interrupts++; +- LOG_DEBUG(PFX "%s: interrupt count: %d prev: %d", +- nic->log_name, count, nic->intr_count); ++ LOG_PACKET(PFX "%s: interrupt count: %d prev: %d", ++ nic->log_name, count, nic->intr_count); + + if (count == nic->intr_count) { +- LOG_WARN(PFX "%s: got interrupt but count still the " +- "same", nic->log_name, 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_DEBUG(PFX "%s: Missed interrupt! on %d not %d", +- nic->log_name, count, nic->intr_count); ++ LOG_PACKET(PFX "%s: Missed interrupt! on %d not %d", ++ nic->log_name, count, nic->intr_count); + } + + nic->intr_count = count; +@@ -833,9 +817,14 @@ static void prepare_ipv4_packet(nic_t * nic, + int queue_rc; + int vlan_id = 0; + +- if (nic_iface->vlan_id && !(NIC_VLAN_STRIP_ENABLED & nic->flags)) +- vlan_id = nic_iface->vlan_id; +- ++ /* 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); +@@ -867,9 +856,12 @@ static void prepare_ipv6_packet(nic_t * nic, + struct uip_vlan_eth_hdr *eth_vlan; + int vlan_id = 0; + +- if (nic_iface->vlan_id && !(NIC_VLAN_STRIP_ENABLED & nic->flags)) +- vlan_id = nic_iface->vlan_id; +- ++ 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) { +@@ -897,96 +889,96 @@ static void prepare_ustack(nic_t * nic, + * there is a VLAN tag or not, or if the hardware + * has stripped out the + * VLAN tag */ +- if ((nic_iface->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); +- } ++ 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 = UIP_ETHTYPE_IPv6; ++ eth->ether_type = htons(UIP_ETHTYPE_IPv6); + } + } + +-static int check_timers(nic_t * nic, +- struct timer *periodic_timer, struct timer *arp_timer) ++int do_timers_per_nic_iface(nic_t *nic, nic_interface_t *nic_iface, ++ struct timer *arp_timer) + { +- if (timer_expired(periodic_timer)) { +- int i; +- nic_interface_t *current; +- +- timer_reset(periodic_timer); ++ packet_t *pkt; ++ struct uip_stack *ustack = &nic_iface->ustack; ++ int i; + +- pthread_mutex_lock(&nic->nic_mutex); ++ pkt = get_next_free_packet(nic); ++ if (pkt == NULL) ++ return -EIO; + +- current = nic->nic_iface; +- while (current != NULL) { +- packet_t *pkt; +- struct uip_stack *ustack = ¤t->ustack; ++ if (nic_iface->ustack.ip_config == AF_INET) { ++ for (i = 0; i < UIP_UDP_CONNS; i++) { ++ prepare_ustack(nic, nic_iface, ustack, pkt); + +- pkt = get_next_free_packet(nic); +- if (pkt == NULL) { +- current = current->next; +- continue; ++ 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; + } +- +- for (i = 0; i < UIP_UDP_CONNS; i++) { +- prepare_ustack(nic, current, 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, +- current, +- ustack, pkt); +- +- (*nic->ops->write) (nic, current, 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; ++} + +- /* Added periodic poll for IPv6 NDP engine */ +- if (ustack->ndpc != NULL) { /* If engine is active */ +- prepare_ustack(nic, current, 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, +- current, +- ustack, pkt); +- (*nic->ops->write) (nic, current, pkt); +- ustack->uip_len = 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; + +- /* Call the ARP timer function every 10 seconds. */ +- if (timer_expired(arp_timer)) { +- timer_reset(arp_timer); +- uip_arp_timer(); +- } ++ timer_reset(periodic_timer); + +- put_packet_in_free_queue(pkt, nic); ++ pthread_mutex_lock(&nic->nic_mutex); + +- current = current->next; ++ 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; + } + +@@ -1012,109 +1004,71 @@ int process_packets(nic_t * nic, + uint16_t type = 0; + int af_type = 0; + struct uip_stack *ustack; +- nic_interface_t *vlan_iface; ++ struct ip_hdr *ip; ++ pIPV6_HDR ip6; ++ void *dst_ip; ++ uint16_t vlan_id; + +- if ((pkt->vlan_tag == 0) || ++ 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 = (pIPV6_HDR) pkt->network_layer; ++ dst_ip = (void *)&ip6->ipv6_dst; + break; + case UIP_ETHTYPE_IPv4: +- af_type = AF_INET; +- break; + case UIP_ETHTYPE_ARP: + af_type = AF_INET; ++ ip = (struct ip_hdr *) pkt->network_layer; ++ dst_ip = (void *)&ip->destipaddr; + break; + default: +- LOG_DEBUG(PFX "%s: Ignoring vlan:0x%x ethertype:0x%x", +- nic->log_name, pkt->vlan_tag, type); ++ LOG_PACKET(PFX "%s: Ignoring vlan:0x%x ethertype:0x%x", ++ nic->log_name, vlan_id, type); + goto done; + } + +- /* check if we have the given VLAN interface */ +- if (nic_iface == NULL) { +- nic_iface = nic_find_nic_iface_protocol(nic, 0, +- af_type); +- if (nic_iface == NULL) { +- LOG_INFO(PFX "%s: Couldn't find interface for " +- "VLAN: %d af_type %d creating it", +- nic->log_name, pkt->vlan_tag, af_type); +- +- /* Create the vlan interface */ +- nic_iface = nic_iface_init(); +- +- if (nic_iface == NULL) { +- LOG_WARN(PFX "%s: Couldn't " +- "allocate " +- "nic_iface for " +- "VLAN: %d af_type %d", +- nic->log_name, pkt->vlan_tag, +- af_type); +- rc = 0; +- goto done; +- } +- +- nic_iface->protocol = af_type; +- nic_iface->vlan_id = 0; +- nic_add_nic_iface(nic, nic_iface); ++ pthread_mutex_lock(&nic->nic_mutex); + +- persist_all_nic_iface(nic); +- } +- if (pkt->vlan_tag) { +- vlan_iface = nic_find_vlan_iface_protocol(nic, +- nic_iface, pkt->vlan_tag, +- af_type); +- if (vlan_iface == NULL) { +- LOG_INFO(PFX "%s couldn't find " +- "interface with VLAN =" +- " %d ip_type: 0x%x " +- "creating it", +- nic->log_name, pkt->vlan_tag, +- af_type); +- +- /* Create the nic interface */ +- vlan_iface = nic_iface_init(); +- +- if (vlan_iface == NULL) { +- LOG_ERR(PFX "Couldn't allocate " +- "nic_iface for VLAN: %d", +- vlan_iface, +- pkt->vlan_tag); +- rc = 0; +- goto done; +- } +- vlan_iface->protocol = af_type; +- vlan_iface->vlan_id = pkt->vlan_tag; +- nic_add_vlan_iface(nic, nic_iface, +- vlan_iface); +- /* TODO: When VLAN support is placed */ +- /* in the iface file revisit this */ +- /* code */ +- 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_all_nic_iface(nic); +- } +- nic_iface = vlan_iface; ++ /* 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; +@@ -1123,27 +1077,17 @@ int process_packets(nic_t * nic, + ustack->uip_len = pkt->buf_size; + ustack->data_link_layer = pkt->buf; + +- pkt->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 ((pkt->vlan_tag == 0) || +- (NIC_VLAN_STRIP_ENABLED & nic->flags)) { ++ if ((vlan_id == 0) || ++ (NIC_VLAN_STRIP_ENABLED & nic->flags)) + ustack->network_layer = ustack->data_link_layer + + sizeof(struct uip_eth_hdr); +- pkt->network_layer = pkt->data_link_layer + +- sizeof(struct uip_eth_hdr); +- type = ntohs(ETH_BUF(pkt->buf)->type); +- } else { ++ else + ustack->network_layer = ustack->data_link_layer + + sizeof(struct uip_vlan_eth_hdr); +- pkt->network_layer = pkt->data_link_layer + +- sizeof(struct uip_vlan_eth_hdr); +- type = ntohs(VLAN_ETH_BUF(pkt->buf)->type); +- } + +- pthread_mutex_lock(&nic->nic_mutex); + /* determine how we should process this packet based on the + * ethernet type */ + switch (type) { +@@ -1270,25 +1214,174 @@ static int process_dhcp_loop(nic_t * nic, + } + + if (timercmp(&total_time, ¤t_time, <)) { +- LOG_ERR(PFX "%s: timeout waiting for DHCP", ++ 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; ++ void *res; ++ 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_join(nic->enable_thread, &res); ++ if (rc != 0) ++ LOG_ERR(PFX "%s: Couldn't join to canceled " ++ "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; +- struct timer periodic_timer, arp_timer; + sigset_t set; +- void *res; ++ struct timer periodic_timer, arp_timer; + + sigfillset(&set); + rc = pthread_sigmask(SIG_BLOCK, &set, NULL); +@@ -1302,10 +1395,11 @@ void *nic_loop(void *arg) + 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; ++ nic_interface_t *nic_iface, *vlan_iface; + + if (nic->flags & NIC_DISABLED) { + LOG_DEBUG(PFX "%s: Waiting to be enabled", +@@ -1322,8 +1416,6 @@ void *nic_loop(void *arg) + } + LOG_DEBUG(PFX "%s: is now enabled", nic->log_name); + } +- pthread_mutex_unlock(&nic->nic_mutex); +- + /* initialize the device to send/rec data */ + rc = (*nic->ops->open) (nic); + if (rc != 0) { +@@ -1331,18 +1423,17 @@ void *nic_loop(void *arg) + nic->log_name); + + if (rc == -ENOTSUP) +- nic->flags &= NIC_EXIT_MAIN_LOOP; ++ 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) { +@@ -1354,13 +1445,12 @@ void *nic_loop(void *arg) + "instead of %d", nic->log_name, 5); + /* Signal that the device enable is done */ + pthread_cond_broadcast(&nic->enable_done_cond); +- pthread_mutex_unlock(&nic->nic_mutex); + goto dev_close; + } + } + /* Indication for the nic_disable routine that the nic + has started running */ +- nic->state |= NIC_STARTED_RUNNING; ++ nic->state = NIC_STARTED_RUNNING; + + /* Initialize the system clocks */ + timer_set(&periodic_timer, CLOCK_SECOND / 2); +@@ -1369,192 +1459,25 @@ void *nic_loop(void *arg) + /* 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) { +- uip_init(&nic_iface->ustack, +- nic->flags & NIC_IPv6_ENABLED); +- memcpy(&nic_iface->ustack.uip_ethaddr.addr, +- nic->mac_addr, 6); +- +- 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]); +- +- if (nic_iface->ustack.ip_config == IPV4_CONFIG_STATIC) { +- struct in_addr addr; +- uip_ip4addr_t tmp = { 0, 0 }; +- +- 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, +- &tmp, nic_iface->mac_addr); +- +- } else if (nic_iface->ustack.ip_config == +- IPV4_CONFIG_DHCP) { +- struct uip_stack *ustack = &nic_iface->ustack; +- uip_ip4addr_t tmp = { 0, 0 }; +- +- set_uip_stack(&nic_iface->ustack, +- &nic_iface->ustack.hostaddr, +- &nic_iface->ustack.netmask, +- &tmp, nic_iface->mac_addr); +- if (dhcpc_init(nic, ustack, +- nic_iface->mac_addr, ETH_ALEN)) { +- if (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 dev_close_free; +- } +- } +- pthread_mutex_unlock(&nic->nic_mutex); +- rc = process_dhcp_loop(nic, nic_iface, ++ 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); +- pthread_mutex_lock(&nic->nic_mutex); +- +- if (rc) { +- LOG_ERR(PFX "%s: DHCP failed", +- nic->log_name); +- nic->flags |= NIC_DISABLED | +- NIC_RESET_UIP; +- nic->flags &= ~NIC_ENABLED; +- /* 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 dev_close_free; +- +- rc = pthread_join(nic->enable_thread, +- &res); +- if (rc != 0) +- LOG_ERR(PFX "%s: Couldn't join " +- "to canceled enable nic" +- " thread", +- nic->log_name); +- +- goto dev_close_free; + } +- +- if (nic->flags & NIC_DISABLED) { +- pthread_mutex_unlock(&nic->nic_mutex); +- break; +- } +- +- LOG_INFO(PFX "%s: Initialized dhcp client", +- nic->log_name); +- } else if (nic_iface->ustack.ip_config == +- IPV6_CONFIG_DHCP || +- nic_iface->ustack.ip_config == +- IPV6_CONFIG_STATIC) { +- struct in6_addr addr6; +- char buf[INET6_ADDRSTRLEN]; +- +- /* Do router solicitation for both STATIC and +- DHCP - all NDP handling will take place in +- the DHCP loop +- STATIC - router advertisement will be handled +- in the uip background loop +- */ +- 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; +- } +- if (nic_iface->ustack.ip_config == +- IPV6_CONFIG_DHCP) { +- 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: DHCPv6 failed", +- nic->log_name); +- } +- if (nic->flags & NIC_DISABLED) { +- pthread_mutex_unlock(&nic-> +- nic_mutex); +- break; +- } +- } else { +- 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: IPv6 rtr " +- "failed", +- nic->log_name); +- } +- 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); +- } +- } else { +- LOG_INFO(PFX "%s: ipconfig = %d?", +- nic->log_name, +- nic_iface->ustack.ip_config); ++ vlan_iface = vlan_iface->next; + } +-skip: +- LOG_INFO(PFX "%s: enabled vlan %d protocol: %d", +- nic->log_name, +- nic_iface->vlan_id, nic_iface->protocol); +- +- nic_iface = nic_iface->vlan_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", +@@ -1567,10 +1490,7 @@ skip: + + /* This is when we start the processing of packets */ + nic->start_time = time(NULL); +- nic->flags &= ~NIC_UNITIALIZED; +- nic->flags |= NIC_INITIALIZED; +- nic->state &= ~NIC_STOPPED; +- nic->state |= NIC_RUNNING; ++ nic->state = NIC_RUNNING; + + nic->flags &= ~NIC_ENABLED_PENDING; + +@@ -1580,14 +1500,14 @@ skip: + + LOG_INFO(PFX "%s: entering main nic loop", nic->log_name); + +- while ((nic->state & NIC_RUNNING) && ++ 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->state == NIC_RUNNING) && + !(nic->flags & NIC_GOING_DOWN)) { + rc = process_packets(nic, + &periodic_timer, +@@ -1609,33 +1529,7 @@ dev_close: + } else { + pthread_mutex_destroy(&nic->xmit_mutex); + pthread_mutex_init(&nic->xmit_mutex, NULL); +- +- if (nic->flags & NIC_RESET_UIP) { +- nic_interface_t *nic_iface = nic->nic_iface; +- nic_interface_t *vlan_iface; +- while (nic_iface != NULL) { +- LOG_INFO(PFX "%s: resetting uIP stack", +- nic->log_name); +- uip_reset(&nic_iface->ustack); +- vlan_iface = nic_iface->vlan_next; +- while (vlan_iface != NULL) { +- LOG_INFO(PFX "%s: resetting " +- "vlan uIP stack", +- nic->log_name); +- uip_reset(&vlan_iface->ustack); +- vlan_iface = +- vlan_iface->vlan_next; +- } +- nic_iface = nic_iface->next; +- } +- nic->flags &= ~NIC_RESET_UIP; +- } + } +- +- nic->flags |= NIC_UNITIALIZED; +- nic->flags &= ~NIC_INITIALIZED; +- nic->flags &= ~NIC_ENABLED_PENDING; +- + nic->pending_count = 0; + + if (!(nic->flags & NIC_EXIT_MAIN_LOOP)) { +@@ -1643,6 +1537,9 @@ dev_close: + 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); +diff --git a/iscsiuio/src/unix/nic.h b/iscsiuio/src/unix/nic.h +index 57d89b4..da900c5 100644 +--- a/iscsiuio/src/unix/nic.h ++++ b/iscsiuio/src/unix/nic.h +@@ -67,6 +67,8 @@ extern struct nic_lib_handle *nic_lib_list; + extern pthread_mutex_t nic_list_mutex; + extern struct nic *nic_list; + ++extern void *nl_process_handle_thread(void *arg); ++ + /******************************************************************************* + * Constants + ******************************************************************************/ +@@ -117,20 +119,30 @@ struct nic_stats { + * 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 0x0001 ++#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; +- struct nic_interface *vlan_next; ++ ++ int iface_num; ++ int request_type; + } nic_interface_t; + + /****************************************************************************** +@@ -178,8 +190,9 @@ typedef struct nic_ops { + int (*clear_tx_intr) (struct nic *); + int (*handle_iscsi_path_req) (struct nic *, + int, +- struct iscsi_uevent * ev, +- struct iscsi_path * path); ++ struct iscsi_uevent *ev, ++ struct iscsi_path *path, ++ nic_interface_t *nic_iface); + } net_ops_t; + + typedef struct nic_lib_handle { +@@ -199,6 +212,9 @@ typedef struct nic { + #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 +@@ -214,7 +230,6 @@ typedef struct nic { + #define NIC_STOPPED 0x0001 + #define NIC_STARTED_RUNNING 0x0002 + #define NIC_RUNNING 0x0004 +-#define NIC_LONG_SLEEP 0x0008 + #define NIC_EXIT 0x0010 + + int fd; /* Holds the file descriptor to UIO */ +@@ -232,6 +247,7 @@ typedef struct nic { + + uint32_t intr_count; /* Total UIO interrupt count */ + ++ /* Held for nic ops manipulation */ + pthread_mutex_t nic_mutex; + + /* iSCSI ring ethernet MAC address */ +@@ -268,6 +284,7 @@ typedef struct nic { + + /* 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 */ +@@ -295,6 +312,19 @@ typedef struct nic { + 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; + + /****************************************************************************** +@@ -307,8 +337,6 @@ 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_add_vlan_iface(nic_t *nic, nic_interface_t *nic_iface, +- nic_interface_t *vlan_iface); + int nic_process_intr(nic_t *nic, int discard_check); + + nic_interface_t *nic_iface_init(); +@@ -339,14 +367,6 @@ int enable_multicast(nic_t * nic); + int disable_multicast(nic_t * nic); + + void nic_set_all_nic_iface_mac_to_parent(nic_t * nic); +-struct nic_interface *nic_find_nic_iface(nic_t * nic, uint16_t vlan_id); +-struct nic_interface *nic_find_nic_iface_protocol(nic_t * nic, +- uint16_t vlan_id, +- uint16_t protocol); +-struct nic_interface *nic_find_vlan_iface_protocol(nic_t *nic, +- nic_interface_t *nic_iface, +- uint16_t vlan_id, +- uint16_t protocol); + int find_nic_lib_using_pci_id(uint32_t vendor, uint32_t device, + uint32_t subvendor, uint32_t subdevice, + nic_lib_handle_t ** handle, +diff --git a/iscsiuio/src/unix/nic_nl.c b/iscsiuio/src/unix/nic_nl.c +index 971f350..34e2062 100644 +--- a/iscsiuio/src/unix/nic_nl.c ++++ b/iscsiuio/src/unix/nic_nl.c +@@ -83,20 +83,6 @@ const static struct sockaddr_nl dest_addr = { + /* Netlink */ + int nl_sock = INVALID_FD; + +-/* Items used to handle the thread used to send/process ARP's */ +-static pthread_t nl_process_thread; +-static 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 = 0; +- +-#define NL_PROCESS_MAX_RING_SIZE 128 +-#define NL_PROCESS_LAST_ENTRY NL_PROCESS_MAX_RING_SIZE - 1 +-#define NL_PROCESS_NEXT_ENTRY(x) ((x + 1) & NL_PROCESS_MAX_RING_SIZE) +-static int nl_process_head; +-static int nl_process_tail; +-static void *nl_process_ring[NL_PROCESS_MAX_RING_SIZE]; +- + #define MAX_TX_DESC_CNT (TX_DESC_CNT - 1) + + #define NEXT_TX_BD(x) (((x) & (MAX_TX_DESC_CNT - 1)) == \ +@@ -222,10 +208,11 @@ int __kipc_call(int fd, void *iov_base, int iov_len) + static int pull_from_nl(char **buf) + { + int rc; +- size_t ev_size; ++ 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, +@@ -249,14 +236,26 @@ static int pull_from_nl(char **buf) + return -EINVAL; + } + +- data = (char *)malloc(nlh->nlmsg_len); ++ 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", nlh->nlmsg_len); ++ "iSCSI message", alloc_size); + return -ENOMEM; + } + +- memset(data, 0, nlh->nlmsg_len); ++ memset(data, 0, alloc_size); + ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr)); + rc = nl_read(nl_sock, data, (int)nlh->nlmsg_len, MSG_WAITALL); + if (rc <= 0) { +@@ -269,10 +268,9 @@ static int pull_from_nl(char **buf) + + goto error; + } +- + *buf = data; + return 0; +- error: ++error: + if (data != NULL) + free(data); + +@@ -284,9 +282,8 @@ const static struct timespec ctldev_sleep_req = { + .tv_nsec = 250000000, + }; + +-static int ctldev_handle(char *data) ++static int ctldev_handle(char *data, nic_t *nic) + { +- nic_t *nic = NULL; + int rc; + struct iscsi_uevent *ev; + uint8_t *payload; +@@ -294,18 +291,12 @@ static int ctldev_handle(char *data) + char *msg_type_str; + uint32_t host_no; + 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"; +- +- host_no = ev->r.req_path.host_no; +- break; +- case ISCSI_KEVENT_IF_DOWN: +- msg_type_str = "if_down"; +- +- host_no = ev->r.notify_if_down.host_no; + break; + default: + /* We don't care about other iSCSI Netlink messages */ +@@ -315,22 +306,16 @@ static int ctldev_handle(char *data) + } + + /* This is a message that drivers should be interested in */ +- LOG_INFO("Received: '%s': host_no: %d", msg_type_str, host_no); +- +- rc = from_host_no_find_associated_eth_device(host_no, &nic); +- if (rc != 0) { +- LOG_ERR(PFX "Dropping msg, couldn't find nic with host no:%d", +- host_no); +- goto error; +- } ++ 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 *nic_iface, *vlan_iface; ++ nic_interface_t *vlan_iface; + uint16_t ip_type; ++ int iface_num, vlan_id; + + if (path->ip_addr_len == 4) + ip_type = AF_INET; +@@ -339,67 +324,107 @@ static int ctldev_handle(char *data) + else + ip_type = 0; + +- /* Find the parent nic_iface */ +- nic_iface = nic_find_nic_iface_protocol(nic, 0, ip_type); ++ /* Find the nic_iface to use */ ++ iface_num = ev->r.req_path.iface_num ? ++ ev->r.req_path.iface_num : IFACE_NUM_INVALID; ++ 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) { +- LOG_ERR(PFX "%s: Couldn't find nic iface " +- "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 (path->vlan_id) { +- vlan_iface = nic_find_vlan_iface_protocol(nic, +- nic_iface, path->vlan_id, ip_type); +- if (vlan_iface == NULL) { +- /* Create a vlan_iface */ +- vlan_iface = nic_iface_init(); +- if (vlan_iface == NULL) { +- LOG_ERR(PFX "%s: Couldn't allocate " +- "space for vlan: %d ip_type: " +- "%d ip_addr_len: %d", +- nic->log_name, path->vlan_id, +- ip_type, path->ip_addr_len); +- goto error; ++ 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; + } +- +- vlan_iface->protocol = ip_type; +- vlan_iface->vlan_id = path->vlan_id; +- nic_add_vlan_iface(nic, nic_iface, vlan_iface); +- +- /* TODO: When VLAN support is placed in */ +- /* the iface file revisit this code */ +- 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_all_nic_iface(nic); +- nic_disable(nic, 0); +- nic_iface = vlan_iface; ++ /* 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; ++ ++ 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->flags & NIC_ENABLED_PENDING)) ++ 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) == NIC_RUNNING) { ++ if (nic->state == NIC_RUNNING) { + rc = 0; + break; + } +@@ -418,49 +443,25 @@ static int ctldev_handle(char *data) + } + + if (nic->ops) { +- char eth_device_name[IFNAMSIZ]; +- + switch (ev->type) { + case ISCSI_KEVENT_PATH_REQ: + /* pass the request up to the user space + * library driver */ +- if (nic->ops->handle_iscsi_path_req) { ++ 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); +- } +- +- LOG_INFO(PFX "%s: 'path_req' operation finished", +- nic->log_name); +- +- rc = 0; +- break; +- case ISCSI_KEVENT_IF_DOWN: +- memcpy(eth_device_name, nic->eth_device_name, +- sizeof(eth_device_name)); +- +- pthread_mutex_lock(&nic_list_mutex); +- ++ path, ++ nic_iface); ++ nic_iface->flags &= ~NIC_IFACE_PATHREQ_WAIT; + pthread_mutex_lock(&nic->nic_mutex); +- nic->flags |= NIC_EXIT_MAIN_LOOP; ++ nic->flags &= ~NIC_PATHREQ_WAIT; + pthread_mutex_unlock(&nic->nic_mutex); +- +- pthread_cond_broadcast(&nic->enable_done_cond); +- +- nic_disable(nic, 1); +- +- nic_remove(nic); +- pthread_mutex_unlock(&nic_list_mutex); +- +- pthread_mutex_lock(&nl_process_mutex); +- nl_process_if_down = 0; +- pthread_mutex_unlock(&nl_process_mutex); ++ LOG_INFO(PFX "%s: 'path_req' operation finished", ++ nic->log_name); + + rc = 0; +- +- LOG_INFO(PFX "%s: 'if_down' operation finished", +- eth_device_name); +- + break; + default: + rc = -EAGAIN; +@@ -468,55 +469,62 @@ static int ctldev_handle(char *data) + } + } + +- error: ++error: + + return rc; + } + +-static void *nl_process_handle_thread(void *arg) ++/* 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(&nl_process_cond, &nl_process_mutex); ++ 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 = nl_process_ring[nl_process_head]; +- nl_process_ring[nl_process_head] = NULL; +- nl_process_tail = NL_PROCESS_NEXT_ENTRY(nl_process_tail); ++ 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(&nl_process_mutex); ++ pthread_mutex_unlock(&nic->nl_process_mutex); + + if (data) { +- ctldev_handle(data); ++ ctldev_handle(data, nic); + free(data); + } + } +- ++error: + return NULL; + } + +-static void flush_nl_process_ring() ++static void flush_nic_nl_process_ring(nic_t *nic) + { + int i; + +- for (i = 0; i < NL_PROCESS_MAX_RING_SIZE; i++) { +- if (nl_process_ring[i] != NULL) { +- free(nl_process_ring[i]); +- nl_process_ring[i] = NULL; ++ 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; + } + } + +- nl_process_head = 0; +- nl_process_tail = 0; ++ nic->nl_process_head = 0; ++ nic->nl_process_tail = 0; + +- LOG_DEBUG(PFX "Flushed NL ring"); ++ LOG_DEBUG(PFX "%s: Flushed NIC NL ring", nic->log_name); + } + + /** +@@ -528,25 +536,9 @@ static void flush_nl_process_ring() + int nic_nl_open() + { + int rc; ++ char *msg_type_str; + +- /* Prepare the thread to issue the ARP's */ +- nl_process_head = 0; +- nl_process_tail = 0; +- nl_process_if_down = 0; +- memset(&nl_process_ring, 0, sizeof(nl_process_ring)); +- +- pthread_mutex_init(&nl_process_mutex, NULL); +- pthread_cond_init(&nl_process_cond, NULL); +- pthread_cond_init(&nl_process_if_down_cond, NULL); +- +- rc = pthread_create(&nl_process_thread, NULL, +- nl_process_handle_thread, NULL); +- if (rc != 0) { +- LOG_ERR("Could not create NL processing thread [%s]", +- strerror(rc)); +- return -EIO; +- } +- ++ /* 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]", +@@ -581,6 +573,8 @@ int nic_nl_open() + 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) +@@ -588,33 +582,91 @@ int nic_nl_open() + + /* Try to abort ARP'ing if a if_down was recieved */ + ev = (struct iscsi_uevent *)NLMSG_DATA(buf); +- if (ev->type == ISCSI_KEVENT_IF_DOWN) { +- LOG_INFO(PFX "Received if_down event"); ++ 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); + +- pthread_mutex_lock(&nl_process_mutex); +- /* Don't flush the nl ring if another if_down +- is in progress */ +- if (!nl_process_if_down) { +- nl_process_if_down = 1; ++ /* Make sure the nic list doesn't get yanked */ ++ pthread_mutex_lock(&nic_list_mutex); + +- flush_nl_process_ring(); +- } +- pthread_mutex_unlock(&nl_process_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 ((nl_process_head + 1 == nl_process_tail) || +- (nl_process_tail == 0 && +- nl_process_head == NL_PROCESS_LAST_ENTRY)) { +- LOG_WARN(PFX "No space on Netlink ring"); ++ 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_lock(&nl_process_mutex); +- nl_process_ring[nl_process_head] = buf; +- nl_process_head = NL_PROCESS_NEXT_ENTRY(nl_process_head); ++ pthread_mutex_unlock(&nic->nl_process_mutex); + +- pthread_cond_signal(&nl_process_cond); +- pthread_mutex_unlock(&nl_process_mutex); ++ pthread_mutex_unlock(&nic_list_mutex); + + LOG_DEBUG(PFX "Pulled nl event"); + } +diff --git a/iscsiuio/src/unix/nic_utils.c b/iscsiuio/src/unix/nic_utils.c +index fe58df8..a1d3e72 100644 +--- a/iscsiuio/src/unix/nic_utils.c ++++ b/iscsiuio/src/unix/nic_utils.c +@@ -65,7 +65,7 @@ + *****************************************************************************/ + 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"; ++ "/sys/class/uio/uio%d/event"; + static const char base_uio_sysfs_name[] = "/sys/class/uio/"; + static const char uio_name[] = "uio"; + +@@ -77,7 +77,7 @@ 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"; ++ "/sys/class/iscsi_host/host%d/netdev"; + static const char cnic_uio_sysfs_resc_template[] = + "/sys/class/uio/uio%i/device/resource%i"; + +@@ -208,6 +208,7 @@ int nic_discover_iscsi_hosts() + + default: + /* There are iSCSI hosts */ ++ pthread_mutex_lock(&nic_list_mutex); + for (i = 0; i < count; i++) { + int host_no; + char *raw = NULL; +@@ -267,6 +268,7 @@ int nic_discover_iscsi_hosts() + + free(raw); + } ++ pthread_mutex_unlock(&nic_list_mutex); + + /* Cleanup the scandir() call */ + for (i = 0; i < count; i++) +@@ -402,6 +404,7 @@ static char *extract_none(struct dirent **files) + /** + * 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 +@@ -431,7 +434,6 @@ int from_host_no_find_associated_eth_device(int host_no, nic_t ** nic) + + rc = -EIO; + +- pthread_mutex_lock(&nic_list_mutex); + current_nic = nic_list; + while (current_nic != NULL) { + if (strcmp(raw, current_nic->eth_device_name) == 0) { +@@ -442,7 +444,6 @@ int from_host_no_find_associated_eth_device(int host_no, nic_t ** nic) + + current_nic = current_nic->next; + } +- pthread_mutex_unlock(&nic_list_mutex); + + free(raw); + +@@ -923,7 +924,7 @@ int nic_enable(nic_t * nic) + nic->log_name, nic->flags, nic->state); + return -EINVAL; + } +- if (nic->state & NIC_STOPPED) { ++ if (nic->state == NIC_STOPPED) { + struct timespec ts; + struct timeval tp; + int rc; +@@ -940,48 +941,20 @@ int nic_enable(nic_t * nic) + rc = gettimeofday(&tp, NULL); + ts.tv_sec = tp.tv_sec; + ts.tv_nsec = tp.tv_usec * 1000; +- ts.tv_sec += 10; ++ ts.tv_sec += 100; + + /* Wait for the device to be enabled */ + rc = pthread_cond_timedwait(&nic->enable_done_cond, + &nic->nic_mutex, &ts); +-#if 0 +- if (rc || !nic->flags & NIC_ENABLED) { +- /* Give it one more shout */ +- pthread_cond_broadcast(&nic->enable_wait_cond); +- rc = gettimeofday(&tp, NULL); +- ts.tv_sec = tp.tv_sec; +- ts.tv_nsec = tp.tv_usec * 1000; +- ts.tv_sec += 5; +- rc = pthread_cond_timedwait(&nic->enable_done_cond, +- &nic->nic_mutex, &ts); +- } +-#endif +- nic->flags &= ~NIC_ENABLED_PENDING; +- + if (rc == 0 && nic->flags & NIC_ENABLED) { + LOG_DEBUG(PFX "%s: device enabled", nic->log_name); + } else { +- LOG_ERR(PFX "%s: waiting to finish nic_enable err:%s", ++ 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)); +- /* Must clean up the ustack */ +- nic_interface_t *nic_iface = nic->nic_iface; +- nic_interface_t *vlan_iface; +- while (nic_iface != NULL) { +- LOG_INFO(PFX "%s: resetting uIP stack", +- nic->log_name); +- uip_reset(&nic_iface->ustack); +- vlan_iface = nic_iface->vlan_next; +- while (vlan_iface != NULL) { +- LOG_INFO(PFX "%s: resetting " +- "vlan uIP stack", +- nic->log_name); +- uip_reset(&vlan_iface->ustack); +- vlan_iface = +- vlan_iface->vlan_next; +- } +- nic_iface = nic_iface->next; +- } + } + pthread_mutex_unlock(&nic->nic_mutex); + +@@ -1001,7 +974,8 @@ int nic_enable(nic_t * nic) + */ + int nic_disable(nic_t * nic, int going_down) + { +- if (nic->state & (NIC_STARTED_RUNNING | NIC_RUNNING)) { ++ if (nic->state == NIC_STARTED_RUNNING || ++ nic->state == NIC_RUNNING) { + struct timespec ts; + struct timeval tp; + int rc; +@@ -1012,8 +986,7 @@ int nic_disable(nic_t * nic, int going_down) + nic->flags &= ~NIC_ENABLED; + nic->flags |= NIC_DISABLED; + nic->flags &= ~NIC_STARTED_RUNNING; +- nic->state &= ~NIC_RUNNING; +- nic->state |= NIC_STOPPED; ++ nic->state = NIC_STOPPED; + + if (going_down) + nic->flags |= NIC_GOING_DOWN; +@@ -1070,7 +1043,9 @@ void nic_remove_all() + 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; + } +@@ -1127,14 +1102,13 @@ error: + * 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) ++void nic_set_all_nic_iface_mac_to_parent(nic_t *nic) + { + nic_interface_t *current, *vlan_current; + +- pthread_mutex_lock(&nic->nic_mutex); +- + current = nic->nic_iface; + while (current != NULL) { + /* Set the initial MAC address of this interface to the parent +@@ -1148,8 +1122,6 @@ void nic_set_all_nic_iface_mac_to_parent(nic_t * nic) + } + current = current->next; + } +- +- pthread_mutex_unlock(&nic->nic_mutex); + } + + /******************************************************************************* +@@ -1272,143 +1244,144 @@ void nic_fill_ethernet_header(nic_interface_t * nic_iface, + * 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 +- * @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 vlan_id) +-{ +- nic_interface_t *current; +- +- pthread_mutex_lock(&nic->nic_mutex); +- +- current = nic->nic_iface; +- while (current != NULL) { +- if (current->vlan_id == vlan_id) { +- pthread_mutex_unlock(&nic->nic_mutex); +- return current; +- } +- +- current = current->next; +- } +- +- pthread_mutex_unlock(&nic->nic_mutex); +- +- return NULL; +-} +- +-/** +- * nic_find_nic_iface_protocol() - This function is used to find an interface +- * from the NIC ++ * 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_protocol(nic_t * nic, +- uint16_t vlan_id, +- uint16_t protocol) ++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_interface_t *current = nic->nic_iface; ++ nic_interface_t *current_vlan = NULL; + +- pthread_mutex_lock(&nic->nic_mutex); +- +- current = nic->nic_iface; + while (current != NULL) { +- if ((current->vlan_id == vlan_id) && +- (current->protocol == protocol)) { +- pthread_mutex_unlock(&nic->nic_mutex); +- return current; ++ 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; + } +- +- pthread_mutex_unlock(&nic->nic_mutex); +- +- return NULL; ++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_iface; +- +- pthread_mutex_lock(&nic->nic_mutex); ++ nic_interface_t *current_vlan, *current; + + current = nic->nic_iface; + while (current != NULL) { + current->flags |= NIC_IFACE_PERSIST; +- vlan_iface = current->vlan_next; +- while (vlan_iface != NULL) { +- vlan_iface->flags |= NIC_IFACE_PERSIST; +- vlan_iface = vlan_iface->vlan_next; ++ current_vlan = current->vlan_next; ++ while (current_vlan != NULL) { ++ current_vlan->flags |= NIC_IFACE_PERSIST; ++ current_vlan = current_vlan->vlan_next; + } + current = current->next; + } +- +- pthread_mutex_unlock(&nic->nic_mutex); +-} +- +-/** +- * nic_find_vlan_iface_protocol() - This function is used to find an interface +- * from the NIC +- * @param nic_iface - Base NIC to look for the vlan interfaces +- * @param vlan_id - VLAN id to look for +- * @param protocol - either AF_INET or AF_INET6 +- * @return nic_iface - if found network interface with the given VLAN ID +- * if not found a NULL is returned +- */ +-nic_interface_t *nic_find_vlan_iface_protocol(nic_t *nic, +- nic_interface_t *nic_iface, +- uint16_t vlan_id, +- uint16_t protocol) +-{ +- nic_interface_t *current; +- +- pthread_mutex_lock(&nic->nic_mutex); +- +- current = nic_iface->vlan_next; +- while (current != NULL) { +- if ((current->vlan_id == vlan_id) && +- (current->protocol == protocol)) { +- pthread_mutex_unlock(&nic->nic_mutex); +- return current; +- } +- current = current->vlan_next; +- } +- +- pthread_mutex_unlock(&nic->nic_mutex); +- return NULL; + } + ++/* 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; + +- pthread_mutex_lock(&nic->nic_mutex); +- +- if (nic->nic_iface == nic_iface) +- goto done; +- +- prev = nic->nic_iface; +- current = nic->nic_iface->next; ++ prev = NULL; ++ current = nic->nic_iface; + while (current != NULL) { +- if (current == nic_iface) { +- prev->next = current->next; +- current->next = nic->nic_iface; +- nic->nic_iface = current; ++ 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: +- pthread_mutex_unlock(&nic->nic_mutex); ++ return; + } ++ + /******************************************************************************* + * Packet management utility functions + ******************************************************************************/ +@@ -1639,7 +1612,7 @@ int capture_file(char **raw, uint32_t * raw_size, const char *path) + } + + read_size = fread(*raw, file_size, 1, fp); +- if (read_size < 0) { ++ if (!read_size) { + LOG_ERR("Could not read capture, path: %s len: %d [%s]", + path, file_size, strerror(ferror(fp))); + free(*raw); +diff --git a/iscsiuio/src/unix/nic_utils.h b/iscsiuio/src/unix/nic_utils.h +index ff76f6b..6c57701 100644 +--- a/iscsiuio/src/unix/nic_utils.h ++++ b/iscsiuio/src/unix/nic_utils.h +@@ -67,7 +67,9 @@ void nic_fill_ethernet_header(nic_interface_t * nic_iface, + int *pkt_size, void **start_addr, + uint16_t ether_type); + +-nic_interface_t *nic_find_nic_iface(nic_t * nic, uint16_t vlan_id); ++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); +diff --git a/iscsiuio/src/unix/nic_vlan.c b/iscsiuio/src/unix/nic_vlan.c +index 4f8f551..90a6244 100644 +--- a/iscsiuio/src/unix/nic_vlan.c ++++ b/iscsiuio/src/unix/nic_vlan.c +@@ -332,7 +332,8 @@ int find_vlans_using_phy_interface(struct vlan_handle *handle, + */ + int valid_vlan(short int vlan) + { +- if (vlan > 1 && vlan < 4095) ++ /* Allow vlan 1 to connect */ ++ if (vlan > 0 && vlan < 4095) + return 1; + + return 0; +diff --git a/iscsiuio/src/unix/packet.c b/iscsiuio/src/unix/packet.c +index 4d8bf55..5047030 100644 +--- a/iscsiuio/src/unix/packet.c ++++ b/iscsiuio/src/unix/packet.c +@@ -88,7 +88,7 @@ void free_packet(struct packet *pkt) + * reset_packet() - This will reset the packet fields to default values + * @param pkt - the packet to reset + */ +-void reset_packet(packet_t * pkt) ++void reset_packet(packet_t *pkt) + { + pkt->next = NULL; + +@@ -101,7 +101,7 @@ void reset_packet(packet_t * pkt) + pkt->network_layer = NULL; + } + +-int alloc_free_queue(nic_t * nic, size_t num_of_packets) ++int alloc_free_queue(nic_t *nic, size_t num_of_packets) + { + int rc, i; + diff --git a/iscsi-initiator-utils.spec b/iscsi-initiator-utils.spec index 3ea7d4e..b8edae4 100644 --- a/iscsi-initiator-utils.spec +++ b/iscsi-initiator-utils.spec @@ -3,7 +3,7 @@ Summary: iSCSI daemon and utility programs Name: iscsi-initiator-utils Version: 6.2.0.872 -Release: 41%{?dist} +Release: 42%{?dist} Source0: http://people.redhat.com/mchristi/iscsi/rhel6.0/source/open-iscsi-2.0-872-rc4-bnx2i.tar.gz Source1: iscsid.init Source2: iscsidevs.init @@ -41,6 +41,8 @@ Patch12: iscsi-initiator-utils-ping-and-chap.patch Patch13: iscsi-initiator-utils-mod-iface-andport-fixes.patch # add rhel version info to iscsi tools Patch14: iscsi-initiator-utils-add-rh-ver.patch +# sync brcm to 0.7.4.3 +Patch15: iscsi-initiator-utils-sync-uio-0.7.4.3.patch Group: System Environment/Daemons License: GPLv2+ @@ -83,6 +85,7 @@ developing applications that use %{name}. %patch12 -p1 -b .ping-and-chap %patch13 -p1 -b .mod-iface-andport-fixes %patch14 -p1 -b .add-rh-ver +%patch15 -p1 -b .sync-uio-0.7.4.3 %build cd utils/open-isns @@ -208,6 +211,9 @@ fi %{_includedir}/libiscsi.h %changelog +* Wed Oct 10 2012 Chris Leech - 6.2.0.872-42 +- 826300 sync iscsiuio to 0.7.4.3 + * Thu Apr 5 2012 Mike Christie 6.2.0.872.41 - 810197 Coverity fixes. - 740054 fix iscsiuio version string