929689a76c
add patch to improve GIL lock performance in libiscsi split Python 2 and Python 3 bindings out into subpackages
40804 lines
1.2 MiB
40804 lines
1.2 MiB
From 8353acb54ebc03da23b5fc904ff58513bd90a8b3 Mon Sep 17 00:00:00 2001
|
|
From: Chris Leech <cleech@redhat.com>
|
|
Date: Tue, 9 Jun 2015 10:09:25 -0700
|
|
Subject: [PATCH] sync to 2.0.873-134-g6aa2c9b
|
|
|
|
71cd021 iscsid: fix iscsid segfault during qla4xxx login
|
|
f0a8c95 ISCSISTART: Bring up the corresponding network interface for iboot
|
|
d81fd49 iscsi tools: fix compile error when OFFLOAD_BOOT_SUPPORT defined
|
|
13d08e7 ISCSID: Passing more net params from ibft to iface
|
|
9dd181d iscsi tools: Convert '-r' argument to an integer before checking if it is a path
|
|
97db3db Update README for removal of DBM requirement
|
|
2d086a8 iscsid,iscsiadm: fix abstract socket length in bind() call
|
|
5d0e19f iscsid: implement systemd-compatible socket activation
|
|
c34e0bd iscsid: add example unit files for systemd
|
|
a7afdf4 iscsi tools: fix get_random_bytes error handling
|
|
d571cdf ISCSID: Added socket communication hooks for uip
|
|
b255332 ISCSID: Modified the Makefile for iscsiuio compilation
|
|
fcab9b7 ISCSID: Added iscsiuio source to the open-iscsi pkg
|
|
42fa258 From: Adheer Chandravanshi <adheer.chandravanshi@qlogic.com>
|
|
d64f50d Manpage changes for flashnode submode support for host mode.
|
|
3584b98 README changes for flashnode submode support for host mode.
|
|
fdac390 PATCH 1 of 1] correctly check return value of nice()
|
|
6674fd4 Allow firmware mode to use debug flag
|
|
fc2a8e9 iscsiadm: return error when login fails
|
|
8b33814 iscsiadm: bind ifaces to portals found using isns
|
|
ff4b2c1 iscsiadm: Check for mode is not required when creating params list
|
|
83d31c7 iscsid/iscsiadm: add support for emulex one connect storage
|
|
9a2bc38 ISCSIUIO: Updated iscsiuio to version 0.7.8.1b for perf optimization
|
|
d9e26d3 Fix discovery error return without return value
|
|
b0ba4d6 iscsid: Fix strlen parameter
|
|
3d7df63 iscsiuio: Change socket bind to use the same struct size as iscsid
|
|
bf39941 [PATCH] Make rescan run in parallel
|
|
3256b93 iscsiadm: Correctly check for invalid hostno and flashnode index
|
|
181af9a iscsi tools: Print additional session info for flashnode session
|
|
82c8533 iscsi tools: sync iscsi_if.h with kernel space
|
|
5992173 [PATCH v5 1/3] ISCSISTART: Saved ibft boot info to the session
|
|
487c312 ISCSID: Added the extraction of the session boot info
|
|
3b4b450 ISCSID: Added iface content override fix
|
|
1fa1b51 iscsi tools: Bug fix on IPC address copy (version 2)
|
|
360a40f flashnode: Add support to set ISCSI_FLASHNODE_CHAP_OUT_IDX param
|
|
b3913c5 iscsiadm: Use '-x' option instead of '-v' to specify chap_tbl_idx
|
|
0c4022d iscsiadm: Man page changes to use -x option for chap_tbl_idx
|
|
38b2993 README changes to use long option --index instead of --flashnode_idx
|
|
062718a iscsiadm: Add support to set CHAP entry using host chap mode
|
|
65ce3a2 iscsi tools: Correctly get username_in and password_in flashnode params
|
|
f1ed1f7 README changes for adding support to set CHAP entry
|
|
0a95bc4 iscsi tools: Setup iface conf file with all iface attrs exported in sysfs
|
|
026c8d7 iscsi_if.h: Remove numbers used for network parameter settings
|
|
d1e07af iscsi_if.h: Additional parameters for network param settings
|
|
466efaa iscsi tools: Use macro to set IPv4/IPv6 IP addresses
|
|
2220ee4 iscsi tools: Use single function to enable/disable network parameters
|
|
d8991c9 iscsi tools: Use single function to set integer network parameters
|
|
da404f2 iscsi tools: Ignore network parameter if not enabled/disabled
|
|
66d9f12 iscsi tools: Additional parameters for network settings
|
|
9260457 iscsi tools: iface params should be updated for node_rec as well.
|
|
75ee9d0 iscsi tools: Let default type of iface be ipv4
|
|
4a5e9e2 iscsi tools: Show iface params based on iface type
|
|
072d8b9 iscsiadm: Added document for description of iface attributes
|
|
fe66238 iscsi_tool: Add offload host statistics support.
|
|
d1e8e68 README: Updated for host statistics.
|
|
4a3076b iscsiadm.8: Updated man page for host statistics.
|
|
77245b9 ISCSIUIO: Added tx doorbell override mechanism
|
|
df68365 ISCSIUIO: Added fix for the iface.subnet_mask decoding for IPv6
|
|
817a083 ISCSIUIO: Added fix for the ARP cache flush mechanism
|
|
eb1d275 ISCSIUIO: Updated RELEASE note and version
|
|
9bd6fba ISCSIUIO: Updated the configure file to reflect the new version
|
|
505ed9d iscsi tools: Fix the iscsiadm help options for host mode
|
|
bd91b81 Man page correction for host mode options of iscsiadm
|
|
5f2f3d7 ISCSIUIO: Removed the auto-generated COPYING file
|
|
2b4a011 iscsiuio: Remove autogenerated files from tracking
|
|
91cc9c3 iscsiuio: Update automake files
|
|
c8113ad iscsiuio: Add .gitignore files
|
|
a877c9d iscsiuio: fix compilation
|
|
9ef01a7 Add missing DESTDIR
|
|
ea05be3 iscsi tools: set non negotiated params early.
|
|
f2ecc22 iscsiadm: Fix the hostno check for stats submode of host mode
|
|
b152630 iscsiadm: Fix the compile time warning
|
|
fabe160 ISCSIUIO: Fixed a pthread resc leak from excessive session recovery
|
|
36a8b41 iscsid: Fix handling of iscsi async events.
|
|
5f28b8b be2iscsi: Fix MaxXmitDataLenght of the driver.
|
|
e696b94 Fix StatSN in Open-iSCSI Stack.
|
|
c0e509e iscsid: retry login for ISCSI_ERR_HOST_NOT_FOUND
|
|
134f8dc iscsid: Fix double close of mgmt ipc fd
|
|
5762ac0 iscsiadm: Initialize param_count in set_host_chap_info
|
|
33cb16e iscsiuio: Rebranding iscsiuio
|
|
96eaaac iscsiadm : make iface.ipaddress optional in iface configs for transports that don't have a hard requirement on it.
|
|
21a7923 Remove unused variable 'path'
|
|
78e24f5 Parse 'origin' value from iBFT
|
|
c9d830b isns: Add docs for deregistering discovery domains.
|
|
147db3c Added new utility script to generate initiator name
|
|
76a441b Added new util script to aid in CNA setup
|
|
f6d7d30 iscsid: don't round up when modifying padding len
|
|
06309ad Fix build warnings for unused variables
|
|
9c5be24 Fix warning about possibly-uninitialized variable
|
|
e253c9a Fix bad sizeof in memset
|
|
6f6f2a0 Fix missing header
|
|
769b480 iscsiuio: Fix warning about non-matching types
|
|
d58864c iscsiuio: Fix strict-aliasing warning with struct mac_address
|
|
f7d4c02 iscsiuio: Resolve strict aliasing issue in iscsiuio/src/unix/nic.c
|
|
cd3d245 iscsiuio: Fix aliasing issue with IPV6_IS_ADDR_UNSPECIFIED
|
|
e2c9c58 iscsiuio: Use attribute(unused) for variables that are unused but needed
|
|
0a253d7 iscsiuio: Use attribute(unused) for *icmpv6_hdr
|
|
366f2f8 iscsiuio: Change nic_disable to return void
|
|
957ce0b iscsiuio: Remove set but unused variables
|
|
0fbf555 iscsiuio: Check return value from nic_queue_tx_packet
|
|
a125761 Code cleanup: no functional changes
|
|
4959a89 Represent DHCP "origin" as an enum, not a string.
|
|
defd640 fwparam_ibft: Check iBFT target and NIC flags
|
|
b8bb7ba Allow modifications for iface.gateway and iface.subnet_mask
|
|
6c14016 actor: Mark actor_check static
|
|
22c5038 actor: simplify actor_check
|
|
5e7f696 actor: s/ACTOR_TICKS/actor_jiffies/
|
|
86b919e actor: Remove ACTOR_TICKS_10MS()
|
|
4190b2d actor: Unobfuscate ACTOR_MAX_LOOPS
|
|
4b5c01e actor: Simplify actor_poll a little
|
|
9981b06 Remove actor_init and rename actor_new to actor_init
|
|
6385e2d Make running actors event-driven
|
|
052fa50 Wake up to reap children
|
|
2966a92 fix regression in iscsi_tcp iface binding
|
|
51c0b6e Supply strings for newly-added error numbers
|
|
892ddaf Allow setting host params to return EAGAIN errors.
|
|
c7fbcd7 guard against NULL ptr during discovery from unexpected event
|
|
7acba59 add discovery as a valid mode in iscsiadm.8
|
|
bc9b5c3 iscsid: fix order of setting uid/gid and drop supplementary groups
|
|
40616d1 iscsiuio CFLAGS fixes
|
|
32e2349 iscsiuio systemd socket activation support
|
|
def3161 Fix incorrect list operation leading to out-of-order items on pend_list
|
|
9297a47 Prevent spinning over poll() when reconnecting to an inaccessible target
|
|
c02b558 Add some more debug logging to actor.c
|
|
63d086c iscsid safe session logout
|
|
006270c iscsid: don't re-read config file for every session logout
|
|
a277d31 Remove duplicate newlines in log messages.
|
|
8da14e6 Fix iBFT target flags check.
|
|
3d04497 Fix small typo in iscsid.conf
|
|
4a4498b buildsys: make 'make clean' idempotent
|
|
da2473d buildsys: respect CFLAGS and LDFLAGS from the outside
|
|
312e904 Remove outdated Debian packaging code.
|
|
df602f0 Spelling and escaping error fixes.
|
|
6aa2c9b Reformat man page synopsis sections
|
|
---
|
|
Makefile | 39 +-
|
|
README | 142 +-
|
|
debian/README.Debian | 44 -
|
|
debian/changelog | 6 -
|
|
debian/compat | 1 -
|
|
debian/control | 27 -
|
|
debian/control.modules.in | 20 -
|
|
debian/copyright | 12 -
|
|
debian/dirs | 3 -
|
|
debian/docs | 4 -
|
|
debian/postinst.modules.in | 11 -
|
|
debian/rules | 152 --
|
|
debian/rules.modules | 39 -
|
|
doc/iscsi_discovery.8 | 12 +-
|
|
doc/iscsiadm.8 | 210 +-
|
|
etc/iscsid.conf | 5 +-
|
|
etc/systemd/iscsid.service | 13 +
|
|
etc/systemd/iscsid.socket | 9 +
|
|
include/fw_context.h | 15 +
|
|
include/iscsi_err.h | 4 +
|
|
include/iscsi_if.h | 468 ++++-
|
|
include/iscsi_proto.h | 1 +
|
|
include/list.h | 6 +
|
|
iscsiuio/.gitignore | 25 +
|
|
iscsiuio/AUTHORS | 0
|
|
iscsiuio/ChangeLog | 7 +
|
|
iscsiuio/INSTALL | 290 +++
|
|
iscsiuio/Makefile.am | 25 +
|
|
iscsiuio/NEWS | 0
|
|
iscsiuio/README | 224 ++
|
|
iscsiuio/RELEASE.TXT | 2032 ++++++++++++++++++
|
|
iscsiuio/configure.ac | 78 +
|
|
iscsiuio/docs/iscsiuio.8 | 89 +
|
|
iscsiuio/iscsiuiolog | 10 +
|
|
iscsiuio/src/Makefile.am | 1 +
|
|
iscsiuio/src/README | 13 +
|
|
iscsiuio/src/apps/Makefile.am | 1 +
|
|
iscsiuio/src/apps/README | 2 +
|
|
iscsiuio/src/apps/brcm-iscsi/Makefile.am | 13 +
|
|
iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi | 1 +
|
|
iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c | 89 +
|
|
iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h | 91 +
|
|
iscsiuio/src/apps/dhcpc/Makefile.am | 13 +
|
|
iscsiuio/src/apps/dhcpc/Makefile.dhcpc | 1 +
|
|
iscsiuio/src/apps/dhcpc/dhcpc.c | 417 ++++
|
|
iscsiuio/src/apps/dhcpc/dhcpc.h | 86 +
|
|
iscsiuio/src/apps/dhcpc/dhcpv6.c | 512 +++++
|
|
iscsiuio/src/apps/dhcpc/dhcpv6.h | 253 +++
|
|
iscsiuio/src/uip-1.0-changelog.txt | 98 +
|
|
iscsiuio/src/uip/Makefile.am | 18 +
|
|
iscsiuio/src/uip/Makefile.include | 47 +
|
|
iscsiuio/src/uip/clock.h | 87 +
|
|
iscsiuio/src/uip/debug.h | 13 +
|
|
iscsiuio/src/uip/icmpv6.h | 302 +++
|
|
iscsiuio/src/uip/ipv6.c | 1297 ++++++++++++
|
|
iscsiuio/src/uip/ipv6.h | 332 +++
|
|
iscsiuio/src/uip/ipv6_ndpc.c | 427 ++++
|
|
iscsiuio/src/uip/ipv6_ndpc.h | 98 +
|
|
iscsiuio/src/uip/ipv6_pkt.h | 50 +
|
|
iscsiuio/src/uip/lc-addrlabels.h | 80 +
|
|
iscsiuio/src/uip/lc-switch.h | 73 +
|
|
iscsiuio/src/uip/lc.h | 130 ++
|
|
iscsiuio/src/uip/psock.c | 339 +++
|
|
iscsiuio/src/uip/psock.h | 383 ++++
|
|
iscsiuio/src/uip/pt.h | 322 +++
|
|
iscsiuio/src/uip/timer.c | 127 ++
|
|
iscsiuio/src/uip/timer.h | 84 +
|
|
iscsiuio/src/uip/uip-neighbor.c | 219 ++
|
|
iscsiuio/src/uip/uip-neighbor.h | 105 +
|
|
iscsiuio/src/uip/uip.c | 2405 ++++++++++++++++++++++
|
|
iscsiuio/src/uip/uip.h | 1569 ++++++++++++++
|
|
iscsiuio/src/uip/uip_arch.h | 137 ++
|
|
iscsiuio/src/uip/uip_arp.c | 479 +++++
|
|
iscsiuio/src/uip/uip_arp.h | 197 ++
|
|
iscsiuio/src/uip/uip_eth.c | 50 +
|
|
iscsiuio/src/uip/uip_eth.h | 43 +
|
|
iscsiuio/src/uip/uipopt.h | 536 +++++
|
|
iscsiuio/src/unix/.gitignore | 2 +
|
|
iscsiuio/src/unix/Makefile.am | 39 +
|
|
iscsiuio/src/unix/clock-arch.c | 54 +
|
|
iscsiuio/src/unix/clock-arch.h | 39 +
|
|
iscsiuio/src/unix/iscsid_ipc.c | 1075 ++++++++++
|
|
iscsiuio/src/unix/iscsid_ipc.h | 52 +
|
|
iscsiuio/src/unix/libs/Makefile.am | 13 +
|
|
iscsiuio/src/unix/libs/bnx2.c | 1165 +++++++++++
|
|
iscsiuio/src/unix/libs/bnx2.h | 304 +++
|
|
iscsiuio/src/unix/libs/bnx2x.c | 1634 +++++++++++++++
|
|
iscsiuio/src/unix/libs/bnx2x.h | 712 +++++++
|
|
iscsiuio/src/unix/libs/cnic.c | 662 ++++++
|
|
iscsiuio/src/unix/libs/cnic.h | 55 +
|
|
iscsiuio/src/unix/logger.c | 181 ++
|
|
iscsiuio/src/unix/logger.h | 129 ++
|
|
iscsiuio/src/unix/main.c | 399 ++++
|
|
iscsiuio/src/unix/nic.c | 1533 ++++++++++++++
|
|
iscsiuio/src/unix/nic.h | 384 ++++
|
|
iscsiuio/src/unix/nic_id.c | 362 ++++
|
|
iscsiuio/src/unix/nic_id.h | 47 +
|
|
iscsiuio/src/unix/nic_nl.c | 678 ++++++
|
|
iscsiuio/src/unix/nic_nl.h | 54 +
|
|
iscsiuio/src/unix/nic_utils.c | 1640 +++++++++++++++
|
|
iscsiuio/src/unix/nic_utils.h | 102 +
|
|
iscsiuio/src/unix/nic_vlan.c | 337 +++
|
|
iscsiuio/src/unix/nic_vlan.h | 89 +
|
|
iscsiuio/src/unix/options.h | 117 ++
|
|
iscsiuio/src/unix/packet.c | 143 ++
|
|
iscsiuio/src/unix/packet.h | 76 +
|
|
iscsiuio/src/unix/uip-conf.h | 160 ++
|
|
sysfs-documentation | 514 +++++
|
|
usr/Makefile | 13 +-
|
|
usr/actor.c | 325 ++-
|
|
usr/actor.h | 14 +-
|
|
usr/auth.c | 22 +-
|
|
usr/be2iscsi.c | 5 -
|
|
usr/config.h | 53 +-
|
|
usr/discovery.c | 56 +-
|
|
usr/discoveryd.c | 10 +-
|
|
usr/event_poll.c | 60 +-
|
|
usr/flashnode.c | 615 ++++++
|
|
usr/flashnode.h | 129 ++
|
|
usr/host.c | 112 +-
|
|
usr/host.h | 4 +
|
|
usr/idbm.c | 505 ++++-
|
|
usr/idbm.h | 8 +
|
|
usr/idbm_fields.h | 112 +
|
|
usr/iface.c | 1275 +++++++++---
|
|
usr/initiator.c | 582 +++++-
|
|
usr/initiator.h | 6 +
|
|
usr/initiator_common.c | 208 +-
|
|
usr/io.c | 10 +-
|
|
usr/iscsi_err.c | 2 +
|
|
usr/iscsi_ipc.h | 19 +
|
|
usr/iscsi_net_util.c | 14 +-
|
|
usr/iscsi_sysfs.c | 590 +++++-
|
|
usr/iscsi_sysfs.h | 20 +-
|
|
usr/iscsi_util.c | 23 +-
|
|
usr/iscsi_util.h | 3 +
|
|
usr/iscsiadm.c | 1077 +++++++++-
|
|
usr/iscsid.c | 47 +-
|
|
usr/iscsid.h | 1 +
|
|
usr/iscsid_req.c | 98 +-
|
|
usr/iscsid_req.h | 2 +
|
|
usr/iscsistart.c | 13 +-
|
|
usr/login.c | 12 +-
|
|
usr/md5.c | 2 +-
|
|
usr/mgmt_ipc.c | 40 +-
|
|
usr/mgmt_ipc.h | 1 +
|
|
usr/netlink.c | 275 ++-
|
|
usr/session_info.c | 28 +-
|
|
usr/session_mgmt.c | 11 +-
|
|
usr/strings.c | 2 +-
|
|
usr/sysfs.c | 106 +-
|
|
usr/sysfs.h | 4 +
|
|
usr/transport.c | 31 +-
|
|
usr/transport.h | 11 +
|
|
usr/types.h | 1 +
|
|
usr/uip_mgmt_ipc.c | 41 +
|
|
usr/uip_mgmt_ipc.h | 73 +
|
|
utils/Makefile | 5 +-
|
|
utils/fwparam_ibft/Makefile | 4 +-
|
|
utils/fwparam_ibft/fw_entry.c | 17 +-
|
|
utils/fwparam_ibft/fwparam_ibft_sysfs.c | 2 +
|
|
utils/fwparam_ibft/fwparam_sysfs.c | 37 +-
|
|
utils/iscsi-gen-initiatorname | 73 +
|
|
utils/iscsi_offload | 378 ++++
|
|
utils/md5.c | 2 +-
|
|
utils/open-isns/bitvector.c | 15 +-
|
|
utils/open-isns/dd.c | 3 +-
|
|
utils/open-isns/doc/isnsadm.8 | 16 +
|
|
utils/open-isns/isnsadm.c | 2 +
|
|
utils/sysdeps/Makefile | 3 +-
|
|
170 files changed, 34076 insertions(+), 1466 deletions(-)
|
|
delete mode 100644 debian/README.Debian
|
|
delete mode 100644 debian/changelog
|
|
delete mode 100644 debian/compat
|
|
delete mode 100644 debian/control
|
|
delete mode 100644 debian/control.modules.in
|
|
delete mode 100644 debian/copyright
|
|
delete mode 100644 debian/dirs
|
|
delete mode 100644 debian/docs
|
|
delete mode 100644 debian/postinst.modules.in
|
|
delete mode 100644 debian/rules
|
|
delete mode 100644 debian/rules.modules
|
|
create mode 100644 etc/systemd/iscsid.service
|
|
create mode 100644 etc/systemd/iscsid.socket
|
|
create mode 100644 iscsiuio/.gitignore
|
|
create mode 100644 iscsiuio/AUTHORS
|
|
create mode 100644 iscsiuio/ChangeLog
|
|
create mode 100644 iscsiuio/INSTALL
|
|
create mode 100644 iscsiuio/Makefile.am
|
|
create mode 100644 iscsiuio/NEWS
|
|
create mode 100644 iscsiuio/README
|
|
create mode 100644 iscsiuio/RELEASE.TXT
|
|
create mode 100644 iscsiuio/configure.ac
|
|
create mode 100644 iscsiuio/docs/iscsiuio.8
|
|
create mode 100644 iscsiuio/iscsiuiolog
|
|
create mode 100644 iscsiuio/src/Makefile.am
|
|
create mode 100644 iscsiuio/src/README
|
|
create mode 100644 iscsiuio/src/apps/Makefile.am
|
|
create mode 100644 iscsiuio/src/apps/README
|
|
create mode 100644 iscsiuio/src/apps/brcm-iscsi/Makefile.am
|
|
create mode 100644 iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi
|
|
create mode 100644 iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c
|
|
create mode 100644 iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h
|
|
create mode 100644 iscsiuio/src/apps/dhcpc/Makefile.am
|
|
create mode 100644 iscsiuio/src/apps/dhcpc/Makefile.dhcpc
|
|
create mode 100644 iscsiuio/src/apps/dhcpc/dhcpc.c
|
|
create mode 100644 iscsiuio/src/apps/dhcpc/dhcpc.h
|
|
create mode 100644 iscsiuio/src/apps/dhcpc/dhcpv6.c
|
|
create mode 100644 iscsiuio/src/apps/dhcpc/dhcpv6.h
|
|
create mode 100644 iscsiuio/src/uip-1.0-changelog.txt
|
|
create mode 100644 iscsiuio/src/uip/Makefile.am
|
|
create mode 100644 iscsiuio/src/uip/Makefile.include
|
|
create mode 100644 iscsiuio/src/uip/clock.h
|
|
create mode 100644 iscsiuio/src/uip/debug.h
|
|
create mode 100644 iscsiuio/src/uip/icmpv6.h
|
|
create mode 100644 iscsiuio/src/uip/ipv6.c
|
|
create mode 100644 iscsiuio/src/uip/ipv6.h
|
|
create mode 100644 iscsiuio/src/uip/ipv6_ndpc.c
|
|
create mode 100644 iscsiuio/src/uip/ipv6_ndpc.h
|
|
create mode 100644 iscsiuio/src/uip/ipv6_pkt.h
|
|
create mode 100644 iscsiuio/src/uip/lc-addrlabels.h
|
|
create mode 100644 iscsiuio/src/uip/lc-switch.h
|
|
create mode 100644 iscsiuio/src/uip/lc.h
|
|
create mode 100644 iscsiuio/src/uip/psock.c
|
|
create mode 100644 iscsiuio/src/uip/psock.h
|
|
create mode 100644 iscsiuio/src/uip/pt.h
|
|
create mode 100644 iscsiuio/src/uip/timer.c
|
|
create mode 100644 iscsiuio/src/uip/timer.h
|
|
create mode 100644 iscsiuio/src/uip/uip-neighbor.c
|
|
create mode 100644 iscsiuio/src/uip/uip-neighbor.h
|
|
create mode 100644 iscsiuio/src/uip/uip.c
|
|
create mode 100644 iscsiuio/src/uip/uip.h
|
|
create mode 100644 iscsiuio/src/uip/uip_arch.h
|
|
create mode 100644 iscsiuio/src/uip/uip_arp.c
|
|
create mode 100644 iscsiuio/src/uip/uip_arp.h
|
|
create mode 100644 iscsiuio/src/uip/uip_eth.c
|
|
create mode 100644 iscsiuio/src/uip/uip_eth.h
|
|
create mode 100644 iscsiuio/src/uip/uipopt.h
|
|
create mode 100644 iscsiuio/src/unix/.gitignore
|
|
create mode 100644 iscsiuio/src/unix/Makefile.am
|
|
create mode 100644 iscsiuio/src/unix/clock-arch.c
|
|
create mode 100644 iscsiuio/src/unix/clock-arch.h
|
|
create mode 100644 iscsiuio/src/unix/iscsid_ipc.c
|
|
create mode 100644 iscsiuio/src/unix/iscsid_ipc.h
|
|
create mode 100644 iscsiuio/src/unix/libs/Makefile.am
|
|
create mode 100644 iscsiuio/src/unix/libs/bnx2.c
|
|
create mode 100644 iscsiuio/src/unix/libs/bnx2.h
|
|
create mode 100644 iscsiuio/src/unix/libs/bnx2x.c
|
|
create mode 100644 iscsiuio/src/unix/libs/bnx2x.h
|
|
create mode 100644 iscsiuio/src/unix/libs/cnic.c
|
|
create mode 100644 iscsiuio/src/unix/libs/cnic.h
|
|
create mode 100644 iscsiuio/src/unix/logger.c
|
|
create mode 100644 iscsiuio/src/unix/logger.h
|
|
create mode 100644 iscsiuio/src/unix/main.c
|
|
create mode 100644 iscsiuio/src/unix/nic.c
|
|
create mode 100644 iscsiuio/src/unix/nic.h
|
|
create mode 100644 iscsiuio/src/unix/nic_id.c
|
|
create mode 100644 iscsiuio/src/unix/nic_id.h
|
|
create mode 100644 iscsiuio/src/unix/nic_nl.c
|
|
create mode 100644 iscsiuio/src/unix/nic_nl.h
|
|
create mode 100644 iscsiuio/src/unix/nic_utils.c
|
|
create mode 100644 iscsiuio/src/unix/nic_utils.h
|
|
create mode 100644 iscsiuio/src/unix/nic_vlan.c
|
|
create mode 100644 iscsiuio/src/unix/nic_vlan.h
|
|
create mode 100644 iscsiuio/src/unix/options.h
|
|
create mode 100644 iscsiuio/src/unix/packet.c
|
|
create mode 100644 iscsiuio/src/unix/packet.h
|
|
create mode 100644 iscsiuio/src/unix/uip-conf.h
|
|
create mode 100644 sysfs-documentation
|
|
create mode 100644 usr/flashnode.c
|
|
create mode 100644 usr/flashnode.h
|
|
create mode 100644 usr/uip_mgmt_ipc.c
|
|
create mode 100644 usr/uip_mgmt_ipc.h
|
|
create mode 100755 utils/iscsi-gen-initiatorname
|
|
create mode 100755 utils/iscsi_offload
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
index c5d9700..1ef9273 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -14,35 +14,54 @@ mandir = $(prefix)/share/man
|
|
etcdir = /etc
|
|
initddir = $(etcdir)/init.d
|
|
|
|
-MANPAGES = doc/iscsid.8 doc/iscsiadm.8 doc/iscsi_discovery.8
|
|
-PROGRAMS = usr/iscsid usr/iscsiadm utils/iscsi_discovery utils/iscsi-iname
|
|
+MANPAGES = doc/iscsid.8 doc/iscsiadm.8 doc/iscsi_discovery.8 iscsiuio/docs/iscsiuio.8
|
|
+PROGRAMS = usr/iscsid usr/iscsiadm utils/iscsi_discovery utils/iscsi-iname iscsiuio/src/unix/iscsiuio
|
|
INSTALL = install
|
|
ETCFILES = etc/iscsid.conf
|
|
IFACEFILES = etc/iface.example
|
|
|
|
+# Compatibility: parse old OPTFLAGS argument
|
|
+ifdef OPTFLAGS
|
|
+CFLAGS = $(OPTFLAGS)
|
|
+endif
|
|
+
|
|
+# Export it so configure of iscsiuio & open-isns will
|
|
+# pick it up.
|
|
+ifneq (,$(CFLAGS))
|
|
+export CFLAGS
|
|
+endif
|
|
+
|
|
# Random comments:
|
|
# using '$(MAKE)' instead of just 'make' allows make to run in parallel
|
|
# over multiple makefile.
|
|
|
|
all: user
|
|
|
|
-user: utils/open-isns/Makefile
|
|
+user: utils/open-isns/Makefile iscsiuio/Makefile
|
|
$(MAKE) -C utils/open-isns
|
|
$(MAKE) -C utils/sysdeps
|
|
$(MAKE) -C utils/fwparam_ibft
|
|
$(MAKE) -C usr
|
|
$(MAKE) -C utils
|
|
+ $(MAKE) -C iscsiuio
|
|
@echo
|
|
@echo "Compilation complete Output file"
|
|
@echo "----------------------------------- ----------------"
|
|
@echo "Built iSCSI daemon: usr/iscsid"
|
|
@echo "Built management application: usr/iscsiadm"
|
|
@echo "Built boot tool: usr/iscsistart"
|
|
+ @echo "Built iscsiuio daemon: iscsiuio/src/unix/iscsiuio"
|
|
@echo
|
|
@echo "Read README file for detailed information."
|
|
|
|
utils/open-isns/Makefile: utils/open-isns/configure utils/open-isns/Makefile.in
|
|
- cd utils/open-isns; ./configure CFLAGS="$(OPTFLAGS)" --with-security=no
|
|
+ cd utils/open-isns; ./configure --with-security=no
|
|
+
|
|
+iscsiuio/Makefile: iscsiuio/configure iscsiuio/Makefile.in
|
|
+ cd iscsiuio; ./configure
|
|
+
|
|
+iscsiuio/configure iscsiuio/Makefile.in: iscsiuio/configure.ac iscsiuio/Makefile.am
|
|
+ cd iscsiuio; autoreconf --install
|
|
|
|
kernel: force
|
|
$(MAKE) -C kernel
|
|
@@ -61,8 +80,10 @@ clean:
|
|
$(MAKE) -C utils clean
|
|
$(MAKE) -C usr clean
|
|
$(MAKE) -C kernel clean
|
|
- $(MAKE) -C utils/open-isns clean
|
|
- $(MAKE) -C utils/open-isns distclean
|
|
+ [ ! -f iscsiuio/Makefile ] || $(MAKE) -C iscsiuio clean
|
|
+ [ ! -f iscsiuio/Makefile ] || $(MAKE) -C iscsiuio distclean
|
|
+ [ ! -f utils/open-isns/Makefile ] || $(MAKE) -C utils/open-isns clean
|
|
+ [ ! -f utils/open-isns/Makefile ] || $(MAKE) -C utils/open-isns distclean
|
|
|
|
# this is for safety
|
|
# now -jXXX will still be safe
|
|
@@ -115,7 +136,7 @@ install_iface: $(IFACEFILES)
|
|
$(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi/ifaces
|
|
|
|
install_etc: $(ETCFILES)
|
|
- if [ ! -f /etc/iscsi/iscsid.conf ]; then \
|
|
+ if [ ! -f $(DESTDIR)/etc/iscsi/iscsid.conf ]; then \
|
|
$(INSTALL) -d $(DESTDIR)$(etcdir)/iscsi ; \
|
|
$(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi ; \
|
|
fi
|
|
@@ -128,11 +149,11 @@ install_kernel:
|
|
$(MAKE) -C kernel install_kernel
|
|
|
|
install_iname:
|
|
- if [ ! -f /etc/iscsi/initiatorname.iscsi ]; then \
|
|
+ if [ ! -f $(DESTDIR)/etc/iscsi/initiatorname.iscsi ]; then \
|
|
echo "InitiatorName=`$(DESTDIR)/sbin/iscsi-iname`" > $(DESTDIR)/etc/iscsi/initiatorname.iscsi ; \
|
|
echo "***************************************************" ; \
|
|
echo "Setting InitiatorName to `cat $(DESTDIR)/etc/iscsi/initiatorname.iscsi`" ; \
|
|
- echo "To override edit /etc/iscsi/initiatorname.iscsi" ; \
|
|
+ echo "To override edit $(DESTDIR)/etc/iscsi/initiatorname.iscsi" ; \
|
|
echo "***************************************************" ; \
|
|
fi
|
|
|
|
diff --git a/README b/README
|
|
index 7364b2d..06d1b6f 100644
|
|
--- a/README
|
|
+++ b/README
|
|
@@ -159,15 +159,20 @@ Usage: iscsid [OPTION]
|
|
5. Open-iSCSI Configuration Utility
|
|
===================================
|
|
|
|
-Open-iSCSI persistent configuration is implemented as a DBM database
|
|
-available on all Linux installations.
|
|
+Open-iSCSI persistent configuration is stored in a number of
|
|
+directories under a configuration root directory, using a flat-file
|
|
+format. This configuration root directory is /etc/iscsi by default,
|
|
+but may also commonly be in /var/lib/iscsi.
|
|
|
|
-The database contains two tables:
|
|
+Configuration is contained in directories for:
|
|
|
|
-- Discovery table (/etc/iscsi/send_targets);
|
|
-- Node table (/etc/iscsi/nodes).
|
|
-
|
|
-The regular place for iSCSI database files: /etc/iscsi/nodes
|
|
+- nodes
|
|
+- slp
|
|
+- isns
|
|
+- static
|
|
+- fw
|
|
+- send_targets
|
|
+- ifaces
|
|
|
|
The iscsiadm utility is a command-line tool to manage (update, delete,
|
|
insert, query) the persistent database.
|
|
@@ -388,7 +393,7 @@ Usage: iscsiadm [OPTION]
|
|
See below for examples.
|
|
-m iface --interface=iscsi_ifacename -C ping --ip=[ipaddr] --packetsize=[size]
|
|
--count=[count] --interval=[interval]
|
|
- -m host --host=hostno|MAC --print=level -C chap --op=[op] --value=[chap_tbl_idx]
|
|
+ -m host --host=hostno|MAC --print=level -C chap --op=[SHOW]
|
|
Display information for a specific host. The host
|
|
can be passed in by host number or by MAC address.
|
|
If a host is not passed in then info
|
|
@@ -401,6 +406,37 @@ Usage: iscsiadm [OPTION]
|
|
is connected to.
|
|
3 = Print iscsi params used.
|
|
4 = Print SCSI info like LUNs, device state.
|
|
+ -m host --host=hostno|MAC -C chap --op=[DELETE] --index=[chap_tbl_idx]
|
|
+ Delete chap entry at the given index from chap table.
|
|
+ -m host --host=hostno|MAC -C chap --op=[NEW | UPDATE] --index=[chap_tbl_idx] \
|
|
+ --name=[name] --value=[value]
|
|
+ Add new or update existing chap entry at the given
|
|
+ index with given username and password pair. If index
|
|
+ is not passed then entry is added at the first free
|
|
+ index in chap table.
|
|
+ -m host --host=hostno|MAC -C flashnode
|
|
+ Display list of all the targets in adapter's
|
|
+ flash (flash node), for the specified host,
|
|
+ with ip, port, tpgt and iqn.
|
|
+ -m host --host=hostno|MAC -C flashnode --op=[NEW] --portal_type=[ipv4|ipv6]
|
|
+ Create new flash node entry for the given host of the
|
|
+ specified portal_type. This returns the index of the
|
|
+ newly created entry on success.
|
|
+ -m host --host=hostno|MAC -C flashnode --index=[flashnode index] \
|
|
+ --op=[UPDATE] --name=[name] --value=[value]
|
|
+ Update the params of the speficied flash node.
|
|
+ The [name] and [value] pairs must be provided for the
|
|
+ params that need to be updated. Multiple params can
|
|
+ be updated using a single command.
|
|
+ -m host --host=hostno|MAC -C flashnode --index=[flashnode index] \
|
|
+ --op=[SHOW | DELETE | LOGIN | LOGOUT]
|
|
+ op=DELETE|LOGIN|LOGOUT will perform deletion/login/
|
|
+ logout operation on the specified flash node.
|
|
+
|
|
+ op=SHOW will list all params with the values for the
|
|
+ specified flash node. This is the default operation.
|
|
+
|
|
+ See the iscsiadm example section for more info.
|
|
-d, --debug debuglevel print debugging information
|
|
-V, --version display version and exit
|
|
-h, --help display this help and exit
|
|
@@ -955,6 +991,96 @@ To now log into targets it is the same as with sofware iscsi. See section
|
|
|
|
./iscsiadm -m session -P 1
|
|
|
|
+
|
|
+ Host mode with flashnode submode:
|
|
+
|
|
+ - Display list of flash nodes for a host
|
|
+
|
|
+ ./iscsiadm -m host -H 6 -C flashnode
|
|
+
|
|
+ This will print list of all the flash node entries for the given host 6
|
|
+ along with their ip, port, tpgt and iqn values.
|
|
+
|
|
+ - Display all parameters of a flash node entry for a host
|
|
+
|
|
+ ./iscsiadm -m host -H 6 -C flashnode -x 0
|
|
+
|
|
+ This will list all the parameter name,value pairs for flash node entry at
|
|
+ index 0 of host 6.
|
|
+
|
|
+ - Add a new flash node entry for a host
|
|
+
|
|
+ ./iscsiadm -m host -H 6 -C flashnode -o new -A ipv4
|
|
+ or
|
|
+ ./iscsiadm -m host -H 6 -C flashnode -o new -A ipv6
|
|
+
|
|
+ This will add new flash node entry for the given host 6 with portal
|
|
+ type of either ipv4 or ipv6. The new operation returns the index of
|
|
+ the newly created flash node entry.
|
|
+
|
|
+ - Update a flashnode entry
|
|
+ ./iscsiadm -m host -H 6 -C flashnode -x 1 -o update \
|
|
+ -n flashnode.conn[0].ipaddress -v 192.168.1.12 \
|
|
+ -n flashnode.session.targetname \
|
|
+ -v iqn.2002-03.com.compellent:5000d310004b0716
|
|
+
|
|
+ This will update the values of ipaddress and targetname params of
|
|
+ flash node entry at index 1 of host 6.
|
|
+
|
|
+ - Login to a flash node entry
|
|
+ ./iscsiadm -m host -H 6 -C flashnode -x 1 -o login
|
|
+
|
|
+ - Logout from a flash node entry
|
|
+ ./iscsiadm -m host -H 6 -C flashnode -x 1 -o logout
|
|
+ or
|
|
+ ./iscsiadm -m session -r $sid -u
|
|
+
|
|
+ Logout can be performed either using the flash node index or using the
|
|
+ corresponding session index.
|
|
+
|
|
+ - Delete a flash node entry
|
|
+ ./iscsiadm -m host -H 6 -C flashnode -x 1 -o delete
|
|
+
|
|
+ Host mode with chap submode:
|
|
+
|
|
+ - Display list of chap entries for a host
|
|
+
|
|
+ ./iscsiadm -m host -H 6 -C chap -o show
|
|
+
|
|
+ This will list all the chap entries for the given host.
|
|
+
|
|
+ - Delete a chap entry for a host
|
|
+
|
|
+ ./iscsiadm -m host -H 6 -C chap -o delete -x 5
|
|
+
|
|
+ This will delete any chap entry present at given index 5.
|
|
+
|
|
+ - Add/Update a local chap entry for a host
|
|
+
|
|
+ ./iscsiadm -m host -H 6 -C chap -o update -x 4 -n username \
|
|
+ -v value -n password -v value
|
|
+
|
|
+ This will update the local chap entry present at index 4. If index 4
|
|
+ is free then entry of type local chap will be created at that index
|
|
+ with given username and password values.
|
|
+
|
|
+ - Add/Update a bidi chap entry for a host
|
|
+
|
|
+ ./iscsiadm -m host -H 6 -C chap -o update -x 5 -n username_in \
|
|
+ -v value -n password_in -v value
|
|
+
|
|
+ This will update the bidi chap entry present at index 5. If index 5
|
|
+ is free then entry of type bidi chap will be created at that index
|
|
+ with given username_in and password_in values.
|
|
+
|
|
+ Host mode with stats submode:
|
|
+
|
|
+ - Display host statistics:
|
|
+ ./iscsiadm -m host -H 6 -C stats
|
|
+
|
|
+ This will print the aggregate statistics on the host adapter port.
|
|
+ This includes MAC, TCP/IP, ECC & iSCSI statistics.
|
|
+
|
|
6. Configuration
|
|
================
|
|
|
|
diff --git a/debian/README.Debian b/debian/README.Debian
|
|
deleted file mode 100644
|
|
index 98ebd23..0000000
|
|
--- a/debian/README.Debian
|
|
+++ /dev/null
|
|
@@ -1,44 +0,0 @@
|
|
-linux-iscsi for Debian
|
|
------------------------------------
|
|
-
|
|
-The linux-iscsi package contains the userspace portion the Linux iSCSI project.
|
|
-It has a dependency on the linux-iscsi-modules package, which needs to be built from the linux-iscsi-modules-source against the specific kernel version running
|
|
-on your system.
|
|
-
|
|
-Building
|
|
---------
|
|
-Modules cannot be built against the kernel-headers alone. You will need
|
|
-to extract and configure your kernel tree, then use the make-kpkg command
|
|
-(from the kernel-package package) to build a new kernel and modules.
|
|
-See the make-kpkg man page, particularly the modules-image section. The
|
|
-following example shows how to build the linux-iscsi-modules package; just
|
|
-substitute the appropriate version strings. Follow these instructions
|
|
-(as root) in order to build the linux-iscsi-modules package for your kernel:
|
|
-
|
|
-dpkg -i linux-iscsi-modules-source_5.0.0.0.3rc6-363_all.deb
|
|
-cd /usr/src
|
|
-rm -rf modules/linux-iscsi
|
|
-tar jxpvf linux-iscsi-modules-source.tar.bz2
|
|
-cd linux-2.6.11.11 (or your appropriate version)
|
|
-make-kpkg --added-modules linux-iscsi modules-image
|
|
-
|
|
-By default, make-kpkg will assume /usr/src/linux-iscsi-modules-source.tar.bz2
|
|
-has been extracted under /usr/src. However, that also requires building as
|
|
-root. If you want to do the build as a non-root user, you need to use the
|
|
-MODULE_LOC environment variable. For example:
|
|
-
|
|
-cd ~/builds
|
|
-export MODULES_LOC=$PWD/modules
|
|
-tar jxpvf /usr/src/linux-iscsi-modules-source.tar.bz2
|
|
-cd ~/builds/linux-2.6.11.11 (or your appropriate version)
|
|
-make-kpkg --added-modules linux-iscsi modules-image
|
|
-
|
|
-Installing
|
|
-----------
|
|
-
|
|
-Once you have built the linux-iscsi-modules package, you can install the
|
|
-binaries:
|
|
-
|
|
-dpkg -i linux-iscsi_5.0.0.0.3rc6-363_i386.deb linux-iscsi-modules-2.6.11.11_5.0.0.0.3rc6-363+10.00.Custom_i386.deb
|
|
-
|
|
- -- Chad Tindel <chad.tindel@hp.com>, Mon, 30 May 2005 15:17:53 -0600
|
|
diff --git a/debian/changelog b/debian/changelog
|
|
deleted file mode 100644
|
|
index f71577e..0000000
|
|
--- a/debian/changelog
|
|
+++ /dev/null
|
|
@@ -1,6 +0,0 @@
|
|
-linux-iscsi (5.0.0.0.3rc6-363) unstable; urgency=low
|
|
-
|
|
- * Initial Release.
|
|
-
|
|
- -- Chad Tindel <chad.tindel@hp.com> Mon, 30 May 2005 15:17:53 -0600
|
|
-
|
|
diff --git a/debian/compat b/debian/compat
|
|
deleted file mode 100644
|
|
index b8626c4..0000000
|
|
--- a/debian/compat
|
|
+++ /dev/null
|
|
@@ -1 +0,0 @@
|
|
-4
|
|
diff --git a/debian/control b/debian/control
|
|
deleted file mode 100644
|
|
index d333569..0000000
|
|
--- a/debian/control
|
|
+++ /dev/null
|
|
@@ -1,27 +0,0 @@
|
|
-Source: linux-iscsi
|
|
-Section: net
|
|
-Priority: optional
|
|
-Maintainer: Chad Tindel <chad.tindel@hp.com>
|
|
-Build-Depends: debhelper (>= 4.0.0), libdb4.3, libdb4.3-dev
|
|
-Standards-Version: 3.6.1
|
|
-
|
|
-Package: linux-iscsi
|
|
-Architecture: any
|
|
-Depends: ${shlibs:Depends}, ${misc:Depends}, linux-iscsi-modules
|
|
-Description: high performance, transport independent implementation of RFC3720.
|
|
- linux-iscsi is a high performance, transport independent, implementation of
|
|
- RFC3720.
|
|
-
|
|
-#Package: linux-iscsi
|
|
-#Architecture: all
|
|
-#Description: Documentation for linux-iscsi
|
|
-#linux-iscsi is a high performance, transport independent, implementation of
|
|
-#RFC3720.
|
|
-
|
|
-Package: linux-iscsi-modules-source
|
|
-Architecture: all
|
|
-Depends: ${shlibs:Depends}, ${misc:Depends}, module-assistant, debhelper (>= 4.0.0), bzip2
|
|
-Description: Source Code for the Linux iSCSI Kernel Modules
|
|
- Along with make-kpkg, this package maybe used to build a linux-iscsi-modules
|
|
- package for a kernel-image package.
|
|
-
|
|
diff --git a/debian/control.modules.in b/debian/control.modules.in
|
|
deleted file mode 100644
|
|
index 9371b34..0000000
|
|
--- a/debian/control.modules.in
|
|
+++ /dev/null
|
|
@@ -1,20 +0,0 @@
|
|
-Source: linux-iscsi-modules
|
|
-Section: net
|
|
-Priority: optional
|
|
-Maintainer: Chad Tindel <chad.tindel@hp.com>
|
|
-Build-Depends: debhelper (>> 4.1.0), bzip2
|
|
-Standards-Version: 3.6.1
|
|
-
|
|
-Package: linux-iscsi-modules-_KVERS_
|
|
-Architecture: any
|
|
-Depends: modutils, linux-iscsi
|
|
-Provides: linux-iscsi-modules
|
|
-Description: Linux Kernel Driver Modules for Linux iSCSI (kernel _KVERS_)
|
|
- This is a Linux driver for iSCSI initiator functionality.
|
|
- .
|
|
- This package contains the compiled kernel modules for _KVERS_
|
|
- .
|
|
- If you have compiled your own kernel, you will most likely need to build
|
|
- your own linux-iscsi-modules. The linux-iscsi-source package has been
|
|
- provided for use with the Debian kernel-package utility to produce a version
|
|
- of linux-iscsi-module for your kernel.
|
|
diff --git a/debian/copyright b/debian/copyright
|
|
deleted file mode 100644
|
|
index 11c0945..0000000
|
|
--- a/debian/copyright
|
|
+++ /dev/null
|
|
@@ -1,12 +0,0 @@
|
|
-This package was debianized by Chad Tindel <chad.tindel@hp.com> on
|
|
-Mon, 30 May 2005 15:17:53 -0600.
|
|
-
|
|
-It was downloaded from http://sourceforge.net/projects/linux-iscsi
|
|
-
|
|
-Copyright Holder: Dmitry Yusupov <dima@neterion.com>
|
|
-
|
|
-License:
|
|
-
|
|
-You are free to distribute this software under the terms of the GNU General
|
|
-Public License. On Debian systems, the complete text of the GNU General Public
|
|
-License can be found in the file `/usr/share/common-licenses/GPL'.
|
|
diff --git a/debian/dirs b/debian/dirs
|
|
deleted file mode 100644
|
|
index c386116..0000000
|
|
--- a/debian/dirs
|
|
+++ /dev/null
|
|
@@ -1,3 +0,0 @@
|
|
-usr/bin
|
|
-usr/sbin
|
|
-etc/init.d
|
|
diff --git a/debian/docs b/debian/docs
|
|
deleted file mode 100644
|
|
index 9b70221..0000000
|
|
--- a/debian/docs
|
|
+++ /dev/null
|
|
@@ -1,4 +0,0 @@
|
|
-README
|
|
-COPYING
|
|
-THANKS
|
|
-TODO
|
|
diff --git a/debian/postinst.modules.in b/debian/postinst.modules.in
|
|
deleted file mode 100644
|
|
index 70dc20d..0000000
|
|
--- a/debian/postinst.modules.in
|
|
+++ /dev/null
|
|
@@ -1,11 +0,0 @@
|
|
-#!/bin/sh
|
|
-
|
|
-set -e
|
|
-
|
|
-if [ "`uname -r`" = "_KVERS_" ]; then
|
|
- /sbin/depmod -a &
|
|
-fi
|
|
-
|
|
-#DEBHELPER#
|
|
-
|
|
-exit 0
|
|
diff --git a/debian/rules b/debian/rules
|
|
deleted file mode 100644
|
|
index f4695c6..0000000
|
|
--- a/debian/rules
|
|
+++ /dev/null
|
|
@@ -1,152 +0,0 @@
|
|
-#!/usr/bin/make -f
|
|
-# -*- makefile -*-
|
|
-# Sample debian/rules that uses debhelper.
|
|
-#
|
|
-# This file was originally written by Joey Hess and Craig Small.
|
|
-# As a special exception, when this file is copied by dh-make into a
|
|
-# dh-make output file, you may use that output file without restriction.
|
|
-# This special exception was added by Craig Small in version 0.37 of dh-make.
|
|
-#
|
|
-# Modified to make a template file for a multi-binary package with separated
|
|
-# build-arch and build-indep targets by Bill Allombert 2001
|
|
-
|
|
-# Uncomment this to turn on verbose mode.
|
|
-#export DH_VERBOSE=1
|
|
-
|
|
-# This has to be exported to make some magic below work.
|
|
-export DH_OPTIONS
|
|
-
|
|
-
|
|
-
|
|
-CFLAGS = -Wall -g
|
|
-
|
|
-ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
|
|
- CFLAGS += -O0
|
|
-else
|
|
- CFLAGS += -O2
|
|
-endif
|
|
-
|
|
-configure: configure-stamp
|
|
-configure-stamp:
|
|
- dh_testdir
|
|
- # Add here commands to configure the package.
|
|
-
|
|
- touch configure-stamp
|
|
-
|
|
-
|
|
-#Architecture
|
|
-build: build-arch build-indep
|
|
-
|
|
-build-arch: build-arch-stamp
|
|
-build-arch-stamp: configure-stamp
|
|
-
|
|
- # Add here commands to compile the arch part of the package.
|
|
- $(MAKE) -C usr
|
|
-
|
|
- touch build-arch-stamp
|
|
-
|
|
-build-indep: build-indep-stamp
|
|
-build-indep-stamp: configure-stamp
|
|
-
|
|
- # Add here commands to compile the indep part of the package.
|
|
- #$(MAKE) doc
|
|
- touch build-indep-stamp
|
|
-
|
|
-clean:
|
|
- dh_testdir
|
|
- dh_testroot
|
|
- rm -f build-arch-stamp build-indep-stamp #CONFIGURE-STAMP#
|
|
-
|
|
- # Add here commands to clean up after the build process.
|
|
- $(MAKE) -C usr clean
|
|
- rm -rf modules
|
|
-
|
|
- dh_clean
|
|
-
|
|
-install: install-indep install-arch
|
|
-install-indep:
|
|
- dh_testdir
|
|
- dh_testroot
|
|
- dh_clean -k -i
|
|
- dh_installdirs -i
|
|
-
|
|
- # create needed directories
|
|
- dh_installdirs -i usr/src/modules/linux-iscsi
|
|
-
|
|
- mkdir -p modules/linux-iscsi/debian
|
|
-
|
|
- # copy the driver source
|
|
- tar --exclude=debian -c * | (cd modules/linux-iscsi && tar xv)
|
|
-
|
|
- # copy all relevant debian/ files
|
|
- cp debian/{compat,copyright} modules/linux-iscsi/debian
|
|
- cat debian/changelog | sed -e 's/linux-iscsi/linux-iscsi-modules/' > modules/linux-iscsi/debian/changelog
|
|
- cp debian/*.modules.in modules/linux-iscsi/debian
|
|
- install -m755 debian/rules.modules modules/linux-iscsi/debian/rules
|
|
-
|
|
- # entar the source
|
|
- tar jcf debian/linux-iscsi-modules-source/usr/src/linux-iscsi-modules-source.tar.bz2 modules
|
|
-
|
|
- # Add here commands to install the indep part of the package into
|
|
- # debian/<package>-doc.
|
|
- #INSTALLDOC#
|
|
-
|
|
- dh_install -i
|
|
-
|
|
-install-arch:
|
|
- dh_testdir
|
|
- dh_testroot
|
|
- dh_clean -k -s
|
|
- dh_installdirs -s
|
|
-
|
|
- # Add here commands to install the arch part of the package into
|
|
- # debian/linux-iscsi.
|
|
- install -m 755 usr/iscsiadm $(CURDIR)/debian/linux-iscsi/usr/bin
|
|
- install -m 755 usr/iscsid $(CURDIR)/debian/linux-iscsi/usr/sbin
|
|
- install -m 644 etc/iscsid.conf $(CURDIR)/debian/linux-iscsi/etc/iscsid.conf.example
|
|
- install -m 755 etc/initd/initd.debian $(CURDIR)/debian/linux-iscsi/etc/init.d/iscsid
|
|
- make clean
|
|
-
|
|
- dh_install -s
|
|
-
|
|
-# Must not depend on anything. This is to be called by
|
|
-# binary-arch/binary-indep
|
|
-# in another 'make' thread.
|
|
-binary-common:
|
|
- dh_testdir
|
|
- dh_testroot
|
|
- dh_installchangelogs
|
|
- dh_installdocs
|
|
- dh_installexamples
|
|
-# dh_installmenu
|
|
-# dh_installdebconf
|
|
-# dh_installlogrotate
|
|
-# dh_installemacsen
|
|
-# dh_installpam
|
|
-# dh_installmime
|
|
-# dh_installinit
|
|
-# dh_installcron
|
|
-# dh_installinfo
|
|
- dh_installman
|
|
- dh_link
|
|
- dh_strip
|
|
- dh_compress
|
|
- dh_fixperms
|
|
-# dh_perl
|
|
-# dh_python
|
|
- dh_makeshlibs
|
|
- dh_installdeb
|
|
- dh_shlibdeps
|
|
- dh_gencontrol
|
|
- dh_md5sums
|
|
- dh_builddeb
|
|
-# Build architecture independant packages using the common target.
|
|
-binary-indep: build-indep install-indep
|
|
- $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common
|
|
-
|
|
-# Build architecture dependant packages using the common target.
|
|
-binary-arch: build-arch install-arch
|
|
- $(MAKE) -f debian/rules DH_OPTIONS=-a binary-common
|
|
-
|
|
-binary: binary-arch binary-indep
|
|
-.PHONY: build clean binary-indep binary-arch binary install install-indep install-arch configure
|
|
diff --git a/debian/rules.modules b/debian/rules.modules
|
|
deleted file mode 100644
|
|
index 1c4dabd..0000000
|
|
--- a/debian/rules.modules
|
|
+++ /dev/null
|
|
@@ -1,39 +0,0 @@
|
|
-#!/usr/bin/make -f
|
|
-
|
|
-# module-assistant stuff
|
|
-PACKAGE = linux-iscsi-modules
|
|
-MA_DIR ?= /usr/share/modass
|
|
--include $(MA_DIR)/include/generic.make
|
|
--include $(MA_DIR)/include/common-rules.make
|
|
-
|
|
-kdist_clean: prep-deb-files
|
|
- dh_clean
|
|
- #$(MAKE) clean KERNEL_PATH=$(KSRC)
|
|
- make clean
|
|
-
|
|
-kdist_config: prep-deb-files
|
|
-
|
|
-TARGET = $(CURDIR)/debian/linux-iscsi-modules-$(KVERS)
|
|
-MODULES_TARGET = $(TARGET)/lib/modules/$(KVERS)/kernel/net/iscsi
|
|
-
|
|
-binary-modules: kdist_config
|
|
- dh_testdir
|
|
- dh_testroot
|
|
- dh_clean -k
|
|
- dh_installdirs lib/modules/$(KVERS)
|
|
-
|
|
- # build and install the module
|
|
- patch -d kernel < kernel/backward-compile-2.6.11.patch
|
|
- make -C kernel KSRC=$(KSRC)
|
|
- mkdir -p $(MODULES_TARGET)
|
|
- install -m 755 kernel/iscsi_tcp.ko $(MODULES_TARGET)
|
|
- install -m 755 kernel/scsi_transport_iscsi.ko $(MODULES_TARGET)
|
|
-
|
|
- dh_installdocs
|
|
- dh_installchangelogs
|
|
- dh_compress
|
|
- dh_fixperms
|
|
- dh_installdeb
|
|
- dh_gencontrol -- -v$(VERSION)
|
|
- dh_md5sums
|
|
- dh_builddeb --destdir=$(DEB_DESTDIR)
|
|
diff --git a/doc/iscsi_discovery.8 b/doc/iscsi_discovery.8
|
|
index a4affc6..e28065c 100644
|
|
--- a/doc/iscsi_discovery.8
|
|
+++ b/doc/iscsi_discovery.8
|
|
@@ -8,7 +8,17 @@
|
|
.SH NAME
|
|
iscsi_discovery \- discover iSCSI targets
|
|
.SH SYNOPSIS
|
|
-.B iscsi_discovery <IP> [-p <port>] [-d] [-t <tcp|iser> [-f]] [-m] [-l]
|
|
+.B iscsi_discovery
|
|
+.I <IP>
|
|
+.RB [ -p
|
|
+.IR <port> ]
|
|
+.RB [ -d ]
|
|
+.RB [\ -t
|
|
+.IR <tcp|iser>
|
|
+.RB [ -f ]
|
|
+.R ]
|
|
+.RB [ -m ]
|
|
+.RB [ -l ]
|
|
|
|
.SH DESCRIPTION
|
|
Perform send-targets discovery to the specified IP. If a discovery record
|
|
diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8
|
|
index 7c209f6..f046236 100644
|
|
--- a/doc/iscsiadm.8
|
|
+++ b/doc/iscsiadm.8
|
|
@@ -2,23 +2,161 @@
|
|
.SH NAME
|
|
iscsiadm \- open-iscsi administration utility
|
|
.SH SYNOPSIS
|
|
-\fBiscsiadm\fR \-m discoverydb [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-I iface \-t type \-p ip:port [ \-lD ] ] | [ [ -p ip:port -t type ] \
|
|
-[ \-o operation ] [ \-n name ] [ \-v value ] [ \-lD ] ]
|
|
+.B iscsiadm
|
|
+.B \-m discoverydb
|
|
+.RB [ \-hV ]
|
|
+.RB [ \-d
|
|
+.IR debug_level ]
|
|
+.RB [ \-P
|
|
+.IR printlevel ]
|
|
+.R [\
|
|
+.BI \-I\ iface\ \-t\ type\ \-p\ ip:port
|
|
+.RB [ \-lD ]
|
|
+.R ] | [
|
|
+.RB [ \-p
|
|
+.I ip:port
|
|
+.B \-t
|
|
+.IR type ]
|
|
+.RB [ \-o
|
|
+.IR operation ]
|
|
+.RB [ \-n
|
|
+.IR name ]
|
|
+.RB [ \-v
|
|
+.IR value ]
|
|
+.RB [ \-lD ]
|
|
+.R ]
|
|
|
|
-\fBiscsiadm\fR \-m discovery [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-I iface \-t type \-p ip:port [ \-l ] ] | [ [ -p ip:port ] [ \-l | \-D ] ]
|
|
+.B iscsiadm
|
|
+.B \-m discovery
|
|
+.RB [ \-hV ]
|
|
+.RB [ \-d
|
|
+.IR debug_level ]
|
|
+.RB [ \-P
|
|
+.IR printlevel ]
|
|
+.R [\
|
|
+.BI \-I\ iface\ \-t\ type\ \-p\ ip:port
|
|
+.RB [ \-l ]
|
|
+.R ] | [
|
|
+.RB [ \-p
|
|
+.IR ip:port ]
|
|
+.RB [ \-l | \-D ]
|
|
+.R ]
|
|
|
|
-\fBiscsiadm\fR \-m node [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-L all,manual,automatic ] [ \-U all,manual,automatic ] [ \-S ] [ [ \-T targetname \-p ip:port \-I iface ] [ \-l | \-u | \-R | \-s] ]
|
|
-[ [ \-o operation ] [ \-n name ] [ \-v value ] [ \-p ip:port ] ]
|
|
+.B iscsiadm
|
|
+.B \-m node
|
|
+.RB [ \-hV ]
|
|
+.RB [ \-d
|
|
+.IR debug_level ]
|
|
+.RB [ \-P
|
|
+.IR printlevel ]
|
|
+.RB [ \-L
|
|
+.IR all,manual,automatic ]
|
|
+.RB [ \-U
|
|
+.IR all,manual,automatic ]
|
|
+.RB [ \-S ]
|
|
+.R [
|
|
+.RB [ \-T
|
|
+.IB targetname\ \-p\ ip:port\ \-I\ iface
|
|
+.R ]
|
|
+.RB [ \-l | \-u | \-R | \-s ]
|
|
+.R ]
|
|
+.R [
|
|
+.RB [ \-o
|
|
+.IR operation ]
|
|
+.RB [ \-n
|
|
+.IR name ]
|
|
+.RB [ \-v
|
|
+.IR value ]
|
|
+.RB [ \-p
|
|
+.IR ip:port ]
|
|
+.R ]
|
|
|
|
-\fBiscsiadm\fR \-m session [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-r sessionid | sysfsdir [ \-R ] [ \-u | \-s | \-o new ] ]
|
|
+.B iscsiadm
|
|
+.B \-m session
|
|
+.RB[ \-hV ]
|
|
+.RB [ \-d
|
|
+.IR debug_level ]
|
|
+.RB [ \-P
|
|
+.IR printlevel ]
|
|
+.R [
|
|
+.B \-r
|
|
+.IR sessionid | sysfsdir
|
|
+.RB [ \-R ]
|
|
+.RB [ \-u | \-s | \-o
|
|
+.IR new ]
|
|
+.R ]
|
|
|
|
-\fBiscsiadm\fR \-m iface [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-I ifacename | \-H hostno|MAC ] [ [ \-o operation ] [ \-n name ] [ \-v value ] ] [ \-C ping [ \-a ip ] [ \-b packetsize ] [ \-c count ] [ \-i interval ] ]
|
|
+.B iscsiadm
|
|
+.B \-m iface
|
|
+.RB [ \-hV ]
|
|
+.RB [ \-d
|
|
+.IR debug_level ]
|
|
+.RB [ \-P
|
|
+.IR printlevel ]
|
|
+.R [
|
|
+.BI \-I\ ifacename
|
|
+.R |
|
|
+.BI \-H\ hostno|MAC
|
|
+.R ]
|
|
+.R [
|
|
+.RB [ \-o
|
|
+.IR operation ]
|
|
+.RB [ \-n
|
|
+.IR name ]
|
|
+.RB [ \-v
|
|
+.IR value ]
|
|
+.R ]
|
|
+.R [
|
|
+.BI \-C\ ping
|
|
+.RB [ \-a
|
|
+.IR ip ]
|
|
+.RB [ \-b
|
|
+.IR packetsize ]
|
|
+.RB [ \-c
|
|
+.IR count ]
|
|
+.RB [ \-i
|
|
+.IR interval ]
|
|
+.R ]
|
|
|
|
-\fBiscsiadm\fR \-m fw [\-l]
|
|
+.B iscsiadm
|
|
+.B \-m fw
|
|
+.RB [ \-d
|
|
+.IR debug_level ]
|
|
+.RB [ \-l ]
|
|
|
|
-\fBiscsiadm\fR \-m host [ \-P printlevel ] [ \-H hostno|MAC ] [ -C chap [ -o operation ] [ -v chap_tbl_idx ] ]
|
|
+.B iscsiadm
|
|
+.B \-m host
|
|
+.RB [ \-P
|
|
+.IR printlevel ]
|
|
+.RB [ \-H
|
|
+.IR hostno|MAC ]
|
|
+.R [
|
|
+.RB [\ \-C
|
|
+.IR chap
|
|
+.RB [ \-x
|
|
+.IR chap_tbl_idx ]
|
|
+.R ] |
|
|
+.RB [\ \-C
|
|
+.IR flashnode
|
|
+.RB [ \-A
|
|
+.IR portal_type ]
|
|
+.RB [ \-x
|
|
+.IR flashnode_idx ]
|
|
+.R ] |
|
|
+.RB [\ \-C
|
|
+.IR stats \ ]
|
|
+.R ]
|
|
+.R [
|
|
+.RB [ \-o
|
|
+.IR operation ]
|
|
+.RB [ \-n
|
|
+.IR name ]
|
|
+.RB [ \-v
|
|
+.IR value ]
|
|
+.R ]
|
|
|
|
-\fBiscsiadm\fR \-k priority
|
|
+.B iscsiadm
|
|
+.B \-k priority
|
|
|
|
.SH "DESCRIPTION"
|
|
The iscsiadm utility is a command-line tool allowing discovery and login
|
|
@@ -47,6 +185,12 @@ daemon (iscsid) be running.
|
|
This option is only valid for ping submode.
|
|
|
|
.TP
|
|
+\fB\-A\fR, \fB\-\-portal_type=\fI[ipv4|ipv6]\fR
|
|
+Specify the portal type for the new flash node entry to be created.
|
|
+.IP
|
|
+This option is only valid for flashnode submode of host mode and only with \fInew\fR operation.
|
|
+
|
|
+.TP
|
|
\fB\-b\fR, \fB\-\-packetsize=\fIpacketsize\fP
|
|
Specify the ping \fIpacketsize\fR.
|
|
|
|
@@ -64,7 +208,15 @@ Specify the submode for mode. op must be name of submode.
|
|
|
|
Currently iscsiadm support ping as submode for iface. For example,
|
|
|
|
-iscsiadm -m iface -I ifacename -C ping -a ipaddr -b packetsize -c count -i interval
|
|
+iscsiadm \-m iface \-I ifacename \-C ping \-a ipaddr \-b packetsize \-c count \-i interval
|
|
+
|
|
+For host, it supports chap , flashnode and stats as submodes. For example,
|
|
+
|
|
+iscsiadm \-m host \-H hostno \-C chap \-x chap_tbl_idx \-o operation
|
|
+
|
|
+iscsiadm \-m host \-H hostno \-C flashnode \-x flashnode_idx \-o operation
|
|
+
|
|
+iscsiadm \-m host \-H hostno \-C stats
|
|
|
|
.TP
|
|
\fB\-d\fR, \fB\-\-debug=\fIdebug_level\fP
|
|
@@ -113,7 +265,7 @@ are experimental and the use is not supported as a stable interface yet.
|
|
In discovery mode multiple interfaces can be specified by passing in multiple
|
|
\-I/\-\-interface instances. For example,
|
|
|
|
-"iscsiadm \-m discoverydb \-t st \-p ip:port \-I iface0 \-I iface2 --discover"
|
|
+"iscsiadm \-m discoverydb \-t st \-p ip:port \-I iface0 \-I iface2 \-\-discover"
|
|
|
|
Will direct iscsiadm to setup the node db to create records which will create
|
|
sessions though the two intefaces passed in.
|
|
@@ -160,18 +312,19 @@ for session mode).
|
|
.TP
|
|
\fB\-m, \-\-mode \fIop\fR
|
|
specify the mode. \fIop\fR
|
|
-must be one of \fIdiscoverydb\fR, \fInode\fR, \fIfw\fR, \fIhost\fR \fIiface\fR or \fIsession\fR.
|
|
+must be one of \fIdiscovery\fR, \fIdiscoverydb\fR, \fInode\fR, \fIfw\fR, \fIhost\fR \fIiface\fR or \fIsession\fR.
|
|
.IP
|
|
-If no other options are specified: for \fIdiscoverydb\fR and \fInode\fR, all
|
|
-of their respective records are displayed; for \fIsession\fR, all active
|
|
-sessions and connections are displayed; for \fIfw\fR, all boot firmware
|
|
-values are displayed; for \fIhost\fR, all iSCSI hosts are displayed; and
|
|
-for \fIiface\fR, all ifaces setup in /etc/iscsi/ifaces are displayed.
|
|
+If no other options are specified: for \fIdiscovery\fR, \fIdiscoverydb\fR and
|
|
+\fInode\fR, all of their respective records are displayed; for \fIsession\fR,
|
|
+all active sessions and connections are displayed; for \fIfw\fR, all boot
|
|
+firmware values are displayed; for \fIhost\fR, all iSCSI hosts are displayed;
|
|
+and for \fIiface\fR, all ifaces setup in /etc/iscsi/ifaces are displayed.
|
|
|
|
.TP
|
|
\fB\-n\fR, \fB\-\-name=\fIname\fR
|
|
-Specify a field \fIname\fR in a record. For use with the \fIupdate\fR
|
|
-operator.
|
|
+In node mode, specify a field \fIname\fR in a record. In flashnode submode of host mode, specify name of the flash node parameter.
|
|
+
|
|
+For use with the \fIupdate\fR operator.
|
|
.IP
|
|
|
|
.TP
|
|
@@ -181,6 +334,8 @@ Specifies a database operator \fIop\fR. \fIop\fR must be one of
|
|
.IP
|
|
For iface mode, \fIapply\fR and \fIapplyall\fR are also applicable.
|
|
.IP
|
|
+For flashnode submode of host mode, \fIlogin\fR and \fIlogout\fR are also applicable.
|
|
+.IP
|
|
This option is valid for all modes except fw. Delete should not be used on a running session. If it is iscsiadm will stop the session and then delete the
|
|
record.
|
|
.IP
|
|
@@ -210,6 +365,12 @@ sid is passed in.
|
|
.IP
|
|
\fIapplyall\fR will cause the network settings to take effect on all the ifaces whose MAC address or host number matches that of the specific host.
|
|
|
|
+.IP
|
|
+\fIlogin\fR will log into the specified flash node entry.
|
|
+
|
|
+.IP
|
|
+\fIlogout\fR does the logout from the given flash node entry.
|
|
+
|
|
.TP
|
|
\fB\-p\fR, \fB\-\-portal=\fIip[:port]\fR
|
|
Use target portal with ip-address \fIip\fR and \fIport\fR. If port is not passed
|
|
@@ -258,6 +419,7 @@ tuple passed in.
|
|
.TP
|
|
\fB\-s\fR, \fB\-\-stats\fR
|
|
Display session statistics.
|
|
+This option when used with host mode, displays host statistics.
|
|
|
|
.TP
|
|
\fB\-S\fR, \fB\-\-show\fR
|
|
@@ -292,12 +454,18 @@ for session mode).
|
|
\fB\-v\fR, \fB\-\-value=\fIvalue\fR
|
|
Specify a \fIvalue\fR for use with the \fIupdate\fR operator.
|
|
.IP
|
|
-This option is only valid for node mode.
|
|
+This option is only valid for node mode and flashnode submode of host mode.
|
|
|
|
.TP
|
|
\fB\-V\fR, \fB\-\-version\fR
|
|
display version and exit
|
|
|
|
+.TP
|
|
+\fB\-x\fR, \fB\-\-index=\fIindex\fR
|
|
+Specify the \fIindex\fR of the entity to operate on.
|
|
+.IP
|
|
+This option is only valid for chap and flashnode submodes of host mode.
|
|
+
|
|
.SH DISCOVERY TYPES
|
|
iSCSI defines 3 discovery types: SendTargets, SLP, and iSNS.
|
|
|
|
diff --git a/etc/iscsid.conf b/etc/iscsid.conf
|
|
index ef76dc0..c30a7dc 100644
|
|
--- a/etc/iscsid.conf
|
|
+++ b/etc/iscsid.conf
|
|
@@ -22,6 +22,9 @@
|
|
# Default for upstream open-iscsi scripts (uncomment to activate).
|
|
iscsid.startup = /sbin/iscsid
|
|
|
|
+# Check for active mounts on devices reachable through a session
|
|
+# and refuse to logout if there are any. Defaults to "No".
|
|
+# iscsid.safe_logout = Yes
|
|
|
|
#############################
|
|
# NIC/HBA and driver settings
|
|
@@ -80,7 +83,7 @@ node.leading_login = No
|
|
# Timeouts
|
|
# ********
|
|
#
|
|
-# See the iSCSI REAME's Advanced Configuration section for tips
|
|
+# See the iSCSI README's Advanced Configuration section for tips
|
|
# on setting timeouts when using multipath or doing root over iSCSI.
|
|
#
|
|
# To specify the length of time to wait for session re-establishment
|
|
diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service
|
|
new file mode 100644
|
|
index 0000000..028e0b3
|
|
--- /dev/null
|
|
+++ b/etc/systemd/iscsid.service
|
|
@@ -0,0 +1,13 @@
|
|
+[Unit]
|
|
+Description=Open-iSCSI
|
|
+Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8)
|
|
+After=network.target NetworkManager-wait-online.service iscsiuio.service tgtd.service targetcli.service
|
|
+
|
|
+[Service]
|
|
+Type=forking
|
|
+PIDFile=/var/run/iscsid.pid
|
|
+ExecStart=/usr/sbin/iscsid
|
|
+ExecStop=/sbin/iscsiadm -k 0 2
|
|
+
|
|
+[Install]
|
|
+WantedBy=multi-user.target
|
|
diff --git a/etc/systemd/iscsid.socket b/etc/systemd/iscsid.socket
|
|
new file mode 100644
|
|
index 0000000..832451d
|
|
--- /dev/null
|
|
+++ b/etc/systemd/iscsid.socket
|
|
@@ -0,0 +1,9 @@
|
|
+[Unit]
|
|
+Description=Open-iSCSI iscsid Socket
|
|
+Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8)
|
|
+
|
|
+[Socket]
|
|
+ListenStream=@ISCSIADM_ABSTRACT_NAMESPACE
|
|
+
|
|
+[Install]
|
|
+WantedBy=sockets.target
|
|
diff --git a/include/fw_context.h b/include/fw_context.h
|
|
index 1640859..44053d8 100644
|
|
--- a/include/fw_context.h
|
|
+++ b/include/fw_context.h
|
|
@@ -28,10 +28,23 @@
|
|
#include "list.h"
|
|
#include "auth.h"
|
|
|
|
+enum ibft_ip_prefix_origin {
|
|
+ IBFT_IP_PREFIX_ORIGIN_OTHER = 0,
|
|
+ IBFT_IP_PREFIX_ORIGIN_MANUAL,
|
|
+ IBFT_IP_PREFIX_ORIGIN_WELL_KNOWN,
|
|
+ IBFT_IP_PREFIX_ORIGIN_DHCP,
|
|
+ IBFT_IP_PREFIX_ORIGIN_ROUTER_ADVERTISEMENT,
|
|
+ IBFT_IP_PREFIX_ORIGIN_UNCHANGED = 16
|
|
+};
|
|
+
|
|
struct boot_context {
|
|
struct list_head list;
|
|
+ char boot_root[BOOT_NAME_MAXLEN];
|
|
+ char boot_nic[BOOT_NAME_MAXLEN];
|
|
+ char boot_target[BOOT_NAME_MAXLEN];
|
|
|
|
/* target settings */
|
|
+ int target_flags;
|
|
int target_port;
|
|
char targetname[TARGET_NAME_MAXLEN + 1];
|
|
char target_ipaddr[NI_MAXHOST];
|
|
@@ -45,6 +58,8 @@ struct boot_context {
|
|
char initiatorname[TARGET_NAME_MAXLEN + 1];
|
|
|
|
/* network settings */
|
|
+ int nic_flags;
|
|
+ enum ibft_ip_prefix_origin origin;
|
|
char dhcp[NI_MAXHOST];
|
|
char iface[IF_NAMESIZE];
|
|
char mac[18];
|
|
diff --git a/include/iscsi_err.h b/include/iscsi_err.h
|
|
index aabea4e..125f443 100644
|
|
--- a/include/iscsi_err.h
|
|
+++ b/include/iscsi_err.h
|
|
@@ -62,6 +62,10 @@ enum {
|
|
ISCSI_ERR_OP_NOT_SUPP = 27,
|
|
/* device or resource in use */
|
|
ISCSI_ERR_BUSY = 28,
|
|
+ /* Operation failed, but retrying layer may succeed */
|
|
+ ISCSI_ERR_AGAIN = 29,
|
|
+ /* unknown discovery type */
|
|
+ ISCSI_ERR_UNKNOWN_DISCOVERY_TYPE = 30,
|
|
|
|
/* Always last. Indicates end of error code space */
|
|
ISCSI_MAX_ERR_VAL,
|
|
diff --git a/include/iscsi_if.h b/include/iscsi_if.h
|
|
index dad9fd8..9d15811 100644
|
|
--- a/include/iscsi_if.h
|
|
+++ b/include/iscsi_if.h
|
|
@@ -68,8 +68,15 @@ enum iscsi_uevent_e {
|
|
ISCSI_UEVENT_PING = UEVENT_BASE + 22,
|
|
ISCSI_UEVENT_GET_CHAP = UEVENT_BASE + 23,
|
|
ISCSI_UEVENT_DELETE_CHAP = UEVENT_BASE + 24,
|
|
-
|
|
- ISCSI_UEVENT_MAX = ISCSI_UEVENT_DELETE_CHAP,
|
|
+ ISCSI_UEVENT_SET_FLASHNODE_PARAMS = UEVENT_BASE + 25,
|
|
+ ISCSI_UEVENT_NEW_FLASHNODE = UEVENT_BASE + 26,
|
|
+ ISCSI_UEVENT_DEL_FLASHNODE = UEVENT_BASE + 27,
|
|
+ ISCSI_UEVENT_LOGIN_FLASHNODE = UEVENT_BASE + 28,
|
|
+ ISCSI_UEVENT_LOGOUT_FLASHNODE = UEVENT_BASE + 29,
|
|
+ ISCSI_UEVENT_LOGOUT_FLASHNODE_SID = UEVENT_BASE + 30,
|
|
+ ISCSI_UEVENT_SET_CHAP = UEVENT_BASE + 31,
|
|
+ ISCSI_UEVENT_GET_HOST_STATS = UEVENT_BASE + 32,
|
|
+ ISCSI_UEVENT_MAX = ISCSI_UEVENT_GET_HOST_STATS,
|
|
|
|
/* up events */
|
|
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
|
|
@@ -219,6 +226,35 @@ struct iscsi_uevent {
|
|
uint32_t host_no;
|
|
uint16_t chap_tbl_idx;
|
|
} delete_chap;
|
|
+ struct msg_set_flashnode_param {
|
|
+ uint32_t host_no;
|
|
+ uint32_t flashnode_idx;
|
|
+ uint32_t count;
|
|
+ } set_flashnode;
|
|
+ struct msg_new_flashnode {
|
|
+ uint32_t host_no;
|
|
+ uint32_t len;
|
|
+ } new_flashnode;
|
|
+ struct msg_del_flashnode {
|
|
+ uint32_t host_no;
|
|
+ uint32_t flashnode_idx;
|
|
+ } del_flashnode;
|
|
+ struct msg_login_flashnode {
|
|
+ uint32_t host_no;
|
|
+ uint32_t flashnode_idx;
|
|
+ } login_flashnode;
|
|
+ struct msg_logout_flashnode {
|
|
+ uint32_t host_no;
|
|
+ uint32_t flashnode_idx;
|
|
+ } logout_flashnode;
|
|
+ struct msg_logout_flashnode_sid {
|
|
+ uint32_t host_no;
|
|
+ uint32_t sid;
|
|
+ } logout_flashnode_sid;
|
|
+ struct msg_get_host_stats {
|
|
+ uint32_t host_no;
|
|
+ } get_host_stats;
|
|
+
|
|
} u;
|
|
union {
|
|
/* messages k -> u */
|
|
@@ -276,6 +312,9 @@ struct iscsi_uevent {
|
|
with each ping request */
|
|
uint32_t data_size;
|
|
} ping_comp;
|
|
+ struct msg_new_flashnode_ret {
|
|
+ uint32_t flashnode_idx;
|
|
+ } new_flashnode_ret;
|
|
} r;
|
|
} __attribute__ ((aligned (sizeof(uint64_t))));
|
|
|
|
@@ -283,8 +322,18 @@ enum iscsi_param_type {
|
|
ISCSI_PARAM, /* iscsi_param (session, conn, target, LU) */
|
|
ISCSI_HOST_PARAM, /* iscsi_host_param */
|
|
ISCSI_NET_PARAM, /* iscsi_net_param */
|
|
+ ISCSI_FLASHNODE_PARAM, /* iscsi_flashnode_param */
|
|
+ ISCSI_CHAP_PARAM, /* iscsi_chap_param */
|
|
+ ISCSI_IFACE_PARAM, /* iscsi_iface_param */
|
|
};
|
|
|
|
+/* structure for minimalist usecase */
|
|
+struct iscsi_param_info {
|
|
+ uint32_t len; /* Actual length of the param value */
|
|
+ uint16_t param; /* iscsi param */
|
|
+ uint8_t value[0]; /* length sized value follows */
|
|
+} __attribute__((__packed__));
|
|
+
|
|
struct iscsi_iface_param_info {
|
|
uint32_t iface_num; /* iface number, 0 - n */
|
|
uint32_t len; /* Actual length of the param */
|
|
@@ -348,28 +397,106 @@ struct iscsi_path {
|
|
#define ISCSI_VLAN_DISABLE 0x01
|
|
#define ISCSI_VLAN_ENABLE 0x02
|
|
|
|
+/* iscsi generic enable/disabled setting for various features */
|
|
+#define ISCSI_NET_PARAM_DISABLE 0x01
|
|
+#define ISCSI_NET_PARAM_ENABLE 0x02
|
|
+
|
|
/* iSCSI network params */
|
|
enum iscsi_net_param {
|
|
ISCSI_NET_PARAM_IPV4_ADDR = 1,
|
|
- ISCSI_NET_PARAM_IPV4_SUBNET = 2,
|
|
- ISCSI_NET_PARAM_IPV4_GW = 3,
|
|
- ISCSI_NET_PARAM_IPV4_BOOTPROTO = 4,
|
|
- ISCSI_NET_PARAM_MAC = 5,
|
|
- ISCSI_NET_PARAM_IPV6_LINKLOCAL = 6,
|
|
- ISCSI_NET_PARAM_IPV6_ADDR = 7,
|
|
- ISCSI_NET_PARAM_IPV6_ROUTER = 8,
|
|
- ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG = 9,
|
|
- ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG = 10,
|
|
- ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG = 11,
|
|
- ISCSI_NET_PARAM_IFACE_ENABLE = 12,
|
|
- ISCSI_NET_PARAM_VLAN_ID = 13,
|
|
- ISCSI_NET_PARAM_VLAN_PRIORITY = 14,
|
|
- ISCSI_NET_PARAM_VLAN_ENABLED = 15,
|
|
- ISCSI_NET_PARAM_VLAN_TAG = 16,
|
|
- ISCSI_NET_PARAM_IFACE_TYPE = 17,
|
|
- ISCSI_NET_PARAM_IFACE_NAME = 18,
|
|
- ISCSI_NET_PARAM_MTU = 19,
|
|
- ISCSI_NET_PARAM_PORT = 20,
|
|
+ ISCSI_NET_PARAM_IPV4_SUBNET,
|
|
+ ISCSI_NET_PARAM_IPV4_GW,
|
|
+ ISCSI_NET_PARAM_IPV4_BOOTPROTO,
|
|
+ ISCSI_NET_PARAM_MAC,
|
|
+ ISCSI_NET_PARAM_IPV6_LINKLOCAL,
|
|
+ ISCSI_NET_PARAM_IPV6_ADDR,
|
|
+ ISCSI_NET_PARAM_IPV6_ROUTER,
|
|
+ ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG,
|
|
+ ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG,
|
|
+ ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG,
|
|
+ ISCSI_NET_PARAM_IFACE_ENABLE,
|
|
+ ISCSI_NET_PARAM_VLAN_ID,
|
|
+ ISCSI_NET_PARAM_VLAN_PRIORITY,
|
|
+ ISCSI_NET_PARAM_VLAN_ENABLED,
|
|
+ ISCSI_NET_PARAM_VLAN_TAG,
|
|
+ ISCSI_NET_PARAM_IFACE_TYPE,
|
|
+ ISCSI_NET_PARAM_IFACE_NAME,
|
|
+ ISCSI_NET_PARAM_MTU,
|
|
+ ISCSI_NET_PARAM_PORT,
|
|
+ ISCSI_NET_PARAM_IPADDR_STATE,
|
|
+ ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE,
|
|
+ ISCSI_NET_PARAM_IPV6_ROUTER_STATE,
|
|
+ ISCSI_NET_PARAM_DELAYED_ACK_EN,
|
|
+ ISCSI_NET_PARAM_TCP_NAGLE_DISABLE,
|
|
+ ISCSI_NET_PARAM_TCP_WSF_DISABLE,
|
|
+ ISCSI_NET_PARAM_TCP_WSF,
|
|
+ ISCSI_NET_PARAM_TCP_TIMER_SCALE,
|
|
+ ISCSI_NET_PARAM_TCP_TIMESTAMP_EN,
|
|
+ ISCSI_NET_PARAM_CACHE_ID,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN,
|
|
+ ISCSI_NET_PARAM_IPV4_TOS_EN,
|
|
+ ISCSI_NET_PARAM_IPV4_TOS,
|
|
+ ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN,
|
|
+ ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE,
|
|
+ ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN,
|
|
+ ISCSI_NET_PARAM_IPV4_TTL,
|
|
+ ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN,
|
|
+ ISCSI_NET_PARAM_IPV6_MLD_EN,
|
|
+ ISCSI_NET_PARAM_IPV6_FLOW_LABEL,
|
|
+ ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS,
|
|
+ ISCSI_NET_PARAM_IPV6_HOP_LIMIT,
|
|
+ ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO,
|
|
+ ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME,
|
|
+ ISCSI_NET_PARAM_IPV6_ND_STALE_TMO,
|
|
+ ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT,
|
|
+ ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU,
|
|
+ ISCSI_NET_PARAM_REDIRECT_EN,
|
|
+};
|
|
+
|
|
+enum iscsi_ipaddress_state {
|
|
+ ISCSI_IPDDRESS_STATE_UNCONFIGURED,
|
|
+ ISCSI_IPDDRESS_STATE_ACQUIRING,
|
|
+ ISCSI_IPDDRESS_STATE_TENTATIVE,
|
|
+ ISCSI_IPDDRESS_STATE_VALID,
|
|
+ ISCSI_IPDDRESS_STATE_DISABLING,
|
|
+ ISCSI_IPDDRESS_STATE_INVALID,
|
|
+ ISCSI_IPDDRESS_STATE_DEPRECATED,
|
|
+};
|
|
+
|
|
+enum iscsi_router_state {
|
|
+ ISCSI_ROUTER_STATE_UNKNOWN,
|
|
+ ISCSI_ROUTER_STATE_ADVERTISED,
|
|
+ ISCSI_ROUTER_STATE_MANUAL,
|
|
+ ISCSI_ROUTER_STATE_STALE,
|
|
+};
|
|
+
|
|
+/* iSCSI specific settings params for iface */
|
|
+enum iscsi_iface_param {
|
|
+ ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO,
|
|
+ ISCSI_IFACE_PARAM_HDRDGST_EN,
|
|
+ ISCSI_IFACE_PARAM_DATADGST_EN,
|
|
+ ISCSI_IFACE_PARAM_IMM_DATA_EN,
|
|
+ ISCSI_IFACE_PARAM_INITIAL_R2T_EN,
|
|
+ ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN,
|
|
+ ISCSI_IFACE_PARAM_PDU_INORDER_EN,
|
|
+ ISCSI_IFACE_PARAM_ERL,
|
|
+ ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH,
|
|
+ ISCSI_IFACE_PARAM_FIRST_BURST,
|
|
+ ISCSI_IFACE_PARAM_MAX_R2T,
|
|
+ ISCSI_IFACE_PARAM_MAX_BURST,
|
|
+ ISCSI_IFACE_PARAM_CHAP_AUTH_EN,
|
|
+ ISCSI_IFACE_PARAM_BIDI_CHAP_EN,
|
|
+ ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL,
|
|
+ ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN,
|
|
+ ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN,
|
|
+ ISCSI_IFACE_PARAM_INITIATOR_NAME,
|
|
};
|
|
|
|
enum iscsi_conn_state {
|
|
@@ -460,61 +587,157 @@ enum iscsi_param {
|
|
|
|
ISCSI_PARAM_TGT_RESET_TMO,
|
|
ISCSI_PARAM_TARGET_ALIAS,
|
|
+
|
|
+ ISCSI_PARAM_CHAP_IN_IDX,
|
|
+ ISCSI_PARAM_CHAP_OUT_IDX,
|
|
+
|
|
+ ISCSI_PARAM_BOOT_ROOT,
|
|
+ ISCSI_PARAM_BOOT_NIC,
|
|
+ ISCSI_PARAM_BOOT_TARGET,
|
|
+
|
|
+ ISCSI_PARAM_AUTO_SND_TGT_DISABLE,
|
|
+ ISCSI_PARAM_DISCOVERY_SESS,
|
|
+ ISCSI_PARAM_PORTAL_TYPE,
|
|
+ ISCSI_PARAM_CHAP_AUTH_EN,
|
|
+ ISCSI_PARAM_DISCOVERY_LOGOUT_EN,
|
|
+ ISCSI_PARAM_BIDI_CHAP_EN,
|
|
+ ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL,
|
|
+
|
|
+ ISCSI_PARAM_DEF_TIME2WAIT,
|
|
+ ISCSI_PARAM_DEF_TIME2RETAIN,
|
|
+ ISCSI_PARAM_MAX_SEGMENT_SIZE,
|
|
+ ISCSI_PARAM_STATSN,
|
|
+ ISCSI_PARAM_KEEPALIVE_TMO,
|
|
+ ISCSI_PARAM_LOCAL_PORT,
|
|
+ ISCSI_PARAM_TSID,
|
|
+ ISCSI_PARAM_DEF_TASKMGMT_TMO,
|
|
+
|
|
+ ISCSI_PARAM_TCP_TIMESTAMP_STAT,
|
|
+ ISCSI_PARAM_TCP_WSF_DISABLE,
|
|
+ ISCSI_PARAM_TCP_NAGLE_DISABLE,
|
|
+ ISCSI_PARAM_TCP_TIMER_SCALE,
|
|
+ ISCSI_PARAM_TCP_TIMESTAMP_EN,
|
|
+ ISCSI_PARAM_TCP_XMIT_WSF,
|
|
+ ISCSI_PARAM_TCP_RECV_WSF,
|
|
+ ISCSI_PARAM_IP_FRAGMENT_DISABLE,
|
|
+ ISCSI_PARAM_IPV4_TOS,
|
|
+ ISCSI_PARAM_IPV6_TC,
|
|
+ ISCSI_PARAM_IPV6_FLOW_LABEL,
|
|
+ ISCSI_PARAM_IS_FW_ASSIGNED_IPV6,
|
|
+
|
|
+ ISCSI_PARAM_DISCOVERY_PARENT_IDX,
|
|
+ ISCSI_PARAM_DISCOVERY_PARENT_TYPE,
|
|
/* must always be last */
|
|
ISCSI_PARAM_MAX,
|
|
};
|
|
|
|
-#define ISCSI_MAX_RECV_DLENGTH (1ULL << ISCSI_PARAM_MAX_RECV_DLENGTH)
|
|
-#define ISCSI_MAX_XMIT_DLENGTH (1ULL << ISCSI_PARAM_MAX_XMIT_DLENGTH)
|
|
-#define ISCSI_HDRDGST_EN (1ULL << ISCSI_PARAM_HDRDGST_EN)
|
|
-#define ISCSI_DATADGST_EN (1ULL << ISCSI_PARAM_DATADGST_EN)
|
|
-#define ISCSI_INITIAL_R2T_EN (1ULL << ISCSI_PARAM_INITIAL_R2T_EN)
|
|
-#define ISCSI_MAX_R2T (1ULL << ISCSI_PARAM_MAX_R2T)
|
|
-#define ISCSI_IMM_DATA_EN (1ULL << ISCSI_PARAM_IMM_DATA_EN)
|
|
-#define ISCSI_FIRST_BURST (1ULL << ISCSI_PARAM_FIRST_BURST)
|
|
-#define ISCSI_MAX_BURST (1ULL << ISCSI_PARAM_MAX_BURST)
|
|
-#define ISCSI_PDU_INORDER_EN (1ULL << ISCSI_PARAM_PDU_INORDER_EN)
|
|
-#define ISCSI_DATASEQ_INORDER_EN (1ULL << ISCSI_PARAM_DATASEQ_INORDER_EN)
|
|
-#define ISCSI_ERL (1ULL << ISCSI_PARAM_ERL)
|
|
-#define ISCSI_IFMARKER_EN (1ULL << ISCSI_PARAM_IFMARKER_EN)
|
|
-#define ISCSI_OFMARKER_EN (1ULL << ISCSI_PARAM_OFMARKER_EN)
|
|
-#define ISCSI_EXP_STATSN (1ULL << ISCSI_PARAM_EXP_STATSN)
|
|
-#define ISCSI_TARGET_NAME (1ULL << ISCSI_PARAM_TARGET_NAME)
|
|
-#define ISCSI_TPGT (1ULL << ISCSI_PARAM_TPGT)
|
|
-#define ISCSI_PERSISTENT_ADDRESS (1ULL << ISCSI_PARAM_PERSISTENT_ADDRESS)
|
|
-#define ISCSI_PERSISTENT_PORT (1ULL << ISCSI_PARAM_PERSISTENT_PORT)
|
|
-#define ISCSI_SESS_RECOVERY_TMO (1ULL << ISCSI_PARAM_SESS_RECOVERY_TMO)
|
|
-#define ISCSI_CONN_PORT (1ULL << ISCSI_PARAM_CONN_PORT)
|
|
-#define ISCSI_CONN_ADDRESS (1ULL << ISCSI_PARAM_CONN_ADDRESS)
|
|
-#define ISCSI_USERNAME (1ULL << ISCSI_PARAM_USERNAME)
|
|
-#define ISCSI_USERNAME_IN (1ULL << ISCSI_PARAM_USERNAME_IN)
|
|
-#define ISCSI_PASSWORD (1ULL << ISCSI_PARAM_PASSWORD)
|
|
-#define ISCSI_PASSWORD_IN (1ULL << ISCSI_PARAM_PASSWORD_IN)
|
|
-#define ISCSI_FAST_ABORT (1ULL << ISCSI_PARAM_FAST_ABORT)
|
|
-#define ISCSI_ABORT_TMO (1ULL << ISCSI_PARAM_ABORT_TMO)
|
|
-#define ISCSI_LU_RESET_TMO (1ULL << ISCSI_PARAM_LU_RESET_TMO)
|
|
-#define ISCSI_HOST_RESET_TMO (1ULL << ISCSI_PARAM_HOST_RESET_TMO)
|
|
-#define ISCSI_PING_TMO (1ULL << ISCSI_PARAM_PING_TMO)
|
|
-#define ISCSI_RECV_TMO (1ULL << ISCSI_PARAM_RECV_TMO)
|
|
-#define ISCSI_IFACE_NAME (1ULL << ISCSI_PARAM_IFACE_NAME)
|
|
-#define ISCSI_ISID (1ULL << ISCSI_PARAM_ISID)
|
|
-#define ISCSI_INITIATOR_NAME (1ULL << ISCSI_PARAM_INITIATOR_NAME)
|
|
-#define ISCSI_TGT_RESET_TMO (1ULL << ISCSI_PARAM_TGT_RESET_TMO)
|
|
-#define ISCSI_TARGET_ALIAS (1ULL << ISCSI_PARAM_TARGET_ALIAS)
|
|
-
|
|
/* iSCSI HBA params */
|
|
enum iscsi_host_param {
|
|
ISCSI_HOST_PARAM_HWADDRESS,
|
|
ISCSI_HOST_PARAM_INITIATOR_NAME,
|
|
ISCSI_HOST_PARAM_NETDEV_NAME,
|
|
ISCSI_HOST_PARAM_IPADDRESS,
|
|
+ ISCSI_HOST_PARAM_PORT_STATE,
|
|
+ ISCSI_HOST_PARAM_PORT_SPEED,
|
|
ISCSI_HOST_PARAM_MAX,
|
|
};
|
|
|
|
-#define ISCSI_HOST_HWADDRESS (1ULL << ISCSI_HOST_PARAM_HWADDRESS)
|
|
-#define ISCSI_HOST_INITIATOR_NAME (1ULL << ISCSI_HOST_PARAM_INITIATOR_NAME)
|
|
-#define ISCSI_HOST_NETDEV_NAME (1ULL << ISCSI_HOST_PARAM_NETDEV_NAME)
|
|
-#define ISCSI_HOST_IPADDRESS (1ULL << ISCSI_HOST_PARAM_IPADDRESS)
|
|
+/* portal type */
|
|
+#define PORTAL_TYPE_IPV4 "ipv4"
|
|
+#define PORTAL_TYPE_IPV6 "ipv6"
|
|
+
|
|
+/* iSCSI Flash Target params */
|
|
+enum iscsi_flashnode_param {
|
|
+ ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6,
|
|
+ ISCSI_FLASHNODE_PORTAL_TYPE,
|
|
+ ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE,
|
|
+ ISCSI_FLASHNODE_DISCOVERY_SESS,
|
|
+ ISCSI_FLASHNODE_ENTRY_EN,
|
|
+ ISCSI_FLASHNODE_HDR_DGST_EN,
|
|
+ ISCSI_FLASHNODE_DATA_DGST_EN,
|
|
+ ISCSI_FLASHNODE_IMM_DATA_EN,
|
|
+ ISCSI_FLASHNODE_INITIAL_R2T_EN,
|
|
+ ISCSI_FLASHNODE_DATASEQ_INORDER,
|
|
+ ISCSI_FLASHNODE_PDU_INORDER,
|
|
+ ISCSI_FLASHNODE_CHAP_AUTH_EN,
|
|
+ ISCSI_FLASHNODE_SNACK_REQ_EN,
|
|
+ ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN,
|
|
+ ISCSI_FLASHNODE_BIDI_CHAP_EN,
|
|
+ /* make authentication for discovery sessions optional */
|
|
+ ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL,
|
|
+ ISCSI_FLASHNODE_ERL,
|
|
+ ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT,
|
|
+ ISCSI_FLASHNODE_TCP_NAGLE_DISABLE,
|
|
+ ISCSI_FLASHNODE_TCP_WSF_DISABLE,
|
|
+ ISCSI_FLASHNODE_TCP_TIMER_SCALE,
|
|
+ ISCSI_FLASHNODE_TCP_TIMESTAMP_EN,
|
|
+ ISCSI_FLASHNODE_IP_FRAG_DISABLE,
|
|
+ ISCSI_FLASHNODE_MAX_RECV_DLENGTH,
|
|
+ ISCSI_FLASHNODE_MAX_XMIT_DLENGTH,
|
|
+ ISCSI_FLASHNODE_FIRST_BURST,
|
|
+ ISCSI_FLASHNODE_DEF_TIME2WAIT,
|
|
+ ISCSI_FLASHNODE_DEF_TIME2RETAIN,
|
|
+ ISCSI_FLASHNODE_MAX_R2T,
|
|
+ ISCSI_FLASHNODE_KEEPALIVE_TMO,
|
|
+ ISCSI_FLASHNODE_ISID,
|
|
+ ISCSI_FLASHNODE_TSID,
|
|
+ ISCSI_FLASHNODE_PORT,
|
|
+ ISCSI_FLASHNODE_MAX_BURST,
|
|
+ ISCSI_FLASHNODE_DEF_TASKMGMT_TMO,
|
|
+ ISCSI_FLASHNODE_IPADDR,
|
|
+ ISCSI_FLASHNODE_ALIAS,
|
|
+ ISCSI_FLASHNODE_REDIRECT_IPADDR,
|
|
+ ISCSI_FLASHNODE_MAX_SEGMENT_SIZE,
|
|
+ ISCSI_FLASHNODE_LOCAL_PORT,
|
|
+ ISCSI_FLASHNODE_IPV4_TOS,
|
|
+ ISCSI_FLASHNODE_IPV6_TC,
|
|
+ ISCSI_FLASHNODE_IPV6_FLOW_LABEL,
|
|
+ ISCSI_FLASHNODE_NAME,
|
|
+ ISCSI_FLASHNODE_TPGT,
|
|
+ ISCSI_FLASHNODE_LINK_LOCAL_IPV6,
|
|
+ ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX,
|
|
+ ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE,
|
|
+ ISCSI_FLASHNODE_TCP_XMIT_WSF,
|
|
+ ISCSI_FLASHNODE_TCP_RECV_WSF,
|
|
+ ISCSI_FLASHNODE_CHAP_IN_IDX,
|
|
+ ISCSI_FLASHNODE_CHAP_OUT_IDX,
|
|
+ ISCSI_FLASHNODE_USERNAME,
|
|
+ ISCSI_FLASHNODE_USERNAME_IN,
|
|
+ ISCSI_FLASHNODE_PASSWORD,
|
|
+ ISCSI_FLASHNODE_PASSWORD_IN,
|
|
+ ISCSI_FLASHNODE_STATSN,
|
|
+ ISCSI_FLASHNODE_EXP_STATSN,
|
|
+ ISCSI_FLASHNODE_IS_BOOT_TGT,
|
|
+
|
|
+ ISCSI_FLASHNODE_MAX,
|
|
+};
|
|
+
|
|
+struct iscsi_flashnode_param_info {
|
|
+ uint32_t len; /* Actual length of the param */
|
|
+ uint16_t param; /* iscsi param value */
|
|
+ uint8_t value[0]; /* length sized value follows */
|
|
+} __attribute__((__packed__));
|
|
+
|
|
+enum iscsi_discovery_parent_type {
|
|
+ ISCSI_DISC_PARENT_UNKNOWN = 0x1,
|
|
+ ISCSI_DISC_PARENT_SENDTGT = 0x2,
|
|
+ ISCSI_DISC_PARENT_ISNS = 0x3,
|
|
+};
|
|
+
|
|
+/* iSCSI port Speed */
|
|
+enum iscsi_port_speed {
|
|
+ ISCSI_PORT_SPEED_UNKNOWN = 0x1,
|
|
+ ISCSI_PORT_SPEED_10MBPS = 0x2,
|
|
+ ISCSI_PORT_SPEED_100MBPS = 0x4,
|
|
+ ISCSI_PORT_SPEED_1GBPS = 0x8,
|
|
+ ISCSI_PORT_SPEED_10GBPS = 0x10,
|
|
+};
|
|
+
|
|
+/* iSCSI port state */
|
|
+enum iscsi_port_state {
|
|
+ ISCSI_PORT_STATE_DOWN = 0x1,
|
|
+ ISCSI_PORT_STATE_UP = 0x2,
|
|
+};
|
|
|
|
/* iSCSI PING status/error code */
|
|
enum iscsi_ping_status_code {
|
|
@@ -551,7 +774,7 @@ enum iscsi_ping_status_code {
|
|
#define CAP_DIGEST_OFFLOAD 0x1000 /* offload hdr and data digests */
|
|
#define CAP_PADDING_OFFLOAD 0x2000 /* offload padding insertion, removal,
|
|
and verification */
|
|
-#define CAP_LOGIN_OFFLOAD 0x4000 /* offload normal session login */
|
|
+#define CAP_LOGIN_OFFLOAD 0x4000 /* offload session login */
|
|
|
|
/*
|
|
* These flags describes reason of stop_conn() call
|
|
@@ -617,9 +840,16 @@ enum chap_type_e {
|
|
CHAP_TYPE_IN,
|
|
};
|
|
|
|
+enum iscsi_chap_param {
|
|
+ ISCSI_CHAP_PARAM_INDEX,
|
|
+ ISCSI_CHAP_PARAM_CHAP_TYPE,
|
|
+ ISCSI_CHAP_PARAM_USERNAME,
|
|
+ ISCSI_CHAP_PARAM_PASSWORD,
|
|
+ ISCSI_CHAP_PARAM_PASSWORD_LEN
|
|
+};
|
|
+
|
|
#define ISCSI_CHAP_AUTH_NAME_MAX_LEN 256
|
|
#define ISCSI_CHAP_AUTH_SECRET_MAX_LEN 256
|
|
-
|
|
struct iscsi_chap_rec {
|
|
uint16_t chap_tbl_idx;
|
|
enum chap_type_e chap_type;
|
|
@@ -628,4 +858,112 @@ struct iscsi_chap_rec {
|
|
uint8_t password_length;
|
|
};
|
|
|
|
+#define ISCSI_HOST_STATS_CUSTOM_MAX 32
|
|
+#define ISCSI_HOST_STATS_CUSTOM_DESC_MAX 64
|
|
+struct iscsi_host_stats_custom {
|
|
+ char desc[ISCSI_HOST_STATS_CUSTOM_DESC_MAX];
|
|
+ uint64_t value;
|
|
+};
|
|
+
|
|
+/* struct iscsi_offload_host_stats: Host statistics,
|
|
+ * Include statistics for MAC, IP, TCP & iSCSI.
|
|
+ */
|
|
+struct iscsi_offload_host_stats {
|
|
+ /* MAC */
|
|
+ uint64_t mactx_frames;
|
|
+ uint64_t mactx_bytes;
|
|
+ uint64_t mactx_multicast_frames;
|
|
+ uint64_t mactx_broadcast_frames;
|
|
+ uint64_t mactx_pause_frames;
|
|
+ uint64_t mactx_control_frames;
|
|
+ uint64_t mactx_deferral;
|
|
+ uint64_t mactx_excess_deferral;
|
|
+ uint64_t mactx_late_collision;
|
|
+ uint64_t mactx_abort;
|
|
+ uint64_t mactx_single_collision;
|
|
+ uint64_t mactx_multiple_collision;
|
|
+ uint64_t mactx_collision;
|
|
+ uint64_t mactx_frames_dropped;
|
|
+ uint64_t mactx_jumbo_frames;
|
|
+ uint64_t macrx_frames;
|
|
+ uint64_t macrx_bytes;
|
|
+ uint64_t macrx_unknown_control_frames;
|
|
+ uint64_t macrx_pause_frames;
|
|
+ uint64_t macrx_control_frames;
|
|
+ uint64_t macrx_dribble;
|
|
+ uint64_t macrx_frame_length_error;
|
|
+ uint64_t macrx_jabber;
|
|
+ uint64_t macrx_carrier_sense_error;
|
|
+ uint64_t macrx_frame_discarded;
|
|
+ uint64_t macrx_frames_dropped;
|
|
+ uint64_t mac_crc_error;
|
|
+ uint64_t mac_encoding_error;
|
|
+ uint64_t macrx_length_error_large;
|
|
+ uint64_t macrx_length_error_small;
|
|
+ uint64_t macrx_multicast_frames;
|
|
+ uint64_t macrx_broadcast_frames;
|
|
+ /* IP */
|
|
+ uint64_t iptx_packets;
|
|
+ uint64_t iptx_bytes;
|
|
+ uint64_t iptx_fragments;
|
|
+ uint64_t iprx_packets;
|
|
+ uint64_t iprx_bytes;
|
|
+ uint64_t iprx_fragments;
|
|
+ uint64_t ip_datagram_reassembly;
|
|
+ uint64_t ip_invalid_address_error;
|
|
+ uint64_t ip_error_packets;
|
|
+ uint64_t ip_fragrx_overlap;
|
|
+ uint64_t ip_fragrx_outoforder;
|
|
+ uint64_t ip_datagram_reassembly_timeout;
|
|
+ uint64_t ipv6tx_packets;
|
|
+ uint64_t ipv6tx_bytes;
|
|
+ uint64_t ipv6tx_fragments;
|
|
+ uint64_t ipv6rx_packets;
|
|
+ uint64_t ipv6rx_bytes;
|
|
+ uint64_t ipv6rx_fragments;
|
|
+ uint64_t ipv6_datagram_reassembly;
|
|
+ uint64_t ipv6_invalid_address_error;
|
|
+ uint64_t ipv6_error_packets;
|
|
+ uint64_t ipv6_fragrx_overlap;
|
|
+ uint64_t ipv6_fragrx_outoforder;
|
|
+ uint64_t ipv6_datagram_reassembly_timeout;
|
|
+ /* TCP */
|
|
+ uint64_t tcptx_segments;
|
|
+ uint64_t tcptx_bytes;
|
|
+ uint64_t tcprx_segments;
|
|
+ uint64_t tcprx_byte;
|
|
+ uint64_t tcp_duplicate_ack_retx;
|
|
+ uint64_t tcp_retx_timer_expired;
|
|
+ uint64_t tcprx_duplicate_ack;
|
|
+ uint64_t tcprx_pure_ackr;
|
|
+ uint64_t tcptx_delayed_ack;
|
|
+ uint64_t tcptx_pure_ack;
|
|
+ uint64_t tcprx_segment_error;
|
|
+ uint64_t tcprx_segment_outoforder;
|
|
+ uint64_t tcprx_window_probe;
|
|
+ uint64_t tcprx_window_update;
|
|
+ uint64_t tcptx_window_probe_persist;
|
|
+ /* ECC */
|
|
+ uint64_t ecc_error_correction;
|
|
+ /* iSCSI */
|
|
+ uint64_t iscsi_pdu_tx;
|
|
+ uint64_t iscsi_data_bytes_tx;
|
|
+ uint64_t iscsi_pdu_rx;
|
|
+ uint64_t iscsi_data_bytes_rx;
|
|
+ uint64_t iscsi_io_completed;
|
|
+ uint64_t iscsi_unexpected_io_rx;
|
|
+ uint64_t iscsi_format_error;
|
|
+ uint64_t iscsi_hdr_digest_error;
|
|
+ uint64_t iscsi_data_digest_error;
|
|
+ uint64_t iscsi_sequence_error;
|
|
+ /*
|
|
+ * iSCSI Custom Host Statistics support, i.e. Transport could
|
|
+ * extend existing host statistics with its own specific statistics
|
|
+ * up to ISCSI_HOST_STATS_CUSTOM_MAX
|
|
+ */
|
|
+ uint32_t custom_length;
|
|
+ struct iscsi_host_stats_custom custom[0]
|
|
+ __attribute__ ((aligned (sizeof(uint64_t))));
|
|
+};
|
|
+
|
|
#endif
|
|
diff --git a/include/iscsi_proto.h b/include/iscsi_proto.h
|
|
index 1c69feb..56f757b 100644
|
|
--- a/include/iscsi_proto.h
|
|
+++ b/include/iscsi_proto.h
|
|
@@ -619,6 +619,7 @@ struct iscsi_reject {
|
|
#define KEY_MAXLEN 64
|
|
#define VALUE_MAXLEN 255
|
|
#define TARGET_NAME_MAXLEN VALUE_MAXLEN
|
|
+#define BOOT_NAME_MAXLEN 256
|
|
|
|
#define ISCSI_DEF_MAX_RECV_SEG_LEN 8192
|
|
#define ISCSI_MIN_MAX_RECV_SEG_LEN 512
|
|
diff --git a/include/list.h b/include/list.h
|
|
index cccc3c3..94ad99b 100644
|
|
--- a/include/list.h
|
|
+++ b/include/list.h
|
|
@@ -38,6 +38,12 @@ static inline int list_empty(const struct list_head *head)
|
|
#define list_entry(ptr, type, member) \
|
|
list_container_of(ptr, type, member)
|
|
|
|
+#define list_first_entry(ptr, type, member) \
|
|
+ list_entry((ptr)->next, type, member)
|
|
+
|
|
+#define list_first_entry_or_null(ptr, type, member) \
|
|
+ (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
|
|
+
|
|
#define list_for_each(pos, head) \
|
|
for (pos = (head)->next; pos != (head); pos = pos->next)
|
|
|
|
diff --git a/iscsiuio/.gitignore b/iscsiuio/.gitignore
|
|
new file mode 100644
|
|
index 0000000..a27452a
|
|
--- /dev/null
|
|
+++ b/iscsiuio/.gitignore
|
|
@@ -0,0 +1,25 @@
|
|
+# Autogenerated files
|
|
+stamp-h1
|
|
+Makefile.in
|
|
+Makefile
|
|
+configure
|
|
+config.h.in
|
|
+config.h
|
|
+config.guess
|
|
+config.log
|
|
+config.status
|
|
+config.sub
|
|
+COPYING
|
|
+
|
|
+.deps
|
|
+autom4te.cache
|
|
+
|
|
+# autotools
|
|
+aclocal.m4
|
|
+compile
|
|
+depcomp
|
|
+install-sh
|
|
+libtool
|
|
+ltmain.sh
|
|
+missing
|
|
+
|
|
diff --git a/iscsiuio/AUTHORS b/iscsiuio/AUTHORS
|
|
new file mode 100644
|
|
index 0000000..e69de29
|
|
diff --git a/iscsiuio/ChangeLog b/iscsiuio/ChangeLog
|
|
new file mode 100644
|
|
index 0000000..a91b4d5
|
|
--- /dev/null
|
|
+++ b/iscsiuio/ChangeLog
|
|
@@ -0,0 +1,7 @@
|
|
+Version 0.4.1 (July 20, 2009)
|
|
+ * Fix from Mike Christie to determine page size from getpagesize()
|
|
+ rather then the constant PAGE_SIZE. PAGE_SIZE is not defined om
|
|
+ ia64 and ppc.
|
|
+ * Update documentation to indicate IPv6 is not supported
|
|
+ * Fix code to catch the message from the CNIC that the network
|
|
+ interface is going down.
|
|
diff --git a/iscsiuio/INSTALL b/iscsiuio/INSTALL
|
|
new file mode 100644
|
|
index 0000000..c9fd2c0
|
|
--- /dev/null
|
|
+++ b/iscsiuio/INSTALL
|
|
@@ -0,0 +1,290 @@
|
|
+Installation Instructions
|
|
+*************************
|
|
+
|
|
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
|
|
+2006, 2007, 2008 Free Software Foundation, Inc.
|
|
+
|
|
+ This file is free documentation; the Free Software Foundation gives
|
|
+unlimited permission to copy, distribute and modify it.
|
|
+
|
|
+Basic Installation
|
|
+==================
|
|
+
|
|
+ Briefly, the shell commands `./configure; make; make install' should
|
|
+configure, build, and install this package. The following
|
|
+more-detailed instructions are generic; see the `README' file for
|
|
+instructions specific to this package.
|
|
+
|
|
+ The `configure' shell script attempts to guess correct values for
|
|
+various system-dependent variables used during compilation. It uses
|
|
+those values to create a `Makefile' in each directory of the package.
|
|
+It may also create one or more `.h' files containing system-dependent
|
|
+definitions. Finally, it creates a shell script `config.status' that
|
|
+you can run in the future to recreate the current configuration, and a
|
|
+file `config.log' containing compiler output (useful mainly for
|
|
+debugging `configure').
|
|
+
|
|
+ It can also use an optional file (typically called `config.cache'
|
|
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
|
+the results of its tests to speed up reconfiguring. Caching is
|
|
+disabled by default to prevent problems with accidental use of stale
|
|
+cache files.
|
|
+
|
|
+ If you need to do unusual things to compile the package, please try
|
|
+to figure out how `configure' could check whether to do them, and mail
|
|
+diffs or instructions to the address given in the `README' so they can
|
|
+be considered for the next release. If you are using the cache, and at
|
|
+some point `config.cache' contains results you don't want to keep, you
|
|
+may remove or edit it.
|
|
+
|
|
+ The file `configure.ac' (or `configure.in') is used to create
|
|
+`configure' by a program called `autoconf'. You need `configure.ac' if
|
|
+you want to change it or regenerate `configure' using a newer version
|
|
+of `autoconf'.
|
|
+
|
|
+The simplest way to compile this package is:
|
|
+
|
|
+ 1. `cd' to the directory containing the package's source code and type
|
|
+ `./configure' to configure the package for your system.
|
|
+
|
|
+ Running `configure' might take a while. While running, it prints
|
|
+ some messages telling which features it is checking for.
|
|
+
|
|
+ 2. Type `make' to compile the package.
|
|
+
|
|
+ 3. Optionally, type `make check' to run any self-tests that come with
|
|
+ the package.
|
|
+
|
|
+ 4. Type `make install' to install the programs and any data files and
|
|
+ documentation.
|
|
+
|
|
+ 5. You can remove the program binaries and object files from the
|
|
+ source code directory by typing `make clean'. To also remove the
|
|
+ files that `configure' created (so you can compile the package for
|
|
+ a different kind of computer), type `make distclean'. There is
|
|
+ also a `make maintainer-clean' target, but that is intended mainly
|
|
+ for the package's developers. If you use it, you may have to get
|
|
+ all sorts of other programs in order to regenerate files that came
|
|
+ with the distribution.
|
|
+
|
|
+ 6. Often, you can also type `make uninstall' to remove the installed
|
|
+ files again.
|
|
+
|
|
+Compilers and Options
|
|
+=====================
|
|
+
|
|
+ Some systems require unusual options for compilation or linking that
|
|
+the `configure' script does not know about. Run `./configure --help'
|
|
+for details on some of the pertinent environment variables.
|
|
+
|
|
+ You can give `configure' initial values for configuration parameters
|
|
+by setting variables in the command line or in the environment. Here
|
|
+is an example:
|
|
+
|
|
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
|
+
|
|
+ *Note Defining Variables::, for more details.
|
|
+
|
|
+Compiling For Multiple Architectures
|
|
+====================================
|
|
+
|
|
+ You can compile the package for more than one kind of computer at the
|
|
+same time, by placing the object files for each architecture in their
|
|
+own directory. To do this, you can use GNU `make'. `cd' to the
|
|
+directory where you want the object files and executables to go and run
|
|
+the `configure' script. `configure' automatically checks for the
|
|
+source code in the directory that `configure' is in and in `..'.
|
|
+
|
|
+ With a non-GNU `make', it is safer to compile the package for one
|
|
+architecture at a time in the source code directory. After you have
|
|
+installed the package for one architecture, use `make distclean' before
|
|
+reconfiguring for another architecture.
|
|
+
|
|
+ On MacOS X 10.5 and later systems, you can create libraries and
|
|
+executables that work on multiple system types--known as "fat" or
|
|
+"universal" binaries--by specifying multiple `-arch' options to the
|
|
+compiler but only a single `-arch' option to the preprocessor. Like
|
|
+this:
|
|
+
|
|
+ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
|
+ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
|
+ CPP="gcc -E" CXXCPP="g++ -E"
|
|
+
|
|
+ This is not guaranteed to produce working output in all cases, you
|
|
+may have to build one architecture at a time and combine the results
|
|
+using the `lipo' tool if you have problems.
|
|
+
|
|
+Installation Names
|
|
+==================
|
|
+
|
|
+ By default, `make install' installs the package's commands under
|
|
+`/usr/local/bin', include files under `/usr/local/include', etc. You
|
|
+can specify an installation prefix other than `/usr/local' by giving
|
|
+`configure' the option `--prefix=PREFIX'.
|
|
+
|
|
+ You can specify separate installation prefixes for
|
|
+architecture-specific files and architecture-independent files. If you
|
|
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
|
+PREFIX as the prefix for installing programs and libraries.
|
|
+Documentation and other data files still use the regular prefix.
|
|
+
|
|
+ In addition, if you use an unusual directory layout you can give
|
|
+options like `--bindir=DIR' to specify different values for particular
|
|
+kinds of files. Run `configure --help' for a list of the directories
|
|
+you can set and what kinds of files go in them.
|
|
+
|
|
+ If the package supports it, you can cause programs to be installed
|
|
+with an extra prefix or suffix on their names by giving `configure' the
|
|
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
|
+
|
|
+Optional Features
|
|
+=================
|
|
+
|
|
+ Some packages pay attention to `--enable-FEATURE' options to
|
|
+`configure', where FEATURE indicates an optional part of the package.
|
|
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
|
+is something like `gnu-as' or `x' (for the X Window System). The
|
|
+`README' should mention any `--enable-' and `--with-' options that the
|
|
+package recognizes.
|
|
+
|
|
+ For packages that use the X Window System, `configure' can usually
|
|
+find the X include and library files automatically, but if it doesn't,
|
|
+you can use the `configure' options `--x-includes=DIR' and
|
|
+`--x-libraries=DIR' to specify their locations.
|
|
+
|
|
+Particular systems
|
|
+==================
|
|
+
|
|
+ On HP-UX, the default C compiler is not ANSI C compatible. If GNU
|
|
+CC is not installed, it is recommended to use the following options in
|
|
+order to use an ANSI C compiler:
|
|
+
|
|
+ ./configure CC="cc -Ae"
|
|
+
|
|
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
|
+
|
|
+ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
|
+parse its `<wchar.h>' header file. The option `-nodtk' can be used as
|
|
+a workaround. If GNU CC is not installed, it is therefore recommended
|
|
+to try
|
|
+
|
|
+ ./configure CC="cc"
|
|
+
|
|
+and if that doesn't work, try
|
|
+
|
|
+ ./configure CC="cc -nodtk"
|
|
+
|
|
+Specifying the System Type
|
|
+==========================
|
|
+
|
|
+ There may be some features `configure' cannot figure out
|
|
+automatically, but needs to determine by the type of machine the package
|
|
+will run on. Usually, assuming the package is built to be run on the
|
|
+_same_ architectures, `configure' can figure that out, but if it prints
|
|
+a message saying it cannot guess the machine type, give it the
|
|
+`--build=TYPE' option. TYPE can either be a short name for the system
|
|
+type, such as `sun4', or a canonical name which has the form:
|
|
+
|
|
+ CPU-COMPANY-SYSTEM
|
|
+
|
|
+where SYSTEM can have one of these forms:
|
|
+
|
|
+ OS KERNEL-OS
|
|
+
|
|
+ See the file `config.sub' for the possible values of each field. If
|
|
+`config.sub' isn't included in this package, then this package doesn't
|
|
+need to know the machine type.
|
|
+
|
|
+ If you are _building_ compiler tools for cross-compiling, you should
|
|
+use the option `--target=TYPE' to select the type of system they will
|
|
+produce code for.
|
|
+
|
|
+ If you want to _use_ a cross compiler, that generates code for a
|
|
+platform different from the build platform, you should specify the
|
|
+"host" platform (i.e., that on which the generated programs will
|
|
+eventually be run) with `--host=TYPE'.
|
|
+
|
|
+Sharing Defaults
|
|
+================
|
|
+
|
|
+ If you want to set default values for `configure' scripts to share,
|
|
+you can create a site shell script called `config.site' that gives
|
|
+default values for variables like `CC', `cache_file', and `prefix'.
|
|
+`configure' looks for `PREFIX/share/config.site' if it exists, then
|
|
+`PREFIX/etc/config.site' if it exists. Or, you can set the
|
|
+`CONFIG_SITE' environment variable to the location of the site script.
|
|
+A warning: not all `configure' scripts look for a site script.
|
|
+
|
|
+Defining Variables
|
|
+==================
|
|
+
|
|
+ Variables not defined in a site shell script can be set in the
|
|
+environment passed to `configure'. However, some packages may run
|
|
+configure again during the build, and the customized values of these
|
|
+variables may be lost. In order to avoid this problem, you should set
|
|
+them in the `configure' command line, using `VAR=value'. For example:
|
|
+
|
|
+ ./configure CC=/usr/local2/bin/gcc
|
|
+
|
|
+causes the specified `gcc' to be used as the C compiler (unless it is
|
|
+overridden in the site shell script).
|
|
+
|
|
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
|
+an Autoconf bug. Until the bug is fixed you can use this workaround:
|
|
+
|
|
+ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
|
|
+
|
|
+`configure' Invocation
|
|
+======================
|
|
+
|
|
+ `configure' recognizes the following options to control how it
|
|
+operates.
|
|
+
|
|
+`--help'
|
|
+`-h'
|
|
+ Print a summary of all of the options to `configure', and exit.
|
|
+
|
|
+`--help=short'
|
|
+`--help=recursive'
|
|
+ Print a summary of the options unique to this package's
|
|
+ `configure', and exit. The `short' variant lists options used
|
|
+ only in the top level, while the `recursive' variant lists options
|
|
+ also present in any nested packages.
|
|
+
|
|
+`--version'
|
|
+`-V'
|
|
+ Print the version of Autoconf used to generate the `configure'
|
|
+ script, and exit.
|
|
+
|
|
+`--cache-file=FILE'
|
|
+ Enable the cache: use and save the results of the tests in FILE,
|
|
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
|
|
+ disable caching.
|
|
+
|
|
+`--config-cache'
|
|
+`-C'
|
|
+ Alias for `--cache-file=config.cache'.
|
|
+
|
|
+`--quiet'
|
|
+`--silent'
|
|
+`-q'
|
|
+ Do not print messages saying which checks are being made. To
|
|
+ suppress all normal output, redirect it to `/dev/null' (any error
|
|
+ messages will still be shown).
|
|
+
|
|
+`--srcdir=DIR'
|
|
+ Look for the package's source code in directory DIR. Usually
|
|
+ `configure' can determine that directory automatically.
|
|
+
|
|
+`--prefix=DIR'
|
|
+ Use DIR as the installation prefix. *Note Installation Names::
|
|
+ for more details, including other options available for fine-tuning
|
|
+ the installation locations.
|
|
+
|
|
+`--no-create'
|
|
+`-n'
|
|
+ Run the configure checks, but stop before creating any output
|
|
+ files.
|
|
+
|
|
+`configure' also accepts some other, not widely useful, options. Run
|
|
+`configure --help' for more details.
|
|
diff --git a/iscsiuio/Makefile.am b/iscsiuio/Makefile.am
|
|
new file mode 100644
|
|
index 0000000..28dd776
|
|
--- /dev/null
|
|
+++ b/iscsiuio/Makefile.am
|
|
@@ -0,0 +1,25 @@
|
|
+SUBDIRS= src
|
|
+
|
|
+EXTRA_DIST = build_date
|
|
+
|
|
+build_date:
|
|
+ echo 'char *build_date = "'`date`'";' > build_date.c
|
|
+ echo 'char *build_date;'> build_date.h
|
|
+
|
|
+manprefix = /usr/share
|
|
+mandir = ${manprefix}/man
|
|
+logdir = /etc/logrotate.d
|
|
+
|
|
+install-am: all-am
|
|
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install-man install-log install-brcm
|
|
+
|
|
+install-man:
|
|
+ cat docs/iscsiuio.8 | GZIP=$(GZIP_ENV) gzip -c > iscsiuio.8.gz
|
|
+ $(INSTALL_PROGRAM) iscsiuio.8.gz $(mandir)/man8
|
|
+
|
|
+install-log:
|
|
+ $(INSTALL_PROGRAM) iscsiuiolog $(logdir)
|
|
+
|
|
+install-brcm:
|
|
+ -rm -f $(sbindir)/brcm_iscsiuio
|
|
+ -ln -s $(sbindir)/iscsiuio $(sbindir)/brcm_iscsiuio
|
|
diff --git a/iscsiuio/NEWS b/iscsiuio/NEWS
|
|
new file mode 100644
|
|
index 0000000..e69de29
|
|
diff --git a/iscsiuio/README b/iscsiuio/README
|
|
new file mode 100644
|
|
index 0000000..9ae1411
|
|
--- /dev/null
|
|
+++ b/iscsiuio/README
|
|
@@ -0,0 +1,224 @@
|
|
+Iscsiuio Userspace Tool
|
|
+Version 0.7.8.2
|
|
+Dec 10, 2013
|
|
+------------------------------------------------------
|
|
+
|
|
+This tool is to be used in conjunction with the QLogic NetXtreme II Linux
|
|
+driver (Kernel module name: 'bnx2' and 'bnx2x'), QLogic CNIC driver,
|
|
+and the QLogic iSCSI driver (Kernel module name: 'bnx2i').
|
|
+This user space tool is used in conjunction with the following
|
|
+QLogic Network Controllers:
|
|
+ bnx2: BCM5706, BCM5708, BCM5709 devices
|
|
+ bnx2x: BCM57710, BCM57711, BCM57711E, BCM57712, BCM57712E,
|
|
+ BCM57800, BCM57810, BCM57840 devices
|
|
+
|
|
+This utility will provide the ARP and DHCP functionality for the iSCSI offload.
|
|
+The communication to the driver is done via Userspace I/O (Kernel module name
|
|
+'uio').
|
|
+
|
|
+There is one component to this application:
|
|
+
|
|
+1. 'iscsiuio' - This is the daemon which aids in creating iSCSI offloaded
|
|
+ connections.
|
|
+
|
|
+Dependencies:
|
|
+=======================================
|
|
+
|
|
+Linux Kernel Dependencies:
|
|
+1. QLogic CNIC driver (cnic)
|
|
+1. QLogic iSCSI offload driver (bnx2i)
|
|
+2. Userspace I/O driver (uio)
|
|
+
|
|
+Directory Structure of this Package:
|
|
+=======================================
|
|
+
|
|
+<root>
|
|
+ |
|
|
+ +-doc (documentation directory: man pages)
|
|
+ |
|
|
+ +-src
|
|
+ |
|
|
+ +- uip - the uIP stack
|
|
+ |
|
|
+ +- unix - iscsiuio source
|
|
+
|
|
+
|
|
+
|
|
+Compiling / Installing
|
|
+=======================================
|
|
+
|
|
+1. Please untar the tarball.
|
|
+2. Run the configure script. This will create the Makefiles and proper
|
|
+ header files needed for the build.
|
|
+3. Run 'make'. This will create the binary, 'iscsiuio'
|
|
+4. Run 'make install' to place the binaries in their installed location.
|
|
+ (The default location is '/sbin')
|
|
+
|
|
+iscsid IFACE Configuration File:
|
|
+=======================================
|
|
+The network interface configuration files are driven by the iscsid iface
|
|
+files. The configuration data is parsed by iscsid and passed to the uIP
|
|
+stack when the connection is established.
|
|
+
|
|
+One can use the following iscsiadm commands to create/set the configuration
|
|
+using the iface files:
|
|
+
|
|
+1. Create the iface file:
|
|
+
|
|
+ iscsiadm -m iface -I <iface name> --op=new
|
|
+
|
|
+2. Discover the targets associated with the new iface
|
|
+
|
|
+ iscsiadm -m discovery -t st -p <iSCSI target IP address> -I <iface name>
|
|
+
|
|
+3. Update the iface file:
|
|
+
|
|
+ To use a static IPv4 address:
|
|
+ iscsiadm -m iface -I <iface name> --op=update --name=iface.ipaddress --value=<static IPv4 address ie: 192.168.0.1>
|
|
+
|
|
+ To use a DHCP address:
|
|
+ iscsiadm -m iface -I <iface name> --op=update --name=iface.ipaddress --value=0.0.0.0
|
|
+
|
|
+ The following values are required.
|
|
+
|
|
+ To specify the bnx2i as the transport:
|
|
+ iscsiadm -m iface -I <iface name> --op=update --name=iface.transport_name --value=bnx2i
|
|
+
|
|
+ To specify the network interface to offload with:
|
|
+
|
|
+ a. Specify the physical network interface name <ie. eth0, eth1, eth2 ...>
|
|
+ iscsiadm -m iface -I <iface name> --op=update --name=iface.net_ifacename --value=<network interface name>
|
|
+
|
|
+ b. Specify the iSCSI MAC address of the iSCSI HBA
|
|
+ iscsiadm -m iface -I <iface name> --op=update --name=iface.hwaddress --value=<MAC address of the iSCSI HBA>
|
|
+
|
|
+4. Now all the settings should be set so that one could connect to their
|
|
+ desired iSCSI target.
|
|
+
|
|
+ iscsiadm -m node -p <iSCSI target IP address> -T <target name> -I <iface name> --login
|
|
+
|
|
+bnx2 Limitations:
|
|
+=======================================
|
|
+* RX iSCSI ring:
|
|
+ * default ring size is 3 entries
|
|
+ * default buffer size is 0x400 bytes
|
|
+* TX iSCSI ring:
|
|
+ * default ring size of 1 entry
|
|
+ * default buffer size is 0x400 bytes
|
|
+
|
|
+bnx2x Limitations:
|
|
+=======================================
|
|
+* RX iSCSI ring:
|
|
+ * default ring size is 15 entries
|
|
+ * default buffer size is 0x400 bytes
|
|
+* TX iSCSI ring:
|
|
+ * default ring size of 1 entry
|
|
+ * default buffer size is 0x400 bytes
|
|
+
|
|
+Other Limiations:
|
|
+
|
|
+Any packets larger then the buffer size will not be sent/received by the
|
|
+hardware and will be dropped.
|
|
+
|
|
+IPv6 support:
|
|
+
|
|
+IPv6 NDP (neighbor discovery protocol), DHCPv6 and Static IPv6 are now
|
|
+supported. The IPv6 address used for the connection will be matched against
|
|
+the DHCPv6/static IPv6 address, the RA (router advertise) address, and the
|
|
+assigned link local address.
|
|
+
|
|
+VLAN support:
|
|
+
|
|
+VLAN support is only supported when using static IP addresses.
|
|
+Also, currently only 1 VLAN is supported per physical network interface.
|
|
+Either non-VLAN offloaded traffic is allowed or VLAN offloaded traffic
|
|
+is allowed. The current implementation does not support both at the
|
|
+same time.
|
|
+
|
|
+Currently there is no explicit VLAN attributes in the iface file.
|
|
+To configure the VLAN offload, the iface.hwaddress attribute or
|
|
+physical net_ifacename (without the VLAN identifier) must be used
|
|
+to specify the HBA device. For the proper CNIC routing, the
|
|
+corresponding L2 interface which has the associated VLAN interface must
|
|
+have an IP address on the same subnet.
|
|
+
|
|
+The following attributes need to be filled when offloading via the
|
|
+VLAN interface:
|
|
+
|
|
+ iface.iscsi_ifacename = <name of this iface file>
|
|
+ iface.hwaddress = XX:XX:XX:XX:XX:XX
|
|
+ iface.ipaddress = XX.XX.XX.XX
|
|
+ iface.transport_name = bnx2i
|
|
+
|
|
+Setting IP address:
|
|
+
|
|
+On RHEL5.4, RHEL5.5+, RHEL6.0+, and SLES11SP1 distributions,
|
|
+discovery login is done over the Linux TCP/IP stack and L2 network
|
|
+interface. The ethx interface corresponding to the HBA must
|
|
+therefore be in the same IP subnet in order to reach the iSCSI
|
|
+target during discovery. However, the HBA's IP address should not
|
|
+be the same as the L2 ethx's IP address.
|
|
+
|
|
+Starting with RHEL6.1 and all other newer distributions, discovery
|
|
+using SendTargets is done over the HBA interface, so there is no
|
|
+need for the HBA and L2 network to be on the same subnet. However,
|
|
+if VLAN is used on the HBA, they still have to be on the same subnet
|
|
+as described above.
|
|
+
|
|
+
|
|
+Setting Netmask and Gateway addresses:
|
|
+
|
|
+With the current limitations of the iface file, there are no entries
|
|
+to allow the user to enter a netmask or gateway IP address.
|
|
+
|
|
+The only way to explicitly configure these options is to use DHCP
|
|
+addressing. Then the netmask/gateway are set on the DHCP server.
|
|
+These settings are then sent to uIP via the DHCPOFFERs.
|
|
+
|
|
+If the netmask is not defined then the netmask are automatically
|
|
+generated depending on the destination IP address.
|
|
+
|
|
+Debugging:
|
|
+=======================================
|
|
+
|
|
+By default, the iscsiuio daemon does not output any messages to the log file,
|
|
+'/var/log/iscsiuio.log'. Message logging is only enabled when the daemon is
|
|
+run under debug mode.
|
|
+
|
|
+To run the daemon in debug mode please pass the parameter '-d <debug level>'
|
|
+
|
|
+where the following debug levels are defined:
|
|
+
|
|
+DEBUG 4 - Print all messages
|
|
+INFO 3 - Print messages needed to follow the uIP code (default)
|
|
+WARN 2 - Print warning messages
|
|
+ERROR 1 - Only print critical errors
|
|
+
|
|
+A sample banner message:
|
|
+
|
|
+INFO [Mon Jun 20 11:23:14 2011]Started iSCSI uio stack: Ver 0.7.0.6
|
|
+INFO [Mon Jun 20 11:23:14 2011]Build date: Mon Jun 20 11:22:05 PDT 2011
|
|
+INFO [Mon Jun 20 11:23:14 2011]Debug mode enabled
|
|
+
|
|
+These messages can be used to help debug any issues.
|
|
+
|
|
+When debugging issues like the iscsid, the iscsiuio daemon can be run
|
|
+in the foreground and the maximum debugging level should be used.
|
|
+
|
|
+To place the daemon in foreground mode please pass the parameter '-f'
|
|
+
|
|
+Note: The messages to the log file are not flushed unless debugging is enabled.
|
|
+
|
|
+Note: If the daemon iscsiuio is running, one will not be able to
|
|
+ trample over the existing binary. One might see the following message:
|
|
+
|
|
+ 'cannot create regular file `/sbin/iscsiuio': Text file busy'
|
|
+
|
|
+ The solve this, please stop the iscsid service and then install.
|
|
+
|
|
+Warning: If full debug is enabled, this may quickly fill the partition
|
|
+containing the iscsiuio logs. This is because full debugging will log
|
|
+packet activity which on a busy network will quickly fill the logs.
|
|
+
|
|
+Note: If the bnx2i and cnic drivers are unloaded, then iscsiuio will also
|
|
+need to be restarted so that it can determine the iscsid version.
|
|
diff --git a/iscsiuio/RELEASE.TXT b/iscsiuio/RELEASE.TXT
|
|
new file mode 100644
|
|
index 0000000..44d67f9
|
|
--- /dev/null
|
|
+++ b/iscsiuio/RELEASE.TXT
|
|
@@ -0,0 +1,2032 @@
|
|
+ Release Notes
|
|
+ QLogic uIP Linux Driver
|
|
+ Version 0.7.8.2
|
|
+ 12/10/2013
|
|
+
|
|
+ QLogic Corporation
|
|
+ 26650 Aliso Viejo Pkwy,
|
|
+ Aliso Viejo, CA 92656
|
|
+
|
|
+ Copyright (c) 2004 - 2013 Broadcom Corporation
|
|
+ Copyright (c) 2014, QLogic Corporation
|
|
+ All rights reserved
|
|
+
|
|
+uIP v0.7.10.2 (Feb 12, 2014)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00072504 - ifconfig shows allocation failure after
|
|
+ up/down few hours with iSCSI + L2 traffic
|
|
+ Cause: A memory leak was discovered in the ongoing pthread creation
|
|
+ destruction code during the connection recovery process
|
|
+ Change: Fixed the pthread creation code
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+uIP v0.7.8.2 (Dec 10, 2013)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00072053 - Some hardware iSCSI paths fail during test
|
|
+ Cause: The test exercised a corner case where the ARP cache flush
|
|
+ mechanism didn't work properly
|
|
+ Change: Fixed the ARP cache flush mechanism
|
|
+ Impact: All
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Added a new tx doorbell field in the uio path to work with
|
|
+ the new bnx2x/cnic drivers that supports VF_RSS
|
|
+ Impact: 10G only
|
|
+
|
|
+ 2. Change: Fixed the iface.subnet_mask decoding for IPv6
|
|
+ Impact: IPv6
|
|
+
|
|
+
|
|
+uIP v0.7.8.1b (May 01, 2013)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Performance optimization by caching the page size
|
|
+ Impact: All
|
|
+
|
|
+ 2. Change: Fixed a bug in the tx completion interrupt handler
|
|
+ Impact: 10G only
|
|
+
|
|
+
|
|
+uIP v0.7.6.1g (Jan 14, 2013)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00067316 - IPv6 address prefix length < 32
|
|
+ bits fails to connect
|
|
+ Cause: CIDR notation has an order bug in the IPv6 section
|
|
+ whenever the prefix length specified is < 32
|
|
+ Change: Fixed the network order bug
|
|
+ Impact: IPv6 only
|
|
+
|
|
+
|
|
+uIP v0.7.6.1f (Nov 14, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00065768 - RHEL5.X iscsiuio segfault possible
|
|
+ if there is a specific 1024 byte size broadcast
|
|
+ packet
|
|
+ Cause: This is another corner case where the packet size
|
|
+ is also exactly 1024 bytes + padding that exceeded
|
|
+ the DMA rx buffer. The previous fix was not
|
|
+ sufficient
|
|
+ Change: Ensure that the packet size + padding do not
|
|
+ exceed this limit.
|
|
+ Impact: 10G only. 1G already has the guard against it.
|
|
+
|
|
+
|
|
+uIP v0.7.6.1e (Nov 07, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00066397 - Unable to connect to iSCSI target
|
|
+ with NPAR enabled on 57840
|
|
+ Cause: The PCI device ID for 57840_MF has been changed from
|
|
+ 0x16ab to 0x16a4
|
|
+ Change: Updated the PCI id table to match exactly what the
|
|
+ bnx2x 1.76 indicates
|
|
+ Impact: 57840 MF
|
|
+
|
|
+
|
|
+uIP v0.7.6.1d (Oct 31, 2012)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Added support for open-iscsi-2.0.873
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+uIP v0.7.6.1c (Oct 15, 2012)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Added support for 10G 57840 4x10 and 2x20
|
|
+ Impact: 10G 57840
|
|
+
|
|
+
|
|
+uIP v0.7.6.1b (Oct 09, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00065690 - Vconfig method of connecting over
|
|
+ tagged vlan with IPv6 failed
|
|
+ Cause: The new net param support changes has prevented
|
|
+ the old vconfig method from execising the IPv6
|
|
+ acquisition engine properly
|
|
+ Change: Ensure that this old vconfig method to run the IPv6
|
|
+ acquisition engine properly and to its entirety
|
|
+ Impact: IPv6 + VLAN using the network VLAN configuration
|
|
+ method
|
|
+
|
|
+ 2. Problem: Cont00065768 - RHEL5.X iscsiuio segfault possible
|
|
+ if there is a specific 1024 byte size broadcast
|
|
+ packet
|
|
+ Cause: This is a corner case where the packet size is
|
|
+ exactly 1024 bytes + padding that exceeded the
|
|
+ DMA rx buffer. This has been there since day 1.
|
|
+ Change: Ensure that the packet size + padding do not
|
|
+ exceed this limit.
|
|
+ Impact: 10G only. 1G already has the guard against it.
|
|
+
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Source optimization - backported source code fixes
|
|
+ as reported from the upstream submission patch
|
|
+ Impact: ALL
|
|
+
|
|
+
|
|
+uIP v0.7.4.2k (Aug 10, 2012)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Enable HP SD mode
|
|
+ Impact: 577XX/578XX
|
|
+
|
|
+
|
|
+uIP v0.7.4.2j (Jul 18, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00064665 - Linux iSCSI connects via gateway address
|
|
+ on the wrong subnet
|
|
+ Cause: The gateway address used was not checked against the
|
|
+ subnet mask specified before the ARP requests. Since
|
|
+ this behavior deters from how L2 operates, therefore,
|
|
+ a change was made to correct this.
|
|
+ Change: Added check of the gateway specified against the subnet
|
|
+ specified.
|
|
+ Impact: Static IPv4 operation
|
|
+
|
|
+ 2. Problem: Cont00064722 - Linux iSCSI unable to force IPv6 LL
|
|
+ override (advanced iface parameters)
|
|
+ Cause: The override LL address was not being populated to the
|
|
+ IPv6 address database correctly
|
|
+ Change: Added this correctly to the IPv6 initialization
|
|
+ Impact: Static/DHCP IPv6 LL address override only
|
|
+
|
|
+
|
|
+uIP v0.7.4.2i (Jul 11, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00064604 - Fails to connect to routed IPv6 target
|
|
+ via RA
|
|
+ Cause: The default router IPv6 address was not being retrieved
|
|
+ correctly.
|
|
+ Change: Fixed the default router IPv6 address read
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+uIP v0.7.4.2h (Jun 15, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00063863 - can't boot into offload image
|
|
+ when VLAN is enabled
|
|
+ Cause: During the iSCSI login exchange, certain iSCSI targets
|
|
+ will send an ARP request even though the TCP connection
|
|
+ has been made. The bug was in this ARP reply where
|
|
+ the local MAC was corrupted when VLAN is enabled.
|
|
+ Change: Fixed the ARP reply packet
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+uIP v0.7.4.2g (Jun 08, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00063816 - The initiator is not able to connect
|
|
+ to the iSCSI targets over VLAN
|
|
+ Cause: The process packet routine did not consider the PCP
|
|
+ of the VLAN tag to be non-zero. This created a
|
|
+ mismatch when this VLAN tag was compared against the
|
|
+ nic_iface->vlan_id which doesn't include the PCP.
|
|
+ Change: Added the consideration of non-zero PCP
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+uIP v0.7.4.2f (Jun 04, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00063626 - Static IPv6 does not connect when
|
|
+ the prefix len is not set explicitly
|
|
+ Cause: The IPv6 prefix length was not set correctly
|
|
+ for Static IPv6 operation when CIDR notation is
|
|
+ not specified
|
|
+ Change: Fixed the default prefix length
|
|
+ Impact: Static IPv6
|
|
+
|
|
+ 2. Problem: Cont00063651 - Cannot connect to iSCSI targets
|
|
+ HP PTM/SF
|
|
+ Cause: Switch-Dependent mode + invalid Outer VLAN was
|
|
+ not supported
|
|
+ Change: Allow SD+invalid OV to fallback to SF operation mode
|
|
+ Impact: 5771X/578XX
|
|
+
|
|
+
|
|
+uIP v0.7.4.2e (May 30, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00063443 - Compilation error on SLES11sp1
|
|
+ Cause: The iface_num field was not defined
|
|
+ Change: Fixed all references to iface_num
|
|
+ Impact: SLES11sp1
|
|
+
|
|
+ 2. Problem: Cont00063518 - HBA fails to connect across router
|
|
+ using iface.gateway address
|
|
+ Cause: The gateway override code did not populate the
|
|
+ address into the lower level engine
|
|
+ Change: Fixed the gateway override code
|
|
+ Impact: IPv4 Static IP operation
|
|
+
|
|
+ 3. Problem: Cont00063567 - IPv6 LL and RA override does not work
|
|
+ Cause: The IPv6 LL/RA override addresses were overwritten
|
|
+ by the NDP engine
|
|
+ Change: Fixed the LL/RA override code
|
|
+ Impact: IPv6 operation
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Added support for jumbo MTU (independent from the L2 MTU)
|
|
+
|
|
+
|
|
+uIP v0.7.4.2d (May 21, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00063421 - Static IPv6 cannot connect via RA/LL
|
|
+ Cause: The router advertise and the linklocal address
|
|
+ were corrupted due to the override capabilities
|
|
+ added for the newer open-iscsi util
|
|
+ Change: Fixed the address override code
|
|
+ Impact: Static IPv6
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Allow VLAN tag = 1 (router management) to connect offload
|
|
+
|
|
+
|
|
+uIP v0.7.4.2c (May 09, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: RHEL BZ 734010/804580 - issues found by the Coverity
|
|
+ scan
|
|
+ Cause: 10 code issues were flagged for revision
|
|
+ Change: Fixed all area of concern
|
|
+ Impact: All
|
|
+
|
|
+ 2. Problem: Cont00063177 - IPv4 DHCP with VLAN specification in
|
|
+ iface file gets wrong address
|
|
+ Cause: The DHCPv4 handler was not discriminating the VLAN tag
|
|
+ associated with the DHCP offers from multiple DHCP
|
|
+ servers
|
|
+ Change: Changed the DHCPv4 handler to drop DHCP offer packets
|
|
+ that doesn't match the VLAN tag of the intended DHCP
|
|
+ discovery packet
|
|
+ Impact: DHCPv4 operation
|
|
+
|
|
+
|
|
+uIP v0.7.4.2b (May 01, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00062993 - IPv6 DHCP with VLAN specification in
|
|
+ iface file gets wrong address
|
|
+ Cause: The DHCPv6 request was using the same DUID as always
|
|
+ so the non-VLAN DHCP server responded to our broadcast
|
|
+ instead
|
|
+ Change: Changed the DHCPv6 request DUID to link address + time
|
|
+ instead of link address alone
|
|
+ Impact: DHCPv6 operation
|
|
+
|
|
+
|
|
+uIP v0.7.4.1j (Apr 24, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00062805 - Cannot login to iSCSI targets on RHEL6.3
|
|
+ Cause: The problem was caused by a change made to the iface_rec
|
|
+ structure in the RHEL6.3 inbox open-iscsi util
|
|
+ Change: The new changes is now incorporated
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+uIP v0.7.4.1i (Apr 16, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00062660 - Unable to login with VLAN iscsiuio
|
|
+ on RHEL6.2
|
|
+ Cause: The open-iscsi util in RHEL6.2 has a bug which
|
|
+ does not pass the correct iface_num to iscsiuio
|
|
+ Change: Added workaround to fall back to do the legacy
|
|
+ VLAN support if iface_num and vlan_id = 0
|
|
+ Impact: RHEL6.2
|
|
+
|
|
+
|
|
+uIP v0.7.4.1h (Apr 13, 2012)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Added support for the new iface_num field in the iscsi_uevent
|
|
+ path
|
|
+
|
|
+ 2. Fixed bug in the nic_iface search engine based on iface_num
|
|
+
|
|
+
|
|
+uIP v0.7.4.1g (Mar 22, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00061869 - Unable to setup an offload iSCSI
|
|
+ connection with FLR/NPAR under ESX5.0:PDA
|
|
+ Cause: The physical function ID was previously extracted
|
|
+ from the sysfs of the VM which might not be consistent
|
|
+ to the actual physical setup due to the function
|
|
+ remapping in the hypervisor
|
|
+ Change: Read the physical function ID directly from the BAR0
|
|
+ ME register
|
|
+ Impact: All
|
|
+
|
|
+ 2. Problem: Cont00062170 - IPv6 login/logout stress fails
|
|
+ Cause: The packet interrupt was lost after running the test
|
|
+ for a much longer period of time. A bug in the
|
|
+ packet processing routine was found to exit prematurely
|
|
+ Change: Fixed the packet processing routine to process all
|
|
+ packets before exiting
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+uIP v0.7.4.1f (Mar 19, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00062170 - IPv6 login/logout stress fails
|
|
+ Cause: The packet buffer routine for IPv6 did not take
|
|
+ network order <-> host order into consideration
|
|
+ Change: Added a htons call to compensate for the ntohs pair
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+uIP v0.7.4.1e (Mar 08, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00061978 - Load/unload stress test fails
|
|
+ Cause: The bnx2x open request was failing due to the module
|
|
+ request procedure. However, the open failure was
|
|
+ not being handled correctly.
|
|
+ Change: Fixed the device open error handling
|
|
+ Impact: 5771X/578XX
|
|
+
|
|
+
|
|
+uIP v0.7.4.1d (Mar 02, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00061708 - Unable to log into target after running
|
|
+ driver load/unload
|
|
+ Cause: A bug was introduced in the previous bug fix (CQ61459)
|
|
+ where a pthread_cond_broadcast call was erroneously
|
|
+ enabled
|
|
+ Change: Restored this back
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+uIP v0.7.4.1c (Feb 16, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00061529 - Unable to connect to target after an
|
|
+ initial failed login attempt until iscsi service is
|
|
+ restarted
|
|
+ Cause: Upon a failed DHCPv4 acquisition due to the wrong VLAN
|
|
+ tag in the initial iface setup, any iscsid connect request
|
|
+ from the same NIC will get dropped due to a bug.
|
|
+ Change: Fixed the bug which prevented new iscsid connect requests
|
|
+ from getting honored
|
|
+ Impact: All
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Updated README
|
|
+
|
|
+
|
|
+uIP v0.7.4.1b (Feb 08, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00061513 - Unable to connect to target over VLAN
|
|
+ interface
|
|
+ Cause: The VLAN id was not properly passed back to the CNIC
|
|
+ driver for the offload request
|
|
+ Change: Fixed the VLAN id being passed back to the CNIC driver
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+uIP v0.7.4.1a (Feb 01, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00049383 - No mechanism in iface file to support
|
|
+ gateway/routing
|
|
+ Change: Added support for the additional network parameters
|
|
+ as passed from the newer iscsi-util.
|
|
+ These parameters include:
|
|
+ IPv4: subnet_mask, gateway
|
|
+ IPv6: ipv6_linklocal, ipv6_router,
|
|
+ ipv6_autocfg, linklocal_autocfg, router_autocfg
|
|
+ VLAN: vlan_id, vlan_priority, vlan_state
|
|
+ Other: mtu, port
|
|
+ Impact: All
|
|
+
|
|
+ 2. Problem: Cont00060806 - Unable to connect target using DHCP over
|
|
+ tagged VLAN
|
|
+ Change: DHCP+VLAN is a new feature enhancement that was added
|
|
+ alongside all other new iface parameters.
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Lock iscsid's connect request with path_req so connect requests
|
|
+ with DHCP/Static will no longer override each other
|
|
+
|
|
+ 2. Fixed the if_down handler from global to nic specific
|
|
+
|
|
+ 3. Fixed various synchronization issues
|
|
+
|
|
+
|
|
+uIP v0.7.2.1e (Jan 05, 2012)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00060734 - ifupdown-mtu change stress with active
|
|
+ session causes iscsiuio to fail
|
|
+ Change: Fixed a race condition between the nic enable thread
|
|
+ and when DHCP fails
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+uIP v0.7.2.1d (Dec 28, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00060368 - segfault observed after failing both
|
|
+ mpio paths
|
|
+ Change: Various memory leaks were identified and resolved in
|
|
+ the nic cleanup path
|
|
+ Impact: All
|
|
+
|
|
+
|
|
+uIP v0.7.2.1c (Dec 16, 2011)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Disable HP SD mode
|
|
+
|
|
+
|
|
+uIP v0.7.2.1b (Dec 14, 2011)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Default iscsiuio logging to off. Use the '-d'
|
|
+ option to enable
|
|
+
|
|
+
|
|
+uIP v0.7.0.14g (Oct 25, 2011)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Fixed the compilation under RHEL6.2
|
|
+ 2. Change: Added oom_adjust call to prevent OOM Killer from killing
|
|
+ iscsiuio when memory is low
|
|
+ 3. Change: Added mlockall setting to prevent page swap
|
|
+
|
|
+
|
|
+uIP v0.7.0.14f (Oct 20, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00058994 - DOS vulnerability in uip during UDP flood
|
|
+ Cause: The warning messages from the UDP handler was logging
|
|
+ at a rate faster than the log file logrotate rate
|
|
+ Therefore, the system's OOM eventually got kicked in to
|
|
+ start terminating running processes which includes iscsiuio
|
|
+ Change: Moved several UDP warning messages from the default log
|
|
+ level to the debug log level
|
|
+ Impact: All (minor)
|
|
+
|
|
+ 2. Problem: Cont00059288 - Show segfault w/ SLES11 SP1 Xen kernel
|
|
+ Cause: The bnx2x chip_id was not read correctly from the PCIe BAR1
|
|
+ under the Xen kernel. The error was in the mmap area.
|
|
+ Change: Corrected the mmapping of the PCI MMIO space.
|
|
+ Impact: Xen kernels
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Changed the log file open error to a warning and let
|
|
+ the daemon progress. This was only observed under iSCSI boot
|
|
+
|
|
+
|
|
+uIP v0.7.0.14e (Sep 19, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00058678 - Can not iboot target from ipv6 path
|
|
+ using VLAN
|
|
+ Cause: A bug was found in the path request path where the vlan
|
|
+ iface's protocol family was not used correctly in the
|
|
+ iface search
|
|
+ Change: This has been corrected
|
|
+
|
|
+
|
|
+uIP v0.7.0.14d (Sep 16, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00058602 - Can't iboot using IPv6 offload path
|
|
+ Cause: The bug was exposed by a fix in 0.7.0.14c where the
|
|
+ IPv6 router solicitation timeout exceeded the nic
|
|
+ enable thread timeout.
|
|
+ Change: The IPv6 router solicitation timeout has been adjusted
|
|
+
|
|
+
|
|
+uIP v0.7.0.14c (Sep 01, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00058256 - Sessions fail after loginstress to via
|
|
+ simultaneous ipv4 and ipv6 dhcp
|
|
+ Cause: Switching between DHCPv4/v6 coupled with VLAN exposed
|
|
+ a drawback in our nic_iface architecture design where
|
|
+ VLAN is not specified by iscsid.
|
|
+ Change: The code was optimized and improved the performance when
|
|
+ switching between DHCPv4/v6+VLAN. However, the ultimate
|
|
+ fix is to make use of the net config parameters introduced
|
|
+ in the newer open-iscsi util which will identify the
|
|
+ specific VLAN nic_iface to use.
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Added support for bnx2x-1.71.00
|
|
+
|
|
+
|
|
+uIP v0.7.0.14b (Aug 23, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00057840 - RHEL6.2 inbox: Unable to connect to
|
|
+ targets with 5709
|
|
+ Cause: For cases when the bnx2/bnx2x driver gets removed, the
|
|
+ uio database that was built by cnic would have the device
|
|
+ ->net reference removed. This has caused an unnecessary
|
|
+ timeout of 5s for each stale uio entry in the database.
|
|
+ Change: Adjusted the routine which seeks the device->net entry
|
|
+ to include more logic instead of hard waiting for 5s.
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Added support for RHEL6.2 for out-of-box release
|
|
+ 2. Change: Updated the man page with -h and -p info
|
|
+ 3. Change: Updated the -h info
|
|
+
|
|
+
|
|
+uIP v0.7.0.13 (Aug 10, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00057768 - iscsiuio logrotate causes daemon failure
|
|
+ Cause: The logrotate script will send a SIGUSR1 signal to notify
|
|
+ the iscsiuio daemon of such action. However, the daemon
|
|
+ wasn't programmed to catch this signal.
|
|
+ Change: Restored the catching of this signal
|
|
+
|
|
+
|
|
+uIP v0.7.0.12 (Aug 04, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00050634 - brcm_iscsiuio Tainted: running IoZone,
|
|
+ Iometer and receiving a UDP flood on 3260
|
|
+ Cause: Upon iscsiuio termination, because of the UDP flood,
|
|
+ the nic thread will be busy servicing those UDP packets
|
|
+ while the signal handling thread will free up all nic
|
|
+ resources. The two threads were not in sync.
|
|
+ Change: Added a nic_remove_all routine to destroy all nic threads
|
|
+ before the nic resources get freed.
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Fixed all warnings as reported by RHELS' Coverity testing.
|
|
+
|
|
+
|
|
+uIP v0.7.0.11 (Aug 02, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Erroneous VLAN tag was being passed by iscsid for connect
|
|
+ request
|
|
+ Cause: The iscsid's iface_rec_t ipc message does not contain this
|
|
+ vlan field. This field was added in uIP for future vlan
|
|
+ support. Since the buffer allocated to receive such message
|
|
+ in uIP didn't get initialized, therefore, garbled up VLAN
|
|
+ tag was getting used.
|
|
+ Change: Added the initialization of this buffer.
|
|
+
|
|
+
|
|
+uIP v0.7.0.10 (Jul 26, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Can't offload when switching from Static to DHCP then back to
|
|
+ Static IPv4 when connecting through a VLAN interface
|
|
+ Cause: The VLAN processing code did not reinstall the IP address
|
|
+ from the default nic_iface to the associated VLAN nic_iface.
|
|
+ This was only done on the very first time when the VLAN
|
|
+ interface was created and not on subsequent instances.
|
|
+ Change: Added code to mirror the default nic_iface IP/netmask/ip_config
|
|
+ on the VLAN nic_iface on every new connection request.
|
|
+
|
|
+
|
|
+uIP v0.7.0.9 (Jul 19, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Can't offload to 57810 NPAR NIC
|
|
+ Cause: The MF/VF variant of the PCI IDs were not supported previously
|
|
+ Change: Added support for the MF/VF variants for 57800/57810/57840
|
|
+
|
|
+
|
|
+uIP v0.7.0.8 (Jun 30, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00056522 - Unable to connect to iSCSI target using
|
|
+ netxtreme2 package 7.0.9
|
|
+ Cause: The iSCSI L2 ring's CID has changed from 17 to 49
|
|
+ Change: The code now gets L2 iSCSI ring CID from the l2_buf directly.
|
|
+ This will work with any version of the cnic driver because
|
|
+ the location is a zero before this change.
|
|
+
|
|
+
|
|
+uIP v0.7.0.7 (Jun 23, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00056460 - iSCSI Offload boot RHEL5u5 x64 dropped tagged
|
|
+ packets with iSCSI Offload Boot with untagged
|
|
+ Cause: The ICMP echo replies to the target was corrupted in both
|
|
+ 1g and 10g mode
|
|
+ Change: The code will now handle both VLAN stripped and no VLAN stripped
|
|
+ incoming packets correctly. Also modified the transmit routine
|
|
+ to strip out any inline VLAN tag before setting up the hw to
|
|
+ insert VLAN tag.
|
|
+
|
|
+
|
|
+uIP v0.7.0.6 (Jun 21, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00056231 - DHCPv4 not working with iSCSI HBA w/
|
|
+ linux-nx2 v7.0.7
|
|
+ Cause: The 10g L2 FW HSI has been modified for PCIe performance
|
|
+ enhancement in the 7.0.7 package (FW 1.70.20) which uIP
|
|
+ has not adapted to.
|
|
+ Change: The eth_rx_cqe size has been increased from 32B to 64B.
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: The utility name has changed from brcm_iscsiuio to iscsiuio
|
|
+ as preparation for upstream submission.
|
|
+ 2. Change: Updated README
|
|
+
|
|
+
|
|
+uIP v0.7.0.5 (Jun 02, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00055915 - iSCSI does not connect on 57800 in 4-port mode
|
|
+ Cause: The 4-port mode was not being determined correctly
|
|
+ Change: Fixed the PORT4MODE register offset and the QZONE_ID macros
|
|
+
|
|
+
|
|
+uIP v0.7.0.4 (May 24, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00055832 - linux iscsiboot can not login to target using
|
|
+ offload path (57800)
|
|
+ Cause: The device ID comparison routine did not take care of the case
|
|
+ when one device ID is bitwise superset of another.
|
|
+ Change: Fixed the device ID comparison routine.
|
|
+
|
|
+
|
|
+uIP v0.7.0.3 (May. 19, 2011)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Updated all fixes to match the released uIP 0.6.4.17
|
|
+
|
|
+ 2. Change: Modified source and Copyright info as preparation for upstream
|
|
+ submission
|
|
+
|
|
+
|
|
+uIP v0.7.0.2 (May. 03, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00048972 - brcm-iscsi.log has no max size and would grow
|
|
+ to consume all free space on hard disk
|
|
+ Cause: There was no mechanism to rotate the log
|
|
+ Change: Added logrotate entry and SIGUSR1 signal handling for log rotate
|
|
+ action
|
|
+
|
|
+ 2. Problem: Cont00054996 - Multi-session, multi-protocol mtu stress
|
|
+ does not recover all sessions
|
|
+ Cause: A segfault was observed during the load/unload module. The
|
|
+ problem was caused by an illegal dereference of a pointer
|
|
+ when IPv6 couldn't find the longest match address from
|
|
+ the ARP (Neighbor) table.
|
|
+ Change: Fixed the dereferencing error
|
|
+
|
|
+ 3. Problem: Cont00054900 - Linux uIP - Please add ability to connect
|
|
+ to routed target with static iface IPv6
|
|
+ Cause: Static IPv6 never runs the IPv6 NDP router sol/adv engine.
|
|
+ Change: IPv6 NDP router sol/adv has now been added to static IPv6
|
|
+ operation.
|
|
+
|
|
+ 4. Problem: Cont00054996 - Multi-session, multi-protocol mtu stress
|
|
+ does not recover all sessions
|
|
+ Cause: Segfaults were observed caused by the accessing of the IPv6
|
|
+ NDP structure while the nic is undergoing a reset either
|
|
+ due to a DHCPv4 request from iscsid or the handling of
|
|
+ if_down due to the NL handler from CNIC.
|
|
+ Change: The fix involves the following:
|
|
+ - Fixed the handling of staggered IPv4/v6 DHCP/static requests
|
|
+ - Fixed memory leak due to reallocation of IPv4 and IPv6
|
|
+ DHCP structs
|
|
+ - Fixed the pthread join stuck problem in the handling
|
|
+ of the if_down NL message
|
|
+
|
|
+ 5. Problem: Cont00054810 - Linux NMI - bnx2x_init_hw_common:PXP2 CFG
|
|
+ failed running iSCSI MTU stress test
|
|
+ Cause: This only happens in DHCPv4 mode. The problem was caused
|
|
+ by contention between the elongated window of performing
|
|
+ DHCP in the enable_nic thread while receiving the asynchronous
|
|
+ if_down NL message (from the MTU change event) from the
|
|
+ CNIC NL thread. The problem occurs when the enable_nic
|
|
+ thread tries to call bnx2x_open while the other thread
|
|
+ calls the bnx2x_close routine.
|
|
+ Change: Fixed mutex lock bugs for the enable_nic thread. Also
|
|
+ extended the nic_disable timeout to 10s to compensate for
|
|
+ the DHCP operation.
|
|
+
|
|
+ 6. Problem: Cont00054818 - RH6.0 - Unable to logout of iSCSI session
|
|
+ after running PQA baseline scripts
|
|
+ Cause: This was caused by the call to cancel the enable_nic
|
|
+ thread when disabling the nic but failed to unlock the
|
|
+ nic mutex that the enable_nic thread held.
|
|
+ Change: Wake up the enable_nic thread and wait for it to complete
|
|
+ instead of canceling it in the nic_disable path.
|
|
+
|
|
+ 7. Problem: Cont00054725 - Previous static HBA IP will be used after
|
|
+ a new static HBA IP has been created
|
|
+ Cause: There was an assumption in the code where if the same
|
|
+ nic_iface structure was found based on the nic/vlan pair,
|
|
+ the specified IP address would not be used. Instead, it
|
|
+ will continue to use the previous defined IP address.
|
|
+ Change: The previous IP address will now be compared against the
|
|
+ the specified IP address before finishing the parce
|
|
+ iface request from iscsid. If different, the current
|
|
+ nic will be disabled and then re-enabled with the newly
|
|
+ specified IP address.
|
|
+
|
|
+ 8. Problem: Cont00054571 - Unable to connect to routed ipv6 target
|
|
+ with RA address and iface DHCPv6
|
|
+ Cause: The default router address was not being employed for
|
|
+ the IPv6 neighbor negotiation. Additionally, the return
|
|
+ address of our neighbor advertisement was incorrect as
|
|
+ it should use the best matched src address instead.
|
|
+ Change: Fixed both the IPv6 neighbor solicitation and advertisement
|
|
+ transmission and handling.
|
|
+
|
|
+ 9. Problem: Cont00054510 - fails to login to 32 session with blanket
|
|
+ login IPv6
|
|
+ Cause: A bug was introduced in uIP 0.6.4.6 where the NIC_RUNNING
|
|
+ flag might not be set when entering the main loop under
|
|
+ certain situations depending on the nic bring up.
|
|
+ Change: A new NIC_STARTED_RUNNING flag is now defined to fix CQ53511.
|
|
+
|
|
+ 10. Problem: Cont00053807 - RA and link local are unable to connect if DHCPv6
|
|
+ fails
|
|
+ Cause: The host link local address was not being searched as one of
|
|
+ the host address to be replied to CNIC for the connect request.
|
|
+ Change: The path reply now includes the search of host link local
|
|
+ address as well.
|
|
+
|
|
+ 11. Problem: Cont00054236 - iSCSI service must be restarted before an IPv6
|
|
+ connection can be made to the Equalogic target
|
|
+ Cause: The problem was intermittent as it depends on which IPv6 address
|
|
+ the target was redirecting to. Since uIP was only extracting
|
|
+ the target's IPv6 address + MAC from the target's neighbor
|
|
+ advertisement packet itself and not from the ICMPv6 option, so
|
|
+ the wrong or no MAC address will get send down to CNIC for the
|
|
+ connection establishment; hence the no connect.
|
|
+ Change: Added the updating of the neighbor discovery table to also use
|
|
+ the Target IPv6 address + MAC specified in the incoming neighbor
|
|
+ advertisement's ICMPv6 option field.
|
|
+
|
|
+ 12. Problem: Cont00053255 - bnx2x panic dump logging into multiple
|
|
+ discovered IPv6 nodes (Equalogic IPv6 target)
|
|
+ Cause: The bnx2x panic was fixed in the 10g fw 6.4.29.
|
|
+ A IPv6 connectivity issue was then found and led to different
|
|
+ kernel/uIP crashes. This was caused by the same IPv6
|
|
+ connectivity problem mentioned above.
|
|
+ Change: Same as above
|
|
+
|
|
+ 13. Problem: Cont00053728 - Sessions never recover after doing initiator-side
|
|
+ cable pull test with IPv6 traffic against Equalogic targets
|
|
+ Cause: It was discovered that the Equalogic would send out periodic
|
|
+ neighbor solicitation to maintain the connection to the
|
|
+ initiator. Since uIP was responding with the assigned IPv6
|
|
+ link local address in the neighbor advertisement
|
|
+ unconditionally, the target was observed to stop transmitting on
|
|
+ the connection specified.
|
|
+ Change: The neighbor advertisement generated will now use the dst IPv6
|
|
+ address from the input neighbor solicitation packet instead of
|
|
+ the assigned IPv6 link local address for both the packet and the
|
|
+ ICMPv6 source IPv6 address.
|
|
+
|
|
+ 14. Problem: Compile error under 32-bit OS
|
|
+ Cause: A bug was introduced in the previous release 0.6.4.6 which
|
|
+ caused a compilation error in 32-bit OS (64-bit compiles
|
|
+ fine)
|
|
+ Change: Fixed the bug
|
|
+
|
|
+ 15. Problem: Cont00053807 - RA and Link local are unable to connect if dhcpv6
|
|
+ fails
|
|
+ Cause: There was a bug in the nl reply where the RA address will never
|
|
+ be sent back to CNIC for the connection request
|
|
+ Change: The best matched address to the dst will now be sent back to
|
|
+ CNIC in the path rsp.
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Updated README to remove the 57713/E references
|
|
+
|
|
+ 2. Change: Allow the ICMP option field in the IPv6 Neighbor Advertisement
|
|
+ response to be included without discrimination. This fixes
|
|
+ an issue connecting against the EQL via RA for DHCPv6.
|
|
+
|
|
+ 3. Change: Updated README for the IPv6 operation, VLAN, and discovery.
|
|
+
|
|
+
|
|
+uIP v0.7.0.1 (Mar. 29, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00053511 - bnx2x panic dump during ifup/down stress with
|
|
+ iSCSI traffic
|
|
+ Cause: The panic dump was resolved by the driver's rq dbell size fix.
|
|
+ After that, uIP crashed due to the asynchronous if_down event
|
|
+ that took the chip resources away while the nic thread is still
|
|
+ continuing to try to send DHCP request.
|
|
+ Change: Added synchronization between the two threads so proper clean up
|
|
+ of the threads can occur.
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Added support for E3 (57800, 57810, and 57840)
|
|
+
|
|
+
|
|
+uIP v0.6.4.5 (Mar. 23, 2011)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Optimized the double VLAN fix of CQ53870 to match
|
|
+ what will be submitted for RHELS5.7 and RHELS6.1 inbox
|
|
+
|
|
+
|
|
+uIP v0.6.4.4 (Mar. 17, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00053870 - Unable to login to iSCSI target via offload
|
|
+ through a Nexus 5020 switch with DCBx enabled
|
|
+ Cause: Double VLAN tagging was observed due to DCBx enabled.
|
|
+ The chip actually adds a VLAN tag if the txbd does not have
|
|
+ VLAN tag enabled under the DCBx environment for PRI setting.
|
|
+ Since uIP does not make use of hw assisted VLAN tagging,
|
|
+ 2 VLAN tag was observed in the data stream.
|
|
+ Change: Enabled hw assisted VLAN tagging in uIP for both 1g and 10g.
|
|
+
|
|
+ 2. Problem: Cont00053792 - maxconnections intermittently fail and
|
|
+ recover using iface DHCPv4
|
|
+ Cause: The DHCPv4 engine erroneously keeps on requesting for a
|
|
+ new lease which tremendously hamper normal path_req
|
|
+ operation. The problem is that the lease time parameter
|
|
+ has overflowed when converted to ticks count.
|
|
+ Change: Expanded the lease timer ticks count parameter from 16 to
|
|
+ 32 bits.
|
|
+
|
|
+ 3. Problem: Cont00053807 - RA and link local are unable to connect if
|
|
+ DHCPv6 fails
|
|
+ Cause: The DHCPv6 engine does not have the failover to use RA
|
|
+ mechanism
|
|
+ Change: Expanded to use best match address instead regardless of
|
|
+ DHCPv6 success or not, or using static v6.
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Cont00051823 - Added man page for brcm_iscsiuio
|
|
+
|
|
+
|
|
+uIP v0.6.4.3 (Mar. 15, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00053719 - intermittent logging into targets that
|
|
+ are not in the same subnet as defined in the iface
|
|
+ Cause: The default route was used erroneously due to a miscompare
|
|
+ Change: Fixed this comparison so if the requested dst is not in
|
|
+ in the same subnet, uIP would not even ARP out.
|
|
+
|
|
+ 2. Problem: Cont00053580 - Unable to do iSCSI boot into Linux OS using
|
|
+ 57710 adapters
|
|
+ Cause: The E1 iro USTORM_RX_PROD_OFFSET doesn't match the t6.4 fw
|
|
+ Change: This is now fixed
|
|
+
|
|
+
|
|
+uIP v0.6.4.2 (Feb. 24, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00050343 - HBA does not follow RFC2131 spec for IPv4
|
|
+ DHCP lease expiration
|
|
+ Cause: The dhcp engine did not have this feature implemented
|
|
+ Change: Added lease time tracking and renewal
|
|
+
|
|
+ 2. Problem: Cont00050801 - Unable to connect to target after switching
|
|
+ between DHCPv4 to static v4
|
|
+ Cause: The configuration flags got corrupted when switching between
|
|
+ dhcp and static or vice versa.
|
|
+ Change: Fixed the flag handling. Also needed to zero out the static
|
|
+ ip address in the host memory when switching to dhcp.
|
|
+ Otherwise, the static ip address will get used mistakenly.
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Cont00051936 - Added IPv6 NDP and DHCPv6 support.
|
|
+
|
|
+
|
|
+uIP v0.6.4.1 (Jan. 27, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00049766 - segfault seen while stopping iscsi service
|
|
+ Cause: The logger output routine was accessing the log resource
|
|
+ while another thread calls fini_logger to free the same
|
|
+ resources
|
|
+ Change: Added pthread mutex lock to the logger routine to exclude
|
|
+ the initializer, user, and finisher
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Added new t6.4 HSI and 57713 support.
|
|
+
|
|
+
|
|
+uIP v0.6.2.13 (Jan. 04, 2011)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00049665 - iscsiboot:linux failed to boot into iscsi
|
|
+ boot image in offload path after 5 iterations
|
|
+ Cause: The hw consumer index for the uIP ring got out of sync
|
|
+ with the producer index. This has led to the xmit mutex
|
|
+ lock be held forever so subsequent ARP requests will not
|
|
+ get transmitted to the wire
|
|
+ Change: Added this out of sync detection and rescue the xmit mutex
|
|
+ lock
|
|
+
|
|
+uIP v0.6.2.12 (Dec. 21, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Cont00051820 - Session fails to reconnect after gateway
|
|
+ fallback
|
|
+ Cause: Under the HSRP test scenario, it was found that an ARP
|
|
+ request from the SUT is required in order for the HSRP
|
|
+ router to begin sending packets downstream to the SUT.
|
|
+ The default ARP age was originally set to 20 minutes
|
|
+ before a new ARP request will get sent,
|
|
+ Change: Changed the ARP age default to Linux default at 5 minutes
|
|
+
|
|
+uIP v0.6.2.11 (Dec. 17, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: For IPv4, the gateway route was not being utilized
|
|
+ when the subnet mask given or calculated does not
|
|
+ match. This resulted in many unwanted connection
|
|
+ attempts.
|
|
+ Cause: A bug was found in the default gateway calculation
|
|
+ logic which prevented the gateway address from being
|
|
+ used.
|
|
+ Change: Fixed the default gateway logic
|
|
+
|
|
+ 2. Problem: For IPv6, there are scenarios where it won't connect
|
|
+ Cause: The IPv6 subnet mask as extracted from the CIDR
|
|
+ format might contain garbage data. This garbage data
|
|
+ was then used as part of the subnet mask which would
|
|
+ prevent the correct address mask.
|
|
+ Change: Fixed the subnet mask
|
|
+
|
|
+uIP v0.6.2.10 (Dec. 15, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: IPv6 does not connect for non-CIDR iface.ipaddress
|
|
+ specification
|
|
+ Cause: A bug where all ones was used as the IPv6 netmask
|
|
+ instead of all zeroes. This prevented all IPv6
|
|
+ path requests from being honored
|
|
+ Change: Fixed the subnet mask used
|
|
+
|
|
+uIP v0.6.2.9 (Dec. 14, 2010)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Added IP address CIDR notation support for the
|
|
+ iface.ipaddress field in the iface file.
|
|
+ This will allow subnet mask to be defined and used.
|
|
+
|
|
+uIP v0.6.2.8 (Dec. 9, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: ipv6 + ifup/down fails to reconnect
|
|
+
|
|
+ Cause: There were 2 problems found:
|
|
+ - the xmit_mutex lock was being held indefinitely
|
|
+ - the nl_process_if_down flag for 10g doorbell ringing
|
|
+ did not get reinitialized
|
|
+
|
|
+ Change: Fixed the xmit_mutex deadlock via trylock
|
|
+ Added nl_process_if_down initialization in the IF_DOWN
|
|
+ process
|
|
+
|
|
+ 2. Problem: Added fix for the NPAR disabled for 57712
|
|
+
|
|
+ Cause: The mac address was not handled correctly
|
|
+
|
|
+ Change: Fixed the mac address handling. Also requires corresponding
|
|
+ kernel component for the complete fix
|
|
+
|
|
+uIP v0.6.2.7 (Dec. 7, 2010)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Use the gateway address from the DHCP server the
|
|
+ destination IP address is not in the current subnet.
|
|
+
|
|
+uIP v0.6.2.6 (Nov. 16, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Warning message seen in the kernel logs,
|
|
+ "uio uio2: uevent: unsupported action string"
|
|
+
|
|
+ Cause: The improper string was echo'ed into the UIO trigger
|
|
+ field. With an improper string, this message would
|
|
+ appear in the kernel logs.
|
|
+
|
|
+ Change: uIP will now write the string "online" to the UIO
|
|
+ trigger field. This is the string expected by the
|
|
+ Linux kernel base driver.
|
|
+
|
|
+ 2. Problem: uIP would segfault during a heavily login/logout
|
|
+ iSCSI subsystem reset senario
|
|
+
|
|
+ Cause: A double free occurred in the logging portion of the
|
|
+ uIP code, but this was root cause to a double free when
|
|
+ manipulating the NetLink buffers.
|
|
+
|
|
+ Change: Properly look at the return code from the routine which
|
|
+ will read NetLink messages. Also only free buffers
|
|
+ if they are allocated.
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Add ability to print kernel version and machine
|
|
+ architecture to further help debug problems.
|
|
+
|
|
+ 2. Change: Apply the netmask from DHCP if provided.
|
|
+
|
|
+uIP v0.6.2.5 (Nov. 10, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: iscsid would try to conenct with unintended iSCSI
|
|
+ targets
|
|
+
|
|
+ Cause: uIP would blindly return the iSCSI target MAC address
|
|
+ regardless if the iSCSI target is reachable via the
|
|
+ given port.
|
|
+
|
|
+ Change: uIP will try to filter the requests coming from CNIC
|
|
+ by automatically generating a network mask based off
|
|
+ the configured IP addressed. Then this netmask is
|
|
+ masked with the destination IP address. If there is
|
|
+ a match, then the path_req is allowed through.
|
|
+
|
|
+ 2. Problem: Problems reconnecting back to the target when running
|
|
+ MTU stress tests.
|
|
+
|
|
+ Cause: cnic/bnx2i and uIP could possibly get out of sync when
|
|
+ an if_down message is sent.
|
|
+
|
|
+ Change: uIP will now immediately react to the if_down message,
|
|
+ and flush all the path req's and then to process to
|
|
+ if_close.
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Fix compile warnings for src/unix/nic_nl.c,
|
|
+ and src/unix/main.c
|
|
+
|
|
+uIP v0.6.2.4 (Nov. 4, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: iSCSI HBA: brcm_iscsiuio segfault during ifdown
|
|
+ with many active sessions
|
|
+
|
|
+ Cause: uIP will segfault when traversing the error path when
|
|
+ an iSCSI connection is starting but the sysfs entries
|
|
+ have not been created yet.
|
|
+
|
|
+ Change: Use the errno value rather then the one from the file
|
|
+ descriptor because the file descriptor will be NULL and
|
|
+ the NULL dereference will cause a segfault.
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Added initial changes for iSCSI multi-function support for
|
|
+ 10G NIC's.
|
|
+ 2. Change: Add more detailed messages for error pathes in nic_utils
|
|
+
|
|
+uIP v0.6.2.3 (October 28, 2010)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Add support for bnx2x-1.62.x drivers
|
|
+
|
|
+uIP v0.6.2.2 (October 18, 2010)
|
|
+=======================================================
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Only allow iSCSI connections with known bnx2x HSI's.
|
|
+
|
|
+uIP v0.6.2.1 (October 7, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: After multiple MTU changes, the ethtool IOCTL used to
|
|
+ determine the bnx2x driver version fails and eventually
|
|
+ iSCSI connections would not reconnect.
|
|
+
|
|
+ Cause: The socket file descriptor used during the ethtool IOCTL
|
|
+ call was never closed and leaked.
|
|
+
|
|
+ Change: On the error path when calling the ethtool IOCTL, the
|
|
+ file descriptor is now properly closed.
|
|
+
|
|
+uIP v0.5.39 (September 15, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Could not offload IPv4 VLAN connection when the target tries
|
|
+ to ARP the iSCSI initiator
|
|
+
|
|
+ Cause: In the ARP reply, the ether field was incorrect.
|
|
+
|
|
+ Change: Properly set the ether field to 802.1Q type (0x8100)
|
|
+
|
|
+uIP v0.5.38 (September 14, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: uIP would cause a panic dump when the NIC was going down
|
|
+
|
|
+ Cause: uIP and CNIC where not synchonized on NIC state
|
|
+
|
|
+ Change: Check if the RX BD's which are zero'ed by CNIC when the
|
|
+ NIC is going down. If the BD addresses are zero, then
|
|
+ uIP will drop the TX packets.
|
|
+
|
|
+uIP v0.5.37 (August 21, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: uIP would segfault on ifup/ifdown stress test when using
|
|
+ DHCP to determine local IP address.
|
|
+
|
|
+ Cause: The uIP would use a NULL buffer during data transmission.
|
|
+
|
|
+ Change: Drop packets when there are no buffer avaliable.
|
|
+
|
|
+uIP v0.5.36 (August 21, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: iSCSI boot would not completely login after the pivot
|
|
+ root operation.
|
|
+
|
|
+ Cause: The uIP would not properly start the NIC interface.
|
|
+
|
|
+ Change: uIP should only check the NIC state to determine whether
|
|
+ to start the NIC thread or not.
|
|
+
|
|
+ 2. Problem: uIP would segfault during if'up if'down testing.
|
|
+
|
|
+ Cause: The uIP would improperly start 2 NIC threads for the
|
|
+ same NIC interface.
|
|
+
|
|
+ Change: uIP should properly lock the NIC list when disabling/removing
|
|
+ the NIC threads.
|
|
+
|
|
+
|
|
+uIP v0.5.35 (August 20, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Sessions would hang with ethtool self-test
|
|
+
|
|
+ Cause: The uIP would hang because the socket layer was stuck
|
|
+ because there is much contention for that socket. This
|
|
+ would hang the CNIC thread.
|
|
+
|
|
+ Change: Remove any IOCTL calls in uIP which may colide with
|
|
+ the ethtool self test. The driver version is only
|
|
+ capture during uIP initialization.
|
|
+
|
|
+ 2. Problem: There were session recovery issue when using DHCP
|
|
+ if up/down tests.
|
|
+
|
|
+ Cause: The uIP would hang because the DHCP requests would
|
|
+ timeout if the network interface is downed which would
|
|
+ hang all the other uIP threads.
|
|
+
|
|
+ Change: Ensure that the DHCP state machine had exit points
|
|
+ if the network interface was down'ed.
|
|
+
|
|
+
|
|
+uIP v0.5.34 (August 18, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Sessions would not recover with ethtool self-test
|
|
+
|
|
+ Cause: The uIP would hang because either the NetLink buffer is
|
|
+ full or that any socket operations used to manipulate
|
|
+ multicast addresses would block.
|
|
+
|
|
+ Change: Ensure that the socket used for multicast addressing is
|
|
+ set to nonblocking. Drain the NetLink buffer without
|
|
+ using the eventing, but with a more aggressive poll routine.
|
|
+
|
|
+ 2. Problem: Sessions would not recover with L2 driver load/unload on
|
|
+ RHEL 6.0 SS9
|
|
+
|
|
+ Cause: The uIP would close the NIC thread too early and would
|
|
+ deadlock on cloing the NIC thread.
|
|
+
|
|
+ Change: Ensure that the NIC thread is canceled/closed only in one
|
|
+ location, in the NIC remove routine.
|
|
+
|
|
+
|
|
+uIP v0.5.33 (August 17, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Error message seen from the uIP stack for valid packets.
|
|
+
|
|
+ Cause: The uIP was incorrectly marking logging messages for valid
|
|
+ packets as errors because it didn't know how to parase them.
|
|
+
|
|
+ Change: Changed the following from error to debug message
|
|
+ ipv6: invalid version
|
|
+ ipv4: invalid version or header length.
|
|
+ icmpv6: unknown ICMP message.
|
|
+ ip: neither tcp nor icmp
|
|
+ Changed the following from error to warn message
|
|
+ udp: bad checksum
|
|
+ tcp: bad checksum
|
|
+ tcp: got reset, aborting connection.
|
|
+
|
|
+ 2. Problem: After multiple iterations the loading and unloading of
|
|
+ the Broadcom Linux drivers with active connections
|
|
+ would not cause the sessions to recover on RHEL 6.0
|
|
+ snapshot 9.
|
|
+
|
|
+ Cause: There was a deadlock in the nic mutex
|
|
+
|
|
+ Change: Lock ordering for the nic mutex and nic list mutex must
|
|
+ be inforced.
|
|
+
|
|
+ 3. Problem: After multiple iterations of running the ethtool selftest
|
|
+ the Broadcom Linux drivers with active connections
|
|
+ would not cause the sessions to recover on RHEL 5.5.
|
|
+
|
|
+ Cause: The Netlink buffer between uIP and CNIC would get full.
|
|
+
|
|
+ Change: Poll more regularly for packets in the Netlink buffer
|
|
+ from 4 times a second to 100 times a 1 second.
|
|
+ Drain packets during the PATH_REQ packet pull.
|
|
+
|
|
+
|
|
+uIP v0.5.32 (August 14, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Error message 'nic eth0: Didn't find type 0xaa bb' seen.
|
|
+
|
|
+ Cause: Valid non-DIX Ethernet packets as being passed to the
|
|
+ uIP. uIP will drop these packets but should be logged
|
|
+ correctly.
|
|
+
|
|
+ Change: These packets are valid, and should only be logged for
|
|
+ debugging purposes.
|
|
+
|
|
+ 2. Problem: Error message 'Dropped previous transmitted packet' seen.
|
|
+
|
|
+ Cause: The TX ring is full, and here uIP is trying to transmit a
|
|
+ packet which will be dropped. This is a valid state but
|
|
+ the log message is marked incorrectly
|
|
+
|
|
+ Change: These messages are not warnings and should be logging when
|
|
+ debugging is enabled.
|
|
+
|
|
+ 3. Problem: Error message: "iscsi_ipc eth0 Transport name is not
|
|
+ equal expected: got: bnx2i" seen.
|
|
+
|
|
+ Cause: The iface_rec structure is different between iscsid version.
|
|
+ For RHEL 5.5, iscsid is versioned 871, for RHEL 6.0 is
|
|
+ versioned 872.
|
|
+
|
|
+ Change: Allow uIP to compile against a different version of iscsid.
|
|
+
|
|
+
|
|
+uIP v0.5.31 (August 12, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Softlock would occur showing that the NetLink table
|
|
+ lock was taken but never released.
|
|
+
|
|
+ Cause: NetLink socket buffer would fill with constant PATH_REQ
|
|
+ messages preventing PATH_REQ response from libiscsi
|
|
+
|
|
+ Change: Now uIP will drain the NetLink buffer while looking for
|
|
+ a response.
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Add documentation for VLAN configuration and restrictions.
|
|
+
|
|
+
|
|
+uIP v0.5.30 (August 6, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: iscsid thread will stall if closing the uio files nodes
|
|
+ is stuck
|
|
+
|
|
+ Cause: uIP would indefinitely block waiting for the mutex shared
|
|
+ by the close routine.
|
|
+
|
|
+ Change: Now uIP will try and poll a bit for the mutex. If it can't
|
|
+ get this mutex in the iscsid thread then an error is return
|
|
+ rather then hold the thread.
|
|
+
|
|
+ 2. Problem: IPv6 Unicast Neighbor Adveriserments would have the
|
|
+ ICMPv6 option header specifying a MAC.
|
|
+
|
|
+ Cause: uIP should use the source IPv6 address to detmine whether
|
|
+ to strip the option header or not and not the target address
|
|
+ in the ICMPv6 field.
|
|
+
|
|
+ Change: The uIP stack return a unicast IPv6 Neighbor Advertisement
|
|
+ without the ICMPv6 option as a response to unicast
|
|
+ IPv6 Neighbor Solicitations.
|
|
+
|
|
+ 3. Problem: There would be TCP SYN packets with improper MAC address.
|
|
+
|
|
+ Cause: A zero'ed MAC address was not passed to CNIC to indicate an
|
|
+ error or if the IP address didn't resolve.
|
|
+
|
|
+ Change: The uIP stack will now return a zero'ed MAC address if it
|
|
+ can't find any entries.
|
|
+
|
|
+
|
|
+uIP v0.5.29 (August 6, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: "uip udp: no matching connection found: lport: 35072"
|
|
+ seen numerous times in the brcm_iscsiuio log file
|
|
+
|
|
+ Cause: This message was incorrectly marked as an error
|
|
+
|
|
+ Change: These messages are valid log entries especially if the
|
|
+ packet was a broadcast UDP packet not destined for the SUT
|
|
+ I will change the code to mark these logs entries as debug.
|
|
+
|
|
+
|
|
+uIP v0.5.28 (August 5, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Can't login into a redirected Equilogic Target
|
|
+
|
|
+ Cause: The Equilogic Target uses a unicast IPv6 Neighbor
|
|
+ Solicitation to test if the host is up. The uIP stack
|
|
+ would return a Neighbor Advertisement with an unneeded
|
|
+ ICMPv6 option.
|
|
+
|
|
+ Change: Only have the uIP stack return a unicast IPv6 Neighbor
|
|
+ Advertisement without the ICMPv6 option.
|
|
+
|
|
+ 2. Problem: With older bnx2/bnx2x/cnic/bnx2i driver combinations
|
|
+ uIP would segfault when these drivers were unloaded.
|
|
+
|
|
+ Cause: When the older drivers were removed, the underlying uio
|
|
+ instance was removed causing uIP to have a stale file handle.
|
|
+ When uIP finally closes using this stale file handle, either
|
|
+ uIP would segfault, or there would be an error in the
|
|
+ uio_release() path.
|
|
+
|
|
+ Change: Only have the uIP close if the UIO file node exists.
|
|
+
|
|
+
|
|
+uIP v0.5.27 (July 31, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: iSCSI HBA: Unable to use DHCP address for iSCSI interface
|
|
+ if a connection was previously made with a static address
|
|
+ on bnx2 devices.
|
|
+
|
|
+ Cause: Because the device is closed and reopen'ed the TX consumer
|
|
+ indexes were not persisted
|
|
+
|
|
+ Change: Only discard the TX consumer indexes only when the devices
|
|
+ will be discarded or closed
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+ 1. Change: Change CNIC references to bnx2 in the bnx2 user space
|
|
+ driver.
|
|
+
|
|
+
|
|
+uIP v0.5.26 (July 30, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: iSCSI HBA: Unable to use DHCP address for iSCSI interface
|
|
+ if a connection was previously made with a static address on
|
|
+ bnx2x devices.
|
|
+
|
|
+ Cause: Because the device is closed and reopen'ed the TX consumer
|
|
+ indexes were not persisted
|
|
+
|
|
+ Change: Only discard the TX consumer indexes only when the devices
|
|
+ will be discarded
|
|
+
|
|
+ 2. Problem: IPv6 using VLAN's didn't login
|
|
+
|
|
+ Cause: The uIP code used to determine if the packet was an IPv6
|
|
+ or not was not working. This VLAN packets for IPv6 were
|
|
+ being mis-interpreted.
|
|
+
|
|
+ Change: Make the function is_ipv6() VLAN aware
|
|
+
|
|
+ 3. Problem: Persistant targets was not loggin in during boot
|
|
+
|
|
+ Cause: If udev was slow and the /dev/uio* were creatly slowly
|
|
+ uIP would fail.
|
|
+
|
|
+ Change: Poll uIP waiting for /dev/uio* file nodes.
|
|
+
|
|
+uIP v0.5.25 (July 27, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: When using IPv4 DHCP, there are no initial DHCP Discover
|
|
+ packets were not seen on the wire.
|
|
+
|
|
+ Cause: Packets generated from the app handler from the uIP stack
|
|
+ were not placed on the wire.
|
|
+
|
|
+ Change: Packets originating from the uIP stack are now always placed
|
|
+ on the wire.
|
|
+
|
|
+uIP v0.5.24 (July 25, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: One would see invalid packet packets flow through the
|
|
+ uIP stack, where the logs would indicate there is a packet
|
|
+ with an invalid length
|
|
+
|
|
+ Cause: The BD and CQE consumer indexes were not properly incremented
|
|
+ and masked.
|
|
+
|
|
+ Change: The BD index is now properly masked. The CQE index is not
|
|
+ incremented using the CQE index rather the mistaken BD index.
|
|
+
|
|
+ Impact: 10G only
|
|
+
|
|
+ 2. Problem: uIP would segfault during the booting of the machine.
|
|
+
|
|
+ Cause: uIP was using a NULL data pointer because there was an
|
|
+ incorrect packet passed to the stack.
|
|
+
|
|
+ Change: Only allow uIP to process data if the packet exists.
|
|
+
|
|
+ 3. Problem: uIP would stop processing packets
|
|
+
|
|
+ Cause: The uIP code would not properly drain the CQE ring causing
|
|
+ it to eventually be full
|
|
+
|
|
+ Change: Consume all the CQE elements even if they are ethernet types
|
|
+ or not.
|
|
+
|
|
+ Impact: 10G only
|
|
+
|
|
+ 4. Problem: uIP would stop after if/down of the network interface.
|
|
+
|
|
+ Cause: uIP was not kick starting the NIC loop thread properly.
|
|
+
|
|
+ Change: Ensure that the NIC loop thread is started by when iscsid
|
|
+ request that the interface start the offload. Mark the NIC
|
|
+ only if the thread is truly canceled.
|
|
+
|
|
+
|
|
+uIP v0.5.23 (July 20, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Segfault during brcm_iscsiuio initialization
|
|
+
|
|
+ Cause: uIP was using a NULL data pointer, because a different
|
|
+ thread re-initialized the uIP stack
|
|
+
|
|
+ Change: Properly synchronize the initialization of the stack
|
|
+
|
|
+ 2. Problem: Deadlock during the printing of heavy debug messages
|
|
+
|
|
+ Cause: The variable macro structures would point to invalid
|
|
+ data
|
|
+
|
|
+ Change: With each invocation of va_copy() a corresponding
|
|
+ invocation of va_end() in the same function for the proper
|
|
+ cleanup
|
|
+
|
|
+ 3. Problem: uIP would hang when the interface could go up/down
|
|
+
|
|
+ Cause: uIP would get out of sync with the state of the network
|
|
+ interface
|
|
+
|
|
+ Change: Instead of detriving state from the UIO file nodes, uIP
|
|
+ will take direction from iscsid on when interfaces will be
|
|
+ started.
|
|
+
|
|
+uIP v0.5.22 (July 15, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Unable to reconnect via iSCSI offload after
|
|
+ ifup/ifdown
|
|
+
|
|
+ Cause: uIP was stuck on the thread when closing the NIC main
|
|
+ loop
|
|
+
|
|
+ Change: Properly synchronize the NetLink CNIC and uevent threads
|
|
+
|
|
+ 2. Problem: uIP would crash during boot up.
|
|
+
|
|
+ Cause: uIP would overwrite a memory location which was already
|
|
+ freed during nic_remove().
|
|
+
|
|
+ Change: Since the NIC is freed there is no need to write to
|
|
+ update the NIC flags
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+
|
|
+ 1. Change: Added IPv6 Link Local support
|
|
+
|
|
+
|
|
+uIP v0.5.21 (July 5, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Unable to connect via iSCSI offload after
|
|
+ changing L2 address
|
|
+
|
|
+ Cause: uIP didn't notice the network inferface going down
|
|
+
|
|
+ Change: Allow uIP to persist the stack's IP address after
|
|
+ a reset
|
|
+
|
|
+ 2. Problem: Unable to connect via IPv4 and IPv6 concurrently
|
|
+
|
|
+ Cause: uIP didn't notice the network inferface going down
|
|
+
|
|
+ Change: Allow uIP to persist the stack's IP address after
|
|
+ a reset and properly bring up the interface
|
|
+
|
|
+ 3. Problem: Unable to connect via VLAN
|
|
+
|
|
+ Cause: IP address was no persisted after a device reset
|
|
+
|
|
+ Change: When CNIC requests a path request, uIP will use the
|
|
+ VLAN passed by the CNIC.
|
|
+
|
|
+
|
|
+uIP v0.5.20 (June 24, 2010)
|
|
+
|
|
+
|
|
+uIP v0.5.20 (June 24, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Certain IPv6 addresses are not repsonded to by
|
|
+ the target.
|
|
+
|
|
+ Cause: The MAC was generated from the target's IPv6
|
|
+ address not the deterived multicast IPv6 address.
|
|
+
|
|
+ Change: The destination MAC address should be deterived
|
|
+ from the packet's destination IPv6 address and
|
|
+ not the target.
|
|
+
|
|
+ 2. Problem: brcm_iscsiuio would segfault when L2 interface is
|
|
+ bought up and down after being logged into
|
|
+
|
|
+ Cause: The NIC thread was not stopped properly
|
|
+
|
|
+ Change: When the UIO device is remove and when the
|
|
+ cooresponding NIC tracked by brcm_iscsiuio, the
|
|
+ daemon would properly wait for the NIC thread to
|
|
+ stop.
|
|
+
|
|
+
|
|
+uIP v0.5.19 (June 22, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Can't login after boot
|
|
+
|
|
+ Cause: If NIC interfaces are brough up and down quickly
|
|
+ uIP wait on an invalid NIC thread
|
|
+
|
|
+ Change: Only wait for the NIC thread if the NIC thread
|
|
+ exists.
|
|
+
|
|
+uIP v0.5.18 (June 21, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Does not compile on SLES 11 SP1
|
|
+
|
|
+ Cause: Automake cached files were included as part of the
|
|
+ uIP-0.5.17 package
|
|
+
|
|
+ Change: Remove automake cached files, and allow these files
|
|
+ to be generated each time the source is compiled
|
|
+
|
|
+ 2. Problem: Does not always receive multicast packets
|
|
+
|
|
+ Cause: Multicast bit was not set in SORT USER 2 register
|
|
+
|
|
+ Change: brcm_iscsiuio will now set the SORT USER 2 registers
|
|
+ with both the broadcast and multicast bits.
|
|
+
|
|
+ 3. Problem: Existing iSCSI connections do not reconnect after
|
|
+ operations which require equivalent driver
|
|
+ load/unload operations
|
|
+
|
|
+ Cause: Multiple path requests would trample NIC configurations
|
|
+
|
|
+ Change: Allow only one path request at a time
|
|
+
|
|
+uIP v0.5.17 (June 16, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: IPv6 neighbor solicitations from brcm_iscsiuio could
|
|
+ not be responded to
|
|
+
|
|
+ Cause: The IPv6 neighbor solicitation packet had an invalid
|
|
+ multicast MAC address
|
|
+
|
|
+ Change: Properly set the MAC address multicast bit and OR
|
|
+ with the IPv6 destination address
|
|
+
|
|
+ 2. Problem: NIC state was not properly synchronized and noticed
|
|
+ by Shyam Iyer <shiyer@redhat.com>
|
|
+
|
|
+ Change: Properly lock the NIC device when changing state
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+
|
|
+ 1. Change: Listen for iscsid before daemonizing to close a timing
|
|
+ gap which might allow iscsid to start before uIP is
|
|
+ completely initialized.
|
|
+
|
|
+uIP v0.5.16 (June 2, 2010)
|
|
+=======================================================
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+
|
|
+ 1. Change: Formally add IPv6 support. Only a static IPv6 address
|
|
+ is supported.
|
|
+
|
|
+uIP v0.5.15 (May 20, 2010)
|
|
+=======================================================
|
|
+
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: brcm_iscsiuio would echo packets off the wire
|
|
+
|
|
+ Cause: Stale packets from the uIP stack could potentially
|
|
+ make it onto the wire causing a network flood
|
|
+
|
|
+ Change: Only place on the wire packets uIP intended to place
|
|
+ on the wire. Drop all other packets.
|
|
+
|
|
+uIP v0.5.14 (May 18, 2010)
|
|
+=======================================================
|
|
+
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: brcm_iscsiuio would crash when offloading using a
|
|
+ bnx2x device /dev/mem could not be
|
|
+ opened, (ie. SE Linux enabled)
|
|
+
|
|
+ Cause: /dev/mem could not be opened, (ie. SE Linux enabled)
|
|
+ and then the NIC would be improperly initialized.
|
|
+
|
|
+ Change: If /dev/mem is not able to be opened, then the device
|
|
+ is closed
|
|
+
|
|
+ 2. Problem: brcm_iscsiuio would crash when brcm_iscsiuio is
|
|
+ being shutdown
|
|
+
|
|
+ Cause: The NIC mutex was deferenced imporperly when the NIC
|
|
+ is being closed
|
|
+
|
|
+ Change: Take the NIC mutex lock only when the NIC is closed.
|
|
+
|
|
+uIP v0.5.13 (May 16, 2010)
|
|
+=======================================================
|
|
+
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: brcm_iscsiuio would crash with heavy traffic directed
|
|
+ at the iSCSI traffic
|
|
+
|
|
+ Cause: Packets which are sized between 1006-1024 bytes would
|
|
+ crash brcm_iscsiuio because brcm_iscsiuio is not sized
|
|
+ to handle such large packets
|
|
+
|
|
+ Change: Drop large packets, properly hold the NIC mutex lock
|
|
+ for the duration when NIC fields are being used.
|
|
+
|
|
+
|
|
+uIP v0.5.12 (May 13, 2010)
|
|
+=======================================================
|
|
+
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: brcm_iscsiuio could crash on when L2 interface is
|
|
+ ifdown'ed
|
|
+
|
|
+ Cause: The local NIC pointer was not initialized properly
|
|
+ in the routine parse_iface()
|
|
+
|
|
+ Change: Properly initialize the NIC pointer
|
|
+
|
|
+ 2. Problem: Documentation referred to older admin_client which
|
|
+ doesn't exist any more because brcm_iscsiuio uses
|
|
+ the iscsid iface file
|
|
+
|
|
+ Change: Remove the stale references
|
|
+
|
|
+
|
|
+uIP v0.5.11 (May 11, 2010)
|
|
+=======================================================
|
|
+
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: brcm_iscsiuio could crash on invalid packet sizes
|
|
+
|
|
+ Cause: The hardware BD could be a large value because of a
|
|
+ hardware error
|
|
+
|
|
+ Change: Limit the size of the packet dumped to the MTU size
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+
|
|
+ 1. Change: During the running of the configure script now
|
|
+ the script will check for ar and ranlib binaries
|
|
+
|
|
+
|
|
+uIP v0.5.10 (May 03, 2010)
|
|
+=======================================================
|
|
+
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: BCM57712 not recognized
|
|
+
|
|
+ Cause: The PCI ID's in the bnx2x file were missing.
|
|
+
|
|
+ Change: Added proper BCM57712, BCM57712E, BCM57713, BCM57713E
|
|
+ PCI ID's
|
|
+
|
|
+ 2. Problem: (CQ 47481) brcm_iscsiuio not installed in correct location
|
|
+
|
|
+ Cause: Default install path for autoconf is /usr/local
|
|
+
|
|
+ Change: Change the default prefix to '/' so the brcm_iscsiuio
|
|
+ binary is installed to /sbin/
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+
|
|
+ 1. Change: Remove dependency on Yacc and Lex
|
|
+
|
|
+
|
|
+uIP v0.5.9 (April 28, 2010)
|
|
+=======================================================
|
|
+
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: bnx2x T6.0 driver would not login
|
|
+
|
|
+ Cause: The bnx2x code was not using the T6.0 HSI offsets
|
|
+
|
|
+ Change: Determine to bnx2x driver version eariler to properly use the
|
|
+ T4.8 or T6.0 HSI
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+
|
|
+ 1. Change: Collapse all the various locks to use the NIC lock to shrink
|
|
+ memory footprint
|
|
+
|
|
+ 2. Change: Consolidate upper layer checksumming code
|
|
+
|
|
+
|
|
+uIP v0.5.5 (March 02, 2010)
|
|
+=======================================================
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+
|
|
+ 1. Change: Add support for T6.0 bnx2x HSI and 57712.
|
|
+
|
|
+ 2. Change: Initial support for IPv6
|
|
+
|
|
+uIP v0.5.8 (April 22, 2010)
|
|
+=======================================================
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+
|
|
+ 1. Change: Add support for T6.0 bnx2x HSI and 57712.
|
|
+
|
|
+ 2. Change: Initial support for IPv6
|
|
+
|
|
+uIP v0.5.7 (March 17, 2010)
|
|
+=======================================================
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+
|
|
+ 1. Change: Add to documentation on discovering on a particular
|
|
+ iface before logging in
|
|
+
|
|
+uIP v0.5.6 (Mar 05, 2009)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: bnx2x panic dump would be seen when sending
|
|
+ traffic to uIP
|
|
+
|
|
+ Cause: The TX producer index was not properly
|
|
+ incrementing when the wrapping occured
|
|
+
|
|
+ Change: Do not skip the last TX producer index like the
|
|
+ TX BD's
|
|
+
|
|
+ Impact: None.
|
|
+
|
|
+uIP v0.5.5 (March 02, 2010)
|
|
+=======================================================
|
|
+ Initial release
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+
|
|
+ 1. Change: Add to documentation on debugging/logging for uIP
|
|
+
|
|
+
|
|
+uIP v0.5.4 (Feb 22, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Compile error where 'ETHERTYPE_VLAN' define
|
|
+ is missing
|
|
+
|
|
+ Cause: Certain distributions do not define 'ETHERTYPE_VLAN'
|
|
+ in the header file "net/ethernet.h".
|
|
+
|
|
+ Change: Added proper defines for ETHERTYPE_VLAN when necessary
|
|
+
|
|
+ Impact: None.
|
|
+
|
|
+
|
|
+uIP v0.5.3 (Feb 18, 2010)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Using VLAN's on offloaded iSCSI connections
|
|
+
|
|
+ Cause: (CQ45983) VLAN tags were not being properly inserted
|
|
+ when sending the ARP request packets
|
|
+
|
|
+ Change: Added VLAN tags when sending ARP request packets
|
|
+
|
|
+ Impact: None.
|
|
+
|
|
+
|
|
+uIP v0.5.2 (Dec 10, 2009)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: Switching between 10G and 1G iSCSI offloaded
|
|
+ devices caused login connectivity problems
|
|
+
|
|
+ Cause: The NIC devices within uIP were not cleanup
|
|
+ properly.
|
|
+
|
|
+ Change: The NIC structure is not re-initialized and the
|
|
+ NIC thread is destroyed when the host network
|
|
+ interface is brought down.
|
|
+
|
|
+ Impact: None.
|
|
+
|
|
+
|
|
+uIP v0.5.1 (Dec 9, 2009)
|
|
+=======================================================
|
|
+ Fixes
|
|
+ -----
|
|
+ 1. Problem: 10G devices behind PCI bridges would not collect
|
|
+
|
|
+ Cause: PCI bus:slot.func string was parsed incorrectly
|
|
+ because the bridge string was used
|
|
+
|
|
+ Change: Parse the proper PCI bus:slot.func string.
|
|
+
|
|
+ Impact: None.
|
|
+
|
|
+
|
|
+uIP v0.5.0b (Nov 24, 2009)
|
|
+=======================================================
|
|
+ Initial release
|
|
+
|
|
+ Enhancements
|
|
+ ------------
|
|
+
|
|
+ 1. Change: Add Broadcom 10G iSCSI offload support
|
|
+
|
|
+ Impact: Linux
|
|
+
|
|
diff --git a/iscsiuio/configure.ac b/iscsiuio/configure.ac
|
|
new file mode 100644
|
|
index 0000000..6c0013b
|
|
--- /dev/null
|
|
+++ b/iscsiuio/configure.ac
|
|
@@ -0,0 +1,78 @@
|
|
+dnl iscsiuio uIP user space stack configure.ac file
|
|
+dnl
|
|
+dnl Copyright (c) 2004-2013 Broadcom Corporation
|
|
+dnl Copyright (c) 2014, QLogic Corporation
|
|
+dnl
|
|
+dnl This program is free software; you can redistribute it and/or modify
|
|
+dnl it under the terms of the GNU General Public License as published by
|
|
+dnl the Free Software Foundation.
|
|
+dnl
|
|
+dnl Written by: Eddie Wai (eddie.wai@broadcom.com)
|
|
+dnl Benjamin Li (benli@broadcom.com)
|
|
+dnl
|
|
+
|
|
+PACKAGE=iscsiuio
|
|
+VERSION=0.7.8.2
|
|
+
|
|
+AC_INIT([iscsiuio], [0.7.8.2], [QLogic-Storage-Upstream@qlogic.com])
|
|
+
|
|
+AM_INIT_AUTOMAKE
|
|
+AC_CONFIG_HEADER(config.h)
|
|
+AC_PATH_PROGS(BASH, bash)
|
|
+
|
|
+AC_PROG_CC
|
|
+AM_PROG_CC_C_O
|
|
+
|
|
+AC_PROG_RANLIB
|
|
+
|
|
+AC_GNU_SOURCE
|
|
+AC_PROG_INSTALL
|
|
+AC_PROG_GCC_TRADITIONAL
|
|
+
|
|
+# Checks for typedefs, structures, and compiler characteristics.
|
|
+AC_C_CONST
|
|
+AC_C_INLINE
|
|
+AC_TYPE_OFF_T
|
|
+AC_TYPE_SIZE_T
|
|
+AC_CHECK_TYPES(int8_t)
|
|
+AC_CHECK_TYPES(uint8_t)
|
|
+AC_CHECK_TYPES(int16_t)
|
|
+AC_CHECK_TYPES(uint16_t)
|
|
+AC_CHECK_TYPES(int32_t)
|
|
+AC_CHECK_TYPES(uint32_t)
|
|
+AC_CHECK_TYPES(int64_t)
|
|
+AC_CHECK_TYPES(uint64_t)
|
|
+AC_CHECK_SIZEOF(short, 2)
|
|
+AC_CHECK_SIZEOF(int, 4)
|
|
+AC_CHECK_SIZEOF(long, 4)
|
|
+
|
|
+AC_C_BIGENDIAN(AC_SUBST([ENDIAN],[BIG]),AC_SUBST([ENDIAN],[LITTLE]))
|
|
+
|
|
+AC_LIBTOOL_DLOPEN
|
|
+
|
|
+# libtool stuff
|
|
+AC_PROG_LIBTOOL
|
|
+
|
|
+: ${CFLAGS:="-O2"}
|
|
+CFLAGS="${CFLAGS} -Wall"
|
|
+## check for --enable-debug first before checking CFLAGS before
|
|
+## so that we don't mix -O and -g
|
|
+AC_ARG_ENABLE(debug,
|
|
+[ --enable-debug Turn on compiler debugging information (default=no)],
|
|
+ [if eval "test x$enable_debug = xyes"; then
|
|
+ CFLAGS="${CFLAGS} -g -O0"
|
|
+ fi])
|
|
+AM_CONDITIONAL([DEBUG], [test x$debug = xtrue])
|
|
+
|
|
+AC_CONFIG_COMMANDS([default],[[ echo 'char *build_date = "'`date`'";' > src/unix/build_date.c && echo 'char *build_date;'> src/unix/build_date.h]],[[]])
|
|
+
|
|
+AC_PREFIX_DEFAULT()
|
|
+
|
|
+AC_OUTPUT([Makefile
|
|
+src/Makefile
|
|
+src/apps/Makefile
|
|
+src/apps/dhcpc/Makefile
|
|
+src/apps/brcm-iscsi/Makefile
|
|
+src/uip/Makefile
|
|
+src/unix/Makefile
|
|
+src/unix/libs/Makefile])
|
|
diff --git a/iscsiuio/docs/iscsiuio.8 b/iscsiuio/docs/iscsiuio.8
|
|
new file mode 100644
|
|
index 0000000..b329979
|
|
--- /dev/null
|
|
+++ b/iscsiuio/docs/iscsiuio.8
|
|
@@ -0,0 +1,89 @@
|
|
+.\" Copyright (c) 2010-2013 Broadcom Corporation
|
|
+.\" Copyright (c) 2014, QLogic Corporation
|
|
+.\" This is free documentation; you can redistribute it and/or
|
|
+.\" modify it under the terms of the GNU General Public License as
|
|
+.\" published by the Free Software Foundation.
|
|
+.\"
|
|
+.\" bnx2.4,v 0.7.8.1b
|
|
+.\"
|
|
+.TH iscsiuio 8 "12/10/2013" "QLogic Corporation"
|
|
+.\"
|
|
+.\" NAME part
|
|
+.\"
|
|
+.SH NAME
|
|
+iscsiuio \- iSCSI UserSpace I/O driver
|
|
+.\"
|
|
+.\" SYNOPSIS part
|
|
+.\"
|
|
+.SH SYNOPSIS
|
|
+.B iscsiuio
|
|
+.RB [ -d -f -v ]
|
|
+.PP
|
|
+.\"
|
|
+.\" DESCRIPTION part
|
|
+.\"
|
|
+.SH DESCRIPTION
|
|
+iscsiuio is the UserSpace I/O driver for the QLogic NetXtreme II
|
|
+BCM5706/5708/5709 series PCI/PCI-X Gigabit Ethernet Network Interface Card
|
|
+(NIC) and for the QLogic NetXtreme II BCM57710/57711/57712/57800/57810/57840
|
|
+series PCI-E 10 Gigabit Ethernet Network Interface Card.
|
|
+The driver has been tested on 2.6.28 kernels and above.
|
|
+.PP
|
|
+Refer to the README.TXT from the driver package on how to
|
|
+compile and install the driver.
|
|
+.PP
|
|
+Refer to various Linux documentations
|
|
+on how to configure network protocol and address.
|
|
+.\"
|
|
+.\" DRIVER DEPENDENCIES part
|
|
+.\"
|
|
+.SH DRIVER DEPENDENCIES
|
|
+
|
|
+.\"
|
|
+.\" PARAMETER part
|
|
+.\"
|
|
+.SH PARAMETERS
|
|
+There are very few parameters when running this application.
|
|
+.TP
|
|
+.BI -d <debug level>
|
|
+This is to enable debug mode where debug messages will be sent to stdout
|
|
+The following debug modes are supported
|
|
+.P
|
|
+.RS
|
|
+DEBUG 4 - Print all messages
|
|
+.P
|
|
+INFO 3 - Print messages needed to follow the uIP code (default)
|
|
+.P
|
|
+WARN 2 - Print warning messages
|
|
+.P
|
|
+ERROR 1 - Only print critical errors
|
|
+.RE
|
|
+.PP
|
|
+.TP
|
|
+.TP
|
|
+.BI -f
|
|
+This is to enable forground mode so that this application doesn't get sent
|
|
+into the background.
|
|
+.PP
|
|
+.TP
|
|
+.BI -v
|
|
+This is to print the version.
|
|
+.PP
|
|
+.TP
|
|
+.BI -p <pidfile>
|
|
+Use pidfile (default /var/run/iscsiuio.pid )
|
|
+.PP
|
|
+.TP
|
|
+.BI -h
|
|
+Display this help and exit.
|
|
+
|
|
+
|
|
+.\"
|
|
+.\" AUTHOR part
|
|
+.\"
|
|
+.SH AUTHOR
|
|
+Benjamin Li \- benli@broadcom.com
|
|
+.P
|
|
+Eddie Wai \- eddie.wai@broadcom.com
|
|
+.SH Maintained by
|
|
+QLogic-Storage-Upstream@qlogic.com
|
|
diff --git a/iscsiuio/iscsiuiolog b/iscsiuio/iscsiuiolog
|
|
new file mode 100644
|
|
index 0000000..360947c
|
|
--- /dev/null
|
|
+++ b/iscsiuio/iscsiuiolog
|
|
@@ -0,0 +1,10 @@
|
|
+/var/log/iscsiuio.log {
|
|
+ weekly
|
|
+ missingok
|
|
+ notifempty
|
|
+ rotate 4
|
|
+ sharedscripts
|
|
+ postrotate
|
|
+ pkill -USR1 iscsiuio 2> /dev/null || true
|
|
+ endscript
|
|
+}
|
|
diff --git a/iscsiuio/src/Makefile.am b/iscsiuio/src/Makefile.am
|
|
new file mode 100644
|
|
index 0000000..44b0085
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/Makefile.am
|
|
@@ -0,0 +1 @@
|
|
+SUBDIRS = apps uip unix
|
|
diff --git a/iscsiuio/src/README b/iscsiuio/src/README
|
|
new file mode 100644
|
|
index 0000000..9fca6fb
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/README
|
|
@@ -0,0 +1,13 @@
|
|
+uIP is a very small implementation of the TCP/IP stack that is written
|
|
+by Adam Dunkels <adam@sics.se>. More information can be obtained
|
|
+at the uIP homepage at http://www.sics.se/~adam/uip/.
|
|
+
|
|
+This is version $Name: uip-1-0 $.
|
|
+
|
|
+The directory structure look as follows:
|
|
+
|
|
+apps/ - Example applications
|
|
+doc/ - Documentation
|
|
+lib/ - Library code used by some applications
|
|
+uip/ - uIP TCP/IP stack code
|
|
+unix/ - uIP as a user space process under FreeBSD or Linux
|
|
diff --git a/iscsiuio/src/apps/Makefile.am b/iscsiuio/src/apps/Makefile.am
|
|
new file mode 100644
|
|
index 0000000..08ed18d
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/apps/Makefile.am
|
|
@@ -0,0 +1 @@
|
|
+SUBDIRS = dhcpc brcm-iscsi
|
|
diff --git a/iscsiuio/src/apps/README b/iscsiuio/src/apps/README
|
|
new file mode 100644
|
|
index 0000000..0096c4e
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/apps/README
|
|
@@ -0,0 +1,2 @@
|
|
+This directory contains a few example applications. They are not all
|
|
+heavily tested, however.
|
|
diff --git a/iscsiuio/src/apps/brcm-iscsi/Makefile.am b/iscsiuio/src/apps/brcm-iscsi/Makefile.am
|
|
new file mode 100644
|
|
index 0000000..00cbd8e
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/apps/brcm-iscsi/Makefile.am
|
|
@@ -0,0 +1,13 @@
|
|
+AM_CFLAGS = -I${top_srcdir}/src/unix \
|
|
+ -I${top_srcdir}/src/uip \
|
|
+ -I${top_srcdir}/src/apps/dhcpc \
|
|
+ -I${top_srcdir}/src/apps/brcm-iscsi \
|
|
+ -I${top_srcdir}/../include \
|
|
+ -I${top_srcdir}/../usr
|
|
+
|
|
+noinst_LIBRARIES = lib_apps_brcm_iscsi.a
|
|
+
|
|
+lib_apps_brcm_iscsi_a_SOURCES = brcm_iscsi.c
|
|
+
|
|
+lib_apps_brcm_iscsi_a_CFLAGS = $(AM_CFLAGS) \
|
|
+ -DBYTE_ORDER=@ENDIAN@
|
|
diff --git a/iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi b/iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi
|
|
new file mode 100644
|
|
index 0000000..732275f
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/apps/brcm-iscsi/Makefile.brcm-iscsi
|
|
@@ -0,0 +1 @@
|
|
+APP_SOURCES += brcm-iscsi.c
|
|
diff --git a/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c b/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c
|
|
new file mode 100644
|
|
index 0000000..4223ca4
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.c
|
|
@@ -0,0 +1,89 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li <benli@broadcom.com>
|
|
+ * Based on code example from Adam Dunkels
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ */
|
|
+/**
|
|
+ * \addtogroup brcm-iscsi
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * An example of how to write uIP applications
|
|
+ * with protosockets
|
|
+ * \author
|
|
+ * Benjamin Li <benli@broadcom.com>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * This is a short example of how to write uIP applications using
|
|
+ * protosockets.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * We define the application state (struct hello_world_state) in the
|
|
+ * hello-world.h file, so we need to include it here. We also include
|
|
+ * uip.h (since this cannot be included in hello-world.h) and
|
|
+ * <string.h>, since we use the memcpy() function in the code.
|
|
+ */
|
|
+#include "brcm_iscsi.h"
|
|
+#include "uip.h"
|
|
+#include <string.h>
|
|
+#include <stdio.h>
|
|
+
|
|
+#include "uip_arp.h"
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+/*
|
|
+ * The initialization function. We must explicitly call this function
|
|
+ * from the system initialization code, some time after uip_init() is
|
|
+ * called.
|
|
+ */
|
|
+void brcm_iscsi_init(void)
|
|
+{
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+/*
|
|
+ * In hello-world.h we have defined the UIP_APPCALL macro to
|
|
+ * hello_world_appcall so that this funcion is uIP's application
|
|
+ * function. This function is called whenever an uIP event occurs
|
|
+ * (e.g. when a new connection is established, new data arrives, sent
|
|
+ * data is acknowledged, data needs to be retransmitted, etc.).
|
|
+ */
|
|
+void brcm_iscsi_appcall(struct uip_stack *ustack)
|
|
+{
|
|
+}
|
|
diff --git a/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h b/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h
|
|
new file mode 100644
|
|
index 0000000..10bfc95
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/apps/brcm-iscsi/brcm_iscsi.h
|
|
@@ -0,0 +1,91 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li <benli@broadcom.com>
|
|
+ * Based on code example from Adam Dunkels
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ */
|
|
+/**
|
|
+ * \addtogroup apps
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \defgroup helloworld Hello, world
|
|
+ * @{
|
|
+ *
|
|
+ * A small example showing how to write applications with
|
|
+ * \ref psock "protosockets".
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Header file for an example of how to write uIP applications
|
|
+ * with protosockets.
|
|
+ * \author
|
|
+ * Benjamin Li <benli@broadcom.com>
|
|
+ */
|
|
+
|
|
+#ifndef __BRCM_ISCSI_H__
|
|
+#define __BRCM_ISCSI_H__
|
|
+
|
|
+/* Since this file will be included by uip.h, we cannot include uip.h
|
|
+ here. But we might need to include uipopt.h if we need the u8_t and
|
|
+ u16_t datatypes. */
|
|
+#include "uipopt.h"
|
|
+#include "uip.h"
|
|
+#include "psock.h"
|
|
+
|
|
+/* Next, we define the hello_world_state structure. This is the state
|
|
+ of our application, and the memory required for this state is
|
|
+ allocated together with each TCP connection. One application state
|
|
+ for each TCP connection. */
|
|
+struct hello_world_state {
|
|
+ struct psock p;
|
|
+ u8_t inputbuffer[32];
|
|
+ u8_t name[40];
|
|
+
|
|
+ struct uip_udp_conn *conn;
|
|
+};
|
|
+
|
|
+/* Finally we define the application function to be called by uIP. */
|
|
+void brcm_iscsi_appcall(struct uip_stack *ustack);
|
|
+#ifndef UIP_APPCALL
|
|
+#define UIP_APPCALL brcm_iscsi_appcall
|
|
+#endif /* UIP_APPCALL */
|
|
+
|
|
+void brcm_iscsi_init(void);
|
|
+
|
|
+#endif /* __BRCM_ISCSI_H__ */
|
|
+/** @} */
|
|
+/** @} */
|
|
diff --git a/iscsiuio/src/apps/dhcpc/Makefile.am b/iscsiuio/src/apps/dhcpc/Makefile.am
|
|
new file mode 100644
|
|
index 0000000..1c97993
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/apps/dhcpc/Makefile.am
|
|
@@ -0,0 +1,13 @@
|
|
+AM_CFLAGS = -I${top_srcdir}/src/unix \
|
|
+ -I${top_srcdir}/src/uip \
|
|
+ -I${top_srcdir}/src/apps/dhcpc \
|
|
+ -I${top_srcdir}/src/apps/brcm-iscsi \
|
|
+ -I${top_srcdir}/../include \
|
|
+ -I${top_srcdir}/../usr
|
|
+
|
|
+noinst_LIBRARIES = lib_apps_dhcpc.a
|
|
+
|
|
+lib_apps_dhcpc_a_SOURCES = dhcpc.c dhcpv6.c
|
|
+
|
|
+lib_apps_dhcpc_a_CFLAGS = $(AM_CFLAGS) \
|
|
+ -DBYTE_ORDER=@ENDIAN@
|
|
diff --git a/iscsiuio/src/apps/dhcpc/Makefile.dhcpc b/iscsiuio/src/apps/dhcpc/Makefile.dhcpc
|
|
new file mode 100644
|
|
index 0000000..f84c84f
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/apps/dhcpc/Makefile.dhcpc
|
|
@@ -0,0 +1 @@
|
|
+APP_SOURCES += dhcpc.c timer.c
|
|
diff --git a/iscsiuio/src/apps/dhcpc/dhcpc.c b/iscsiuio/src/apps/dhcpc/dhcpc.c
|
|
new file mode 100644
|
|
index 0000000..f4a9994
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/apps/dhcpc/dhcpc.c
|
|
@@ -0,0 +1,417 @@
|
|
+/*
|
|
+ * Copyright (c) 2005, Swedish Institute of Computer Science
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <errno.h>
|
|
+#include <pthread.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <stdlib.h>
|
|
+#include <arpa/inet.h>
|
|
+
|
|
+#include "uip.h"
|
|
+#include "dhcpc.h"
|
|
+#include "timer.h"
|
|
+#include "pt.h"
|
|
+
|
|
+#include "debug.h"
|
|
+#include "logger.h"
|
|
+#include "nic.h"
|
|
+#include "nic_utils.h"
|
|
+
|
|
+struct __attribute__ ((__packed__)) dhcp_msg {
|
|
+ u8_t op, htype, hlen, hops;
|
|
+ u8_t xid[4];
|
|
+ u16_t secs, flags;
|
|
+ u8_t ciaddr[4];
|
|
+ u8_t yiaddr[4];
|
|
+ u8_t siaddr[4];
|
|
+ u8_t giaddr[4];
|
|
+ u8_t chaddr[16];
|
|
+#ifndef UIP_CONF_DHCP_LIGHT
|
|
+ u8_t sname[64];
|
|
+ u8_t file[128];
|
|
+#endif
|
|
+ u8_t options[312];
|
|
+};
|
|
+
|
|
+#define BOOTP_BROADCAST 0x8000
|
|
+
|
|
+#define DHCP_REQUEST 1
|
|
+#define DHCP_REPLY 2
|
|
+#define DHCP_HTYPE_ETHERNET 1
|
|
+#define DHCP_HLEN_ETHERNET 6
|
|
+#define DHCP_MSG_LEN 236
|
|
+
|
|
+#define DHCPC_SERVER_PORT 67
|
|
+#define DHCPC_CLIENT_PORT 68
|
|
+
|
|
+#define DHCPDISCOVER 1
|
|
+#define DHCPOFFER 2
|
|
+#define DHCPREQUEST 3
|
|
+#define DHCPDECLINE 4
|
|
+#define DHCPACK 5
|
|
+#define DHCPNAK 6
|
|
+#define DHCPRELEASE 7
|
|
+
|
|
+#define DHCP_OPTION_SUBNET_MASK 1
|
|
+#define DHCP_OPTION_ROUTER 3
|
|
+#define DHCP_OPTION_DNS_SERVER 6
|
|
+#define DHCP_OPTION_REQ_IPADDR 50
|
|
+#define DHCP_OPTION_LEASE_TIME 51
|
|
+#define DHCP_OPTION_MSG_TYPE 53
|
|
+#define DHCP_OPTION_SERVER_ID 54
|
|
+#define DHCP_OPTION_REQ_LIST 55
|
|
+#define DHCP_OPTION_END 255
|
|
+
|
|
+static u8_t xid[4] = { 0xad, 0xde, 0x12, 0x23 };
|
|
+static const u8_t magic_cookie[4] = { 99, 130, 83, 99 };
|
|
+
|
|
+struct dhcpc_options dhcpc_opt = {
|
|
+ .enable_random_xid = 1,
|
|
+};
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static u8_t *add_msg_type(u8_t *optptr, u8_t type)
|
|
+{
|
|
+ *optptr++ = DHCP_OPTION_MSG_TYPE;
|
|
+ *optptr++ = 1;
|
|
+ *optptr++ = type;
|
|
+ return optptr;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static u8_t *add_server_id(struct dhcpc_state *s, u8_t *optptr)
|
|
+{
|
|
+ *optptr++ = DHCP_OPTION_SERVER_ID;
|
|
+ *optptr++ = 4;
|
|
+ memcpy(optptr, s->serverid, 4);
|
|
+ return optptr + 4;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static u8_t *add_req_ipaddr(struct dhcpc_state *s, u8_t *optptr)
|
|
+{
|
|
+ *optptr++ = DHCP_OPTION_REQ_IPADDR;
|
|
+ *optptr++ = 4;
|
|
+ memcpy(optptr, s->ipaddr, 4);
|
|
+ return optptr + 4;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static u8_t *add_req_options(u8_t *optptr)
|
|
+{
|
|
+ *optptr++ = DHCP_OPTION_REQ_LIST;
|
|
+ *optptr++ = 3;
|
|
+ *optptr++ = DHCP_OPTION_SUBNET_MASK;
|
|
+ *optptr++ = DHCP_OPTION_ROUTER;
|
|
+ *optptr++ = DHCP_OPTION_DNS_SERVER;
|
|
+ return optptr;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static u8_t *add_end(u8_t *optptr)
|
|
+{
|
|
+ *optptr++ = DHCP_OPTION_END;
|
|
+ return optptr;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static void create_msg(struct dhcpc_state *s, struct dhcp_msg *m)
|
|
+{
|
|
+ m->op = DHCP_REQUEST;
|
|
+ m->htype = DHCP_HTYPE_ETHERNET;
|
|
+ m->hlen = s->mac_len;
|
|
+ m->hops = 0;
|
|
+ memcpy(m->xid, xid, sizeof(m->xid));
|
|
+ m->secs = 0;
|
|
+ m->flags = const_htons(BOOTP_BROADCAST); /* Broadcast bit. */
|
|
+ /* uip_ipaddr_copy(m->ciaddr, uip_hostaddr); */
|
|
+ memcpy(m->ciaddr, s->ustack->hostaddr, sizeof(m->ciaddr));
|
|
+ memset(m->yiaddr, 0, sizeof(m->yiaddr));
|
|
+ memset(m->siaddr, 0, sizeof(m->siaddr));
|
|
+ memset(m->giaddr, 0, sizeof(m->giaddr));
|
|
+ memcpy(m->chaddr, s->mac_addr, s->mac_len);
|
|
+ memset(&m->chaddr[s->mac_len], 0, sizeof(m->chaddr) - s->mac_len);
|
|
+#ifndef UIP_CONF_DHCP_LIGHT
|
|
+ memset(m->sname, 0, sizeof(m->sname));
|
|
+ memset(m->file, 0, sizeof(m->file));
|
|
+#endif
|
|
+
|
|
+ memcpy(m->options, magic_cookie, sizeof(magic_cookie));
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static void send_discover(struct dhcpc_state *s)
|
|
+{
|
|
+ u8_t *end;
|
|
+ struct dhcp_msg *m = (struct dhcp_msg *)s->ustack->uip_appdata;
|
|
+
|
|
+ create_msg(s, m);
|
|
+
|
|
+ end = add_msg_type(&m->options[4], DHCPDISCOVER);
|
|
+ end = add_req_options(end);
|
|
+ end = add_end(end);
|
|
+
|
|
+ uip_appsend(s->ustack, s->ustack->uip_appdata,
|
|
+ end - (u8_t *) s->ustack->uip_appdata);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static void send_request(struct dhcpc_state *s)
|
|
+{
|
|
+ u8_t *end;
|
|
+ struct dhcp_msg *m = (struct dhcp_msg *)s->ustack->uip_appdata;
|
|
+
|
|
+ create_msg(s, m);
|
|
+
|
|
+ end = add_msg_type(&m->options[4], DHCPREQUEST);
|
|
+ end = add_server_id(s, end);
|
|
+ end = add_req_ipaddr(s, end);
|
|
+ end = add_end(end);
|
|
+
|
|
+ uip_appsend(s->ustack, s->ustack->uip_appdata,
|
|
+ end - (u8_t *) s->ustack->uip_appdata);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static u8_t parse_options(struct dhcpc_state *s, u8_t *optptr, int len)
|
|
+{
|
|
+ u8_t *end = optptr + len;
|
|
+ u8_t type = 0;
|
|
+
|
|
+ while (optptr < end) {
|
|
+ switch (*optptr) {
|
|
+ case DHCP_OPTION_SUBNET_MASK:
|
|
+ memcpy(s->netmask, optptr + 2, 4);
|
|
+ break;
|
|
+ case DHCP_OPTION_ROUTER:
|
|
+ memcpy(s->default_router, optptr + 2, 4);
|
|
+ break;
|
|
+ case DHCP_OPTION_DNS_SERVER:
|
|
+ memcpy(s->dnsaddr, optptr + 2, 4);
|
|
+ break;
|
|
+ case DHCP_OPTION_MSG_TYPE:
|
|
+ type = *(optptr + 2);
|
|
+ break;
|
|
+ case DHCP_OPTION_SERVER_ID:
|
|
+ memcpy(s->serverid, optptr + 2, 4);
|
|
+ break;
|
|
+ case DHCP_OPTION_LEASE_TIME:
|
|
+ memcpy(s->lease_time, optptr + 2, 4);
|
|
+ break;
|
|
+ case DHCP_OPTION_END:
|
|
+ return type;
|
|
+ }
|
|
+
|
|
+ optptr += optptr[1] + 2;
|
|
+ }
|
|
+ return type;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static u8_t parse_msg(struct dhcpc_state *s)
|
|
+{
|
|
+ struct dhcp_msg *m = (struct dhcp_msg *)s->ustack->uip_appdata;
|
|
+
|
|
+ if (m->op == DHCP_REPLY &&
|
|
+ memcmp(m->xid, xid, sizeof(xid)) == 0 &&
|
|
+ memcmp(m->chaddr, s->mac_addr, s->mac_len) == 0) {
|
|
+ memcpy(s->ipaddr, m->yiaddr, 4);
|
|
+ return parse_options(s, &m->options[4], uip_datalen(s->ustack));
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static PT_THREAD(handle_dhcp(struct uip_stack *ustack))
|
|
+{
|
|
+ struct dhcpc_state *s;
|
|
+ s = ustack->dhcpc;
|
|
+
|
|
+ if (s == NULL) {
|
|
+ LOG_WARN("Could not find dhcpc state");
|
|
+ return PT_ENDED;
|
|
+ }
|
|
+
|
|
+ PT_BEGIN(&s->pt);
|
|
+
|
|
+ /* try_again: */
|
|
+ s->state = STATE_SENDING;
|
|
+ s->ticks = CLOCK_SECOND;
|
|
+
|
|
+ do {
|
|
+ send_discover(s);
|
|
+ timer_set(&s->timer, s->ticks);
|
|
+ PT_WAIT_UNTIL(&s->pt, uip_newdata(s->ustack)
|
|
+ || timer_expired(&s->timer));
|
|
+
|
|
+ if (uip_newdata(s->ustack) && parse_msg(s) == DHCPOFFER) {
|
|
+ s->state = STATE_OFFER_RECEIVED;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (s->ticks < CLOCK_SECOND * 60)
|
|
+ s->ticks += CLOCK_SECOND;
|
|
+ else
|
|
+ PT_RESTART(&s->pt);
|
|
+ } while (s->state != STATE_OFFER_RECEIVED);
|
|
+
|
|
+ s->ticks = CLOCK_SECOND;
|
|
+
|
|
+ do {
|
|
+ send_request(s);
|
|
+ timer_set(&s->timer, s->ticks);
|
|
+ s->ustack->uip_flags &= ~UIP_NEWDATA;
|
|
+ PT_WAIT_UNTIL(&s->pt, uip_newdata(s->ustack)
|
|
+ || timer_expired(&s->timer));
|
|
+
|
|
+ if (uip_newdata(s->ustack) && parse_msg(s) == DHCPACK) {
|
|
+ s->state = STATE_CONFIG_RECEIVED;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (s->ticks <= CLOCK_SECOND * 10)
|
|
+ s->ticks += CLOCK_SECOND;
|
|
+ else
|
|
+ PT_RESTART(&s->pt);
|
|
+ } while (s->state != STATE_CONFIG_RECEIVED);
|
|
+
|
|
+ LOG_INFO("Got IP address %d.%d.%d.%d",
|
|
+ uip_ipaddr1(s->ipaddr), uip_ipaddr2(s->ipaddr),
|
|
+ uip_ipaddr3(s->ipaddr), uip_ipaddr4(s->ipaddr));
|
|
+ LOG_INFO("Got netmask %d.%d.%d.%d",
|
|
+ uip_ipaddr1(s->netmask), uip_ipaddr2(s->netmask),
|
|
+ uip_ipaddr3(s->netmask), uip_ipaddr4(s->netmask));
|
|
+ LOG_INFO("Got DNS server %d.%d.%d.%d",
|
|
+ uip_ipaddr1(s->dnsaddr), uip_ipaddr2(s->dnsaddr),
|
|
+ uip_ipaddr3(s->dnsaddr), uip_ipaddr4(s->dnsaddr));
|
|
+ LOG_INFO("Got default router %d.%d.%d.%d",
|
|
+ uip_ipaddr1(s->default_router), uip_ipaddr2(s->default_router),
|
|
+ uip_ipaddr3(s->default_router),
|
|
+ uip_ipaddr4(s->default_router));
|
|
+ s->lease_time_nl32 =
|
|
+ ntohs(s->lease_time[0]) * 65536ul + ntohs(s->lease_time[1]);
|
|
+ LOG_INFO("Lease expires in %ld seconds", s->lease_time_nl32);
|
|
+
|
|
+ s->last_update = time(NULL);
|
|
+
|
|
+ set_uip_stack(s->ustack,
|
|
+ (uip_ip4addr_t *) s->ipaddr,
|
|
+ (uip_ip4addr_t *) s->netmask,
|
|
+ (uip_ip4addr_t *) s->default_router,
|
|
+ (uint8_t *) s->mac_addr);
|
|
+
|
|
+ /* Put the stack thread back into a long sleep */
|
|
+ s->nic->flags |= NIC_LONG_SLEEP;
|
|
+
|
|
+ /* timer_stop(&s.timer); */
|
|
+
|
|
+ /* Handle DHCP lease expiration */
|
|
+ s->ticks = CLOCK_SECOND * s->lease_time_nl32;
|
|
+ timer_set(&s->timer, s->ticks);
|
|
+ PT_WAIT_UNTIL(&s->pt, timer_expired(&s->timer));
|
|
+ LOG_INFO("Lease expired, re-acquire IP address");
|
|
+ s->nic->flags &= ~NIC_LONG_SLEEP;
|
|
+ PT_RESTART(&s->pt);
|
|
+
|
|
+ /*
|
|
+ * PT_END restarts the thread so we do this instead. Eventually we
|
|
+ * should reacquire expired leases here.
|
|
+ */
|
|
+
|
|
+ while (1)
|
|
+ PT_YIELD(&s->pt);
|
|
+
|
|
+ PT_END(&(s->pt));
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+int dhcpc_init(nic_t *nic, struct uip_stack *ustack,
|
|
+ const void *mac_addr, int mac_len)
|
|
+{
|
|
+ uip_ip4addr_t addr;
|
|
+ struct dhcpc_state *s = ustack->dhcpc;
|
|
+
|
|
+ if (s) {
|
|
+ LOG_DEBUG("DHCP: DHCP context already allocated");
|
|
+ return -EALREADY;
|
|
+ }
|
|
+ s = malloc(sizeof(*s));
|
|
+ if (s == NULL) {
|
|
+ LOG_ERR("Couldn't allocate size for dhcpc info");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ memset(s, 0, sizeof(*s));
|
|
+ s->nic = nic;
|
|
+ s->ustack = ustack;
|
|
+ s->mac_addr = mac_addr;
|
|
+ s->mac_len = mac_len;
|
|
+ s->state = STATE_INITIAL;
|
|
+
|
|
+ /* Initialize XID to randomly */
|
|
+ if (dhcpc_opt.enable_random_xid == 1) {
|
|
+ u32_t gen_xid;
|
|
+ gen_xid = random();
|
|
+ memcpy(xid, &gen_xid, sizeof(gen_xid));
|
|
+ }
|
|
+ uip_ipaddr(addr, 255, 255, 255, 255);
|
|
+ s->conn = uip_udp_new(ustack, &addr, const_htons(DHCPC_SERVER_PORT));
|
|
+ if (s->conn != NULL)
|
|
+ uip_udp_bind(s->conn, const_htons(DHCPC_CLIENT_PORT));
|
|
+
|
|
+ ustack->dhcpc = s;
|
|
+
|
|
+ /* Let the RX poll value take over */
|
|
+ nic->flags &= ~NIC_LONG_SLEEP;
|
|
+
|
|
+ PT_INIT(&s->pt);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+void dhcpc_appcall(struct uip_stack *ustack)
|
|
+{
|
|
+ handle_dhcp(ustack);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+void dhcpc_request(struct uip_stack *ustack)
|
|
+{
|
|
+ struct dhcpc_state *s = ustack->dhcpc;
|
|
+
|
|
+ if (s != NULL && s->state == STATE_INITIAL)
|
|
+ handle_dhcp(ustack);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
diff --git a/iscsiuio/src/apps/dhcpc/dhcpc.h b/iscsiuio/src/apps/dhcpc/dhcpc.h
|
|
new file mode 100644
|
|
index 0000000..89cf086
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/apps/dhcpc/dhcpc.h
|
|
@@ -0,0 +1,86 @@
|
|
+/*
|
|
+ * Copyright (c) 2005, Swedish Institute of Computer Science
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ */
|
|
+#ifndef __DHCPC_H__
|
|
+#define __DHCPC_H__
|
|
+
|
|
+#include <time.h>
|
|
+
|
|
+#include "nic.h"
|
|
+#include "timer.h"
|
|
+#include "pt.h"
|
|
+#include "uip.h"
|
|
+
|
|
+#define STATE_INITIAL 0
|
|
+#define STATE_SENDING 1
|
|
+#define STATE_OFFER_RECEIVED 2
|
|
+#define STATE_CONFIG_RECEIVED 3
|
|
+
|
|
+struct dhcpc_state {
|
|
+ struct pt pt;
|
|
+
|
|
+ nic_t *nic;
|
|
+ struct uip_stack *ustack;
|
|
+ char state;
|
|
+ struct uip_udp_conn *conn;
|
|
+ struct timer timer;
|
|
+ u32_t ticks;
|
|
+ const void *mac_addr;
|
|
+ int mac_len;
|
|
+
|
|
+ u8_t serverid[4];
|
|
+
|
|
+ u16_t lease_time[2];
|
|
+ u32_t lease_time_nl32;
|
|
+ u16_t ipaddr[2];
|
|
+ u16_t netmask[2];
|
|
+ u16_t dnsaddr[2];
|
|
+ u16_t default_router[2];
|
|
+
|
|
+ time_t last_update;
|
|
+};
|
|
+
|
|
+struct dhcpc_options {
|
|
+ u8_t enable_random_xid;
|
|
+ u8_t xid[4];
|
|
+};
|
|
+
|
|
+int dhcpc_init(nic_t *nic, struct uip_stack *ustack,
|
|
+ const void *mac_addr, int mac_len);
|
|
+void dhcpc_request(struct uip_stack *ustack);
|
|
+
|
|
+void dhcpc_appcall(struct uip_stack *ustack);
|
|
+
|
|
+void dhcpc_configured(const struct dhcpc_state *s);
|
|
+
|
|
+#define UIP_UDP_APPCALL dhcpc_appcall
|
|
+
|
|
+#endif /* __DHCPC_H__ */
|
|
diff --git a/iscsiuio/src/apps/dhcpc/dhcpv6.c b/iscsiuio/src/apps/dhcpc/dhcpv6.c
|
|
new file mode 100644
|
|
index 0000000..a4e25f0
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/apps/dhcpc/dhcpv6.c
|
|
@@ -0,0 +1,512 @@
|
|
+/*
|
|
+ * Copyright (c) 2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Eddie Wai <eddie.wai@broadcom.com>
|
|
+ * Based on code from Kevin Tran's iSCSI boot code
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * dhcpv6.c - DHCPv6 engine
|
|
+ *
|
|
+ */
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include "ipv6.h"
|
|
+#include "ipv6_pkt.h"
|
|
+#include "dhcpv6.h"
|
|
+#include "logger.h"
|
|
+
|
|
+/* Local function prototypes */
|
|
+static int dhcpv6_send_solicit_packet(struct dhcpv6_context *context);
|
|
+static int dhcpv6_send_request_packet(struct dhcpv6_context *context);
|
|
+static u16_t dhcpv6_init_packet(struct dhcpv6_context *context, u8_t type);
|
|
+static void dhcpv6_init_dhcpv6_server_addr(struct ipv6_addr *addr);
|
|
+static void dhcpv6_handle_advertise(struct dhcpv6_context *context,
|
|
+ u16_t dhcpv6_len);
|
|
+static void dhcpv6_handle_reply(struct dhcpv6_context *context,
|
|
+ u16_t dhcpv6_len);
|
|
+static int dhcpv6_process_opt_ia_na(struct dhcpv6_context *context,
|
|
+ struct dhcpv6_opt_hdr *opt_hdr);
|
|
+static void dhcpv6_process_opt_dns_servers(struct dhcpv6_context *context,
|
|
+ struct dhcpv6_opt_hdr *opt_hdr);
|
|
+static void dhcpv6_parse_vendor_option(struct dhcpv6_context *context,
|
|
+ u8_t *option, int len);
|
|
+
|
|
+void dhcpv6_init(struct dhcpv6_context *context)
|
|
+{
|
|
+ context->seconds = 0;
|
|
+ context->our_mac_addr =
|
|
+ ipv6_get_link_addr(context->ipv6_context);
|
|
+
|
|
+ /* Use the last four bytes of MAC address as base of the transaction
|
|
+ ID */
|
|
+ context->dhcpv6_transaction_id = context->our_mac_addr->last_4_bytes;
|
|
+
|
|
+ context->dhcpv6_done = FALSE;
|
|
+ strcpy(context->dhcp_vendor_id, "BRCM ISAN");
|
|
+}
|
|
+
|
|
+int dhcpv6_do_discovery(struct dhcpv6_context *context)
|
|
+{
|
|
+ int retc = ISCSI_FAILURE;
|
|
+
|
|
+ context->eth =
|
|
+ (struct eth_hdr *)context->ipv6_context->ustack->data_link_layer;
|
|
+ context->ipv6 =
|
|
+ (struct ipv6_hdr *)context->ipv6_context->ustack->network_layer;
|
|
+ context->udp =
|
|
+ (struct udp_hdr *)((u8_t *)context->ipv6 + sizeof(struct ipv6_hdr));
|
|
+
|
|
+ /* Send out DHCPv6 Solicit packet. */
|
|
+ dhcpv6_send_solicit_packet(context);
|
|
+
|
|
+ return retc;
|
|
+}
|
|
+
|
|
+static int dhcpv6_send_solicit_packet(struct dhcpv6_context *context)
|
|
+{
|
|
+ u16_t packet_len;
|
|
+
|
|
+ LOG_DEBUG("DHCPV6: Send solicit");
|
|
+ packet_len = dhcpv6_init_packet(context, DHCPV6_SOLICIT);
|
|
+ context->dhcpv6_state = DHCPV6_STATE_SOLICIT_SENT;
|
|
+ ipv6_send_udp_packet(context->ipv6_context, packet_len);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int dhcpv6_send_request_packet(struct dhcpv6_context *context)
|
|
+{
|
|
+ u16_t packet_len;
|
|
+
|
|
+ LOG_DEBUG("DHCPV6: Send request");
|
|
+ packet_len = dhcpv6_init_packet(context, DHCPV6_REQUEST);
|
|
+
|
|
+ context->dhcpv6_state = DHCPV6_STATE_REQ_SENT;
|
|
+ ipv6_send_udp_packet(context->ipv6_context, packet_len);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static u16_t dhcpv6_init_packet(struct dhcpv6_context *context, u8_t type)
|
|
+{
|
|
+ u16_t pkt_len;
|
|
+ struct udp_hdr *udp = context->udp;
|
|
+ union dhcpv6_hdr *dhcpv6;
|
|
+ struct dhcpv6_option *opt;
|
|
+ u16_t len;
|
|
+
|
|
+ /* Initialize dest IP with well-known DHCP server address */
|
|
+ dhcpv6_init_dhcpv6_server_addr(&context->ipv6->ipv6_dst);
|
|
+ /* Initialize dest MAC based on MC dest IP */
|
|
+ ipv6_mc_init_dest_mac(context->eth, context->ipv6);
|
|
+
|
|
+ /* Initialize UDP header */
|
|
+ udp->src_port = HOST_TO_NET16(DHCPV6_CLIENT_PORT);
|
|
+ udp->dest_port = HOST_TO_NET16(DHCPV6_SERVER_PORT);
|
|
+
|
|
+ /*
|
|
+ * DHCPv6 section has the following format per RFC 3315
|
|
+ *
|
|
+ * 0 1 2 3
|
|
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ * | msg-type | transaction-id |
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ * | |
|
|
+ * . options .
|
|
+ * . (variable) .
|
|
+ * | |
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ */
|
|
+ dhcpv6 = (union dhcpv6_hdr *)((u8_t *)udp + sizeof(struct udp_hdr));
|
|
+
|
|
+ if (dhcpv6->dhcpv6_type != type)
|
|
+ context->dhcpv6_transaction_id++;
|
|
+
|
|
+ dhcpv6->dhcpv6_trans_id = context->dhcpv6_transaction_id;
|
|
+ dhcpv6->dhcpv6_type = type;
|
|
+
|
|
+ /* Keep track of length of all DHCP options. */
|
|
+ pkt_len = sizeof(union dhcpv6_hdr);
|
|
+
|
|
+ if (dhcpv6->dhcpv6_type == DHCPV6_REQUEST) {
|
|
+ /* We will send back whatever DHCPv6 sent us */
|
|
+ return ((u8_t *)udp - (u8_t *)context->eth +
|
|
+ NET_TO_HOST16(udp->length));
|
|
+ }
|
|
+
|
|
+ opt = (struct dhcpv6_option *)((u8_t *)dhcpv6 +
|
|
+ sizeof(union dhcpv6_hdr));
|
|
+ /* Add client ID option */
|
|
+ opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_CLIENTID);
|
|
+ opt->hdr.length = HOST_TO_NET16(sizeof(struct dhcpv6_opt_client_id));
|
|
+ opt->type.client_id.duid_type =
|
|
+ HOST_TO_NET16(DHCPV6_DUID_TYPE_LINK_LAYER_AND_TIME);
|
|
+ opt->type.client_id.hw_type = HOST_TO_NET16(DHCPV6_HW_TYPE_ETHERNET);
|
|
+ opt->type.client_id.time = HOST_TO_NET32(clock_time()/1000 -
|
|
+ 0x3A4FC880);
|
|
+ memcpy((char *)&opt->type.client_id.link_layer_addr,
|
|
+ (char *)context->our_mac_addr, sizeof(struct mac_address));
|
|
+ pkt_len += sizeof(struct dhcpv6_opt_client_id) +
|
|
+ sizeof(struct dhcpv6_opt_hdr);
|
|
+ opt = (struct dhcpv6_option *)((u8_t *)opt +
|
|
+ sizeof(struct dhcpv6_opt_client_id) +
|
|
+ sizeof(struct dhcpv6_opt_hdr));
|
|
+
|
|
+ /* Add Vendor Class option if it's configured */
|
|
+ len = strlen(context->dhcp_vendor_id);
|
|
+ if (len > 0) {
|
|
+ opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_VENDOR_CLASS);
|
|
+ opt->hdr.length =
|
|
+ HOST_TO_NET16(sizeof(struct dhcpv6_vendor_class)
|
|
+ + len - 1);
|
|
+ opt->type.vendor_class.enterprise_number =
|
|
+ HOST_TO_NET32(IANA_ENTERPRISE_NUM_BROADCOM);
|
|
+ opt->type.vendor_class.vendor_class_length = HOST_TO_NET16(len);
|
|
+ memcpy((char *)&opt->type.vendor_class.
|
|
+ vendor_class_data[0],
|
|
+ (char *)context->dhcp_vendor_id, len);
|
|
+ pkt_len +=
|
|
+ sizeof(struct dhcpv6_vendor_class) - 1 + len +
|
|
+ sizeof(struct dhcpv6_opt_hdr);
|
|
+ opt =
|
|
+ (struct dhcpv6_option *)((u8_t *)opt +
|
|
+ sizeof(struct dhcpv6_vendor_class) - 1 + len +
|
|
+ sizeof(struct dhcpv6_opt_hdr));
|
|
+ }
|
|
+
|
|
+ /* Add IA_NA option */
|
|
+ opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_IA_NA);
|
|
+ opt->hdr.length = HOST_TO_NET16(sizeof(struct dhcpv6_opt_id_assoc_na));
|
|
+ opt->type.ida_na.iaid = htonl(context->our_mac_addr->last_4_bytes);
|
|
+ opt->type.ida_na.t1 = 0;
|
|
+ opt->type.ida_na.t2 = 0;
|
|
+ pkt_len += sizeof(struct dhcpv6_opt_id_assoc_na) +
|
|
+ sizeof(struct dhcpv6_opt_hdr);
|
|
+ opt = (struct dhcpv6_option *)((u8_t *)opt +
|
|
+ sizeof(struct dhcpv6_opt_id_assoc_na) +
|
|
+ sizeof(struct dhcpv6_opt_hdr));
|
|
+ /* Add Elapsed Time option */
|
|
+ opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_ELAPSED_TIME);
|
|
+ opt->hdr.length = HOST_TO_NET16(sizeof(struct dhcpv6_opt_elapse_time));
|
|
+ opt->type.elapsed_time.time = HOST_TO_NET16(context->seconds);
|
|
+ pkt_len += sizeof(struct dhcpv6_opt_elapse_time) +
|
|
+ sizeof(struct dhcpv6_opt_hdr);
|
|
+
|
|
+ /* Add Option Request List */
|
|
+ opt = (struct dhcpv6_option *)((u8_t *)opt +
|
|
+ sizeof(struct dhcpv6_opt_elapse_time) +
|
|
+ sizeof(struct dhcpv6_opt_hdr));
|
|
+ opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_ORO);
|
|
+ opt->hdr.length = HOST_TO_NET16(3 *
|
|
+ sizeof(struct dhcpv6_opt_request_list));
|
|
+ opt->type.list.request_code[0] = HOST_TO_NET16(DHCPV6_OPT_VENDOR_CLASS);
|
|
+ opt->type.list.request_code[1] = HOST_TO_NET16(DHCPV6_OPT_VENDOR_OPTS);
|
|
+ opt->type.list.request_code[2] = HOST_TO_NET16(DHCPV6_OPT_DNS_SERVERS);
|
|
+ pkt_len += 3 * sizeof(struct dhcpv6_opt_request_list) +
|
|
+ sizeof(struct dhcpv6_opt_hdr);
|
|
+
|
|
+ udp->length = HOST_TO_NET16(sizeof(struct udp_hdr) + pkt_len);
|
|
+
|
|
+ pkt_len +=
|
|
+ ((u8_t *)udp - (u8_t *)context->eth) + sizeof(struct udp_hdr);
|
|
+
|
|
+ return pkt_len;
|
|
+}
|
|
+
|
|
+static void dhcpv6_init_dhcpv6_server_addr(struct ipv6_addr *addr)
|
|
+{
|
|
+ /* Well-known DHCPv6 server address is ff02::1:2 */
|
|
+ memset((char *)addr, 0, sizeof(struct ipv6_addr));
|
|
+ addr->addr8[0] = 0xff;
|
|
+ addr->addr8[1] = 0x02;
|
|
+ addr->addr8[13] = 0x01;
|
|
+ addr->addr8[15] = 0x02;
|
|
+}
|
|
+
|
|
+void ipv6_udp_handle_dhcp(struct dhcpv6_context *context)
|
|
+{
|
|
+ union dhcpv6_hdr *dhcpv6;
|
|
+ u16_t dhcpv6_len;
|
|
+
|
|
+ if (context->dhcpv6_done == TRUE)
|
|
+ return;
|
|
+
|
|
+ dhcpv6 = (union dhcpv6_hdr *)((u8_t *)context->udp +
|
|
+ sizeof(struct udp_hdr));
|
|
+
|
|
+ if (dhcpv6->dhcpv6_trans_id != context->dhcpv6_transaction_id)
|
|
+ return;
|
|
+
|
|
+ dhcpv6_len =
|
|
+ NET_TO_HOST16(context->udp->length) - sizeof(struct udp_hdr);
|
|
+
|
|
+ switch (dhcpv6->dhcpv6_type) {
|
|
+ case DHCPV6_ADVERTISE:
|
|
+ dhcpv6_handle_advertise(context, dhcpv6_len);
|
|
+ break;
|
|
+
|
|
+ case DHCPV6_REPLY:
|
|
+ dhcpv6_handle_reply(context, dhcpv6_len);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void dhcpv6_handle_advertise(struct dhcpv6_context *context,
|
|
+ u16_t dhcpv6_len)
|
|
+{
|
|
+ union dhcpv6_hdr *dhcpv6 =
|
|
+ (union dhcpv6_hdr *)((u8_t *)context->udp +
|
|
+ sizeof(struct udp_hdr));
|
|
+ struct dhcpv6_opt_hdr *opt;
|
|
+ u16_t type;
|
|
+ int i;
|
|
+ int opt_len;
|
|
+ u8_t *vendor_id = NULL;
|
|
+ u16_t vendor_id_len = 0;
|
|
+ u8_t *vendor_opt_data = NULL;
|
|
+ int vendor_opt_len = 0;
|
|
+ int addr_cnt = 0;
|
|
+
|
|
+ /* We only handle DHCPv6 advertise if we recently sent DHCPv6 solicit */
|
|
+ if (context->dhcpv6_state != DHCPV6_STATE_SOLICIT_SENT)
|
|
+ return;
|
|
+
|
|
+ LOG_DEBUG("DHCPV6: handle advertise");
|
|
+ context->dhcpv6_state = DHCPV6_STATE_ADV_RCVD;
|
|
+
|
|
+ i = 0;
|
|
+ while (i < (dhcpv6_len - sizeof(union dhcpv6_hdr))) {
|
|
+ opt = (struct dhcpv6_opt_hdr *)((u8_t *)dhcpv6 +
|
|
+ sizeof(union dhcpv6_hdr) + i);
|
|
+ opt_len = NET_TO_HOST16(opt->length);
|
|
+
|
|
+ type = NET_TO_HOST16(opt->type);
|
|
+
|
|
+ /* We only care about some of the options */
|
|
+ switch (type) {
|
|
+ case DHCPV6_OPT_IA_NA:
|
|
+ if (context->
|
|
+ dhcpv6_task & DHCPV6_TASK_GET_IP_ADDRESS) {
|
|
+ addr_cnt +=
|
|
+ dhcpv6_process_opt_ia_na(context, opt);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case DHCPV6_OPT_VENDOR_CLASS:
|
|
+ vendor_id_len =
|
|
+ NET_TO_HOST16(((struct dhcpv6_option *)opt)->type.
|
|
+ vendor_class.vendor_class_length);
|
|
+ vendor_id =
|
|
+ &((struct dhcpv6_option *)opt)->type.vendor_class.
|
|
+ vendor_class_data[0];
|
|
+ break;
|
|
+
|
|
+ case DHCPV6_OPT_VENDOR_OPTS:
|
|
+ vendor_opt_len = opt_len - 4;
|
|
+ vendor_opt_data =
|
|
+ &((struct dhcpv6_option *)opt)->type.vendor_opts.
|
|
+ vendor_opt_data[0];
|
|
+ break;
|
|
+
|
|
+ case DHCPV6_OPT_DNS_SERVERS:
|
|
+ if (context->dhcpv6_task & DHCPV6_TASK_GET_OTHER_PARAMS)
|
|
+ dhcpv6_process_opt_dns_servers(context, opt);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ i += NET_TO_HOST16(opt->length) + sizeof(struct dhcpv6_opt_hdr);
|
|
+ }
|
|
+
|
|
+ if (context->dhcpv6_task & DHCPV6_TASK_GET_OTHER_PARAMS) {
|
|
+ if ((vendor_id_len > 0) &&
|
|
+ (strncmp((char *)vendor_id,
|
|
+ (char *)context->dhcp_vendor_id,
|
|
+ vendor_id_len) == 0)) {
|
|
+ dhcpv6_parse_vendor_option(context,
|
|
+ vendor_opt_data,
|
|
+ vendor_opt_len);
|
|
+ context->dhcpv6_done = TRUE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (context->dhcpv6_task & DHCPV6_TASK_GET_IP_ADDRESS) {
|
|
+ if (addr_cnt > 0) {
|
|
+ /*
|
|
+ * If we need to acquire IP address from the server,
|
|
+ * we need to send Request to server to confirm.
|
|
+ */
|
|
+ dhcpv6_send_request_packet(context);
|
|
+ context->dhcpv6_done = TRUE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (context->dhcpv6_done) {
|
|
+ /* Keep track of IPv6 address of DHCHv6 server */
|
|
+ memcpy((char *)&context->dhcp_server,
|
|
+ (char *)&context->ipv6->ipv6_src,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ }
|
|
+}
|
|
+
|
|
+static int dhcpv6_process_opt_ia_na(struct dhcpv6_context *context,
|
|
+ struct dhcpv6_opt_hdr *opt_hdr)
|
|
+{
|
|
+ int i;
|
|
+ int opt_len;
|
|
+ struct dhcpv6_option *opt;
|
|
+ int len;
|
|
+ int addr_cnt;
|
|
+ opt_len = NET_TO_HOST16(opt_hdr->length) -
|
|
+ sizeof(struct dhcpv6_opt_id_assoc_na);
|
|
+
|
|
+ i = 0;
|
|
+ addr_cnt = 0;
|
|
+ while (i < opt_len) {
|
|
+ opt =
|
|
+ (struct dhcpv6_option *)((u8_t *)opt_hdr +
|
|
+ sizeof(struct dhcpv6_opt_hdr) +
|
|
+ sizeof(struct dhcpv6_opt_id_assoc_na) + i);
|
|
+
|
|
+ len = NET_TO_HOST16(opt->hdr.length);
|
|
+ switch (NET_TO_HOST16(opt->hdr.type)) {
|
|
+ case DHCPV6_OPT_IAADDR:
|
|
+ if (len >
|
|
+ (sizeof(struct dhcpv6_opt_hdr) +
|
|
+ sizeof(struct dhcpv6_opt_iaa_addr))) {
|
|
+ struct dhcpv6_option *in_opt;
|
|
+
|
|
+ in_opt = (struct dhcpv6_option *)((u8_t *)opt +
|
|
+ sizeof(struct dhcpv6_opt_hdr) +
|
|
+ sizeof(struct dhcpv6_opt_iaa_addr));
|
|
+ if (in_opt->hdr.type ==
|
|
+ HOST_TO_NET16(DHCPV6_OPT_STATUS_CODE)) {
|
|
+ /* This entry has error! */
|
|
+ if (in_opt->type.sts.status != 0)
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ LOG_INFO("DHCPv6: Got IP Addr");
|
|
+ /* Status is OK, let's add this addr to our address
|
|
+ list */
|
|
+ ipv6_add_prefix_entry(context->ipv6_context,
|
|
+ &opt->type.iaa_addr.addr, 64);
|
|
+
|
|
+ /* Add multicast address for this address */
|
|
+ ipv6_add_solit_node_address(context->
|
|
+ ipv6_context,
|
|
+ &opt->type.iaa_addr.addr);
|
|
+ addr_cnt++;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ i += len + sizeof(struct dhcpv6_opt_hdr);
|
|
+ }
|
|
+
|
|
+ return addr_cnt;
|
|
+}
|
|
+
|
|
+static void dhcpv6_process_opt_dns_servers(struct dhcpv6_context *context,
|
|
+ struct dhcpv6_opt_hdr *opt_hdr)
|
|
+{
|
|
+ int opt_len;
|
|
+
|
|
+ opt_len = NET_TO_HOST16(opt_hdr->length);
|
|
+
|
|
+ if (opt_len >= sizeof(struct ipv6_addr))
|
|
+ memcpy((char *)&context->primary_dns_server,
|
|
+ (char *)&((struct dhcpv6_option *)opt_hdr)->type.dns.
|
|
+ primary_addr, sizeof(struct ipv6_addr));
|
|
+
|
|
+ if (opt_len >= 2 * sizeof(struct ipv6_addr))
|
|
+ memcpy((char *)&context->secondary_dns_server,
|
|
+ (char *)&((struct dhcpv6_option *)opt_hdr)->type.dns.
|
|
+ secondary_addr, sizeof(struct ipv6_addr));
|
|
+}
|
|
+
|
|
+static void dhcpv6_handle_reply(struct dhcpv6_context *context,
|
|
+ u16_t dhcpv6_len)
|
|
+{
|
|
+ if (context->dhcpv6_state != DHCPV6_STATE_REQ_SENT)
|
|
+ return;
|
|
+
|
|
+ context->dhcpv6_done = TRUE;
|
|
+}
|
|
+
|
|
+static void dhcpv6_parse_vendor_option(struct dhcpv6_context *context,
|
|
+ u8_t *option, int len)
|
|
+{
|
|
+ struct dhcpv6_option *opt;
|
|
+ u16_t type;
|
|
+ int opt_len;
|
|
+ int data_len;
|
|
+ int i;
|
|
+ u8_t *data;
|
|
+
|
|
+ for (i = 0; i < len; i += opt_len + sizeof(struct dhcpv6_opt_hdr)) {
|
|
+ opt = (struct dhcpv6_option *)((u8_t *)option + i);
|
|
+ type = HOST_TO_NET16(opt->hdr.type);
|
|
+ opt_len = HOST_TO_NET16(opt->hdr.length);
|
|
+ data = &opt->type.data[0];
|
|
+ data_len = strlen((char *)data);
|
|
+
|
|
+ switch (type) {
|
|
+ case 201:
|
|
+ /* iSCSI target 1 */
|
|
+ break;
|
|
+
|
|
+ case 202:
|
|
+ /* iSCSI target 2 */
|
|
+ break;
|
|
+
|
|
+ case 203:
|
|
+ if (data_len > ISCSI_MAX_ISCSI_NAME_LENGTH)
|
|
+ data_len = ISCSI_MAX_ISCSI_NAME_LENGTH;
|
|
+ data[data_len] = '\0';
|
|
+ strcpy(context->initiatorName, (char *)data);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/iscsiuio/src/apps/dhcpc/dhcpv6.h b/iscsiuio/src/apps/dhcpc/dhcpv6.h
|
|
new file mode 100644
|
|
index 0000000..d4ec4b9
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/apps/dhcpc/dhcpv6.h
|
|
@@ -0,0 +1,253 @@
|
|
+/*
|
|
+ * Copyright (c) 2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Eddie Wai <eddie.wai@broadcom.com>
|
|
+ * Based on code from Kevin Tran's iSCSI boot code
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * dhcpv6.h - DHCPv6 engine header
|
|
+ *
|
|
+ */
|
|
+#ifndef __IDHCPV6_H__
|
|
+#define __IDHCPV6_H__
|
|
+
|
|
+#include "ipv6_ndpc.h"
|
|
+#include "ipv6.h"
|
|
+
|
|
+#define ISCSI_MAX_ISCSI_NAME_LENGTH 128
|
|
+/* DHCPv6 Message types. */
|
|
+#define DHCPV6_SOLICIT 1
|
|
+#define DHCPV6_ADVERTISE 2
|
|
+#define DHCPV6_REQUEST 3
|
|
+#define DHCPV6_CONFIRM 4
|
|
+#define DHCPV6_RENEW 5
|
|
+#define DHCPV6_REBIND 6
|
|
+#define DHCPV6_REPLY 7
|
|
+#define DHCPV6_RELEASE 8
|
|
+#define DHCPV6_DECLINE 9
|
|
+#define DHCPV6_RECONFIGURE 10
|
|
+#define DHCPV6_INFO_REQUEST 11
|
|
+#define DHCPV6_RELAY_FORW 12
|
|
+#define DHCPV6_RELAY_REPL 13
|
|
+
|
|
+/* Option codes. */
|
|
+#define DHCPV6_OPT_CLIENTID 1 /* Client ID option - built by stack */
|
|
+#define DHCPV6_OPT_SERVERID 2 /* Server ID option - built by stack */
|
|
+#define DHCPV6_OPT_IA_NA 3 /* IA_NA option - built by user */
|
|
+#define DHCPV6_OPT_IA_TA 4 /* IA_TA option - not supported */
|
|
+#define DHCPV6_OPT_IAADDR 5 /* IA_ADDR option - built by user */
|
|
+#define DHCPV6_OPT_ORO 6 /* Option Request Option - built by
|
|
+ stack */
|
|
+#define DHCPV6_OPT_PREFERENCE 7 /* Preference option - built by server
|
|
+ */
|
|
+#define DHCPV6_OPT_ELAPSED_TIME 8 /* Elapsed Time option - built by stack
|
|
+ */
|
|
+#define DHCPV6_OPT_RELAY_MSG 9 /* Relay Message option - not supported
|
|
+ */
|
|
+#define DHCPV6_OPT_AUTH 11 /* Authentication option - built by
|
|
+ stack */
|
|
+#define DHCPV6_OPT_UNICAST 12 /* Server Unicast option - built by
|
|
+ server */
|
|
+#define DHCPV6_OPT_STATUS_CODE 13 /* Status Code option - built by stack
|
|
+ */
|
|
+#define DHCPV6_OPT_RAPID_COMMIT 14 /* Rapid Commit option - built by user
|
|
+ */
|
|
+#define DHCPV6_OPT_USER_CLASS 15 /* User Class option - built by user */
|
|
+#define DHCPV6_OPT_VENDOR_CLASS 16 /* Vendor Class option - built by user
|
|
+ */
|
|
+#define DHCPV6_OPT_VENDOR_OPTS 17 /* Vendor-Specific Information option -
|
|
+ build by user */
|
|
+#define DHCPV6_OPT_INTERFACE_ID 18 /* Interface ID option - not supported
|
|
+ */
|
|
+#define DHCPV6_OPT_RECONF_MSG 19 /* Reconfigure Message option - built
|
|
+ by server */
|
|
+#define DHCPV6_OPT_RECONF_ACCEPT 20 /* Reconfigure Accept option - built by
|
|
+ user */
|
|
+#define DHCPV6_OPT_SIP_SERVER_D 21 /* NOT SUPPORTED - included for
|
|
+ completeness only */
|
|
+#define DHCPV6_OPT_SIP_SERVER_A 22 /* NOT SUPPORTED - included for
|
|
+ completeness only */
|
|
+#define DHCPV6_OPT_DNS_SERVERS 23 /* DNS Recursive Name Server option -
|
|
+ built by server */
|
|
+#define DHCPV6_OPT_DOMAIN_LIST 24 /* Domain Search List option - not
|
|
+ supported */
|
|
+#define DHCPV6_MAX_OPT_CODES 25 /* This will be the count + 1 since
|
|
+ the parsing array starts
|
|
+ at [1] instead of [0] */
|
|
+
|
|
+/* Authentication protocol types. */
|
|
+#define DHCPV6_DELAYED_AUTH_PROT 2 /* Delayed Authentication protocol. */
|
|
+#define DHCPV6_RECON_KEY_AUTH_PROT 3 /* Reconfigure Key Authentication
|
|
+ protocol. */
|
|
+
|
|
+struct dhcpv6_context {
|
|
+#define DHCP_VENDOR_ID_LEN 128
|
|
+ char dhcp_vendor_id[DHCP_VENDOR_ID_LEN];
|
|
+ struct mac_address *our_mac_addr;
|
|
+ u32_t dhcpv6_transaction_id;
|
|
+ u16_t seconds;
|
|
+ int timeout;
|
|
+ int dhcpv6_done;
|
|
+
|
|
+#define DHCPV6_STATE_UNKNOWN 0
|
|
+#define DHCPV6_STATE_SOLICIT_SENT 1
|
|
+#define DHCPV6_STATE_ADV_RCVD 2
|
|
+#define DHCPV6_STATE_REQ_SENT 3
|
|
+#define DHCPV6_STATE_CONFIRM_SENT 4
|
|
+ int dhcpv6_state;
|
|
+ u16_t dhcpv6_task;
|
|
+ struct ipv6_context *ipv6_context;
|
|
+ struct eth_hdr *eth;
|
|
+ struct ipv6_hdr *ipv6;
|
|
+ struct udp_hdr *udp;
|
|
+
|
|
+ char initiatorName[ISCSI_MAX_ISCSI_NAME_LENGTH];
|
|
+ struct ipv6_addr dhcp_server;
|
|
+ struct ipv6_addr primary_dns_server;
|
|
+ struct ipv6_addr secondary_dns_server;
|
|
+
|
|
+};
|
|
+
|
|
+union dhcpv6_hdr {
|
|
+ struct {
|
|
+ u32_t type:8;
|
|
+ u32_t trans_id:24;
|
|
+ } field;
|
|
+
|
|
+ u32_t type_transaction;
|
|
+};
|
|
+
|
|
+#define dhcpv6_type field.type
|
|
+#define dhcpv6_trans_id field.trans_id
|
|
+
|
|
+struct dhcpv6_opt_hdr {
|
|
+ u16_t type;
|
|
+ u16_t length;
|
|
+};
|
|
+
|
|
+struct dhcpv6_opt_client_id {
|
|
+ u16_t duid_type;
|
|
+#define DHCPV6_DUID_TYPE_LINK_LAYER_AND_TIME 1
|
|
+#define DHCPV6_DUID_TYPE_VENDOR_BASED 2
|
|
+#define DHCPV6_DUID_TYPE_LINK_LAYER 3
|
|
+ u16_t hw_type;
|
|
+#define DHCPV6_HW_TYPE_ETHERNET 1
|
|
+ u32_t time;
|
|
+ struct mac_address link_layer_addr;
|
|
+};
|
|
+
|
|
+struct dhcpv6_opt_id_assoc_na {
|
|
+ u32_t iaid;
|
|
+#define DHCPV6_OPT_IA_NA_IAID 0x306373L
|
|
+ u32_t t1;
|
|
+ u32_t t2;
|
|
+};
|
|
+
|
|
+struct dhcpv6_opt_elapse_time {
|
|
+ u16_t time;
|
|
+};
|
|
+
|
|
+struct dhcpv6_opt_iaa_addr {
|
|
+ struct ipv6_addr addr;
|
|
+ u32_t preferred_lifetime;
|
|
+ u32_t valid_lifetime;
|
|
+};
|
|
+
|
|
+struct dhcpv6_opt_status {
|
|
+ u16_t status;
|
|
+};
|
|
+
|
|
+struct dhcpv6_opt_request_list {
|
|
+ u16_t request_code[1];
|
|
+};
|
|
+
|
|
+struct dhcpv6_opt_dns {
|
|
+ struct ipv6_addr primary_addr;
|
|
+ struct ipv6_addr secondary_addr;
|
|
+};
|
|
+
|
|
+struct dhcpv6_vendor_class {
|
|
+ u32_t enterprise_number;
|
|
+ u16_t vendor_class_length;
|
|
+ u8_t vendor_class_data[1];
|
|
+};
|
|
+
|
|
+struct dhcpv6_vendor_opts {
|
|
+ u32_t enterprise_number;
|
|
+ u8_t vendor_opt_data[1];
|
|
+};
|
|
+
|
|
+struct dhcpv6_option {
|
|
+ struct dhcpv6_opt_hdr hdr;
|
|
+ union {
|
|
+ struct dhcpv6_vendor_opts vendor_opts;
|
|
+ struct dhcpv6_vendor_class vendor_class;
|
|
+ struct dhcpv6_opt_client_id client_id;
|
|
+ struct dhcpv6_opt_id_assoc_na ida_na;
|
|
+ struct dhcpv6_opt_elapse_time elapsed_time;
|
|
+ struct dhcpv6_opt_iaa_addr iaa_addr;
|
|
+ struct dhcpv6_opt_status sts;
|
|
+ struct dhcpv6_opt_request_list list;
|
|
+ struct dhcpv6_opt_dns dns;
|
|
+ u8_t data[1];
|
|
+ } type;
|
|
+};
|
|
+
|
|
+#define DHCPV6_NUM_OF_RETRY 4
|
|
+
|
|
+#define DHCPV6_ACK_TIMEOUT 2
|
|
+
|
|
+#define IANA_ENTERPRISE_NUM_BROADCOM 0x113d
|
|
+
|
|
+/* QLogic Extended DHCP options used in iSCSI boot */
|
|
+#define DHCPV6_TAG_FIRST_ISCSI_TARGET_NAME 201
|
|
+#define DHCPV6_TAG_SECOND_ISCSI_TARGET_NAME 202
|
|
+#define DHCPV6_TAG_ISCSI_INITIATOR_NAME 203
|
|
+
|
|
+#define MAX_DHCP_RX_OFFERS 4
|
|
+#define MAX_DHCP_OPTION43_LENGTH 1024
|
|
+
|
|
+#define DHCPV6_TASK_GET_IP_ADDRESS 0x1
|
|
+#define DHCPV6_TASK_GET_OTHER_PARAMS 0x2
|
|
+
|
|
+enum {
|
|
+ ISCSI_FAILURE,
|
|
+ ISCSI_USER_ABORT,
|
|
+ ISCSI_SUCCESS
|
|
+};
|
|
+
|
|
+/* Function prototypes */
|
|
+int dhcpv6_do_discovery(struct dhcpv6_context *context);
|
|
+void ipv6_udp_handle_dhcp(struct dhcpv6_context *context);
|
|
+void dhcpv6_init(struct dhcpv6_context *context);
|
|
+
|
|
+#endif /* __IDHCPV6_H__ */
|
|
diff --git a/iscsiuio/src/uip-1.0-changelog.txt b/iscsiuio/src/uip-1.0-changelog.txt
|
|
new file mode 100644
|
|
index 0000000..800e444
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip-1.0-changelog.txt
|
|
@@ -0,0 +1,98 @@
|
|
+* A new API: protosockets that are similar to BSD sockets but does not
|
|
+ require any underlying multithreading system.
|
|
+
|
|
+* Very rudimentary IPv6 support
|
|
+
|
|
+* New application: DHCP client. Web server rewritten with protosockets.
|
|
+
|
|
+* Removed uIP zero-copy functionality in order to simplify uIP device
|
|
+ driver coding: outbound packets are now *always* stored in full in
|
|
+ the uip_buf buffer.
|
|
+
|
|
+* Checksum computation is now part of uip.c, but it still is possible
|
|
+ to implement them in assembly code by specifying a configuration
|
|
+ option. Checksum code now runs on architectures with 2-byte alignment.
|
|
+
|
|
+* Added TCP persistent timer.
|
|
+
|
|
+* Made all IP address representations use the new uip_ipaddr_ip
|
|
+ datatype for clarity.
|
|
+
|
|
+* Updated window behavior so that sending to a host with a small open
|
|
+ window works better now.
|
|
+
|
|
+* UDP API change: uip_udp_new() now takes port numbers in network byte
|
|
+ order like TCP functions.
|
|
+
|
|
+* Allow reception of packets when no IP address is configured to make
|
|
+ DHCP work.
|
|
+
|
|
+* Moved Ethernet address into main uIP module from ARP module.
|
|
+
|
|
+* Made constants explicit #defines and moved them out of the code
|
|
+ (header sizes, TCP options, TCP header length field).
|
|
+
|
|
+* If uip_len is less than that reported by the IP header, the packet
|
|
+ is discarded. If uip_len is greater than the length reported by the
|
|
+ IP header, uip_len is adjusted.
|
|
+
|
|
+* Moved header size definitions into header file.
|
|
+
|
|
+* Added uIP call for polling an application without triggering any
|
|
+ timer events. Removed redundant assignments of uip_len and uip_slen.
|
|
+
|
|
+* Removed compiler warning about icmp_input label being defined when
|
|
+ UIP_PINGADDRCONF was not used.
|
|
+
|
|
+* Added UIP_APPDATA_SIZE macro that holds the available buffer size
|
|
+ for user data.
|
|
+
|
|
+* Added uip_udp_bind() call.
|
|
+
|
|
+* Moved checksum code into main uIP module.
|
|
+
|
|
+* Switched the TCP, UDP and IP header structures to be structs rather
|
|
+ than typedefs.
|
|
+
|
|
+* Prefixed TCP state names with UIP_ to avoid name space
|
|
+ contamination.
|
|
+
|
|
+* Changed declarations of uip_appdatap and friends to void * to avoid
|
|
+ explicit typecasts.
|
|
+
|
|
+* Bugfixes
|
|
+
|
|
+ o TCP: Fixed bug with high byte of peer window size.
|
|
+
|
|
+ o TCP: Fixed bug that in some cases prevented concurrent reception and
|
|
+ transmission of TCP data.
|
|
+
|
|
+ o TCP: uip_connect() didn't correctly calculate age of TIME_WAIT
|
|
+ connections.
|
|
+
|
|
+ o TCP: Array index for uip_conns[] array was out of bounds in
|
|
+ comparison. Comparison changed to make index within bounds.
|
|
+
|
|
+ o TCP: if the remote host crashes and tries to reestablish an old
|
|
+ connection, uIP should respond with an ACK with the correct
|
|
+ sequence and acknowledgment numbers, to which the remote host
|
|
+ should respond with an ACK. uIP did not respond with the correct
|
|
+ ACK.
|
|
+
|
|
+ o TCP: Fixed check for SYNACK segment: now checks only relevant TCP
|
|
+ control flags and discards flags reserved for future expansion.
|
|
+
|
|
+ o TCP: Fixed bug where uIP did not inform application that a connection
|
|
+ had been aborted during an active open.
|
|
+
|
|
+ o TCP: FIN segment was accepted even though application had stopped
|
|
+ incoming data with uip_stop().
|
|
+
|
|
+ o TCP: A FINACK segment would not always correctly acknowledge data.
|
|
+
|
|
+ o UDP: checksums are now calculated after all fields have been
|
|
+ filled in.
|
|
+
|
|
+ o UDP: network byte order on lastport in uip_udp_new().
|
|
+
|
|
+ o IP: memset() bugs in IP fragment reassembly code fixed.
|
|
diff --git a/iscsiuio/src/uip/Makefile.am b/iscsiuio/src/uip/Makefile.am
|
|
new file mode 100644
|
|
index 0000000..16170d7
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/Makefile.am
|
|
@@ -0,0 +1,18 @@
|
|
+AM_CFLAGS = -I${top_srcdir}/src/unix \
|
|
+ -I${top_srcdir}/src/apps/dhcpc \
|
|
+ -I${top_srcdir}/src/apps/brcm-iscsi \
|
|
+ -I${top_srcdir}/../include \
|
|
+ -I${top_srcdir}/../usr
|
|
+
|
|
+noinst_LIBRARIES = lib_iscsi_uip.a
|
|
+
|
|
+lib_iscsi_uip_a_SOURCES = uip.c \
|
|
+ uip_arp.c \
|
|
+ psock.c \
|
|
+ timer.c \
|
|
+ uip-neighbor.c \
|
|
+ uip_eth.c \
|
|
+ ipv6_ndpc.c \
|
|
+ ipv6.c
|
|
+
|
|
+lib_iscsi_uip_a_CFLAGS = -DBYTE_ORDER=@ENDIAN@ $(AM_CFLAGS)
|
|
diff --git a/iscsiuio/src/uip/Makefile.include b/iscsiuio/src/uip/Makefile.include
|
|
new file mode 100644
|
|
index 0000000..aa3ac63
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/Makefile.include
|
|
@@ -0,0 +1,47 @@
|
|
+
|
|
+
|
|
+ifdef APPS
|
|
+ APPDIRS = $(foreach APP, $(APPS), ../apps/$(APP))
|
|
+ -include $(foreach APP, $(APPS), ../apps/$(APP)/Makefile.$(APP))
|
|
+ CFLAGS += $(addprefix -I../apps/,$(APPS))
|
|
+endif
|
|
+
|
|
+ifndef CCDEP
|
|
+ CCDEP = $(CC)
|
|
+endif
|
|
+ifndef CCDEPCFLAGS
|
|
+ CCDEPCFLAGS = $(CFLAGS)
|
|
+endif
|
|
+ifndef OBJECTDIR
|
|
+ OBJECTDIR = obj
|
|
+endif
|
|
+
|
|
+ifeq (${wildcard $(OBJECTDIR)},)
|
|
+ DUMMY := ${shell mkdir $(OBJECTDIR)}
|
|
+endif
|
|
+
|
|
+
|
|
+vpath %.c . ../uip ../lib $(APPDIRS)
|
|
+
|
|
+$(OBJECTDIR)/%.o: %.c
|
|
+ $(CC) $(CFLAGS) -c $< -o $@
|
|
+
|
|
+$(OBJECTDIR)/%.d: %.c
|
|
+ @set -e; rm -f $@; \
|
|
+ $(CCDEP) -MM $(CCDEPCFLAGS) $< > $@.$$$$; \
|
|
+ sed 's,\($*\)\.o[ :]*,$(OBJECTDIR)/\1.o $@ : ,g' < $@.$$$$ > $@; \
|
|
+ rm -f $@.$$$$
|
|
+
|
|
+UIP_SOURCES=uip.c uip_arp.c uiplib.c psock.c timer.c uip-neighbor.c uip_eth.c ipv6_ndp.c ipv6.c
|
|
+
|
|
+
|
|
+ifneq ($(MAKECMDGOALS),clean)
|
|
+-include $(addprefix $(OBJECTDIR)/,$(UIP_SOURCES:.c=.d) \
|
|
+ $(APP_SOURCES:.c=.d))
|
|
+endif
|
|
+
|
|
+libuip.a: ${addprefix $(OBJECTDIR)/, $(UIP_SOURCES:.c=.o)}
|
|
+ $(AR) rc $@ $^
|
|
+
|
|
+libapps.a: ${addprefix $(OBJECTDIR)/, $(APP_SOURCES:.c=.o)}
|
|
+ $(AR) rc $@ $^
|
|
diff --git a/iscsiuio/src/uip/clock.h b/iscsiuio/src/uip/clock.h
|
|
new file mode 100644
|
|
index 0000000..d79326b
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/clock.h
|
|
@@ -0,0 +1,87 @@
|
|
+/**
|
|
+ * \defgroup clock Clock interface
|
|
+ *
|
|
+ * The clock interface is the interface between the \ref timer "timer library"
|
|
+ * and the platform specific clock functionality. The clock
|
|
+ * interface must be implemented for each platform that uses the \ref
|
|
+ * timer "timer library".
|
|
+ *
|
|
+ * The clock interface does only one this: it measures time. The clock
|
|
+ * interface provides a macro, CLOCK_SECOND, which corresponds to one
|
|
+ * second of system time.
|
|
+ *
|
|
+ * \sa \ref timer "Timer library"
|
|
+ *
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ * Author: Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ */
|
|
+#ifndef __CLOCK_H__
|
|
+#define __CLOCK_H__
|
|
+
|
|
+#include "clock-arch.h"
|
|
+
|
|
+/**
|
|
+ * Initialize the clock library.
|
|
+ *
|
|
+ * This function initializes the clock library and should be called
|
|
+ * from the main() function of the system.
|
|
+ *
|
|
+ */
|
|
+void clock_init(void);
|
|
+
|
|
+/**
|
|
+ * Get the current clock time.
|
|
+ *
|
|
+ * This function returns the current system clock time.
|
|
+ *
|
|
+ * \return The current clock time, measured in system ticks.
|
|
+ */
|
|
+clock_time_t clock_time(void);
|
|
+
|
|
+/**
|
|
+ * A second, measured in system clock time.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifdef CLOCK_CONF_SECOND
|
|
+#define CLOCK_SECOND CLOCK_CONF_SECOND
|
|
+#else
|
|
+#define CLOCK_SECOND (clock_time_t)32
|
|
+#endif
|
|
+
|
|
+#endif /* __CLOCK_H__ */
|
|
+
|
|
+/** @} */
|
|
diff --git a/iscsiuio/src/uip/debug.h b/iscsiuio/src/uip/debug.h
|
|
new file mode 100644
|
|
index 0000000..a58fa7a
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/debug.h
|
|
@@ -0,0 +1,13 @@
|
|
+#ifndef __DEBUG_H__
|
|
+#define __DEBUG_H__
|
|
+
|
|
+#ifdef DEBUG
|
|
+#define UIP_DEBUG(args...) \
|
|
+ do { \
|
|
+ fprintf(stdout, args); \
|
|
+ fflush(stdout); \
|
|
+ } while (0);
|
|
+#else
|
|
+#endif
|
|
+
|
|
+#endif
|
|
diff --git a/iscsiuio/src/uip/icmpv6.h b/iscsiuio/src/uip/icmpv6.h
|
|
new file mode 100644
|
|
index 0000000..cbf9aa8
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/icmpv6.h
|
|
@@ -0,0 +1,302 @@
|
|
+/*
|
|
+ * Copyright (c) 2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Eddie Wai (eddie.wai@broadcom.com)
|
|
+ * Based on Kevin Tran's iSCSI boot code
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * icmpv6.h - This file contains macro definitions pertaining to ICMPv6
|
|
+ *
|
|
+ * RFC 2463 : ICMPv6 Specification
|
|
+ * RFC 2461 : Neighbor Discovery for IPv6
|
|
+ *
|
|
+ */
|
|
+#ifndef __ICMPV6_H__
|
|
+#define __ICMPV6_H__
|
|
+
|
|
+/* Base ICMP Header sizes */
|
|
+#define IPV6_RTR_SOL_HDR_SIZE 8
|
|
+#define IPV6_RTR_ADV_HDR_SIZE 16
|
|
+#define IPV6_NEIGH_SOL_HDR_SIZE 24
|
|
+#define IPV6_NEIGH_ADV_HDR_SIZE 24
|
|
+#define IPV6_LINK_LAYER_OPT_SIZE 2
|
|
+#define IPV6_LINK_LAYER_OPT_LENGTH 8
|
|
+#define IPV6_MTU_OPT_SIZE 8
|
|
+#define IPV6_PREFIX_OPT_SIZE 32
|
|
+#define IPV6_ECHO_REQUEST_HDR_SIZE 8
|
|
+#define IPV6_ECHO_REPLY_HDR_SIZE 8
|
|
+#define IPV6_REDIRECT_SIZE 40
|
|
+#define IPV6_DHAAD_REQ_HDR_SIZE 8
|
|
+#define IPV6_DHAAD_REPLY_HDR_SIZE 8
|
|
+#define IPV6_PRFXSOL_HDR_SIZE 8
|
|
+#define IPV6_PRFXADV_HDR_SIZE 8
|
|
+#define IPV6_RTR_ADV_INT_OPT_SIZE 8
|
|
+
|
|
+/* ICMP Message Types */
|
|
+/* Error messages are always less than 128 */
|
|
+#define ICMPV6_DST_UNREACH 1 /* Destination Unreachable */
|
|
+#define ICMPV6_PACKET_TOO_BIG 2 /* Packet Too Big */
|
|
+#define ICMPV6_TIME_EXCEEDED 3 /* Time Exceeded */
|
|
+#define ICMPV6_PARAM_PROB 4 /* Parameter Problem */
|
|
+
|
|
+#define ICMPV6_RTR_SOL 133 /* Router Solicitation */
|
|
+#define ICMPV6_RTR_ADV 134 /* Router Advertisement */
|
|
+#define ICMPV6_NEIGH_SOL 135 /* Neighbor Solicitation */
|
|
+#define ICMPV6_NEIGH_ADV 136 /* Neighbor Advertisement */
|
|
+#define ICMPV6_REDIRECT 137 /* Redirect */
|
|
+#define ICMPV6_ECHO_REQUEST 128 /* Echo Request */
|
|
+#define ICMPV6_ECHO_REPLY 129 /* Echo Reply */
|
|
+#define ICMPV6_WRUREQUEST 139 /* Who Are You Request */
|
|
+#define ICMPV6_WRUREPLY 140 /* Who Are You Reply */
|
|
+#define ICMPV6_ROUTER_RENUMBERING 138 /* Router Renumbering */
|
|
+#define ICMPV6_HA_ADDR_DISC_REQ 144 /* Dynamic Home Agent Address
|
|
+ Discovery Request */
|
|
+#define ICMPV6_HA_ADDR_DISC_REPLY 145 /* Dynamic Home Agent Address
|
|
+ Discovery Reply */
|
|
+#define ICMPV6_MP_SOLICIT 146 /* Mobile Prefix Solicitation */
|
|
+#define ICMPV6_MP_ADV 147 /* Mobile Prefix Reply */
|
|
+
|
|
+/* Destination Unreachable Codes */
|
|
+#define ICMPV6_DST_UNREACH_NOROUTE 0
|
|
+#define ICMPV6_DST_UNREACH_ADMIN 1
|
|
+#define ICMPV6_DST_UNREACH_ADDRESS 3
|
|
+#define ICMPV6_DST_UNREACH_PORT 4
|
|
+
|
|
+/* Time Exceeded Codes */
|
|
+#define ICMPV6_TIME_EXCD_HPLMT 0 /* Hop Limit exceeded in transit */
|
|
+#define ICMPV6_TIME_EXCD_REASM 1 /* Fragment reassembly time exceeded */
|
|
+
|
|
+/* Parameter Problem Codes */
|
|
+#define ICMPV6_PARM_PROB_HEADER 0
|
|
+#define ICMPV6_PARM_PROB_NEXT_HDR 1
|
|
+#define ICMPV6_PARM_PROB_OPTION 2
|
|
+
|
|
+/* ICMP Option Types */
|
|
+#define IPV6_ICMP_OPTION_SRC_ADDR 1 /* Source Link-Layer Address */
|
|
+#define IPV6_ICMP_OPTION_TAR_ADDR 2 /* Target Link-Layer Address */
|
|
+#define IPV6_ICMP_OPTION_PREFIX 3 /* Prefix */
|
|
+#define IPV6_ICMP_OPTION_RED_HDR 4 /* Redirect Header */
|
|
+#define IPV6_ICMP_OPTION_MTU 5 /* Link MTU */
|
|
+#define IPV6_ICMP_OPTION_RTR_ADV_INT 7 /* Rtr Advertisement Interval */
|
|
+
|
|
+/* ICMP Offsets */
|
|
+#define IPV6_ICMP_TYPE_OFFSET 0
|
|
+#define IPV6_ICMP_CODE_OFFSET 1
|
|
+#define IPV6_ICMP_CKSUM_OFFSET 2
|
|
+#define IPV6_ICMP_RESERVED_OFFSET 4
|
|
+#define IPV6_ICMP_DATA_OFFSET 8
|
|
+
|
|
+/* ICMP Router Solicitation Offsets */
|
|
+#define IPV6_ICMP_RTR_SOL_RES_OFFSET 4
|
|
+#define IPV6_ICMP_RTR_SOL_OPTIONS_OFFSET 8
|
|
+
|
|
+/* ICMP Router Advertisement Offsets */
|
|
+#define IPV6_ICMP_RTR_ADV_CURHOPLMT_OFFSET 4
|
|
+#define IPV6_ICMP_RTR_ADV_MGDANDCFG_BIT_OFFSET 5
|
|
+#define IPV6_ICMP_RTR_ADV_RTR_LIFETIME_OFFSET 6
|
|
+#define IPV6_ICMP_RTR_ADV_RCHBL_TIME_OFFSET 8
|
|
+#define IPV6_ICMP_RTR_ADV_RTRNS_TMR_OFFSET 12
|
|
+#define IPV6_ICMP_RTR_ADV_OPTIONS_OFFSET 16
|
|
+
|
|
+/* ICMP Neighbor Solicitation Offsets */
|
|
+#define IPV6_ICMP_NEIGH_SOL_RES_OFFSET 4
|
|
+#define IPV6_ICMP_NEIGH_SOL_TRGT_ADDRS_OFFSET 8
|
|
+#define IPV6_ICMP_NEIGH_SOL_OPTIONS_OFFSET 24
|
|
+
|
|
+/* ICMP Neighbor Advertisement Offsets */
|
|
+#define IPV6_ICMP_NEIGH_ADV_FLAG_OFFSET 4
|
|
+#define IPV6_ICMP_NEIGH_ADV_TRGT_ADDRS_OFFSET 8
|
|
+#define IPV6_ICMP_NEIGH_ADV_OPTIONS_OFFSET 24
|
|
+
|
|
+/* ICMP Redirect Offsets */
|
|
+#define IPV6_ICMP_REDIRECT_TRGT_ADDRS_OFFSET 8
|
|
+#define IPV6_ICMP_REDIRECT_DEST_ADDRS_OFFSET 24
|
|
+#define IPV6_ICMP_REDIRECT_OPTIONS_OFFSET 40
|
|
+
|
|
+/* ICMP Option Offsets */
|
|
+#define IPV6_ICMP_OPTION_TYPE_OFFSET 0
|
|
+#define IPV6_ICMP_OPTION_LENGTH_OFFSET 1
|
|
+
|
|
+/* ICMP Link-Layer Address Option Offsets */
|
|
+#define IPV6_ICMP_LL_OPTION_ADDRESS_OFFSET 2
|
|
+
|
|
+/* ICMP Prefix Option Offsets */
|
|
+#define IPV6_ICMP_PREFIX_PRE_LENGTH_OFFSET 2
|
|
+#define IPV6_ICMP_PREFIX_FLAG_OFFSET 3
|
|
+#define IPV6_ICMP_PREFIX_VALID_LIFETIME_OFFSET 4
|
|
+#define IPV6_ICMP_PREFIX_PREF_LIFETIME_OFFSET 8
|
|
+#define IPV6_ICMP_PREFIX_RES2_OFFSET 12
|
|
+#define IPV6_ICMP_PREFIX_PREFIX_OFFSET 16
|
|
+
|
|
+/* ICMP Redirected Header Option Offsets */
|
|
+#define IPV6_ICMP_RED_OPTION_TYPE_OFFSET 0
|
|
+#define IPV6_ICMP_RED_OPTION_LEN_OFFSET 1
|
|
+#define IPV6_ICMP_RED_OPTION_RES1_OFFSET 2
|
|
+#define IPV6_ICMP_RED_OPTION_RES2_OFFSET 4
|
|
+#define IPV6_ICMP_RED_OPTION_DATA_OFFSET 8
|
|
+
|
|
+/* ICMP MTU Option Offsets */
|
|
+#define IPV6_ICMP_MTU_RESERVED_OFFSET 2
|
|
+#define IPV6_ICMP_MTU_OFFSET 4
|
|
+
|
|
+/* ICMP Echo Request Offsets */
|
|
+#define IPV6_ICMP_ECHO_ID 4
|
|
+#define IPV6_ICMP_ECHO_SEQ 6
|
|
+#define IPV6_ICMP_ECHO_DATA 8
|
|
+
|
|
+/* ICMP Destination Unreachable Offsets */
|
|
+#define IPV6_DST_UNREACH_UNUSED 4
|
|
+#define IPV6_DST_UNREACH_DATA 8
|
|
+
|
|
+/* ICMP Parameter Problem Offsets */
|
|
+#define IPV6_PARAM_PROB_PTR 4
|
|
+#define IPV6_PARAM_PROT_DATA 8
|
|
+
|
|
+/* ICMP Time Exceeded Offsets */
|
|
+#define IPV6_TIME_EXCEEDED_DATA 8
|
|
+
|
|
+/* ICMP Packet Too Big Offsets */
|
|
+#define IPV6_PKT_TOO_BIG_MTU 4
|
|
+#define IPV6_PKT_TOO_BIG_DATA 8
|
|
+
|
|
+/* Home Agent Address Discovery Request Header Offsets */
|
|
+#define ICMPV6_HA_ADDR_DISC_REQ_ID_OFFSET 4
|
|
+#define ICMPV6_HA_ADDR_DISC_REQ_RSVD_OFFSET 6
|
|
+
|
|
+/* Home Agent Address Discovery Reply Header Offsets */
|
|
+#define ICMPV6_HA_ADDR_DISC_REPLY_ID_OFFSET 4
|
|
+#define ICMPV6_HA_ADDR_DISC_REPLY_RSVD_OFFSET 6
|
|
+#define ICMPV6_HA_ADDR_DISC_REPLY_HA_ADDR_OFFSET 8
|
|
+
|
|
+/* Mobile Prefix Solicitation Header Offsets */
|
|
+#define ICMPV6_MP_SOLICIT_ID_OFFSET 4
|
|
+#define ICMPV6_MP_SOLICIT_RSVD_OFFSET 6
|
|
+
|
|
+/* Mobile Prefix Advertisement Header Offsets */
|
|
+#define ICMPV6_MP_ADV_ID_OFFSET 4
|
|
+#define ICMPV6_MP_ADV_MGDANDCFG_BIT_OFFSET 6
|
|
+#define ICMPV6_MP_ADV_OPT_OFFSET 8
|
|
+
|
|
+/* Advertisement Interval Option Header Offsets */
|
|
+#define ICMPV6_ADV_INT_TYPE_OFFSET 0
|
|
+#define ICMPV6_ADV_INT_LEN_OFFSET 1
|
|
+#define ICMPV6_ADV_INT_RSVD_OFFSET 2
|
|
+#define ICMPV6_ADV_INT_ADV_INT_OFFSET 4
|
|
+
|
|
+#define ICMPV6_HEADER_LEN 4
|
|
+
|
|
+#define IPV6_PREFIX_FLAG_ONLINK 0x80
|
|
+#define IPV6_PREFIX_FLAG_AUTO 0x40
|
|
+#define IPV6_PREFIX_FLAG_ROUTER 0x20
|
|
+
|
|
+#define IPV6_NA_FLAG_ROUTER 0x80
|
|
+#define IPV6_NA_FLAG_SOLICITED 0x40
|
|
+#define IPV6_NA_FLAG_OVERRIDE 0x20
|
|
+
|
|
+/* Router Advertisement Flags */
|
|
+#define IPV6_RA_MANAGED_FLAG 0x80
|
|
+#define IPV6_RA_CONFIG_FLAG 0x40
|
|
+
|
|
+/* Mobile Prefix Advertisement Flags */
|
|
+#define IPV6_PA_MANAGED_FLAG 0x80
|
|
+#define IPV6_PA_CONFIG_FLAG 0x40
|
|
+
|
|
+/* Validation Values */
|
|
+#define ICMPV6_VALID_HOP_LIMIT 255 /* Valid Hop Limit */
|
|
+#define ICMPV6_VALID_CODE 0 /* Valid Code */
|
|
+#define ICMPV6_RTRSOL_MIN_LENGTH 8 /* Minimum valid length for
|
|
+ Router Solicitation */
|
|
+#define ICMPV6_RTRADV_MIN_LENGTH 16 /* Minimum valid length for
|
|
+ Router Advertisement */
|
|
+#define ICMPV6_NEIGHSOL_MIN_LENGTH 24 /* Minimum valid length for
|
|
+ Neighbor Solicitation */
|
|
+#define ICMPV6_NEIGHADV_MIN_LENGTH 24 /* Minimum valid length for
|
|
+ Neighbor Advertisement */
|
|
+#define ICMPV6_REDIRECT_MIN_LENGTH 40 /* Minimum valid length for
|
|
+ Neighbor Advertisement */
|
|
+
|
|
+/* ICMPV6 Header */
|
|
+struct icmpv6_hdr {
|
|
+ u8_t icmpv6_type; /* type field */
|
|
+ u8_t icmpv6_code; /* code field */
|
|
+ u16_t icmpv6_cksum; /* checksum field */
|
|
+ union {
|
|
+ u32_t icmpv6_un_data32[1]; /* type-specific field */
|
|
+ u16_t icmpv6_un_data16[2]; /* type-specific field */
|
|
+ u8_t icmpv6_un_data8[4]; /* type-specific field */
|
|
+ } data;
|
|
+};
|
|
+
|
|
+#define icmpv6_data data.icmpv6_un_data32[0]
|
|
+
|
|
+struct icmpv6_opt_hdr {
|
|
+ u8_t type;
|
|
+ u8_t len;
|
|
+};
|
|
+
|
|
+struct icmpv6_opt_link_addr {
|
|
+ struct icmpv6_opt_hdr hdr;
|
|
+ u8_t link_addr[6];
|
|
+};
|
|
+
|
|
+struct icmpv6_opt_prefix {
|
|
+ struct icmpv6_opt_hdr hdr;
|
|
+ u8_t prefix_len;
|
|
+ u8_t flags;
|
|
+#define ICMPV6_OPT_PREFIX_FLAG_ON_LINK (1 << 7)
|
|
+#define ICMPV6_OPT_PREFIX_FLAG_BIT_A (1 << 6)
|
|
+ u32_t valid_lifetime;
|
|
+ u32_t preferred_lifetime;
|
|
+ u32_t reserved;
|
|
+ struct ipv6_addr prefix;
|
|
+};
|
|
+
|
|
+/* Neighbor Solicitation */
|
|
+struct icmpv6_nd_solicit {
|
|
+ struct icmpv6_hdr nd_ns_hdr;
|
|
+};
|
|
+
|
|
+/* Router Advertisement */
|
|
+struct icmpv6_router_advert {
|
|
+ struct icmpv6_hdr header;
|
|
+ u32_t reachable_time;
|
|
+ u32_t retransmit_timer;
|
|
+};
|
|
+
|
|
+#define nd_ra_type header.icmpv6_type
|
|
+#define nd_ra_code header.icmpv6_code
|
|
+#define nd_ra_cksum header.icmpv6_cksum
|
|
+#define nd_ra_curhoplimit header.data.icmpv6_un_data8[0]
|
|
+#define nd_ra_flags_reserved header.data.icmpv6_un_data8[1]
|
|
+#define nd_ra_router_lifetime header.data.icmpv6_un_data16[1]
|
|
+
|
|
+#endif /* __ICMPV6_H__ */
|
|
diff --git a/iscsiuio/src/uip/ipv6.c b/iscsiuio/src/uip/ipv6.c
|
|
new file mode 100644
|
|
index 0000000..5c627ac
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/ipv6.c
|
|
@@ -0,0 +1,1297 @@
|
|
+/*
|
|
+ * Copyright (c) 2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Eddie Wai (eddie.wai@broadcom.com)
|
|
+ * Based on Kevin Tran's iSCSI boot code
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * ipv6.c - This file contains simplifed IPv6 processing code.
|
|
+ *
|
|
+ */
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <arpa/inet.h>
|
|
+#include "logger.h"
|
|
+#include "uip.h"
|
|
+#include "ipv6.h"
|
|
+#include "ipv6_pkt.h"
|
|
+#include "icmpv6.h"
|
|
+#include "uipopt.h"
|
|
+#include "dhcpv6.h"
|
|
+
|
|
+inline int best_match_bufcmp(u8_t *a, u8_t *b, int len)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < len; i++) {
|
|
+ if (a[i] != b[i])
|
|
+ break;
|
|
+ }
|
|
+ return i;
|
|
+}
|
|
+
|
|
+/* Local function prototypes */
|
|
+static int ipv6_is_it_our_address(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr);
|
|
+static void ipv6_insert_protocol_chksum(struct ipv6_hdr *ipv6);
|
|
+static void ipv6_update_arp_table(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr,
|
|
+ struct mac_address *mac_addr);
|
|
+static void ipv6_icmp_init_link_option(struct ipv6_context *context,
|
|
+ struct icmpv6_opt_link_addr *link_opt,
|
|
+ u8_t type);
|
|
+static void ipv6_icmp_rx(struct ipv6_context *context);
|
|
+static void ipv6_icmp_handle_nd_adv(struct ipv6_context *context);
|
|
+static void ipv6_icmp_handle_nd_sol(struct ipv6_context *context);
|
|
+static void ipv6_icmp_handle_echo_request(struct ipv6_context *context);
|
|
+static void ipv6_icmp_handle_router_adv(struct ipv6_context *context);
|
|
+static void ipv6_icmp_process_prefix(struct ipv6_context *context,
|
|
+ struct icmpv6_opt_prefix *icmp_prefix);
|
|
+static void ipv6_udp_rx(struct ipv6_context *context);
|
|
+
|
|
+int iscsiL2Send(struct ipv6_context *context, int pkt_len)
|
|
+{
|
|
+ LOG_DEBUG("IPv6: iscsiL2Send");
|
|
+ uip_send(context->ustack,
|
|
+ (void *)context->ustack->data_link_layer, pkt_len);
|
|
+
|
|
+ return pkt_len;
|
|
+}
|
|
+
|
|
+int iscsiL2AddMcAddr(struct ipv6_context *context,
|
|
+ struct mac_address *new_mc_addr)
|
|
+{
|
|
+ int i;
|
|
+ struct mac_address *mc_addr;
|
|
+ const struct mac_address all_zeroes_mc = { { { 0, 0, 0, 0, 0, 0 } } };
|
|
+
|
|
+ mc_addr = context->mc_addr;
|
|
+ for (i = 0; i < MAX_MCADDR_TABLE; i++, mc_addr++)
|
|
+ if (!memcmp((char *)mc_addr,
|
|
+ (char *)new_mc_addr, sizeof(struct mac_address)))
|
|
+ return TRUE; /* Already in the mc table */
|
|
+
|
|
+ mc_addr = context->mc_addr;
|
|
+ for (i = 0; i < MAX_MCADDR_TABLE; i++, mc_addr++) {
|
|
+ if (!memcmp((char *)mc_addr,
|
|
+ (char *)&all_zeroes_mc, sizeof(struct mac_address))) {
|
|
+ memcpy((char *)mc_addr,
|
|
+ (char *)new_mc_addr, sizeof(struct mac_address));
|
|
+ LOG_DEBUG("IPv6: mc_addr added "
|
|
+ "%02x:%02x:%02x:%02x:%02x:%02x",
|
|
+ *(u8_t *)new_mc_addr,
|
|
+ *((u8_t *)new_mc_addr + 1),
|
|
+ *((u8_t *)new_mc_addr + 2),
|
|
+ *((u8_t *)new_mc_addr + 3),
|
|
+ *((u8_t *)new_mc_addr + 4),
|
|
+ *((u8_t *)new_mc_addr + 5));
|
|
+ return TRUE;
|
|
+ }
|
|
+ }
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+int iscsiL2IsOurMcAddr(struct ipv6_context *context,
|
|
+ struct mac_address *dest_mac)
|
|
+{
|
|
+ int i;
|
|
+ struct mac_address *mc_addr;
|
|
+
|
|
+ mc_addr = context->mc_addr;
|
|
+ for (i = 0; i < MAX_MCADDR_TABLE; i++, mc_addr++)
|
|
+ if (!memcmp((char *)mc_addr,
|
|
+ (char *)dest_mac->addr, sizeof(struct mac_address)))
|
|
+ return TRUE;
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+void ipv6_init(struct ndpc_state *ndp, int cfg)
|
|
+{
|
|
+ int i;
|
|
+ struct ipv6_context *context = (struct ipv6_context *)ndp->ipv6_context;
|
|
+ struct mac_address *mac_addr = (struct mac_address *)ndp->mac_addr;
|
|
+ struct ipv6_arp_entry *ipv6_arp_table;
|
|
+ struct ipv6_prefix_entry *ipv6_prefix_table;
|
|
+ struct mac_address mc_addr;
|
|
+
|
|
+ if (context == NULL) {
|
|
+ LOG_ERR("IPV6: INIT ipv6_context is NULL");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ memset((char *)context, 0, sizeof(struct ipv6_context));
|
|
+
|
|
+ /* Associate the nic_iface's ustack to this ipv6_context */
|
|
+ context->ustack = ndp->ustack;
|
|
+
|
|
+ ipv6_arp_table = &context->ipv6_arp_table[0];
|
|
+ ipv6_prefix_table = &context->ipv6_prefix_table[0];
|
|
+
|
|
+ memset((char *)ipv6_arp_table, 0, sizeof(*ipv6_arp_table));
|
|
+ memset((char *)ipv6_prefix_table, 0, sizeof(*ipv6_prefix_table));
|
|
+ memcpy((char *)&context->mac_addr,
|
|
+ (char *)mac_addr, sizeof(struct mac_address));
|
|
+ /*
|
|
+ * Per RFC 2373.
|
|
+ * There are two types of local-use unicast addresses defined. These
|
|
+ * are Link-Local and Site-Local. The Link-Local is for use on a single
|
|
+ * link and the Site-Local is for use in a single site. Link-Local
|
|
+ * addresses have the following format:
|
|
+ *
|
|
+ * | 10 |
|
|
+ * | bits | 54 bits | 64 bits |
|
|
+ * +----------+-------------------------+----------------------------+
|
|
+ * |1111111010| 0 | interface ID |
|
|
+ * +----------+-------------------------+----------------------------+
|
|
+ */
|
|
+ if (context->ustack->linklocal_autocfg != IPV6_LL_AUTOCFG_OFF) {
|
|
+ context->link_local_addr.addr8[0] = 0xfe;
|
|
+ context->link_local_addr.addr8[1] = 0x80;
|
|
+ /* Bit 1 is 1 to indicate universal scope. */
|
|
+ context->link_local_addr.addr8[8] = mac_addr->addr[0] | 0x2;
|
|
+ context->link_local_addr.addr8[9] = mac_addr->addr[1];
|
|
+ context->link_local_addr.addr8[10] = mac_addr->addr[2];
|
|
+ context->link_local_addr.addr8[11] = 0xff;
|
|
+ context->link_local_addr.addr8[12] = 0xfe;
|
|
+ context->link_local_addr.addr8[13] = mac_addr->addr[3];
|
|
+ context->link_local_addr.addr8[14] = mac_addr->addr[4];
|
|
+ context->link_local_addr.addr8[15] = mac_addr->addr[5];
|
|
+
|
|
+ context->link_local_multi.addr8[0] = 0xff;
|
|
+ context->link_local_multi.addr8[1] = 0x02;
|
|
+ context->link_local_multi.addr8[11] = 0x01;
|
|
+ context->link_local_multi.addr8[12] = 0xff;
|
|
+ context->link_local_multi.addr8[13] |=
|
|
+ context->link_local_addr.addr8[13];
|
|
+ context->link_local_multi.addr16[7] =
|
|
+ context->link_local_addr.addr16[7];
|
|
+
|
|
+ /* Default Prefix length is 64 */
|
|
+ /* Add Link local address to the head of the ipv6 address
|
|
+ list */
|
|
+ ipv6_add_prefix_entry(context,
|
|
+ &context->link_local_addr, 64);
|
|
+ }
|
|
+ /*
|
|
+ * Convert Multicast IP address to Multicast MAC adress per
|
|
+ * RFC 2464: Transmission of IPv6 Packets over Ethernet Networks
|
|
+ *
|
|
+ * An IPv6 packet with a multicast destination address DST, consisting
|
|
+ * of the sixteen octets DST[1] through DST[16], is transmitted to the
|
|
+ * Ethernet multicast address whose first two octets are the value 3333
|
|
+ * hexadecimal and whose last four octets are the last four octets of
|
|
+ * DST.
|
|
+ *
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ * |0 0 1 1 0 0 1 1|0 0 1 1 0 0 1 1|
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ * | DST[13] | DST[14] |
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ * | DST[15] | DST[16] |
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ *
|
|
+ * IPv6 requires the following Multicast IP addresses setup per node.
|
|
+ */
|
|
+ for (i = 0; i < 3; i++) {
|
|
+ mc_addr.addr[0] = 0x33;
|
|
+ mc_addr.addr[1] = 0x33;
|
|
+ mc_addr.addr[2] = 0x0;
|
|
+ mc_addr.addr[3] = 0x0;
|
|
+ mc_addr.addr[4] = 0x0;
|
|
+
|
|
+ switch (i) {
|
|
+ case 0:
|
|
+ /* All Nodes Multicast IPv6 address : ff02::1 */
|
|
+ mc_addr.addr[5] = 0x1;
|
|
+ break;
|
|
+
|
|
+ case 1:
|
|
+ /* All Host Multicast IPv6 address : ff02::3 */
|
|
+ mc_addr.addr[5] = 0x3;
|
|
+ break;
|
|
+
|
|
+ case 2:
|
|
+ /* Solicited Node Multicast Address: ff02::01:ffxx:yyzz
|
|
+ */
|
|
+ mc_addr.addr[2] = 0xff;
|
|
+ mc_addr.addr[3] = mac_addr->addr[3];
|
|
+ mc_addr.addr[4] = mac_addr->addr[4];
|
|
+ mc_addr.addr[5] = mac_addr->addr[5];
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ iscsiL2AddMcAddr(context, &mc_addr);
|
|
+ }
|
|
+
|
|
+ /* Default HOP number */
|
|
+ context->hop_limit = IPV6_HOP_LIMIT;
|
|
+}
|
|
+
|
|
+int ipv6_add_prefix_entry(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr, u8_t prefix_len)
|
|
+{
|
|
+ int i;
|
|
+ struct ipv6_prefix_entry *prefix_entry;
|
|
+ struct ipv6_prefix_entry *ipv6_prefix_table =
|
|
+ context->ipv6_prefix_table;
|
|
+ char addr_str[INET6_ADDRSTRLEN];
|
|
+
|
|
+ /* Check if there is an valid entry already. */
|
|
+ for (i = 0; i < IPV6_NUM_OF_ADDRESS_ENTRY; i++) {
|
|
+ prefix_entry = &ipv6_prefix_table[i];
|
|
+
|
|
+ if (prefix_entry->prefix_len != 0) {
|
|
+ if (memcmp((char *)&prefix_entry->ip_addr,
|
|
+ (char *)ip_addr,
|
|
+ sizeof(struct ipv6_addr)) == 0) {
|
|
+ /* We already initialize on this interface.
|
|
+ There is nothing to do */
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Find an unused entry */
|
|
+ for (i = 0; i < IPV6_NUM_OF_ADDRESS_ENTRY; i++) {
|
|
+ prefix_entry = &ipv6_prefix_table[i];
|
|
+
|
|
+ if (prefix_entry->prefix_len == 0)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (prefix_entry->prefix_len != 0)
|
|
+ return -1;
|
|
+
|
|
+ prefix_entry->prefix_len = prefix_len / 8;
|
|
+
|
|
+ memcpy((char *)&prefix_entry->ip_addr,
|
|
+ (char *)ip_addr, sizeof(struct ipv6_addr));
|
|
+
|
|
+ inet_ntop(AF_INET6, &prefix_entry->ip_addr.addr8, addr_str,
|
|
+ sizeof(addr_str));
|
|
+
|
|
+ LOG_DEBUG("IPv6: add prefix IP addr %s", addr_str);
|
|
+
|
|
+ /* Put it on the list on head of the list. */
|
|
+ if (context->addr_list != NULL)
|
|
+ prefix_entry->next = context->addr_list;
|
|
+ else
|
|
+ prefix_entry->next = NULL;
|
|
+
|
|
+ context->addr_list = prefix_entry;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void ipv6_rx_packet(struct ipv6_context *context, u16_t len)
|
|
+{
|
|
+ struct ipv6_hdr *ipv6;
|
|
+ u16_t protocol;
|
|
+
|
|
+ if (!context->ustack) {
|
|
+ LOG_WARN("ipv6 rx pkt ipv6_context = %p ustack = %p", context,
|
|
+ context->ustack);
|
|
+ return;
|
|
+ }
|
|
+ ipv6 = (struct ipv6_hdr *)context->ustack->network_layer;
|
|
+ /* Make sure it's an IPv6 packet */
|
|
+ if ((ipv6->ipv6_version_fc & 0xf0) != IPV6_VERSION) {
|
|
+ /* It's not an IPv6 packet. Drop it. */
|
|
+ LOG_WARN("IPv6 version 0x%x not IPv6", ipv6->ipv6_version_fc);
|
|
+ return;
|
|
+ }
|
|
+ protocol = ipv6_process_rx(ipv6);
|
|
+
|
|
+ switch (protocol) {
|
|
+ case IPPROTO_ICMPV6:
|
|
+ ipv6_icmp_rx(context);
|
|
+ break;
|
|
+
|
|
+ case IPPROTO_UDP:
|
|
+ /* Indicate to UDP processing code */
|
|
+ ipv6_udp_rx(context);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+void ipv6_mc_init_dest_mac(struct eth_hdr *eth, struct ipv6_hdr *ipv6)
|
|
+{
|
|
+ int i;
|
|
+ /*
|
|
+ * Initialize address mapping of IPV6 Multicast to multicast MAC
|
|
+ * address per RFC 2464.
|
|
+ *
|
|
+ * An IPv6 packet with a multicast destination address DST, consisting
|
|
+ * of the sixteen octets DST[1] through DST[16], is transmitted to the
|
|
+ * Ethernet multicast address whose first two octets are the value 3333
|
|
+ * hexadecimal and whose last four octets are the last four octets of
|
|
+ * DST.
|
|
+ *
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ * |0 0 1 1 0 0 1 1|0 0 1 1 0 0 1 1|
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ * | DST[13] | DST[14] |
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ * | DST[15] | DST[16] |
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ */
|
|
+ eth->dest_mac.addr[0] = 0x33;
|
|
+ eth->dest_mac.addr[1] = 0x33;
|
|
+ for (i = 0; i < 4; i++)
|
|
+ eth->dest_mac.addr[2 + i] = ipv6->ipv6_dst.addr8[12 + i];
|
|
+}
|
|
+
|
|
+int ipv6_autoconfig(struct ipv6_context *context)
|
|
+{
|
|
+ return ipv6_discover_address(context);
|
|
+}
|
|
+
|
|
+int ipv6_discover_address(struct ipv6_context *context)
|
|
+{
|
|
+ struct eth_hdr *eth =
|
|
+ (struct eth_hdr *)context->ustack->data_link_layer;
|
|
+ struct ipv6_hdr *ipv6 =
|
|
+ (struct ipv6_hdr *)context->ustack->network_layer;
|
|
+ struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
|
|
+ sizeof(struct ipv6_hdr));
|
|
+ int rc = 0;
|
|
+
|
|
+ /* Retrieve tx buffer */
|
|
+ if (eth == NULL || ipv6 == NULL)
|
|
+ return -EAGAIN;
|
|
+
|
|
+ /* Setup IPv6 All Routers Multicast address : ff02::2 */
|
|
+ memset((char *)&ipv6->ipv6_dst, 0, sizeof(struct ipv6_addr));
|
|
+ ipv6->ipv6_dst.addr8[0] = 0xff;
|
|
+ ipv6->ipv6_dst.addr8[1] = 0x02;
|
|
+ ipv6->ipv6_dst.addr8[15] = 0x02;
|
|
+ ipv6->ipv6_hop_limit = 255;
|
|
+
|
|
+ /* Initialize MAC header based on destination MAC address */
|
|
+ ipv6_mc_init_dest_mac(eth, ipv6);
|
|
+ ipv6->ipv6_nxt_hdr = IPPROTO_ICMPV6;
|
|
+
|
|
+ icmp->icmpv6_type = ICMPV6_RTR_SOL;
|
|
+ icmp->icmpv6_code = 0;
|
|
+ icmp->icmpv6_data = 0;
|
|
+ icmp->icmpv6_cksum = 0;
|
|
+ ipv6_icmp_init_link_option(context,
|
|
+ (struct icmpv6_opt_link_addr *)((u8_t *)icmp
|
|
+ + sizeof(struct icmpv6_hdr)),
|
|
+ IPV6_ICMP_OPTION_SRC_ADDR);
|
|
+ ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) +
|
|
+ sizeof(struct icmpv6_opt_link_addr)));
|
|
+ memcpy((char *)&ipv6->ipv6_src,
|
|
+ (char *)&context->link_local_addr,
|
|
+ sizeof(struct ipv6_addr));
|
|
+
|
|
+ icmp->icmpv6_cksum = 0;
|
|
+ LOG_DEBUG("IPv6: Send rtr sol");
|
|
+ ipv6_send(context, (u8_t *) icmp - (u8_t *) eth +
|
|
+ sizeof(struct icmpv6_hdr) +
|
|
+ sizeof(struct icmpv6_opt_link_addr));
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+u16_t ipv6_process_rx(struct ipv6_hdr *ipv6)
|
|
+{
|
|
+ return ipv6->ipv6_nxt_hdr;
|
|
+}
|
|
+
|
|
+int ipv6_send(struct ipv6_context *context, u16_t packet_len)
|
|
+{
|
|
+ struct eth_hdr *eth =
|
|
+ (struct eth_hdr *)context->ustack->data_link_layer;
|
|
+ struct ipv6_hdr *ipv6 =
|
|
+ (struct ipv6_hdr *)context->ustack->network_layer;
|
|
+
|
|
+ ipv6_setup_hdrs(context, eth, ipv6, packet_len);
|
|
+
|
|
+ return iscsiL2Send(context, packet_len);
|
|
+}
|
|
+
|
|
+void ipv6_send_udp_packet(struct ipv6_context *context, u16_t packet_len)
|
|
+{
|
|
+ struct eth_hdr *eth =
|
|
+ (struct eth_hdr *)context->ustack->data_link_layer;
|
|
+ struct ipv6_hdr *ipv6 =
|
|
+ (struct ipv6_hdr *)context->ustack->network_layer;
|
|
+ struct udp_hdr *udp = (struct udp_hdr *)((u8_t *)ipv6 +
|
|
+ sizeof(struct ipv6_hdr));
|
|
+
|
|
+ ipv6->ipv6_nxt_hdr = IPPROTO_UDP;
|
|
+ ipv6->ipv6_plen =
|
|
+ HOST_TO_NET16(packet_len - ((u8_t *)udp - (u8_t *)eth));
|
|
+
|
|
+ udp->chksum = 0;
|
|
+
|
|
+ /*
|
|
+ * We only use UDP packet for DHCPv6. The source address is always
|
|
+ * link-local address.
|
|
+ */
|
|
+ ipv6->ipv6_src.addr[0] = 0;
|
|
+
|
|
+ /* Hop limit is always 1 for DHCPv6 packet. */
|
|
+ ipv6->ipv6_hop_limit = 1;
|
|
+
|
|
+ ipv6_send(context, packet_len);
|
|
+}
|
|
+
|
|
+void ipv6_setup_hdrs(struct ipv6_context *context, struct eth_hdr *eth,
|
|
+ struct ipv6_hdr *ipv6, u16_t packet_len)
|
|
+{
|
|
+ struct ipv6_addr *our_address;
|
|
+
|
|
+ /* VLAN will be taken cared of in the nic layer */
|
|
+ eth->len_type = HOST_TO_NET16(LAYER2_TYPE_IPV6);
|
|
+ memcpy((char *)ð->src_mac,
|
|
+ (char *)&context->mac_addr, sizeof(struct mac_address));
|
|
+
|
|
+ /* Put the traffic class into the packet. */
|
|
+ memset(&ipv6->ipv6_version_fc, 0, sizeof(u32_t));
|
|
+ ipv6->ipv6_version_fc = IPV6_VERSION;
|
|
+ if (ipv6->ipv6_hop_limit == 0)
|
|
+ ipv6->ipv6_hop_limit = context->hop_limit;
|
|
+
|
|
+ if (ipv6->ipv6_src.addr[0] == 0) {
|
|
+ /* Need to initialize source IP address. */
|
|
+ our_address = ipv6_our_address(context);
|
|
+ if (our_address != NULL) {
|
|
+ /* Assume that caller has filled in the destination
|
|
+ IP address */
|
|
+ memcpy((char *)&ipv6->ipv6_src,
|
|
+ (char *)our_address, sizeof(struct ipv6_addr));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ipv6_insert_protocol_chksum(ipv6);
|
|
+}
|
|
+
|
|
+static void ipv6_insert_protocol_chksum(struct ipv6_hdr *ipv6)
|
|
+{
|
|
+ u32_t sum;
|
|
+ u16_t *ptr;
|
|
+ u16_t *protocol_data_ptr;
|
|
+ int i;
|
|
+ u16_t protocol_data_len;
|
|
+ u16_t checksum;
|
|
+
|
|
+ /*
|
|
+ * This routine assumes that there is no extension header. This driver
|
|
+ * doesn't user extension header to keep driver small and simple.
|
|
+ *
|
|
+ * Pseudo check consists of the following:
|
|
+ * SRC IP, DST IP, Protocol Data Length, and Next Header.
|
|
+ */
|
|
+ sum = 0;
|
|
+ ptr = (u16_t *)&ipv6->ipv6_src;
|
|
+
|
|
+ for (i = 0; i < sizeof(struct ipv6_addr); i++) {
|
|
+ sum += HOST_TO_NET16(*ptr);
|
|
+ ptr++;
|
|
+ }
|
|
+
|
|
+ /* Keep track where the layer header is */
|
|
+ protocol_data_ptr = ptr;
|
|
+
|
|
+ protocol_data_len = HOST_TO_NET16(ipv6->ipv6_plen);
|
|
+ sum += protocol_data_len;
|
|
+ sum += ipv6->ipv6_nxt_hdr;
|
|
+ /* Sum now contains sum of IPv6 pseudo header. Let's add the data
|
|
+ streams. */
|
|
+ if (protocol_data_len & 1) {
|
|
+ /* Length of data is odd */
|
|
+ *((u8_t *) ptr + protocol_data_len) = 0;
|
|
+ protocol_data_len++;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < protocol_data_len / 2; i++) {
|
|
+ sum += HOST_TO_NET16(*ptr);
|
|
+ ptr++;
|
|
+ }
|
|
+
|
|
+ sum = (sum >> 16) + (sum & 0xffff);
|
|
+ sum += (sum >> 16);
|
|
+ sum &= 0xffff;
|
|
+ checksum = (u16_t) (~sum);
|
|
+ checksum = HOST_TO_NET16(checksum);
|
|
+
|
|
+ switch (ipv6->ipv6_nxt_hdr) {
|
|
+ case IPPROTO_ICMPV6:
|
|
+ /* Insert correct ICMPv6 checksum */
|
|
+ ((struct icmpv6_hdr *)(protocol_data_ptr))->icmpv6_cksum =
|
|
+ checksum;
|
|
+ break;
|
|
+ case IPPROTO_UDP:
|
|
+ /* Insert correct UDP checksum */
|
|
+ ((struct udp_hdr *)protocol_data_ptr)->chksum = checksum;
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+int ipv6_is_it_our_link_local_address(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr)
|
|
+{
|
|
+ u8_t *test_addr = (u8_t *) ip_addr->addr8;
|
|
+ u8_t test_remainder;
|
|
+
|
|
+ if (test_addr[0] != context->link_local_addr.addr8[0])
|
|
+ return FALSE;
|
|
+
|
|
+ test_remainder = (test_addr[1] & 0xC0) >> 6;
|
|
+ if (test_remainder != 2)
|
|
+ return FALSE;
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static int ipv6_is_it_our_address(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ipv6_addr)
|
|
+{
|
|
+ struct ipv6_prefix_entry *ipv6_prefix;
|
|
+
|
|
+ for (ipv6_prefix = context->addr_list; ipv6_prefix != NULL;
|
|
+ ipv6_prefix = ipv6_prefix->next) {
|
|
+ if (IPV6_ARE_ADDR_EQUAL(&ipv6_prefix->ip_addr, ipv6_addr))
|
|
+ return TRUE;
|
|
+ }
|
|
+
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+struct ipv6_addr *ipv6_our_address(struct ipv6_context *context)
|
|
+{
|
|
+ return &context->link_local_addr;
|
|
+}
|
|
+
|
|
+int ipv6_ip_in_arp_table(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr,
|
|
+ struct mac_address *mac_addr)
|
|
+{
|
|
+ struct ipv6_arp_entry *arp_entry;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < UIP_ARPTAB_SIZE; i++) {
|
|
+ arp_entry = &context->ipv6_arp_table[i];
|
|
+
|
|
+ if (IPV6_ARE_ADDR_EQUAL(&arp_entry->ip_addr, ip_addr)) {
|
|
+ memcpy((char *)mac_addr, &arp_entry->mac_addr,
|
|
+ sizeof(struct mac_address));
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+struct ipv6_addr *ipv6_find_longest_match(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr)
|
|
+{
|
|
+ struct ipv6_prefix_entry *ipv6_prefix;
|
|
+ struct ipv6_prefix_entry *best_match = NULL;
|
|
+ int longest_len = -1;
|
|
+ int len;
|
|
+
|
|
+ for (ipv6_prefix = context->addr_list; ipv6_prefix != NULL;
|
|
+ ipv6_prefix = ipv6_prefix->next) {
|
|
+ if (!IPV6_IS_ADDR_LINKLOCAL(&ipv6_prefix->ip_addr)) {
|
|
+ len = best_match_bufcmp((u8_t *)&ipv6_prefix->ip_addr,
|
|
+ (u8_t *)ip_addr,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ if (len > longest_len) {
|
|
+ best_match = ipv6_prefix;
|
|
+ longest_len = len;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (best_match)
|
|
+ return &best_match->ip_addr;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+void ipv6_arp_out(struct ipv6_context *context, int *uip_len)
|
|
+{
|
|
+ /* Empty routine */
|
|
+}
|
|
+
|
|
+
|
|
+static void ipv6_update_arp_table(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr,
|
|
+ struct mac_address *mac_addr)
|
|
+{
|
|
+ struct ipv6_arp_entry *arp_entry;
|
|
+ int i;
|
|
+ struct ipv6_arp_entry *ipv6_arp_table = context->ipv6_arp_table;
|
|
+
|
|
+ LOG_DEBUG("IPv6: Neighbor update");
|
|
+ /*
|
|
+ * Walk through the ARP mapping table and try to find an entry to
|
|
+ * update. If none is found, the IP -> MAC address mapping is
|
|
+ * inserted in the ARP table.
|
|
+ */
|
|
+ for (i = 0; i < UIP_ARPTAB_SIZE; i++) {
|
|
+ arp_entry = &ipv6_arp_table[i];
|
|
+
|
|
+ /* Only check those entries that are actually in use. */
|
|
+ if (arp_entry->ip_addr.addr[0] != 0) {
|
|
+ /*
|
|
+ * Check if the source IP address of the incoming
|
|
+ * packet matches the IP address in this ARP table
|
|
+ * entry.
|
|
+ */
|
|
+ if (IPV6_ARE_ADDR_EQUAL(&arp_entry->ip_addr, ip_addr)) {
|
|
+ /* An old entry found, update this and return */
|
|
+ memcpy((char *)&arp_entry->mac_addr,
|
|
+ (char *)mac_addr,
|
|
+ sizeof(struct mac_address));
|
|
+ arp_entry->time = context->arptime;
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * If we get here, no existing ARP table entry was found, so we
|
|
+ * create one.
|
|
+ *
|
|
+ * First, we try to find an unused entry in the ARP table.
|
|
+ */
|
|
+ for (i = 0; i < UIP_ARPTAB_SIZE; i++) {
|
|
+ arp_entry = &ipv6_arp_table[i];
|
|
+
|
|
+ if (arp_entry->ip_addr.addr[0] == 0)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (i == UIP_ARPTAB_SIZE)
|
|
+ return;
|
|
+
|
|
+ /* Index j is the entry that is least used */
|
|
+ arp_entry = &ipv6_arp_table[i];
|
|
+ memcpy((char *)&arp_entry->ip_addr, (char *)ip_addr,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ memcpy((char *)&arp_entry->mac_addr,
|
|
+ (char *)mac_addr, sizeof(struct mac_address));
|
|
+
|
|
+ arp_entry->time = context->arptime;
|
|
+}
|
|
+
|
|
+/* DestIP is intact */
|
|
+int ipv6_send_nd_solicited_packet(struct ipv6_context *context,
|
|
+ struct eth_hdr *eth, struct ipv6_hdr *ipv6)
|
|
+{
|
|
+ struct icmpv6_hdr *icmp;
|
|
+ int pkt_len = 0;
|
|
+ struct ipv6_addr *longest_match_addr;
|
|
+ char addr_str[INET6_ADDRSTRLEN];
|
|
+
|
|
+ ipv6->ipv6_nxt_hdr = IPPROTO_ICMPV6;
|
|
+
|
|
+ /* Depending on the IPv6 address of the target, we'll need to determine
|
|
+ whether we use the assigned IPv6 address/RA or the link local address
|
|
+ */
|
|
+ /* Use Link-local as source address */
|
|
+ if (ipv6_is_it_our_link_local_address(context, &ipv6->ipv6_dst) ==
|
|
+ TRUE) {
|
|
+ LOG_DEBUG("IPv6: NS using link local");
|
|
+ memcpy((char *)&ipv6->ipv6_src,
|
|
+ (char *)&context->link_local_addr,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ } else {
|
|
+ longest_match_addr =
|
|
+ ipv6_find_longest_match(context, &ipv6->ipv6_dst);
|
|
+ if (longest_match_addr) {
|
|
+ LOG_DEBUG("IPv6: NS using longest match addr");
|
|
+ memcpy((char *)&ipv6->ipv6_src,
|
|
+ (char *)longest_match_addr,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ } else {
|
|
+ LOG_DEBUG("IPv6: NS using link local instead");
|
|
+ memcpy((char *)&ipv6->ipv6_src,
|
|
+ (char *)&context->link_local_addr,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ }
|
|
+ }
|
|
+ icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 + sizeof(struct ipv6_hdr));
|
|
+
|
|
+ inet_ntop(AF_INET6, &ipv6->ipv6_src.addr8, addr_str, sizeof(addr_str));
|
|
+ LOG_DEBUG("IPv6: NS host IP addr: %s", addr_str);
|
|
+ /*
|
|
+ * Destination IP address to be resolved is after the ICMPv6
|
|
+ * header.
|
|
+ */
|
|
+ memcpy((char *)((u8_t *)icmp + sizeof(struct icmpv6_hdr)),
|
|
+ (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr));
|
|
+
|
|
+ /*
|
|
+ * Destination IP in the IPv6 header contains solicited-node multicast
|
|
+ * address corresponding to the target address.
|
|
+ *
|
|
+ * ff02::01:ffxx:yyzz. Where xyz are least
|
|
+ * significant of 24-bit MAC address.
|
|
+ */
|
|
+ memset((char *)&ipv6->ipv6_dst, 0, sizeof(struct ipv6_addr) - 3);
|
|
+ ipv6->ipv6_dst.addr8[0] = 0xff;
|
|
+ ipv6->ipv6_dst.addr8[1] = 0x02;
|
|
+ ipv6->ipv6_dst.addr8[11] = 0x01;
|
|
+ ipv6->ipv6_dst.addr8[12] = 0xff;
|
|
+ ipv6_mc_init_dest_mac(eth, ipv6);
|
|
+ ipv6->ipv6_hop_limit = 255;
|
|
+
|
|
+ icmp->icmpv6_type = ICMPV6_NEIGH_SOL;
|
|
+ icmp->icmpv6_code = 0;
|
|
+ icmp->icmpv6_data = 0;
|
|
+ icmp->icmpv6_cksum = 0;
|
|
+ ipv6_icmp_init_link_option(context,
|
|
+ (struct icmpv6_opt_link_addr *)((u8_t *)icmp
|
|
+ + sizeof(struct icmpv6_hdr)
|
|
+ + sizeof(struct ipv6_addr)),
|
|
+ IPV6_ICMP_OPTION_SRC_ADDR);
|
|
+ ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) +
|
|
+ sizeof(struct icmpv6_opt_link_addr) +
|
|
+ sizeof(struct ipv6_addr)));
|
|
+ /* Total packet size */
|
|
+ pkt_len = (u8_t *) icmp - (u8_t *) eth +
|
|
+ sizeof(struct icmpv6_hdr) +
|
|
+ sizeof(struct icmpv6_opt_link_addr) + sizeof(struct ipv6_addr);
|
|
+ ipv6_setup_hdrs(context, eth, ipv6, pkt_len);
|
|
+ return pkt_len;
|
|
+}
|
|
+
|
|
+static void ipv6_icmp_init_link_option(struct ipv6_context *context,
|
|
+ struct icmpv6_opt_link_addr *link_opt,
|
|
+ u8_t type)
|
|
+{
|
|
+ link_opt->hdr.type = type;
|
|
+ link_opt->hdr.len = sizeof(struct icmpv6_opt_link_addr) / 8;
|
|
+ memcpy((char *)&link_opt->link_addr,
|
|
+ (char *)&context->mac_addr, sizeof(struct mac_address));
|
|
+}
|
|
+
|
|
+static void ipv6_icmp_rx(struct ipv6_context *context)
|
|
+{
|
|
+ struct ipv6_hdr *ipv6 =
|
|
+ (struct ipv6_hdr *)context->ustack->network_layer;
|
|
+ struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
|
|
+ sizeof(struct ipv6_hdr));
|
|
+
|
|
+ switch (icmp->icmpv6_type) {
|
|
+ case ICMPV6_RTR_ADV:
|
|
+ ipv6_icmp_handle_router_adv(context);
|
|
+ break;
|
|
+
|
|
+ case ICMPV6_NEIGH_SOL:
|
|
+ ipv6_icmp_handle_nd_sol(context);
|
|
+ break;
|
|
+
|
|
+ case ICMPV6_NEIGH_ADV:
|
|
+ ipv6_icmp_handle_nd_adv(context);
|
|
+ break;
|
|
+
|
|
+ case ICMPV6_ECHO_REQUEST:
|
|
+ /* Response with ICMP reply */
|
|
+ ipv6_icmp_handle_echo_request(context);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void ipv6_icmp_handle_router_adv(struct ipv6_context *context)
|
|
+{
|
|
+ struct ipv6_hdr *ipv6 =
|
|
+ (struct ipv6_hdr *)context->ustack->network_layer;
|
|
+ struct icmpv6_router_advert *icmp =
|
|
+ (struct icmpv6_router_advert *)((u8_t *)ipv6 + sizeof(struct ipv6_hdr));
|
|
+ struct icmpv6_opt_hdr *icmp_opt;
|
|
+ u16_t opt_len;
|
|
+ u16_t len;
|
|
+ char addr_str[INET6_ADDRSTRLEN];
|
|
+
|
|
+ if (context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED)
|
|
+ return;
|
|
+
|
|
+ opt_len = HOST_TO_NET16(ipv6->ipv6_plen) -
|
|
+ sizeof(struct icmpv6_router_advert);
|
|
+
|
|
+ icmp_opt = (struct icmpv6_opt_hdr *)((u8_t *)icmp +
|
|
+ sizeof(struct icmpv6_router_advert));
|
|
+ len = 0;
|
|
+ while (len < opt_len) {
|
|
+ icmp_opt = (struct icmpv6_opt_hdr *)((u8_t *)icmp +
|
|
+ sizeof(struct icmpv6_router_advert) +
|
|
+ len);
|
|
+
|
|
+ switch (icmp_opt->type) {
|
|
+ case IPV6_ICMP_OPTION_PREFIX:
|
|
+ ipv6_icmp_process_prefix(context,
|
|
+ (struct icmpv6_opt_prefix *)icmp_opt);
|
|
+ context->flags |= IPV6_FLAGS_ROUTER_ADV_RECEIVED;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ len += icmp_opt->len * 8;
|
|
+ }
|
|
+
|
|
+ if (context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED) {
|
|
+ LOG_DEBUG("IPv6: RTR ADV nd_ra_flags = 0x%x",
|
|
+ icmp->nd_ra_flags_reserved);
|
|
+ if (icmp->nd_ra_curhoplimit > 0)
|
|
+ context->hop_limit = icmp->nd_ra_curhoplimit;
|
|
+
|
|
+ if (icmp->nd_ra_flags_reserved & IPV6_RA_MANAGED_FLAG)
|
|
+ context->flags |= IPV6_FLAGS_MANAGED_ADDR_CONFIG;
|
|
+
|
|
+ if (icmp->nd_ra_flags_reserved & IPV6_RA_CONFIG_FLAG)
|
|
+ context->flags |= IPV6_FLAGS_OTHER_STATEFUL_CONFIG;
|
|
+
|
|
+ if (icmp->nd_ra_router_lifetime != 0) {
|
|
+ /* There is a default router. */
|
|
+ if (context->ustack->router_autocfg !=
|
|
+ IPV6_RTR_AUTOCFG_OFF)
|
|
+ memcpy(
|
|
+ (char *)&context->default_router,
|
|
+ (char *)&ipv6->ipv6_src,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ inet_ntop(AF_INET6, &context->default_router,
|
|
+ addr_str, sizeof(addr_str));
|
|
+ LOG_DEBUG("IPv6: Got default router IP addr: %s",
|
|
+ addr_str);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void ipv6_icmp_process_prefix(struct ipv6_context *context,
|
|
+ struct icmpv6_opt_prefix *icmp_prefix)
|
|
+{
|
|
+ struct ipv6_addr addr;
|
|
+ char addr_str[INET6_ADDRSTRLEN];
|
|
+
|
|
+ /* we only process on-link address info */
|
|
+ if (!(icmp_prefix->flags & ICMPV6_OPT_PREFIX_FLAG_ON_LINK))
|
|
+ return;
|
|
+
|
|
+ /*
|
|
+ * We only process prefix length of 64 since our Identifier is 64-bit
|
|
+ */
|
|
+ if (icmp_prefix->prefix_len == 64) {
|
|
+ /* Copy 64-bit from the local-link address to create
|
|
+ IPv6 address */
|
|
+ memcpy((char *)&addr,
|
|
+ (char *)&icmp_prefix->prefix, 8);
|
|
+ memcpy((char *)&addr.addr8[8],
|
|
+ &context->link_local_addr.addr8[8], 8);
|
|
+ inet_ntop(AF_INET6, &addr, addr_str, sizeof(addr_str));
|
|
+ LOG_DEBUG("IPv6: Got RA ICMP option IP addr: %s", addr_str);
|
|
+ ipv6_add_prefix_entry(context, &addr, 64);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void ipv6_icmp_handle_nd_adv(struct ipv6_context *context)
|
|
+{
|
|
+ struct eth_hdr *eth =
|
|
+ (struct eth_hdr *)context->ustack->data_link_layer;
|
|
+ struct ipv6_hdr *ipv6 =
|
|
+ (struct ipv6_hdr *)context->ustack->network_layer;
|
|
+ struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
|
|
+ sizeof(struct ipv6_hdr));
|
|
+ struct icmpv6_opt_link_addr *link_opt =
|
|
+ (struct icmpv6_opt_link_addr *)((u8_t *)icmp +
|
|
+ sizeof(struct icmpv6_hdr) + sizeof(struct ipv6_addr));
|
|
+ struct ipv6_addr *tar_addr6;
|
|
+ char addr_str[INET6_ADDRSTRLEN];
|
|
+
|
|
+ /* Added the multicast check for ARP table update */
|
|
+ /* Should we qualify for only our host's multicast and our
|
|
+ link_local_multicast?? */
|
|
+ LOG_DEBUG("IPv6: Handle nd adv");
|
|
+ if ((ipv6_is_it_our_address(context, &ipv6->ipv6_dst) == TRUE) ||
|
|
+ (memcmp((char *)&context->link_local_multi,
|
|
+ (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr)) == 0) ||
|
|
+ (memcmp((char *)&context->multi,
|
|
+ (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr)) == 0)) {
|
|
+ /*
|
|
+ * This is an ARP reply for our addresses. Let's update the
|
|
+ * ARP table.
|
|
+ */
|
|
+ ipv6_update_arp_table(context, &ipv6->ipv6_src,
|
|
+ ð->src_mac);
|
|
+
|
|
+ /* Now check for the target address option and update that as
|
|
+ well */
|
|
+ if (link_opt->hdr.type == IPV6_ICMP_OPTION_TAR_ADDR) {
|
|
+ tar_addr6 = (struct ipv6_addr *)((u8_t *)icmp +
|
|
+ sizeof(struct icmpv6_hdr));
|
|
+ LOG_DEBUG("IPV6: Target MAC "
|
|
+ "%02x:%02x:%02x:%02x:%02x:%02x",
|
|
+ link_opt->link_addr[0], link_opt->link_addr[1],
|
|
+ link_opt->link_addr[2], link_opt->link_addr[3],
|
|
+ link_opt->link_addr[4], link_opt->link_addr[5]);
|
|
+ inet_ntop(AF_INET6, &tar_addr6->addr8, addr_str,
|
|
+ sizeof(addr_str));
|
|
+ LOG_DEBUG("IPv6: Target IP addr %s", addr_str);
|
|
+ ipv6_update_arp_table(context, tar_addr6,
|
|
+ (struct mac_address *)link_opt->link_addr);
|
|
+ }
|
|
+
|
|
+ }
|
|
+}
|
|
+
|
|
+static void ipv6_icmp_handle_nd_sol(struct ipv6_context *context)
|
|
+{
|
|
+ struct eth_hdr *eth =
|
|
+ (struct eth_hdr *)context->ustack->data_link_layer;
|
|
+ struct ipv6_hdr *ipv6 =
|
|
+ (struct ipv6_hdr *)context->ustack->network_layer;
|
|
+ struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
|
|
+ sizeof(struct ipv6_hdr));
|
|
+ struct icmpv6_opt_link_addr *link_opt =
|
|
+ (struct icmpv6_opt_link_addr *)((u8_t *)icmp +
|
|
+ sizeof(struct icmpv6_hdr) + sizeof(struct ipv6_addr));
|
|
+ int icmpv6_opt_len = 0;
|
|
+ struct ipv6_addr tmp;
|
|
+ struct ipv6_addr *longest_match_addr, *tar_addr6;
|
|
+
|
|
+ LOG_DEBUG("IPv6: Handle nd sol");
|
|
+
|
|
+ if ((memcmp((char *)&context->mac_addr,
|
|
+ (char *)ð->dest_mac, sizeof(struct mac_address)) != 0) &&
|
|
+ (iscsiL2IsOurMcAddr(context, (struct mac_address *)ð->dest_mac)
|
|
+ == FALSE)) {
|
|
+ /* This packet is not for us to handle */
|
|
+ LOG_DEBUG("IPv6: MAC not addressed to us "
|
|
+ "%02x:%02x:%02x:%02x:%02x:%02x",
|
|
+ eth->dest_mac.addr[0], eth->dest_mac.addr[1],
|
|
+ eth->dest_mac.addr[2], eth->dest_mac.addr[3],
|
|
+ eth->dest_mac.addr[4], eth->dest_mac.addr[5]);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Also check for the icmpv6_data before generating the reply */
|
|
+ if (ipv6_is_it_our_address(context,
|
|
+ (struct ipv6_addr *) ((u8_t *) icmp +
|
|
+ sizeof(struct icmpv6_hdr)))
|
|
+ == FALSE) {
|
|
+ /* This packet is not for us to handle */
|
|
+ LOG_DEBUG("IPv6: IP not addressed to us");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Copy source MAC to Destination MAC */
|
|
+ memcpy((char *)ð->dest_mac,
|
|
+ (char *)ð->src_mac, sizeof(struct mac_address));
|
|
+
|
|
+ /* Dest IP contains source IP */
|
|
+ memcpy((char *)&tmp,
|
|
+ (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr));
|
|
+ memcpy((char *)&ipv6->ipv6_dst,
|
|
+ (char *)&ipv6->ipv6_src, sizeof(struct ipv6_addr));
|
|
+
|
|
+ /* Examine the Neighbor Solicitation ICMPv6 target address field.
|
|
+ If target address exist, use that to find best match src address
|
|
+ for the reply */
|
|
+ if (link_opt->hdr.type == IPV6_ICMP_OPTION_SRC_ADDR) {
|
|
+ tar_addr6 = (struct ipv6_addr *)((u8_t *)icmp +
|
|
+ sizeof(struct icmpv6_hdr));
|
|
+ if (ipv6_is_it_our_link_local_address(context, tar_addr6)
|
|
+ == TRUE) {
|
|
+ LOG_DEBUG("IPv6: NA using link local");
|
|
+ memcpy((char *)&ipv6->ipv6_src,
|
|
+ (char *)&context->link_local_addr,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ } else {
|
|
+ longest_match_addr =
|
|
+ ipv6_find_longest_match(context, tar_addr6);
|
|
+ if (longest_match_addr) {
|
|
+ LOG_DEBUG("IPv6: NA using longest match addr");
|
|
+ memcpy((char *)&ipv6->ipv6_src,
|
|
+ (char *)longest_match_addr,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ } else {
|
|
+ LOG_DEBUG("IPv6: NA using link local instead");
|
|
+ memcpy((char *)&ipv6->ipv6_src,
|
|
+ (char *)&context->link_local_addr,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ /* No target link address, just use whatever it sent to us */
|
|
+ LOG_DEBUG("IPv6: NA use dst addr");
|
|
+ memcpy((char *)&ipv6->ipv6_src,
|
|
+ (char *)&tmp,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ }
|
|
+ ipv6->ipv6_hop_limit = 255;
|
|
+ icmp->icmpv6_type = ICMPV6_NEIGH_ADV;
|
|
+ icmp->icmpv6_code = 0;
|
|
+ icmp->icmpv6_data = 0;
|
|
+ icmp->icmpv6_cksum = 0;
|
|
+ icmp->data.icmpv6_un_data8[0] =
|
|
+ IPV6_NA_FLAG_SOLICITED | IPV6_NA_FLAG_OVERRIDE;
|
|
+ memcpy((char *)((u8_t *)icmp + sizeof(struct icmpv6_hdr)),
|
|
+ (char *)&ipv6->ipv6_src,
|
|
+ sizeof(struct ipv6_addr));
|
|
+
|
|
+ /* Add the target link address option only for all solicitation */
|
|
+ ipv6_icmp_init_link_option(context,
|
|
+ (struct icmpv6_opt_link_addr *)((u8_t *)icmp +
|
|
+ sizeof(struct icmpv6_hdr) +
|
|
+ sizeof(struct ipv6_addr)),
|
|
+ IPV6_ICMP_OPTION_TAR_ADDR);
|
|
+ icmpv6_opt_len = sizeof(struct icmpv6_opt_link_addr);
|
|
+ ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) +
|
|
+ icmpv6_opt_len + sizeof(struct ipv6_addr)));
|
|
+ LOG_DEBUG("IPv6: Send nd adv");
|
|
+ ipv6_send(context,
|
|
+ (u8_t *) icmp - (u8_t *) eth +
|
|
+ sizeof(struct icmpv6_hdr) +
|
|
+ sizeof(struct icmpv6_opt_link_addr) +
|
|
+ sizeof(struct ipv6_addr));
|
|
+ return;
|
|
+}
|
|
+
|
|
+static void ipv6_icmp_handle_echo_request(struct ipv6_context *context)
|
|
+{
|
|
+ struct eth_hdr *eth =
|
|
+ (struct eth_hdr *)context->ustack->data_link_layer;
|
|
+ struct ipv6_hdr *ipv6 =
|
|
+ (struct ipv6_hdr *)context->ustack->network_layer;
|
|
+ struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
|
|
+ sizeof(struct ipv6_hdr));
|
|
+ struct ipv6_addr temp;
|
|
+
|
|
+ /* Copy source MAC to Destination MAC */
|
|
+ memcpy((char *)ð->dest_mac,
|
|
+ (char *)ð->src_mac, sizeof(struct mac_address));
|
|
+
|
|
+ memcpy((char *)&temp,
|
|
+ (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr));
|
|
+
|
|
+ /* Dest IP contains source IP */
|
|
+ memcpy((char *)&ipv6->ipv6_dst,
|
|
+ (char *)&ipv6->ipv6_src, sizeof(struct ipv6_addr));
|
|
+ /* Use Link-local as source address */
|
|
+ memcpy((char *)&ipv6->ipv6_src,
|
|
+ (char *)&temp, sizeof(struct ipv6_addr));
|
|
+
|
|
+ ipv6->ipv6_hop_limit = context->hop_limit;
|
|
+ icmp->icmpv6_type = ICMPV6_ECHO_REPLY;
|
|
+ icmp->icmpv6_code = 0;
|
|
+ icmp->icmpv6_cksum = 0;
|
|
+ LOG_DEBUG("IPv6: Send echo reply");
|
|
+ ipv6_send(context, (u8_t *) icmp - (u8_t *) eth +
|
|
+ sizeof(struct ipv6_hdr) + HOST_TO_NET16(ipv6->ipv6_plen));
|
|
+ return;
|
|
+}
|
|
+
|
|
+void ipv6_set_ip_params(struct ipv6_context *context,
|
|
+ struct ipv6_addr *src_ip, u8_t prefix_len,
|
|
+ struct ipv6_addr *default_gateway,
|
|
+ struct ipv6_addr *linklocal)
|
|
+{
|
|
+ if (!(IPV6_IS_ADDR_UNSPECIFIED(src_ip))) {
|
|
+ ipv6_add_prefix_entry(context, src_ip, prefix_len);
|
|
+ /* Create the multi_dest address */
|
|
+ memset(&context->multi_dest, 0, sizeof(struct ipv6_addr));
|
|
+ context->multi_dest.addr8[0] = 0xff;
|
|
+ context->multi_dest.addr8[1] = 0x02;
|
|
+ context->multi_dest.addr8[11] = 0x01;
|
|
+ context->multi_dest.addr8[12] = 0xff;
|
|
+ context->multi_dest.addr8[13] = src_ip->addr8[13];
|
|
+ context->multi_dest.addr16[7] = src_ip->addr16[7];
|
|
+ /* Create the multi address */
|
|
+ memset(&context->multi, 0, sizeof(struct ipv6_addr));
|
|
+ context->multi.addr8[0] = 0xfc;
|
|
+ context->multi.addr8[2] = 0x02;
|
|
+ context->multi.addr16[7] = src_ip->addr16[7];
|
|
+ }
|
|
+
|
|
+ if (!(IPV6_IS_ADDR_UNSPECIFIED(default_gateway))) {
|
|
+ /* Override the default gateway addr */
|
|
+ memcpy((char *)&context->default_router,
|
|
+ (char *)default_gateway, sizeof(struct ipv6_addr));
|
|
+ ipv6_add_prefix_entry(context, default_gateway,
|
|
+ prefix_len);
|
|
+ }
|
|
+ if (!(IPV6_IS_ADDR_UNSPECIFIED(linklocal))) {
|
|
+ /* Override the linklocal addr */
|
|
+ memcpy((char *)&context->link_local_addr,
|
|
+ (char *)linklocal, sizeof(struct ipv6_addr));
|
|
+ context->link_local_multi.addr8[0] = 0xff;
|
|
+ context->link_local_multi.addr8[1] = 0x02;
|
|
+ context->link_local_multi.addr8[11] = 0x01;
|
|
+ context->link_local_multi.addr8[12] = 0xff;
|
|
+ context->link_local_multi.addr8[13] |=
|
|
+ context->link_local_addr.addr8[13];
|
|
+ context->link_local_multi.addr16[7] =
|
|
+ context->link_local_addr.addr16[7];
|
|
+
|
|
+ /* Default Prefix length is 64 */
|
|
+ /* Add Link local address to the head of the ipv6 address
|
|
+ list */
|
|
+ ipv6_add_prefix_entry(context,
|
|
+ &context->link_local_addr, 64);
|
|
+ }
|
|
+}
|
|
+
|
|
+int ipv6_get_source_ip_addrs(struct ipv6_context *context,
|
|
+ struct ipv6_addr_entry *addr_list)
|
|
+{
|
|
+ struct ipv6_prefix_entry *ipv6_prefix;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0, ipv6_prefix = context->addr_list; ipv6_prefix != NULL;
|
|
+ ipv6_prefix = ipv6_prefix->next) {
|
|
+ memcpy((char *)&addr_list->ip_addr,
|
|
+ (char *)&ipv6_prefix->ip_addr,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ addr_list->prefix_len = ipv6_prefix->prefix_len * 8;
|
|
+
|
|
+ i++;
|
|
+ addr_list++;
|
|
+ }
|
|
+
|
|
+ return i;
|
|
+}
|
|
+
|
|
+int ipv6_get_default_router_ip_addrs(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr)
|
|
+{
|
|
+ /* This is a default router. */
|
|
+ memcpy((char *)ip_addr,
|
|
+ (char *)&context->default_router,
|
|
+ sizeof(struct ipv6_addr));
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static void ipv6_udp_rx(struct ipv6_context *context)
|
|
+{
|
|
+ struct eth_hdr *eth =
|
|
+ (struct eth_hdr *)context->ustack->data_link_layer;
|
|
+ struct ipv6_hdr *ipv6 =
|
|
+ (struct ipv6_hdr *)context->ustack->network_layer;
|
|
+ struct udp_hdr *udp = (struct udp_hdr *)((u8_t *)ipv6 +
|
|
+ sizeof(struct ipv6_hdr));
|
|
+ struct dhcpv6_context *dhcpv6c;
|
|
+
|
|
+ /*
|
|
+ * We only care about DHCPv6 packets from the DHCPv6 server. We drop
|
|
+ * all others.
|
|
+ */
|
|
+ if (!(context->flags & IPV6_FLAGS_DISABLE_DHCPV6)) {
|
|
+ if ((udp->src_port == HOST_TO_NET16(DHCPV6_SERVER_PORT)) &&
|
|
+ (udp->dest_port == HOST_TO_NET16(DHCPV6_CLIENT_PORT))) {
|
|
+ dhcpv6c = context->dhcpv6_context;
|
|
+ dhcpv6c->eth = eth;
|
|
+ dhcpv6c->ipv6 = ipv6;
|
|
+ dhcpv6c->udp = udp;
|
|
+ ipv6_udp_handle_dhcp(dhcpv6c);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+struct mac_address *ipv6_get_link_addr(struct ipv6_context *context)
|
|
+{
|
|
+ return &context->mac_addr;
|
|
+}
|
|
+
|
|
+u16_t ipv6_do_stateful_dhcpv6(struct ipv6_context *context, u32_t flags)
|
|
+{
|
|
+ u16_t task = 0;
|
|
+ u16_t ra_flags;
|
|
+
|
|
+ ra_flags = context->flags &
|
|
+ (IPV6_FLAGS_MANAGED_ADDR_CONFIG | IPV6_FLAGS_OTHER_STATEFUL_CONFIG);
|
|
+
|
|
+ if (!(context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED)) {
|
|
+ LOG_DEBUG("IPv6: There is no IPv6 router on the network");
|
|
+ ra_flags |=
|
|
+ (IPV6_FLAGS_MANAGED_ADDR_CONFIG |
|
|
+ IPV6_FLAGS_OTHER_STATEFUL_CONFIG);
|
|
+ }
|
|
+
|
|
+ if ((flags & ISCSI_FLAGS_DHCP_TCPIP_CONFIG) &&
|
|
+ (ra_flags & IPV6_FLAGS_MANAGED_ADDR_CONFIG))
|
|
+ task |= DHCPV6_TASK_GET_IP_ADDRESS;
|
|
+
|
|
+ if ((flags & ISCSI_FLAGS_DHCP_ISCSI_CONFIG) &&
|
|
+ (ra_flags & IPV6_FLAGS_OTHER_STATEFUL_CONFIG))
|
|
+ task |= DHCPV6_TASK_GET_OTHER_PARAMS;
|
|
+
|
|
+ LOG_DEBUG("IPv6: Stateful flags = 0x%x, ra_flags = 0x%x, task = 0x%x",
|
|
+ flags, ra_flags, task);
|
|
+
|
|
+ return task;
|
|
+}
|
|
+
|
|
+void ipv6_add_solit_node_address(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr)
|
|
+{
|
|
+ struct mac_address mac_addr;
|
|
+
|
|
+ /*
|
|
+ * Add Solicited Node Multicast Address for statically configured IPv6
|
|
+ * address.
|
|
+ */
|
|
+ mac_addr.addr[0] = 0x33;
|
|
+ mac_addr.addr[1] = 0x33;
|
|
+ mac_addr.addr[2] = 0xff;
|
|
+ mac_addr.addr[3] = ip_addr->addr8[13];
|
|
+ mac_addr.addr[4] = ip_addr->addr8[14];
|
|
+ mac_addr.addr[5] = ip_addr->addr8[15];
|
|
+ iscsiL2AddMcAddr(context, (struct mac_address *)&mac_addr);
|
|
+}
|
|
+
|
|
+void ipv6_cfg_link_local_addr(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr)
|
|
+{
|
|
+ memcpy((char *)&context->link_local_addr,
|
|
+ (char *)ip_addr, sizeof(struct ipv6_addr));
|
|
+}
|
|
+
|
|
+void ipv6_disable_dhcpv6(struct ipv6_context *context)
|
|
+{
|
|
+ context->flags |= IPV6_FLAGS_DISABLE_DHCPV6;
|
|
+}
|
|
diff --git a/iscsiuio/src/uip/ipv6.h b/iscsiuio/src/uip/ipv6.h
|
|
new file mode 100644
|
|
index 0000000..bc63762
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/ipv6.h
|
|
@@ -0,0 +1,332 @@
|
|
+/*
|
|
+ * Copyright (c) 2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Eddie Wai (eddie.wai@broadcom.com)
|
|
+ * Based on Kevin Tran's iSCSI boot code
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * ipv6.h - This file contains macro definitions pertaining to IPv6.
|
|
+ *
|
|
+ * RFC 2460 : IPv6 Specification.
|
|
+ * RFC 2373 : IPv6 Addressing Architecture.
|
|
+ * RFC 2462 : IPv6 Stateless Address Autoconfiguration.
|
|
+ * RFC 2464 : Transmission of IPv6 Packets over Ethernet Networks.
|
|
+ *
|
|
+ */
|
|
+#ifndef __IPV6_H__
|
|
+#define __IPV6_H__
|
|
+
|
|
+#include "ipv6_ndpc.h"
|
|
+
|
|
+#define FALSE 0
|
|
+#define TRUE 1
|
|
+
|
|
+#define LINK_LOCAL_PREFIX_LENGTH 2
|
|
+#define LAYER2_HEADER_LENGTH 14
|
|
+#define LAYER2_VLAN_HEADER_LENGTH 16
|
|
+#define LAYER2_TYPE_IPV6 0x86dd
|
|
+
|
|
+struct ipv6_addr {
|
|
+ union {
|
|
+ u8_t addr8[16];
|
|
+ u16_t addr16[8];
|
|
+ u32_t addr[4];
|
|
+ };
|
|
+};
|
|
+
|
|
+struct udp_hdr {
|
|
+ u16_t src_port;
|
|
+ u16_t dest_port;
|
|
+ u16_t length;
|
|
+ u16_t chksum;
|
|
+};
|
|
+
|
|
+struct mac_address {
|
|
+ union {
|
|
+ u8_t addr[6];
|
|
+ struct {
|
|
+ u16_t first_2_bytes;
|
|
+ u32_t last_4_bytes;
|
|
+ } __attribute__ ((packed));
|
|
+ };
|
|
+};
|
|
+
|
|
+#define HOST_TO_NET16(a) htons(a)
|
|
+#define HOST_TO_NET32(a) htonl(a)
|
|
+#define NET_TO_HOST16(a) ntohs(a)
|
|
+/*
|
|
+ * Local definition for masks
|
|
+ */
|
|
+#define IPV6_MASK0 { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }
|
|
+#define IPV6_MASK32 { { { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, \
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }
|
|
+#define IPV6_MASK64 { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }
|
|
+#define IPV6_MASK96 { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
|
|
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } }
|
|
+#define IPV6_MASK128 { { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
|
|
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } }
|
|
+
|
|
+#ifdef BIG_ENDIAN
|
|
+#define IPV6_ADDR_INT32_ONE 1
|
|
+#define IPV6_ADDR_INT32_TWO 2
|
|
+#define IPV6_ADDR_INT32_MNL 0xff010000
|
|
+#define IPV6_ADDR_INT32_MLL 0xff020000
|
|
+#define IPV6_ADDR_INT32_SMP 0x0000ffff
|
|
+#define IPV6_ADDR_INT16_ULL 0xfe80
|
|
+#define IPV6_ADDR_INT16_USL 0xfec0
|
|
+#define IPV6_ADDR_INT16_MLL 0xff02
|
|
+#else /* LITTE ENDIAN */
|
|
+#define IPV6_ADDR_INT32_ONE 0x01000000
|
|
+#define IPV6_ADDR_INT32_TWO 0x02000000
|
|
+#define IPV6_ADDR_INT32_MNL 0x000001ff
|
|
+#define IPV6_ADDR_INT32_MLL 0x000002ff
|
|
+#define IPV6_ADDR_INT32_SMP 0xffff0000
|
|
+#define IPV6_ADDR_INT16_ULL 0x80fe
|
|
+#define IPV6_ADDR_INT16_USL 0xc0fe
|
|
+#define IPV6_ADDR_INT16_MLL 0x02ff
|
|
+#endif
|
|
+
|
|
+/*
|
|
+ * Definition of some useful macros to handle IP6 addresses
|
|
+ */
|
|
+#define IPV6_ADDR_ANY_INIT \
|
|
+ { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }
|
|
+#define IPV6_ADDR_LOOPBACK_INIT \
|
|
+ { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
|
|
+#define IPV6_ADDR_NODELOCAL_ALLNODES_INIT \
|
|
+ { { { 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
|
|
+#define IPV6_ADDR_INTFACELOCAL_ALLNODES_INIT \
|
|
+ { { { 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
|
|
+#define IPV6_ADDR_LINKLOCAL_ALLNODES_INIT \
|
|
+ { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
|
|
+#define IPV6_ADDR_LINKLOCAL_ALLROUTERS_INIT \
|
|
+ { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } }
|
|
+
|
|
+#define IPV6_ARE_ADDR_EQUAL(a, b) \
|
|
+ (memcmp((char *)a, (char *)b, sizeof(struct ipv6_addr)) == 0)
|
|
+
|
|
+/* Unspecified IPv6 address */
|
|
+#define IPV6_IS_ADDR_UNSPECIFIED(a) \
|
|
+ ((((a)->addr[0]) == 0) && \
|
|
+ (((a)->addr[1]) == 0) && \
|
|
+ (((a)->addr[2]) == 0) && \
|
|
+ (((a)->addr[3]) == 0))
|
|
+
|
|
+/* IPv6 Scope Values */
|
|
+#define IPV6_ADDR_SCOPE_INTFACELOCAL 0x01 /* Node-local scope */
|
|
+#define IPV6_ADDR_SCOPE_LINKLOCAL 0x02 /* Link-local scope */
|
|
+#define IPV6_ADDR_SCOPE_SITELOCAL 0x05 /* Site-local scope */
|
|
+#define IPV6_ADDR_SCOPE_ORGLOCAL 0x08 /* Organization-local scope */
|
|
+#define IPV6_ADDR_SCOPE_GLOBAL 0x0e /* Global scope */
|
|
+
|
|
+/* Link-local Unicast : 10-bits much be 1111111010b --> 0xfe80. */
|
|
+#define IPV6_IS_ADDR_LINKLOCAL(a) \
|
|
+ (((a)->addr8[0] == 0xfe) && (((a)->addr8[1] & 0xc0) == 0x80))
|
|
+
|
|
+/* Site-local Unicast : 10-bits much be 1111111011b --> 0xfec0. */
|
|
+#define IPV6_IS_ADDR_SITELOCAL(a) \
|
|
+ (((a)->addr8[0] == 0xfe) && (((a)->addr8[1] & 0xc0) == 0xc0))
|
|
+
|
|
+/* Multicast : 10bits much be 11111111b. Next 4 bits is flags | 4-bit scope */
|
|
+#define IPV6_IS_ADDR_MULTICAST(a) ((a)->addr8[0] == 0xff)
|
|
+
|
|
+#define IPV6_ADDR_MC_SCOPE(a) ((a)->addr8[1] & 0x0f)
|
|
+
|
|
+/* Multicast Scope */
|
|
+
|
|
+struct eth_hdr {
|
|
+ struct mac_address dest_mac;
|
|
+ struct mac_address src_mac;
|
|
+ u16_t len_type;
|
|
+};
|
|
+
|
|
+struct ipv6_hdr {
|
|
+ union {
|
|
+ struct {
|
|
+ u32_t ipv6_flow; /* Version (4-bit) |
|
|
+ Traffic Class (8-bit) |
|
|
+ Flow ID (20-bit) */
|
|
+ u16_t ipv6_plen; /* Payload length */
|
|
+ u8_t ipv6_nxt_hdr; /* Next Header */
|
|
+ u8_t ipv6_hop_limit; /* hop limit */
|
|
+ } ipv6_dw1;
|
|
+
|
|
+ u8_t ipv6_version_fc; /* 4 bits version, top 4 bits class */
|
|
+ } ipv6_ctrl;
|
|
+
|
|
+ struct ipv6_addr ipv6_src; /* Source address */
|
|
+ struct ipv6_addr ipv6_dst; /* Destination address */
|
|
+};
|
|
+
|
|
+#define ipv6_version_fc ipv6_ctrl.ipv6_version_fc
|
|
+#define ipv6_flow ipv6_ctrl.ipv6_dw1.ipv6_flow
|
|
+#define ipv6_plen ipv6_ctrl.ipv6_dw1.ipv6_plen
|
|
+#define ipv6_nxt_hdr ipv6_ctrl.ipv6_dw1.ipv6_nxt_hdr
|
|
+#define ipv6_hop_limit ipv6_ctrl.ipv6_dw1.ipv6_hop_limit
|
|
+
|
|
+#define IPV6_VERSION 0x60
|
|
+#define IPV6_VERSION_MASK 0xf0
|
|
+#define IPV6_HOP_LIMIT 64
|
|
+
|
|
+/* Length of the IP header with no next header */
|
|
+#define IPV6_HEADER_LEN sizeof(struct ipv6_hdr)
|
|
+
|
|
+#ifdef BIG_ENDIAN
|
|
+#define IPV6_FLOWINFO_MASK 0x0fffffff /* flow info (28 bits) */
|
|
+#define IPV6_FLOWLABEL_MASK 0x000fffff /* flow label (20 bits) */
|
|
+#else /* LITTLE_ENDIAN */
|
|
+#define IPV6_FLOWINFO_MASK 0xffffff0f /* flow info (28 bits) */
|
|
+#define IPV6_FLOWLABEL_MASK 0xffff0f00 /* flow label (20 bits) */
|
|
+#endif
|
|
+
|
|
+struct packet_ipv6 {
|
|
+ struct mac_address dest_mac;
|
|
+ struct mac_address src_mac;
|
|
+ u16_t len_type;
|
|
+ struct ipv6_hdr ipv6;
|
|
+ union {
|
|
+ struct udp_hdr udp;
|
|
+ } layer4_prot;
|
|
+};
|
|
+
|
|
+struct packet_ipv6_vlan {
|
|
+ struct mac_address dest_mac;
|
|
+ struct mac_address src_mac;
|
|
+ u16_t len_type;
|
|
+ u16_t vlan_id;
|
|
+ struct ipv6_hdr ipv6;
|
|
+ union {
|
|
+ struct udp_hdr udp;
|
|
+ } layer4_prot;
|
|
+};
|
|
+
|
|
+struct ipv6_arp_entry {
|
|
+ struct ipv6_addr ip_addr;
|
|
+ struct mac_address mac_addr;
|
|
+ u8_t time;
|
|
+};
|
|
+
|
|
+#define IPV6_NUM_OF_ADDRESS_ENTRY 4
|
|
+
|
|
+struct ipv6_prefix_entry {
|
|
+ struct ipv6_prefix_entry *next;
|
|
+ struct ipv6_addr ip_addr;
|
|
+ u8_t prefix_len;
|
|
+};
|
|
+
|
|
+struct ipv6_addr_entry {
|
|
+ struct ipv6_addr ip_addr;
|
|
+ u8_t prefix_len;
|
|
+};
|
|
+
|
|
+struct ipv6_context {
|
|
+ u16_t flags;
|
|
+#define IPV6_FLAGS_MANAGED_ADDR_CONFIG (1 << 0)
|
|
+#define IPV6_FLAGS_OTHER_STATEFUL_CONFIG (1 << 1)
|
|
+#define IPV6_FLAGS_ROUTER_ADV_RECEIVED (1 << 2)
|
|
+#define IPV6_FLAGS_DISABLE_DHCPV6 (1 << 3)
|
|
+
|
|
+ struct mac_address mac_addr;
|
|
+ struct ipv6_addr link_local_addr;
|
|
+ struct ipv6_addr link_local_multi;
|
|
+ struct ipv6_addr multi; /* For Static IPv6 only */
|
|
+ struct ipv6_addr multi_dest; /* For Static IPv6 only */
|
|
+ struct ipv6_addr default_router;
|
|
+ struct ipv6_prefix_entry *addr_list;
|
|
+ u8_t hop_limit;
|
|
+#define UIP_ARPTAB_SIZE 8
|
|
+
|
|
+ struct uip_stack *ustack;
|
|
+#define MAX_MCADDR_TABLE 5
|
|
+ struct mac_address mc_addr[MAX_MCADDR_TABLE];
|
|
+ u8_t arptime;
|
|
+ struct ipv6_arp_entry ipv6_arp_table[UIP_ARPTAB_SIZE];
|
|
+ struct ipv6_prefix_entry ipv6_prefix_table[IPV6_NUM_OF_ADDRESS_ENTRY];
|
|
+
|
|
+ /* VLAN support */
|
|
+
|
|
+ void *dhcpv6_context;
|
|
+};
|
|
+
|
|
+#define ISCSI_FLAGS_DHCP_TCPIP_CONFIG (1<<0)
|
|
+#define ISCSI_FLAGS_DHCP_ISCSI_CONFIG (1<<1)
|
|
+
|
|
+#define IPV6_MAX_ROUTER_SOL_DELAY 4
|
|
+#define IPV6_MAX_ROUTER_SOL_RETRY 3
|
|
+
|
|
+#define DHCPV6_CLIENT_PORT 546
|
|
+#define DHCPV6_SERVER_PORT 547
|
|
+
|
|
+/* Function prototype */
|
|
+void ipv6_init(struct ndpc_state *ndp, int cfg);
|
|
+int ipv6_autoconfig(struct ipv6_context *context);
|
|
+int ipv6_discover_address(struct ipv6_context *context);
|
|
+struct ipv6_addr *ipv6_our_address(struct ipv6_context *context);
|
|
+int ipv6_ip_in_arp_table(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ipv6_addr,
|
|
+ struct mac_address *mac_addr);
|
|
+void ipv6_arp_timer(struct ipv6_context *context);
|
|
+void ipv6_arp_out(struct ipv6_context *context, int *uip_len);
|
|
+int ipv6_add_prefix_entry(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr, u8_t prefix_len);
|
|
+void ipv6_set_ip_params(struct ipv6_context *context,
|
|
+ struct ipv6_addr *src_ip, u8_t prefix_len,
|
|
+ struct ipv6_addr *default_gateway,
|
|
+ struct ipv6_addr *linklocal);
|
|
+void ipv6_set_host_addr(struct ipv6_context *context, struct ipv6_addr *src_ip);
|
|
+int ipv6_get_default_router_ip_addrs(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr);
|
|
+struct mac_address *ipv6_get_link_addr(struct ipv6_context *context);
|
|
+u16_t ipv6_do_stateful_dhcpv6(struct ipv6_context *context, u32_t flags);
|
|
+void ipv6_add_solit_node_address(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr);
|
|
+int ipv6_get_source_ip_addrs(struct ipv6_context *context,
|
|
+ struct ipv6_addr_entry *addr_list);
|
|
+void ipv6_cfg_link_local_addr(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr);
|
|
+void ipv6_disable_dhcpv6(struct ipv6_context *context);
|
|
+int ipv6_send_nd_solicited_packet(struct ipv6_context *context,
|
|
+ struct eth_hdr *eth, struct ipv6_hdr *ipv6);
|
|
+int ipv6_is_it_our_link_local_address(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr);
|
|
+void ipv6_mc_init_dest_mac(struct eth_hdr *eth, struct ipv6_hdr *ipv6);
|
|
+struct ipv6_addr *ipv6_find_longest_match(struct ipv6_context *context,
|
|
+ struct ipv6_addr *ip_addr);
|
|
+
|
|
+#endif /* __IPV6_H__ */
|
|
diff --git a/iscsiuio/src/uip/ipv6_ndpc.c b/iscsiuio/src/uip/ipv6_ndpc.c
|
|
new file mode 100644
|
|
index 0000000..a396cb7
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/ipv6_ndpc.c
|
|
@@ -0,0 +1,427 @@
|
|
+/*
|
|
+ * Copyright (c) 2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Eddie Wai (eddie.wai@broadcom.com)
|
|
+ * Based on the Swedish Institute of Computer Science's
|
|
+ * dhcpc.c code
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * ipv6_ndpc.c - Top level IPv6 Network Discovery Protocol Engine (RFC4861)
|
|
+ *
|
|
+ */
|
|
+#include <errno.h>
|
|
+#include <pthread.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <stdlib.h>
|
|
+#include <arpa/inet.h>
|
|
+
|
|
+#include "uip.h"
|
|
+#include "ipv6_ndpc.h"
|
|
+#include "timer.h"
|
|
+#include "pt.h"
|
|
+
|
|
+#include "debug.h"
|
|
+#include "logger.h"
|
|
+#include "nic.h"
|
|
+#include "nic_utils.h"
|
|
+#include "ipv6.h"
|
|
+#include "ipv6_pkt.h"
|
|
+#include "dhcpv6.h"
|
|
+
|
|
+const int dhcpv6_retry_timeout[DHCPV6_NUM_OF_RETRY] = { 1, 2, 4, 8 };
|
|
+
|
|
+static PT_THREAD(handle_ndp(struct uip_stack *ustack, int force))
|
|
+{
|
|
+ struct ndpc_state *s;
|
|
+ struct ipv6_context *ipv6c;
|
|
+ struct dhcpv6_context *dhcpv6c = NULL;
|
|
+ u16_t task = 0;
|
|
+ char buf[INET6_ADDRSTRLEN];
|
|
+
|
|
+ s = ustack->ndpc;
|
|
+ if (s == NULL) {
|
|
+ LOG_DEBUG("NDP: Could not find ndpc state");
|
|
+ return PT_ENDED;
|
|
+ }
|
|
+
|
|
+ ipv6c = s->ipv6_context;
|
|
+ if (!ipv6c)
|
|
+ goto ndpc_state_null;
|
|
+
|
|
+ dhcpv6c = s->dhcpv6_context;
|
|
+
|
|
+ PT_BEGIN(&s->pt);
|
|
+
|
|
+ if (s->state == NDPC_STATE_BACKGROUND_LOOP)
|
|
+ goto ipv6_loop;
|
|
+
|
|
+ if (s->state == NDPC_STATE_RTR_ADV)
|
|
+ goto rtr_adv;
|
|
+
|
|
+ /* For AUTOCFG == DHCPv6, do all
|
|
+ For == ND, skip DHCP only and do RTR
|
|
+ For == UNUSED/UNSPEC, do all as according to DHCP or not */
|
|
+ s->state = NDPC_STATE_RTR_SOL;
|
|
+ /* try_again: */
|
|
+ s->ticks = CLOCK_SECOND * IPV6_MAX_ROUTER_SOL_DELAY;
|
|
+ s->retry_count = 0;
|
|
+ do {
|
|
+ /* Perform router solicitation and wait for
|
|
+ router advertisement */
|
|
+ LOG_DEBUG("%s: ndpc_handle send rtr sol", s->nic->log_name);
|
|
+ ipv6_autoconfig(s->ipv6_context);
|
|
+
|
|
+ timer_set(&s->timer, s->ticks);
|
|
+wait_rtr:
|
|
+ s->ustack->uip_flags &= ~UIP_NEWDATA;
|
|
+ LOG_DEBUG("%s: ndpc_handle wait for rtr adv flags=0x%x",
|
|
+ s->nic->log_name, ipv6c->flags);
|
|
+ PT_WAIT_UNTIL(&s->pt, uip_newdata(s->ustack)
|
|
+ || timer_expired(&s->timer) || force);
|
|
+
|
|
+ if (uip_newdata(s->ustack)) {
|
|
+ /* Validate incoming packets
|
|
+ Note that the uip_len is init from nic loop */
|
|
+ ipv6_rx_packet(ipv6c, (u16_t) uip_datalen(s->ustack));
|
|
+ if (ipv6c->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED) {
|
|
+ LOG_INFO("%s: ROUTER_ADV_RECEIVED",
|
|
+ s->nic->log_name);
|
|
+ /* Success */
|
|
+ break;
|
|
+ } else if (!timer_expired(&s->timer)) {
|
|
+ /* Yes new data, but not what we want,
|
|
+ check for timer expiration before bumping
|
|
+ tick */
|
|
+ goto wait_rtr;
|
|
+ }
|
|
+ }
|
|
+ s->retry_count++;
|
|
+ if (s->retry_count >= IPV6_MAX_ROUTER_SOL_RETRY)
|
|
+ /* Max router solicitation retry reached. Move to
|
|
+ IPv6 loop (no DHCPv6) */
|
|
+ goto no_rtr_adv;
|
|
+
|
|
+ } while (!(ipv6c->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED));
|
|
+
|
|
+ LOG_DEBUG("%s: ndpc_handle got rtr adv", s->nic->log_name);
|
|
+
|
|
+no_rtr_adv:
|
|
+ s->state = NDPC_STATE_RTR_ADV;
|
|
+
|
|
+rtr_adv:
|
|
+ if (!(ustack->ip_config & IPV6_CONFIG_DHCP))
|
|
+ goto staticv6;
|
|
+
|
|
+ /* Only DHCPv6 comes here */
|
|
+ task = ipv6_do_stateful_dhcpv6(ipv6c, ISCSI_FLAGS_DHCP_TCPIP_CONFIG);
|
|
+ if (task) {
|
|
+ /* Run the DHCPv6 engine */
|
|
+
|
|
+ if (!dhcpv6c)
|
|
+ goto ipv6_loop;
|
|
+
|
|
+ dhcpv6c->dhcpv6_task = task;
|
|
+ s->retry_count = 0;
|
|
+ s->state = NDPC_STATE_DHCPV6_DIS;
|
|
+ do {
|
|
+ /* Do dhcpv6 */
|
|
+ dhcpv6c->timeout = dhcpv6_retry_timeout[s->retry_count];
|
|
+ s->ticks = CLOCK_SECOND * dhcpv6c->timeout;
|
|
+ LOG_DEBUG("%s: ndpc_handle send dhcpv6 sol retry "
|
|
+ "cnt=%d", s->nic->log_name, s->retry_count);
|
|
+ dhcpv6_do_discovery(dhcpv6c);
|
|
+
|
|
+ timer_set(&s->timer, s->ticks);
|
|
+wait_dhcp:
|
|
+ s->ustack->uip_flags &= ~UIP_NEWDATA;
|
|
+ PT_WAIT_UNTIL(&s->pt, uip_newdata(s->ustack)
|
|
+ || timer_expired(&s->timer) || force);
|
|
+
|
|
+ if (uip_newdata(s->ustack)) {
|
|
+ /* Validate incoming packets
|
|
+ Note that the uip_len is init from nic
|
|
+ loop */
|
|
+ ipv6_rx_packet(ipv6c,
|
|
+ (u16_t) uip_datalen(s->ustack));
|
|
+ if (dhcpv6c->dhcpv6_done == TRUE)
|
|
+ break;
|
|
+ else if (!timer_expired(&s->timer)) {
|
|
+ /* Yes new data, but not what we want,
|
|
+ check for timer expiration before
|
|
+ bumping tick */
|
|
+ goto wait_dhcp;
|
|
+ }
|
|
+ }
|
|
+ s->retry_count++;
|
|
+ if (s->retry_count < DHCPV6_NUM_OF_RETRY) {
|
|
+ dhcpv6c->seconds += dhcpv6c->timeout;
|
|
+ } else {
|
|
+ LOG_DEBUG("%s: ndpc_handle DHCP failed",
|
|
+ s->nic->log_name);
|
|
+ /* Allow to goto background loop */
|
|
+ goto ipv6_loop;
|
|
+ }
|
|
+ } while (dhcpv6c->dhcpv6_done == FALSE);
|
|
+ s->state = NDPC_STATE_DHCPV6_DONE;
|
|
+
|
|
+ LOG_DEBUG("%s: ndpc_handle got dhcpv6", s->nic->log_name);
|
|
+
|
|
+ /* End of DHCPv6 engine */
|
|
+ } else {
|
|
+ /* Static IPv6 */
|
|
+ if (ustack->ip_config == IPV6_CONFIG_DHCP) {
|
|
+ LOG_DEBUG("%s: ndpc_handle DHCP failed",
|
|
+ s->nic->log_name);
|
|
+ PT_RESTART(&s->pt);
|
|
+ }
|
|
+staticv6:
|
|
+ ipv6_disable_dhcpv6(ipv6c);
|
|
+ }
|
|
+ /* Copy out the default_router_addr6 and ll */
|
|
+ if (ustack->router_autocfg != IPV6_RTR_AUTOCFG_OFF)
|
|
+ memcpy(&ustack->default_route_addr6,
|
|
+ &ipv6c->default_router, sizeof(struct ipv6_addr));
|
|
+ inet_ntop(AF_INET6, &ustack->default_route_addr6,
|
|
+ buf, sizeof(buf));
|
|
+ LOG_INFO("%s: Default router IP: %s", s->nic->log_name,
|
|
+ buf);
|
|
+
|
|
+ if (ustack->linklocal_autocfg != IPV6_LL_AUTOCFG_OFF)
|
|
+ memcpy(&ustack->linklocal6, &ipv6c->link_local_addr,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ inet_ntop(AF_INET6, &ustack->linklocal6,
|
|
+ buf, sizeof(buf));
|
|
+ LOG_INFO("%s: Linklocal IP: %s", s->nic->log_name,
|
|
+ buf);
|
|
+
|
|
+ipv6_loop:
|
|
+ s->state = NDPC_STATE_BACKGROUND_LOOP;
|
|
+ LOG_DEBUG("%s: Loop", s->nic->log_name);
|
|
+ /* Background IPv6 loop */
|
|
+ while (1) {
|
|
+ /* Handle all neightbor solicitation/advertisement here */
|
|
+ s->ustack->uip_flags &= ~UIP_NEWDATA;
|
|
+ PT_WAIT_UNTIL(&s->pt, uip_newdata(s->ustack));
|
|
+
|
|
+ /* Validate incoming packets */
|
|
+ ipv6_rx_packet(ipv6c, (u16_t) uip_datalen(s->ustack));
|
|
+ }
|
|
+
|
|
+ndpc_state_null:
|
|
+
|
|
+ while (1)
|
|
+ PT_YIELD(&s->pt);
|
|
+
|
|
+ PT_END(&(s->pt));
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+int ndpc_init(nic_t *nic, struct uip_stack *ustack,
|
|
+ const void *mac_addr, int mac_len)
|
|
+{
|
|
+ struct ipv6_context *ipv6c;
|
|
+ struct dhcpv6_context *dhcpv6c;
|
|
+ struct ndpc_state *s = ustack->ndpc;
|
|
+ struct ipv6_addr src, gw, ll;
|
|
+ char buf[INET6_ADDRSTRLEN];
|
|
+
|
|
+ if (s) {
|
|
+ LOG_DEBUG("NDP: NDP context already allocated");
|
|
+ /* Already allocated, skip*/
|
|
+ return -EALREADY;
|
|
+ }
|
|
+ s = malloc(sizeof(*s));
|
|
+ if (s == NULL) {
|
|
+ LOG_ERR("%s: Couldn't allocate size for ndpc info",
|
|
+ nic->log_name);
|
|
+ goto error;
|
|
+ }
|
|
+ memset(s, 0, sizeof(*s));
|
|
+
|
|
+ if (s->ipv6_context) {
|
|
+ LOG_DEBUG("NDP: IPv6 context already allocated");
|
|
+ ipv6c = s->ipv6_context;
|
|
+ goto init1;
|
|
+ }
|
|
+ ipv6c = malloc(sizeof(struct ipv6_context));
|
|
+ if (ipv6c == NULL) {
|
|
+ LOG_ERR("%s: Couldn't allocate mem for IPv6 context info",
|
|
+ nic->log_name);
|
|
+ goto error1;
|
|
+ }
|
|
+init1:
|
|
+ if (s->dhcpv6_context) {
|
|
+ LOG_DEBUG("NDP: DHCPv6 context already allocated");
|
|
+ dhcpv6c = s->dhcpv6_context;
|
|
+ goto init2;
|
|
+ }
|
|
+ dhcpv6c = malloc(sizeof(struct dhcpv6_context));
|
|
+ if (dhcpv6c == NULL) {
|
|
+ LOG_ERR("%s: Couldn't allocate mem for DHCPv6 context info",
|
|
+ nic->log_name);
|
|
+ goto error2;
|
|
+ }
|
|
+init2:
|
|
+ memset(s, 0, sizeof(*s));
|
|
+ memset(ipv6c, 0, sizeof(*ipv6c));
|
|
+ memset(dhcpv6c, 0, sizeof(*dhcpv6c));
|
|
+
|
|
+ s->ipv6_context = ipv6c;
|
|
+ s->dhcpv6_context = dhcpv6c;
|
|
+
|
|
+ s->nic = nic;
|
|
+ s->ustack = ustack;
|
|
+ s->mac_addr = (void *)mac_addr;
|
|
+ s->mac_len = mac_len;
|
|
+ s->state = NDPC_STATE_INIT;
|
|
+
|
|
+ /* Init IPV6_CONTEXT */
|
|
+ ipv6_init(s, ustack->ip_config);
|
|
+
|
|
+ dhcpv6c->ipv6_context = ipv6c;
|
|
+ ipv6c->dhcpv6_context = dhcpv6c;
|
|
+
|
|
+ /* Init DHCPV6_CONTEXT */
|
|
+ dhcpv6_init(dhcpv6c);
|
|
+
|
|
+ ustack->ndpc = s;
|
|
+
|
|
+ PT_INIT(&s->pt);
|
|
+
|
|
+ if (ustack->ip_config == IPV6_CONFIG_DHCP) {
|
|
+ /* DHCPv6 specific */
|
|
+ memset(&src, 0, sizeof(src));
|
|
+ } else {
|
|
+ /* Static v6 specific */
|
|
+ memcpy(&src.addr8, &ustack->hostaddr6,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ ipv6_add_solit_node_address(ipv6c, &src);
|
|
+
|
|
+ inet_ntop(AF_INET6, &src.addr8, buf, sizeof(buf));
|
|
+ LOG_INFO("%s: Static hostaddr IP: %s", s->nic->log_name,
|
|
+ buf);
|
|
+ }
|
|
+ /* Copy out the default_router_addr6 and ll */
|
|
+ if (ustack->router_autocfg == IPV6_RTR_AUTOCFG_OFF)
|
|
+ memcpy(&gw.addr8, &ustack->default_route_addr6,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ else
|
|
+ memset(&gw, 0, sizeof(gw));
|
|
+
|
|
+ if (ustack->linklocal_autocfg == IPV6_LL_AUTOCFG_OFF)
|
|
+ memcpy(&ll.addr8, &ustack->linklocal6,
|
|
+ sizeof(struct ipv6_addr));
|
|
+ else
|
|
+ memset(&ll, 0, sizeof(ll));
|
|
+ ipv6_set_ip_params(ipv6c, &src,
|
|
+ ustack->prefix_len, &gw, &ll);
|
|
+
|
|
+ return 0;
|
|
+error2:
|
|
+ free(ipv6c);
|
|
+ s->ipv6_context = NULL;
|
|
+error1:
|
|
+ free(s);
|
|
+ ustack->ndpc = NULL;
|
|
+error:
|
|
+ return -ENOMEM;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+void ndpc_call(struct uip_stack *ustack)
|
|
+{
|
|
+ handle_ndp(ustack, 0);
|
|
+}
|
|
+
|
|
+void ndpc_exit(struct ndpc_state *ndp)
|
|
+{
|
|
+ LOG_DEBUG("NDP - Exit ndpc_state = %p", ndp);
|
|
+ if (!ndp)
|
|
+ return;
|
|
+ if (ndp->ipv6_context)
|
|
+ free(ndp->ipv6_context);
|
|
+ if (ndp->dhcpv6_context)
|
|
+ free(ndp->dhcpv6_context);
|
|
+ free(ndp);
|
|
+}
|
|
+
|
|
+int ndpc_request(struct uip_stack *ustack, void *in, void *out, int request)
|
|
+{
|
|
+ struct ndpc_state *s;
|
|
+ struct ipv6_context *ipv6c;
|
|
+ int ret = 0;
|
|
+
|
|
+ if (!ustack) {
|
|
+ LOG_DEBUG("NDP: ustack == NULL");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ s = ustack->ndpc;
|
|
+ if (s == NULL) {
|
|
+ LOG_DEBUG("NDP: Could not find ndpc state for request %d",
|
|
+ request);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ while (s->state != NDPC_STATE_BACKGROUND_LOOP) {
|
|
+ LOG_DEBUG("%s: ndpc state not in background loop, run handler "
|
|
+ "request = %d", s->nic->log_name, request);
|
|
+ handle_ndp(ustack, 1);
|
|
+ }
|
|
+
|
|
+ ipv6c = s->ipv6_context;
|
|
+ switch (request) {
|
|
+ case NEIGHBOR_SOLICIT:
|
|
+ *(int *)out = ipv6_send_nd_solicited_packet(ipv6c,
|
|
+ (struct eth_hdr *)((struct ndpc_reqptr *)in)->eth,
|
|
+ (struct ipv6_hdr *)((struct ndpc_reqptr *)in)->ipv6);
|
|
+ break;
|
|
+ case CHECK_LINK_LOCAL_ADDR:
|
|
+ *(int *)out = ipv6_is_it_our_link_local_address(ipv6c,
|
|
+ (struct ipv6_addr *)in);
|
|
+ break;
|
|
+ case CHECK_ARP_TABLE:
|
|
+ *(int *)out = ipv6_ip_in_arp_table(ipv6c,
|
|
+ (struct ipv6_addr *)((struct ndpc_reqptr *)in)->ipv6,
|
|
+ (struct mac_address *)((struct ndpc_reqptr *)in)->eth);
|
|
+ break;
|
|
+ case GET_HOST_ADDR:
|
|
+ *(struct ipv6_addr **)out = ipv6_find_longest_match(ipv6c,
|
|
+ (struct ipv6_addr *)in);
|
|
+ break;
|
|
+ default:
|
|
+ ret = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
diff --git a/iscsiuio/src/uip/ipv6_ndpc.h b/iscsiuio/src/uip/ipv6_ndpc.h
|
|
new file mode 100644
|
|
index 0000000..709a050
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/ipv6_ndpc.h
|
|
@@ -0,0 +1,98 @@
|
|
+/*
|
|
+ * Copyright (c) 2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Eddie Wai (eddie.wai@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * ipv6_ndpc.h - Top level IPv6 Network Discovery Protocol Engine (RFC4861)
|
|
+ *
|
|
+ */
|
|
+#ifndef __NDPC_H__
|
|
+#define __NDPC_H__
|
|
+
|
|
+#include <time.h>
|
|
+
|
|
+#include "nic.h"
|
|
+#include "timer.h"
|
|
+#include "pt.h"
|
|
+
|
|
+struct ndpc_reqptr {
|
|
+ void *eth;
|
|
+ void *ipv6;
|
|
+};
|
|
+
|
|
+struct ndpc_state {
|
|
+ struct pt pt;
|
|
+
|
|
+ nic_t *nic;
|
|
+ struct uip_stack *ustack;
|
|
+ char state;
|
|
+ struct timer timer;
|
|
+ u16_t ticks;
|
|
+ void *mac_addr;
|
|
+ int mac_len;
|
|
+ int retry_count;
|
|
+
|
|
+ time_t last_update;
|
|
+
|
|
+ void *ipv6_context;
|
|
+ void *dhcpv6_context;
|
|
+};
|
|
+
|
|
+enum {
|
|
+ NDPC_STATE_INIT,
|
|
+ NDPC_STATE_RTR_SOL,
|
|
+ NDPC_STATE_RTR_ADV,
|
|
+ NDPC_STATE_DHCPV6_DIS,
|
|
+ NDPC_STATE_DHCPV6_DONE,
|
|
+ NDPC_STATE_BACKGROUND_LOOP
|
|
+};
|
|
+
|
|
+int ndpc_init(nic_t *nic, struct uip_stack *ustack,
|
|
+ const void *mac_addr, int mac_len);
|
|
+void ndpc_call(struct uip_stack *ustack);
|
|
+void ndpc_exit(struct ndpc_state *ndp);
|
|
+
|
|
+enum {
|
|
+ NEIGHBOR_SOLICIT,
|
|
+ CHECK_LINK_LOCAL_ADDR,
|
|
+ GET_LINK_LOCAL_ADDR,
|
|
+ GET_DEFAULT_ROUTER_ADDR,
|
|
+ CHECK_ARP_TABLE,
|
|
+ GET_HOST_ADDR
|
|
+};
|
|
+
|
|
+int ndpc_request(struct uip_stack *ustack, void *in, void *out, int request);
|
|
+
|
|
+#define UIP_NDP_CALL ndpc_call
|
|
+
|
|
+#endif /* __NDPC_H__ */
|
|
diff --git a/iscsiuio/src/uip/ipv6_pkt.h b/iscsiuio/src/uip/ipv6_pkt.h
|
|
new file mode 100644
|
|
index 0000000..b42f1aa
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/ipv6_pkt.h
|
|
@@ -0,0 +1,50 @@
|
|
+/*
|
|
+ * Copyright (c) 2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Eddie Wai (eddie.wai@broadcom.com)
|
|
+ * Based on Kevin Tran's iSCSI boot code
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * ipv6_packet.h - IPv6 routine include file
|
|
+ *
|
|
+ */
|
|
+#ifndef __IPV6_PKT_H__
|
|
+#define __IPV6_PKT_H__
|
|
+
|
|
+u16_t ipv6_process_rx(struct ipv6_hdr *ipv6);
|
|
+void ipv6_rx_packet(struct ipv6_context *context, u16_t len);
|
|
+void ipv6_setup_hdrs(struct ipv6_context *context, struct eth_hdr *eth,
|
|
+ struct ipv6_hdr *ipv6, u16_t packet_len);
|
|
+int ipv6_send(struct ipv6_context *context, u16_t packet_len);
|
|
+void ipv6_send_udp_packet(struct ipv6_context *context, u16_t packet_len);
|
|
+
|
|
+#endif /* __IPV6_PKT_H__ */
|
|
diff --git a/iscsiuio/src/uip/lc-addrlabels.h b/iscsiuio/src/uip/lc-addrlabels.h
|
|
new file mode 100644
|
|
index 0000000..c394b22
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/lc-addrlabels.h
|
|
@@ -0,0 +1,80 @@
|
|
+/*
|
|
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ * Author: Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \addtogroup lc
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Implementation of local continuations based on the "Labels as
|
|
+ * values" feature of gcc
|
|
+ * \author
|
|
+ * Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ * This implementation of local continuations is based on a special
|
|
+ * feature of the GCC C compiler called "labels as values". This
|
|
+ * feature allows assigning pointers with the address of the code
|
|
+ * corresponding to a particular C label.
|
|
+ *
|
|
+ * For more information, see the GCC documentation:
|
|
+ * http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
|
|
+ *
|
|
+ * Thanks to dividuum for finding the nice local scope label
|
|
+ * implementation.
|
|
+ */
|
|
+
|
|
+#ifndef __LC_ADDRLABELS_H__
|
|
+#define __LC_ADDRLABELS_H__
|
|
+
|
|
+/** \hideinitializer */
|
|
+
|
|
+#define LC_INIT(s) (s = NULL)
|
|
+
|
|
+#define LC_RESUME(s) \
|
|
+ do { \
|
|
+ if (s != NULL) { \
|
|
+ goto *s; \
|
|
+ } \
|
|
+ } while (0)
|
|
+
|
|
+#define LC_SET(s) \
|
|
+ do { ({ __label__ resume; resume: (s) = &&resume; }); } while (0)
|
|
+
|
|
+#define LC_END(s)
|
|
+
|
|
+#endif /* __LC_ADDRLABELS_H__ */
|
|
+
|
|
+/** @} */
|
|
diff --git a/iscsiuio/src/uip/lc-switch.h b/iscsiuio/src/uip/lc-switch.h
|
|
new file mode 100644
|
|
index 0000000..1839b36
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/lc-switch.h
|
|
@@ -0,0 +1,73 @@
|
|
+/*
|
|
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ * Author: Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \addtogroup lc
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Implementation of local continuations based on switch() statment
|
|
+ * \author Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ * This implementation of local continuations uses the C switch()
|
|
+ * statement to resume execution of a function somewhere inside the
|
|
+ * function's body. The implementation is based on the fact that
|
|
+ * switch() statements are able to jump directly into the bodies of
|
|
+ * control structures such as if() or while() statmenets.
|
|
+ *
|
|
+ * This implementation borrows heavily from Simon Tatham's coroutines
|
|
+ * implementation in C:
|
|
+ * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
|
|
+ */
|
|
+
|
|
+#ifndef __LC_SWITCH_H__
|
|
+#define __LC_SWTICH_H__
|
|
+
|
|
+/* WARNING! lc implementation using switch() does not work if an
|
|
+ LC_SET() is done within another switch() statement! */
|
|
+
|
|
+/** \hideinitializer */
|
|
+#define LC_INIT(s) s = 0;
|
|
+
|
|
+#define LC_RESUME(s) switch (s) { case 0:
|
|
+
|
|
+#define LC_SET(s) s = __LINE__; case __LINE__:
|
|
+
|
|
+#define LC_END(s) }
|
|
+
|
|
+#endif /* __LC_SWITCH_H__ */
|
|
+
|
|
+/** @} */
|
|
diff --git a/iscsiuio/src/uip/lc.h b/iscsiuio/src/uip/lc.h
|
|
new file mode 100644
|
|
index 0000000..2e4a7bb
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/lc.h
|
|
@@ -0,0 +1,130 @@
|
|
+/*
|
|
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ * Author: Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \addtogroup pt
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \defgroup lc Local continuations
|
|
+ * @{
|
|
+ *
|
|
+ * Local continuations form the basis for implementing protothreads. A
|
|
+ * local continuation can be <i>set</i> in a specific function to
|
|
+ * capture the state of the function. After a local continuation has
|
|
+ * been set can be <i>resumed</i> in order to restore the state of the
|
|
+ * function at the point where the local continuation was set.
|
|
+ *
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file lc.h
|
|
+ * Local continuations
|
|
+ * \author
|
|
+ * Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifdef DOXYGEN
|
|
+/**
|
|
+ * Initialize a local continuation.
|
|
+ *
|
|
+ * This operation initializes the local continuation, thereby
|
|
+ * unsetting any previously set continuation state.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define LC_INIT(lc)
|
|
+
|
|
+/**
|
|
+ * Set a local continuation.
|
|
+ *
|
|
+ * The set operation saves the state of the function at the point
|
|
+ * where the operation is executed. As far as the set operation is
|
|
+ * concerned, the state of the function does <b>not</b> include the
|
|
+ * call-stack or local (automatic) variables, but only the program
|
|
+ * counter and such CPU registers that needs to be saved.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define LC_SET(lc)
|
|
+
|
|
+/**
|
|
+ * Resume a local continuation.
|
|
+ *
|
|
+ * The resume operation resumes a previously set local continuation, thus
|
|
+ * restoring the state in which the function was when the local
|
|
+ * continuation was set. If the local continuation has not been
|
|
+ * previously set, the resume operation does nothing.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define LC_RESUME(lc)
|
|
+
|
|
+/**
|
|
+ * Mark the end of local continuation usage.
|
|
+ *
|
|
+ * The end operation signifies that local continuations should not be
|
|
+ * used any more in the function. This operation is not needed for
|
|
+ * most implementations of local continuation, but is required by a
|
|
+ * few implementations.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define LC_END(lc)
|
|
+
|
|
+/**
|
|
+ * \var typedef lc_t;
|
|
+ *
|
|
+ * The local continuation type.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#endif /* DOXYGEN */
|
|
+
|
|
+#ifndef __LC_H__
|
|
+#define __LC_H__
|
|
+
|
|
+#ifdef LC_CONF_INCLUDE
|
|
+#include LC_CONF_INCLUDE
|
|
+#else
|
|
+#include "lc-switch.h"
|
|
+#endif /* LC_CONF_INCLUDE */
|
|
+
|
|
+#endif /* __LC_H__ */
|
|
+
|
|
+/** @} */
|
|
+/** @} */
|
|
diff --git a/iscsiuio/src/uip/psock.c b/iscsiuio/src/uip/psock.c
|
|
new file mode 100644
|
|
index 0000000..fcffbe7
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/psock.c
|
|
@@ -0,0 +1,339 @@
|
|
+/*
|
|
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ * Author: Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include "uipopt.h"
|
|
+#include "psock.h"
|
|
+#include "uip.h"
|
|
+
|
|
+#define STATE_NONE 0
|
|
+#define STATE_ACKED 1
|
|
+#define STATE_READ 2
|
|
+#define STATE_BLOCKED_NEWDATA 3
|
|
+#define STATE_BLOCKED_CLOSE 4
|
|
+#define STATE_BLOCKED_SEND 5
|
|
+#define STATE_DATA_SENT 6
|
|
+
|
|
+/*
|
|
+ * Return value of the buffering functions that indicates that a
|
|
+ * buffer was not filled by incoming data.
|
|
+ *
|
|
+ */
|
|
+#define BUF_NOT_FULL 0
|
|
+#define BUF_NOT_FOUND 0
|
|
+
|
|
+/*
|
|
+ * Return value of the buffering functions that indicates that a
|
|
+ * buffer was completely filled by incoming data.
|
|
+ *
|
|
+ */
|
|
+#define BUF_FULL 1
|
|
+
|
|
+/*
|
|
+ * Return value of the buffering functions that indicates that an
|
|
+ * end-marker byte was found.
|
|
+ *
|
|
+ */
|
|
+#define BUF_FOUND 2
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static void buf_setup(struct psock_buf *buf, u8_t *bufptr, u16_t bufsize)
|
|
+{
|
|
+ buf->ptr = bufptr;
|
|
+ buf->left = bufsize;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static u8_t
|
|
+buf_bufdata(struct psock_buf *buf, u16_t len, u8_t **dataptr, u16_t *datalen)
|
|
+{
|
|
+ if (*datalen < buf->left) {
|
|
+ memcpy(buf->ptr, *dataptr, *datalen);
|
|
+ buf->ptr += *datalen;
|
|
+ buf->left -= *datalen;
|
|
+ *dataptr += *datalen;
|
|
+ *datalen = 0;
|
|
+ return BUF_NOT_FULL;
|
|
+ } else if (*datalen == buf->left) {
|
|
+ memcpy(buf->ptr, *dataptr, *datalen);
|
|
+ buf->ptr += *datalen;
|
|
+ buf->left = 0;
|
|
+ *dataptr += *datalen;
|
|
+ *datalen = 0;
|
|
+ return BUF_FULL;
|
|
+ } else {
|
|
+ memcpy(buf->ptr, *dataptr, buf->left);
|
|
+ buf->ptr += buf->left;
|
|
+ *datalen -= buf->left;
|
|
+ *dataptr += buf->left;
|
|
+ buf->left = 0;
|
|
+ return BUF_FULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static u8_t
|
|
+buf_bufto(register struct psock_buf *buf, u8_t endmarker,
|
|
+ register u8_t **dataptr, register u16_t *datalen)
|
|
+{
|
|
+ u8_t c;
|
|
+ while (buf->left > 0 && *datalen > 0) {
|
|
+ c = *buf->ptr = **dataptr;
|
|
+ ++*dataptr;
|
|
+ ++buf->ptr;
|
|
+ --*datalen;
|
|
+ --buf->left;
|
|
+
|
|
+ if (c == endmarker)
|
|
+ return BUF_FOUND;
|
|
+ }
|
|
+
|
|
+ if (*datalen == 0)
|
|
+ return BUF_NOT_FOUND;
|
|
+
|
|
+ while (*datalen > 0) {
|
|
+ c = **dataptr;
|
|
+ --*datalen;
|
|
+ ++*dataptr;
|
|
+
|
|
+ if (c == endmarker)
|
|
+ return BUF_FOUND | BUF_FULL;
|
|
+ }
|
|
+
|
|
+ return BUF_FULL;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static char send_data(register struct psock *s)
|
|
+{
|
|
+ if (s->state != STATE_DATA_SENT || uip_rexmit(s->ustack)) {
|
|
+ if (s->sendlen > uip_mss(s->ustack))
|
|
+ uip_appsend(s->ustack, s->sendptr, uip_mss(s->ustack));
|
|
+ else
|
|
+ uip_appsend(s->ustack, s->sendptr, s->sendlen);
|
|
+ s->state = STATE_DATA_SENT;
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static char data_acked(struct psock *s)
|
|
+{
|
|
+ if (s->state == STATE_DATA_SENT && uip_acked(s->ustack)) {
|
|
+ if (s->sendlen > uip_mss(s->ustack)) {
|
|
+ s->sendlen -= uip_mss(s->ustack);
|
|
+ s->sendptr += uip_mss(s->ustack);
|
|
+ } else {
|
|
+ s->sendptr += s->sendlen;
|
|
+ s->sendlen = 0;
|
|
+ }
|
|
+ s->state = STATE_ACKED;
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+PT_THREAD(psock_send(struct uip_stack *ustack,
|
|
+ register struct psock *s, const u8_t *buf,
|
|
+ unsigned int len))
|
|
+{
|
|
+ PT_BEGIN(&s->psockpt);
|
|
+
|
|
+ /* If there is no data to send, we exit immediately. */
|
|
+ if (len == 0) {
|
|
+ PT_EXIT(&s->psockpt);
|
|
+ }
|
|
+
|
|
+ /* Save the length of and a pointer to the data that is to be
|
|
+ sent. */
|
|
+ s->sendptr = buf;
|
|
+ s->sendlen = len;
|
|
+
|
|
+ s->state = STATE_NONE;
|
|
+
|
|
+ /* We loop here until all data is sent. The s->sendlen variable is
|
|
+ updated by the data_sent() function. */
|
|
+ while (s->sendlen > 0) {
|
|
+
|
|
+ /*
|
|
+ * The condition for this PT_WAIT_UNTIL is a little tricky: the
|
|
+ * protothread will wait here until all data has been acked
|
|
+ * (data_acked() returns true) and until all data has been sent
|
|
+ * (send_data() returns true). The two functions data_acked()
|
|
+ * and send_data() must be called in succession to ensure that
|
|
+ * all data is sent. Therefore the & operator is used instead of
|
|
+ * the && operator, which would cause only the data_acked()
|
|
+ * function to be called when it returns false.
|
|
+ */
|
|
+ PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
|
|
+ }
|
|
+
|
|
+ s->state = STATE_NONE;
|
|
+
|
|
+ PT_END(&s->psockpt);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+PT_THREAD(psock_generator_send(register struct psock *s,
|
|
+ unsigned short (*generate) (void *), void *arg))
|
|
+{
|
|
+ PT_BEGIN(&s->psockpt);
|
|
+
|
|
+ /* Ensure that there is a generator function to call. */
|
|
+ if (generate == NULL) {
|
|
+ PT_EXIT(&s->psockpt);
|
|
+ }
|
|
+
|
|
+ /* Call the generator function to generate the data in the
|
|
+ uip_appdata buffer. */
|
|
+ s->sendlen = generate(arg);
|
|
+ s->sendptr = s->ustack->uip_appdata;
|
|
+
|
|
+ s->state = STATE_NONE;
|
|
+ do {
|
|
+ /* Call the generator function again if we are called to perform
|
|
+ a retransmission. */
|
|
+ if (uip_rexmit(s->ustack))
|
|
+ generate(arg);
|
|
+ /* Wait until all data is sent and acknowledged. */
|
|
+ PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
|
|
+ } while (s->sendlen > 0);
|
|
+
|
|
+ s->state = STATE_NONE;
|
|
+
|
|
+ PT_END(&s->psockpt);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+u16_t psock_datalen(struct psock *psock)
|
|
+{
|
|
+ return psock->bufsize - psock->buf.left;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+char psock_newdata(struct psock *s)
|
|
+{
|
|
+ if (s->readlen > 0) {
|
|
+ /* There is data in the uip_appdata buffer that has not yet been
|
|
+ read with the PSOCK_READ functions. */
|
|
+ return 1;
|
|
+ } else if (s->state == STATE_READ) {
|
|
+ /* All data in uip_appdata buffer already consumed. */
|
|
+ s->state = STATE_BLOCKED_NEWDATA;
|
|
+ return 0;
|
|
+ } else if (uip_newdata(s->ustack)) {
|
|
+ /* There is new data that has not been consumed. */
|
|
+ return 1;
|
|
+ } else {
|
|
+ /* There is no new data. */
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+PT_THREAD(psock_readto(register struct psock *psock, u8_t c))
|
|
+{
|
|
+ PT_BEGIN(&psock->psockpt);
|
|
+
|
|
+ buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
|
|
+
|
|
+ /* XXX: Should add buf_checkmarker() before do{} loop, if
|
|
+ incoming data has been handled while waiting for a write. */
|
|
+
|
|
+ do {
|
|
+ if (psock->readlen == 0) {
|
|
+ PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
|
|
+ psock->state = STATE_READ;
|
|
+ psock->readptr = (u8_t *) psock->ustack->uip_appdata;
|
|
+ psock->readlen = uip_datalen(psock->ustack);
|
|
+ }
|
|
+ } while ((buf_bufto(&psock->buf, c,
|
|
+ &psock->readptr,
|
|
+ &psock->readlen) & BUF_FOUND) == 0);
|
|
+
|
|
+ if (psock_datalen(psock) == 0) {
|
|
+ psock->state = STATE_NONE;
|
|
+ PT_RESTART(&psock->psockpt);
|
|
+ }
|
|
+ PT_END(&psock->psockpt);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+PT_THREAD(psock_readbuf(register struct psock *psock))
|
|
+{
|
|
+ PT_BEGIN(&psock->psockpt);
|
|
+
|
|
+ buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
|
|
+
|
|
+ /* XXX: Should add buf_checkmarker() before do{} loop, if
|
|
+ incoming data has been handled while waiting for a write. */
|
|
+
|
|
+ do {
|
|
+ if (psock->readlen == 0) {
|
|
+ PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
|
|
+ printf("Waited for newdata\n");
|
|
+ psock->state = STATE_READ;
|
|
+ psock->readptr = (u8_t *) psock->ustack->uip_appdata;
|
|
+ psock->readlen = uip_datalen(psock->ustack);
|
|
+ }
|
|
+ } while (buf_bufdata(&psock->buf, psock->bufsize,
|
|
+ &psock->readptr, &psock->readlen) != BUF_FULL);
|
|
+
|
|
+ if (psock_datalen(psock) == 0) {
|
|
+ psock->state = STATE_NONE;
|
|
+ PT_RESTART(&psock->psockpt);
|
|
+ }
|
|
+ PT_END(&psock->psockpt);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+void
|
|
+psock_init(struct uip_stack *ustack,
|
|
+ register struct psock *psock, u8_t *buffer, unsigned int buffersize)
|
|
+{
|
|
+ psock->state = STATE_NONE;
|
|
+ psock->readlen = 0;
|
|
+ psock->bufptr = buffer;
|
|
+ psock->bufsize = buffersize;
|
|
+ psock->ustack = ustack;
|
|
+ buf_setup(&psock->buf, buffer, buffersize);
|
|
+ PT_INIT(&psock->pt);
|
|
+ PT_INIT(&psock->psockpt);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
diff --git a/iscsiuio/src/uip/psock.h b/iscsiuio/src/uip/psock.h
|
|
new file mode 100644
|
|
index 0000000..ea86ef5
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/psock.h
|
|
@@ -0,0 +1,383 @@
|
|
+/*
|
|
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ * Author: Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \defgroup psock Protosockets library
|
|
+ * @{
|
|
+ *
|
|
+ * The protosocket library provides an interface to the uIP stack that is
|
|
+ * similar to the traditional BSD socket interface. Unlike programs
|
|
+ * written for the ordinary uIP event-driven interface, programs
|
|
+ * written with the protosocket library are executed in a sequential
|
|
+ * fashion and does not have to be implemented as explicit state
|
|
+ * machines.
|
|
+ *
|
|
+ * Protosockets only work with TCP connections.
|
|
+ *
|
|
+ * The protosocket library uses \ref pt protothreads to provide
|
|
+ * sequential control flow. This makes the protosockets lightweight in
|
|
+ * terms of memory, but also means that protosockets inherits the
|
|
+ * functional limitations of protothreads. Each protosocket lives only
|
|
+ * within a single function. Automatic variables (stack variables) are
|
|
+ * not retained across a protosocket library function call.
|
|
+ *
|
|
+ * \note Because the protosocket library uses protothreads, local
|
|
+ * variables will not always be saved across a call to a protosocket
|
|
+ * library function. It is therefore advised that local variables are
|
|
+ * used with extreme care.
|
|
+ *
|
|
+ * The protosocket library provides functions for sending data without
|
|
+ * having to deal with retransmissions and acknowledgements, as well
|
|
+ * as functions for reading data without having to deal with data
|
|
+ * being split across more than one TCP segment.
|
|
+ *
|
|
+ * Because each protosocket runs as a protothread, the protosocket has to be
|
|
+ * started with a call to PSOCK_BEGIN() at the start of the function
|
|
+ * in which the protosocket is used. Similarly, the protosocket protothread can
|
|
+ * be terminated by a call to PSOCK_EXIT().
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Protosocket library header file
|
|
+ * \author
|
|
+ * Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __PSOCK_H__
|
|
+#define __PSOCK_H__
|
|
+
|
|
+#include "uip.h"
|
|
+#include "uipopt.h"
|
|
+#include "pt.h"
|
|
+
|
|
+ /*
|
|
+ * The structure that holds the state of a buffer.
|
|
+ *
|
|
+ * This structure holds the state of a uIP buffer. The structure has
|
|
+ * no user-visible elements, but is used through the functions
|
|
+ * provided by the library.
|
|
+ *
|
|
+ */
|
|
+struct psock_buf {
|
|
+ u8_t *ptr;
|
|
+ unsigned short left;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * The representation of a protosocket.
|
|
+ *
|
|
+ * The protosocket structrure is an opaque structure with no user-visible
|
|
+ * elements.
|
|
+ */
|
|
+struct psock {
|
|
+ struct pt pt, psockpt; /* Protothreads - one that's using the psock
|
|
+ functions, and one that runs inside the
|
|
+ psock functions. */
|
|
+ const u8_t *sendptr; /* Pointer to the next data to be sent. */
|
|
+ u8_t *readptr; /* Pointer to the next data to be read. */
|
|
+
|
|
+ u8_t *bufptr; /* Pointer to the buffer used for buffering
|
|
+ incoming data. */
|
|
+
|
|
+ u16_t sendlen; /* The number of bytes left to be sent. */
|
|
+ u16_t readlen; /* The number of bytes left to be read. */
|
|
+
|
|
+ struct psock_buf buf; /* The structure holding the state of the
|
|
+ input buffer. */
|
|
+ unsigned int bufsize; /* The size of the input buffer. */
|
|
+
|
|
+ unsigned char state; /* The state of the protosocket. */
|
|
+
|
|
+ struct uip_stack *ustack;
|
|
+};
|
|
+
|
|
+void psock_init(struct uip_stack *ustack,
|
|
+ struct psock *psock, u8_t *buffer, unsigned int buffersize);
|
|
+/**
|
|
+ * Initialize a protosocket.
|
|
+ *
|
|
+ * This macro initializes a protosocket and must be called before the
|
|
+ * protosocket is used. The initialization also specifies the input buffer
|
|
+ * for the protosocket.
|
|
+ *
|
|
+ * \param psock (struct psock *) A pointer to the protosocket to be
|
|
+ * initialized
|
|
+ *
|
|
+ * \param buffer (char *) A pointer to the input buffer for the
|
|
+ * protosocket.
|
|
+ *
|
|
+ * \param buffersize (unsigned int) The size of the input buffer.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_INIT(psock, buffer, buffersize) \
|
|
+ psock_init(psock, buffer, buffersize)
|
|
+
|
|
+/**
|
|
+ * Start the protosocket protothread in a function.
|
|
+ *
|
|
+ * This macro starts the protothread associated with the protosocket and
|
|
+ * must come before other protosocket calls in the function it is used.
|
|
+ *
|
|
+ * \param psock (struct psock *) A pointer to the protosocket to be
|
|
+ * started.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_BEGIN(psock) PT_BEGIN(&((psock)->pt))
|
|
+
|
|
+PT_THREAD(psock_send(struct uip_stack *ustack,
|
|
+ struct psock *psock, const u8_t *buf, unsigned int len));
|
|
+/**
|
|
+ * Send data.
|
|
+ *
|
|
+ * This macro sends data over a protosocket. The protosocket protothread blocks
|
|
+ * until all data has been sent and is known to have been received by
|
|
+ * the remote end of the TCP connection.
|
|
+ *
|
|
+ * \param psock (struct psock *) A pointer to the protosocket over which
|
|
+ * data is to be sent.
|
|
+ *
|
|
+ * \param data (char *) A pointer to the data that is to be sent.
|
|
+ *
|
|
+ * \param datalen (unsigned int) The length of the data that is to be
|
|
+ * sent.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_SEND(psock, data, datalen) \
|
|
+ PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, data, datalen))
|
|
+
|
|
+/**
|
|
+ * \brief Send a null-terminated string.
|
|
+ * \param psock Pointer to the protosocket.
|
|
+ * \param str The string to be sent.
|
|
+ *
|
|
+ * This function sends a null-terminated string over the
|
|
+ * protosocket.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_SEND_STR(psock, str) \
|
|
+ PT_WAIT_THREAD(&((psock)->pt), psock_send(psock, str, strlen(str)))
|
|
+
|
|
+PT_THREAD(psock_generator_send(struct psock *psock,
|
|
+ unsigned short (*f) (void *), void *arg));
|
|
+
|
|
+/**
|
|
+ * \brief Generate data with a function and send it
|
|
+ * \param psock Pointer to the protosocket.
|
|
+ * \param generator Pointer to the generator function
|
|
+ * \param arg Argument to the generator function
|
|
+ *
|
|
+ * This function generates data and sends it over the
|
|
+ * protosocket. This can be used to dynamically generate
|
|
+ * data for a transmission, instead of generating the data
|
|
+ * in a buffer beforehand. This function reduces the need for
|
|
+ * buffer memory. The generator function is implemented by
|
|
+ * the application, and a pointer to the function is given
|
|
+ * as an argument with the call to PSOCK_GENERATOR_SEND().
|
|
+ *
|
|
+ * The generator function should place the generated data
|
|
+ * directly in the uip_appdata buffer, and return the
|
|
+ * length of the generated data. The generator function is
|
|
+ * called by the protosocket layer when the data first is
|
|
+ * sent, and once for every retransmission that is needed.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_GENERATOR_SEND(psock, generator, arg) \
|
|
+ PT_WAIT_THREAD(&((psock)->pt), \
|
|
+ psock_generator_send(psock, generator, arg))
|
|
+
|
|
+/**
|
|
+ * Close a protosocket.
|
|
+ *
|
|
+ * This macro closes a protosocket and can only be called from within the
|
|
+ * protothread in which the protosocket lives.
|
|
+ *
|
|
+ * \param psock (struct psock *) A pointer to the protosocket that is to
|
|
+ * be closed.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_CLOSE(psock) uip_close()
|
|
+
|
|
+PT_THREAD(psock_readbuf(struct psock *psock));
|
|
+/**
|
|
+ * Read data until the buffer is full.
|
|
+ *
|
|
+ * This macro will block waiting for data and read the data into the
|
|
+ * input buffer specified with the call to PSOCK_INIT(). Data is read
|
|
+ * until the buffer is full..
|
|
+ *
|
|
+ * \param psock (struct psock *) A pointer to the protosocket from which
|
|
+ * data should be read.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_READBUF(psock) \
|
|
+ PT_WAIT_THREAD(&((psock)->pt), psock_readbuf(psock))
|
|
+
|
|
+PT_THREAD(psock_readto(struct psock *psock, unsigned char c));
|
|
+/**
|
|
+ * Read data up to a specified character.
|
|
+ *
|
|
+ * This macro will block waiting for data and read the data into the
|
|
+ * input buffer specified with the call to PSOCK_INIT(). Data is only
|
|
+ * read until the specifieed character appears in the data stream.
|
|
+ *
|
|
+ * \param psock (struct psock *) A pointer to the protosocket from which
|
|
+ * data should be read.
|
|
+ *
|
|
+ * \param c (char) The character at which to stop reading.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_READTO(psock, c) \
|
|
+ PT_WAIT_THREAD(&((psock)->pt), psock_readto(psock, c))
|
|
+
|
|
+/**
|
|
+ * The length of the data that was previously read.
|
|
+ *
|
|
+ * This macro returns the length of the data that was previously read
|
|
+ * using PSOCK_READTO() or PSOCK_READ().
|
|
+ *
|
|
+ * \param psock (struct psock *) A pointer to the protosocket holding the data.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_DATALEN(psock) psock_datalen(psock)
|
|
+
|
|
+u16_t psock_datalen(struct psock *psock);
|
|
+
|
|
+/**
|
|
+ * Exit the protosocket's protothread.
|
|
+ *
|
|
+ * This macro terminates the protothread of the protosocket and should
|
|
+ * almost always be used in conjunction with PSOCK_CLOSE().
|
|
+ *
|
|
+ * \sa PSOCK_CLOSE_EXIT()
|
|
+ *
|
|
+ * \param psock (struct psock *) A pointer to the protosocket.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_EXIT(psock) PT_EXIT(&((psock)->pt))
|
|
+
|
|
+/**
|
|
+ * Close a protosocket and exit the protosocket's protothread.
|
|
+ *
|
|
+ * This macro closes a protosocket and exits the protosocket's protothread.
|
|
+ *
|
|
+ * \param psock (struct psock *) A pointer to the protosocket.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_CLOSE_EXIT(psock) \
|
|
+ do { \
|
|
+ PSOCK_CLOSE(psock); \
|
|
+ PSOCK_EXIT(psock); \
|
|
+ } while (0)
|
|
+
|
|
+/**
|
|
+ * Declare the end of a protosocket's protothread.
|
|
+ *
|
|
+ * This macro is used for declaring that the protosocket's protothread
|
|
+ * ends. It must always be used together with a matching PSOCK_BEGIN()
|
|
+ * macro.
|
|
+ *
|
|
+ * \param psock (struct psock *) A pointer to the protosocket.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_END(psock) PT_END(&((psock)->pt))
|
|
+
|
|
+char psock_newdata(struct psock *s);
|
|
+
|
|
+/**
|
|
+ * Check if new data has arrived on a protosocket.
|
|
+ *
|
|
+ * This macro is used in conjunction with the PSOCK_WAIT_UNTIL()
|
|
+ * macro to check if data has arrived on a protosocket.
|
|
+ *
|
|
+ * \param psock (struct psock *) A pointer to the protosocket.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_NEWDATA(psock) psock_newdata(psock)
|
|
+
|
|
+/**
|
|
+ * Wait until a condition is true.
|
|
+ *
|
|
+ * This macro blocks the protothread until the specified condition is
|
|
+ * true. The macro PSOCK_NEWDATA() can be used to check if new data
|
|
+ * arrives when the protosocket is waiting.
|
|
+ *
|
|
+ * Typically, this macro is used as follows:
|
|
+ *
|
|
+ \code
|
|
+ PT_THREAD(thread(struct psock *s, struct timer *t))
|
|
+ {
|
|
+ PSOCK_BEGIN(s);
|
|
+
|
|
+ PSOCK_WAIT_UNTIL(s, PSOCK_NEWADATA(s) || timer_expired(t));
|
|
+
|
|
+ if(PSOCK_NEWDATA(s)) {
|
|
+ PSOCK_READTO(s, '\n');
|
|
+ } else {
|
|
+ handle_timed_out(s);
|
|
+ }
|
|
+
|
|
+ PSOCK_END(s);
|
|
+ }
|
|
+ \endcode
|
|
+ *
|
|
+ * \param psock (struct psock *) A pointer to the protosocket.
|
|
+ * \param condition The condition to wait for.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PSOCK_WAIT_UNTIL(psock, condition) \
|
|
+ PT_WAIT_UNTIL(&((psock)->pt), (condition));
|
|
+
|
|
+#define PSOCK_WAIT_THREAD(psock, condition) \
|
|
+ PT_WAIT_THREAD(&((psock)->pt), (condition))
|
|
+
|
|
+#endif /* __PSOCK_H__ */
|
|
+
|
|
+/** @} */
|
|
diff --git a/iscsiuio/src/uip/pt.h b/iscsiuio/src/uip/pt.h
|
|
new file mode 100644
|
|
index 0000000..ffb1d15
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/pt.h
|
|
@@ -0,0 +1,322 @@
|
|
+/*
|
|
+ * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ * Author: Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \addtogroup pt
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Protothreads implementation.
|
|
+ * \author
|
|
+ * Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __PT_H__
|
|
+#define __PT_H__
|
|
+
|
|
+#include "lc.h"
|
|
+
|
|
+struct pt {
|
|
+ unsigned short lc;
|
|
+};
|
|
+
|
|
+#define PT_WAITING 0
|
|
+#define PT_EXITED 1
|
|
+#define PT_ENDED 2
|
|
+#define PT_YIELDED 3
|
|
+
|
|
+/**
|
|
+ * \name Initialization
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Initialize a protothread.
|
|
+ *
|
|
+ * Initializes a protothread. Initialization must be done prior to
|
|
+ * starting to execute the protothread.
|
|
+ *
|
|
+ * \param pt A pointer to the protothread control structure.
|
|
+ *
|
|
+ * \sa PT_SPAWN()
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_INIT(pt) LC_INIT((pt)->lc)
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/**
|
|
+ * \name Declaration and definition
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Declaration of a protothread.
|
|
+ *
|
|
+ * This macro is used to declare a protothread. All protothreads must
|
|
+ * be declared with this macro.
|
|
+ *
|
|
+ * \param name_args The name and arguments of the C function
|
|
+ * implementing the protothread.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_THREAD(name_args) char name_args
|
|
+
|
|
+/**
|
|
+ * Declare the start of a protothread inside the C function
|
|
+ * implementing the protothread.
|
|
+ *
|
|
+ * This macro is used to declare the starting point of a
|
|
+ * protothread. It should be placed at the start of the function in
|
|
+ * which the protothread runs. All C statements above the PT_BEGIN()
|
|
+ * invokation will be executed each time the protothread is scheduled.
|
|
+ *
|
|
+ * \param pt A pointer to the protothread control structure.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_BEGIN(pt) { char PT_YIELD_FLAG __attribute__((__unused__)) = 1; LC_RESUME((pt)->lc)
|
|
+
|
|
+/**
|
|
+ * Declare the end of a protothread.
|
|
+ *
|
|
+ * This macro is used for declaring that a protothread ends. It must
|
|
+ * always be used together with a matching PT_BEGIN() macro.
|
|
+ *
|
|
+ * \param pt A pointer to the protothread control structure.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \
|
|
+ PT_INIT(pt); return PT_ENDED; }
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/**
|
|
+ * \name Blocked wait
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Block and wait until condition is true.
|
|
+ *
|
|
+ * This macro blocks the protothread until the specified condition is
|
|
+ * true.
|
|
+ *
|
|
+ * \param pt A pointer to the protothread control structure.
|
|
+ * \param condition The condition.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_WAIT_UNTIL(pt, condition) \
|
|
+ do { \
|
|
+ LC_SET((pt)->lc); \
|
|
+ if (!(condition)) { \
|
|
+ return PT_WAITING; \
|
|
+ } \
|
|
+ } while (0)
|
|
+
|
|
+/**
|
|
+ * Block and wait while condition is true.
|
|
+ *
|
|
+ * This function blocks and waits while condition is true. See
|
|
+ * PT_WAIT_UNTIL().
|
|
+ *
|
|
+ * \param pt A pointer to the protothread control structure.
|
|
+ * \param cond The condition.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond))
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/**
|
|
+ * \name Hierarchical protothreads
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Block and wait until a child protothread completes.
|
|
+ *
|
|
+ * This macro schedules a child protothread. The current protothread
|
|
+ * will block until the child protothread completes.
|
|
+ *
|
|
+ * \note The child protothread must be manually initialized with the
|
|
+ * PT_INIT() function before this function is used.
|
|
+ *
|
|
+ * \param pt A pointer to the protothread control structure.
|
|
+ * \param thread The child protothread with arguments
|
|
+ *
|
|
+ * \sa PT_SPAWN()
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread))
|
|
+
|
|
+/**
|
|
+ * Spawn a child protothread and wait until it exits.
|
|
+ *
|
|
+ * This macro spawns a child protothread and waits until it exits. The
|
|
+ * macro can only be used within a protothread.
|
|
+ *
|
|
+ * \param pt A pointer to the protothread control structure.
|
|
+ * \param child A pointer to the child protothread's control structure.
|
|
+ * \param thread The child protothread with arguments
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_SPAWN(pt, child, thread) \
|
|
+ do { \
|
|
+ PT_INIT((child)); \
|
|
+ PT_WAIT_THREAD((pt), (thread)); \
|
|
+ } while (0)
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/**
|
|
+ * \name Exiting and restarting
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Restart the protothread.
|
|
+ *
|
|
+ * This macro will block and cause the running protothread to restart
|
|
+ * its execution at the place of the PT_BEGIN() call.
|
|
+ *
|
|
+ * \param pt A pointer to the protothread control structure.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_RESTART(pt) \
|
|
+ do { \
|
|
+ PT_INIT(pt); \
|
|
+ return PT_WAITING; \
|
|
+ } while (0)
|
|
+
|
|
+/**
|
|
+ * Exit the protothread.
|
|
+ *
|
|
+ * This macro causes the protothread to exit. If the protothread was
|
|
+ * spawned by another protothread, the parent protothread will become
|
|
+ * unblocked and can continue to run.
|
|
+ *
|
|
+ * \param pt A pointer to the protothread control structure.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_EXIT(pt) \
|
|
+ do { \
|
|
+ PT_INIT(pt); \
|
|
+ return PT_EXITED; \
|
|
+ } while (0)
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/**
|
|
+ * \name Calling a protothread
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Schedule a protothread.
|
|
+ *
|
|
+ * This function shedules a protothread. The return value of the
|
|
+ * function is non-zero if the protothread is running or zero if the
|
|
+ * protothread has exited.
|
|
+ *
|
|
+ * \param f The call to the C function implementing the protothread to
|
|
+ * be scheduled
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_SCHEDULE(f) ((f) == PT_WAITING)
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/**
|
|
+ * \name Yielding from a protothread
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Yield from the current protothread.
|
|
+ *
|
|
+ * This function will yield the protothread, thereby allowing other
|
|
+ * processing to take place in the system.
|
|
+ *
|
|
+ * \param pt A pointer to the protothread control structure.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_YIELD(pt) \
|
|
+ do { \
|
|
+ PT_YIELD_FLAG = 0; \
|
|
+ LC_SET((pt)->lc); \
|
|
+ if (PT_YIELD_FLAG == 0) { \
|
|
+ return PT_YIELDED; \
|
|
+ } \
|
|
+ } while (0)
|
|
+
|
|
+/**
|
|
+ * \brief Yield from the protothread until a condition occurs.
|
|
+ * \param pt A pointer to the protothread control structure.
|
|
+ * \param cond The condition.
|
|
+ *
|
|
+ * This function will yield the protothread, until the
|
|
+ * specified condition evaluates to true.
|
|
+ *
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define PT_YIELD_UNTIL(pt, cond) \
|
|
+ do { \
|
|
+ PT_YIELD_FLAG = 0; \
|
|
+ LC_SET((pt)->lc); \
|
|
+ if ((PT_YIELD_FLAG == 0) || !(cond)) { \
|
|
+ return PT_YIELDED; \
|
|
+ } \
|
|
+ } while (0)
|
|
+
|
|
+/** @} */
|
|
+
|
|
+#endif /* __PT_H__ */
|
|
+
|
|
+/** @} */
|
|
diff --git a/iscsiuio/src/uip/timer.c b/iscsiuio/src/uip/timer.c
|
|
new file mode 100644
|
|
index 0000000..da77148
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/timer.c
|
|
@@ -0,0 +1,127 @@
|
|
+/**
|
|
+ * \addtogroup timer
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Timer library implementation.
|
|
+ * \author
|
|
+ * Adam Dunkels <adam@sics.se>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ * Author: Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include "clock.h"
|
|
+#include "timer.h"
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+/**
|
|
+ * Set a timer.
|
|
+ *
|
|
+ * This function is used to set a timer for a time sometime in the
|
|
+ * future. The function timer_expired() will evaluate to true after
|
|
+ * the timer has expired.
|
|
+ *
|
|
+ * \param t A pointer to the timer
|
|
+ * \param interval The interval before the timer expires.
|
|
+ *
|
|
+ */
|
|
+void timer_set(struct timer *t, clock_time_t interval)
|
|
+{
|
|
+ t->interval = interval;
|
|
+ t->start = clock_time();
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+/**
|
|
+ * Reset the timer with the same interval.
|
|
+ *
|
|
+ * This function resets the timer with the same interval that was
|
|
+ * given to the timer_set() function. The start point of the interval
|
|
+ * is the exact time that the timer last expired. Therefore, this
|
|
+ * function will cause the timer to be stable over time, unlike the
|
|
+ * timer_rester() function.
|
|
+ *
|
|
+ * \param t A pointer to the timer.
|
|
+ *
|
|
+ * \sa timer_restart()
|
|
+ */
|
|
+void timer_reset(struct timer *t)
|
|
+{
|
|
+ t->start += t->interval;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+/**
|
|
+ * Restart the timer from the current point in time
|
|
+ *
|
|
+ * This function restarts a timer with the same interval that was
|
|
+ * given to the timer_set() function. The timer will start at the
|
|
+ * current time.
|
|
+ *
|
|
+ * \note A periodic timer will drift if this function is used to reset
|
|
+ * it. For preioric timers, use the timer_reset() function instead.
|
|
+ *
|
|
+ * \param t A pointer to the timer.
|
|
+ *
|
|
+ * \sa timer_reset()
|
|
+ */
|
|
+void timer_restart(struct timer *t)
|
|
+{
|
|
+ t->start = clock_time();
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+/**
|
|
+ * Check if a timer has expired.
|
|
+ *
|
|
+ * This function tests if a timer has expired and returns true or
|
|
+ * false depending on its status.
|
|
+ *
|
|
+ * \param t A pointer to the timer
|
|
+ *
|
|
+ * \return Non-zero if the timer has expired, zero otherwise.
|
|
+ *
|
|
+ */
|
|
+int timer_expired(struct timer *t)
|
|
+{
|
|
+ return (clock_time_t) (clock_time() - t->start) >=
|
|
+ (clock_time_t) t->interval;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+
|
|
+/** @} */
|
|
diff --git a/iscsiuio/src/uip/timer.h b/iscsiuio/src/uip/timer.h
|
|
new file mode 100644
|
|
index 0000000..12739fd
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/timer.h
|
|
@@ -0,0 +1,84 @@
|
|
+/**
|
|
+ * \defgroup timer Timer library
|
|
+ *
|
|
+ * The timer library provides functions for setting, resetting and
|
|
+ * restarting timers, and for checking if a timer has expired. An
|
|
+ * application must "manually" check if its timers have expired; this
|
|
+ * is not done automatically.
|
|
+ *
|
|
+ * A timer is declared as a \c struct \c timer and all access to the
|
|
+ * timer is made by a pointer to the declared timer.
|
|
+ *
|
|
+ * \note The timer library uses the \ref clock "Clock library" to
|
|
+ * measure time. Intervals should be specified in the format used by
|
|
+ * the clock library.
|
|
+ *
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Timer library header file.
|
|
+ * \author
|
|
+ * Adam Dunkels <adam@sics.se>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2004, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ * Author: Adam Dunkels <adam@sics.se>
|
|
+ *
|
|
+ */
|
|
+#ifndef __TIMER_H__
|
|
+#define __TIMER_H__
|
|
+
|
|
+#include "clock.h"
|
|
+
|
|
+/**
|
|
+ * A timer.
|
|
+ *
|
|
+ * This structure is used for declaring a timer. The timer must be set
|
|
+ * with timer_set() before it can be used.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+struct timer {
|
|
+ clock_time_t start;
|
|
+ clock_time_t interval;
|
|
+};
|
|
+
|
|
+void timer_set(struct timer *t, clock_time_t interval);
|
|
+void timer_reset(struct timer *t);
|
|
+void timer_restart(struct timer *t);
|
|
+int timer_expired(struct timer *t);
|
|
+
|
|
+#endif /* __TIMER_H__ */
|
|
+
|
|
+/** @} */
|
|
diff --git a/iscsiuio/src/uip/uip-neighbor.c b/iscsiuio/src/uip/uip-neighbor.c
|
|
new file mode 100644
|
|
index 0000000..4c80c32
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/uip-neighbor.c
|
|
@@ -0,0 +1,219 @@
|
|
+/*
|
|
+ * Copyright (c) 2006, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Database of link-local neighbors, used by IPv6 code and
|
|
+ * to be used by a future ARP code rewrite.
|
|
+ * \author
|
|
+ * Adam Dunkels <adam@sics.se>
|
|
+ */
|
|
+
|
|
+#include "logger.h"
|
|
+#include "uip.h"
|
|
+#include "uip-neighbor.h"
|
|
+
|
|
+#include <errno.h>
|
|
+#include <string.h>
|
|
+#include <arpa/inet.h>
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Constants
|
|
+ ******************************************************************************/
|
|
+#define PFX "uip-neigh "
|
|
+
|
|
+#define MAX_TIME 128
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+void uip_neighbor_init(struct uip_stack *ustack)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ pthread_mutex_lock(&ustack->lock);
|
|
+ for (i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
|
|
+ memset(&(ustack->neighbor_entries[i].ipaddr), 0,
|
|
+ sizeof(ustack->neighbor_entries[i].ipaddr));
|
|
+ memset(&(ustack->neighbor_entries[i].mac_addr), 0,
|
|
+ sizeof(ustack->neighbor_entries[i].mac_addr));
|
|
+ ustack->neighbor_entries[i].time = MAX_TIME;
|
|
+ }
|
|
+ pthread_mutex_unlock(&ustack->lock);
|
|
+}
|
|
+
|
|
+void uip_neighbor_add(struct uip_stack *ustack,
|
|
+ struct in6_addr *addr6, struct uip_eth_addr *addr)
|
|
+{
|
|
+ int i, oldest;
|
|
+ u8_t oldest_time;
|
|
+ char buf[INET6_ADDRSTRLEN];
|
|
+
|
|
+ inet_ntop(AF_INET6, addr6, buf, sizeof(buf));
|
|
+
|
|
+ pthread_mutex_lock(&ustack->lock);
|
|
+
|
|
+ /* Find the first unused entry or the oldest used entry. */
|
|
+ oldest_time = 0;
|
|
+ oldest = 0;
|
|
+ for (i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
|
|
+ if (ustack->neighbor_entries[i].time == MAX_TIME) {
|
|
+ oldest = i;
|
|
+ break;
|
|
+ }
|
|
+ if (uip_ip6addr_cmp
|
|
+ (ustack->neighbor_entries[i].ipaddr.s6_addr, addr6)) {
|
|
+ oldest = i;
|
|
+ break;
|
|
+ }
|
|
+ if (ustack->neighbor_entries[i].time > oldest_time) {
|
|
+ oldest = i;
|
|
+ oldest_time = ustack->neighbor_entries[i].time;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Use the oldest or first free entry (either pointed to by the
|
|
+ "oldest" variable). */
|
|
+ ustack->neighbor_entries[oldest].time = 0;
|
|
+ uip_ip6addr_copy(ustack->neighbor_entries[oldest].ipaddr.s6_addr,
|
|
+ addr6);
|
|
+ memcpy(&ustack->neighbor_entries[oldest].mac_addr, addr,
|
|
+ sizeof(struct uip_eth_addr));
|
|
+
|
|
+ LOG_DEBUG("Adding neighbor %s with "
|
|
+ "mac address %02x:%02x:%02x:%02x:%02x:%02x at %d",
|
|
+ buf, addr->addr[0], addr->addr[1], addr->addr[2],
|
|
+ addr->addr[3], addr->addr[4], addr->addr[5], oldest);
|
|
+
|
|
+ pthread_mutex_unlock(&ustack->lock);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static struct neighbor_entry *find_entry(struct uip_stack *ustack,
|
|
+ struct in6_addr *addr6)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
|
|
+ if (uip_ip6addr_cmp
|
|
+ (ustack->neighbor_entries[i].ipaddr.s6_addr,
|
|
+ addr6->s6_addr)) {
|
|
+ return &ustack->neighbor_entries[i];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+void uip_neighbor_update(struct uip_stack *ustack, struct in6_addr *addr6)
|
|
+{
|
|
+ struct neighbor_entry *e;
|
|
+
|
|
+ pthread_mutex_lock(&ustack->lock);
|
|
+
|
|
+ e = find_entry(ustack, addr6);
|
|
+ if (e != NULL)
|
|
+ e->time = 0;
|
|
+
|
|
+ pthread_mutex_unlock(&ustack->lock);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+int uip_neighbor_lookup(struct uip_stack *ustack,
|
|
+ struct in6_addr *addr6, uint8_t *mac_addr)
|
|
+{
|
|
+ struct neighbor_entry *e;
|
|
+
|
|
+ pthread_mutex_lock(&ustack->lock);
|
|
+ e = find_entry(ustack, addr6);
|
|
+ if (e != NULL) {
|
|
+ char addr6_str[INET6_ADDRSTRLEN];
|
|
+ uint8_t *entry_mac_addr;
|
|
+
|
|
+ addr6_str[0] = '\0';
|
|
+ inet_ntop(AF_INET6, addr6->s6_addr, addr6_str,
|
|
+ sizeof(addr6_str));
|
|
+ entry_mac_addr = (uint8_t *)&e->mac_addr.addr;
|
|
+
|
|
+ LOG_DEBUG(PFX
|
|
+ "Found %s at %02x:%02x:%02x:%02x:%02x:%02x",
|
|
+ addr6_str,
|
|
+ entry_mac_addr[0], entry_mac_addr[1],
|
|
+ entry_mac_addr[2], entry_mac_addr[3],
|
|
+ entry_mac_addr[4], entry_mac_addr[5]);
|
|
+
|
|
+ memcpy(mac_addr, entry_mac_addr, sizeof(e->mac_addr));
|
|
+ pthread_mutex_unlock(&ustack->lock);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ pthread_mutex_unlock(&ustack->lock);
|
|
+ return -ENOENT;
|
|
+}
|
|
+
|
|
+void uip_neighbor_out(struct uip_stack *ustack)
|
|
+{
|
|
+ struct neighbor_entry *e;
|
|
+ struct uip_eth_hdr *eth_hdr =
|
|
+ (struct uip_eth_hdr *)ustack->data_link_layer;
|
|
+ struct uip_ipv6_hdr *ipv6_hdr =
|
|
+ (struct uip_ipv6_hdr *)ustack->network_layer;
|
|
+
|
|
+ pthread_mutex_lock(&ustack->lock);
|
|
+
|
|
+ /* Find the destination IP address in the neighbor table and construct
|
|
+ the Ethernet header. If the destination IP addres isn't on the
|
|
+ local network, we use the default router's IP address instead.
|
|
+
|
|
+ If not ARP table entry is found, we overwrite the original IP
|
|
+ packet with an ARP request for the IP address. */
|
|
+ e = find_entry(ustack, (struct in6_addr *)ipv6_hdr->destipaddr);
|
|
+ if (e == NULL) {
|
|
+ struct uip_eth_addr eth_addr_tmp;
|
|
+
|
|
+ memcpy(ð_addr_tmp, eth_hdr->src.addr, sizeof(eth_addr_tmp));
|
|
+ memcpy(eth_hdr->src.addr, ustack->uip_ethaddr.addr,
|
|
+ sizeof(eth_hdr->src.addr));
|
|
+ memcpy(eth_hdr->dest.addr, ð_addr_tmp,
|
|
+ sizeof(eth_hdr->dest.addr));
|
|
+
|
|
+ pthread_mutex_unlock(&ustack->lock);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ memcpy(eth_hdr->dest.addr, &e->mac_addr, sizeof(eth_hdr->dest.addr));
|
|
+ memcpy(eth_hdr->src.addr, ustack->uip_ethaddr.addr,
|
|
+ sizeof(eth_hdr->src.addr));
|
|
+
|
|
+ pthread_mutex_unlock(&ustack->lock);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
diff --git a/iscsiuio/src/uip/uip-neighbor.h b/iscsiuio/src/uip/uip-neighbor.h
|
|
new file mode 100644
|
|
index 0000000..d10c57b
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/uip-neighbor.h
|
|
@@ -0,0 +1,105 @@
|
|
+/*
|
|
+ * Copyright (c) 2006, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Header file for database of link-local neighbors, used by
|
|
+ * IPv6 code and to be used by future ARP code.
|
|
+ * \author
|
|
+ * Adam Dunkels <adam@sics.se>
|
|
+ */
|
|
+
|
|
+#ifndef __UIP_NEIGHBOR_H__
|
|
+#define __UIP_NEIGHBOR_H__
|
|
+
|
|
+#include "uip.h"
|
|
+#include "uip_eth.h"
|
|
+
|
|
+/* ICMP types */
|
|
+/* ICMPv6 error Messages */
|
|
+#define ICMPV6_DEST_UNREACH 1
|
|
+#define ICMPV6_PKT_TOOBIG 2
|
|
+#define ICMPV6_TIME_EXCEED 3
|
|
+#define ICMPV6_PARAMPROB 4
|
|
+
|
|
+/* ICMPv6 Informational Messages */
|
|
+#define ICMPV6_ECHO_REQUEST 128
|
|
+#define ICMPV6_ECHO_REPLY 129
|
|
+#define ICMPV6_MGM_QUERY 130
|
|
+#define ICMPV6_MGM_REPORT 131
|
|
+#define ICMPV6_MGM_REDUCTION 132
|
|
+
|
|
+/* Codes for Destination Unreachable */
|
|
+#define ICMPV6_NOROUTE 0
|
|
+#define ICMPV6_ADM_PROHIBITED 1
|
|
+#define ICMPV6_NOT_NEIGHBOUR 2
|
|
+#define ICMPV6_ADDR_UNREACH 3
|
|
+#define ICMPV6_PORT_UNREACH 4
|
|
+
|
|
+/* Codes for Time Exceeded */
|
|
+#define ICMPV6_EXC_HOPLIMIT 0
|
|
+#define ICMPV6_EXC_FRAGTIME 1
|
|
+
|
|
+/* Codes for Parameter Problem */
|
|
+#define ICMPV6_HDR_FIELD 0
|
|
+#define ICMPV6_UNK_NEXTHDR 1
|
|
+#define ICMPV6_UNK_OPTION 2
|
|
+
|
|
+#if 0
|
|
+struct __attribute__ ((__packed__)) icmpv6_hdr {
|
|
+ u8_t type;
|
|
+ u8_t code;
|
|
+ u16_t checksum;
|
|
+ union {
|
|
+ struct {
|
|
+ u16_t id;
|
|
+ u16_t sequence;
|
|
+ } echo;
|
|
+ u32_t gateway;
|
|
+ struct {
|
|
+ u16_t unused;
|
|
+ u16_t mtu;
|
|
+ } frag;
|
|
+ } un;
|
|
+};
|
|
+#endif
|
|
+
|
|
+void uip_neighbor_init(struct uip_stack *ustack);
|
|
+void uip_neighbor_add(struct uip_stack *ustack,
|
|
+ struct in6_addr *addr6, struct uip_eth_addr *addr);
|
|
+void uip_neighbor_update(struct uip_stack *ustack, struct in6_addr *addr6);
|
|
+int uip_neighbor_lookup(struct uip_stack *ustack, struct in6_addr *ipaddr,
|
|
+ uint8_t *mac_addr);
|
|
+void uip_neighbor_periodic(void);
|
|
+void uip_neighbor_out(struct uip_stack *ustack);
|
|
+
|
|
+#endif /* __UIP-NEIGHBOR_H__ */
|
|
diff --git a/iscsiuio/src/uip/uip.c b/iscsiuio/src/uip/uip.c
|
|
new file mode 100644
|
|
index 0000000..ec3d6ce
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/uip.c
|
|
@@ -0,0 +1,2405 @@
|
|
+#include <netinet/in.h>
|
|
+#include <netinet/ip6.h>
|
|
+#include <netinet/icmp6.h>
|
|
+#include <sys/types.h>
|
|
+#include <arpa/inet.h>
|
|
+#include "uip.h"
|
|
+#include "dhcpc.h"
|
|
+#include "ipv6_ndpc.h"
|
|
+#include "brcm_iscsi.h"
|
|
+
|
|
+/**
|
|
+ * \defgroup uip The uIP TCP/IP stack
|
|
+ * @{
|
|
+ *
|
|
+ * uIP is an implementation of the TCP/IP protocol stack intended for
|
|
+ * small 8-bit and 16-bit microcontrollers.
|
|
+ *
|
|
+ * uIP provides the necessary protocols for Internet communication,
|
|
+ * with a very small code footprint and RAM requirements - the uIP
|
|
+ * code size is on the order of a few kilobytes and RAM usage is on
|
|
+ * the order of a few hundred bytes.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * The uIP TCP/IP stack code.
|
|
+ * \author Adam Dunkels <adam@dunkels.com>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2001-2003, Adam Dunkels.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack.
|
|
+ *
|
|
+ *
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * uIP is a small implementation of the IP, UDP and TCP protocols (as
|
|
+ * well as some basic ICMP stuff). The implementation couples the IP,
|
|
+ * UDP, TCP and the application layers very tightly. To keep the size
|
|
+ * of the compiled code down, this code frequently uses the goto
|
|
+ * statement. While it would be possible to break the uip_process()
|
|
+ * function into many smaller functions, this would increase the code
|
|
+ * size because of the overhead of parameter passing and the fact that
|
|
+ * the optimier would not be as efficient.
|
|
+ *
|
|
+ * The principle is that we have a small buffer, called the uip_buf,
|
|
+ * in which the device driver puts an incoming packet. The TCP/IP
|
|
+ * stack parses the headers in the packet, and calls the
|
|
+ * application. If the remote host has sent data to the application,
|
|
+ * this data is present in the uip_buf and the application read the
|
|
+ * data from there. It is up to the application to put this data into
|
|
+ * a byte stream if needed. The application will not be fed with data
|
|
+ * that is out of sequence.
|
|
+ *
|
|
+ * If the application whishes to send data to the peer, it should put
|
|
+ * its data into the uip_buf. The uip_appdata pointer points to the
|
|
+ * first available byte. The TCP/IP stack will calculate the
|
|
+ * checksums, and fill in the necessary header fields and finally send
|
|
+ * the packet back to the peer.
|
|
+*/
|
|
+
|
|
+#include "logger.h"
|
|
+
|
|
+#include "uip.h"
|
|
+#include "uipopt.h"
|
|
+#include "uip_arch.h"
|
|
+#include "uip_eth.h"
|
|
+#include "uip-neighbor.h"
|
|
+
|
|
+#include <string.h>
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Constants
|
|
+ ******************************************************************************/
|
|
+#define PFX "uip "
|
|
+
|
|
+static const uip_ip6addr_t all_ones_addr6 = {
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
|
|
+};
|
|
+static const uip_ip4addr_t all_ones_addr4 = { 0xffff, 0xffff };
|
|
+
|
|
+const uip_ip6addr_t all_zeroes_addr6 = {
|
|
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
|
|
+};
|
|
+const uip_ip4addr_t all_zeroes_addr4 = { 0x0000, 0x0000 };
|
|
+
|
|
+const uint8_t mutlicast_ipv6_prefix[16] = {
|
|
+ 0xfc, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
+};
|
|
+
|
|
+const uint8_t link_local_addres_prefix[16] = {
|
|
+ 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
+};
|
|
+const uint32_t link_local_address_prefix_length = 10;
|
|
+
|
|
+/* Structures and definitions. */
|
|
+#define TCP_FIN 0x01
|
|
+#define TCP_SYN 0x02
|
|
+#define TCP_RST 0x04
|
|
+#define TCP_PSH 0x08
|
|
+#define TCP_ACK 0x10
|
|
+#define TCP_URG 0x20
|
|
+#define TCP_CTL 0x3f
|
|
+
|
|
+#define TCP_OPT_END 0 /* End of TCP options list */
|
|
+#define TCP_OPT_NOOP 1 /* "No-operation" TCP option */
|
|
+#define TCP_OPT_MSS 2 /* Maximum segment size TCP option */
|
|
+
|
|
+#define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */
|
|
+
|
|
+#define ICMP_ECHO_REPLY 0
|
|
+#define ICMP_ECHO 8
|
|
+
|
|
+#define ICMP6_ECHO_REPLY 129
|
|
+#define ICMP6_ECHO 128
|
|
+#define ICMP6_NEIGHBOR_SOLICITATION 135
|
|
+#define ICMP6_NEIGHBOR_ADVERTISEMENT 136
|
|
+
|
|
+#define ICMP6_FLAG_S (1 << 6)
|
|
+
|
|
+#define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1
|
|
+#define ICMP6_OPTION_TARGET_LINK_ADDRESS 2
|
|
+
|
|
+/* Macros. */
|
|
+#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0])
|
|
+#define UDPBUF(ustack) ((struct uip_udpip_hdr *)ustack->network_layer)
|
|
+
|
|
+/******************************************************************************
|
|
+ * Utility Functions
|
|
+ *****************************************************************************/
|
|
+static int is_ipv6(struct uip_stack *ustack)
|
|
+{
|
|
+ u16_t type;
|
|
+
|
|
+ type = ETH_BUF(ustack->uip_buf)->type;
|
|
+ type = ntohs(type);
|
|
+ if (type == UIP_ETHTYPE_8021Q)
|
|
+ type = ntohs(VLAN_ETH_BUF(ustack->uip_buf)->type);
|
|
+ else
|
|
+ type = ntohs(ETH_BUF(ustack->uip_buf)->type);
|
|
+
|
|
+ return (type == UIP_ETHTYPE_IPv6);
|
|
+}
|
|
+
|
|
+int is_ipv6_link_local_address(uip_ip6addr_t *addr)
|
|
+{
|
|
+ u8_t *test_adddr = (u8_t *) addr;
|
|
+ u8_t test_remainder;
|
|
+
|
|
+ if (test_adddr[0] != link_local_addres_prefix[0])
|
|
+ return 0;
|
|
+
|
|
+ test_remainder = (test_adddr[1] & 0xC0) >> 6;
|
|
+ if (test_remainder != 2)
|
|
+ return 0;
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+void uip_sethostaddr4(struct uip_stack *ustack, uip_ip4addr_t *addr)
|
|
+{
|
|
+ pthread_mutex_lock(&ustack->lock);
|
|
+ uip_ip4addr_copy(ustack->hostaddr, (addr));
|
|
+ pthread_mutex_unlock(&ustack->lock);
|
|
+}
|
|
+
|
|
+void uip_setdraddr4(struct uip_stack *ustack, uip_ip4addr_t *addr)
|
|
+{
|
|
+ pthread_mutex_lock(&ustack->lock);
|
|
+ uip_ip4addr_copy(ustack->default_route_addr, (addr));
|
|
+ pthread_mutex_unlock(&ustack->lock);
|
|
+}
|
|
+
|
|
+void uip_setnetmask4(struct uip_stack *ustack, uip_ip4addr_t *addr)
|
|
+{
|
|
+ pthread_mutex_lock(&ustack->lock);
|
|
+ uip_ip4addr_copy(ustack->netmask, (addr));
|
|
+ pthread_mutex_unlock(&ustack->lock);
|
|
+}
|
|
+
|
|
+void uip_setethernetmac(struct uip_stack *ustack, uint8_t *mac)
|
|
+{
|
|
+ pthread_mutex_lock(&ustack->lock);
|
|
+ memcpy(ustack->uip_ethaddr.addr, (mac), 6);
|
|
+ pthread_mutex_unlock(&ustack->lock);
|
|
+}
|
|
+
|
|
+void set_uip_stack(struct uip_stack *ustack,
|
|
+ uip_ip4addr_t *ip,
|
|
+ uip_ip4addr_t *netmask,
|
|
+ uip_ip4addr_t *default_route, uint8_t *mac_addr)
|
|
+{
|
|
+ uip_sethostaddr4(ustack, ip);
|
|
+ uip_setnetmask4(ustack, netmask);
|
|
+ uip_setdraddr4(ustack, default_route);
|
|
+ uip_setethernetmac(ustack, mac_addr);
|
|
+}
|
|
+
|
|
+#if !UIP_ARCH_ADD32
|
|
+void uip_add32(u8_t *op32, u16_t op16, u8_t *uip_acc32)
|
|
+{
|
|
+ uip_acc32[3] = op32[3] + (op16 & 0xff);
|
|
+ uip_acc32[2] = op32[2] + (op16 >> 8);
|
|
+ uip_acc32[1] = op32[1];
|
|
+ uip_acc32[0] = op32[0];
|
|
+
|
|
+ if (uip_acc32[2] < (op16 >> 8)) {
|
|
+ ++uip_acc32[1];
|
|
+ if (uip_acc32[1] == 0)
|
|
+ ++uip_acc32[0];
|
|
+ }
|
|
+
|
|
+ if (uip_acc32[3] < (op16 & 0xff)) {
|
|
+ ++uip_acc32[2];
|
|
+ if (uip_acc32[2] == 0) {
|
|
+ ++uip_acc32[1];
|
|
+ if (uip_acc32[1] == 0)
|
|
+ ++uip_acc32[0];
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+#endif /* UIP_ARCH_ADD32 */
|
|
+
|
|
+#if !UIP_ARCH_CHKSUM
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static u16_t chksum(u16_t sum, const u8_t *data, u16_t len)
|
|
+{
|
|
+ u16_t t;
|
|
+ const u8_t *dataptr;
|
|
+ const u8_t *last_byte;
|
|
+
|
|
+ dataptr = data;
|
|
+ last_byte = data + len - 1;
|
|
+
|
|
+ while (dataptr < last_byte) { /* At least two more bytes */
|
|
+ t = (dataptr[0] << 8) + dataptr[1];
|
|
+ sum += t;
|
|
+ if (sum < t)
|
|
+ sum++; /* carry */
|
|
+ dataptr += 2;
|
|
+ }
|
|
+
|
|
+ if (dataptr == last_byte) {
|
|
+ t = (dataptr[0] << 8) + 0;
|
|
+ sum += t;
|
|
+ if (sum < t)
|
|
+ sum++; /* carry */
|
|
+ }
|
|
+
|
|
+ /* Return sum in host byte order. */
|
|
+ return sum;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+u16_t uip_chksum(u16_t *data, u16_t len)
|
|
+{
|
|
+ return htons(chksum(0, (u8_t *)data, len));
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+#ifndef UIP_ARCH_IPCHKSUM
|
|
+u16_t uip_ipchksum(struct uip_stack *ustack)
|
|
+{
|
|
+ u16_t sum;
|
|
+ u16_t uip_iph_len;
|
|
+
|
|
+ if (is_ipv6(ustack))
|
|
+ uip_iph_len = UIP_IPv6_H_LEN;
|
|
+ else
|
|
+ uip_iph_len = UIP_IPv4_H_LEN;
|
|
+
|
|
+ sum = chksum(0, ustack->network_layer, uip_iph_len);
|
|
+ return (sum == 0) ? 0xffff : htons(sum);
|
|
+}
|
|
+#endif
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static u16_t upper_layer_chksum_ipv4(struct uip_stack *ustack, u8_t proto)
|
|
+{
|
|
+ u16_t upper_layer_len;
|
|
+ u16_t sum;
|
|
+ struct uip_tcp_ipv4_hdr *tcp_ipv4_hdr = NULL;
|
|
+
|
|
+ tcp_ipv4_hdr = (struct uip_tcp_ipv4_hdr *)ustack->network_layer;
|
|
+
|
|
+ upper_layer_len = (((u16_t) (tcp_ipv4_hdr->len[0]) << 8) +
|
|
+ tcp_ipv4_hdr->len[1]) - UIP_IPv4_H_LEN;
|
|
+
|
|
+ /* First sum pseudoheader. */
|
|
+ /* IP protocol and length fields. This addition cannot carry. */
|
|
+ sum = upper_layer_len + proto;
|
|
+
|
|
+ sum =
|
|
+ chksum(sum, (u8_t *)&tcp_ipv4_hdr->srcipaddr[0],
|
|
+ 2 * sizeof(uip_ip4addr_t));
|
|
+ /* Sum TCP header and data. */
|
|
+ sum = chksum(sum, ustack->network_layer + UIP_IPv4_H_LEN,
|
|
+ upper_layer_len);
|
|
+
|
|
+ return (sum == 0) ? 0xffff : htons(sum);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static uint16_t upper_layer_checksum_ipv6(uint8_t *data, uint8_t proto)
|
|
+{
|
|
+ uint16_t upper_layer_len;
|
|
+ uint16_t sum;
|
|
+ struct ip6_hdr *ipv6_hdr;
|
|
+ uint8_t *upper_layer;
|
|
+ uint32_t val;
|
|
+
|
|
+ ipv6_hdr = (struct ip6_hdr *)data;
|
|
+
|
|
+ upper_layer_len = ntohs(ipv6_hdr->ip6_plen);
|
|
+
|
|
+ /* First sum pseudoheader. */
|
|
+ sum = 0;
|
|
+ sum = chksum(sum, (const u8_t *)ipv6_hdr->ip6_src.s6_addr,
|
|
+ sizeof(ipv6_hdr->ip6_src));
|
|
+ sum = chksum(sum, (const u8_t *)ipv6_hdr->ip6_dst.s6_addr,
|
|
+ sizeof(ipv6_hdr->ip6_dst));
|
|
+
|
|
+ val = htons(upper_layer_len);
|
|
+ sum = chksum(sum, (u8_t *)&val, sizeof(val));
|
|
+
|
|
+ val = htons(proto);
|
|
+ sum = chksum(sum, (u8_t *)&val, sizeof(val));
|
|
+
|
|
+ upper_layer = (uint8_t *)(ipv6_hdr + 1);
|
|
+ sum = chksum(sum, upper_layer, upper_layer_len);
|
|
+
|
|
+ return (sum == 0) ? 0xffff : htons(sum);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+
|
|
+u16_t uip_icmp6chksum(struct uip_stack *ustack)
|
|
+{
|
|
+ uint8_t *data = ustack->network_layer;
|
|
+
|
|
+ return upper_layer_checksum_ipv6(data, UIP_PROTO_ICMP6);
|
|
+}
|
|
+
|
|
+uint16_t icmpv6_checksum(uint8_t *data)
|
|
+{
|
|
+ return upper_layer_checksum_ipv6(data, IPPROTO_ICMPV6);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+u16_t uip_tcpchksum(struct uip_stack *ustack)
|
|
+{
|
|
+ return upper_layer_chksum_ipv4(ustack, UIP_PROTO_TCP);
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+#if UIP_UDP_CHECKSUMS
|
|
+static u16_t uip_udpchksum_ipv4(struct uip_stack *ustack)
|
|
+{
|
|
+ return upper_layer_chksum_ipv4(ustack, UIP_PROTO_UDP);
|
|
+}
|
|
+
|
|
+static u16_t uip_udpchksum_ipv6(struct uip_stack *ustack)
|
|
+{
|
|
+ uint8_t *data = ustack->network_layer;
|
|
+
|
|
+ return upper_layer_checksum_ipv6(data, UIP_PROTO_UDP);
|
|
+}
|
|
+
|
|
+u16_t uip_udpchksum(struct uip_stack *ustack)
|
|
+{
|
|
+ if (is_ipv6(ustack))
|
|
+ return uip_udpchksum_ipv6(ustack);
|
|
+ else
|
|
+ return uip_udpchksum_ipv4(ustack);
|
|
+}
|
|
+#endif /* UIP_UDP_CHECKSUMS */
|
|
+#endif /* UIP_ARCH_CHKSUM */
|
|
+/*---------------------------------------------------------------------------*/
|
|
+void uip_init(struct uip_stack *ustack, uint8_t ipv6_enabled)
|
|
+{
|
|
+ u8_t c;
|
|
+
|
|
+ for (c = 0; c < UIP_LISTENPORTS; ++c)
|
|
+ ustack->uip_listenports[c] = 0;
|
|
+ for (c = 0; c < UIP_CONNS; ++c)
|
|
+ ustack->uip_conns[c].tcpstateflags = UIP_CLOSED;
|
|
+#if UIP_ACTIVE_OPEN
|
|
+ ustack->lastport = 1024;
|
|
+#endif /* UIP_ACTIVE_OPEN */
|
|
+
|
|
+#if UIP_UDP
|
|
+ for (c = 0; c < UIP_UDP_CONNS; ++c)
|
|
+ ustack->uip_udp_conns[c].lport = 0;
|
|
+#endif /* UIP_UDP */
|
|
+
|
|
+ /* IPv4 initialization. */
|
|
+#if UIP_FIXEDADDR == 0
|
|
+ /* uip_hostaddr[0] = uip_hostaddr[1] = 0; */
|
|
+#endif /* UIP_FIXEDADDR */
|
|
+
|
|
+ /* zero out the uIP statistics */
|
|
+ memset(&ustack->stats, 0, sizeof(ustack->stats));
|
|
+
|
|
+ /* prepare the uIP lock */
|
|
+ pthread_mutex_init(&ustack->lock, NULL);
|
|
+
|
|
+ if (ipv6_enabled)
|
|
+ ustack->enable_IPv6 = UIP_SUPPORT_IPv6_ENABLED;
|
|
+ else
|
|
+ ustack->enable_IPv6 = UIP_SUPPORT_IPv6_DISABLED;
|
|
+
|
|
+ ustack->dhcpc = NULL;
|
|
+ ustack->ndpc = NULL;
|
|
+}
|
|
+void uip_reset(struct uip_stack *ustack)
|
|
+{
|
|
+ /* There was an associated DHCP object, this memory needs to be
|
|
+ * freed */
|
|
+ if (ustack->dhcpc)
|
|
+ free(ustack->dhcpc);
|
|
+
|
|
+ ndpc_exit(ustack->ndpc);
|
|
+
|
|
+ memset(ustack, 0, sizeof(*ustack));
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+#if UIP_ACTIVE_OPEN
|
|
+struct uip_conn *uip_connect(struct uip_stack *ustack, uip_ip4addr_t *ripaddr,
|
|
+ u16_t rport)
|
|
+{
|
|
+ u8_t c;
|
|
+ register struct uip_conn *conn, *cconn;
|
|
+
|
|
+ /* Find an unused local port. */
|
|
+again:
|
|
+ ++ustack->lastport;
|
|
+
|
|
+ if (ustack->lastport >= 32000)
|
|
+ ustack->lastport = 4096;
|
|
+
|
|
+ /* Check if this port is already in use, and if so try to find
|
|
+ another one. */
|
|
+ for (c = 0; c < UIP_CONNS; ++c) {
|
|
+ conn = &ustack->uip_conns[c];
|
|
+ if (conn->tcpstateflags != UIP_CLOSED &&
|
|
+ conn->lport == htons(ustack->lastport)) {
|
|
+ goto again;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ conn = 0;
|
|
+ for (c = 0; c < UIP_CONNS; ++c) {
|
|
+ cconn = &ustack->uip_conns[c];
|
|
+ if (cconn->tcpstateflags == UIP_CLOSED) {
|
|
+ conn = cconn;
|
|
+ break;
|
|
+ }
|
|
+ if (cconn->tcpstateflags == UIP_TIME_WAIT) {
|
|
+ if (conn == 0 || cconn->timer > conn->timer)
|
|
+ conn = cconn;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (conn == 0)
|
|
+ return 0;
|
|
+
|
|
+ conn->tcpstateflags = UIP_SYN_SENT;
|
|
+
|
|
+ conn->snd_nxt[0] = ustack->iss[0];
|
|
+ conn->snd_nxt[1] = ustack->iss[1];
|
|
+ conn->snd_nxt[2] = ustack->iss[2];
|
|
+ conn->snd_nxt[3] = ustack->iss[3];
|
|
+
|
|
+ conn->initialmss = conn->mss = UIP_TCP_MSS;
|
|
+
|
|
+ conn->len = 1; /* TCP length of the SYN is one. */
|
|
+ conn->nrtx = 0;
|
|
+ conn->timer = 1; /* Send the SYN next time around. */
|
|
+ conn->rto = UIP_RTO;
|
|
+ conn->sa = 0;
|
|
+ conn->sv = 16; /* Initial value of the RTT variance. */
|
|
+ conn->lport = htons(ustack->lastport);
|
|
+ conn->rport = rport;
|
|
+ uip_ip4addr_copy(&conn->ripaddr, ripaddr);
|
|
+
|
|
+ return conn;
|
|
+}
|
|
+#endif /* UIP_ACTIVE_OPEN */
|
|
+/*---------------------------------------------------------------------------*/
|
|
+#if UIP_UDP
|
|
+struct uip_udp_conn *uip_udp_new(struct uip_stack *ustack,
|
|
+ uip_ip4addr_t *ripaddr, u16_t rport)
|
|
+{
|
|
+ u8_t c;
|
|
+ register struct uip_udp_conn *conn;
|
|
+
|
|
+ /* Find an unused local port. */
|
|
+again:
|
|
+ ++ustack->lastport;
|
|
+
|
|
+ if (ustack->lastport >= 32000)
|
|
+ ustack->lastport = 4096;
|
|
+
|
|
+ for (c = 0; c < UIP_UDP_CONNS; ++c) {
|
|
+ if (ustack->uip_udp_conns[c].lport == htons(ustack->lastport))
|
|
+ goto again;
|
|
+ }
|
|
+
|
|
+ conn = 0;
|
|
+ for (c = 0; c < UIP_UDP_CONNS; ++c) {
|
|
+ if (ustack->uip_udp_conns[c].lport == 0) {
|
|
+ conn = &ustack->uip_udp_conns[c];
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (conn == 0)
|
|
+ return 0;
|
|
+
|
|
+ conn->lport = htons(ustack->lastport);
|
|
+ conn->rport = rport;
|
|
+ if (ripaddr == NULL)
|
|
+ memset(conn->ripaddr, 0, sizeof(uip_ip4addr_t));
|
|
+ else
|
|
+ uip_ip4addr_copy(&conn->ripaddr, ripaddr);
|
|
+ conn->ttl = UIP_TTL;
|
|
+
|
|
+ return conn;
|
|
+}
|
|
+#endif /* UIP_UDP */
|
|
+/*---------------------------------------------------------------------------*/
|
|
+void uip_unlisten(struct uip_stack *ustack, u16_t port)
|
|
+{
|
|
+ u8_t c;
|
|
+
|
|
+ for (c = 0; c < UIP_LISTENPORTS; ++c) {
|
|
+ if (ustack->uip_listenports[c] == port) {
|
|
+ ustack->uip_listenports[c] = 0;
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+void uip_listen(struct uip_stack *ustack, u16_t port)
|
|
+{
|
|
+ u8_t c;
|
|
+
|
|
+ for (c = 0; c < UIP_LISTENPORTS; ++c) {
|
|
+ if (ustack->uip_listenports[c] == 0) {
|
|
+ ustack->uip_listenports[c] = port;
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Is new incoming data available?
|
|
+ *
|
|
+ * Will reduce to non-zero if there is new data for the application
|
|
+ * present at the uip_appdata pointer. The size of the data is
|
|
+ * avaliable through the uip_len variable.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_newdata(struct uip_stack *ustack)
|
|
+{
|
|
+ return ustack->uip_flags & UIP_NEWDATA;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Has previously sent data been acknowledged?
|
|
+ *
|
|
+ * Will reduce to non-zero if the previously sent data has been
|
|
+ * acknowledged by the remote host. This means that the application
|
|
+ * can send new data.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_acked() (uip_flags & UIP_ACKDATA)
|
|
+
|
|
+/**
|
|
+ * Has the connection just been connected?
|
|
+ *
|
|
+ * Reduces to non-zero if the current connection has been connected to
|
|
+ * a remote host. This will happen both if the connection has been
|
|
+ * actively opened (with uip_connect()) or passively opened (with
|
|
+ * uip_listen()).
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_connected(struct uip_stack *ustack)
|
|
+{
|
|
+ return ustack->uip_flags & UIP_CONNECTED;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Has the connection been closed by the other end?
|
|
+ *
|
|
+ * Is non-zero if the connection has been closed by the remote
|
|
+ * host. The application may then do the necessary clean-ups.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_closed(struct uip_stack *ustack)
|
|
+{
|
|
+ return ustack->uip_flags & UIP_CLOSE;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Has the connection been aborted by the other end?
|
|
+ *
|
|
+ * Non-zero if the current connection has been aborted (reset) by the
|
|
+ * remote host.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_aborted(struct uip_stack *ustack)
|
|
+{
|
|
+ return ustack->uip_flags & UIP_ABORT;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Has the connection timed out?
|
|
+ *
|
|
+ * Non-zero if the current connection has been aborted due to too many
|
|
+ * retransmissions.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_timedout(struct uip_stack *ustack)
|
|
+{
|
|
+ return ustack->uip_flags & UIP_TIMEDOUT;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Do we need to retransmit previously data?
|
|
+ *
|
|
+ * Reduces to non-zero if the previously sent data has been lost in
|
|
+ * the network, and the application should retransmit it. The
|
|
+ * application should send the exact same data as it did the last
|
|
+ * time, using the uip_send() function.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_rexmit(struct uip_stack *ustack)
|
|
+{
|
|
+ return ustack->uip_flags & UIP_REXMIT;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Is the connection being polled by uIP?
|
|
+ *
|
|
+ * Is non-zero if the reason the application is invoked is that the
|
|
+ * current connection has been idle for a while and should be
|
|
+ * polled.
|
|
+ *
|
|
+ * The polling event can be used for sending data without having to
|
|
+ * wait for the remote host to send data.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_poll(struct uip_stack *ustack)
|
|
+{
|
|
+ return ustack->uip_flags & UIP_POLL;
|
|
+}
|
|
+
|
|
+int uip_initialmss(struct uip_stack *ustack)
|
|
+{
|
|
+ return ustack->uip_conn->initialmss;
|
|
+}
|
|
+
|
|
+int uip_mss(struct uip_stack *ustack)
|
|
+{
|
|
+ return ustack->uip_conn->mss;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+/* XXX: IP fragment reassembly: not well-tested. */
|
|
+
|
|
+#if UIP_REASSEMBLY && !UIP_CONF_IPV6
|
|
+#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
|
|
+static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
|
|
+static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
|
|
+static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f,
|
|
+ 0x0f, 0x07, 0x03, 0x01
|
|
+};
|
|
+static u16_t uip_reasslen;
|
|
+static u8_t uip_reassflags;
|
|
+#define UIP_REASS_FLAG_LASTFRAG 0x01
|
|
+static u8_t uip_reasstmr;
|
|
+
|
|
+#define IP_MF 0x20
|
|
+
|
|
+static u8_t uip_reass(void)
|
|
+{
|
|
+ u16_t offset, len;
|
|
+ u16_t i;
|
|
+
|
|
+ /* If ip_reasstmr is zero, no packet is present in the buffer, so we
|
|
+ write the IP header of the fragment into the reassembly
|
|
+ buffer. The timer is updated with the maximum age. */
|
|
+ if (uip_reasstmr == 0) {
|
|
+ memcpy(uip_reassbuf, &BUF(ustack)->vhl, uip_iph_len);
|
|
+ uip_reasstmr = UIP_REASS_MAXAGE;
|
|
+ uip_reassflags = 0;
|
|
+ /* Clear the bitmap. */
|
|
+ memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap));
|
|
+ }
|
|
+
|
|
+ /* Check if the incoming fragment matches the one currently present
|
|
+ in the reasembly buffer. If so, we proceed with copying the
|
|
+ fragment into the buffer. */
|
|
+ if (BUF(ustack)->srcipaddr[0] == FBUF(ustack)->srcipaddr[0] &&
|
|
+ BUF(ustack)->srcipaddr[1] == FBUF(ustack)->srcipaddr[1] &&
|
|
+ BUF(ustack)->destipaddr[0] == FBUF(ustack)->destipaddr[0] &&
|
|
+ BUF(ustack)->destipaddr[1] == FBUF(ustack)->destipaddr[1] &&
|
|
+ BUF(ustack)->ipid[0] == FBUF(ustack)->ipid[0] &&
|
|
+ BUF(ustack)->ipid[1] == FBUF(ustack)->ipid[1]) {
|
|
+
|
|
+ len =
|
|
+ (BUF(ustack)->len[0] << 8) + BUF(ustack)->len[1] -
|
|
+ (BUF(ustack)->vhl & 0x0f) * 4;
|
|
+ offset =
|
|
+ (((BUF(ustack)->ipoffset[0] & 0x3f) << 8) +
|
|
+ BUF(ustack)->ipoffset[1]) * 8;
|
|
+
|
|
+ /* If the offset or the offset + fragment length overflows the
|
|
+ reassembly buffer, we discard the entire packet. */
|
|
+ if (offset > UIP_REASS_BUFSIZE ||
|
|
+ offset + len > UIP_REASS_BUFSIZE) {
|
|
+ uip_reasstmr = 0;
|
|
+ goto nullreturn;
|
|
+ }
|
|
+
|
|
+ /* Copy the fragment into the reassembly buffer, at the right
|
|
+ offset. */
|
|
+ memcpy(&uip_reassbuf[uip_iph_len + offset],
|
|
+ (char *)BUF + (int)((BUF(ustack)->vhl & 0x0f) * 4), len);
|
|
+
|
|
+ /* Update the bitmap. */
|
|
+ if (offset / (8 * 8) == (offset + len) / (8 * 8)) {
|
|
+ /* If the two endpoints are in the same byte, we only
|
|
+ update that byte. */
|
|
+
|
|
+ uip_reassbitmap[offset / (8 * 8)] |=
|
|
+ bitmap_bits[(offset / 8) & 7] &
|
|
+ ~bitmap_bits[((offset + len) / 8) & 7];
|
|
+ } else {
|
|
+ /* If the two endpoints are in different bytes, we
|
|
+ update the bytes in the endpoints and fill the
|
|
+ stuff inbetween with 0xff. */
|
|
+ uip_reassbitmap[offset / (8 * 8)] |=
|
|
+ bitmap_bits[(offset / 8) & 7];
|
|
+ for (i = 1 + offset / (8 * 8);
|
|
+ i < (offset + len) / (8 * 8); ++i) {
|
|
+ uip_reassbitmap[i] = 0xff;
|
|
+ }
|
|
+ uip_reassbitmap[(offset + len) / (8 * 8)] |=
|
|
+ ~bitmap_bits[((offset + len) / 8) & 7];
|
|
+ }
|
|
+
|
|
+ /* If this fragment has the More Fragments flag set to zero, we
|
|
+ know that this is the last fragment, so we can calculate the
|
|
+ size of the entire packet. We also set the
|
|
+ IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
|
|
+ the final fragment. */
|
|
+
|
|
+ if ((BUF(ustack)->ipoffset[0] & IP_MF) == 0) {
|
|
+ uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
|
|
+ uip_reasslen = offset + len;
|
|
+ }
|
|
+
|
|
+ /* Finally, we check if we have a full packet in the buffer.
|
|
+ We do this by checking if we have the last fragment and if
|
|
+ all bits in the bitmap are set. */
|
|
+ if (uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
|
|
+ /* Check all bytes up to and including all but the last
|
|
+ byte in the bitmap. */
|
|
+ for (i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
|
|
+ if (uip_reassbitmap[i] != 0xff)
|
|
+ goto nullreturn;
|
|
+ }
|
|
+ /* Check the last byte in the bitmap. It should contain
|
|
+ just the right amount of bits. */
|
|
+ if (uip_reassbitmap[uip_reasslen / (8 * 8)] !=
|
|
+ (u8_t) ~bitmap_bits[uip_reasslen / 8 & 7])
|
|
+ goto nullreturn;
|
|
+
|
|
+ /* If we have come this far, we have a full packet in
|
|
+ the buffer, so we allocate a pbuf and copy the
|
|
+ packet into it. We also reset the timer. */
|
|
+ uip_reasstmr = 0;
|
|
+ memcpy(BUF, FBUF, uip_reasslen);
|
|
+
|
|
+ /* Pretend to be a "normal" (i.e., not fragmented) IP
|
|
+ packet from now on. */
|
|
+ BUF(ustack)->ipoffset[0] = BUF(ustack)->ipoffset[1] = 0;
|
|
+ BUF(ustack)->len[0] = uip_reasslen >> 8;
|
|
+ BUF(ustack)->len[1] = uip_reasslen & 0xff;
|
|
+ BUF(ustack)->ipchksum = 0;
|
|
+ BUF(ustack)->ipchksum = ~(uip_ipchksum());
|
|
+
|
|
+ return uip_reasslen;
|
|
+ }
|
|
+ }
|
|
+
|
|
+nullreturn:
|
|
+ return 0;
|
|
+}
|
|
+#endif /* UIP_REASSEMBLY */
|
|
+/*---------------------------------------------------------------------------*/
|
|
+static void uip_add_rcv_nxt(struct uip_stack *ustack, u16_t n)
|
|
+{
|
|
+ u8_t uip_acc32[4];
|
|
+
|
|
+ uip_add32(ustack->uip_conn->rcv_nxt, n, uip_acc32);
|
|
+ ustack->uip_conn->rcv_nxt[0] = uip_acc32[0];
|
|
+ ustack->uip_conn->rcv_nxt[1] = uip_acc32[1];
|
|
+ ustack->uip_conn->rcv_nxt[2] = uip_acc32[2];
|
|
+ ustack->uip_conn->rcv_nxt[3] = uip_acc32[3];
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/**
|
|
+ * \defgroup uipdevfunc uIP device driver functions
|
|
+ * @{
|
|
+ *
|
|
+ * These functions are used by a network device driver for interacting
|
|
+ * with uIP.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Process an incoming packet.
|
|
+ *
|
|
+ * This function should be called when the device driver has received
|
|
+ * a packet from the network. The packet from the device driver must
|
|
+ * be present in the uip_buf buffer, and the length of the packet
|
|
+ * should be placed in the uip_len variable.
|
|
+ *
|
|
+ * When the function returns, there may be an outbound packet placed
|
|
+ * in the uip_buf packet buffer. If so, the uip_len variable is set to
|
|
+ * the length of the packet. If no packet is to be sent out, the
|
|
+ * uip_len variable is set to 0.
|
|
+ *
|
|
+ * The usual way of calling the function is presented by the source
|
|
+ * code below.
|
|
+ \code
|
|
+ uip_len = devicedriver_poll();
|
|
+ if(uip_len > 0) {
|
|
+ uip_input();
|
|
+ if(uip_len > 0) {
|
|
+ devicedriver_send();
|
|
+ }
|
|
+ }
|
|
+ \endcode
|
|
+ *
|
|
+ * \note If you are writing a uIP device driver that needs ARP
|
|
+ * (Address Resolution Protocol), e.g., when running uIP over
|
|
+ * Ethernet, you will need to call the uIP ARP code before calling
|
|
+ * this function:
|
|
+ \code
|
|
+ #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
|
|
+ uip_len = ethernet_devicedrver_poll();
|
|
+ if(uip_len > 0) {
|
|
+ if (BUF(ustack)->type == HTONS(UIP_ETHTYPE_IP)) {
|
|
+ uip_arp_ipin();
|
|
+ uip_input();
|
|
+ if (uip_len > 0) {
|
|
+ uip_arp_out();
|
|
+ ethernet_devicedriver_send();
|
|
+ }
|
|
+ } else if (BUF(ustack)->type == HTONS(UIP_ETHTYPE_ARP)) {
|
|
+ uip_arp_arpin();
|
|
+ if (uip_len > 0)
|
|
+ ethernet_devicedriver_send();
|
|
+ }
|
|
+ \endcode
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+void uip_input(struct uip_stack *ustack)
|
|
+{
|
|
+ uip_process(ustack, UIP_DATA);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Periodic processing for a connection identified by its number.
|
|
+ *
|
|
+ * This function does the necessary periodic processing (timers,
|
|
+ * polling) for a uIP TCP conneciton, and should be called when the
|
|
+ * periodic uIP timer goes off. It should be called for every
|
|
+ * connection, regardless of whether they are open of closed.
|
|
+ *
|
|
+ * When the function returns, it may have an outbound packet waiting
|
|
+ * for service in the uIP packet buffer, and if so the uip_len
|
|
+ * variable is set to a value larger than zero. The device driver
|
|
+ * should be called to send out the packet.
|
|
+ *
|
|
+ * The ususal way of calling the function is through a for() loop like
|
|
+ * this:
|
|
+ \code
|
|
+ for(i = 0; i < UIP_CONNS; ++i) {
|
|
+ uip_periodic(i);
|
|
+ if(uip_len > 0) {
|
|
+ devicedriver_send();
|
|
+ }
|
|
+ }
|
|
+ \endcode
|
|
+ *
|
|
+ * \note If you are writing a uIP device driver that needs ARP
|
|
+ * (Address Resolution Protocol), e.g., when running uIP over
|
|
+ * Ethernet, you will need to call the uip_arp_out() function before
|
|
+ * calling the device driver:
|
|
+ \code
|
|
+ for(i = 0; i < UIP_CONNS; ++i) {
|
|
+ uip_periodic(i);
|
|
+ if(uip_len > 0) {
|
|
+ uip_arp_out();
|
|
+ ethernet_devicedriver_send();
|
|
+ }
|
|
+ }
|
|
+ \endcode
|
|
+ *
|
|
+ * \param conn The number of the connection which is to be periodically polled.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+void uip_periodic(struct uip_stack *ustack, int conn)
|
|
+{
|
|
+ ustack->uip_conn = &ustack->uip_conns[conn];
|
|
+ uip_process(ustack, UIP_TIMER);
|
|
+}
|
|
+
|
|
+#if UIP_UDP
|
|
+/**
|
|
+ * Periodic processing for a UDP connection identified by its number.
|
|
+ *
|
|
+ * This function is essentially the same as uip_periodic(), but for
|
|
+ * UDP connections. It is called in a similar fashion as the
|
|
+ * uip_periodic() function:
|
|
+ \code
|
|
+ for(i = 0; i < UIP_UDP_CONNS; i++) {
|
|
+ uip_udp_periodic(i);
|
|
+ if(uip_len > 0) {
|
|
+ devicedriver_send();
|
|
+ }
|
|
+ }
|
|
+ \endcode
|
|
+ *
|
|
+ * \note As for the uip_periodic() function, special care has to be
|
|
+ * taken when using uIP together with ARP and Ethernet:
|
|
+ \code
|
|
+ for(i = 0; i < UIP_UDP_CONNS; i++) {
|
|
+ uip_udp_periodic(i);
|
|
+ if(uip_len > 0) {
|
|
+ uip_arp_out();
|
|
+ ethernet_devicedriver_send();
|
|
+ }
|
|
+ }
|
|
+ \endcode
|
|
+ *
|
|
+ * \param conn The number of the UDP connection to be processed.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+void uip_udp_periodic(struct uip_stack *ustack, int conn)
|
|
+{
|
|
+ ustack->uip_udp_conn = &ustack->uip_udp_conns[conn];
|
|
+ uip_process(ustack, UIP_UDP_TIMER);
|
|
+}
|
|
+#endif
|
|
+
|
|
+void uip_ndp_periodic(struct uip_stack *ustack)
|
|
+{
|
|
+ uip_process(ustack, UIP_NDP_TIMER);
|
|
+}
|
|
+
|
|
+void uip_process(struct uip_stack *ustack, u8_t flag)
|
|
+{
|
|
+ u8_t c;
|
|
+ u16_t tmp16;
|
|
+ register struct uip_conn *uip_connr = ustack->uip_conn;
|
|
+
|
|
+ u16_t uip_iph_len = 0;
|
|
+ u16_t uip_ip_udph_len = 0;
|
|
+ u16_t uip_ip_tcph_len = 0;
|
|
+ struct ip6_hdr *ipv6_hdr = NULL;
|
|
+ struct uip_tcp_ipv4_hdr *tcp_ipv4_hdr = NULL;
|
|
+ struct uip_tcp_hdr *tcp_hdr = NULL;
|
|
+ struct uip_icmpv4_hdr *icmpv4_hdr = NULL;
|
|
+ struct uip_icmpv6_hdr *icmpv6_hdr __attribute__((__unused__)) = NULL;
|
|
+ struct uip_udp_hdr *udp_hdr = NULL;
|
|
+
|
|
+ /* Drop invalid packets */
|
|
+ if (ustack->uip_buf == NULL) {
|
|
+ LOG_ERR(PFX "ustack->uip_buf == NULL.");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (is_ipv6(ustack)) {
|
|
+ uint8_t *buf;
|
|
+ uip_iph_len = UIP_IPv6_H_LEN;
|
|
+ uip_ip_udph_len = UIP_IPv6_UDPH_LEN;
|
|
+ uip_ip_tcph_len = UIP_IPv6_TCPH_LEN;
|
|
+
|
|
+ ipv6_hdr = (struct ip6_hdr *)ustack->network_layer;
|
|
+
|
|
+ buf = ustack->network_layer;
|
|
+ buf += sizeof(struct uip_ipv6_hdr);
|
|
+ tcp_hdr = (struct uip_tcp_hdr *)buf;
|
|
+
|
|
+ buf = ustack->network_layer;
|
|
+ buf += sizeof(struct uip_ipv6_hdr);
|
|
+ udp_hdr = (struct uip_udp_hdr *)buf;
|
|
+
|
|
+ buf = ustack->network_layer;
|
|
+ buf += sizeof(struct uip_ipv6_hdr);
|
|
+ icmpv6_hdr = (struct uip_icmpv6_hdr *)buf;
|
|
+ } else {
|
|
+ uint8_t *buf;
|
|
+
|
|
+ uip_iph_len = UIP_IPv4_H_LEN;
|
|
+ uip_ip_udph_len = UIP_IPv4_UDPH_LEN;
|
|
+ uip_ip_tcph_len = UIP_IPv4_TCPH_LEN;
|
|
+
|
|
+ tcp_ipv4_hdr = (struct uip_tcp_ipv4_hdr *)ustack->network_layer;
|
|
+
|
|
+ buf = ustack->network_layer;
|
|
+ buf += sizeof(struct uip_ipv4_hdr);
|
|
+ tcp_hdr = (struct uip_tcp_hdr *)buf;
|
|
+
|
|
+ buf = ustack->network_layer;
|
|
+ buf += sizeof(struct uip_ipv4_hdr);
|
|
+ icmpv4_hdr = (struct uip_icmpv4_hdr *)buf;
|
|
+
|
|
+ buf = ustack->network_layer;
|
|
+ buf += sizeof(struct uip_ipv4_hdr);
|
|
+ udp_hdr = (struct uip_udp_hdr *)buf;
|
|
+ } /* End of ipv6 */
|
|
+
|
|
+#if UIP_UDP
|
|
+ if (flag == UIP_UDP_SEND_CONN)
|
|
+ goto udp_send;
|
|
+#endif /* UIP_UDP */
|
|
+ ustack->uip_sappdata = ustack->uip_appdata = ustack->network_layer +
|
|
+ uip_ip_tcph_len;
|
|
+
|
|
+ /* Check if we were invoked because of a poll request for a
|
|
+ particular connection. */
|
|
+ if (flag == UIP_POLL_REQUEST) {
|
|
+ if ((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED
|
|
+ && !uip_outstanding(uip_connr)) {
|
|
+ ustack->uip_flags = UIP_POLL;
|
|
+ UIP_APPCALL(ustack);
|
|
+ goto appsend;
|
|
+ }
|
|
+ goto drop;
|
|
+
|
|
+ /* Check if we were invoked because of the perodic timer
|
|
+ firing. */
|
|
+ } else if (flag == UIP_TIMER) {
|
|
+#if UIP_REASSEMBLY
|
|
+ if (uip_reasstmr != 0)
|
|
+ --uip_reasstmr;
|
|
+#endif /* UIP_REASSEMBLY */
|
|
+ /* Increase the initial sequence number. */
|
|
+ if (++ustack->iss[3] == 0) {
|
|
+ if (++ustack->iss[2] == 0) {
|
|
+ if (++ustack->iss[1] == 0)
|
|
+ ++ustack->iss[0];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Reset the length variables. */
|
|
+ ustack->uip_len = 0;
|
|
+ ustack->uip_slen = 0;
|
|
+
|
|
+ /* Check if the connection is in a state in which we simply wait
|
|
+ for the connection to time out. If so, we increase the
|
|
+ connection's timer and remove the connection if it times
|
|
+ out. */
|
|
+ if (uip_connr->tcpstateflags == UIP_TIME_WAIT ||
|
|
+ uip_connr->tcpstateflags == UIP_FIN_WAIT_2) {
|
|
+ ++(uip_connr->timer);
|
|
+ if (uip_connr->timer == UIP_TIME_WAIT_TIMEOUT)
|
|
+ uip_connr->tcpstateflags = UIP_CLOSED;
|
|
+ } else if (uip_connr->tcpstateflags != UIP_CLOSED) {
|
|
+ /* If the connection has outstanding data, we increase
|
|
+ the connection's timer and see if it has reached the
|
|
+ RTO value in which case we retransmit. */
|
|
+ if (uip_outstanding(uip_connr)) {
|
|
+ if (uip_connr->timer-- == 0) {
|
|
+ if (uip_connr->nrtx == UIP_MAXRTX ||
|
|
+ ((uip_connr->tcpstateflags ==
|
|
+ UIP_SYN_SENT
|
|
+ || uip_connr->tcpstateflags ==
|
|
+ UIP_SYN_RCVD)
|
|
+ && uip_connr->nrtx ==
|
|
+ UIP_MAXSYNRTX)) {
|
|
+ uip_connr->tcpstateflags =
|
|
+ UIP_CLOSED;
|
|
+
|
|
+ /* We call UIP_APPCALL() with
|
|
+ uip_flags set to UIP_TIMEDOUT
|
|
+ to inform the application
|
|
+ that the connection has timed
|
|
+ out. */
|
|
+ ustack->uip_flags =
|
|
+ UIP_TIMEDOUT;
|
|
+ UIP_APPCALL(ustack);
|
|
+
|
|
+ /* We also send a reset packet
|
|
+ to the remote host. */
|
|
+ tcp_hdr->flags =
|
|
+ TCP_RST | TCP_ACK;
|
|
+ goto tcp_send_nodata;
|
|
+ }
|
|
+
|
|
+ /* Exponential backoff. */
|
|
+ uip_connr->timer =
|
|
+ UIP_RTO << (uip_connr->nrtx >
|
|
+ 4 ? 4 : uip_connr->
|
|
+ nrtx);
|
|
+ ++(uip_connr->nrtx);
|
|
+
|
|
+ /* Ok, so we need to retransmit.
|
|
+ We do this differently depending on
|
|
+ which state we are in.
|
|
+ In ESTABLISHED, we call upon the
|
|
+ application so that it may prepare
|
|
+ the data for the retransmit.
|
|
+ In SYN_RCVD, we resend the SYNACK
|
|
+ that we sent earlier and in LAST_ACK
|
|
+ we have to retransmit our FINACK. */
|
|
+ ++ustack->stats.tcp.rexmit;
|
|
+ switch (uip_connr->
|
|
+ tcpstateflags & UIP_TS_MASK) {
|
|
+ case UIP_SYN_RCVD:
|
|
+ /* In the SYN_RCVD state, we
|
|
+ should retransmit our SYNACK
|
|
+ */
|
|
+ goto tcp_send_synack;
|
|
+#if UIP_ACTIVE_OPEN
|
|
+ case UIP_SYN_SENT:
|
|
+ /* In the SYN_SENT state,
|
|
+ we retransmit out SYN. */
|
|
+ tcp_hdr->flags = 0;
|
|
+ goto tcp_send_syn;
|
|
+#endif /* UIP_ACTIVE_OPEN */
|
|
+
|
|
+ case UIP_ESTABLISHED:
|
|
+ /* In the ESTABLISHED state,
|
|
+ we call upon the application
|
|
+ to do the actual retransmit
|
|
+ after which we jump into
|
|
+ the code for sending out the
|
|
+ packet (the apprexmit
|
|
+ label). */
|
|
+ ustack->uip_flags = UIP_REXMIT;
|
|
+ UIP_APPCALL(ustack);
|
|
+ goto apprexmit;
|
|
+
|
|
+ case UIP_FIN_WAIT_1:
|
|
+ case UIP_CLOSING:
|
|
+ case UIP_LAST_ACK:
|
|
+ /* In all these states we should
|
|
+ retransmit a FINACK. */
|
|
+ goto tcp_send_finack;
|
|
+
|
|
+ }
|
|
+ }
|
|
+ } else if ((uip_connr->tcpstateflags & UIP_TS_MASK) ==
|
|
+ UIP_ESTABLISHED) {
|
|
+ /* If there was no need for a retransmission,
|
|
+ we poll the application for new data. */
|
|
+ ustack->uip_flags = UIP_POLL;
|
|
+ UIP_APPCALL(ustack);
|
|
+ goto appsend;
|
|
+ }
|
|
+ }
|
|
+ goto drop;
|
|
+ } /* End of UIP_TIMER */
|
|
+#if UIP_UDP
|
|
+ if (flag == UIP_UDP_TIMER) {
|
|
+ /* This is for IPv4 DHCP only! */
|
|
+ if (ustack->uip_udp_conn->lport != 0) {
|
|
+ ustack->uip_conn = NULL;
|
|
+ ustack->uip_sappdata = ustack->uip_appdata =
|
|
+ ustack->network_layer + uip_ip_udph_len;
|
|
+ ustack->uip_len = ustack->uip_slen = 0;
|
|
+ ustack->uip_flags = UIP_POLL;
|
|
+ UIP_UDP_APPCALL(ustack);
|
|
+ goto udp_send;
|
|
+ } else {
|
|
+ goto drop;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ if (flag == UIP_NDP_TIMER) {
|
|
+ /* This is for IPv6 NDP Only! */
|
|
+ if (1) { /* If NDP engine active */
|
|
+ ustack->uip_len = ustack->uip_slen = 0;
|
|
+ ustack->uip_flags = UIP_POLL;
|
|
+ goto ndp_send;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* This is where the input processing starts. */
|
|
+ ++ustack->stats.ip.recv;
|
|
+
|
|
+ /* Start of IP input header processing code. */
|
|
+
|
|
+ if (is_ipv6(ustack)) {
|
|
+ u8_t version = ((ipv6_hdr->ip6_vfc) & 0xf0) >> 4;
|
|
+
|
|
+ /* Check validity of the IP header. */
|
|
+ if (version != 0x6) { /* IP version and header length. */
|
|
+ ++ustack->stats.ip.drop;
|
|
+ ++ustack->stats.ip.vhlerr;
|
|
+ LOG_DEBUG(PFX "ipv6: invalid version(0x%x).", version);
|
|
+ goto drop;
|
|
+ }
|
|
+ } else {
|
|
+ /* Check validity of the IP header. */
|
|
+ if (tcp_ipv4_hdr->vhl != 0x45) {
|
|
+ /* IP version and header length. */
|
|
+ ++ustack->stats.ip.drop;
|
|
+ ++ustack->stats.ip.vhlerr;
|
|
+ LOG_DEBUG(PFX
|
|
+ "ipv4: invalid version or header length: "
|
|
+ "0x%x.",
|
|
+ tcp_ipv4_hdr->vhl);
|
|
+ goto drop;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Check the size of the packet. If the size reported to us in
|
|
+ uip_len is smaller the size reported in the IP header, we assume
|
|
+ that the packet has been corrupted in transit. If the size of
|
|
+ uip_len is larger than the size reported in the IP packet header,
|
|
+ the packet has been padded and we set uip_len to the correct
|
|
+ value.. */
|
|
+
|
|
+ if (is_ipv6(ustack)) {
|
|
+ u16_t len = ntohs(ipv6_hdr->ip6_plen);
|
|
+ if (len > ustack->uip_len) {
|
|
+ LOG_DEBUG(PFX
|
|
+ "ip: packet shorter than reported in IP header"
|
|
+ ":IPv6_BUF(ustack)->len: %d ustack->uip_len: "
|
|
+ "%d", len, ustack->uip_len);
|
|
+ goto drop;
|
|
+ }
|
|
+ } else {
|
|
+ if ((tcp_ipv4_hdr->len[0] << 8) +
|
|
+ tcp_ipv4_hdr->len[1] <= ustack->uip_len) {
|
|
+ ustack->uip_len = (tcp_ipv4_hdr->len[0] << 8) +
|
|
+ tcp_ipv4_hdr->len[1];
|
|
+ } else {
|
|
+ LOG_DEBUG(PFX
|
|
+ "ip: packet shorter than reported in IP header"
|
|
+ ":tcp_ipv4_hdr->len: %d ustack->uip_len:%d.",
|
|
+ (tcp_ipv4_hdr->len[0] << 8) +
|
|
+ tcp_ipv4_hdr->len[1], ustack->uip_len);
|
|
+ goto drop;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!is_ipv6(ustack)) {
|
|
+ /* Check the fragment flag. */
|
|
+ if ((tcp_ipv4_hdr->ipoffset[0] & 0x3f) != 0 ||
|
|
+ tcp_ipv4_hdr->ipoffset[1] != 0) {
|
|
+#if UIP_REASSEMBLY
|
|
+ uip_len = uip_reass();
|
|
+ if (uip_len == 0)
|
|
+ goto drop;
|
|
+#else /* UIP_REASSEMBLY */
|
|
+ ++ustack->stats.ip.drop;
|
|
+ ++ustack->stats.ip.fragerr;
|
|
+ LOG_WARN(PFX "ip: fragment dropped.");
|
|
+ goto drop;
|
|
+#endif /* UIP_REASSEMBLY */
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!is_ipv6(ustack)) {
|
|
+ /* ipv4 */
|
|
+ if (uip_ip4addr_cmp(ustack->hostaddr, all_zeroes_addr4)) {
|
|
+ /* If we are configured to use ping IP address
|
|
+ configuration and hasn't been assigned an IP
|
|
+ address yet, we accept all ICMP packets. */
|
|
+#if UIP_PINGADDRCONF && !UIP_CONF_IPV6
|
|
+ if (tcp_ipv4_hdr->proto == UIP_PROTO_ICMP) {
|
|
+ LOG_WARN(PFX
|
|
+ "ip: possible ping config packet "
|
|
+ "received.");
|
|
+ goto icmp_input;
|
|
+ } else {
|
|
+ LOG_WARN(PFX
|
|
+ "ip: packet dropped since no "
|
|
+ "address assigned.");
|
|
+ goto drop;
|
|
+ }
|
|
+#endif /* UIP_PINGADDRCONF */
|
|
+ } else {
|
|
+ int broadcast_addr = 0xFFFFFFFF;
|
|
+ /* If IP broadcast support is configured, we check for
|
|
+ a broadcast UDP packet, which may be destined to us
|
|
+ */
|
|
+ if ((tcp_ipv4_hdr->proto == UIP_PROTO_UDP) &&
|
|
+ (uip_ip4addr_cmp
|
|
+ (tcp_ipv4_hdr->destipaddr, &broadcast_addr))
|
|
+ /*&&
|
|
+ uip_ipchksum() == 0xffff */
|
|
+ ) {
|
|
+ goto udp_input;
|
|
+ }
|
|
+
|
|
+ /* Check if the packet is destined for our IP address
|
|
+ */
|
|
+ if (!uip_ip4addr_cmp(tcp_ipv4_hdr->destipaddr,
|
|
+ ustack->hostaddr)) {
|
|
+ ++ustack->stats.ip.drop;
|
|
+ goto drop;
|
|
+ }
|
|
+ }
|
|
+ if (uip_ipchksum(ustack) != 0xffff) {
|
|
+ /* Compute and check the IP header checksum. */
|
|
+ ++ustack->stats.ip.drop;
|
|
+ ++ustack->stats.ip.chkerr;
|
|
+ LOG_ERR(PFX "ip: bad checksum.");
|
|
+ goto drop;
|
|
+ }
|
|
+ } /* End of ipv4 */
|
|
+
|
|
+ if (is_ipv6(ustack)) {
|
|
+ if (ipv6_hdr->ip6_nxt == UIP_PROTO_TCP) {
|
|
+ /* Check for TCP packet. If so, proceed with TCP input
|
|
+ processing. */
|
|
+ goto ndp_newdata;
|
|
+ }
|
|
+#if UIP_UDP
|
|
+ if (ipv6_hdr->ip6_nxt == UIP_PROTO_UDP)
|
|
+ goto ndp_newdata;
|
|
+#endif /* UIP_UDP */
|
|
+
|
|
+ /* This is IPv6 ICMPv6 processing code. */
|
|
+ if (ipv6_hdr->ip6_nxt != UIP_PROTO_ICMP6) {
|
|
+ /* We only allow ICMPv6 packets from here. */
|
|
+ ++ustack->stats.ip.drop;
|
|
+ ++ustack->stats.ip.protoerr;
|
|
+ goto drop;
|
|
+ }
|
|
+
|
|
+ ++ustack->stats.icmp.recv;
|
|
+
|
|
+ndp_newdata:
|
|
+ /* This call is to handle the IPv6 Network Discovery Protocol */
|
|
+ ustack->uip_flags = UIP_NEWDATA;
|
|
+ ustack->uip_slen = 0;
|
|
+ndp_send:
|
|
+ UIP_NDP_CALL(ustack);
|
|
+ if (ustack->uip_slen != 0) {
|
|
+ ustack->uip_len = ustack->uip_slen;
|
|
+ goto send;
|
|
+ } else {
|
|
+ goto drop;
|
|
+ }
|
|
+ } else {
|
|
+ /* IPv4 Processing */
|
|
+ if (tcp_ipv4_hdr->proto == UIP_PROTO_TCP) {
|
|
+ /* Check for TCP packet. If so, proceed with TCP input
|
|
+ processing. */
|
|
+ goto tcp_input;
|
|
+ }
|
|
+#if UIP_UDP
|
|
+ if (tcp_ipv4_hdr->proto == UIP_PROTO_UDP)
|
|
+ goto udp_input;
|
|
+#endif /* UIP_UDP */
|
|
+
|
|
+ /* ICMPv4 processing code follows. */
|
|
+ if (tcp_ipv4_hdr->proto != UIP_PROTO_ICMP) {
|
|
+ /* We only allow ICMP packets from here. */
|
|
+ ++ustack->stats.ip.drop;
|
|
+ ++ustack->stats.ip.protoerr;
|
|
+ LOG_DEBUG(PFX "ip: neither tcp nor icmp.");
|
|
+ goto drop;
|
|
+ }
|
|
+#if UIP_PINGADDRCONF
|
|
+icmp_input:
|
|
+#endif /* UIP_PINGADDRCONF */
|
|
+ ++ustack->stats.icmp.recv;
|
|
+
|
|
+ /* ICMP echo (i.e., ping) processing. This is simple, we only
|
|
+ change the ICMP type from ECHO to ECHO_REPLY and adjust the
|
|
+ ICMP checksum before we return the packet. */
|
|
+ if (icmpv4_hdr->type != ICMP_ECHO) {
|
|
+ ++ustack->stats.icmp.drop;
|
|
+ ++ustack->stats.icmp.typeerr;
|
|
+ LOG_DEBUG(PFX "icmp: not icmp echo.");
|
|
+ goto drop;
|
|
+ }
|
|
+
|
|
+ /* If we are configured to use ping IP address assignment, we
|
|
+ use the destination IP address of this ping packet and assign
|
|
+ it to ourself. */
|
|
+#if UIP_PINGADDRCONF
|
|
+ if ((ustack->hostaddr[0] | ustack->hostaddr[1]) == 0) {
|
|
+ ustack->hostaddr[0] = tcp_ipv4_hdr->destipaddr[0];
|
|
+ ustack->hostaddr[1] = tcp_ipv4_hdr->destipaddr[1];
|
|
+ }
|
|
+#endif /* UIP_PINGADDRCONF */
|
|
+
|
|
+ icmpv4_hdr->type = ICMP_ECHO_REPLY;
|
|
+
|
|
+ if (icmpv4_hdr->icmpchksum >= htons(0xffff -
|
|
+ (ICMP_ECHO << 8))) {
|
|
+ icmpv4_hdr->icmpchksum += htons(ICMP_ECHO << 8) + 1;
|
|
+ } else {
|
|
+ icmpv4_hdr->icmpchksum += htons(ICMP_ECHO << 8);
|
|
+ }
|
|
+
|
|
+ /* Swap IP addresses. */
|
|
+ uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr,
|
|
+ tcp_ipv4_hdr->srcipaddr);
|
|
+ uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr);
|
|
+
|
|
+ ++ustack->stats.icmp.sent;
|
|
+ goto send;
|
|
+
|
|
+ /* End of IPv4 input header processing code. */
|
|
+ }
|
|
+
|
|
+#if UIP_UDP
|
|
+ /* UDP input processing. */
|
|
+udp_input:
|
|
+ /* UDP processing is really just a hack. We don't do anything to the
|
|
+ UDP/IP headers, but let the UDP application do all the hard
|
|
+ work. If the application sets uip_slen, it has a packet to
|
|
+ send. */
|
|
+#if UIP_UDP_CHECKSUMS
|
|
+ ustack->uip_len = ustack->uip_len - uip_ip_udph_len;
|
|
+ ustack->uip_appdata = ustack->network_layer + uip_ip_udph_len;
|
|
+ if (UDPBUF(ustack)->udpchksum != 0 && uip_udpchksum(ustack) != 0xffff) {
|
|
+ ++ustack->stats.udp.drop;
|
|
+ ++ustack->stats.udp.chkerr;
|
|
+ LOG_DEBUG(PFX "udp: bad checksum.");
|
|
+ goto drop;
|
|
+ }
|
|
+#else /* UIP_UDP_CHECKSUMS */
|
|
+ uip_len = uip_len - uip_ip_udph_len;
|
|
+#endif /* UIP_UDP_CHECKSUMS */
|
|
+
|
|
+ if (is_ipv6(ustack))
|
|
+ goto udp_found;
|
|
+
|
|
+ /* Demultiplex this UDP packet between the UDP "connections". */
|
|
+ for (ustack->uip_udp_conn = &ustack->uip_udp_conns[0];
|
|
+ ustack->uip_udp_conn < &ustack->uip_udp_conns[UIP_UDP_CONNS];
|
|
+ ++ustack->uip_udp_conn) {
|
|
+ /* If the local UDP port is non-zero, the connection is
|
|
+ considered to be used. If so, the local port number is
|
|
+ checked against the destination port number in the
|
|
+ received packet. If the two port
|
|
+ numbers match, the remote port number is checked if the
|
|
+ connection is bound to a remote port. Finally, if the
|
|
+ connection is bound to a remote IP address, the source IP
|
|
+ address of the packet is checked. */
|
|
+
|
|
+ if (ustack->uip_udp_conn->lport != 0 &&
|
|
+ UDPBUF(ustack)->destport == ustack->uip_udp_conn->lport &&
|
|
+ (ustack->uip_udp_conn->rport == 0 ||
|
|
+ UDPBUF(ustack)->srcport == ustack->uip_udp_conn->rport) &&
|
|
+ (uip_ip4addr_cmp(ustack->uip_udp_conn->ripaddr,
|
|
+ all_zeroes_addr4) ||
|
|
+ uip_ip4addr_cmp(ustack->uip_udp_conn->ripaddr,
|
|
+ all_ones_addr4) ||
|
|
+ uip_ip4addr_cmp(tcp_ipv4_hdr->srcipaddr,
|
|
+ ustack->uip_udp_conn->ripaddr))) {
|
|
+ goto udp_found;
|
|
+ }
|
|
+ }
|
|
+ LOG_DEBUG(PFX
|
|
+ "udp: no matching connection found: dest port: %d src port: "
|
|
+ "%d", udp_hdr->destport, udp_hdr->srcport);
|
|
+ goto drop;
|
|
+
|
|
+udp_found:
|
|
+ ustack->uip_conn = NULL;
|
|
+ ustack->uip_flags = UIP_NEWDATA;
|
|
+ ustack->uip_sappdata = ustack->uip_appdata = ustack->network_layer +
|
|
+ uip_ip_udph_len;
|
|
+ ustack->uip_slen = 0;
|
|
+ if (is_ipv6(ustack))
|
|
+ UIP_NDP_CALL(ustack);
|
|
+ else
|
|
+ UIP_UDP_APPCALL(ustack);
|
|
+udp_send:
|
|
+ if (ustack->uip_slen == 0)
|
|
+ goto drop;
|
|
+
|
|
+ ustack->uip_len = ustack->uip_slen + uip_ip_udph_len;
|
|
+
|
|
+ if (is_ipv6(ustack)) {
|
|
+ goto ip_send_nolen;
|
|
+ } else {
|
|
+ tcp_ipv4_hdr->len[0] = (ustack->uip_len >> 8);
|
|
+ tcp_ipv4_hdr->len[1] = (ustack->uip_len & 0xff);
|
|
+ tcp_ipv4_hdr->ttl = ustack->uip_udp_conn->ttl;
|
|
+ tcp_ipv4_hdr->proto = UIP_PROTO_UDP;
|
|
+ }
|
|
+
|
|
+ udp_hdr->udplen = htons(ustack->uip_slen + UIP_UDPH_LEN);
|
|
+ udp_hdr->udpchksum = 0;
|
|
+
|
|
+ udp_hdr->srcport = ustack->uip_udp_conn->lport;
|
|
+ udp_hdr->destport = ustack->uip_udp_conn->rport;
|
|
+
|
|
+ uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr);
|
|
+ uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr,
|
|
+ ustack->uip_udp_conn->ripaddr);
|
|
+
|
|
+ ustack->uip_appdata = ustack->network_layer + uip_ip_tcph_len;
|
|
+
|
|
+ if (ustack->uip_buf == NULL) {
|
|
+ LOG_WARN(PFX "uip_buf == NULL on udp send");
|
|
+ goto drop;
|
|
+ }
|
|
+#if UIP_UDP_CHECKSUMS
|
|
+ /* Calculate UDP checksum. */
|
|
+ udp_hdr->udpchksum = ~(uip_udpchksum(ustack));
|
|
+ if (udp_hdr->udpchksum == 0)
|
|
+ udp_hdr->udpchksum = 0xffff;
|
|
+#endif /* UIP_UDP_CHECKSUMS */
|
|
+
|
|
+ goto ip_send_nolen;
|
|
+#endif /* UIP_UDP */
|
|
+
|
|
+ /* TCP input processing. */
|
|
+tcp_input:
|
|
+ ++ustack->stats.tcp.recv;
|
|
+
|
|
+ /* Start of TCP input header processing code. */
|
|
+
|
|
+ if (uip_tcpchksum(ustack) != 0xffff) { /* Compute and check the TCP
|
|
+ checksum. */
|
|
+ ++ustack->stats.tcp.drop;
|
|
+ ++ustack->stats.tcp.chkerr;
|
|
+ LOG_WARN(PFX "tcp: bad checksum.");
|
|
+ goto drop;
|
|
+ }
|
|
+
|
|
+ if (is_ipv6(ustack)) {
|
|
+ /* Demultiplex this segment. */
|
|
+ /* First check any active connections. */
|
|
+ for (uip_connr = &ustack->uip_conns[0];
|
|
+ uip_connr <= &ustack->uip_conns[UIP_CONNS - 1];
|
|
+ ++uip_connr) {
|
|
+ if (uip_connr->tcpstateflags != UIP_CLOSED &&
|
|
+ tcp_hdr->destport == uip_connr->lport &&
|
|
+ tcp_hdr->srcport == uip_connr->rport &&
|
|
+ uip_ip6addr_cmp(IPv6_BUF(ustack)->srcipaddr,
|
|
+ uip_connr->ripaddr)) {
|
|
+ goto found;
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ /* Demultiplex this segment. */
|
|
+ /* First check any active connections. */
|
|
+ for (uip_connr = &ustack->uip_conns[0];
|
|
+ uip_connr <= &ustack->uip_conns[UIP_CONNS - 1];
|
|
+ ++uip_connr) {
|
|
+ if (uip_connr->tcpstateflags != UIP_CLOSED &&
|
|
+ tcp_hdr->destport == uip_connr->lport &&
|
|
+ tcp_hdr->srcport == uip_connr->rport &&
|
|
+ uip_ip4addr_cmp(tcp_ipv4_hdr->srcipaddr,
|
|
+ uip_connr->ripaddr)) {
|
|
+ goto found;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* If we didn't find and active connection that expected the packet,
|
|
+ either this packet is an old duplicate, or this is a SYN packet
|
|
+ destined for a connection in LISTEN. If the SYN flag isn't set,
|
|
+ it is an old packet and we send a RST. */
|
|
+ if ((tcp_hdr->flags & TCP_CTL) != TCP_SYN)
|
|
+ goto reset;
|
|
+
|
|
+ tmp16 = tcp_hdr->destport;
|
|
+ /* Next, check listening connections. */
|
|
+ for (c = 0; c < UIP_LISTENPORTS; ++c) {
|
|
+ if (tmp16 == ustack->uip_listenports[c])
|
|
+ goto found_listen;
|
|
+ }
|
|
+
|
|
+ /* No matching connection found, so we send a RST packet. */
|
|
+ ++ustack->stats.tcp.synrst;
|
|
+reset:
|
|
+
|
|
+ /* We do not send resets in response to resets. */
|
|
+ if (tcp_hdr->flags & TCP_RST)
|
|
+ goto drop;
|
|
+
|
|
+ ++ustack->stats.tcp.rst;
|
|
+
|
|
+ tcp_hdr->flags = TCP_RST | TCP_ACK;
|
|
+ ustack->uip_len = uip_ip_tcph_len;
|
|
+ tcp_hdr->tcpoffset = 5 << 4;
|
|
+
|
|
+ /* Flip the seqno and ackno fields in the TCP header. */
|
|
+ c = tcp_hdr->seqno[3];
|
|
+ tcp_hdr->seqno[3] = tcp_hdr->ackno[3];
|
|
+ tcp_hdr->ackno[3] = c;
|
|
+
|
|
+ c = tcp_hdr->seqno[2];
|
|
+ tcp_hdr->seqno[2] = tcp_hdr->ackno[2];
|
|
+ tcp_hdr->ackno[2] = c;
|
|
+
|
|
+ c = tcp_hdr->seqno[1];
|
|
+ tcp_hdr->seqno[1] = tcp_hdr->ackno[1];
|
|
+ tcp_hdr->ackno[1] = c;
|
|
+
|
|
+ c = tcp_hdr->seqno[0];
|
|
+ tcp_hdr->seqno[0] = tcp_hdr->ackno[0];
|
|
+ tcp_hdr->ackno[0] = c;
|
|
+
|
|
+ /* We also have to increase the sequence number we are
|
|
+ acknowledging. If the least significant byte overflowed, we need
|
|
+ to propagate the carry to the other bytes as well. */
|
|
+ if (++tcp_hdr->ackno[3] == 0) {
|
|
+ if (++tcp_hdr->ackno[2] == 0) {
|
|
+ if (++tcp_hdr->ackno[1] == 0)
|
|
+ ++tcp_hdr->ackno[0];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Swap port numbers. */
|
|
+ tmp16 = tcp_hdr->srcport;
|
|
+ tcp_hdr->srcport = tcp_hdr->destport;
|
|
+ tcp_hdr->destport = tmp16;
|
|
+
|
|
+ /* Swap IP addresses. */
|
|
+ if (is_ipv6(ustack)) {
|
|
+ uip_ip6addr_copy(IPv6_BUF(ustack)->destipaddr,
|
|
+ IPv6_BUF(ustack)->srcipaddr);
|
|
+ uip_ip6addr_copy(IPv6_BUF(ustack)->srcipaddr,
|
|
+ ustack->hostaddr6);
|
|
+ } else {
|
|
+ uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr,
|
|
+ tcp_ipv4_hdr->srcipaddr);
|
|
+ uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr);
|
|
+ }
|
|
+
|
|
+ /* And send out the RST packet! */
|
|
+ goto tcp_send_noconn;
|
|
+
|
|
+ /* This label will be jumped to if we matched the incoming packet
|
|
+ with a connection in LISTEN. In that case, we should create a new
|
|
+ connection and send a SYNACK in return. */
|
|
+found_listen:
|
|
+ /* First we check if there are any connections avaliable. Unused
|
|
+ connections are kept in the same table as used connections, but
|
|
+ unused ones have the tcpstate set to CLOSED. Also, connections in
|
|
+ TIME_WAIT are kept track of and we'll use the oldest one if no
|
|
+ CLOSED connections are found. Thanks to Eddie C. Dost for a very
|
|
+ nice algorithm for the TIME_WAIT search. */
|
|
+ uip_connr = 0;
|
|
+ for (c = 0; c < UIP_CONNS; ++c) {
|
|
+ if (ustack->uip_conns[c].tcpstateflags == UIP_CLOSED) {
|
|
+ uip_connr = &ustack->uip_conns[c];
|
|
+ break;
|
|
+ }
|
|
+ if (ustack->uip_conns[c].tcpstateflags == UIP_TIME_WAIT) {
|
|
+ if (uip_connr == 0 ||
|
|
+ ustack->uip_conns[c].timer > uip_connr->timer) {
|
|
+ uip_connr = &ustack->uip_conns[c];
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (uip_connr == 0) {
|
|
+ /* All connections are used already, we drop packet and hope
|
|
+ that the remote end will retransmit the packet at a time when
|
|
+ we have more spare connections. */
|
|
+ ++ustack->stats.tcp.syndrop;
|
|
+ LOG_WARN(PFX "tcp: found no unused connections.");
|
|
+ goto drop;
|
|
+ }
|
|
+ ustack->uip_conn = uip_connr;
|
|
+
|
|
+ /* Fill in the necessary fields for the new connection. */
|
|
+ uip_connr->rto = uip_connr->timer = UIP_RTO;
|
|
+ uip_connr->sa = 0;
|
|
+ uip_connr->sv = 4;
|
|
+ uip_connr->nrtx = 0;
|
|
+ uip_connr->lport = tcp_hdr->destport;
|
|
+ uip_connr->rport = tcp_hdr->srcport;
|
|
+ if (is_ipv6(ustack)) {
|
|
+ uip_ip6addr_copy(uip_connr->ripaddr,
|
|
+ IPv6_BUF(ustack)->srcipaddr);
|
|
+ } else {
|
|
+ uip_ip4addr_copy(uip_connr->ripaddr, tcp_ipv4_hdr->srcipaddr);
|
|
+ }
|
|
+ uip_connr->tcpstateflags = UIP_SYN_RCVD;
|
|
+
|
|
+ uip_connr->snd_nxt[0] = ustack->iss[0];
|
|
+ uip_connr->snd_nxt[1] = ustack->iss[1];
|
|
+ uip_connr->snd_nxt[2] = ustack->iss[2];
|
|
+ uip_connr->snd_nxt[3] = ustack->iss[3];
|
|
+ uip_connr->len = 1;
|
|
+
|
|
+ /* rcv_nxt should be the seqno from the incoming packet + 1. */
|
|
+ uip_connr->rcv_nxt[3] = tcp_hdr->seqno[3];
|
|
+ uip_connr->rcv_nxt[2] = tcp_hdr->seqno[2];
|
|
+ uip_connr->rcv_nxt[1] = tcp_hdr->seqno[1];
|
|
+ uip_connr->rcv_nxt[0] = tcp_hdr->seqno[0];
|
|
+ uip_add_rcv_nxt(ustack, 1);
|
|
+
|
|
+ /* Parse the TCP MSS option, if present. */
|
|
+ if ((tcp_hdr->tcpoffset & 0xf0) > 0x50) {
|
|
+ for (c = 0; c < ((tcp_hdr->tcpoffset >> 4) - 5) << 2;) {
|
|
+ ustack->opt =
|
|
+ ustack->uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + c];
|
|
+ if (ustack->opt == TCP_OPT_END) {
|
|
+ /* End of options. */
|
|
+ break;
|
|
+ } else if (ustack->opt == TCP_OPT_NOOP) {
|
|
+ ++c;
|
|
+ /* NOP option. */
|
|
+ } else if (ustack->opt == TCP_OPT_MSS &&
|
|
+ ustack->uip_buf[uip_ip_tcph_len +
|
|
+ UIP_LLH_LEN + 1 + c] ==
|
|
+ TCP_OPT_MSS_LEN) {
|
|
+ /* An MSS option with the right option length.*/
|
|
+ tmp16 =
|
|
+ ((u16_t) ustack->
|
|
+ uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 2 +
|
|
+ c] << 8) | (u16_t) ustack->
|
|
+ uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 3 +
|
|
+ c];
|
|
+ uip_connr->initialmss = uip_connr->mss =
|
|
+ tmp16 > UIP_TCP_MSS ? UIP_TCP_MSS : tmp16;
|
|
+
|
|
+ /* And we are done processing options. */
|
|
+ break;
|
|
+ } else {
|
|
+ /* All other options have a length field, so
|
|
+ that we easily can skip past them. */
|
|
+ if (ustack->
|
|
+ uip_buf[uip_ip_tcph_len + UIP_LLH_LEN + 1 +
|
|
+ c] == 0) {
|
|
+ /* If the length field is zero, the
|
|
+ options are malformed
|
|
+ and we don't process them further. */
|
|
+ break;
|
|
+ }
|
|
+ c += ustack->uip_buf[uip_ip_tcph_len +
|
|
+ UIP_LLH_LEN + 1 + c];
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Our response will be a SYNACK. */
|
|
+#if UIP_ACTIVE_OPEN
|
|
+tcp_send_synack:
|
|
+ tcp_hdr->flags = TCP_ACK;
|
|
+
|
|
+tcp_send_syn:
|
|
+ tcp_hdr->flags |= TCP_SYN;
|
|
+#else /* UIP_ACTIVE_OPEN */
|
|
+tcp_send_synack:
|
|
+ tcp_hdr->flags = TCP_SYN | TCP_ACK;
|
|
+#endif /* UIP_ACTIVE_OPEN */
|
|
+
|
|
+ /* We send out the TCP Maximum Segment Size option with our
|
|
+ SYNACK. */
|
|
+ tcp_hdr->optdata[0] = TCP_OPT_MSS;
|
|
+ tcp_hdr->optdata[1] = TCP_OPT_MSS_LEN;
|
|
+ tcp_hdr->optdata[2] = (UIP_TCP_MSS) / 256;
|
|
+ tcp_hdr->optdata[3] = (UIP_TCP_MSS) & 255;
|
|
+ ustack->uip_len = uip_ip_tcph_len + TCP_OPT_MSS_LEN;
|
|
+ tcp_hdr->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4;
|
|
+ goto tcp_send;
|
|
+
|
|
+ /* This label will be jumped to if we found an active connection. */
|
|
+found:
|
|
+ ustack->uip_conn = uip_connr;
|
|
+ ustack->uip_flags = 0;
|
|
+ /* We do a very naive form of TCP reset processing; we just accept
|
|
+ any RST and kill our connection. We should in fact check if the
|
|
+ sequence number of this reset is wihtin our advertised window
|
|
+ before we accept the reset. */
|
|
+ if (tcp_hdr->flags & TCP_RST) {
|
|
+ uip_connr->tcpstateflags = UIP_CLOSED;
|
|
+ LOG_WARN(PFX "tcp: got reset, aborting connection.");
|
|
+ ustack->uip_flags = UIP_ABORT;
|
|
+ UIP_APPCALL(ustack);
|
|
+ goto drop;
|
|
+ }
|
|
+ /* Calculated the length of the data, if the application has sent
|
|
+ any data to us. */
|
|
+ c = (tcp_hdr->tcpoffset >> 4) << 2;
|
|
+ /* uip_len will contain the length of the actual TCP data. This is
|
|
+ calculated by subtracing the length of the TCP header (in
|
|
+ c) and the length of the IP header (20 bytes). */
|
|
+ ustack->uip_len = ustack->uip_len - c - uip_iph_len;
|
|
+
|
|
+ /* First, check if the sequence number of the incoming packet is
|
|
+ what we're expecting next. If not, we send out an ACK with the
|
|
+ correct numbers in. */
|
|
+ if (!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) &&
|
|
+ ((tcp_hdr->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) {
|
|
+ if ((ustack->uip_len > 0
|
|
+ || ((tcp_hdr->flags & (TCP_SYN | TCP_FIN)) != 0))
|
|
+ && (tcp_hdr->seqno[0] != uip_connr->rcv_nxt[0]
|
|
+ || tcp_hdr->seqno[1] != uip_connr->rcv_nxt[1]
|
|
+ || tcp_hdr->seqno[2] != uip_connr->rcv_nxt[2]
|
|
+ || tcp_hdr->seqno[3] != uip_connr->rcv_nxt[3])) {
|
|
+ goto tcp_send_ack;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ {
|
|
+ u8_t uip_acc32[4];
|
|
+
|
|
+ /* Next, check if the incoming segment acks any outstanding
|
|
+ data. If so, we update the sequence number, reset the len of
|
|
+ the outstanding data, calc RTT estimations, and reset the
|
|
+ retransmission timer. */
|
|
+ if ((tcp_hdr->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
|
|
+ uip_add32(uip_connr->snd_nxt, uip_connr->len,
|
|
+ uip_acc32);
|
|
+
|
|
+ if (tcp_hdr->ackno[0] == uip_acc32[0] &&
|
|
+ tcp_hdr->ackno[1] == uip_acc32[1] &&
|
|
+ tcp_hdr->ackno[2] == uip_acc32[2] &&
|
|
+ tcp_hdr->ackno[3] == uip_acc32[3]) {
|
|
+ /* Update sequence number. */
|
|
+ uip_connr->snd_nxt[0] = uip_acc32[0];
|
|
+ uip_connr->snd_nxt[1] = uip_acc32[1];
|
|
+ uip_connr->snd_nxt[2] = uip_acc32[2];
|
|
+ uip_connr->snd_nxt[3] = uip_acc32[3];
|
|
+
|
|
+ /* Do RTT estimation, unless we have done
|
|
+ retransmissions. */
|
|
+ if (uip_connr->nrtx == 0) {
|
|
+ signed char m;
|
|
+ m = uip_connr->rto - uip_connr->timer;
|
|
+ /* This is taken directly from VJs
|
|
+ original code in his paper */
|
|
+ m = m - (uip_connr->sa >> 3);
|
|
+ uip_connr->sa += m;
|
|
+ if (m < 0)
|
|
+ m = -m;
|
|
+ m = m - (uip_connr->sv >> 2);
|
|
+ uip_connr->sv += m;
|
|
+ uip_connr->rto =
|
|
+ (uip_connr->sa >> 3) +
|
|
+ uip_connr->sv;
|
|
+
|
|
+ }
|
|
+ /* Set the acknowledged flag. */
|
|
+ ustack->uip_flags = UIP_ACKDATA;
|
|
+ /* Reset the retransmission timer. */
|
|
+ uip_connr->timer = uip_connr->rto;
|
|
+
|
|
+ /* Reset length of outstanding data. */
|
|
+ uip_connr->len = 0;
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ /* Do different things depending on in what state the connection is. */
|
|
+ switch (uip_connr->tcpstateflags & UIP_TS_MASK) {
|
|
+ /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
|
|
+ implemented, since we force the application to close when the
|
|
+ peer sends a FIN (hence the application goes directly from
|
|
+ ESTABLISHED to LAST_ACK). */
|
|
+ case UIP_SYN_RCVD:
|
|
+ /* In SYN_RCVD we have sent out a SYNACK in response to a SYN,
|
|
+ and we are waiting for an ACK that acknowledges the data we
|
|
+ sent out the last time. Therefore, we want to have the
|
|
+ UIP_ACKDATA flag set.
|
|
+ If so, we enter the ESTABLISHED state. */
|
|
+ if (ustack->uip_flags & UIP_ACKDATA) {
|
|
+ uip_connr->tcpstateflags = UIP_ESTABLISHED;
|
|
+ ustack->uip_flags = UIP_CONNECTED;
|
|
+ uip_connr->len = 0;
|
|
+ if (ustack->uip_len > 0) {
|
|
+ ustack->uip_flags |= UIP_NEWDATA;
|
|
+ uip_add_rcv_nxt(ustack, ustack->uip_len);
|
|
+ }
|
|
+ ustack->uip_slen = 0;
|
|
+ UIP_APPCALL(ustack);
|
|
+ goto appsend;
|
|
+ }
|
|
+ goto drop;
|
|
+#if UIP_ACTIVE_OPEN
|
|
+ case UIP_SYN_SENT:
|
|
+ /* In SYN_SENT, we wait for a SYNACK that is sent in response to
|
|
+ our SYN. The rcv_nxt is set to sequence number in the SYNACK
|
|
+ plus one, and we send an ACK. We move into the ESTABLISHED
|
|
+ state. */
|
|
+ if ((ustack->uip_flags & UIP_ACKDATA) &&
|
|
+ (tcp_hdr->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) {
|
|
+
|
|
+ /* Parse the TCP MSS option, if present. */
|
|
+ if ((tcp_hdr->tcpoffset & 0xf0) > 0x50) {
|
|
+ for (c = 0;
|
|
+ c <
|
|
+ ((tcp_hdr->tcpoffset >> 4) - 5) << 2;) {
|
|
+ ustack->opt =
|
|
+ ustack->uip_buf[uip_ip_tcph_len +
|
|
+ UIP_LLH_LEN + c];
|
|
+ if (ustack->opt == TCP_OPT_END) {
|
|
+ /* End of options. */
|
|
+ break;
|
|
+ } else if (ustack->opt ==
|
|
+ TCP_OPT_NOOP) {
|
|
+ ++c;
|
|
+ /* NOP option. */
|
|
+ } else if (ustack->opt == TCP_OPT_MSS &&
|
|
+ ustack->
|
|
+ uip_buf[uip_ip_tcph_len +
|
|
+ UIP_LLH_LEN + 1 +
|
|
+ c] ==
|
|
+ TCP_OPT_MSS_LEN) {
|
|
+ /* An MSS option with the right
|
|
+ option length. */
|
|
+ tmp16 =
|
|
+ (ustack->
|
|
+ uip_buf[uip_ip_tcph_len +
|
|
+ UIP_LLH_LEN + 2 +
|
|
+ c] << 8) | ustack->
|
|
+ uip_buf[uip_ip_tcph_len +
|
|
+ UIP_LLH_LEN + 3 +
|
|
+ c];
|
|
+ uip_connr->initialmss =
|
|
+ uip_connr->mss =
|
|
+ tmp16 >
|
|
+ UIP_TCP_MSS ? UIP_TCP_MSS :
|
|
+ tmp16;
|
|
+
|
|
+ /* And we are done processing
|
|
+ options. */
|
|
+ break;
|
|
+ } else {
|
|
+ /* All other options have a
|
|
+ length field, so that we
|
|
+ easily can skip past them */
|
|
+ if (ustack->
|
|
+ uip_buf[uip_ip_tcph_len +
|
|
+ UIP_LLH_LEN + 1 +
|
|
+ c] == 0) {
|
|
+ /* If the length field
|
|
+ is zero, the options
|
|
+ are malformed and we
|
|
+ don't process them
|
|
+ further. */
|
|
+ break;
|
|
+ }
|
|
+ c += ustack->
|
|
+ uip_buf[uip_ip_tcph_len +
|
|
+ UIP_LLH_LEN + 1 +
|
|
+ c];
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ uip_connr->tcpstateflags = UIP_ESTABLISHED;
|
|
+ uip_connr->rcv_nxt[0] = tcp_hdr->seqno[0];
|
|
+ uip_connr->rcv_nxt[1] = tcp_hdr->seqno[1];
|
|
+ uip_connr->rcv_nxt[2] = tcp_hdr->seqno[2];
|
|
+ uip_connr->rcv_nxt[3] = tcp_hdr->seqno[3];
|
|
+ uip_add_rcv_nxt(ustack, 1);
|
|
+ ustack->uip_flags = UIP_CONNECTED | UIP_NEWDATA;
|
|
+ uip_connr->len = 0;
|
|
+ ustack->uip_len = 0;
|
|
+ ustack->uip_slen = 0;
|
|
+ UIP_APPCALL(ustack);
|
|
+ goto appsend;
|
|
+ }
|
|
+ /* Inform the application that the connection failed */
|
|
+ ustack->uip_flags = UIP_ABORT;
|
|
+ UIP_APPCALL(ustack);
|
|
+ /* The connection is closed after we send the RST */
|
|
+ ustack->uip_conn->tcpstateflags = UIP_CLOSED;
|
|
+ goto reset;
|
|
+#endif /* UIP_ACTIVE_OPEN */
|
|
+
|
|
+ case UIP_ESTABLISHED:
|
|
+ /* In the ESTABLISHED state, we call upon the application to
|
|
+ feed data into the uip_buf. If the UIP_ACKDATA flag is set,
|
|
+ the application should put new data into the buffer,
|
|
+ otherwise we are retransmitting an old segment, and the
|
|
+ application should put that data into the buffer.
|
|
+
|
|
+ If the incoming packet is a FIN, we should close the
|
|
+ connection on this side as well, and we send out a FIN and
|
|
+ enter the LAST_ACK state. We require that there is no
|
|
+ outstanding data; otherwise the sequence numbers will be
|
|
+ screwed up. */
|
|
+
|
|
+ if (tcp_hdr->flags & TCP_FIN
|
|
+ && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
|
|
+ if (uip_outstanding(uip_connr))
|
|
+ goto drop;
|
|
+ uip_add_rcv_nxt(ustack, 1 + ustack->uip_len);
|
|
+ ustack->uip_flags |= UIP_CLOSE;
|
|
+ if (ustack->uip_len > 0)
|
|
+ ustack->uip_flags |= UIP_NEWDATA;
|
|
+ UIP_APPCALL(ustack);
|
|
+ uip_connr->len = 1;
|
|
+ uip_connr->tcpstateflags = UIP_LAST_ACK;
|
|
+ uip_connr->nrtx = 0;
|
|
+tcp_send_finack:
|
|
+ tcp_hdr->flags = TCP_FIN | TCP_ACK;
|
|
+ goto tcp_send_nodata;
|
|
+ }
|
|
+
|
|
+ /* Check the URG flag. If this is set, the segment carries
|
|
+ urgent data that we must pass to the application. */
|
|
+ if ((tcp_hdr->flags & TCP_URG) != 0) {
|
|
+#if UIP_URGDATA > 0
|
|
+ uip_urglen = (tcp_hdr->urgp[0] << 8) | tcp_hdr->urgp[1];
|
|
+ if (uip_urglen > uip_len) {
|
|
+ /* There is more urgent data in the next segment
|
|
+ to come. */
|
|
+ uip_urglen = uip_len;
|
|
+ }
|
|
+ uip_add_rcv_nxt(uip_urglen);
|
|
+ uip_len -= uip_urglen;
|
|
+ uip_urgdata = uip_appdata;
|
|
+ uip_appdata += uip_urglen;
|
|
+ } else {
|
|
+ uip_urglen = 0;
|
|
+#else /* UIP_URGDATA > 0 */
|
|
+ ustack->uip_appdata =
|
|
+ ((char *)ustack->uip_appdata) +
|
|
+ ((tcp_hdr->urgp[0] << 8) | tcp_hdr->urgp[1]);
|
|
+ ustack->uip_len -=
|
|
+ (tcp_hdr->urgp[0] << 8) | tcp_hdr->urgp[1];
|
|
+#endif /* UIP_URGDATA > 0 */
|
|
+ }
|
|
+
|
|
+ /* If uip_len > 0 we have TCP data in the packet, and we flag
|
|
+ this by setting the UIP_NEWDATA flag and update the sequence
|
|
+ number we acknowledge. If the application has stopped the
|
|
+ dataflow using uip_stop(), we must not accept any data
|
|
+ packets from the remote host. */
|
|
+ if (ustack->uip_len > 0
|
|
+ && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
|
|
+ ustack->uip_flags |= UIP_NEWDATA;
|
|
+ uip_add_rcv_nxt(ustack, ustack->uip_len);
|
|
+ }
|
|
+
|
|
+ /* Check if the available buffer space advertised by the other
|
|
+ end is smaller than the initial MSS for this connection.
|
|
+ If so, we set the current MSS to the window size to ensure
|
|
+ that the application does not send more data than the other
|
|
+ end can handle.
|
|
+
|
|
+ If the remote host advertises a zero window, we set the MSS
|
|
+ to the initial MSS so that the application will send an
|
|
+ entire MSS of data. This data will not be acknowledged by
|
|
+ the receiver, and the application will retransmit it.
|
|
+ This is called the "persistent timer" and uses the
|
|
+ retransmission mechanim.
|
|
+ */
|
|
+ tmp16 =
|
|
+ ((u16_t) tcp_hdr->wnd[0] << 8) + (u16_t) tcp_hdr->wnd[1];
|
|
+ if (tmp16 > uip_connr->initialmss || tmp16 == 0)
|
|
+ tmp16 = uip_connr->initialmss;
|
|
+ uip_connr->mss = tmp16;
|
|
+
|
|
+ /* If this packet constitutes an ACK for outstanding data
|
|
+ (flagged by the UIP_ACKDATA flag, we should call the
|
|
+ application since it might want to send more data.
|
|
+ If the incoming packet had data from the peer
|
|
+ (as flagged by the UIP_NEWDATA flag), the application
|
|
+ must also be notified.
|
|
+
|
|
+ When the application is called, the global variable uip_len
|
|
+ contains the length of the incoming data. The application can
|
|
+ access the incoming data through the global pointer
|
|
+ uip_appdata, which usually points uip_ip_tcph_len +
|
|
+ UIP_LLH_LEN bytes into the uip_buf array.
|
|
+
|
|
+ If the application wishes to send any data, this data should
|
|
+ be put into the uip_appdata and the length of the data should
|
|
+ be put into uip_len. If the application don't have any data
|
|
+ to send, uip_len must be set to 0. */
|
|
+ if (ustack->uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
|
|
+ ustack->uip_slen = 0;
|
|
+ UIP_APPCALL(ustack);
|
|
+
|
|
+appsend:
|
|
+
|
|
+ if (ustack->uip_flags & UIP_ABORT) {
|
|
+ ustack->uip_slen = 0;
|
|
+ uip_connr->tcpstateflags = UIP_CLOSED;
|
|
+ tcp_hdr->flags = TCP_RST | TCP_ACK;
|
|
+ goto tcp_send_nodata;
|
|
+ }
|
|
+
|
|
+ if (ustack->uip_flags & UIP_CLOSE) {
|
|
+ ustack->uip_slen = 0;
|
|
+ uip_connr->len = 1;
|
|
+ uip_connr->tcpstateflags = UIP_FIN_WAIT_1;
|
|
+ uip_connr->nrtx = 0;
|
|
+ tcp_hdr->flags = TCP_FIN | TCP_ACK;
|
|
+ goto tcp_send_nodata;
|
|
+ }
|
|
+
|
|
+ /* If uip_slen > 0, the application has data to be sent
|
|
+ */
|
|
+ if (ustack->uip_slen > 0) {
|
|
+
|
|
+ /* If the connection has acknowledged data, the
|
|
+ contents of the ->len variable should be
|
|
+ discarded. */
|
|
+ if ((ustack->uip_flags & UIP_ACKDATA) != 0)
|
|
+ uip_connr->len = 0;
|
|
+
|
|
+ /* If the ->len variable is non-zero the
|
|
+ connection has already data in transit and
|
|
+ cannot send anymore right now. */
|
|
+ if (uip_connr->len == 0) {
|
|
+
|
|
+ /* The application cannot send more than
|
|
+ what is allowed by the mss (the
|
|
+ minumum of the MSS and the available
|
|
+ window). */
|
|
+ if (ustack->uip_slen > uip_connr->mss) {
|
|
+ ustack->uip_slen =
|
|
+ uip_connr->mss;
|
|
+ }
|
|
+
|
|
+ /* Remember how much data we send out
|
|
+ now so that we know when everything
|
|
+ has been acknowledged. */
|
|
+ uip_connr->len = ustack->uip_slen;
|
|
+ } else {
|
|
+
|
|
+ /* If the application already had
|
|
+ unacknowledged data, we make sure
|
|
+ that the application does not send
|
|
+ (i.e., retransmit) out more than it
|
|
+ previously sent out. */
|
|
+ ustack->uip_slen = uip_connr->len;
|
|
+ }
|
|
+ }
|
|
+ uip_connr->nrtx = 0;
|
|
+apprexmit:
|
|
+ ustack->uip_appdata = ustack->uip_sappdata;
|
|
+
|
|
+ /* If the application has data to be sent, or if the
|
|
+ incoming packet had new data in it, we must send
|
|
+ out a packet. */
|
|
+ if (ustack->uip_slen > 0 && uip_connr->len > 0) {
|
|
+ /* Add the length of the IP and TCP headers. */
|
|
+ ustack->uip_len =
|
|
+ uip_connr->len + uip_ip_tcph_len;
|
|
+ /* We always set the ACK flag in response
|
|
+ packets. */
|
|
+ tcp_hdr->flags = TCP_ACK | TCP_PSH;
|
|
+ /* Send the packet. */
|
|
+ goto tcp_send_noopts;
|
|
+ }
|
|
+ /* If there is no data to send, just send out a pure ACK
|
|
+ if there is newdata. */
|
|
+ if (ustack->uip_flags & UIP_NEWDATA) {
|
|
+ ustack->uip_len = uip_ip_tcph_len;
|
|
+ tcp_hdr->flags = TCP_ACK;
|
|
+ goto tcp_send_noopts;
|
|
+ }
|
|
+ }
|
|
+ goto drop;
|
|
+ case UIP_LAST_ACK:
|
|
+ /* We can close this connection if the peer has acknowledged our
|
|
+ FIN. This is indicated by the UIP_ACKDATA flag. */
|
|
+ if (ustack->uip_flags & UIP_ACKDATA) {
|
|
+ uip_connr->tcpstateflags = UIP_CLOSED;
|
|
+ ustack->uip_flags = UIP_CLOSE;
|
|
+ UIP_APPCALL(ustack);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case UIP_FIN_WAIT_1:
|
|
+ /* The application has closed the connection, but the remote
|
|
+ host hasn't closed its end yet. Thus we do nothing but wait
|
|
+ for a FIN from the other side. */
|
|
+ if (ustack->uip_len > 0)
|
|
+ uip_add_rcv_nxt(ustack, ustack->uip_len);
|
|
+ if (tcp_hdr->flags & TCP_FIN) {
|
|
+ if (ustack->uip_flags & UIP_ACKDATA) {
|
|
+ uip_connr->tcpstateflags = UIP_TIME_WAIT;
|
|
+ uip_connr->timer = 0;
|
|
+ uip_connr->len = 0;
|
|
+ } else {
|
|
+ uip_connr->tcpstateflags = UIP_CLOSING;
|
|
+ }
|
|
+ uip_add_rcv_nxt(ustack, 1);
|
|
+ ustack->uip_flags = UIP_CLOSE;
|
|
+ UIP_APPCALL(ustack);
|
|
+ goto tcp_send_ack;
|
|
+ } else if (ustack->uip_flags & UIP_ACKDATA) {
|
|
+ uip_connr->tcpstateflags = UIP_FIN_WAIT_2;
|
|
+ uip_connr->len = 0;
|
|
+ goto drop;
|
|
+ }
|
|
+ if (ustack->uip_len > 0)
|
|
+ goto tcp_send_ack;
|
|
+ goto drop;
|
|
+
|
|
+ case UIP_FIN_WAIT_2:
|
|
+ if (ustack->uip_len > 0)
|
|
+ uip_add_rcv_nxt(ustack, ustack->uip_len);
|
|
+ if (tcp_hdr->flags & TCP_FIN) {
|
|
+ uip_connr->tcpstateflags = UIP_TIME_WAIT;
|
|
+ uip_connr->timer = 0;
|
|
+ uip_add_rcv_nxt(ustack, 1);
|
|
+ ustack->uip_flags = UIP_CLOSE;
|
|
+ UIP_APPCALL(ustack);
|
|
+ goto tcp_send_ack;
|
|
+ }
|
|
+ if (ustack->uip_len > 0)
|
|
+ goto tcp_send_ack;
|
|
+ goto drop;
|
|
+
|
|
+ case UIP_TIME_WAIT:
|
|
+ goto tcp_send_ack;
|
|
+
|
|
+ case UIP_CLOSING:
|
|
+ if (ustack->uip_flags & UIP_ACKDATA) {
|
|
+ uip_connr->tcpstateflags = UIP_TIME_WAIT;
|
|
+ uip_connr->timer = 0;
|
|
+ }
|
|
+ }
|
|
+ goto drop;
|
|
+
|
|
+ /* We jump here when we are ready to send the packet, and just want
|
|
+ to set the appropriate TCP sequence numbers in the TCP header. */
|
|
+tcp_send_ack:
|
|
+ tcp_hdr->flags = TCP_ACK;
|
|
+tcp_send_nodata:
|
|
+ ustack->uip_len = uip_ip_tcph_len;
|
|
+tcp_send_noopts:
|
|
+ tcp_hdr->tcpoffset = (UIP_TCPH_LEN / 4) << 4;
|
|
+tcp_send:
|
|
+ /* We're done with the input processing. We are now ready to send a
|
|
+ reply. Our job is to fill in all the fields of the TCP and IP
|
|
+ headers before calculating the checksum and finally send the
|
|
+ packet. */
|
|
+ tcp_hdr->ackno[0] = uip_connr->rcv_nxt[0];
|
|
+ tcp_hdr->ackno[1] = uip_connr->rcv_nxt[1];
|
|
+ tcp_hdr->ackno[2] = uip_connr->rcv_nxt[2];
|
|
+ tcp_hdr->ackno[3] = uip_connr->rcv_nxt[3];
|
|
+
|
|
+ tcp_hdr->seqno[0] = uip_connr->snd_nxt[0];
|
|
+ tcp_hdr->seqno[1] = uip_connr->snd_nxt[1];
|
|
+ tcp_hdr->seqno[2] = uip_connr->snd_nxt[2];
|
|
+ tcp_hdr->seqno[3] = uip_connr->snd_nxt[3];
|
|
+
|
|
+ if (is_ipv6(ustack)) {
|
|
+ IPv6_BUF(ustack)->proto = UIP_PROTO_TCP;
|
|
+ uip_ip6addr_copy(IPv6_BUF(ustack)->srcipaddr,
|
|
+ ustack->hostaddr6);
|
|
+ uip_ip6addr_copy(IPv6_BUF(ustack)->destipaddr,
|
|
+ uip_connr->ripaddr6);
|
|
+ } else {
|
|
+ tcp_ipv4_hdr->proto = UIP_PROTO_TCP;
|
|
+ uip_ip4addr_copy(tcp_ipv4_hdr->srcipaddr, ustack->hostaddr);
|
|
+ uip_ip4addr_copy(tcp_ipv4_hdr->destipaddr, uip_connr->ripaddr);
|
|
+ }
|
|
+
|
|
+ tcp_hdr->srcport = uip_connr->lport;
|
|
+ tcp_hdr->destport = uip_connr->rport;
|
|
+
|
|
+ if (uip_connr->tcpstateflags & UIP_STOPPED) {
|
|
+ /* If the connection has issued uip_stop(), we advertise a zero
|
|
+ window so that the remote host will stop sending data. */
|
|
+ tcp_hdr->wnd[0] = tcp_hdr->wnd[1] = 0;
|
|
+ } else {
|
|
+ tcp_hdr->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
|
|
+ tcp_hdr->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
|
|
+ }
|
|
+
|
|
+tcp_send_noconn:
|
|
+ if (is_ipv6(ustack)) {
|
|
+ IPv6_BUF(ustack)->ttl = UIP_TTL;
|
|
+
|
|
+ /* For IPv6, the IP length field does not include the IPv6 IP
|
|
+ header length. */
|
|
+ IPv6_BUF(ustack)->len[0] =
|
|
+ ((ustack->uip_len - uip_iph_len) >> 8);
|
|
+ IPv6_BUF(ustack)->len[1] =
|
|
+ ((ustack->uip_len - uip_iph_len) & 0xff);
|
|
+ } else {
|
|
+ tcp_ipv4_hdr->ttl = UIP_TTL;
|
|
+ tcp_ipv4_hdr->len[0] = (ustack->uip_len >> 8);
|
|
+ tcp_ipv4_hdr->len[1] = (ustack->uip_len & 0xff);
|
|
+ }
|
|
+
|
|
+ tcp_hdr->urgp[0] = tcp_hdr->urgp[1] = 0;
|
|
+
|
|
+ /* Calculate TCP checksum. */
|
|
+ tcp_hdr->tcpchksum = 0;
|
|
+ tcp_hdr->tcpchksum = ~(uip_tcpchksum(ustack));
|
|
+
|
|
+ip_send_nolen:
|
|
+
|
|
+ if (!is_ipv6(ustack)) {
|
|
+ tcp_ipv4_hdr->vhl = 0x45;
|
|
+ tcp_ipv4_hdr->tos = 0;
|
|
+ tcp_ipv4_hdr->ipoffset[0] = tcp_ipv4_hdr->ipoffset[1] = 0;
|
|
+ ++ustack->ipid;
|
|
+ tcp_ipv4_hdr->ipid[0] = ustack->ipid >> 8;
|
|
+ tcp_ipv4_hdr->ipid[1] = ustack->ipid & 0xff;
|
|
+ /* Calculate IP checksum. */
|
|
+ tcp_ipv4_hdr->ipchksum = 0;
|
|
+ tcp_ipv4_hdr->ipchksum = ~(uip_ipchksum(ustack));
|
|
+ }
|
|
+
|
|
+ ++ustack->stats.tcp.sent;
|
|
+send:
|
|
+ if (is_ipv6(ustack)) {
|
|
+ LOG_DEBUG(PFX "Sending packet with length %d (%d)",
|
|
+ ustack->uip_len, ipv6_hdr ? ipv6_hdr->ip6_plen : 0);
|
|
+ } else {
|
|
+ LOG_DEBUG(PFX "Sending packet with length %d (%d)",
|
|
+ ustack->uip_len,
|
|
+ (tcp_ipv4_hdr->len[0] << 8) | tcp_ipv4_hdr->len[1]);
|
|
+ }
|
|
+ ++ustack->stats.ip.sent;
|
|
+ /* Return and let the caller do the actual transmission. */
|
|
+ ustack->uip_flags = 0;
|
|
+ return;
|
|
+drop:
|
|
+ ustack->uip_len = 0;
|
|
+ ustack->uip_flags = 0;
|
|
+ return;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+void uip_send(struct uip_stack *ustack, const void *data, int len)
|
|
+{
|
|
+ if (len > 0) {
|
|
+ ustack->uip_slen = len;
|
|
+ if (data != ustack->uip_buf)
|
|
+ memcpy(ustack->uip_buf, (data), ustack->uip_slen);
|
|
+ }
|
|
+}
|
|
+
|
|
+void uip_appsend(struct uip_stack *ustack, const void *data, int len)
|
|
+{
|
|
+ if (len > 0) {
|
|
+ ustack->uip_slen = len;
|
|
+ if (data != ustack->uip_sappdata)
|
|
+ memcpy(ustack->uip_sappdata, (data), ustack->uip_slen);
|
|
+ }
|
|
+}
|
|
+
|
|
+u16_t uip_datalen(struct uip_stack *ustack)
|
|
+{
|
|
+ return ustack->uip_len;
|
|
+}
|
|
+
|
|
+/** @} */
|
|
diff --git a/iscsiuio/src/uip/uip.h b/iscsiuio/src/uip/uip.h
|
|
new file mode 100644
|
|
index 0000000..0225f6a
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/uip.h
|
|
@@ -0,0 +1,1569 @@
|
|
+
|
|
+/**
|
|
+ * \addtogroup uip
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Header file for the uIP TCP/IP stack.
|
|
+ * \author Adam Dunkels <adam@dunkels.com>
|
|
+ *
|
|
+ * The uIP TCP/IP stack header file contains definitions for a number
|
|
+ * of C macros that are used by uIP programs as well as internal uIP
|
|
+ * structures, TCP/IP header structures and function declarations.
|
|
+ *
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2001-2003, Adam Dunkels.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack.
|
|
+ *
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __UIP_H__
|
|
+#define __UIP_H__
|
|
+
|
|
+#include <netinet/in.h>
|
|
+#include <pthread.h>
|
|
+
|
|
+#include "uipopt.h"
|
|
+
|
|
+#include "debug.h"
|
|
+
|
|
+#include "uip_eth.h"
|
|
+
|
|
+/* Forware declaration */
|
|
+struct uip_stack;
|
|
+
|
|
+/**
|
|
+ * Repressentation of an IP address.
|
|
+ *
|
|
+ */
|
|
+typedef u16_t uip_ip4addr_t[2];
|
|
+typedef u16_t uip_ip6addr_t[8];
|
|
+
|
|
+const uip_ip6addr_t all_zeroes_addr6;
|
|
+const uip_ip4addr_t all_zeroes_addr4;
|
|
+
|
|
+#define ETH_BUF(buf) ((struct uip_eth_hdr *)buf)
|
|
+#define VLAN_ETH_BUF(buf) ((struct uip_vlan_eth_hdr *)buf)
|
|
+#define IPv4_BUF(buf) ((struct uip_tcp_ipv4_hdr *)buf)
|
|
+#define IPv6_BUF(buf) ((struct uip_tcp_ipv6_hdr *)buf)
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+/* First, the functions that should be called from the
|
|
+ * system. Initialization, the periodic timer and incoming packets are
|
|
+ * handled by the following three functions.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Set the IP address of this host.
|
|
+ *
|
|
+ * The IP address is represented as a 4-byte array where the first
|
|
+ * octet of the IP address is put in the first member of the 4-byte
|
|
+ * array.
|
|
+ *
|
|
+ * Example:
|
|
+ \code
|
|
+
|
|
+ uip_ipaddr_t addr;
|
|
+
|
|
+ uip_ipaddr(&addr, 192,168,1,2);
|
|
+ uip_sethostaddr(&addr);
|
|
+
|
|
+ \endcode
|
|
+ * \param addr A pointer to an IP address of type uip_ipaddr_t;
|
|
+ *
|
|
+ * \sa uip_ipaddr()
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+void uip_sethostaddr4(struct uip_stack *ustack, uip_ip4addr_t *addr);
|
|
+
|
|
+/**
|
|
+ * Set the default router's IP address.
|
|
+ *
|
|
+ * \param addr A pointer to a uip_ipaddr_t variable containing the IP
|
|
+ * address of the default router.
|
|
+ *
|
|
+ * \sa uip_ipaddr()
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+void uip_setdraddr4(struct uip_stack *ustack, uip_ip4addr_t *addr);
|
|
+
|
|
+/**
|
|
+ * Set the netmask.
|
|
+ *
|
|
+ * \param addr A pointer to a uip_ipaddr_t variable containing the IP
|
|
+ * address of the netmask.
|
|
+ *
|
|
+ * \sa uip_ipaddr()
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+void uip_setnetmask4(struct uip_stack *ustack, uip_ip4addr_t *addr);
|
|
+
|
|
+/**
|
|
+ * Set the ethernet MAC address.
|
|
+ *
|
|
+ * \param addr A pointer to a uip_ipaddr_t variable containing the IP
|
|
+ * address of the netmask.
|
|
+ *
|
|
+ * \sa uip_ipaddr()
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+void uip_setethernetmac(struct uip_stack *ustack, uint8_t *mac);
|
|
+
|
|
+/**
|
|
+ * Get the default router's IP address.
|
|
+ *
|
|
+ * \param addr A pointer to a uip_ipaddr_t variable that will be
|
|
+ * filled in with the IP address of the default router.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_getdraddr(addr) uip_ipaddr_copy((addr), uip_draddr)
|
|
+
|
|
+/**
|
|
+ * Get the netmask.
|
|
+ *
|
|
+ * \param addr A pointer to a uip_ipaddr_t variable that will be
|
|
+ * filled in with the value of the netmask.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_getnetmask(addr) uip_ipaddr_copy((addr), uip_netmask)
|
|
+
|
|
+void set_uip_stack(struct uip_stack *ustack,
|
|
+ uip_ip4addr_t *ip,
|
|
+ uip_ip4addr_t *netmask,
|
|
+ uip_ip4addr_t *default_route, uint8_t *mac_addr);
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/**
|
|
+ * \defgroup uipinit uIP initialization functions
|
|
+ * @{
|
|
+ *
|
|
+ * The uIP initialization functions are used for booting uIP.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * uIP initialization function.
|
|
+ *
|
|
+ * This function should be called at boot up to initilize the uIP
|
|
+ * TCP/IP stack.
|
|
+ */
|
|
+void uip_init(struct uip_stack *ustack, uint8_t enable_ipv6);
|
|
+
|
|
+/**
|
|
+ * uIP reset function.
|
|
+ *
|
|
+ * This function should be called at to reset the uIP TCP/IP stack.
|
|
+ */
|
|
+void uip_reset(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * uIP initialization function.
|
|
+ *
|
|
+ * This function may be used at boot time to set the initial ip_id.
|
|
+ */
|
|
+void uip_setipid(u16_t id);
|
|
+
|
|
+/**
|
|
+ *
|
|
+ *
|
|
+ */
|
|
+#define uip_conn_active(conn) (uip_conns[conn].tcpstateflags != UIP_CLOSED)
|
|
+
|
|
+#if UIP_UDP
|
|
+void uip_udp_periodic(struct uip_stack *ustack, int conn);
|
|
+#endif /* UIP_UDP */
|
|
+
|
|
+void uip_ndp_periodic(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * The uIP packet buffer.
|
|
+ *
|
|
+ * The uip_buf array is used to hold incoming and outgoing
|
|
+ * packets. The device driver should place incoming data into this
|
|
+ * buffer. When sending data, the device driver should read the link
|
|
+ * level headers and the TCP/IP headers from this buffer. The size of
|
|
+ * the link level headers is configured by the UIP_LLH_LEN define.
|
|
+ *
|
|
+ * \note The application data need not be placed in this buffer, so
|
|
+ * the device driver must read it from the place pointed to by the
|
|
+ * uip_appdata pointer as illustrated by the following example:
|
|
+ \code
|
|
+ void
|
|
+ devicedriver_send(void)
|
|
+ {
|
|
+ hwsend(&uip_buf[0], UIP_LLH_LEN);
|
|
+ if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
|
|
+ hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN);
|
|
+ } else {
|
|
+ hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN);
|
|
+ hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN);
|
|
+ }
|
|
+ }
|
|
+ \endcode
|
|
+ */
|
|
+/*extern u8_t uip_buf[UIP_BUFSIZE+2]; */
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+/* Functions that are used by the uIP application program. Opening and
|
|
+ * closing connections, sending and receiving data, etc. is all
|
|
+ * handled by the functions below.
|
|
+*/
|
|
+/**
|
|
+ * \defgroup uipappfunc uIP application functions
|
|
+ * @{
|
|
+ *
|
|
+ * Functions used by an application running of top of uIP.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Start listening to the specified port.
|
|
+ *
|
|
+ * \note Since this function expects the port number in network byte
|
|
+ * order, a conversion using HTONS() or htons() is necessary.
|
|
+ *
|
|
+ \code
|
|
+ uip_listen(HTONS(80));
|
|
+ \endcode
|
|
+ *
|
|
+ * \param port A 16-bit port number in network byte order.
|
|
+ */
|
|
+void uip_listen(struct uip_stack *ustack, u16_t port);
|
|
+
|
|
+/**
|
|
+ * Stop listening to the specified port.
|
|
+ *
|
|
+ * \note Since this function expects the port number in network byte
|
|
+ * order, a conversion using HTONS() or htons() is necessary.
|
|
+ *
|
|
+ \code
|
|
+ uip_unlisten(HTONS(80));
|
|
+ \endcode
|
|
+ *
|
|
+ * \param port A 16-bit port number in network byte order.
|
|
+ */
|
|
+void uip_unlisten(struct uip_stack *ustack, u16_t port);
|
|
+
|
|
+/**
|
|
+ * Connect to a remote host using TCP.
|
|
+ *
|
|
+ * This function is used to start a new connection to the specified
|
|
+ * port on the specied host. It allocates a new connection identifier,
|
|
+ * sets the connection to the SYN_SENT state and sets the
|
|
+ * retransmission timer to 0. This will cause a TCP SYN segment to be
|
|
+ * sent out the next time this connection is periodically processed,
|
|
+ * which usually is done within 0.5 seconds after the call to
|
|
+ * uip_connect().
|
|
+ *
|
|
+ * \note This function is avaliable only if support for active open
|
|
+ * has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h.
|
|
+ *
|
|
+ * \note Since this function requires the port number to be in network
|
|
+ * byte order, a conversion using HTONS() or htons() is necessary.
|
|
+ *
|
|
+ \code
|
|
+ uip_ipaddr_t ipaddr;
|
|
+
|
|
+ uip_ipaddr(&ipaddr, 192,168,1,2);
|
|
+ uip_connect(&ipaddr, HTONS(80));
|
|
+ \endcode
|
|
+ *
|
|
+ * \param ripaddr The IP address of the remote hot.
|
|
+ *
|
|
+ * \param port A 16-bit port number in network byte order.
|
|
+ *
|
|
+ * \return A pointer to the uIP connection identifier for the new connection,
|
|
+ * or NULL if no connection could be allocated.
|
|
+ *
|
|
+ */
|
|
+struct uip_conn *uip_connect(struct uip_stack *ustack,
|
|
+ uip_ip4addr_t *ripaddr, u16_t port);
|
|
+
|
|
+/**
|
|
+ * \internal
|
|
+ *
|
|
+ * Check if a connection has outstanding (i.e., unacknowledged) data.
|
|
+ *
|
|
+ * \param conn A pointer to the uip_conn structure for the connection.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_outstanding(conn) ((conn)->len)
|
|
+
|
|
+/**
|
|
+ * Send data on the current connection.
|
|
+ *
|
|
+ * This function is used to send out a single segment of TCP
|
|
+ * data. Only applications that have been invoked by uIP for event
|
|
+ * processing can send data.
|
|
+ *
|
|
+ * The amount of data that actually is sent out after a call to this
|
|
+ * funcion is determined by the maximum amount of data TCP allows. uIP
|
|
+ * will automatically crop the data so that only the appropriate
|
|
+ * amount of data is sent. The function uip_mss() can be used to query
|
|
+ * uIP for the amount of data that actually will be sent.
|
|
+ *
|
|
+ * \note This function does not guarantee that the sent data will
|
|
+ * arrive at the destination. If the data is lost in the network, the
|
|
+ * application will be invoked with the uip_rexmit() event being
|
|
+ * set. The application will then have to resend the data using this
|
|
+ * function.
|
|
+ *
|
|
+ * \param data A pointer to the data which is to be sent.
|
|
+ *
|
|
+ * \param len The maximum amount of data bytes to be sent.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+void uip_send(struct uip_stack *ustack, const void *data, int len);
|
|
+void uip_appsend(struct uip_stack *ustack, const void *data, int len);
|
|
+
|
|
+/**
|
|
+ * The length of any incoming data that is currently avaliable (if avaliable)
|
|
+ * in the uip_appdata buffer.
|
|
+ *
|
|
+ * The test function uip_data() must first be used to check if there
|
|
+ * is any data available at all.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+/*void uip_datalen(void);*/
|
|
+u16_t uip_datalen(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * The length of any out-of-band data (urgent data) that has arrived
|
|
+ * on the connection.
|
|
+ *
|
|
+ * \note The configuration parameter UIP_URGDATA must be set for this
|
|
+ * function to be enabled.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_urgdatalen() uip_urglen
|
|
+
|
|
+/**
|
|
+ * Close the current connection.
|
|
+ *
|
|
+ * This function will close the current connection in a nice way.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_close() (uip_flags = UIP_CLOSE)
|
|
+
|
|
+/**
|
|
+ * Abort the current connection.
|
|
+ *
|
|
+ * This function will abort (reset) the current connection, and is
|
|
+ * usually used when an error has occured that prevents using the
|
|
+ * uip_close() function.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_abort() (uip_flags = UIP_ABORT)
|
|
+
|
|
+/**
|
|
+ * Tell the sending host to stop sending data.
|
|
+ *
|
|
+ * This function will close our receiver's window so that we stop
|
|
+ * receiving data for the current connection.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_stop() (uip_conn->tcpstateflags |= UIP_STOPPED)
|
|
+
|
|
+/**
|
|
+ * Find out if the current connection has been previously stopped with
|
|
+ * uip_stop().
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_stopped(conn) ((conn)->tcpstateflags & UIP_STOPPED)
|
|
+
|
|
+/**
|
|
+ * Restart the current connection, if is has previously been stopped
|
|
+ * with uip_stop().
|
|
+ *
|
|
+ * This function will open the receiver's window again so that we
|
|
+ * start receiving data for the current connection.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_restart() do { uip_flags |= UIP_NEWDATA; \
|
|
+ uip_conn->tcpstateflags &= ~UIP_STOPPED; \
|
|
+ } while (0)
|
|
+
|
|
+/* uIP tests that can be made to determine in what state the current
|
|
+ connection is, and what the application function should do. */
|
|
+
|
|
+/**
|
|
+ * Is the current connection a UDP connection?
|
|
+ *
|
|
+ * This function checks whether the current connection is a UDP connection.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ *
|
|
+ */
|
|
+#define uip_udpconnection() (uip_conn == NULL)
|
|
+
|
|
+/**
|
|
+ * Function declarations for hte uip_flags
|
|
+ */
|
|
+/**
|
|
+ * Is new incoming data available?
|
|
+ *
|
|
+ * Will reduce to non-zero if there is new data for the application
|
|
+ * present at the uip_appdata pointer. The size of the data is
|
|
+ * avaliable through the uip_len variable.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_newdata(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Has previously sent data been acknowledged?
|
|
+ *
|
|
+ * Will reduce to non-zero if the previously sent data has been
|
|
+ * acknowledged by the remote host. This means that the application
|
|
+ * can send new data.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_acked(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Has the connection just been connected?
|
|
+ *
|
|
+ * Reduces to non-zero if the current connection has been connected to
|
|
+ * a remote host. This will happen both if the connection has been
|
|
+ * actively opened (with uip_connect()) or passively opened (with
|
|
+ * uip_listen()).
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_connected(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Has the connection been closed by the other end?
|
|
+ *
|
|
+ * Is non-zero if the connection has been closed by the remote
|
|
+ * host. The application may then do the necessary clean-ups.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_closed(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Has the connection been aborted by the other end?
|
|
+ *
|
|
+ * Non-zero if the current connection has been aborted (reset) by the
|
|
+ * remote host.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_aborted(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Has the connection timed out?
|
|
+ *
|
|
+ * Non-zero if the current connection has been aborted due to too many
|
|
+ * retransmissions.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_timedout(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Do we need to retransmit previously data?
|
|
+ *
|
|
+ * Reduces to non-zero if the previously sent data has been lost in
|
|
+ * the network, and the application should retransmit it. The
|
|
+ * application should send the exact same data as it did the last
|
|
+ * time, using the uip_send() function.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_rexmit(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Is the connection being polled by uIP?
|
|
+ *
|
|
+ * Is non-zero if the reason the application is invoked is that the
|
|
+ * current connection has been idle for a while and should be
|
|
+ * polled.
|
|
+ *
|
|
+ * The polling event can be used for sending data without having to
|
|
+ * wait for the remote host to send data.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_poll(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Get the initial maxium segment size (MSS) of the current
|
|
+ * connection.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_initialmss(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Get the current maxium segment size that can be sent on the current
|
|
+ * connection.
|
|
+ *
|
|
+ * The current maxiumum segment size that can be sent on the
|
|
+ * connection is computed from the receiver's window and the MSS of
|
|
+ * the connection (which also is available by calling
|
|
+ * uip_initialmss()).
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+int uip_mss(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Set up a new UDP connection.
|
|
+ *
|
|
+ * This function sets up a new UDP connection. The function will
|
|
+ * automatically allocate an unused local port for the new
|
|
+ * connection. However, another port can be chosen by using the
|
|
+ * uip_udp_bind() call, after the uip_udp_new() function has been
|
|
+ * called.
|
|
+ *
|
|
+ * Example:
|
|
+ \code
|
|
+ uip_ipaddr_t addr;
|
|
+ struct uip_udp_conn *c;
|
|
+
|
|
+ uip_ipaddr(&addr, 192,168,2,1);
|
|
+ c = uip_udp_new(&addr, HTONS(12345));
|
|
+ if(c != NULL) {
|
|
+ uip_udp_bind(c, HTONS(12344));
|
|
+ }
|
|
+ \endcode
|
|
+ * \param ripaddr The IP address of the remote host.
|
|
+ *
|
|
+ * \param rport The remote port number in network byte order.
|
|
+ *
|
|
+ * \return The uip_udp_conn structure for the new connection or NULL
|
|
+ * if no connection could be allocated.
|
|
+ */
|
|
+struct uip_udp_conn *uip_udp_new(struct uip_stack *ustack,
|
|
+ uip_ip4addr_t *ripaddr, u16_t rport);
|
|
+
|
|
+/**
|
|
+ * Removed a UDP connection.
|
|
+ *
|
|
+ * \param conn A pointer to the uip_udp_conn structure for the connection.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_udp_remove(conn) ((conn)->lport = 0)
|
|
+
|
|
+/**
|
|
+ * Bind a UDP connection to a local port.
|
|
+ *
|
|
+ * \param conn A pointer to the uip_udp_conn structure for the
|
|
+ * connection.
|
|
+ *
|
|
+ * \param port The local port number, in network byte order.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_udp_bind(conn, port) ((conn)->lport = port)
|
|
+
|
|
+/**
|
|
+ * Send a UDP datagram of length len on the current connection.
|
|
+ *
|
|
+ * This function can only be called in response to a UDP event (poll
|
|
+ * or newdata). The data must be present in the uip_buf buffer, at the
|
|
+ * place pointed to by the uip_appdata pointer.
|
|
+ *
|
|
+ * \param len The length of the data in the uip_buf buffer.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_udp_send(len) uip_appsend((char *)uip_appdata, len)
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/* uIP convenience and converting functions. */
|
|
+
|
|
+/**
|
|
+ * \defgroup uipconvfunc uIP conversion functions
|
|
+ * @{
|
|
+ *
|
|
+ * These functions can be used for converting between different data
|
|
+ * formats used by uIP.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Construct an IP address from four bytes.
|
|
+ *
|
|
+ * This function constructs an IP address of the type that uIP handles
|
|
+ * internally from four bytes. The function is handy for specifying IP
|
|
+ * addresses to use with e.g. the uip_connect() function.
|
|
+ *
|
|
+ * Example:
|
|
+ \code
|
|
+ uip_ipaddr_t ipaddr;
|
|
+ struct uip_conn *c;
|
|
+
|
|
+ uip_ipaddr(&ipaddr, 192,168,1,2);
|
|
+ c = uip_connect(&ipaddr, HTONS(80));
|
|
+ \endcode
|
|
+ *
|
|
+ * \param addr A pointer to a uip_ipaddr_t variable that will be
|
|
+ * filled in with the IP address.
|
|
+ *
|
|
+ * \param addr0 The first octet of the IP address.
|
|
+ * \param addr1 The second octet of the IP address.
|
|
+ * \param addr2 The third octet of the IP address.
|
|
+ * \param addr3 The forth octet of the IP address.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_ipaddr(addr, addr0, addr1, addr2, addr3) do { \
|
|
+ ((u16_t *)(addr))[0] = const_htons(((addr0) << 8) | (addr1)); \
|
|
+ ((u16_t *)(addr))[1] = const_htons(((addr2) << 8) | (addr3)); \
|
|
+ } while (0)
|
|
+
|
|
+/**
|
|
+ * Construct an IPv6 address from eight 16-bit words.
|
|
+ *
|
|
+ * This function constructs an IPv6 address.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_ip6addr(addr, addr0, addr1, addr2, addr3, addr4, addr5, addr6, \
|
|
+ addr7) \
|
|
+ do { \
|
|
+ ((u16_t *)(addr))[0] = HTONS((addr0)); \
|
|
+ ((u16_t *)(addr))[1] = HTONS((addr1)); \
|
|
+ ((u16_t *)(addr))[2] = HTONS((addr2)); \
|
|
+ ((u16_t *)(addr))[3] = HTONS((addr3)); \
|
|
+ ((u16_t *)(addr))[4] = HTONS((addr4)); \
|
|
+ ((u16_t *)(addr))[5] = HTONS((addr5)); \
|
|
+ ((u16_t *)(addr))[6] = HTONS((addr6)); \
|
|
+ ((u16_t *)(addr))[7] = HTONS((addr7)); \
|
|
+ } while (0)
|
|
+
|
|
+/**
|
|
+ * Copy an IP address to another IP address.
|
|
+ *
|
|
+ * Copies an IP address from one place to another.
|
|
+ *
|
|
+ * Example:
|
|
+ \code
|
|
+ uip_ipaddr_t ipaddr1, ipaddr2;
|
|
+
|
|
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
|
|
+ uip_ipaddr_copy(&ipaddr2, &ipaddr1);
|
|
+ \endcode
|
|
+ *
|
|
+ * \param dest The destination for the copy.
|
|
+ * \param src The source from where to copy.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_ip4addr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip4addr_t))
|
|
+#define uip_ip6addr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip6addr_t))
|
|
+
|
|
+/**
|
|
+ * Compare two IP addresses
|
|
+ *
|
|
+ * Compares two IP addresses.
|
|
+ *
|
|
+ * Example:
|
|
+ \code
|
|
+ uip_ipaddr_t ipaddr1, ipaddr2;
|
|
+
|
|
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
|
|
+ if(uip_ipaddr_cmp(&ipaddr2, &ipaddr1)) {
|
|
+ printf("They are the same");
|
|
+ }
|
|
+ \endcode
|
|
+ *
|
|
+ * \param addr1 The first IP address.
|
|
+ * \param addr2 The second IP address.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_ip4addr_cmp(addr1, addr2) (memcmp(addr1, addr2, \
|
|
+ sizeof(uip_ip4addr_t)) == 0)
|
|
+#define uip_ip6addr_cmp(addr1, addr2) (memcmp(addr1, addr2, \
|
|
+ sizeof(uip_ip6addr_t)) == 0)
|
|
+
|
|
+/**
|
|
+ * Compare two IP addresses with netmasks
|
|
+ *
|
|
+ * Compares two IP addresses with netmasks. The masks are used to mask
|
|
+ * out the bits that are to be compared.
|
|
+ *
|
|
+ * Example:
|
|
+ \code
|
|
+ uip_ipaddr_t ipaddr1, ipaddr2, mask;
|
|
+
|
|
+ uip_ipaddr(&mask, 255,255,255,0);
|
|
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
|
|
+ uip_ipaddr(&ipaddr2, 192,16,1,3);
|
|
+ if(uip_ipaddr_maskcmp(&ipaddr1, &ipaddr2, &mask)) {
|
|
+ printf("They are the same");
|
|
+ }
|
|
+ \endcode
|
|
+ *
|
|
+ * \param addr1 The first IP address.
|
|
+ * \param addr2 The second IP address.
|
|
+ * \param mask The netmask.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_ip4addr_maskcmp(addr1, addr2, mask) \
|
|
+ (((((u16_t *)addr1)[0] & ((u16_t *)mask)[0]) == \
|
|
+ (((u16_t *)addr2)[0] & ((u16_t *)mask)[0])) && \
|
|
+ ((((u16_t *)addr1)[1] & ((u16_t *)mask)[1]) == \
|
|
+ (((u16_t *)addr2)[1] & ((u16_t *)mask)[1])))
|
|
+
|
|
+/**
|
|
+ * Mask out the network part of an IP address.
|
|
+ *
|
|
+ * Masks out the network part of an IP address, given the address and
|
|
+ * the netmask.
|
|
+ *
|
|
+ * Example:
|
|
+ \code
|
|
+ uip_ipaddr_t ipaddr1, ipaddr2, netmask;
|
|
+
|
|
+ uip_ipaddr(&ipaddr1, 192,16,1,2);
|
|
+ uip_ipaddr(&netmask, 255,255,255,0);
|
|
+ uip_ipaddr_mask(&ipaddr2, &ipaddr1, &netmask);
|
|
+ \endcode
|
|
+ *
|
|
+ * In the example above, the variable "ipaddr2" will contain the IP
|
|
+ * address 192.168.1.0.
|
|
+ *
|
|
+ * \param dest Where the result is to be placed.
|
|
+ * \param src The IP address.
|
|
+ * \param mask The netmask.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_ip4addr_mask(dest, src, mask) do { \
|
|
+ ((u16_t *)dest)[0] = ((u16_t *)src)[0] & ((u16_t *)mask)[0]; \
|
|
+ ((u16_t *)dest)[1] = ((u16_t *)src)[1] & ((u16_t *)mask)[1]; \
|
|
+ } while (0)
|
|
+
|
|
+/**
|
|
+ * Pick the first octet of an IP address.
|
|
+ *
|
|
+ * Picks out the first octet of an IP address.
|
|
+ *
|
|
+ * Example:
|
|
+ \code
|
|
+ uip_ipaddr_t ipaddr;
|
|
+ u8_t octet;
|
|
+
|
|
+ uip_ipaddr(&ipaddr, 1,2,3,4);
|
|
+ octet = uip_ipaddr1(&ipaddr);
|
|
+ \endcode
|
|
+ *
|
|
+ * In the example above, the variable "octet" will contain the value 1.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_ipaddr1(addr) (htons(((u16_t *)(addr))[0]) >> 8)
|
|
+
|
|
+/**
|
|
+ * Pick the second octet of an IP address.
|
|
+ *
|
|
+ * Picks out the second octet of an IP address.
|
|
+ *
|
|
+ * Example:
|
|
+ \code
|
|
+ uip_ipaddr_t ipaddr;
|
|
+ u8_t octet;
|
|
+
|
|
+ uip_ipaddr(&ipaddr, 1,2,3,4);
|
|
+ octet = uip_ipaddr2(&ipaddr);
|
|
+ \endcode
|
|
+ *
|
|
+ * In the example above, the variable "octet" will contain the value 2.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_ipaddr2(addr) (htons(((u16_t *)(addr))[0]) & 0xff)
|
|
+
|
|
+/**
|
|
+ * Pick the third octet of an IP address.
|
|
+ *
|
|
+ * Picks out the third octet of an IP address.
|
|
+ *
|
|
+ * Example:
|
|
+ \code
|
|
+ uip_ipaddr_t ipaddr;
|
|
+ u8_t octet;
|
|
+
|
|
+ uip_ipaddr(&ipaddr, 1,2,3,4);
|
|
+ octet = uip_ipaddr3(&ipaddr);
|
|
+ \endcode
|
|
+ *
|
|
+ * In the example above, the variable "octet" will contain the value 3.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_ipaddr3(addr) (htons(((u16_t *)(addr))[1]) >> 8)
|
|
+
|
|
+/**
|
|
+ * Pick the fourth octet of an IP address.
|
|
+ *
|
|
+ * Picks out the fourth octet of an IP address.
|
|
+ *
|
|
+ * Example:
|
|
+ \code
|
|
+ uip_ipaddr_t ipaddr;
|
|
+ u8_t octet;
|
|
+
|
|
+ uip_ipaddr(&ipaddr, 1,2,3,4);
|
|
+ octet = uip_ipaddr4(&ipaddr);
|
|
+ \endcode
|
|
+ *
|
|
+ * In the example above, the variable "octet" will contain the value 4.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_ipaddr4(addr) (htons(((u16_t *)(addr))[1]) & 0xff)
|
|
+
|
|
+/**
|
|
+ * Convert 16-bit quantity from host byte order to network byte order.
|
|
+ *
|
|
+ * This macro is primarily used for converting constants from host
|
|
+ * byte order to network byte order. For converting variables to
|
|
+ * network byte order, use the htons() function instead.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#if 0
|
|
+#ifndef HTONS
|
|
+# if UIP_BYTE_ORDER == UIP_BIG_ENDIAN
|
|
+# define HTONS(n) (n)
|
|
+# else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
|
|
+# define HTONS(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8))
|
|
+# endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
|
|
+#else
|
|
+#error "HTONS already defined!"
|
|
+#endif /* HTONS */
|
|
+#endif
|
|
+
|
|
+#if UIP_BYTE_ORDER == UIP_BIG_ENDIAN
|
|
+# error "Should not be here"
|
|
+# define const_htons(n) (n)
|
|
+# else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
|
|
+# define const_htons(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8))
|
|
+# endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
|
|
+
|
|
+/* BWL */
|
|
+#if 0
|
|
+/**
|
|
+ * Convert 16-bit quantity from host byte order to network byte order.
|
|
+ *
|
|
+ * This function is primarily used for converting variables from host
|
|
+ * byte order to network byte order. For converting constants to
|
|
+ * network byte order, use the HTONS() macro instead.
|
|
+ */
|
|
+#ifndef htons
|
|
+u16_t htons(u16_t val);
|
|
+#endif /* htons */
|
|
+#ifndef ntohs
|
|
+#define ntohs htons
|
|
+#endif
|
|
+#endif
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/**
|
|
+ * Pointer to the application data in the packet buffer.
|
|
+ *
|
|
+ * This pointer points to the application data when the application is
|
|
+ * called. If the application wishes to send data, the application may
|
|
+ * use this space to write the data into before calling uip_send().
|
|
+ */
|
|
+/* extern void *uip_appdata; */
|
|
+
|
|
+#if UIP_URGDATA > 0
|
|
+/* u8_t *uip_urgdata:
|
|
+ *
|
|
+ * This pointer points to any urgent data that has been received. Only
|
|
+ * present if compiled with support for urgent data (UIP_URGDATA).
|
|
+ */
|
|
+extern void *uip_urgdata;
|
|
+#endif /* UIP_URGDATA > 0 */
|
|
+
|
|
+/**
|
|
+ * \defgroup uipdrivervars Variables used in uIP device drivers
|
|
+ * @{
|
|
+ *
|
|
+ * uIP has a few global variables that are used in device drivers for
|
|
+ * uIP.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * The length of the packet in the uip_buf buffer.
|
|
+ *
|
|
+ * The global variable uip_len holds the length of the packet in the
|
|
+ * uip_buf buffer.
|
|
+ *
|
|
+ * When the network device driver calls the uIP input function,
|
|
+ * uip_len should be set to the length of the packet in the uip_buf
|
|
+ * buffer.
|
|
+ *
|
|
+ * When sending packets, the device driver should use the contents of
|
|
+ * the uip_len variable to determine the length of the outgoing
|
|
+ * packet.
|
|
+ *
|
|
+ */
|
|
+/* extern u16_t uip_len; */
|
|
+
|
|
+/** @} */
|
|
+
|
|
+#if UIP_URGDATA > 0
|
|
+extern u16_t uip_urglen, uip_surglen;
|
|
+#endif /* UIP_URGDATA > 0 */
|
|
+
|
|
+/**
|
|
+ * Representation of a uIP TCP connection.
|
|
+ *
|
|
+ * The uip_conn structure is used for identifying a connection. All
|
|
+ * but one field in the structure are to be considered read-only by an
|
|
+ * application. The only exception is the appstate field whos purpose
|
|
+ * is to let the application store application-specific state (e.g.,
|
|
+ * file pointers) for the connection. The type of this field is
|
|
+ * configured in the "uipopt.h" header file.
|
|
+ */
|
|
+struct __attribute__ ((__packed__)) uip_conn {
|
|
+ uip_ip4addr_t ripaddr;
|
|
+ uip_ip6addr_t ripaddr6;
|
|
+ /**< The IP address of the remote host. */
|
|
+
|
|
+ u16_t lport; /**< The local TCP port, in network byte order. */
|
|
+ u16_t rport; /**< The local remote TCP port, in network byte
|
|
+ order. */
|
|
+
|
|
+ u8_t rcv_nxt[4];
|
|
+ /**< The sequence number that we expect to
|
|
+ receive next. */
|
|
+ u8_t snd_nxt[4];
|
|
+ /**< The sequence number that was last sent by
|
|
+ us. */
|
|
+ u16_t len; /**< Length of the data that was previously sent. */
|
|
+ u16_t mss; /**< Current maximum segment size for the
|
|
+ connection. */
|
|
+ u16_t initialmss;
|
|
+ /**< Initial maximum segment size for the
|
|
+ connection. */
|
|
+ u8_t sa; /**< Retransmission time-out calculation state
|
|
+ variable. */
|
|
+ u8_t sv; /**< Retransmission time-out calculation state
|
|
+ variable. */
|
|
+ u8_t rto; /**< Retransmission time-out. */
|
|
+ u8_t tcpstateflags;
|
|
+ /**< TCP state and flags. */
|
|
+ u8_t timer; /**< The retransmission timer. */
|
|
+ u8_t nrtx; /**< The number of retransmissions for the last
|
|
+ segment sent. */
|
|
+};
|
|
+
|
|
+/**
|
|
+ * \addtogroup uiparch
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * 4-byte array used for the 32-bit sequence number calculations.
|
|
+ */
|
|
+extern u8_t uip_acc32[4];
|
|
+
|
|
+/** @} */
|
|
+
|
|
+#if UIP_UDP
|
|
+/**
|
|
+ * Representation of a uIP UDP connection.
|
|
+ */
|
|
+struct uip_udp_conn {
|
|
+ uip_ip4addr_t ripaddr;
|
|
+ /**< The IP address of the remote peer. */
|
|
+ u16_t lport; /**< The local port number in network byte order. */
|
|
+ u16_t rport; /**< The remote port number in network byte order. */
|
|
+ u8_t ttl; /**< Default time-to-live. */
|
|
+
|
|
+ /** The application state. */
|
|
+/* uip_udp_appstate_t appstate; */
|
|
+};
|
|
+
|
|
+#endif /* UIP_UDP */
|
|
+
|
|
+/**
|
|
+ * The structure holding the TCP/IP statistics that are gathered if
|
|
+ * UIP_STATISTICS is set to 1.
|
|
+ *
|
|
+ */
|
|
+struct uip_stats {
|
|
+ struct {
|
|
+ uip_stats_t drop;
|
|
+ /**< Number of dropped packets at the IP
|
|
+ layer. */
|
|
+ uip_stats_t recv;
|
|
+ /**< Number of received packets at the IP
|
|
+ layer. */
|
|
+ uip_stats_t sent;
|
|
+ /**< Number of sent packets at the IP
|
|
+ layer. */
|
|
+ uip_stats_t vhlerr;
|
|
+ /**< Number of packets dropped due to wrong
|
|
+ IP version or header length. */
|
|
+ uip_stats_t hblenerr;
|
|
+ /**< Number of packets dropped due to wrong
|
|
+ IP length, high byte. */
|
|
+ uip_stats_t lblenerr;
|
|
+ /**< Number of packets dropped due to wrong
|
|
+ IP length, low byte. */
|
|
+ uip_stats_t fragerr;
|
|
+ /**< Number of packets dropped since they
|
|
+ were IP fragments. */
|
|
+ uip_stats_t chkerr;
|
|
+ /**< Number of packets dropped due to IP
|
|
+ checksum errors. */
|
|
+ uip_stats_t protoerr;
|
|
+ /**< Number of packets dropped since they
|
|
+ were neither ICMP, UDP nor TCP. */
|
|
+ } ip; /**< IP statistics. */
|
|
+ struct {
|
|
+ uip_stats_t drop;
|
|
+ /**< Number of dropped ICMP packets. */
|
|
+ uip_stats_t recv;
|
|
+ /**< Number of received ICMP packets. */
|
|
+ uip_stats_t sent;
|
|
+ /**< Number of sent ICMP packets. */
|
|
+ uip_stats_t typeerr;
|
|
+ /**< Number of ICMP packets with a wrong
|
|
+ type. */
|
|
+ } icmp; /**< ICMP statistics. */
|
|
+ struct {
|
|
+ uip_stats_t drop;
|
|
+ /**< Number of dropped TCP segments. */
|
|
+ uip_stats_t recv;
|
|
+ /**< Number of recived TCP segments. */
|
|
+ uip_stats_t sent;
|
|
+ /**< Number of sent TCP segments. */
|
|
+ uip_stats_t chkerr;
|
|
+ /**< Number of TCP segments with a bad
|
|
+ checksum. */
|
|
+ uip_stats_t ackerr;
|
|
+ /**< Number of TCP segments with a bad ACK
|
|
+ number. */
|
|
+ uip_stats_t rst;
|
|
+ /**< Number of recevied TCP RST (reset) segments. */
|
|
+ uip_stats_t rexmit;
|
|
+ /**< Number of retransmitted TCP segments. */
|
|
+ uip_stats_t syndrop;
|
|
+ /**< Number of dropped SYNs due to too few
|
|
+ connections was avaliable. */
|
|
+ uip_stats_t synrst;
|
|
+ /**< Number of SYNs for closed ports,
|
|
+ triggering a RST. */
|
|
+ } tcp; /**< TCP statistics. */
|
|
+#if UIP_UDP
|
|
+ struct {
|
|
+ uip_stats_t drop;
|
|
+ /**< Number of dropped UDP segments. */
|
|
+ uip_stats_t recv;
|
|
+ /**< Number of recived UDP segments. */
|
|
+ uip_stats_t sent;
|
|
+ /**< Number of sent UDP segments. */
|
|
+ uip_stats_t chkerr;
|
|
+ /**< Number of UDP segments with a bad
|
|
+ checksum. */
|
|
+ } udp; /**< UDP statistics. */
|
|
+#endif /* UIP_UDP */
|
|
+};
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+/* All the stuff below this point is internal to uIP and should not be
|
|
+ * used directly by an application or by a device driver.
|
|
+ */
|
|
+/*---------------------------------------------------------------------------*/
|
|
+/* u8_t uip_flags:
|
|
+ *
|
|
+ * When the application is called, uip_flags will contain the flags
|
|
+ * that are defined in this file. Please read below for more
|
|
+ * infomation.
|
|
+ */
|
|
+/* extern u8_t uip_flags; */
|
|
+
|
|
+/* The following flags may be set in the global variable uip_flags
|
|
+ before calling the application callback. The UIP_ACKDATA,
|
|
+ UIP_NEWDATA, and UIP_CLOSE flags may both be set at the same time,
|
|
+ whereas the others are mutualy exclusive. Note that these flags
|
|
+ should *NOT* be accessed directly, but only through the uIP
|
|
+ functions/macros. */
|
|
+
|
|
+#define UIP_ACKDATA 1 /* Signifies that the outstanding data was
|
|
+ acked and the application should send
|
|
+ out new data instead of retransmitting
|
|
+ the last data. */
|
|
+#define UIP_NEWDATA 2 /* Flags the fact that the peer has sent
|
|
+ us new data. */
|
|
+#define UIP_REXMIT 4 /* Tells the application to retransmit the
|
|
+ data that was last sent. */
|
|
+#define UIP_POLL 8 /* Used for polling the application, to
|
|
+ check if the application has data that
|
|
+ it wants to send. */
|
|
+#define UIP_CLOSE 16 /* The remote host has closed the
|
|
+ connection, thus the connection has
|
|
+ gone away. Or the application signals
|
|
+ that it wants to close the
|
|
+ connection. */
|
|
+#define UIP_ABORT 32 /* The remote host has aborted the
|
|
+ connection, thus the connection has
|
|
+ gone away. Or the application signals
|
|
+ that it wants to abort the
|
|
+ connection. */
|
|
+#define UIP_CONNECTED 64 /* We have got a connection from a remote
|
|
+ host and have set up a new connection
|
|
+ for it, or an active connection has
|
|
+ been successfully established. */
|
|
+
|
|
+#define UIP_TIMEDOUT 128 /* The connection has been aborted due to
|
|
+ too many retransmissions. */
|
|
+
|
|
+void uip_input(struct uip_stack *ustack);
|
|
+void uip_periodic(struct uip_stack *ustack, int conn);
|
|
+
|
|
+/* uip_process(flag):
|
|
+ *
|
|
+ * The actual uIP function which does all the work.
|
|
+ */
|
|
+void uip_process(struct uip_stack *ustack, u8_t flag);
|
|
+
|
|
+/* The following flags are passed as an argument to the uip_process()
|
|
+ function. They are used to distinguish between the two cases where
|
|
+ uip_process() is called. It can be called either because we have
|
|
+ incoming data that should be processed, or because the periodic
|
|
+ timer has fired. These values are never used directly, but only in
|
|
+ the macrose defined in this file. */
|
|
+
|
|
+#define UIP_DATA 1 /* Tells uIP that there is incoming
|
|
+ data in the uip_buf buffer. The
|
|
+ length of the data is stored in the
|
|
+ global variable uip_len. */
|
|
+#define UIP_TIMER 2 /* Tells uIP that the periodic timer
|
|
+ has fired. */
|
|
+#define UIP_POLL_REQUEST 3 /* Tells uIP that a connection should
|
|
+ be polled. */
|
|
+#define UIP_UDP_SEND_CONN 4 /* Tells uIP that a UDP datagram
|
|
+ should be constructed in the
|
|
+ uip_buf buffer. */
|
|
+#if UIP_UDP
|
|
+#define UIP_UDP_TIMER 5
|
|
+#endif /* UIP_UDP */
|
|
+
|
|
+#define UIP_NDP_TIMER 6
|
|
+
|
|
+/* The TCP states used in the uip_conn->tcpstateflags. */
|
|
+#define UIP_CLOSED 0
|
|
+#define UIP_SYN_RCVD 1
|
|
+#define UIP_SYN_SENT 2
|
|
+#define UIP_ESTABLISHED 3
|
|
+#define UIP_FIN_WAIT_1 4
|
|
+#define UIP_FIN_WAIT_2 5
|
|
+#define UIP_CLOSING 6
|
|
+#define UIP_TIME_WAIT 7
|
|
+#define UIP_LAST_ACK 8
|
|
+#define UIP_TS_MASK 15
|
|
+
|
|
+#define UIP_STOPPED 16
|
|
+
|
|
+struct __attribute__ ((__packed__)) uip_tcp_hdr {
|
|
+ /* TCP header. */
|
|
+ u16_t srcport, destport;
|
|
+ u8_t seqno[4], ackno[4], tcpoffset, flags, wnd[2];
|
|
+ u16_t tcpchksum;
|
|
+ u8_t urgp[2];
|
|
+ u8_t optdata[4];
|
|
+};
|
|
+
|
|
+struct __attribute__ ((__packed__)) uip_ipv4_hdr {
|
|
+ /* IPv4 header. */
|
|
+ u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto;
|
|
+ u16_t ipchksum;
|
|
+ u16_t srcipaddr[2], destipaddr[2];
|
|
+};
|
|
+
|
|
+struct __attribute__ ((__packed__)) uip_ipv6_hdr {
|
|
+ /* IPv6 header. */
|
|
+ u8_t vtc, tcflow;
|
|
+ u16_t flow;
|
|
+ u16_t len;
|
|
+ u8_t proto, ttl;
|
|
+ uip_ip6addr_t srcipaddr, destipaddr;
|
|
+};
|
|
+
|
|
+/* The TCP and IPv4 headers. */
|
|
+struct __attribute__ ((__packed__)) uip_tcp_ipv4_hdr {
|
|
+ /* IPv4 header. */
|
|
+ u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto;
|
|
+ u16_t ipchksum;
|
|
+ u16_t srcipaddr[2], destipaddr[2];
|
|
+
|
|
+ /* TCP header. */
|
|
+ u16_t srcport, destport;
|
|
+ u8_t seqno[4], ackno[4], tcpoffset, flags, wnd[2];
|
|
+ u16_t tcpchksum;
|
|
+ u8_t urgp[2];
|
|
+ u8_t optdata[4];
|
|
+};
|
|
+
|
|
+/* The TCP and IP headers. */
|
|
+struct __attribute__ ((__packed__)) uip_tcp_ipv6_hdr {
|
|
+ /* IPv6 header. */
|
|
+ u8_t vtc, tcflow;
|
|
+ u16_t flow;
|
|
+ u8_t len[2];
|
|
+ u8_t proto, ttl;
|
|
+ uip_ip6addr_t srcipaddr, destipaddr;
|
|
+
|
|
+ /* TCP header. */
|
|
+ u16_t srcport, destport;
|
|
+ u8_t seqno[4], ackno[4], tcpoffset, flags, wnd[2];
|
|
+ u16_t tcpchksum;
|
|
+ u8_t urgp[2];
|
|
+ u8_t optdata[4];
|
|
+};
|
|
+
|
|
+/* The ICMPv4 */
|
|
+struct __attribute__ ((__packed__)) uip_icmpv4_hdr {
|
|
+ /* ICMP (echo) header. */
|
|
+ u8_t type, icode;
|
|
+ u16_t icmpchksum;
|
|
+ u16_t id, seqno;
|
|
+};
|
|
+
|
|
+/* The ICMPv6 */
|
|
+struct __attribute__ ((__packed__)) uip_icmpv6_hdr {
|
|
+ /* ICMP (echo) header. */
|
|
+ u8_t type, icode;
|
|
+ u16_t icmpchksum;
|
|
+ u8_t flags, reserved1, reserved2, reserved3;
|
|
+ u8_t icmp6data[16];
|
|
+ u8_t options[1];
|
|
+};
|
|
+
|
|
+/* The ICMP and IP headers. */
|
|
+struct __attribute__ ((__packed__)) uip_icmpip_hdr {
|
|
+#if UIP_CONF_IPV6
|
|
+ /* IPv6 header. */
|
|
+ u8_t vtc, tcf;
|
|
+ u16_t flow;
|
|
+ u8_t len[2];
|
|
+ u8_t proto, ttl;
|
|
+ uip_ip6addr_t srcipaddr, destipaddr;
|
|
+#else /* UIP_CONF_IPV6 */
|
|
+ /* IPv4 header. */
|
|
+ u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto;
|
|
+ u16_t ipchksum;
|
|
+ u16_t srcipaddr[2], destipaddr[2];
|
|
+#endif /* UIP_CONF_IPV6 */
|
|
+
|
|
+ /* ICMP (echo) header. */
|
|
+ u8_t type, icode;
|
|
+ u16_t icmpchksum;
|
|
+#if !UIP_CONF_IPV6
|
|
+ u16_t id, seqno;
|
|
+#else /* !UIP_CONF_IPV6 */
|
|
+ u8_t flags, reserved1, reserved2, reserved3;
|
|
+ u8_t icmp6data[16];
|
|
+ u8_t options[1];
|
|
+#endif /* !UIP_CONF_IPV6 */
|
|
+};
|
|
+
|
|
+/* The UDP */
|
|
+struct __attribute__ ((__packed__)) uip_udp_hdr {
|
|
+ /* UDP header. */
|
|
+ u16_t srcport, destport;
|
|
+ u16_t udplen;
|
|
+ u16_t udpchksum;
|
|
+};
|
|
+
|
|
+/* The UDP and IP headers. */
|
|
+struct __attribute__ ((__packed__)) uip_udpip_hdr {
|
|
+#if UIP_CONF_IPV6
|
|
+ /* IPv6 header. */
|
|
+ u8_t vtc, tcf;
|
|
+ u16_t flow;
|
|
+ u8_t len[2];
|
|
+ u8_t proto, ttl;
|
|
+ uip_ip6addr_t srcipaddr, destipaddr;
|
|
+#else /* UIP_CONF_IPV6 */
|
|
+ /* IP header. */
|
|
+ u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto;
|
|
+ u16_t ipchksum;
|
|
+ u16_t srcipaddr[2], destipaddr[2];
|
|
+#endif /* UIP_CONF_IPV6 */
|
|
+
|
|
+ /* UDP header. */
|
|
+ u16_t srcport, destport;
|
|
+ u16_t udplen;
|
|
+ u16_t udpchksum;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * The buffer size available for user data in the \ref uip_buf buffer.
|
|
+ *
|
|
+ * This macro holds the available size for user data in the \ref
|
|
+ * uip_buf buffer. The macro is intended to be used for checking
|
|
+ * bounds of available user data.
|
|
+ *
|
|
+ * Example:
|
|
+ \code
|
|
+ snprintf(uip_appdata, UIP_APPDATA_SIZE, "%u\n", i);
|
|
+ \endcode
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_APPDATA_SIZE (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN)
|
|
+
|
|
+#define UIP_PROTO_ICMP 1
|
|
+#define UIP_PROTO_TCP 6
|
|
+#define UIP_PROTO_UDP 17
|
|
+#define UIP_PROTO_ICMP6 58
|
|
+
|
|
+/* Header sizes. */
|
|
+#define UIP_IPv6_H_LEN 40 /* Size of IPv6 header */
|
|
+#define UIP_IPv4_H_LEN 20 /* Size of IPv4 header */
|
|
+
|
|
+#define UIP_UDPH_LEN 8 /* Size of UDP header */
|
|
+#define UIP_TCPH_LEN 20 /* Size of TCP header */
|
|
+
|
|
+#define UIP_IPv4_UDPH_LEN (UIP_UDPH_LEN + UIP_IPv4_H_LEN) /* Size of IPv4
|
|
+ + UDP
|
|
+ header */
|
|
+#define UIP_IPv4_TCPH_LEN (UIP_TCPH_LEN + UIP_IPv4_H_LEN) /* Size of IPv4
|
|
+ + TCP
|
|
+ header */
|
|
+#define UIP_TCP_IPv4_HLEN UIP_IPv4_TCPH_LEN
|
|
+
|
|
+#define UIP_IPv6_UDPH_LEN (UIP_UDPH_LEN + UIP_IPv6_H_LEN) /* Size of IPv6
|
|
+ + UDP
|
|
+ header */
|
|
+#define UIP_IPv6_TCPH_LEN (UIP_TCPH_LEN + UIP_IPv6_H_LEN) /* Size of IPv6
|
|
+ + TCP
|
|
+ header */
|
|
+#define UIP_TCP_IPv6_HLEN UIP_IPv6_TCPH_LEN
|
|
+
|
|
+/**
|
|
+ * Calculate the Internet checksum over a buffer.
|
|
+ *
|
|
+ * The Internet checksum is the one's complement of the one's
|
|
+ * complement sum of all 16-bit words in the buffer.
|
|
+ *
|
|
+ * See RFC1071.
|
|
+ *
|
|
+ * \param buf A pointer to the buffer over which the checksum is to be
|
|
+ * computed.
|
|
+ *
|
|
+ * \param len The length of the buffer over which the checksum is to
|
|
+ * be computed.
|
|
+ *
|
|
+ * \return The Internet checksum of the buffer.
|
|
+ */
|
|
+u16_t uip_chksum(u16_t *buf, u16_t len);
|
|
+
|
|
+/**
|
|
+ * Calculate the IP header checksum of the packet header in uip_buf.
|
|
+ *
|
|
+ * The IP header checksum is the Internet checksum of the 20 bytes of
|
|
+ * the IP header.
|
|
+ *
|
|
+ * \return The IP header checksum of the IP header in the uip_buf
|
|
+ * buffer.
|
|
+ */
|
|
+u16_t uip_ipchksum(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Calculate the TCP checksum of the packet in uip_buf and uip_appdata.
|
|
+ *
|
|
+ * The TCP checksum is the Internet checksum of data contents of the
|
|
+ * TCP segment, and a pseudo-header as defined in RFC793.
|
|
+ *
|
|
+ * \return The TCP checksum of the TCP segment in uip_buf and pointed
|
|
+ * to by uip_appdata.
|
|
+ */
|
|
+u16_t uip_tcpchksum(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Calculate the UDP checksum of the packet in uip_buf and uip_appdata.
|
|
+ *
|
|
+ * The UDP checksum is the Internet checksum of data contents of the
|
|
+ * UDP segment, and a pseudo-header as defined in RFC768.
|
|
+ *
|
|
+ * \return The UDP checksum of the UDP segment in uip_buf and pointed
|
|
+ * to by uip_appdata.
|
|
+ */
|
|
+u16_t uip_udpchksum(struct uip_stack *ustack);
|
|
+
|
|
+/* IPv6 checksum */
|
|
+uint16_t icmpv6_checksum(uint8_t *data);
|
|
+
|
|
+struct neighbor_entry {
|
|
+ struct in6_addr ipaddr;
|
|
+ struct uip_eth_addr mac_addr;
|
|
+ u8_t time;
|
|
+};
|
|
+
|
|
+struct uip_stack {
|
|
+ struct uip_eth_addr uip_ethaddr;
|
|
+
|
|
+ u8_t *uip_buf;
|
|
+
|
|
+ uint8_t *data_link_layer; /* Pointer to the data link layer */
|
|
+ uint8_t *network_layer; /* Pointer to the network layer */
|
|
+ void *uip_appdata; /* The uip_appdata pointer points to
|
|
+ application data. */
|
|
+ void *uip_sappdata; /* The uip_appdata pointer points to
|
|
+ the application data which is to
|
|
+ be sent. */
|
|
+#if UIP_URGDATA > 0
|
|
+ void *uip_urgdata; /* The uip_urgdata pointer points to
|
|
+ urgent data (out-of-band data), if
|
|
+ present. */
|
|
+ u16_t uip_urglen, uip_surglen;
|
|
+#endif /* UIP_URGDATA > 0 */
|
|
+
|
|
+ u16_t uip_len, uip_slen; /* The uip_len is either 8 or 16 bits,
|
|
+ depending on the maximum packet
|
|
+ size. */
|
|
+ u8_t uip_flags; /* The uip_flags variable is used for
|
|
+ communication between the TCP/IP stack
|
|
+ and the application program. */
|
|
+ struct uip_conn *uip_conn; /* uip_conn always points to the current
|
|
+ connection. */
|
|
+
|
|
+ struct uip_conn uip_conns[UIP_CONNS];
|
|
+ /* The uip_conns array holds all TCP
|
|
+ connections. */
|
|
+ u16_t uip_listenports[UIP_LISTENPORTS];
|
|
+ /* The uip_listenports list all currently
|
|
+ listning ports. */
|
|
+#if UIP_UDP
|
|
+ struct uip_udp_conn *uip_udp_conn;
|
|
+ struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
|
|
+#endif /* UIP_UDP */
|
|
+
|
|
+ u16_t ipid; /* This ipid variable is an increasing
|
|
+ number that is used for the IP ID
|
|
+ field. */
|
|
+
|
|
+ u8_t iss[4]; /* The iss variable is used for the TCP
|
|
+ initial sequence number. */
|
|
+
|
|
+#if UIP_ACTIVE_OPEN
|
|
+ u16_t lastport; /* Keeps track of the last port used for
|
|
+ a new connection. */
|
|
+#endif /* UIP_ACTIVE_OPEN */
|
|
+
|
|
+#define IP_CONFIG_OFF 0x00
|
|
+#define IPV4_CONFIG_OFF 0x01
|
|
+#define IPV4_CONFIG_STATIC 0x02
|
|
+#define IPV4_CONFIG_DHCP 0x04
|
|
+#define IPV6_CONFIG_OFF 0x10
|
|
+#define IPV6_CONFIG_STATIC 0x20
|
|
+#define IPV6_CONFIG_DHCP 0x40
|
|
+ u8_t ip_config;
|
|
+
|
|
+ uip_ip4addr_t hostaddr, netmask, default_route_addr;
|
|
+ uip_ip6addr_t hostaddr6, netmask6, default_route_addr6,
|
|
+ linklocal6;
|
|
+ int prefix_len;
|
|
+ u8_t ipv6_autocfg;
|
|
+#define IPV6_AUTOCFG_DHCPV6 (1<<0)
|
|
+#define IPV6_AUTOCFG_ND (1<<1)
|
|
+#define IPV6_AUTOCFG_NOTSPEC (1<<6)
|
|
+#define IPV6_AUTOCFG_NOTUSED (1<<7)
|
|
+ u8_t linklocal_autocfg;
|
|
+#define IPV6_LL_AUTOCFG_ON (1<<0)
|
|
+#define IPV6_LL_AUTOCFG_OFF (1<<1)
|
|
+#define IPV6_LL_AUTOCFG_NOTSPEC (1<<6)
|
|
+#define IPV6_LL_AUTOCFG_NOTUSED (1<<7)
|
|
+ u8_t router_autocfg;
|
|
+#define IPV6_RTR_AUTOCFG_ON (1<<0)
|
|
+#define IPV6_RTR_AUTOCFG_OFF (1<<1)
|
|
+#define IPV6_RTR_AUTOCFG_NOTSPEC (1<<6)
|
|
+#define IPV6_RTR_AUTOCFG_NOTUSED (1<<7)
|
|
+
|
|
+#define UIP_NEIGHBOR_ENTRIES 8
|
|
+ struct neighbor_entry neighbor_entries[UIP_NEIGHBOR_ENTRIES];
|
|
+
|
|
+ struct uip_stats stats;
|
|
+
|
|
+ u8_t opt;
|
|
+
|
|
+ pthread_mutex_t lock;
|
|
+
|
|
+ /* IPv6 support */
|
|
+#define UIP_SUPPORT_IPv6_ENABLED 0x01
|
|
+#define UIP_SUPPORT_IPv6_DISABLED 0x02
|
|
+ u8_t enable_IPv6;
|
|
+
|
|
+ /* DHCPC client attached */
|
|
+ void *dhcpc;
|
|
+
|
|
+ /* NDP client */
|
|
+ void *ndpc;
|
|
+};
|
|
+
|
|
+/*******************************************************************************
|
|
+ * IPv6 Support
|
|
+ ******************************************************************************/
|
|
+int set_ipv6_link_local_address(struct uip_stack *ustack);
|
|
+int is_ipv6_link_local_address(uip_ip6addr_t *addr);
|
|
+
|
|
+void dump_uip_packet(struct uip_stack *ustack);
|
|
+
|
|
+#endif /* __UIP_H__ */
|
|
+
|
|
+/** @} */
|
|
diff --git a/iscsiuio/src/uip/uip_arch.h b/iscsiuio/src/uip/uip_arch.h
|
|
new file mode 100644
|
|
index 0000000..3ddacec
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/uip_arch.h
|
|
@@ -0,0 +1,137 @@
|
|
+/**
|
|
+ * \addtogroup uip
|
|
+ * {@
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \defgroup uiparch Architecture specific uIP functions
|
|
+ * @{
|
|
+ *
|
|
+ * The functions in the architecture specific module implement the IP
|
|
+ * check sum and 32-bit additions.
|
|
+ *
|
|
+ * The IP checksum calculation is the most computationally expensive
|
|
+ * operation in the TCP/IP stack and it therefore pays off to
|
|
+ * implement this in efficient assembler. The purpose of the uip-arch
|
|
+ * module is to let the checksum functions to be implemented in
|
|
+ * architecture specific assembler.
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Declarations of architecture specific functions.
|
|
+ * \author Adam Dunkels <adam@dunkels.com>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2001, Adam Dunkels.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack.
|
|
+ *
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __UIP_ARCH_H__
|
|
+#define __UIP_ARCH_H__
|
|
+
|
|
+#include "uip.h"
|
|
+
|
|
+/**
|
|
+ * Carry out a 32-bit addition.
|
|
+ *
|
|
+ * Because not all architectures for which uIP is intended has native
|
|
+ * 32-bit arithmetic, uIP uses an external C function for doing the
|
|
+ * required 32-bit additions in the TCP protocol processing. This
|
|
+ * function should add the two arguments and place the result in the
|
|
+ * global variable uip_acc32.
|
|
+ *
|
|
+ * \note The 32-bit integer pointed to by the op32 parameter and the
|
|
+ * result in the uip_acc32 variable are in network byte order (big
|
|
+ * endian).
|
|
+ *
|
|
+ * \param op32 A pointer to a 4-byte array representing a 32-bit
|
|
+ * integer in network byte order (big endian).
|
|
+ *
|
|
+ * \param op16 A 16-bit integer in host byte order.
|
|
+ */
|
|
+void uip_add32(u8_t *op32, u16_t op16, u8_t *uip_add32);
|
|
+
|
|
+/**
|
|
+ * Calculate the Internet checksum over a buffer.
|
|
+ *
|
|
+ * The Internet checksum is the one's complement of the one's
|
|
+ * complement sum of all 16-bit words in the buffer.
|
|
+ *
|
|
+ * See RFC1071.
|
|
+ *
|
|
+ * \note This function is not called in the current version of uIP,
|
|
+ * but future versions might make use of it.
|
|
+ *
|
|
+ * \param buf A pointer to the buffer over which the checksum is to be
|
|
+ * computed.
|
|
+ *
|
|
+ * \param len The length of the buffer over which the checksum is to
|
|
+ * be computed.
|
|
+ *
|
|
+ * \return The Internet checksum of the buffer.
|
|
+ */
|
|
+u16_t uip_chksum(u16_t *buf, u16_t len);
|
|
+
|
|
+/**
|
|
+ * Calculate the IP header checksum of the packet header in uip_buf.
|
|
+ *
|
|
+ * The IP header checksum is the Internet checksum of the 20 bytes of
|
|
+ * the IP header.
|
|
+ *
|
|
+ * \return The IP header checksum of the IP header in the uip_buf
|
|
+ * buffer.
|
|
+ */
|
|
+u16_t uip_ipchksum(struct uip_stack *ustack);
|
|
+
|
|
+/**
|
|
+ * Calculate the TCP checksum of the packet in uip_buf and uip_appdata.
|
|
+ *
|
|
+ * The TCP checksum is the Internet checksum of data contents of the
|
|
+ * TCP segment, and a pseudo-header as defined in RFC793.
|
|
+ *
|
|
+ * \note The uip_appdata pointer that points to the packet data may
|
|
+ * point anywhere in memory, so it is not possible to simply calculate
|
|
+ * the Internet checksum of the contents of the uip_buf buffer.
|
|
+ *
|
|
+ * \return The TCP checksum of the TCP segment in uip_buf and pointed
|
|
+ * to by uip_appdata.
|
|
+ */
|
|
+u16_t uip_tcpchksum(struct uip_stack *ustack);
|
|
+
|
|
+u16_t uip_udpchksum(struct uip_stack *ustack);
|
|
+
|
|
+/** @} */
|
|
+/** @} */
|
|
+
|
|
+#endif /* __UIP_ARCH_H__ */
|
|
diff --git a/iscsiuio/src/uip/uip_arp.c b/iscsiuio/src/uip/uip_arp.c
|
|
new file mode 100644
|
|
index 0000000..1b3761f
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/uip_arp.c
|
|
@@ -0,0 +1,479 @@
|
|
+#include <errno.h>
|
|
+#include <netinet/in.h>
|
|
+#include <arpa/inet.h>
|
|
+
|
|
+#include "logger.h"
|
|
+#include "packet.h"
|
|
+
|
|
+/**
|
|
+ * \addtogroup uip
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \defgroup uiparp uIP Address Resolution Protocol
|
|
+ * @{
|
|
+ *
|
|
+ * The Address Resolution Protocol ARP is used for mapping between IP
|
|
+ * addresses and link level addresses such as the Ethernet MAC
|
|
+ * addresses. ARP uses broadcast queries to ask for the link level
|
|
+ * address of a known IP address and the host which is configured with
|
|
+ * the IP address for which the query was meant, will respond with its
|
|
+ * link level address.
|
|
+ *
|
|
+ * \note This ARP implementation only supports Ethernet.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Implementation of the ARP Address Resolution Protocol.
|
|
+ * \author Adam Dunkels <adam@dunkels.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2001-2003, Adam Dunkels.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack.
|
|
+ *
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include "uip_arp.h"
|
|
+#include "uip_eth.h"
|
|
+
|
|
+#include <pthread.h>
|
|
+#include <string.h>
|
|
+
|
|
+static const struct uip_eth_addr broadcast_ethaddr = {
|
|
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} };
|
|
+static const u16_t broadcast_ipaddr[2] = { 0xffff, 0xffff };
|
|
+
|
|
+pthread_mutex_t arp_table_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
+static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
|
|
+
|
|
+static u8_t arptime;
|
|
+
|
|
+/**
|
|
+ * Initialize the ARP module.
|
|
+ *
|
|
+ */
|
|
+/*----------------------------------------------------------------------------*/
|
|
+void uip_arp_init(void)
|
|
+{
|
|
+ u8_t i;
|
|
+ for (i = 0; i < UIP_ARPTAB_SIZE; ++i)
|
|
+ memset(&arp_table[i], 0, sizeof(arp_table[i]));
|
|
+
|
|
+ pthread_mutex_init(&arp_table_mutex, NULL);
|
|
+}
|
|
+
|
|
+/*----------------------------------------------------------------------------*/
|
|
+/**
|
|
+ * Periodic ARP processing function.
|
|
+ *
|
|
+ * This function performs periodic timer processing in the ARP module
|
|
+ * and should be called at regular intervals. The recommended interval
|
|
+ * is 10 seconds between the calls.
|
|
+ *
|
|
+ */
|
|
+/*----------------------------------------------------------------------------*/
|
|
+void uip_arp_timer(void)
|
|
+{
|
|
+ u8_t i;
|
|
+ struct arp_entry *tabptr;
|
|
+
|
|
+ ++arptime;
|
|
+ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) {
|
|
+ tabptr = &arp_table[i];
|
|
+ if ((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 &&
|
|
+ (u8_t)(arptime - tabptr->time) >= UIP_ARP_MAXAGE)
|
|
+ memset(tabptr->ipaddr, 0, 4);
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+/*----------------------------------------------------------------------------*/
|
|
+static void uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr)
|
|
+{
|
|
+ u8_t i;
|
|
+ struct arp_entry *tabptr;
|
|
+
|
|
+ pthread_mutex_lock(&arp_table_mutex);
|
|
+ /* Walk through the ARP mapping table and try to find an entry to
|
|
+ update. If none is found, the IP -> MAC address mapping is
|
|
+ inserted in the ARP table. */
|
|
+ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) {
|
|
+
|
|
+ tabptr = &arp_table[i];
|
|
+ /* Only check those entries that are actually in use. */
|
|
+ if (tabptr->ipaddr[0] != 0 && tabptr->ipaddr[1] != 0) {
|
|
+
|
|
+ /* Check if the source IP address of the incoming packet
|
|
+ matches the IP address in this ARP table entry. */
|
|
+ if (ipaddr[0] == tabptr->ipaddr[0] &&
|
|
+ ipaddr[1] == tabptr->ipaddr[1]) {
|
|
+
|
|
+ tabptr->time = arptime;
|
|
+
|
|
+ pthread_mutex_unlock(&arp_table_mutex);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* If we get here, no existing ARP table entry was found, so we
|
|
+ create one. */
|
|
+
|
|
+ /* First, we try to find an unused entry in the ARP table. */
|
|
+ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) {
|
|
+ tabptr = &arp_table[i];
|
|
+ if (tabptr->ipaddr[0] == 0 && tabptr->ipaddr[1] == 0)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* If no unused entry is found, we try to find the oldest entry and
|
|
+ throw it away. */
|
|
+ if (i == UIP_ARPTAB_SIZE) {
|
|
+ u8_t c;
|
|
+ u8_t tmpage = 0;
|
|
+ c = 0;
|
|
+ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) {
|
|
+ tabptr = &arp_table[i];
|
|
+ if ((u8_t)(arptime - tabptr->time) > tmpage) {
|
|
+ tmpage = (u8_t)(arptime - tabptr->time);
|
|
+ c = i;
|
|
+ }
|
|
+ }
|
|
+ i = c;
|
|
+ tabptr = &arp_table[i];
|
|
+ }
|
|
+
|
|
+ /* Now, i is the ARP table entry which we will fill with the new
|
|
+ information. */
|
|
+ memcpy(tabptr->ipaddr, ipaddr, 4);
|
|
+ memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
|
|
+ tabptr->time = arptime;
|
|
+
|
|
+ pthread_mutex_unlock(&arp_table_mutex);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * ARP processing for incoming ARP packets.
|
|
+ *
|
|
+ * This function should be called by the device driver when an ARP
|
|
+ * packet has been received. The function will act differently
|
|
+ * depending on the ARP packet type: if it is a reply for a request
|
|
+ * that we previously sent out, the ARP cache will be filled in with
|
|
+ * the values from the ARP reply. If the incoming ARP packet is an ARP
|
|
+ * request for our IP address, an ARP reply packet is created and put
|
|
+ * into the uip_buf[] buffer.
|
|
+ *
|
|
+ * When the function returns, the value of the global variable uip_len
|
|
+ * indicates whether the device driver should send out a packet or
|
|
+ * not. If uip_len is zero, no packet should be sent. If uip_len is
|
|
+ * non-zero, it contains the length of the outbound packet that is
|
|
+ * present in the uip_buf[] buffer.
|
|
+ *
|
|
+ * This function expects an ARP packet with a prepended Ethernet
|
|
+ * header in the uip_buf[] buffer, and the length of the packet in the
|
|
+ * global variable uip_len.
|
|
+ */
|
|
+void uip_arp_ipin(struct uip_stack *ustack, packet_t *pkt)
|
|
+{
|
|
+ struct ip_hdr *ip;
|
|
+ struct uip_eth_hdr *eth;
|
|
+
|
|
+ eth = (struct uip_eth_hdr *)pkt->data_link_layer;
|
|
+ ip = (struct ip_hdr *)pkt->network_layer;
|
|
+
|
|
+ if (uip_ip4addr_cmp(ip->destipaddr, ustack->hostaddr)) {
|
|
+ /* First, we register the one who made the request in our ARP
|
|
+ table, since it is likely that we will do more communication
|
|
+ with this host in the future. */
|
|
+ uip_arp_update(ip->srcipaddr, ð->src);
|
|
+ }
|
|
+}
|
|
+
|
|
+void
|
|
+uip_arp_arpin(nic_interface_t *nic_iface,
|
|
+ struct uip_stack *ustack, packet_t *pkt)
|
|
+{
|
|
+ struct arp_hdr *arp;
|
|
+ struct uip_eth_hdr *eth;
|
|
+
|
|
+ if (pkt->buf_size < sizeof(struct arp_hdr)) {
|
|
+ pkt->buf_size = 0;
|
|
+ return;
|
|
+ }
|
|
+ pkt->buf_size = 0;
|
|
+
|
|
+ eth = (struct uip_eth_hdr *)pkt->data_link_layer;
|
|
+ arp = (struct arp_hdr *)pkt->network_layer;
|
|
+
|
|
+ switch (arp->opcode) {
|
|
+ case const_htons(ARP_REQUEST):
|
|
+ /* ARP request. If it asked for our address, we send out a
|
|
+ reply. */
|
|
+ if (uip_ip4addr_cmp(arp->dipaddr, ustack->hostaddr)) {
|
|
+ /* First, we register the one who made the request in
|
|
+ our ARP table, since it is likely that we will do
|
|
+ more communication with this host in the future. */
|
|
+ uip_arp_update(arp->sipaddr, &arp->shwaddr);
|
|
+
|
|
+ /* The reply opcode is 2. */
|
|
+ arp->opcode = htons(2);
|
|
+
|
|
+ memcpy(arp->dhwaddr.addr, arp->shwaddr.addr, 6);
|
|
+ memcpy(arp->shwaddr.addr, ustack->uip_ethaddr.addr, 6);
|
|
+ memcpy(eth->src.addr, ustack->uip_ethaddr.addr, 6);
|
|
+ memcpy(eth->dest.addr, arp->dhwaddr.addr, 6);
|
|
+
|
|
+ arp->dipaddr[0] = arp->sipaddr[0];
|
|
+ arp->dipaddr[1] = arp->sipaddr[1];
|
|
+ arp->sipaddr[0] = ustack->hostaddr[0];
|
|
+ arp->sipaddr[1] = ustack->hostaddr[1];
|
|
+
|
|
+ if (nic_iface->vlan_id == 0) {
|
|
+ eth->type = htons(UIP_ETHTYPE_ARP);
|
|
+ pkt->buf_size = sizeof(*arp) + sizeof(*eth);
|
|
+ } else {
|
|
+ eth->type = htons(UIP_ETHTYPE_8021Q);
|
|
+ pkt->buf_size = sizeof(*arp) +
|
|
+ sizeof(struct uip_vlan_eth_hdr);
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ case const_htons(ARP_REPLY):
|
|
+ uip_arp_update(arp->sipaddr, &arp->shwaddr);
|
|
+ break;
|
|
+ default:
|
|
+ LOG_WARN("Unknown ARP opcode: %d", ntohs(arp->opcode));
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Prepend Ethernet header to an outbound IP packet and see if we need
|
|
+ * to send out an ARP request.
|
|
+ *
|
|
+ * This function should be called before sending out an IP packet. The
|
|
+ * function checks the destination IP address of the IP packet to see
|
|
+ * what Ethernet MAC address that should be used as a destination MAC
|
|
+ * address on the Ethernet.
|
|
+ *
|
|
+ * If the destination IP address is in the local network (determined
|
|
+ * by logical ANDing of netmask and our IP address), the function
|
|
+ * checks the ARP cache to see if an entry for the destination IP
|
|
+ * address is found. If so, an Ethernet header is prepended and the
|
|
+ * function returns. If no ARP cache entry is found for the
|
|
+ * destination IP address, the packet in the uip_buf[] is replaced by
|
|
+ * an ARP request packet for the IP address. The IP packet is dropped
|
|
+ * and it is assumed that they higher level protocols (e.g., TCP)
|
|
+ * eventually will retransmit the dropped packet.
|
|
+ *
|
|
+ * If the destination IP address is not on the local network, the IP
|
|
+ * address of the default router is used instead.
|
|
+ *
|
|
+ * When the function returns, a packet is present in the uip_buf[]
|
|
+ * buffer, and the length of the packet is in the global variable
|
|
+ * uip_len.
|
|
+ */
|
|
+
|
|
+dest_ipv4_addr_t
|
|
+uip_determine_dest_ipv4_addr(struct uip_stack *ustack, u16_t *ipaddr)
|
|
+{
|
|
+ struct uip_eth_hdr *eth;
|
|
+ struct ip_hdr *ip_buf;
|
|
+
|
|
+ eth = (struct uip_eth_hdr *)ustack->data_link_layer;
|
|
+ ip_buf = (struct ip_hdr *)ustack->network_layer;
|
|
+
|
|
+ /* Find the destination IP address in the ARP table and construct
|
|
+ the Ethernet header. If the destination IP addres isn't on the
|
|
+ local network, we use the default router's IP address instead.
|
|
+
|
|
+ If not ARP table entry is found, we overwrite the original IP
|
|
+ packet with an ARP request for the IP address. */
|
|
+
|
|
+ /* First check if destination is a local broadcast. */
|
|
+ if (uip_ip4addr_cmp(ip_buf->destipaddr, broadcast_ipaddr)) {
|
|
+ memcpy(ð->dest, broadcast_ethaddr.addr, 6);
|
|
+
|
|
+ return LOCAL_BROADCAST;
|
|
+ } else {
|
|
+ /* Check if the destination address is on the local network. */
|
|
+ if (!uip_ip4addr_maskcmp(ip_buf->destipaddr,
|
|
+ ustack->hostaddr, ustack->netmask)) {
|
|
+ /* Destination address was not on the local network,
|
|
+ so we need to use the default router's IP address
|
|
+ instead of the destination address when determining
|
|
+ the MAC address. */
|
|
+ uip_ip4addr_copy(ipaddr, ustack->default_route_addr);
|
|
+ } else {
|
|
+ /* Else, we use the destination IP address. */
|
|
+ uip_ip4addr_copy(ipaddr, ip_buf->destipaddr);
|
|
+ }
|
|
+
|
|
+ return NONLOCAL_BROADCAST;
|
|
+ }
|
|
+}
|
|
+
|
|
+arp_out_t is_in_arp_table(u16_t *ipaddr, struct arp_entry **tabptr)
|
|
+{
|
|
+ u8_t i;
|
|
+
|
|
+ pthread_mutex_lock(&arp_table_mutex);
|
|
+
|
|
+ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) {
|
|
+ if (uip_ip4addr_cmp(ipaddr, arp_table[i].ipaddr)) {
|
|
+ *tabptr = &arp_table[i];
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pthread_mutex_unlock(&arp_table_mutex);
|
|
+
|
|
+ if (i == UIP_ARPTAB_SIZE)
|
|
+ return NOT_IN_ARP_TABLE;
|
|
+ else
|
|
+ return IS_IN_ARP_TABLE;
|
|
+}
|
|
+
|
|
+void uip_build_arp_request(struct uip_stack *ustack, u16_t *ipaddr)
|
|
+{
|
|
+ struct arp_hdr *arp;
|
|
+ struct uip_eth_hdr *eth;
|
|
+
|
|
+ arp = (struct arp_hdr *)ustack->network_layer;
|
|
+ eth = (struct uip_eth_hdr *)ustack->data_link_layer;
|
|
+
|
|
+ /* The destination address was not in our ARP table, so we
|
|
+ overwrite the IP packet with an ARP request. */
|
|
+
|
|
+ memset(eth->dest.addr, 0xff, 6);
|
|
+ memset(arp->dhwaddr.addr, 0x00, 6);
|
|
+ memcpy(eth->src.addr, ustack->uip_ethaddr.addr, 6);
|
|
+ memcpy(arp->shwaddr.addr, ustack->uip_ethaddr.addr, 6);
|
|
+
|
|
+ uip_ip4addr_copy(arp->dipaddr, ipaddr);
|
|
+ uip_ip4addr_copy(arp->sipaddr, ustack->hostaddr);
|
|
+ arp->opcode = const_htons(ARP_REQUEST); /* ARP request. */
|
|
+ arp->hwtype = const_htons(ARP_HWTYPE_ETH);
|
|
+ arp->protocol = const_htons(UIP_ETHTYPE_IPv4);
|
|
+ arp->hwlen = 6;
|
|
+ arp->protolen = 4;
|
|
+ eth->type = const_htons(UIP_ETHTYPE_ARP);
|
|
+
|
|
+ ustack->uip_appdata = &ustack->uip_buf[UIP_TCP_IPv4_HLEN + UIP_LLH_LEN];
|
|
+
|
|
+ ustack->uip_len = sizeof(*arp) + sizeof(*eth);
|
|
+}
|
|
+
|
|
+void
|
|
+uip_build_eth_header(struct uip_stack *ustack,
|
|
+ u16_t *ipaddr,
|
|
+ struct arp_entry *tabptr,
|
|
+ struct packet *pkt, u16_t vlan_id)
|
|
+{
|
|
+ struct uip_ipv4_hdr *ip_buf;
|
|
+ struct uip_eth_hdr *eth;
|
|
+ struct uip_vlan_eth_hdr *eth_vlan;
|
|
+
|
|
+ ip_buf = (struct uip_ipv4_hdr *)ustack->network_layer;
|
|
+ eth = (struct uip_eth_hdr *)ustack->data_link_layer;
|
|
+ eth_vlan = (struct uip_vlan_eth_hdr *)ustack->data_link_layer;
|
|
+
|
|
+ /* First check if destination is a local broadcast. */
|
|
+ if (uip_ip4addr_cmp(ip_buf->destipaddr, broadcast_ipaddr)) {
|
|
+ memcpy(eth->dest.addr, broadcast_ethaddr.addr, 6);
|
|
+ } else {
|
|
+ /* Build an ethernet header. */
|
|
+ memcpy(eth->dest.addr, tabptr->ethaddr.addr, 6);
|
|
+ }
|
|
+ memcpy(eth->src.addr, ustack->uip_ethaddr.addr, 6);
|
|
+
|
|
+ if (vlan_id == 0) {
|
|
+ eth->type = htons(UIP_ETHTYPE_IPv4);
|
|
+
|
|
+ ustack->uip_len += sizeof(struct uip_eth_hdr);
|
|
+ pkt->buf_size += sizeof(struct uip_eth_hdr);
|
|
+ } else {
|
|
+ eth_vlan->tpid = htons(UIP_ETHTYPE_8021Q);
|
|
+ eth_vlan->vid = htons(vlan_id);
|
|
+ eth_vlan->type = htons(UIP_ETHTYPE_IPv4);
|
|
+
|
|
+ ustack->uip_len += sizeof(struct uip_vlan_eth_hdr);
|
|
+ pkt->buf_size += sizeof(struct uip_vlan_eth_hdr);
|
|
+ }
|
|
+}
|
|
+
|
|
+static struct arp_entry *uip_get_arp_entry(int index)
|
|
+{
|
|
+ return &arp_table[index];
|
|
+}
|
|
+
|
|
+int uip_lookup_arp_entry(uint32_t ip_addr, uint8_t *mac_addr)
|
|
+{
|
|
+ int i;
|
|
+ int rc = -EINVAL;
|
|
+
|
|
+ pthread_mutex_lock(&arp_table_mutex);
|
|
+
|
|
+ for (i = 0; i < UIP_ARPTAB_SIZE; ++i) {
|
|
+ struct arp_entry *entry = uip_get_arp_entry(i);
|
|
+
|
|
+ if (((entry->ipaddr[1] << 16) == (ip_addr & 0xffff0000)) &&
|
|
+ ((entry->ipaddr[0]) == (ip_addr & 0x0000ffff))) {
|
|
+ struct in_addr addr;
|
|
+ char *addr_str;
|
|
+
|
|
+ addr.s_addr = ip_addr;
|
|
+ addr_str = inet_ntoa(addr);
|
|
+
|
|
+ memcpy(mac_addr, entry->ethaddr.addr, 6);
|
|
+
|
|
+ LOG_INFO("Found %s at %02x:%02x:%02x:%02x:%02x:%02x",
|
|
+ addr_str,
|
|
+ mac_addr[0], mac_addr[1], mac_addr[2],
|
|
+ mac_addr[3], mac_addr[4], mac_addr[5]);
|
|
+ rc = 0;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pthread_mutex_unlock(&arp_table_mutex);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*----------------------------------------------------------------------------*/
|
|
+
|
|
+/** @} */
|
|
+/** @} */
|
|
diff --git a/iscsiuio/src/uip/uip_arp.h b/iscsiuio/src/uip/uip_arp.h
|
|
new file mode 100644
|
|
index 0000000..339d57d
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/uip_arp.h
|
|
@@ -0,0 +1,197 @@
|
|
+/**
|
|
+ * \addtogroup uip
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \addtogroup uiparp
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Macros and definitions for the ARP module.
|
|
+ * \author Adam Dunkels <adam@dunkels.com>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2001-2003, Adam Dunkels.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack.
|
|
+ *
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __UIP_ARP_H__
|
|
+#define __UIP_ARP_H__
|
|
+
|
|
+#include "packet.h"
|
|
+#include "uip.h"
|
|
+#include "uip_eth.h"
|
|
+
|
|
+#define ARP_REQUEST 1
|
|
+#define ARP_REPLY 2
|
|
+
|
|
+#define ARP_HWTYPE_ETH 1
|
|
+
|
|
+struct __attribute__ ((__packed__)) arp_hdr {
|
|
+ u16_t hwtype;
|
|
+ u16_t protocol;
|
|
+ u8_t hwlen;
|
|
+ u8_t protolen;
|
|
+ u16_t opcode;
|
|
+ struct uip_eth_addr shwaddr;
|
|
+ u16_t sipaddr[2];
|
|
+ struct uip_eth_addr dhwaddr;
|
|
+ u16_t dipaddr[2];
|
|
+};
|
|
+
|
|
+struct __attribute__ ((__packed__)) ip_hdr {
|
|
+ /* IP header. */
|
|
+ u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto;
|
|
+ u16_t ipchksum;
|
|
+ u16_t srcipaddr[2], destipaddr[2];
|
|
+};
|
|
+
|
|
+struct __attribute__ ((__packed__)) ethip_hdr {
|
|
+ struct uip_eth_hdr ethhdr;
|
|
+ /* IP header. */
|
|
+ u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto;
|
|
+ u16_t ipchksum;
|
|
+ u16_t srcipaddr[2], destipaddr[2];
|
|
+};
|
|
+
|
|
+struct arp_entry {
|
|
+ u16_t ipaddr[2];
|
|
+ struct uip_eth_addr ethaddr;
|
|
+ u8_t time;
|
|
+};
|
|
+
|
|
+/* The uip_arp_init() function must be called before any of the other
|
|
+ ARP functions. */
|
|
+void uip_arp_init(void);
|
|
+
|
|
+/* The uip_arp_ipin() function should be called whenever an IP packet
|
|
+ arrives from the Ethernet. This function refreshes the ARP table or
|
|
+ inserts a new mapping if none exists. The function assumes that an
|
|
+ IP packet with an Ethernet header is present in the uip_buf buffer
|
|
+ and that the length of the packet is in the uip_len variable. */
|
|
+/*void uip_arp_ipin(void);*/
|
|
+/* #define uip_arp_ipin() */
|
|
+void uip_arp_ipin(struct uip_stack *ustack, struct packet *pkt);
|
|
+
|
|
+/* The uip_arp_arpin() should be called when an ARP packet is received
|
|
+ by the Ethernet driver. This function also assumes that the
|
|
+ Ethernet frame is present in the uip_buf buffer. When the
|
|
+ uip_arp_arpin() function returns, the contents of the uip_buf
|
|
+ buffer should be sent out on the Ethernet if the uip_len variable
|
|
+ is > 0. */
|
|
+void uip_arp_arpin(nic_interface_t *nic_iface,
|
|
+ struct uip_stack *ustack, struct packet *pkt);
|
|
+
|
|
+typedef enum {
|
|
+ ARP_SENT = 1,
|
|
+ ETH_HEADER_APPEDEND = 2,
|
|
+} arp_out_t;
|
|
+
|
|
+typedef enum {
|
|
+ LOCAL_BROADCAST = 1,
|
|
+ NONLOCAL_BROADCAST = 2,
|
|
+} dest_ipv4_addr_t;
|
|
+
|
|
+typedef enum {
|
|
+ IS_IN_ARP_TABLE = 1,
|
|
+ NOT_IN_ARP_TABLE = 2,
|
|
+} arp_table_query_t;
|
|
+
|
|
+dest_ipv4_addr_t
|
|
+uip_determine_dest_ipv4_addr(struct uip_stack *ustack, u16_t *ipaddr);
|
|
+arp_out_t is_in_arp_table(u16_t *ipaddr, struct arp_entry **tabptr);
|
|
+
|
|
+void uip_build_arp_request(struct uip_stack *ustack, u16_t *ipaddr);
|
|
+
|
|
+void
|
|
+uip_build_eth_header(struct uip_stack *ustack,
|
|
+ u16_t *ipaddr,
|
|
+ struct arp_entry *tabptr,
|
|
+ struct packet *pkt, u16_t vlan_id);
|
|
+
|
|
+/* The uip_arp_out() function should be called when an IP packet
|
|
+ should be sent out on the Ethernet. This function creates an
|
|
+ Ethernet header before the IP header in the uip_buf buffer. The
|
|
+ Ethernet header will have the correct Ethernet MAC destination
|
|
+ address filled in if an ARP table entry for the destination IP
|
|
+ address (or the IP address of the default router) is present. If no
|
|
+ such table entry is found, the IP packet is overwritten with an ARP
|
|
+ request and we rely on TCP to retransmit the packet that was
|
|
+ overwritten. In any case, the uip_len variable holds the length of
|
|
+ the Ethernet frame that should be transmitted. */
|
|
+arp_out_t uip_arp_out(struct uip_stack *ustack);
|
|
+
|
|
+/* The uip_arp_timer() function should be called every ten seconds. It
|
|
+ is responsible for flushing old entries in the ARP table. */
|
|
+void uip_arp_timer(void);
|
|
+
|
|
+int uip_lookup_arp_entry(uint32_t ip_addr, uint8_t *mac_addr);
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/**
|
|
+ * \addtogroup uipconffunc
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Specifiy the Ethernet MAC address.
|
|
+ *
|
|
+ * The ARP code needs to know the MAC address of the Ethernet card in
|
|
+ * order to be able to respond to ARP queries and to generate working
|
|
+ * Ethernet headers.
|
|
+ *
|
|
+ * \note This macro only specifies the Ethernet MAC address to the ARP
|
|
+ * code. It cannot be used to change the MAC address of the Ethernet
|
|
+ * card.
|
|
+ *
|
|
+ * \param eaddr A pointer to a struct uip_eth_addr containing the
|
|
+ * Ethernet MAC address of the Ethernet card.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define uip_setethaddr(eaddr) do { \
|
|
+ uip_ethaddr.addr[0] = eaddr.addr[0]; \
|
|
+ uip_ethaddr.addr[1] = eaddr.addr[1]; \
|
|
+ uip_ethaddr.addr[2] = eaddr.addr[2]; \
|
|
+ uip_ethaddr.addr[3] = eaddr.addr[3]; \
|
|
+ uip_ethaddr.addr[4] = eaddr.addr[4]; \
|
|
+ uip_ethaddr.addr[5] = eaddr.addr[5]; \
|
|
+ } while (0)
|
|
+
|
|
+/** @} */
|
|
+/** @} */
|
|
+
|
|
+#endif /* __UIP_ARP_H__ */
|
|
diff --git a/iscsiuio/src/uip/uip_eth.c b/iscsiuio/src/uip/uip_eth.c
|
|
new file mode 100644
|
|
index 0000000..9e1ea81
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/uip_eth.c
|
|
@@ -0,0 +1,50 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * uip_eth.c - CNIC UIO uIP user space stack
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include "uip.h"
|
|
+#include "uip_eth.h"
|
|
+
|
|
+int is_vlan_packet(struct uip_vlan_eth_hdr *hdr)
|
|
+{
|
|
+ /* The TPID field in a 802.1Q Header must be 0x8100 */
|
|
+ if (hdr->tpid == const_htons(UIP_ETHTYPE_8021Q))
|
|
+ return 1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/iscsiuio/src/uip/uip_eth.h b/iscsiuio/src/uip/uip_eth.h
|
|
new file mode 100644
|
|
index 0000000..830c04c
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/uip_eth.h
|
|
@@ -0,0 +1,43 @@
|
|
+#ifndef __UIP_ETH_H__
|
|
+#define __UIP_ETH_H__
|
|
+
|
|
+#include "uipopt.h"
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Ether types
|
|
+ ******************************************************************************/
|
|
+#define UIP_ETHTYPE_ARP 0x0806
|
|
+#define UIP_ETHTYPE_IPv4 0x0800
|
|
+#define UIP_ETHTYPE_8021Q 0x8100
|
|
+#define UIP_ETHTYPE_IPv6 0x86dd
|
|
+
|
|
+/**
|
|
+ * Representation of a 48-bit Ethernet address.
|
|
+ */
|
|
+struct uip_eth_addr {
|
|
+ u8_t addr[6];
|
|
+};
|
|
+
|
|
+/**
|
|
+ * The Ethernet header.
|
|
+ */
|
|
+struct __attribute__ ((__packed__)) uip_eth_hdr {
|
|
+ struct uip_eth_addr dest;
|
|
+ struct uip_eth_addr src;
|
|
+ u16_t type;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * The 802.1Q Ethernet header (VLAN).
|
|
+ */
|
|
+struct __attribute__ ((__packed__)) uip_vlan_eth_hdr {
|
|
+ struct uip_eth_addr dest;
|
|
+ struct uip_eth_addr src;
|
|
+ u16_t tpid;
|
|
+ u16_t vid;
|
|
+ u16_t type;
|
|
+};
|
|
+
|
|
+int is_vlan_packet(struct uip_vlan_eth_hdr *hdr);
|
|
+
|
|
+#endif /* __UIP_ETH_H__ */
|
|
diff --git a/iscsiuio/src/uip/uipopt.h b/iscsiuio/src/uip/uipopt.h
|
|
new file mode 100644
|
|
index 0000000..946fce2
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/uip/uipopt.h
|
|
@@ -0,0 +1,536 @@
|
|
+/**
|
|
+ * \defgroup uipopt Configuration options for uIP
|
|
+ * @{
|
|
+ *
|
|
+ * uIP is configured using the per-project configuration file
|
|
+ * uipopt.h. This file contains all compile-time options for uIP and
|
|
+ * should be tweaked to match each specific project. The uIP
|
|
+ * distribution contains a documented example "uipopt.h" that can be
|
|
+ * copied and modified for each project.
|
|
+ *
|
|
+ * \note Most of the configuration options in the uipopt.h should not
|
|
+ * be changed, but rather the per-project uip-conf.h file.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Configuration options for uIP.
|
|
+ * \author Adam Dunkels <adam@dunkels.com>
|
|
+ *
|
|
+ * This file is used for tweaking various configuration options for
|
|
+ * uIP. You should make a copy of this file into one of your project's
|
|
+ * directories instead of editing this example "uipopt.h" file that
|
|
+ * comes with the uIP distribution.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2001-2003, Adam Dunkels.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack.
|
|
+ *
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __UIPOPT_H__
|
|
+#define __UIPOPT_H__
|
|
+
|
|
+#ifndef UIP_LITTLE_ENDIAN
|
|
+#define UIP_LITTLE_ENDIAN 3412
|
|
+#endif /* UIP_LITTLE_ENDIAN */
|
|
+#ifndef UIP_BIG_ENDIAN
|
|
+#define UIP_BIG_ENDIAN 1234
|
|
+#endif /* UIP_BIG_ENDIAN */
|
|
+
|
|
+#include "uip-conf.h"
|
|
+
|
|
+/*----------------------------------------------------------------------------*/
|
|
+
|
|
+/**
|
|
+ * \name Static configuration options
|
|
+ * @{
|
|
+ *
|
|
+ * These configuration options can be used for setting the IP address
|
|
+ * settings statically, but only if UIP_FIXEDADDR is set to 1. The
|
|
+ * configuration options for a specific node includes IP address,
|
|
+ * netmask and default router as well as the Ethernet address. The
|
|
+ * netmask, default router and Ethernet address are appliciable only
|
|
+ * if uIP should be run over Ethernet.
|
|
+ *
|
|
+ * All of these should be changed to suit your project.
|
|
+*/
|
|
+
|
|
+/**
|
|
+ * Determines if uIP should use a fixed IP address or not.
|
|
+ *
|
|
+ * If uIP should use a fixed IP address, the settings are set in the
|
|
+ * uipopt.h file. If not, the macros uip_sethostaddr(),
|
|
+ * uip_setdraddr() and uip_setnetmask() should be used instead.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_FIXEDADDR 0
|
|
+
|
|
+/**
|
|
+ * Ping IP address asignment.
|
|
+ *
|
|
+ * uIP uses a "ping" packets for setting its own IP address if this
|
|
+ * option is set. If so, uIP will start with an empty IP address and
|
|
+ * the destination IP address of the first incoming "ping" (ICMP echo)
|
|
+ * packet will be used for setting the hosts IP address.
|
|
+ *
|
|
+ * \note This works only if UIP_FIXEDADDR is 0.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifdef UIP_CONF_PINGADDRCONF
|
|
+#define UIP_PINGADDRCONF UIP_CONF_PINGADDRCONF
|
|
+#else /* UIP_CONF_PINGADDRCONF */
|
|
+#define UIP_PINGADDRCONF 0
|
|
+#endif /* UIP_CONF_PINGADDRCONF */
|
|
+
|
|
+/**
|
|
+ * Specifies if the uIP ARP module should be compiled with a fixed
|
|
+ * Ethernet MAC address or not.
|
|
+ *
|
|
+ * If this configuration option is 0, the macro uip_setethaddr() can
|
|
+ * be used to specify the Ethernet address at run-time.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_FIXEDETHADDR 0
|
|
+
|
|
+/** @} */
|
|
+/*------------------------------------------------------------------------------*/
|
|
+/**
|
|
+ * \name IP configuration options
|
|
+ * @{
|
|
+ *
|
|
+ */
|
|
+/**
|
|
+ * The IP TTL (time to live) of IP packets sent by uIP.
|
|
+ *
|
|
+ * This should normally not be changed.
|
|
+ */
|
|
+#define UIP_TTL 64
|
|
+
|
|
+/**
|
|
+ * Turn on support for IP packet reassembly.
|
|
+ *
|
|
+ * uIP supports reassembly of fragmented IP packets. This features
|
|
+ * requires an additonal amount of RAM to hold the reassembly buffer
|
|
+ * and the reassembly code size is approximately 700 bytes. The
|
|
+ * reassembly buffer is of the same size as the uip_buf buffer
|
|
+ * (configured by UIP_BUFSIZE).
|
|
+ *
|
|
+ * \note IP packet reassembly is not heavily tested.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_REASSEMBLY 0
|
|
+
|
|
+/**
|
|
+ * The maximum time an IP fragment should wait in the reassembly
|
|
+ * buffer before it is dropped.
|
|
+ *
|
|
+ */
|
|
+#define UIP_REASS_MAXAGE 40
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/*----------------------------------------------------------------------------*/
|
|
+/**
|
|
+ * \name UDP configuration options
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Toggles wether UDP support should be compiled in or not.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifdef UIP_CONF_UDP
|
|
+#define UIP_UDP UIP_CONF_UDP
|
|
+#else /* UIP_CONF_UDP */
|
|
+#define UIP_UDP 0
|
|
+#endif /* UIP_CONF_UDP */
|
|
+
|
|
+/**
|
|
+ * Toggles if UDP checksums should be used or not.
|
|
+ *
|
|
+ * \note Support for UDP checksums is currently not included in uIP,
|
|
+ * so this option has no function.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifdef UIP_CONF_UDP_CHECKSUMS
|
|
+#define UIP_UDP_CHECKSUMS UIP_CONF_UDP_CHECKSUMS
|
|
+#else
|
|
+#define UIP_UDP_CHECKSUMS 0
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * The maximum amount of concurrent UDP connections.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifdef UIP_CONF_UDP_CONNS
|
|
+#define UIP_UDP_CONNS UIP_CONF_UDP_CONNS
|
|
+#else /* UIP_CONF_UDP_CONNS */
|
|
+#define UIP_UDP_CONNS 10
|
|
+#endif /* UIP_CONF_UDP_CONNS */
|
|
+
|
|
+/**
|
|
+ * The name of the function that should be called when UDP datagrams arrive.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+
|
|
+/** @} */
|
|
+/*------------------------------------------------------------------------------*/
|
|
+/**
|
|
+ * \name TCP configuration options
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Determines if support for opening connections from uIP should be
|
|
+ * compiled in.
|
|
+ *
|
|
+ * If the applications that are running on top of uIP for this project
|
|
+ * do not need to open outgoing TCP connections, this configration
|
|
+ * option can be turned off to reduce the code size of uIP.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_ACTIVE_OPEN 1
|
|
+
|
|
+/**
|
|
+ * The maximum number of simultaneously open TCP connections.
|
|
+ *
|
|
+ * Since the TCP connections are statically allocated, turning this
|
|
+ * configuration knob down results in less RAM used. Each TCP
|
|
+ * connection requires approximatly 30 bytes of memory.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifndef UIP_CONF_MAX_CONNECTIONS
|
|
+#define UIP_CONNS 10
|
|
+#else /* UIP_CONF_MAX_CONNECTIONS */
|
|
+#define UIP_CONNS UIP_CONF_MAX_CONNECTIONS
|
|
+#endif /* UIP_CONF_MAX_CONNECTIONS */
|
|
+
|
|
+/**
|
|
+ * The maximum number of simultaneously listening TCP ports.
|
|
+ *
|
|
+ * Each listening TCP port requires 2 bytes of memory.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifndef UIP_CONF_MAX_LISTENPORTS
|
|
+#define UIP_LISTENPORTS 20
|
|
+#else /* UIP_CONF_MAX_LISTENPORTS */
|
|
+#define UIP_LISTENPORTS UIP_CONF_MAX_LISTENPORTS
|
|
+#endif /* UIP_CONF_MAX_LISTENPORTS */
|
|
+
|
|
+/**
|
|
+ * Determines if support for TCP urgent data notification should be
|
|
+ * compiled in.
|
|
+ *
|
|
+ * Urgent data (out-of-band data) is a rarely used TCP feature that
|
|
+ * very seldom would be required.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_URGDATA 0
|
|
+
|
|
+/**
|
|
+ * The initial retransmission timeout counted in timer pulses.
|
|
+ *
|
|
+ * This should not be changed.
|
|
+ */
|
|
+#define UIP_RTO 3
|
|
+
|
|
+/**
|
|
+ * The maximum number of times a segment should be retransmitted
|
|
+ * before the connection should be aborted.
|
|
+ *
|
|
+ * This should not be changed.
|
|
+ */
|
|
+#define UIP_MAXRTX 8
|
|
+
|
|
+/**
|
|
+ * The maximum number of times a SYN segment should be retransmitted
|
|
+ * before a connection request should be deemed to have been
|
|
+ * unsuccessful.
|
|
+ *
|
|
+ * This should not need to be changed.
|
|
+ */
|
|
+#define UIP_MAXSYNRTX 5
|
|
+
|
|
+/**
|
|
+ * The TCP maximum segment size.
|
|
+ *
|
|
+ * This is should not be to set to more than
|
|
+ * UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN.
|
|
+ */
|
|
+#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCP_IPv4_HLEN)
|
|
+
|
|
+/**
|
|
+ * The size of the advertised receiver's window.
|
|
+ *
|
|
+ * Should be set low (i.e., to the size of the uip_buf buffer) is the
|
|
+ * application is slow to process incoming data, or high (32768 bytes)
|
|
+ * if the application processes data quickly.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifndef UIP_CONF_RECEIVE_WINDOW
|
|
+#define UIP_RECEIVE_WINDOW UIP_TCP_MSS
|
|
+#else
|
|
+#define UIP_RECEIVE_WINDOW UIP_CONF_RECEIVE_WINDOW
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * How long a connection should stay in the TIME_WAIT state.
|
|
+ *
|
|
+ * This configiration option has no real implication, and it should be
|
|
+ * left untouched.
|
|
+ */
|
|
+#define UIP_TIME_WAIT_TIMEOUT 120
|
|
+
|
|
+/** @} */
|
|
+/*------------------------------------------------------------------------------*/
|
|
+/**
|
|
+ * \name ARP configuration options
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * The size of the ARP table.
|
|
+ *
|
|
+ * This option should be set to a larger value if this uIP node will
|
|
+ * have many connections from the local network.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifdef UIP_CONF_ARPTAB_SIZE
|
|
+#define UIP_ARPTAB_SIZE UIP_CONF_ARPTAB_SIZE
|
|
+#else
|
|
+#define UIP_ARPTAB_SIZE 8
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * The maxium age of ARP table entries measured in 10ths of seconds.
|
|
+ *
|
|
+ * An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD
|
|
+ * default).
|
|
+ * Changed the default to 30 which corresponds to 5 minutes (Linux default)
|
|
+ */
|
|
+#define UIP_ARP_MAXAGE 30
|
|
+
|
|
+/** @} */
|
|
+
|
|
+/*----------------------------------------------------------------------------*/
|
|
+
|
|
+/**
|
|
+ * \name General configuration options
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * The size of the uIP packet buffer.
|
|
+ *
|
|
+ * The uIP packet buffer should not be smaller than 60 bytes, and does
|
|
+ * not need to be larger than 1500 bytes. Lower size results in lower
|
|
+ * TCP throughput, larger size results in higher TCP throughput.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifndef UIP_CONF_BUFFER_SIZE
|
|
+#define UIP_BUFSIZE 400
|
|
+#else /* UIP_CONF_BUFFER_SIZE */
|
|
+#define UIP_BUFSIZE UIP_CONF_BUFFER_SIZE
|
|
+#endif /* UIP_CONF_BUFFER_SIZE */
|
|
+
|
|
+/**
|
|
+ * Determines if statistics support should be compiled in.
|
|
+ *
|
|
+ * The statistics is useful for debugging and to show the user.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifndef UIP_CONF_STATISTICS
|
|
+#define UIP_STATISTICS 0
|
|
+#else /* UIP_CONF_STATISTICS */
|
|
+#define UIP_STATISTICS UIP_CONF_STATISTICS
|
|
+#endif /* UIP_CONF_STATISTICS */
|
|
+
|
|
+/**
|
|
+ * Determines if logging of certain events should be compiled in.
|
|
+ *
|
|
+ * This is useful mostly for debugging. The function uip_log()
|
|
+ * must be implemented to suit the architecture of the project, if
|
|
+ * logging is turned on.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifndef UIP_CONF_LOGGING
|
|
+#define UIP_LOGGING 0
|
|
+#else /* UIP_CONF_LOGGING */
|
|
+#define UIP_LOGGING UIP_CONF_LOGGING
|
|
+#endif /* UIP_CONF_LOGGING */
|
|
+
|
|
+/**
|
|
+ * Broadcast support.
|
|
+ *
|
|
+ * This flag configures IP broadcast support. This is useful only
|
|
+ * together with UDP.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ *
|
|
+ */
|
|
+#ifndef UIP_CONF_BROADCAST
|
|
+#define UIP_BROADCAST 0
|
|
+#else /* UIP_CONF_BROADCAST */
|
|
+#define UIP_BROADCAST UIP_CONF_BROADCAST
|
|
+#endif /* UIP_CONF_BROADCAST */
|
|
+
|
|
+/**
|
|
+ * Print out a uIP log message.
|
|
+ *
|
|
+ * This function must be implemented by the module that uses uIP, and
|
|
+ * is called by uIP whenever a log message is generated.
|
|
+ */
|
|
+void uip_log(char *msg);
|
|
+
|
|
+/**
|
|
+ * The link level header length.
|
|
+ *
|
|
+ * This is the offset into the uip_buf where the IP header can be
|
|
+ * found. For Ethernet, this should be set to 14. For SLIP, this
|
|
+ * should be set to 0.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifdef UIP_CONF_LLH_LEN
|
|
+#define UIP_LLH_LEN UIP_CONF_LLH_LEN
|
|
+#else /* UIP_CONF_LLH_LEN */
|
|
+#define UIP_LLH_LEN 14
|
|
+#endif /* UIP_CONF_LLH_LEN */
|
|
+
|
|
+#if 0
|
|
+/** @} */
|
|
+/*------------------------------------------------------------------------------*/
|
|
+/**
|
|
+ * \name CPU architecture configuration
|
|
+ * @{
|
|
+ *
|
|
+ * The CPU architecture configuration is where the endianess of the
|
|
+ * CPU on which uIP is to be run is specified. Most CPUs today are
|
|
+ * little endian, and the most notable exception are the Motorolas
|
|
+ * which are big endian. The BYTE_ORDER macro should be changed to
|
|
+ * reflect the CPU architecture on which uIP is to be run.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * The byte order of the CPU architecture on which uIP is to be run.
|
|
+ *
|
|
+ * This option can be either BIG_ENDIAN (Motorola byte order) or
|
|
+ * LITTLE_ENDIAN (Intel byte order).
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#ifdef UIP_CONF_BYTE_ORDER
|
|
+#define UIP_BYTE_ORDER UIP_CONF_BYTE_ORDER
|
|
+#else /* UIP_CONF_BYTE_ORDER */
|
|
+#define UIP_BYTE_ORDER UIP_LITTLE_ENDIAN
|
|
+#endif /* UIP_CONF_BYTE_ORDER */
|
|
+#endif
|
|
+
|
|
+/** @} */
|
|
+/*------------------------------------------------------------------------------*/
|
|
+
|
|
+/**
|
|
+ * \name Appication specific configurations
|
|
+ * @{
|
|
+ *
|
|
+ * An uIP application is implemented using a single application
|
|
+ * function that is called by uIP whenever a TCP/IP event occurs. The
|
|
+ * name of this function must be registered with uIP at compile time
|
|
+ * using the UIP_APPCALL definition.
|
|
+ *
|
|
+ * uIP applications can store the application state within the
|
|
+ * uip_conn structure by specifying the type of the application
|
|
+ * structure by typedef:ing the type uip_tcp_appstate_t and uip_udp_appstate_t.
|
|
+ *
|
|
+ * The file containing the definitions must be included in the
|
|
+ * uipopt.h file.
|
|
+ *
|
|
+ * The following example illustrates how this can look.
|
|
+ \code
|
|
+
|
|
+void httpd_appcall(void);
|
|
+#define UIP_APPCALL httpd_appcall
|
|
+
|
|
+struct httpd_state {
|
|
+ u8_t state;
|
|
+ u16_t count;
|
|
+ char *dataptr;
|
|
+ char *script;
|
|
+};
|
|
+typedef struct httpd_state uip_tcp_appstate_t
|
|
+ \endcode
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \var #define UIP_APPCALL
|
|
+ *
|
|
+ * The name of the application function that uIP should call in
|
|
+ * response to TCP/IP events.
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \var typedef uip_tcp_appstate_t
|
|
+ *
|
|
+ * The type of the application state that is to be stored in the
|
|
+ * uip_conn structure. This usually is typedef:ed to a struct holding
|
|
+ * application state information.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \var typedef uip_udp_appstate_t
|
|
+ *
|
|
+ * The type of the application state that is to be stored in the
|
|
+ * uip_conn structure. This usually is typedef:ed to a struct holding
|
|
+ * application state information.
|
|
+ */
|
|
+/** @} */
|
|
+/** @} */
|
|
+
|
|
+#endif /* __UIPOPT_H__ */
|
|
diff --git a/iscsiuio/src/unix/.gitignore b/iscsiuio/src/unix/.gitignore
|
|
new file mode 100644
|
|
index 0000000..a2dca2d
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/.gitignore
|
|
@@ -0,0 +1,2 @@
|
|
+build_date.c
|
|
+build_date.h
|
|
diff --git a/iscsiuio/src/unix/Makefile.am b/iscsiuio/src/unix/Makefile.am
|
|
new file mode 100644
|
|
index 0000000..898691d
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/Makefile.am
|
|
@@ -0,0 +1,39 @@
|
|
+SUBDIRS= libs
|
|
+
|
|
+AM_CFLAGS = -I${top_srcdir}/src/uip \
|
|
+ -I${top_srcdir}/src/apps/brcm-iscsi \
|
|
+ -I${top_srcdir}/src/apps/dhcpc \
|
|
+ -I${top_srcdir}/src/unix/libs \
|
|
+ -I${top_srcdir}/../include \
|
|
+ -I${top_srcdir}/../usr
|
|
+
|
|
+sbin_PROGRAMS = iscsiuio
|
|
+
|
|
+iscsiuio_SOURCES = build_date.c \
|
|
+ main.c \
|
|
+ clock-arch.c \
|
|
+ logger.c \
|
|
+ nic.c \
|
|
+ nic_id.c \
|
|
+ nic_vlan.c \
|
|
+ nic_nl.c \
|
|
+ nic_utils.c \
|
|
+ packet.c \
|
|
+ iscsid_ipc.c
|
|
+
|
|
+iscsiuio_CFLAGS = $(AM_CFLAGS) \
|
|
+ $(LIBNL_CFLAGS) \
|
|
+ -DBYTE_ORDER=@ENDIAN@
|
|
+
|
|
+iscsiuio_LDFLAGS= $(AM_LDADD) \
|
|
+ -ldl \
|
|
+ -rdynamic \
|
|
+ $(LIBNL_LIBS) \
|
|
+ -lpthread
|
|
+
|
|
+iscsiuio_LDADD = ${top_srcdir}/src/uip/lib_iscsi_uip.a \
|
|
+ ${top_srcdir}/src/apps/dhcpc/lib_apps_dhcpc.a\
|
|
+ ${top_srcdir}/src/apps/brcm-iscsi/lib_apps_brcm_iscsi.a \
|
|
+ ${top_srcdir}/src/unix/libs/lib_iscsiuio_hw_cnic.a
|
|
+
|
|
+iscsiuio_YFLAGS = -d
|
|
diff --git a/iscsiuio/src/unix/clock-arch.c b/iscsiuio/src/unix/clock-arch.c
|
|
new file mode 100644
|
|
index 0000000..d853101
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/clock-arch.c
|
|
@@ -0,0 +1,54 @@
|
|
+/*
|
|
+ * Copyright (c) 2006, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * Implementation of architecture-specific clock functionality
|
|
+ * \author
|
|
+ * Adam Dunkels <adam@sics.se>
|
|
+ */
|
|
+
|
|
+#include "clock-arch.h"
|
|
+#include <sys/time.h>
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+clock_time_t clock_time(void)
|
|
+{
|
|
+ struct timeval tv;
|
|
+ struct timezone tz;
|
|
+
|
|
+ gettimeofday(&tv, &tz);
|
|
+
|
|
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
diff --git a/iscsiuio/src/unix/clock-arch.h b/iscsiuio/src/unix/clock-arch.h
|
|
new file mode 100644
|
|
index 0000000..888933f
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/clock-arch.h
|
|
@@ -0,0 +1,39 @@
|
|
+/*
|
|
+ * Copyright (c) 2006, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __CLOCK_ARCH_H__
|
|
+#define __CLOCK_ARCH_H__
|
|
+
|
|
+typedef int clock_time_t;
|
|
+#define CLOCK_CONF_SECOND 1000
|
|
+
|
|
+#endif /* __CLOCK_ARCH_H__ */
|
|
diff --git a/iscsiuio/src/unix/iscsid_ipc.c b/iscsiuio/src/unix/iscsid_ipc.c
|
|
new file mode 100644
|
|
index 0000000..3e92d90
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/iscsid_ipc.c
|
|
@@ -0,0 +1,1075 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * iscsi_ipc.c - Generic NIC management/utility functions
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <errno.h>
|
|
+#include <pthread.h>
|
|
+#include <signal.h>
|
|
+#include <string.h>
|
|
+#include <stdio.h>
|
|
+#include <unistd.h>
|
|
+#include <arpa/inet.h>
|
|
+#include <sys/socket.h>
|
|
+#include <sys/time.h>
|
|
+#include <sys/un.h>
|
|
+
|
|
+#define PFX "iscsi_ipc "
|
|
+
|
|
+/* TODO fix me */
|
|
+#define IFNAMSIZ 15
|
|
+
|
|
+#include "nic.h"
|
|
+#include "nic_utils.h"
|
|
+#include "nic_vlan.h"
|
|
+#include "options.h"
|
|
+#include "mgmt_ipc.h"
|
|
+#include "iscsid_ipc.h"
|
|
+#include "uip.h"
|
|
+#include "uip_mgmt_ipc.h"
|
|
+
|
|
+#include "logger.h"
|
|
+#include "uip.h"
|
|
+
|
|
+/* private iscsid options stucture */
|
|
+struct iscsid_options {
|
|
+ int fd;
|
|
+ pthread_t thread;
|
|
+};
|
|
+
|
|
+struct iface_rec_decode {
|
|
+ /* General */
|
|
+ int32_t iface_num;
|
|
+ uint32_t ip_type;
|
|
+
|
|
+ /* IPv4 */
|
|
+ struct in_addr ipv4_addr;
|
|
+ struct in_addr ipv4_subnet_mask;
|
|
+ struct in_addr ipv4_gateway;
|
|
+
|
|
+ /* IPv6 */
|
|
+ struct in6_addr ipv6_addr;
|
|
+ struct in6_addr ipv6_subnet_mask;
|
|
+ uint32_t prefix_len;
|
|
+ struct in6_addr ipv6_linklocal;
|
|
+ struct in6_addr ipv6_router;
|
|
+
|
|
+ uint8_t ipv6_autocfg;
|
|
+ uint8_t linklocal_autocfg;
|
|
+ uint8_t router_autocfg;
|
|
+
|
|
+ uint8_t vlan_state;
|
|
+ uint8_t vlan_priority;
|
|
+ uint16_t vlan_id;
|
|
+
|
|
+#define MIN_MTU_SUPPORT 46
|
|
+#define MAX_MTU_SUPPORT 9000
|
|
+ uint16_t mtu;
|
|
+};
|
|
+
|
|
+
|
|
+/******************************************************************************
|
|
+ * iscsid_ipc Constants
|
|
+ *****************************************************************************/
|
|
+static const char uio_udev_path_template[] = "/dev/uio%d";
|
|
+
|
|
+/******************************************************************************
|
|
+ * Globals
|
|
+ *****************************************************************************/
|
|
+static struct iscsid_options iscsid_opts = {
|
|
+ .fd = INVALID_FD,
|
|
+ .thread = INVALID_THREAD,
|
|
+};
|
|
+
|
|
+/******************************************************************************
|
|
+ * iscsid Functions
|
|
+ *****************************************************************************/
|
|
+
|
|
+static void *enable_nic_thread(void *data)
|
|
+{
|
|
+ nic_t *nic = (nic_t *) data;
|
|
+
|
|
+ prepare_nic_thread(nic);
|
|
+ LOG_INFO(PFX "%s: started NIC enable thread state: 0x%x",
|
|
+ nic->log_name, nic->state)
|
|
+
|
|
+ /* Enable the NIC */
|
|
+ nic_enable(nic);
|
|
+
|
|
+ nic->enable_thread = INVALID_THREAD;
|
|
+
|
|
+ pthread_exit(NULL);
|
|
+}
|
|
+
|
|
+static int decode_cidr(char *in_ipaddr_str, struct iface_rec_decode *ird)
|
|
+{
|
|
+ int rc = 0, i;
|
|
+ char *tmp, *tok;
|
|
+ char ipaddr_str[NI_MAXHOST];
|
|
+ char str[INET6_ADDRSTRLEN];
|
|
+ int keepbits = 0;
|
|
+ struct in_addr ia;
|
|
+ struct in6_addr ia6;
|
|
+
|
|
+ if (strlen(in_ipaddr_str) > NI_MAXHOST)
|
|
+ strncpy(ipaddr_str, in_ipaddr_str, NI_MAXHOST);
|
|
+ else
|
|
+ strcpy(ipaddr_str, in_ipaddr_str);
|
|
+
|
|
+ /* Find the CIDR if any */
|
|
+ tmp = strchr(ipaddr_str, '/');
|
|
+ if (tmp) {
|
|
+ /* CIDR found, now decode, tmpbuf = ip, tmp = netmask */
|
|
+ tmp = ipaddr_str;
|
|
+ tok = strsep(&tmp, "/");
|
|
+ LOG_INFO(PFX "in cidr: bitmask '%s' ip '%s'", tmp, tok);
|
|
+ keepbits = atoi(tmp);
|
|
+ strcpy(ipaddr_str, tok);
|
|
+ }
|
|
+
|
|
+ /* Determine if the IP address passed from the iface file is
|
|
+ * an IPv4 or IPv6 address */
|
|
+ rc = inet_pton(AF_INET, ipaddr_str, &ird->ipv6_addr);
|
|
+ if (rc == 0) {
|
|
+ /* Test to determine if the addres is an IPv6 address */
|
|
+ rc = inet_pton(AF_INET6, ipaddr_str, &ird->ipv6_addr);
|
|
+ if (rc == 0) {
|
|
+ LOG_ERR(PFX "Could not parse IP address: '%s'",
|
|
+ ipaddr_str);
|
|
+ goto out;
|
|
+ }
|
|
+ ird->ip_type = AF_INET6;
|
|
+ if (keepbits > 128) {
|
|
+ LOG_ERR(PFX "CIDR netmask > 128 for IPv6: %d(%s)",
|
|
+ keepbits, tmp);
|
|
+ goto out;
|
|
+ }
|
|
+ if (!keepbits) {
|
|
+ /* Default prefix mask to 64 */
|
|
+ memcpy(&ird->ipv6_subnet_mask.s6_addr, all_zeroes_addr6,
|
|
+ sizeof(struct in6_addr));
|
|
+ ird->prefix_len = 64;
|
|
+ for (i = 0; i < 2; i++)
|
|
+ ird->ipv6_subnet_mask.s6_addr32[i] = 0xffffffff;
|
|
+ goto out;
|
|
+ }
|
|
+ ird->prefix_len = keepbits;
|
|
+ memcpy(&ia6.s6_addr, all_zeroes_addr6, sizeof(struct in6_addr));
|
|
+ for (i = 0; i < 4; i++) {
|
|
+ if (keepbits < 32) {
|
|
+ ia6.s6_addr32[i] = keepbits > 0 ?
|
|
+ 0x00 - (1 << (32 - keepbits)) : 0;
|
|
+ ia6.s6_addr32[i] = htonl(ia6.s6_addr32[i]);
|
|
+ break;
|
|
+ } else
|
|
+ ia6.s6_addr32[i] = 0xFFFFFFFF;
|
|
+ keepbits -= 32;
|
|
+ }
|
|
+ ird->ipv6_subnet_mask = ia6;
|
|
+ if (inet_ntop(AF_INET6, &ia6, str, sizeof(str)))
|
|
+ LOG_INFO(PFX "Using netmask: %s", str);
|
|
+ } else {
|
|
+ ird->ip_type = AF_INET;
|
|
+ rc = inet_pton(AF_INET, ipaddr_str, &ird->ipv4_addr);
|
|
+
|
|
+ if (keepbits > 32) {
|
|
+ LOG_ERR(PFX "CIDR netmask > 32 for IPv4: %d(%s)",
|
|
+ keepbits, tmp);
|
|
+ goto out;
|
|
+ }
|
|
+ ia.s_addr = keepbits > 0 ? 0x00 - (1 << (32 - keepbits)) : 0;
|
|
+ ird->ipv4_subnet_mask.s_addr = htonl(ia.s_addr);
|
|
+ LOG_INFO(PFX "Using netmask: %s",
|
|
+ inet_ntoa(ird->ipv4_subnet_mask));
|
|
+ }
|
|
+out:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int decode_iface(struct iface_rec_decode *ird, struct iface_rec *rec)
|
|
+{
|
|
+ int rc = 0;
|
|
+ char ipaddr_str[NI_MAXHOST];
|
|
+
|
|
+ /* Decodes the rec contents */
|
|
+ memset(ird, 0, sizeof(struct iface_rec_decode));
|
|
+
|
|
+ /* Detect for CIDR notation and strip off the netmask if present */
|
|
+ rc = decode_cidr(rec->ipaddress, ird);
|
|
+ if (rc && !ird->ip_type) {
|
|
+ LOG_ERR(PFX "cidr decode err: rc=%d, ip_type=%d",
|
|
+ rc, ird->ip_type);
|
|
+ /* Can't decode address, just exit */
|
|
+ return rc;
|
|
+ }
|
|
+ rc = 0;
|
|
+ ird->iface_num = rec->iface_num;
|
|
+ ird->vlan_id = rec->vlan_id;
|
|
+ if (rec->iface_num != IFACE_NUM_INVALID) {
|
|
+ ird->mtu = rec->mtu;
|
|
+ if (rec->vlan_id && strcmp(rec->vlan_state, "disable")) {
|
|
+ ird->vlan_state = 1;
|
|
+ ird->vlan_priority = rec->vlan_priority;
|
|
+ ird->vlan_id = rec->vlan_id;
|
|
+ }
|
|
+ if (ird->ip_type == AF_INET6) {
|
|
+ if (!strcmp(rec->ipv6_autocfg, "dhcpv6"))
|
|
+ ird->ipv6_autocfg = IPV6_AUTOCFG_DHCPV6;
|
|
+ else if (!strcmp(rec->ipv6_autocfg, "nd"))
|
|
+ ird->ipv6_autocfg = IPV6_AUTOCFG_ND;
|
|
+ else
|
|
+ ird->ipv6_autocfg = IPV6_AUTOCFG_NOTSPEC;
|
|
+
|
|
+ if (!strcmp(rec->linklocal_autocfg, "auto"))
|
|
+ ird->linklocal_autocfg = IPV6_LL_AUTOCFG_ON;
|
|
+ else if (!strcmp(rec->linklocal_autocfg, "off"))
|
|
+ ird->linklocal_autocfg = IPV6_LL_AUTOCFG_OFF;
|
|
+ else /* default */
|
|
+ ird->linklocal_autocfg = IPV6_LL_AUTOCFG_ON;
|
|
+
|
|
+ if (!strcmp(rec->router_autocfg, "auto"))
|
|
+ ird->router_autocfg = IPV6_RTR_AUTOCFG_ON;
|
|
+ else if (!strcmp(rec->router_autocfg, "off"))
|
|
+ ird->router_autocfg = IPV6_RTR_AUTOCFG_OFF;
|
|
+ else /* default */
|
|
+ ird->router_autocfg = IPV6_RTR_AUTOCFG_ON;
|
|
+
|
|
+ /* Decode the addresses based on the control flags */
|
|
+ /* For DHCP, ignore the IPv6 addr in the iface */
|
|
+ if (ird->ipv6_autocfg == IPV6_AUTOCFG_DHCPV6)
|
|
+ memcpy(&ird->ipv6_addr, all_zeroes_addr6,
|
|
+ sizeof(struct in6_addr));
|
|
+ /* Subnet mask priority: CIDR, then rec */
|
|
+ if (!ird->ipv6_subnet_mask.s6_addr)
|
|
+ inet_pton(AF_INET6, rec->subnet_mask,
|
|
+ &ird->ipv6_subnet_mask);
|
|
+
|
|
+ /* For LL on, ignore the IPv6 addr in the iface */
|
|
+ if (ird->linklocal_autocfg == IPV6_LL_AUTOCFG_OFF) {
|
|
+ if (strlen(rec->ipv6_linklocal) > NI_MAXHOST)
|
|
+ strncpy(ipaddr_str, rec->ipv6_linklocal,
|
|
+ NI_MAXHOST);
|
|
+ else
|
|
+ strcpy(ipaddr_str, rec->ipv6_linklocal);
|
|
+ inet_pton(AF_INET6, ipaddr_str,
|
|
+ &ird->ipv6_linklocal);
|
|
+ }
|
|
+
|
|
+ /* For RTR on, ignore the IPv6 addr in the iface */
|
|
+ if (ird->router_autocfg == IPV6_RTR_AUTOCFG_OFF) {
|
|
+ if (strlen(rec->ipv6_router) > NI_MAXHOST)
|
|
+ strncpy(ipaddr_str, rec->ipv6_router,
|
|
+ NI_MAXHOST);
|
|
+ else
|
|
+ strcpy(ipaddr_str, rec->ipv6_router);
|
|
+ inet_pton(AF_INET6, ipaddr_str,
|
|
+ &ird->ipv6_router);
|
|
+ }
|
|
+ } else {
|
|
+ /* Subnet mask priority: CIDR, rec, default */
|
|
+ if (!ird->ipv4_subnet_mask.s_addr)
|
|
+ inet_pton(AF_INET, rec->subnet_mask,
|
|
+ &ird->ipv4_subnet_mask);
|
|
+ if (!ird->ipv4_subnet_mask.s_addr)
|
|
+ ird->ipv4_subnet_mask.s_addr =
|
|
+ calculate_default_netmask(
|
|
+ ird->ipv4_addr.s_addr);
|
|
+
|
|
+ if (strlen(rec->gateway) > NI_MAXHOST)
|
|
+ strncpy(ipaddr_str, rec->gateway, NI_MAXHOST);
|
|
+ else
|
|
+ strcpy(ipaddr_str, rec->gateway);
|
|
+ inet_pton(AF_INET, ipaddr_str, &ird->ipv4_gateway);
|
|
+ }
|
|
+ } else {
|
|
+ ird->ipv6_autocfg = IPV6_AUTOCFG_NOTUSED;
|
|
+ ird->linklocal_autocfg = IPV6_LL_AUTOCFG_NOTUSED;
|
|
+ ird->router_autocfg = IPV6_RTR_AUTOCFG_NOTUSED;
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int parse_iface(void *arg)
|
|
+{
|
|
+ int rc, i;
|
|
+ nic_t *nic = NULL;
|
|
+ nic_interface_t *nic_iface;
|
|
+ char *transport_name;
|
|
+ size_t transport_name_size;
|
|
+ nic_lib_handle_t *handle;
|
|
+ iscsid_uip_broadcast_t *data;
|
|
+ char ipv6_buf_str[INET6_ADDRSTRLEN];
|
|
+ int request_type = 0;
|
|
+ struct iface_rec *rec;
|
|
+ struct iface_rec_decode ird;
|
|
+ struct in_addr src_match, dst_match;
|
|
+ pthread_attr_t attr;
|
|
+
|
|
+ data = (iscsid_uip_broadcast_t *) arg;
|
|
+ rec = &data->u.iface_rec.rec;
|
|
+ LOG_INFO(PFX "Received request for '%s' to set IP address: '%s' "
|
|
+ "VLAN: '%d'",
|
|
+ rec->netdev,
|
|
+ rec->ipaddress,
|
|
+ rec->vlan_id);
|
|
+
|
|
+ rc = decode_iface(&ird, rec);
|
|
+ if (ird.vlan_id && valid_vlan(ird.vlan_id) == 0) {
|
|
+ LOG_ERR(PFX "Invalid VLAN tag: %d", ird.vlan_id);
|
|
+ rc = -EIO;
|
|
+ goto early_exit;
|
|
+ }
|
|
+ if (rc && !ird.ip_type) {
|
|
+ LOG_ERR(PFX "iface err: rc=%d, ip_type=%d", rc, ird.ip_type);
|
|
+ goto early_exit;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < 10; i++) {
|
|
+ struct timespec sleep_req, sleep_rem;
|
|
+
|
|
+ if (pthread_mutex_trylock(&nic_list_mutex) == 0)
|
|
+ break;
|
|
+
|
|
+ sleep_req.tv_sec = 0;
|
|
+ sleep_req.tv_nsec = 100000;
|
|
+ nanosleep(&sleep_req, &sleep_rem);
|
|
+ }
|
|
+
|
|
+ if (i >= 10) {
|
|
+ LOG_WARN(PFX "Could not acquire nic_list_mutex lock");
|
|
+ rc = -EIO;
|
|
+ goto early_exit;
|
|
+ }
|
|
+
|
|
+ /* nic_list_mutex locked */
|
|
+
|
|
+ /* Check if we can find the NIC device using the netdev
|
|
+ * name */
|
|
+ rc = from_netdev_name_find_nic(rec->netdev, &nic);
|
|
+
|
|
+ if (rc != 0) {
|
|
+ LOG_WARN(PFX "Couldn't find NIC: %s, creating an instance",
|
|
+ rec->netdev);
|
|
+
|
|
+ nic = nic_init();
|
|
+ if (nic == NULL) {
|
|
+ LOG_ERR(PFX "Couldn't allocate space for NIC %s",
|
|
+ rec->netdev);
|
|
+
|
|
+ rc = -ENOMEM;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ strncpy(nic->eth_device_name,
|
|
+ rec->netdev,
|
|
+ sizeof(nic->eth_device_name));
|
|
+ nic->config_device_name = nic->eth_device_name;
|
|
+ nic->log_name = nic->eth_device_name;
|
|
+
|
|
+ if (nic_fill_name(nic) != 0) {
|
|
+ free(nic);
|
|
+ rc = -EIO;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ nic_add(nic);
|
|
+ } else {
|
|
+ LOG_INFO(PFX " %s, using existing NIC",
|
|
+ rec->netdev);
|
|
+ }
|
|
+
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ if (nic->flags & NIC_GOING_DOWN) {
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ rc = -EIO;
|
|
+ LOG_INFO(PFX "nic->flags GOING DOWN");
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ /* If we retry too many times allow iscsid to timeout */
|
|
+ if (nic->pending_count > 1000) {
|
|
+ nic->pending_count = 0;
|
|
+ nic->flags &= ~NIC_ENABLED_PENDING;
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ LOG_WARN(PFX "%s: pending count exceeded 1000", nic->log_name);
|
|
+
|
|
+ rc = 0;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ if (nic->flags & NIC_ENABLED_PENDING) {
|
|
+ struct timespec sleep_req, sleep_rem;
|
|
+
|
|
+ nic->pending_count++;
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ sleep_req.tv_sec = 0;
|
|
+ sleep_req.tv_nsec = 100000;
|
|
+ nanosleep(&sleep_req, &sleep_rem);
|
|
+
|
|
+ LOG_INFO(PFX "%s: enabled pending", nic->log_name);
|
|
+
|
|
+ rc = -EAGAIN;
|
|
+ goto done;
|
|
+ }
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ prepare_library(nic);
|
|
+
|
|
+ /* Sanity Check to ensure the transport names are the same */
|
|
+ handle = nic->nic_library;
|
|
+ if (handle != NULL) {
|
|
+ (*handle->ops->lib_ops.get_transport_name) (&transport_name,
|
|
+ &transport_name_size);
|
|
+
|
|
+ if (strncmp(transport_name,
|
|
+ rec->transport_name,
|
|
+ transport_name_size) != 0) {
|
|
+ LOG_ERR(PFX "%s Transport name is not equal "
|
|
+ "expected: %s got: %s",
|
|
+ nic->log_name,
|
|
+ rec->transport_name,
|
|
+ transport_name);
|
|
+ }
|
|
+ } else {
|
|
+ LOG_ERR(PFX "%s Couldn't find nic library ", nic->log_name);
|
|
+ rc = -EIO;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "%s library set using transport_name %s",
|
|
+ nic->log_name, transport_name);
|
|
+
|
|
+ /* Determine how to configure the IP address */
|
|
+ if (ird.ip_type == AF_INET) {
|
|
+ if (memcmp(&ird.ipv4_addr,
|
|
+ all_zeroes_addr4, sizeof(uip_ip4addr_t)) == 0) {
|
|
+ LOG_INFO(PFX "%s: requesting configuration using DHCP",
|
|
+ nic->log_name);
|
|
+ request_type = IPV4_CONFIG_DHCP;
|
|
+ } else {
|
|
+ LOG_INFO(PFX "%s: requesting configuration using "
|
|
+ "static IP address", nic->log_name);
|
|
+ request_type = IPV4_CONFIG_STATIC;
|
|
+ }
|
|
+ } else if (ird.ip_type == AF_INET6) {
|
|
+ /* For the new 872_22, check ipv6_autocfg for DHCPv6 instead */
|
|
+ switch (ird.ipv6_autocfg) {
|
|
+ case IPV6_AUTOCFG_DHCPV6:
|
|
+ request_type = IPV6_CONFIG_DHCP;
|
|
+ break;
|
|
+ case IPV6_AUTOCFG_ND:
|
|
+ request_type = IPV6_CONFIG_STATIC;
|
|
+ break;
|
|
+ case IPV6_AUTOCFG_NOTSPEC:
|
|
+ /* Treat NOTSPEC the same as NOTUSED for now */
|
|
+ case IPV6_AUTOCFG_NOTUSED:
|
|
+ /* For 871 */
|
|
+ default:
|
|
+ /* Just the IP address to determine */
|
|
+ if (memcmp(&ird.ipv6_addr,
|
|
+ all_zeroes_addr6,
|
|
+ sizeof(struct in6_addr)) == 0)
|
|
+ request_type = IPV6_CONFIG_DHCP;
|
|
+ else
|
|
+ request_type = IPV6_CONFIG_STATIC;
|
|
+ }
|
|
+ } else {
|
|
+ LOG_ERR(PFX "%s: unknown ip_type to configure: 0x%x",
|
|
+ nic->log_name, ird.ip_type);
|
|
+
|
|
+ rc = -EIO;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+
|
|
+ nic_iface = nic_find_nic_iface(nic, ird.ip_type, ird.vlan_id,
|
|
+ ird.iface_num, request_type);
|
|
+
|
|
+ if (nic->flags & NIC_PATHREQ_WAIT) {
|
|
+ if (!nic_iface ||
|
|
+ !(nic_iface->flags & NIC_IFACE_PATHREQ_WAIT)) {
|
|
+ int pathreq_wait;
|
|
+
|
|
+ if (nic_iface &&
|
|
+ (nic_iface->flags & NIC_IFACE_PATHREQ_WAIT2))
|
|
+ pathreq_wait = 12;
|
|
+ else
|
|
+ pathreq_wait = 10;
|
|
+
|
|
+ if (nic->pathreq_pending_count < pathreq_wait) {
|
|
+ struct timespec sleep_req, sleep_rem;
|
|
+
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ nic->pathreq_pending_count++;
|
|
+ sleep_req.tv_sec = 0;
|
|
+ sleep_req.tv_nsec = 100000;
|
|
+ nanosleep(&sleep_req, &sleep_rem);
|
|
+ /* Somebody else is waiting for PATH_REQ */
|
|
+ LOG_INFO(PFX "%s: path req pending cnt=%d",
|
|
+ nic->log_name,
|
|
+ nic->pathreq_pending_count);
|
|
+ rc = -EAGAIN;
|
|
+ goto done;
|
|
+ } else {
|
|
+ nic->pathreq_pending_count = 0;
|
|
+ LOG_DEBUG(PFX "%s: path req pending cnt "
|
|
+ "exceeded!", nic->log_name);
|
|
+ /* Allow to fall thru */
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ nic->flags |= NIC_PATHREQ_WAIT;
|
|
+
|
|
+ /* Create the network interface if it doesn't exist */
|
|
+ if (nic_iface == NULL) {
|
|
+ LOG_DEBUG(PFX "%s couldn't find interface with "
|
|
+ "ip_type: 0x%x creating it",
|
|
+ nic->log_name, ird.ip_type);
|
|
+ nic_iface = nic_iface_init();
|
|
+
|
|
+ if (nic_iface == NULL) {
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ LOG_ERR(PFX "%s Couldn't allocate "
|
|
+ "interface with ip_type: 0x%x",
|
|
+ nic->log_name, ird.ip_type);
|
|
+ goto done;
|
|
+ }
|
|
+ nic_iface->protocol = ird.ip_type;
|
|
+ nic_iface->vlan_id = ird.vlan_id;
|
|
+ nic_iface->vlan_priority = ird.vlan_priority;
|
|
+ if (ird.mtu >= MIN_MTU_SUPPORT && ird.mtu <= MAX_MTU_SUPPORT)
|
|
+ nic_iface->mtu = ird.mtu;
|
|
+ nic_iface->iface_num = ird.iface_num;
|
|
+ nic_iface->request_type = request_type;
|
|
+ nic_add_nic_iface(nic, nic_iface);
|
|
+
|
|
+ persist_all_nic_iface(nic);
|
|
+
|
|
+ LOG_INFO(PFX "%s: created network interface",
|
|
+ nic->log_name);
|
|
+ } else {
|
|
+ /* Move the nic_iface to the front */
|
|
+ set_nic_iface(nic, nic_iface);
|
|
+ LOG_INFO(PFX "%s: using existing network interface",
|
|
+ nic->log_name);
|
|
+ }
|
|
+
|
|
+ nic_iface->flags |= NIC_IFACE_PATHREQ_WAIT1;
|
|
+ if (nic->nl_process_thread == INVALID_THREAD) {
|
|
+ pthread_attr_init(&attr);
|
|
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
+ rc = pthread_create(&nic->nl_process_thread, &attr,
|
|
+ nl_process_handle_thread, nic);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR(PFX "%s: Could not create NIC NL "
|
|
+ "processing thread [%s]", nic->log_name,
|
|
+ strerror(rc));
|
|
+ nic->nl_process_thread = INVALID_THREAD;
|
|
+ /* Reset both WAIT flags */
|
|
+ nic_iface->flags &= ~NIC_IFACE_PATHREQ_WAIT;
|
|
+ nic->flags &= ~NIC_PATHREQ_WAIT;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ if (nic_iface->ustack.ip_config == request_type) {
|
|
+ /* Same request_type, check for STATIC address change */
|
|
+ if (request_type == IPV4_CONFIG_STATIC) {
|
|
+ if (memcmp(nic_iface->ustack.hostaddr, &ird.ipv4_addr,
|
|
+ sizeof(struct in_addr)))
|
|
+ goto reacquire;
|
|
+ } else if (request_type == IPV6_CONFIG_STATIC) {
|
|
+ if (memcmp(nic_iface->ustack.hostaddr6, &ird.ipv6_addr,
|
|
+ sizeof(struct in6_addr)))
|
|
+ goto reacquire;
|
|
+ else
|
|
+ inet_ntop(AF_INET6, &ird.ipv6_addr,
|
|
+ ipv6_buf_str,
|
|
+ sizeof(ipv6_buf_str));
|
|
+ }
|
|
+ LOG_INFO(PFX "%s: IP configuration didn't change using 0x%x",
|
|
+ nic->log_name, nic_iface->ustack.ip_config);
|
|
+ /* No need to acquire the IP address */
|
|
+ inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str,
|
|
+ sizeof(ipv6_buf_str));
|
|
+
|
|
+ goto enable_nic;
|
|
+ }
|
|
+reacquire:
|
|
+ /* Config needs to re-acquire for this nic_iface */
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ nic_iface->flags |= NIC_IFACE_ACQUIRE;
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ /* Disable the nic loop from further processing, upon returned,
|
|
+ the nic_iface should be cleared */
|
|
+ nic_disable(nic, 0);
|
|
+
|
|
+ /* Check to see if this is using DHCP or if this is
|
|
+ * a static IPv4 address. This is done by checking
|
|
+ * if the IP address is equal to 0.0.0.0. If it is
|
|
+ * then the user has specified to use DHCP. If not
|
|
+ * then the user has spcicied to use a static IP address
|
|
+ * an the default netmask will be used */
|
|
+ switch (request_type) {
|
|
+ case IPV4_CONFIG_DHCP:
|
|
+ memset(nic_iface->ustack.hostaddr, 0, sizeof(struct in_addr));
|
|
+ LOG_INFO(PFX "%s: configuring using DHCP", nic->log_name);
|
|
+ nic_iface->ustack.ip_config = IPV4_CONFIG_DHCP;
|
|
+ break;
|
|
+
|
|
+ case IPV4_CONFIG_STATIC:
|
|
+ memcpy(nic_iface->ustack.hostaddr, &ird.ipv4_addr,
|
|
+ sizeof(struct in_addr));
|
|
+ LOG_INFO(PFX "%s: configuring using static IP "
|
|
+ "IPv4 address :%s ",
|
|
+ nic->log_name, inet_ntoa(ird.ipv4_addr));
|
|
+
|
|
+ if (ird.ipv4_subnet_mask.s_addr)
|
|
+ memcpy(nic_iface->ustack.netmask,
|
|
+ &ird.ipv4_subnet_mask, sizeof(struct in_addr));
|
|
+ LOG_INFO(PFX " netmask: %s", inet_ntoa(ird.ipv4_subnet_mask));
|
|
+
|
|
+ /* Default route */
|
|
+ if (ird.ipv4_gateway.s_addr) {
|
|
+ /* Check for validity */
|
|
+ src_match.s_addr = ird.ipv4_addr.s_addr &
|
|
+ ird.ipv4_subnet_mask.s_addr;
|
|
+ dst_match.s_addr = ird.ipv4_gateway.s_addr &
|
|
+ ird.ipv4_subnet_mask.s_addr;
|
|
+ if (src_match.s_addr == dst_match.s_addr)
|
|
+ memcpy(nic_iface->ustack.default_route_addr,
|
|
+ &ird.ipv4_gateway,
|
|
+ sizeof(struct in_addr));
|
|
+ }
|
|
+ nic_iface->ustack.ip_config = IPV4_CONFIG_STATIC;
|
|
+ break;
|
|
+
|
|
+ case IPV6_CONFIG_DHCP:
|
|
+ memset(nic_iface->ustack.hostaddr6, 0,
|
|
+ sizeof(struct in6_addr));
|
|
+ nic_iface->ustack.prefix_len = ird.prefix_len;
|
|
+ nic_iface->ustack.ipv6_autocfg = ird.ipv6_autocfg;
|
|
+ nic_iface->ustack.linklocal_autocfg = ird.linklocal_autocfg;
|
|
+ nic_iface->ustack.router_autocfg = ird.router_autocfg;
|
|
+
|
|
+ if (memcmp(&ird.ipv6_subnet_mask, all_zeroes_addr6,
|
|
+ sizeof(struct in6_addr)))
|
|
+ memcpy(nic_iface->ustack.netmask6,
|
|
+ &ird.ipv6_subnet_mask, sizeof(struct in6_addr));
|
|
+ if (ird.linklocal_autocfg == IPV6_LL_AUTOCFG_OFF)
|
|
+ memcpy(nic_iface->ustack.linklocal6,
|
|
+ &ird.ipv6_linklocal, sizeof(struct in6_addr));
|
|
+ if (ird.router_autocfg == IPV6_RTR_AUTOCFG_OFF)
|
|
+ memcpy(nic_iface->ustack.default_route_addr6,
|
|
+ &ird.ipv6_router, sizeof(struct in6_addr));
|
|
+ inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str,
|
|
+ sizeof(ipv6_buf_str));
|
|
+ LOG_INFO(PFX "%s: configuring using DHCPv6",
|
|
+ nic->log_name);
|
|
+ nic_iface->ustack.ip_config = IPV6_CONFIG_DHCP;
|
|
+ break;
|
|
+
|
|
+ case IPV6_CONFIG_STATIC:
|
|
+ memcpy(nic_iface->ustack.hostaddr6, &ird.ipv6_addr,
|
|
+ sizeof(struct in6_addr));
|
|
+ nic_iface->ustack.prefix_len = ird.prefix_len;
|
|
+ nic_iface->ustack.ipv6_autocfg = ird.ipv6_autocfg;
|
|
+ nic_iface->ustack.linklocal_autocfg = ird.linklocal_autocfg;
|
|
+ nic_iface->ustack.router_autocfg = ird.router_autocfg;
|
|
+
|
|
+ if (memcmp(&ird.ipv6_subnet_mask, all_zeroes_addr6,
|
|
+ sizeof(struct in6_addr)))
|
|
+ memcpy(nic_iface->ustack.netmask6,
|
|
+ &ird.ipv6_subnet_mask, sizeof(struct in6_addr));
|
|
+ if (ird.linklocal_autocfg == IPV6_LL_AUTOCFG_OFF)
|
|
+ memcpy(nic_iface->ustack.linklocal6,
|
|
+ &ird.ipv6_linklocal, sizeof(struct in6_addr));
|
|
+ if (ird.router_autocfg == IPV6_RTR_AUTOCFG_OFF)
|
|
+ memcpy(nic_iface->ustack.default_route_addr6,
|
|
+ &ird.ipv6_router, sizeof(struct in6_addr));
|
|
+
|
|
+ inet_ntop(AF_INET6, &ird.ipv6_addr, ipv6_buf_str,
|
|
+ sizeof(ipv6_buf_str));
|
|
+ LOG_INFO(PFX "%s: configuring using static IP "
|
|
+ "IPv6 address: '%s'", nic->log_name, ipv6_buf_str);
|
|
+
|
|
+ nic_iface->ustack.ip_config = IPV6_CONFIG_STATIC;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ LOG_INFO(PFX "%s: Unknown request type: 0x%x",
|
|
+ nic->log_name, request_type);
|
|
+
|
|
+ }
|
|
+
|
|
+enable_nic:
|
|
+ switch (nic->state) {
|
|
+ case NIC_STOPPED:
|
|
+ /* This thread will be thrown away when completed */
|
|
+ if (nic->enable_thread != INVALID_THREAD) {
|
|
+ rc = pthread_cancel(nic->enable_thread);
|
|
+ if (rc != 0) {
|
|
+ LOG_INFO(PFX "%s: failed to cancel enable NIC "
|
|
+ "thread\n", nic->log_name);
|
|
+ goto eagain;
|
|
+ }
|
|
+ }
|
|
+ pthread_attr_init(&attr);
|
|
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
+ rc = pthread_create(&nic->enable_thread, &attr,
|
|
+ enable_nic_thread, (void *)nic);
|
|
+ if (rc != 0)
|
|
+ LOG_WARN(PFX "%s: failed starting enable NIC thread\n",
|
|
+ nic->log_name);
|
|
+eagain:
|
|
+ rc = -EAGAIN;
|
|
+ break;
|
|
+
|
|
+ case NIC_RUNNING:
|
|
+ LOG_INFO(PFX "%s: NIC already enabled "
|
|
+ "flags: 0x%x state: 0x%x\n",
|
|
+ nic->log_name, nic->flags, nic->state);
|
|
+ rc = 0;
|
|
+ break;
|
|
+ default:
|
|
+ LOG_INFO(PFX "%s: NIC enable still in progress "
|
|
+ "flags: 0x%x state: 0x%x\n",
|
|
+ nic->log_name, nic->flags, nic->state);
|
|
+ rc = -EAGAIN;
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "ISCSID_UIP_IPC_GET_IFACE: command: %x "
|
|
+ "name: %s, netdev: %s ipaddr: %s vlan: %d transport_name:%s",
|
|
+ data->header.command, rec->name, rec->netdev,
|
|
+ (ird.ip_type == AF_INET) ? inet_ntoa(ird.ipv4_addr) :
|
|
+ ipv6_buf_str,
|
|
+ ird.vlan_id, rec->transport_name);
|
|
+
|
|
+done:
|
|
+ pthread_mutex_unlock(&nic_list_mutex);
|
|
+
|
|
+early_exit:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * process_iscsid_broadcast() - This function is used to process the
|
|
+ * broadcast messages from iscsid
|
|
+ */
|
|
+int process_iscsid_broadcast(int s2)
|
|
+{
|
|
+ int rc = 0;
|
|
+ iscsid_uip_broadcast_t *data;
|
|
+ iscsid_uip_rsp_t rsp;
|
|
+ FILE *fd;
|
|
+ size_t size;
|
|
+ iscsid_uip_cmd_e cmd;
|
|
+ uint32_t payload_len;
|
|
+
|
|
+ fd = fdopen(s2, "r+");
|
|
+ if (fd == NULL) {
|
|
+ LOG_ERR(PFX "Couldn't open file descriptor: %d(%s)",
|
|
+ errno, strerror(errno));
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* This will be freed by parse_iface_thread() */
|
|
+ data = (iscsid_uip_broadcast_t *) calloc(1, sizeof(*data));
|
|
+ if (data == NULL) {
|
|
+ LOG_ERR(PFX "Couldn't allocate memory for iface data");
|
|
+ rc = -ENOMEM;
|
|
+ goto error;
|
|
+ }
|
|
+ memset(data, 0, sizeof(*data));
|
|
+
|
|
+ size = fread(data, sizeof(iscsid_uip_broadcast_header_t), 1, fd);
|
|
+ if (!size) {
|
|
+ LOG_ERR(PFX "Could not read request: %d(%s)",
|
|
+ errno, strerror(errno));
|
|
+ rc = ferror(fd);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ cmd = data->header.command;
|
|
+ payload_len = data->header.payload_len;
|
|
+
|
|
+ LOG_DEBUG(PFX "recv iscsid request: cmd: %d, payload_len: %d",
|
|
+ cmd, payload_len);
|
|
+
|
|
+ size = fread(&data->u.iface_rec, payload_len, 1, fd);
|
|
+ if (!size) {
|
|
+ LOG_ERR(PFX "Could not read data: %d(%s)",
|
|
+ errno, strerror(errno));
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ switch (cmd) {
|
|
+ case ISCSID_UIP_IPC_GET_IFACE:
|
|
+ rc = parse_iface(data);
|
|
+ switch (rc) {
|
|
+ case 0:
|
|
+ rsp.command = cmd;
|
|
+ rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_UP;
|
|
+ break;
|
|
+ case -EAGAIN:
|
|
+ rsp.command = cmd;
|
|
+ rsp.err = ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING;
|
|
+ break;
|
|
+ default:
|
|
+ rsp.command = cmd;
|
|
+ rsp.err = ISCSID_UIP_MGMT_IPC_ERR;
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ default:
|
|
+ LOG_WARN(PFX "Unknown iscsid broadcast command: %x",
|
|
+ data->header.command);
|
|
+
|
|
+ /* Send a response back to iscsid to tell it the
|
|
+ operation succeeded */
|
|
+ rsp.command = cmd;
|
|
+ rsp.err = ISCSID_UIP_MGMT_IPC_OK;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ size = fwrite(&rsp, sizeof(rsp), 1, fd);
|
|
+ if (size == -1) {
|
|
+ LOG_ERR(PFX "Could not send response: %d(%s)",
|
|
+ errno, strerror(errno));
|
|
+ rc = ferror(fd);
|
|
+ }
|
|
+
|
|
+error:
|
|
+ free(data);
|
|
+ fclose(fd);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static void iscsid_loop_close(void *arg)
|
|
+{
|
|
+ close(iscsid_opts.fd);
|
|
+
|
|
+ LOG_INFO(PFX "iSCSI daemon socket closed");
|
|
+}
|
|
+
|
|
+/**
|
|
+ * iscsid_loop() - This is the function which will process the broadcast
|
|
+ * messages from iscsid
|
|
+ *
|
|
+ */
|
|
+static void *iscsid_loop(void *arg)
|
|
+{
|
|
+ int rc;
|
|
+ sigset_t set;
|
|
+
|
|
+ pthread_cleanup_push(iscsid_loop_close, arg);
|
|
+
|
|
+ sigfillset(&set);
|
|
+ rc = pthread_sigmask(SIG_BLOCK, &set, NULL);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR(PFX
|
|
+ "Couldn't set signal mask for the iscisd listening "
|
|
+ "thread");
|
|
+ }
|
|
+
|
|
+ LOG_DEBUG(PFX "Started iscsid listening thread");
|
|
+
|
|
+ while (1) {
|
|
+ struct sockaddr_un remote;
|
|
+ socklen_t sock_len;
|
|
+ int s2;
|
|
+
|
|
+ LOG_DEBUG(PFX "Waiting for iscsid command");
|
|
+
|
|
+ sock_len = sizeof(remote);
|
|
+ s2 = accept(iscsid_opts.fd,
|
|
+ (struct sockaddr *)&remote, &sock_len);
|
|
+ if (s2 == -1) {
|
|
+ if (errno == EAGAIN) {
|
|
+ LOG_DEBUG("Got EAGAIN from accept");
|
|
+ sleep(1);
|
|
+ continue;
|
|
+ } else if (errno == EINTR) {
|
|
+ LOG_DEBUG("Got EINTR from accept");
|
|
+ /* The program is terminating, time to exit */
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ LOG_ERR(PFX "Could not accept: %d(%s)",
|
|
+ s2, strerror(errno));
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ process_iscsid_broadcast(s2);
|
|
+ close(s2);
|
|
+ }
|
|
+
|
|
+ pthread_cleanup_pop(0);
|
|
+
|
|
+ LOG_ERR(PFX "exit iscsid listening thread");
|
|
+
|
|
+ pthread_exit(NULL);
|
|
+}
|
|
+
|
|
+#define SD_SOCKET_FDS_START 3
|
|
+
|
|
+static int ipc_systemd(void)
|
|
+{
|
|
+ char *env;
|
|
+
|
|
+ env = getenv("LISTEN_PID");
|
|
+
|
|
+ if (!env || (strtoul(env, NULL, 10) != getpid()))
|
|
+ return -EINVAL;
|
|
+
|
|
+ env = getenv("LISTEN_FDS");
|
|
+
|
|
+ if (!env)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (strtoul(env, NULL, 10) != 1) {
|
|
+ LOG_ERR("Did not receive exactly one IPC socket from systemd");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return SD_SOCKET_FDS_START;
|
|
+}
|
|
+
|
|
+/******************************************************************************
|
|
+ * Initialize/Cleanup routines
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * iscsid_init() - This function will setup the thread used to listen for
|
|
+ * the iscsid broadcast messages
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+int iscsid_init()
|
|
+{
|
|
+ int rc, addr_len;
|
|
+ struct sockaddr_un addr;
|
|
+
|
|
+ iscsid_opts.fd = ipc_systemd();
|
|
+ if (iscsid_opts.fd >= 0)
|
|
+ return 0;
|
|
+
|
|
+ iscsid_opts.fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
|
+ if (iscsid_opts.fd < 0) {
|
|
+ LOG_ERR(PFX "Can not create IPC socket");
|
|
+ return iscsid_opts.fd;
|
|
+ }
|
|
+
|
|
+ addr_len = offsetof(struct sockaddr_un, sun_path) + strlen(ISCSID_UIP_NAMESPACE) + 1;
|
|
+
|
|
+ memset(&addr, 0, sizeof(addr));
|
|
+ addr.sun_family = AF_LOCAL;
|
|
+ memcpy((char *)&addr.sun_path + 1, ISCSID_UIP_NAMESPACE,
|
|
+ strlen(ISCSID_UIP_NAMESPACE));
|
|
+
|
|
+ rc = bind(iscsid_opts.fd, (struct sockaddr *)&addr, addr_len);
|
|
+ if (rc < 0) {
|
|
+ LOG_ERR(PFX "Can not bind IPC socket: %s", strerror(errno));
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ rc = listen(iscsid_opts.fd, 32);
|
|
+ if (rc < 0) {
|
|
+ LOG_ERR(PFX "Can not listen IPC socket: %s", strerror(errno));
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+error:
|
|
+ close(iscsid_opts.fd);
|
|
+ iscsid_opts.fd = INVALID_FD;
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * iscsid_start() - This function will start the thread used to listen for
|
|
+ * the iscsid broadcast messages
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+int iscsid_start()
|
|
+{
|
|
+ pthread_attr_t attr;
|
|
+ int rc;
|
|
+
|
|
+ pthread_attr_init(&attr);
|
|
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
+ rc = pthread_create(&iscsid_opts.thread, &attr, iscsid_loop, NULL);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR(PFX "Could not start iscsid listening thread rc=%d",
|
|
+ rc);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ close(iscsid_opts.fd);
|
|
+ iscsid_opts.fd = INVALID_FD;
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * iscsid_cleanup() - This is called when stoping the thread listening
|
|
+ * for the iscsid broadcast messages
|
|
+ */
|
|
+void iscsid_cleanup()
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ if (iscsid_opts.fd != INVALID_FD) {
|
|
+ rc = pthread_cancel(iscsid_opts.thread);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR("Could not cancel iscsid listening thread: %s",
|
|
+ strerror(rc));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "iscsid listening thread has shutdown");
|
|
+}
|
|
diff --git a/iscsiuio/src/unix/iscsid_ipc.h b/iscsiuio/src/unix/iscsid_ipc.h
|
|
new file mode 100644
|
|
index 0000000..60bcd71
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/iscsid_ipc.h
|
|
@@ -0,0 +1,52 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * iscsid_ipc.h: Generic NIC management/utility functions
|
|
+ *
|
|
+ */
|
|
+#ifndef __ISCSID_IPC_H__
|
|
+#define __ISCSID_IPC_H__
|
|
+
|
|
+#include "uip.h"
|
|
+#include "mgmt_ipc.h"
|
|
+
|
|
+enum mgmt_ipc_err iscsid_connect(int *fd);
|
|
+int iscsid_get_ipaddr(int fd, uip_ip4addr_t *ipaddr);
|
|
+
|
|
+int iscsid_init();
|
|
+int iscsid_start();
|
|
+void iscsid_cleanup();
|
|
+
|
|
+#endif /* __ISCSID_IPC_H__ */
|
|
diff --git a/iscsiuio/src/unix/libs/Makefile.am b/iscsiuio/src/unix/libs/Makefile.am
|
|
new file mode 100644
|
|
index 0000000..890415f
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/libs/Makefile.am
|
|
@@ -0,0 +1,13 @@
|
|
+AM_CFLAGS = -I${top_srcdir}/src/uip \
|
|
+ -I${top_srcdir}/src/unix \
|
|
+ -I${top_srcdir}/src/unix/libs \
|
|
+ -I${top_srcdir}/src/apps/dhcpc \
|
|
+ -I${top_srcdir}/../include \
|
|
+ -I${top_srcdir}/../usr
|
|
+
|
|
+noinst_LIBRARIES = lib_iscsiuio_hw_cnic.a
|
|
+
|
|
+lib_iscsiuio_hw_cnic_a_SOURCES = ../build_date.c \
|
|
+ cnic.c \
|
|
+ bnx2.c \
|
|
+ bnx2x.c
|
|
diff --git a/iscsiuio/src/unix/libs/bnx2.c b/iscsiuio/src/unix/libs/bnx2.c
|
|
new file mode 100644
|
|
index 0000000..937336e
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/libs/bnx2.c
|
|
@@ -0,0 +1,1165 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * bnx2.c - bnx2 user space driver
|
|
+ *
|
|
+ */
|
|
+#include <errno.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <arpa/inet.h>
|
|
+#include <sys/mman.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/user.h>
|
|
+#include <fcntl.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+#include "config.h"
|
|
+
|
|
+#include "build_date.h"
|
|
+#include "bnx2.h"
|
|
+#include "cnic.h"
|
|
+#include "logger.h"
|
|
+#include "nic.h"
|
|
+#include "nic_utils.h"
|
|
+#include "options.h"
|
|
+
|
|
+#define PFX "bnx2 "
|
|
+
|
|
+/* Foward struct declarations */
|
|
+struct nic_ops bnx2_op;
|
|
+
|
|
+/*******************************************************************************
|
|
+ * NIC Library Strings
|
|
+ ******************************************************************************/
|
|
+static const char library_name[] = "bnx2";
|
|
+static const char library_version[] = PACKAGE_VERSION;
|
|
+static const char library_uio_name[] = "bnx2_cnic";
|
|
+
|
|
+/* The name that should be returned from /sys/class/uio/uio0/name */
|
|
+static const char cnic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name";
|
|
+static const char cnic_uio_sysfs_name[] = "bnx2_cnic";
|
|
+
|
|
+/*******************************************************************************
|
|
+ * String constants used to display human readable adapter name
|
|
+ ******************************************************************************/
|
|
+static const char brcm_5706C[] = "QLogic NetXtreme II BCM5706 1000Base-T";
|
|
+static const char hp_NC370T[] =
|
|
+ "HP NC370T Multifunction Gigabit Server Adapter";
|
|
+static const char hp_NC370I[] =
|
|
+ "HP NC370i Multifunction Gigabit Server Adapter";
|
|
+static const char brcm_5706S[] = "QLogic NetXtreme II BCM5706 1000Base-SX";
|
|
+static const char hp_NC370F[] =
|
|
+ "HP NC370F Multifunction Gigabit Server Adapter";
|
|
+static const char brcm_5708C[] = "QLogic NetXtreme II BCM5708 1000Base-T";
|
|
+static const char brcm_5708S[] = "QLogic NetXtreme II BCM5708 1000Base-SX";
|
|
+static const char brcm_5709C[] = "QLogic NetXtreme II BCM5709 1000Base-T";
|
|
+static const char brcm_5709S[] = "QLogic NetXtreme II BCM5709 1000Base-SX";
|
|
+static const char brcm_5716C[] = "QLogic NetXtreme II BCM5716 1000Base-T";
|
|
+static const char brcm_5716S[] = "QLogic NetXtreme II BCM5716 1000Base-SX";
|
|
+
|
|
+/*******************************************************************************
|
|
+ * PCI ID constants
|
|
+ ******************************************************************************/
|
|
+#define PCI_VENDOR_ID_BROADCOM 0x14e4
|
|
+#define PCI_DEVICE_ID_NX2_5709 0x1639
|
|
+#define PCI_DEVICE_ID_NX2_5709S 0x163a
|
|
+#define PCI_DEVICE_ID_NX2_5706 0x164a
|
|
+#define PCI_DEVICE_ID_NX2_5708 0x164c
|
|
+#define PCI_DEVICE_ID_NX2_5706S 0x16aa
|
|
+#define PCI_DEVICE_ID_NX2_5708S 0x16ac
|
|
+
|
|
+#define PCI_VENDOR_ID_HP 0x103c
|
|
+
|
|
+#define PCI_ANY_ID (~0)
|
|
+
|
|
+/* This is the table used to match PCI vendor and device ID's to the
|
|
+ * human readable string names of the devices */
|
|
+static const struct pci_device_id bnx2_pci_tbl[] = {
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
|
|
+ PCI_VENDOR_ID_HP, 0x3101, hp_NC370T},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
|
|
+ PCI_VENDOR_ID_HP, 0x3106, hp_NC370I},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_5706S},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_5708C},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
|
|
+ PCI_VENDOR_ID_HP, 0x3102, hp_NC370F},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_5706S},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_5708S},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_5709C},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_5709S},
|
|
+ {PCI_VENDOR_ID_BROADCOM, 0x163b,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_5716C},
|
|
+ {PCI_VENDOR_ID_BROADCOM, 0x163c,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_5716S},
|
|
+};
|
|
+
|
|
+/*******************************************************************************
|
|
+ * bnx2 Library Functions
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * bnx2_get_library_name() - Used to get the name of this NIC libary
|
|
+ * @param name - This function will return the pointer to this NIC
|
|
+ * library name
|
|
+ * @param name_size
|
|
+ */
|
|
+static void bnx2_get_library_name(char **name, size_t *name_size)
|
|
+{
|
|
+ *name = (char *)library_name;
|
|
+ *name_size = sizeof(library_name);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_get_library_version() - Used to get the version string of this
|
|
+ * NIC libary
|
|
+ * @param version - This function will return the pointer to this NIC
|
|
+ * library version string
|
|
+ * @param version_size - This will be set with the version size
|
|
+ */
|
|
+static void bnx2_get_library_version(char **version, size_t *version_size)
|
|
+{
|
|
+ *version = (char *)library_version;
|
|
+ *version_size = sizeof(library_version);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_get_build_date() - Used to get the build date string of this library
|
|
+ * @param version - This function will return the pointer to this NIC
|
|
+ * library build date string
|
|
+ * @param version_size - This will be set with the build date string size
|
|
+ */
|
|
+static void bnx2_get_build_date(char **build, size_t *build_size)
|
|
+{
|
|
+ *build = (char *)build_date;
|
|
+ *build_size = sizeof(build_date);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_get_transport_name() - Used to get the transport name associated
|
|
+ * with this this NIC libary
|
|
+ * @param transport_name - This function will return the pointer to this NIC
|
|
+ * library's associated transport string
|
|
+ * @param transport_name_size - This will be set with the transport name size
|
|
+ */
|
|
+static void bnx2_get_transport_name(char **transport_name,
|
|
+ size_t *transport_name_size)
|
|
+{
|
|
+ *transport_name = (char *)bnx2i_library_transport_name;
|
|
+ *transport_name_size = bnx2i_library_transport_name_size;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_get_uio_name() - Used to get the uio name associated with this this
|
|
+ * NIC libary
|
|
+ * @param uio_name - This function will return the pointer to this NIC
|
|
+ * library's associated uio string
|
|
+ * @param transport_name_size - This will be set with the uio name size
|
|
+ */
|
|
+static void bnx2_get_uio_name(char **uio_name, size_t *uio_name_size)
|
|
+{
|
|
+ *uio_name = (char *)library_uio_name;
|
|
+ *uio_name_size = sizeof(library_uio_name);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_get_pci_table() - Used to get the PCI table for this NIC libary
|
|
+ * to determine which NIC's based off of PCI ID's
|
|
+ * are supported
|
|
+ * @param table - This function will return the pointer to the PCI table
|
|
+ * @param entries - This function will return the number of entries in the NIC
|
|
+ * library's PCI table
|
|
+ */
|
|
+static void bnx2_get_pci_table(struct pci_device_id **table, uint32_t *entries)
|
|
+{
|
|
+ *table = (struct pci_device_id *)bnx2_pci_tbl;
|
|
+ *entries = (uint32_t) (sizeof(bnx2_pci_tbl) / sizeof(bnx2_pci_tbl[0]));
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_get_ops() - Used to get the NIC library op table
|
|
+ * @param op - The op table of this NIC library
|
|
+ */
|
|
+struct nic_ops *bnx2_get_ops()
|
|
+{
|
|
+ return &bnx2_op;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * bnx2 Utility Functions
|
|
+ ******************************************************************************/
|
|
+/*******************************************************************************
|
|
+ * Utility Functions Used to read register from the bnx2 device
|
|
+ ******************************************************************************/
|
|
+static void bnx2_wr32(bnx2_t *bp, __u32 off, __u32 val)
|
|
+{
|
|
+ *((volatile __u32 *)(bp->reg + off)) = val;
|
|
+}
|
|
+
|
|
+static void bnx2_wr16(bnx2_t *bp, __u32 off, __u16 val)
|
|
+{
|
|
+ *((volatile __u16 *)(bp->reg + off)) = val;
|
|
+}
|
|
+
|
|
+static __u32 bnx2_rd32(bnx2_t *bp, __u32 off)
|
|
+{
|
|
+ return *((volatile __u32 *)(bp->reg + off));
|
|
+}
|
|
+
|
|
+static int bnx2_reg_sync(bnx2_t *bp, __u32 off, __u16 length)
|
|
+{
|
|
+ return msync(bp->reg + off, length, MS_SYNC);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_get_chip_id() - Used to retrive the chip ID from the nic
|
|
+ * @param dev - Device used to determin NIC type
|
|
+ * @return Chip ID read from the MISC ID register
|
|
+ */
|
|
+static int bnx2_get_chip_id(bnx2_t *bp)
|
|
+{
|
|
+ return bnx2_rd32(bp, BNX2_MISC_ID);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_uio_verify()
|
|
+ *
|
|
+ */
|
|
+static int bnx2_uio_verify(nic_t *nic)
|
|
+{
|
|
+ char *raw = NULL, *raw_tmp;
|
|
+ uint32_t raw_size = 0;
|
|
+ char temp_path[sizeof(cnic_uio_sysfs_name_tempate) + 8];
|
|
+ int rc = 0;
|
|
+
|
|
+ /* Build the path to determine uio name */
|
|
+ snprintf(temp_path, sizeof(temp_path),
|
|
+ cnic_uio_sysfs_name_tempate, nic->uio_minor);
|
|
+
|
|
+ rc = capture_file(&raw, &raw_size, temp_path);
|
|
+ if (rc != 0)
|
|
+ goto error;
|
|
+
|
|
+ /* sanitize name string by replacing newline with null termination */
|
|
+ raw_tmp = raw;
|
|
+ while (*raw_tmp != '\n')
|
|
+ raw_tmp++;
|
|
+ *raw_tmp = '\0';
|
|
+
|
|
+ if (strncmp(raw, cnic_uio_sysfs_name, sizeof(cnic_uio_sysfs_name)) !=
|
|
+ 0) {
|
|
+ LOG_ERR(PFX "%s: uio names not equal: "
|
|
+ "expecting %s got %s from %s",
|
|
+ nic->log_name, cnic_uio_sysfs_name, raw, temp_path);
|
|
+ rc = -EIO;
|
|
+ }
|
|
+
|
|
+ free(raw);
|
|
+
|
|
+ LOG_INFO(PFX "%s: Verified is a cnic_uio device", nic->log_name);
|
|
+
|
|
+error:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * bnx2 Utility Functions to get to the hardware consumer indexes
|
|
+ ******************************************************************************/
|
|
+static __u16 bnx2_get_rx_msix(bnx2_t *bp)
|
|
+{
|
|
+ struct status_block_msix *sblk = bp->status_blk.msix;
|
|
+ __u16 rx_cons;
|
|
+
|
|
+ msync(sblk, sizeof(*sblk), MS_SYNC);
|
|
+ rx_cons = sblk->status_rx_quick_consumer_index;
|
|
+ barrier();
|
|
+ if ((rx_cons & (MAX_RX_DESC_CNT)) == (MAX_RX_DESC_CNT))
|
|
+ rx_cons++;
|
|
+
|
|
+ return rx_cons;
|
|
+}
|
|
+
|
|
+static __u16 bnx2_get_rx_msi(bnx2_t *bp)
|
|
+{
|
|
+ struct status_block *sblk = bp->status_blk.msi;
|
|
+ __u16 rx_cons;
|
|
+
|
|
+ msync(sblk, sizeof(*sblk), MS_SYNC);
|
|
+ rx_cons = BNX2_SBLK_EVEN_IDX(sblk->rx2);
|
|
+ barrier();
|
|
+ if ((rx_cons & (MAX_RX_DESC_CNT)) == (MAX_RX_DESC_CNT))
|
|
+ rx_cons++;
|
|
+
|
|
+ return rx_cons;
|
|
+}
|
|
+
|
|
+static __u16 bnx2_get_tx_msix(bnx2_t *bp)
|
|
+{
|
|
+ struct status_block_msix *sblk = bp->status_blk.msix;
|
|
+ __u16 tx_cons;
|
|
+
|
|
+ msync(sblk, sizeof(*sblk), MS_SYNC);
|
|
+ tx_cons = sblk->status_tx_quick_consumer_index;
|
|
+ barrier();
|
|
+ if ((tx_cons & (MAX_TX_DESC_CNT)) == (MAX_TX_DESC_CNT))
|
|
+ tx_cons++;
|
|
+
|
|
+ return tx_cons;
|
|
+}
|
|
+
|
|
+static __u16 bnx2_get_tx_msi(bnx2_t *bp)
|
|
+{
|
|
+ struct status_block *sblk = bp->status_blk.msi;
|
|
+ __u16 tx_cons;
|
|
+
|
|
+ msync(sblk, sizeof(*sblk), MS_SYNC);
|
|
+ tx_cons = BNX2_SBLK_EVEN_IDX(sblk->tx2);
|
|
+ barrier();
|
|
+ if ((tx_cons & (MAX_TX_DESC_CNT)) == (MAX_TX_DESC_CNT))
|
|
+ tx_cons++;
|
|
+
|
|
+ return tx_cons;
|
|
+}
|
|
+
|
|
+typedef enum {
|
|
+ CNIC_VLAN_STRIPPING_ENABLED = 1,
|
|
+ CNIC_VLAN_STRIPPING_DISABLED = 2,
|
|
+} CNIC_VLAN_STRIPPING_MODE;
|
|
+
|
|
+/**
|
|
+ * bnx2_strip_vlan_enabled() - This will query the device to determine whether
|
|
+ * VLAN tag stripping is enabled or not
|
|
+ * @param dev - device to check stripping or not
|
|
+ * @ return CNIC_VLAN_STRIPPING_ENABLED stripping is enabled
|
|
+ * CNIC_VLAN_STRIPPING_DISABLED stripping is not enabled
|
|
+ */
|
|
+static CNIC_VLAN_STRIPPING_MODE bnx2_strip_vlan_enabled(bnx2_t *bp)
|
|
+{
|
|
+ uint32_t val;
|
|
+
|
|
+ val = bnx2_rd32(bp, BNX2_EMAC_RX_MODE);
|
|
+
|
|
+ if (val & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)
|
|
+ return CNIC_VLAN_STRIPPING_DISABLED;
|
|
+ else
|
|
+ return CNIC_VLAN_STRIPPING_ENABLED;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_free() - Used to free a bnx2 structure
|
|
+ */
|
|
+static void bnx2_free(nic_t *nic)
|
|
+{
|
|
+ if (nic->priv)
|
|
+ free(nic->priv);
|
|
+ nic->priv = NULL;
|
|
+}
|
|
+
|
|
+
|
|
+/**
|
|
+ * bnx2_alloc() - Used to allocate a bnx2 structure
|
|
+ */
|
|
+static bnx2_t *bnx2_alloc(nic_t *nic)
|
|
+{
|
|
+ bnx2_t *bp = malloc(sizeof(*bp));
|
|
+ if (bp == NULL) {
|
|
+ LOG_ERR(PFX "%s: Could not allocate bnx2 space", nic->log_name);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* Clear out the bnx2 contents */
|
|
+ memset(bp, 0, sizeof(*bp));
|
|
+
|
|
+ bp->bar0_fd = INVALID_FD;
|
|
+ bp->flags = BNX2_UIO_TX_HAS_SENT;
|
|
+
|
|
+ bp->parent = nic;
|
|
+ nic->priv = (void *)bp;
|
|
+
|
|
+ return bp;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_open() - This will initialize all the hardware resources
|
|
+ * @param dev - The struct nic device to open
|
|
+ * @return 0 on success, on failure a errno will be returned
|
|
+ */
|
|
+static int bnx2_open(nic_t *nic)
|
|
+{
|
|
+ bnx2_t *bp;
|
|
+ struct stat uio_stat;
|
|
+ int i, rc;
|
|
+ __u32 val;
|
|
+ uint32_t tx_cid;
|
|
+ __u32 msix_vector = 0;
|
|
+ char sysfs_resc_path[80];
|
|
+
|
|
+ /* Sanity Check: validate the parameters */
|
|
+ if (nic == NULL) {
|
|
+ LOG_ERR(PFX "bnx2_open(): nic == NULL");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if ((nic->priv) != NULL &&
|
|
+ (((bnx2_t *) (nic->priv))->flags & BNX2_OPENED)) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ bp = bnx2_alloc(nic);
|
|
+ if (bp == NULL) {
|
|
+ LOG_ERR(PFX "bnx2_open(): Couldn't allocate bp priv struct",
|
|
+ nic->log_name);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ while (nic->fd < 0) {
|
|
+ nic->fd = open(nic->uio_device_name, O_RDWR | O_NONBLOCK);
|
|
+ if (nic->fd != INVALID_FD) {
|
|
+ LOG_ERR(PFX
|
|
+ "%s: uio device has been brought up via pid: "
|
|
+ "%d on fd: %d",
|
|
+ nic->uio_device_name, getpid(), nic->fd);
|
|
+
|
|
+ rc = bnx2_uio_verify(nic);
|
|
+ if (rc != 0)
|
|
+ continue;
|
|
+
|
|
+ break;
|
|
+ } else {
|
|
+ LOG_WARN(PFX "%s: Could not open device: %s, [%s]",
|
|
+ nic->log_name, nic->uio_device_name,
|
|
+ strerror(errno));
|
|
+ manually_trigger_uio_event(nic, nic->uio_minor);
|
|
+
|
|
+ /* udev might not have created the file yet */
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ sleep(1);
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ }
|
|
+ }
|
|
+ if (fstat(nic->fd, &uio_stat) < 0) {
|
|
+ LOG_ERR(PFX "%s: Could not fstat device", nic->log_name);
|
|
+ errno = -ENODEV;
|
|
+ goto error_alloc_rx_ring;
|
|
+ }
|
|
+ nic->uio_minor = minor(uio_stat.st_rdev);
|
|
+
|
|
+ cnic_get_sysfs_pci_resource_path(nic, 0, sysfs_resc_path, 80);
|
|
+ bp->bar0_fd = open(sysfs_resc_path, O_RDWR | O_SYNC);
|
|
+ if (bp->bar0_fd < 0) {
|
|
+ LOG_ERR(PFX "%s: Could not open %s", nic->log_name,
|
|
+ sysfs_resc_path);
|
|
+ errno = -ENODEV;
|
|
+ goto error_alloc_rx_ring;
|
|
+ }
|
|
+
|
|
+ /* TODO: hardcoded with the cnic driver */
|
|
+ bp->rx_ring_size = 3;
|
|
+ bp->rx_buffer_size = 0x400;
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: using rx ring size: %d, rx buffer size: %d",
|
|
+ nic->log_name, bp->rx_ring_size, bp->rx_buffer_size);
|
|
+
|
|
+ /* Determine the number of UIO events that have already occured */
|
|
+ rc = detemine_initial_uio_events(nic, &nic->intr_count);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR("Could not determine the number ofinitial UIO events");
|
|
+ nic->intr_count = 0;
|
|
+ }
|
|
+
|
|
+ /* Allocate space for rx ring pointer */
|
|
+ bp->rx_ring = malloc(sizeof(struct l2_fhdr *) * bp->rx_ring_size);
|
|
+ if (bp->rx_ring == NULL) {
|
|
+ LOG_ERR(PFX "%s: Could not allocate space for rx_ring",
|
|
+ nic->log_name);
|
|
+ errno = -ENOMEM;
|
|
+ goto error_alloc_rx_ring;
|
|
+ }
|
|
+ mlock(bp->rx_ring, sizeof(struct l2_fhdr *) * bp->rx_ring_size);
|
|
+
|
|
+ /* Allocate space for rx pkt ring */
|
|
+ bp->rx_pkt_ring = malloc(sizeof(void *) * bp->rx_ring_size);
|
|
+ if (bp->rx_pkt_ring == NULL) {
|
|
+ LOG_ERR(PFX "%s: Could not allocate space for rx_pkt_ring",
|
|
+ nic->log_name);
|
|
+ errno = -ENOMEM;
|
|
+ goto error_alloc_rx_pkt_ring;
|
|
+ }
|
|
+ mlock(bp->rx_pkt_ring, sizeof(void *) * bp->rx_ring_size);
|
|
+
|
|
+ bp->reg = mmap(NULL, 0x12800, PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
+ bp->bar0_fd, (off_t) 0);
|
|
+ if (bp->reg == MAP_FAILED) {
|
|
+ LOG_INFO(PFX "%s: Couldn't mmap registers: %s",
|
|
+ nic->log_name, strerror(errno));
|
|
+ bp->reg = NULL;
|
|
+ goto error_regs;
|
|
+ }
|
|
+
|
|
+ msync(bp->reg, 0x12800, MS_SYNC);
|
|
+ LOG_DEBUG(PFX "Chip ID: %x", bnx2_get_chip_id(bp));
|
|
+
|
|
+ /* on a 5709 when using MSI-X the status block is at an offset */
|
|
+ if (BNX2_CHIP_NUM(bnx2_get_chip_id(bp)) == CHIP_NUM_5709) {
|
|
+ /* determine if we are using MSI-X */
|
|
+ val = bnx2_rd32(bp, BNX2_TSCH_TSS_CFG);
|
|
+ if (val) {
|
|
+ /* We are in MSI-X mode */
|
|
+ uint32_t base_cid = ((val >> 10) & 0x7ff) << 3;
|
|
+ msix_vector = (val >> 24) & 0xf;
|
|
+
|
|
+ bp->status_blk_size = (128 * 9);
|
|
+
|
|
+ tx_cid = base_cid + msix_vector - 1;
|
|
+ bp->flags |= BNX2_UIO_MSIX_ENABLED;
|
|
+
|
|
+ bp->get_tx_cons = bnx2_get_tx_msix;
|
|
+ bp->get_rx_cons = bnx2_get_rx_msix;
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: tss_cfg: 0x%x tx cid: %d",
|
|
+ nic->log_name, val, tx_cid);
|
|
+
|
|
+ LOG_INFO(PFX "%s: detected using MSI-X vector: %d",
|
|
+ nic->log_name, msix_vector);
|
|
+ } else {
|
|
+ /* We are not in MSI-X mode */
|
|
+ bp->status_blk_size = 64;
|
|
+ tx_cid = 20;
|
|
+
|
|
+ bp->get_tx_cons = bnx2_get_tx_msi;
|
|
+ bp->get_rx_cons = bnx2_get_rx_msi;
|
|
+ }
|
|
+ } else {
|
|
+ bp->status_blk_size = 64;
|
|
+ tx_cid = 20;
|
|
+
|
|
+ bp->get_tx_cons = bnx2_get_tx_msi;
|
|
+ bp->get_rx_cons = bnx2_get_rx_msi;
|
|
+ }
|
|
+
|
|
+ bp->sblk_map = mmap(NULL, bp->status_blk_size,
|
|
+ PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
+ nic->fd, (off_t) nic->page_size);
|
|
+ if (bp->sblk_map == MAP_FAILED) {
|
|
+ LOG_INFO(PFX "%s: Could not mmap status block: %s",
|
|
+ nic->log_name, strerror(errno));
|
|
+ goto error_sblk;
|
|
+ }
|
|
+
|
|
+ if (bp->flags & BNX2_UIO_MSIX_ENABLED) {
|
|
+ uint8_t *status_blk = (uint8_t *) bp->sblk_map;
|
|
+ status_blk += (msix_vector * 128);
|
|
+
|
|
+ bp->status_blk.msix = (struct status_block_msix *)status_blk;
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: msix initial cons: tx:%d rx:%d",
|
|
+ nic->log_name,
|
|
+ bp->status_blk.msix->status_tx_quick_consumer_index,
|
|
+ bp->status_blk.msix->status_rx_quick_consumer_index);
|
|
+ } else {
|
|
+ bp->status_blk.msi = (struct status_block *)bp->sblk_map;
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: msi initial tx:%d rx:%d",
|
|
+ nic->log_name,
|
|
+ BNX2_SBLK_EVEN_IDX(bp->status_blk.msi->tx2),
|
|
+ BNX2_SBLK_EVEN_IDX(bp->status_blk.msi->rx2));
|
|
+ }
|
|
+
|
|
+ bp->tx_ring = mmap(NULL, 2 * nic->page_size,
|
|
+ PROT_READ | PROT_WRITE, MAP_SHARED, nic->fd,
|
|
+ (off_t) 2 * nic->page_size);
|
|
+ if (bp->tx_ring == MAP_FAILED) {
|
|
+ LOG_INFO(PFX "%s: Could not mmap tx ring: %s",
|
|
+ nic->log_name, strerror(errno));
|
|
+ bp->tx_ring = NULL;
|
|
+ goto error_tx_ring;
|
|
+ }
|
|
+
|
|
+ bp->bufs = mmap(NULL, (bp->rx_ring_size + 1) * bp->rx_buffer_size,
|
|
+ PROT_READ | PROT_WRITE,
|
|
+ MAP_SHARED, nic->fd, (off_t) 3 * nic->page_size);
|
|
+ if (bp->bufs == MAP_FAILED) {
|
|
+ LOG_INFO(PFX "%s: Could not mmap buffers: %s",
|
|
+ nic->log_name, strerror(errno));
|
|
+ bp->bufs = NULL;
|
|
+ goto error_bufs;
|
|
+ }
|
|
+
|
|
+ bp->tx_bidx_io = MB_GET_CID_ADDR(tx_cid) + BNX2_L2CTX_TX_HOST_BIDX;
|
|
+ bp->tx_bseq_io = MB_GET_CID_ADDR(tx_cid) + BNX2_L2CTX_TX_HOST_BSEQ;
|
|
+ LOG_INFO(PFX "%s: tx_bidx_io: 0x%x tx_bseq_io: 0x%x",
|
|
+ nic->log_name, bp->tx_bidx_io, bp->tx_bseq_io);
|
|
+
|
|
+ bp->rx_bidx_io = MB_GET_CID_ADDR(2) + BNX2_L2CTX_HOST_BDIDX;
|
|
+ bp->rx_bseq_io = MB_GET_CID_ADDR(2) + BNX2_L2CTX_HOST_BSEQ;
|
|
+
|
|
+ bp->tx_cons = 0;
|
|
+ bp->tx_prod = 0;
|
|
+ bp->tx_pkt = bp->bufs;
|
|
+
|
|
+ bp->rx_index = 0;
|
|
+ bp->rx_cons = 0;
|
|
+ bp->rx_prod = bp->rx_ring_size;
|
|
+ bp->rx_bseq = bp->rx_prod * bp->rx_buffer_size;
|
|
+ bnx2_wr16(bp, bp->rx_bidx_io, bp->rx_prod);
|
|
+ bnx2_wr32(bp, bp->rx_bseq_io, bp->rx_bseq);
|
|
+
|
|
+ bnx2_reg_sync(bp, bp->rx_bidx_io, sizeof(__u16));
|
|
+ bnx2_reg_sync(bp, bp->rx_bseq_io, sizeof(__u32));
|
|
+
|
|
+ for (i = 0; i < bp->rx_ring_size; i++) {
|
|
+ void *ptr = bp->bufs + (bp->rx_buffer_size * (i + 1));
|
|
+
|
|
+ bp->rx_ring[i] = (struct l2_fhdr *)ptr;
|
|
+ bp->rx_pkt_ring[i] = ptr + sizeof(struct l2_fhdr) + 2;
|
|
+ }
|
|
+
|
|
+ /* Read the MAC address used for the iSCSI interface */
|
|
+ val = bnx2_rd32(bp, BNX2_EMAC_MAC_MATCH4);
|
|
+ nic->mac_addr[0] = (__u8) (val >> 8);
|
|
+ nic->mac_addr[1] = (__u8) val;
|
|
+
|
|
+ val = bnx2_rd32(bp, BNX2_EMAC_MAC_MATCH5);
|
|
+ nic->mac_addr[2] = (__u8) (val >> 24);
|
|
+ nic->mac_addr[3] = (__u8) (val >> 16);
|
|
+ nic->mac_addr[4] = (__u8) (val >> 8);
|
|
+ nic->mac_addr[5] = (__u8) val;
|
|
+
|
|
+ LOG_INFO(PFX "%s: Using mac address: %2x:%2x:%2x:%2x:%2x:%2x",
|
|
+ nic->log_name,
|
|
+ nic->mac_addr[0], nic->mac_addr[1], nic->mac_addr[2],
|
|
+ nic->mac_addr[3], nic->mac_addr[4], nic->mac_addr[5]);
|
|
+
|
|
+ /* Determine if Hardware VLAN tag stripping is enabled or not */
|
|
+ if (CNIC_VLAN_STRIPPING_ENABLED == bnx2_strip_vlan_enabled(bp))
|
|
+ nic->flags |= NIC_VLAN_STRIP_ENABLED;
|
|
+
|
|
+ /* Prepare the multicast addresses */
|
|
+ val = 4 | BNX2_RPM_SORT_USER2_BC_EN | BNX2_RPM_SORT_USER2_MC_EN;
|
|
+ if (BNX2_CHIP_NUM(bnx2_get_chip_id(bp)) != CHIP_NUM_5709)
|
|
+ val |= BNX2_RPM_SORT_USER2_PROM_VLAN;
|
|
+
|
|
+ bnx2_wr32(bp, BNX2_RPM_SORT_USER2, 0x0);
|
|
+ bnx2_wr32(bp, BNX2_RPM_SORT_USER2, val);
|
|
+ bnx2_wr32(bp, BNX2_RPM_SORT_USER2, val | BNX2_RPM_SORT_USER2_ENA);
|
|
+
|
|
+ rc = enable_multicast(nic);
|
|
+ if (rc != 0) {
|
|
+ errno = rc;
|
|
+ goto error_bufs;
|
|
+ }
|
|
+ msync(bp->reg, 0x12800, MS_SYNC);
|
|
+ LOG_INFO("%s: bnx2 uio initialized", nic->log_name);
|
|
+
|
|
+ bp->flags |= BNX2_OPENED;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+error_bufs:
|
|
+ munmap(bp->tx_ring, 2 * nic->page_size);
|
|
+
|
|
+error_tx_ring:
|
|
+ munmap(bp->status_blk.msi, bp->status_blk_size);
|
|
+
|
|
+error_sblk:
|
|
+ munmap(bp->reg, 0x12800);
|
|
+
|
|
+error_regs:
|
|
+ munlock(bp->rx_pkt_ring, sizeof(void *) * bp->rx_ring_size);
|
|
+ free(bp->rx_pkt_ring);
|
|
+ bp->rx_pkt_ring = NULL;
|
|
+
|
|
+error_alloc_rx_pkt_ring:
|
|
+ munlock(bp->rx_ring, sizeof(struct l2_fhdr *) * bp->rx_ring_size);
|
|
+ free(bp->rx_ring);
|
|
+ bp->rx_ring = NULL;
|
|
+
|
|
+error_alloc_rx_ring:
|
|
+ if (nic->fd != INVALID_FD) {
|
|
+ close(nic->fd);
|
|
+ nic->fd = INVALID_FD;
|
|
+ }
|
|
+ bnx2_free(nic);
|
|
+
|
|
+ return errno;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_uio_close_resources() - Used to free resource for the bnx2 NIC
|
|
+ * @param nic - NIC device to free resource
|
|
+ * @param graceful - whether to wait to close gracefully
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+static int bnx2_uio_close_resources(nic_t *nic, NIC_SHUTDOWN_T graceful)
|
|
+{
|
|
+ bnx2_t *bp = (bnx2_t *) nic->priv;
|
|
+ int rc = 0;
|
|
+
|
|
+ /* Remove the multicast addresses if added */
|
|
+ if ((nic->flags & NIC_ADDED_MULICAST) &&
|
|
+ (graceful == ALLOW_GRACEFUL_SHUTDOWN))
|
|
+ disable_multicast(nic);
|
|
+
|
|
+ /* Check if there is an assoicated bnx2 device */
|
|
+ if (bp == NULL) {
|
|
+ LOG_WARN(PFX "%s: when closing resources there is "
|
|
+ "no assoicated bnx2", nic->log_name);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* Clean up allocated memory */
|
|
+ if (bp->rx_ring != NULL) {
|
|
+ free(bp->rx_ring);
|
|
+ bp->rx_ring = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->rx_pkt_ring != NULL) {
|
|
+ free(bp->rx_pkt_ring);
|
|
+ bp->rx_pkt_ring = NULL;
|
|
+ }
|
|
+
|
|
+ /* Clean up mapped registers */
|
|
+ if (bp->bufs != NULL) {
|
|
+ rc = munmap(bp->bufs,
|
|
+ (bp->rx_ring_size + 1) * bp->rx_buffer_size);
|
|
+ if (rc != 0)
|
|
+ LOG_WARN(PFX "%s: Couldn't unmap bufs", nic->log_name);
|
|
+ bp->bufs = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->tx_ring != NULL) {
|
|
+ rc = munmap(bp->tx_ring, 2 * nic->page_size);
|
|
+ if (rc != 0)
|
|
+ LOG_WARN(PFX "%s: Couldn't unmap tx_rings",
|
|
+ nic->log_name);
|
|
+ bp->tx_ring = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->status_blk.msix != NULL || bp->status_blk.msi != NULL) {
|
|
+ rc = munmap(bp->sblk_map, bp->status_blk_size);
|
|
+ if (rc != 0)
|
|
+ LOG_WARN(PFX "%s: Couldn't unmap status block",
|
|
+ nic->log_name);
|
|
+ bp->sblk_map = NULL;
|
|
+
|
|
+ bp->status_blk.msix = NULL;
|
|
+ bp->status_blk.msi = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->reg != NULL) {
|
|
+ rc = munmap(bp->reg, 0x12800);
|
|
+ if (rc != 0)
|
|
+ LOG_WARN(PFX "%s: Couldn't unmap regs", nic->log_name);
|
|
+ bp->reg = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->bar0_fd != INVALID_FD) {
|
|
+ close(bp->bar0_fd);
|
|
+ bp->bar0_fd = INVALID_FD;
|
|
+ }
|
|
+
|
|
+ if (nic->fd != INVALID_FD) {
|
|
+ rc = close(nic->fd);
|
|
+ if (rc != 0) {
|
|
+ LOG_WARN(PFX
|
|
+ "%s: Couldn't close uio file descriptor: %d",
|
|
+ nic->log_name, nic->fd);
|
|
+ } else {
|
|
+ LOG_DEBUG(PFX "%s: Closed uio file descriptor: %d",
|
|
+ nic->log_name, nic->fd);
|
|
+ }
|
|
+
|
|
+ nic->fd = INVALID_FD;
|
|
+ } else {
|
|
+ LOG_WARN(PFX "%s: Invalid uio file descriptor: %d",
|
|
+ nic->log_name, nic->fd);
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "%s: Closed all resources", nic->log_name);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_close() - Used to close the NIC device
|
|
+ * @param nic - NIC device to close
|
|
+ * @param graceful - whether to wait to close gracefully
|
|
+ * @return 0 if successful, <0 if there is an error
|
|
+ */
|
|
+static int bnx2_close(nic_t *nic, NIC_SHUTDOWN_T graceful)
|
|
+{
|
|
+ /* Sanity Check: validate the parameters */
|
|
+ if (nic == NULL) {
|
|
+ LOG_ERR(PFX "bnx2_close(): nic == NULL");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "Closing NIC device: %s", nic->log_name);
|
|
+
|
|
+ bnx2_uio_close_resources(nic, graceful);
|
|
+ bnx2_free(nic);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void bnx2_prepare_xmit_packet(nic_t *nic,
|
|
+ nic_interface_t *nic_iface,
|
|
+ struct packet *pkt)
|
|
+{
|
|
+ bnx2_t *bp = (bnx2_t *) nic->priv;
|
|
+ struct uip_vlan_eth_hdr *eth_vlan = (struct uip_vlan_eth_hdr *)pkt->buf;
|
|
+ struct uip_eth_hdr *eth = (struct uip_eth_hdr *)bp->tx_pkt;
|
|
+
|
|
+ if (eth_vlan->tpid == htons(UIP_ETHTYPE_8021Q)) {
|
|
+ memcpy(bp->tx_pkt, pkt->buf, sizeof(struct uip_eth_hdr));
|
|
+ eth->type = eth_vlan->type;
|
|
+ pkt->buf_size -= (sizeof(struct uip_vlan_eth_hdr) -
|
|
+ sizeof(struct uip_eth_hdr));
|
|
+ memcpy(bp->tx_pkt + sizeof(struct uip_eth_hdr),
|
|
+ pkt->buf + sizeof(struct uip_vlan_eth_hdr),
|
|
+ pkt->buf_size - sizeof(struct uip_eth_hdr));
|
|
+ } else
|
|
+ memcpy(bp->tx_pkt, pkt->buf, pkt->buf_size);
|
|
+
|
|
+ msync(bp->tx_pkt, pkt->buf_size, MS_SYNC);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_get_tx_pkt() - This function is used to a TX packet from the NIC
|
|
+ * @param nic - The NIC device to send the packet
|
|
+ *
|
|
+ */
|
|
+void *bnx2_get_tx_pkt(nic_t *nic)
|
|
+{
|
|
+ bnx2_t *bp = (bnx2_t *) nic->priv;
|
|
+ return bp->tx_pkt;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_start_xmit() - This function is used to send a packet of data
|
|
+ * @param nic - The NIC device to send the packet
|
|
+ * @param len - the length of the TX packet
|
|
+ *
|
|
+ */
|
|
+void bnx2_start_xmit(nic_t *nic, size_t len, u16_t vlan_id)
|
|
+{
|
|
+ bnx2_t *bp = (bnx2_t *) nic->priv;
|
|
+ uint16_t ring_prod;
|
|
+ struct tx_bd *txbd;
|
|
+ struct rx_bd *rxbd;
|
|
+ rxbd = (struct rx_bd *)(((__u8 *) bp->tx_ring) + nic->page_size);
|
|
+
|
|
+ if ((rxbd->rx_bd_haddr_hi == 0) && (rxbd->rx_bd_haddr_lo == 0)) {
|
|
+ LOG_PACKET(PFX "%s: trying to transmit when device is closed",
|
|
+ nic->log_name);
|
|
+ pthread_mutex_unlock(&nic->xmit_mutex);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ring_prod = TX_RING_IDX(bp->tx_prod);
|
|
+ txbd = &bp->tx_ring[ring_prod];
|
|
+
|
|
+ txbd->tx_bd_mss_nbytes = len;
|
|
+
|
|
+ if (vlan_id) {
|
|
+ txbd->tx_bd_vlan_tag_flags = (vlan_id << 16) |
|
|
+ TX_BD_FLAGS_VLAN_TAG | TX_BD_FLAGS_END | TX_BD_FLAGS_START;
|
|
+ } else
|
|
+ txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_END |
|
|
+ TX_BD_FLAGS_START;
|
|
+
|
|
+ bp->tx_bseq += len;
|
|
+ bp->tx_prod = NEXT_TX_BD(bp->tx_prod);
|
|
+
|
|
+ bnx2_wr16(bp, bp->tx_bidx_io, bp->tx_prod);
|
|
+ bnx2_wr32(bp, bp->tx_bseq_io, bp->tx_bseq);
|
|
+
|
|
+ bnx2_reg_sync(bp, bp->tx_bidx_io, sizeof(__u16));
|
|
+ bnx2_reg_sync(bp, bp->tx_bseq_io, sizeof(__u32));
|
|
+
|
|
+ LOG_PACKET(PFX "%s: sent %d bytes using dev->tx_prod: %d",
|
|
+ nic->log_name, len, bp->tx_prod);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_write() - Used to write the data to the hardware
|
|
+ * @param nic - NIC hardware to read from
|
|
+ * @param pkt - The packet which will hold the data to be sent on the wire
|
|
+ * @return 0 if successful, <0 if failed
|
|
+ */
|
|
+int bnx2_write(nic_t *nic, nic_interface_t *nic_iface, packet_t *pkt)
|
|
+{
|
|
+ bnx2_t *bp;
|
|
+ struct uip_stack *uip;
|
|
+
|
|
+ /* Sanity Check: validate the parameters */
|
|
+ if (nic == NULL || nic_iface == NULL || pkt == NULL) {
|
|
+ LOG_ERR(PFX "%s: bnx2_write() nic == 0x%p || "
|
|
+ " nic_iface == 0x%p || "
|
|
+ " pkt == 0x%x", nic, nic_iface, pkt);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ bp = (bnx2_t *)nic->priv;
|
|
+ uip = &nic_iface->ustack;
|
|
+
|
|
+ if (pkt->buf_size == 0) {
|
|
+ LOG_ERR(PFX "%s: Trying to transmitted 0 sized packet",
|
|
+ nic->log_name);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (pthread_mutex_trylock(&nic->xmit_mutex) != 0) {
|
|
+ LOG_PACKET(PFX "%s: Dropped previous transmitted packet",
|
|
+ nic->log_name);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ bnx2_prepare_xmit_packet(nic, nic_iface, pkt);
|
|
+ bnx2_start_xmit(nic, pkt->buf_size,
|
|
+ (nic_iface->vlan_priority << 12) |
|
|
+ nic_iface->vlan_id);
|
|
+
|
|
+ /* bump the bnx2 dev send statistics */
|
|
+ nic->stats.tx.packets++;
|
|
+ nic->stats.tx.bytes += uip->uip_len;
|
|
+
|
|
+ LOG_PACKET(PFX "%s: transmitted %d bytes "
|
|
+ "dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bseq:%d",
|
|
+ nic->log_name, pkt->buf_size,
|
|
+ bp->tx_cons, bp->tx_prod, bp->tx_bseq);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2_read() - Used to read the data from the hardware
|
|
+ * @param nic - NIC hardware to read from
|
|
+ * @param pkt - The packet which will hold the data
|
|
+ * @return 0 if successful, <0 if failed
|
|
+ */
|
|
+static int bnx2_read(nic_t *nic, packet_t *pkt)
|
|
+{
|
|
+ bnx2_t *bp;
|
|
+ int rc = 0;
|
|
+ uint16_t hw_cons, sw_cons;
|
|
+
|
|
+ /* Sanity Check: validate the parameters */
|
|
+ if (unlikely(nic == NULL || pkt == NULL)) {
|
|
+ LOG_ERR(PFX "%s: bnx2_write() nic == 0x%p || "
|
|
+ " pkt == 0x%x", nic, pkt);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ bp = (bnx2_t *)nic->priv;
|
|
+
|
|
+ hw_cons = bp->get_rx_cons(bp);
|
|
+ sw_cons = bp->rx_cons;
|
|
+
|
|
+ if (sw_cons != hw_cons) {
|
|
+ uint8_t rx_index = bp->rx_index % 3;
|
|
+ struct l2_fhdr *rx_hdr = bp->rx_ring[rx_index];
|
|
+ void *rx_pkt = bp->rx_pkt_ring[rx_index];
|
|
+ int len;
|
|
+ uint16_t errors;
|
|
+
|
|
+ LOG_PACKET(PFX "%s: clearing rx interrupt: %d %d %d",
|
|
+ nic->log_name, sw_cons, hw_cons, rx_index);
|
|
+
|
|
+ msync(rx_hdr, sizeof(struct l2_fhdr), MS_SYNC);
|
|
+ errors = ((rx_hdr->l2_fhdr_status & 0xffff0000) >> 16);
|
|
+ len = ((rx_hdr->l2_fhdr_vtag_len & 0xffff0000) >> 16) - 4;
|
|
+
|
|
+ if (unlikely((errors & (L2_FHDR_ERRORS_BAD_CRC |
|
|
+ L2_FHDR_ERRORS_PHY_DECODE |
|
|
+ L2_FHDR_ERRORS_ALIGNMENT |
|
|
+ L2_FHDR_ERRORS_TOO_SHORT |
|
|
+ L2_FHDR_ERRORS_GIANT_FRAME)) ||
|
|
+ (len <= 0) ||
|
|
+ (len > (bp->rx_buffer_size -
|
|
+ (sizeof(struct l2_fhdr) + 2))) ||
|
|
+ (len > pkt->max_buf_size))) {
|
|
+ /* One of the fields in the BD is bad */
|
|
+ uint16_t status = ((rx_hdr->l2_fhdr_status &
|
|
+ 0x0000ffff));
|
|
+
|
|
+ LOG_ERR(PFX "%s: Recv error: 0x%x status: 0x%x "
|
|
+ "len: %d", nic->log_name, errors, status, len);
|
|
+
|
|
+ if ((len < (bp->rx_buffer_size -
|
|
+ (sizeof(struct l2_fhdr) + 2))) &&
|
|
+ (len < pkt->max_buf_size))
|
|
+ dump_packet_to_log(pkt->nic_iface, rx_pkt, len);
|
|
+ } else {
|
|
+ if (len < (bp->rx_buffer_size -
|
|
+ (sizeof(struct l2_fhdr) + 2))) {
|
|
+ msync(rx_pkt, len, MS_SYNC);
|
|
+ /* Copy the data */
|
|
+ memcpy(pkt->buf, rx_pkt, len);
|
|
+ pkt->buf_size = len;
|
|
+
|
|
+ /* Properly set the packet flags */
|
|
+ /* check if there is VLAN tagging on the
|
|
+ * packet */
|
|
+ if (rx_hdr->l2_fhdr_status &
|
|
+ L2_FHDR_STATUS_VLAN_TAG) {
|
|
+ pkt->vlan_tag =
|
|
+ rx_hdr->l2_fhdr_vtag_len & 0x0FFF;
|
|
+ pkt->flags |= VLAN_TAGGED;
|
|
+ } else {
|
|
+ pkt->vlan_tag = 0;
|
|
+ }
|
|
+
|
|
+ rc = 1;
|
|
+
|
|
+ LOG_PACKET(PFX "%s: processing packet "
|
|
+ "length: %d", nic->log_name, len);
|
|
+ } else {
|
|
+ /* If the NIC passes up a packet bigger
|
|
+ * then the RX buffer, flag it */
|
|
+ LOG_ERR(PFX "%s: invalid packet length %d "
|
|
+ "recieve ", nic->log_name, len);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ bp->rx_index++;
|
|
+ sw_cons = NEXT_RX_BD(sw_cons);
|
|
+ bp->rx_prod = NEXT_RX_BD(bp->rx_prod);
|
|
+ bp->rx_bseq += 0x400;
|
|
+
|
|
+ bp->rx_cons = sw_cons;
|
|
+ bnx2_wr16(bp, bp->rx_bidx_io, bp->rx_prod);
|
|
+ bnx2_wr32(bp, bp->rx_bseq_io, bp->rx_bseq);
|
|
+
|
|
+ bnx2_reg_sync(bp, bp->rx_bidx_io, sizeof(__u16));
|
|
+ bnx2_reg_sync(bp, bp->rx_bseq_io, sizeof(__u32));
|
|
+
|
|
+ /* bump the bnx2 dev recv statistics */
|
|
+ nic->stats.rx.packets++;
|
|
+ nic->stats.rx.bytes += pkt->buf_size;
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Clearing TX interrupts
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * bnx2_clear_tx_intr() - This routine is called when a TX interrupt occurs
|
|
+ * @param nic - the nic the interrupt occured on
|
|
+ * @return 0 on success
|
|
+ */
|
|
+static int bnx2_clear_tx_intr(nic_t *nic)
|
|
+{
|
|
+ bnx2_t *bp;
|
|
+ uint16_t hw_cons;
|
|
+
|
|
+ /* Sanity check: ensure the parameters passed in are valid */
|
|
+ if (unlikely(nic == NULL)) {
|
|
+ LOG_ERR(PFX "bnx2_read() nic == NULL");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ bp = (bnx2_t *) nic->priv;
|
|
+ hw_cons = bp->get_tx_cons(bp);
|
|
+
|
|
+ if (bp->flags & BNX2_UIO_TX_HAS_SENT)
|
|
+ bp->flags &= ~BNX2_UIO_TX_HAS_SENT;
|
|
+
|
|
+ LOG_PACKET(PFX "%s: clearing tx interrupt [%d %d]",
|
|
+ nic->log_name, bp->tx_cons, hw_cons);
|
|
+
|
|
+ bp->tx_cons = hw_cons;
|
|
+
|
|
+ /* There is a queued TX packet that needs to be sent out. The usual
|
|
+ * case is when stack will send an ARP packet out before sending the
|
|
+ * intended packet */
|
|
+ if (nic->tx_packet_queue != NULL) {
|
|
+ packet_t *pkt;
|
|
+
|
|
+ LOG_PACKET(PFX "%s: sending queued tx packet", nic->log_name);
|
|
+ pkt = nic_dequeue_tx_packet(nic);
|
|
+
|
|
+ /* Got a TX packet buffer of the TX queue and put it onto
|
|
+ * the hardware */
|
|
+ if (pkt != NULL) {
|
|
+ bnx2_prepare_xmit_packet(nic, pkt->nic_iface, pkt);
|
|
+
|
|
+ bnx2_start_xmit(nic, pkt->buf_size,
|
|
+ (pkt->nic_iface->vlan_priority << 12) |
|
|
+ pkt->nic_iface->vlan_id);
|
|
+
|
|
+ LOG_PACKET(PFX "%s: transmitted queued packet %d bytes "
|
|
+ "dev->tx_cons: %d, dev->tx_prod: %d, "
|
|
+ "dev->tx_bseq:%d",
|
|
+ nic->log_name, pkt->buf_size,
|
|
+ bp->tx_cons, bp->tx_prod, bp->tx_bseq);
|
|
+
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pthread_mutex_unlock(&nic->xmit_mutex);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * bnx2 NIC op's table
|
|
+ ******************************************************************************/
|
|
+struct nic_ops bnx2_op = {
|
|
+ .description = "bnx2",
|
|
+ .open = bnx2_open,
|
|
+ .close = bnx2_close,
|
|
+ .write = bnx2_write,
|
|
+ .get_tx_pkt = bnx2_get_tx_pkt,
|
|
+ .start_xmit = bnx2_start_xmit,
|
|
+ .read = bnx2_read,
|
|
+ .clear_tx_intr = bnx2_clear_tx_intr,
|
|
+ .handle_iscsi_path_req = cnic_handle_iscsi_path_req,
|
|
+
|
|
+ .lib_ops = {
|
|
+ .get_library_name = bnx2_get_library_name,
|
|
+ .get_pci_table = bnx2_get_pci_table,
|
|
+ .get_library_version = bnx2_get_library_version,
|
|
+ .get_build_date = bnx2_get_build_date,
|
|
+ .get_transport_name = bnx2_get_transport_name,
|
|
+ .get_uio_name = bnx2_get_uio_name,
|
|
+ },
|
|
+};
|
|
diff --git a/iscsiuio/src/unix/libs/bnx2.h b/iscsiuio/src/unix/libs/bnx2.h
|
|
new file mode 100644
|
|
index 0000000..3ec9437
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/libs/bnx2.h
|
|
@@ -0,0 +1,304 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * bnx2.h - bnx2 user space driver
|
|
+ *
|
|
+ */
|
|
+#ifndef __BNX2_H__
|
|
+#define __BNX2_H__
|
|
+
|
|
+#include "nic.h"
|
|
+
|
|
+/******************************************************************************
|
|
+ * Default BNX2 values
|
|
+ ******************************************************************************/
|
|
+#define DEFAULT_NUM_RXBD 3
|
|
+#define DEFAULT_RX_LEN 0x400
|
|
+
|
|
+/******************************************************************************
|
|
+ * BNX2 Hardware structures
|
|
+ ******************************************************************************/
|
|
+/* status_block definition for MSI */
|
|
+struct status_block {
|
|
+ volatile __u32 status_attn_bits;
|
|
+ volatile __u32 status_attn_bits_ack;
|
|
+ volatile __u32 tx0;
|
|
+ volatile __u32 tx2;
|
|
+ volatile __u32 rx0;
|
|
+ volatile __u32 rx2;
|
|
+ volatile __u32 rx4;
|
|
+ volatile __u32 rx6;
|
|
+ volatile __u32 rx8;
|
|
+ volatile __u32 rx10;
|
|
+ volatile __u32 rx12;
|
|
+ volatile __u32 rx14;
|
|
+ volatile __u32 cmd;
|
|
+ volatile __u32 idx;
|
|
+};
|
|
+
|
|
+/* status_block definition for MSI-X */
|
|
+struct status_block_msix {
|
|
+#if 0
|
|
+#if defined(__BIG_ENDIAN)
|
|
+ __u16 status_tx_quick_consumer_index;
|
|
+ __u16 status_rx_quick_consumer_index;
|
|
+ __u16 status_completion_producer_index;
|
|
+ __u16 status_cmd_consumer_index;
|
|
+ __u32 status_unused;
|
|
+ __u16 status_idx;
|
|
+ __u8 status_unused2;
|
|
+ __u8 status_blk_num;
|
|
+#elif defined(__LITTLE_ENDIAN)
|
|
+ __u16 status_rx_quick_consumer_index;
|
|
+ __u16 status_tx_quick_consumer_index;
|
|
+ __u16 status_cmd_consumer_index;
|
|
+ __u16 status_completion_producer_index;
|
|
+ __u32 status_unused;
|
|
+ __u8 status_blk_num;
|
|
+ __u8 status_unused2;
|
|
+ __u16 status_idx;
|
|
+#endif
|
|
+#endif
|
|
+ __u16 status_rx_quick_consumer_index;
|
|
+ __u16 status_tx_quick_consumer_index;
|
|
+ __u16 status_cmd_consumer_index;
|
|
+ __u16 status_completion_producer_index;
|
|
+ __u32 status_unused;
|
|
+ __u8 status_blk_num;
|
|
+ __u8 status_unused2;
|
|
+ __u16 status_idx;
|
|
+};
|
|
+
|
|
+/* TX Buffer descriptor */
|
|
+struct tx_bd {
|
|
+ __u32 tx_bd_haddr_hi;
|
|
+ __u32 tx_bd_haddr_lo;
|
|
+ __u32 tx_bd_mss_nbytes;
|
|
+ __u32 tx_bd_vlan_tag_flags;
|
|
+#define TX_BD_FLAGS_VLAN_TAG (1<<3)
|
|
+#define TX_BD_FLAGS_END (1<<6)
|
|
+#define TX_BD_FLAGS_START (1<<7)
|
|
+};
|
|
+
|
|
+/* RX Buffer descriptor */
|
|
+struct rx_bd {
|
|
+ __u32 rx_bd_haddr_hi;
|
|
+ __u32 rx_bd_haddr_lo;
|
|
+
|
|
+ __u32 rx_bd_len;
|
|
+ __u32 rx_bd_flags;
|
|
+#define RX_BD_FLAGS_END (1<<2)
|
|
+#define RX_BD_FLAGS_START (1<<3)
|
|
+
|
|
+};
|
|
+
|
|
+/* This is the RX L2 Frame header */
|
|
+struct l2_fhdr {
|
|
+ __u32 l2_fhdr_status;
|
|
+#define L2_FHDR_ERRORS_BAD_CRC (1<<17)
|
|
+#define L2_FHDR_ERRORS_PHY_DECODE (1<<18)
|
|
+#define L2_FHDR_ERRORS_ALIGNMENT (1<<19)
|
|
+#define L2_FHDR_ERRORS_TOO_SHORT (1<<20)
|
|
+#define L2_FHDR_ERRORS_GIANT_FRAME (1<<21)
|
|
+#define L2_FHDR_ERRORS_TCP_XSUM (1<<28)
|
|
+#define L2_FHDR_ERRORS_UDP_XSUM (1<<31)
|
|
+
|
|
+#define L2_FHDR_STATUS_UDP_DATAGRAM (1<<15)
|
|
+#define L2_FHDR_STATUS_TCP_DATAGRAM (1<<14)
|
|
+#define L2_FHDR_STATUS_IP_DATAGRAM (1<<13)
|
|
+#define L2_FHDR_STATUS_LLC_SNAP (1<<7)
|
|
+#define L2_FHDR_STATUS_VLAN_TAG (1<<6)
|
|
+
|
|
+ __u32 l2_fhdr_hash;
|
|
+
|
|
+ __u32 l2_fhdr_vtag_len;
|
|
+ __u32 l2_fhdr_xsum;
|
|
+};
|
|
+
|
|
+/******************************************************************************
|
|
+ * BNX2 Registers Defitions/Values
|
|
+ ******************************************************************************/
|
|
+#define BNX2_MISC_ID 0x00000808
|
|
+#define BNX2_EMAC_MAC_MATCH4 0x00001420
|
|
+#define BNX2_EMAC_MAC_MATCH5 0x00001424
|
|
+
|
|
+#define BNX2_EMAC_RX_MODE 0x000014c8
|
|
+#define BNX2_EMAC_RX_MODE_RESET (1L<<0)
|
|
+#define BNX2_EMAC_RX_MODE_FLOW_EN (1L<<2)
|
|
+#define BNX2_EMAC_RX_MODE_KEEP_MAC_CONTROL (1L<<3)
|
|
+#define BNX2_EMAC_RX_MODE_KEEP_PAUSE (1L<<4)
|
|
+#define BNX2_EMAC_RX_MODE_ACCEPT_OVERSIZE (1L<<5)
|
|
+#define BNX2_EMAC_RX_MODE_ACCEPT_RUNTS (1L<<6)
|
|
+#define BNX2_EMAC_RX_MODE_LLC_CHK (1L<<7)
|
|
+#define BNX2_EMAC_RX_MODE_PROMISCUOUS (1L<<8)
|
|
+#define BNX2_EMAC_RX_MODE_NO_CRC_CHK (1L<<9)
|
|
+#define BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG (1L<<10)
|
|
+#define BNX2_EMAC_RX_MODE_FILT_BROADCAST (1L<<11)
|
|
+#define BNX2_EMAC_RX_MODE_SORT_MODE (1L<<12)
|
|
+
|
|
+#define BNX2_RPM_SORT_USER2 0x00001828
|
|
+#define BNX2_RPM_SORT_USER2_PM_EN (0xffffL<<0)
|
|
+#define BNX2_RPM_SORT_USER2_BC_EN (1L<<16)
|
|
+#define BNX2_RPM_SORT_USER2_MC_EN (1L<<17)
|
|
+#define BNX2_RPM_SORT_USER2_MC_HSH_EN (1L<<18)
|
|
+#define BNX2_RPM_SORT_USER2_PROM_EN (1L<<19)
|
|
+#define BNX2_RPM_SORT_USER2_VLAN_EN (0xfL<<20)
|
|
+#define BNX2_RPM_SORT_USER2_PROM_VLAN (1L<<24)
|
|
+#define BNX2_RPM_SORT_USER2_ENA (1L<<31)
|
|
+
|
|
+/*
|
|
+ * tsch_reg definition
|
|
+ * offset: 0x4c00
|
|
+ */
|
|
+#define BNX2_TSCH_TSS_CFG 0x00004c1c
|
|
+#define BNX2_TSCH_TSS_CFG_TSS_START_CID (0x7ffL<<8)
|
|
+#define BNX2_TSCH_TSS_CFG_NUM_OF_TSS_CON (0xfL<<24)
|
|
+#define CNIC_UIO_INVALID_FD -1
|
|
+
|
|
+#define BNX2_L2CTX_TX_HOST_BIDX 0x00000088
|
|
+#define BNX2_L2CTX_TX_HOST_BSEQ 0x00000090
|
|
+
|
|
+#define BNX2_L2CTX_HOST_BDIDX 0x00000004
|
|
+#define BNX2_L2CTX_HOST_BSEQ 0x00000008
|
|
+
|
|
+/* Used to determin the CHIP ID */
|
|
+/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
|
|
+#define BNX2_CHIP_NUM(bp) ((bp) & 0xffff0000)
|
|
+#define CHIP_NUM_5706 0x57060000
|
|
+#define CHIP_NUM_5708 0x57080000
|
|
+#define CHIP_NUM_5709 0x57090000
|
|
+
|
|
+#define CHIP_REV(bp) ((bp) & 0x0000f000)
|
|
+#define CHIP_REV_Ax 0x00000000
|
|
+#define CHIP_REV_Bx 0x00001000
|
|
+#define CHIP_REV_Cx 0x00002000
|
|
+
|
|
+#define CHIP_METAL(bp) ((bp) & 0x00000ff0)
|
|
+#define CHIP_BONDING(bp) ((bp) & 0x0000000f)
|
|
+
|
|
+#define CHIP_ID(bp) ((bp) & 0xfffffff0)
|
|
+#define CHIP_ID_5706_A0 0x57060000
|
|
+#define CHIP_ID_5706_A1 0x57060010
|
|
+#define CHIP_ID_5706_A2 0x57060020
|
|
+#define CHIP_ID_5708_A0 0x57080000
|
|
+#define CHIP_ID_5708_B0 0x57081000
|
|
+#define CHIP_ID_5708_B1 0x57081010
|
|
+#define CHIP_ID_5709_A0 0x57090000
|
|
+#define CHIP_ID_5709_A1 0x57090010
|
|
+
|
|
+#define CHIP_BOND_ID(bp) ((bp) & 0xf)
|
|
+
|
|
+#define BNX2_SBLK_EVEN_IDX(x) (((x) & 0xffff0000) >> 16)
|
|
+
|
|
+#define TX_DESC_CNT (4096 / sizeof(struct tx_bd))
|
|
+#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
|
|
+
|
|
+#define NEXT_TX_BD(x) ((((x) & (MAX_TX_DESC_CNT - 1)) == \
|
|
+ (MAX_TX_DESC_CNT - 1)) ? \
|
|
+ (x) + 2 : (x) + 1)
|
|
+
|
|
+#define TX_RING_IDX(x) ((x) & MAX_TX_DESC_CNT)
|
|
+
|
|
+#define RX_DESC_CNT (4096 / sizeof(struct rx_bd))
|
|
+#define MAX_RX_DESC_CNT (RX_DESC_CNT - 1)
|
|
+
|
|
+#define NEXT_RX_BD(x) ((((x) & (MAX_RX_DESC_CNT - 1)) == \
|
|
+ (MAX_RX_DESC_CNT - 1)) ? \
|
|
+ (x) + 2 : (x) + 1)
|
|
+
|
|
+#define MB_KERNEL_CTX_SHIFT 8
|
|
+#define MB_KERNEL_CTX_SIZE (1 << MB_KERNEL_CTX_SHIFT)
|
|
+#define MB_KERNEL_CTX_MASK (MB_KERNEL_CTX_SIZE - 1)
|
|
+#define MB_GET_CID_ADDR(_cid) (0x10000 + ((_cid) << MB_KERNEL_CTX_SHIFT))
|
|
+
|
|
+typedef struct bnx2 {
|
|
+ nic_t *parent;
|
|
+
|
|
+ uint16_t flags;
|
|
+#define BNX2_UIO_MSIX_ENABLED 0x0001
|
|
+#define BNX2_UIO_TX_HAS_SENT 0x0002
|
|
+#define BNX2_OPENED 0x0004
|
|
+
|
|
+ int bar0_fd;
|
|
+ void *reg; /* Pointer to the mapped registers */
|
|
+
|
|
+ __u32 tx_bidx_io;
|
|
+ __u32 tx_bseq_io;
|
|
+
|
|
+ __u16 tx_prod;
|
|
+ __u16 tx_cons;
|
|
+ __u32 tx_bseq;
|
|
+
|
|
+ __u32 rx_bidx_io;
|
|
+ __u32 rx_bseq_io;
|
|
+
|
|
+ __u16 rx_prod;
|
|
+ __u16 rx_cons;
|
|
+ __u32 rx_bseq;
|
|
+
|
|
+ /* RX ring parameters */
|
|
+ uint32_t rx_ring_size;
|
|
+ uint32_t rx_buffer_size;
|
|
+
|
|
+ void *bufs; /* Pointer to the mapped buffer space */
|
|
+
|
|
+ /* Hardware Status Block locations */
|
|
+ void *sblk_map;
|
|
+ union {
|
|
+ struct status_block *msi;
|
|
+ struct status_block_msix *msix;
|
|
+ } status_blk;
|
|
+ size_t status_blk_size;
|
|
+
|
|
+ __u16(*get_rx_cons) (struct bnx2 *);
|
|
+ __u16(*get_tx_cons) (struct bnx2 *);
|
|
+
|
|
+ uint16_t rx_index;
|
|
+ struct l2_fhdr **rx_ring;
|
|
+ void **rx_pkt_ring;
|
|
+
|
|
+ struct tx_bd *tx_ring;
|
|
+ void *tx_pkt;
|
|
+
|
|
+ struct l2_fhdr rcv_l2_fhdr;
|
|
+ __u8 rcv_buf[1500 + 2];
|
|
+ __u32 rcv_size;
|
|
+} bnx2_t;
|
|
+
|
|
+/******************************************************************************
|
|
+ * bnx2 Function Declarations
|
|
+ ******************************************************************************/
|
|
+struct nic_ops *bnx2_get_ops();
|
|
+#endif /* __BNX2_H__ */
|
|
diff --git a/iscsiuio/src/unix/libs/bnx2x.c b/iscsiuio/src/unix/libs/bnx2x.c
|
|
new file mode 100644
|
|
index 0000000..1495762
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/libs/bnx2x.c
|
|
@@ -0,0 +1,1634 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * bnx2x.c - bnx2x user space driver
|
|
+ *
|
|
+ */
|
|
+#include <errno.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <arpa/inet.h>
|
|
+#include <linux/types.h> /* Needed for linux/ethtool.h on RHEL 5.x */
|
|
+#include <linux/sockios.h>
|
|
+#include <linux/ethtool.h>
|
|
+#include <sys/mman.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/user.h>
|
|
+#include <fcntl.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+#include "config.h"
|
|
+
|
|
+#include "build_date.h"
|
|
+#include "bnx2x.h"
|
|
+#include "cnic.h"
|
|
+#include "logger.h"
|
|
+#include "nic.h"
|
|
+#include "nic_id.h"
|
|
+#include "nic_utils.h"
|
|
+#include "options.h"
|
|
+
|
|
+#define PFX "bnx2x "
|
|
+
|
|
+/* Foward struct declarations */
|
|
+struct nic_ops bnx2x_op;
|
|
+
|
|
+/*******************************************************************************
|
|
+ * NIC Library Strings
|
|
+ ******************************************************************************/
|
|
+static const char library_name[] = "bnx2x";
|
|
+static const char library_version[] = PACKAGE_VERSION;
|
|
+static const char library_uio_name[] = "bnx2x_cnic";
|
|
+
|
|
+/* The name that should be returned from /sys/class/uio/uio0/name */
|
|
+static const char cnic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name";
|
|
+static const char bnx2x_uio_sysfs_name[] = "bnx2x_cnic";
|
|
+
|
|
+/*******************************************************************************
|
|
+ * String constants used to display human readable adapter name
|
|
+ ******************************************************************************/
|
|
+static const char brcm_57710[] = "QLogic NetXtreme II BCM57710 10-Gigabit";
|
|
+static const char brcm_57711[] = "QLogic NetXtreme II BCM57711 10-Gigabit";
|
|
+static const char brcm_57711e[] = "QLogic NetXtreme II BCM57711E 10-Gigabit";
|
|
+static const char brcm_57712[] = "QLogic NetXtreme II BCM57712 10-Gigabit";
|
|
+static const char brcm_57712_MF[] = "QLogic NetXtreme II BCM57712 MF "
|
|
+ "10-Gigabit";
|
|
+static const char brcm_57712_VF[] = "QLogic NetXtreme II BCM57712 VF "
|
|
+ "10-Gigabit";
|
|
+static const char brcm_57713[] = "QLogic NetXtreme II BCM57713 10-Gigabit";
|
|
+static const char brcm_57713e[] = "QLogic NetXtreme II BCM57713E 10-Gigabit";
|
|
+static const char brcm_57800[] = "QLogic NetXtreme II BCM57800 10-Gigabit";
|
|
+static const char brcm_57800_MF[] = "QLogic NetXtreme II BCM57800 MF "
|
|
+ "10-Gigabit";
|
|
+static const char brcm_57800_VF[] = "QLogic NetXtreme II BCM57800 VF "
|
|
+ "10-Gigabit";
|
|
+static const char brcm_57810[] = "QLogic NetXtreme II BCM57810 10-Gigabit";
|
|
+static const char brcm_57810_MF[] = "QLogic NetXtreme II BCM57810 MF "
|
|
+ "10-Gigabit";
|
|
+static const char brcm_57810_VF[] = "QLogic NetXtreme II BCM57810 VF "
|
|
+ "10-Gigabit";
|
|
+static const char brcm_57811[] = "QLogic NetXtreme II BCM57811 10-Gigabit";
|
|
+static const char brcm_57811_MF[] = "QLogic NetXtreme II BCM57811 MF "
|
|
+ "10-Gigabit";
|
|
+static const char brcm_57811_VF[] = "QLogic NetXtreme II BCM57811 VF "
|
|
+ "10-Gigabit";
|
|
+static const char brcm_57840[] = "QLogic NetXtreme II BCM57840 10-Gigabit";
|
|
+static const char brcm_57840_MF[] = "QLogic NetXtreme II BCM57840 MF "
|
|
+ "10-Gigabit";
|
|
+static const char brcm_57840_VF[] = "QLogic NetXtreme II BCM57840 VF "
|
|
+ "10-Gigabit";
|
|
+static const char brcm_57840_4_10[] = "QLogic NetXtreme II BCM57840 4x"
|
|
+ "10-Gigabit";
|
|
+static const char brcm_57840_2_20[] = "QLogic NetXtreme II BCM57840 2x"
|
|
+ "20-Gigabit";
|
|
+
|
|
+/*******************************************************************************
|
|
+ * PCI ID constants
|
|
+ ******************************************************************************/
|
|
+#define PCI_VENDOR_ID_BROADCOM 0x14e4
|
|
+#define PCI_DEVICE_ID_NX2_57710 0x164e
|
|
+#define PCI_DEVICE_ID_NX2_57711 0x164f
|
|
+#define PCI_DEVICE_ID_NX2_57711E 0x1650
|
|
+#define PCI_DEVICE_ID_NX2_57712 0x1662
|
|
+#define PCI_DEVICE_ID_NX2_57712_MF 0x1663
|
|
+#define PCI_DEVICE_ID_NX2_57712_VF 0x166f
|
|
+#define PCI_DEVICE_ID_NX2_57713 0x1651
|
|
+#define PCI_DEVICE_ID_NX2_57713E 0x1652
|
|
+#define PCI_DEVICE_ID_NX2_57800 0x168a
|
|
+#define PCI_DEVICE_ID_NX2_57800_MF 0x16a5
|
|
+#define PCI_DEVICE_ID_NX2_57800_VF 0x16a9
|
|
+#define PCI_DEVICE_ID_NX2_57810 0x168e
|
|
+#define PCI_DEVICE_ID_NX2_57810_MF 0x16ae
|
|
+#define PCI_DEVICE_ID_NX2_57810_VF 0x16af
|
|
+#define PCI_DEVICE_ID_NX2_57811 0x163d
|
|
+#define PCI_DEVICE_ID_NX2_57811_MF 0x163e
|
|
+#define PCI_DEVICE_ID_NX2_57811_VF 0x163f
|
|
+#define PCI_DEVICE_ID_NX2_57840_OBSOLETE 0x168d
|
|
+#define PCI_DEVICE_ID_NX2_57840_MF_OBSOLETE 0x16ab
|
|
+#define PCI_DEVICE_ID_NX2_57840_4_10 0x16a1
|
|
+#define PCI_DEVICE_ID_NX2_57840_2_20 0x16a2
|
|
+#define PCI_DEVICE_ID_NX2_57840_MF 0x16a4
|
|
+#define PCI_DEVICE_ID_NX2_57840_VF 0x16ad
|
|
+#define PCI_ANY_ID (~0)
|
|
+
|
|
+/* This is the table used to match PCI vendor and device ID's to the
|
|
+ * human readable string names of the devices */
|
|
+static const struct pci_device_id bnx2x_pci_tbl[] = {
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57710},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57711},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711E,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57711e},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57712,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57712},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57712_MF,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57712_MF},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57712_VF,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57712_VF},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57713,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57713},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57713E,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57713e},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57800,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57800},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57800_MF,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57800_MF},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57800_VF,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57800_VF},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57810,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57810},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57810_MF,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57810_MF},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57810_VF,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57810_VF},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57811,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57811},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57811_MF,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57811_MF},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57811_VF,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57811_VF},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_OBSOLETE,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57840},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_MF_OBSOLETE,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_MF},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_4_10,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_4_10},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_2_20,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_2_20},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_MF,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_MF},
|
|
+ {PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57840_VF,
|
|
+ PCI_ANY_ID, PCI_ANY_ID, brcm_57840_VF},
|
|
+};
|
|
+
|
|
+static struct iro e1_iro[2] = {
|
|
+ {0x45a0, 0x90, 0x8, 0x0, 0x8}, /* T6.0 */
|
|
+ {0x50c8, 0x90, 0x8, 0x0, 0x8}, /* T6.4 */
|
|
+};
|
|
+
|
|
+static struct iro e1h_iro[2] = {
|
|
+ {0x1c40, 0xe0, 0x8, 0x0, 0x8}, /* T6.0 */
|
|
+ {0x1e00, 0xe0, 0x8, 0x0, 0x8}, /* T6.4 */
|
|
+};
|
|
+
|
|
+static struct iro e2_iro[2] = {
|
|
+ {0x6000, 0x20, 0x0, 0x0, 0x8}, /* T6.0 */
|
|
+ {0x6000, 0x20, 0x0, 0x0, 0x8}, /* T6.4 */
|
|
+};
|
|
+
|
|
+struct bnx2x_driver_version bnx2x_version = {
|
|
+ BNX2X_UNKNOWN_MAJOR_VERSION,
|
|
+ BNX2X_UNKNOWN_MINOR_VERSION,
|
|
+ BNX2X_UNKNOWN_SUB_MINOR_VERSION,
|
|
+};
|
|
+
|
|
+static int bnx2x_clear_tx_intr(nic_t *nic);
|
|
+
|
|
+/*******************************************************************************
|
|
+ * BNX2X Library Functions
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * bnx2x_get_library_name() - Used to get the name of this NIC libary
|
|
+ * @param name - This function will return the pointer to this NIC
|
|
+ * library name
|
|
+ * @param name_size
|
|
+ */
|
|
+static void bnx2x_get_library_name(char **name, size_t *name_size)
|
|
+{
|
|
+ *name = (char *)library_name;
|
|
+ *name_size = sizeof(library_name);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_get_library_version() - Used to get the version string of this
|
|
+ * NIC libary
|
|
+ * @param version - This function will return the pointer to this NIC
|
|
+ * library version string
|
|
+ * @param version_size - This will be set with the version size
|
|
+ */
|
|
+static void bnx2x_get_library_version(char **version, size_t *version_size)
|
|
+{
|
|
+ *version = (char *)library_version;
|
|
+ *version_size = sizeof(library_version);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_get_build_date() - Used to get the build date string of this library
|
|
+ * @param version - This function will return the pointer to this NIC
|
|
+ * library build date string
|
|
+ * @param version_size - This will be set with the build date string size
|
|
+ */
|
|
+static void bnx2x_get_build_date(char **build, size_t *build_size)
|
|
+{
|
|
+ *build = (char *)build_date;
|
|
+ *build_size = sizeof(build_date);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_get_transport_name() - Used to get the transport name associated
|
|
+ * with this this NIC libary
|
|
+ * @param transport_name - This function will return the pointer to this NIC
|
|
+ * library's associated transport string
|
|
+ * @param transport_name_size - This will be set with the transport name size
|
|
+ */
|
|
+static void bnx2x_get_transport_name(char **transport_name,
|
|
+ size_t *transport_name_size)
|
|
+{
|
|
+ *transport_name = (char *)bnx2i_library_transport_name;
|
|
+ *transport_name_size = bnx2i_library_transport_name_size;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_get_uio_name() - Used to get the uio name associated with this this
|
|
+ * NIC libary
|
|
+ * @param uio_name - This function will return the pointer to this NIC
|
|
+ * library's associated uio string
|
|
+ * @param transport_name_size - This will be set with the uio name size
|
|
+ */
|
|
+static void bnx2x_get_uio_name(char **uio_name, size_t *uio_name_size)
|
|
+{
|
|
+ *uio_name = (char *)library_uio_name;
|
|
+ *uio_name_size = sizeof(library_uio_name);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_get_pci_table() - Used to get the PCI table for this NIC libary to
|
|
+ * determine which NIC's based off of PCI ID's are
|
|
+ * supported
|
|
+ * @param table - This function will return the pointer to the PCI table
|
|
+ * @param entries - This function will return the number of entries in the NIC
|
|
+ * library's PCI table
|
|
+ */
|
|
+static void bnx2x_get_pci_table(struct pci_device_id **table,
|
|
+ uint32_t *entries)
|
|
+{
|
|
+ *table = (struct pci_device_id *)bnx2x_pci_tbl;
|
|
+ *entries =
|
|
+ (uint32_t) (sizeof(bnx2x_pci_tbl) / sizeof(bnx2x_pci_tbl[0]));
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_get_ops() - Used to get the NIC library op table
|
|
+ * @param op - The op table of this NIC library
|
|
+ */
|
|
+struct nic_ops *bnx2x_get_ops()
|
|
+{
|
|
+ return &bnx2x_op;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * bnx2x Utility Functions
|
|
+ ******************************************************************************/
|
|
+/*******************************************************************************
|
|
+ * Utility Functions Used to read register from the bnx2x device
|
|
+ ******************************************************************************/
|
|
+static void bnx2x_set_drv_version_unknown(bnx2x_t *bp)
|
|
+{
|
|
+ bp->version.major = BNX2X_UNKNOWN_MAJOR_VERSION;
|
|
+ bp->version.minor = BNX2X_UNKNOWN_MINOR_VERSION;
|
|
+ bp->version.sub_minor = BNX2X_UNKNOWN_SUB_MINOR_VERSION;
|
|
+}
|
|
+
|
|
+/* Return: 1 = Unknown, 0 = Known */
|
|
+static int bnx2x_is_drv_version_unknown(struct bnx2x_driver_version *version)
|
|
+{
|
|
+ if ((version->major == (uint16_t)BNX2X_UNKNOWN_MAJOR_VERSION) &&
|
|
+ (version->minor == (uint16_t)BNX2X_UNKNOWN_MINOR_VERSION) &&
|
|
+ (version->sub_minor == (uint16_t)BNX2X_UNKNOWN_SUB_MINOR_VERSION)) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_get_drv_version() - Used to determine the driver version
|
|
+ * @param bp - Device used to determine bnx2x driver version
|
|
+ */
|
|
+static int bnx2x_get_drv_version(bnx2x_t *bp)
|
|
+{
|
|
+ nic_t *nic = bp->parent;
|
|
+ int fd, rc;
|
|
+ struct ifreq ifr;
|
|
+ struct ethtool_drvinfo drvinfo;
|
|
+ char *tok, *save_ptr = NULL;
|
|
+
|
|
+ /* Setup our control structures. */
|
|
+ memset(&ifr, 0, sizeof(ifr));
|
|
+ strcpy(ifr.ifr_name, nic->eth_device_name);
|
|
+
|
|
+ /* Open control socket. */
|
|
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
+ if (fd < 0) {
|
|
+ LOG_ERR(PFX "%s: Cannot get socket to determine version "
|
|
+ "[0x%x %s]", nic->log_name, errno, strerror(errno));
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ drvinfo.cmd = ETHTOOL_GDRVINFO;
|
|
+ ifr.ifr_data = (caddr_t) &drvinfo;
|
|
+ rc = ioctl(fd, SIOCETHTOOL, &ifr);
|
|
+ if (rc < 0) {
|
|
+ LOG_ERR(PFX "%s: call to ethool IOCTL failed [0x%x %s]",
|
|
+ nic->log_name, errno, strerror(errno));
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ tok = strtok_r(drvinfo.version, ".", &save_ptr);
|
|
+ if (tok == NULL) {
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+ bp->version.major = atoi(tok);
|
|
+
|
|
+ tok = strtok_r(NULL, ".", &save_ptr);
|
|
+ if (tok == NULL) {
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+ bp->version.minor = atoi(tok);
|
|
+
|
|
+ tok = strtok_r(NULL, ".", &save_ptr);
|
|
+ if (tok == NULL) {
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+ bp->version.sub_minor = atoi(tok);
|
|
+
|
|
+ LOG_INFO(PFX "%s: bnx2x driver using version %d.%d.%d",
|
|
+ nic->log_name,
|
|
+ bp->version.major, bp->version.minor, bp->version.sub_minor);
|
|
+
|
|
+ close(fd);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ close(fd);
|
|
+ bnx2x_set_drv_version_unknown(bp);
|
|
+
|
|
+ LOG_ERR(PFX "%s: error parsing driver string: '%s'",
|
|
+ nic->log_name, drvinfo.version);
|
|
+
|
|
+ return rc;
|
|
+
|
|
+}
|
|
+
|
|
+static inline int bnx2x_is_ver70(bnx2x_t *bp)
|
|
+{
|
|
+ return (bp->version.major == 1 && bp->version.minor >= 70);
|
|
+}
|
|
+
|
|
+static inline int bnx2x_is_ver60(bnx2x_t *bp)
|
|
+{
|
|
+ return (bp->version.major == 1 && (bp->version.minor == 60 ||
|
|
+ bp->version.minor == 62 ||
|
|
+ bp->version.minor == 64));
|
|
+}
|
|
+
|
|
+static inline int bnx2x_is_ver60_plus(bnx2x_t *bp)
|
|
+{
|
|
+ return bnx2x_is_ver60(bp) || bnx2x_is_ver70(bp);
|
|
+}
|
|
+
|
|
+static inline int bnx2x_is_ver52(bnx2x_t *bp)
|
|
+{
|
|
+ return (bp->version.major == 1 && bp->version.minor == 52);
|
|
+}
|
|
+
|
|
+static void bnx2x_wr32(bnx2x_t *bp, __u32 off, __u32 val)
|
|
+{
|
|
+ *((volatile __u32 *)(bp->reg + off)) = val;
|
|
+}
|
|
+
|
|
+static void bnx2x_doorbell(bnx2x_t *bp, __u32 off, __u32 val)
|
|
+{
|
|
+ *((volatile __u32 *)(bp->reg2 + off)) = val;
|
|
+}
|
|
+
|
|
+static void bnx2x_flush_doorbell(bnx2x_t *bp, __u32 off)
|
|
+{
|
|
+ volatile __u32 tmp __attribute__((__unused__));
|
|
+
|
|
+ barrier();
|
|
+ tmp = *((volatile __u32 *)(bp->reg2 + off));
|
|
+}
|
|
+
|
|
+static __u32 bnx2x_rd32(bnx2x_t *bp, __u32 off)
|
|
+{
|
|
+ return *((volatile __u32 *)(bp->reg + off));
|
|
+}
|
|
+
|
|
+static int bnx2x_reg_sync(bnx2x_t *bp, __u32 off, __u16 length)
|
|
+{
|
|
+ return msync(bp->reg + off, length, MS_SYNC);
|
|
+}
|
|
+
|
|
+static void bnx2x_update_rx_prod(bnx2x_t *bp)
|
|
+{
|
|
+ struct ustorm_eth_rx_producers rx_prods = { 0 };
|
|
+ int i;
|
|
+
|
|
+ rx_prods.bd_prod = bp->rx_bd_prod;
|
|
+ rx_prods.cqe_prod = bp->rx_prod;
|
|
+
|
|
+ barrier();
|
|
+
|
|
+ for (i = 0; i < sizeof(struct ustorm_eth_rx_producers) / 4; i++)
|
|
+ bnx2x_wr32(bp, bp->rx_prod_io + i * 4,
|
|
+ ((__u32 *)&rx_prods)[i]);
|
|
+
|
|
+ barrier();
|
|
+
|
|
+ bnx2x_reg_sync(bp, bp->rx_prod_io,
|
|
+ sizeof(struct ustorm_eth_rx_producers));
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_get_chip_id() - Used to retrive the chip ID from the nic
|
|
+ * @param dev - Device used to determin NIC type
|
|
+ * @return Chip ID read from the MISC ID register
|
|
+ */
|
|
+static int bnx2x_get_chip_id(bnx2x_t *bp)
|
|
+{
|
|
+ int val, id;
|
|
+
|
|
+ /* Get the chip revision id and number. */
|
|
+ /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
|
|
+ val = bnx2x_rd32(bp, BNX2X_MISC_REG_CHIP_NUM);
|
|
+ id = ((val & 0xffff) << 16);
|
|
+ val = bnx2x_rd32(bp, BNX2X_MISC_REG_CHIP_REV);
|
|
+ id |= ((val & 0xf) << 12);
|
|
+ val = bnx2x_rd32(bp, BNX2X_MISC_REG_CHIP_METAL);
|
|
+ id |= ((val & 0xff) << 4);
|
|
+ val = bnx2x_rd32(bp, BNX2X_MISC_REG_BOND_ID);
|
|
+ id |= (val & 0xf);
|
|
+
|
|
+ return id;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_uio_verify()
|
|
+ *
|
|
+ */
|
|
+static int bnx2x_uio_verify(nic_t *nic)
|
|
+{
|
|
+ char *raw = NULL, *raw_tmp;
|
|
+ uint32_t raw_size = 0;
|
|
+ char temp_path[sizeof(cnic_uio_sysfs_name_tempate) + 8];
|
|
+ int rc = 0;
|
|
+
|
|
+ /* Build the path to determine uio name */
|
|
+ snprintf(temp_path, sizeof(temp_path),
|
|
+ cnic_uio_sysfs_name_tempate, nic->uio_minor);
|
|
+
|
|
+ rc = capture_file(&raw, &raw_size, temp_path);
|
|
+ if (rc != 0)
|
|
+ goto error;
|
|
+
|
|
+ /* sanitize name string by replacing newline with null termination */
|
|
+ raw_tmp = raw;
|
|
+ while (*raw_tmp != '\n')
|
|
+ raw_tmp++;
|
|
+ *raw_tmp = '\0';
|
|
+
|
|
+ if (strncmp(raw, bnx2x_uio_sysfs_name,
|
|
+ sizeof(bnx2x_uio_sysfs_name)) != 0) {
|
|
+ LOG_ERR(PFX "%s: uio names not equal: "
|
|
+ "expecting %s got %s from %s",
|
|
+ nic->log_name, bnx2x_uio_sysfs_name, raw, temp_path);
|
|
+ rc = -EIO;
|
|
+ }
|
|
+
|
|
+ free(raw);
|
|
+
|
|
+ LOG_INFO(PFX "%s: Verified is a cnic_uio device", nic->log_name);
|
|
+
|
|
+error:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * bnx2x Utility Functions to get to the hardware consumer indexes
|
|
+ ******************************************************************************/
|
|
+static __u16 bnx2x_get_rx(bnx2x_t *bp)
|
|
+{
|
|
+ struct host_def_status_block *sblk = bp->status_blk.def;
|
|
+ __u16 rx_comp_cons;
|
|
+
|
|
+ msync(sblk, sizeof(*sblk), MS_SYNC);
|
|
+ rx_comp_cons =
|
|
+ sblk->u_def_status_block.
|
|
+ index_values[HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS];
|
|
+ if ((rx_comp_cons & BNX2X_MAX_RCQ_DESC_CNT(bp)) ==
|
|
+ BNX2X_MAX_RCQ_DESC_CNT(bp))
|
|
+ rx_comp_cons++;
|
|
+
|
|
+ return rx_comp_cons;
|
|
+}
|
|
+
|
|
+static __u16 bnx2x_get_rx_60(bnx2x_t *bp)
|
|
+{
|
|
+ struct host_sp_status_block *sblk = bp->status_blk.sp;
|
|
+ __u16 rx_comp_cons;
|
|
+
|
|
+ msync(sblk, sizeof(*sblk), MS_SYNC);
|
|
+ rx_comp_cons =
|
|
+ sblk->sp_sb.index_values[HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS];
|
|
+ if ((rx_comp_cons & BNX2X_MAX_RCQ_DESC_CNT(bp)) ==
|
|
+ BNX2X_MAX_RCQ_DESC_CNT(bp))
|
|
+ rx_comp_cons++;
|
|
+
|
|
+ return rx_comp_cons;
|
|
+}
|
|
+
|
|
+static __u16 bnx2x_get_tx(bnx2x_t *bp)
|
|
+{
|
|
+ struct host_def_status_block *sblk = bp->status_blk.def;
|
|
+ __u16 tx_cons;
|
|
+
|
|
+ msync(sblk, sizeof(*sblk), MS_SYNC);
|
|
+ tx_cons =
|
|
+ sblk->c_def_status_block.
|
|
+ index_values[HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS];
|
|
+
|
|
+ return tx_cons;
|
|
+}
|
|
+
|
|
+static __u16 bnx2x_get_tx_60(bnx2x_t *bp)
|
|
+{
|
|
+ struct host_sp_status_block *sblk = bp->status_blk.sp;
|
|
+ __u16 tx_cons;
|
|
+
|
|
+ msync(sblk, sizeof(*sblk), MS_SYNC);
|
|
+ tx_cons = sblk->sp_sb.index_values[HC_SP_INDEX_ETH_ISCSI_CQ_CONS];
|
|
+
|
|
+ return tx_cons;
|
|
+}
|
|
+
|
|
+typedef enum {
|
|
+ CNIC_VLAN_STRIPPING_ENABLED = 1,
|
|
+ CNIC_VLAN_STRIPPING_DISABLED = 2,
|
|
+} CNIC_VLAN_STRIPPING_MODE;
|
|
+
|
|
+/**
|
|
+ * bnx2x_strip_vlan_enabled() - This will query the device to determine whether
|
|
+ * VLAN tag stripping is enabled or not
|
|
+ * @param dev - device to check stripping or not
|
|
+ * @ return CNIC_VLAN_STRIPPING_ENABLED stripping is enabled
|
|
+ * CNIC_VLAN_STRIPPING_DISABLED stripping is not enabled
|
|
+ */
|
|
+static CNIC_VLAN_STRIPPING_MODE bnx2x_strip_vlan_enabled(bnx2x_t *bp)
|
|
+{
|
|
+ return CNIC_VLAN_STRIPPING_DISABLED;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_free() - Used to free a bnx2x structure
|
|
+ */
|
|
+static void bnx2x_free(nic_t *nic)
|
|
+{
|
|
+ if (nic->priv)
|
|
+ free(nic->priv);
|
|
+ nic->priv = NULL;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_alloc() - Used to allocate a bnx2x structure
|
|
+ */
|
|
+static bnx2x_t *bnx2x_alloc(nic_t *nic)
|
|
+{
|
|
+ bnx2x_t *bp = malloc(sizeof(*bp));
|
|
+
|
|
+ if (bp == NULL) {
|
|
+ LOG_ERR(PFX "%s: Could not allocate BNX2X space",
|
|
+ nic->log_name);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* Clear out the CNIC contents */
|
|
+ memset(bp, 0, sizeof(*bp));
|
|
+
|
|
+ bp->bar0_fd = INVALID_FD;
|
|
+ bp->bar2_fd = INVALID_FD;
|
|
+
|
|
+ bp->parent = nic;
|
|
+ nic->priv = (void *)bp;
|
|
+
|
|
+ bnx2x_set_drv_version_unknown(bp);
|
|
+
|
|
+ return bp;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_open() - This will initialize all the hardware resources underneath
|
|
+ * a struct cnic_uio device
|
|
+ * @param dev - The struct cnic_uio device to attach the hardware with
|
|
+ * @return 0 on success, on failure a errno will be returned
|
|
+ */
|
|
+static int bnx2x_open(nic_t *nic)
|
|
+{
|
|
+ bnx2x_t *bp;
|
|
+ struct stat uio_stat;
|
|
+ int i, rc;
|
|
+ __u32 val;
|
|
+ int count;
|
|
+ char sysfs_resc_path[80];
|
|
+ uint32_t bus;
|
|
+ uint32_t slot;
|
|
+ uint32_t func;
|
|
+
|
|
+ /* Sanity Check: validate the parameters */
|
|
+ if (nic == NULL) {
|
|
+ LOG_ERR(PFX "nic == NULL");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if ((nic->priv) != NULL &&
|
|
+ (((bnx2x_t *) (nic->priv))->flags & BNX2X_OPENED)) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ bp = bnx2x_alloc(nic);
|
|
+ if (bp == NULL)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ if (bnx2x_is_drv_version_unknown(&bnx2x_version)) {
|
|
+ /* If version is unknown, go read from ethtool */
|
|
+ rc = bnx2x_get_drv_version(bp);
|
|
+ if (rc)
|
|
+ goto open_error;
|
|
+ } else {
|
|
+ /* Version is not unknown, just use it */
|
|
+ bnx2x_version.major = bp->version.major;
|
|
+ bnx2x_version.minor = bp->version.minor;
|
|
+ bnx2x_version.sub_minor = bp->version.sub_minor;
|
|
+ }
|
|
+
|
|
+ count = 0;
|
|
+ while ((nic->fd < 0) && count < 15) {
|
|
+ /* udev might not have created the file yet */
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ sleep(1);
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+
|
|
+ nic->fd = open(nic->uio_device_name, O_RDWR | O_NONBLOCK);
|
|
+ if (nic->fd != INVALID_FD) {
|
|
+ LOG_ERR(PFX "%s: uio device has been brought up "
|
|
+ "via pid: %d on fd: %d",
|
|
+ nic->uio_device_name, getpid(), nic->fd);
|
|
+
|
|
+ rc = bnx2x_uio_verify(nic);
|
|
+ if (rc != 0)
|
|
+ continue;
|
|
+
|
|
+ break;
|
|
+ } else {
|
|
+ LOG_WARN(PFX "%s: Could not open device: %s, [%s]",
|
|
+ nic->log_name, nic->uio_device_name,
|
|
+ strerror(errno));
|
|
+
|
|
+ manually_trigger_uio_event(nic, nic->uio_minor);
|
|
+
|
|
+ /* udev might not have created the file yet */
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ sleep(1);
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+
|
|
+ count++;
|
|
+ }
|
|
+ }
|
|
+ if (fstat(nic->fd, &uio_stat) < 0) {
|
|
+ LOG_ERR(PFX "%s: Could not fstat device", nic->log_name);
|
|
+ rc = -ENODEV;
|
|
+ goto open_error;
|
|
+ }
|
|
+ nic->uio_minor = minor(uio_stat.st_rdev);
|
|
+
|
|
+ cnic_get_sysfs_pci_resource_path(nic, 0, sysfs_resc_path, 80);
|
|
+ bp->bar0_fd = open(sysfs_resc_path, O_RDWR | O_SYNC);
|
|
+ if (bp->bar0_fd < 0) {
|
|
+ LOG_ERR(PFX "%s: Could not open %s", nic->log_name,
|
|
+ sysfs_resc_path);
|
|
+ rc = -ENODEV;
|
|
+ goto open_error;
|
|
+ }
|
|
+
|
|
+ bp->reg = mmap(NULL, BNX2X_BAR_SIZE, PROT_READ | PROT_WRITE,
|
|
+ MAP_SHARED, bp->bar0_fd, (off_t) 0);
|
|
+
|
|
+ if (bp->reg == MAP_FAILED) {
|
|
+ LOG_INFO(PFX "%s: Couldn't mmap BAR registers: %s",
|
|
+ nic->log_name, strerror(errno));
|
|
+ bp->reg = NULL;
|
|
+ rc = errno;
|
|
+ goto open_error;
|
|
+ }
|
|
+
|
|
+ msync(bp->reg, BNX2X_BAR_SIZE, MS_SYNC);
|
|
+
|
|
+ cnic_get_sysfs_pci_resource_path(nic, 2, sysfs_resc_path, 80);
|
|
+ bp->bar2_fd = open(sysfs_resc_path, O_RDWR | O_SYNC);
|
|
+ if (bp->bar2_fd < 0) {
|
|
+ LOG_ERR(PFX "%s: Could not open %s", nic->log_name,
|
|
+ sysfs_resc_path);
|
|
+ rc = -ENODEV;
|
|
+ goto open_error;
|
|
+ }
|
|
+
|
|
+ bp->reg2 = mmap(NULL, BNX2X_BAR2_SIZE, PROT_READ | PROT_WRITE,
|
|
+ MAP_SHARED, bp->bar2_fd, (off_t) 0);
|
|
+
|
|
+ if (bp->reg2 == MAP_FAILED) {
|
|
+ LOG_INFO(PFX "%s: Couldn't mmap BAR2 registers: %s",
|
|
+ nic->log_name, strerror(errno));
|
|
+ bp->reg2 = NULL;
|
|
+ rc = errno;
|
|
+ goto open_error;
|
|
+ }
|
|
+
|
|
+ /* TODO: hardcoded with the cnic driver */
|
|
+ bp->rx_ring_size = 15;
|
|
+ bp->rx_buffer_size = 0x400;
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: using rx ring size: %d, rx buffer size: %d",
|
|
+ nic->log_name, bp->rx_ring_size, bp->rx_buffer_size);
|
|
+
|
|
+ /* Determine the number of UIO events that have already occured */
|
|
+ rc = detemine_initial_uio_events(nic, &nic->intr_count);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR("Could not determine the number ofinitial UIO events");
|
|
+ nic->intr_count = 0;
|
|
+ }
|
|
+
|
|
+ /* Allocate space for rx pkt ring */
|
|
+ bp->rx_pkt_ring = malloc(sizeof(void *) * bp->rx_ring_size);
|
|
+ if (bp->rx_pkt_ring == NULL) {
|
|
+ LOG_ERR(PFX "%s: Could not allocate space for rx_pkt_ring",
|
|
+ nic->log_name);
|
|
+ rc = errno;
|
|
+ goto open_error;
|
|
+ }
|
|
+
|
|
+ if (bnx2x_is_ver60_plus(bp))
|
|
+ bp->status_blk_size = sizeof(struct host_sp_status_block);
|
|
+ else if (bnx2x_is_ver52(bp))
|
|
+ bp->status_blk_size = sizeof(struct host_def_status_block);
|
|
+ else {
|
|
+ LOG_INFO(PFX "%s: Unsupported bnx2x driver [%d.%d]",
|
|
+ nic->log_name, bp->version.major, bp->version.minor);
|
|
+
|
|
+ rc = -ENOTSUP;
|
|
+ goto open_error;
|
|
+ }
|
|
+
|
|
+ bp->status_blk.def = mmap(NULL, bp->status_blk_size,
|
|
+ PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
+ nic->fd, (off_t) nic->page_size);
|
|
+ if (bp->status_blk.def == MAP_FAILED) {
|
|
+ LOG_INFO(PFX "%s: Could not mmap status block: %s",
|
|
+ nic->log_name, strerror(errno));
|
|
+ bp->status_blk.def = NULL;
|
|
+ rc = errno;
|
|
+ goto open_error;
|
|
+ }
|
|
+
|
|
+ bp->tx_ring = mmap(NULL, 4 * nic->page_size,
|
|
+ PROT_READ | PROT_WRITE,
|
|
+ MAP_SHARED | MAP_LOCKED,
|
|
+ nic->fd, (off_t) 2 * nic->page_size);
|
|
+ if (bp->tx_ring == MAP_FAILED) {
|
|
+ LOG_INFO(PFX "%s: Could not mmap tx ring: %s",
|
|
+ nic->log_name, strerror(errno));
|
|
+ bp->tx_ring = NULL;
|
|
+ rc = errno;
|
|
+ goto open_error;
|
|
+ }
|
|
+
|
|
+ bp->rx_comp_ring.cqe = (union eth_rx_cqe *)
|
|
+ (((__u8 *) bp->tx_ring) + 2 * nic->page_size);
|
|
+
|
|
+ bp->bufs = mmap(NULL, (bp->rx_ring_size + 1) * bp->rx_buffer_size,
|
|
+ PROT_READ | PROT_WRITE,
|
|
+ MAP_SHARED | MAP_LOCKED,
|
|
+ nic->fd, (off_t) 3 * nic->page_size);
|
|
+ if (bp->bufs == MAP_FAILED) {
|
|
+ LOG_INFO(PFX "%s: Could not mmap buffers: %s",
|
|
+ nic->log_name, strerror(errno));
|
|
+ bp->bufs = NULL;
|
|
+ rc = errno;
|
|
+ goto open_error;
|
|
+ }
|
|
+
|
|
+ bp->chip_id = bnx2x_get_chip_id(bp);
|
|
+ LOG_DEBUG(PFX "Chip ID: %x", bp->chip_id);
|
|
+
|
|
+ rc = get_bus_slot_func_num(nic, &bus, &slot, &func);
|
|
+ if (rc != 0) {
|
|
+ LOG_INFO(PFX "%s: Couldn't determine bus:slot.func",
|
|
+ nic->log_name);
|
|
+ goto open_error;
|
|
+ }
|
|
+ /* In E1/E1H use pci device function as read from sysfs.
|
|
+ * In E2/E3 read physical function from ME register since these chips
|
|
+ * support Physical Device Assignment where kernel BDF maybe arbitrary
|
|
+ * (depending on hypervisor).
|
|
+ */
|
|
+ if (CHIP_IS_E2_PLUS(bp)) {
|
|
+ func = (bnx2x_rd32(bp, BAR_ME_REGISTER) & ME_REG_ABS_PF_NUM) >>
|
|
+ ME_REG_ABS_PF_NUM_SHIFT;
|
|
+ }
|
|
+ bp->func = func;
|
|
+ bp->port = bp->func % PORT_MAX;
|
|
+
|
|
+ if (CHIP_IS_E2_PLUS(bp)) {
|
|
+ __u32 val = bnx2x_rd32(bp, MISC_REG_PORT4MODE_EN_OVWR);
|
|
+ if (!(val & 1))
|
|
+ val = bnx2x_rd32(bp, MISC_REG_PORT4MODE_EN);
|
|
+ else
|
|
+ val = (val >> 1) & 1;
|
|
+
|
|
+ if (val)
|
|
+ bp->pfid = func >> 1;
|
|
+ else
|
|
+ bp->pfid = func & 0x6;
|
|
+ } else {
|
|
+ bp->pfid = func;
|
|
+ }
|
|
+
|
|
+ if (bnx2x_is_ver60_plus(bp))
|
|
+ bp->port = bp->pfid & 1;
|
|
+
|
|
+ bp->cid = 17;
|
|
+ bp->client_id = 17;
|
|
+
|
|
+ if (bnx2x_is_ver60_plus(bp)) {
|
|
+ struct client_init_general_data *data = bp->bufs;
|
|
+
|
|
+ bp->client_id = data->client_id;
|
|
+ if (data->uid.cid)
|
|
+ bp->cid = data->uid.cid;
|
|
+ if (bp->version.minor >= 78 && bp->version.sub_minor >= 55 &&
|
|
+ data->uid.cid_override_key == UIO_USE_TX_DOORBELL) {
|
|
+ bp->tx_doorbell = data->uid.tx_db_off;
|
|
+ LOG_INFO(PFX "%s: tx doorbell override offset = 0x%x",
|
|
+ nic->log_name, bp->tx_doorbell);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "%s: func 0x%x, pfid 0x%x, client_id 0x%x, cid 0x%x",
|
|
+ nic->log_name, bp->func, bp->pfid, bp->client_id, bp->cid);
|
|
+
|
|
+ if (CHIP_IS_E1(bp))
|
|
+ bp->iro = e1_iro;
|
|
+ else if (CHIP_IS_E1H(bp))
|
|
+ bp->iro = e1h_iro;
|
|
+ else if (CHIP_IS_E2_PLUS(bp))
|
|
+ bp->iro = e2_iro;
|
|
+
|
|
+ if (bnx2x_is_ver60_plus(bp)) {
|
|
+ __u32 cl_qzone_id = BNX2X_CL_QZONE_ID(bp, bp->client_id);
|
|
+
|
|
+ bp->iro_idx = 0;
|
|
+ if (bp->version.minor >= 64) {
|
|
+ bp->iro_idx = 1;
|
|
+ cl_qzone_id = BNX2X_CL_QZONE_ID_64(bp, bp->client_id);
|
|
+ }
|
|
+
|
|
+ bp->rx_prod_io = BAR_USTRORM_INTMEM +
|
|
+ (CHIP_IS_E2_PLUS(bp) ?
|
|
+ USTORM_RX_PRODS_E2_OFFSET(cl_qzone_id) :
|
|
+ USTORM_RX_PRODS_E1X_OFFSET(bp->port, bp->client_id));
|
|
+
|
|
+ if (!bp->tx_doorbell)
|
|
+ bp->tx_doorbell = bp->cid * 0x80 + 0x40;
|
|
+
|
|
+ bp->get_rx_cons = bnx2x_get_rx_60;
|
|
+ bp->get_tx_cons = bnx2x_get_tx_60;
|
|
+ bp->tx_vlan_tag_bit = ETH_TX_BD_FLAGS_VLAN_TAG_T6X;
|
|
+ } else {
|
|
+ bp->rx_prod_io = BAR_USTRORM_INTMEM +
|
|
+ USTORM_RX_PRODS_OFFSET(bp->port, bp->client_id);
|
|
+
|
|
+ bp->tx_doorbell = bp->cid * nic->page_size + 0x40;
|
|
+
|
|
+ bp->get_rx_cons = bnx2x_get_rx;
|
|
+ bp->get_tx_cons = bnx2x_get_tx;
|
|
+ bp->tx_vlan_tag_bit = ETH_TX_BD_FLAGS_VLAN_TAG_T5X;
|
|
+ }
|
|
+
|
|
+ bp->tx_cons = 0;
|
|
+ bp->tx_prod = 0;
|
|
+ bp->tx_bd_prod = 0;
|
|
+ bp->tx_pkt = bp->bufs;
|
|
+
|
|
+ bp->rx_index = 0;
|
|
+ bp->rx_cons = 0;
|
|
+ bp->rx_bd_cons = 0;
|
|
+ bp->rx_prod = 127;
|
|
+ bp->rx_bd_prod = bp->rx_ring_size;
|
|
+
|
|
+ for (i = 0; i < bp->rx_ring_size; i++) {
|
|
+ void *ptr = bp->bufs + (bp->rx_buffer_size * (i + 1));
|
|
+
|
|
+ bp->rx_pkt_ring[i] = ptr;
|
|
+ }
|
|
+
|
|
+ val = bnx2x_rd32(bp, MISC_REG_SHARED_MEM_ADDR);
|
|
+
|
|
+ bp->shmem_base = val;
|
|
+ val = bnx2x_rd32(bp, bp->shmem_base + SHMEM_ISCSI_MAC_UPPER(bp));
|
|
+ nic->mac_addr[0] = (__u8) (val >> 8);
|
|
+ nic->mac_addr[1] = (__u8) val;
|
|
+ val = bnx2x_rd32(bp, bp->shmem_base + SHMEM_ISCSI_MAC_LOWER(bp));
|
|
+ nic->mac_addr[2] = (__u8) (val >> 24);
|
|
+ nic->mac_addr[3] = (__u8) (val >> 16);
|
|
+ nic->mac_addr[4] = (__u8) (val >> 8);
|
|
+ nic->mac_addr[5] = (__u8) val;
|
|
+
|
|
+ if (bnx2x_is_ver60_plus(bp) && CHIP_IS_E2_PLUS(bp)) {
|
|
+ __u32 mf_cfg_addr = 0;
|
|
+ __u32 mac_offset;
|
|
+ __u8 mac[6];
|
|
+
|
|
+ val = bnx2x_rd32(bp, (BNX2X_PATH(bp) ? MISC_REG_GENERIC_CR_1 :
|
|
+ MISC_REG_GENERIC_CR_0));
|
|
+ bp->shmem_base2 = val;
|
|
+ if (bp->shmem_base2) {
|
|
+ /* size */
|
|
+ val = bnx2x_rd32(bp, bp->shmem_base2);
|
|
+
|
|
+ if (val > 0x10)
|
|
+ mf_cfg_addr =
|
|
+ bnx2x_rd32(bp, bp->shmem_base2 + 0x10);
|
|
+ }
|
|
+
|
|
+ if (!mf_cfg_addr)
|
|
+ mf_cfg_addr = bp->shmem_base + 0x7e4;
|
|
+
|
|
+ /* shared_feat_cfg.config */
|
|
+ val = bnx2x_rd32(bp, bp->shmem_base + 0x354);
|
|
+ /* SI mode */
|
|
+ if ((val & 0x700) == 0x300) {
|
|
+ mac_offset = 0xe4 + (bp->func * 0x28) + 4;
|
|
+ val = bnx2x_rd32(bp, mf_cfg_addr + mac_offset);
|
|
+ mac[0] = (__u8) (val >> 8);
|
|
+ mac[1] = (__u8) val;
|
|
+ mac_offset += 4;
|
|
+ val = bnx2x_rd32(bp, mf_cfg_addr + mac_offset);
|
|
+ mac[2] = (__u8) (val >> 24);
|
|
+ mac[3] = (__u8) (val >> 16);
|
|
+ mac[4] = (__u8) (val >> 8);
|
|
+ mac[5] = (__u8) val;
|
|
+
|
|
+ if (mac[0] != 0xff) {
|
|
+ memcpy(nic->mac_addr, mac, 6);
|
|
+ } else if (bp->func > 1) {
|
|
+ LOG_INFO(PFX "%s: Invalid mac address: "
|
|
+ "%02x:%02x:%02x:%02x:%02x:%02x, abort",
|
|
+ nic->log_name,
|
|
+ mac[0], mac[1], mac[2],
|
|
+ mac[3], mac[4], mac[5]);
|
|
+ rc = -ENOTSUP;
|
|
+ goto open_error;
|
|
+ }
|
|
+ } else if ((val & 0x700) == 0) {
|
|
+ __u32 proto_offset = 0x24 + (bp->func * 0x18);
|
|
+ __u32 ovtag_offset = proto_offset + 0xc;
|
|
+
|
|
+ rc = -ENOTSUP;
|
|
+ val = bnx2x_rd32(bp, mf_cfg_addr + ovtag_offset);
|
|
+ val &= 0xffff;
|
|
+ /* SD mode, check for valid outer VLAN */
|
|
+ if (val == 0xffff) {
|
|
+ LOG_ERR(PFX "%s: Invalid OV detected for SD, "
|
|
+ " fallback to SF mode!\n",
|
|
+ nic->log_name);
|
|
+ goto SF;
|
|
+ }
|
|
+ /* Check for iSCSI protocol */
|
|
+ val = bnx2x_rd32(bp, mf_cfg_addr + proto_offset);
|
|
+ if ((val & 6) != 6)
|
|
+ goto open_error;
|
|
+
|
|
+ mac_offset = proto_offset + 0x4;
|
|
+ val = bnx2x_rd32(bp, mf_cfg_addr + mac_offset);
|
|
+ mac[0] = (__u8) (val >> 8);
|
|
+ mac[1] = (__u8) val;
|
|
+ mac_offset += 4;
|
|
+ val = bnx2x_rd32(bp, mf_cfg_addr + mac_offset);
|
|
+ mac[2] = (__u8) (val >> 24);
|
|
+ mac[3] = (__u8) (val >> 16);
|
|
+ mac[4] = (__u8) (val >> 8);
|
|
+ mac[5] = (__u8) val;
|
|
+ memcpy(nic->mac_addr, mac, 6);
|
|
+
|
|
+ }
|
|
+ }
|
|
+SF:
|
|
+ LOG_INFO(PFX "%s: Using mac address: %02x:%02x:%02x:%02x:%02x:%02x",
|
|
+ nic->log_name,
|
|
+ nic->mac_addr[0], nic->mac_addr[1], nic->mac_addr[2],
|
|
+ nic->mac_addr[3], nic->mac_addr[4], nic->mac_addr[5]);
|
|
+
|
|
+ /* Determine if Hardware VLAN tag stripping is enabled or not */
|
|
+ if (CNIC_VLAN_STRIPPING_ENABLED == bnx2x_strip_vlan_enabled(bp))
|
|
+ nic->flags |= NIC_VLAN_STRIP_ENABLED;
|
|
+
|
|
+ msync(bp->reg, BNX2X_BAR_SIZE, MS_SYNC);
|
|
+
|
|
+ LOG_INFO("%s: bnx2x initialized", nic->log_name);
|
|
+
|
|
+ bnx2x_update_rx_prod(bp);
|
|
+ bp->flags |= BNX2X_OPENED;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+open_error:
|
|
+ if (bp->tx_ring) {
|
|
+ munmap(bp->tx_ring, 4 * nic->page_size);
|
|
+ bp->tx_ring = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->status_blk.def) {
|
|
+ munmap(bp->status_blk.def, bp->status_blk_size);
|
|
+ bp->status_blk.def = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->reg) {
|
|
+ munmap(bp->reg, BNX2X_BAR_SIZE);
|
|
+ bp->reg = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->reg2) {
|
|
+ munmap(bp->reg2, BNX2X_BAR2_SIZE);
|
|
+ bp->reg2 = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->rx_pkt_ring) {
|
|
+ free(bp->rx_pkt_ring);
|
|
+ bp->rx_pkt_ring = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->bar2_fd != INVALID_FD) {
|
|
+ close(bp->bar2_fd);
|
|
+ bp->bar2_fd = INVALID_FD;
|
|
+ }
|
|
+
|
|
+ if (bp->bar0_fd != INVALID_FD) {
|
|
+ close(bp->bar0_fd);
|
|
+ bp->bar0_fd = INVALID_FD;
|
|
+ }
|
|
+ if (nic->fd != INVALID_FD) {
|
|
+ close(nic->fd);
|
|
+ nic->fd = INVALID_FD;
|
|
+ }
|
|
+ bnx2x_free(nic);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_uio_close_resources() - Used to free resource for the NIC/CNIC
|
|
+ * @param nic - NIC device to free resource
|
|
+ * @param graceful - whether to wait to close gracefully
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+static int bnx2x_uio_close_resources(nic_t *nic, NIC_SHUTDOWN_T graceful)
|
|
+{
|
|
+ bnx2x_t *bp = (bnx2x_t *) nic->priv;
|
|
+ int rc = 0;
|
|
+
|
|
+ /* Check if there is an assoicated bnx2x device */
|
|
+ if (bp == NULL) {
|
|
+ LOG_WARN(PFX "%s: when closing resources there is "
|
|
+ "no assoicated bnx2x", nic->log_name);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* Clean up allocated memory */
|
|
+
|
|
+ if (bp->rx_pkt_ring != NULL) {
|
|
+ free(bp->rx_pkt_ring);
|
|
+ bp->rx_pkt_ring = NULL;
|
|
+ }
|
|
+
|
|
+ /* Clean up mapped registers */
|
|
+ if (bp->bufs != NULL) {
|
|
+ rc = munmap(bp->bufs,
|
|
+ (bp->rx_ring_size + 1) * bp->rx_buffer_size);
|
|
+ if (rc != 0)
|
|
+ LOG_WARN(PFX "%s: Couldn't unmap bufs", nic->log_name);
|
|
+ bp->bufs = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->tx_ring != NULL) {
|
|
+ rc = munmap(bp->tx_ring, 4 * nic->page_size);
|
|
+ if (rc != 0)
|
|
+ LOG_WARN(PFX "%s: Couldn't unmap tx_rings",
|
|
+ nic->log_name);
|
|
+ bp->tx_ring = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->status_blk.def != NULL) {
|
|
+ rc = munmap(bp->status_blk.def, bp->status_blk_size);
|
|
+ if (rc != 0)
|
|
+ LOG_WARN(PFX "%s: Couldn't unmap status block",
|
|
+ nic->log_name);
|
|
+ bp->status_blk.def = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->reg != NULL) {
|
|
+ rc = munmap(bp->reg, BNX2X_BAR_SIZE);
|
|
+ if (rc != 0)
|
|
+ LOG_WARN(PFX "%s: Couldn't unmap regs", nic->log_name);
|
|
+ bp->reg = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->reg2 != NULL) {
|
|
+ rc = munmap(bp->reg2, BNX2X_BAR2_SIZE);
|
|
+ if (rc != 0)
|
|
+ LOG_WARN(PFX "%s: Couldn't unmap regs", nic->log_name);
|
|
+ bp->reg2 = NULL;
|
|
+ }
|
|
+
|
|
+ if (bp->bar2_fd != INVALID_FD) {
|
|
+ close(bp->bar2_fd);
|
|
+ bp->bar2_fd = INVALID_FD;
|
|
+ }
|
|
+
|
|
+ if (bp->bar0_fd != INVALID_FD) {
|
|
+ close(bp->bar0_fd);
|
|
+ bp->bar0_fd = INVALID_FD;
|
|
+ }
|
|
+
|
|
+ if (nic->fd != INVALID_FD) {
|
|
+ rc = close(nic->fd);
|
|
+ if (rc != 0) {
|
|
+ LOG_WARN(PFX
|
|
+ "%s: Couldn't close uio file descriptor: %d",
|
|
+ nic->log_name, nic->fd);
|
|
+ } else {
|
|
+ LOG_DEBUG(PFX "%s: Closed uio file descriptor: %d",
|
|
+ nic->log_name, nic->fd);
|
|
+ }
|
|
+
|
|
+ nic->fd = INVALID_FD;
|
|
+ } else {
|
|
+ LOG_WARN(PFX "%s: Invalid uio file descriptor: %d",
|
|
+ nic->log_name, nic->fd);
|
|
+ }
|
|
+
|
|
+ bnx2x_set_drv_version_unknown(bp);
|
|
+
|
|
+ LOG_INFO(PFX "%s: Closed all resources", nic->log_name);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_close() - Used to close the NIC device
|
|
+ * @param nic - NIC device to close
|
|
+ * @param graceful - whether to wait to close gracefully
|
|
+ * @return 0 if successful, <0 if there is an error
|
|
+ */
|
|
+static int bnx2x_close(nic_t *nic, NIC_SHUTDOWN_T graceful)
|
|
+{
|
|
+ /* Sanity Check: validate the parameters */
|
|
+ if (nic == NULL) {
|
|
+ LOG_ERR(PFX "bnx2x_close(): nic == NULL");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ if (nic->priv == NULL) {
|
|
+ LOG_ERR(PFX "bnx2x_close(): nic->priv == NULL");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "Closing NIC device: %s", nic->log_name);
|
|
+
|
|
+ bnx2x_uio_close_resources(nic, graceful);
|
|
+ bnx2x_free(nic);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void bnx2x_prepare_xmit_packet(nic_t *nic,
|
|
+ nic_interface_t *nic_iface,
|
|
+ struct packet *pkt)
|
|
+{
|
|
+ bnx2x_t *bp = (bnx2x_t *) nic->priv;
|
|
+ struct uip_vlan_eth_hdr *eth_vlan = (struct uip_vlan_eth_hdr *)pkt->buf;
|
|
+ struct uip_eth_hdr *eth = (struct uip_eth_hdr *)bp->tx_pkt;
|
|
+
|
|
+ if (eth_vlan->tpid == htons(UIP_ETHTYPE_8021Q)) {
|
|
+ memcpy(bp->tx_pkt, pkt->buf, sizeof(struct uip_eth_hdr));
|
|
+ eth->type = eth_vlan->type;
|
|
+ pkt->buf_size -= (sizeof(struct uip_vlan_eth_hdr) -
|
|
+ sizeof(struct uip_eth_hdr));
|
|
+ memcpy(bp->tx_pkt + sizeof(struct uip_eth_hdr),
|
|
+ pkt->buf + sizeof(struct uip_vlan_eth_hdr),
|
|
+ pkt->buf_size - sizeof(struct uip_eth_hdr));
|
|
+ } else
|
|
+ memcpy(bp->tx_pkt, pkt->buf, pkt->buf_size);
|
|
+
|
|
+ msync(bp->tx_pkt, pkt->buf_size, MS_SYNC);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_get_tx_pkt() - This function is used to a TX packet from the NIC
|
|
+ * @param nic - The NIC device to send the packet
|
|
+ */
|
|
+void *bnx2x_get_tx_pkt(nic_t *nic)
|
|
+{
|
|
+ bnx2x_t *bp = (bnx2x_t *) nic->priv;
|
|
+ return bp->tx_pkt;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_start_xmit() - This function is used to send a packet of data
|
|
+ * @param nic - The NIC device to send the packet
|
|
+ * @param len - the length of the TX packet
|
|
+ *
|
|
+ */
|
|
+void bnx2x_start_xmit(nic_t *nic, size_t len, u16_t vlan_id)
|
|
+{
|
|
+ bnx2x_t *bp = (bnx2x_t *) nic->priv;
|
|
+ uint16_t ring_prod;
|
|
+ struct eth_tx_start_bd *txbd;
|
|
+ struct eth_tx_bd *txbd2;
|
|
+ struct eth_rx_bd *rx_bd;
|
|
+ rx_bd = (struct eth_rx_bd *)(((__u8 *) bp->tx_ring) + nic->page_size);
|
|
+
|
|
+ if ((rx_bd->addr_hi == 0) && (rx_bd->addr_lo == 0)) {
|
|
+ LOG_PACKET(PFX "%s: trying to transmit when device is closed",
|
|
+ nic->log_name);
|
|
+ pthread_mutex_unlock(&nic->xmit_mutex);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ring_prod = BNX2X_TX_RING_IDX(bp->tx_bd_prod);
|
|
+ txbd = &bp->tx_ring[ring_prod];
|
|
+
|
|
+ BNX2X_SET_TX_VLAN(bp, txbd, vlan_id);
|
|
+
|
|
+ bp->tx_prod++;
|
|
+ bp->tx_bd_prod = BNX2X_NEXT_TX_BD(bp->tx_bd_prod);
|
|
+ bp->tx_bd_prod = BNX2X_NEXT_TX_BD(bp->tx_bd_prod);
|
|
+
|
|
+ ring_prod = BNX2X_TX_RING_IDX(bp->tx_bd_prod);
|
|
+ txbd2 = (struct eth_tx_bd *)&bp->tx_ring[ring_prod];
|
|
+
|
|
+ txbd2->nbytes = len - 0x10;
|
|
+ txbd2->total_pkt_bytes = len;
|
|
+
|
|
+ bp->tx_bd_prod = BNX2X_NEXT_TX_BD(bp->tx_bd_prod);
|
|
+
|
|
+ barrier();
|
|
+ if (nic->nl_process_if_down == 0) {
|
|
+ bnx2x_doorbell(bp, bp->tx_doorbell, 0x02 |
|
|
+ (bp->tx_bd_prod << 16));
|
|
+ bnx2x_flush_doorbell(bp, bp->tx_doorbell);
|
|
+ } else {
|
|
+ /* If the doorbell is not rung, the packet will not
|
|
+ get sent. Hence, the xmit_mutex lock will not
|
|
+ get freed.
|
|
+ */
|
|
+ pthread_mutex_unlock(&nic->xmit_mutex);
|
|
+ }
|
|
+ LOG_PACKET(PFX "%s: sent %d bytes using bp->tx_prod: %d",
|
|
+ nic->log_name, len, bp->tx_prod);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_write() - Used to write the data to the hardware
|
|
+ * @param nic - NIC hardware to read from
|
|
+ * @param pkt - The packet which will hold the data to be sent on the wire
|
|
+ * @return 0 if successful, <0 if failed
|
|
+ */
|
|
+int bnx2x_write(nic_t *nic, nic_interface_t *nic_iface, packet_t *pkt)
|
|
+{
|
|
+ bnx2x_t *bp;
|
|
+ struct uip_stack *uip;
|
|
+ int i = 0;
|
|
+
|
|
+ /* Sanity Check: validate the parameters */
|
|
+ if (nic == NULL || nic_iface == NULL || pkt == NULL) {
|
|
+ LOG_ERR(PFX "%s: bnx2x_write() nic == 0x%p || "
|
|
+ " nic_iface == 0x%p || "
|
|
+ " pkt == 0x%x", nic, nic_iface, pkt);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ bp = (bnx2x_t *) nic->priv;
|
|
+ uip = &nic_iface->ustack;
|
|
+
|
|
+ if (pkt->buf_size == 0) {
|
|
+ LOG_ERR(PFX "%s: Trying to transmitted 0 sized packet",
|
|
+ nic->log_name);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Try to wait for a TX completion */
|
|
+ for (i = 0; i < 15; i++) {
|
|
+ struct timespec sleep_req = {.tv_sec = 0, .tv_nsec = 5000000 },
|
|
+ sleep_rem;
|
|
+
|
|
+ if (bnx2x_clear_tx_intr(nic) == 0)
|
|
+ break;
|
|
+
|
|
+ nanosleep(&sleep_req, &sleep_rem);
|
|
+ }
|
|
+
|
|
+ if (pthread_mutex_trylock(&nic->xmit_mutex) != 0) {
|
|
+ LOG_PACKET(PFX "%s: Dropped previous transmitted packet",
|
|
+ nic->log_name);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ bnx2x_prepare_xmit_packet(nic, nic_iface, pkt);
|
|
+ bnx2x_start_xmit(nic, pkt->buf_size,
|
|
+ (nic_iface->vlan_priority << 12) |
|
|
+ nic_iface->vlan_id);
|
|
+
|
|
+ /* bump the cnic dev send statistics */
|
|
+ nic->stats.tx.packets++;
|
|
+ nic->stats.tx.bytes += uip->uip_len;
|
|
+
|
|
+ LOG_PACKET(PFX "%s: transmitted %d bytes "
|
|
+ "dev->tx_cons: %d, dev->tx_prod: %d, dev->tx_bd_prod:%d",
|
|
+ nic->log_name, pkt->buf_size,
|
|
+ bp->tx_cons, bp->tx_prod, bp->tx_bd_prod);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline int bnx2x_get_rx_pad(bnx2x_t *bp, union eth_rx_cqe *cqe)
|
|
+{
|
|
+ int pad = 0;
|
|
+
|
|
+ if (bnx2x_is_ver70(bp))
|
|
+ pad = ((union eth_rx_cqe_70 *)cqe)->fast_path_cqe_70. \
|
|
+ placement_offset;
|
|
+ else if (bnx2x_is_ver60(bp)) {
|
|
+ if (bp->version.minor >= 64)
|
|
+ pad = cqe->fast_path_cqe_64.placement_offset;
|
|
+ else
|
|
+ pad = cqe->fast_path_cqe.placement_offset;
|
|
+ }
|
|
+ return pad;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * bnx2x_read() - Used to read the data from the hardware
|
|
+ * @param nic - NIC hardware to read from
|
|
+ * @param pkt - The packet which will hold the data
|
|
+ * @return 0 if successful, <0 if failed
|
|
+ */
|
|
+static int bnx2x_read(nic_t *nic, packet_t *pkt)
|
|
+{
|
|
+ bnx2x_t *bp;
|
|
+ int rc = 0;
|
|
+ uint16_t hw_cons, sw_cons, bd_cons, bd_prod;
|
|
+
|
|
+ /* Sanity Check: validate the parameters */
|
|
+ if (nic == NULL || pkt == NULL) {
|
|
+ LOG_ERR(PFX "%s: bnx2x_read() nic == 0x%p || "
|
|
+ " pkt == 0x%x", nic, pkt);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ bp = (bnx2x_t *) nic->priv;
|
|
+
|
|
+ hw_cons = bp->get_rx_cons(bp);
|
|
+ sw_cons = bp->rx_cons;
|
|
+ bd_cons = BNX2X_RX_BD(bp->rx_bd_cons);
|
|
+ bd_prod = BNX2X_RX_BD(bp->rx_bd_prod);
|
|
+
|
|
+ if (sw_cons != hw_cons) {
|
|
+ uint16_t comp_ring_index = sw_cons & BNX2X_MAX_RCQ_DESC_CNT(bp);
|
|
+ uint8_t ring_index;
|
|
+ union eth_rx_cqe *cqe;
|
|
+ __u8 cqe_fp_flags;
|
|
+ void *rx_pkt;
|
|
+ int len, pad, cqe_size, max_len;
|
|
+ rc = 1;
|
|
+
|
|
+ if (bnx2x_is_ver70(bp)) {
|
|
+ cqe = (union eth_rx_cqe *)
|
|
+ &bp->rx_comp_ring.cqe70[comp_ring_index];
|
|
+ cqe_size = sizeof(union eth_rx_cqe_70);
|
|
+ } else {
|
|
+ cqe = &bp->rx_comp_ring.cqe[comp_ring_index];
|
|
+ cqe_size = sizeof(union eth_rx_cqe);
|
|
+ }
|
|
+ cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
|
|
+
|
|
+ LOG_PACKET(PFX "%s: clearing rx interrupt: %d %d",
|
|
+ nic->log_name, sw_cons, hw_cons);
|
|
+
|
|
+ msync(cqe, cqe_size, MS_SYNC);
|
|
+
|
|
+ if (!(cqe_fp_flags & ETH_FAST_PATH_RX_CQE_TYPE)) {
|
|
+ ring_index = bd_cons % 15;
|
|
+ len = cqe->fast_path_cqe.pkt_len;
|
|
+ pad = bnx2x_get_rx_pad(bp, cqe);
|
|
+ rx_pkt = bp->rx_pkt_ring[ring_index] + pad;
|
|
+
|
|
+ /* Doto query MTU size of physical device */
|
|
+ /* Ensure len is valid */
|
|
+ max_len = pkt->max_buf_size < bp->rx_buffer_size ?
|
|
+ pkt->max_buf_size : bp->rx_buffer_size;
|
|
+ if (len + pad > max_len) {
|
|
+ LOG_DEBUG(PFX "%s: bad BD length: %d",
|
|
+ nic->log_name, len);
|
|
+ len = max_len - pad;
|
|
+ }
|
|
+ if (len > 0) {
|
|
+ msync(rx_pkt, len, MS_SYNC);
|
|
+ /* Copy the data */
|
|
+ memcpy(pkt->buf, rx_pkt, len);
|
|
+ pkt->buf_size = len;
|
|
+
|
|
+ /* Properly set the packet flags */
|
|
+ /* check if there is VLAN tagging */
|
|
+ if (cqe->fast_path_cqe.vlan_tag != 0) {
|
|
+ pkt->vlan_tag =
|
|
+ cqe->fast_path_cqe.vlan_tag;
|
|
+ pkt->flags |= VLAN_TAGGED;
|
|
+ } else {
|
|
+ pkt->vlan_tag = 0;
|
|
+ }
|
|
+
|
|
+ LOG_PACKET(PFX
|
|
+ "%s: processing packet length: %d",
|
|
+ nic->log_name, len);
|
|
+
|
|
+ /* bump the cnic dev recv statistics */
|
|
+ nic->stats.rx.packets++;
|
|
+ nic->stats.rx.bytes += pkt->buf_size;
|
|
+ }
|
|
+
|
|
+ bd_cons = BNX2X_NEXT_RX_IDX(bd_cons);
|
|
+ bd_prod = BNX2X_NEXT_RX_IDX(bd_prod);
|
|
+
|
|
+ }
|
|
+ sw_cons = BNX2X_NEXT_RCQ_IDX(bp, sw_cons);
|
|
+ bp->rx_prod = BNX2X_NEXT_RCQ_IDX(bp, bp->rx_prod);
|
|
+ }
|
|
+ bp->rx_cons = sw_cons;
|
|
+ bp->rx_bd_cons = bd_cons;
|
|
+ bp->rx_bd_prod = bd_prod;
|
|
+ bp->rx_hw_prod = hw_cons;
|
|
+
|
|
+ if (rc)
|
|
+ bnx2x_update_rx_prod(bp);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Clearing TX interrupts
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * bnx2x_clear_tx_intr() - This routine is called when a TX interrupt occurs
|
|
+ * @param nic - the nic the interrupt occured on
|
|
+ * @return 0 on success
|
|
+ */
|
|
+static int bnx2x_clear_tx_intr(nic_t *nic)
|
|
+{
|
|
+ bnx2x_t *bp;
|
|
+ uint16_t hw_cons;
|
|
+
|
|
+ /* Sanity check: ensure the parameters passed in are valid */
|
|
+ if (unlikely(nic == NULL)) {
|
|
+ LOG_ERR(PFX "bnx2x_read() nic == NULL");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ bp = (bnx2x_t *) nic->priv;
|
|
+ hw_cons = bp->get_tx_cons(bp);
|
|
+
|
|
+ if (bp->tx_cons == hw_cons) {
|
|
+ if (bp->tx_cons == bp->tx_prod) {
|
|
+ /* Make sure the xmit_mutex lock is unlock */
|
|
+ if (pthread_mutex_trylock(&nic->xmit_mutex))
|
|
+ LOG_ERR(PFX "bnx2x tx lock with prod == cons");
|
|
+
|
|
+ pthread_mutex_unlock(&nic->xmit_mutex);
|
|
+ return 0;
|
|
+ }
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ LOG_PACKET(PFX "%s: clearing tx interrupt [%d %d]",
|
|
+ nic->log_name, bp->tx_cons, hw_cons);
|
|
+ bp->tx_cons = hw_cons;
|
|
+
|
|
+ /* There is a queued TX packet that needs to be sent out. The usual
|
|
+ * case is when stack will send an ARP packet out before sending the
|
|
+ * intended packet */
|
|
+ if (nic->tx_packet_queue != NULL) {
|
|
+ packet_t *pkt;
|
|
+ int i;
|
|
+
|
|
+ LOG_PACKET(PFX "%s: sending queued tx packet", nic->log_name);
|
|
+ pkt = nic_dequeue_tx_packet(nic);
|
|
+
|
|
+ /* Got a TX packet buffer of the TX queue and put it onto
|
|
+ * the hardware */
|
|
+ if (pkt != NULL) {
|
|
+ bnx2x_prepare_xmit_packet(nic, pkt->nic_iface, pkt);
|
|
+
|
|
+ bnx2x_start_xmit(nic, pkt->buf_size,
|
|
+ (pkt->nic_iface->vlan_priority << 12) |
|
|
+ pkt->nic_iface->vlan_id);
|
|
+
|
|
+ LOG_PACKET(PFX "%s: transmitted queued packet %d bytes "
|
|
+ "dev->tx_cons: %d, dev->tx_prod: %d, "
|
|
+ "dev->tx_bd_prod:%d",
|
|
+ nic->log_name, pkt->buf_size,
|
|
+ bp->tx_cons, bp->tx_prod, bp->tx_bd_prod);
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* Try to wait for a TX completion */
|
|
+ for (i = 0; i < 15; i++) {
|
|
+ struct timespec sleep_req = {.tv_sec = 0,
|
|
+ .tv_nsec = 5000000
|
|
+ }, sleep_rem;
|
|
+
|
|
+ hw_cons = bp->get_tx_cons(bp);
|
|
+ if (bp->tx_cons != hw_cons) {
|
|
+ LOG_PACKET(PFX
|
|
+ "%s: clearing tx interrupt [%d %d]",
|
|
+ nic->log_name, bp->tx_cons, hw_cons);
|
|
+ bp->tx_cons = hw_cons;
|
|
+
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ nanosleep(&sleep_req, &sleep_rem);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ pthread_mutex_unlock(&nic->xmit_mutex);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * bnx2x NIC op's table
|
|
+ ******************************************************************************/
|
|
+struct nic_ops bnx2x_op = {
|
|
+ .description = "bnx2x",
|
|
+ .open = bnx2x_open,
|
|
+ .close = bnx2x_close,
|
|
+ .write = bnx2x_write,
|
|
+ .get_tx_pkt = bnx2x_get_tx_pkt,
|
|
+ .start_xmit = bnx2x_start_xmit,
|
|
+ .read = bnx2x_read,
|
|
+ .clear_tx_intr = bnx2x_clear_tx_intr,
|
|
+ .handle_iscsi_path_req = cnic_handle_iscsi_path_req,
|
|
+
|
|
+ .lib_ops = {
|
|
+ .get_library_name = bnx2x_get_library_name,
|
|
+ .get_pci_table = bnx2x_get_pci_table,
|
|
+ .get_library_version = bnx2x_get_library_version,
|
|
+ .get_build_date = bnx2x_get_build_date,
|
|
+ .get_transport_name = bnx2x_get_transport_name,
|
|
+ .get_uio_name = bnx2x_get_uio_name,
|
|
+ },
|
|
+};
|
|
diff --git a/iscsiuio/src/unix/libs/bnx2x.h b/iscsiuio/src/unix/libs/bnx2x.h
|
|
new file mode 100644
|
|
index 0000000..ce55cfc
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/libs/bnx2x.h
|
|
@@ -0,0 +1,712 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * bnx2x.h - bnx2x user space driver
|
|
+ *
|
|
+ */
|
|
+#ifndef __BNX2X_H__
|
|
+#define __BNX2X_H__
|
|
+
|
|
+#include "nic.h"
|
|
+
|
|
+/******************************************************************************
|
|
+ * Default CNIC values
|
|
+ ******************************************************************************/
|
|
+#define DEFAULT_BNX2X_NUM_RXBD 15
|
|
+#define DEFAULT_BNX2X_RX_LEN 0x400
|
|
+
|
|
+/******************************************************************************
|
|
+ * BNX2X Hardware structures
|
|
+ ******************************************************************************/
|
|
+#define HC_USTORM_DEF_SB_NUM_INDICES 8
|
|
+#define HC_CSTORM_DEF_SB_NUM_INDICES 8
|
|
+#define HC_XSTORM_DEF_SB_NUM_INDICES 4
|
|
+#define HC_TSTORM_DEF_SB_NUM_INDICES 4
|
|
+
|
|
+struct atten_def_status_block {
|
|
+ volatile __u32 attn_bits;
|
|
+ volatile __u32 attn_bits_ack;
|
|
+ volatile __u8 status_block_id;
|
|
+ volatile __u8 reserved0;
|
|
+ volatile __u16 attn_bits_index;
|
|
+ volatile __u32 reserved1;
|
|
+};
|
|
+
|
|
+struct cstorm_def_status_block_u {
|
|
+ volatile __u16 index_values[HC_USTORM_DEF_SB_NUM_INDICES];
|
|
+ volatile __u16 status_block_index;
|
|
+ volatile __u8 func;
|
|
+ volatile __u8 status_block_id;
|
|
+ volatile __u32 __flags;
|
|
+};
|
|
+
|
|
+struct cstorm_def_status_block_c {
|
|
+ volatile __u16 index_values[HC_CSTORM_DEF_SB_NUM_INDICES];
|
|
+ volatile __u16 status_block_index;
|
|
+ volatile __u8 func;
|
|
+ volatile __u8 status_block_id;
|
|
+ volatile __u32 __flags;
|
|
+};
|
|
+
|
|
+struct xstorm_def_status_block {
|
|
+ volatile __u16 index_values[HC_XSTORM_DEF_SB_NUM_INDICES];
|
|
+ volatile __u16 status_block_index;
|
|
+ volatile __u8 func;
|
|
+ volatile __u8 status_block_id;
|
|
+ volatile __u32 __flags;
|
|
+};
|
|
+
|
|
+struct tstorm_def_status_block {
|
|
+ volatile __u16 index_values[HC_TSTORM_DEF_SB_NUM_INDICES];
|
|
+ volatile __u16 status_block_index;
|
|
+ volatile __u8 func;
|
|
+ volatile __u8 status_block_id;
|
|
+ volatile __u32 __flags;
|
|
+};
|
|
+
|
|
+struct host_def_status_block {
|
|
+ struct atten_def_status_block atten_status_block;
|
|
+ struct cstorm_def_status_block_u u_def_status_block;
|
|
+ struct cstorm_def_status_block_c c_def_status_block;
|
|
+ struct xstorm_def_status_block x_def_status_block;
|
|
+ struct tstorm_def_status_block t_def_status_block;
|
|
+};
|
|
+
|
|
+#define HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS 1
|
|
+#define HC_INDEX_DEF_U_ETH_ISCSI_RX_BD_CONS 3
|
|
+#define HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS 5
|
|
+
|
|
+struct atten_sp_status_block {
|
|
+ __u32 attn_bits;
|
|
+ __u32 attn_bits_ack;
|
|
+ __u8 status_block_id;
|
|
+ __u8 reserved0;
|
|
+ __u16 attn_bits_index;
|
|
+ __u32 reserved1;
|
|
+};
|
|
+
|
|
+#define HC_SP_SB_MAX_INDICES 16
|
|
+
|
|
+struct hc_sp_status_block {
|
|
+ __u16 index_values[HC_SP_SB_MAX_INDICES];
|
|
+ __u16 running_index;
|
|
+ __u16 rsrv;
|
|
+ __u32 rsrv1;
|
|
+};
|
|
+
|
|
+struct host_sp_status_block {
|
|
+ struct atten_sp_status_block atten_status_block;
|
|
+ struct hc_sp_status_block sp_sb;
|
|
+};
|
|
+
|
|
+#define HC_SP_INDEX_ETH_ISCSI_CQ_CONS 5
|
|
+#define HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS 1
|
|
+
|
|
+/*
|
|
+ * VLAN mode on TX BDs
|
|
+ */
|
|
+enum eth_tx_vlan_type {
|
|
+ X_ETH_NO_VLAN = 0,
|
|
+ X_ETH_OUTBAND_VLAN = 1,
|
|
+ X_ETH_INBAND_VLAN = 2,
|
|
+ X_ETH_FW_ADDED_VLAN = 3,
|
|
+ MAX_ETH_TX_VLAN_TYPE
|
|
+};
|
|
+
|
|
+/* TX Buffer descriptor */
|
|
+struct eth_tx_bd_flags {
|
|
+ __u8 as_bitfield;
|
|
+/* t6.X HSI */
|
|
+#define ETH_TX_BD_FLAGS_IP_CSUM_T6X (0x1<<0)
|
|
+#define ETH_TX_BD_FLAGS_IP_CSUM_SHIFT_T6X 0
|
|
+#define ETH_TX_BD_FLAGS_L4_CSUM_T6X (0x1<<1)
|
|
+#define ETH_TX_BD_FLAGS_L4_CSUM_SHIFT_T6X 1
|
|
+#define ETH_TX_BD_FLAGS_VLAN_MODE_T6X (0x3<<2)
|
|
+#define ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT_T6X 2
|
|
+#define ETH_TX_BD_FLAGS_START_BD_T6X (0x1<<4)
|
|
+#define ETH_TX_BD_FLAGS_START_BD_SHIFT_T6X 4
|
|
+#define ETH_TX_BD_FLAGS_IS_UDP_T6X (0x1<<5)
|
|
+#define ETH_TX_BD_FLAGS_IS_UDP_SHIFT_T6X 5
|
|
+#define ETH_TX_BD_FLAGS_SW_LSO_T6X (0x1<<6)
|
|
+#define ETH_TX_BD_FLAGS_SW_LSO_SHIFT_T6X 6
|
|
+#define ETH_TX_BD_FLAGS_IPV6_T6X (0x1<<7)
|
|
+#define ETH_TX_BD_FLAGS_IPV6_SHIFT_T6X 7
|
|
+
|
|
+/* Legacy t5.2 HSI defines */
|
|
+#define ETH_TX_BD_FLAGS_VLAN_TAG_T5X (0x1<<0)
|
|
+#define ETH_TX_BD_FLAGS_VLAN_TAG_SHIFT_T5X 0
|
|
+#define ETH_TX_BD_FLAGS_IP_CSUM_T5X (0x1<<1)
|
|
+#define ETH_TX_BD_FLAGS_IP_CSUM_SHIFT_T5X 1
|
|
+#define ETH_TX_BD_FLAGS_L4_CSUM_T5X (0x1<<2)
|
|
+#define ETH_TX_BD_FLAGS_L4_CSUM_SHIFT_T5X 2
|
|
+#define ETH_TX_BD_FLAGS_END_BD_T5X (0x1<<3)
|
|
+#define ETH_TX_BD_FLAGS_END_BD_SHIFT_T5X 3
|
|
+#define ETH_TX_BD_FLAGS_START_BD_T5X (0x1<<4)
|
|
+#define ETH_TX_BD_FLAGS_START_BD_SHIFT_T5X 4
|
|
+#define ETH_TX_BD_FLAGS_HDR_POOL_T5X (0x1<<5)
|
|
+#define ETH_TX_BD_FLAGS_HDR_POOL_SHIFT_T5X 5
|
|
+#define ETH_TX_BD_FLAGS_SW_LSO_T5X (0x1<<6)
|
|
+#define ETH_TX_BD_FLAGS_SW_LSO_SHIFT_T5X 6
|
|
+#define ETH_TX_BD_FLAGS_IPV6_T5X (0x1<<7)
|
|
+#define ETH_TX_BD_FLAGS_IPV6_SHIFT_T5X 7
|
|
+};
|
|
+
|
|
+#define ETH_TX_BD_FLAGS_VLAN_TAG_T6X \
|
|
+ (X_ETH_OUTBAND_VLAN << ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT_T6X)
|
|
+
|
|
+#define BNX2X_SET_TX_VLAN(bp, txbd, vlan_id) \
|
|
+ do { \
|
|
+ if (vlan_id) { \
|
|
+ (txbd)->vlan = vlan_id; \
|
|
+ (txbd)->bd_flags.as_bitfield |= \
|
|
+ (bp)->tx_vlan_tag_bit; \
|
|
+ } else { \
|
|
+ (txbd)->vlan = (bp)->tx_prod; \
|
|
+ (txbd)->bd_flags.as_bitfield &= \
|
|
+ ~(bp)->tx_vlan_tag_bit; \
|
|
+ } \
|
|
+ } while (0)
|
|
+
|
|
+struct eth_tx_start_bd {
|
|
+ __u32 addr_lo;
|
|
+ __u32 addr_hi;
|
|
+ __u16 nbd;
|
|
+ __u16 nbytes;
|
|
+ __u16 vlan;
|
|
+ struct eth_tx_bd_flags bd_flags;
|
|
+ __u8 general_data;
|
|
+#define ETH_TX_START_BD_HDR_NBDS (0x3F<<0)
|
|
+#define ETH_TX_START_BD_HDR_NBDS_SHIFT 0
|
|
+#define ETH_TX_START_BD_ETH_ADDR_TYPE (0x3<<6)
|
|
+#define ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT 6
|
|
+};
|
|
+
|
|
+struct eth_tx_bd {
|
|
+ __u32 addr_lo;
|
|
+ __u32 addr_hi;
|
|
+ __u16 total_pkt_bytes;
|
|
+ __u16 nbytes;
|
|
+ __u8 reserved[4];
|
|
+};
|
|
+
|
|
+/* RX Buffer descriptor */
|
|
+struct eth_rx_bd {
|
|
+ __u32 addr_lo;
|
|
+ __u32 addr_hi;
|
|
+};
|
|
+
|
|
+struct ramrod_data {
|
|
+ volatile __u32 data_lo;
|
|
+ volatile __u32 data_hi;
|
|
+};
|
|
+
|
|
+struct common_ramrod_eth_rx_cqe {
|
|
+ volatile __u8 ramrod_type;
|
|
+#define COMMON_RAMROD_ETH_RX_CQE_TYPE (0x1<<0)
|
|
+#define COMMON_RAMROD_ETH_RX_CQE_TYPE_SHIFT 0
|
|
+#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0 (0x7F<<1)
|
|
+#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0_SHIFT 1
|
|
+ volatile __u8 conn_type;
|
|
+ volatile __u16 reserved1;
|
|
+ volatile __u32 conn_and_cmd_data;
|
|
+#define COMMON_RAMROD_ETH_RX_CQE_CID (0xFFFFFF<<0)
|
|
+#define COMMON_RAMROD_ETH_RX_CQE_CID_SHIFT 0
|
|
+#define COMMON_RAMROD_ETH_RX_CQE_CMD_ID (0xFF<<24)
|
|
+#define COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT 24
|
|
+ struct ramrod_data protocol_data;
|
|
+ __u32 reserved2[4];
|
|
+};
|
|
+
|
|
+struct common_ramrod_eth_rx_cqe_70 {
|
|
+ volatile __u8 ramrod_type;
|
|
+ volatile __u8 conn_type;
|
|
+ volatile __u16 reserved1;
|
|
+ volatile __u32 conn_and_cmd_data;
|
|
+ struct ramrod_data protocol_data;
|
|
+ __u32 echo;
|
|
+ __u32 reserved2[11];
|
|
+};
|
|
+
|
|
+struct parsing_flags {
|
|
+ volatile __u16 flags;
|
|
+};
|
|
+
|
|
+struct eth_fast_path_rx_cqe {
|
|
+ volatile __u8 type_error_flags;
|
|
+#define ETH_FAST_PATH_RX_CQE_TYPE (0x1<<0)
|
|
+#define ETH_FAST_PATH_RX_CQE_TYPE_SHIFT 0
|
|
+#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG (0x1<<1)
|
|
+#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG_SHIFT 1
|
|
+#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG (0x1<<2)
|
|
+#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_SHIFT 2
|
|
+#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG (0x1<<3)
|
|
+#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_SHIFT 3
|
|
+#define ETH_FAST_PATH_RX_CQE_START_FLG (0x1<<4)
|
|
+#define ETH_FAST_PATH_RX_CQE_START_FLG_SHIFT 4
|
|
+#define ETH_FAST_PATH_RX_CQE_END_FLG (0x1<<5)
|
|
+#define ETH_FAST_PATH_RX_CQE_END_FLG_SHIFT 5
|
|
+#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x3<<6)
|
|
+#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 6
|
|
+ volatile __u8 status_flags;
|
|
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE (0x7<<0)
|
|
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE_SHIFT 0
|
|
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG (0x1<<3)
|
|
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG_SHIFT 3
|
|
+#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG (0x1<<4)
|
|
+#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG_SHIFT 4
|
|
+#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG (0x1<<5)
|
|
+#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG_SHIFT 5
|
|
+#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG (0x1<<6)
|
|
+#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG_SHIFT 6
|
|
+#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG (0x1<<7)
|
|
+#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG_SHIFT 7
|
|
+ volatile __u8 placement_offset;
|
|
+ volatile __u8 queue_index;
|
|
+ volatile __u32 rss_hash_result;
|
|
+ volatile __u16 vlan_tag;
|
|
+ volatile __u16 pkt_len;
|
|
+ volatile __u16 len_on_bd;
|
|
+ struct parsing_flags pars_flags;
|
|
+ volatile __u16 sgl[8];
|
|
+};
|
|
+
|
|
+union eth_sgl_or_raw_data {
|
|
+ volatile __u16 sgl[8];
|
|
+ volatile __u32 raw_data[4];
|
|
+};
|
|
+
|
|
+struct eth_fast_path_rx_cqe_64 {
|
|
+ volatile __u8 type_error_flags;
|
|
+#define ETH_FAST_PATH_RX_CQE_TYPE_64 (0x3<<0)
|
|
+#define ETH_FAST_PATH_RX_CQE_TYPE_SHIFT_64 0
|
|
+#define ETH_FAST_PATH_RX_CQE_SGL_RAW_SEL (0x1<<2)
|
|
+#define ETH_FAST_PATH_RX_CQE_SGL_RAW_SEL_SHIFT 2
|
|
+#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG_64 (0x1<<3)
|
|
+#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG_SHIFT_64 3
|
|
+#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_64 (0x1<<4)
|
|
+#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_SHIFT_64 4
|
|
+#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_64 (0x1<<5)
|
|
+#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_SHIFT_64 5
|
|
+#define ETH_FAST_PATH_RX_CQE_RESERVED0_64 (0x3<<6)
|
|
+#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT_64 6
|
|
+ volatile __u8 status_flags;
|
|
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE (0x7<<0)
|
|
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE_SHIFT 0
|
|
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG (0x1<<3)
|
|
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG_SHIFT 3
|
|
+#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG (0x1<<4)
|
|
+#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG_SHIFT 4
|
|
+#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG (0x1<<5)
|
|
+#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG_SHIFT 5
|
|
+#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG (0x1<<6)
|
|
+#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG_SHIFT 6
|
|
+#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG (0x1<<7)
|
|
+#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG_SHIFT 7
|
|
+ volatile __u8 queue_index;
|
|
+ volatile __u8 placement_offset;
|
|
+ volatile __u32 rss_hash_result;
|
|
+ volatile __u16 vlan_tag;
|
|
+ volatile __u16 pkt_len;
|
|
+ volatile __u16 len_on_bd;
|
|
+ struct parsing_flags pars_flags;
|
|
+ union eth_sgl_or_raw_data sgl_or_raw_data;
|
|
+};
|
|
+
|
|
+struct eth_fast_path_rx_cqe_70 {
|
|
+ volatile __u8 type_error_flags;
|
|
+ volatile __u8 status_flags;
|
|
+ volatile __u8 queue_index;
|
|
+ volatile __u8 placement_offset;
|
|
+ volatile __u32 rss_hash_result;
|
|
+ volatile __u16 vlan_tag;
|
|
+ volatile __u16 pkt_len;
|
|
+ volatile __u16 len_on_bd;
|
|
+ struct parsing_flags pars_flags;
|
|
+ union eth_sgl_or_raw_data sgl_or_raw_data;
|
|
+ __u32 reserved1[8];
|
|
+};
|
|
+
|
|
+struct eth_rx_cqe_next_page {
|
|
+ __u32 addr_lo;
|
|
+ __u32 addr_hi;
|
|
+ __u32 reserved[6];
|
|
+};
|
|
+
|
|
+struct eth_rx_cqe_next_page_70 {
|
|
+ __u32 addr_lo;
|
|
+ __u32 addr_hi;
|
|
+ __u32 reserved[14];
|
|
+};
|
|
+
|
|
+union eth_rx_cqe {
|
|
+ struct eth_fast_path_rx_cqe fast_path_cqe;
|
|
+ struct eth_fast_path_rx_cqe_64 fast_path_cqe_64;
|
|
+ struct common_ramrod_eth_rx_cqe ramrod_cqe;
|
|
+ struct eth_rx_cqe_next_page next_page_cqe;
|
|
+};
|
|
+
|
|
+union eth_rx_cqe_70 {
|
|
+ struct eth_fast_path_rx_cqe_70 fast_path_cqe_70;
|
|
+ struct common_ramrod_eth_rx_cqe_70 ramrod_cqe_70;
|
|
+ struct eth_rx_cqe_next_page_70 next_page_cqe_70;
|
|
+};
|
|
+
|
|
+struct uio_init_data {
|
|
+ __u32 cid;
|
|
+ __u32 tx_db_off;
|
|
+ __u32 cid_override_key;
|
|
+#define UIO_USE_TX_DOORBELL 0x017855DB
|
|
+};
|
|
+
|
|
+struct client_init_general_data {
|
|
+ __u8 client_id;
|
|
+ __u8 statistics_counter_id;
|
|
+ __u8 statistics_en_flg;
|
|
+ __u8 is_fcoe_flg;
|
|
+ __u8 activate_flg;
|
|
+ __u8 sp_client_id;
|
|
+ __u16 mtu;
|
|
+ __u8 statistics_zero_flg;
|
|
+ __u8 func_id;
|
|
+ __u8 cos;
|
|
+ __u8 traffic_type;
|
|
+ struct uio_init_data uid;
|
|
+};
|
|
+
|
|
+/******************************************************************************
|
|
+ * BNX2X Registers and HSI
|
|
+ ******************************************************************************/
|
|
+#define BNX2X_BAR_SIZE 0x500000
|
|
+#define BNX2X_BAR2_SIZE 0x12000
|
|
+
|
|
+#define BNX2X_CHIP_ID(bp) (bp->chip_id & 0xfffffff0)
|
|
+
|
|
+#define PORT_MAX 2
|
|
+
|
|
+/* [R 4] This field indicates the type of the device. '0' - 2 Ports; '1' - 1
|
|
+ * Port. */
|
|
+#define BNX2X_MISC_REG_BOND_ID 0xa400
|
|
+/* [R 8] These bits indicate the metal revision of the chip. This value
|
|
+ * starts at 0x00 for each all-layer tape-out and increments by one for each
|
|
+ * tape-out. */
|
|
+#define BNX2X_MISC_REG_CHIP_METAL 0xa404
|
|
+/* [R 16] These bits indicate the part number for the chip. */
|
|
+#define BNX2X_MISC_REG_CHIP_NUM 0xa408
|
|
+/* [R 4] These bits indicate the base revision of the chip. This value
|
|
+ * starts at 0x0 for the A0 tape-out and increments by one for each
|
|
+ * all-layer tape-out. */
|
|
+#define BNX2X_MISC_REG_CHIP_REV 0xa40c
|
|
+
|
|
+/* From the bnx2x driver */
|
|
+#define CHIP_NUM(bp) (bp->chip_id >> 16)
|
|
+#define CHIP_NUM_57710 0x164e
|
|
+#define CHIP_NUM_57711 0x164f
|
|
+#define CHIP_NUM_57711E 0x1650
|
|
+#define CHIP_NUM_57712 0x1662
|
|
+#define CHIP_NUM_57712_MF 0x1663
|
|
+#define CHIP_NUM_57712_VF 0x166f
|
|
+#define CHIP_NUM_57713 0x1651
|
|
+#define CHIP_NUM_57713E 0x1652
|
|
+#define CHIP_NUM_57800 0x168a
|
|
+#define CHIP_NUM_57800_MF 0x16a5
|
|
+#define CHIP_NUM_57800_VF 0x16a9
|
|
+#define CHIP_NUM_57810 0x168e
|
|
+#define CHIP_NUM_57810_MF 0x16ae
|
|
+#define CHIP_NUM_57810_VF 0x16af
|
|
+#define CHIP_NUM_57811 0x163d
|
|
+#define CHIP_NUM_57811_MF 0x163e
|
|
+#define CHIP_NUM_57811_VF 0x163f
|
|
+#define CHIP_NUM_57840_OBSOLETE 0x168d
|
|
+#define CHIP_NUM_57840_MF_OBSOLETE 0x16ab
|
|
+#define CHIP_NUM_57840_4_10 0x16a1
|
|
+#define CHIP_NUM_57840_2_20 0x16a2
|
|
+#define CHIP_NUM_57840_MF 0x16a4
|
|
+#define CHIP_NUM_57840_VF 0x16ad
|
|
+
|
|
+#define CHIP_IS_E1(bp) (CHIP_NUM(bp) == CHIP_NUM_57710)
|
|
+#define CHIP_IS_57711(bp) (CHIP_NUM(bp) == CHIP_NUM_57711)
|
|
+#define CHIP_IS_57711E(bp) (CHIP_NUM(bp) == CHIP_NUM_57711E)
|
|
+#define CHIP_IS_57712(bp) (CHIP_NUM(bp) == CHIP_NUM_57712)
|
|
+#define CHIP_IS_57712_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57712_VF)
|
|
+#define CHIP_IS_57712_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57712_MF)
|
|
+#define CHIP_IS_57800(bp) (CHIP_NUM(bp) == CHIP_NUM_57800)
|
|
+#define CHIP_IS_57800_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57800_MF)
|
|
+#define CHIP_IS_57800_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57800_VF)
|
|
+#define CHIP_IS_57810(bp) (CHIP_NUM(bp) == CHIP_NUM_57810)
|
|
+#define CHIP_IS_57810_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57810_MF)
|
|
+#define CHIP_IS_57810_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57810_VF)
|
|
+#define CHIP_IS_57811(bp) (CHIP_NUM(bp) == CHIP_NUM_57811)
|
|
+#define CHIP_IS_57811_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57811_MF)
|
|
+#define CHIP_IS_57811_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57811_VF)
|
|
+
|
|
+#define CHIP_IS_57840(bp) \
|
|
+ ((CHIP_NUM(bp) == CHIP_NUM_57840_4_10) || \
|
|
+ (CHIP_NUM(bp) == CHIP_NUM_57840_2_20) || \
|
|
+ (CHIP_NUM(bp) == CHIP_NUM_57840_OBSOLETE))
|
|
+#define CHIP_IS_57840_MF(bp) ((CHIP_NUM(bp) == CHIP_NUM_57840_MF) || \
|
|
+ (CHIP_NUM(bp) == CHIP_NUM_57840_MF_OBSOLETE))
|
|
+#define CHIP_IS_57840_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57840_VF)
|
|
+#define CHIP_IS_E1H(bp) (CHIP_IS_57711(bp) || \
|
|
+ CHIP_IS_57711E(bp))
|
|
+
|
|
+#define CHIP_IS_E2(bp) (CHIP_IS_57712(bp) || \
|
|
+ CHIP_IS_57712_MF(bp) || \
|
|
+ CHIP_IS_57712_VF(bp))
|
|
+#define CHIP_IS_E3(bp) (CHIP_IS_57800(bp) || \
|
|
+ CHIP_IS_57800_MF(bp) || \
|
|
+ CHIP_IS_57800_VF(bp) || \
|
|
+ CHIP_IS_57810(bp) || \
|
|
+ CHIP_IS_57810_MF(bp) || \
|
|
+ CHIP_IS_57810_VF(bp) || \
|
|
+ CHIP_IS_57840(bp) || \
|
|
+ CHIP_IS_57840_MF(bp) || \
|
|
+ CHIP_IS_57840_VF(bp) || \
|
|
+ CHIP_IS_57811(bp) || \
|
|
+ CHIP_IS_57811_MF(bp) || \
|
|
+ CHIP_IS_57811_VF(bp))
|
|
+
|
|
+#define CHIP_IS_E1x(bp) (CHIP_IS_E1((bp)) || CHIP_IS_E1H((bp)))
|
|
+#define USES_WARPCORE(bp) (CHIP_IS_E3(bp))
|
|
+#define IS_E1H_OFFSET (!CHIP_IS_E1H(bp))
|
|
+/* End of From the bnx2x driver */
|
|
+
|
|
+#define CHIP_IS_E2_PLUS(bp) (CHIP_IS_E2(bp) || CHIP_IS_E3(bp))
|
|
+
|
|
+#define MISC_REG_SHARED_MEM_ADDR 0xa2b4
|
|
+
|
|
+#define MISC_REG_BOND_ID 0xa400
|
|
+#define MISC_REG_CHIP_METAL 0xa404
|
|
+#define MISC_REG_CHIP_NUM 0xa408
|
|
+#define MISC_REG_CHIP_REV 0xa40c
|
|
+
|
|
+#define MISC_REG_PORT4MODE_EN 0xa750
|
|
+#define MISC_REG_PORT4MODE_EN_OVWR 0xa720
|
|
+
|
|
+#define MISC_REG_GENERIC_CR_0 0xa460
|
|
+#define MISC_REG_GENERIC_CR_1 0xa464
|
|
+
|
|
+#define BAR_USTRORM_INTMEM 0x400000
|
|
+#define BAR_CSTRORM_INTMEM 0x410000
|
|
+#define BAR_XSTRORM_INTMEM 0x420000
|
|
+#define BAR_TSTRORM_INTMEM 0x430000
|
|
+
|
|
+#define BAR_ME_REGISTER 0x450000
|
|
+#define ME_REG_PF_NUM_SHIFT 0
|
|
+#define ME_REG_PF_NUM\
|
|
+ (7L<<ME_REG_PF_NUM_SHIFT) /* Relative PF Num */
|
|
+#define ME_REG_VF_VALID (1<<8)
|
|
+#define ME_REG_VF_NUM_SHIFT 9
|
|
+#define ME_REG_VF_NUM_MASK (0x3f<<ME_REG_VF_NUM_SHIFT)
|
|
+#define ME_REG_VF_ERR (0x1<<3)
|
|
+#define ME_REG_ABS_PF_NUM_SHIFT 16
|
|
+#define ME_REG_ABS_PF_NUM\
|
|
+ (7L<<ME_REG_ABS_PF_NUM_SHIFT) /* Absolute PF Num */
|
|
+
|
|
+#define USTORM_RX_PRODS_OFFSET(port, client_id) \
|
|
+ (IS_E1H_OFFSET ? (0x4000 + (port * 0x360) + (client_id * 0x30)) \
|
|
+ :(0x1000 + (port * 0x680) + (client_id * 0x40)))
|
|
+
|
|
+struct iro {
|
|
+ __u32 base;
|
|
+ __u16 m1;
|
|
+ __u16 m2;
|
|
+ __u16 m3;
|
|
+ __u16 size;
|
|
+};
|
|
+
|
|
+#define IRO_ENT (bp->iro[bp->iro_idx])
|
|
+
|
|
+#define USTORM_RX_PRODS_E1X_OFFSET(port, client_id) \
|
|
+ (IRO_ENT.base + ((port) * IRO_ENT.m1) + ((client_id) * IRO_ENT.m2))
|
|
+
|
|
+#define USTORM_RX_PRODS_E2_OFFSET(qzone_id) \
|
|
+ (IRO_ENT.base + ((qzone_id) * IRO_ENT.m1))
|
|
+
|
|
+#define ETH_MAX_RX_CLIENTS_E1H 28
|
|
+#define ETH_MAX_RX_CLIENTS_E2 28
|
|
+
|
|
+#define BNX2X_CL_QZONE_ID(bp, cli) \
|
|
+ (cli + (bp->port * (CHIP_IS_E2(bp) ? \
|
|
+ ETH_MAX_RX_CLIENTS_E2 : \
|
|
+ ETH_MAX_RX_CLIENTS_E1H)))
|
|
+
|
|
+#define BNX2X_CL_QZONE_ID_64(bp, cli) \
|
|
+ (CHIP_IS_E2_PLUS(bp) ? (cli) : \
|
|
+ (cli + (bp->port * ETH_MAX_RX_CLIENTS_E1H)))
|
|
+
|
|
+#define BNX2X_PATH(bp) (!CHIP_IS_E2_PLUS(bp) ? 0 : (bp)->func & 1)
|
|
+
|
|
+#define SHMEM_P0_ISCSI_MAC_UPPER 0x4c
|
|
+#define SHMEM_P0_ISCSI_MAC_LOWER 0x50
|
|
+#define SHMEM_P1_ISCSI_MAC_UPPER 0x1dc
|
|
+#define SHMEM_P1_ISCSI_MAC_LOWER 0x1e0
|
|
+
|
|
+#define SHMEM_ISCSI_MAC_UPPER(bp) \
|
|
+ (((bp)->port == 0) ? \
|
|
+ SHMEM_P0_ISCSI_MAC_UPPER : SHMEM_P1_ISCSI_MAC_UPPER)
|
|
+
|
|
+#define SHMEM_ISCSI_MAC_LOWER(bp) \
|
|
+ (((bp)->port == 0) ? \
|
|
+ SHMEM_P0_ISCSI_MAC_LOWER : SHMEM_P1_ISCSI_MAC_LOWER)
|
|
+
|
|
+#define BNX2X_RCQ_DESC_CNT (4096 / sizeof(union eth_rx_cqe))
|
|
+#define BNX2X_RCQ_DESC_CNT_70 (4096 / sizeof(union eth_rx_cqe_70))
|
|
+#define BNX2X_MAX_RCQ_DESC_CNT(bp) \
|
|
+ ((bnx2x_is_ver70(bp) ? BNX2X_RCQ_DESC_CNT_70 : BNX2X_RCQ_DESC_CNT) - 1)
|
|
+
|
|
+#define BNX2X_RX_DESC_CNT (4096 / sizeof(struct eth_rx_bd))
|
|
+#define BNX2X_MAX_RX_DESC_CNT (BNX2X_RX_DESC_CNT - 2)
|
|
+#define BNX2X_NUM_RX_BD (BNX2X_RX_DESC_CNT * 1)
|
|
+#define BNX2X_MAX_RX_BD (BNX2X_NUM_RX_BD - 1)
|
|
+
|
|
+#define BNX2X_TX_DESC_CNT (4096 / sizeof(struct eth_tx_start_bd))
|
|
+#define BNX2X_MAX_TX_DESC_CNT (BNX2X_TX_DESC_CNT - 1)
|
|
+
|
|
+#define BNX2X_NEXT_RX_IDX(x) ((((x) & (BNX2X_RX_DESC_CNT - 1)) == \
|
|
+ (BNX2X_MAX_RX_DESC_CNT - 1)) ? \
|
|
+ (x) + 3 : (x) + 1)
|
|
+
|
|
+#define BNX2X_NEXT_RCQ_IDX(bp, x) \
|
|
+ ((((x) & BNX2X_MAX_RCQ_DESC_CNT(bp)) == \
|
|
+ (BNX2X_MAX_RCQ_DESC_CNT(bp) - 1)) ? (x) + 2 : (x) + 1)
|
|
+#define BNX2X_RX_BD(x) ((x) & BNX2X_MAX_RX_BD)
|
|
+
|
|
+#define BNX2X_NEXT_TX_BD(x) ((((x) & (BNX2X_MAX_TX_DESC_CNT - 1)) == \
|
|
+ (BNX2X_MAX_TX_DESC_CNT - 1)) ? \
|
|
+ (x) + 2 : (x) + 1)
|
|
+
|
|
+#define BNX2X_TX_RING_IDX(x) ((x) & BNX2X_MAX_TX_DESC_CNT)
|
|
+
|
|
+struct ustorm_eth_rx_producers {
|
|
+ __u16 cqe_prod;
|
|
+ __u16 bd_prod;
|
|
+ __u16 sge_prod;
|
|
+ __u16 reserved;
|
|
+};
|
|
+
|
|
+#define BNX2X_UNKNOWN_MAJOR_VERSION -1
|
|
+#define BNX2X_UNKNOWN_MINOR_VERSION -1
|
|
+#define BNX2X_UNKNOWN_SUB_MINOR_VERSION -1
|
|
+struct bnx2x_driver_version {
|
|
+ uint16_t major;
|
|
+ uint16_t minor;
|
|
+ uint16_t sub_minor;
|
|
+};
|
|
+
|
|
+typedef struct bnx2x {
|
|
+ nic_t *parent;
|
|
+
|
|
+ struct bnx2x_driver_version version;
|
|
+
|
|
+ uint16_t flags;
|
|
+#define CNIC_UIO_UNITIALIZED 0x0001
|
|
+#define CNIC_UIO_INITIALIZED 0x0002
|
|
+#define CNIC_UIO_ENABLED 0x0004
|
|
+#define CNIC_UIO_DISABLED 0x0008
|
|
+#define CNIC_UIO_IPv6_ENABLED 0x0010
|
|
+#define CNIC_UIO_ADDED_MULICAST 0x0020
|
|
+#define CNIC_UIO_MSIX_ENABLED 0x0200
|
|
+#define CNIC_UIO_TX_HAS_SENT 0x0400
|
|
+#define BNX2X_OPENED 0x0800
|
|
+
|
|
+ void *reg; /* Pointer to the BAR1 mapped registers */
|
|
+ void *reg2; /* Pointer to the BAR2 mapped registers */
|
|
+
|
|
+ int bar0_fd;
|
|
+ int bar2_fd;
|
|
+
|
|
+ __u32 chip_id;
|
|
+ __u32 shmem_base;
|
|
+ __u32 shmem_base2;
|
|
+ int func;
|
|
+ int port;
|
|
+ int pfid;
|
|
+ __u32 cid;
|
|
+ __u32 client_id;
|
|
+
|
|
+ struct iro *iro;
|
|
+ int iro_idx;
|
|
+
|
|
+ __u32 tx_doorbell;
|
|
+
|
|
+ __u16 tx_prod;
|
|
+ __u16 tx_bd_prod;
|
|
+ __u16 tx_cons;
|
|
+ __u8 tx_vlan_tag_bit;
|
|
+
|
|
+ __u32 rx_prod_io;
|
|
+
|
|
+ __u16 rx_prod;
|
|
+ __u16 rx_bd_prod;
|
|
+ __u16 rx_cons;
|
|
+ __u16 rx_bd_cons;
|
|
+ __u16 rx_hw_prod;
|
|
+
|
|
+ __u16(*get_rx_cons) (struct bnx2x *);
|
|
+ __u16(*get_tx_cons) (struct bnx2x *);
|
|
+
|
|
+ /* RX ring parameters */
|
|
+ uint32_t rx_ring_size;
|
|
+ uint32_t rx_buffer_size;
|
|
+
|
|
+ void *bufs; /* Pointer to the mapped buffer space */
|
|
+
|
|
+ /* Hardware Status Block locations */
|
|
+ void *sblk_map;
|
|
+ union {
|
|
+ struct host_def_status_block *def;
|
|
+ struct host_sp_status_block *sp;
|
|
+ } status_blk;
|
|
+
|
|
+ int status_blk_size;
|
|
+
|
|
+ uint16_t rx_index;
|
|
+ union {
|
|
+ union eth_rx_cqe *cqe;
|
|
+ union eth_rx_cqe_70 *cqe70;
|
|
+ } rx_comp_ring;
|
|
+ void **rx_pkt_ring;
|
|
+
|
|
+ struct eth_tx_start_bd *tx_ring;
|
|
+ void *tx_pkt;
|
|
+
|
|
+} bnx2x_t;
|
|
+
|
|
+/******************************************************************************
|
|
+ * bnx2x Function Declarations
|
|
+ ******************************************************************************/
|
|
+void bnx2x_start_xmit(nic_t *nic, size_t len, u16_t vlan_id);
|
|
+
|
|
+struct nic_ops *bnx2x_get_ops();
|
|
+#endif /* __BNX2X_H__ */
|
|
diff --git a/iscsiuio/src/unix/libs/cnic.c b/iscsiuio/src/unix/libs/cnic.c
|
|
new file mode 100644
|
|
index 0000000..7f473c4
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/libs/cnic.c
|
|
@@ -0,0 +1,662 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * cnic.c - CNIC UIO uIP user space stack
|
|
+ *
|
|
+ */
|
|
+#include <errno.h>
|
|
+#include <pthread.h>
|
|
+#include <signal.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <unistd.h>
|
|
+#include <arpa/inet.h>
|
|
+#include <linux/limits.h>
|
|
+#include <netinet/if_ether.h>
|
|
+#include <netinet/in.h>
|
|
+#include <netinet/ip6.h>
|
|
+#include <netinet/icmp6.h>
|
|
+#include <linux/netlink.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <sys/time.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/user.h>
|
|
+#include <sys/socket.h>
|
|
+
|
|
+#include "uip_arp.h"
|
|
+#include "nic.h"
|
|
+#include "nic_utils.h"
|
|
+#include "logger.h"
|
|
+#include "options.h"
|
|
+
|
|
+#include "cnic.h"
|
|
+#include "iscsi_if.h"
|
|
+#include "ipv6_ndpc.h"
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Constants
|
|
+ ******************************************************************************/
|
|
+#define PFX "CNIC "
|
|
+
|
|
+static const uip_ip6addr_t all_ones_addr6 = {
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff };
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Constants shared between the bnx2 and bnx2x modules
|
|
+ ******************************************************************************/
|
|
+const char bnx2i_library_transport_name[] = "bnx2i";
|
|
+const size_t bnx2i_library_transport_name_size =
|
|
+ sizeof(bnx2i_library_transport_name);
|
|
+
|
|
+/******************************************************************************
|
|
+ * Netlink Functions
|
|
+ ******************************************************************************/
|
|
+
|
|
+static int cnic_arp_send(nic_t *nic, nic_interface_t *nic_iface, int fd,
|
|
+ __u8 *mac_addr, __u32 ip_addr, char *addr_str)
|
|
+{
|
|
+ struct ether_header *eth;
|
|
+ struct ether_arp *arp;
|
|
+ __u32 dst_ip = ip_addr;
|
|
+ int pkt_size = sizeof(*eth) + sizeof(*arp);
|
|
+ int rc;
|
|
+ struct in_addr addr;
|
|
+ static const uint8_t multicast_mac[] = {
|
|
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
+
|
|
+ rc = pthread_mutex_trylock(&nic->xmit_mutex);
|
|
+ if (rc != 0) {
|
|
+ LOG_DEBUG(PFX "%s: could not get xmit_mutex", nic->log_name);
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ eth = (*nic->ops->get_tx_pkt) (nic);
|
|
+ if (eth == NULL) {
|
|
+ LOG_WARN(PFX "%s: couldn't get tx packet", nic->log_name);
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ nic_fill_ethernet_header(nic_iface, eth,
|
|
+ nic->mac_addr, (void *)multicast_mac,
|
|
+ &pkt_size, (void *)&arp, ETHERTYPE_ARP);
|
|
+
|
|
+ arp->arp_hrd = htons(ARPHRD_ETHER);
|
|
+ arp->arp_pro = htons(ETHERTYPE_IP);
|
|
+ arp->arp_hln = ETH_ALEN;
|
|
+ arp->arp_pln = 4;
|
|
+ arp->arp_op = htons(ARPOP_REQUEST);
|
|
+ memcpy(arp->arp_sha, nic->mac_addr, ETH_ALEN);
|
|
+ memset(arp->arp_tha, 0, ETH_ALEN);
|
|
+
|
|
+ /* Copy the IP address's into the ARP response */
|
|
+ memcpy(arp->arp_spa, nic_iface->ustack.hostaddr, 4);
|
|
+ memcpy(arp->arp_tpa, &dst_ip, 4);
|
|
+
|
|
+ (*nic->nic_library->ops->start_xmit) (nic, pkt_size,
|
|
+ (nic_iface->vlan_priority << 12) |
|
|
+ nic_iface->vlan_id);
|
|
+
|
|
+ memcpy(&addr.s_addr, &dst_ip, sizeof(addr.s_addr));
|
|
+ LOG_DEBUG(PFX "%s: Sent cnic arp request for IP: %s",
|
|
+ nic->log_name, addr_str);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int cnic_neigh_soliciation_send(nic_t *nic,
|
|
+ nic_interface_t *nic_iface, int fd,
|
|
+ __u8 *mac_addr,
|
|
+ struct in6_addr *addr6_dst,
|
|
+ char *addr_str)
|
|
+{
|
|
+ struct ether_header *eth;
|
|
+ struct ip6_hdr *ipv6_hdr;
|
|
+ int rc, pkt_size;
|
|
+ char buf[INET6_ADDRSTRLEN];
|
|
+ struct ndpc_reqptr req_ptr;
|
|
+
|
|
+ rc = pthread_mutex_trylock(&nic->xmit_mutex);
|
|
+ if (rc != 0) {
|
|
+ LOG_WARN(PFX "%s: could not get xmit_mutex", nic->log_name);
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ /* Build the ethernet header */
|
|
+ eth = (*nic->ops->get_tx_pkt) (nic);
|
|
+ if (eth == NULL) {
|
|
+ LOG_WARN(PFX "%s: couldn't get tx packet", nic->log_name);
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ /* Copy the requested target address to the ipv6.dst */
|
|
+ ipv6_hdr =
|
|
+ (struct ip6_hdr *)((u8_t *) eth + sizeof(struct ether_header));
|
|
+
|
|
+ memcpy(ipv6_hdr->ip6_dst.s6_addr, addr6_dst->s6_addr,
|
|
+ sizeof(struct in6_addr));
|
|
+
|
|
+ nic_fill_ethernet_header(nic_iface, eth, nic->mac_addr, nic->mac_addr,
|
|
+ &pkt_size, (void *)&ipv6_hdr, ETHERTYPE_IPV6);
|
|
+ req_ptr.eth = (void *)eth;
|
|
+ req_ptr.ipv6 = (void *)ipv6_hdr;
|
|
+ if (ndpc_request(&nic_iface->ustack, &req_ptr, &pkt_size,
|
|
+ NEIGHBOR_SOLICIT))
|
|
+ return -EAGAIN;
|
|
+
|
|
+ /* Debug to print out the pkt context */
|
|
+ inet_ntop(AF_INET6, ipv6_hdr->ip6_dst.s6_addr, buf, sizeof(buf));
|
|
+ LOG_DEBUG(PFX "%s: ipv6 dst addr: %s", nic->log_name, buf);
|
|
+ LOG_DEBUG(PFX "neighbor sol content "
|
|
+ "dst mac %02x:%02x:%02x:%02x:%02x:%02x",
|
|
+ eth->ether_dhost[0], eth->ether_dhost[1],
|
|
+ eth->ether_dhost[2], eth->ether_dhost[3],
|
|
+ eth->ether_dhost[4], eth->ether_dhost[5]);
|
|
+ LOG_DEBUG(PFX "src mac %02x:%02x:%02x:%02x:%02x:%02x",
|
|
+ eth->ether_shost[0], eth->ether_shost[1],
|
|
+ eth->ether_shost[2], eth->ether_shost[3],
|
|
+ eth->ether_shost[4], eth->ether_shost[5]);
|
|
+ (*nic->nic_library->ops->start_xmit) (nic, pkt_size,
|
|
+ (nic_iface->vlan_priority << 12) |
|
|
+ nic_iface->vlan_id);
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: Sent cnic ICMPv6 neighbor request %s",
|
|
+ nic->log_name, addr_str);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int cnic_nl_neigh_rsp(nic_t *nic, int fd,
|
|
+ struct iscsi_uevent *ev,
|
|
+ struct iscsi_path *path_req,
|
|
+ __u8 *mac_addr,
|
|
+ nic_interface_t *nic_iface, int status, int type)
|
|
+{
|
|
+ int rc;
|
|
+ uint8_t *ret_buf;
|
|
+ struct iscsi_uevent *ret_ev;
|
|
+ struct iscsi_path *path_rsp;
|
|
+ struct sockaddr_nl dest_addr;
|
|
+ char addr_dst_str[INET6_ADDRSTRLEN];
|
|
+
|
|
+ memset(&dest_addr, 0, sizeof(dest_addr));
|
|
+ dest_addr.nl_family = AF_NETLINK;
|
|
+ dest_addr.nl_pid = 0;
|
|
+ dest_addr.nl_groups = 0; /* unicast */
|
|
+
|
|
+ ret_buf = calloc(1, NLMSG_SPACE(sizeof(struct iscsi_uevent) + 256));
|
|
+ if (ret_buf == NULL) {
|
|
+ LOG_ERR(PFX "Could not allocate memory for path req resposne");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ memset(ret_buf, 0, NLMSG_SPACE(sizeof(struct iscsi_uevent) + 256));
|
|
+
|
|
+ /* prepare the iscsi_uevent buffer */
|
|
+ ret_ev = (struct iscsi_uevent *)ret_buf;
|
|
+ ret_ev->type = ISCSI_UEVENT_PATH_UPDATE;
|
|
+ ret_ev->transport_handle = ev->transport_handle;
|
|
+ ret_ev->u.set_path.host_no = ev->r.req_path.host_no;
|
|
+
|
|
+ /* Prepare the iscsi_path buffer */
|
|
+ path_rsp = (struct iscsi_path *)(ret_buf + sizeof(*ret_ev));
|
|
+ path_rsp->handle = path_req->handle;
|
|
+ if (type == AF_INET) {
|
|
+ path_rsp->ip_addr_len = 4;
|
|
+ memcpy(&path_rsp->src.v4_addr, nic_iface->ustack.hostaddr,
|
|
+ sizeof(nic_iface->ustack.hostaddr));
|
|
+
|
|
+ inet_ntop(AF_INET, &path_rsp->src.v4_addr,
|
|
+ addr_dst_str, sizeof(addr_dst_str));
|
|
+ } else {
|
|
+ u8_t *src_ipv6;
|
|
+ int ret;
|
|
+
|
|
+ /* Depending on the IPv6 address of the target we will need to
|
|
+ * determine whether we use the assigned IPv6 address or the
|
|
+ * link local IPv6 address */
|
|
+ if (ndpc_request(&nic_iface->ustack, &path_req->dst.v6_addr,
|
|
+ &ret, CHECK_LINK_LOCAL_ADDR)) {
|
|
+ src_ipv6 = (u8_t *)all_zeroes_addr6;
|
|
+ LOG_DEBUG(PFX "RSP Check LL failed");
|
|
+ goto src_done;
|
|
+ }
|
|
+ if (ret) {
|
|
+ /* Get link local IPv6 address */
|
|
+ src_ipv6 = (u8_t *)&nic_iface->ustack.linklocal6;
|
|
+ } else {
|
|
+ if (ndpc_request(&nic_iface->ustack,
|
|
+ &path_req->dst.v6_addr,
|
|
+ &src_ipv6, GET_HOST_ADDR)) {
|
|
+ src_ipv6 = (u8_t *)all_zeroes_addr6;
|
|
+ LOG_DEBUG(PFX "RSP Get host addr failed");
|
|
+ }
|
|
+ if (src_ipv6 == NULL) {
|
|
+ src_ipv6 = (u8_t *)all_zeroes_addr6;
|
|
+ LOG_DEBUG(PFX "RSP no Best matched addr found");
|
|
+ }
|
|
+ }
|
|
+src_done:
|
|
+ path_rsp->ip_addr_len = 16;
|
|
+ memcpy(&path_rsp->src.v6_addr, src_ipv6,
|
|
+ sizeof(nic_iface->ustack.hostaddr6));
|
|
+
|
|
+ inet_ntop(AF_INET6, &path_rsp->src.v6_addr,
|
|
+ addr_dst_str, sizeof(addr_dst_str));
|
|
+ }
|
|
+ memcpy(path_rsp->mac_addr, mac_addr, 6);
|
|
+ path_rsp->vlan_id = (nic_iface->vlan_priority << 12) |
|
|
+ nic_iface->vlan_id;
|
|
+ path_rsp->pmtu = nic_iface->mtu ? nic_iface->mtu : path_req->pmtu;
|
|
+
|
|
+ rc = __kipc_call(fd, ret_ev, sizeof(*ret_ev) + sizeof(*path_rsp));
|
|
+ if (rc > 0) {
|
|
+ LOG_DEBUG(PFX "neighbor reply sent back to kernel "
|
|
+ "%s at %02x:%02x:%02x:%02x:%02x:%02x with vlan %d",
|
|
+ addr_dst_str,
|
|
+ mac_addr[0], mac_addr[1],
|
|
+ mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5],
|
|
+ nic_iface->vlan_id);
|
|
+
|
|
+ } else {
|
|
+ LOG_ERR(PFX "send neighbor reply failed: %d", rc);
|
|
+ }
|
|
+
|
|
+ free(ret_buf);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static const struct timeval tp_wait = {
|
|
+ .tv_sec = 0,
|
|
+ .tv_usec = 250000,
|
|
+};
|
|
+
|
|
+/**
|
|
+ * cnic_handle_ipv4_iscsi_path_req() - This function will handle the IPv4
|
|
+ * path req calls the bnx2i kernel module
|
|
+ * @param nic - The nic the message is directed towards
|
|
+ * @param fd - The file descriptor to be used to extract the private data
|
|
+ * @param ev - The iscsi_uevent
|
|
+ * @param buf - The private message buffer
|
|
+ */
|
|
+int cnic_handle_ipv4_iscsi_path_req(nic_t *nic, int fd,
|
|
+ struct iscsi_uevent *ev,
|
|
+ struct iscsi_path *path,
|
|
+ nic_interface_t *nic_iface)
|
|
+{
|
|
+ struct in_addr src_addr, dst_addr,
|
|
+ src_matching_addr, dst_matching_addr, netmask;
|
|
+ __u8 mac_addr[6];
|
|
+ int rc;
|
|
+ uint16_t arp_retry;
|
|
+ int status = 0;
|
|
+#define MAX_ARP_RETRY 4
|
|
+
|
|
+ memset(mac_addr, 0, sizeof(mac_addr));
|
|
+ memcpy(&dst_addr, &path->dst.v4_addr, sizeof(dst_addr));
|
|
+ memcpy(&src_addr, nic_iface->ustack.hostaddr, sizeof(src_addr));
|
|
+
|
|
+ if (nic_iface->ustack.netmask[0] | nic_iface->ustack.netmask[1])
|
|
+ memcpy(&netmask.s_addr, nic_iface->ustack.netmask,
|
|
+ sizeof(src_addr));
|
|
+ else
|
|
+ netmask.s_addr = calculate_default_netmask(dst_addr.s_addr);
|
|
+
|
|
+ src_matching_addr.s_addr = src_addr.s_addr & netmask.s_addr;
|
|
+ dst_matching_addr.s_addr = dst_addr.s_addr & netmask.s_addr;
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: src=%s", nic->log_name, inet_ntoa(src_addr));
|
|
+ LOG_DEBUG(PFX "%s: dst=%s", nic->log_name, inet_ntoa(dst_addr));
|
|
+ LOG_DEBUG(PFX "%s: nm=%s", nic->log_name, inet_ntoa(netmask));
|
|
+ if (src_matching_addr.s_addr != dst_matching_addr.s_addr) {
|
|
+ /* If there is an assigned gateway address then use it
|
|
+ * if the source address doesn't match */
|
|
+ if (nic_iface->ustack.default_route_addr[0] |
|
|
+ nic_iface->ustack.default_route_addr[1]) {
|
|
+ memcpy(&dst_addr,
|
|
+ &nic_iface->ustack.default_route_addr,
|
|
+ sizeof(dst_addr));
|
|
+ } else {
|
|
+ arp_retry = MAX_ARP_RETRY;
|
|
+ LOG_DEBUG(PFX "%s: no default", nic->log_name);
|
|
+ goto done;
|
|
+ }
|
|
+ }
|
|
+ arp_retry = 0;
|
|
+
|
|
+ rc = uip_lookup_arp_entry(dst_addr.s_addr, mac_addr);
|
|
+ if (rc != 0) {
|
|
+ while ((arp_retry < MAX_ARP_RETRY) && (event_loop_stop == 0)) {
|
|
+ char *dst_addr_str;
|
|
+ int count;
|
|
+ struct timespec ts;
|
|
+ struct timeval tp;
|
|
+ struct timeval tp_abs;
|
|
+
|
|
+ dst_addr_str = inet_ntoa(dst_addr);
|
|
+
|
|
+ LOG_INFO(PFX "%s: Didn't find IPv4: '%s' in ARP table",
|
|
+ nic->log_name, dst_addr_str);
|
|
+ rc = cnic_arp_send(nic, nic_iface, fd,
|
|
+ mac_addr,
|
|
+ dst_addr.s_addr, dst_addr_str);
|
|
+ if (rc != 0) {
|
|
+ status = -EIO;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ for (count = 0; count < 8; count++) {
|
|
+ /* Convert from timeval to timespec */
|
|
+ rc = gettimeofday(&tp, NULL);
|
|
+
|
|
+ timeradd(&tp, &tp_wait, &tp_abs);
|
|
+
|
|
+ ts.tv_sec = tp_abs.tv_sec;
|
|
+ ts.tv_nsec = tp_abs.tv_usec * 1000;
|
|
+
|
|
+ /* Wait 1s for if_down */
|
|
+ pthread_mutex_lock(&nic->nl_process_mutex);
|
|
+ rc = pthread_cond_timedwait
|
|
+ (&nic->nl_process_if_down_cond,
|
|
+ &nic->nl_process_mutex, &ts);
|
|
+
|
|
+ if (rc == ETIMEDOUT) {
|
|
+ pthread_mutex_unlock
|
|
+ (&nic->nl_process_mutex);
|
|
+
|
|
+ rc = uip_lookup_arp_entry(dst_addr.
|
|
+ s_addr,
|
|
+ mac_addr);
|
|
+ if (rc == 0)
|
|
+ goto done;
|
|
+ } else {
|
|
+ nic->nl_process_if_down = 0;
|
|
+ pthread_mutex_unlock
|
|
+ (&nic->nl_process_mutex);
|
|
+
|
|
+ arp_retry = MAX_ARP_RETRY;
|
|
+ goto done;
|
|
+
|
|
+ }
|
|
+ }
|
|
+
|
|
+ arp_retry++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+done:
|
|
+
|
|
+ if (arp_retry >= MAX_ARP_RETRY) {
|
|
+ status = -EIO;
|
|
+ rc = -EIO;
|
|
+ }
|
|
+
|
|
+ if (status != 0 || rc != 0)
|
|
+ pthread_mutex_unlock(&nic->xmit_mutex);
|
|
+
|
|
+ cnic_nl_neigh_rsp(nic, fd, ev, path, mac_addr,
|
|
+ nic_iface, status, AF_INET);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * cnic_handle_ipv6_iscsi_path_req() - This function will handle the IPv4
|
|
+ * path req calls the bnx2i kernel module
|
|
+ * @param nic - The nic the message is directed towards
|
|
+ * @param fd - The file descriptor to be used to extract the private data
|
|
+ * @param ev - The iscsi_uevent
|
|
+ * @param buf - The private message buffer
|
|
+ */
|
|
+int cnic_handle_ipv6_iscsi_path_req(nic_t *nic, int fd,
|
|
+ struct iscsi_uevent *ev,
|
|
+ struct iscsi_path *path,
|
|
+ nic_interface_t *nic_iface)
|
|
+{
|
|
+ __u8 mac_addr[6];
|
|
+ int rc, i;
|
|
+ uint16_t neighbor_retry;
|
|
+ int status = 0;
|
|
+ char addr_dst_str[INET6_ADDRSTRLEN];
|
|
+ struct in6_addr src_addr, dst_addr,
|
|
+ src_matching_addr, dst_matching_addr, netmask;
|
|
+ struct in6_addr *addr;
|
|
+ struct ndpc_reqptr req_ptr;
|
|
+
|
|
+ memset(mac_addr, 0, sizeof(mac_addr));
|
|
+
|
|
+ inet_ntop(AF_INET6, &path->dst.v6_addr,
|
|
+ addr_dst_str, sizeof(addr_dst_str));
|
|
+
|
|
+ /* Depending on the IPv6 address of the target we will need to
|
|
+ * determine whether we use the assigned IPv6 address or the
|
|
+ * link local IPv6 address */
|
|
+ memcpy(&dst_addr, &path->dst.v6_addr, sizeof(struct in6_addr));
|
|
+ if (ndpc_request(&nic_iface->ustack, &dst_addr,
|
|
+ &rc, CHECK_LINK_LOCAL_ADDR)) {
|
|
+ neighbor_retry = MAX_ARP_RETRY;
|
|
+ LOG_DEBUG(PFX "Check LL failed");
|
|
+ goto done;
|
|
+ }
|
|
+ if (rc) {
|
|
+ LOG_DEBUG(PFX "Use LL");
|
|
+ /* Get link local IPv6 address */
|
|
+ addr = (struct in6_addr *)&nic_iface->ustack.linklocal6;
|
|
+ } else {
|
|
+ LOG_DEBUG(PFX "Use Best matched");
|
|
+ if (ndpc_request(&nic_iface->ustack,
|
|
+ &dst_addr,
|
|
+ &addr, GET_HOST_ADDR)) {
|
|
+ neighbor_retry = MAX_ARP_RETRY;
|
|
+ LOG_DEBUG(PFX "Use Best matched failed");
|
|
+ goto done;
|
|
+ }
|
|
+ if (addr == NULL) {
|
|
+ neighbor_retry = MAX_ARP_RETRY;
|
|
+ LOG_DEBUG(PFX "No Best matched found");
|
|
+ goto done;
|
|
+ }
|
|
+ }
|
|
+ /* Got the best matched src IP address */
|
|
+ memcpy(&src_addr, addr, sizeof(struct in6_addr));
|
|
+
|
|
+ if (nic_iface->ustack.netmask6[0] | nic_iface->ustack.netmask6[1] |
|
|
+ nic_iface->ustack.netmask6[2] | nic_iface->ustack.netmask6[3] |
|
|
+ nic_iface->ustack.netmask6[4] | nic_iface->ustack.netmask6[5] |
|
|
+ nic_iface->ustack.netmask6[6] | nic_iface->ustack.netmask6[7])
|
|
+ memcpy(&netmask.s6_addr, nic_iface->ustack.netmask6,
|
|
+ sizeof(struct in6_addr));
|
|
+ else
|
|
+ memcpy(&netmask.s6_addr, all_zeroes_addr6,
|
|
+ sizeof(struct in6_addr));
|
|
+
|
|
+ inet_ntop(AF_INET6, &src_addr.s6_addr16, addr_dst_str,
|
|
+ sizeof(addr_dst_str));
|
|
+ LOG_DEBUG(PFX "src IP addr %s", addr_dst_str);
|
|
+ inet_ntop(AF_INET6, &dst_addr.s6_addr16, addr_dst_str,
|
|
+ sizeof(addr_dst_str));
|
|
+ LOG_DEBUG(PFX "dst IP addr %s", addr_dst_str);
|
|
+ inet_ntop(AF_INET6, &netmask.s6_addr16, addr_dst_str,
|
|
+ sizeof(addr_dst_str));
|
|
+ LOG_DEBUG(PFX "prefix mask %s", addr_dst_str);
|
|
+
|
|
+ for (i = 0; i < 4; i++) {
|
|
+ src_matching_addr.s6_addr32[i] = src_addr.s6_addr32[i] &
|
|
+ netmask.s6_addr32[i];
|
|
+ dst_matching_addr.s6_addr32[i] = dst_addr.s6_addr32[i] &
|
|
+ netmask.s6_addr32[i];
|
|
+ if (src_matching_addr.s6_addr32[i] !=
|
|
+ dst_matching_addr.s6_addr32[i]) {
|
|
+ /* No match with the prefix mask, use default route */
|
|
+ if (memcmp(nic_iface->ustack.default_route_addr6,
|
|
+ all_zeroes_addr6, sizeof(*addr))) {
|
|
+ memcpy(&dst_addr,
|
|
+ nic_iface->ustack.default_route_addr6,
|
|
+ sizeof(dst_addr));
|
|
+ inet_ntop(AF_INET6, &dst_addr.s6_addr16,
|
|
+ addr_dst_str, sizeof(addr_dst_str));
|
|
+ LOG_DEBUG(PFX "Use default router IP addr %s",
|
|
+ addr_dst_str);
|
|
+ break;
|
|
+ } else {
|
|
+ neighbor_retry = MAX_ARP_RETRY;
|
|
+ goto done;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+#define MAX_ARP_RETRY 4
|
|
+ neighbor_retry = 0;
|
|
+
|
|
+ req_ptr.eth = (void *)mac_addr;
|
|
+ req_ptr.ipv6 = (void *)&dst_addr;
|
|
+ if (ndpc_request(&nic_iface->ustack, &req_ptr, &rc, CHECK_ARP_TABLE)) {
|
|
+ /* ndpc request failed, skip neighbor solicit send */
|
|
+ neighbor_retry = MAX_ARP_RETRY;
|
|
+ goto done;
|
|
+ }
|
|
+ if (!rc) {
|
|
+ inet_ntop(AF_INET6, &dst_addr.s6_addr16,
|
|
+ addr_dst_str, sizeof(addr_dst_str));
|
|
+ LOG_DEBUG(PFX
|
|
+ "%s: Preparing to send IPv6 neighbor solicitation "
|
|
+ "to dst: '%s'", nic->log_name, addr_dst_str);
|
|
+ while ((neighbor_retry < MAX_ARP_RETRY)
|
|
+ && (event_loop_stop == 0)) {
|
|
+ int count;
|
|
+ struct timespec ts;
|
|
+ struct timeval tp;
|
|
+ struct timeval tp_abs;
|
|
+
|
|
+ LOG_INFO(PFX "%s: Didn't find IPv6: '%s'\n",
|
|
+ nic->log_name, addr_dst_str);
|
|
+
|
|
+ rc = cnic_neigh_soliciation_send(nic, nic_iface, fd,
|
|
+ mac_addr,
|
|
+ &dst_addr,
|
|
+ addr_dst_str);
|
|
+ if (rc != 0) {
|
|
+ status = -EIO;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ for (count = 0; count < 8; count++) {
|
|
+ /* Convert from timeval to timespec */
|
|
+ rc = gettimeofday(&tp, NULL);
|
|
+
|
|
+ timeradd(&tp, &tp_wait, &tp_abs);
|
|
+
|
|
+ ts.tv_sec = tp_abs.tv_sec;
|
|
+ ts.tv_nsec = tp_abs.tv_usec * 1000;
|
|
+
|
|
+ pthread_mutex_lock(&nic->nl_process_mutex);
|
|
+ rc = pthread_cond_timedwait
|
|
+ (&nic->nl_process_if_down_cond,
|
|
+ &nic->nl_process_mutex, &ts);
|
|
+
|
|
+ if (rc == ETIMEDOUT) {
|
|
+ pthread_mutex_unlock
|
|
+ (&nic->nl_process_mutex);
|
|
+
|
|
+ req_ptr.eth = (void *)mac_addr;
|
|
+ req_ptr.ipv6 = (void *)&dst_addr;
|
|
+ if (ndpc_request
|
|
+ (&nic_iface->ustack, &req_ptr, &rc,
|
|
+ CHECK_ARP_TABLE)) {
|
|
+ /* ndpc request failed,
|
|
+ force retry */
|
|
+ rc = 0;
|
|
+ }
|
|
+ if (rc)
|
|
+ goto done;
|
|
+ } else {
|
|
+ nic->nl_process_if_down = 0;
|
|
+ pthread_mutex_unlock
|
|
+ (&nic->nl_process_mutex);
|
|
+
|
|
+ neighbor_retry = MAX_ARP_RETRY;
|
|
+ goto done;
|
|
+ }
|
|
+ }
|
|
+ neighbor_retry++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+done:
|
|
+ if (neighbor_retry >= MAX_ARP_RETRY) {
|
|
+ status = -EIO;
|
|
+ rc = -EIO;
|
|
+ }
|
|
+
|
|
+ if (status != 0 || rc != 0)
|
|
+ pthread_mutex_unlock(&nic->xmit_mutex);
|
|
+
|
|
+ cnic_nl_neigh_rsp(nic, fd, ev, path, mac_addr,
|
|
+ nic_iface, status, AF_INET6);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * cnic_handle_iscsi_path_req() - This function will handle the path req calls
|
|
+ * the bnx2i kernel module
|
|
+ * @param nic - The nic the message is directed towards
|
|
+ * @param fd - The file descriptor to be used to extract the private data
|
|
+ * @param ev - The iscsi_uevent
|
|
+ * @param path - The private message buffer
|
|
+ * @param nic_iface - The nic_iface to use for this connection request
|
|
+ */
|
|
+int cnic_handle_iscsi_path_req(nic_t *nic, int fd, struct iscsi_uevent *ev,
|
|
+ struct iscsi_path *path,
|
|
+ nic_interface_t *nic_iface)
|
|
+{
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: Netlink message with VLAN ID: %d, path MTU: %d "
|
|
+ "minor: %d ip_addr_len: %d",
|
|
+ nic->log_name, path->vlan_id, path->pmtu, 0 /* TODO FIX */ ,
|
|
+ path->ip_addr_len);
|
|
+
|
|
+ if (path->ip_addr_len == 4)
|
|
+ return cnic_handle_ipv4_iscsi_path_req(nic, fd, ev, path,
|
|
+ nic_iface);
|
|
+ else if (path->ip_addr_len == 16)
|
|
+ return cnic_handle_ipv6_iscsi_path_req(nic, fd, ev, path,
|
|
+ nic_iface);
|
|
+ else {
|
|
+ LOG_DEBUG(PFX "%s: unknown ip_addr_len: %d size dropping ",
|
|
+ nic->log_name, path->ip_addr_len);
|
|
+ return -EIO;
|
|
+ }
|
|
+}
|
|
diff --git a/iscsiuio/src/unix/libs/cnic.h b/iscsiuio/src/unix/libs/cnic.h
|
|
new file mode 100644
|
|
index 0000000..6244a94
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/libs/cnic.h
|
|
@@ -0,0 +1,55 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * cnic.h - CNIC UIO uIP user space stack
|
|
+ *
|
|
+ */
|
|
+#ifndef __CNIC_NL_H__
|
|
+#define __CNIC_NL_H__
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Constants shared between the bnx2 and bnx2x modules
|
|
+ ******************************************************************************/
|
|
+extern const char bnx2i_library_transport_name[];
|
|
+extern const size_t bnx2i_library_transport_name_size;
|
|
+
|
|
+int cnic_nl_open();
|
|
+void cnic_nl_close();
|
|
+
|
|
+int cnic_handle_iscsi_path_req(nic_t *nic, int, struct iscsi_uevent *,
|
|
+ struct iscsi_path *path,
|
|
+ nic_interface_t *nic_iface);
|
|
+
|
|
+#endif /* __CNIC_NL_H__ */
|
|
diff --git a/iscsiuio/src/unix/logger.c b/iscsiuio/src/unix/logger.c
|
|
new file mode 100644
|
|
index 0000000..d41f9e8
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/logger.c
|
|
@@ -0,0 +1,181 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * logger.c - Logging Utilities
|
|
+ *
|
|
+ */
|
|
+#include <errno.h>
|
|
+#include <string.h>
|
|
+#include <time.h>
|
|
+#include <stdarg.h>
|
|
+#include <stdlib.h>
|
|
+
|
|
+#include "options.h"
|
|
+#include "logger.h"
|
|
+
|
|
+/******************************************************************************
|
|
+ * Default logger values
|
|
+ ******************************************************************************/
|
|
+static const char default_logger_filename[] = "/var/log/iscsiuio.log";
|
|
+
|
|
+struct logger main_log = {
|
|
+ .enabled = LOGGER_ENABLED,
|
|
+ .fp = NULL,
|
|
+ .log_file = (char *)default_logger_filename,
|
|
+ .level = LOG_LEVEL_INFO,
|
|
+ .lock = PTHREAD_MUTEX_INITIALIZER,
|
|
+
|
|
+ .stats = {
|
|
+ .debug = 0,
|
|
+ .info = 0,
|
|
+ .warn = 0,
|
|
+ .error = 0,
|
|
+
|
|
+ .last_log_time = 0,
|
|
+ },
|
|
+};
|
|
+
|
|
+/******************************************************************************
|
|
+ * Logger Functions
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * log_uip() - Main logging function
|
|
+ * @param level_str - log level string
|
|
+ * @param fmt - log format
|
|
+ */
|
|
+void log_uip(char *level_str, char *fmt, ...)
|
|
+{
|
|
+ char time_buf[32];
|
|
+ va_list ap, ap2;
|
|
+
|
|
+ pthread_mutex_lock(&main_log.lock);
|
|
+ va_start(ap, fmt);
|
|
+
|
|
+ if (main_log.fp == NULL)
|
|
+ goto end;
|
|
+
|
|
+ main_log.stats.last_log_time = time(NULL);
|
|
+ strftime(time_buf, 26, "%a %b %d %T %Y",
|
|
+ localtime(&main_log.stats.last_log_time));
|
|
+ va_copy(ap2, ap);
|
|
+
|
|
+ if (main_log.enabled == LOGGER_ENABLED) {
|
|
+ fprintf(main_log.fp, "%s [%s]", level_str, time_buf);
|
|
+ vfprintf(main_log.fp, fmt, ap);
|
|
+ fprintf(main_log.fp, "\n");
|
|
+ }
|
|
+
|
|
+ if (opt.debug == DEBUG_ON) {
|
|
+ fprintf(stdout, "%s [%s]", level_str, time_buf);
|
|
+ vfprintf(stdout, fmt, ap2);
|
|
+ fprintf(stdout, "\n");
|
|
+
|
|
+ /* Force the printing of the log file */
|
|
+ fflush(main_log.fp);
|
|
+
|
|
+ /* Force the printing of the log out to standard output */
|
|
+ fflush(stdout);
|
|
+ }
|
|
+
|
|
+end:
|
|
+ va_end(ap2);
|
|
+ va_end(ap);
|
|
+ pthread_mutex_unlock(&main_log.lock);
|
|
+}
|
|
+
|
|
+/******************************************************************************
|
|
+ * Initialize/Clean up routines
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * init_logger() - Prepare the logger
|
|
+ * @param filename - path to where the log will be written to
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+int init_logger(char *filename)
|
|
+{
|
|
+ int rc = 0;
|
|
+
|
|
+ pthread_mutex_lock(&main_log.lock);
|
|
+
|
|
+ if (opt.debug != DEBUG_ON) {
|
|
+ rc = -EIO;
|
|
+ goto disable;
|
|
+ }
|
|
+ main_log.fp = fopen(filename, "a");
|
|
+ if (main_log.fp == NULL) {
|
|
+ printf("Could not create log file: %s <%s>\n",
|
|
+ filename, strerror(errno));
|
|
+ rc = -EIO;
|
|
+ }
|
|
+disable:
|
|
+ if (rc)
|
|
+ main_log.enabled = LOGGER_DISABLED;
|
|
+ else
|
|
+ main_log.enabled = LOGGER_ENABLED;
|
|
+
|
|
+ pthread_mutex_unlock(&main_log.lock);
|
|
+
|
|
+ if (!rc)
|
|
+ LOG_INFO("Initialize logger using log file: %s", filename);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+void fini_logger(int type)
|
|
+{
|
|
+ pthread_mutex_lock(&main_log.lock);
|
|
+
|
|
+ if (main_log.fp != NULL) {
|
|
+ fclose(main_log.fp);
|
|
+ main_log.fp = NULL;
|
|
+
|
|
+ if (opt.debug == DEBUG_ON) {
|
|
+ printf("Closed logger\n");
|
|
+ fflush(stdout);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (type == SHUTDOWN_LOGGER) {
|
|
+ if ((main_log.log_file != NULL) &&
|
|
+ (main_log.log_file != default_logger_filename)) {
|
|
+ free(main_log.log_file);
|
|
+ main_log.log_file = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ main_log.enabled = LOGGER_DISABLED;
|
|
+
|
|
+ pthread_mutex_unlock(&main_log.lock);
|
|
+}
|
|
diff --git a/iscsiuio/src/unix/logger.h b/iscsiuio/src/unix/logger.h
|
|
new file mode 100644
|
|
index 0000000..06e2084
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/logger.h
|
|
@@ -0,0 +1,129 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * logger.h - Logging Utilities
|
|
+ *
|
|
+ */
|
|
+#ifndef __LOGGER_H__
|
|
+#define __LOGGER_H__
|
|
+
|
|
+#include <pthread.h>
|
|
+#include <stdio.h>
|
|
+#include <time.h>
|
|
+#include <stdint.h>
|
|
+#include <sys/types.h>
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Logger Levels
|
|
+ ******************************************************************************/
|
|
+#define LOG_LEVEL_PACKET 5
|
|
+#define LOG_LEVEL_DEBUG 4
|
|
+#define LOG_LEVEL_INFO 3
|
|
+#define LOG_LEVEL_WARN 2
|
|
+#define LOG_LEVEL_ERR 1
|
|
+#define LOG_LEVEL_UNKNOWN 0
|
|
+
|
|
+#define LOG_LEVEL_PACKET_STR "PKT "
|
|
+#define LOG_LEVEL_DEBUG_STR "DBG "
|
|
+#define LOG_LEVEL_INFO_STR "INFO "
|
|
+#define LOG_LEVEL_WARN_STR "WARN "
|
|
+#define LOG_LEVEL_ERR_STR "ERR "
|
|
+#define LOG_LEVEL_UNKNOWN_STR "? "
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Logging Macro's
|
|
+ ******************************************************************************/
|
|
+#define LOG_PACKET(fmt, args...) { if (LOG_LEVEL_PACKET <= \
|
|
+ main_log.level) { \
|
|
+ log_uip(LOG_LEVEL_PACKET_STR, fmt,\
|
|
+ ##args);\
|
|
+ } }
|
|
+#define LOG_DEBUG(fmt, args...) { if (LOG_LEVEL_DEBUG <= main_log.level) { \
|
|
+ log_uip(LOG_LEVEL_DEBUG_STR, fmt,\
|
|
+ ##args);\
|
|
+ } }
|
|
+
|
|
+#define LOG_INFO(fmt, args...) { if (LOG_LEVEL_INFO <= main_log.level) { \
|
|
+ log_uip(LOG_LEVEL_INFO_STR, fmt,\
|
|
+ ##args); \
|
|
+ } }
|
|
+#define LOG_WARN(fmt, args...) { if (LOG_LEVEL_WARN <= main_log.level) { \
|
|
+ log_uip(LOG_LEVEL_WARN_STR, fmt,\
|
|
+ ##args); \
|
|
+ } }
|
|
+#define LOG_ERR(fmt, args...) { if (LOG_LEVEL_ERR <= main_log.level) { \
|
|
+ log_uip(LOG_LEVEL_ERR_STR, fmt,\
|
|
+ ##args); \
|
|
+ } }
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Logging Statistics
|
|
+ ******************************************************************************/
|
|
+struct logger_stats {
|
|
+ uint64_t debug;
|
|
+ uint64_t info;
|
|
+ uint64_t warn;
|
|
+ uint64_t error;
|
|
+
|
|
+ time_t last_log_time;
|
|
+};
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Logger Structure
|
|
+ ******************************************************************************/
|
|
+struct logger {
|
|
+ FILE *fp;
|
|
+ char *log_file;
|
|
+ int8_t level;
|
|
+
|
|
+#define LOGGER_ENABLED 0x01
|
|
+#define LOGGER_DISABLED 0x02
|
|
+ int8_t enabled;
|
|
+
|
|
+ pthread_mutex_t lock;
|
|
+
|
|
+ struct logger_stats stats;
|
|
+};
|
|
+
|
|
+extern struct logger main_log;
|
|
+
|
|
+int init_logger(char *);
|
|
+void log_uip(char *level_str, char *fmt, ...);
|
|
+void fini_logger(int);
|
|
+
|
|
+#define CLOSE_LOGGER 0x01
|
|
+#define SHUTDOWN_LOGGER 0x02
|
|
+
|
|
+#endif
|
|
diff --git a/iscsiuio/src/unix/main.c b/iscsiuio/src/unix/main.c
|
|
new file mode 100644
|
|
index 0000000..c1a72d8
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/main.c
|
|
@@ -0,0 +1,399 @@
|
|
+/*
|
|
+ * Copyright (c) 2001, Adam Dunkels.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack.
|
|
+ *
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <dlfcn.h>
|
|
+#include <errno.h>
|
|
+#include <fcntl.h>
|
|
+#include <string.h>
|
|
+#include <signal.h>
|
|
+#include <stdlib.h>
|
|
+#include <getopt.h>
|
|
+#include <unistd.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/utsname.h>
|
|
+#include <net/ethernet.h>
|
|
+#include <arpa/inet.h>
|
|
+#include <sys/mman.h>
|
|
+
|
|
+#include "uip.h"
|
|
+#include "uip_arp.h"
|
|
+#include "uip_eth.h"
|
|
+
|
|
+#include "timer.h"
|
|
+
|
|
+#include "build_date.h"
|
|
+#include "config.h"
|
|
+#include "iscsid_ipc.h"
|
|
+#include "logger.h"
|
|
+#include "nic.h"
|
|
+#include "nic_id.h"
|
|
+#include "nic_nl.h"
|
|
+#include "nic_utils.h"
|
|
+#include "options.h"
|
|
+#include "packet.h"
|
|
+
|
|
+#include "dhcpc.h"
|
|
+
|
|
+#include "iscsid_ipc.h"
|
|
+#include "brcm_iscsi.h"
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Constants
|
|
+ ******************************************************************************/
|
|
+#define PFX "main "
|
|
+
|
|
+static const char default_pid_filepath[] = "/var/run/iscsiuio.pid";
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Global Variables
|
|
+ ******************************************************************************/
|
|
+static const struct option long_options[] = {
|
|
+ {"debug", 0, 0, 0},
|
|
+ {"version", 0, 0, 0},
|
|
+ {"help", 0, 0, 0},
|
|
+ {0, 0, 0, 0}
|
|
+};
|
|
+
|
|
+struct options opt = {
|
|
+ .debug = DEBUG_OFF,
|
|
+};
|
|
+
|
|
+int event_loop_stop;
|
|
+extern nic_t *nic_list;
|
|
+
|
|
+struct utsname cur_utsname;
|
|
+
|
|
+/**
|
|
+ * cleanup() - This function is called when this program is to be closed
|
|
+ * This function will clean up all the cnic uio interfaces and
|
|
+ * flush/close the logger
|
|
+ */
|
|
+static void cleanup()
|
|
+{
|
|
+ iscsid_cleanup();
|
|
+
|
|
+ nic_remove_all();
|
|
+
|
|
+ unload_all_nic_libraries();
|
|
+
|
|
+ LOG_INFO("Done waiting for cnic's/stacks to gracefully close");
|
|
+
|
|
+ fini_logger(SHUTDOWN_LOGGER);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * signal_handle_thread() - This is the signal handling thread of this program
|
|
+ * This is the only thread which will handle signals.
|
|
+ * All signals are routed here and handled here to
|
|
+ * provide consistant handling.
|
|
+ */
|
|
+static pthread_t signal_thread;
|
|
+static void *signal_handle_thread(void *arg)
|
|
+{
|
|
+ sigset_t set;
|
|
+ int rc;
|
|
+ int signal;
|
|
+
|
|
+ sigfillset(&set);
|
|
+
|
|
+ LOG_INFO("signal handling thread ready");
|
|
+
|
|
+signal_wait:
|
|
+ rc = sigwait(&set, &signal);
|
|
+
|
|
+ switch (signal) {
|
|
+ case SIGINT:
|
|
+ LOG_INFO("Caught SIGINT signal");
|
|
+ break;
|
|
+ case SIGUSR1:
|
|
+ LOG_INFO("Caught SIGUSR1 signal, rotate log");
|
|
+ fini_logger(SHUTDOWN_LOGGER);
|
|
+ rc = init_logger(main_log.log_file);
|
|
+ if (rc != 0)
|
|
+ printf("Could not initialize the logger in "
|
|
+ "signal!\n");
|
|
+ goto signal_wait;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ event_loop_stop = 1;
|
|
+
|
|
+ LOG_INFO("terminating...");
|
|
+
|
|
+ cleanup();
|
|
+ exit(EXIT_SUCCESS);
|
|
+}
|
|
+
|
|
+static void show_version()
|
|
+{
|
|
+ printf("%s: Version '%s', Build Date: '%s'\n",
|
|
+ APP_NAME, PACKAGE_VERSION, build_date);
|
|
+}
|
|
+
|
|
+static void main_usage()
|
|
+{
|
|
+ show_version();
|
|
+
|
|
+ printf("\nUsage: %s [OPTION]\n", APP_NAME);
|
|
+ printf("iscsiuio daemon.\n"
|
|
+ "-f, --foreground make the program run in the foreground\n"
|
|
+ "-d, --debug debuglevel print debugging information\n"
|
|
+ "-p, --pid=pidfile use pid file (default %s).\n"
|
|
+ "-h, --help display this help and exit\n"
|
|
+ "-v, --version display version and exit\n",
|
|
+ default_pid_filepath);
|
|
+}
|
|
+
|
|
+static void daemon_init()
|
|
+{
|
|
+ int fd;
|
|
+
|
|
+ fd = open("/dev/null", O_RDWR);
|
|
+ if (fd == -1)
|
|
+ exit(-1);
|
|
+
|
|
+ dup2(fd, 0);
|
|
+ dup2(fd, 1);
|
|
+ dup2(fd, 2);
|
|
+ setsid();
|
|
+ chdir("/");
|
|
+}
|
|
+
|
|
+#define ISCSI_OOM_PATH_LEN 48
|
|
+
|
|
+int oom_adjust(void)
|
|
+{
|
|
+ int fd;
|
|
+ char path[ISCSI_OOM_PATH_LEN];
|
|
+ struct stat statb;
|
|
+
|
|
+ if (nice(-10) < 0)
|
|
+ LOG_DEBUG("Could not increase process priority: %s",
|
|
+ strerror(errno));
|
|
+
|
|
+ snprintf(path, ISCSI_OOM_PATH_LEN, "/proc/%d/oom_score_adj", getpid());
|
|
+ if (stat(path, &statb)) {
|
|
+ /* older kernel so use old oom_adj file */
|
|
+ snprintf(path, ISCSI_OOM_PATH_LEN, "/proc/%d/oom_adj",
|
|
+ getpid());
|
|
+ }
|
|
+ fd = open(path, O_WRONLY);
|
|
+ if (fd < 0)
|
|
+ return -1;
|
|
+ if (write(fd, "-16", 3) < 0) /* for 2.6.11 */
|
|
+ LOG_DEBUG("Could not set oom score to -16: %s",
|
|
+ strerror(errno));
|
|
+ if (write(fd, "-17", 3) < 0) /* for Andrea's patch */
|
|
+ LOG_DEBUG("Could not set oom score to -17: %s",
|
|
+ strerror(errno));
|
|
+ close(fd);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Main routine
|
|
+ ******************************************************************************/
|
|
+int main(int argc, char *argv[])
|
|
+{
|
|
+ int rc;
|
|
+ sigset_t set;
|
|
+ const char *pid_file = default_pid_filepath;
|
|
+ int fd;
|
|
+ int foreground = 0;
|
|
+ pid_t pid;
|
|
+ pthread_attr_t attr;
|
|
+
|
|
+ /* Record the start time for the user space daemon */
|
|
+ opt.start_time = time(NULL);
|
|
+
|
|
+ /* parse the parameters */
|
|
+ while (1) {
|
|
+ int c, option_index;
|
|
+
|
|
+ c = getopt_long(argc, argv, "fd:p:vh",
|
|
+ long_options, &option_index);
|
|
+
|
|
+ if (c == -1)
|
|
+ break;
|
|
+
|
|
+ switch (c) {
|
|
+
|
|
+ case 'f':
|
|
+ foreground = 1;
|
|
+ break;
|
|
+
|
|
+ /* Enable debugging mode */
|
|
+ case 'd':
|
|
+ main_log.level = atoi(optarg);
|
|
+ opt.debug = DEBUG_ON;
|
|
+ break;
|
|
+ case 'p':
|
|
+ pid_file = optarg;
|
|
+ break;
|
|
+ case 'v':
|
|
+ show_version();
|
|
+ exit(EXIT_SUCCESS);
|
|
+ case 'h':
|
|
+ default:
|
|
+ main_usage();
|
|
+ exit(EXIT_SUCCESS);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (main_log.enabled == LOGGER_ENABLED) {
|
|
+ /* initialize the logger */
|
|
+ rc = init_logger(main_log.log_file);
|
|
+ if (rc != 0 && opt.debug == DEBUG_ON)
|
|
+ printf("WARN: Could not initialize the logger\n");
|
|
+ }
|
|
+
|
|
+ LOG_INFO("Started iSCSI uio stack: Ver " PACKAGE_VERSION);
|
|
+ LOG_INFO("Build date: %s", build_date);
|
|
+
|
|
+ if (opt.debug == DEBUG_ON)
|
|
+ LOG_INFO("Debug mode enabled");
|
|
+
|
|
+ event_loop_stop = 0;
|
|
+ nic_list = NULL;
|
|
+
|
|
+ /* Determine the current kernel version */
|
|
+ memset(&cur_utsname, 0, sizeof(cur_utsname));
|
|
+
|
|
+ rc = uname(&cur_utsname);
|
|
+ if (rc == 0) {
|
|
+ LOG_INFO("Running on sysname: '%s', release: '%s', "
|
|
+ "version '%s' machine: '%s'",
|
|
+ cur_utsname.sysname, cur_utsname.release,
|
|
+ cur_utsname.version, cur_utsname.machine);
|
|
+ } else
|
|
+ LOG_WARN("Could not determine kernel version");
|
|
+
|
|
+ /* Initialze the iscsid listener */
|
|
+ rc = iscsid_init();
|
|
+ if (rc != 0)
|
|
+ goto error;
|
|
+
|
|
+ if (!foreground) {
|
|
+ char buf[64];
|
|
+ ssize_t written_bytes;
|
|
+
|
|
+ fd = open(pid_file, O_WRONLY | O_CREAT, 0644);
|
|
+ if (fd < 0) {
|
|
+ printf("Unable to create pid file: %s", pid_file);
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ pid = fork();
|
|
+ if (pid < 0) {
|
|
+ printf("Starting daemon failed");
|
|
+ exit(1);
|
|
+ } else if (pid) {
|
|
+ exit(0);
|
|
+ }
|
|
+
|
|
+ rc = chdir("/");
|
|
+ if (rc == -1)
|
|
+ printf("Unable to chdir(\") [%s]", strerror(errno));
|
|
+
|
|
+ if (lockf(fd, F_TLOCK, 0) < 0) {
|
|
+ printf("Unable to lock pid file: %s [%s]",
|
|
+ pid_file, strerror(errno));
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ rc = ftruncate(fd, 0);
|
|
+ if (rc == -1)
|
|
+ printf("ftruncate(%d, 0) failed [%s]",
|
|
+ fd, strerror(errno));
|
|
+
|
|
+ sprintf(buf, "%d\n", getpid());
|
|
+ written_bytes = write(fd, buf, strlen(buf));
|
|
+ if (written_bytes == -1)
|
|
+ printf("Could not write lock file [%s]",
|
|
+ strerror(errno));
|
|
+
|
|
+ daemon_init();
|
|
+ }
|
|
+
|
|
+ /* Load the NIC libraries */
|
|
+ rc = load_all_nic_libraries();
|
|
+ if (rc != 0)
|
|
+ goto error;
|
|
+
|
|
+ brcm_iscsi_init();
|
|
+
|
|
+ /* ensure we don't see any signals */
|
|
+ sigemptyset(&set);
|
|
+ sigaddset(&set, SIGINT);
|
|
+ sigaddset(&set, SIGQUIT);
|
|
+ sigaddset(&set, SIGTERM);
|
|
+ sigaddset(&set, SIGUSR1);
|
|
+ rc = pthread_sigmask(SIG_SETMASK, &set, NULL);
|
|
+
|
|
+ /* Spin off the signal handling thread */
|
|
+ pthread_attr_init(&attr);
|
|
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
+ rc = pthread_create(&signal_thread, &attr, signal_handle_thread, NULL);
|
|
+ if (rc != 0)
|
|
+ LOG_ERR("Could not create signal handling thread");
|
|
+
|
|
+ /* Using sysfs to discover iSCSI hosts */
|
|
+ nic_discover_iscsi_hosts();
|
|
+
|
|
+ /* oom-killer will not kill us at the night... */
|
|
+ if (oom_adjust())
|
|
+ LOG_DEBUG("Can not adjust oom-killer's pardon");
|
|
+
|
|
+ /* we don't want our active sessions to be paged out... */
|
|
+ if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
|
|
+ LOG_ERR("failed to mlockall, exiting...");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ /* Start the iscsid listener */
|
|
+ rc = iscsid_start();
|
|
+ if (rc != 0)
|
|
+ goto error;
|
|
+
|
|
+ /* NetLink connection to listen to NETLINK_ISCSI private messages */
|
|
+ nic_nl_open();
|
|
+
|
|
+error:
|
|
+ cleanup();
|
|
+ exit(EXIT_FAILURE);
|
|
+}
|
|
diff --git a/iscsiuio/src/unix/nic.c b/iscsiuio/src/unix/nic.c
|
|
new file mode 100644
|
|
index 0000000..38a5776
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/nic.c
|
|
@@ -0,0 +1,1533 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * nic.c - Generic NIC management/utility functions
|
|
+ *
|
|
+ */
|
|
+#include <dlfcn.h>
|
|
+#include <errno.h>
|
|
+#include <pthread.h>
|
|
+#include <signal.h>
|
|
+#include <string.h>
|
|
+#include <time.h>
|
|
+#include <unistd.h>
|
|
+#include <sys/socket.h>
|
|
+#include <sys/time.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <netinet/in.h>
|
|
+#include <arpa/inet.h>
|
|
+
|
|
+#include "dhcpc.h"
|
|
+#include "ipv6_ndpc.h"
|
|
+
|
|
+#include "logger.h"
|
|
+#include "nic.h"
|
|
+#include "nic_utils.h"
|
|
+#include "options.h"
|
|
+
|
|
+#include "uip.h"
|
|
+#include "uip_arp.h"
|
|
+#include "uip_eth.h"
|
|
+#include "uip-neighbor.h"
|
|
+
|
|
+#include "bnx2.h"
|
|
+#include "bnx2x.h"
|
|
+#include "ipv6.h"
|
|
+
|
|
+/******************************************************************************
|
|
+ * Constants
|
|
+ *****************************************************************************/
|
|
+#define PFX "nic "
|
|
+#define PCI_ANY_ID (~0)
|
|
+
|
|
+/******************************************************************************
|
|
+ * Global variables
|
|
+ *****************************************************************************/
|
|
+/* Used to store a list of NIC libraries */
|
|
+pthread_mutex_t nic_lib_list_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
+nic_lib_handle_t *nic_lib_list;
|
|
+
|
|
+/* Used to store a list of active cnic devices */
|
|
+pthread_mutex_t nic_list_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
+nic_t *nic_list;
|
|
+
|
|
+/******************************************************************************
|
|
+ * Functions to handle NIC libraries
|
|
+ *****************************************************************************/
|
|
+/**
|
|
+ * alloc_nic_library_handle() - Used to allocate a NIC library handle
|
|
+ * @return NULL if memory couldn't be allocated, pointer to the handle
|
|
+ * to the NIC library handle
|
|
+ */
|
|
+static nic_lib_handle_t *alloc_nic_library_handle()
|
|
+{
|
|
+ nic_lib_handle_t *handle;
|
|
+
|
|
+ handle = malloc(sizeof(*handle));
|
|
+ if (handle == NULL) {
|
|
+ LOG_ERR("Could not allocate memory for library handle");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ memset(handle, 0, sizeof(*handle));
|
|
+ handle->ops = NULL;
|
|
+
|
|
+ pthread_mutex_init(&handle->mutex, NULL);
|
|
+
|
|
+ return handle;
|
|
+}
|
|
+
|
|
+static void free_nic_library_handle(nic_lib_handle_t *handle)
|
|
+{
|
|
+ free(handle);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * load_nic_library() - This function is used to load a NIC library
|
|
+ * @param handle - This is the library handle to load
|
|
+ * @return 0 = Success; <0 = failure
|
|
+ */
|
|
+static int load_nic_library(nic_lib_handle_t *handle)
|
|
+{
|
|
+ int rc;
|
|
+ char *library_name;
|
|
+ size_t library_name_size;
|
|
+ char *library_version;
|
|
+ size_t library_version_size;
|
|
+ char *build_date_str;
|
|
+ size_t build_date_str_size;
|
|
+
|
|
+ pthread_mutex_lock(&handle->mutex);
|
|
+
|
|
+ /* Validate the NIC ops table ensure that all the fields are not NULL */
|
|
+ if ((handle->ops->open) == NULL ||
|
|
+ (handle->ops->close) == NULL ||
|
|
+ (handle->ops->read) == NULL ||
|
|
+ (handle->ops->write) == NULL ||
|
|
+ (handle->ops->clear_tx_intr == NULL)) {
|
|
+ LOG_ERR("Invalid NIC ops table: open: 0x%x, close: 0x%x,"
|
|
+ "read: 0x%x, write: 0x%x clear_tx_intr: 0x%x "
|
|
+ "lib_ops: 0x%x",
|
|
+ handle->ops->open, handle->ops->close,
|
|
+ handle->ops->read, handle->ops->write,
|
|
+ handle->ops->clear_tx_intr, handle->ops->lib_ops);
|
|
+ rc = -EINVAL;
|
|
+ handle->ops = NULL;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ /* Validate the NIC library ops table to ensure that all the proper
|
|
+ * fields are filled */
|
|
+ if ((handle->ops->lib_ops.get_library_name == NULL) ||
|
|
+ (handle->ops->lib_ops.get_pci_table == NULL) ||
|
|
+ (handle->ops->lib_ops.get_library_version == NULL) ||
|
|
+ (handle->ops->lib_ops.get_build_date == NULL) ||
|
|
+ (handle->ops->lib_ops.get_transport_name == NULL)) {
|
|
+ rc = -EINVAL;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ (*handle->ops->lib_ops.get_library_name) (&library_name,
|
|
+ &library_name_size);
|
|
+ (*handle->ops->lib_ops.get_library_version) (&library_version,
|
|
+ &library_version_size);
|
|
+ (*handle->ops->lib_ops.get_build_date) (&build_date_str,
|
|
+ &build_date_str_size);
|
|
+
|
|
+ LOG_DEBUG("Loaded nic library '%s' Version: '%s' build on %s'",
|
|
+ library_name, library_version, build_date_str);
|
|
+
|
|
+ pthread_mutex_unlock(&handle->mutex);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ pthread_mutex_unlock(&handle->mutex);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static struct nic_ops *(*nic_get_ops[]) () = {
|
|
+bnx2_get_ops, bnx2x_get_ops,};
|
|
+
|
|
+int load_all_nic_libraries()
|
|
+{
|
|
+ int rc, i = 0;
|
|
+ nic_lib_handle_t *handle;
|
|
+
|
|
+ for (i = 0; i < sizeof(nic_get_ops) / sizeof(nic_get_ops[0]); i++) {
|
|
+ /* Add the CNIC library */
|
|
+ handle = alloc_nic_library_handle();
|
|
+ if (handle == NULL) {
|
|
+ LOG_ERR("Could not allocate memory for CNIC nic lib");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ handle->ops = (*nic_get_ops[i]) ();
|
|
+
|
|
+ rc = load_nic_library(handle);
|
|
+ if (rc != 0) {
|
|
+ free_nic_library_handle(handle);
|
|
+ return rc;
|
|
+ }
|
|
+ /* Add the CNIC library to the list of library handles */
|
|
+ pthread_mutex_lock(&nic_lib_list_mutex);
|
|
+
|
|
+ /* Add this library to the list of nic libraries we
|
|
+ * know about */
|
|
+ if (nic_lib_list == NULL) {
|
|
+ nic_lib_list = handle;
|
|
+ } else {
|
|
+ nic_lib_handle_t *current = nic_lib_list;
|
|
+
|
|
+ while (current->next != NULL)
|
|
+ current = current->next;
|
|
+
|
|
+ current->next = handle;
|
|
+ }
|
|
+ pthread_mutex_unlock(&nic_lib_list_mutex);
|
|
+
|
|
+ LOG_DEBUG("Added '%s' nic library", handle->ops->description);
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int unload_all_nic_libraries()
|
|
+{
|
|
+ nic_lib_handle_t *current, *next;
|
|
+
|
|
+ pthread_mutex_lock(&nic_lib_list_mutex);
|
|
+ current = nic_lib_list;
|
|
+
|
|
+ while (current != NULL) {
|
|
+ next = current->next;
|
|
+ free_nic_library_handle(current);
|
|
+
|
|
+ current = next;
|
|
+ }
|
|
+
|
|
+ pthread_mutex_unlock(&nic_lib_list_mutex);
|
|
+
|
|
+ nic_lib_list = NULL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+NIC_LIBRARY_EXIST_T does_nic_uio_name_exist(char *name)
|
|
+{
|
|
+ NIC_LIBRARY_EXIST_T rc;
|
|
+ nic_lib_handle_t *current;
|
|
+
|
|
+ pthread_mutex_lock(&nic_lib_list_mutex);
|
|
+ current = nic_lib_list;
|
|
+
|
|
+ while (current != NULL) {
|
|
+ char *uio_name;
|
|
+ size_t uio_name_size;
|
|
+
|
|
+ (*current->ops->lib_ops.get_uio_name) (&uio_name,
|
|
+ &uio_name_size);
|
|
+
|
|
+ if (strncmp(name, uio_name, uio_name_size) == 0) {
|
|
+ rc = NIC_LIBRARY_EXSITS;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ current = current->next;
|
|
+ }
|
|
+
|
|
+ rc = NIC_LIBRARY_DOESNT_EXIST;
|
|
+
|
|
+done:
|
|
+ pthread_mutex_unlock(&nic_lib_list_mutex);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+NIC_LIBRARY_EXIST_T does_nic_library_exist(char *name)
|
|
+{
|
|
+ NIC_LIBRARY_EXIST_T rc;
|
|
+ nic_lib_handle_t *current;
|
|
+
|
|
+ pthread_mutex_lock(&nic_lib_list_mutex);
|
|
+ current = nic_lib_list;
|
|
+
|
|
+ while (current != NULL) {
|
|
+ char *library_name;
|
|
+ size_t library_name_size;
|
|
+
|
|
+ (*current->ops->lib_ops.get_library_name) (&library_name,
|
|
+ &library_name_size);
|
|
+
|
|
+ if (strncmp(name, library_name, library_name_size) == 0) {
|
|
+ rc = NIC_LIBRARY_EXSITS;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ current = current->next;
|
|
+ }
|
|
+
|
|
+ rc = NIC_LIBRARY_DOESNT_EXIST;
|
|
+
|
|
+done:
|
|
+ pthread_mutex_unlock(&nic_lib_list_mutex);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * find_nic_lib_using_pci_id() - Find the proper NIC library using the
|
|
+ * PCI ID's
|
|
+ * @param vendor - PCI vendor ID to search on
|
|
+ * @param device - PCI device ID to search on
|
|
+ * @param subvendor - PCI subvendor ID to search on
|
|
+ * @param subdevice - PCI subdevice ID to search on
|
|
+ * @param handle - This function will return the nic lib handle if found
|
|
+ * @return 0 if found, <0 not found
|
|
+ */
|
|
+int find_nic_lib_using_pci_id(uint32_t vendor, uint32_t device,
|
|
+ uint32_t subvendor, uint32_t subdevice,
|
|
+ nic_lib_handle_t **handle,
|
|
+ struct pci_device_id **pci_entry)
|
|
+{
|
|
+ int rc;
|
|
+ nic_lib_handle_t *current;
|
|
+
|
|
+ pthread_mutex_lock(&nic_lib_list_mutex);
|
|
+ current = nic_lib_list;
|
|
+
|
|
+ while (current != NULL) {
|
|
+ struct pci_device_id *pci_table;
|
|
+ uint32_t entries;
|
|
+ int i;
|
|
+
|
|
+ current->ops->lib_ops.get_pci_table(&pci_table, &entries);
|
|
+
|
|
+ /* Sanity check the the pci table coming from the
|
|
+ * hardware library */
|
|
+ if (entries > MAX_PCI_DEVICE_ENTRIES) {
|
|
+ LOG_WARN(PFX "Too many pci_table entries(%d) skipping",
|
|
+ entries);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < entries; i++) {
|
|
+ LOG_DEBUG(PFX "Checking against: "
|
|
+ "vendor: 0x%x device:0x%x "
|
|
+ "subvendor:0x%x subdevice:0x%x",
|
|
+ pci_table[i].vendor, pci_table[i].device,
|
|
+ pci_table[i].subvendor,
|
|
+ pci_table[i].subdevice);
|
|
+
|
|
+ if ((pci_table[i].vendor == vendor) &&
|
|
+ (pci_table[i].device == device) &&
|
|
+ (pci_table[i].subvendor == PCI_ANY_ID ||
|
|
+ pci_table[i].subvendor == subvendor) &&
|
|
+ (pci_table[i].subdevice == PCI_ANY_ID ||
|
|
+ pci_table[i].subdevice == subdevice)) {
|
|
+ *handle = current;
|
|
+ *pci_entry = &pci_table[i];
|
|
+ rc = 0;
|
|
+ goto done;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ current = current->next;
|
|
+ }
|
|
+ rc = -EINVAL;
|
|
+
|
|
+done:
|
|
+ pthread_mutex_unlock(&nic_lib_list_mutex);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nic_init() - This will properly initialize a struct cnic_uio device
|
|
+ * @return NULL is there is a failure and pointer to an allocated/initialized
|
|
+ * struct cnic_uio on success
|
|
+ */
|
|
+nic_t *nic_init()
|
|
+{
|
|
+ nic_t *nic;
|
|
+
|
|
+ nic = malloc(sizeof(*nic));
|
|
+ if (nic == NULL) {
|
|
+ LOG_ERR("Couldn't malloc space for nic");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ memset(nic, 0, sizeof(*nic));
|
|
+ nic->uio_minor = -1;
|
|
+ nic->fd = INVALID_FD;
|
|
+ nic->next = NULL;
|
|
+ nic->thread = INVALID_THREAD;
|
|
+ nic->enable_thread = INVALID_THREAD;
|
|
+ nic->flags |= NIC_DISABLED;
|
|
+ nic->state = NIC_STOPPED;
|
|
+ nic->free_packet_queue = NULL;
|
|
+ nic->tx_packet_queue = NULL;
|
|
+ nic->nic_library = NULL;
|
|
+ nic->pci_id = NULL;
|
|
+ nic->page_size = getpagesize();
|
|
+
|
|
+ /* nic_mutex is used to protect nic ops */
|
|
+ pthread_mutex_init(&nic->nic_mutex, NULL);
|
|
+ pthread_mutex_init(&nic->xmit_mutex, NULL);
|
|
+ pthread_mutex_init(&nic->free_packet_queue_mutex, NULL);
|
|
+
|
|
+ pthread_cond_init(&nic->enable_wait_cond, NULL);
|
|
+ pthread_cond_init(&nic->enable_done_cond, NULL);
|
|
+ pthread_cond_init(&nic->nic_loop_started_cond, NULL);
|
|
+ pthread_cond_init(&nic->disable_wait_cond, NULL);
|
|
+
|
|
+ nic->rx_poll_usec = DEFAULT_RX_POLL_USEC;
|
|
+
|
|
+ pthread_mutex_init(&nic->nl_process_mutex, NULL);
|
|
+ pthread_cond_init(&nic->nl_process_if_down_cond, NULL);
|
|
+ pthread_cond_init(&nic->nl_process_cond, NULL);
|
|
+ nic->nl_process_thread = INVALID_THREAD;
|
|
+ nic->nl_process_if_down = 0;
|
|
+ nic->nl_process_head = 0;
|
|
+ nic->nl_process_tail = 0;
|
|
+ memset(&nic->nl_process_ring, 0, sizeof(nic->nl_process_ring));
|
|
+
|
|
+ return nic;
|
|
+}
|
|
+
|
|
+void nic_add(nic_t *nic)
|
|
+{
|
|
+ /* Add this device to our list of nics */
|
|
+ if (nic_list == NULL) {
|
|
+ nic_list = nic;
|
|
+ } else {
|
|
+ nic_t *current = nic_list;
|
|
+
|
|
+ while (current->next != NULL)
|
|
+ current = current->next;
|
|
+
|
|
+ current->next = nic;
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nic_remove() - Used to remove the NIC for the nic list
|
|
+ * @param nic - the nic to remove
|
|
+ */
|
|
+int nic_remove(nic_t *nic)
|
|
+{
|
|
+ int rc;
|
|
+ nic_t *prev, *current;
|
|
+ struct stat file_stat;
|
|
+ nic_interface_t *nic_iface, *next_nic_iface, *vlan_iface;
|
|
+
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+
|
|
+ /* Check if the file node exists before closing */
|
|
+ rc = stat(nic->uio_device_name, &file_stat);
|
|
+ if ((rc == 0) && (nic->ops))
|
|
+ nic->ops->close(nic, 0);
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ nic->state = NIC_EXIT;
|
|
+
|
|
+ if (nic->enable_thread != INVALID_THREAD) {
|
|
+ LOG_DEBUG(PFX "%s: Canceling nic enable thread", nic->log_name);
|
|
+
|
|
+ rc = pthread_cancel(nic->enable_thread);
|
|
+ if (rc != 0)
|
|
+ LOG_DEBUG(PFX "%s: Couldn't send cancel to nic enable "
|
|
+ "thread", nic->log_name);
|
|
+
|
|
+ nic->enable_thread = INVALID_THREAD;
|
|
+ LOG_DEBUG(PFX "%s: nic enable thread cleaned", nic->log_name);
|
|
+ } else {
|
|
+ LOG_DEBUG(PFX "%s: NIC enable thread already canceled",
|
|
+ nic->log_name);
|
|
+ }
|
|
+
|
|
+ if (nic->thread != INVALID_THREAD) {
|
|
+ LOG_DEBUG(PFX "%s: Canceling nic thread", nic->log_name);
|
|
+
|
|
+ rc = pthread_cancel(nic->thread);
|
|
+ if (rc != 0)
|
|
+ LOG_DEBUG(PFX "%s: Couldn't send cancel to nic",
|
|
+ nic->log_name);
|
|
+
|
|
+ nic->thread = INVALID_THREAD;
|
|
+ LOG_DEBUG(PFX "%s: nic thread cleaned", nic->log_name);
|
|
+ } else {
|
|
+ LOG_DEBUG(PFX "%s: NIC thread already canceled", nic->log_name);
|
|
+ }
|
|
+
|
|
+ if (nic->nl_process_thread != INVALID_THREAD) {
|
|
+ LOG_DEBUG(PFX "%s: Canceling nic nl thread", nic->log_name);
|
|
+
|
|
+ rc = pthread_cancel(nic->nl_process_thread);
|
|
+ if (rc != 0)
|
|
+ LOG_DEBUG(PFX "%s: Couldn't send cancel to nic nl "
|
|
+ "thread", nic->log_name);
|
|
+
|
|
+ nic->nl_process_thread = INVALID_THREAD;
|
|
+ LOG_DEBUG(PFX "%s: nic nl thread cleaned", nic->log_name);
|
|
+ } else {
|
|
+ LOG_DEBUG(PFX "%s: NIC nl thread already canceled",
|
|
+ nic->log_name);
|
|
+ }
|
|
+
|
|
+ current = prev = nic_list;
|
|
+ while (current != NULL) {
|
|
+ if (current == nic)
|
|
+ break;
|
|
+
|
|
+ prev = current;
|
|
+ current = current->next;
|
|
+ }
|
|
+
|
|
+ if (current != NULL) {
|
|
+ if (current == nic_list)
|
|
+ nic_list = current->next;
|
|
+ else
|
|
+ prev->next = current->next;
|
|
+
|
|
+ /* Before freeing the nic, must free all the associated
|
|
+ nic_iface */
|
|
+ nic_iface = current->nic_iface;
|
|
+ while (nic_iface != NULL) {
|
|
+ vlan_iface = nic_iface->vlan_next;
|
|
+ while (vlan_iface != NULL) {
|
|
+ next_nic_iface = vlan_iface->vlan_next;
|
|
+ free(vlan_iface);
|
|
+ vlan_iface = next_nic_iface;
|
|
+ }
|
|
+ next_nic_iface = nic_iface->next;
|
|
+ free(nic_iface);
|
|
+ nic_iface = next_nic_iface;
|
|
+ }
|
|
+ free(nic);
|
|
+ } else {
|
|
+ LOG_ERR(PFX "%s: Couldn't find nic to remove", nic->log_name);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nic_close() - Used to indicate to a NIC that it should close
|
|
+ * Must be called with nic->nic_mutex
|
|
+ * @param nic - the nic to close
|
|
+ * @param graceful - ALLOW_GRACEFUL_SHUTDOWN will check the nic state
|
|
+ * before proceeding to close()
|
|
+ * FORCE_SHUTDOWN will force the nic to close()
|
|
+ * reguardless of the state
|
|
+ * @param clean - this will free the proper strings assoicated
|
|
+ * with the NIC
|
|
+ *
|
|
+ */
|
|
+void nic_close(nic_t *nic, NIC_SHUTDOWN_T graceful, int clean)
|
|
+{
|
|
+ int rc;
|
|
+ nic_interface_t *nic_iface, *vlan_iface;
|
|
+ struct stat file_stat;
|
|
+
|
|
+ /* The NIC could be configured by the uIP config file
|
|
+ * but not assoicated with a hardware library just yet
|
|
+ * we will need to check for this */
|
|
+ if (nic->ops == NULL) {
|
|
+ LOG_WARN(PFX "%s: when closing nic->ops == NULL",
|
|
+ nic->log_name);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ /* Check if the file node exists */
|
|
+ rc = stat(nic->uio_device_name, &file_stat);
|
|
+ if ((rc == 0) && (nic->ops))
|
|
+ rc = (*nic->ops->close) (nic, graceful);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR(PFX "%s: Could not close nic", nic->log_name);
|
|
+ } else {
|
|
+ nic->state = NIC_STOPPED;
|
|
+ nic->flags &= ~NIC_ENABLED;
|
|
+ nic->flags |= NIC_DISABLED;
|
|
+ }
|
|
+
|
|
+ nic_iface = nic->nic_iface;
|
|
+ while (nic_iface != NULL) {
|
|
+ if (!((nic_iface->flags & NIC_IFACE_PERSIST) ==
|
|
+ NIC_IFACE_PERSIST)) {
|
|
+ uip_reset(&nic_iface->ustack);
|
|
+ vlan_iface = nic_iface->vlan_next;
|
|
+ while (vlan_iface != NULL) {
|
|
+ uip_reset(&vlan_iface->ustack);
|
|
+ vlan_iface = vlan_iface->vlan_next;
|
|
+ }
|
|
+ }
|
|
+ nic_iface = nic_iface->next;
|
|
+ }
|
|
+
|
|
+ /* The NIC must be destroyed and init'ed once again,
|
|
+ * POSIX defines that the mutex will be undefined it
|
|
+ * init'ed twice without a destroy */
|
|
+ pthread_mutex_destroy(&nic->xmit_mutex);
|
|
+ pthread_mutex_init(&nic->xmit_mutex, NULL);
|
|
+
|
|
+ if (clean & FREE_CONFIG_NAME) {
|
|
+ /* Free any named strings we might be holding onto */
|
|
+ if (nic->flags & NIC_CONFIG_NAME_MALLOC) {
|
|
+ free(nic->config_device_name);
|
|
+ nic->flags &= ~NIC_CONFIG_NAME_MALLOC;
|
|
+ }
|
|
+ nic->config_device_name = NULL;
|
|
+ }
|
|
+
|
|
+ if (clean & FREE_UIO_NAME) {
|
|
+ if (nic->flags & NIC_UIO_NAME_MALLOC) {
|
|
+ free(nic->uio_device_name);
|
|
+ nic->uio_device_name = NULL;
|
|
+
|
|
+ nic->flags &= ~NIC_UIO_NAME_MALLOC;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ LOG_ERR(PFX "%s: nic closed", nic->log_name);
|
|
+error:
|
|
+ return;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nic_iface_init() - This function is used to add an interface to the
|
|
+ * structure cnic_uio
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+nic_interface_t *nic_iface_init()
|
|
+{
|
|
+ nic_interface_t *nic_iface = malloc(sizeof(*nic_iface));
|
|
+ if (nic_iface == NULL) {
|
|
+ LOG_ERR("Could not allocate space for nic iface");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ memset(nic_iface, 0, sizeof(*nic_iface));
|
|
+ nic_iface->next = NULL;
|
|
+ nic_iface->vlan_next = NULL;
|
|
+ nic_iface->iface_num = IFACE_NUM_INVALID;
|
|
+ nic_iface->request_type = IP_CONFIG_OFF;
|
|
+
|
|
+ return nic_iface;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nic_add_nic_iface() - This function is used to add an interface to the
|
|
+ * nic structure
|
|
+ * Called with nic_mutex held
|
|
+ * @param nic - struct nic device to add the interface to
|
|
+ * @param nic_iface - network interface used to add to the nic
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+int nic_add_nic_iface(nic_t *nic, nic_interface_t *nic_iface)
|
|
+{
|
|
+ nic_interface_t *current, *prev;
|
|
+
|
|
+ /* Make sure it doesn't already exist */
|
|
+ current = nic_find_nic_iface(nic, nic_iface->protocol,
|
|
+ nic_iface->vlan_id, nic_iface->iface_num,
|
|
+ nic_iface->request_type);
|
|
+ if (current) {
|
|
+ LOG_DEBUG(PFX "%s: nic interface for VLAN: %d, protocol: %d"
|
|
+ " already exist", nic->log_name, nic_iface->vlan_id,
|
|
+ nic_iface->protocol);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ prev = NULL;
|
|
+ current = nic->nic_iface;
|
|
+ while (current != NULL) {
|
|
+ if (current->protocol == nic_iface->protocol) {
|
|
+ /* Replace parent */
|
|
+ nic_iface->vlan_next = current;
|
|
+ nic_iface->next = current->next;
|
|
+ current->next = NULL;
|
|
+ if (prev)
|
|
+ prev->next = nic_iface;
|
|
+ else
|
|
+ nic->nic_iface = nic_iface;
|
|
+ goto done;
|
|
+ }
|
|
+ prev = current;
|
|
+ current = current->next;
|
|
+ }
|
|
+ nic_iface->next = nic->nic_iface;
|
|
+ nic->nic_iface = nic_iface;
|
|
+done:
|
|
+ /* Set nic_interface common fields */
|
|
+ nic_iface->parent = nic;
|
|
+ memcpy(&nic_iface->ustack.uip_ethaddr.addr, nic->mac_addr, ETH_ALEN);
|
|
+ nic->num_of_nic_iface++;
|
|
+
|
|
+ LOG_INFO(PFX "%s: Added nic interface for VLAN: %d, protocol: %d",
|
|
+ nic->log_name, nic_iface->vlan_id, nic_iface->protocol);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/******************************************************************************
|
|
+ * Routine to process interrupts from the NIC device
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * nic_process_intr() - Routine used to process interrupts from the hardware
|
|
+ * @param nic - NIC hardware to process the interrupt on
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+int nic_process_intr(nic_t *nic, int discard_check)
|
|
+{
|
|
+ fd_set fdset;
|
|
+ int ret;
|
|
+ int count;
|
|
+ struct timeval tv;
|
|
+
|
|
+ /* Simple sanity checks */
|
|
+ if (discard_check != 1 && nic->state != NIC_RUNNING) {
|
|
+ LOG_ERR(PFX "%s: Couldn't process interupt NIC not running",
|
|
+ nic->log_name);
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ if (discard_check != 1 && nic->fd == INVALID_FD) {
|
|
+ LOG_ERR(PFX "%s: NIC fd not valid", nic->log_name);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ FD_ZERO(&fdset);
|
|
+ FD_SET(nic->fd, &fdset);
|
|
+
|
|
+ tv.tv_sec = 0;
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ if (nic->flags & NIC_LONG_SLEEP)
|
|
+ tv.tv_usec = 1000;
|
|
+ else
|
|
+ tv.tv_usec = nic->rx_poll_usec;
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ /* Wait for an interrupt to come in or timeout */
|
|
+ ret = select(nic->fd + 1, &fdset, NULL, NULL, &tv);
|
|
+ switch (ret) {
|
|
+ case 1:
|
|
+ /* Usually there should only be one file descriptor ready
|
|
+ * to read */
|
|
+ break;
|
|
+ case 0:
|
|
+ return ret;
|
|
+ case -1:
|
|
+ LOG_ERR(PFX "%s: error waiting for interrupt: %s",
|
|
+ nic->log_name, strerror(errno));
|
|
+ return 0;
|
|
+ default:
|
|
+ LOG_ERR(PFX "%s: unknown number of FD's, ignoring: %d ret",
|
|
+ nic->log_name, ret);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ ret = read(nic->fd, &count, sizeof(count));
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ if (ret > 0) {
|
|
+ nic->stats.interrupts++;
|
|
+ LOG_PACKET(PFX "%s: interrupt count: %d prev: %d",
|
|
+ nic->log_name, count, nic->intr_count);
|
|
+
|
|
+ if (count == nic->intr_count) {
|
|
+ LOG_PACKET(PFX "%s: got interrupt but count still the "
|
|
+ "same", nic->log_name, count);
|
|
+ }
|
|
+
|
|
+ /* Check if we missed an interrupt. With UIO,
|
|
+ * the count should be incremental */
|
|
+ if (count != nic->intr_count + 1) {
|
|
+ nic->stats.missed_interrupts++;
|
|
+ LOG_PACKET(PFX "%s: Missed interrupt! on %d not %d",
|
|
+ nic->log_name, count, nic->intr_count);
|
|
+ }
|
|
+
|
|
+ nic->intr_count = count;
|
|
+
|
|
+ (*nic->ops->clear_tx_intr) (nic);
|
|
+ ret = 1;
|
|
+ }
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void prepare_ipv4_packet(nic_t *nic,
|
|
+ nic_interface_t *nic_iface,
|
|
+ struct uip_stack *ustack, packet_t *pkt)
|
|
+{
|
|
+ u16_t ipaddr[2];
|
|
+ arp_table_query_t arp_query;
|
|
+ dest_ipv4_addr_t dest_ipv4_addr;
|
|
+ struct arp_entry *tabptr;
|
|
+ int queue_rc;
|
|
+ int vlan_id = 0;
|
|
+
|
|
+ /* If the rx vlan tag is not stripped and vlan is present in the pkt,
|
|
+ manual stripping is required because tx is using hw vlan tag! */
|
|
+ if (pkt->network_layer == pkt->data_link_layer +
|
|
+ sizeof(struct uip_vlan_eth_hdr)) {
|
|
+ /* VLAN is detected in the pkt buf */
|
|
+ memcpy(pkt->data_link_layer + 12, pkt->network_layer - 2,
|
|
+ pkt->buf_size - sizeof(struct uip_vlan_eth_hdr) + 2);
|
|
+ }
|
|
+ dest_ipv4_addr = uip_determine_dest_ipv4_addr(ustack, ipaddr);
|
|
+ if (dest_ipv4_addr == LOCAL_BROADCAST) {
|
|
+ uip_build_eth_header(ustack, ipaddr, NULL, pkt, vlan_id);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ arp_query = is_in_arp_table(ipaddr, &tabptr);
|
|
+
|
|
+ switch (arp_query) {
|
|
+ case IS_IN_ARP_TABLE:
|
|
+ uip_build_eth_header(ustack,
|
|
+ ipaddr, tabptr, pkt, vlan_id);
|
|
+ break;
|
|
+ case NOT_IN_ARP_TABLE:
|
|
+ queue_rc = nic_queue_tx_packet(nic, nic_iface, pkt);
|
|
+ if (queue_rc) {
|
|
+ LOG_ERR("could not queue TX packet: %d", queue_rc);
|
|
+ } else {
|
|
+ uip_build_arp_request(ustack, ipaddr);
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ LOG_ERR("Unknown arp state");
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void prepare_ipv6_packet(nic_t *nic,
|
|
+ nic_interface_t *nic_iface,
|
|
+ struct uip_stack *ustack, packet_t *pkt)
|
|
+{
|
|
+ struct uip_eth_hdr *eth;
|
|
+ struct uip_vlan_eth_hdr *eth_vlan;
|
|
+ int vlan_id = 0;
|
|
+
|
|
+ if (pkt->network_layer == pkt->data_link_layer +
|
|
+ sizeof(struct uip_vlan_eth_hdr)) {
|
|
+ /* VLAN is detected in the pkt buf */
|
|
+ memcpy(pkt->data_link_layer + 12, pkt->network_layer - 2,
|
|
+ pkt->buf_size - sizeof(struct uip_vlan_eth_hdr) + 2);
|
|
+ }
|
|
+ eth = (struct uip_eth_hdr *)ustack->data_link_layer;
|
|
+ eth_vlan = (struct uip_vlan_eth_hdr *)ustack->data_link_layer;
|
|
+ if (vlan_id == 0) {
|
|
+ eth->type = htons(UIP_ETHTYPE_IPv6);
|
|
+ } else {
|
|
+ eth_vlan->tpid = htons(UIP_ETHTYPE_8021Q);
|
|
+ eth_vlan->vid = htons(vlan_id);
|
|
+ eth_vlan->type = htons(UIP_ETHTYPE_IPv6);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void prepare_ustack(nic_t *nic,
|
|
+ nic_interface_t *nic_iface,
|
|
+ struct uip_stack *ustack, struct packet *pkt)
|
|
+{
|
|
+ struct ether_header *eth = NULL;
|
|
+ ustack->uip_buf = pkt->buf;
|
|
+ ustack->uip_len = pkt->buf_size;
|
|
+
|
|
+ pkt->nic = nic;
|
|
+ pkt->nic_iface = nic_iface;
|
|
+
|
|
+ ustack->data_link_layer = pkt->buf;
|
|
+ /* Adjust the network layer pointer depending if
|
|
+ * there is a VLAN tag or not, or if the hardware
|
|
+ * has stripped out the
|
|
+ * VLAN tag */
|
|
+ ustack->network_layer = ustack->data_link_layer +
|
|
+ sizeof(struct uip_eth_hdr);
|
|
+ /* Init buffer to be IPv6 */
|
|
+ if (nic_iface->ustack.ip_config == IPV6_CONFIG_DHCP ||
|
|
+ nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) {
|
|
+ eth = (struct ether_header *)ustack->data_link_layer;
|
|
+ eth->ether_type = htons(UIP_ETHTYPE_IPv6);
|
|
+ }
|
|
+}
|
|
+
|
|
+int do_timers_per_nic_iface(nic_t *nic, nic_interface_t *nic_iface,
|
|
+ struct timer *arp_timer)
|
|
+{
|
|
+ packet_t *pkt;
|
|
+ struct uip_stack *ustack = &nic_iface->ustack;
|
|
+ int i;
|
|
+
|
|
+ pkt = get_next_free_packet(nic);
|
|
+ if (pkt == NULL)
|
|
+ return -EIO;
|
|
+
|
|
+ if (nic_iface->protocol == AF_INET) {
|
|
+ for (i = 0; i < UIP_UDP_CONNS; i++) {
|
|
+ prepare_ustack(nic, nic_iface, ustack, pkt);
|
|
+
|
|
+ uip_udp_periodic(ustack, i);
|
|
+ /* If the above function invocation resulted
|
|
+ * in data that should be sent out on the
|
|
+ * network, the global variable uip_len is
|
|
+ * set to a value > 0. */
|
|
+ if (ustack->uip_len > 0) {
|
|
+ pkt->buf_size = ustack->uip_len;
|
|
+
|
|
+ prepare_ipv4_packet(nic, nic_iface, ustack,
|
|
+ pkt);
|
|
+
|
|
+ (*nic->ops->write) (nic, nic_iface, pkt);
|
|
+ ustack->uip_len = 0;
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ /* Added periodic poll for IPv6 NDP engine */
|
|
+ if (ustack->ndpc != NULL) { /* If engine is active */
|
|
+ prepare_ustack(nic, nic_iface, ustack, pkt);
|
|
+
|
|
+ uip_ndp_periodic(ustack);
|
|
+ /* If the above function invocation resulted
|
|
+ * in data that should be sent out on the
|
|
+ * network, the global variable uip_len is
|
|
+ * set to a value > 0. */
|
|
+ if (ustack->uip_len > 0) {
|
|
+ pkt->buf_size = ustack->uip_len;
|
|
+ prepare_ipv6_packet(nic, nic_iface, ustack,
|
|
+ pkt);
|
|
+ (*nic->ops->write) (nic, nic_iface, pkt);
|
|
+ ustack->uip_len = 0;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ /* Call the ARP timer function every 10 seconds. */
|
|
+ if (timer_expired(arp_timer)) {
|
|
+ timer_reset(arp_timer);
|
|
+ uip_arp_timer();
|
|
+ }
|
|
+ put_packet_in_free_queue(pkt, nic);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int check_timers(nic_t *nic,
|
|
+ struct timer *periodic_timer, struct timer *arp_timer)
|
|
+{
|
|
+ if (timer_expired(periodic_timer)) {
|
|
+ nic_interface_t *nic_iface, *vlan_iface;
|
|
+
|
|
+ timer_reset(periodic_timer);
|
|
+
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+
|
|
+ nic_iface = nic->nic_iface;
|
|
+ while (nic_iface != NULL) {
|
|
+ do_timers_per_nic_iface(nic, nic_iface, arp_timer);
|
|
+ vlan_iface = nic_iface->vlan_next;
|
|
+ while (vlan_iface != NULL) {
|
|
+ do_timers_per_nic_iface(nic, vlan_iface,
|
|
+ arp_timer);
|
|
+ vlan_iface = vlan_iface->vlan_next;
|
|
+ }
|
|
+ nic_iface = nic_iface->next;
|
|
+ }
|
|
+
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int process_packets(nic_t *nic,
|
|
+ struct timer *periodic_timer,
|
|
+ struct timer *arp_timer, nic_interface_t *nic_iface)
|
|
+{
|
|
+ int rc;
|
|
+ packet_t *pkt;
|
|
+
|
|
+ pkt = get_next_free_packet(nic);
|
|
+ if (pkt == NULL) {
|
|
+ LOG_DEBUG(PFX "%s: Couldn't get buffer for processing packet",
|
|
+ nic->log_name);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ rc = (*nic->ops->read) (nic, pkt);
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ if ((rc != 0) && (pkt->buf_size > 0)) {
|
|
+ uint16_t type = 0;
|
|
+ int af_type = 0;
|
|
+ struct uip_stack *ustack;
|
|
+ uint16_t vlan_id;
|
|
+
|
|
+ pkt->data_link_layer = pkt->buf;
|
|
+
|
|
+ vlan_id = pkt->vlan_tag & 0xFFF;
|
|
+ if ((vlan_id == 0) ||
|
|
+ (NIC_VLAN_STRIP_ENABLED & nic->flags)) {
|
|
+ struct uip_eth_hdr *hdr = ETH_BUF(pkt->buf);
|
|
+ type = ntohs(hdr->type);
|
|
+ pkt->network_layer = pkt->data_link_layer +
|
|
+ sizeof(struct uip_eth_hdr);
|
|
+ } else {
|
|
+ struct uip_vlan_eth_hdr *hdr = VLAN_ETH_BUF(pkt->buf);
|
|
+ type = ntohs(hdr->type);
|
|
+ pkt->network_layer = pkt->data_link_layer +
|
|
+ sizeof(struct uip_vlan_eth_hdr);
|
|
+ }
|
|
+
|
|
+ switch (type) {
|
|
+ case UIP_ETHTYPE_IPv6:
|
|
+ af_type = AF_INET6;
|
|
+ break;
|
|
+ case UIP_ETHTYPE_IPv4:
|
|
+ case UIP_ETHTYPE_ARP:
|
|
+ af_type = AF_INET;
|
|
+ break;
|
|
+ default:
|
|
+ LOG_PACKET(PFX "%s: Ignoring vlan:0x%x ethertype:0x%x",
|
|
+ nic->log_name, vlan_id, type);
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+
|
|
+ /* check if we have the given VLAN interface */
|
|
+ if (nic_iface != NULL) {
|
|
+ if (vlan_id != nic_iface->vlan_id) {
|
|
+ /* Matching nic_iface not found, drop */
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ rc = EINVAL; /* Return the +error code */
|
|
+ goto done;
|
|
+ }
|
|
+ goto nic_iface_present;
|
|
+ }
|
|
+
|
|
+ /* Best effort to find the correct instance
|
|
+ Input: protocol and vlan_tag */
|
|
+ nic_iface = nic_find_nic_iface(nic, af_type, vlan_id,
|
|
+ IFACE_NUM_INVALID,
|
|
+ IP_CONFIG_OFF);
|
|
+ if (nic_iface == NULL) {
|
|
+ /* Matching nic_iface not found */
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ LOG_PACKET(PFX "%s: Couldn't find interface for "
|
|
+ "VLAN: %d af_type %d",
|
|
+ nic->log_name, vlan_id, af_type);
|
|
+ rc = EINVAL; /* Return the +error code */
|
|
+ goto done;
|
|
+ }
|
|
+nic_iface_present:
|
|
+ pkt->nic_iface = nic_iface;
|
|
+
|
|
+ ustack = &nic_iface->ustack;
|
|
+
|
|
+ ustack->uip_buf = pkt->buf;
|
|
+ ustack->uip_len = pkt->buf_size;
|
|
+ ustack->data_link_layer = pkt->buf;
|
|
+
|
|
+ /* Adjust the network layer pointer depending if there is a
|
|
+ * VLAN tag or not, or if the hardware has stripped out the
|
|
+ * VLAN tag */
|
|
+ if ((vlan_id == 0) ||
|
|
+ (NIC_VLAN_STRIP_ENABLED & nic->flags))
|
|
+ ustack->network_layer = ustack->data_link_layer +
|
|
+ sizeof(struct uip_eth_hdr);
|
|
+ else
|
|
+ ustack->network_layer = ustack->data_link_layer +
|
|
+ sizeof(struct uip_vlan_eth_hdr);
|
|
+
|
|
+ /* determine how we should process this packet based on the
|
|
+ * ethernet type */
|
|
+ switch (type) {
|
|
+ case UIP_ETHTYPE_IPv6:
|
|
+ uip_input(ustack);
|
|
+ if (ustack->uip_len > 0) {
|
|
+ /* The pkt generated has already consulted
|
|
+ the IPv6 ARP table */
|
|
+ pkt->buf_size = ustack->uip_len;
|
|
+ prepare_ipv6_packet(nic, nic_iface,
|
|
+ ustack, pkt);
|
|
+
|
|
+ (*nic->ops->write) (nic, nic_iface, pkt);
|
|
+ }
|
|
+ break;
|
|
+ case UIP_ETHTYPE_IPv4:
|
|
+ uip_arp_ipin(ustack, pkt);
|
|
+ uip_input(ustack);
|
|
+ /* If the above function invocation resulted
|
|
+ * in data that should be sent out on the
|
|
+ * network, the global variable uip_len is
|
|
+ * set to a value > 0. */
|
|
+ if (ustack->uip_len > 0) {
|
|
+ prepare_ipv4_packet(nic, nic_iface,
|
|
+ ustack, pkt);
|
|
+
|
|
+ (*nic->ops->write) (nic, nic_iface, pkt);
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ case UIP_ETHTYPE_ARP:
|
|
+ uip_arp_arpin(nic_iface, ustack, pkt);
|
|
+
|
|
+ /* If the above function invocation resulted
|
|
+ * in data that should be sent out on the
|
|
+ * network, the global variable uip_len
|
|
+ * is set to a value > 0. */
|
|
+ if (pkt->buf_size > 0)
|
|
+ (*nic->ops->write) (nic, nic_iface, pkt);
|
|
+ break;
|
|
+ }
|
|
+ ustack->uip_len = 0;
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ }
|
|
+
|
|
+done:
|
|
+ put_packet_in_free_queue(pkt, nic);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int process_dhcp_loop(nic_t *nic,
|
|
+ nic_interface_t *nic_iface,
|
|
+ struct timer *periodic_timer,
|
|
+ struct timer *arp_timer)
|
|
+{
|
|
+ struct dhcpc_state *s;
|
|
+ struct ndpc_state *n;
|
|
+ int rc;
|
|
+ struct timeval start_time;
|
|
+ struct timeval current_time;
|
|
+ struct timeval wait_time;
|
|
+ struct timeval total_time;
|
|
+
|
|
+ /* 10s loop time to wait for DHCP */
|
|
+ switch (nic_iface->ustack.ip_config) {
|
|
+ case IPV4_CONFIG_DHCP:
|
|
+ wait_time.tv_sec = 10;
|
|
+ break;
|
|
+ case IPV6_CONFIG_DHCP:
|
|
+ wait_time.tv_sec = 15;
|
|
+ break;
|
|
+ case IPV6_CONFIG_STATIC:
|
|
+ wait_time.tv_sec = 4;
|
|
+ break;
|
|
+ default:
|
|
+ wait_time.tv_sec = 2;
|
|
+ }
|
|
+ wait_time.tv_usec = 0;
|
|
+
|
|
+ s = nic_iface->ustack.dhcpc;
|
|
+ n = nic_iface->ustack.ndpc;
|
|
+
|
|
+ if (gettimeofday(&start_time, NULL)) {
|
|
+ LOG_ERR(PFX "%s: Couldn't get time of day to start DHCP timer",
|
|
+ nic->log_name);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ timeradd(&start_time, &wait_time, &total_time);
|
|
+
|
|
+ periodic_timer->start = periodic_timer->start -
|
|
+ periodic_timer->interval;
|
|
+
|
|
+ while ((event_loop_stop == 0) &&
|
|
+ (nic->flags & NIC_ENABLED) && !(nic->flags & NIC_GOING_DOWN)) {
|
|
+
|
|
+ if (nic_iface->ustack.ip_config == IPV4_CONFIG_DHCP) {
|
|
+ if (s->state == STATE_CONFIG_RECEIVED)
|
|
+ break;
|
|
+ }
|
|
+ if (nic_iface->ustack.ip_config == IPV6_CONFIG_DHCP ||
|
|
+ nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) {
|
|
+ if (n->state == NDPC_STATE_BACKGROUND_LOOP)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* Check the periodic and ARP timer */
|
|
+ check_timers(nic, periodic_timer, arp_timer);
|
|
+
|
|
+ rc = nic_process_intr(nic, 1);
|
|
+
|
|
+ while ((rc > 0) && (!(nic->flags & NIC_GOING_DOWN))) {
|
|
+ rc = process_packets(nic,
|
|
+ periodic_timer,
|
|
+ arp_timer, nic_iface);
|
|
+ }
|
|
+
|
|
+ if (gettimeofday(¤t_time, NULL)) {
|
|
+ LOG_ERR(PFX "%s: Couldn't get current time for "
|
|
+ "DHCP start", nic->log_name);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ if (timercmp(&total_time, ¤t_time, <)) {
|
|
+ LOG_ERR(PFX "%s: timeout waiting for DHCP/NDP",
|
|
+ nic->log_name);
|
|
+ if (nic_iface->ustack.ip_config == IPV6_CONFIG_DHCP ||
|
|
+ nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC)
|
|
+ n->retry_count = IPV6_MAX_ROUTER_SOL_RETRY;
|
|
+ return -EIO;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (nic->flags & NIC_GOING_DOWN)
|
|
+ return -EIO;
|
|
+ else if (nic->flags & NIC_DISABLED)
|
|
+ return -EINVAL;
|
|
+ else
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Called with nic_mutex locked */
|
|
+static int do_acquisition(nic_t *nic, nic_interface_t *nic_iface,
|
|
+ struct timer *periodic_timer, struct timer *arp_timer)
|
|
+{
|
|
+ struct in_addr addr;
|
|
+ struct in6_addr addr6;
|
|
+ char buf[INET6_ADDRSTRLEN];
|
|
+ int rc = -1;
|
|
+
|
|
+ /* New acquisition */
|
|
+ uip_init(&nic_iface->ustack, nic->flags & NIC_IPv6_ENABLED);
|
|
+ memcpy(&nic_iface->ustack.uip_ethaddr.addr, nic->mac_addr, ETH_ALEN);
|
|
+
|
|
+ LOG_INFO(PFX "%s: Initialized ip stack: VLAN: %d",
|
|
+ nic->log_name, nic_iface->vlan_id);
|
|
+
|
|
+ LOG_INFO(PFX "%s: mac: %02x:%02x:%02x:%02x:%02x:%02x",
|
|
+ nic->log_name,
|
|
+ nic_iface->mac_addr[0],
|
|
+ nic_iface->mac_addr[1],
|
|
+ nic_iface->mac_addr[2],
|
|
+ nic_iface->mac_addr[3],
|
|
+ nic_iface->mac_addr[4],
|
|
+ nic_iface->mac_addr[5]);
|
|
+
|
|
+ switch (nic_iface->ustack.ip_config) {
|
|
+ case IPV4_CONFIG_STATIC:
|
|
+ memcpy(&addr.s_addr, nic_iface->ustack.hostaddr,
|
|
+ sizeof(addr.s_addr));
|
|
+
|
|
+ LOG_INFO(PFX "%s: Using IP address: %s",
|
|
+ nic->log_name, inet_ntoa(addr));
|
|
+
|
|
+ memcpy(&addr.s_addr, nic_iface->ustack.netmask,
|
|
+ sizeof(addr.s_addr));
|
|
+
|
|
+ LOG_INFO(PFX "%s: Using netmask: %s",
|
|
+ nic->log_name, inet_ntoa(addr));
|
|
+
|
|
+ set_uip_stack(&nic_iface->ustack,
|
|
+ &nic_iface->ustack.hostaddr,
|
|
+ &nic_iface->ustack.netmask,
|
|
+ &nic_iface->ustack.default_route_addr,
|
|
+ nic_iface->mac_addr);
|
|
+ break;
|
|
+
|
|
+ case IPV4_CONFIG_DHCP:
|
|
+ set_uip_stack(&nic_iface->ustack,
|
|
+ &nic_iface->ustack.hostaddr,
|
|
+ &nic_iface->ustack.netmask,
|
|
+ &nic_iface->ustack.default_route_addr,
|
|
+ nic_iface->mac_addr);
|
|
+ if (dhcpc_init(nic, &nic_iface->ustack,
|
|
+ nic_iface->mac_addr, ETH_ALEN)) {
|
|
+ if (nic_iface->ustack.dhcpc) {
|
|
+ LOG_DEBUG(PFX "%s: DHCPv4 engine already "
|
|
+ "initialized!", nic->log_name);
|
|
+ goto skip;
|
|
+ } else {
|
|
+ LOG_DEBUG(PFX "%s: DHCPv4 engine failed "
|
|
+ "initialization!", nic->log_name);
|
|
+ goto error;
|
|
+ }
|
|
+ }
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ rc = process_dhcp_loop(nic, nic_iface, periodic_timer,
|
|
+ arp_timer);
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+
|
|
+ if (rc) {
|
|
+ LOG_ERR(PFX "%s: DHCP failed", nic->log_name);
|
|
+ /* For DHCPv4 failure, the ustack must be cleaned so
|
|
+ it can re-acquire on the next iscsid request */
|
|
+ uip_reset(&nic_iface->ustack);
|
|
+
|
|
+ /* Signal that the device enable is
|
|
+ done */
|
|
+ pthread_cond_broadcast(&nic->enable_done_cond);
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ if (nic->enable_thread == INVALID_THREAD)
|
|
+ goto dhcp_err;
|
|
+
|
|
+ rc = pthread_cancel(nic->enable_thread);
|
|
+ if (rc != 0)
|
|
+ LOG_ERR(PFX "%s: Couldn't cancel "
|
|
+ "enable nic thread", nic->log_name);
|
|
+dhcp_err:
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (nic->flags & NIC_DISABLED) {
|
|
+ /* Break out of this loop */
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "%s: Initialized dhcp client", nic->log_name);
|
|
+ break;
|
|
+
|
|
+ case IPV6_CONFIG_DHCP:
|
|
+ case IPV6_CONFIG_STATIC:
|
|
+ if (ndpc_init(nic, &nic_iface->ustack, nic_iface->mac_addr,
|
|
+ ETH_ALEN)) {
|
|
+ LOG_DEBUG(PFX "%s: IPv6 engine already initialized!",
|
|
+ nic->log_name);
|
|
+ goto skip;
|
|
+ }
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ rc = process_dhcp_loop(nic, nic_iface, periodic_timer,
|
|
+ arp_timer);
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ if (rc) {
|
|
+ /* Don't reset and allow to use RA and LL */
|
|
+ LOG_ERR(PFX "%s: IPv6 DHCP/NDP failed", nic->log_name);
|
|
+ }
|
|
+ if (nic_iface->ustack.ip_config == IPV6_CONFIG_STATIC) {
|
|
+ memcpy(&addr6.s6_addr, nic_iface->ustack.hostaddr6,
|
|
+ sizeof(addr6.s6_addr));
|
|
+ inet_ntop(AF_INET6, addr6.s6_addr, buf, sizeof(buf));
|
|
+ LOG_INFO(PFX "%s: hostaddr IP: %s", nic->log_name, buf);
|
|
+ memcpy(&addr6.s6_addr, nic_iface->ustack.netmask6,
|
|
+ sizeof(addr6.s6_addr));
|
|
+ inet_ntop(AF_INET6, addr6.s6_addr, buf, sizeof(buf));
|
|
+ LOG_INFO(PFX "%s: netmask IP: %s", nic->log_name, buf);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ LOG_INFO(PFX "%s: ipconfig = %d?", nic->log_name,
|
|
+ nic_iface->ustack.ip_config);
|
|
+ }
|
|
+skip:
|
|
+ /* Mark acquisition done for this nic iface */
|
|
+ nic_iface->flags &= ~NIC_IFACE_ACQUIRE;
|
|
+
|
|
+ LOG_INFO(PFX "%s: enabled vlan %d protocol: %d", nic->log_name,
|
|
+ nic_iface->vlan_id, nic_iface->protocol);
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ return -EIO;
|
|
+}
|
|
+
|
|
+
|
|
+void *nic_loop(void *arg)
|
|
+{
|
|
+ nic_t *nic = (nic_t *) arg;
|
|
+ int rc = -1;
|
|
+ sigset_t set;
|
|
+ struct timer periodic_timer, arp_timer;
|
|
+
|
|
+ sigfillset(&set);
|
|
+ rc = pthread_sigmask(SIG_BLOCK, &set, NULL);
|
|
+ if (rc != 0) {
|
|
+ /* TODO: determine if we need to exit this thread if we fail
|
|
+ * to set the signal mask */
|
|
+ LOG_ERR(PFX "%s: Couldn't set signal mask", nic->log_name);
|
|
+ }
|
|
+
|
|
+ /* Signal the device to enable itself */
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ pthread_cond_signal(&nic->nic_loop_started_cond);
|
|
+
|
|
+ /* nic_mutex must be locked */
|
|
+ while ((event_loop_stop == 0) &&
|
|
+ !(nic->flags & NIC_EXIT_MAIN_LOOP) &&
|
|
+ !(nic->flags & NIC_GOING_DOWN)) {
|
|
+ nic_interface_t *nic_iface, *vlan_iface;
|
|
+
|
|
+ if (nic->flags & NIC_DISABLED) {
|
|
+ LOG_DEBUG(PFX "%s: Waiting to be enabled",
|
|
+ nic->log_name);
|
|
+
|
|
+ /* Wait for the device to be enabled */
|
|
+ /* nic_mutex is already locked */
|
|
+ pthread_cond_wait(&nic->enable_wait_cond,
|
|
+ &nic->nic_mutex);
|
|
+
|
|
+ if (nic->state == NIC_EXIT) {
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ pthread_exit(NULL);
|
|
+ }
|
|
+ LOG_DEBUG(PFX "%s: is now enabled", nic->log_name);
|
|
+ }
|
|
+ /* initialize the device to send/rec data */
|
|
+ rc = (*nic->ops->open) (nic);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR(PFX "%s: Could not initialize CNIC UIO device",
|
|
+ nic->log_name);
|
|
+
|
|
+ if (rc == -ENOTSUP)
|
|
+ nic->flags |= NIC_EXIT_MAIN_LOOP;
|
|
+ else
|
|
+ nic->flags &= ~NIC_ENABLED;
|
|
+
|
|
+ /* Signal that the device enable is done */
|
|
+ pthread_cond_broadcast(&nic->enable_done_cond);
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ goto dev_close;
|
|
+ }
|
|
+ nic_set_all_nic_iface_mac_to_parent(nic);
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ rc = alloc_free_queue(nic, 5);
|
|
+ if (rc != 5) {
|
|
+ if (rc != 0) {
|
|
+ LOG_WARN(PFX "%s: Allocated %d packets "
|
|
+ "instead of %d", nic->log_name, rc, 5);
|
|
+ } else {
|
|
+ LOG_ERR(PFX "%s: No packets allocated "
|
|
+ "instead of %d", nic->log_name, 5);
|
|
+ /* Signal that the device enable is done */
|
|
+ pthread_cond_broadcast(&nic->enable_done_cond);
|
|
+ goto dev_close;
|
|
+ }
|
|
+ }
|
|
+ /* Indication for the nic_disable routine that the nic
|
|
+ has started running */
|
|
+ nic->state = NIC_STARTED_RUNNING;
|
|
+
|
|
+ /* Initialize the system clocks */
|
|
+ timer_set(&periodic_timer, CLOCK_SECOND / 2);
|
|
+ timer_set(&arp_timer, CLOCK_SECOND * 10);
|
|
+
|
|
+ /* Prepare the stack for each of the VLAN interfaces */
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+
|
|
+ /* If DHCP fails, exit loop and restart the engine */
|
|
+ nic_iface = nic->nic_iface;
|
|
+ while (nic_iface != NULL) {
|
|
+ if (nic_iface->flags & NIC_IFACE_ACQUIRE) {
|
|
+ do_acquisition(nic, nic_iface,
|
|
+ &periodic_timer,
|
|
+ &arp_timer);
|
|
+ }
|
|
+ vlan_iface = nic_iface->vlan_next;
|
|
+ while (vlan_iface != NULL) {
|
|
+ if (vlan_iface->flags & NIC_IFACE_ACQUIRE) {
|
|
+ do_acquisition(nic, vlan_iface,
|
|
+ &periodic_timer,
|
|
+ &arp_timer);
|
|
+ }
|
|
+ vlan_iface = vlan_iface->next;
|
|
+ }
|
|
+ nic_iface = nic_iface->next;
|
|
+ }
|
|
+ if (nic->flags & NIC_DISABLED) {
|
|
+ LOG_WARN(PFX "%s: nic was disabled during nic loop, "
|
|
+ "closing flag 0x%x",
|
|
+ nic->log_name, nic->flags);
|
|
+ /* Signal that the device enable is done */
|
|
+ pthread_cond_broadcast(&nic->enable_done_cond);
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ goto dev_close_free;
|
|
+ }
|
|
+
|
|
+ /* This is when we start the processing of packets */
|
|
+ nic->start_time = time(NULL);
|
|
+ nic->state = NIC_RUNNING;
|
|
+
|
|
+ nic->flags &= ~NIC_ENABLED_PENDING;
|
|
+
|
|
+ /* Signal that the device enable is done */
|
|
+ pthread_cond_broadcast(&nic->enable_done_cond);
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ LOG_INFO(PFX "%s: entering main nic loop", nic->log_name);
|
|
+
|
|
+ while ((nic->state == NIC_RUNNING) &&
|
|
+ (event_loop_stop == 0) &&
|
|
+ !(nic->flags & NIC_GOING_DOWN)) {
|
|
+ /* Check the periodic and ARP timer */
|
|
+ check_timers(nic, &periodic_timer, &arp_timer);
|
|
+ rc = nic_process_intr(nic, 0);
|
|
+ while ((rc > 0) &&
|
|
+ (nic->state == NIC_RUNNING) &&
|
|
+ !(nic->flags & NIC_GOING_DOWN)) {
|
|
+ rc = process_packets(nic,
|
|
+ &periodic_timer,
|
|
+ &arp_timer, NULL);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "%s: exited main processing loop", nic->log_name);
|
|
+
|
|
+dev_close_free:
|
|
+ free_free_queue(nic);
|
|
+dev_close:
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+
|
|
+ if (nic->flags & NIC_GOING_DOWN) {
|
|
+ nic_close(nic, 1, FREE_NO_STRINGS);
|
|
+
|
|
+ nic->flags &= ~NIC_GOING_DOWN;
|
|
+ } else {
|
|
+ pthread_mutex_destroy(&nic->xmit_mutex);
|
|
+ pthread_mutex_init(&nic->xmit_mutex, NULL);
|
|
+ }
|
|
+ nic->pending_count = 0;
|
|
+
|
|
+ if (!(nic->flags & NIC_EXIT_MAIN_LOOP)) {
|
|
+ /* Signal we are done closing CNIC/UIO device */
|
|
+ pthread_cond_broadcast(&nic->disable_wait_cond);
|
|
+ }
|
|
+ }
|
|
+ /* clean up the nic flags */
|
|
+ nic->flags &= ~NIC_ENABLED_PENDING;
|
|
+
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ LOG_INFO(PFX "%s: nic loop thread exited", nic->log_name);
|
|
+
|
|
+ nic->thread = INVALID_THREAD;
|
|
+
|
|
+ pthread_exit(NULL);
|
|
+}
|
|
diff --git a/iscsiuio/src/unix/nic.h b/iscsiuio/src/unix/nic.h
|
|
new file mode 100644
|
|
index 0000000..8484032
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/nic.h
|
|
@@ -0,0 +1,384 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * nic.h - NIC header file
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <errno.h>
|
|
+
|
|
+#ifndef __NIC_H__
|
|
+#define __NIC_H__
|
|
+
|
|
+#include <stdint.h>
|
|
+#include <netinet/if_ether.h>
|
|
+#include <net/if.h>
|
|
+#include <linux/limits.h>
|
|
+#include <stdlib.h>
|
|
+#include <pthread.h>
|
|
+
|
|
+#include "nic_nl.h"
|
|
+#include "packet.h"
|
|
+#include "uip.h"
|
|
+
|
|
+#include "iscsi_if.h"
|
|
+
|
|
+/* Foward declarations */
|
|
+struct nic_ops;
|
|
+struct nic_lib_handle;
|
|
+struct packet;
|
|
+struct nic_op;
|
|
+
|
|
+extern pthread_mutex_t nic_lib_list_mutex;
|
|
+extern struct nic_lib_handle *nic_lib_list;
|
|
+
|
|
+/* Used to store a list of active cnic devices */
|
|
+extern pthread_mutex_t nic_list_mutex;
|
|
+extern struct nic *nic_list;
|
|
+
|
|
+extern void *nl_process_handle_thread(void *arg);
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Constants
|
|
+ ******************************************************************************/
|
|
+#define MAX_PCI_DEVICE_ENTRIES 64 /* Maxium number of pci_device_id
|
|
+ entries a hw library may contain */
|
|
+
|
|
+#define FREE_CONFIG_NAME 0x0001
|
|
+#define FREE_UIO_NAME 0x0002
|
|
+#define FREE_ALL_STRINGS (FREE_CONFIG_NAME | FREE_UIO_NAME)
|
|
+#define FREE_NO_STRINGS 0x0000
|
|
+
|
|
+/******************************************************************************
|
|
+ * Enumerations
|
|
+ ******************************************************************************/
|
|
+typedef enum {
|
|
+ ALLOW_GRACEFUL_SHUTDOWN = 1,
|
|
+ FORCE_SHUTDOWN = 2,
|
|
+} NIC_SHUTDOWN_T;
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Structure used to hold PCI vendor, device, subvendor and subdevice ID's
|
|
+ ******************************************************************************/
|
|
+struct pci_device_id {
|
|
+ const uint32_t vendor, device; /* Vendor and device ID or PCI_ANY_ID */
|
|
+ const uint32_t subvendor, subdevice; /* Subsystem ID's/PCI_ANY_ID */
|
|
+ const char *device_name; /* Data private to the driver */
|
|
+};
|
|
+
|
|
+/******************************************************************************
|
|
+ * NIC statistics structure
|
|
+ ******************************************************************************/
|
|
+struct nic_stats {
|
|
+ uint64_t interrupts;
|
|
+ uint64_t missed_interrupts;
|
|
+
|
|
+ struct {
|
|
+ uint64_t packets;
|
|
+ uint64_t bytes;
|
|
+ } tx;
|
|
+
|
|
+ struct {
|
|
+ uint64_t packets;
|
|
+ uint64_t bytes;
|
|
+ } rx;
|
|
+};
|
|
+
|
|
+/******************************************************************************
|
|
+ * NIC interface structure
|
|
+ ******************************************************************************/
|
|
+typedef struct nic_interface {
|
|
+ struct nic_interface *vlan_next;
|
|
+ struct nic_interface *next;
|
|
+ struct nic *parent;
|
|
+
|
|
+ uint16_t protocol;
|
|
+ uint16_t flags;
|
|
+#define NIC_IFACE_PERSIST (1<<0)
|
|
+#define NIC_IFACE_ACQUIRE (1<<1)
|
|
+#define NIC_IFACE_PATHREQ_WAIT1 (1<<2)
|
|
+#define NIC_IFACE_PATHREQ_WAIT2 (1<<3)
|
|
+#define NIC_IFACE_PATHREQ_WAIT (NIC_IFACE_PATHREQ_WAIT1 | \
|
|
+ NIC_IFACE_PATHREQ_WAIT2)
|
|
+ uint8_t mac_addr[ETH_ALEN];
|
|
+ uint8_t vlan_priority;
|
|
+ uint16_t vlan_id;
|
|
+#define NO_VLAN 0x8000
|
|
+
|
|
+ uint16_t mtu;
|
|
+ time_t start_time;
|
|
+
|
|
+ struct uip_stack ustack;
|
|
+
|
|
+#define IFACE_NUM_PRESENT (1<<0)
|
|
+#define IFACE_NUM_INVALID -1
|
|
+ int iface_num;
|
|
+ int request_type;
|
|
+} nic_interface_t;
|
|
+
|
|
+/******************************************************************************
|
|
+ * NIC lib operations structure
|
|
+ ******************************************************************************/
|
|
+struct nic_lib_ops {
|
|
+ /* Used to get the NIC library name */
|
|
+ void (*get_library_name) (char **library_name,
|
|
+ size_t *library_name_size);
|
|
+
|
|
+ /* Used to get to the PCI table supported by the NIC library */
|
|
+ void (*get_pci_table) (struct pci_device_id **table,
|
|
+ uint32_t *entries);
|
|
+
|
|
+ /* Used to get the version of this NIC library */
|
|
+ void (*get_library_version) (char **version_string,
|
|
+ size_t *version_string_size);
|
|
+
|
|
+ /* Used to get the NIC library build date */
|
|
+ void (*get_build_date) (char **build_date_string,
|
|
+ size_t *build_date_string_size);
|
|
+
|
|
+ /* Used to get the transport name assoicated with this library */
|
|
+ void (*get_transport_name) (char **transport_name,
|
|
+ size_t *transport_name_size);
|
|
+
|
|
+ /* Used to get the uio name assoicated with this library */
|
|
+ void (*get_uio_name) (char **uio_name, size_t *uio_name_size);
|
|
+
|
|
+};
|
|
+
|
|
+/*******************************************************************************
|
|
+ * NIC op table definition
|
|
+ ******************************************************************************/
|
|
+typedef struct nic_ops {
|
|
+ struct nic_lib_ops lib_ops;
|
|
+
|
|
+ char *description;
|
|
+ int (*open) (struct nic *);
|
|
+ int (*close) (struct nic *, NIC_SHUTDOWN_T);
|
|
+ int (*read) (struct nic *, struct packet *);
|
|
+ int (*write) (struct nic *, nic_interface_t *, struct packet *);
|
|
+ void *(*get_tx_pkt) (struct nic *);
|
|
+ void (*start_xmit) (struct nic *, size_t, u16_t vlan_id);
|
|
+ int (*clear_tx_intr) (struct nic *);
|
|
+ int (*handle_iscsi_path_req) (struct nic *,
|
|
+ int,
|
|
+ struct iscsi_uevent *ev,
|
|
+ struct iscsi_path *path,
|
|
+ nic_interface_t *nic_iface);
|
|
+} net_ops_t;
|
|
+
|
|
+typedef struct nic_lib_handle {
|
|
+ struct nic_lib_handle *next;
|
|
+
|
|
+ pthread_mutex_t mutex;
|
|
+ struct nic_ops *ops;
|
|
+} nic_lib_handle_t;
|
|
+
|
|
+typedef struct nic {
|
|
+ struct nic *next;
|
|
+
|
|
+ uint32_t flags;
|
|
+#define NIC_UNITIALIZED 0x0001
|
|
+#define NIC_INITIALIZED 0x0002
|
|
+#define NIC_ENABLED 0x0004
|
|
+#define NIC_DISABLED 0x0008
|
|
+#define NIC_IPv6_ENABLED 0x0010
|
|
+#define NIC_ADDED_MULICAST 0x0020
|
|
+#define NIC_LONG_SLEEP 0x0040
|
|
+#define NIC_PATHREQ_WAIT 0x0080
|
|
+
|
|
+#define NIC_VLAN_STRIP_ENABLED 0x0100
|
|
+#define NIC_MSIX_ENABLED 0x0200
|
|
+#define NIC_TX_HAS_SENT 0x0400
|
|
+#define NIC_ENABLED_PENDING 0x0800
|
|
+
|
|
+#define NIC_UIO_NAME_MALLOC 0x1000
|
|
+#define NIC_CONFIG_NAME_MALLOC 0x2000
|
|
+#define NIC_EXIT_MAIN_LOOP 0x4000
|
|
+#define NIC_GOING_DOWN 0x8000
|
|
+#define NIC_RESET_UIP 0x10000
|
|
+
|
|
+ uint16_t state;
|
|
+#define NIC_STOPPED 0x0001
|
|
+#define NIC_STARTED_RUNNING 0x0002
|
|
+#define NIC_RUNNING 0x0004
|
|
+#define NIC_EXIT 0x0010
|
|
+
|
|
+ int fd; /* Holds the file descriptor to UIO */
|
|
+ uint16_t uio_minor; /* Holds the UIO minor number */
|
|
+
|
|
+ uint32_t host_no; /* Holds the associated host number */
|
|
+
|
|
+ char *library_name; /* Name of the library to assoicate with */
|
|
+ char *log_name; /* Human friendly name used in the log
|
|
+ file */
|
|
+ char *config_device_name; /* Name read from the XML configuration
|
|
+ file */
|
|
+ char eth_device_name[IFNAMSIZ]; /* Network interface name */
|
|
+ char *uio_device_name; /* UIO device name */
|
|
+
|
|
+ uint32_t intr_count; /* Total UIO interrupt count */
|
|
+
|
|
+ int page_size;
|
|
+
|
|
+ /* Held for nic ops manipulation */
|
|
+ pthread_mutex_t nic_mutex;
|
|
+
|
|
+ /* iSCSI ring ethernet MAC address */
|
|
+ __u8 mac_addr[ETH_ALEN];
|
|
+
|
|
+ /* Used to manage the network interfaces of this device */
|
|
+ __u32 num_of_nic_iface;
|
|
+ nic_interface_t *nic_iface;
|
|
+
|
|
+ /* Wait for the device to be enabled */
|
|
+ pthread_cond_t enable_wait_cond;
|
|
+
|
|
+ /* Wait for the device to be finished enabled */
|
|
+ pthread_cond_t enable_done_cond;
|
|
+
|
|
+ /* Wait for the nic loop to start */
|
|
+ pthread_cond_t nic_loop_started_cond;
|
|
+
|
|
+ /* Wait for the device to be disabled */
|
|
+ pthread_cond_t disable_wait_cond;
|
|
+
|
|
+ /* Held when transmitting */
|
|
+ pthread_mutex_t xmit_mutex;
|
|
+
|
|
+ /* The thread this device is running on */
|
|
+ pthread_t thread;
|
|
+
|
|
+ /* The thread used to enable the device */
|
|
+ pthread_t enable_thread;
|
|
+
|
|
+ /* Statistical Information on this device */
|
|
+ time_t start_time;
|
|
+ struct nic_stats stats;
|
|
+
|
|
+ /* Number of retrys from iscsid */
|
|
+ uint32_t pending_count;
|
|
+ uint32_t pathreq_pending_count;
|
|
+
|
|
+#define DEFAULT_RX_POLL_USEC 100 /* usec */
|
|
+ /* options enabled by the user */
|
|
+ uint32_t rx_poll_usec;
|
|
+
|
|
+ /* Used to hold hardware specific data */
|
|
+ void *priv;
|
|
+
|
|
+ /* Used to hold the TX packets that are needed to be sent */
|
|
+ struct packet *tx_packet_queue;
|
|
+
|
|
+ /* Mutex to protect the list of free packets */
|
|
+ pthread_mutex_t free_packet_queue_mutex;
|
|
+
|
|
+ /* Used to hold the free packets that are needed to be sent */
|
|
+ struct packet *free_packet_queue;
|
|
+
|
|
+ /* Points to the NIC library */
|
|
+ nic_lib_handle_t *nic_library;
|
|
+
|
|
+ /* Points to the PCI table entry */
|
|
+ struct pci_device_id *pci_id;
|
|
+
|
|
+ /* Used to process the interrupt */
|
|
+ int (*process_intr) (struct nic *nic);
|
|
+
|
|
+ struct nic_ops *ops;
|
|
+
|
|
+ /* NL processing parameters */
|
|
+ pthread_t nl_process_thread;
|
|
+ pthread_cond_t nl_process_cond;
|
|
+ pthread_cond_t nl_process_if_down_cond;
|
|
+ pthread_mutex_t nl_process_mutex;
|
|
+ int nl_process_if_down;
|
|
+ int nl_process_head;
|
|
+ int nl_process_tail;
|
|
+#define NIC_NL_PROCESS_MAX_RING_SIZE 128
|
|
+#define NIC_NL_PROCESS_LAST_ENTRY (NIC_NL_PROCESS_MAX_RING_SIZE - 1)
|
|
+#define NIC_NL_PROCESS_NEXT_ENTRY(x) ((x + 1) & NIC_NL_PROCESS_MAX_RING_SIZE)
|
|
+ void *nl_process_ring[NIC_NL_PROCESS_MAX_RING_SIZE];
|
|
+} nic_t;
|
|
+
|
|
+/******************************************************************************
|
|
+ * Function Prototypes
|
|
+ *****************************************************************************/
|
|
+int load_all_nic_libraries();
|
|
+
|
|
+nic_t *nic_init();
|
|
+void nic_add(nic_t *nic);
|
|
+int nic_remove(nic_t *nic);
|
|
+
|
|
+int nic_add_nic_iface(nic_t *nic, nic_interface_t *nic_iface);
|
|
+int nic_process_intr(nic_t *nic, int discard_check);
|
|
+
|
|
+nic_interface_t *nic_iface_init();
|
|
+
|
|
+typedef enum {
|
|
+ NIC_LIBRARY_EXSITS = 1,
|
|
+ NIC_LIBRARY_DOESNT_EXIST = 2,
|
|
+} NIC_LIBRARY_EXIST_T;
|
|
+
|
|
+NIC_LIBRARY_EXIST_T does_nic_uio_name_exist(char *name);
|
|
+NIC_LIBRARY_EXIST_T does_nic_library_exist(char *name);
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Packet management utility functions
|
|
+ ******************************************************************************/
|
|
+struct packet *get_next_tx_packet(nic_t *nic);
|
|
+struct packet *get_next_free_packet(nic_t *nic);
|
|
+void put_packet_in_tx_queue(struct packet *pkt, nic_t *nic);
|
|
+void put_packet_in_free_queue(struct packet *pkt, nic_t *nic);
|
|
+
|
|
+int unload_all_nic_libraries();
|
|
+void nic_close(nic_t *nic, NIC_SHUTDOWN_T graceful, int clean);
|
|
+
|
|
+/* Use this function to fill in minor number and uio, and eth names */
|
|
+int nic_fill_name(nic_t *nic);
|
|
+
|
|
+int enable_multicast(nic_t *nic);
|
|
+int disable_multicast(nic_t *nic);
|
|
+
|
|
+void nic_set_all_nic_iface_mac_to_parent(nic_t *nic);
|
|
+int find_nic_lib_using_pci_id(uint32_t vendor, uint32_t device,
|
|
+ uint32_t subvendor, uint32_t subdevice,
|
|
+ nic_lib_handle_t **handle,
|
|
+ struct pci_device_id **pci_entry);
|
|
+
|
|
+void *nic_loop(void *arg);
|
|
+
|
|
+int nic_packet_capture(struct nic *, struct packet *pkt);
|
|
+
|
|
+#endif /* __NIC_H__ */
|
|
diff --git a/iscsiuio/src/unix/nic_id.c b/iscsiuio/src/unix/nic_id.c
|
|
new file mode 100644
|
|
index 0000000..6b2467c
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/nic_id.c
|
|
@@ -0,0 +1,362 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * nic_id.c - Using sysfs to determine the PCI vendor, device, subvendor and
|
|
+ * subdevice ID's
|
|
+ *
|
|
+ */
|
|
+#include <errno.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <unistd.h>
|
|
+#include <sys/socket.h>
|
|
+
|
|
+#include "logger.h"
|
|
+#include "nic.h"
|
|
+
|
|
+#define PFX "nic_id "
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Sysfs constant strings used to get PCI vendor, and device ID's
|
|
+ ******************************************************************************/
|
|
+const char uio_vendor_id_template[] = "/sys/class/uio/uio%d/device/vendor";
|
|
+const char uio_subvendor_id_template[] =
|
|
+ "/sys/class/uio/uio%d/device/subsystem_vendor";
|
|
+const char uio_device_id_template[] = "/sys/class/uio/uio%d/device/device";
|
|
+const char uio_subdevice_id_template[] =
|
|
+ "/sys/class/uio/uio%d/device/subsystem_device";
|
|
+const char uio_device_symlink_template[] = "/sys/class/uio/uio%d/device";
|
|
+
|
|
+/**
|
|
+ * get_id() - Utility function to read hex values from sysfs
|
|
+ * @param nic - NIC device to use
|
|
+ * @param sysfs_template - sysfs path template to use
|
|
+ * @param sysfs_template_size - sysfs path template size in bytes
|
|
+ * @parm id - this is the value returned from the sysfs entry
|
|
+ * @return 0 on success <0 on failure
|
|
+ */
|
|
+static int get_id(nic_t *nic,
|
|
+ const char *sysfs_template,
|
|
+ const size_t sysfs_template_size, uint32_t *id)
|
|
+{
|
|
+ int rc = 0;
|
|
+ FILE *fp;
|
|
+ size_t chars_read;
|
|
+ char buf[7];
|
|
+ char *path;
|
|
+ size_t path_size;
|
|
+
|
|
+ path_size = sysfs_template_size + 4;
|
|
+ path = malloc(path_size);
|
|
+ if (path == NULL) {
|
|
+ LOG_ERR("Could not allocate memory for %s", sysfs_template);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ snprintf(path, path_size, sysfs_template, nic->uio_minor);
|
|
+
|
|
+ fp = fopen(path, "r");
|
|
+ if (fp == NULL) {
|
|
+ LOG_ERR(PFX "%s: Could not open path: %s [%s]",
|
|
+ nic->log_name, path, strerror(errno));
|
|
+ rc = -EIO;
|
|
+ goto error_fopen;
|
|
+ }
|
|
+
|
|
+ chars_read = fread(buf, sizeof(buf), 1, fp);
|
|
+ if (chars_read != 1) {
|
|
+ LOG_ERR(PFX "%s: Could not read from: %s [%s]",
|
|
+ nic->log_name, path, strerror(ferror(fp)));
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ chars_read = sscanf(buf, "%x", id);
|
|
+ if (chars_read != 1) {
|
|
+ LOG_ERR(PFX "%s: Could interpret value: %s from: %s [%s]",
|
|
+ nic->log_name, buf, path, strerror(errno));
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+error:
|
|
+ fclose(fp);
|
|
+
|
|
+error_fopen:
|
|
+ free(path);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int get_vendor(nic_t *nic, uint32_t *id)
|
|
+{
|
|
+ return get_id(nic,
|
|
+ uio_vendor_id_template, sizeof(uio_vendor_id_template),
|
|
+ id);
|
|
+}
|
|
+
|
|
+static int get_subvendor(nic_t *nic, uint32_t *id)
|
|
+{
|
|
+ return get_id(nic,
|
|
+ uio_subvendor_id_template,
|
|
+ sizeof(uio_subvendor_id_template), id);
|
|
+}
|
|
+
|
|
+static int get_device(nic_t *nic, uint32_t *id)
|
|
+{
|
|
+ return get_id(nic,
|
|
+ uio_device_id_template,
|
|
+ sizeof(uio_device_id_template), id);
|
|
+}
|
|
+
|
|
+static int get_subdevice(nic_t *nic, uint32_t *id)
|
|
+{
|
|
+ return get_id(nic,
|
|
+ uio_subdevice_id_template,
|
|
+ sizeof(uio_subdevice_id_template), id);
|
|
+}
|
|
+
|
|
+int get_bus_slot_func_num(nic_t *nic,
|
|
+ uint32_t *bus, uint32_t *slot, uint32_t *func)
|
|
+{
|
|
+ size_t size;
|
|
+ char *path, *tok, *tok2;
|
|
+ int path_tokens, i;
|
|
+ size_t path_size;
|
|
+ char *read_pci_bus_slot_func_str;
|
|
+ char pci_bus_slot_func_str[32];
|
|
+ int rc;
|
|
+ char *saveptr;
|
|
+
|
|
+ path_size = sizeof(uio_device_symlink_template) + 4;
|
|
+ path = malloc(path_size);
|
|
+ if (path == NULL) {
|
|
+ LOG_ERR(PFX "%s: Could not allocate path memory for %s",
|
|
+ nic->log_name, uio_device_symlink_template);
|
|
+ rc = -ENOMEM;
|
|
+ goto error_alloc_path;
|
|
+ }
|
|
+
|
|
+ read_pci_bus_slot_func_str = malloc(128);
|
|
+ if (read_pci_bus_slot_func_str == NULL) {
|
|
+ LOG_ERR(PFX "%s: Could not allocate read pci bus memory for %s",
|
|
+ nic->log_name, uio_device_symlink_template);
|
|
+ rc = -ENOMEM;
|
|
+ goto error_alloc_read_pci_bus;
|
|
+ }
|
|
+
|
|
+ snprintf(path, path_size, uio_device_symlink_template, nic->uio_minor);
|
|
+
|
|
+ size = readlink(path, read_pci_bus_slot_func_str, 128);
|
|
+ if (size == -1) {
|
|
+ LOG_ERR(PFX "%s: Error with %s: %s",
|
|
+ nic->log_name, path, strerror(errno));
|
|
+ rc = errno;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (size > ((128) - 1)) {
|
|
+ read_pci_bus_slot_func_str[128 - 1] = '\0';
|
|
+ LOG_ERR(PFX "%s: not enough space (%d) for reading PCI "
|
|
+ "slot:bus.func %s: %s",
|
|
+ nic->log_name, size, path, strerror(errno));
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ /* readlink() doesn't NULL terminate the string */
|
|
+ read_pci_bus_slot_func_str[size] = '\0';
|
|
+
|
|
+ path_tokens = 0;
|
|
+ tok = strtok_r(read_pci_bus_slot_func_str, "/", &saveptr);
|
|
+ while (tok != NULL) {
|
|
+ path_tokens++;
|
|
+ tok = strtok_r(NULL, "/", &saveptr);
|
|
+ }
|
|
+
|
|
+ size = readlink(path, read_pci_bus_slot_func_str, 128);
|
|
+ if (size == -1) {
|
|
+ LOG_ERR(PFX "%s: Error with %s: %s",
|
|
+ nic->log_name, path, strerror(errno));
|
|
+ rc = errno;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (size > ((128) - 1)) {
|
|
+ read_pci_bus_slot_func_str[128 - 1] = '\0';
|
|
+ LOG_ERR(PFX "%s: not enough space for reading PCI "
|
|
+ "slot:bus.func %s: %s",
|
|
+ nic->log_name, path, strerror(errno));
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ /* readlink() doesn't NULL terminate the string */
|
|
+ read_pci_bus_slot_func_str[size] = '\0';
|
|
+
|
|
+ tok = strtok_r(read_pci_bus_slot_func_str, "/", &saveptr);
|
|
+ for (i = 0; i < path_tokens - 1; i++)
|
|
+ tok = strtok_r(NULL, "/", &saveptr);
|
|
+ strcpy(pci_bus_slot_func_str, tok);
|
|
+
|
|
+ tok = strtok_r(pci_bus_slot_func_str, ":", &saveptr);
|
|
+ if (tok == NULL) {
|
|
+ LOG_ERR(PFX "%s: Error with slot string: %s",
|
|
+ nic->log_name, pci_bus_slot_func_str);
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ tok = strtok_r(NULL, ":", &saveptr);
|
|
+ if (tok == NULL) {
|
|
+ LOG_ERR(PFX "%s: Error parsing slot: %s",
|
|
+ nic->log_name, pci_bus_slot_func_str);
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ sscanf(tok, "%x", bus);
|
|
+
|
|
+ /* Need to extract the next token "xx.x" */
|
|
+ tok = strtok_r(NULL, ":", &saveptr);
|
|
+ if (tok == NULL) {
|
|
+ LOG_ERR(PFX "%s: Error extracing bus.func: %s",
|
|
+ nic->log_name, pci_bus_slot_func_str);
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ tok2 = strtok_r(tok, ".", &saveptr);
|
|
+ if (tok2 == NULL) {
|
|
+ LOG_ERR(PFX "%s: Error parsing bus: %s",
|
|
+ nic->log_name, pci_bus_slot_func_str);
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ sscanf(tok2, "%x", slot);
|
|
+
|
|
+ tok2 = strtok_r(NULL, ".", &saveptr);
|
|
+ if (tok2 == NULL) {
|
|
+ LOG_ERR(PFX "%s: Error parsing func: %s",
|
|
+ nic->log_name, pci_bus_slot_func_str);
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ sscanf(tok2, "%x", func);
|
|
+ LOG_INFO(PFX "%s: is found at %02x:%02x.%02x", nic->log_name,
|
|
+ *bus, *slot, *func);
|
|
+ rc = 0;
|
|
+error:
|
|
+ free(read_pci_bus_slot_func_str);
|
|
+error_alloc_read_pci_bus:
|
|
+ free(path);
|
|
+error_alloc_path:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * find_set_nic_lib() - Match the NIC library to the NIC
|
|
+ * @param nic - NIC device to determine which NIC library to use
|
|
+ * @return 0 on success <0 on failure
|
|
+ */
|
|
+int find_set_nic_lib(nic_t *nic)
|
|
+{
|
|
+ uint32_t vendor;
|
|
+ uint32_t subvendor;
|
|
+ uint32_t device;
|
|
+ uint32_t subdevice;
|
|
+
|
|
+ uint32_t pci_bus;
|
|
+ uint32_t pci_slot;
|
|
+ uint32_t pci_func;
|
|
+ int rc = 0;
|
|
+
|
|
+ nic_lib_handle_t *handle;
|
|
+ struct pci_device_id *pci_entry;
|
|
+
|
|
+ rc = get_vendor(nic, &vendor);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR(PFX "%s: Could not get vendor id [0x%x]",
|
|
+ nic->log_name, rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ rc = get_subvendor(nic, &subvendor);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR(PFX "%s: Could not get subvendor id [0x%x]",
|
|
+ nic->log_name, rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ rc = get_device(nic, &device);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR(PFX "%s: Could not get device id [0x%x]",
|
|
+ nic->log_name, rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ rc = get_subdevice(nic, &subdevice);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR(PFX "%s: Could not get subdevice id [0x%x]",
|
|
+ nic->log_name, rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ get_bus_slot_func_num(nic, &pci_bus, &pci_slot, &pci_func);
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: Looking for device vendor: "
|
|
+ "0x%x subvendor: 0x%x device: 0x%x subdevice: 0x%x",
|
|
+ nic->log_name, vendor, subvendor, device, subdevice);
|
|
+
|
|
+ rc = find_nic_lib_using_pci_id(vendor, device, subvendor, subdevice,
|
|
+ &handle, &pci_entry);
|
|
+
|
|
+ if (rc != 0) {
|
|
+ LOG_WARN(PFX "%s: Couldn't find proper NIC library",
|
|
+ nic->log_name);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ nic->nic_library = handle;
|
|
+ nic->pci_id = pci_entry;
|
|
+
|
|
+ /* Prepare the NIC library op table */
|
|
+ nic->ops = handle->ops;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/iscsiuio/src/unix/nic_id.h b/iscsiuio/src/unix/nic_id.h
|
|
new file mode 100644
|
|
index 0000000..340580f
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/nic_id.h
|
|
@@ -0,0 +1,47 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * nic_id.h - NIC uIP NetLink user space stack
|
|
+ *
|
|
+ */
|
|
+#ifndef __NIC_ID_H__
|
|
+#define __NIC_ID_H__
|
|
+
|
|
+int find_set_nic_lib(nic_t *nic);
|
|
+
|
|
+int get_bus_slot_func_num(nic_t *nic,
|
|
+ uint32_t *bus, uint32_t *slot, uint32_t *func);
|
|
+
|
|
+#endif /* __NIC_ID_H__ */
|
|
diff --git a/iscsiuio/src/unix/nic_nl.c b/iscsiuio/src/unix/nic_nl.c
|
|
new file mode 100644
|
|
index 0000000..391003f
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/nic_nl.c
|
|
@@ -0,0 +1,678 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * nic_nl.c - NIC uIP NetLink user space stack
|
|
+ *
|
|
+ */
|
|
+#include <errno.h>
|
|
+#include <pthread.h>
|
|
+#include <signal.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <unistd.h>
|
|
+#include <arpa/inet.h>
|
|
+#include <linux/limits.h>
|
|
+#include <netinet/if_ether.h>
|
|
+#include <netinet/in.h>
|
|
+#include <linux/netlink.h>
|
|
+#include <iscsi_if.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <sys/poll.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/user.h>
|
|
+#include <sys/socket.h>
|
|
+
|
|
+#include "uip_arp.h"
|
|
+#include "logger.h"
|
|
+#include "options.h"
|
|
+
|
|
+#include "nic.h"
|
|
+#include "nic_nl.h"
|
|
+#include "nic_utils.h"
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Constants
|
|
+ ******************************************************************************/
|
|
+#define PFX "NIC_NL "
|
|
+
|
|
+static u8_t nlm_sendbuf[NLM_BUF_DEFAULT_MAX];
|
|
+
|
|
+static struct sockaddr_nl src_addr;
|
|
+
|
|
+static const struct sockaddr_nl dest_addr = {
|
|
+ .nl_family = AF_NETLINK,
|
|
+ .nl_pid = 0, /* kernel */
|
|
+ .nl_groups = 0, /* unicast */
|
|
+};
|
|
+
|
|
+#define POLL_NL 0
|
|
+#define POLL_MAX 1
|
|
+
|
|
+/* Netlink */
|
|
+int nl_sock = INVALID_FD;
|
|
+
|
|
+static int nl_read(int ctrl_fd, char *data, int size, int flags)
|
|
+{
|
|
+ int rc;
|
|
+ struct iovec iov;
|
|
+ struct msghdr msg;
|
|
+
|
|
+ iov.iov_base = data;
|
|
+ iov.iov_len = size;
|
|
+
|
|
+ memset(&src_addr, 0, sizeof(src_addr));
|
|
+ src_addr.nl_family = AF_NETLINK;
|
|
+ src_addr.nl_pid = getpid();
|
|
+ src_addr.nl_groups = 1;
|
|
+
|
|
+ memset(&msg, 0, sizeof(msg));
|
|
+ msg.msg_name = (void *)&src_addr;
|
|
+ msg.msg_namelen = sizeof(src_addr);
|
|
+ msg.msg_iov = &iov;
|
|
+ msg.msg_iovlen = 1;
|
|
+
|
|
+ rc = recvmsg(ctrl_fd, &msg, flags);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int
|
|
+kwritev(int fd, enum iscsi_uevent_e type, struct iovec *iovp, int count)
|
|
+{
|
|
+ int i, rc;
|
|
+ struct nlmsghdr *nlh;
|
|
+ struct msghdr msg;
|
|
+ struct iovec iov;
|
|
+ int datalen = 0;
|
|
+
|
|
+ for (i = 0; i < count; i++)
|
|
+ datalen += iovp[i].iov_len;
|
|
+
|
|
+ nlh = (struct nlmsghdr *)nlm_sendbuf;
|
|
+ memset(nlh, 0, NLMSG_SPACE(datalen));
|
|
+
|
|
+ nlh->nlmsg_len = NLMSG_SPACE(datalen);
|
|
+ nlh->nlmsg_pid = getpid();
|
|
+ nlh->nlmsg_flags = 0;
|
|
+ nlh->nlmsg_type = type;
|
|
+
|
|
+ datalen = 0;
|
|
+ for (i = 0; i < count; i++) {
|
|
+ memcpy(NLMSG_DATA(nlh) + datalen, iovp[i].iov_base,
|
|
+ iovp[i].iov_len);
|
|
+ datalen += iovp[i].iov_len;
|
|
+ }
|
|
+ iov.iov_base = (void *)nlh;
|
|
+ iov.iov_len = nlh->nlmsg_len;
|
|
+
|
|
+ memset(&msg, 0, sizeof(msg));
|
|
+ msg.msg_name = (void *)&dest_addr;
|
|
+ msg.msg_namelen = sizeof(dest_addr);
|
|
+ msg.msg_iov = &iov;
|
|
+ msg.msg_iovlen = 1;
|
|
+
|
|
+ do {
|
|
+ rc = sendmsg(fd, &msg, 0);
|
|
+ if (rc == -ENOMEM) {
|
|
+ LOG_ERR(PFX "sendmsg: alloc_skb() failed");
|
|
+ sleep(1);
|
|
+ } else if (rc < 0) {
|
|
+ LOG_ERR(PFX "sendmsg: bug?: on %d %s[0x%x]",
|
|
+ fd, strerror(errno), errno);
|
|
+ sleep(1);
|
|
+ }
|
|
+ } while ((rc < 0) && (event_loop_stop == 0));
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * __kipc_call() should never block. Therefore
|
|
+ * Netlink's xmit logic is serialized. This means we do not allocate on
|
|
+ * xmit path. Instead we reuse nlm_sendbuf buffer.
|
|
+ *
|
|
+ * Transport must assure non-blocking operations for:
|
|
+ *
|
|
+ * - session_create()
|
|
+ * - conn_create()
|
|
+ * - conn_bind()
|
|
+ * _ set_param()
|
|
+ * - conn_start()
|
|
+ * - conn_stop()
|
|
+ *
|
|
+ * Its OK to block for cleanup for short period of time in operatations for:
|
|
+ *
|
|
+ * - conn_destroy()
|
|
+ * - session_destroy()
|
|
+ *
|
|
+ * FIXME: interface needs to be extended to allow longer blocking on
|
|
+ * cleanup. (Dima)
|
|
+ */
|
|
+int __kipc_call(int fd, void *iov_base, int iov_len)
|
|
+{
|
|
+ int rc;
|
|
+ struct iovec iov;
|
|
+ struct iscsi_uevent *ev = iov_base;
|
|
+ enum iscsi_uevent_e type = ev->type;
|
|
+
|
|
+ /* Sanity check */
|
|
+ if (iov_base == NULL)
|
|
+ return -EINVAL;
|
|
+
|
|
+ iov.iov_base = iov_base;
|
|
+ iov.iov_len = iov_len;
|
|
+
|
|
+ rc = kwritev(fd, type, &iov, 1);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int pull_from_nl(char **buf)
|
|
+{
|
|
+ int rc;
|
|
+ size_t ev_size, payload_size, alloc_size;
|
|
+ char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
|
|
+ struct nlmsghdr *nlh;
|
|
+ char *data = NULL;
|
|
+ struct iscsi_uevent *ev;
|
|
+
|
|
+ /* Take a quick peek at what how much uIP will need to read */
|
|
+ rc = nl_read(nl_sock, nlm_ev,
|
|
+ NLMSG_SPACE(sizeof(struct iscsi_uevent)),
|
|
+ MSG_PEEK | MSG_WAITALL);
|
|
+ if (rc <= 0) {
|
|
+ LOG_ERR("can not read nlm_ev, error %s[%d]",
|
|
+ strerror(errno), rc);
|
|
+ if (rc == 0)
|
|
+ return -EIO;
|
|
+ else
|
|
+ return errno;
|
|
+ }
|
|
+ nlh = (struct nlmsghdr *)nlm_ev;
|
|
+
|
|
+ if (unlikely(nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsghdr)))) {
|
|
+ LOG_ERR(PFX "Invalid nlh->nlmsg_len length: "
|
|
+ "nlh->nlmsg_len(%d) < "
|
|
+ "NLMSG_ALIGN(sizeof(struct nlmsghdr))(%d)",
|
|
+ nlh->nlmsg_len, NLMSG_ALIGN(sizeof(struct nlmsghdr)));
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ev = (struct iscsi_uevent *)NLMSG_DATA(nlh);
|
|
+ if (ev->type == ISCSI_KEVENT_PATH_REQ) {
|
|
+ ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
|
|
+ payload_size = ev_size - sizeof(struct iscsi_uevent);
|
|
+ if (payload_size < sizeof(struct iscsi_path))
|
|
+ alloc_size = nlh->nlmsg_len + (payload_size -
|
|
+ sizeof(struct iscsi_path));
|
|
+ else
|
|
+ alloc_size = nlh->nlmsg_len;
|
|
+ } else {
|
|
+ alloc_size = nlh->nlmsg_len;
|
|
+ }
|
|
+ data = (char *)malloc(alloc_size);
|
|
+ if (unlikely(data == NULL)) {
|
|
+ LOG_ERR(PFX "Couldn't allocate %d bytes for Netlink "
|
|
+ "iSCSI message", alloc_size);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ memset(data, 0, alloc_size);
|
|
+ rc = nl_read(nl_sock, data, (int)nlh->nlmsg_len, MSG_WAITALL);
|
|
+ if (rc <= 0) {
|
|
+ LOG_ERR("can not read nlm_ev, error %s[%d]",
|
|
+ strerror(errno), rc);
|
|
+ if (rc == 0)
|
|
+ rc = -EIO;
|
|
+ else
|
|
+ rc = errno;
|
|
+
|
|
+ goto error;
|
|
+ }
|
|
+ *buf = data;
|
|
+ return 0;
|
|
+error:
|
|
+ if (data != NULL)
|
|
+ free(data);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static const struct timespec ctldev_sleep_req = {
|
|
+ .tv_sec = 0,
|
|
+ .tv_nsec = 250000000,
|
|
+};
|
|
+
|
|
+static int ctldev_handle(char *data, nic_t *nic)
|
|
+{
|
|
+ int rc;
|
|
+ struct iscsi_uevent *ev;
|
|
+ uint8_t *payload;
|
|
+ struct iscsi_path *path;
|
|
+ char *msg_type_str;
|
|
+ int i;
|
|
+ nic_interface_t *nic_iface = NULL;
|
|
+
|
|
+ ev = (struct iscsi_uevent *)NLMSG_DATA(data);
|
|
+ switch (ev->type) {
|
|
+ case ISCSI_KEVENT_PATH_REQ:
|
|
+ msg_type_str = "path_req";
|
|
+ break;
|
|
+ default:
|
|
+ /* We don't care about other iSCSI Netlink messages */
|
|
+ LOG_DEBUG(PFX "Received ev->type: 0x%x", ev->type);
|
|
+ rc = 0;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ /* This is a message that drivers should be interested in */
|
|
+ LOG_INFO(PFX "%s: Processing '%s'", nic->log_name, msg_type_str);
|
|
+
|
|
+ payload = (uint8_t *) ((uint8_t *) ev) + sizeof(*ev);
|
|
+ path = (struct iscsi_path *)payload;
|
|
+
|
|
+ if (ev->type == ISCSI_KEVENT_PATH_REQ) {
|
|
+ struct timespec sleep_rem;
|
|
+ nic_interface_t *vlan_iface;
|
|
+ uint16_t ip_type;
|
|
+ int iface_num, vlan_id;
|
|
+
|
|
+ if (path->ip_addr_len == 4)
|
|
+ ip_type = AF_INET;
|
|
+ else if (path->ip_addr_len == 16)
|
|
+ ip_type = AF_INET6;
|
|
+ else
|
|
+ ip_type = 0;
|
|
+#ifdef REQ_PATH_IFACE_NUM
|
|
+ /* Find the nic_iface to use */
|
|
+ iface_num = ev->r.req_path.iface_num ?
|
|
+ ev->r.req_path.iface_num : IFACE_NUM_INVALID;
|
|
+#else
|
|
+ iface_num = IFACE_NUM_INVALID;
|
|
+#endif
|
|
+ vlan_id = path->vlan_id ? path->vlan_id : NO_VLAN;
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: PATH_REQ with iface_num %d VLAN %d",
|
|
+ nic->log_name, iface_num, vlan_id);
|
|
+
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+
|
|
+ nic_iface = nic_find_nic_iface(nic, ip_type, vlan_id,
|
|
+ iface_num, IP_CONFIG_OFF);
|
|
+ if (nic_iface == NULL) {
|
|
+ nic_iface = nic_find_nic_iface(nic, ip_type,
|
|
+ NO_VLAN,
|
|
+ IFACE_NUM_INVALID,
|
|
+ IP_CONFIG_OFF);
|
|
+ if (nic_iface == NULL) {
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ LOG_ERR(PFX "%s: Couldn't find nic iface parent"
|
|
+ " vlan: %d ip_type: %d "
|
|
+ "ip_addr_len: %d to clone",
|
|
+ nic->log_name, path->vlan_id, ip_type,
|
|
+ path->ip_addr_len);
|
|
+ goto error;
|
|
+ }
|
|
+ if (nic_iface->iface_num != IFACE_NUM_INVALID) {
|
|
+ /* New VLAN support:
|
|
+ Use the nic_iface found from the top
|
|
+ of the protocol family and ignore
|
|
+ the VLAN id from the path_req */
|
|
+ if (!(nic_iface->iface_num == 0 &&
|
|
+ nic_iface->vlan_id == 0 &&
|
|
+ path->vlan_id)) {
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ goto nic_iface_done;
|
|
+ }
|
|
+ /* If iface_num == 0 and vlan_id == 0 but
|
|
+ the vlan_id from path_req is > 0,
|
|
+ then fallthru to the legacy support since
|
|
+ this is most likely from an older iscsid
|
|
+ (RHEL6.2/6.3 but has iface_num support)
|
|
+ */
|
|
+ }
|
|
+ /* Legacy VLAN support:
|
|
+ This newly created nic_iface must inherit the
|
|
+ network parameters from the parent nic_iface
|
|
+ */
|
|
+ LOG_DEBUG(PFX "%s: Created the nic_iface for vlan: %d "
|
|
+ "ip_type: %d", nic->log_name, path->vlan_id,
|
|
+ ip_type);
|
|
+ vlan_iface = nic_iface_init();
|
|
+ if (vlan_iface == NULL) {
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ LOG_ERR(PFX "%s: Couldn't allocate "
|
|
+ "space for vlan: %d ip_type: "
|
|
+ "%d", nic->log_name, path->vlan_id,
|
|
+ ip_type);
|
|
+ goto error;
|
|
+ }
|
|
+ vlan_iface->protocol = ip_type;
|
|
+ vlan_iface->vlan_id = path->vlan_id;
|
|
+ nic_add_nic_iface(nic, vlan_iface);
|
|
+
|
|
+ vlan_iface->ustack.ip_config =
|
|
+ nic_iface->ustack.ip_config;
|
|
+ memcpy(vlan_iface->ustack.hostaddr,
|
|
+ nic_iface->ustack.hostaddr,
|
|
+ sizeof(nic_iface->ustack.hostaddr));
|
|
+ memcpy(vlan_iface->ustack.netmask,
|
|
+ nic_iface->ustack.netmask,
|
|
+ sizeof(nic_iface->ustack.netmask));
|
|
+ memcpy(vlan_iface->ustack.netmask6,
|
|
+ nic_iface->ustack.netmask6,
|
|
+ sizeof(nic_iface->ustack.netmask6));
|
|
+ memcpy(vlan_iface->ustack.hostaddr6,
|
|
+ nic_iface->ustack.hostaddr6,
|
|
+ sizeof(nic_iface->ustack.hostaddr6));
|
|
+
|
|
+ /* Persist so when nic_close won't call uip_reset
|
|
+ to nullify nic_iface->ustack */
|
|
+ persist_all_nic_iface(nic);
|
|
+
|
|
+ nic_iface = vlan_iface;
|
|
+ nic_iface->flags |= NIC_IFACE_ACQUIRE;
|
|
+
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ /* nic_disable but not going down */
|
|
+ nic_disable(nic, 0);
|
|
+ } else {
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ }
|
|
+nic_iface_done:
|
|
+ /* Force enable the NIC */
|
|
+ if (nic->state == NIC_STOPPED)
|
|
+ nic_enable(nic);
|
|
+
|
|
+ /* Ensure that the NIC is RUNNING */
|
|
+ rc = -EIO;
|
|
+ for (i = 0; i < 10; i++) {
|
|
+ if (nic->state == NIC_RUNNING) {
|
|
+ rc = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ nanosleep(&ctldev_sleep_req, &sleep_rem);
|
|
+ }
|
|
+
|
|
+ if (rc != 0) {
|
|
+ LOG_WARN(PFX "%s[vlan: %d protocol: %d]: not running, "
|
|
+ "cmd: 0x%x nic state: 0x%x flags: 0x%x",
|
|
+ nic->log_name,
|
|
+ nic_iface->vlan_id, nic_iface->protocol,
|
|
+ ev->type, nic->state, nic->flags);
|
|
+ goto error;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (nic->ops) {
|
|
+ switch (ev->type) {
|
|
+ case ISCSI_KEVENT_PATH_REQ:
|
|
+ /* pass the request up to the user space
|
|
+ * library driver */
|
|
+ nic_iface->flags |= NIC_IFACE_PATHREQ_WAIT2;
|
|
+ nic_iface->flags &= ~NIC_IFACE_PATHREQ_WAIT1;
|
|
+ if (nic->ops->handle_iscsi_path_req)
|
|
+ nic->ops->handle_iscsi_path_req(nic,
|
|
+ nl_sock, ev,
|
|
+ path,
|
|
+ nic_iface);
|
|
+ nic_iface->flags &= ~NIC_IFACE_PATHREQ_WAIT;
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ nic->flags &= ~NIC_PATHREQ_WAIT;
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ LOG_INFO(PFX "%s: 'path_req' operation finished",
|
|
+ nic->log_name);
|
|
+
|
|
+ rc = 0;
|
|
+ break;
|
|
+ default:
|
|
+ rc = -EAGAIN;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+error:
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/* NIC specific nl processing thread */
|
|
+void *nl_process_handle_thread(void *arg)
|
|
+{
|
|
+ int rc;
|
|
+ nic_t *nic = (nic_t *)arg;
|
|
+
|
|
+ if (nic == NULL)
|
|
+ goto error;
|
|
+
|
|
+ while (!event_loop_stop) {
|
|
+ char *data = NULL;
|
|
+
|
|
+ rc = pthread_cond_wait(&nic->nl_process_cond,
|
|
+ &nic->nl_process_mutex);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR("Fatal error in NL processing thread "
|
|
+ "during wait[%s]", strerror(rc));
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ data = nic->nl_process_ring[nic->nl_process_head];
|
|
+ nic->nl_process_ring[nic->nl_process_head] = NULL;
|
|
+ nic->nl_process_tail =
|
|
+ NIC_NL_PROCESS_NEXT_ENTRY(nic->nl_process_tail);
|
|
+
|
|
+ pthread_mutex_unlock(&nic->nl_process_mutex);
|
|
+
|
|
+ if (data) {
|
|
+ ctldev_handle(data, nic);
|
|
+ free(data);
|
|
+ }
|
|
+ }
|
|
+error:
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void flush_nic_nl_process_ring(nic_t *nic)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < NIC_NL_PROCESS_MAX_RING_SIZE; i++) {
|
|
+ if (nic->nl_process_ring[i] != NULL) {
|
|
+ free(nic->nl_process_ring[i]);
|
|
+ nic->nl_process_ring[i] = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ nic->nl_process_head = 0;
|
|
+ nic->nl_process_tail = 0;
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: Flushed NIC NL ring", nic->log_name);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nic_nl_open() - This is called when opening/creating the Netlink listening
|
|
+ * thread
|
|
+ * @param dev - CNIC UIO device to create a NetLink listener on
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+int nic_nl_open()
|
|
+{
|
|
+ int rc;
|
|
+ char *msg_type_str;
|
|
+
|
|
+ /* Prepare the thread to issue the ARP's */
|
|
+ nl_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ISCSI);
|
|
+ if (nl_sock < 0) {
|
|
+ LOG_ERR(PFX "can not create NETLINK_ISCSI socket [%s]",
|
|
+ strerror(errno));
|
|
+ rc = -ENOMEM;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ memset(&src_addr, 0, sizeof(src_addr));
|
|
+ src_addr.nl_family = AF_NETLINK;
|
|
+ src_addr.nl_pid = getpid();
|
|
+ src_addr.nl_groups = ISCSI_NL_GRP_UIP;
|
|
+
|
|
+ while ((!event_loop_stop)) {
|
|
+ rc = bind(nl_sock,
|
|
+ (struct sockaddr *)&src_addr, sizeof(src_addr));
|
|
+ if (rc == 0)
|
|
+ break;
|
|
+
|
|
+ LOG_ERR(PFX "waiting binding to NETLINK_ISCSI socket");
|
|
+
|
|
+ sleep(1);
|
|
+ }
|
|
+
|
|
+ if (event_loop_stop) {
|
|
+ rc = -EINVAL;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "Netlink to CNIC on pid %d is ready", src_addr.nl_pid);
|
|
+
|
|
+ while (!event_loop_stop) {
|
|
+ struct iscsi_uevent *ev;
|
|
+ char *buf = NULL;
|
|
+ uint32_t host_no;
|
|
+ nic_t *nic;
|
|
+
|
|
+ rc = pull_from_nl(&buf);
|
|
+ if (rc != 0)
|
|
+ continue;
|
|
+
|
|
+ /* Try to abort ARP'ing if a if_down was received */
|
|
+ ev = (struct iscsi_uevent *)NLMSG_DATA(buf);
|
|
+ switch (ev->type) {
|
|
+ case ISCSI_KEVENT_IF_DOWN:
|
|
+ host_no = ev->r.notify_if_down.host_no;
|
|
+ msg_type_str = "if_down";
|
|
+ break;
|
|
+ case ISCSI_KEVENT_PATH_REQ:
|
|
+ host_no = ev->r.req_path.host_no;
|
|
+ msg_type_str = "path_req";
|
|
+ break;
|
|
+ default:
|
|
+ /* We don't care about other iSCSI Netlink messages */
|
|
+ continue;
|
|
+ }
|
|
+ LOG_INFO(PFX "Received %s for host %d", msg_type_str, host_no);
|
|
+
|
|
+ /* Make sure the nic list doesn't get yanked */
|
|
+ pthread_mutex_lock(&nic_list_mutex);
|
|
+
|
|
+ rc = from_host_no_find_associated_eth_device(host_no, &nic);
|
|
+ if (rc != 0) {
|
|
+ pthread_mutex_unlock(&nic_list_mutex);
|
|
+ LOG_ERR(PFX "Dropping msg, couldn't find nic with host "
|
|
+ "no: %d", host_no);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* Found the nic */
|
|
+ if (nic->nl_process_thread == INVALID_THREAD) {
|
|
+ /* If thread is not valid, just drop it */
|
|
+ pthread_mutex_unlock(&nic_list_mutex);
|
|
+ LOG_ERR(PFX "Dropping msg, nic nl process thread "
|
|
+ "not ready for host no: %d", host_no);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (ev->type == ISCSI_KEVENT_IF_DOWN) {
|
|
+ char eth_device_name[IFNAMSIZ];
|
|
+
|
|
+ pthread_mutex_lock(&nic->nl_process_mutex);
|
|
+ nic->nl_process_if_down = 1;
|
|
+ flush_nic_nl_process_ring(nic);
|
|
+ pthread_cond_broadcast(&nic->nl_process_if_down_cond);
|
|
+ pthread_mutex_unlock(&nic->nl_process_mutex);
|
|
+
|
|
+ memcpy(eth_device_name, nic->eth_device_name,
|
|
+ sizeof(eth_device_name));
|
|
+
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ nic->flags &= ~NIC_PATHREQ_WAIT;
|
|
+ nic->flags |= NIC_EXIT_MAIN_LOOP;
|
|
+ pthread_cond_broadcast(&nic->enable_done_cond);
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ pthread_mutex_lock(&nic->nl_process_mutex);
|
|
+ nic->nl_process_if_down = 0;
|
|
+ pthread_mutex_unlock(&nic->nl_process_mutex);
|
|
+
|
|
+ nic_disable(nic, 1);
|
|
+
|
|
+ nic_remove(nic);
|
|
+ pthread_mutex_unlock(&nic_list_mutex);
|
|
+
|
|
+ LOG_INFO(PFX "%s: 'if_down' operation finished",
|
|
+ eth_device_name);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* Place msg into the nic specific queue */
|
|
+ pthread_mutex_lock(&nic->nl_process_mutex);
|
|
+ if ((nic->nl_process_head + 1 == nic->nl_process_tail) ||
|
|
+ (nic->nl_process_tail == 0 &&
|
|
+ nic->nl_process_head == NIC_NL_PROCESS_LAST_ENTRY)) {
|
|
+ pthread_mutex_unlock(&nic->nl_process_mutex);
|
|
+ pthread_mutex_unlock(&nic_list_mutex);
|
|
+ LOG_WARN(PFX "%s: No space on Netlink ring",
|
|
+ nic->log_name);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ nic->nl_process_ring[nic->nl_process_head] = buf;
|
|
+ nic->nl_process_head =
|
|
+ NIC_NL_PROCESS_NEXT_ENTRY(nic->nl_process_head);
|
|
+ pthread_cond_signal(&nic->nl_process_cond);
|
|
+
|
|
+ pthread_mutex_unlock(&nic->nl_process_mutex);
|
|
+
|
|
+ pthread_mutex_unlock(&nic_list_mutex);
|
|
+
|
|
+ LOG_DEBUG(PFX "Pulled nl event");
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "Netlink thread exit'ing");
|
|
+ rc = 0;
|
|
+
|
|
+error:
|
|
+ return 0;
|
|
+}
|
|
diff --git a/iscsiuio/src/unix/nic_nl.h b/iscsiuio/src/unix/nic_nl.h
|
|
new file mode 100644
|
|
index 0000000..c68d81c
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/nic_nl.h
|
|
@@ -0,0 +1,54 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * nic_nl.h - NIC uIP NetLink user space stack
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __NIC_NL_H__
|
|
+#define __NIC_NL_H__
|
|
+
|
|
+#include <pthread.h>
|
|
+
|
|
+int nic_nl_open();
|
|
+void nic_nl_close();
|
|
+
|
|
+int __kipc_call(int fd, void *iov_base, int iov_len);
|
|
+
|
|
+extern pthread_cond_t nl_process_if_down_cond;
|
|
+extern pthread_mutex_t nl_process_mutex;
|
|
+extern int nl_process_if_down;
|
|
+
|
|
+#endif /* __NIC_NL_H__ */
|
|
diff --git a/iscsiuio/src/unix/nic_utils.c b/iscsiuio/src/unix/nic_utils.c
|
|
new file mode 100644
|
|
index 0000000..d57cc4f
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/nic_utils.c
|
|
@@ -0,0 +1,1640 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * nic_util.c - shared NIC utility functions
|
|
+ *
|
|
+ */
|
|
+#include <dirent.h>
|
|
+#include <errno.h>
|
|
+#include <fcntl.h>
|
|
+#define _GNU_SOURCE
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <time.h>
|
|
+#include <unistd.h>
|
|
+#include <arpa/inet.h>
|
|
+#include <linux/sockios.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/socket.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/time.h>
|
|
+
|
|
+#include "logger.h"
|
|
+#include "nic.h"
|
|
+#include "nic_id.h"
|
|
+#include "nic_vlan.h"
|
|
+#include "nic_utils.h"
|
|
+#include "options.h"
|
|
+
|
|
+#define PFX "nic_utils "
|
|
+
|
|
+/******************************************************************************
|
|
+ * String constants
|
|
+ *****************************************************************************/
|
|
+static const char nic_uio_sysfs_name_tempate[] = "/sys/class/uio/uio%i/name";
|
|
+static const char cnic_sysfs_uio_event_template[] =
|
|
+ "/sys/class/uio/uio%d/event";
|
|
+static const char base_uio_sysfs_name[] = "/sys/class/uio/";
|
|
+static const char uio_name[] = "uio";
|
|
+
|
|
+static const char uio_base_dir[] = "/dev/uio";
|
|
+static const char uio_udev_path_template[] = "/dev/uio%hd";
|
|
+static const char uio_uevent_path_template[] = "/sys/class/uio/uio%d/uevent";
|
|
+
|
|
+static const char base_iscsi_host_name[] = "/sys/class/iscsi_host/";
|
|
+static const char host_template[] = "host%d";
|
|
+static const char iscsi_host_path_template[] = "/sys/class/iscsi_host/host%d";
|
|
+static const char iscsi_host_path_netdev_template[] =
|
|
+ "/sys/class/iscsi_host/host%d/netdev";
|
|
+static const char cnic_uio_sysfs_resc_template[] =
|
|
+ "/sys/class/uio/uio%i/device/resource%i";
|
|
+
|
|
+/**
|
|
+ * manually_trigger_uio_event() - If the uio file node doesn't exist then
|
|
+ * try to retrigger udev to create the file
|
|
+ * node by touch the uevent file in sysfs
|
|
+ * @param nic - the nic to trigger on
|
|
+ * @param uio_minor - UIO the minor number to use
|
|
+ * @return 0 on success
|
|
+ */
|
|
+int manually_trigger_uio_event(nic_t *nic, int uio_minor)
|
|
+{
|
|
+ int fd;
|
|
+ char uio_uevent_path[sizeof(uio_uevent_path_template) + 10];
|
|
+ char enable_str[] = "online";
|
|
+ int rc;
|
|
+ size_t bytes_wrote;
|
|
+
|
|
+ rc = sprintf(uio_uevent_path, uio_uevent_path_template, uio_minor);
|
|
+ if (rc < 0) {
|
|
+ LOG_ERR(PFX "%s: Could not build uio uevent path",
|
|
+ nic->log_name);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: triggering UIO uevent path: %s",
|
|
+ nic->log_name, uio_uevent_path);
|
|
+
|
|
+ fd = open(uio_uevent_path, O_WRONLY);
|
|
+ if (fd == -1) {
|
|
+ LOG_ERR(PFX "%s: Could not open uio uevent path: %s [%s]",
|
|
+ nic->log_name, uio_uevent_path, strerror(errno));
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ bytes_wrote = write(fd, enable_str, sizeof(enable_str));
|
|
+ if (bytes_wrote != sizeof(enable_str)) {
|
|
+ LOG_ERR(PFX "%s: Could write to uio uevent path: %s [%s]",
|
|
+ nic->log_name, uio_uevent_path, strerror(errno));
|
|
+ rc = -EIO;
|
|
+ } else
|
|
+ rc = 0;
|
|
+
|
|
+ close(fd);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int wait_for_file_node_timed(nic_t *nic, char *filepath, int seconds)
|
|
+{
|
|
+ struct timeval start_time;
|
|
+ struct timeval wait_time;
|
|
+ struct timeval total_time;
|
|
+ struct timespec sleep_req, sleep_rem;
|
|
+
|
|
+ sleep_req.tv_sec = 0;
|
|
+ sleep_req.tv_nsec = 250000000;
|
|
+
|
|
+ wait_time.tv_sec = seconds;
|
|
+ wait_time.tv_usec = 0;
|
|
+
|
|
+ if (gettimeofday(&start_time, NULL)) {
|
|
+ LOG_ERR(PFX "%s: Couldn't gettimeofday() during watch file: %s"
|
|
+ "[%s]", nic->log_name, filepath, strerror(errno));
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ timeradd(&start_time, &wait_time, &total_time);
|
|
+
|
|
+ while (1) {
|
|
+ struct timeval current_time;
|
|
+ struct stat file_stat;
|
|
+
|
|
+ /* Check if the file node exists */
|
|
+ if (stat(filepath, &file_stat) == 0)
|
|
+ return 0;
|
|
+
|
|
+ if (gettimeofday(¤t_time, NULL)) {
|
|
+ LOG_ERR(PFX "%s: Couldn't get current time for "
|
|
+ "watching file: %s [%s]",
|
|
+ nic->log_name, filepath, strerror(errno));
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* Timeout has excceded return -ETIME */
|
|
+ if (timercmp(&total_time, ¤t_time, <)) {
|
|
+ LOG_ERR(PFX "%s: timeout waiting %d secs for file: %s",
|
|
+ nic->log_name, seconds, filepath);
|
|
+ return -ETIME;
|
|
+ }
|
|
+
|
|
+ nanosleep(&sleep_req, &sleep_rem);
|
|
+ }
|
|
+}
|
|
+
|
|
+/******************************************************************************
|
|
+ * Autodiscovery of iscsi_hosts
|
|
+ *****************************************************************************/
|
|
+static int filter_host_name(const struct dirent *entry)
|
|
+{
|
|
+ if ((memcmp(entry->d_name, "host", 4) == 0))
|
|
+ return 1;
|
|
+ else
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int nic_discover_iscsi_hosts()
|
|
+{
|
|
+ struct dirent **files;
|
|
+ int count;
|
|
+ int i;
|
|
+ int rc;
|
|
+
|
|
+ count = scandir(base_iscsi_host_name, &files, filter_host_name,
|
|
+ alphasort);
|
|
+
|
|
+ switch (count) {
|
|
+ case 0:
|
|
+ /* Currently there are no iSCSI hosts */
|
|
+ rc = 0;
|
|
+ break;
|
|
+
|
|
+ case -1:
|
|
+ LOG_WARN(PFX "Error when scanning path: %s[%s]",
|
|
+ base_iscsi_host_name, strerror(errno));
|
|
+ rc = -EINVAL;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ /* There are iSCSI hosts */
|
|
+ pthread_mutex_lock(&nic_list_mutex);
|
|
+ for (i = 0; i < count; i++) {
|
|
+ int host_no;
|
|
+ char *raw = NULL;
|
|
+ uint32_t raw_size = 0;
|
|
+ char temp_path[sizeof(iscsi_host_path_netdev_template) +
|
|
+ 8];
|
|
+ rc = sscanf(files[i]->d_name, host_template, &host_no);
|
|
+ nic_t *nic;
|
|
+
|
|
+ LOG_INFO(PFX "Found host[%d]: %s",
|
|
+ host_no, files[i]->d_name);
|
|
+
|
|
+ /* Build the path to determine netdev name */
|
|
+ snprintf(temp_path, sizeof(temp_path),
|
|
+ iscsi_host_path_netdev_template, host_no);
|
|
+
|
|
+ rc = capture_file(&raw, &raw_size, temp_path);
|
|
+ if (rc != 0)
|
|
+ continue;
|
|
+
|
|
+ rc = from_host_no_find_associated_eth_device(host_no,
|
|
+ &nic);
|
|
+ if (rc != 0) {
|
|
+ /* Normalize the string */
|
|
+ if (raw[raw_size - 1] == '\n')
|
|
+ raw[raw_size - 1] = '\0';
|
|
+
|
|
+ nic = nic_init();
|
|
+ if (nic == NULL) {
|
|
+ LOG_ERR(PFX "Couldn't allocate "
|
|
+ "space for NIC %s "
|
|
+ "during scan", raw);
|
|
+
|
|
+ rc = -ENOMEM;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ strncpy(nic->eth_device_name, raw, raw_size);
|
|
+ nic->config_device_name = nic->eth_device_name;
|
|
+ nic->log_name = nic->eth_device_name;
|
|
+
|
|
+ if (nic_fill_name(nic) != 0) {
|
|
+ free(nic);
|
|
+ free(raw);
|
|
+ rc = -EIO;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ nic_add(nic);
|
|
+
|
|
+ LOG_INFO(PFX "NIC not found creating an "
|
|
+ "instance for host_no: %d %s",
|
|
+ host_no, nic->eth_device_name);
|
|
+ } else
|
|
+ LOG_INFO(PFX "%s: NIC found host_no: %d",
|
|
+ nic->log_name, host_no);
|
|
+
|
|
+ free(raw);
|
|
+ }
|
|
+ pthread_mutex_unlock(&nic_list_mutex);
|
|
+
|
|
+ /* Cleanup the scandir() call */
|
|
+ for (i = 0; i < count; i++)
|
|
+ free(files[i]);
|
|
+ free(files);
|
|
+
|
|
+ rc = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/******************************************************************************
|
|
+ * Enable/Disable Multicast on physical interface
|
|
+ *****************************************************************************/
|
|
+static int nic_util_enable_disable_multicast(nic_t *nic, uint32_t cmd)
|
|
+{
|
|
+ int rc = 0;
|
|
+ struct uip_eth_addr multicast_addr;
|
|
+ int fd;
|
|
+ struct ifreq ifr;
|
|
+
|
|
+ /* adding ethernet multicast address for IPv6 */
|
|
+ memcpy(&multicast_addr, nic->mac_addr, ETH_ALEN);
|
|
+ multicast_addr.addr[0] = 0x33;
|
|
+ multicast_addr.addr[1] = 0x33;
|
|
+ multicast_addr.addr[2] = 0xff;
|
|
+
|
|
+ /* Prepare the request */
|
|
+ memset(&ifr, 0, sizeof(ifr));
|
|
+ strncpy(ifr.ifr_name, nic->eth_device_name,
|
|
+ sizeof(nic->eth_device_name));
|
|
+ memcpy(ifr.ifr_hwaddr.sa_data, multicast_addr.addr, ETH_ALEN);
|
|
+
|
|
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
+ if (fd < 0) {
|
|
+ LOG_ERR(PFX "%s: Couldn't create socket to %s "
|
|
+ "multicast address: %s",
|
|
+ nic->log_name,
|
|
+ cmd == SIOCADDMULTI ? "added" : "delete",
|
|
+ strerror(errno));
|
|
+ return errno;
|
|
+ }
|
|
+
|
|
+ rc = fcntl(fd, F_SETFL, O_NONBLOCK);
|
|
+ if (rc != 0) {
|
|
+ LOG_WARN("%s: Couldn't set to ethtool IOCTL to "
|
|
+ "non-blocking [%s]", nic->log_name, strerror(errno));
|
|
+ }
|
|
+
|
|
+ if (ioctl(fd, cmd, (char *)&ifr) != 0) {
|
|
+ LOG_ERR("%s: Couldn't issue ioctl socket to %s "
|
|
+ "multicast address: %s",
|
|
+ nic->log_name,
|
|
+ cmd == SIOCADDMULTI ? "add" : "delete",
|
|
+ strerror(errno));
|
|
+ rc = errno;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "%s: %s address %02x:%02x:%02x:%02x:%02x:%02x "
|
|
+ "to multicast list",
|
|
+ nic->log_name,
|
|
+ cmd == SIOCADDMULTI ? "Added" : "Deleted",
|
|
+ multicast_addr.addr[0], multicast_addr.addr[1],
|
|
+ multicast_addr.addr[2], multicast_addr.addr[3],
|
|
+ multicast_addr.addr[4], multicast_addr.addr[5]);
|
|
+
|
|
+ if (cmd == SIOCADDMULTI)
|
|
+ nic->flags |= NIC_ADDED_MULICAST;
|
|
+ else
|
|
+ nic->flags &= ~NIC_ADDED_MULICAST;
|
|
+
|
|
+error:
|
|
+ close(fd);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * enable_multicast() - This fuction is used to enable
|
|
+ * the listening of multicast addresses for a given network interface
|
|
+ * @param nic - NIC device to enable multicast on
|
|
+ * @return 0 for success or <0 for failure
|
|
+ */
|
|
+int enable_multicast(nic_t *nic)
|
|
+{
|
|
+ return nic_util_enable_disable_multicast(nic, SIOCADDMULTI);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * disable_multicast() - This fuction is used to disable
|
|
+ * the listening of multicast addresses for a given network interface
|
|
+ * @param dev - NIC device to disable multicast on
|
|
+ * @return 0 for success or <0 for failure
|
|
+ */
|
|
+int disable_multicast(nic_t *nic)
|
|
+{
|
|
+ return nic_util_enable_disable_multicast(nic, SIOCDELMULTI);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Finding associated UIO/physical network interfaces
|
|
+ ******************************************************************************/
|
|
+static int filter_net_name(const struct dirent *entry)
|
|
+{
|
|
+ if ((memcmp(entry->d_name, "net:", 4) == 0))
|
|
+ return 1;
|
|
+ else
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static char *extract_net_name(struct dirent **files)
|
|
+{
|
|
+ return strstr(files[0]->d_name, ":");
|
|
+}
|
|
+
|
|
+static int filter_dot_out(const struct dirent *entry)
|
|
+{
|
|
+ if ((memcmp(entry->d_name, ".", 1) == 0))
|
|
+ return 0;
|
|
+ else
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static char *extract_none(struct dirent **files)
|
|
+{
|
|
+ return files[0]->d_name;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * from_host_no_find_nic() - Given the host number
|
|
+ * this function will try to find the assoicated nic interface
|
|
+ * Must be called with nic_list_mutex lock
|
|
+ * @param host_no - minor number of the UIO device
|
|
+ * @param nic - pointer to the NIC will set if successful
|
|
+ * @return 0 on success, <0 on error
|
|
+ */
|
|
+int from_host_no_find_associated_eth_device(int host_no, nic_t **nic)
|
|
+{
|
|
+ nic_t *current_nic = nic_list;
|
|
+ char *raw = NULL, *raw_tmp;
|
|
+ uint32_t raw_size = 0;
|
|
+
|
|
+ char temp_path[sizeof(iscsi_host_path_netdev_template) + 8];
|
|
+ int rc = -EIO;
|
|
+
|
|
+ /* Build the path to determine uio name */
|
|
+ snprintf(temp_path, sizeof(temp_path),
|
|
+ iscsi_host_path_netdev_template, host_no);
|
|
+
|
|
+ rc = capture_file(&raw, &raw_size, temp_path);
|
|
+ if (rc != 0)
|
|
+ goto error;
|
|
+
|
|
+ /* sanitize name string by replacing newline with null termination */
|
|
+ raw_tmp = raw;
|
|
+ while (*raw_tmp != '\n' && raw_size--)
|
|
+ raw_tmp++;
|
|
+ *raw_tmp = '\0';
|
|
+
|
|
+ rc = -EIO;
|
|
+
|
|
+ current_nic = nic_list;
|
|
+ while (current_nic != NULL) {
|
|
+ if (strcmp(raw, current_nic->eth_device_name) == 0) {
|
|
+ *nic = current_nic;
|
|
+ rc = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ current_nic = current_nic->next;
|
|
+ }
|
|
+
|
|
+ free(raw);
|
|
+
|
|
+error:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * NIC packet handling functions
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * from_uio_find_associated_eth_device() - Given the uio minor number
|
|
+ * this function will try to find the assoicated phyisical network
|
|
+ * interface
|
|
+ * @param uio_minor - minor number of the UIO device
|
|
+ * @param name - char buffer which will be filled if successful
|
|
+ * @param name_size - size of the name buffer
|
|
+ * @return >0 minor number <0 an error
|
|
+ */
|
|
+static int from_uio_find_associated_eth_device(nic_t *nic,
|
|
+ int uio_minor,
|
|
+ char *name, size_t name_size)
|
|
+{
|
|
+ char *path;
|
|
+ int rc;
|
|
+ int count;
|
|
+ struct dirent **files;
|
|
+ char *parsed_name;
|
|
+ int i;
|
|
+ int path_iterator;
|
|
+ char *search_paths[] = { "/sys/class/uio/uio%i/device/",
|
|
+ "/sys/class/uio/uio%i/device/net"
|
|
+ };
|
|
+ int path_to[] = { 5, 1 };
|
|
+ int (*search_filters[]) (const struct dirent *) = {
|
|
+ filter_net_name, filter_dot_out,};
|
|
+ char *(*extract_name[]) (struct dirent **files) = {
|
|
+ extract_net_name, extract_none,};
|
|
+ int extract_name_offset[] = { 1, 0 };
|
|
+
|
|
+ path = malloc(PATH_MAX);
|
|
+ if (path == NULL) {
|
|
+ LOG_ERR(PFX "Could not allocate memory for path");
|
|
+ rc = -ENOMEM;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ for (path_iterator = 0;
|
|
+ path_iterator < sizeof(search_paths) / sizeof(search_paths[0]);
|
|
+ path_iterator++) {
|
|
+ /* Build the path to determine uio name */
|
|
+ rc = sprintf(path, search_paths[path_iterator], uio_minor);
|
|
+
|
|
+ wait_for_file_node_timed(nic, path, path_to[path_iterator]);
|
|
+
|
|
+ count = scandir(path, &files,
|
|
+ search_filters[path_iterator], alphasort);
|
|
+
|
|
+ switch (count) {
|
|
+ case 1:
|
|
+ parsed_name = (*extract_name[path_iterator]) (files);
|
|
+ if (parsed_name == NULL) {
|
|
+ LOG_WARN(PFX "Couldn't find delimiter in: %s",
|
|
+ files[0]->d_name);
|
|
+
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ strncpy(name,
|
|
+ parsed_name +
|
|
+ extract_name_offset[path_iterator], name_size);
|
|
+
|
|
+ free(files[0]);
|
|
+ free(files);
|
|
+
|
|
+ rc = 0;
|
|
+ break;
|
|
+
|
|
+ case 0:
|
|
+ rc = -EINVAL;
|
|
+ break;
|
|
+
|
|
+ case -1:
|
|
+ LOG_WARN(PFX "Error when scanning path: %s[%s]",
|
|
+ path, strerror(errno));
|
|
+ rc = -EINVAL;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ LOG_WARN(PFX
|
|
+ "Too many entries when looking for device: %s",
|
|
+ path);
|
|
+
|
|
+ /* Cleanup the scandir() call */
|
|
+ for (i = 0; i < count; i++)
|
|
+ free(files[i]);
|
|
+ free(files);
|
|
+
|
|
+ rc = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (rc == 0)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+error:
|
|
+ free(path);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * filter_uio_name() - This is the callback used by scandir when looking for
|
|
+ * the number of uio entries
|
|
+ */
|
|
+static int filter_uio_name(const struct dirent *entry)
|
|
+{
|
|
+ /* Only return if the name of the file begins with 'uio' */
|
|
+ if ((memcmp(entry->d_name, uio_name, sizeof(uio_name) - 1) == 0))
|
|
+ return 1;
|
|
+ else
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * from_netdev_name_find_nic() - This is used to find the NIC device given
|
|
+ * the netdev name
|
|
+ * @param interface_name - name of the interface to search on
|
|
+ * @param nic - pointer of the pointer to the NIC
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+int from_netdev_name_find_nic(char *interface_name, nic_t **nic)
|
|
+{
|
|
+ nic_t *current_nic;
|
|
+
|
|
+ current_nic = nic_list;
|
|
+ while (current_nic != NULL) {
|
|
+ if (strcmp(interface_name, current_nic->eth_device_name) == 0)
|
|
+ break;
|
|
+
|
|
+ current_nic = current_nic->next;
|
|
+ }
|
|
+
|
|
+ if (current_nic == NULL)
|
|
+ return -EINVAL;
|
|
+
|
|
+ *nic = current_nic;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * from_phys_name_find_assoicated_uio_device() - This is used to find the
|
|
+ * uio minor
|
|
+ * when given a network interface name
|
|
+ * @param interface_name - network interface name to search for
|
|
+ * @return >0 minor number <0 an error
|
|
+ */
|
|
+int from_phys_name_find_assoicated_uio_device(nic_t *nic)
|
|
+{
|
|
+ char *path = NULL;
|
|
+ int count;
|
|
+ struct dirent **files;
|
|
+ int i;
|
|
+ int rc;
|
|
+ char *interface_name = nic->config_device_name;
|
|
+
|
|
+ if (interface_name == NULL)
|
|
+ interface_name = nic->eth_device_name;
|
|
+
|
|
+ /* Wait at least 10 seconds for uio sysfs entries to appear */
|
|
+ rc = wait_for_file_node_timed(nic, (char *)base_uio_sysfs_name, 10);
|
|
+ if (rc != 0)
|
|
+ return rc;
|
|
+
|
|
+ count = scandir(base_uio_sysfs_name,
|
|
+ &files, filter_uio_name, alphasort);
|
|
+
|
|
+ switch (count) {
|
|
+ case 0:
|
|
+ LOG_WARN(PFX "Couldn't find %s to determine uio minor",
|
|
+ interface_name);
|
|
+ return -EINVAL;
|
|
+
|
|
+ case -1:
|
|
+ LOG_WARN(PFX "Error when scanning for %s in path: %s [%s]",
|
|
+ interface_name, base_uio_sysfs_name, strerror(errno));
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ path = malloc(PATH_MAX);
|
|
+ if (path == NULL) {
|
|
+ LOG_ERR(PFX "Could not allocate memory for path");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ /* Run through the contents of the filtered files to see if the
|
|
+ * network interface name matches that of the uio device */
|
|
+ for (i = 0; i < count; i++) {
|
|
+ int uio_minor;
|
|
+ char eth_name[IFNAMSIZ];
|
|
+
|
|
+ rc = sscanf(files[i]->d_name, "uio%d", &uio_minor);
|
|
+ if (rc != 1) {
|
|
+ LOG_WARN("Could not parse: %s", files[i]->d_name);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ rc = from_uio_find_associated_eth_device(nic,
|
|
+ uio_minor,
|
|
+ eth_name,
|
|
+ sizeof(eth_name));
|
|
+ if (rc != 0) {
|
|
+ LOG_WARN("uio minor: %d not valid [%D]", uio_minor, rc);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (strncmp(eth_name, interface_name, sizeof(eth_name)) == 0) {
|
|
+ memcpy(nic->eth_device_name,
|
|
+ eth_name, sizeof(nic->eth_device_name));
|
|
+
|
|
+ LOG_INFO(PFX "%s associated with uio%d",
|
|
+ nic->eth_device_name, uio_minor);
|
|
+
|
|
+ rc = uio_minor;
|
|
+ goto done;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ LOG_WARN("Could not find assoicate uio device with %s", interface_name);
|
|
+
|
|
+ rc = -EINVAL;
|
|
+done:
|
|
+ if (path != NULL)
|
|
+ free(path);
|
|
+
|
|
+ for (i = 0; i < count; i++)
|
|
+ free(files[i]);
|
|
+ free(files);
|
|
+
|
|
+ return rc;
|
|
+
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nic_verify_uio_sysfs_name() - Using the name entry in sysfs it will try to
|
|
+ * match the NIC library name
|
|
+ * @param nic - The NIC hardware to check
|
|
+ *
|
|
+ */
|
|
+int nic_verify_uio_sysfs_name(nic_t *nic)
|
|
+{
|
|
+ char *raw = NULL, *raw_tmp;
|
|
+ uint32_t raw_size = 0;
|
|
+ char temp_path[sizeof(nic_uio_sysfs_name_tempate) + 8];
|
|
+ int rc = 0;
|
|
+
|
|
+ /* Build the path to determine uio name */
|
|
+ snprintf(temp_path, sizeof(temp_path),
|
|
+ nic_uio_sysfs_name_tempate, nic->uio_minor);
|
|
+
|
|
+ rc = capture_file(&raw, &raw_size, temp_path);
|
|
+ if (rc != 0)
|
|
+ goto error;
|
|
+
|
|
+ /* sanitize name string by replacing newline with null termination */
|
|
+ raw_tmp = raw;
|
|
+ while (*raw_tmp != '\n' && raw_size--)
|
|
+ raw_tmp++;
|
|
+ *raw_tmp = '\0';
|
|
+
|
|
+ /* If the nic library is not set then check if there is a library
|
|
+ * which matches the library name */
|
|
+ if (nic->nic_library == NULL) {
|
|
+ NIC_LIBRARY_EXIST_T exist;
|
|
+
|
|
+ exist = does_nic_uio_name_exist(raw);
|
|
+ if (exist == NIC_LIBRARY_DOESNT_EXIST) {
|
|
+ LOG_ERR(PFX "%s: could not find library: %s ",
|
|
+ nic->log_name, raw);
|
|
+ rc = -EIO;
|
|
+ }
|
|
+ } else {
|
|
+ char *library_name;
|
|
+ size_t library_name_size;
|
|
+
|
|
+ /* Get the string name from the NIC library */
|
|
+ (*nic->ops->lib_ops.get_library_name) (&library_name,
|
|
+ &library_name_size);
|
|
+
|
|
+ if (strcmp(raw, library_name) != 0) {
|
|
+ LOG_ERR(PFX "%s: uio names not equal: "
|
|
+ "expecting %s got %s from %s",
|
|
+ nic->log_name, library_name, raw, temp_path);
|
|
+ rc = -EIO;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ free(raw);
|
|
+
|
|
+ LOG_INFO(PFX "%s: Verified is a cnic_uio device", nic->log_name);
|
|
+
|
|
+error:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nic_fill_name() - This will initialize all the hardware resources underneath
|
|
+ * a struct cnic_uio device
|
|
+ * @param nic - The nic device to attach the hardware with
|
|
+ * @return 0 on success, on failure a errno will be returned
|
|
+ */
|
|
+int nic_fill_name(nic_t *nic)
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ if ((nic->config_device_name != NULL) &&
|
|
+ (memcmp(uio_base_dir, nic->config_device_name,
|
|
+ sizeof(uio_base_dir) - 1) == 0)) {
|
|
+ uint16_t uio_minor;
|
|
+ char eth_name[sizeof(nic->eth_device_name)];
|
|
+
|
|
+ wait_for_file_node_timed(nic, nic->config_device_name, 5);
|
|
+
|
|
+ /* Determine the minor number for the UIO device */
|
|
+ rc = sscanf(nic->config_device_name, uio_udev_path_template,
|
|
+ &uio_minor);
|
|
+ if (rc != 1) {
|
|
+ LOG_WARN(PFX "%s: Could not parse for minor number",
|
|
+ nic->uio_device_name);
|
|
+ return -EINVAL;
|
|
+ } else
|
|
+ nic->uio_minor = uio_minor;
|
|
+
|
|
+ nic->uio_device_name = nic->config_device_name;
|
|
+
|
|
+ /* Determine the assoicated physical network interface */
|
|
+ rc = from_uio_find_associated_eth_device(nic,
|
|
+ nic->uio_minor,
|
|
+ eth_name,
|
|
+ sizeof(eth_name));
|
|
+ if (rc != 0) {
|
|
+ LOG_WARN(PFX "%s: Couldn't find associated eth device",
|
|
+ nic->uio_device_name);
|
|
+ } else {
|
|
+ memcpy(nic->eth_device_name,
|
|
+ eth_name, sizeof(eth_name));
|
|
+ }
|
|
+
|
|
+ LOG_INFO(PFX "%s: configured for uio device for %s",
|
|
+ nic->log_name, nic->uio_device_name);
|
|
+
|
|
+ } else {
|
|
+ LOG_INFO(PFX "looking for uio device for %s",
|
|
+ nic->config_device_name);
|
|
+
|
|
+ rc = from_phys_name_find_assoicated_uio_device(nic);
|
|
+ if (rc < 0) {
|
|
+ LOG_ERR(PFX "Could not determine UIO name for %s",
|
|
+ nic->config_device_name);
|
|
+
|
|
+ return -rc;
|
|
+ }
|
|
+
|
|
+ nic->uio_minor = rc;
|
|
+
|
|
+ if (nic->flags & NIC_UIO_NAME_MALLOC)
|
|
+ free(nic->uio_device_name);
|
|
+
|
|
+ nic->uio_device_name =
|
|
+ malloc(sizeof(uio_udev_path_template) + 8);
|
|
+ if (nic->uio_device_name == NULL) {
|
|
+ LOG_INFO(PFX "%s: Couldn't malloc space for uio name",
|
|
+ nic->log_name);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ snprintf(nic->uio_device_name,
|
|
+ sizeof(uio_udev_path_template) + 8,
|
|
+ uio_udev_path_template, nic->uio_minor);
|
|
+
|
|
+ nic->flags |= NIC_UIO_NAME_MALLOC;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void cnic_get_sysfs_pci_resource_path(nic_t *nic, int resc_no,
|
|
+ char *sys_path, size_t size)
|
|
+{
|
|
+ /* Build the path to sysfs pci resource */
|
|
+ snprintf(sys_path, size,
|
|
+ cnic_uio_sysfs_resc_template, nic->uio_minor, resc_no);
|
|
+
|
|
+}
|
|
+
|
|
+void prepare_library(nic_t *nic)
|
|
+{
|
|
+ int rc;
|
|
+ NIC_LIBRARY_EXIST_T exist;
|
|
+
|
|
+ nic_fill_name(nic);
|
|
+
|
|
+ /* No assoicated library, we can skip it */
|
|
+ if (nic->library_name != NULL) {
|
|
+ /* Check that we have the proper NIC library loaded */
|
|
+ exist = does_nic_library_exist(nic->library_name);
|
|
+ if (exist == NIC_LIBRARY_DOESNT_EXIST) {
|
|
+ LOG_ERR(PFX "NIC library doesn't exists: %s",
|
|
+ nic->library_name);
|
|
+ goto error;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Determine the NIC library to use based on the PCI Id */
|
|
+ rc = find_set_nic_lib(nic);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR(PFX "%s: Couldn't find NIC library", nic->log_name);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ LOG_INFO("%s: found NIC '%s'", nic->log_name, nic->pci_id->device_name);
|
|
+error:
|
|
+ return;
|
|
+}
|
|
+
|
|
+void prepare_nic_thread(nic_t *nic)
|
|
+{
|
|
+ pthread_attr_t attr;
|
|
+ int rc;
|
|
+
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ if (nic->thread == INVALID_THREAD) {
|
|
+ struct timespec ts;
|
|
+ struct timeval tp;
|
|
+
|
|
+ LOG_INFO(PFX "%s: spinning up thread for nic", nic->log_name);
|
|
+
|
|
+ /* Try to spin up the nic thread */
|
|
+ pthread_attr_init(&attr);
|
|
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
+ rc = pthread_create(&nic->thread, &attr, nic_loop, nic);
|
|
+ if (rc != 0) {
|
|
+ LOG_ERR(PFX "%s: Couldn't create thread for nic",
|
|
+ nic->log_name);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ /* Convert from timeval to timespec */
|
|
+ rc = gettimeofday(&tp, NULL);
|
|
+ ts.tv_sec = tp.tv_sec;
|
|
+ ts.tv_nsec = tp.tv_usec * 1000;
|
|
+ ts.tv_sec += 5; /* TODO: hardcoded wait for 5 seconds */
|
|
+
|
|
+ /* Wait for the nic loop thread to to running */
|
|
+ rc = pthread_cond_timedwait(&nic->nic_loop_started_cond,
|
|
+ &nic->nic_mutex, &ts);
|
|
+
|
|
+ LOG_INFO("Created nic thread: %s", nic->log_name);
|
|
+ }
|
|
+
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+error:
|
|
+ return;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Functions used to enable/disable the NIC
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * nic_enable() - Function used to enable the NIC
|
|
+ * @param nic - NIC to enable
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+int nic_enable(nic_t *nic)
|
|
+{
|
|
+ if (nic->flags & NIC_GOING_DOWN) {
|
|
+ LOG_INFO(PFX "%s: NIC device is going down, "
|
|
+ "flag: 0x%x state: 0x%x",
|
|
+ nic->log_name, nic->flags, nic->state);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ if (nic->state == NIC_STOPPED) {
|
|
+ struct timespec ts;
|
|
+ struct timeval tp;
|
|
+ int rc;
|
|
+
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ /* Signal the device to enable itself */
|
|
+ pthread_cond_broadcast(&nic->enable_wait_cond);
|
|
+
|
|
+ nic->flags &= ~NIC_DISABLED;
|
|
+ nic->flags |= NIC_ENABLED;
|
|
+ nic->flags |= NIC_ENABLED_PENDING;
|
|
+
|
|
+ /* Convert from timeval to timespec */
|
|
+ rc = gettimeofday(&tp, NULL);
|
|
+ ts.tv_sec = tp.tv_sec;
|
|
+ ts.tv_nsec = tp.tv_usec * 1000;
|
|
+ ts.tv_sec += 100;
|
|
+
|
|
+ /* Wait for the device to be enabled */
|
|
+ rc = pthread_cond_timedwait(&nic->enable_done_cond,
|
|
+ &nic->nic_mutex, &ts);
|
|
+ if (rc == 0 && nic->flags & NIC_ENABLED) {
|
|
+ LOG_DEBUG(PFX "%s: device enabled", nic->log_name);
|
|
+ } else {
|
|
+ nic->flags &= ~NIC_ENABLED;
|
|
+ nic->flags |= NIC_DISABLED;
|
|
+ nic->flags &= ~NIC_ENABLED_PENDING;
|
|
+
|
|
+ LOG_ERR(PFX "%s: waiting to finish nic_enable err: %s",
|
|
+ nic->log_name, strerror(rc));
|
|
+ }
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ return rc;
|
|
+ } else {
|
|
+ LOG_INFO(PFX "%s: device already enabled: "
|
|
+ "flag: 0x%x state: 0x%x",
|
|
+ nic->log_name, nic->flags, nic->state);
|
|
+ return -EALREADY;
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nic_disable() - Function used to disable the NIC
|
|
+ * @param nic - NIC to disble
|
|
+ * @return void
|
|
+ */
|
|
+void nic_disable(nic_t *nic, int going_down)
|
|
+{
|
|
+ if (nic->state == NIC_STARTED_RUNNING ||
|
|
+ nic->state == NIC_RUNNING) {
|
|
+ struct timespec ts;
|
|
+ struct timeval tp;
|
|
+ int rc;
|
|
+
|
|
+ /* Wait for the device to be disabled */
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+
|
|
+ nic->flags &= ~NIC_ENABLED;
|
|
+ nic->flags |= NIC_DISABLED;
|
|
+ nic->flags &= ~NIC_STARTED_RUNNING;
|
|
+ nic->state = NIC_STOPPED;
|
|
+
|
|
+ if (going_down)
|
|
+ nic->flags |= NIC_GOING_DOWN;
|
|
+
|
|
+ /* Convert from timeval to timespec */
|
|
+ rc = gettimeofday(&tp, NULL);
|
|
+ if (rc) {
|
|
+ LOG_ERR("gettimeofday failed, should never happen: %d\n", errno);
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ts.tv_sec = tp.tv_sec;
|
|
+ ts.tv_nsec = tp.tv_usec * 1000;
|
|
+ ts.tv_sec += 5; /* TODO: hardcoded wait for 5 seconds */
|
|
+
|
|
+ /* Wait for the device to be disabled */
|
|
+ rc = pthread_cond_timedwait(&nic->disable_wait_cond,
|
|
+ &nic->nic_mutex, &ts);
|
|
+ if (rc) {
|
|
+ LOG_ERR("cond_timedwait failed, should never happen: %d\n", errno);
|
|
+ }
|
|
+
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: device disabled", nic->log_name);
|
|
+
|
|
+ } else {
|
|
+ LOG_WARN(PFX "%s: device already disabled: "
|
|
+ "flag: 0x%x state: 0x%x",
|
|
+ nic->log_name, nic->flags, nic->state);
|
|
+ }
|
|
+}
|
|
+
|
|
+void nic_close_all()
|
|
+{
|
|
+ nic_t *nic;
|
|
+
|
|
+ pthread_mutex_lock(&nic_list_mutex);
|
|
+
|
|
+ /* Start the shutdown process */
|
|
+ nic = nic_list;
|
|
+ while (nic != NULL) {
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ nic_close(nic, 1, FREE_ALL_STRINGS);
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+
|
|
+ nic = nic->next;
|
|
+ }
|
|
+ pthread_mutex_unlock(&nic_list_mutex);
|
|
+
|
|
+ LOG_INFO(PFX "All NICs closed");
|
|
+}
|
|
+
|
|
+void nic_remove_all()
|
|
+{
|
|
+ nic_t *nic, *nic_next;
|
|
+
|
|
+ pthread_mutex_lock(&nic_list_mutex);
|
|
+
|
|
+ /* Start the shutdown process */
|
|
+ nic = nic_list;
|
|
+ while (nic != NULL) {
|
|
+ nic_next = nic->next;
|
|
+ pthread_mutex_lock(&nic->nic_mutex);
|
|
+ nic_close(nic, 1, FREE_ALL_STRINGS);
|
|
+ pthread_mutex_unlock(&nic->nic_mutex);
|
|
+ nic_remove(nic);
|
|
+ nic = nic_next;
|
|
+ }
|
|
+ pthread_mutex_unlock(&nic_list_mutex);
|
|
+
|
|
+ LOG_INFO(PFX "All NICs removed");
|
|
+}
|
|
+
|
|
+
|
|
+/******************************************************************************
|
|
+ * Routines to read initialized UIO values from sysfs
|
|
+ *****************************************************************************/
|
|
+/**
|
|
+ * determine_initial_uio_events() - This utility function will
|
|
+ * determine the number of uio events that have occured on the
|
|
+ * given device. This value is read from the UIO sysfs entry
|
|
+ * @param dev - device to read from
|
|
+ * @param num_of_event - number of UIO events
|
|
+ * @return 0 is success, <0 failure
|
|
+ */
|
|
+int detemine_initial_uio_events(nic_t *nic, uint32_t *num_of_events)
|
|
+{
|
|
+ char *raw = NULL;
|
|
+ uint32_t raw_size = 0;
|
|
+ ssize_t elements_read;
|
|
+ char temp_path[sizeof(cnic_sysfs_uio_event_template) + 8];
|
|
+ int rc;
|
|
+
|
|
+ /* Capture RX buffer size */
|
|
+ snprintf(temp_path, sizeof(temp_path),
|
|
+ cnic_sysfs_uio_event_template, nic->uio_minor);
|
|
+
|
|
+ rc = capture_file(&raw, &raw_size, temp_path);
|
|
+ if (rc != 0)
|
|
+ goto error;
|
|
+
|
|
+ elements_read = sscanf(raw, "%d", num_of_events);
|
|
+ if (elements_read != 1) {
|
|
+ LOG_ERR(PFX "%s: Couldn't parse UIO events size from %s",
|
|
+ nic->log_name, temp_path);
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ rc = 0;
|
|
+error:
|
|
+ if (raw != NULL)
|
|
+ free(raw);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nic_set_all_nic_iface_mac_to_parent() - This is a utility function used to
|
|
+ * intialize all the MAC addresses of the network interfaces for a given
|
|
+ * CNIC UIO device
|
|
+ * Call with nic mutex held
|
|
+ * @param dev - CNIC UIO device to initialize
|
|
+ */
|
|
+void nic_set_all_nic_iface_mac_to_parent(nic_t *nic)
|
|
+{
|
|
+ nic_interface_t *current, *vlan_current;
|
|
+
|
|
+ current = nic->nic_iface;
|
|
+ while (current != NULL) {
|
|
+ /* Set the initial MAC address of this interface to the parent
|
|
+ * adapter */
|
|
+ memcpy(current->mac_addr, nic->mac_addr, 6);
|
|
+
|
|
+ vlan_current = current->vlan_next;
|
|
+ while (vlan_current != NULL) {
|
|
+ memcpy(vlan_current->mac_addr, nic->mac_addr, 6);
|
|
+ vlan_current = vlan_current->vlan_next;
|
|
+ }
|
|
+ current = current->next;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * NIC packet handling functions
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * nic_alloc_packet_buffer() - Used to allocate a packet buffer used to
|
|
+ * send a TX packet later
|
|
+ * @param nic - nic device to send the packet on
|
|
+ * @param nic_iface - nic interface to send out on
|
|
+ * @param buf - pointer to the buffer to send
|
|
+ * @param buf_size - size in bytes of the buffer to send
|
|
+ * @return pointer to the allocated packet buffer
|
|
+ * NULL if memory could not be allocated
|
|
+ */
|
|
+static packet_t *nic_alloc_packet_buffer(nic_t *nic,
|
|
+ nic_interface_t *nic_iface,
|
|
+ uint8_t *buf, size_t buf_size)
|
|
+{
|
|
+ packet_t *pkt;
|
|
+
|
|
+ pkt = malloc(sizeof(*pkt) + buf_size);
|
|
+ if (pkt == NULL) {
|
|
+ LOG_ERR(PFX "%s: Couldn't allocate space for packet buffer",
|
|
+ nic->log_name);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ pkt->next = NULL;
|
|
+ pkt->nic = nic;
|
|
+ pkt->nic_iface = nic_iface;
|
|
+ pkt->buf_size = buf_size;
|
|
+ memcpy(pkt->buf, buf, buf_size);
|
|
+
|
|
+ return pkt;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nic_queue_tx_packet() - Used to queue a TX packet buffer to send later
|
|
+ * @param nic - NIC device to send the packet on
|
|
+ * @param nic_iface - NIC interface to send on the packet on
|
|
+ * @param pkt - packet to queue
|
|
+ * @return 0 if successful or <0 if unsuccessful
|
|
+ */
|
|
+int nic_queue_tx_packet(nic_t *nic,
|
|
+ nic_interface_t *nic_iface, packet_t *pkt)
|
|
+{
|
|
+ packet_t *queued_pkt;
|
|
+
|
|
+ queued_pkt = nic_alloc_packet_buffer(nic, nic_iface,
|
|
+ pkt->buf, pkt->buf_size);
|
|
+ if (queued_pkt == NULL) {
|
|
+ LOG_ERR(PFX "%s: Couldn't allocate tx packet to queue",
|
|
+ nic->log_name);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ if (nic->tx_packet_queue == NULL) {
|
|
+ nic->tx_packet_queue = queued_pkt;
|
|
+ } else {
|
|
+ packet_t *current_pkt;
|
|
+
|
|
+ current_pkt = nic->tx_packet_queue;
|
|
+ while (current_pkt->next != NULL)
|
|
+ current_pkt = current_pkt->next;
|
|
+
|
|
+ current_pkt->next = queued_pkt;
|
|
+ }
|
|
+
|
|
+ LOG_DEBUG(PFX "%s: tx packet queued", nic->log_name);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nic_dequeue_tx_packet() - Used pop a TX packet buffer of the TX
|
|
+ * @param dev - cnic_uio device to send the packet on
|
|
+ * @param buf - pointer to the buffer to send
|
|
+ * @param buf_size - size in bytes of the buffer to send
|
|
+ * @return NULL if there are no more TX packet buffers to send
|
|
+ * pointer to the packet buffer which is detached from the device
|
|
+ */
|
|
+packet_t *nic_dequeue_tx_packet(nic_t *nic)
|
|
+{
|
|
+ packet_t *pkt;
|
|
+
|
|
+ pkt = nic->tx_packet_queue;
|
|
+
|
|
+ /* There is a packet buffer to send, time to detach it from the
|
|
+ * cnic_uio device */
|
|
+ if (pkt != NULL) {
|
|
+ nic->tx_packet_queue = pkt->next;
|
|
+ pkt->next = NULL;
|
|
+ }
|
|
+
|
|
+ return pkt;
|
|
+}
|
|
+
|
|
+void nic_fill_ethernet_header(nic_interface_t *nic_iface,
|
|
+ void *data,
|
|
+ void *src_addr, void *dest_addr,
|
|
+ int *pkt_size, void **start_addr,
|
|
+ uint16_t ether_type)
|
|
+{
|
|
+ struct ether_header *eth;
|
|
+ uint16_t *vlan_hdr;
|
|
+
|
|
+ eth = data;
|
|
+
|
|
+ memcpy(eth->ether_shost, src_addr, ETH_ALEN);
|
|
+ memcpy(eth->ether_dhost, dest_addr, ETH_ALEN);
|
|
+
|
|
+ vlan_hdr = (uint16_t *) (eth + 1);
|
|
+ eth->ether_type = htons(ether_type);
|
|
+
|
|
+ *start_addr = vlan_hdr;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * NIC interface management utility functions
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * nic_find_nic_iface() - This function is used to find an interface
|
|
+ * from the NIC
|
|
+ * @param nic - NIC to look for network interfaces
|
|
+ * @param vlan_id - VLAN id to look for
|
|
+ * @param protocol - either AF_INET or AF_INET6
|
|
+ * @param iface_num - iface num to use if present
|
|
+ * @param request_type - IPV4/6 DHCP/STATIC
|
|
+ * @return nic_iface - if found network interface with the given VLAN ID
|
|
+ * if not found a NULL is returned
|
|
+ */
|
|
+nic_interface_t *nic_find_nic_iface(nic_t *nic,
|
|
+ uint16_t protocol,
|
|
+ uint16_t vlan_id,
|
|
+ int iface_num,
|
|
+ int request_type)
|
|
+{
|
|
+ nic_interface_t *current = nic->nic_iface;
|
|
+ nic_interface_t *current_vlan = NULL;
|
|
+
|
|
+ while (current != NULL) {
|
|
+ if (current->protocol != protocol)
|
|
+ goto next;
|
|
+
|
|
+ /* Check for iface_num first */
|
|
+ if (iface_num != IFACE_NUM_INVALID) {
|
|
+ if (current->iface_num == iface_num) {
|
|
+ /* Exception is when iface_num == 0, need to
|
|
+ check for request_type also if !=
|
|
+ IP_CONFIG_OFF */
|
|
+ if (!iface_num && request_type !=
|
|
+ IP_CONFIG_OFF) {
|
|
+ if (current->request_type ==
|
|
+ request_type)
|
|
+ goto found;
|
|
+ } else {
|
|
+ goto found;
|
|
+ }
|
|
+ }
|
|
+ } else if (vlan_id == NO_VLAN) {
|
|
+ /* Just return the top of the family */
|
|
+ goto found;
|
|
+ } else {
|
|
+ if ((current->vlan_id == vlan_id) &&
|
|
+ ((request_type == IP_CONFIG_OFF) ||
|
|
+ (current->request_type == request_type)))
|
|
+ goto found;
|
|
+ }
|
|
+ /* vlan_next loop */
|
|
+ current_vlan = current->vlan_next;
|
|
+ while (current_vlan != NULL) {
|
|
+ if (iface_num != IFACE_NUM_INVALID) {
|
|
+ if (current_vlan->iface_num == iface_num) {
|
|
+ if (!iface_num && request_type !=
|
|
+ IP_CONFIG_OFF) {
|
|
+ if (current_vlan->request_type
|
|
+ == request_type)
|
|
+ goto vlan_found;
|
|
+ } else {
|
|
+ goto vlan_found;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if ((current_vlan->vlan_id == vlan_id) &&
|
|
+ ((request_type == IP_CONFIG_OFF) ||
|
|
+ (current_vlan->request_type == request_type)))
|
|
+ goto vlan_found;
|
|
+
|
|
+ current_vlan = current_vlan->vlan_next;
|
|
+ }
|
|
+next:
|
|
+ current = current->next;
|
|
+ }
|
|
+vlan_found:
|
|
+ current = current_vlan;
|
|
+found:
|
|
+ return current;
|
|
+}
|
|
+
|
|
+/* Called with nic mutex held */
|
|
+void persist_all_nic_iface(nic_t *nic)
|
|
+{
|
|
+ nic_interface_t *current_vlan, *current;
|
|
+
|
|
+ current = nic->nic_iface;
|
|
+ while (current != NULL) {
|
|
+ current->flags |= NIC_IFACE_PERSIST;
|
|
+ current_vlan = current->vlan_next;
|
|
+ while (current_vlan != NULL) {
|
|
+ current_vlan->flags |= NIC_IFACE_PERSIST;
|
|
+ current_vlan = current_vlan->vlan_next;
|
|
+ }
|
|
+ current = current->next;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Sets the nic_iface to the front of the AF */
|
|
+void set_nic_iface(nic_t *nic, nic_interface_t *nic_iface)
|
|
+{
|
|
+ nic_interface_t *current, *prev;
|
|
+ nic_interface_t *current_vlan, *prev_vlan;
|
|
+
|
|
+ prev = NULL;
|
|
+ current = nic->nic_iface;
|
|
+ while (current != NULL) {
|
|
+ if (current->protocol != nic_iface->protocol)
|
|
+ goto next;
|
|
+ /* If its already on top of the list, exit */
|
|
+ if (current == nic_iface)
|
|
+ goto done;
|
|
+
|
|
+ prev_vlan = current;
|
|
+ current_vlan = current->vlan_next;
|
|
+
|
|
+ while (current_vlan != NULL) {
|
|
+ if (current_vlan == nic_iface) {
|
|
+ /* Found inside the vlan list */
|
|
+ /* For vlan == 0, place on top of
|
|
+ the AF list */
|
|
+ prev_vlan->vlan_next =
|
|
+ current_vlan->vlan_next;
|
|
+ current_vlan->vlan_next = current;
|
|
+ if (prev)
|
|
+ prev->next = current_vlan;
|
|
+ else
|
|
+ nic->nic_iface = current_vlan;
|
|
+ goto done;
|
|
+ }
|
|
+ prev_vlan = current_vlan;
|
|
+ current_vlan = current_vlan->vlan_next;
|
|
+ }
|
|
+next:
|
|
+ prev = current;
|
|
+ current = current->next;
|
|
+ }
|
|
+done:
|
|
+ return;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Packet management utility functions
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * get_next_packet_in_queue() - This function will return the next packet in
|
|
+ * the queue
|
|
+ * @param queue - the queue to pull the packet from
|
|
+ * @return the packet in the queue
|
|
+ */
|
|
+static packet_t *get_next_packet_in_queue(packet_t **queue)
|
|
+{
|
|
+ packet_t *pkt;
|
|
+
|
|
+ if (*queue == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ pkt = *queue;
|
|
+ *queue = pkt->next;
|
|
+
|
|
+ return pkt;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * get_next_tx_packet() - This function will return the next packet in
|
|
+ * the TX queue
|
|
+ * @param nic - NIC to pull the TX packet from
|
|
+ * @return the packet in hte queue
|
|
+ */
|
|
+packet_t *get_next_tx_packet(nic_t *nic)
|
|
+{
|
|
+ return get_next_packet_in_queue(&nic->tx_packet_queue);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * get_next_free_packet() - This function will return the next packet in
|
|
+ * the free queue
|
|
+ * @param nic - NIC to pull the RX packet from
|
|
+ * @return the packet in hte queue
|
|
+ */
|
|
+packet_t *get_next_free_packet(nic_t *nic)
|
|
+{
|
|
+ packet_t *pkt;
|
|
+ pthread_mutex_lock(&nic->free_packet_queue_mutex);
|
|
+ pkt = get_next_packet_in_queue(&nic->free_packet_queue);
|
|
+ pthread_mutex_unlock(&nic->free_packet_queue_mutex);
|
|
+
|
|
+ if (pkt != NULL)
|
|
+ reset_packet(pkt);
|
|
+
|
|
+ return pkt;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * put_packet_in_queue() - This function will place the packet in the given
|
|
+ * queue
|
|
+ * @param pkt - the packet to place
|
|
+ * @param queue - the queue to place the packet
|
|
+ * @return the packet in the queue
|
|
+ */
|
|
+static void put_packet_in_queue(packet_t *pkt, packet_t **queue)
|
|
+{
|
|
+ if (*queue == NULL)
|
|
+ *queue = pkt;
|
|
+ else {
|
|
+ pkt->next = *queue;
|
|
+ *queue = pkt;
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * put_packet_in_tx_queue() - This function will place the packet in
|
|
+ * the TX queue
|
|
+ * @param pkt - packet to place
|
|
+ * @param nic - NIC to pull the TX packet from
|
|
+ * @return the packet in hte queue
|
|
+ */
|
|
+void put_packet_in_tx_queue(packet_t *pkt, nic_t *nic)
|
|
+{
|
|
+ return put_packet_in_queue(pkt, &nic->tx_packet_queue);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * put_packet_in_free_queue() - This function will place the packet in
|
|
+ * the RX queue
|
|
+ * @param pkt - packet to place
|
|
+ * @param nic - NIC to pull the RX packet from
|
|
+ * @return the packet in hte queue
|
|
+ */
|
|
+void put_packet_in_free_queue(packet_t *pkt, nic_t *nic)
|
|
+{
|
|
+ pthread_mutex_lock(&nic->free_packet_queue_mutex);
|
|
+ put_packet_in_queue(pkt, &nic->free_packet_queue);
|
|
+ pthread_mutex_unlock(&nic->free_packet_queue_mutex);
|
|
+}
|
|
+
|
|
+uint32_t calculate_default_netmask(uint32_t ip_addr)
|
|
+{
|
|
+ uint32_t netmask;
|
|
+
|
|
+ if (IN_CLASSA(ntohl(ip_addr)))
|
|
+ netmask = htonl(IN_CLASSA_NET);
|
|
+ else if (IN_CLASSB(ntohl(ip_addr)))
|
|
+ netmask = htonl(IN_CLASSB_NET);
|
|
+ else if (IN_CLASSC(ntohl(ip_addr)))
|
|
+ netmask = htonl(IN_CLASSC_NET);
|
|
+ else {
|
|
+ LOG_ERR("Unable to guess netmask for address %x\n", &ip_addr);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return netmask;
|
|
+}
|
|
+
|
|
+void dump_packet_to_log(struct nic_interface *iface,
|
|
+ uint8_t *buf, uint16_t buf_len)
|
|
+{
|
|
+
|
|
+ FILE *file;
|
|
+ char str[80];
|
|
+ int i, count;
|
|
+
|
|
+ file = fmemopen(str, sizeof(str), "w+");
|
|
+ if (file == NULL) {
|
|
+ LOG_ERR(PFX "Could not create logging file stream for packet "
|
|
+ "logging: [%d: %s]", errno, strerror(errno));
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ LOG_PACKET(PFX "%s: Start packet dump len: %d", iface->parent->log_name,
|
|
+ buf_len);
|
|
+
|
|
+ for (i = 0; i < buf_len; i++) {
|
|
+ rewind(file);
|
|
+ fprintf(file, "%03x: ", i);
|
|
+
|
|
+ for (count = 0; (count < 8) && i < buf_len; count++, i++)
|
|
+ fprintf(file, " %02x", buf[i]);
|
|
+ fflush(file);
|
|
+
|
|
+ LOG_PACKET(PFX "%s: %s", iface->parent->log_name, str);
|
|
+ }
|
|
+
|
|
+ LOG_PACKET(PFX "%s: end packet dump", iface->parent->log_name);
|
|
+
|
|
+ fclose(file);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * File Management
|
|
+ ******************************************************************************/
|
|
+ /**
|
|
+ * determine_file_size_read() - when fstat doesn't work on filepath
|
|
+ * within the /proc filesytem, we need to read/count the size of the file
|
|
+ * until we hit a EOF
|
|
+ * @parm filepath - path of the file in which to determine the filesize in
|
|
+ * bytes
|
|
+ * @return file size in bytes, <0 on failure
|
|
+ */
|
|
+int determine_file_size_read(const char *filepath)
|
|
+{
|
|
+ size_t total_size = 0;
|
|
+ ssize_t size = 1;
|
|
+ int fd;
|
|
+ char buf[1024];
|
|
+
|
|
+ fd = open(filepath, O_RDONLY);
|
|
+ if (fd == -1) {
|
|
+ LOG_ERR("Could not open file: %s [%s]",
|
|
+ filepath, strerror(errno));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ while (size > 0) {
|
|
+ size = read(fd, buf, sizeof(buf));
|
|
+
|
|
+ switch (size) {
|
|
+ case 0:
|
|
+ break;
|
|
+ case -1:
|
|
+ LOG_ERR("Error reading file: %s [%s]",
|
|
+ filepath, strerror(errno));
|
|
+ total_size = -1;
|
|
+ break;
|
|
+ default:
|
|
+ total_size += size;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ close(fd);
|
|
+
|
|
+ return total_size;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * capture_file() - Used to capture a file into a buffer
|
|
+ * @param raw - This pointer will be set to the buffer which will hold the
|
|
+ * file contents
|
|
+ * @param raw_size - This is the size of the buffer returned
|
|
+ * @param path - The file path to capture the data from
|
|
+ * @return 0 is returned on success, <0 is returned on failure
|
|
+ */
|
|
+int capture_file(char **raw, uint32_t *raw_size, const char *path)
|
|
+{
|
|
+ FILE *fp;
|
|
+ size_t read_size;
|
|
+ int rc = 0;
|
|
+ int file_size;
|
|
+
|
|
+ file_size = determine_file_size_read(path);
|
|
+ if (file_size < 0) {
|
|
+ LOG_ERR("Could not determine size %s", path);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ fp = fopen(path, "r");
|
|
+ if (fp == NULL) {
|
|
+ LOG_ERR("Could not open path %s [%s]", path, strerror(errno));
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ *raw = malloc(file_size);
|
|
+ if (*raw == NULL) {
|
|
+ LOG_ERR("Could not malloc space for capture %s", path);
|
|
+ rc = -ENOMEM;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ read_size = fread(*raw, file_size, 1, fp);
|
|
+ if (!read_size) {
|
|
+ LOG_ERR("Could not read capture, path: %s len: %d [%s]",
|
|
+ path, file_size, strerror(ferror(fp)));
|
|
+ free(*raw);
|
|
+ *raw = NULL;
|
|
+ rc = errno;
|
|
+ } else
|
|
+ *raw_size = file_size;
|
|
+
|
|
+error:
|
|
+ fclose(fp);
|
|
+
|
|
+ LOG_INFO("Done capturing %s", path);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
diff --git a/iscsiuio/src/unix/nic_utils.h b/iscsiuio/src/unix/nic_utils.h
|
|
new file mode 100644
|
|
index 0000000..d5c1b58
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/nic_utils.h
|
|
@@ -0,0 +1,102 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * nic_util.h - NIC utility functions
|
|
+ *
|
|
+ */
|
|
+#ifndef __NIC_UTILS_H__
|
|
+#define __NIC_UTILS_H__
|
|
+
|
|
+#include "nic.h"
|
|
+
|
|
+/******************************************************************************
|
|
+ * Function Prototype
|
|
+ ******************************************************************************/
|
|
+int manually_trigger_uio_event(nic_t *nic, int uio_minor);
|
|
+
|
|
+int nic_discover_iscsi_hosts();
|
|
+
|
|
+int enable_mutlicast(nic_t *nic);
|
|
+int disable_mutlicast(nic_t *nic);
|
|
+
|
|
+int from_netdev_name_find_nic(char *interface_name, nic_t **nic);
|
|
+
|
|
+int from_host_no_find_associated_eth_device(int host_no, nic_t **nic);
|
|
+
|
|
+int from_phys_name_find_assoicated_uio_device(nic_t *nic);
|
|
+
|
|
+int nic_queue_tx_packet(nic_t *nic,
|
|
+ nic_interface_t *nic_iface, packet_t *pkt);
|
|
+
|
|
+packet_t *nic_dequeue_tx_packet(nic_t *nic);
|
|
+
|
|
+void nic_fill_ethernet_header(nic_interface_t *nic_iface,
|
|
+ void *data,
|
|
+ void *src_addr, void *dest_addr,
|
|
+ int *pkt_size, void **start_addr,
|
|
+ uint16_t ether_type);
|
|
+
|
|
+struct nic_interface *nic_find_nic_iface(nic_t *nic, uint16_t protocol,
|
|
+ uint16_t vlan_id, int iface_num,
|
|
+ int request_type);
|
|
+void set_nic_iface(nic_t *nic, nic_interface_t *nic_iface);
|
|
+
|
|
+void persist_all_nic_iface(nic_t *nic);
|
|
+
|
|
+int add_vlan_interfaces(nic_t *nic);
|
|
+
|
|
+int nic_verify_uio_sysfs_name(nic_t *nic);
|
|
+void cnic_get_sysfs_pci_resource_path(nic_t *nic, int resc_no,
|
|
+ char *sys_path, size_t size);
|
|
+void nic_close_all();
|
|
+void nic_remove_all();
|
|
+
|
|
+int detemine_initial_uio_events(nic_t *nic, uint32_t *num_of_events);
|
|
+
|
|
+uint32_t calculate_default_netmask(uint32_t ip_addr);
|
|
+
|
|
+void prepare_nic_thread(nic_t *nic);
|
|
+void prepare_library(nic_t *nic);
|
|
+
|
|
+int nic_enable(nic_t *nic);
|
|
+void nic_disable(nic_t *nic, int going_down);
|
|
+
|
|
+void dump_packet_to_log(struct nic_interface *iface,
|
|
+ uint8_t *buf, uint16_t buf_len);
|
|
+
|
|
+int determine_file_size_read(const char *filepath);
|
|
+int capture_file(char **raw, uint32_t *raw_size, const char *path);
|
|
+
|
|
+#endif /* __NIC_UTILS_H__ */
|
|
diff --git a/iscsiuio/src/unix/nic_vlan.c b/iscsiuio/src/unix/nic_vlan.c
|
|
new file mode 100644
|
|
index 0000000..eb33381
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/nic_vlan.c
|
|
@@ -0,0 +1,337 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * nic_vlan.c - uIP user space stack VLAN utilities
|
|
+ *
|
|
+ */
|
|
+#define _GNU_SOURCE
|
|
+#include <errno.h>
|
|
+#include <fcntl.h>
|
|
+#include <pthread.h>
|
|
+#include <string.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/stat.h>
|
|
+
|
|
+#include <arpa/inet.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/socket.h>
|
|
+#include <sys/un.h>
|
|
+
|
|
+#include "logger.h"
|
|
+#include "nic.h"
|
|
+#include "nic_utils.h"
|
|
+#include "nic_vlan.h"
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Constants
|
|
+ ******************************************************************************/
|
|
+#define PFX "vlan"
|
|
+
|
|
+static const char proc_vlan_config_path[] = "/proc/net/vlan/config";
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Resolving Found VLAN's for CNIC
|
|
+ ******************************************************************************/
|
|
+int init_vlan_found_handle(struct vlan_found_handle *found_handle,
|
|
+ struct vlan_handle *handle)
|
|
+{
|
|
+ memset(found_handle, 0, sizeof(*found_handle));
|
|
+
|
|
+ found_handle->entries = malloc(found_handle->num_of_entries *
|
|
+ sizeof(struct vlan_found_entry));
|
|
+ if (found_handle->entries == NULL) {
|
|
+ LOG_ERR("Could not allocate space for found entries");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ found_handle->handle = handle;
|
|
+ found_handle->num_of_entries = handle->num_of_entries;
|
|
+
|
|
+ memset(found_handle->entries, 0, found_handle->num_of_entries *
|
|
+ sizeof(struct vlan_found_entry));
|
|
+
|
|
+ handle->outstanding_found_handles++;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void release_vlan_found_handle(struct vlan_found_handle *found_handle)
|
|
+{
|
|
+ if (found_handle->entries != NULL) {
|
|
+ free(found_handle->entries);
|
|
+ found_handle->entries = NULL;
|
|
+ }
|
|
+
|
|
+ found_handle->num_of_entries = 0;
|
|
+
|
|
+ found_handle->handle->outstanding_found_handles--;
|
|
+
|
|
+ found_handle->handle = NULL;
|
|
+
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Resolving VLAN's for CNIC
|
|
+ ******************************************************************************/
|
|
+/**
|
|
+ * init_vlan_handle() - Used to initialize struct ipv4_route_handle so
|
|
+ * that is can be used
|
|
+ * @param handle - Pointer to struct ipv4_route_handle to initialize
|
|
+ * @return 0 on success and <0 on failure
|
|
+ */
|
|
+void init_vlan_table(struct vlan_handle *handle)
|
|
+{
|
|
+ handle->entries = NULL;
|
|
+ handle->num_of_entries = 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * parse_vlan_table() - Given the raw dump of a Linux vlan table, this
|
|
+ * function will parse the into entries held by
|
|
+ * struct vlan_handle
|
|
+ * @param handle - struct vlan_handle used to hold the parsed contents
|
|
+ * @param raw - buffer to parse the contents from
|
|
+ * @param raw_size - size of the buffer in bytes
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+int parse_vlan_table(struct vlan_handle *handle, char *raw, uint32_t raw_size)
|
|
+{
|
|
+ FILE *fp;
|
|
+ int i;
|
|
+ char *token;
|
|
+ size_t size;
|
|
+ int rc;
|
|
+
|
|
+ token = raw;
|
|
+
|
|
+ /* determine the number of entries */
|
|
+ while (*token != '\0') {
|
|
+ if (*token == '\n')
|
|
+ handle->num_of_entries++;
|
|
+
|
|
+ token++;
|
|
+ }
|
|
+
|
|
+ /* There are 2 lines which describe the vlan table
|
|
+ * This lines need to be skipped with counting */
|
|
+ handle->num_of_entries -= 2;
|
|
+
|
|
+ LOG_INFO("Number of vlan entries: %d", handle->num_of_entries);
|
|
+
|
|
+ size = handle->num_of_entries * sizeof(struct vlan_entry);
|
|
+ handle->entries = malloc(size);
|
|
+ if (handle->entries == NULL) {
|
|
+ LOG_ERR
|
|
+ ("Couldn't malloc space to parse vlan table. entires: %d "
|
|
+ "size: %d",
|
|
+ handle->num_of_entries, size);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ fp = fmemopen(raw, raw_size, "r");
|
|
+ if (fp == NULL) {
|
|
+ LOG_ERR("Could not open raw dump of vlan table");
|
|
+ rc = errno;
|
|
+ goto fmemopen_error;
|
|
+ }
|
|
+
|
|
+ if (fscanf(fp, "%*[^\n]\n") < 0) { /* Skip the first line. */
|
|
+ LOG_ERR("Empty or missing line, or read error");
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (fscanf(fp, "%*[^\n]\n") < 0) { /* Skip the second line. */
|
|
+ LOG_ERR("Empty or missing line, or read error");
|
|
+ rc = -EIO;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ i = 0;
|
|
+ /* Time to parse the routing table */
|
|
+ while (1) {
|
|
+ struct vlan_entry *entry = &handle->entries[i];
|
|
+ int r;
|
|
+
|
|
+ r = fscanf(fp, "%15s |%hu |%15s",
|
|
+ entry->vlan_iface_name,
|
|
+ &entry->vlan_id, entry->phy_iface_name);
|
|
+ if (r != 3) {
|
|
+ if (feof(fp)) { /* EOF with no (nonspace) chars read. */
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ LOG_WARN("Parsing error: parsed %d elements", r);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ i++;
|
|
+
|
|
+ LOG_DEBUG("Vlan %d: vlan iface:%s vlan id:%d phys iface:%s",
|
|
+ i,
|
|
+ entry->vlan_iface_name,
|
|
+ entry->vlan_id, entry->phy_iface_name);
|
|
+ }
|
|
+
|
|
+ fclose(fp);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ fclose(fp);
|
|
+
|
|
+fmemopen_error:
|
|
+ if (handle->entries != NULL)
|
|
+ free(handle->entries);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * capture_vlan_table() - This function will snapshot the Linux vlan
|
|
+ * routing table for further processing
|
|
+ * @param handle - struct vlan_handle used to hold the routing context
|
|
+ * @return 0 on success, <0 on failure
|
|
+ */
|
|
+int capture_vlan_table(struct vlan_handle *handle)
|
|
+{
|
|
+ char *raw = NULL;
|
|
+ uint32_t raw_size = 0;
|
|
+ int rc;
|
|
+
|
|
+ rc = capture_file(&raw, &raw_size, proc_vlan_config_path);
|
|
+ if (rc != 0)
|
|
+ goto error;
|
|
+
|
|
+ rc = parse_vlan_table(handle, raw, raw_size);
|
|
+ if (rc != 0)
|
|
+ goto error;
|
|
+
|
|
+error:
|
|
+ if (raw != NULL)
|
|
+ free(raw);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * release_vlan_table() - This function will free all resources used by
|
|
+ * the handle
|
|
+ * @param handle - struct vlan_handle used to hold the routing context
|
|
+ */
|
|
+void release_vlan_table(struct vlan_handle *handle)
|
|
+{
|
|
+ if (handle->entries != NULL) {
|
|
+ free(handle->entries);
|
|
+ handle->entries = NULL;
|
|
+ }
|
|
+
|
|
+ handle->num_of_entries = 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * find_phy_using_vlan_interface() - Given the interface name determine VLAN
|
|
+ * tag ID to match either the physical or VLAN interface name
|
|
+ * @param vlan_iface_name - VLAN interface used to find the physical
|
|
+ * interface
|
|
+ * @param phy_iface_name - returned value is the physical interface name
|
|
+ * @param vlan_id - returned value is the VLAN id
|
|
+ * @return 1 is returned if the interface is a VLAN, 0 if the interface is not
|
|
+ * <0 is returned if there is an error
|
|
+ */
|
|
+int find_phy_using_vlan_interface(struct vlan_handle *handle,
|
|
+ char *vlan_iface_name,
|
|
+ char **phy_iface_name, uint16_t *vlan_id)
|
|
+{
|
|
+ int i, rc = 0;
|
|
+
|
|
+ for (i = 0; i < handle->num_of_entries; i++) {
|
|
+ struct vlan_entry *entry = &handle->entries[i];
|
|
+
|
|
+ /* Compare VLAN interface names to find a match */
|
|
+ if (strcmp(entry->vlan_iface_name, vlan_iface_name) == 0) {
|
|
+ *phy_iface_name = entry->phy_iface_name;
|
|
+ *vlan_id = entry->vlan_id;
|
|
+ rc = 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * find_vlans_using_phy_interface() - Given the physical interface name this
|
|
+ * function will determine the VLAN interface name and VLAN ID
|
|
+ * @param iface_name - physical interface used to find the vlan interface
|
|
+ * @param vlan_iface_name - returned value is the VLAN interface name
|
|
+ * @return The number of VLAN interfaces found
|
|
+ */
|
|
+int find_vlans_using_phy_interface(struct vlan_handle *handle,
|
|
+ struct vlan_found_handle *found_handle,
|
|
+ char *phy_iface_name)
|
|
+{
|
|
+ int i, num_found = 0;
|
|
+
|
|
+ for (i = 0; i < handle->num_of_entries; i++) {
|
|
+ struct vlan_entry *entry = &handle->entries[i];
|
|
+
|
|
+ /* Compare interface names to find a match */
|
|
+ if (strcmp(entry->phy_iface_name, phy_iface_name) == 0) {
|
|
+ found_handle->entries[i].found = VLAN_ENTRY_FOUND;
|
|
+ num_found++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return num_found;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * valid_vlan() - determine if the vlan value which is passed is valid
|
|
+ * @param vlan - vlan value to test
|
|
+ * @return 0 - not valid, 1 - valid
|
|
+ */
|
|
+int valid_vlan(short int vlan)
|
|
+{
|
|
+ /* Allow vlan 1 to connect */
|
|
+ if (vlan > 0 && vlan < 4095)
|
|
+ return 1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/iscsiuio/src/unix/nic_vlan.h b/iscsiuio/src/unix/nic_vlan.h
|
|
new file mode 100644
|
|
index 0000000..610f721
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/nic_vlan.h
|
|
@@ -0,0 +1,89 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * nic_vlan.h - uIP user space stack VLAN utilities
|
|
+ *
|
|
+ */
|
|
+#ifndef __NIC_VLAN_H__
|
|
+#define __NIC_VLAN_H__
|
|
+
|
|
+#include <sys/types.h>
|
|
+
|
|
+/* Used to hold entries in the vlan table */
|
|
+struct vlan_entry {
|
|
+ char vlan_iface_name[16];
|
|
+ char phy_iface_name[16];
|
|
+ uint16_t vlan_id;
|
|
+};
|
|
+
|
|
+struct vlan_handle {
|
|
+ struct vlan_entry *entries;
|
|
+ uint32_t num_of_entries;
|
|
+
|
|
+ uint32_t outstanding_found_handles;
|
|
+};
|
|
+
|
|
+struct vlan_found_entry {
|
|
+#define VLAN_ENTRY_FOUND 1
|
|
+#define VLAN_ENTRY_NOT_FOUND 0
|
|
+ uint8_t found;
|
|
+};
|
|
+
|
|
+struct vlan_found_handle {
|
|
+ struct vlan_handle *handle;
|
|
+ uint32_t num_of_entries;
|
|
+ struct vlan_found_entry *entries;
|
|
+};
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Function Prototypes
|
|
+ ******************************************************************************/
|
|
+void init_vlan_table(struct vlan_handle *handle);
|
|
+int capture_vlan_table(struct vlan_handle *handle);
|
|
+void release_vlan_table(struct vlan_handle *handle);
|
|
+
|
|
+int find_phy_using_vlan_interface(struct vlan_handle *handle,
|
|
+ char *vlan_iface_name,
|
|
+ char **phy_iface_name, uint16_t *vlan_id);
|
|
+int find_vlans_using_phy_interface(struct vlan_handle *handle,
|
|
+ struct vlan_found_handle *found_handle,
|
|
+ char *phy_iface_name);
|
|
+
|
|
+int init_vlan_found_handle(struct vlan_found_handle *found_handle,
|
|
+ struct vlan_handle *handle);
|
|
+void release_vlan_found_handle(struct vlan_found_handle *found_handle);
|
|
+
|
|
+int valid_vlan(short int vlan);
|
|
+#endif /* __NIC_VLAN_H__ */
|
|
diff --git a/iscsiuio/src/unix/options.h b/iscsiuio/src/unix/options.h
|
|
new file mode 100644
|
|
index 0000000..df03255
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/options.h
|
|
@@ -0,0 +1,117 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * options.h - CNIC UIO uIP user space stack
|
|
+ *
|
|
+ */
|
|
+#ifndef __OPTIONS_H__
|
|
+#define __OPTIONS_H__
|
|
+
|
|
+#include <byteswap.h>
|
|
+#include <time.h>
|
|
+#include <sys/types.h>
|
|
+
|
|
+/******************************************************************************
|
|
+ * Constants which are tuned at compile time by the user
|
|
+ *****************************************************************************/
|
|
+
|
|
+/**
|
|
+ * MAX_COUNT_NIC_NL_RESP - This is the maximum number of polls uIP will
|
|
+ * try for a kernel response after a PATH_REQ
|
|
+ */
|
|
+#define MAX_COUNT_NIC_NL_RESP 128
|
|
+
|
|
+/**
|
|
+ * NLM_BUF_DEFAULT_MAX - This is the buffer size allocated for the send/receive
|
|
+ * buffers used by the uIP Netlink subsystem. This
|
|
+ * value is in bytes.
|
|
+ */
|
|
+#define NLM_BUF_DEFAULT_MAX 8192 /* bytes */
|
|
+
|
|
+/******************************************************************************
|
|
+ * Non adjustable constants
|
|
+ *****************************************************************************/
|
|
+#ifndef ETHERTYPE_IP
|
|
+#define ETHERTYPE_IP 0x0800 /* IP */
|
|
+#endif /* ETHERTYPE_IP */
|
|
+
|
|
+#ifndef ETHERTYPE_IPV6
|
|
+#define ETHERTYPE_IPV6 0x86dd /* IP protocol version 6 */
|
|
+#endif /* ETHERTYPE_IPV6 */
|
|
+
|
|
+#ifndef ETHERTYPE_ARP
|
|
+#define ETHERTYPE_ARP 0x0806 /* Address resolution */
|
|
+#endif /* ETHERTYPE_ARP */
|
|
+
|
|
+#ifndef ETHERTYPE_VLAN
|
|
+#define ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tagging */
|
|
+#endif /* ETHERTYPE_VLAN */
|
|
+
|
|
+#define APP_NAME "iscsiuio"
|
|
+/* BUILD_DATE is automatically generated from the Makefile */
|
|
+
|
|
+#define DEBUG_OFF 0x1
|
|
+#define DEBUG_ON 0x2
|
|
+
|
|
+#define INVALID_FD -1
|
|
+#define INVALID_THREAD -1
|
|
+
|
|
+struct options {
|
|
+ char debug;
|
|
+
|
|
+ /* Time the userspace daemon was started */
|
|
+ time_t start_time;
|
|
+};
|
|
+
|
|
+extern int event_loop_stop;
|
|
+extern struct options opt;
|
|
+
|
|
+#ifdef WORDS_BIGENDIAN
|
|
+#define ntohll(x) (x)
|
|
+#define htonll(x) (x)
|
|
+#else
|
|
+#define ntohll(x) bswap_64(x)
|
|
+#define htonll(x) bswap_64(x)
|
|
+#endif
|
|
+
|
|
+# define likely(x) __builtin_expect(!!(x), 1)
|
|
+# define unlikely(x) __builtin_expect(!!(x), 0)
|
|
+
|
|
+/* taken from Linux kernel, include/linux/compiler-gcc.h */
|
|
+/* Optimization barrier */
|
|
+/* The "volatile" is due to gcc bugs */
|
|
+#define barrier() __asm__ __volatile__("": : :"memory")
|
|
+
|
|
+#endif
|
|
diff --git a/iscsiuio/src/unix/packet.c b/iscsiuio/src/unix/packet.c
|
|
new file mode 100644
|
|
index 0000000..c0eeb1f
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/packet.c
|
|
@@ -0,0 +1,143 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * packet.c - packet management
|
|
+ *
|
|
+ */
|
|
+#include <errno.h>
|
|
+#include <stdio.h>
|
|
+
|
|
+#include "logger.h"
|
|
+#include "packet.h"
|
|
+#include "nic.h"
|
|
+
|
|
+/**
|
|
+ * alloc_packet() - Function used to allocate memory for a packet
|
|
+ * @param max_buf_size - max packet size
|
|
+ * @param priv_size - size of the assoicated private data
|
|
+ * @return NULL if failed, on success return a pointer to the packet
|
|
+ */
|
|
+struct packet *alloc_packet(size_t max_buf_size, size_t priv_size)
|
|
+{
|
|
+ struct packet *pkt;
|
|
+ void *priv;
|
|
+
|
|
+ pkt = malloc(max_buf_size + sizeof(struct packet));
|
|
+ if (pkt == NULL) {
|
|
+ LOG_ERR("Could not allocate any memory for packet");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ priv = malloc(priv_size);
|
|
+ if (priv == NULL) {
|
|
+ LOG_ERR("Could not allocate any memory for private structure");
|
|
+ goto free_pkt;
|
|
+ }
|
|
+
|
|
+ pkt->max_buf_size = max_buf_size;
|
|
+ pkt->priv = priv;
|
|
+
|
|
+ return pkt;
|
|
+
|
|
+free_pkt:
|
|
+ free(pkt);
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+void free_packet(struct packet *pkt)
|
|
+{
|
|
+ if (pkt->priv != NULL)
|
|
+ free(pkt->priv);
|
|
+
|
|
+ free(pkt);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * reset_packet() - This will reset the packet fields to default values
|
|
+ * @param pkt - the packet to reset
|
|
+ */
|
|
+void reset_packet(packet_t *pkt)
|
|
+{
|
|
+ pkt->next = NULL;
|
|
+
|
|
+ pkt->flags = 0;
|
|
+ pkt->vlan_tag = 0;
|
|
+
|
|
+ pkt->buf_size = 0;
|
|
+
|
|
+ pkt->data_link_layer = NULL;
|
|
+ pkt->network_layer = NULL;
|
|
+}
|
|
+
|
|
+int alloc_free_queue(nic_t *nic, size_t num_of_packets)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ pthread_mutex_lock(&nic->free_packet_queue_mutex);
|
|
+ for (i = 0; i < num_of_packets; i++) {
|
|
+ packet_t *pkt;
|
|
+
|
|
+ pkt = alloc_packet(1500, 1500);
|
|
+ if (pkt == NULL) {
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ reset_packet(pkt);
|
|
+
|
|
+ pkt->next = nic->free_packet_queue;
|
|
+ nic->free_packet_queue = pkt;
|
|
+ }
|
|
+
|
|
+done:
|
|
+ pthread_mutex_unlock(&nic->free_packet_queue_mutex);
|
|
+
|
|
+ return i;
|
|
+}
|
|
+
|
|
+void free_free_queue(nic_t *nic)
|
|
+{
|
|
+ packet_t *pkt, *pkt_next;
|
|
+
|
|
+ pthread_mutex_lock(&nic->free_packet_queue_mutex);
|
|
+ pkt = nic->free_packet_queue;
|
|
+ while (pkt) {
|
|
+ pkt_next = pkt->next;
|
|
+ free_packet(pkt);
|
|
+ pkt = pkt_next;
|
|
+ }
|
|
+ nic->free_packet_queue = NULL;
|
|
+ pthread_mutex_unlock(&nic->free_packet_queue_mutex);
|
|
+}
|
|
diff --git a/iscsiuio/src/unix/packet.h b/iscsiuio/src/unix/packet.h
|
|
new file mode 100644
|
|
index 0000000..b63d688
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/packet.h
|
|
@@ -0,0 +1,76 @@
|
|
+/*
|
|
+ * Copyright (c) 2009-2011, Broadcom Corporation
|
|
+ * Copyright (c) 2014, QLogic Corporation
|
|
+ *
|
|
+ * Written by: Benjamin Li (benli@broadcom.com)
|
|
+ *
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. All advertising materials mentioning features or use of this software
|
|
+ * must display the following acknowledgement:
|
|
+ * This product includes software developed by Adam Dunkels.
|
|
+ * 4. The name of the author may not be used to endorse or promote
|
|
+ * products derived from this software without specific prior
|
|
+ * written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+ *
|
|
+ * packet.h - packet definitions
|
|
+ *
|
|
+ */
|
|
+#include <errno.h>
|
|
+
|
|
+#ifndef __PACKET_H__
|
|
+#define __PACKET_H__
|
|
+
|
|
+#include "nic.h"
|
|
+
|
|
+struct nic;
|
|
+struct nic_interface;
|
|
+
|
|
+typedef struct packet {
|
|
+ struct packet *next;
|
|
+
|
|
+ uint32_t flags;
|
|
+#define VLAN_TAGGED 0x0001
|
|
+ uint16_t vlan_tag;
|
|
+
|
|
+ size_t max_buf_size;
|
|
+ size_t buf_size;
|
|
+
|
|
+ uint8_t *data_link_layer;
|
|
+ uint8_t *network_layer;
|
|
+
|
|
+ struct nic *nic;
|
|
+ struct nic_interface *nic_iface;
|
|
+
|
|
+ void *priv;
|
|
+ uint8_t buf[];
|
|
+} packet_t;
|
|
+
|
|
+/******************************************************************************
|
|
+ * Packet Function Declarations
|
|
+ *****************************************************************************/
|
|
+int alloc_free_queue(struct nic *, size_t num_of_packets);
|
|
+void free_free_queue(struct nic *);
|
|
+void reset_packet(packet_t *pkt);
|
|
+
|
|
+#endif /* __PACKET_H__ */
|
|
diff --git a/iscsiuio/src/unix/uip-conf.h b/iscsiuio/src/unix/uip-conf.h
|
|
new file mode 100644
|
|
index 0000000..e6e11a5
|
|
--- /dev/null
|
|
+++ b/iscsiuio/src/unix/uip-conf.h
|
|
@@ -0,0 +1,160 @@
|
|
+/**
|
|
+ * \addtogroup uipopt
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \name Project-specific configuration options
|
|
+ * @{
|
|
+ *
|
|
+ * uIP has a number of configuration options that can be overridden
|
|
+ * for each project. These are kept in a project-specific uip-conf.h
|
|
+ * file and all configuration names have the prefix UIP_CONF.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2006, Swedish Institute of Computer Science.
|
|
+ * All rights reserved.
|
|
+ *
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
+ * modification, are permitted provided that the following conditions
|
|
+ * are met:
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
+ * 3. Neither the name of the Institute nor the names of its contributors
|
|
+ * may be used to endorse or promote products derived from this software
|
|
+ * without specific prior written permission.
|
|
+ *
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
+ * SUCH DAMAGE.
|
|
+ *
|
|
+ * This file is part of the uIP TCP/IP stack
|
|
+ *
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * \file
|
|
+ * An example uIP configuration file
|
|
+ * \author
|
|
+ * Adam Dunkels <adam@sics.se>
|
|
+ */
|
|
+
|
|
+#ifndef __UIP_CONF_H__
|
|
+#define __UIP_CONF_H__
|
|
+
|
|
+#include <inttypes.h>
|
|
+
|
|
+/**
|
|
+ * 8 bit datatype
|
|
+ *
|
|
+ * This typedef defines the 8-bit type used throughout uIP.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+typedef uint8_t u8_t;
|
|
+
|
|
+/**
|
|
+ * 16 bit datatype
|
|
+ *
|
|
+ * This typedef defines the 16-bit type used throughout uIP.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+typedef uint16_t u16_t;
|
|
+
|
|
+/**
|
|
+ * 32 bit datatype
|
|
+ *
|
|
+ * This typedef defines the 16-bit type used throughout uIP.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+typedef uint32_t u32_t;
|
|
+
|
|
+/**
|
|
+ * Statistics datatype
|
|
+ *
|
|
+ * This typedef defines the dataype used for keeping statistics in
|
|
+ * uIP.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+typedef uint64_t uip_stats_t;
|
|
+
|
|
+/**
|
|
+ * Maximum number of TCP connections.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_CONF_MAX_CONNECTIONS 40
|
|
+
|
|
+/**
|
|
+ * Maximum number of listening TCP ports.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_CONF_MAX_LISTENPORTS 40
|
|
+
|
|
+/**
|
|
+ * uIP buffer size.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_CONF_BUFFER_SIZE 420
|
|
+
|
|
+/**
|
|
+ * CPU byte order.
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_CONF_BYTE_ORDER LITTLE_ENDIAN
|
|
+
|
|
+/**
|
|
+ * Logging on or off
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_CONF_LOGGING 1
|
|
+
|
|
+/**
|
|
+ * UDP support on or off
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_CONF_UDP 1
|
|
+
|
|
+/**
|
|
+ * UDP checksums on or off
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_CONF_UDP_CHECKSUMS 1
|
|
+
|
|
+/**
|
|
+ * uIP statistics on or off
|
|
+ *
|
|
+ * \hideinitializer
|
|
+ */
|
|
+#define UIP_CONF_STATISTICS 1
|
|
+
|
|
+#define UIP_CONF_IPV6 0
|
|
+
|
|
+#define INET_ADDRSTRLEN 16
|
|
+#define INET6_ADDRSTRLEN 46
|
|
+
|
|
+#endif /* __UIP_CONF_H__ */
|
|
+
|
|
+/** @} */
|
|
+/** @} */
|
|
diff --git a/sysfs-documentation b/sysfs-documentation
|
|
new file mode 100644
|
|
index 0000000..54fc497
|
|
--- /dev/null
|
|
+++ b/sysfs-documentation
|
|
@@ -0,0 +1,514 @@
|
|
+Description of iface attributes and their valid values
|
|
+======================================================
|
|
+
|
|
+== IPv4 attributes ==
|
|
+
|
|
+ipaddress
|
|
+---------
|
|
+IP address in format XXX.XXX.XXX.XXX
|
|
+
|
|
+gateway
|
|
+-------
|
|
+IP address of the network router or gateway device in format XXX.XXX.XXX.XXX
|
|
+
|
|
+subnet
|
|
+------
|
|
+Broadcast address in format XXX.XXX.XXX.XXX
|
|
+
|
|
+bootproto
|
|
+---------
|
|
+The protocol type used to initialize interface
|
|
+
|
|
+Valid values: "dhcp" or "static"
|
|
+
|
|
+dhcp_dns_address_en
|
|
+-------------------
|
|
+Request DNS Server IP Addresses and Domain Name
|
|
+
|
|
+If bootproto is set to dhcp and dhcp_dns_address_en is enable,
|
|
+requests DNS addresses (option 6) and domain name (option 15) in its
|
|
+DHCP parameter request list.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+dhcp_slp_da_info_en
|
|
+-------------------
|
|
+Request SLP DA Information and SLP Scope
|
|
+If bootproto is set to dhcp and dhcp_slp_da_info_en is enable,
|
|
+requests SLP DA information (option 78) and SLP scope (option 79)
|
|
+in its DHCP parameter request list.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+tos_en
|
|
+------
|
|
+Enable IPv4 type of service (ToS)
|
|
+
|
|
+When tos_en is set to enable, use value set in tos when transmitting IPv4 TCP
|
|
+packets on iSCSI connections.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+tos
|
|
+---
|
|
+IPv4 Type of service (ToS)
|
|
+
|
|
+When tos_en is set to enable, use value set in tos when transmitting IPv4 TCP
|
|
+packets on iSCSI connections.
|
|
+
|
|
+Valid range: 8-bit value. [0-255]
|
|
+
|
|
+grat_arp_en
|
|
+-----------
|
|
+Enable Gratuitous ARP Requests
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+dhcp_alt_client_id_en
|
|
+---------------------
|
|
+DHCP Use Alternate Client ID
|
|
+
|
|
+When dhcp_alt_client_id_en is set to enable, use the Client ID configured in
|
|
+dhcp_alt_client_id as its Client ID (DHCP option 61) in outgoing DHCP messages.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+dhcp_alt_client_id
|
|
+------------------
|
|
+DHCP Alternate Client ID
|
|
+
|
|
+When dhcp_alt_client_id_en is set to enable, use value set in dhcp_alt_client_id
|
|
+for Client ID in DHCP messages.
|
|
+
|
|
+Valid values: 11-byte Client ID
|
|
+
|
|
+dhcp_req_vendor_id_en
|
|
+---------------------
|
|
+DHCP Require Vendor ID
|
|
+
|
|
+When dhcp_req_vendor_id_en is set to enable, use value set in dhcp_vendor_id as
|
|
+its vendor ID (DHCP option 60) in outgoing DHCP messages.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+dhcp_use_vendor_id_en
|
|
+---------------------
|
|
+DHCP Use Vendor ID
|
|
+
|
|
+When dhcp_use_vendor_id_en is set to enable, use value set in dhcp_vendor_id as
|
|
+its vendor ID (DHCP option 60) in outgoing DHCP messages.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+dhcp_vendor_id
|
|
+--------------
|
|
+DHCP Vendor ID
|
|
+
|
|
+When dhcp_req_vendor_id_en or dhcp_use_vendor_id_en is set to enable,
|
|
+use value set in dhcp_vendor_id for Vendor ID in DHCP messages.
|
|
+
|
|
+Valid values: 11-byte Client ID
|
|
+
|
|
+dhcp_learn_iqn_en
|
|
+-----------------
|
|
+DHCP Learn IQN
|
|
+
|
|
+When dhcp_learn_iqn_en is set to enable, iSCSI initiator attempts to use DHCP
|
|
+to learn its (IQN) iSCSI name.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+fragment_disable
|
|
+----------------
|
|
+Fragmentation Disable.
|
|
+
|
|
+When fragment_disable is set to disable, iSCSI initiator cannot fragment IP
|
|
+datagrams.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+incoming_forwarding_en
|
|
+----------------------
|
|
+When incoming_forwarding_en is set to enable, iSCSI initiator forwards all
|
|
+incoming network traffic to the network driver, except for iSCSI TCP packets
|
|
+destined to the iSCSI initiator.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+ttl
|
|
+---
|
|
+IPv4 Time to Live (TTL)
|
|
+
|
|
+This attribute contain TTL value sent in IPv4 TCP packets transmitted on
|
|
+iSCSI connections.
|
|
+
|
|
+Valid range: 8-bit value. [0-255]
|
|
+
|
|
+== IPv6 attributes ==
|
|
+
|
|
+ipaddress
|
|
+---------
|
|
+IP address in IPv6 format.
|
|
+
|
|
+link_local_addr
|
|
+---------------
|
|
+Link local address in IPv6 format.
|
|
+
|
|
+router_addr
|
|
+-----------
|
|
+Router address in IPv6 format.
|
|
+
|
|
+ipaddr_autocfg
|
|
+--------------
|
|
+Autoconfigure IPv6 Address.
|
|
+
|
|
+Valid values: nd, dhcpv6 or disable
|
|
+qla4xxx don't support dhcpv6.
|
|
+
|
|
+link_local_autocfg
|
|
+------------------
|
|
+Autoconfigure IPv6 Link Local Address.
|
|
+
|
|
+IPv6 neighbor discovery protocol to discover Link Local Address.
|
|
+
|
|
+Valid values: auto or disable
|
|
+
|
|
+
|
|
+router_autocfg
|
|
+--------------
|
|
+Autoconfigure IPv6 Router address.
|
|
+
|
|
+IPv6 neighbor discovery protocol to discover a default router address.
|
|
+
|
|
+Valid values: auto or disable
|
|
+
|
|
+link_local_state
|
|
+----------------
|
|
+This Read-only attribute show Link Local IP address state in sysfs.
|
|
+
|
|
+Valid values: Unconfigured, Acquiring, Tentative, Valid, Disabling, Invalid,
|
|
+ Deprecated.
|
|
+
|
|
+
|
|
+router_state
|
|
+------------
|
|
+This Read-only attribute shows router state.
|
|
+
|
|
+Valid values: Unknown, Advertised, Manual, Stale.
|
|
+
|
|
+
|
|
+grat_neighbor_adv_en
|
|
+--------------------
|
|
+Enable Gratuitious Neighbor Advertisement
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+mld_en
|
|
+------
|
|
+Enable IPv6 Multicast Listener Discovery
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+flow_label
|
|
+----------
|
|
+This attribute specifies the default value of the Flow Label field in the
|
|
+IPv6 header of TCP packets transmitted on iSCSI connections
|
|
+
|
|
+Valid range: 20-bit value. [0-1048575]
|
|
+Value zero indicates that the traffic is not assigned to a labelled flow.
|
|
+
|
|
+traffic_class
|
|
+-------------
|
|
+This attribute specifies the IPv6 traffic class value to be used in IPv6
|
|
+TCP packets transmitted from the firmware on iSCSI connections.
|
|
+
|
|
+Valid range: 8-bit value. [0-255]
|
|
+
|
|
+hop_limit
|
|
+---------
|
|
+This attribute specifies the IPv6 hop limit value to be used in IPv6 TCP
|
|
+packets transmitted from the firmware on iSCSI connections
|
|
+
|
|
+Valid range: 8-bit value. [0-255]
|
|
+
|
|
+nd_reachable_tmo
|
|
+----------------
|
|
+This attribute specifies the time (in milliseconds) that a node assumes
|
|
+that the neighbor is reachable after confirmation.
|
|
+
|
|
+Valid range: 4-byte value. [0-4294967295]
|
|
+
|
|
+nd_rexmit_time
|
|
+--------------
|
|
+This attribute specifies the time (in milliseconds) between retransmitted
|
|
+neighbor solicitation messages.
|
|
+
|
|
+Valid range: 4-byte value. [0-4294967295]
|
|
+
|
|
+nd_stale_tmo
|
|
+------------
|
|
+This attribute specifies the time (in milliseconds) after which a stale
|
|
+neighbor or destination cache entry is discarded.
|
|
+
|
|
+Valid range: 4-byte value. [0-4294967295]
|
|
+
|
|
+dup_addr_detect_cnt
|
|
+-------------------
|
|
+This attribute specifies the IPv6 duplicate address detection count
|
|
+
|
|
+Valid range: 8-bit value. [0-255]
|
|
+ 0 - Disable
|
|
+ 1 - TryOnce
|
|
+ 2 - TryTwice, and so on
|
|
+
|
|
+router_adv_link_mtu
|
|
+-------------------
|
|
+IPv6 Router Advertised Link MTU Size.
|
|
+
|
|
+Valid range: 1280 bytes to 1500 bytes
|
|
+
|
|
+== Common ==
|
|
+enabled
|
|
+-------
|
|
+This attribute is used to enable or disable IPv4 or IPv6 protocol.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+vlan_id
|
|
+-------
|
|
+This attribute specifies 12-bit VLAN identifier (VID)
|
|
+
|
|
+Valid range: 12-bit value. [1-4094]
|
|
+
|
|
+vlan_priority
|
|
+-------------
|
|
+This attribute specifies Priority to outbound packets containing the
|
|
+specified VLAN-ID (VID)
|
|
+
|
|
+Valid range: 3-bit value. [0-7]
|
|
+
|
|
+vlan_enabled
|
|
+------------
|
|
+VLAN Tagging Enable.
|
|
+
|
|
+When this attribute is set to enable, use value set in vlan_id and
|
|
+vlan_priority to transmit IP packets, and discards IP packets that were
|
|
+received without a matching VLAN ID
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+mtu
|
|
+---
|
|
+Ethernet MTU Size.
|
|
+
|
|
+This field specifies the maximum payload length in byte of an
|
|
+Ethernet frame supported by iSCSI initiator.
|
|
+
|
|
+Valid values: 576 bytes to 9000 bytes
|
|
+
|
|
+port
|
|
+----
|
|
+This attribute shows the initiator iSCSI port number.
|
|
+
|
|
+ipaddress_state
|
|
+---------------
|
|
+This Read-only attribute show IP address state.
|
|
+
|
|
+Valid values: Unconfigured, Acquiring, Tentative, Valid, Disabling, Invalid,
|
|
+ Deprecated.
|
|
+
|
|
+delayed_ack_en
|
|
+--------------
|
|
+When this attribute is set to enable, TCP delayed ACK is enabled.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+tcp_nagle_disable
|
|
+-----------------
|
|
+When this attribute is set to disable, TCP Nagle algorithm is disabled.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+tcp_wsf_disable
|
|
+---------------
|
|
+When this attribute is set to disable, TCP window scale is disabled.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+tcp_wsf
|
|
+-------
|
|
+This attribute specifies the TCP window scale factor to be negotiated
|
|
+on TCP connections.
|
|
+
|
|
+Valid range: 8-bit value. [0-255]
|
|
+
|
|
+tcp_timer_scale
|
|
+---------------
|
|
+The TCP Timer Scale is scale factor that adjusts the time interval between
|
|
+timer ticks on a TCP connection. The scale factor allows for faster time-outs
|
|
+for connections running on a very small network, versus connections running
|
|
+on a very large network.
|
|
+
|
|
+Valid range: 3-bit value. [0-7]
|
|
+
|
|
+tcp_timestamp_en
|
|
+----------------
|
|
+When this attribute is set to enable, iSCSI initiator negotiates to use time
|
|
+stamps in TCP headers
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+cache_id
|
|
+--------
|
|
+This Read-only attribute is used to find the valid cache entries for the
|
|
+interface.
|
|
+
|
|
+For IPv4, ARP cache entry
|
|
+For IPv6, Neighbor cache entry
|
|
+
|
|
+redirect_en
|
|
+-----------
|
|
+For IPv4:
|
|
+When this attribute is set to enable, an ARP redirect can modify the address
|
|
+resolution protocol (ARP) table and any active connections.
|
|
+
|
|
+For IPv6:
|
|
+When this attribute is set to enable and neighbor advertisements are received,
|
|
+the connection table is examined and updated if any active connections match
|
|
+the IP address on the neighbor advertisement. This action is required for
|
|
+failover and redirect.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+def_taskmgmt_tmo
|
|
+----------------
|
|
+This attribute specifies timeout interval in seconds that iSCSI uses for
|
|
+timing out task-management commands.
|
|
+
|
|
+Valid range: 16-bit value [0-65535].
|
|
+
|
|
+header_digest
|
|
+-------------
|
|
+When this attribute is set to enable iSCSI initiator negotiates for
|
|
+HeaderDigest=CRC32 and when set to disable negotiates HeaderDigest=none.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+data_digest
|
|
+-----------
|
|
+When this attribute is set to enable iSCSI initiator negotiates for
|
|
+DataDigest=CRC32 and when set to disable negotiates DataDigest=none.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+immediate_data
|
|
+--------------
|
|
+When this attribute is set to enable iSCSI initiator negotiates for
|
|
+ImmediateData=yes and When set to disable negotiates ImmediateData=none
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+initial_r2t
|
|
+-----------
|
|
+When this attribute is set to enable iSCSI initiator negotiates for
|
|
+InitialR2T=yes. When set to disable negotiates InitialR2T=no.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+data_seq_in_order
|
|
+-----------------
|
|
+When this attribute is set to enable iSCSI initiator set data sequences
|
|
+in order
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+qla4xxx does not support out-of-order data sequences
|
|
+
|
|
+data_pdu_in_order
|
|
+-----------------
|
|
+When this attribute is set to enable iSCSI initiator set Data PDU
|
|
+in order
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+qla4xxx does not support out-of-order Data PDUs.
|
|
+
|
|
+erl
|
|
+---
|
|
+Error Recovery Level
|
|
+
|
|
+This attribute specifies error recovery level (ERL) supported by the
|
|
+connection.
|
|
+
|
|
+Valid values: 2-bit value [0-2]
|
|
+
|
|
+max_recv_dlength
|
|
+----------------
|
|
+iSCSI Maximum Receive Data Segment Length.
|
|
+
|
|
+This attribute specifies Maximum data segment length in bytes, that receive
|
|
+in an iSCSI PDU.
|
|
+
|
|
+first_burst_len
|
|
+---------------
|
|
+iSCSI First Burst Length
|
|
+
|
|
+This attribute Specifies the maximum amount of unsolicited data an iSCSI
|
|
+initiator can send to the target during the execution of a single SCSI command,
|
|
+in bytes.
|
|
+
|
|
+max_outstanding_r2t
|
|
+-------------------
|
|
+iSCSI Maximum Outstanding R2T
|
|
+
|
|
+This attribute Specifies how many R2T PDUs per command can be outstanding
|
|
+during an iSCSI session.
|
|
+
|
|
+max_burst_len
|
|
+-------------
|
|
+This attribute Specifies the maximum length for unsolicited or immediate data
|
|
+iSCSI session can send or receive.
|
|
+
|
|
+chap_auth
|
|
+---------
|
|
+When this attribute is set to enable iSCSI session performs authentication
|
|
+during the security state of login phase.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+bidi_chap
|
|
+---------
|
|
+When this attribute is set to enable iSCSI session generates a CHAP challenge
|
|
+to any target that has issued a CHAP challenge to the iSCSI session.
|
|
+iSCSI session issues the challenge to the target after responding to the
|
|
+targets challenge. This attribute is ignored if chap_auth is set to disable.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+discovery_auth_optional
|
|
+-----------------------
|
|
+When this attribute is set to enable and the chap_auth is set to enable,
|
|
+iSCSI session does not require authentication on discovery sessions unless
|
|
+requested by the peer. When this attribute is set to disable iSCSI session
|
|
+requires CHAP authentication for a discovery session.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+discovery_logout
|
|
+----------------
|
|
+When this attribute is set to enable, iSCSI initiator initiates an iSCSI logout
|
|
+on a discovery session when discovery is complete (before closing the connection).
|
|
+When this attribute is set to disable, iSCSI initiator closes the connection when
|
|
+discovery is complete.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+strict_login_comp_en
|
|
+--------------------
|
|
+When this attribute is set to enable, iSCSI initiator enforces the iSCSI login
|
|
+negotiation rules. When this attribute is set to disable, iSCSI initiator does
|
|
+not enforce iSCSI login negotiation.
|
|
+
|
|
+Valid values: "enable" or "disable"
|
|
+
|
|
+initiator_name
|
|
+--------------
|
|
+This Read-only attribute contains the iSCSI Name string used by the firmware.
|
|
diff --git a/usr/Makefile b/usr/Makefile
|
|
index 673b7f1..e23fee1 100644
|
|
--- a/usr/Makefile
|
|
+++ b/usr/Makefile
|
|
@@ -28,9 +28,9 @@ IPC_OBJ=ioctl.o
|
|
endif
|
|
endif
|
|
|
|
-OPTFLAGS ?= -O2 -g
|
|
+CFLAGS ?= -O2 -g
|
|
WARNFLAGS ?= -Wall -Wstrict-prototypes
|
|
-CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -I../include -I. -I../utils/open-isns \
|
|
+CFLAGS += $(WARNFLAGS) -I../include -I. -I../utils/open-isns \
|
|
-D$(OSNAME) $(IPC_CFLAGS)
|
|
PROGRAMS = iscsid iscsiadm iscsistart
|
|
|
|
@@ -40,7 +40,8 @@ SYSDEPS_SRCS = $(wildcard ../utils/sysdeps/*.o)
|
|
ISCSI_LIB_SRCS = iscsi_util.o io.o auth.o iscsi_timer.o login.o log.o md5.o \
|
|
sha1.o iface.o idbm.o sysfs.o host.o session_info.o iscsi_sysfs.o \
|
|
iscsi_net_util.o iscsid_req.o transport.o iser.o cxgbi.o be2iscsi.o \
|
|
- initiator_common.o iscsi_err.o $(IPC_OBJ) $(SYSDEPS_SRCS)
|
|
+ initiator_common.o iscsi_err.o flashnode.o uip_mgmt_ipc.o \
|
|
+ $(IPC_OBJ) $(SYSDEPS_SRCS)
|
|
# core initiator files
|
|
INITIATOR_SRCS = initiator.o scsi.o actor.o event_poll.o mgmt_ipc.o kern_err_table.o
|
|
|
|
@@ -54,14 +55,14 @@ all: $(PROGRAMS)
|
|
|
|
iscsid: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(DISCOVERY_SRCS) \
|
|
iscsid.o session_mgmt.o discoveryd.o
|
|
- $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns
|
|
+ $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lrt -lmount
|
|
|
|
iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o
|
|
- $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns
|
|
+ $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -L../utils/open-isns -lisns
|
|
|
|
iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \
|
|
iscsistart.o statics.o
|
|
- $(CC) $(CFLAGS) -static $^ -o $@
|
|
+ $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lrt -lmount
|
|
clean:
|
|
rm -f *.o $(PROGRAMS) .depend $(LIBSYS)
|
|
|
|
diff --git a/usr/actor.c b/usr/actor.c
|
|
index b8f8e61..b4f9e95 100644
|
|
--- a/usr/actor.c
|
|
+++ b/usr/actor.c
|
|
@@ -1,7 +1,8 @@
|
|
/*
|
|
- * iSCSI usermode single-threaded scheduler
|
|
+ * iSCSI timeout & deferred work handling
|
|
*
|
|
* Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
|
|
+ * Copyright (C) 2014 Red Hat Inc.
|
|
* maintained by open-iscsi@googlegroups.com
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
@@ -17,53 +18,32 @@
|
|
* See the file COPYING included with this distribution for more details.
|
|
*/
|
|
#include <inttypes.h>
|
|
+#include <time.h>
|
|
+#include <sys/signalfd.h>
|
|
+#include <assert.h>
|
|
+#include <unistd.h>
|
|
#include "actor.h"
|
|
#include "log.h"
|
|
#include "list.h"
|
|
|
|
static LIST_HEAD(pend_list);
|
|
-static LIST_HEAD(poll_list);
|
|
-static LIST_HEAD(actor_list);
|
|
-static volatile uint64_t previous_time;
|
|
-static volatile uint32_t scheduler_loops;
|
|
+static LIST_HEAD(ready_list);
|
|
static volatile int poll_in_progress;
|
|
-static volatile uint64_t actor_jiffies = 0;
|
|
-
|
|
-#define actor_diff(_time1, _time2) ({ \
|
|
- uint64_t __ret; \
|
|
- if ((_time2) >= (_time1)) \
|
|
- __ret = (_time2) - (_time1); \
|
|
- else \
|
|
- __ret = ((~0ULL) - (_time1)) + (_time2); \
|
|
- __ret; \
|
|
-})
|
|
-
|
|
-#define ACTOR_TICKS actor_jiffies
|
|
-#define ACTOR_TICKS_10MS(_a) (_a)
|
|
-#define ACTOR_MS_TO_TICKS(_a) ((_a)/ACTOR_RESOLUTION)
|
|
|
|
static uint64_t
|
|
-actor_diff_time(actor_t *thread, uint64_t current_time)
|
|
+actor_time_left(actor_t *thread, uint64_t current_time)
|
|
{
|
|
- uint64_t diff_time = actor_diff(thread->scheduled_at, current_time);
|
|
- if(diff_time >= thread->ttschedule)
|
|
+ if (current_time > thread->ttschedule)
|
|
return 0;
|
|
- return (thread->ttschedule - diff_time);
|
|
+ else
|
|
+ return (thread->ttschedule - current_time);
|
|
}
|
|
|
|
#define time_after(a,b) \
|
|
((int64_t)(b) - (int64_t)(a) < 0)
|
|
|
|
void
|
|
-actor_init(void)
|
|
-{
|
|
- poll_in_progress = 0;
|
|
- previous_time = 0;
|
|
- scheduler_loops = 0;
|
|
-}
|
|
-
|
|
-void
|
|
-actor_new(actor_t *thread, void (*callback)(void *), void *data)
|
|
+actor_init(actor_t *thread, void (*callback)(void *), void *data)
|
|
{
|
|
INIT_LIST_HEAD(&thread->list);
|
|
thread->state = ACTOR_NOTSCHEDULED;
|
|
@@ -77,11 +57,18 @@ actor_delete(actor_t *thread)
|
|
log_debug(7, "thread %08lx delete: state %d", (long)thread,
|
|
thread->state);
|
|
switch(thread->state) {
|
|
- case ACTOR_SCHEDULED:
|
|
case ACTOR_WAITING:
|
|
- case ACTOR_POLL_WAITING:
|
|
+ /* TODO: remove/reset alarm if we were 1st entry in pend_list */
|
|
+ /* priority: low */
|
|
+ /* fallthrough */
|
|
+ case ACTOR_SCHEDULED:
|
|
log_debug(1, "deleting a scheduled/waiting thread!");
|
|
list_del_init(&thread->list);
|
|
+ if (list_empty(&pend_list)) {
|
|
+ log_debug(7, "nothing left on pend_list, deactivating alarm");
|
|
+ alarm(0);
|
|
+ }
|
|
+
|
|
break;
|
|
default:
|
|
break;
|
|
@@ -89,73 +76,94 @@ actor_delete(actor_t *thread)
|
|
thread->state = ACTOR_NOTSCHEDULED;
|
|
}
|
|
|
|
+/*
|
|
+ * Inserts actor on pend list and sets alarm if new item is
|
|
+ * sooner than previous entries.
|
|
+ */
|
|
static void
|
|
-actor_schedule_private(actor_t *thread, uint32_t ttschedule, int head)
|
|
+actor_insert_on_pend_list(actor_t *thread, uint32_t delay_secs)
|
|
{
|
|
- uint64_t delay_time, current_time;
|
|
- actor_t *next_thread;
|
|
+ struct actor *orig_head;
|
|
+ struct actor *new_head;
|
|
+ struct actor *next_thread;
|
|
|
|
- delay_time = ACTOR_MS_TO_TICKS(ttschedule);
|
|
- current_time = ACTOR_TICKS;
|
|
+ orig_head = list_first_entry_or_null(&pend_list,
|
|
+ struct actor, list);
|
|
|
|
- log_debug(7, "thread %p schedule: delay %" PRIu64 " state %d",
|
|
- thread, delay_time, thread->state);
|
|
+ /* insert new entry in sort order */
|
|
+ list_for_each_entry(next_thread, &pend_list, list) {
|
|
+ if (time_after(next_thread->ttschedule, thread->ttschedule)) {
|
|
+ log_debug(7, "next thread %p due %lld", next_thread,
|
|
+ (long long)next_thread->ttschedule);
|
|
+ log_debug(7, "new thread %p is before (%lld), inserting", thread,
|
|
+ (long long)thread->ttschedule);
|
|
+
|
|
+ /* insert new thread before the next thread */
|
|
+ __list_add(&thread->list, next_thread->list.prev, &next_thread->list);
|
|
+ goto inserted;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (orig_head) {
|
|
+ log_debug(7, "last thread %p due %lld", next_thread,
|
|
+ (long long)next_thread->ttschedule);
|
|
+ log_debug(7, "new thread %p is after (%lld), inserting at tail", thread,
|
|
+ (long long)thread->ttschedule);
|
|
+ }
|
|
+ else
|
|
+ log_debug(7, "new thread %p due %lld is first item on pend_list", thread,
|
|
+ (long long)thread->ttschedule);
|
|
+
|
|
+ /* Not before any existing entries */
|
|
+ list_add_tail(&thread->list, &pend_list);
|
|
+
|
|
+inserted:
|
|
+ new_head = list_first_entry(&pend_list, struct actor, list);
|
|
+ if (orig_head != new_head) {
|
|
+ int result = alarm(delay_secs);
|
|
+ log_debug(7, "new alarm set for %d seconds, old alarm %d",
|
|
+ delay_secs, result);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+actor_schedule_private(actor_t *thread, uint32_t delay_secs, int head)
|
|
+{
|
|
+ time_t current_time;
|
|
+
|
|
+ struct timespec tv;
|
|
+
|
|
+ if (clock_gettime(CLOCK_MONOTONIC_COARSE, &tv)) {
|
|
+ log_error("clock_getime failed, can't schedule!");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ current_time = tv.tv_sec;
|
|
+
|
|
+ log_debug(7, "thread %p schedule: delay %u state %d",
|
|
+ thread, delay_secs, thread->state);
|
|
|
|
- /* convert ttscheduled msecs in 10s of msecs by dividing for now.
|
|
- * later we will change param to 10s of msecs */
|
|
switch(thread->state) {
|
|
case ACTOR_WAITING:
|
|
log_error("rescheduling a waiting thread!");
|
|
list_del(&thread->list);
|
|
+ /* fall-through */
|
|
case ACTOR_NOTSCHEDULED:
|
|
INIT_LIST_HEAD(&thread->list);
|
|
- /* if ttschedule is 0, put in scheduled queue and change
|
|
- * state to scheduled, else add current time to ttschedule and
|
|
- * insert in the queue at the correct point */
|
|
- if (delay_time == 0) {
|
|
- /* For head addition, it must go onto the head of the
|
|
- actor_list regardless if poll is in progress or not
|
|
- */
|
|
- if (poll_in_progress && !head) {
|
|
- thread->state = ACTOR_POLL_WAITING;
|
|
- list_add_tail(&thread->list,
|
|
- &poll_list);
|
|
- } else {
|
|
- thread->state = ACTOR_SCHEDULED;
|
|
- if (head)
|
|
- list_add(&thread->list,
|
|
- &actor_list);
|
|
- else
|
|
- list_add_tail(&thread->list,
|
|
- &actor_list);
|
|
- }
|
|
+
|
|
+ if (delay_secs == 0) {
|
|
+ thread->state = ACTOR_SCHEDULED;
|
|
+ if (head)
|
|
+ list_add(&thread->list, &ready_list);
|
|
+ else
|
|
+ list_add_tail(&thread->list, &ready_list);
|
|
} else {
|
|
thread->state = ACTOR_WAITING;
|
|
- thread->ttschedule = delay_time;
|
|
- thread->scheduled_at = current_time;
|
|
+ thread->ttschedule = current_time + delay_secs;
|
|
|
|
- /* insert new entry in sort order */
|
|
- list_for_each_entry(next_thread, &pend_list, list) {
|
|
- log_debug(7, "thread %p %" PRIu64 " %"PRIu64,
|
|
- next_thread,
|
|
- next_thread->scheduled_at +
|
|
- next_thread->ttschedule,
|
|
- current_time + delay_time);
|
|
-
|
|
- if (time_after(next_thread->scheduled_at +
|
|
- next_thread->ttschedule,
|
|
- current_time + delay_time)) {
|
|
- list_add(&thread->list,
|
|
- &next_thread->list);
|
|
- goto done;
|
|
- }
|
|
- }
|
|
-
|
|
- list_add_tail(&thread->list, &pend_list);
|
|
+ actor_insert_on_pend_list(thread, delay_secs);
|
|
}
|
|
-done:
|
|
break;
|
|
- case ACTOR_POLL_WAITING:
|
|
case ACTOR_SCHEDULED:
|
|
// don't do anything
|
|
break;
|
|
@@ -180,117 +188,90 @@ actor_schedule(actor_t *thread)
|
|
}
|
|
|
|
void
|
|
-actor_timer(actor_t *thread, uint32_t timeout, void (*callback)(void *),
|
|
+actor_timer(actor_t *thread, uint32_t timeout_secs, void (*callback)(void *),
|
|
void *data)
|
|
{
|
|
- actor_new(thread, callback, data);
|
|
- actor_schedule_private(thread, timeout, 0);
|
|
-}
|
|
-
|
|
-int
|
|
-actor_timer_mod(actor_t *thread, uint32_t timeout, void *data)
|
|
-{
|
|
- if (thread->state == ACTOR_WAITING) {
|
|
- list_del_init(&thread->list);
|
|
- thread->data = data;
|
|
- actor_schedule_private(thread, timeout, 0);
|
|
- return 1;
|
|
- }
|
|
- return 0;
|
|
-}
|
|
-
|
|
-void
|
|
-actor_check(uint64_t current_time)
|
|
-{
|
|
- struct actor *thread, *tmp;
|
|
-
|
|
- list_for_each_entry_safe(thread, tmp, &pend_list, list) {
|
|
- if (actor_diff_time(thread, current_time)) {
|
|
- log_debug(7, "thread %08lx wait some more",
|
|
- (long)thread);
|
|
- /* wait some more */
|
|
- break;
|
|
- }
|
|
-
|
|
- /* it is time to schedule this entry */
|
|
- list_del_init(&thread->list);
|
|
-
|
|
- log_debug(2, "thread %08lx was scheduled at %" PRIu64 ":"
|
|
- "%" PRIu64 ", curtime %" PRIu64 " q_forw %p "
|
|
- "&pend_list %p",
|
|
- (long)thread, thread->scheduled_at, thread->ttschedule,
|
|
- current_time, pend_list.next, &pend_list);
|
|
-
|
|
- if (poll_in_progress) {
|
|
- thread->state = ACTOR_POLL_WAITING;
|
|
- list_add_tail(&thread->list, &poll_list);
|
|
- log_debug(7, "thread %08lx now in poll_list",
|
|
- (long)thread);
|
|
- } else {
|
|
- thread->state = ACTOR_SCHEDULED;
|
|
- list_add_tail(&thread->list, &actor_list);
|
|
- log_debug(7, "thread %08lx now in actor_list",
|
|
- (long)thread);
|
|
- }
|
|
- }
|
|
+ actor_init(thread, callback, data);
|
|
+ actor_schedule_private(thread, timeout_secs, 0);
|
|
}
|
|
|
|
+/*
|
|
+ * Execute all items that have expired.
|
|
+ *
|
|
+ * Set an alarm if items remain. Caller must catch SIGALRM and
|
|
+ * then re-invoke this function.
|
|
+ */
|
|
void
|
|
actor_poll(void)
|
|
{
|
|
+ struct actor *thread, *tmp;
|
|
uint64_t current_time;
|
|
- struct actor *thread;
|
|
+ struct timespec tv;
|
|
|
|
- /* check that there are no any concurrency */
|
|
if (poll_in_progress) {
|
|
- log_error("concurrent actor_poll() is not allowed");
|
|
+ log_error("recursive actor_poll() is not allowed");
|
|
+ return;
|
|
}
|
|
|
|
- /* don't check wait list every single poll.
|
|
- * get new time. Shift it to make 10s of msecs approx
|
|
- * if new time is not same as old time */
|
|
- if (scheduler_loops++ > ACTOR_MAX_LOOPS) {
|
|
- /* try coming in about every 100 msecs */
|
|
- current_time = ACTOR_TICKS;
|
|
- scheduler_loops = 0;
|
|
- /* checking whether we are in the same tick... */
|
|
- if ( ACTOR_TICKS_10MS(current_time) !=
|
|
- ACTOR_TICKS_10MS(previous_time)) {
|
|
- previous_time = current_time;
|
|
- actor_check(current_time);
|
|
+ if (clock_gettime(CLOCK_MONOTONIC_COARSE, &tv)) {
|
|
+ log_error("clock_gettime failed, can't schedule!");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ current_time = tv.tv_sec;
|
|
+
|
|
+ /*
|
|
+ * Move items that are ripe from pend_list to ready_list.
|
|
+ * Actors are in sorted order of ascending run time, so
|
|
+ * stop at the first unripe entry.
|
|
+ */
|
|
+ log_debug(7, "current time %" PRIu64, current_time);
|
|
+
|
|
+ list_for_each_entry_safe(thread, tmp, &pend_list, list) {
|
|
+ uint64_t time_left = actor_time_left(thread, current_time);
|
|
+ if (time_left) {
|
|
+ log_debug(7, "thread %08lx due %" PRIu64 ", wait %" PRIu64 " more",
|
|
+ (long)thread, thread->ttschedule, time_left);
|
|
+
|
|
+ alarm(time_left);
|
|
+ break;
|
|
}
|
|
+
|
|
+ /* This entry can be run now */
|
|
+ list_del_init(&thread->list);
|
|
+
|
|
+ log_debug(2, "thread %08lx was scheduled for "
|
|
+ "%" PRIu64 ", curtime %" PRIu64 " q_forw %p "
|
|
+ "&pend_list %p",
|
|
+ (long)thread, thread->ttschedule,
|
|
+ current_time, pend_list.next, &pend_list);
|
|
+
|
|
+ list_add_tail(&thread->list, &ready_list);
|
|
+ assert(thread->state == ACTOR_WAITING);
|
|
+ thread->state = ACTOR_SCHEDULED;
|
|
+ log_debug(7, "thread %08lx now in ready_list",
|
|
+ (long)thread);
|
|
+ }
|
|
+
|
|
+ /* Disable alarm if nothing else pending */
|
|
+ if (list_empty(&pend_list)) {
|
|
+ log_debug(7, "nothing on pend_list, deactivating alarm");
|
|
+ alarm(0);
|
|
}
|
|
|
|
- /* the following code to check in the main data path */
|
|
poll_in_progress = 1;
|
|
- while (!list_empty(&actor_list)) {
|
|
- thread = list_entry(actor_list.next, struct actor, list);
|
|
+ while (!list_empty(&ready_list)) {
|
|
+ thread = list_first_entry(&ready_list, struct actor, list);
|
|
list_del_init(&thread->list);
|
|
|
|
if (thread->state != ACTOR_SCHEDULED)
|
|
- log_error("actor_list: thread state corrupted! "
|
|
+ log_error("ready_list: thread state corrupted! "
|
|
"Thread with state %d in actor list.",
|
|
thread->state);
|
|
thread->state = ACTOR_NOTSCHEDULED;
|
|
log_debug(7, "exec thread %08lx callback", (long)thread);
|
|
thread->callback(thread->data);
|
|
- log_debug(7, "thread removed\n");
|
|
+ log_debug(7, "thread %08lx done", (long)thread);
|
|
}
|
|
poll_in_progress = 0;
|
|
-
|
|
- while (!list_empty(&poll_list)) {
|
|
- thread = list_entry(poll_list.next, struct actor, list);
|
|
- list_del_init(&thread->list);
|
|
-
|
|
- if (thread->state != ACTOR_POLL_WAITING)
|
|
- log_error("poll_list: thread state corrupted!"
|
|
- "Thread with state %d in poll list.",
|
|
- thread->state);
|
|
- thread->state = ACTOR_SCHEDULED;
|
|
- list_add_tail(&thread->list, &actor_list);
|
|
- log_debug(7, "thread %08lx removed from poll_list",
|
|
- (long)thread);
|
|
- }
|
|
-
|
|
- ACTOR_TICKS++;
|
|
}
|
|
diff --git a/usr/actor.h b/usr/actor.h
|
|
index 704224d..7283dce 100644
|
|
--- a/usr/actor.h
|
|
+++ b/usr/actor.h
|
|
@@ -22,15 +22,11 @@
|
|
#include "types.h"
|
|
#include "list.h"
|
|
|
|
-#define ACTOR_RESOLUTION 250 /* in millis */
|
|
-#define ACTOR_MAX_LOOPS 1
|
|
-
|
|
typedef enum actor_state_e {
|
|
ACTOR_INVALID,
|
|
ACTOR_WAITING,
|
|
ACTOR_SCHEDULED,
|
|
ACTOR_NOTSCHEDULED,
|
|
- ACTOR_POLL_WAITING
|
|
} actor_state_e;
|
|
|
|
typedef struct actor {
|
|
@@ -38,18 +34,16 @@ typedef struct actor {
|
|
actor_state_e state;
|
|
void *data;
|
|
void (*callback)(void * );
|
|
- uint64_t scheduled_at;
|
|
- uint64_t ttschedule;
|
|
+ time_t ttschedule;
|
|
} actor_t;
|
|
|
|
-extern void actor_new(actor_t *thread, void (*callback)(void *), void * data);
|
|
+extern void actor_init(actor_t *thread, void (*callback)(void *), void * data);
|
|
extern void actor_delete(actor_t *thread);
|
|
extern void actor_schedule_head(actor_t *thread);
|
|
extern void actor_schedule(actor_t *thread);
|
|
-extern void actor_timer(actor_t *thread, uint32_t timeout,
|
|
+extern void actor_timer(actor_t *thread, uint32_t delay_secs,
|
|
void (*callback)(void *), void *data);
|
|
-extern int actor_timer_mod(actor_t *thread, uint32_t new_timeout, void *data);
|
|
+extern int actor_timer_mod(actor_t *thread, uint32_t new_delay_secs, void *data);
|
|
extern void actor_poll(void);
|
|
-extern void actor_init(void);
|
|
|
|
#endif /* ACTOR_H */
|
|
diff --git a/usr/auth.c b/usr/auth.c
|
|
index c924545..00b4388 100644
|
|
--- a/usr/auth.c
|
|
+++ b/usr/auth.c
|
|
@@ -109,13 +109,13 @@ acl_chap_auth_request(struct iscsi_acl *client, char *username, unsigned int id,
|
|
/* the expected credentials are in the session */
|
|
if (session->username_in == NULL) {
|
|
log_error("failing authentication, no incoming username "
|
|
- "configured to authenticate target %s\n",
|
|
+ "configured to authenticate target %s",
|
|
session->target_name);
|
|
return AUTH_STATUS_FAIL;
|
|
}
|
|
if (strcmp(username, session->username_in) != 0) {
|
|
log_error("failing authentication, received incorrect "
|
|
- "username from target %s\n", session->target_name);
|
|
+ "username from target %s", session->target_name);
|
|
return AUTH_STATUS_FAIL;
|
|
}
|
|
|
|
@@ -123,7 +123,7 @@ acl_chap_auth_request(struct iscsi_acl *client, char *username, unsigned int id,
|
|
(session->password_in == NULL) ||
|
|
(session->password_in[0] == '\0')) {
|
|
log_error("failing authentication, no incoming password "
|
|
- "configured to authenticate target %s\n",
|
|
+ "configured to authenticate target %s",
|
|
session->target_name);
|
|
return AUTH_STATUS_FAIL;
|
|
}
|
|
@@ -132,7 +132,7 @@ acl_chap_auth_request(struct iscsi_acl *client, char *username, unsigned int id,
|
|
|
|
if (rsp_length != sizeof(verify_data)) {
|
|
log_error("failing authentication, received incorrect "
|
|
- "CHAP response length %u from target %s\n",
|
|
+ "CHAP response length %u from target %s",
|
|
rsp_length, session->target_name);
|
|
return AUTH_STATUS_FAIL;
|
|
}
|
|
@@ -154,13 +154,13 @@ acl_chap_auth_request(struct iscsi_acl *client, char *username, unsigned int id,
|
|
auth_md5_final(verify_data, &context);
|
|
|
|
if (memcmp(response_data, verify_data, sizeof(verify_data)) == 0) {
|
|
- log_debug(1, "initiator authenticated target %s\n",
|
|
+ log_debug(1, "initiator authenticated target %s",
|
|
session->target_name);
|
|
return AUTH_STATUS_PASS;
|
|
}
|
|
|
|
log_error("failing authentication, received incorrect CHAP "
|
|
- "response from target %s\n", session->target_name);
|
|
+ "response from target %s", session->target_name);
|
|
return AUTH_STATUS_FAIL;
|
|
}
|
|
|
|
@@ -189,24 +189,24 @@ get_random_bytes(unsigned char *data, unsigned int length)
|
|
|
|
long r;
|
|
unsigned n;
|
|
- int fd;
|
|
+ int fd, r_size = sizeof(r);
|
|
|
|
fd = open("/dev/urandom", O_RDONLY);
|
|
while (length > 0) {
|
|
|
|
- if (!fd || read(fd, &r, sizeof(long)) != -1)
|
|
+ if (fd == -1 || read(fd, &r, r_size) != r_size)
|
|
r = rand();
|
|
r = r ^ (r >> 8);
|
|
r = r ^ (r >> 4);
|
|
n = r & 0x7;
|
|
|
|
- if (!fd || read(fd, &r, sizeof(long)) != -1)
|
|
+ if (fd == -1 || read(fd, &r, r_size) != r_size)
|
|
r = rand();
|
|
r = r ^ (r >> 8);
|
|
r = r ^ (r >> 5);
|
|
n = (n << 3) | (r & 0x7);
|
|
|
|
- if (!fd || read(fd, &r, sizeof(long)) != -1)
|
|
+ if (fd == -1 || read(fd, &r, r_size) != r_size)
|
|
r = rand();
|
|
r = r ^ (r >> 8);
|
|
r = r ^ (r >> 5);
|
|
@@ -2002,7 +2002,7 @@ acl_dbg_status_to_text(int dbg_status)
|
|
"AuthMethod negotiation failed",
|
|
"AuthMethod negotiated to none",
|
|
"CHAP algorithm negotiation failed",
|
|
- "CHAP challange reflected",
|
|
+ "CHAP challenge reflected",
|
|
"Local password same as remote",
|
|
"Local password not set",
|
|
"CHAP identifier bad",
|
|
diff --git a/usr/be2iscsi.c b/usr/be2iscsi.c
|
|
index ce8b719..8a346a5 100644
|
|
--- a/usr/be2iscsi.c
|
|
+++ b/usr/be2iscsi.c
|
|
@@ -19,7 +19,6 @@
|
|
void be2iscsi_create_conn(struct iscsi_conn *conn)
|
|
{
|
|
struct iscsi_session *session = conn->session;
|
|
- conn_rec_t *conn_rec = &session->nrec.conn[conn->id];
|
|
|
|
if (conn->max_recv_dlength > 65536)
|
|
conn->max_recv_dlength = 65536;
|
|
@@ -33,10 +32,6 @@ void be2iscsi_create_conn(struct iscsi_conn *conn)
|
|
if (conn->max_xmit_dlength > 65536)
|
|
conn->max_xmit_dlength = 65536;
|
|
|
|
- if (!conn_rec->iscsi.MaxXmitDataSegmentLength ||
|
|
- conn_rec->iscsi.MaxXmitDataSegmentLength > 65536)
|
|
- conn_rec->iscsi.MaxXmitDataSegmentLength = 65536;
|
|
-
|
|
session->erl = 0;
|
|
session->initial_r2t_en = 1;
|
|
}
|
|
diff --git a/usr/config.h b/usr/config.h
|
|
index 998caff..fd31a54 100644
|
|
--- a/usr/config.h
|
|
+++ b/usr/config.h
|
|
@@ -201,6 +201,9 @@ typedef struct session_rec {
|
|
* allowed to be initiated on this record
|
|
*/
|
|
unsigned char multiple;
|
|
+ char boot_root[BOOT_NAME_MAXLEN];
|
|
+ char boot_nic[BOOT_NAME_MAXLEN];
|
|
+ char boot_target[BOOT_NAME_MAXLEN];
|
|
} session_rec_t;
|
|
|
|
#define ISCSI_TRANSPORT_NAME_MAXLEN 16
|
|
@@ -229,11 +232,59 @@ typedef struct iface_rec {
|
|
* 1 = enable */
|
|
uint16_t mtu;
|
|
uint16_t port;
|
|
+ char delayed_ack[ISCSI_MAX_STR_LEN];
|
|
+ char nagle[ISCSI_MAX_STR_LEN];
|
|
+ char tcp_wsf_state[ISCSI_MAX_STR_LEN];
|
|
+ uint8_t tcp_wsf;
|
|
+ uint8_t tcp_timer_scale;
|
|
+ char tcp_timestamp[ISCSI_MAX_STR_LEN];
|
|
+ char dhcp_dns[ISCSI_MAX_STR_LEN];
|
|
+ char dhcp_slp_da[ISCSI_MAX_STR_LEN];
|
|
+ char tos_state[ISCSI_MAX_STR_LEN];
|
|
+ uint8_t tos;
|
|
+ char gratuitous_arp[ISCSI_MAX_STR_LEN];
|
|
+ char dhcp_alt_client_id_state[ISCSI_MAX_STR_LEN];
|
|
+ char dhcp_alt_client_id[ISCSI_MAX_STR_LEN];
|
|
+ char dhcp_req_vendor_id_state[ISCSI_MAX_STR_LEN];
|
|
+ char dhcp_vendor_id_state[ISCSI_MAX_STR_LEN];
|
|
+ char dhcp_vendor_id[ISCSI_MAX_STR_LEN];
|
|
+ char dhcp_learn_iqn[ISCSI_MAX_STR_LEN];
|
|
+ char fragmentation[ISCSI_MAX_STR_LEN];
|
|
+ char incoming_forwarding[ISCSI_MAX_STR_LEN];
|
|
+ uint8_t ttl;
|
|
+ char gratuitous_neighbor_adv[ISCSI_MAX_STR_LEN];
|
|
+ char redirect[ISCSI_MAX_STR_LEN];
|
|
+ char mld[ISCSI_MAX_STR_LEN];
|
|
+ uint32_t flow_label;
|
|
+ uint32_t traffic_class;
|
|
+ uint8_t hop_limit;
|
|
+ uint32_t nd_reachable_tmo;
|
|
+ uint32_t nd_rexmit_time;
|
|
+ uint32_t nd_stale_tmo;
|
|
+ uint8_t dup_addr_detect_cnt;
|
|
+ uint32_t router_adv_link_mtu;
|
|
+ uint16_t def_task_mgmt_tmo;
|
|
+ char header_digest[ISCSI_MAX_STR_LEN];
|
|
+ char data_digest[ISCSI_MAX_STR_LEN];
|
|
+ char immediate_data[ISCSI_MAX_STR_LEN];
|
|
+ char initial_r2t[ISCSI_MAX_STR_LEN];
|
|
+ char data_seq_inorder[ISCSI_MAX_STR_LEN];
|
|
+ char data_pdu_inorder[ISCSI_MAX_STR_LEN];
|
|
+ uint8_t erl;
|
|
+ uint32_t max_recv_dlength;
|
|
+ uint32_t first_burst_len;
|
|
+ uint16_t max_out_r2t;
|
|
+ uint32_t max_burst_len;
|
|
+ char chap_auth[ISCSI_MAX_STR_LEN];
|
|
+ char bidi_chap[ISCSI_MAX_STR_LEN];
|
|
+ char strict_login_comp[ISCSI_MAX_STR_LEN];
|
|
+ char discovery_auth[ISCSI_MAX_STR_LEN];
|
|
+ char discovery_logout[ISCSI_MAX_STR_LEN];
|
|
char port_state[ISCSI_MAX_STR_LEN];
|
|
char port_speed[ISCSI_MAX_STR_LEN];
|
|
/*
|
|
* TODO: we may have to make this bigger and interconnect
|
|
- * specific for infinniband
|
|
+ * specific for infiniband
|
|
*/
|
|
char hwaddress[ISCSI_HWADDRESS_BUF_SIZE];
|
|
char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN];
|
|
diff --git a/usr/discovery.c b/usr/discovery.c
|
|
index afce6c0..38968ca 100644
|
|
--- a/usr/discovery.c
|
|
+++ b/usr/discovery.c
|
|
@@ -111,7 +111,7 @@ int discovery_isns_set_servername(char *address, int port)
|
|
int len;
|
|
|
|
if (port > USHRT_MAX) {
|
|
- log_error("Invalid port %d\n", port);
|
|
+ log_error("Invalid port %d", port);
|
|
return ISCSI_ERR_INVAL;
|
|
}
|
|
|
|
@@ -193,7 +193,7 @@ int discovery_isns_query(struct discovery_rec *drec, const char *iname,
|
|
status = isns_query_response_get_objects(qry, &objects);
|
|
if (status) {
|
|
log_error("Unable to extract object list from query "
|
|
- "response: %s\n", isns_strerror(status));
|
|
+ "response: %s", isns_strerror(status));
|
|
rc = ISCSI_ERR;
|
|
goto free_query;
|
|
}
|
|
@@ -391,7 +391,7 @@ int discovery_fw(void *data, struct iface_rec *iface,
|
|
rc = fw_get_targets(&targets);
|
|
if (rc) {
|
|
log_error("Could not get list of targets from firmware. "
|
|
- "(err %d)\n", rc);
|
|
+ "(err %d)", rc);
|
|
return rc;
|
|
}
|
|
if (list_empty(&targets))
|
|
@@ -406,7 +406,7 @@ int discovery_fw(void *data, struct iface_rec *iface,
|
|
rec = idbm_create_rec_from_boot_context(bcontext);
|
|
if (!rec) {
|
|
log_error("Could not convert firmware info to "
|
|
- "node record.\n");
|
|
+ "node record.");
|
|
rc = ISCSI_ERR_NOMEM;
|
|
goto free_targets;
|
|
}
|
|
@@ -456,7 +456,7 @@ int discovery_offload_sendtargets(int host_no, int do_login,
|
|
*/
|
|
rc = iscsid_exec_req(&req, &rsp, 1);
|
|
if (rc) {
|
|
- log_error("Could not offload sendtargets to %s.\n",
|
|
+ log_error("Could not offload sendtargets to %s.",
|
|
drec->address);
|
|
iscsi_err_print_msg(rc);
|
|
return rc;
|
|
@@ -817,7 +817,7 @@ iscsi_alloc_session(struct iscsi_sendtargets_config *config,
|
|
session->t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
|
|
if (!session->t) {
|
|
log_error("iSCSI driver %s is not loaded. Load the module "
|
|
- "then retry the command.\n", iface->transport_name);
|
|
+ "then retry the command.", iface->transport_name);
|
|
*rc = ISCSI_ERR_TRANS_NOT_FOUND;
|
|
goto fail;
|
|
}
|
|
@@ -1036,7 +1036,7 @@ static void iscsi_destroy_session(struct iscsi_session *session)
|
|
rc = ipc->stop_conn(session->t->handle, session->id,
|
|
conn->id, STOP_CONN_TERM);
|
|
if (rc) {
|
|
- log_error("Could not stop conn %d:%d cleanly (err %d)\n",
|
|
+ log_error("Could not stop conn %d:%d cleanly (err %d)",
|
|
session->id, conn->id, rc);
|
|
goto done;
|
|
}
|
|
@@ -1091,7 +1091,7 @@ static int iscsi_create_leading_conn(struct iscsi_session *session)
|
|
*/
|
|
conn->socket_fd = ipc->ctldev_open();
|
|
if (conn->socket_fd < 0) {
|
|
- log_error("Could not open netlink interface (err %d)\n",
|
|
+ log_error("Could not open netlink interface (err %d)",
|
|
errno);
|
|
return ISCSI_ERR_INTERNAL;
|
|
}
|
|
@@ -1109,14 +1109,15 @@ static int iscsi_create_leading_conn(struct iscsi_session *session)
|
|
|
|
rc = iscsi_host_set_net_params(iface, session);
|
|
if (rc) {
|
|
- log_error("Could not set host net params (err %d)\n",
|
|
+ log_error("Could not set host net params (err %d)",
|
|
rc);
|
|
- rc = ISCSI_ERR_INTERNAL;
|
|
+ if (rc != ISCSI_ERR_AGAIN)
|
|
+ rc = ISCSI_ERR_INTERNAL;
|
|
goto close_ipc;
|
|
}
|
|
|
|
/* create interconnect endpoint */
|
|
- log_debug(2, "%s discovery ep connect\n", __FUNCTION__);
|
|
+ log_debug(2, "%s discovery ep connect", __FUNCTION__);
|
|
rc = t->template->ep_connect(conn, 1);
|
|
if (rc < 0) {
|
|
rc = ISCSI_ERR_TRANS;
|
|
@@ -1139,21 +1140,21 @@ static int iscsi_create_leading_conn(struct iscsi_session *session)
|
|
break;
|
|
} while (1);
|
|
|
|
- log_debug(2, "%s discovery create session\n", __FUNCTION__);
|
|
+ log_debug(2, "%s discovery create session", __FUNCTION__);
|
|
/* create kernel structs */
|
|
rc = ipc->create_session(session->t->handle,
|
|
conn->transport_ep_handle, 1, 32, 1,
|
|
&session->id, &host_no);
|
|
if (rc) {
|
|
- log_error("Could not create kernel session (err %d).\n", rc);
|
|
+ log_error("Could not create kernel session (err %d).", rc);
|
|
rc = ISCSI_ERR_INTERNAL;
|
|
goto disconnect;
|
|
}
|
|
- log_debug(2, "%s discovery created session %u\n", __FUNCTION__,
|
|
+ log_debug(2, "%s discovery created session %u", __FUNCTION__,
|
|
session->id);
|
|
session->isid[3] = session->id;
|
|
|
|
- log_debug(2, "%s discovery create conn\n", __FUNCTION__);
|
|
+ log_debug(2, "%s discovery create conn", __FUNCTION__);
|
|
rc = ipc->create_conn(t->handle, session->id, conn->id, &conn->id);
|
|
if (rc) {
|
|
log_error("Could not create connection (err %d)", rc);
|
|
@@ -1161,7 +1162,7 @@ static int iscsi_create_leading_conn(struct iscsi_session *session)
|
|
goto disconnect;
|
|
}
|
|
|
|
- log_debug(2, "%s discovery bind conn\n", __FUNCTION__);
|
|
+ log_debug(2, "%s discovery bind conn", __FUNCTION__);
|
|
if (ipc->bind_conn(t->handle, session->id, conn->id,
|
|
conn->transport_ep_handle, (conn->id == 0), &rc) ||
|
|
rc) {
|
|
@@ -1207,7 +1208,7 @@ close_ipc:
|
|
static struct iscsi_ev_context *
|
|
iscsi_ev_context_get(struct iscsi_conn *conn, int ev_size)
|
|
{
|
|
- log_debug(2, "%s: ev_size %d\n", __FUNCTION__, ev_size);
|
|
+ log_debug(2, "%s: ev_size %d", __FUNCTION__, ev_size);
|
|
|
|
ipc_ev_context.data = calloc(1, ev_size);
|
|
if (!ipc_ev_context.data)
|
|
@@ -1403,6 +1404,17 @@ redirect_reconnect:
|
|
iscsi_copy_operational_params(&session->conn[0], &config->session_conf,
|
|
&config->conn_conf);
|
|
|
|
+ if (t->caps & CAP_TEXT_NEGO) {
|
|
+ log_debug(2, "%s discovery set params", __FUNCTION__);
|
|
+ rc = iscsi_session_set_params(conn);
|
|
+ if (rc) {
|
|
+ log_error("Could not set iscsi params for conn %d:%d "
|
|
+ "(err %d)", session->id, conn->id, rc);
|
|
+ rc = ISCSI_ERR_INTERNAL;
|
|
+ goto login_failed;
|
|
+ }
|
|
+ }
|
|
+
|
|
if ((session->t->caps & CAP_LOGIN_OFFLOAD))
|
|
goto start_conn;
|
|
|
|
@@ -1477,7 +1489,7 @@ redirect_reconnect:
|
|
case ISCSI_LOGIN_STATUS_AUTH_FAILED:
|
|
case ISCSI_LOGIN_STATUS_TGT_FORBIDDEN:
|
|
log_error("discovery login to %s rejected: "
|
|
- "initiator failed authorization\n",
|
|
+ "initiator failed authorization",
|
|
conn->host);
|
|
rc = ISCSI_ERR_LOGIN_AUTH_FAILED;
|
|
goto login_failed;
|
|
@@ -1509,16 +1521,16 @@ redirect_reconnect:
|
|
return 0;
|
|
|
|
start_conn:
|
|
- log_debug(2, "%s discovery set params\n", __FUNCTION__);
|
|
- rc = iscsi_session_set_params(conn);
|
|
+ log_debug(2, "%s discovery set neg params", __FUNCTION__);
|
|
+ rc = iscsi_session_set_neg_params(conn);
|
|
if (rc) {
|
|
log_error("Could not set iscsi params for conn %d:%d (err "
|
|
- "%d)\n", session->id, conn->id, rc);
|
|
+ "%d)", session->id, conn->id, rc);
|
|
rc = ISCSI_ERR_INTERNAL;
|
|
goto login_failed;
|
|
}
|
|
|
|
- log_debug(2, "%s discovery start conn\n", __FUNCTION__);
|
|
+ log_debug(2, "%s discovery start conn", __FUNCTION__);
|
|
if (ipc->start_conn(t->handle, session->id, conn->id, &rc) || rc) {
|
|
log_error("Cannot start conn %d:%d (err %d)",
|
|
session->id, conn->id, rc);
|
|
diff --git a/usr/discoveryd.c b/usr/discoveryd.c
|
|
index de080ea..1e14977 100644
|
|
--- a/usr/discoveryd.c
|
|
+++ b/usr/discoveryd.c
|
|
@@ -211,7 +211,7 @@ static void fork_disc(const char *def_iname, struct discovery_rec *drec,
|
|
exit(0);
|
|
} else if (pid < 0)
|
|
log_error("Fork failed (err %d - %s). Will not be able "
|
|
- "to perform discovery to %s.\n",
|
|
+ "to perform discovery to %s.",
|
|
errno, strerror(errno), drec->address);
|
|
else {
|
|
shutdown_callback(pid);
|
|
@@ -254,7 +254,7 @@ static int isns_build_objs(isns_portal_info_t *portal_info,
|
|
nportals = isns_enumerate_portals(iflist, nportals);
|
|
if (nportals == 0) {
|
|
log_error("Unable to enumerate portals - "
|
|
- "no usable interfaces found\n");
|
|
+ "no usable interfaces found");
|
|
free(iflist);
|
|
return ISCSI_ERR_NO_OBJS_FOUND;
|
|
}
|
|
@@ -557,7 +557,7 @@ static int isns_setup_registration_refresh(isns_simple_t *rsp, int poll_inval)
|
|
status = isns_query_response_get_objects(rsp, &objs);
|
|
if (status) {
|
|
log_error("Unable to extract object list from "
|
|
- "registration response: %s\n",
|
|
+ "registration response: %s",
|
|
isns_strerror(status));
|
|
return ISCSI_ERR;
|
|
}
|
|
@@ -693,7 +693,7 @@ static int isns_register_objs(isns_client_t *clnt, isns_object_list_t *objs,
|
|
|
|
status = isns_simple_call(clnt->ic_socket, ®);
|
|
if (status != ISNS_SUCCESS) {
|
|
- log_error("SCN registration for node %s failed: %s\n",
|
|
+ log_error("SCN registration for node %s failed: %s",
|
|
isns_source_name(node->source),
|
|
isns_strerror(status));
|
|
/*
|
|
@@ -907,7 +907,7 @@ static int isns_scn_recv(isns_server_t *svr, isns_socket_t *svr_sock,
|
|
|
|
function = isns_message_function(msg);
|
|
if (function != ISNS_STATE_CHANGE_NOTIFICATION) {
|
|
- log_warning("Discarding unexpected %s message\n",
|
|
+ log_warning("Discarding unexpected %s message",
|
|
isns_function_name(function));
|
|
isns_message_release(msg);
|
|
continue;
|
|
diff --git a/usr/event_poll.c b/usr/event_poll.c
|
|
index f36fec1..209ee02 100644
|
|
--- a/usr/event_poll.c
|
|
+++ b/usr/event_poll.c
|
|
@@ -26,6 +26,8 @@
|
|
#include <sys/poll.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
+#include <sys/signalfd.h>
|
|
+#include <unistd.h>
|
|
|
|
#include "mgmt_ipc.h"
|
|
#include "iscsi_ipc.h"
|
|
@@ -37,7 +39,9 @@
|
|
#include "initiator.h"
|
|
#include "iscsi_err.h"
|
|
|
|
-static int reap_count;
|
|
+static unsigned int reap_count;
|
|
+
|
|
+#define REAP_WAKEUP 1000 /* in millisecs */
|
|
|
|
void reap_inc(void)
|
|
{
|
|
@@ -50,7 +54,7 @@ void reap_proc(void)
|
|
|
|
/*
|
|
* We don't really need reap_count, but calling wait() all the
|
|
- * time seems execessive.
|
|
+ * time seems excessive.
|
|
*/
|
|
max_reaps = reap_count;
|
|
for (i = 0; i < max_reaps; i++) {
|
|
@@ -80,7 +84,7 @@ int shutdown_callback(pid_t pid)
|
|
|
|
INIT_LIST_HEAD(&cb->list);
|
|
cb->pid = pid;
|
|
- log_debug(1, "adding %d for shutdown cb\n", pid);
|
|
+ log_debug(1, "adding %d for shutdown cb", pid);
|
|
list_add_tail(&cb->list, &shutdown_callbacks);
|
|
return 0;
|
|
}
|
|
@@ -90,7 +94,7 @@ static void shutdown_notify_pids(void)
|
|
struct shutdown_callback *cb;
|
|
|
|
list_for_each_entry(cb, &shutdown_callbacks, list) {
|
|
- log_debug(1, "Killing %d\n", cb->pid);
|
|
+ log_debug(1, "Killing %d", cb->pid);
|
|
kill(cb->pid, SIGTERM);
|
|
}
|
|
}
|
|
@@ -105,7 +109,7 @@ static int shutdown_wait_pids(void)
|
|
* sign that it is gone.
|
|
*/
|
|
if (waitpid(cb->pid, NULL, WNOHANG)) {
|
|
- log_debug(1, "%d done\n", cb->pid);
|
|
+ log_debug(1, "%d done", cb->pid);
|
|
list_del(&cb->list);
|
|
free(cb);
|
|
}
|
|
@@ -116,12 +120,12 @@ static int shutdown_wait_pids(void)
|
|
|
|
#define POLL_CTRL 0
|
|
#define POLL_IPC 1
|
|
-#define POLL_MAX 2
|
|
+#define POLL_ALARM 2
|
|
+#define POLL_MAX 3
|
|
|
|
static int event_loop_stop;
|
|
static queue_task_t *shutdown_qtask;
|
|
|
|
-
|
|
void event_loop_exit(queue_task_t *qtask)
|
|
{
|
|
shutdown_qtask = qtask;
|
|
@@ -132,11 +136,26 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd)
|
|
{
|
|
struct pollfd poll_array[POLL_MAX];
|
|
int res, has_shutdown_children = 0;
|
|
+ sigset_t sigset;
|
|
+ int sig_fd;
|
|
+
|
|
+ /* Mask off SIGALRM so we can recv it via signalfd */
|
|
+ sigemptyset(&sigset);
|
|
+ sigaddset(&sigset, SIGALRM);
|
|
+ sigprocmask(SIG_SETMASK, &sigset, NULL);
|
|
+
|
|
+ sig_fd = signalfd(-1, &sigset, SFD_NONBLOCK);
|
|
+ if (sig_fd == -1) {
|
|
+ log_error("signalfd failed: %m");
|
|
+ return;
|
|
+ }
|
|
|
|
poll_array[POLL_CTRL].fd = control_fd;
|
|
poll_array[POLL_CTRL].events = POLLIN;
|
|
poll_array[POLL_IPC].fd = mgmt_ipc_fd;
|
|
poll_array[POLL_IPC].events = POLLIN;
|
|
+ poll_array[POLL_ALARM].fd = sig_fd;
|
|
+ poll_array[POLL_ALARM].events = POLLIN;
|
|
|
|
event_loop_stop = 0;
|
|
while (1) {
|
|
@@ -149,7 +168,11 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd)
|
|
break;
|
|
}
|
|
|
|
- res = poll(poll_array, POLL_MAX, ACTOR_RESOLUTION);
|
|
+ /* Runs actors and may set alarm for future actors */
|
|
+ actor_poll();
|
|
+
|
|
+ res = poll(poll_array, POLL_MAX, reap_count ? REAP_WAKEUP : -1);
|
|
+
|
|
if (res > 0) {
|
|
log_debug(6, "poll result %d", res);
|
|
if (poll_array[POLL_CTRL].revents)
|
|
@@ -157,6 +180,18 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd)
|
|
|
|
if (poll_array[POLL_IPC].revents)
|
|
mgmt_ipc_handle(mgmt_ipc_fd);
|
|
+
|
|
+ if (poll_array[POLL_ALARM].revents) {
|
|
+ struct signalfd_siginfo si;
|
|
+
|
|
+ if (read(sig_fd, &si, sizeof(si)) == -1) {
|
|
+ log_error("got sigfd read() error, errno (%d), "
|
|
+ "exiting", errno);
|
|
+ break;
|
|
+ } else {
|
|
+ log_debug(1, "Poll was woken by an alarm");
|
|
+ }
|
|
+ }
|
|
} else if (res < 0) {
|
|
if (errno == EINTR) {
|
|
log_debug(1, "event_loop interrupted");
|
|
@@ -165,15 +200,20 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd)
|
|
"exiting", res, errno);
|
|
break;
|
|
}
|
|
- } else
|
|
- actor_poll();
|
|
+ }
|
|
+
|
|
reap_proc();
|
|
+
|
|
/*
|
|
* flush sysfs cache since kernel objs may
|
|
* have changed as a result of handling op
|
|
*/
|
|
sysfs_cleanup();
|
|
}
|
|
+
|
|
if (shutdown_qtask)
|
|
mgmt_ipc_write_rsp(shutdown_qtask, ISCSI_SUCCESS);
|
|
+
|
|
+ close(sig_fd);
|
|
+ sigprocmask(SIG_UNBLOCK, &sigset, NULL);
|
|
}
|
|
diff --git a/usr/flashnode.c b/usr/flashnode.c
|
|
new file mode 100644
|
|
index 0000000..fe5ab57
|
|
--- /dev/null
|
|
+++ b/usr/flashnode.c
|
|
@@ -0,0 +1,615 @@
|
|
+/*
|
|
+ * iSCSI flashnode helpers
|
|
+ *
|
|
+ * Copyright (C) 2013 QLogic Corporation.
|
|
+ * Maintained by open-iscsi@googlegroups.com
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published
|
|
+ * by the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful, but
|
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * General Public License for more details.
|
|
+ *
|
|
+ * See the file COPYING included with this distribution for more details.
|
|
+ */
|
|
+#include <errno.h>
|
|
+#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <unistd.h>
|
|
+#include <string.h>
|
|
+#include <sys/stat.h>
|
|
+#include <arpa/inet.h>
|
|
+
|
|
+#include "log.h"
|
|
+#include "idbm.h"
|
|
+#include "iscsi_util.h"
|
|
+#include "transport.h"
|
|
+#include "iscsi_sysfs.h"
|
|
+#include "list.h"
|
|
+#include "sysdeps.h"
|
|
+#include "idbm_fields.h"
|
|
+#include "iscsi_err.h"
|
|
+#include "iscsi_ipc.h"
|
|
+#include "iscsi_netlink.h"
|
|
+#include "flashnode.h"
|
|
+#include "iscsi_settings.h"
|
|
+
|
|
+char key[NAME_MAXVAL];
|
|
+
|
|
+char *to_key(const char *fmt)
|
|
+{
|
|
+ int i = 0;
|
|
+ memset(key, 0, sizeof(key));
|
|
+ sprintf(key, fmt, i);
|
|
+ return key;
|
|
+}
|
|
+
|
|
+int flashnode_info_print_flat(void *data, struct flashnode_rec *fnode,
|
|
+ uint32_t host_no, uint32_t flashnode_idx)
|
|
+{
|
|
+ printf("%s: [%d] ", fnode->transport_name, flashnode_idx);
|
|
+ if (!strlen((char *)fnode->conn[0].ipaddress))
|
|
+ printf("%s:", UNKNOWN_VALUE);
|
|
+ else if (strchr((char *)fnode->conn[0].ipaddress, '.'))
|
|
+ printf("%s:", fnode->conn[0].ipaddress);
|
|
+ else
|
|
+ printf("[%s]:", fnode->conn[0].ipaddress);
|
|
+
|
|
+ if (!fnode->conn[0].port)
|
|
+ printf("%s,", UNKNOWN_VALUE);
|
|
+ else
|
|
+ printf("%u,", fnode->conn[0].port);
|
|
+
|
|
+ printf("%u ", fnode->sess.tpgt);
|
|
+
|
|
+ if (!strlen(fnode->sess.targetname))
|
|
+ printf("%s\n", UNKNOWN_VALUE);
|
|
+ else
|
|
+ printf("%s\n", fnode->sess.targetname);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int flashnode_fill_isid(struct flashnode_rec *fnode, struct iovec *iov)
|
|
+{
|
|
+ struct iscsi_flashnode_param_info *fnode_param;
|
|
+ struct nlattr *attr;
|
|
+ int len;
|
|
+ uint8_t isid[6];
|
|
+
|
|
+ len = sizeof(struct iscsi_flashnode_param_info) + 6;
|
|
+ iov->iov_base = iscsi_nla_alloc(ISCSI_FLASHNODE_ISID, len);
|
|
+ if (!iov->iov_base)
|
|
+ return 1;
|
|
+
|
|
+ attr = iov->iov_base;
|
|
+ iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
+
|
|
+ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
|
|
+ fnode_param->param = ISCSI_FLASHNODE_ISID;
|
|
+ fnode_param->len = 6;
|
|
+
|
|
+ sscanf(fnode->sess.isid, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
|
|
+ &isid[0], &isid[1], &isid[2], &isid[3], &isid[4], &isid[5]);
|
|
+
|
|
+ memcpy(fnode_param->value, isid, fnode_param->len);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int flashnode_fill_ipv4_addr(struct flashnode_rec *fnode,
|
|
+ struct iovec *iov, int param_type)
|
|
+{
|
|
+ struct iscsi_flashnode_param_info *fnode_param;
|
|
+ struct nlattr *attr;
|
|
+ int len;
|
|
+ int rc;
|
|
+
|
|
+ len = sizeof(struct iscsi_flashnode_param_info) + 4;
|
|
+ iov->iov_base = iscsi_nla_alloc(param_type, len);
|
|
+ if (!iov->iov_base)
|
|
+ return 1;
|
|
+
|
|
+ attr = iov->iov_base;
|
|
+ iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
+
|
|
+ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
|
|
+ fnode_param->param = param_type;
|
|
+ fnode_param->len = 4;
|
|
+
|
|
+ switch (param_type) {
|
|
+ case ISCSI_FLASHNODE_IPADDR:
|
|
+ rc = inet_pton(AF_INET, (char *)fnode->conn[0].ipaddress,
|
|
+ fnode_param->value);
|
|
+ break;
|
|
+ case ISCSI_FLASHNODE_REDIRECT_IPADDR:
|
|
+ rc = inet_pton(AF_INET, (char *)fnode->conn[0].redirect_ipaddr,
|
|
+ fnode_param->value);
|
|
+ break;
|
|
+ default:
|
|
+ goto free;
|
|
+ }
|
|
+
|
|
+ if (rc <= 0)
|
|
+ goto free;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+free:
|
|
+ free(iov->iov_base);
|
|
+ iov->iov_base = NULL;
|
|
+ iov->iov_len = 0;
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int flashnode_fill_ipv6_addr(struct flashnode_rec *fnode,
|
|
+ struct iovec *iov, int param_type)
|
|
+{
|
|
+ struct iscsi_flashnode_param_info *fnode_param;
|
|
+ struct nlattr *attr;
|
|
+ int len;
|
|
+ int rc;
|
|
+
|
|
+ len = sizeof(struct iscsi_flashnode_param_info) + 16;
|
|
+ iov->iov_base = iscsi_nla_alloc(param_type, len);
|
|
+ if (!iov->iov_base)
|
|
+ return 1;
|
|
+
|
|
+ attr = iov->iov_base;
|
|
+ iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
+
|
|
+ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
|
|
+ fnode_param->param = param_type;
|
|
+ fnode_param->len = 16;
|
|
+
|
|
+ switch (param_type) {
|
|
+ case ISCSI_FLASHNODE_IPADDR:
|
|
+ rc = inet_pton(AF_INET6, (char *)fnode->conn[0].ipaddress,
|
|
+ fnode_param->value);
|
|
+ break;
|
|
+ case ISCSI_FLASHNODE_REDIRECT_IPADDR:
|
|
+ rc = inet_pton(AF_INET6, (char *)fnode->conn[0].redirect_ipaddr,
|
|
+ fnode_param->value);
|
|
+ break;
|
|
+ case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
|
|
+ rc = inet_pton(AF_INET6, (char *)fnode->conn[0].link_local_ipv6,
|
|
+ fnode_param->value);
|
|
+ break;
|
|
+ default:
|
|
+ goto free;
|
|
+ }
|
|
+
|
|
+ if (rc <= 0)
|
|
+ goto free;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+free:
|
|
+ free(iov->iov_base);
|
|
+ iov->iov_base = NULL;
|
|
+ iov->iov_len = 0;
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int flashnode_fill_ipaddr(struct flashnode_rec *fnode, struct iovec *iov,
|
|
+ int param_type)
|
|
+{
|
|
+ int rc = 0;
|
|
+
|
|
+ if (!strncmp(fnode->sess.portal_type, "ipv4", 4))
|
|
+ rc = flashnode_fill_ipv4_addr(fnode, iov, param_type);
|
|
+ else
|
|
+ rc = flashnode_fill_ipv6_addr(fnode, iov, param_type);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int flashnode_fill_uint8(struct flashnode_rec *fnode, struct iovec *iov,
|
|
+ int param_type, uint8_t val)
|
|
+{
|
|
+ struct iscsi_flashnode_param_info *fnode_param;
|
|
+ struct nlattr *attr;
|
|
+ int len;
|
|
+
|
|
+ len = sizeof(struct iscsi_flashnode_param_info) + 1;
|
|
+ iov->iov_base = iscsi_nla_alloc(param_type, len);
|
|
+ if (!iov->iov_base)
|
|
+ return 1;
|
|
+
|
|
+ attr = iov->iov_base;
|
|
+ iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
+
|
|
+ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
|
|
+ fnode_param->param = param_type;
|
|
+ fnode_param->len = 1;
|
|
+ fnode_param->value[0] = val;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int flashnode_fill_uint16(struct flashnode_rec *fnode, struct iovec *iov,
|
|
+ int param_type, uint16_t val)
|
|
+{
|
|
+ struct iscsi_flashnode_param_info *fnode_param;
|
|
+ struct nlattr *attr;
|
|
+ int len;
|
|
+
|
|
+ len = sizeof(struct iscsi_flashnode_param_info) + 2;
|
|
+ iov->iov_base = iscsi_nla_alloc(param_type, len);
|
|
+ if (!iov->iov_base)
|
|
+ return 1;
|
|
+
|
|
+ attr = iov->iov_base;
|
|
+ iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
+
|
|
+ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
|
|
+ fnode_param->param = param_type;
|
|
+ fnode_param->len = 2;
|
|
+ memcpy(fnode_param->value, &val, fnode_param->len);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int flashnode_fill_uint32(struct flashnode_rec *fnode, struct iovec *iov,
|
|
+ int param_type, uint32_t val)
|
|
+{
|
|
+ struct iscsi_flashnode_param_info *fnode_param;
|
|
+ struct nlattr *attr;
|
|
+ int len;
|
|
+
|
|
+ len = sizeof(struct iscsi_flashnode_param_info) + 4;
|
|
+ iov->iov_base = iscsi_nla_alloc(param_type, len);
|
|
+ if (!iov->iov_base)
|
|
+ return 1;
|
|
+
|
|
+ attr = iov->iov_base;
|
|
+ iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
+
|
|
+ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
|
|
+ fnode_param->param = param_type;
|
|
+ fnode_param->len = 4;
|
|
+ memcpy(fnode_param->value, &val, fnode_param->len);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int flashnode_fill_str(struct flashnode_rec *fnode, struct iovec *iov,
|
|
+ int param_type, char *buf, int buflen)
|
|
+{
|
|
+ struct iscsi_flashnode_param_info *fnode_param;
|
|
+ struct nlattr *attr;
|
|
+ int len;
|
|
+
|
|
+ len = sizeof(struct iscsi_flashnode_param_info) + buflen;
|
|
+ iov->iov_base = iscsi_nla_alloc(param_type, len);
|
|
+ if (!iov->iov_base)
|
|
+ return 1;
|
|
+
|
|
+ attr = iov->iov_base;
|
|
+ iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
+
|
|
+ fnode_param = (struct iscsi_flashnode_param_info *)ISCSI_NLA_DATA(attr);
|
|
+ fnode_param->param = param_type;
|
|
+ fnode_param->len = buflen;
|
|
+ memcpy(fnode_param->value, buf, fnode_param->len);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int flashnode_build_config(struct list_head *params,
|
|
+ struct flashnode_rec *fnode, struct iovec *iovs)
|
|
+{
|
|
+ struct user_param *param;
|
|
+ struct iovec *iov = NULL;
|
|
+ int count = 0;
|
|
+ int port = 3260;
|
|
+
|
|
+ /* start at 2, because 0 is for nlmsghdr and 1 for event */
|
|
+ iov = iovs + 2;
|
|
+
|
|
+ list_for_each_entry(param, params, list) {
|
|
+ if (!strcmp(param->name, FLASHNODE_SESS_AUTO_SND_TGT_DISABLE)) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE,
|
|
+ fnode->sess.auto_snd_tgt_disable))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ FLASHNODE_SESS_DISCOVERY_SESS)) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_DISCOVERY_SESS,
|
|
+ fnode->sess.discovery_session))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_ENTRY_EN)) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_ENTRY_EN,
|
|
+ fnode->sess.entry_enable))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_IMM_DATA_EN)) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_IMM_DATA_EN,
|
|
+ fnode->sess.immediate_data))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ FLASHNODE_SESS_INITIAL_R2T_EN)) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_INITIAL_R2T_EN,
|
|
+ fnode->sess.initial_r2t))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ FLASHNODE_SESS_DATASEQ_INORDER)) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_DATASEQ_INORDER,
|
|
+ fnode->sess.data_seq_in_order))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_PDU_INORDER)) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_PDU_INORDER,
|
|
+ fnode->sess.data_pdu_in_order))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_CHAP_AUTH_EN)) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_CHAP_AUTH_EN,
|
|
+ fnode->sess.chap_auth_en))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ FLASHNODE_SESS_DISCOVERY_LOGOUT_EN)) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN,
|
|
+ fnode->sess.discovery_logout_en))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_BIDI_CHAP_EN )) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_BIDI_CHAP_EN,
|
|
+ fnode->sess.bidi_chap_en))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ FLASHNODE_SESS_DISCOVERY_AUTH_OPTIONAL)) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL,
|
|
+ fnode->sess.discovery_auth_optional))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_ERL)) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_ERL,
|
|
+ fnode->sess.erl))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ FLASHNODE_SESS_DEF_TIME2WAIT)) {
|
|
+ if (!flashnode_fill_uint16(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_DEF_TIME2WAIT,
|
|
+ fnode->sess.def_time2wait))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ FLASHNODE_SESS_DEF_TIME2RETAIN)) {
|
|
+ if (!flashnode_fill_uint16(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_DEF_TIME2RETAIN,
|
|
+ fnode->sess.def_time2retain))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_MAX_R2T)) {
|
|
+ if (!flashnode_fill_uint16(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_MAX_R2T,
|
|
+ fnode->sess.max_outstanding_r2t))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_TSID)) {
|
|
+ if (!flashnode_fill_uint16(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_TSID,
|
|
+ fnode->sess.tsid))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_MAX_BURST)) {
|
|
+ if (!flashnode_fill_uint32(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_MAX_BURST,
|
|
+ fnode->sess.max_burst_len))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ FLASHNODE_SESS_DEF_TASKMGMT_TMO)) {
|
|
+ if (!flashnode_fill_uint16(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_DEF_TASKMGMT_TMO,
|
|
+ fnode->sess.def_taskmgmt_tmo))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_NAME)) {
|
|
+ if (!flashnode_fill_str(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_NAME,
|
|
+ fnode->sess.targetname,
|
|
+ sizeof(fnode->sess.targetname)))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_FIRST_BURST)) {
|
|
+ if (!flashnode_fill_uint32(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_FIRST_BURST,
|
|
+ fnode->sess.first_burst_len))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_ISID)) {
|
|
+ if (!flashnode_fill_isid(fnode, &iov[count]))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_ALIAS)) {
|
|
+ if (!flashnode_fill_str(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_ALIAS,
|
|
+ fnode->sess.targetalias,
|
|
+ sizeof(fnode->sess.targetalias)))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_TPGT)) {
|
|
+ if (!flashnode_fill_uint16(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_TPGT,
|
|
+ fnode->sess.tpgt))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ FLASHNODE_SESS_DISCOVERY_PARENT_IDX)) {
|
|
+ if (!flashnode_fill_uint16(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX,
|
|
+ fnode->sess.discovery_parent_idx))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ FLASHNODE_SESS_DISCOVERY_PARENT_TYPE)) {
|
|
+ if (!flashnode_fill_str(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE,
|
|
+ fnode->sess.discovery_parent_type,
|
|
+ sizeof(fnode->sess.discovery_parent_type)))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, FLASHNODE_SESS_PORTAL_TYPE)) {
|
|
+ if (!flashnode_fill_str(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_PORTAL_TYPE,
|
|
+ fnode->sess.portal_type,
|
|
+ sizeof(fnode->sess.portal_type)))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_SESS_CHAP_OUT_IDX))) {
|
|
+ if (!flashnode_fill_uint32(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_CHAP_OUT_IDX,
|
|
+ fnode->sess.chap_out_idx))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name, to_key(FLASHNODE_CONN_PORT))) {
|
|
+ if (fnode->conn[0].port)
|
|
+ port = fnode->conn[0].port;
|
|
+ if (!flashnode_fill_uint16(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_PORT, port))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_IPADDR))) {
|
|
+ if (!flashnode_fill_ipaddr(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_IPADDR))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_MAX_RECV_DLENGTH))) {
|
|
+ if (!flashnode_fill_uint32(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_MAX_RECV_DLENGTH,
|
|
+ fnode->conn[0].max_recv_dlength))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_IS_FW_ASSIGNED_IPV6))) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6,
|
|
+ fnode->conn[0].is_fw_assigned_ipv6))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_HDR_DGST_EN))) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_HDR_DGST_EN,
|
|
+ fnode->conn[0].header_digest_en))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_DATA_DGST_EN))) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_DATA_DGST_EN,
|
|
+ fnode->conn[0].data_digest_en))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_SNACK_REQ_EN))) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_SNACK_REQ_EN,
|
|
+ fnode->conn[0].snack_req_en))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_TCP_TIMESTAMP_STAT))) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT,
|
|
+ fnode->conn[0].tcp_timestamp_stat))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_TCP_NAGLE_DISABLE))) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_TCP_NAGLE_DISABLE,
|
|
+ fnode->conn[0].tcp_nagle_disable))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_TCP_WSF_DISABLE))) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_TCP_WSF_DISABLE,
|
|
+ fnode->conn[0].tcp_wsf_disable))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_TCP_TIMER_SCALE))) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_TCP_TIMER_SCALE,
|
|
+ fnode->conn[0].tcp_timer_scale))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_TCP_TIMESTAMP_EN))) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_TCP_TIMESTAMP_EN,
|
|
+ fnode->conn[0].tcp_timestamp_en))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_IP_FRAG_DISABLE))) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_IP_FRAG_DISABLE,
|
|
+ fnode->conn[0].fragment_disable))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_MAX_XMIT_DLENGTH))) {
|
|
+ if (!flashnode_fill_uint32(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_MAX_XMIT_DLENGTH,
|
|
+ fnode->conn[0].max_xmit_dlength))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_KEEPALIVE_TMO))) {
|
|
+ if (!flashnode_fill_uint16(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_KEEPALIVE_TMO,
|
|
+ fnode->conn[0].keepalive_tmo))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_REDIRECT_IPADDR))) {
|
|
+ if (!flashnode_fill_ipaddr(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_REDIRECT_IPADDR))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_MAX_SEGMENT_SIZE))) {
|
|
+ if (!flashnode_fill_uint32(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_MAX_SEGMENT_SIZE,
|
|
+ fnode->conn[0].max_segment_size))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_LOCAL_PORT))) {
|
|
+ if (!flashnode_fill_uint16(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_LOCAL_PORT,
|
|
+ fnode->conn[0].local_port))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_IPV4_TOS))) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_IPV4_TOS,
|
|
+ fnode->conn[0].ipv4_tos))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_IPV6_TC))) {
|
|
+ if (!flashnode_fill_uint8(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_IPV6_TC,
|
|
+ fnode->conn[0].ipv6_traffic_class))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_IPV6_FLOW_LABEL))) {
|
|
+ if (!flashnode_fill_uint16(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_IPV6_FLOW_LABEL,
|
|
+ fnode->conn[0].ipv6_flow_lbl))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_LINK_LOCAL_IPV6))) {
|
|
+ if (!flashnode_fill_ipv6_addr(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_LINK_LOCAL_IPV6))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_TCP_XMIT_WSF))) {
|
|
+ if (!flashnode_fill_uint32(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_TCP_XMIT_WSF,
|
|
+ fnode->conn[0].tcp_xmit_wsf))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_TCP_RECV_WSF))) {
|
|
+ if (!flashnode_fill_uint32(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_TCP_RECV_WSF,
|
|
+ fnode->conn[0].tcp_recv_wsf))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_STATSN))) {
|
|
+ if (!flashnode_fill_uint32(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_STATSN,
|
|
+ fnode->conn[0].stat_sn))
|
|
+ count++;
|
|
+ } else if (!strcmp(param->name,
|
|
+ to_key(FLASHNODE_CONN_EXP_STATSN))) {
|
|
+ if (!flashnode_fill_uint32(fnode, &iov[count],
|
|
+ ISCSI_FLASHNODE_EXP_STATSN,
|
|
+ fnode->conn[0].exp_stat_sn))
|
|
+ count++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return count;
|
|
+}
|
|
diff --git a/usr/flashnode.h b/usr/flashnode.h
|
|
new file mode 100644
|
|
index 0000000..2950fb5
|
|
--- /dev/null
|
|
+++ b/usr/flashnode.h
|
|
@@ -0,0 +1,129 @@
|
|
+/*
|
|
+ * iSCSI flashnode helpers
|
|
+ *
|
|
+ * Copyright (C) 2013 QLogic Corporation.
|
|
+ * Maintained by open-iscsi@googlegroups.com
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published
|
|
+ * by the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful, but
|
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * General Public License for more details.
|
|
+ *
|
|
+ * See the file COPYING included with this distribution for more details.
|
|
+ */
|
|
+#ifndef FLASHNODE_H
|
|
+#define FLASHNODE_H
|
|
+#include <sys/types.h>
|
|
+#include <netdb.h>
|
|
+#include <net/if.h>
|
|
+
|
|
+#include "types.h"
|
|
+#include "config.h"
|
|
+#include "auth.h"
|
|
+
|
|
+#define MAX_FLASHNODE_IDX UINT_MAX
|
|
+
|
|
+typedef enum portal_type {
|
|
+ IPV4,
|
|
+ IPV6,
|
|
+} portal_type_e;
|
|
+
|
|
+typedef struct flashnode_sess_rec {
|
|
+ char targetname[TARGET_NAME_MAXLEN];
|
|
+ char targetalias[TARGET_NAME_MAXLEN];
|
|
+ char username[AUTH_STR_MAX_LEN];
|
|
+ char username_in[AUTH_STR_MAX_LEN];
|
|
+ char password[AUTH_STR_MAX_LEN];
|
|
+ char password_in[AUTH_STR_MAX_LEN];
|
|
+ /* indicates if discovery was done through iSNS discovery service
|
|
+ * or through sendTarget */
|
|
+ char discovery_parent_type[ISCSI_MAX_STR_LEN];
|
|
+ char isid[16];
|
|
+ char portal_type[5]; /* ipv4 or ipv6 */
|
|
+ unsigned first_burst_len;
|
|
+ unsigned max_burst_len;
|
|
+ uint16_t def_time2wait;
|
|
+ uint16_t def_time2retain;
|
|
+ uint16_t max_outstanding_r2t;
|
|
+ uint16_t tsid;
|
|
+ uint16_t def_taskmgmt_tmo;
|
|
+ uint16_t tpgt;
|
|
+ uint16_t chap_out_idx;
|
|
+ uint16_t chap_in_idx;
|
|
+ /* index of iSCSI discovery session if the entry is
|
|
+ * discovered by iSCSI discovery session
|
|
+ */
|
|
+ uint16_t discovery_parent_idx;
|
|
+ /* Firmware auto sendtarget discovery disable */
|
|
+ uint8_t auto_snd_tgt_disable;
|
|
+ uint8_t discovery_session;
|
|
+ /* indicates if this flashnode entry is enabled or disabled */
|
|
+ uint8_t entry_enable;
|
|
+ uint8_t immediate_data;
|
|
+ uint8_t initial_r2t;
|
|
+ uint8_t data_seq_in_order;
|
|
+ uint8_t data_pdu_in_order;
|
|
+ uint8_t chap_auth_en;
|
|
+ /* enables firmware to auto logout the discovery session on discovery
|
|
+ * completion
|
|
+ */
|
|
+ uint8_t discovery_logout_en;
|
|
+ uint8_t bidi_chap_en;
|
|
+ /* makes authentication for discovery session optional */
|
|
+ uint8_t discovery_auth_optional;
|
|
+ uint8_t erl;
|
|
+ uint8_t is_boot_target;
|
|
+} flashnode_sess_rec_t;
|
|
+
|
|
+typedef struct flashnode_conn_rec {
|
|
+ char ipaddress[NI_MAXHOST];
|
|
+ char redirect_ipaddr[NI_MAXHOST];
|
|
+ char link_local_ipv6[NI_MAXHOST];
|
|
+ unsigned max_recv_dlength;
|
|
+ unsigned max_xmit_dlength;
|
|
+ unsigned max_segment_size;
|
|
+ unsigned tcp_xmit_wsf;
|
|
+ unsigned tcp_recv_wsf;
|
|
+ uint32_t stat_sn;
|
|
+ uint32_t exp_stat_sn;
|
|
+ uint16_t keepalive_tmo;
|
|
+ uint16_t port;
|
|
+ uint16_t local_port;
|
|
+ uint16_t ipv6_flow_lbl;
|
|
+ /* Link local IPv6 address is assigned by firmware or driver */
|
|
+ uint8_t is_fw_assigned_ipv6;
|
|
+ uint8_t header_digest_en;
|
|
+ uint8_t data_digest_en;
|
|
+ uint8_t snack_req_en;
|
|
+ /* tcp timestamp negotiation status */
|
|
+ uint8_t tcp_timestamp_stat;
|
|
+ uint8_t tcp_nagle_disable;
|
|
+ /* tcp window scale factor */
|
|
+ uint8_t tcp_wsf_disable;
|
|
+ uint8_t tcp_timer_scale;
|
|
+ uint8_t tcp_timestamp_en;
|
|
+ uint8_t fragment_disable;
|
|
+ uint8_t ipv4_tos;
|
|
+ uint8_t ipv6_traffic_class;
|
|
+} flashnode_conn_rec_t;
|
|
+
|
|
+struct flashnode_rec {
|
|
+ struct list_head list;
|
|
+ char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN];
|
|
+ flashnode_sess_rec_t sess;
|
|
+ flashnode_conn_rec_t conn[ISCSI_CONN_MAX];
|
|
+};
|
|
+
|
|
+extern int flashnode_info_print_flat(void *data, struct flashnode_rec *tgt,
|
|
+ uint32_t host_no, uint32_t flashnode_idx);
|
|
+extern int iscsi_logout_flashnode_sid(struct iscsi_transport *t,
|
|
+ uint32_t host_no, uint32_t sid);
|
|
+extern int flashnode_build_config(struct list_head *params,
|
|
+ struct flashnode_rec *flashnode,
|
|
+ struct iovec *iovs);
|
|
+#endif
|
|
diff --git a/usr/host.c b/usr/host.c
|
|
index b03e50f..f2052d3 100644
|
|
--- a/usr/host.c
|
|
+++ b/usr/host.c
|
|
@@ -34,6 +34,7 @@
|
|
#include "initiator.h"
|
|
#include "iface.h"
|
|
#include "iscsi_err.h"
|
|
+#include "iscsi_netlink.h"
|
|
|
|
static int match_host_to_session(void *data, struct session_info *info)
|
|
{
|
|
@@ -242,7 +243,7 @@ static int host_info_print_tree(void *data, struct host_info *hinfo)
|
|
link_info.data = &hinfo->host_no;
|
|
|
|
err = iscsi_sysfs_for_each_session(&link_info, &num_found,
|
|
- session_info_create_list);
|
|
+ session_info_create_list, 0);
|
|
if (err || !num_found)
|
|
return 0;
|
|
|
|
@@ -314,3 +315,112 @@ int host_info_print(int info_level, uint32_t host_no)
|
|
}
|
|
return 0;
|
|
}
|
|
+
|
|
+static int chap_fill_param_uint(struct iovec *iov, int param,
|
|
+ uint32_t param_val, int param_len)
|
|
+{
|
|
+ struct iscsi_param_info *param_info;
|
|
+ struct nlattr *attr;
|
|
+ int len;
|
|
+ uint8_t val8 = 0;
|
|
+ uint16_t val16 = 0;
|
|
+ uint32_t val32 = 0;
|
|
+ char *val = NULL;
|
|
+
|
|
+ len = sizeof(struct iscsi_param_info) + param_len;
|
|
+ iov->iov_base = iscsi_nla_alloc(param, len);
|
|
+ if (!iov->iov_base)
|
|
+ return 1;
|
|
+
|
|
+ attr = iov->iov_base;
|
|
+ iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
+
|
|
+ param_info = (struct iscsi_param_info *)ISCSI_NLA_DATA(attr);
|
|
+ param_info->param = param;
|
|
+ param_info->len = param_len;
|
|
+
|
|
+ switch (param_len) {
|
|
+ case 1:
|
|
+ val8 = (uint8_t)param_val;
|
|
+ val = (char *)&val8;
|
|
+ break;
|
|
+
|
|
+ case 2:
|
|
+ val16 = (uint16_t)param_val;
|
|
+ val = (char *)&val16;
|
|
+ break;
|
|
+
|
|
+ case 4:
|
|
+ val32 = (uint32_t)param_val;
|
|
+ val = (char *)&val32;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ goto free;
|
|
+ }
|
|
+ memcpy(param_info->value, val, param_len);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+free:
|
|
+ free(iov->iov_base);
|
|
+ iov->iov_base = NULL;
|
|
+ iov->iov_len = 0;
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int chap_fill_param_str(struct iovec *iov, int param, char *param_val,
|
|
+ int param_len)
|
|
+{
|
|
+ struct iscsi_param_info *param_info;
|
|
+ struct nlattr *attr;
|
|
+ int len;
|
|
+
|
|
+ len = sizeof(struct iscsi_param_info) + param_len;
|
|
+ iov->iov_base = iscsi_nla_alloc(param, len);
|
|
+ if (!iov->iov_base)
|
|
+ return 1;
|
|
+
|
|
+ attr = iov->iov_base;
|
|
+ iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
+
|
|
+ param_info = (struct iscsi_param_info *)ISCSI_NLA_DATA(attr);
|
|
+ param_info->param = param;
|
|
+ param_info->len = param_len;
|
|
+ memcpy(param_info->value, param_val, param_len);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int chap_build_config(struct iscsi_chap_rec *crec, struct iovec *iovs)
|
|
+{
|
|
+ struct iovec *iov = NULL;
|
|
+ int count = 0;
|
|
+
|
|
+ /* start at 2, because 0 is for nlmsghdr and 1 for event */
|
|
+ iov = iovs + 2;
|
|
+
|
|
+ if (!chap_fill_param_uint(&iov[count], ISCSI_CHAP_PARAM_INDEX,
|
|
+ crec->chap_tbl_idx,
|
|
+ sizeof(crec->chap_tbl_idx)))
|
|
+ count++;
|
|
+
|
|
+ if (!chap_fill_param_uint(&iov[count], ISCSI_CHAP_PARAM_CHAP_TYPE,
|
|
+ crec->chap_type, sizeof(crec->chap_type)))
|
|
+ count++;
|
|
+
|
|
+ if (!chap_fill_param_str(&iov[count], ISCSI_CHAP_PARAM_USERNAME,
|
|
+ crec->username, strlen(crec->username)))
|
|
+ count++;
|
|
+
|
|
+ if (!chap_fill_param_str(&iov[count], ISCSI_CHAP_PARAM_PASSWORD,
|
|
+ (char *)crec->password,
|
|
+ strlen((char *)crec->password)))
|
|
+ count++;
|
|
+
|
|
+ if (!chap_fill_param_uint(&iov[count], ISCSI_CHAP_PARAM_PASSWORD_LEN,
|
|
+ crec->password_length,
|
|
+ sizeof(crec->password_length)))
|
|
+ count++;
|
|
+
|
|
+ return count;
|
|
+}
|
|
diff --git a/usr/host.h b/usr/host.h
|
|
index 894ab91..149aa0d 100644
|
|
--- a/usr/host.h
|
|
+++ b/usr/host.h
|
|
@@ -5,6 +5,9 @@
|
|
#include "types.h"
|
|
#include "config.h"
|
|
|
|
+#define MAX_HOST_NO UINT_MAX
|
|
+
|
|
+#define MAX_CHAP_ENTRIES 2048
|
|
#define MAX_CHAP_BUF_SZ 4096
|
|
#define REQ_CHAP_BUF_SZ (MAX_CHAP_BUF_SZ + sizeof(struct iscsi_uevent))
|
|
|
|
@@ -14,5 +17,6 @@ struct host_info {
|
|
};
|
|
|
|
extern int host_info_print(int info_level, uint32_t host_no);
|
|
+extern int chap_build_config(struct iscsi_chap_rec *crec, struct iovec *iovs);
|
|
|
|
#endif
|
|
diff --git a/usr/idbm.c b/usr/idbm.c
|
|
index 4d30aa9..198a5ef 100644
|
|
--- a/usr/idbm.c
|
|
+++ b/usr/idbm.c
|
|
@@ -94,6 +94,17 @@ static struct idbm *db;
|
|
_n++; \
|
|
} while (0)
|
|
|
|
+#define __recinfo_uint32(_key, _info, _rec, _name, _show, _n, _mod) do { \
|
|
+ _info[_n].type = TYPE_UINT32; \
|
|
+ strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
|
|
+ snprintf(_info[_n].value, VALUE_MAXVAL, "%d", _rec->_name); \
|
|
+ _info[_n].data = &_rec->_name; \
|
|
+ _info[_n].data_len = sizeof(_rec->_name); \
|
|
+ _info[_n].visible = _show; \
|
|
+ _info[_n].can_modify = _mod; \
|
|
+ _n++; \
|
|
+} while (0)
|
|
+
|
|
#define __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod) do { \
|
|
_info[_n].type = TYPE_INT_O; \
|
|
strlcpy(_info[_n].name, _key, NAME_MAXVAL); \
|
|
@@ -226,6 +237,9 @@ void
|
|
idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
|
|
{
|
|
int num = 0, i;
|
|
+ int iface_type;
|
|
+
|
|
+ iface_type = iface_get_iptype(&r->iface);
|
|
|
|
__recinfo_str(NODE_NAME, ri, r, name, IDBM_SHOW, num, 0);
|
|
__recinfo_int(NODE_TPGT, ri, r, tpgt, IDBM_SHOW, num, 0);
|
|
@@ -248,6 +262,8 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
|
|
__recinfo_str(IFACE_IPADDR, ri, r, iface.ipaddress, IDBM_SHOW, num, 1);
|
|
__recinfo_str(IFACE_ISCSINAME, ri, r, iface.name, IDBM_SHOW, num, 1);
|
|
__recinfo_str(IFACE_NETNAME, ri, r, iface.netdev, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_GATEWAY, ri, r, iface.gateway, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_SUBNET_MASK, ri, r, iface.subnet_mask, IDBM_SHOW, num, 1);
|
|
/*
|
|
* svn 780 compat: older versions used node.transport_name and
|
|
* rec->transport_name
|
|
@@ -255,21 +271,6 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
|
|
__recinfo_str(IFACE_TRANSPORTNAME, ri, r, iface.transport_name,
|
|
IDBM_SHOW, num, 1);
|
|
__recinfo_str(IFACE_INAME, ri, r, iface.iname, IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_BOOT_PROTO, ri, r, iface.bootproto, IDBM_SHOW,
|
|
- num, 1);
|
|
- __recinfo_str(IFACE_SUBNET_MASK, ri, r, iface.subnet_mask,
|
|
- IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_GATEWAY, ri, r, iface.gateway, IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_IPV6_AUTOCFG, ri, r, iface.ipv6_autocfg,
|
|
- IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_LINKLOCAL_AUTOCFG, ri, r, iface.linklocal_autocfg,
|
|
- IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_ROUTER_AUTOCFG, ri, r, iface.router_autocfg,
|
|
- IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_LINKLOCAL, ri, r, iface.ipv6_linklocal,
|
|
- IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_ROUTER, ri, r, iface.ipv6_router, IDBM_SHOW, num,
|
|
- 1);
|
|
__recinfo_str(IFACE_STATE, ri, r, iface.state, IDBM_SHOW, num, 1);
|
|
__recinfo_uint16(IFACE_VLAN_ID, ri, r, iface.vlan_id, IDBM_SHOW, num,
|
|
1);
|
|
@@ -281,6 +282,115 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
|
|
__recinfo_uint16(IFACE_MTU, ri, r, iface.mtu, IDBM_SHOW, num, 1);
|
|
__recinfo_uint16(IFACE_PORT, ri, r, iface.port, IDBM_SHOW, num, 1);
|
|
|
|
+ if (iface_type == ISCSI_IFACE_TYPE_IPV4) {
|
|
+ __recinfo_str(IFACE_BOOT_PROTO, ri, r, iface.bootproto,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_ALT_CID, ri, r,
|
|
+ iface.dhcp_alt_client_id_state, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_ALT_CID_STR, ri, r,
|
|
+ iface.dhcp_alt_client_id, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_DNS, ri, r, iface.dhcp_dns, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_LEARN_IQN, ri, r,
|
|
+ iface.dhcp_learn_iqn, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_REQ_VID, ri, r,
|
|
+ iface.dhcp_req_vendor_id_state, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_VID, ri, r, iface.dhcp_vendor_id_state,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_VID_STR, ri, r, iface.dhcp_vendor_id,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_SLP_DA, ri, r, iface.dhcp_slp_da,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_FRAGMENTATION, ri, r, iface.fragmentation,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_GRAT_ARP, ri, r, iface.gratuitous_arp,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_IN_FORWARD, ri, r,
|
|
+ iface.incoming_forwarding, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_TOS_STATE, ri, r, iface.tos_state,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(IFACE_TOS, ri, r, iface.tos, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(IFACE_TTL, ri, r, iface.ttl, IDBM_SHOW, num, 1);
|
|
+ } else if (iface_type == ISCSI_IFACE_TYPE_IPV6) {
|
|
+ __recinfo_str(IFACE_IPV6_AUTOCFG, ri, r, iface.ipv6_autocfg,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_LINKLOCAL_AUTOCFG, ri, r,
|
|
+ iface.linklocal_autocfg, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_ROUTER_AUTOCFG, ri, r, iface.router_autocfg,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_LINKLOCAL, ri, r, iface.ipv6_linklocal,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_ROUTER, ri, r, iface.ipv6_router,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(IFACE_DUP_ADDR_DETECT_CNT, ri, r,
|
|
+ iface.dup_addr_detect_cnt, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_FLOW_LABEL, ri, r, iface.flow_label,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_GRAT_NEIGHBOR_ADV, ri, r,
|
|
+ iface.gratuitous_neighbor_adv, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(IFACE_HOP_LIMIT, ri, r, iface.hop_limit,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_MLD, ri, r, iface.mld, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_ND_REACHABLE_TMO, ri, r,
|
|
+ iface.nd_reachable_tmo, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_ND_REXMIT_TIME, ri, r,
|
|
+ iface.nd_rexmit_time, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_ND_STALE_TMO, ri, r, iface.nd_stale_tmo,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_RTR_ADV_LINK_MTU, ri, r,
|
|
+ iface.router_adv_link_mtu, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(IFACE_TRAFFIC_CLASS, ri, r, iface.traffic_class,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ }
|
|
+
|
|
+ __recinfo_str(IFACE_DELAYED_ACK, ri, r, iface.delayed_ack, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_TCP_NAGLE, ri, r, iface.nagle, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_TCP_WSF_STATE, ri, r, iface.tcp_wsf_state,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(IFACE_TCP_WSF, ri, r, iface.tcp_wsf, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(IFACE_TCP_TIMER_SCALE, ri, r, iface.tcp_timer_scale,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_TCP_TIMESTAMP, ri, r, iface.tcp_timestamp,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_REDIRECT, ri, r, iface.redirect, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint16(IFACE_DEF_TMF_TMO, ri, r, iface.def_task_mgmt_tmo,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_HDRDGST, ri, r, iface.header_digest, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_DATADGST, ri, r, iface.data_digest, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_IMM_DATA, ri, r, iface.immediate_data, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_INITIAL_R2T, ri, r, iface.initial_r2t, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_DSEQ_INORDER, ri, r, iface.data_seq_inorder,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DPDU_INORDER, ri, r, iface.data_pdu_inorder,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(IFACE_ERL, ri, r, iface.erl, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_MAX_RECV_DLEN, ri, r, iface.max_recv_dlength,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_FIRST_BURST, ri, r, iface.first_burst_len,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint16(IFACE_MAX_R2T, ri, r, iface.max_out_r2t, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_uint32(IFACE_MAX_BURST, ri, r, iface.max_burst_len, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_CHAP_AUTH, ri, r, iface.chap_auth, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_BIDI_CHAP, ri, r, iface.bidi_chap, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_STRICT_LOGIN_COMP, ri, r, iface.strict_login_comp,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DISCOVERY_AUTH, ri, r, iface.discovery_auth,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DISCOVERY_LOGOUT, ri, r, iface.discovery_logout,
|
|
+ IDBM_SHOW, num, 1);
|
|
+
|
|
+
|
|
__recinfo_str(NODE_DISC_ADDR, ri, r, disc_address, IDBM_SHOW,
|
|
num, 0);
|
|
__recinfo_int(NODE_DISC_PORT, ri, r, disc_port, IDBM_SHOW,
|
|
@@ -414,6 +524,9 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
|
|
void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
|
|
{
|
|
int num = 0;
|
|
+ int iface_type;
|
|
+
|
|
+ iface_type = iface_get_iptype(r);
|
|
|
|
__recinfo_str(IFACE_ISCSINAME, ri, r, name, IDBM_SHOW, num, 0);
|
|
__recinfo_str(IFACE_NETNAME, ri, r, netdev, IDBM_SHOW, num, 1);
|
|
@@ -422,19 +535,6 @@ void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
|
|
__recinfo_str(IFACE_TRANSPORTNAME, ri, r, transport_name,
|
|
IDBM_SHOW, num, 1);
|
|
__recinfo_str(IFACE_INAME, ri, r, iname, IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_BOOT_PROTO, ri, r, bootproto, IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_SUBNET_MASK, ri, r, subnet_mask,
|
|
- IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_GATEWAY, ri, r, gateway, IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_IPV6_AUTOCFG, ri, r, ipv6_autocfg,
|
|
- IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_LINKLOCAL_AUTOCFG, ri, r, linklocal_autocfg,
|
|
- IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_ROUTER_AUTOCFG, ri, r, router_autocfg,
|
|
- IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_LINKLOCAL, ri, r, ipv6_linklocal,
|
|
- IDBM_SHOW, num, 1);
|
|
- __recinfo_str(IFACE_ROUTER, ri, r, ipv6_router, IDBM_SHOW, num, 1);
|
|
__recinfo_str(IFACE_STATE, ri, r, state, IDBM_SHOW, num, 1);
|
|
__recinfo_uint16(IFACE_VLAN_ID, ri, r, vlan_id, IDBM_SHOW, num, 1);
|
|
__recinfo_uint8(IFACE_VLAN_PRIORITY, ri, r, vlan_priority,
|
|
@@ -443,9 +543,110 @@ void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri)
|
|
__recinfo_int(IFACE_NUM, ri, r, iface_num, IDBM_SHOW, num, 1);
|
|
__recinfo_uint16(IFACE_MTU, ri, r, mtu, IDBM_SHOW, num, 1);
|
|
__recinfo_uint16(IFACE_PORT, ri, r, port, IDBM_SHOW, num, 1);
|
|
+
|
|
+ if (iface_type == ISCSI_IFACE_TYPE_IPV4) {
|
|
+ __recinfo_str(IFACE_BOOT_PROTO, ri, r, bootproto, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_SUBNET_MASK, ri, r, subnet_mask, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_GATEWAY, ri, r, gateway, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_ALT_CID, ri, r,
|
|
+ dhcp_alt_client_id_state, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_ALT_CID_STR, ri, r, dhcp_alt_client_id,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_DNS, ri, r, dhcp_dns, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_LEARN_IQN, ri, r, dhcp_learn_iqn,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_REQ_VID, ri, r,
|
|
+ dhcp_req_vendor_id_state, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_VID, ri, r, dhcp_vendor_id_state,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_VID_STR, ri, r, dhcp_vendor_id,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DHCP_SLP_DA, ri, r, dhcp_slp_da, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_FRAGMENTATION, ri, r, fragmentation,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_GRAT_ARP, ri, r, gratuitous_arp, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_IN_FORWARD, ri, r, incoming_forwarding,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_TOS_STATE, ri, r, tos_state, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_uint8(IFACE_TOS, ri, r, tos, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(IFACE_TTL, ri, r, ttl, IDBM_SHOW, num, 1);
|
|
+ } else if (iface_type == ISCSI_IFACE_TYPE_IPV6) {
|
|
+ __recinfo_str(IFACE_IPV6_AUTOCFG, ri, r, ipv6_autocfg,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_LINKLOCAL_AUTOCFG, ri, r, linklocal_autocfg,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_ROUTER_AUTOCFG, ri, r, router_autocfg,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_LINKLOCAL, ri, r, ipv6_linklocal, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_ROUTER, ri, r, ipv6_router, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_uint8(IFACE_DUP_ADDR_DETECT_CNT, ri, r,
|
|
+ dup_addr_detect_cnt, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_FLOW_LABEL, ri, r, flow_label, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_GRAT_NEIGHBOR_ADV, ri, r,
|
|
+ gratuitous_neighbor_adv, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(IFACE_HOP_LIMIT, ri, r, hop_limit, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_MLD, ri, r, mld, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_ND_REACHABLE_TMO, ri, r,
|
|
+ nd_reachable_tmo, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_ND_REXMIT_TIME, ri, r, nd_rexmit_time,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_ND_STALE_TMO, ri, r, nd_stale_tmo,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_RTR_ADV_LINK_MTU, ri, r,
|
|
+ router_adv_link_mtu, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(IFACE_TRAFFIC_CLASS, ri, r, traffic_class,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ }
|
|
+
|
|
+ __recinfo_str(IFACE_DELAYED_ACK, ri, r, delayed_ack, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_TCP_NAGLE, ri, r, nagle, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_TCP_WSF_STATE, ri, r, tcp_wsf_state, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_uint8(IFACE_TCP_WSF, ri, r, tcp_wsf, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(IFACE_TCP_TIMER_SCALE, ri, r, tcp_timer_scale,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_TCP_TIMESTAMP, ri, r, tcp_timestamp, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_REDIRECT, ri, r, redirect, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint16(IFACE_DEF_TMF_TMO, ri, r, def_task_mgmt_tmo, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_HDRDGST, ri, r, header_digest, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DATADGST, ri, r, data_digest, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_IMM_DATA, ri, r, immediate_data, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_INITIAL_R2T, ri, r, initial_r2t, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DSEQ_INORDER, ri, r, data_seq_inorder, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_DPDU_INORDER, ri, r, data_pdu_inorder, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_uint8(IFACE_ERL, ri, r, erl, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_MAX_RECV_DLEN, ri, r, max_recv_dlength,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_FIRST_BURST, ri, r, first_burst_len, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_uint16(IFACE_MAX_R2T, ri, r, max_out_r2t, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(IFACE_MAX_BURST, ri, r, max_burst_len, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_CHAP_AUTH, ri, r, chap_auth, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_BIDI_CHAP, ri, r, bidi_chap, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_STRICT_LOGIN_COMP, ri, r, strict_login_comp,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(IFACE_DISCOVERY_AUTH, ri, r, discovery_auth, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(IFACE_DISCOVERY_LOGOUT, ri, r, discovery_logout,
|
|
+ IDBM_SHOW, num, 1);
|
|
}
|
|
|
|
-static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
|
|
+void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
|
|
{
|
|
int num = 0;
|
|
|
|
@@ -454,14 +655,14 @@ static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
|
|
|
|
if (r->chap_type == CHAP_TYPE_OUT) {
|
|
__recinfo_str(HOST_AUTH_USERNAME, ri, r, username, IDBM_SHOW,
|
|
- num, 0);
|
|
+ num, 1);
|
|
__recinfo_str(HOST_AUTH_PASSWORD, ri, r, password, IDBM_MASKED,
|
|
num, 1);
|
|
__recinfo_int(HOST_AUTH_PASSWORD_LEN, ri, r, password_length,
|
|
IDBM_HIDE, num, 1);
|
|
} else {
|
|
__recinfo_str(HOST_AUTH_USERNAME_IN, ri, r, username, IDBM_SHOW,
|
|
- num, 0);
|
|
+ num, 1);
|
|
__recinfo_str(HOST_AUTH_PASSWORD_IN, ri, r, password,
|
|
IDBM_MASKED, num, 1);
|
|
__recinfo_int(HOST_AUTH_PASSWORD_IN_LEN, ri, r, password_length,
|
|
@@ -469,6 +670,158 @@ static void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri)
|
|
}
|
|
}
|
|
|
|
+void idbm_recinfo_flashnode(struct flashnode_rec *r, recinfo_t *ri)
|
|
+{
|
|
+ int num = 0;
|
|
+ int i;
|
|
+
|
|
+ __recinfo_uint8(FLASHNODE_SESS_AUTO_SND_TGT_DISABLE, ri, r,
|
|
+ sess.auto_snd_tgt_disable, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(FLASHNODE_SESS_DISCOVERY_SESS, ri, r,
|
|
+ sess.discovery_session, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(FLASHNODE_SESS_PORTAL_TYPE, ri, r, sess.portal_type,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(FLASHNODE_SESS_ENTRY_EN, ri, r,
|
|
+ sess.entry_enable, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(FLASHNODE_SESS_IMM_DATA_EN, ri, r, sess.immediate_data,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(FLASHNODE_SESS_INITIAL_R2T_EN, ri, r, sess.initial_r2t,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(FLASHNODE_SESS_DATASEQ_INORDER, ri, r,
|
|
+ sess.data_seq_in_order, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(FLASHNODE_SESS_PDU_INORDER, ri, r,
|
|
+ sess.data_pdu_in_order, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(FLASHNODE_SESS_CHAP_AUTH_EN, ri, r, sess.chap_auth_en,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(FLASHNODE_SESS_DISCOVERY_LOGOUT_EN, ri, r,
|
|
+ sess.discovery_logout_en, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(FLASHNODE_SESS_BIDI_CHAP_EN, ri, r, sess.bidi_chap_en,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(FLASHNODE_SESS_DISCOVERY_AUTH_OPTIONAL, ri, r,
|
|
+ sess.discovery_auth_optional, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(FLASHNODE_SESS_ERL, ri, r, sess.erl, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint32(FLASHNODE_SESS_FIRST_BURST, ri, r,
|
|
+ sess.first_burst_len, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint16(FLASHNODE_SESS_DEF_TIME2WAIT, ri, r,
|
|
+ sess.def_time2wait, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint16(FLASHNODE_SESS_DEF_TIME2RETAIN, ri, r,
|
|
+ sess.def_time2retain, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint16(FLASHNODE_SESS_MAX_R2T, ri, r,
|
|
+ sess.max_outstanding_r2t, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(FLASHNODE_SESS_ISID, ri, r, sess.isid, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint16(FLASHNODE_SESS_TSID, ri, r, sess.tsid, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_uint32(FLASHNODE_SESS_MAX_BURST, ri, r, sess.max_burst_len,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint16(FLASHNODE_SESS_DEF_TASKMGMT_TMO, ri, r,
|
|
+ sess.def_taskmgmt_tmo, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(FLASHNODE_SESS_ALIAS, ri, r, sess.targetalias, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(FLASHNODE_SESS_NAME, ri, r, sess.targetname, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_uint16(FLASHNODE_SESS_DISCOVERY_PARENT_IDX, ri, r,
|
|
+ sess.discovery_parent_idx, IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(FLASHNODE_SESS_DISCOVERY_PARENT_TYPE, ri, r,
|
|
+ sess.discovery_parent_type, IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint16(FLASHNODE_SESS_TPGT, ri, r, sess.tpgt, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_uint16(FLASHNODE_SESS_CHAP_OUT_IDX, ri, r, sess.chap_out_idx,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint16(FLASHNODE_SESS_CHAP_IN_IDX, ri, r, sess.chap_in_idx,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(FLASHNODE_SESS_USERNAME, ri, r, sess.username, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(FLASHNODE_SESS_USERNAME_IN, ri, r, sess.username_in,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_str(FLASHNODE_SESS_PASSWORD, ri, r, sess.password, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ __recinfo_str(FLASHNODE_SESS_PASSWORD_IN, ri, r, sess.password_in,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ __recinfo_uint8(FLASHNODE_SESS_IS_BOOT_TGT, ri, r, sess.is_boot_target,
|
|
+ IDBM_SHOW, num, 1);
|
|
+
|
|
+ for (i = 0; i < ISCSI_CONN_MAX; i++) {
|
|
+ char key[NAME_MAXVAL];
|
|
+
|
|
+ sprintf(key, FLASHNODE_CONN_IS_FW_ASSIGNED_IPV6, i);
|
|
+ __recinfo_uint8(key, ri, r, conn[i].is_fw_assigned_ipv6,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_HDR_DGST_EN, i);
|
|
+ __recinfo_uint8(key, ri, r, conn[i].header_digest_en, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_DATA_DGST_EN, i);
|
|
+ __recinfo_uint8(key, ri, r, conn[i].data_digest_en, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_SNACK_REQ_EN, i);
|
|
+ __recinfo_uint8(key, ri, r, conn[i].snack_req_en, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_TCP_TIMESTAMP_STAT, i);
|
|
+ __recinfo_uint8(key, ri, r, conn[i].tcp_timestamp_stat,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_TCP_NAGLE_DISABLE, i);
|
|
+ __recinfo_uint8(key, ri, r, conn[i].tcp_nagle_disable,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_TCP_WSF_DISABLE, i);
|
|
+ __recinfo_uint8(key, ri, r, conn[i].tcp_wsf_disable, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_TCP_TIMER_SCALE, i);
|
|
+ __recinfo_uint8(key, ri, r, conn[i].tcp_timer_scale, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_TCP_TIMESTAMP_EN, i);
|
|
+ __recinfo_uint8(key, ri, r, conn[i].tcp_timestamp_en,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_IP_FRAG_DISABLE, i);
|
|
+ __recinfo_uint8(key, ri, r, conn[i].fragment_disable, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_MAX_XMIT_DLENGTH, i);
|
|
+ __recinfo_uint32(key, ri, r, conn[i].max_xmit_dlength,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_MAX_RECV_DLENGTH, i);
|
|
+ __recinfo_uint32(key, ri, r, conn[i].max_recv_dlength,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_KEEPALIVE_TMO, i);
|
|
+ __recinfo_uint16(key, ri, r, conn[i].keepalive_tmo, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_PORT, i);
|
|
+ __recinfo_uint16(key, ri, r, conn[i].port, IDBM_SHOW, num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_IPADDR, i);
|
|
+ __recinfo_str(key, ri, r, conn[i].ipaddress, IDBM_SHOW, num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_REDIRECT_IPADDR, i);
|
|
+ __recinfo_str(key, ri, r, conn[i].redirect_ipaddr, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_MAX_SEGMENT_SIZE, i);
|
|
+ __recinfo_uint32(key, ri, r, conn[i].max_segment_size,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_LOCAL_PORT, i);
|
|
+ __recinfo_uint16(key, ri, r, conn[i].local_port, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_IPV4_TOS, i);
|
|
+ __recinfo_uint8(key, ri, r, conn[i].ipv4_tos, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_IPV6_TC, i);
|
|
+ __recinfo_uint8(key, ri, r, conn[i].ipv6_traffic_class,
|
|
+ IDBM_SHOW, num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_IPV6_FLOW_LABEL, i);
|
|
+ __recinfo_uint16(key, ri, r, conn[i].ipv6_flow_lbl, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_LINK_LOCAL_IPV6, i);
|
|
+ __recinfo_str(key, ri, r, conn[i].link_local_ipv6, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_TCP_XMIT_WSF, i);
|
|
+ __recinfo_uint32(key, ri, r, conn[i].tcp_xmit_wsf, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_TCP_RECV_WSF, i);
|
|
+ __recinfo_uint32(key, ri, r, conn[i].tcp_recv_wsf, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_STATSN, i);
|
|
+ __recinfo_uint32(key, ri, r, conn[i].stat_sn, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ sprintf(key, FLASHNODE_CONN_EXP_STATSN, i);
|
|
+ __recinfo_uint32(key, ri, r, conn[i].exp_stat_sn, IDBM_SHOW,
|
|
+ num, 1);
|
|
+ }
|
|
+}
|
|
+
|
|
recinfo_t *idbm_recinfo_alloc(int max_keys)
|
|
{
|
|
recinfo_t *info;
|
|
@@ -502,6 +855,9 @@ void idbm_print(int type, void *rec, int show, FILE *f)
|
|
case IDBM_PRINT_TYPE_HOST_CHAP:
|
|
idbm_recinfo_host_chap((struct iscsi_chap_rec *)rec, info);
|
|
break;
|
|
+ case IDBM_PRINT_TYPE_FLASHNODE:
|
|
+ idbm_recinfo_flashnode((struct flashnode_rec *)rec, info);
|
|
+ break;
|
|
}
|
|
|
|
fprintf(f, "%s\n", ISCSI_BEGIN_REC);
|
|
@@ -629,6 +985,13 @@ setup_passwd_len:
|
|
*(uint16_t *)info[i].data =
|
|
strtoul(value, NULL, 10);
|
|
goto updated;
|
|
+ } else if (info[i].type == TYPE_UINT32) {
|
|
+ if (!info[i].data)
|
|
+ continue;
|
|
+
|
|
+ *(uint32_t *)info[i].data =
|
|
+ strtoul(value, NULL, 10);
|
|
+ goto updated;
|
|
} else if (info[i].type == TYPE_STR) {
|
|
if (!info[i].data)
|
|
continue;
|
|
@@ -679,6 +1042,8 @@ updated:
|
|
check_password_param(discovery.sendtargets.auth.password_in);
|
|
check_password_param(discovery.slp.auth.password);
|
|
check_password_param(discovery.slp.auth.password_in);
|
|
+ check_password_param(host.auth.password);
|
|
+ check_password_param(host.auth.password_in);
|
|
|
|
return 0;
|
|
}
|
|
@@ -694,7 +1059,7 @@ int idbm_verify_param(recinfo_t *info, char *name)
|
|
if (strcmp(name, info[i].name))
|
|
continue;
|
|
|
|
- log_debug(7, "verify %s %d\n", name, info[i].can_modify);
|
|
+ log_debug(7, "verify %s %d", name, info[i].can_modify);
|
|
if (info[i].can_modify)
|
|
return 0;
|
|
else {
|
|
@@ -797,20 +1162,20 @@ static void idbm_sync_config(void)
|
|
idbm_recinfo_node(&db->nrec, db->ninfo);
|
|
|
|
if (!db->get_config_file) {
|
|
- log_debug(1, "Could not get config file. No config file fn\n");
|
|
+ log_debug(1, "Could not get config file. No config file fn");
|
|
return;
|
|
}
|
|
|
|
config_file = db->get_config_file();
|
|
if (!config_file) {
|
|
- log_debug(1, "Could not get config file for sync config\n");
|
|
+ log_debug(1, "Could not get config file for sync config");
|
|
return;
|
|
}
|
|
|
|
f = fopen(config_file, "r");
|
|
if (!f) {
|
|
log_debug(1, "cannot open configuration file %s. "
|
|
- "Default location is %s.\n",
|
|
+ "Default location is %s.",
|
|
config_file, CONFIG_FILE);
|
|
return;
|
|
}
|
|
@@ -880,6 +1245,12 @@ int idbm_print_host_chap_info(struct iscsi_chap_rec *chap)
|
|
return 0;
|
|
}
|
|
|
|
+int idbm_print_flashnode_info(struct flashnode_rec *fnode)
|
|
+{
|
|
+ idbm_print(IDBM_PRINT_TYPE_FLASHNODE, fnode, 1, stdout);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int idbm_print_node_flat(void *data, node_rec_t *rec)
|
|
{
|
|
if (strchr(rec->conn[0].address, '.'))
|
|
@@ -960,7 +1331,7 @@ int idbm_lock(void)
|
|
|
|
if (access(LOCK_DIR, F_OK) != 0) {
|
|
if (mkdir(LOCK_DIR, 0660) != 0) {
|
|
- log_error("Could not open %s: %s\n", LOCK_DIR,
|
|
+ log_error("Could not open %s: %s", LOCK_DIR,
|
|
strerror(errno));
|
|
return ISCSI_ERR_IDBM;
|
|
}
|
|
@@ -1040,7 +1411,7 @@ static int __idbm_rec_read(node_rec_t *out_rec, char *conf)
|
|
|
|
f = fopen(conf, "r");
|
|
if (!f) {
|
|
- log_debug(5, "Could not open %s err %s\n", conf,
|
|
+ log_debug(5, "Could not open %s err %s", conf,
|
|
strerror(errno));
|
|
rc = ISCSI_ERR_IDBM;
|
|
goto unlock;
|
|
@@ -1182,7 +1553,7 @@ static int idbm_for_each_drec(int type, char *config_root, void *data,
|
|
!strcmp(entity_dent->d_name, ".."))
|
|
continue;
|
|
|
|
- log_debug(5, "found %s\n", entity_dent->d_name);
|
|
+ log_debug(5, "found %s", entity_dent->d_name);
|
|
|
|
tmp_port = strchr(entity_dent->d_name, ',');
|
|
if (!tmp_port)
|
|
@@ -1439,7 +1810,7 @@ int idbm_for_each_portal(int *found, void *data, idbm_portal_op_fn *fn,
|
|
!strcmp(portal_dent->d_name, ".."))
|
|
continue;
|
|
|
|
- log_debug(5, "found %s\n", portal_dent->d_name);
|
|
+ log_debug(5, "found %s", portal_dent->d_name);
|
|
tmp_port = strchr(portal_dent->d_name, ',');
|
|
if (!tmp_port)
|
|
continue;
|
|
@@ -1481,7 +1852,7 @@ int idbm_for_each_node(int *found, void *data, idbm_node_op_fn *fn)
|
|
!strcmp(node_dent->d_name, ".."))
|
|
continue;
|
|
|
|
- log_debug(5, "searching %s\n", node_dent->d_name);
|
|
+ log_debug(5, "searching %s", node_dent->d_name);
|
|
curr_rc = fn(found, data, node_dent->d_name);
|
|
/* less than zero means it was not a match */
|
|
if (curr_rc > 0 && !rc)
|
|
@@ -1557,7 +1928,7 @@ idbm_discovery_read(discovery_rec_t *out_rec, int drec_type,
|
|
snprintf(portal, PATH_MAX, "%s/%s,%d",
|
|
disc_type_to_config_vals[drec_type].config_root,
|
|
addr, port);
|
|
- log_debug(5, "Looking for config file %s\n", portal);
|
|
+ log_debug(5, "Looking for config file %s", portal);
|
|
|
|
rc = idbm_lock();
|
|
if (rc)
|
|
@@ -1566,7 +1937,7 @@ idbm_discovery_read(discovery_rec_t *out_rec, int drec_type,
|
|
f = idbm_open_rec_r(portal,
|
|
disc_type_to_config_vals[drec_type].config_name);
|
|
if (!f) {
|
|
- log_debug(1, "Could not open %s: %s\n", portal,
|
|
+ log_debug(1, "Could not open %s: %s", portal,
|
|
strerror(errno));
|
|
rc = ISCSI_ERR_IDBM;
|
|
goto unlock;
|
|
@@ -1596,7 +1967,7 @@ static FILE *idbm_open_rec_w(char *portal, char *config)
|
|
FILE *f;
|
|
int err;
|
|
|
|
- log_debug(5, "Looking for config file %s\n", portal);
|
|
+ log_debug(5, "Looking for config file %s", portal);
|
|
|
|
err = stat(portal, &statb);
|
|
if (err)
|
|
@@ -1608,14 +1979,14 @@ static FILE *idbm_open_rec_w(char *portal, char *config)
|
|
*/
|
|
if (unlink(portal)) {
|
|
log_error("Could not convert %s to %s/%s. "
|
|
- "err %d\n", portal, portal,
|
|
+ "err %d", portal, portal,
|
|
config, errno);
|
|
return NULL;
|
|
}
|
|
|
|
mkdir_portal:
|
|
if (mkdir(portal, 0660) != 0) {
|
|
- log_error("Could not make dir %s err %d\n",
|
|
+ log_error("Could not make dir %s err %d",
|
|
portal, errno);
|
|
return NULL;
|
|
}
|
|
@@ -1625,7 +1996,7 @@ mkdir_portal:
|
|
strlcat(portal, config, PATH_MAX);
|
|
f = fopen(portal, "w");
|
|
if (!f)
|
|
- log_error("Could not open %s err %d\n", portal, errno);
|
|
+ log_error("Could not open %s err %d", portal, errno);
|
|
return f;
|
|
}
|
|
|
|
@@ -1638,14 +2009,14 @@ static int idbm_rec_write(node_rec_t *rec)
|
|
|
|
portal = malloc(PATH_MAX);
|
|
if (!portal) {
|
|
- log_error("Could not alloc portal\n");
|
|
+ log_error("Could not alloc portal");
|
|
return ISCSI_ERR_NOMEM;
|
|
}
|
|
|
|
snprintf(portal, PATH_MAX, "%s", NODE_CONFIG_DIR);
|
|
if (access(portal, F_OK) != 0) {
|
|
if (mkdir(portal, 0660) != 0) {
|
|
- log_error("Could not make %s: %s\n", portal,
|
|
+ log_error("Could not make %s: %s", portal,
|
|
strerror(errno));
|
|
rc = ISCSI_ERR_IDBM;
|
|
goto free_portal;
|
|
@@ -1655,7 +2026,7 @@ static int idbm_rec_write(node_rec_t *rec)
|
|
snprintf(portal, PATH_MAX, "%s/%s", NODE_CONFIG_DIR, rec->name);
|
|
if (access(portal, F_OK) != 0) {
|
|
if (mkdir(portal, 0660) != 0) {
|
|
- log_error("Could not make %s: %s\n", portal,
|
|
+ log_error("Could not make %s: %s", portal,
|
|
strerror(errno));
|
|
rc = ISCSI_ERR_IDBM;
|
|
goto free_portal;
|
|
@@ -1698,7 +2069,7 @@ static int idbm_rec_write(node_rec_t *rec)
|
|
* Old style portal as a file, but with tpgt. Let's update it.
|
|
*/
|
|
if (unlink(portal)) {
|
|
- log_error("Could not convert %s: %s\n", portal,
|
|
+ log_error("Could not convert %s: %s", portal,
|
|
strerror(errno));
|
|
rc = ISCSI_ERR_IDBM;
|
|
goto unlock;
|
|
@@ -1713,7 +2084,7 @@ mkdir_portal:
|
|
rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt);
|
|
if (stat(portal, &statb)) {
|
|
if (mkdir(portal, 0660) != 0) {
|
|
- log_error("Could not make dir %s: %s\n",
|
|
+ log_error("Could not make dir %s: %s",
|
|
portal, strerror(errno));
|
|
rc = ISCSI_ERR_IDBM;
|
|
goto unlock;
|
|
@@ -1726,7 +2097,7 @@ mkdir_portal:
|
|
open_conf:
|
|
f = fopen(portal, "w");
|
|
if (!f) {
|
|
- log_error("Could not open %s: %sd\n", portal, strerror(errno));
|
|
+ log_error("Could not open %s: %s", portal, strerror(errno));
|
|
rc = ISCSI_ERR_IDBM;
|
|
goto unlock;
|
|
}
|
|
@@ -1752,7 +2123,7 @@ idbm_discovery_write(discovery_rec_t *rec)
|
|
|
|
portal = malloc(PATH_MAX);
|
|
if (!portal) {
|
|
- log_error("Could not alloc portal\n");
|
|
+ log_error("Could not alloc portal");
|
|
return ISCSI_ERR_NOMEM;
|
|
}
|
|
|
|
@@ -1764,7 +2135,7 @@ idbm_discovery_write(discovery_rec_t *rec)
|
|
disc_type_to_config_vals[rec->type].config_root);
|
|
if (access(portal, F_OK) != 0) {
|
|
if (mkdir(portal, 0660) != 0) {
|
|
- log_error("Could not make %s: %s\n", portal,
|
|
+ log_error("Could not make %s: %s", portal,
|
|
strerror(errno));
|
|
rc = ISCSI_ERR_IDBM;
|
|
goto unlock;
|
|
@@ -1778,7 +2149,7 @@ idbm_discovery_write(discovery_rec_t *rec)
|
|
f = idbm_open_rec_w(portal,
|
|
disc_type_to_config_vals[rec->type].config_name);
|
|
if (!f) {
|
|
- log_error("Could not open %s: %s\n", portal, strerror(errno));
|
|
+ log_error("Could not open %s: %s", portal, strerror(errno));
|
|
rc = ISCSI_ERR_IDBM;
|
|
goto unlock;
|
|
}
|
|
@@ -2150,10 +2521,10 @@ int idbm_delete_discovery(discovery_rec_t *drec)
|
|
snprintf(portal, PATH_MAX, "%s/%s,%d",
|
|
disc_type_to_config_vals[drec->type].config_root,
|
|
drec->address, drec->port);
|
|
- log_debug(5, "Removing config file %s\n", portal);
|
|
+ log_debug(5, "Removing config file %s", portal);
|
|
|
|
if (stat(portal, &statb)) {
|
|
- log_debug(5, "Could not stat %s to delete disc err %d\n",
|
|
+ log_debug(5, "Could not stat %s to delete disc err %d",
|
|
portal, errno);
|
|
goto free_portal;
|
|
}
|
|
@@ -2166,7 +2537,7 @@ int idbm_delete_discovery(discovery_rec_t *drec)
|
|
}
|
|
|
|
if (unlink(portal))
|
|
- log_debug(5, "Could not remove %s err %d\n", portal, errno);
|
|
+ log_debug(5, "Could not remove %s err %d", portal, errno);
|
|
|
|
memset(portal, 0, PATH_MAX);
|
|
snprintf(portal, PATH_MAX, "%s/%s,%d",
|
|
@@ -2216,7 +2587,7 @@ static int idbm_remove_disc_to_node_link(node_rec_t *rec,
|
|
goto done;
|
|
}
|
|
|
|
- log_debug(7, "found drec %s %d\n",
|
|
+ log_debug(7, "found drec %s %d",
|
|
tmprec->disc_address, tmprec->disc_port);
|
|
/* rm link from discovery source to node */
|
|
memset(portal, 0, PATH_MAX);
|
|
@@ -2230,7 +2601,7 @@ static int idbm_remove_disc_to_node_link(node_rec_t *rec,
|
|
|
|
if (!stat(portal, &statb)) {
|
|
if (unlink(portal)) {
|
|
- log_error("Could not remove link %s: %s\n",
|
|
+ log_error("Could not remove link %s: %s",
|
|
portal, strerror(errno));
|
|
rc = ISCSI_ERR_IDBM;
|
|
} else
|
|
@@ -2267,7 +2638,7 @@ int idbm_delete_node(node_rec_t *rec)
|
|
memset(portal, 0, PATH_MAX);
|
|
snprintf(portal, PATH_MAX, "%s/%s/%s,%d", NODE_CONFIG_DIR,
|
|
rec->name, rec->conn[0].address, rec->conn[0].port);
|
|
- log_debug(5, "Removing config file %s iface id %s\n",
|
|
+ log_debug(5, "Removing config file %s iface id %s",
|
|
portal, rec->iface.name);
|
|
|
|
rc = idbm_lock();
|
|
@@ -2285,14 +2656,14 @@ int idbm_delete_node(node_rec_t *rec)
|
|
if (!stat(portal, &statb))
|
|
goto rm_conf;
|
|
|
|
- log_error("Could not stat %s to delete node: %s\n",
|
|
+ log_error("Could not stat %s to delete node: %s",
|
|
portal, strerror(errno));
|
|
rc = ISCSI_ERR_IDBM;
|
|
goto unlock;
|
|
|
|
rm_conf:
|
|
if (unlink(portal)) {
|
|
- log_error("Could not remove %s: %s\n", portal, strerror(errno));
|
|
+ log_error("Could not remove %s: %s", portal, strerror(errno));
|
|
rc = ISCSI_ERR_IDBM;
|
|
goto unlock;
|
|
}
|
|
@@ -2470,7 +2841,7 @@ int idbm_init(idbm_get_config_file_fn *fn)
|
|
/* make sure root db dir is there */
|
|
if (access(ISCSI_CONFIG_ROOT, F_OK) != 0) {
|
|
if (mkdir(ISCSI_CONFIG_ROOT, 0660) != 0) {
|
|
- log_error("Could not make %s %d\n", ISCSI_CONFIG_ROOT,
|
|
+ log_error("Could not make %s %d", ISCSI_CONFIG_ROOT,
|
|
errno);
|
|
return errno;
|
|
}
|
|
@@ -2569,6 +2940,12 @@ struct node_rec *idbm_create_rec_from_boot_context(struct boot_context *context)
|
|
strlen((char *)context->chap_password);
|
|
rec->session.auth.password_in_length =
|
|
strlen((char *)context->chap_password_in);
|
|
+ strlcpy(rec->session.boot_root, context->boot_root,
|
|
+ sizeof(context->boot_root));
|
|
+ strlcpy(rec->session.boot_nic, context->boot_nic,
|
|
+ sizeof(context->boot_nic));
|
|
+ strlcpy(rec->session.boot_target, context->boot_target,
|
|
+ sizeof(context->boot_target));
|
|
|
|
iface_setup_from_boot_context(&rec->iface, context);
|
|
|
|
diff --git a/usr/idbm.h b/usr/idbm.h
|
|
index 245f046..b9020fe 100644
|
|
--- a/usr/idbm.h
|
|
+++ b/usr/idbm.h
|
|
@@ -27,6 +27,7 @@
|
|
#include "initiator.h"
|
|
#include "config.h"
|
|
#include "list.h"
|
|
+#include "flashnode.h"
|
|
|
|
#define NODE_CONFIG_DIR ISCSI_CONFIG_ROOT"nodes"
|
|
#define SLP_CONFIG_DIR ISCSI_CONFIG_ROOT"slp"
|
|
@@ -42,6 +43,7 @@
|
|
#define TYPE_STR 2
|
|
#define TYPE_UINT8 3
|
|
#define TYPE_UINT16 4
|
|
+#define TYPE_UINT32 5
|
|
#define MAX_KEYS 256 /* number of keys total(including CNX_MAX) */
|
|
#define NAME_MAXVAL 128 /* the maximum length of key name */
|
|
#define VALUE_MAXVAL 256 /* the maximum length of 223 bytes in the RFC. */
|
|
@@ -85,6 +87,7 @@ struct user_param {
|
|
struct list_head list;
|
|
char *name;
|
|
char *value;
|
|
+ int param;
|
|
};
|
|
|
|
typedef int (idbm_iface_op_fn)(void *data, node_rec_t *rec);
|
|
@@ -168,6 +171,7 @@ enum {
|
|
IDBM_PRINT_TYPE_NODE,
|
|
IDBM_PRINT_TYPE_IFACE,
|
|
IDBM_PRINT_TYPE_HOST_CHAP,
|
|
+ IDBM_PRINT_TYPE_FLASHNODE
|
|
};
|
|
|
|
extern void idbm_print(int type, void *rec, int show, FILE *f);
|
|
@@ -181,5 +185,9 @@ extern struct node_rec *
|
|
idbm_create_rec_from_boot_context(struct boot_context *context);
|
|
|
|
extern int idbm_print_host_chap_info(struct iscsi_chap_rec *chap);
|
|
+extern void idbm_recinfo_host_chap(struct iscsi_chap_rec *r, recinfo_t *ri);
|
|
+
|
|
+extern int idbm_print_flashnode_info(struct flashnode_rec *target);
|
|
+extern void idbm_recinfo_flashnode(struct flashnode_rec *r, recinfo_t *ri);
|
|
|
|
#endif /* IDBM_H */
|
|
diff --git a/usr/idbm_fields.h b/usr/idbm_fields.h
|
|
index 358d014..5790a03 100644
|
|
--- a/usr/idbm_fields.h
|
|
+++ b/usr/idbm_fields.h
|
|
@@ -89,6 +89,55 @@
|
|
#define IFACE_NUM "iface.iface_num"
|
|
#define IFACE_MTU "iface.mtu"
|
|
#define IFACE_PORT "iface.port"
|
|
+#define IFACE_DELAYED_ACK "iface.delayed_ack"
|
|
+#define IFACE_TCP_NAGLE "iface.tcp_nagle"
|
|
+#define IFACE_TCP_WSF_STATE "iface.tcp_wsf_state"
|
|
+#define IFACE_TCP_WSF "iface.tcp_wsf"
|
|
+#define IFACE_TCP_TIMER_SCALE "iface.tcp_timer_scale"
|
|
+#define IFACE_TCP_TIMESTAMP "iface.tcp_timestamp"
|
|
+#define IFACE_DHCP_DNS "iface.dhcp_dns"
|
|
+#define IFACE_DHCP_SLP_DA "iface.dhcp_slp_da"
|
|
+#define IFACE_TOS_STATE "iface.tos_state"
|
|
+#define IFACE_TOS "iface.tos"
|
|
+#define IFACE_GRAT_ARP "iface.gratuitous_arp"
|
|
+#define IFACE_DHCP_ALT_CID "iface.dhcp_alt_client_id_state"
|
|
+#define IFACE_DHCP_ALT_CID_STR "iface.dhcp_alt_client_id"
|
|
+#define IFACE_DHCP_REQ_VID "iface.dhcp_req_vendor_id_state"
|
|
+#define IFACE_DHCP_VID "iface.dhcp_vendor_id_state"
|
|
+#define IFACE_DHCP_VID_STR "iface.dhcp_vendor_id"
|
|
+#define IFACE_DHCP_LEARN_IQN "iface.dhcp_learn_iqn"
|
|
+#define IFACE_FRAGMENTATION "iface.fragmentation"
|
|
+#define IFACE_IN_FORWARD "iface.incoming_forwarding"
|
|
+#define IFACE_TTL "iface.ttl"
|
|
+#define IFACE_GRAT_NEIGHBOR_ADV "iface.gratuitous_neighbor_adv"
|
|
+#define IFACE_REDIRECT "iface.redirect"
|
|
+#define IFACE_IGNORE_ICMP_ECHO_REQ "iface.ignore_icmp_echo_request"
|
|
+#define IFACE_MLD "iface.mld"
|
|
+#define IFACE_FLOW_LABEL "iface.flow_label"
|
|
+#define IFACE_TRAFFIC_CLASS "iface.traffic_class"
|
|
+#define IFACE_HOP_LIMIT "iface.hop_limit"
|
|
+#define IFACE_ND_REACHABLE_TMO "iface.nd_reachable_tmo"
|
|
+#define IFACE_ND_REXMIT_TIME "iface.nd_rexmit_time"
|
|
+#define IFACE_ND_STALE_TMO "iface.nd_stale_tmo"
|
|
+#define IFACE_DUP_ADDR_DETECT_CNT "iface.dup_addr_detect_cnt"
|
|
+#define IFACE_RTR_ADV_LINK_MTU "iface.router_adv_link_mtu"
|
|
+#define IFACE_DEF_TMF_TMO "iface.def_task_mgmt_timeout"
|
|
+#define IFACE_HDRDGST "iface.header_digest"
|
|
+#define IFACE_DATADGST "iface.data_digest"
|
|
+#define IFACE_IMM_DATA "iface.immediate_data"
|
|
+#define IFACE_INITIAL_R2T "iface.initial_r2t"
|
|
+#define IFACE_DSEQ_INORDER "iface.data_seq_inorder"
|
|
+#define IFACE_DPDU_INORDER "iface.data_pdu_inorder"
|
|
+#define IFACE_ERL "iface.erl"
|
|
+#define IFACE_MAX_RECV_DLEN "iface.max_receive_data_len"
|
|
+#define IFACE_FIRST_BURST "iface.first_burst_len"
|
|
+#define IFACE_MAX_R2T "iface.max_outstanding_r2t"
|
|
+#define IFACE_MAX_BURST "iface.max_burst_len"
|
|
+#define IFACE_CHAP_AUTH "iface.chap_auth"
|
|
+#define IFACE_BIDI_CHAP "iface.bidi_chap"
|
|
+#define IFACE_STRICT_LOGIN_COMP "iface.strict_login_compliance"
|
|
+#define IFACE_DISCOVERY_AUTH "iface.discovery_auth"
|
|
+#define IFACE_DISCOVERY_LOGOUT "iface.discovery_logout"
|
|
|
|
/* discovery fields */
|
|
#define DISC_STARTUP "discovery.startup"
|
|
@@ -126,4 +175,67 @@
|
|
#define HOST_AUTH_PASSWORD_IN "host.auth.password_in"
|
|
#define HOST_AUTH_PASSWORD_IN_LEN "host.auth.password_in_length"
|
|
|
|
+/* flash target session fields */
|
|
+#define FLASHNODE_SESS_AUTO_SND_TGT_DISABLE "flashnode.session.auto_snd_tgt_disable"
|
|
+#define FLASHNODE_SESS_DISCOVERY_SESS "flashnode.session.discovery_session"
|
|
+#define FLASHNODE_SESS_PORTAL_TYPE "flashnode.session.portal_type"
|
|
+#define FLASHNODE_SESS_ENTRY_EN "flashnode.session.entry_enable"
|
|
+#define FLASHNODE_SESS_IMM_DATA_EN "flashnode.session.immediate_data"
|
|
+#define FLASHNODE_SESS_INITIAL_R2T_EN "flashnode.session.initial_r2t"
|
|
+#define FLASHNODE_SESS_DATASEQ_INORDER "flashnode.session.data_seq_in_order"
|
|
+#define FLASHNODE_SESS_PDU_INORDER "flashnode.session.data_pdu_in_order"
|
|
+#define FLASHNODE_SESS_CHAP_AUTH_EN "flashnode.session.chap_auth_en"
|
|
+#define FLASHNODE_SESS_DISCOVERY_LOGOUT_EN "flashnode.session.discovery_logout_en"
|
|
+#define FLASHNODE_SESS_BIDI_CHAP_EN "flashnode.session.bidi_chap_en"
|
|
+#define FLASHNODE_SESS_DISCOVERY_AUTH_OPTIONAL "flashnode.session.discovery_auth_optional"
|
|
+#define FLASHNODE_SESS_ERL "flashnode.session.erl"
|
|
+#define FLASHNODE_SESS_FIRST_BURST "flashnode.session.first_burst_len"
|
|
+#define FLASHNODE_SESS_DEF_TIME2WAIT "flashnode.session.def_time2wait"
|
|
+#define FLASHNODE_SESS_DEF_TIME2RETAIN "flashnode.session.def_time2retain"
|
|
+#define FLASHNODE_SESS_MAX_R2T "flashnode.session.max_outstanding_r2t"
|
|
+#define FLASHNODE_SESS_ISID "flashnode.session.isid"
|
|
+#define FLASHNODE_SESS_TSID "flashnode.session.tsid"
|
|
+#define FLASHNODE_SESS_MAX_BURST "flashnode.session.max_burst_len"
|
|
+#define FLASHNODE_SESS_DEF_TASKMGMT_TMO "flashnode.session.def_taskmgmt_tmo"
|
|
+#define FLASHNODE_SESS_ALIAS "flashnode.session.targetalias"
|
|
+#define FLASHNODE_SESS_NAME "flashnode.session.targetname"
|
|
+#define FLASHNODE_SESS_TPGT "flashnode.session.tpgt"
|
|
+#define FLASHNODE_SESS_DISCOVERY_PARENT_IDX "flashnode.session.discovery_parent_idx"
|
|
+#define FLASHNODE_SESS_DISCOVERY_PARENT_TYPE "flashnode.session.discovery_parent_type"
|
|
+#define FLASHNODE_SESS_CHAP_OUT_IDX "flashnode.session.chap_out_idx"
|
|
+#define FLASHNODE_SESS_CHAP_IN_IDX "flashnode.session.chap_in_idx"
|
|
+#define FLASHNODE_SESS_USERNAME "flashnode.session.username"
|
|
+#define FLASHNODE_SESS_USERNAME_IN "flashnode.session.username_in"
|
|
+#define FLASHNODE_SESS_PASSWORD "flashnode.session.password"
|
|
+#define FLASHNODE_SESS_PASSWORD_IN "flashnode.session.password_in"
|
|
+#define FLASHNODE_SESS_IS_BOOT_TGT "flashnode.session.is_boot_target"
|
|
+
|
|
+/* flash target connection fields */
|
|
+#define FLASHNODE_CONN_IS_FW_ASSIGNED_IPV6 "flashnode.conn[%d].is_fw_assigned_ipv6"
|
|
+#define FLASHNODE_CONN_HDR_DGST_EN "flashnode.conn[%d].header_digest_en"
|
|
+#define FLASHNODE_CONN_DATA_DGST_EN "flashnode.conn[%d].data_digest_en"
|
|
+#define FLASHNODE_CONN_SNACK_REQ_EN "flashnode.conn[%d].snack_req_en"
|
|
+#define FLASHNODE_CONN_TCP_TIMESTAMP_STAT "flashnode.conn[%d].tcp_timestamp_stat"
|
|
+#define FLASHNODE_CONN_TCP_NAGLE_DISABLE "flashnode.conn[%d].tcp_nagle_disable"
|
|
+#define FLASHNODE_CONN_TCP_WSF_DISABLE "flashnode.conn[%d].tcp_wsf_disable"
|
|
+#define FLASHNODE_CONN_TCP_TIMER_SCALE "flashnode.conn[%d].tcp_timer_scale"
|
|
+#define FLASHNODE_CONN_TCP_TIMESTAMP_EN "flashnode.conn[%d].tcp_timestamp_en"
|
|
+#define FLASHNODE_CONN_IP_FRAG_DISABLE "flashnode.conn[%d].fragment_disable"
|
|
+#define FLASHNODE_CONN_MAX_RECV_DLENGTH "flashnode.conn[%d].max_recv_dlength"
|
|
+#define FLASHNODE_CONN_MAX_XMIT_DLENGTH "flashnode.conn[%d].max_xmit_dlength"
|
|
+#define FLASHNODE_CONN_KEEPALIVE_TMO "flashnode.conn[%d].keepalive_tmo"
|
|
+#define FLASHNODE_CONN_PORT "flashnode.conn[%d].port"
|
|
+#define FLASHNODE_CONN_IPADDR "flashnode.conn[%d].ipaddress"
|
|
+#define FLASHNODE_CONN_REDIRECT_IPADDR "flashnode.conn[%d].redirect_ipaddr"
|
|
+#define FLASHNODE_CONN_MAX_SEGMENT_SIZE "flashnode.conn[%d].max_segment_size"
|
|
+#define FLASHNODE_CONN_LOCAL_PORT "flashnode.conn[%d].local_port"
|
|
+#define FLASHNODE_CONN_IPV4_TOS "flashnode.conn[%d].ipv4_tos"
|
|
+#define FLASHNODE_CONN_IPV6_TC "flashnode.conn[%d].ipv6_traffic_class"
|
|
+#define FLASHNODE_CONN_IPV6_FLOW_LABEL "flashnode.conn[%d].ipv6_flow_label"
|
|
+#define FLASHNODE_CONN_LINK_LOCAL_IPV6 "flashnode.conn[%d].link_local_ipv6"
|
|
+#define FLASHNODE_CONN_TCP_XMIT_WSF "flashnode.conn[%d].tcp_xmit_wsf"
|
|
+#define FLASHNODE_CONN_TCP_RECV_WSF "flashnode.conn[%d].tcp_recv_wsf"
|
|
+#define FLASHNODE_CONN_STATSN "flashnode.conn[%d].statsn"
|
|
+#define FLASHNODE_CONN_EXP_STATSN "flashnode.conn[%d].exp_statsn"
|
|
+
|
|
#endif
|
|
diff --git a/usr/iface.c b/usr/iface.c
|
|
index 3a9582e..0a7f0bb 100644
|
|
--- a/usr/iface.c
|
|
+++ b/usr/iface.c
|
|
@@ -227,7 +227,7 @@ int iface_conf_delete(struct iface_rec *iface)
|
|
def_iface = iface_match_default(iface);
|
|
if (def_iface) {
|
|
log_error("iface %s is a special interface and "
|
|
- "cannot be deleted.\n", iface->name);
|
|
+ "cannot be deleted.", iface->name);
|
|
return ISCSI_ERR_INVAL;
|
|
}
|
|
|
|
@@ -259,7 +259,7 @@ int iface_conf_write(struct iface_rec *iface)
|
|
def_iface = iface_match_default(iface);
|
|
if (def_iface) {
|
|
log_error("iface %s is a special interface and "
|
|
- "is not stored in %s.\n", iface->name,
|
|
+ "is not stored in %s.", iface->name,
|
|
IFACE_CONFIG_DIR);
|
|
return ISCSI_ERR_INVAL;
|
|
}
|
|
@@ -299,7 +299,7 @@ int iface_conf_update(struct list_head *params, struct iface_rec *iface)
|
|
def_iface = iface_match_default(iface);
|
|
if (def_iface) {
|
|
log_error("iface %s is a special interface and "
|
|
- "cannot be modified.\n", iface->name);
|
|
+ "cannot be modified.", iface->name);
|
|
return ISCSI_ERR_INVAL;
|
|
}
|
|
|
|
@@ -450,8 +450,10 @@ int iface_get_iptype(struct iface_rec *iface)
|
|
/* try to figure out by name */
|
|
if (strstr(iface->name, "ipv4"))
|
|
return ISCSI_IFACE_TYPE_IPV4;
|
|
- else
|
|
+ else if (strstr(iface->name, "ipv6"))
|
|
return ISCSI_IFACE_TYPE_IPV6;
|
|
+ else /* assume ipv4 by default */
|
|
+ return ISCSI_IFACE_TYPE_IPV4;
|
|
} else {
|
|
if (strcmp(iface->bootproto, "dhcp") &&
|
|
!strstr(iface->ipaddress, "."))
|
|
@@ -470,17 +472,14 @@ static int iface_setup_binding_from_kern_iface(void *data,
|
|
|
|
if (!strlen(hinfo->iface.hwaddress)) {
|
|
log_error("Invalid offload iSCSI host %u. Missing "
|
|
- "hwaddress. Try upgrading %s driver.\n",
|
|
+ "hwaddress. Try upgrading %s driver.",
|
|
hinfo->host_no, hinfo->iface.transport_name);
|
|
return 0;
|
|
}
|
|
|
|
memset(&iface, 0, sizeof(struct iface_rec));
|
|
- strcpy(iface.hwaddress, hinfo->iface.hwaddress);
|
|
- strcpy(iface.transport_name, hinfo->iface.transport_name);
|
|
-
|
|
if (kern_iface) {
|
|
- iface.iface_num = kern_iface->iface_num;
|
|
+ memcpy(&iface, kern_iface, sizeof(iface));
|
|
|
|
snprintf(iface.name, sizeof(iface.name), "%s.%s.%s.%u",
|
|
kern_iface->transport_name,
|
|
@@ -492,6 +491,9 @@ static int iface_setup_binding_from_kern_iface(void *data,
|
|
hinfo->iface.transport_name, hinfo->iface.hwaddress);
|
|
}
|
|
|
|
+ strcpy(iface.hwaddress, hinfo->iface.hwaddress);
|
|
+ strcpy(iface.transport_name, hinfo->iface.transport_name);
|
|
+
|
|
memset(iface_path, 0, sizeof(iface_path));
|
|
snprintf(iface_path, PATH_MAX, "%s/%s", IFACE_CONFIG_DIR,
|
|
iface.name);
|
|
@@ -601,6 +603,105 @@ void iface_copy(struct iface_rec *dst, struct iface_rec *src)
|
|
dst->mtu = src->mtu;
|
|
if (src->port)
|
|
dst->port = src->port;
|
|
+ if (strlen(src->delayed_ack))
|
|
+ strcpy(dst->delayed_ack, src->delayed_ack);
|
|
+ if (strlen(src->nagle))
|
|
+ strcpy(dst->nagle, src->nagle);
|
|
+ if (strlen(src->tcp_wsf_state))
|
|
+ strcpy(dst->tcp_wsf_state, src->tcp_wsf_state);
|
|
+ if (src->tcp_wsf)
|
|
+ dst->tcp_wsf = src->tcp_wsf;
|
|
+ if (src->tcp_timer_scale)
|
|
+ dst->tcp_timer_scale = src->tcp_timer_scale;
|
|
+ if (strlen(src->tcp_timestamp))
|
|
+ strcpy(dst->tcp_timestamp, src->tcp_timestamp);
|
|
+ if (strlen(src->dhcp_dns))
|
|
+ strcpy(dst->dhcp_dns, src->dhcp_dns);
|
|
+ if (strlen(src->dhcp_slp_da))
|
|
+ strcpy(dst->dhcp_slp_da, src->dhcp_slp_da);
|
|
+ if (strlen(src->tos_state))
|
|
+ strcpy(dst->tos_state, src->tos_state);
|
|
+ if (src->tos)
|
|
+ dst->tos = src->tos;
|
|
+ if (strlen(src->gratuitous_arp))
|
|
+ strcpy(dst->gratuitous_arp, src->gratuitous_arp);
|
|
+ if (strlen(src->dhcp_alt_client_id_state))
|
|
+ strcpy(dst->dhcp_alt_client_id_state,
|
|
+ src->dhcp_alt_client_id_state);
|
|
+ if (strlen(src->dhcp_alt_client_id))
|
|
+ strcpy(dst->dhcp_alt_client_id, src->dhcp_alt_client_id);
|
|
+ if (strlen(src->dhcp_req_vendor_id_state))
|
|
+ strcpy(dst->dhcp_req_vendor_id_state,
|
|
+ src->dhcp_req_vendor_id_state);
|
|
+ if (strlen(src->dhcp_vendor_id_state))
|
|
+ strcpy(dst->dhcp_vendor_id_state, src->dhcp_vendor_id_state);
|
|
+ if (strlen(src->dhcp_vendor_id))
|
|
+ strcpy(dst->dhcp_vendor_id, src->dhcp_vendor_id);
|
|
+ if (strlen(src->dhcp_learn_iqn))
|
|
+ strcpy(dst->dhcp_learn_iqn, src->dhcp_learn_iqn);
|
|
+ if (strlen(src->fragmentation))
|
|
+ strcpy(dst->fragmentation, src->fragmentation);
|
|
+ if (strlen(src->incoming_forwarding))
|
|
+ strcpy(dst->incoming_forwarding, src->incoming_forwarding);
|
|
+ if (src->ttl)
|
|
+ dst->ttl = src->ttl;
|
|
+ if (strlen(src->gratuitous_neighbor_adv))
|
|
+ strcpy(dst->gratuitous_neighbor_adv,
|
|
+ src->gratuitous_neighbor_adv);
|
|
+ if (strlen(src->redirect))
|
|
+ strcpy(dst->redirect, src->redirect);
|
|
+ if (strlen(src->mld))
|
|
+ strcpy(dst->mld, src->mld);
|
|
+ if (src->flow_label)
|
|
+ dst->flow_label = src->flow_label;
|
|
+ if (src->traffic_class)
|
|
+ dst->traffic_class = src->traffic_class;
|
|
+ if (src->hop_limit)
|
|
+ dst->hop_limit = src->hop_limit;
|
|
+ if (src->nd_reachable_tmo)
|
|
+ dst->nd_reachable_tmo = src->nd_reachable_tmo;
|
|
+ if (src->nd_rexmit_time)
|
|
+ dst->nd_rexmit_time = src->nd_rexmit_time;
|
|
+ if (src->nd_stale_tmo)
|
|
+ dst->nd_stale_tmo = src->nd_stale_tmo;
|
|
+ if (src->dup_addr_detect_cnt)
|
|
+ dst->dup_addr_detect_cnt = src->dup_addr_detect_cnt;
|
|
+ if (src->router_adv_link_mtu)
|
|
+ dst->router_adv_link_mtu = src->router_adv_link_mtu;
|
|
+ if (src->def_task_mgmt_tmo)
|
|
+ dst->def_task_mgmt_tmo = src->def_task_mgmt_tmo;
|
|
+ if (strlen(src->header_digest))
|
|
+ strcpy(dst->header_digest, src->header_digest);
|
|
+ if (strlen(src->data_digest))
|
|
+ strcpy(dst->data_digest, src->data_digest);
|
|
+ if (strlen(src->immediate_data))
|
|
+ strcpy(dst->immediate_data, src->immediate_data);
|
|
+ if (strlen(src->initial_r2t))
|
|
+ strcpy(dst->initial_r2t, src->initial_r2t);
|
|
+ if (strlen(src->data_seq_inorder))
|
|
+ strcpy(dst->data_seq_inorder, src->data_seq_inorder);
|
|
+ if (strlen(src->data_pdu_inorder))
|
|
+ strcpy(dst->data_pdu_inorder, src->data_pdu_inorder);
|
|
+ if (src->erl)
|
|
+ dst->erl = src->erl;
|
|
+ if (src->max_recv_dlength)
|
|
+ dst->max_recv_dlength = src->max_recv_dlength;
|
|
+ if (src->first_burst_len)
|
|
+ dst->first_burst_len = src->first_burst_len;
|
|
+ if (src->max_out_r2t)
|
|
+ dst->max_out_r2t = src->max_out_r2t;
|
|
+ if (src->max_burst_len)
|
|
+ dst->max_burst_len = src->max_burst_len;
|
|
+ if (strlen(src->chap_auth))
|
|
+ strcpy(dst->chap_auth, src->chap_auth);
|
|
+ if (strlen(src->bidi_chap))
|
|
+ strcpy(dst->bidi_chap, src->bidi_chap);
|
|
+ if (strlen(src->strict_login_comp))
|
|
+ strcpy(dst->strict_login_comp, src->strict_login_comp);
|
|
+ if (strlen(src->discovery_auth))
|
|
+ strcpy(dst->discovery_auth, src->discovery_auth);
|
|
+ if (strlen(src->discovery_logout))
|
|
+ strcpy(dst->discovery_logout, src->discovery_logout);
|
|
if (strlen(src->hwaddress))
|
|
strcpy(dst->hwaddress, src->hwaddress);
|
|
if (strlen(src->transport_name))
|
|
@@ -894,7 +995,6 @@ int iface_setup_from_boot_context(struct iface_rec *iface,
|
|
struct boot_context *context)
|
|
{
|
|
struct iscsi_transport *t = NULL;
|
|
- char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN];
|
|
uint32_t hostno;
|
|
|
|
if (strlen(context->initiatorname))
|
|
@@ -902,7 +1002,8 @@ int iface_setup_from_boot_context(struct iface_rec *iface,
|
|
sizeof(iface->iname));
|
|
|
|
if (strlen(context->scsi_host_name)) {
|
|
- if (sscanf(context->scsi_host_name, "iscsi_boot%u", &hostno) != 1) {
|
|
+ if (sscanf(context->scsi_host_name,
|
|
+ "iscsi_boot%u", &hostno) != 1) {
|
|
log_error("Could not parse %s's host no.",
|
|
context->scsi_host_name);
|
|
return 0;
|
|
@@ -910,6 +1011,8 @@ int iface_setup_from_boot_context(struct iface_rec *iface,
|
|
} else if (strlen(context->iface)) {
|
|
/* this ifdef is only temp until distros and firmwares are updated */
|
|
#ifdef OFFLOAD_BOOT_SUPPORTED
|
|
+ char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN];
|
|
+ int rc;
|
|
|
|
memset(transport_name, 0, ISCSI_TRANSPORT_NAME_MAXLEN);
|
|
/* make sure offload driver is loaded */
|
|
@@ -917,6 +1020,10 @@ int iface_setup_from_boot_context(struct iface_rec *iface,
|
|
transport_name))
|
|
t = iscsi_sysfs_get_transport_by_name(transport_name);
|
|
|
|
+ if (net_ifup_netdev(context->iface))
|
|
+ log_warning("Could not bring up netdev %s for boot",
|
|
+ context->iface);
|
|
+
|
|
hostno = iscsi_sysfs_get_host_no_from_hwaddress(context->mac,
|
|
&rc);
|
|
if (rc) {
|
|
@@ -925,7 +1032,7 @@ int iface_setup_from_boot_context(struct iface_rec *iface,
|
|
* host then the MAC must be for network card, so boot
|
|
* is not going to be offloaded.
|
|
*/
|
|
- log_debug(3, "Could not match %s to host\n",
|
|
+ log_debug(3, "Could not match %s to host",
|
|
context->mac);
|
|
return 0;
|
|
}
|
|
@@ -957,7 +1064,12 @@ int iface_setup_from_boot_context(struct iface_rec *iface,
|
|
sizeof(iface->hwaddress));
|
|
strlcpy(iface->ipaddress, context->ipaddr,
|
|
sizeof(iface->ipaddress));
|
|
- log_debug(1, "iface " iface_fmt "\n", iface_str(iface));
|
|
+ iface->vlan_id = atoi(context->vlan);
|
|
+ strlcpy(iface->subnet_mask, context->mask,
|
|
+ sizeof(iface->subnet_mask));
|
|
+ strlcpy(iface->gateway, context->gateway,
|
|
+ sizeof(iface->gateway));
|
|
+ log_debug(1, "iface " iface_fmt "", iface_str(iface));
|
|
return 1;
|
|
}
|
|
|
|
@@ -982,7 +1094,7 @@ int iface_create_ifaces_from_boot_contexts(struct list_head *ifaces,
|
|
/* use dummy name. If valid it will get overwritten below */
|
|
iface = iface_alloc(DEFAULT_IFACENAME, &rc);
|
|
if (!iface) {
|
|
- log_error("Could not setup iface %s for boot\n",
|
|
+ log_error("Could not setup iface %s for boot",
|
|
context->iface);
|
|
goto fail;
|
|
}
|
|
@@ -1016,6 +1128,79 @@ struct iface_param_count {
|
|
int count;
|
|
};
|
|
|
|
+#define IFACE_NET_PARAM_EN_CNT(param_val, cnt) { \
|
|
+ if (!strcmp(param_val, "disable") || \
|
|
+ !strcmp(param_val, "enable")) \
|
|
+ (*cnt)++; \
|
|
+}
|
|
+
|
|
+/**
|
|
+ * iface_get_common_param_count - Gets common parameters count for given iface
|
|
+ * @iface: iface to setup
|
|
+ * @count: number of parameters to set
|
|
+ */
|
|
+static void iface_get_common_param_count(struct iface_rec *iface, int *count)
|
|
+{
|
|
+ if (strcmp(iface->vlan_state, "disable")) {
|
|
+ /* vlan_state enabled */
|
|
+ (*count)++;
|
|
+
|
|
+ if (iface->vlan_id)
|
|
+ /* For vlan value */
|
|
+ (*count)++;
|
|
+ } else {
|
|
+ /* vlan_state disabled */
|
|
+ (*count)++;
|
|
+ }
|
|
+
|
|
+ if (iface->mtu)
|
|
+ (*count)++;
|
|
+
|
|
+ if (iface->port)
|
|
+ (*count)++;
|
|
+
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->delayed_ack, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->nagle, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->tcp_wsf_state, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->tcp_timestamp, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->redirect, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->header_digest, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->data_digest, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->immediate_data, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->initial_r2t, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->data_seq_inorder, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->data_pdu_inorder, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->chap_auth, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->bidi_chap, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->strict_login_comp, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->discovery_auth, count);
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->discovery_logout, count);
|
|
+
|
|
+ if (iface->tcp_wsf)
|
|
+ (*count)++;
|
|
+
|
|
+ if (iface->tcp_timer_scale)
|
|
+ (*count)++;
|
|
+
|
|
+ if (iface->def_task_mgmt_tmo)
|
|
+ (*count)++;
|
|
+
|
|
+ if (iface->erl)
|
|
+ (*count)++;
|
|
+
|
|
+ if (iface->max_recv_dlength)
|
|
+ (*count)++;
|
|
+
|
|
+ if (iface->first_burst_len)
|
|
+ (*count)++;
|
|
+
|
|
+ if (iface->max_burst_len)
|
|
+ (*count)++;
|
|
+
|
|
+ if (iface->max_out_r2t)
|
|
+ (*count)++;
|
|
+}
|
|
+
|
|
/**
|
|
* __iface_get_param_count - Gets netconfig parameter count for given iface
|
|
* @data: iface_param_count structure
|
|
@@ -1034,10 +1219,10 @@ static int __iface_get_param_count(void *data, struct iface_rec *iface)
|
|
if (iptype == ISCSI_IFACE_TYPE_IPV4) {
|
|
|
|
if (strcmp(iface->state, "disable")) {
|
|
- if (strstr(iface->bootproto, "dhcp"))
|
|
+ if (strstr(iface->bootproto, "dhcp")) {
|
|
/* DHCP enabled */
|
|
count++;
|
|
- else {
|
|
+ } else {
|
|
/* DHCP disabled */
|
|
count++;
|
|
|
|
@@ -1052,12 +1237,13 @@ static int __iface_get_param_count(void *data, struct iface_rec *iface)
|
|
if (strstr(iface->gateway, "."))
|
|
/* User configured Gateway */
|
|
count++;
|
|
- } else
|
|
+ } else {
|
|
/*
|
|
* IPv4 Address not valid, decrement
|
|
* count of DHCP
|
|
*/
|
|
count--;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -1068,37 +1254,68 @@ static int __iface_get_param_count(void *data, struct iface_rec *iface)
|
|
/* iface state */
|
|
count++;
|
|
|
|
- if (strcmp(iface->vlan_state, "disable")) {
|
|
- /* vlan_state enabled */
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->dhcp_dns,
|
|
+ &count);
|
|
+
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->dhcp_slp_da,
|
|
+ &count);
|
|
+
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->tos_state,
|
|
+ &count);
|
|
+
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->gratuitous_arp,
|
|
+ &count);
|
|
+
|
|
+ IFACE_NET_PARAM_EN_CNT(
|
|
+ iface->dhcp_alt_client_id_state,
|
|
+ &count);
|
|
+
|
|
+ if (iface->dhcp_alt_client_id[0])
|
|
count++;
|
|
|
|
- if (iface->vlan_id)
|
|
- /* For vlan value */
|
|
- count++;
|
|
- } else
|
|
- /* vlan_state disabled */
|
|
+ IFACE_NET_PARAM_EN_CNT(
|
|
+ iface->dhcp_req_vendor_id_state,
|
|
+ &count);
|
|
+
|
|
+ IFACE_NET_PARAM_EN_CNT(
|
|
+ iface->dhcp_vendor_id_state,
|
|
+ &count);
|
|
+
|
|
+ if (iface->dhcp_vendor_id[0])
|
|
count++;
|
|
|
|
- if (iface->mtu)
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->dhcp_learn_iqn,
|
|
+ &count);
|
|
+
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->fragmentation,
|
|
+ &count);
|
|
+
|
|
+ IFACE_NET_PARAM_EN_CNT(
|
|
+ iface->incoming_forwarding,
|
|
+ &count);
|
|
+
|
|
+ if (iface->tos)
|
|
count++;
|
|
|
|
- if (iface->port)
|
|
+ if (iface->ttl)
|
|
count++;
|
|
+
|
|
+ iface_get_common_param_count(iface, &count);
|
|
}
|
|
- } else
|
|
+ } else {
|
|
/* IPv4 is disabled, iface state */
|
|
count++;
|
|
-
|
|
+ }
|
|
} else if (iptype == ISCSI_IFACE_TYPE_IPV6) {
|
|
|
|
if (strcmp(iface->state, "disable")) {
|
|
|
|
/* IPv6 Address */
|
|
if (strstr(iface->ipv6_autocfg, "nd") ||
|
|
- strstr(iface->ipv6_autocfg, "dhcpv6"))
|
|
+ strstr(iface->ipv6_autocfg, "dhcpv6")) {
|
|
/* Autocfg enabled */
|
|
count++;
|
|
- else {
|
|
+ } else {
|
|
/* Autocfg disabled */
|
|
count++;
|
|
|
|
@@ -1159,26 +1376,42 @@ static int __iface_get_param_count(void *data, struct iface_rec *iface)
|
|
/* iface state */
|
|
count++;
|
|
|
|
- if (strcmp(iface->vlan_state, "disable")) {
|
|
- /* vlan_state enabled */
|
|
+ IFACE_NET_PARAM_EN_CNT(
|
|
+ iface->gratuitous_neighbor_adv,
|
|
+ &count);
|
|
+
|
|
+ IFACE_NET_PARAM_EN_CNT(iface->mld, &count);
|
|
+
|
|
+ if (iface->flow_label)
|
|
+ count++;
|
|
+
|
|
+ if (iface->traffic_class)
|
|
+ count++;
|
|
+
|
|
+ if (iface->hop_limit)
|
|
count++;
|
|
|
|
- if (iface->vlan_id)
|
|
- /* For vlan value */
|
|
- count++;
|
|
- } else
|
|
- /* vlan_state disabled */
|
|
+ if (iface->nd_reachable_tmo)
|
|
count++;
|
|
|
|
- if (iface->mtu)
|
|
+ if (iface->nd_rexmit_time)
|
|
count++;
|
|
|
|
- if (iface->port)
|
|
+ if (iface->nd_stale_tmo)
|
|
count++;
|
|
+
|
|
+ if (iface->dup_addr_detect_cnt)
|
|
+ count++;
|
|
+
|
|
+ if (iface->router_adv_link_mtu)
|
|
+ count++;
|
|
+
|
|
+ iface_get_common_param_count(iface, &count);
|
|
}
|
|
- } else
|
|
+ } else {
|
|
/* IPv6 is disabled, iface state */
|
|
count++;
|
|
+ }
|
|
}
|
|
|
|
iface_params->count += count;
|
|
@@ -1197,7 +1430,7 @@ int iface_get_param_count(struct iface_rec *iface, int iface_all)
|
|
int num_found = 0, rc;
|
|
struct iface_param_count iface_params;
|
|
|
|
- log_debug(8, "In iface_get_param_count\n");
|
|
+ log_debug(8, "In iface_get_param_count");
|
|
|
|
iface_params.primary = iface;
|
|
iface_params.count = 0;
|
|
@@ -1208,63 +1441,73 @@ int iface_get_param_count(struct iface_rec *iface, int iface_all)
|
|
else
|
|
rc = __iface_get_param_count(&iface_params, iface);
|
|
|
|
- log_debug(8, "iface_get_param_count: rc = %d, count = %d\n",
|
|
+ log_debug(8, "iface_get_param_count: rc = %d, count = %d",
|
|
rc, iface_params.count);
|
|
return iface_params.count;
|
|
}
|
|
|
|
-/* IPv4/IPv6 Port: 3260 or User defined */
|
|
-static int iface_fill_port(struct iovec *iov, struct iface_rec *iface,
|
|
- uint32_t iface_type)
|
|
+/* write integer parameter value */
|
|
+static int iface_fill_int_param_val(struct iovec *iov, uint32_t iface_num,
|
|
+ uint8_t iface_type, uint16_t param,
|
|
+ uint8_t param_type, uint32_t param_len,
|
|
+ uint32_t param_val)
|
|
{
|
|
int len;
|
|
struct iscsi_iface_param_info *net_param;
|
|
- uint16_t port = 3260;
|
|
struct nlattr *attr;
|
|
+ uint8_t val8 = 0;
|
|
+ uint16_t val16 = 0;
|
|
+ uint32_t val32 = 0;
|
|
+ char *val = NULL;
|
|
|
|
- len = sizeof(struct iscsi_iface_param_info) + sizeof(port);
|
|
- iov->iov_base = iscsi_nla_alloc(ISCSI_NET_PARAM_PORT, len);
|
|
- if (!iov->iov_base)
|
|
- return 1;
|
|
- attr = iov->iov_base;
|
|
- iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
-
|
|
- net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr);
|
|
- net_param->param = ISCSI_NET_PARAM_PORT;
|
|
- net_param->iface_type = iface_type;
|
|
- net_param->iface_num = iface->iface_num;
|
|
- net_param->param_type = ISCSI_NET_PARAM;
|
|
- net_param->len = 2;
|
|
- if (iface->port)
|
|
- port = iface->port;
|
|
- memcpy(net_param->value, &port, net_param->len);
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int iface_fill_mtu(struct iovec *iov, struct iface_rec *iface,
|
|
- uint32_t iface_type)
|
|
-{
|
|
- int len;
|
|
- struct iscsi_iface_param_info *net_param;
|
|
- uint16_t mtu = 0;
|
|
- struct nlattr *attr;
|
|
-
|
|
- len = sizeof(struct iscsi_iface_param_info) + 2;
|
|
- iov->iov_base = iscsi_nla_alloc(ISCSI_NET_PARAM_MTU, len);
|
|
+ len = sizeof(struct iscsi_iface_param_info) + param_len;
|
|
+ iov->iov_base = iscsi_nla_alloc(param, len);
|
|
if (!(iov->iov_base))
|
|
return 1;
|
|
+
|
|
attr = iov->iov_base;
|
|
iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
-
|
|
net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr);
|
|
- net_param->param = ISCSI_NET_PARAM_MTU;
|
|
+ net_param->iface_num = iface_num;
|
|
+ net_param->len = param_len;
|
|
+ net_param->param = param;
|
|
net_param->iface_type = iface_type;
|
|
- net_param->iface_num = iface->iface_num;
|
|
- net_param->param_type = ISCSI_NET_PARAM;
|
|
- net_param->len = 2;
|
|
- mtu = iface->mtu;
|
|
- memcpy(net_param->value, &mtu, net_param->len);
|
|
+ net_param->param_type = param_type;
|
|
+ switch (param_len) {
|
|
+ case 1:
|
|
+ val8 = (uint8_t)param_val;
|
|
+ val = (char *)&val8;
|
|
+ break;
|
|
+
|
|
+ case 2:
|
|
+ val16 = (uint16_t)param_val;
|
|
+ val = (char *)&val16;
|
|
+ break;
|
|
+
|
|
+ case 4:
|
|
+ val32 = (uint32_t)param_val;
|
|
+ val = (char *)&val32;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ goto free;
|
|
+ }
|
|
+ memcpy(net_param->value, val, param_len);
|
|
return 0;
|
|
+free:
|
|
+ free(iov->iov_base);
|
|
+ iov->iov_base = NULL;
|
|
+ iov->iov_len = 0;
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+#define IFACE_SET_PARAM_INTVAL(iov, inum, itype, param, ptype, plen, \
|
|
+ ival, gcnt, lcnt) { \
|
|
+ if (ival && !iface_fill_int_param_val(iov, inum, itype, param, \
|
|
+ ptype, plen, ival)) { \
|
|
+ (*gcnt)++; \
|
|
+ (*lcnt)++; \
|
|
+ } \
|
|
}
|
|
|
|
/* IPv4/IPv6 VLAN_ID: decimal value <= 4095 */
|
|
@@ -1301,60 +1544,52 @@ static int iface_fill_vlan_id(struct iovec *iov, struct iface_rec *iface,
|
|
return 0;
|
|
}
|
|
|
|
-/* IPv4/IPv6 VLAN state: disable/enable */
|
|
-static int iface_fill_vlan_state(struct iovec *iov, struct iface_rec *iface,
|
|
- uint32_t iface_type)
|
|
+/* disable/enable parameters */
|
|
+static int iface_fill_param_state(struct iovec *iov, uint32_t iface_num,
|
|
+ uint8_t iface_type, uint16_t param,
|
|
+ uint8_t param_type, char *param_val)
|
|
{
|
|
int len;
|
|
struct iscsi_iface_param_info *net_param;
|
|
struct nlattr *attr;
|
|
|
|
+ if (!param_val[0])
|
|
+ return 1;
|
|
+
|
|
len = sizeof(struct iscsi_iface_param_info) + 1;
|
|
- iov->iov_base = iscsi_nla_alloc(ISCSI_NET_PARAM_VLAN_ENABLED, len);
|
|
+ iov->iov_base = iscsi_nla_alloc(param, len);
|
|
if (!(iov->iov_base))
|
|
return 1;
|
|
|
|
attr = iov->iov_base;
|
|
iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr);
|
|
- net_param->param = ISCSI_NET_PARAM_VLAN_ENABLED;
|
|
- net_param->iface_type = iface_type;
|
|
- net_param->iface_num = iface->iface_num;
|
|
- net_param->param_type = ISCSI_NET_PARAM;
|
|
+ net_param->iface_num = iface_num;
|
|
net_param->len = 1;
|
|
- if (strcmp(iface->vlan_state, "disable") && iface->vlan_id)
|
|
- net_param->value[0] = ISCSI_VLAN_ENABLE;
|
|
- else /* Assume disabled */
|
|
- net_param->value[0] = ISCSI_VLAN_DISABLE;
|
|
+ net_param->param = param;
|
|
+ net_param->iface_type = iface_type;
|
|
+ net_param->param_type = param_type;
|
|
+ if (!strcmp(param_val, "disable"))
|
|
+ net_param->value[0] = ISCSI_NET_PARAM_DISABLE;
|
|
+ else if (!strcmp(param_val, "enable"))
|
|
+ net_param->value[0] = ISCSI_NET_PARAM_ENABLE;
|
|
+ else
|
|
+ goto free;
|
|
return 0;
|
|
+free:
|
|
+ free(iov->iov_base);
|
|
+ iov->iov_base = NULL;
|
|
+ iov->iov_len = 0;
|
|
+ return 1;
|
|
}
|
|
|
|
-/* IPv4/IPv6 Network state: disable/enable */
|
|
-static int iface_fill_net_state(struct iovec *iov, struct iface_rec *iface,
|
|
- uint32_t iface_type)
|
|
-{
|
|
- int len;
|
|
- struct iscsi_iface_param_info *net_param;
|
|
- struct nlattr *attr;
|
|
-
|
|
- len = sizeof(struct iscsi_iface_param_info) + 1;
|
|
- iov->iov_base = iscsi_nla_alloc(ISCSI_NET_PARAM_IFACE_ENABLE, len);
|
|
- if (!(iov->iov_base))
|
|
- return 1;
|
|
-
|
|
- attr = iov->iov_base;
|
|
- iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
- net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr);
|
|
- net_param->param = ISCSI_NET_PARAM_IFACE_ENABLE;
|
|
- net_param->iface_type = iface_type;
|
|
- net_param->iface_num = iface->iface_num;
|
|
- net_param->param_type = ISCSI_NET_PARAM;
|
|
- net_param->len = 1;
|
|
- if (!strcmp(iface->state, "disable"))
|
|
- net_param->value[0] = ISCSI_IFACE_DISABLE;
|
|
- else /* Assume enabled */
|
|
- net_param->value[0] = ISCSI_IFACE_ENABLE;
|
|
- return 0;
|
|
+#define IFACE_SET_PARAM_STATE(iov, inum, itype, param, ptype, ival, \
|
|
+ gcnt, lcnt) { \
|
|
+ if (!iface_fill_param_state(iov, inum, itype, param, ptype, \
|
|
+ ival)) { \
|
|
+ (*gcnt)++; \
|
|
+ (*lcnt)++; \
|
|
+ } \
|
|
}
|
|
|
|
/* IPv4 Bootproto: DHCP/static */
|
|
@@ -1474,8 +1709,8 @@ static int iface_fill_router_autocfg(struct iovec *iov, struct iface_rec *iface)
|
|
}
|
|
|
|
/* IPv4 IPAddress/Subnet Mask/Gateway: 4 bytes */
|
|
-static int iface_fill_net_ipv4_addr(struct iovec *iov, struct iface_rec *iface,
|
|
- uint32_t param)
|
|
+static int iface_fill_net_ipv4_addr(struct iovec *iov, uint32_t iface_num,
|
|
+ uint16_t param, char *param_val)
|
|
{
|
|
int rc = 1;
|
|
int len;
|
|
@@ -1492,29 +1727,12 @@ static int iface_fill_net_ipv4_addr(struct iovec *iov, struct iface_rec *iface,
|
|
net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr);
|
|
net_param->param = param;
|
|
net_param->iface_type = ISCSI_IFACE_TYPE_IPV4;
|
|
- net_param->iface_num = iface->iface_num;
|
|
+ net_param->iface_num = iface_num;
|
|
net_param->len = 4;
|
|
net_param->param_type = ISCSI_NET_PARAM;
|
|
-
|
|
- switch (param) {
|
|
- case ISCSI_NET_PARAM_IPV4_ADDR:
|
|
- rc = inet_pton(AF_INET, iface->ipaddress, net_param->value);
|
|
- if (rc <= 0)
|
|
- goto free;
|
|
- break;
|
|
- case ISCSI_NET_PARAM_IPV4_SUBNET:
|
|
- rc = inet_pton(AF_INET, iface->subnet_mask, net_param->value);
|
|
- if (rc <= 0)
|
|
- goto free;
|
|
- break;
|
|
- case ISCSI_NET_PARAM_IPV4_GW:
|
|
- rc = inet_pton(AF_INET, iface->gateway, net_param->value);
|
|
- if (rc <= 0)
|
|
- goto free;
|
|
- break;
|
|
- default:
|
|
+ rc = inet_pton(AF_INET, param_val, net_param->value);
|
|
+ if (rc <= 0)
|
|
goto free;
|
|
- }
|
|
|
|
/* validate */
|
|
if (!net_param->value[0] && !net_param->value[1] &&
|
|
@@ -1529,9 +1747,19 @@ free:
|
|
return 1;
|
|
}
|
|
|
|
+#define IFACE_SET_NET_PARAM_IPV4_ADDR(iov, inum, param, ival, gcnt, \
|
|
+ lcnt) { \
|
|
+ if (strstr(ival, ".")) { \
|
|
+ if (!iface_fill_net_ipv4_addr(iov, inum, param, ival)) {\
|
|
+ (*gcnt)++; \
|
|
+ (*lcnt)++; \
|
|
+ } \
|
|
+ } \
|
|
+}
|
|
+
|
|
/* IPv6 IPAddress/LinkLocal/Router: 16 bytes */
|
|
-static int iface_fill_net_ipv6_addr(struct iovec *iov, struct iface_rec *iface,
|
|
- uint32_t param)
|
|
+static int iface_fill_net_ipv6_addr(struct iovec *iov, uint32_t iface_num,
|
|
+ uint16_t param, char *param_val)
|
|
{
|
|
int rc;
|
|
int len;
|
|
@@ -1548,30 +1776,12 @@ static int iface_fill_net_ipv6_addr(struct iovec *iov, struct iface_rec *iface,
|
|
net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr);
|
|
net_param->param = param;
|
|
net_param->iface_type = ISCSI_IFACE_TYPE_IPV6;
|
|
- net_param->iface_num = iface->iface_num;
|
|
+ net_param->iface_num = iface_num;
|
|
net_param->param_type = ISCSI_NET_PARAM;
|
|
net_param->len = 16;
|
|
-
|
|
- switch (param) {
|
|
- case ISCSI_NET_PARAM_IPV6_ADDR:
|
|
- rc = inet_pton(AF_INET6, iface->ipaddress, net_param->value);
|
|
- if (rc <= 0)
|
|
- goto free;
|
|
- break;
|
|
- case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
|
|
- rc = inet_pton(AF_INET6, iface->ipv6_linklocal,
|
|
- net_param->value);
|
|
- if (rc <= 0)
|
|
- goto free;
|
|
- break;
|
|
- case ISCSI_NET_PARAM_IPV6_ROUTER:
|
|
- rc = inet_pton(AF_INET6, iface->ipv6_router, net_param->value);
|
|
- if (rc <= 0)
|
|
- goto free;
|
|
- break;
|
|
- default:
|
|
+ rc = inet_pton(AF_INET6, param_val, net_param->value);
|
|
+ if (rc <= 0)
|
|
goto free;
|
|
- }
|
|
|
|
return 0;
|
|
free:
|
|
@@ -1581,6 +1791,54 @@ free:
|
|
return 1;
|
|
}
|
|
|
|
+#define IFACE_SET_NET_PARAM_IPV6_ADDR(iov, inum, param, ival, gcnt, \
|
|
+ lcnt) { \
|
|
+ if (strstr(ival, ":")) { \
|
|
+ if (!iface_fill_net_ipv6_addr(iov, inum, param, ival)) {\
|
|
+ (*gcnt)++; \
|
|
+ (*lcnt)++; \
|
|
+ } \
|
|
+ } \
|
|
+}
|
|
+
|
|
+/* write string parameter value */
|
|
+static int iface_fill_str_param_val(struct iovec *iov, uint32_t iface_num,
|
|
+ uint8_t iface_type, uint16_t param,
|
|
+ uint32_t param_len, char *param_val)
|
|
+{
|
|
+ int len;
|
|
+ struct iscsi_iface_param_info *net_param;
|
|
+ struct nlattr *attr;
|
|
+
|
|
+ if (!param_val[0])
|
|
+ return 1;
|
|
+
|
|
+ len = sizeof(struct iscsi_iface_param_info) + param_len;
|
|
+ iov->iov_base = iscsi_nla_alloc(param, len);
|
|
+ if (!(iov->iov_base))
|
|
+ return 1;
|
|
+
|
|
+ attr = iov->iov_base;
|
|
+ iov->iov_len = NLA_ALIGN(attr->nla_len);
|
|
+ net_param = (struct iscsi_iface_param_info *)ISCSI_NLA_DATA(attr);
|
|
+ net_param->iface_num = iface_num;
|
|
+ net_param->len = param_len;
|
|
+ net_param->param = param;
|
|
+ net_param->iface_type = iface_type;
|
|
+ net_param->param_type = ISCSI_NET_PARAM;
|
|
+ memcpy(net_param->value, param_val, param_len);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#define IFACE_SET_NET_PARAM_STRVAL(iov, inum, itype, param, plen, \
|
|
+ ival, gcnt, lcnt) { \
|
|
+ if (!iface_fill_str_param_val(iov, inum, itype, param, plen, \
|
|
+ ival)) { \
|
|
+ (*gcnt)++; \
|
|
+ (*lcnt)++; \
|
|
+ } \
|
|
+}
|
|
+
|
|
struct iface_net_config {
|
|
struct iface_rec *primary;
|
|
struct iovec *iovs;
|
|
@@ -1600,16 +1858,21 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface)
|
|
/* start at 2, because 0 is for nlmsghdr and 1 for event */
|
|
iov = net_config->iovs + 2;
|
|
|
|
+ if (!iface->port)
|
|
+ iface->port = 3260;
|
|
+
|
|
iptype = iface_get_iptype(iface);
|
|
- if (iptype == ISCSI_IFACE_TYPE_IPV4) {
|
|
+ switch (iptype) {
|
|
+ case ISCSI_IFACE_TYPE_IPV4:
|
|
if (!strcmp(iface->state, "disable")) {
|
|
- if (!iface_fill_net_state(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_IFACE_TYPE_IPV4)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
-
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IFACE_ENABLE,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->state,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
return 0;
|
|
}
|
|
|
|
@@ -1625,28 +1888,27 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface)
|
|
net_config->count++;
|
|
count++;
|
|
}
|
|
- if (!iface_fill_net_ipv4_addr(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_NET_PARAM_IPV4_ADDR)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
- if (strstr(iface->subnet_mask, ".")) {
|
|
- if (!iface_fill_net_ipv4_addr(
|
|
- &iov[net_config->count], iface,
|
|
- ISCSI_NET_PARAM_IPV4_SUBNET)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
- }
|
|
- if (strstr(iface->gateway, ".")) {
|
|
- if (!iface_fill_net_ipv4_addr(
|
|
- &iov[net_config->count], iface,
|
|
- ISCSI_NET_PARAM_IPV4_GW)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
- }
|
|
+
|
|
+ IFACE_SET_NET_PARAM_IPV4_ADDR(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_NET_PARAM_IPV4_ADDR,
|
|
+ iface->ipaddress,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_NET_PARAM_IPV4_ADDR(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_NET_PARAM_IPV4_SUBNET,
|
|
+ iface->subnet_mask,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_NET_PARAM_IPV4_ADDR(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_NET_PARAM_IPV4_GW,
|
|
+ iface->gateway,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
}
|
|
|
|
/*
|
|
@@ -1654,51 +1916,146 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface)
|
|
* fill state and other parameters (if any)
|
|
*/
|
|
if (count) {
|
|
- if (!iface_fill_net_state(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_IFACE_TYPE_IPV4)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
- if (!iface_fill_vlan_state(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_IFACE_TYPE_IPV4)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
- if (strcmp(iface->vlan_state, "disable") &&
|
|
- iface->vlan_id) {
|
|
- if (!iface_fill_vlan_id(&iov[net_config->count],
|
|
- iface, ISCSI_IFACE_TYPE_IPV4)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
- }
|
|
- if (iface->mtu) {
|
|
- if (!iface_fill_mtu(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_IFACE_TYPE_IPV4)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
- }
|
|
- if (iface->port) {
|
|
- if (!iface_fill_port(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_IFACE_TYPE_IPV4)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
- }
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->dhcp_dns,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->dhcp_slp_da,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_TOS_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->tos_state,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_TOS,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 1,
|
|
+ iface->tos,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->gratuitous_arp,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->dhcp_alt_client_id_state,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_NET_PARAM_STRVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID,
|
|
+ strlen(iface->dhcp_alt_client_id),
|
|
+ iface->dhcp_alt_client_id,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->dhcp_req_vendor_id_state,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->dhcp_vendor_id_state,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_NET_PARAM_STRVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID,
|
|
+ strlen(iface->dhcp_vendor_id),
|
|
+ iface->dhcp_vendor_id,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->dhcp_learn_iqn,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->fragmentation,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->incoming_forwarding,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV4,
|
|
+ ISCSI_NET_PARAM_IPV4_TTL,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 1,
|
|
+ iface->ttl,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
}
|
|
- } else if (iptype == ISCSI_IFACE_TYPE_IPV6) {
|
|
+ break;
|
|
+
|
|
+ case ISCSI_IFACE_TYPE_IPV6:
|
|
if (!strcmp(iface->state, "disable")) {
|
|
- if (!iface_fill_net_state(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_IFACE_TYPE_IPV6)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV6,
|
|
+ ISCSI_NET_PARAM_IFACE_ENABLE,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->state,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
return 0;
|
|
}
|
|
|
|
@@ -1717,12 +2074,12 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface)
|
|
count++;
|
|
}
|
|
/* User provided IPv6 Address */
|
|
- if (!iface_fill_net_ipv6_addr(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_NET_PARAM_IPV6_ADDR)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
+ IFACE_SET_NET_PARAM_IPV6_ADDR(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_NET_PARAM_IPV6_ADDR,
|
|
+ iface->ipaddress,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
}
|
|
|
|
/* For LinkLocal Address */
|
|
@@ -1741,12 +2098,12 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface)
|
|
count++;
|
|
}
|
|
/* User provided Link Local Address */
|
|
- if (!iface_fill_net_ipv6_addr(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_NET_PARAM_IPV6_LINKLOCAL)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
+ IFACE_SET_NET_PARAM_IPV6_ADDR(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_NET_PARAM_IPV6_LINKLOCAL,
|
|
+ iface->ipv6_linklocal,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
}
|
|
|
|
/* For Router Address */
|
|
@@ -1763,12 +2120,12 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface)
|
|
count++;
|
|
}
|
|
/* User provided Router Address */
|
|
- if (!iface_fill_net_ipv6_addr(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_NET_PARAM_IPV6_ROUTER)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
+ IFACE_SET_NET_PARAM_IPV6_ADDR(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_NET_PARAM_IPV6_ROUTER,
|
|
+ iface->ipv6_router,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
}
|
|
|
|
/*
|
|
@@ -1776,44 +2133,378 @@ static int __iface_build_net_config(void *data, struct iface_rec *iface)
|
|
* fill state and other parameters
|
|
*/
|
|
if (count) {
|
|
- if (!iface_fill_net_state(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_IFACE_TYPE_IPV6)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
- if (!iface_fill_vlan_state(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_IFACE_TYPE_IPV6)) {
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV6,
|
|
+ ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->gratuitous_neighbor_adv,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV6,
|
|
+ ISCSI_NET_PARAM_IPV6_MLD_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->mld,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV6,
|
|
+ ISCSI_NET_PARAM_IPV6_FLOW_LABEL,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 4,
|
|
+ iface->flow_label,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV6,
|
|
+ ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 1,
|
|
+ iface->traffic_class,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV6,
|
|
+ ISCSI_NET_PARAM_IPV6_HOP_LIMIT,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 1,
|
|
+ iface->hop_limit,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV6,
|
|
+ ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 4,
|
|
+ iface->nd_reachable_tmo,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV6,
|
|
+ ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 4,
|
|
+ iface->nd_rexmit_time,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV6,
|
|
+ ISCSI_NET_PARAM_IPV6_ND_STALE_TMO,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 4,
|
|
+ iface->nd_stale_tmo,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV6,
|
|
+ ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 1,
|
|
+ iface->dup_addr_detect_cnt,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ ISCSI_IFACE_TYPE_IPV6,
|
|
+ ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 4,
|
|
+ iface->router_adv_link_mtu,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* Fill parameters common to IPv4 and IPv6 ifaces */
|
|
+ if (count) {
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_NET_PARAM_IFACE_ENABLE,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->state,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_NET_PARAM_VLAN_ENABLED,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->vlan_state,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ if (strcmp(iface->vlan_state, "disable") && iface->vlan_id) {
|
|
+ if (!iface_fill_vlan_id(&iov[net_config->count], iface,
|
|
+ iptype)) {
|
|
net_config->count++;
|
|
count++;
|
|
}
|
|
- if (strcmp(iface->vlan_state, "disable") &&
|
|
- iface->vlan_id) {
|
|
- if (!iface_fill_vlan_id(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_IFACE_TYPE_IPV6)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
- }
|
|
- if (iface->mtu) {
|
|
- if (!iface_fill_mtu(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_IFACE_TYPE_IPV6)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
- }
|
|
- if (iface->port) {
|
|
- if (!iface_fill_port(&iov[net_config->count],
|
|
- iface,
|
|
- ISCSI_IFACE_TYPE_IPV6)) {
|
|
- net_config->count++;
|
|
- count++;
|
|
- }
|
|
- }
|
|
}
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_NET_PARAM_MTU,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 2,
|
|
+ iface->mtu,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_NET_PARAM_PORT,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 2,
|
|
+ iface->port,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_NET_PARAM_DELAYED_ACK_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->delayed_ack,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_NET_PARAM_TCP_NAGLE_DISABLE,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->nagle,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_NET_PARAM_TCP_WSF_DISABLE,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->tcp_wsf_state,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_NET_PARAM_TCP_WSF,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 1,
|
|
+ iface->tcp_wsf,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_NET_PARAM_TCP_TIMER_SCALE,
|
|
+ ISCSI_NET_PARAM,
|
|
+ 1,
|
|
+ iface->tcp_timer_scale,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_NET_PARAM_TCP_TIMESTAMP_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->tcp_timestamp,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_NET_PARAM_REDIRECT_EN,
|
|
+ ISCSI_NET_PARAM,
|
|
+ iface->redirect,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ 2,
|
|
+ iface->def_task_mgmt_tmo,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_HDRDGST_EN,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ iface->header_digest,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_DATADGST_EN,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ iface->data_digest,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_IMM_DATA_EN,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ iface->immediate_data,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_INITIAL_R2T_EN,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ iface->initial_r2t,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ iface->data_seq_inorder,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_PDU_INORDER_EN,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ iface->data_pdu_inorder,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_ERL,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ 1,
|
|
+ iface->erl,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ 4,
|
|
+ iface->max_recv_dlength,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_FIRST_BURST,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ 4,
|
|
+ iface->first_burst_len,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_MAX_R2T,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ 2,
|
|
+ iface->max_out_r2t,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_INTVAL(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_MAX_BURST,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ 4,
|
|
+ iface->max_burst_len,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_CHAP_AUTH_EN,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ iface->chap_auth,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_BIDI_CHAP_EN,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ iface->bidi_chap,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ iface->strict_login_comp,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ iface->discovery_auth,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
+
|
|
+ IFACE_SET_PARAM_STATE(&iov[net_config->count],
|
|
+ iface->iface_num,
|
|
+ iptype,
|
|
+ ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN,
|
|
+ ISCSI_IFACE_PARAM,
|
|
+ iface->discovery_logout,
|
|
+ &net_config->count,
|
|
+ &count);
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -1832,7 +2523,7 @@ int iface_build_net_config(struct iface_rec *iface, int iface_all,
|
|
int num_found = 0, rc;
|
|
struct iface_net_config net_config;
|
|
|
|
- log_debug(8, "In iface_build_net_config\n");
|
|
+ log_debug(8, "In iface_build_net_config");
|
|
|
|
net_config.primary = iface;
|
|
net_config.iovs = iovs;
|
|
@@ -1844,7 +2535,7 @@ int iface_build_net_config(struct iface_rec *iface, int iface_all,
|
|
else
|
|
rc = __iface_build_net_config(&net_config, iface);
|
|
|
|
- log_debug(8, "iface_build_net_config: rc = %d, count = %d\n",
|
|
+ log_debug(8, "iface_build_net_config: rc = %d, count = %d",
|
|
rc, net_config.count);
|
|
return net_config.count;
|
|
}
|
|
diff --git a/usr/initiator.c b/usr/initiator.c
|
|
index 79ca32c..3b39c5d 100644
|
|
--- a/usr/initiator.c
|
|
+++ b/usr/initiator.c
|
|
@@ -30,6 +30,7 @@
|
|
#include <errno.h>
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
+#include <libmount/libmount.h>
|
|
|
|
#include "initiator.h"
|
|
#include "transport.h"
|
|
@@ -45,6 +46,7 @@
|
|
#include "iscsi_sysfs.h"
|
|
#include "iscsi_settings.h"
|
|
#include "iface.h"
|
|
+#include "host.h"
|
|
#include "sysdeps.h"
|
|
#include "iscsi_err.h"
|
|
#include "kern_err_table.h"
|
|
@@ -54,10 +56,19 @@
|
|
|
|
#define PROC_DIR "/proc"
|
|
|
|
+struct login_task_retry_info {
|
|
+ actor_t retry_actor;
|
|
+ queue_task_t *qtask;
|
|
+ node_rec_t *rec;
|
|
+ int retry_count;
|
|
+};
|
|
+
|
|
static void iscsi_login_timedout(void *data);
|
|
static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
|
|
struct iscsi_conn *conn, unsigned long tmo,
|
|
int event);
|
|
+static int queue_session_login_task_retry(struct login_task_retry_info *info,
|
|
+ node_rec_t *rec, queue_task_t *qtask);
|
|
|
|
static int iscsi_ev_context_alloc(iscsi_conn_t *conn)
|
|
{
|
|
@@ -222,7 +233,7 @@ __check_iscsi_status_class(iscsi_session_t *session, int cid,
|
|
}
|
|
case ISCSI_STATUS_CLS_TARGET_ERR:
|
|
log_error("conn %d login rejected: target error "
|
|
- "(%02x/%02x)\n", conn->id, status_class, status_detail);
|
|
+ "(%02x/%02x)", conn->id, status_class, status_detail);
|
|
/*
|
|
* We have no idea what the problem is. But spec says initiator
|
|
* may retry later.
|
|
@@ -230,7 +241,7 @@ __check_iscsi_status_class(iscsi_session_t *session, int cid,
|
|
return CONN_LOGIN_RETRY;
|
|
default:
|
|
log_error("conn %d login response with unknown status "
|
|
- "class 0x%x, detail 0x%x\n", conn->id, status_class,
|
|
+ "class 0x%x, detail 0x%x", conn->id, status_class,
|
|
status_detail);
|
|
break;
|
|
}
|
|
@@ -265,7 +276,7 @@ __session_conn_create(iscsi_session_t *session, int cid)
|
|
conn->logout_timeout = conn_rec->timeo.logout_timeout;
|
|
if (!conn->logout_timeout) {
|
|
log_error("Invalid timeo.logout_timeout. Must be greater "
|
|
- "than zero. Using default %d.\n",
|
|
+ "than zero. Using default %d.",
|
|
DEF_LOGOUT_TIMEO);
|
|
conn->logout_timeout = DEF_LOGOUT_TIMEO;
|
|
}
|
|
@@ -273,7 +284,7 @@ __session_conn_create(iscsi_session_t *session, int cid)
|
|
conn->login_timeout = conn_rec->timeo.login_timeout;
|
|
if (!conn->login_timeout) {
|
|
log_error("Invalid timeo.login_timeout. Must be greater "
|
|
- "than zero. Using default %d.\n",
|
|
+ "than zero. Using default %d.",
|
|
DEF_LOGIN_TIMEO);
|
|
conn->login_timeout = DEF_LOGIN_TIMEO;
|
|
}
|
|
@@ -285,14 +296,14 @@ __session_conn_create(iscsi_session_t *session, int cid)
|
|
conn->noop_out_timeout = conn_rec->timeo.noop_out_timeout;
|
|
if (conn->noop_out_interval && !conn->noop_out_timeout) {
|
|
log_error("Invalid timeo.noop_out_timeout. Must be greater "
|
|
- "than zero. Using default %d.\n",
|
|
+ "than zero. Using default %d.",
|
|
DEF_NOOP_OUT_TIMEO);
|
|
conn->noop_out_timeout = DEF_NOOP_OUT_TIMEO;
|
|
}
|
|
|
|
if (conn->noop_out_timeout && !conn->noop_out_interval) {
|
|
log_error("Invalid timeo.noop_out_interval. Must be greater "
|
|
- "than zero. Using default %d.\n",
|
|
+ "than zero. Using default %d.",
|
|
DEF_NOOP_OUT_INTERVAL);
|
|
conn->noop_out_interval = DEF_NOOP_OUT_INTERVAL;
|
|
}
|
|
@@ -323,14 +334,17 @@ session_release(iscsi_session_t *session)
|
|
}
|
|
|
|
static iscsi_session_t*
|
|
-__session_create(node_rec_t *rec, struct iscsi_transport *t)
|
|
+__session_create(node_rec_t *rec, struct iscsi_transport *t, int *rc)
|
|
{
|
|
iscsi_session_t *session;
|
|
- int hostno, rc = 0;
|
|
+ int hostno;
|
|
+
|
|
+ *rc = 0;
|
|
|
|
session = calloc(1, sizeof (*session));
|
|
if (session == NULL) {
|
|
log_debug(1, "can not allocate memory for session");
|
|
+ *rc = ISCSI_ERR_NOMEM;
|
|
return NULL;
|
|
}
|
|
log_debug(2, "Allocted session %p", session);
|
|
@@ -355,8 +369,8 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t)
|
|
session->initiator_name = dconfig->initiator_name;
|
|
else {
|
|
log_error("No initiator name set. Cannot create session.");
|
|
- free(session);
|
|
- return NULL;
|
|
+ *rc = ISCSI_ERR_INVAL;
|
|
+ goto free_session;
|
|
}
|
|
|
|
if (strlen(session->nrec.iface.alias))
|
|
@@ -383,31 +397,31 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t)
|
|
/* setup authentication variables for the session*/
|
|
iscsi_setup_authentication(session, &rec->session.auth);
|
|
|
|
- session->param_mask = ~0ULL;
|
|
- if (!(t->caps & CAP_MULTI_R2T))
|
|
- session->param_mask &= ~ISCSI_MAX_R2T;
|
|
- if (!(t->caps & CAP_HDRDGST))
|
|
- session->param_mask &= ~ISCSI_HDRDGST_EN;
|
|
- if (!(t->caps & CAP_DATADGST))
|
|
- session->param_mask &= ~ISCSI_DATADGST_EN;
|
|
- if (!(t->caps & CAP_MARKERS)) {
|
|
- session->param_mask &= ~ISCSI_IFMARKER_EN;
|
|
- session->param_mask &= ~ISCSI_OFMARKER_EN;
|
|
- }
|
|
+ iscsi_session_init_params(session);
|
|
|
|
- hostno = iscsi_sysfs_get_host_no_from_hwinfo(&rec->iface, &rc);
|
|
- if (!rc) {
|
|
- /*
|
|
- * if the netdev or mac was set, then we are going to want
|
|
- * to want to bind the all the conns/eps to a specific host
|
|
- * if offload is used.
|
|
- */
|
|
- session->conn[0].bind_ep = 1;
|
|
- session->hostno = hostno;
|
|
- }
|
|
+ if (t->template->bind_ep_required) {
|
|
+ hostno = iscsi_sysfs_get_host_no_from_hwinfo(&rec->iface, rc);
|
|
+ if (!*rc) {
|
|
+ /*
|
|
+ * if the netdev or mac was set, then we are going to want
|
|
+ * to want to bind the all the conns/eps to a specific host
|
|
+ * if offload is used.
|
|
+ */
|
|
+ session->conn[0].bind_ep = 1;
|
|
+ session->hostno = hostno;
|
|
+ } else if (*rc == ISCSI_ERR_HOST_NOT_FOUND) {
|
|
+ goto free_session;
|
|
+ } else {
|
|
+ *rc = 0;
|
|
+ }
|
|
+ }
|
|
|
|
list_add_tail(&session->list, &t->sessions);
|
|
return session;
|
|
+
|
|
+free_session:
|
|
+ free(session);
|
|
+ return NULL;
|
|
}
|
|
|
|
static void iscsi_flush_context_pool(struct iscsi_session *session)
|
|
@@ -431,7 +445,7 @@ static void iscsi_flush_context_pool(struct iscsi_session *session)
|
|
static void
|
|
__session_destroy(iscsi_session_t *session)
|
|
{
|
|
- log_debug(1, "destroying session\n");
|
|
+ log_debug(1, "destroying session");
|
|
list_del(&session->list);
|
|
iscsi_flush_context_pool(session);
|
|
session_release(session);
|
|
@@ -509,14 +523,14 @@ queue_delayed_reopen(queue_task_t *qtask, int delay)
|
|
{
|
|
iscsi_conn_t *conn = qtask->conn;
|
|
|
|
- log_debug(4, "Requeue reopen attempt in %d secs\n", delay);
|
|
+ log_debug(4, "Requeue reopen attempt in %d secs", delay);
|
|
|
|
/*
|
|
* iscsi_login_eh can handle the login resched as
|
|
* if it were login time out
|
|
*/
|
|
actor_delete(&conn->login_timer);
|
|
- actor_timer(&conn->login_timer, delay * 1000,
|
|
+ actor_timer(&conn->login_timer, delay,
|
|
iscsi_login_timedout, qtask);
|
|
}
|
|
|
|
@@ -552,11 +566,53 @@ static int iscsi_conn_connect(struct iscsi_conn *conn, queue_task_t *qtask)
|
|
iscsi_sched_ev_context(ev_context, conn, 0, EV_CONN_POLL);
|
|
log_debug(3, "Setting login timer %p timeout %d", &conn->login_timer,
|
|
conn->login_timeout);
|
|
- actor_timer(&conn->login_timer, conn->login_timeout * 1000,
|
|
+ actor_timer(&conn->login_timer, conn->login_timeout,
|
|
iscsi_login_timedout, qtask);
|
|
return 0;
|
|
}
|
|
|
|
+static void iscsi_uio_poll_login_timedout(void *data)
|
|
+{
|
|
+ struct queue_task *qtask = data;
|
|
+ struct iscsi_conn *conn = qtask->conn;
|
|
+ iscsi_session_t *session = conn->session;
|
|
+
|
|
+ log_debug(3, "timeout waiting for UIO ...");
|
|
+ mgmt_ipc_write_rsp(qtask, ISCSI_ERR_TRANS_TIMEOUT);
|
|
+ conn_delete_timers(conn);
|
|
+ __session_destroy(session);
|
|
+}
|
|
+
|
|
+static int iscsi_sched_uio_poll(queue_task_t *qtask)
|
|
+{
|
|
+ struct iscsi_conn *conn = qtask->conn;
|
|
+ struct iscsi_session *session = conn->session;
|
|
+ struct iscsi_transport *t = session->t;
|
|
+ struct iscsi_ev_context *ev_context;
|
|
+
|
|
+ if (!t->template->set_net_config)
|
|
+ return 0;
|
|
+
|
|
+ ev_context = iscsi_ev_context_get(conn, 0);
|
|
+ if (!ev_context) {
|
|
+ /* while reopening the recv pool should be full */
|
|
+ log_error("BUG: __session_conn_reopen could "
|
|
+ "not get conn context for recv.");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ ev_context->data = qtask;
|
|
+ conn->state = ISCSI_CONN_STATE_XPT_WAIT;
|
|
+
|
|
+ iscsi_sched_ev_context(ev_context, conn, 0, EV_UIO_POLL);
|
|
+
|
|
+ log_debug(3, "Setting login UIO poll timer %p timeout %d",
|
|
+ &conn->login_timer, conn->login_timeout);
|
|
+ actor_timer(&conn->login_timer, conn->login_timeout,
|
|
+ iscsi_uio_poll_login_timedout, qtask);
|
|
+ return -EAGAIN;
|
|
+}
|
|
+
|
|
static void
|
|
__session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop,
|
|
int redirected)
|
|
@@ -598,6 +654,11 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop,
|
|
if (!redirected)
|
|
session->reopen_cnt++;
|
|
|
|
+ /* uIP will needs to be re-triggered on the connection re-open */
|
|
+ if (iscsi_set_net_config(conn->session->t, conn->session,
|
|
+ &conn->session->nrec.iface) != 0)
|
|
+ goto queue_reopen;
|
|
+
|
|
if (iscsi_conn_connect(conn, qtask)) {
|
|
delay = ISCSI_CONN_ERR_REOPEN_DELAY;
|
|
goto queue_reopen;
|
|
@@ -605,7 +666,7 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop,
|
|
return;
|
|
|
|
queue_reopen:
|
|
- log_debug(4, "Waiting %u seconds before trying to reconnect.\n", delay);
|
|
+ log_debug(4, "Waiting %u seconds before trying to reconnect.", delay);
|
|
queue_delayed_reopen(qtask, delay);
|
|
}
|
|
|
|
@@ -638,7 +699,7 @@ static int iscsi_retry_initial_login(struct iscsi_conn *conn)
|
|
timeout.tv_sec = initial_login_retry_max * conn->login_timeout;
|
|
if (gettimeofday(&now, NULL)) {
|
|
log_error("Could not get time of day. Dropping down to "
|
|
- "max retry check.\n");
|
|
+ "max retry check.");
|
|
return initial_login_retry_max > conn->session->reopen_cnt;
|
|
}
|
|
timeradd(&conn->initial_connect_time, &timeout, &fail_time);
|
|
@@ -649,7 +710,7 @@ static int iscsi_retry_initial_login(struct iscsi_conn *conn)
|
|
*/
|
|
if (timercmp(&now, &fail_time, >)) {
|
|
log_debug(1, "Giving up on initial login attempt after "
|
|
- "%u seconds.\n",
|
|
+ "%u seconds.",
|
|
initial_login_retry_max * conn->login_timeout);
|
|
return 0;
|
|
}
|
|
@@ -756,7 +817,7 @@ static void iscsi_login_eh(struct iscsi_conn *conn, struct queue_task *qtask,
|
|
|
|
break;
|
|
default:
|
|
- log_error("Ignoring login error %d in conn state %d.\n",
|
|
+ log_error("Ignoring login error %d in conn state %d.",
|
|
err, conn->state);
|
|
break;
|
|
}
|
|
@@ -830,7 +891,7 @@ __conn_error_handle(iscsi_session_t *session, iscsi_conn_t *conn)
|
|
"let connection stop");
|
|
return;
|
|
default:
|
|
- log_debug(8, "invalid state %d\n", conn->state);
|
|
+ log_debug(8, "invalid state %d", conn->state);
|
|
return;
|
|
}
|
|
|
|
@@ -887,7 +948,7 @@ static void iscsi_login_redirect(iscsi_conn_t *conn)
|
|
iscsi_session_t *session = conn->session;
|
|
iscsi_login_context_t *c = &conn->login_context;
|
|
|
|
- log_debug(3, "login redirect ...\n");
|
|
+ log_debug(3, "login redirect ...");
|
|
|
|
if (session->r_stage == R_STAGE_NO_CHANGE)
|
|
session->r_stage = R_STAGE_SESSION_REDIRECT;
|
|
@@ -954,9 +1015,9 @@ static void conn_send_nop_out(void *data)
|
|
|
|
__send_nopout(conn);
|
|
|
|
- actor_timer(&conn->nop_out_timer, conn->noop_out_timeout*1000,
|
|
+ actor_timer(&conn->nop_out_timer, conn->noop_out_timeout,
|
|
conn_nop_out_timeout, conn);
|
|
- log_debug(3, "noop out timeout timer %p start, timeout %d\n",
|
|
+ log_debug(3, "noop out timeout timer %p start, timeout %d",
|
|
&conn->nop_out_timer, conn->noop_out_timeout);
|
|
}
|
|
|
|
@@ -993,7 +1054,7 @@ static void session_scan_host(struct iscsi_session *session, int hostno,
|
|
exit(0);
|
|
} else if (pid > 0) {
|
|
reap_inc();
|
|
- if (qtask) {
|
|
+ if (qtask && qtask->mgmt_ipc_fd >= 0) {
|
|
close(qtask->mgmt_ipc_fd);
|
|
free(qtask);
|
|
}
|
|
@@ -1010,12 +1071,7 @@ setup_full_feature_phase(iscsi_conn_t *conn)
|
|
|
|
actor_delete(&conn->login_timer);
|
|
|
|
- if (iscsi_session_set_params(conn)) {
|
|
- iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
|
|
- return;
|
|
- }
|
|
-
|
|
- if (iscsi_host_set_params(session)) {
|
|
+ if (iscsi_session_set_neg_params(conn)) {
|
|
iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
|
|
return;
|
|
}
|
|
@@ -1062,9 +1118,9 @@ setup_full_feature_phase(iscsi_conn_t *conn)
|
|
|
|
/* noop_out */
|
|
if (conn->userspace_nop && conn->noop_out_interval) {
|
|
- actor_timer(&conn->nop_out_timer, conn->noop_out_interval*1000,
|
|
+ actor_timer(&conn->nop_out_timer, conn->noop_out_interval,
|
|
conn_send_nop_out, conn);
|
|
- log_debug(3, "noop out timer %p start\n",
|
|
+ log_debug(3, "noop out timer %p start",
|
|
&conn->nop_out_timer);
|
|
}
|
|
}
|
|
@@ -1079,7 +1135,7 @@ static void iscsi_logout_timedout(void *data)
|
|
* assume we were in ISCSI_CONN_STATE_IN_LOGOUT or there
|
|
* was some nasty error
|
|
*/
|
|
- log_debug(3, "logout timeout, dropping conn...\n");
|
|
+ log_debug(3, "logout timeout, dropping conn...");
|
|
__conn_error_handle(conn->session, conn);
|
|
}
|
|
|
|
@@ -1110,7 +1166,7 @@ static int iscsi_send_logout(iscsi_conn_t *conn)
|
|
iscsi_sched_ev_context(ev_context, conn,
|
|
conn->logout_timeout,
|
|
EV_CONN_LOGOUT_TIMER);
|
|
- log_debug(3, "logout timeout timer %u\n",
|
|
+ log_debug(3, "logout timeout timer %u",
|
|
conn->logout_timeout * 1000);
|
|
}
|
|
|
|
@@ -1146,7 +1202,7 @@ static void iscsi_recv_nop_in(iscsi_conn_t *conn, struct iscsi_hdr *hdr)
|
|
/* noop out rsp */
|
|
actor_delete(&conn->nop_out_timer);
|
|
/* schedule a new ping */
|
|
- actor_timer(&conn->nop_out_timer, conn->noop_out_interval*1000,
|
|
+ actor_timer(&conn->nop_out_timer, conn->noop_out_interval,
|
|
conn_send_nop_out, conn);
|
|
} else /* noop in req */
|
|
if (!__send_nopin_rsp(conn, (struct iscsi_nopin*)hdr,
|
|
@@ -1159,7 +1215,7 @@ static void iscsi_recv_logout_rsp(iscsi_conn_t *conn, struct iscsi_hdr *hdr)
|
|
{
|
|
struct iscsi_logout_rsp *logout_rsp = (struct iscsi_logout_rsp *)hdr;
|
|
|
|
- log_debug(3, "Recv: logout response %d\n", logout_rsp->response);
|
|
+ log_debug(3, "Recv: logout response %d", logout_rsp->response);
|
|
if (logout_rsp->response == 2 || logout_rsp->response == 3) {
|
|
conn->session->def_time2wait = ntohs(logout_rsp->t2wait);
|
|
log_debug(4, "logout rsp returned time2wait %u",
|
|
@@ -1177,7 +1233,7 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr)
|
|
unsigned int senselen;
|
|
struct scsi_sense_hdr sshdr;
|
|
|
|
- log_debug(3, "Read AEN %d\n", async_hdr->async_event);
|
|
+ log_debug(3, "Read AEN %d", async_hdr->async_event);
|
|
|
|
switch (async_hdr->async_event) {
|
|
case ISCSI_ASYNC_MSG_SCSI_EVENT:
|
|
@@ -1195,33 +1251,33 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr)
|
|
break;
|
|
case ISCSI_ASYNC_MSG_REQUEST_LOGOUT:
|
|
log_warning("Target requests logout within %u seconds for "
|
|
- "connection\n", ntohs(async_hdr->param3));
|
|
+ "connection", ntohs(async_hdr->param3));
|
|
if (iscsi_send_logout(conn))
|
|
log_error("Could not send logout in response to"
|
|
- "logout request aen\n");
|
|
+ "logout request aen");
|
|
break;
|
|
case ISCSI_ASYNC_MSG_DROPPING_CONNECTION:
|
|
log_warning("Target dropping connection %u, reconnect min %u "
|
|
- "max %u\n", ntohs(async_hdr->param1),
|
|
+ "max %u", ntohs(async_hdr->param1),
|
|
ntohs(async_hdr->param2), ntohs(async_hdr->param3));
|
|
session->def_time2wait =
|
|
(uint32_t)ntohs(async_hdr->param2) & 0x0000FFFFFL;
|
|
break;
|
|
case ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS:
|
|
log_warning("Target dropping all connections, reconnect min %u "
|
|
- "max %u\n", ntohs(async_hdr->param2),
|
|
+ "max %u", ntohs(async_hdr->param2),
|
|
ntohs(async_hdr->param3));
|
|
session->def_time2wait =
|
|
(uint32_t)ntohs(async_hdr->param2) & 0x0000FFFFFL;
|
|
break;
|
|
case ISCSI_ASYNC_MSG_PARAM_NEGOTIATION:
|
|
log_warning("Received async event param negotiation, "
|
|
- "dropping session\n");
|
|
+ "dropping session");
|
|
__conn_error_handle(session, conn);
|
|
break;
|
|
case ISCSI_ASYNC_MSG_VENDOR_SPECIFIC:
|
|
default:
|
|
- log_warning("AEN not supported\n");
|
|
+ log_warning("AEN not supported");
|
|
}
|
|
}
|
|
|
|
@@ -1336,7 +1392,7 @@ static void session_conn_recv_pdu(void *data)
|
|
break;
|
|
default:
|
|
iscsi_ev_context_put(ev_context);
|
|
- log_error("Invalid state. Dropping PDU.\n");
|
|
+ log_error("Invalid state. Dropping PDU.");
|
|
}
|
|
}
|
|
|
|
@@ -1420,7 +1476,7 @@ static void session_increase_wq_priority(struct iscsi_session *session)
|
|
fail:
|
|
log_error("Could not set session%d priority. "
|
|
"READ/WRITE throughout and latency could be "
|
|
- "affected.\n", session->id);
|
|
+ "affected.", session->id);
|
|
}
|
|
|
|
static int session_ipc_create(struct iscsi_session *session)
|
|
@@ -1469,6 +1525,11 @@ static void setup_offload_login_phase(iscsi_conn_t *conn)
|
|
return;
|
|
}
|
|
|
|
+ if (iscsi_session_set_neg_params(conn)) {
|
|
+ iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
|
|
+ return;
|
|
+ }
|
|
+
|
|
if (iscsi_host_set_params(session)) {
|
|
iscsi_login_eh(conn, c->qtask, ISCSI_ERR_LOGIN);
|
|
return;
|
|
@@ -1511,7 +1572,6 @@ static void session_conn_poll(void *data)
|
|
rc = session->t->template->ep_poll(conn, 1);
|
|
if (rc == 0) {
|
|
log_debug(4, "poll not connected %d", rc);
|
|
- /* timedout: Poll again. */
|
|
ev_context = iscsi_ev_context_get(conn, 0);
|
|
if (!ev_context) {
|
|
/* while polling the recv pool should be full */
|
|
@@ -1521,7 +1581,8 @@ static void session_conn_poll(void *data)
|
|
return;
|
|
}
|
|
ev_context->data = qtask;
|
|
- iscsi_sched_ev_context(ev_context, conn, 0, EV_CONN_POLL);
|
|
+ /* not connected yet, check later */
|
|
+ iscsi_sched_ev_context(ev_context, conn, 1, EV_CONN_POLL);
|
|
} else if (rc > 0) {
|
|
/* connected! */
|
|
memset(c, 0, sizeof(iscsi_login_context_t));
|
|
@@ -1580,6 +1641,16 @@ static void session_conn_poll(void *data)
|
|
return;
|
|
}
|
|
|
|
+ if (iscsi_session_set_params(conn)) {
|
|
+ iscsi_login_eh(conn, qtask, ISCSI_ERR_LOGIN);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (iscsi_host_set_params(session)) {
|
|
+ iscsi_login_eh(conn, qtask, ISCSI_ERR_LOGIN);
|
|
+ return;
|
|
+ }
|
|
+
|
|
if (iscsi_login_begin(session, c)) {
|
|
iscsi_login_eh(conn, qtask, ISCSI_ERR_LOGIN);
|
|
return;
|
|
@@ -1618,6 +1689,9 @@ static void session_conn_process_login(void *data)
|
|
if (state == ISCSI_CONN_STATE_FREE)
|
|
goto failed_login;
|
|
|
|
+ if (conn->state == ISCSI_CONN_STATE_LOGGED_IN)
|
|
+ return;
|
|
+
|
|
conn->state = ISCSI_CONN_STATE_LOGGED_IN;
|
|
/*
|
|
* ok we were in_login and now we got the notification that we are
|
|
@@ -1667,6 +1741,53 @@ failed_login:
|
|
|
|
}
|
|
|
|
+static void session_conn_uio_poll(void *data)
|
|
+{
|
|
+ struct iscsi_ev_context *ev_context = data;
|
|
+ iscsi_conn_t *conn = ev_context->conn;
|
|
+ struct iscsi_session *session = conn->session;
|
|
+ queue_task_t *qtask = ev_context->data;
|
|
+ int rc;
|
|
+
|
|
+ log_debug(4, "retrying uio poll");
|
|
+ rc = iscsi_set_net_config(session->t, session,
|
|
+ &conn->session->nrec.iface);
|
|
+ if (rc != 0) {
|
|
+ if (rc == ISCSI_ERR_AGAIN) {
|
|
+ ev_context->data = qtask;
|
|
+ iscsi_sched_ev_context(ev_context, conn, 2,
|
|
+ EV_UIO_POLL);
|
|
+ return;
|
|
+ } else {
|
|
+ log_error("session_conn_uio_poll() "
|
|
+ "connection failure [0x%x]", rc);
|
|
+ actor_delete(&conn->login_timer);
|
|
+ iscsi_login_eh(conn, qtask, ISCSI_ERR_INTERNAL);
|
|
+ iscsi_ev_context_put(ev_context);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ iscsi_ev_context_put(ev_context);
|
|
+ actor_delete(&conn->login_timer);
|
|
+ log_debug(4, "UIO ready trying connect");
|
|
+
|
|
+ /* uIP is ready try to connect */
|
|
+ if (gettimeofday(&conn->initial_connect_time, NULL))
|
|
+ log_error("Could not get initial connect time. If "
|
|
+ "login errors iscsid may give up the initial "
|
|
+ "login early. You should manually login.");
|
|
+
|
|
+ conn->state = ISCSI_CONN_STATE_XPT_WAIT;
|
|
+ if (iscsi_conn_connect(conn, qtask)) {
|
|
+ int delay = ISCSI_CONN_ERR_REOPEN_DELAY;
|
|
+
|
|
+ log_debug(4, "Waiting %u seconds before trying to reconnect.",
|
|
+ delay);
|
|
+ queue_delayed_reopen(qtask, delay);
|
|
+ }
|
|
+}
|
|
+
|
|
static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
|
|
struct iscsi_conn *conn, unsigned long tmo,
|
|
int event)
|
|
@@ -1679,14 +1800,14 @@ static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
|
|
ev_context->conn = conn;
|
|
switch (event) {
|
|
case EV_CONN_RECV_PDU:
|
|
- actor_new(&ev_context->actor, session_conn_recv_pdu,
|
|
+ actor_init(&ev_context->actor, session_conn_recv_pdu,
|
|
ev_context);
|
|
actor_schedule(&ev_context->actor);
|
|
break;
|
|
case EV_CONN_ERROR:
|
|
error = *(enum iscsi_err *)ev_context->data;
|
|
|
|
- actor_new(&ev_context->actor, session_conn_error,
|
|
+ actor_init(&ev_context->actor, session_conn_error,
|
|
ev_context);
|
|
/*
|
|
* We handle invalid host, by killing the session.
|
|
@@ -1699,21 +1820,25 @@ static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
|
|
actor_schedule(&ev_context->actor);
|
|
break;
|
|
case EV_CONN_LOGIN:
|
|
- actor_new(&ev_context->actor, session_conn_process_login,
|
|
+ actor_init(&ev_context->actor, session_conn_process_login,
|
|
ev_context);
|
|
actor_schedule(&ev_context->actor);
|
|
break;
|
|
case EV_CONN_POLL:
|
|
- actor_new(&ev_context->actor, session_conn_poll,
|
|
+ actor_timer(&ev_context->actor, tmo,
|
|
+ session_conn_poll, ev_context);
|
|
+ break;
|
|
+ case EV_UIO_POLL:
|
|
+ actor_init(&ev_context->actor, session_conn_uio_poll,
|
|
ev_context);
|
|
actor_schedule(&ev_context->actor);
|
|
break;
|
|
case EV_CONN_LOGOUT_TIMER:
|
|
- actor_timer(&ev_context->actor, tmo * 1000,
|
|
+ actor_timer(&ev_context->actor, tmo,
|
|
iscsi_logout_timedout, ev_context);
|
|
break;
|
|
case EV_CONN_STOP:
|
|
- actor_new(&ev_context->actor, iscsi_stop,
|
|
+ actor_init(&ev_context->actor, iscsi_stop,
|
|
ev_context);
|
|
actor_schedule(&ev_context->actor);
|
|
break;
|
|
@@ -1752,14 +1877,14 @@ static int session_is_running(node_rec_t *rec)
|
|
if (session_find_by_rec(rec))
|
|
return 1;
|
|
|
|
- if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session))
|
|
+ if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session,
|
|
+ 0))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
-int
|
|
-session_login_task(node_rec_t *rec, queue_task_t *qtask)
|
|
+static int __session_login_task(node_rec_t *rec, queue_task_t *qtask)
|
|
{
|
|
iscsi_session_t *session;
|
|
iscsi_conn_t *conn;
|
|
@@ -1782,7 +1907,7 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
|
|
(!(t->caps & CAP_RECOVERY_L1) &&
|
|
rec->session.iscsi.ERL > 1)) {
|
|
log_error("Transport '%s' does not support ERL %d."
|
|
- "Setting ERL to ERL0.\n",
|
|
+ "Setting ERL to ERL0.",
|
|
t->name, rec->session.iscsi.ERL);
|
|
rec->session.iscsi.ERL = 0;
|
|
}
|
|
@@ -1815,19 +1940,21 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
|
|
if (!(t->caps & CAP_MARKERS) &&
|
|
rec->conn[0].iscsi.IFMarker) {
|
|
log_error("Transport '%s' does not support IFMarker. "
|
|
- "Disabling IFMarkers.\n", t->name);
|
|
+ "Disabling IFMarkers.", t->name);
|
|
rec->conn[0].iscsi.IFMarker = 0;
|
|
}
|
|
|
|
if (!(t->caps & CAP_MARKERS) &&
|
|
rec->conn[0].iscsi.OFMarker) {
|
|
log_error("Transport '%s' does not support OFMarker."
|
|
- "Disabling OFMarkers.\n", t->name);
|
|
+ "Disabling OFMarkers.", t->name);
|
|
rec->conn[0].iscsi.OFMarker = 0;
|
|
}
|
|
|
|
- session = __session_create(rec, t);
|
|
- if (!session)
|
|
+ session = __session_create(rec, t, &rc);
|
|
+ if (rc == ISCSI_ERR_HOST_NOT_FOUND)
|
|
+ return rc;
|
|
+ else if (!session)
|
|
return ISCSI_ERR_LOGIN;
|
|
|
|
/* FIXME: login all connections! marked as "automatic" */
|
|
@@ -1841,7 +1968,17 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
|
|
conn = &session->conn[0];
|
|
qtask->conn = conn;
|
|
|
|
- if (iscsi_host_set_net_params(&rec->iface, session)) {
|
|
+ rc = iscsi_host_set_net_params(&rec->iface, session);
|
|
+ if (rc == ISCSI_ERR_AGAIN) {
|
|
+ iscsi_sched_uio_poll(qtask);
|
|
+ /*
|
|
+ * Cannot block iscsid, so caller is going to internally
|
|
+ * retry the operation.
|
|
+ */
|
|
+ qtask->rsp.command = MGMT_IPC_SESSION_LOGIN;
|
|
+ qtask->rsp.err = ISCSI_SUCCESS;
|
|
+ return ISCSI_SUCCESS;
|
|
+ } else if (rc) {
|
|
__session_destroy(session);
|
|
return ISCSI_ERR_LOGIN;
|
|
}
|
|
@@ -1857,7 +1994,7 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
|
|
|
|
if (iscsi_conn_connect(conn, qtask)) {
|
|
log_debug(4, "Initial connect failed. Waiting %u seconds "
|
|
- "before trying to reconnect.\n",
|
|
+ "before trying to reconnect.",
|
|
ISCSI_CONN_ERR_REOPEN_DELAY);
|
|
queue_delayed_reopen(qtask, ISCSI_CONN_ERR_REOPEN_DELAY);
|
|
}
|
|
@@ -1865,6 +2002,74 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
|
|
return ISCSI_SUCCESS;
|
|
}
|
|
|
|
+int
|
|
+session_login_task(node_rec_t *rec, queue_task_t *qtask)
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ rc = __session_login_task(rec, qtask);
|
|
+ if (rc == ISCSI_ERR_HOST_NOT_FOUND) {
|
|
+ rc = queue_session_login_task_retry(NULL, rec, qtask);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+ /*
|
|
+ * we are going to internally retry. Will return final rc
|
|
+ * when completed
|
|
+ */
|
|
+ return ISCSI_SUCCESS;
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static void session_login_task_retry(void *data)
|
|
+{
|
|
+ struct login_task_retry_info *info = data;
|
|
+ int rc;
|
|
+
|
|
+ rc = __session_login_task(info->rec, info->qtask);
|
|
+ if (rc == ISCSI_ERR_HOST_NOT_FOUND) {
|
|
+ if (info->retry_count == 5) {
|
|
+ /* give up */
|
|
+ goto write_rsp;
|
|
+ }
|
|
+
|
|
+ rc = queue_session_login_task_retry(info, info->rec,
|
|
+ info->qtask);
|
|
+ if (rc)
|
|
+ goto write_rsp;
|
|
+ /* we are going to internally retry */
|
|
+ return;
|
|
+ } else if (rc) {
|
|
+ /* hard error - no retry */
|
|
+ goto write_rsp;
|
|
+ } else
|
|
+ /* successfully started login operation */
|
|
+ goto free;
|
|
+write_rsp:
|
|
+ mgmt_ipc_write_rsp(info->qtask, rc);
|
|
+free:
|
|
+ free(info);
|
|
+}
|
|
+
|
|
+static int queue_session_login_task_retry(struct login_task_retry_info *info,
|
|
+ node_rec_t *rec, queue_task_t *qtask)
|
|
+{
|
|
+ if (!info) {
|
|
+ info = malloc(sizeof(*info));
|
|
+ if (!info)
|
|
+ return ISCSI_ERR_NOMEM;
|
|
+ memset(info, 0, sizeof(*info));
|
|
+ info->qtask = qtask;
|
|
+ info->rec = rec;
|
|
+ }
|
|
+
|
|
+ info->retry_count++;
|
|
+ log_debug(4, "queue session setup attempt in %d secs, retries %d",
|
|
+ 3, info->retry_count);
|
|
+ actor_timer(&info->retry_actor, 3, session_login_task_retry, info);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int
|
|
sync_conn(iscsi_session_t *session, uint32_t cid)
|
|
{
|
|
@@ -1892,14 +2097,14 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid)
|
|
if (!t)
|
|
return ISCSI_ERR_TRANS_NOT_FOUND;
|
|
|
|
- session = __session_create(rec, t);
|
|
+ session = __session_create(rec, t, &err);
|
|
if (!session)
|
|
return ISCSI_ERR_LOGIN;
|
|
|
|
session->id = sid;
|
|
session->hostno = iscsi_sysfs_get_host_no_from_sid(sid, &err);
|
|
if (err) {
|
|
- log_error("Could not get hostno for session %d\n", sid);
|
|
+ log_error("Could not get hostno for session %d", sid);
|
|
goto destroy_session;
|
|
}
|
|
|
|
@@ -1920,7 +2125,7 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid)
|
|
|
|
destroy_session:
|
|
__session_destroy(session);
|
|
- log_error("Could not sync session%d err %d\n", sid, err);
|
|
+ log_error("Could not sync session%d err %d", sid, err);
|
|
return err;
|
|
}
|
|
|
|
@@ -1931,10 +2136,199 @@ static int session_unbind(struct iscsi_session *session)
|
|
err = ipc->unbind_session(session->t->handle, session->id);
|
|
if (err)
|
|
/* older kernels did not support unbind */
|
|
- log_debug(2, "Could not unbind session %d.\n", err);
|
|
+ log_debug(2, "Could not unbind session %d.", err);
|
|
return err;
|
|
}
|
|
|
|
+static struct libmnt_table *mtab, *swaps;
|
|
+
|
|
+static void libmount_cleanup(void)
|
|
+{
|
|
+ mnt_free_table(mtab);
|
|
+ mnt_free_table(swaps);
|
|
+ mtab = swaps = NULL;
|
|
+}
|
|
+
|
|
+static int libmount_init(void)
|
|
+{
|
|
+ mnt_init_debug(0);
|
|
+ mtab = mnt_new_table();
|
|
+ swaps = mnt_new_table();
|
|
+ if (!mtab || !swaps) {
|
|
+ libmount_cleanup();
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ mnt_table_parse_mtab(mtab, NULL);
|
|
+ mnt_table_parse_swaps(swaps, NULL);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int trans_filter(const struct dirent *d)
|
|
+{
|
|
+ if (!strcmp(".", d->d_name) || !strcmp("..", d->d_name))
|
|
+ return 0;
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static int subdir_filter(const struct dirent *d)
|
|
+{
|
|
+ if (!(d->d_type & DT_DIR))
|
|
+ return 0;
|
|
+ return trans_filter(d);
|
|
+}
|
|
+
|
|
+static int is_partition(const char *path)
|
|
+{
|
|
+ char *devtype;
|
|
+ int rc = 0;
|
|
+
|
|
+ devtype = sysfs_get_uevent_devtype(path);
|
|
+ if (!devtype)
|
|
+ return 0;
|
|
+ if (strcmp(devtype, "partition") == 0)
|
|
+ rc = 1;
|
|
+ free(devtype);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int blockdev_check_mnts(char *syspath)
|
|
+{
|
|
+ struct libmnt_fs *fs;
|
|
+ char *devname = NULL;
|
|
+ char *_devname = NULL;
|
|
+ int rc = 0;
|
|
+
|
|
+ devname = sysfs_get_uevent_devname(syspath);
|
|
+ if (!devname)
|
|
+ goto out;
|
|
+
|
|
+ _devname = calloc(1, PATH_MAX);
|
|
+ if (!_devname)
|
|
+ goto out;
|
|
+ snprintf(_devname, PATH_MAX, "/dev/%s", devname);
|
|
+
|
|
+ fs = mnt_table_find_source(mtab, _devname, MNT_ITER_FORWARD);
|
|
+ if (fs) {
|
|
+ rc = 1;
|
|
+ goto out;
|
|
+ }
|
|
+ fs = mnt_table_find_source(swaps, _devname, MNT_ITER_FORWARD);
|
|
+ if (fs)
|
|
+ rc = 1;
|
|
+out:
|
|
+ free(devname);
|
|
+ free(_devname);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int count_device_users(char *syspath);
|
|
+
|
|
+static int blockdev_get_partitions(char *syspath)
|
|
+{
|
|
+ struct dirent **parts = NULL;
|
|
+ int n, i;
|
|
+ int count = 0;
|
|
+
|
|
+ n = scandir(syspath, &parts, subdir_filter, alphasort);
|
|
+ for (i = 0; i < n; i++) {
|
|
+ char *newpath;
|
|
+
|
|
+ newpath = calloc(1, PATH_MAX);
|
|
+ if (!newpath)
|
|
+ continue;
|
|
+ snprintf(newpath, PATH_MAX, "%s/%s", syspath, parts[i]->d_name);
|
|
+ free(parts[i]);
|
|
+ if (is_partition(newpath)) {
|
|
+ count += count_device_users(newpath);
|
|
+ }
|
|
+ free(newpath);
|
|
+ }
|
|
+ free(parts);
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static int blockdev_get_holders(char *syspath)
|
|
+{
|
|
+ char *path = NULL;
|
|
+ struct dirent **holds = NULL;
|
|
+ int n, i;
|
|
+ int count = 0;
|
|
+
|
|
+ path = calloc(1, PATH_MAX);
|
|
+ if (!path)
|
|
+ return 0;
|
|
+ snprintf(path, PATH_MAX, "%s/holders", syspath);
|
|
+
|
|
+ n = scandir(path, &holds, trans_filter, alphasort);
|
|
+ for (i = 0; i < n; i++) {
|
|
+ char *newpath;
|
|
+ char *rp;
|
|
+
|
|
+ newpath = calloc(1, PATH_MAX);
|
|
+ if (!newpath)
|
|
+ continue;
|
|
+ snprintf(newpath, PATH_MAX, "%s/%s", path, holds[i]->d_name);
|
|
+
|
|
+ free(holds[i]);
|
|
+ rp = realpath(newpath, NULL);
|
|
+ if (rp)
|
|
+ count += count_device_users(rp);
|
|
+ free(newpath);
|
|
+ free(rp);
|
|
+ }
|
|
+ free(path);
|
|
+ free(holds);
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static int count_device_users(char *syspath)
|
|
+{
|
|
+ int count = 0;
|
|
+ count += blockdev_check_mnts(syspath);
|
|
+ count += blockdev_get_partitions(syspath);
|
|
+ count += blockdev_get_holders(syspath);
|
|
+ return count;
|
|
+};
|
|
+
|
|
+static void device_in_use(void *data, int host_no, int target, int lun)
|
|
+{
|
|
+ char *syspath = NULL;
|
|
+ char *devname = NULL;
|
|
+ int *count = data;
|
|
+
|
|
+ devname = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun);
|
|
+ if (!devname)
|
|
+ goto out;
|
|
+ syspath = calloc(1, PATH_MAX);
|
|
+ if (!syspath)
|
|
+ goto out;
|
|
+ snprintf(syspath, PATH_MAX, "/sys/class/block/%s", devname);
|
|
+ *count += count_device_users(syspath);
|
|
+out:
|
|
+ free(syspath);
|
|
+ free(devname);
|
|
+}
|
|
+
|
|
+static int session_in_use(int sid)
|
|
+{
|
|
+ int host_no = -1, err = 0;
|
|
+ int count = 0;
|
|
+
|
|
+ if (libmount_init()) {
|
|
+ log_error("Failed to initialize libmount, "
|
|
+ "not checking for active mounts on session [%d].",
|
|
+ sid);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err);
|
|
+ if (!err)
|
|
+ iscsi_sysfs_for_each_device(&count, host_no, sid, device_in_use);
|
|
+
|
|
+ libmount_cleanup();
|
|
+ return count;
|
|
+}
|
|
+
|
|
int session_logout_task(int sid, queue_task_t *qtask)
|
|
{
|
|
iscsi_session_t *session;
|
|
@@ -1943,7 +2337,7 @@ int session_logout_task(int sid, queue_task_t *qtask)
|
|
|
|
session = session_find_by_sid(sid);
|
|
if (!session) {
|
|
- log_debug(1, "session sid %d not found.\n", sid);
|
|
+ log_debug(1, "session sid %d not found.", sid);
|
|
return ISCSI_ERR_SESS_NOT_FOUND;
|
|
}
|
|
conn = &session->conn[0];
|
|
@@ -1958,10 +2352,16 @@ int session_logout_task(int sid, queue_task_t *qtask)
|
|
session->r_stage == R_STAGE_SESSION_REDIRECT))) {
|
|
invalid_state:
|
|
log_error("session in invalid state for logout. "
|
|
- "Try again later\n");
|
|
+ "Try again later");
|
|
return ISCSI_ERR_INTERNAL;
|
|
}
|
|
|
|
+ if (dconfig->safe_logout && session_in_use(sid)) {
|
|
+ log_error("Session is actively in use for mounted storage, "
|
|
+ "and iscsid.safe_logout is configured.");
|
|
+ return ISCSI_ERR_BUSY;
|
|
+ }
|
|
+
|
|
/* FIXME: logout all active connections */
|
|
conn = &session->conn[0];
|
|
if (conn->logout_qtask)
|
|
@@ -1983,7 +2383,7 @@ invalid_state:
|
|
return ISCSI_SUCCESS;
|
|
}
|
|
|
|
- log_error("Could not send logout pdu. Dropping session\n");
|
|
+ log_error("Could not send logout pdu. Dropping session");
|
|
/* fallthrough */
|
|
default:
|
|
rc = session_conn_shutdown(conn, qtask, ISCSI_SUCCESS);
|
|
@@ -2001,7 +2401,7 @@ iscsi_host_send_targets(queue_task_t *qtask, int host_no, int do_login,
|
|
|
|
t = iscsi_sysfs_get_transport_by_hba(host_no);
|
|
if (!t) {
|
|
- log_error("Invalid host no %d for sendtargets\n", host_no);
|
|
+ log_error("Invalid host no %d for sendtargets", host_no);
|
|
return ISCSI_ERR_TRANS_NOT_FOUND;
|
|
}
|
|
if (!(t->caps & CAP_SENDTARGETS_OFFLOAD))
|
|
diff --git a/usr/initiator.h b/usr/initiator.h
|
|
index b45caab..c34625b 100644
|
|
--- a/usr/initiator.h
|
|
+++ b/usr/initiator.h
|
|
@@ -83,6 +83,7 @@ typedef enum iscsi_event_e {
|
|
EV_CONN_LOGOUT_TIMER,
|
|
EV_CONN_STOP,
|
|
EV_CONN_LOGIN,
|
|
+ EV_UIO_POLL,
|
|
} iscsi_event_e;
|
|
|
|
struct queue_task;
|
|
@@ -343,6 +344,7 @@ extern void free_initiator(void);
|
|
extern void iscsi_initiator_init(void);
|
|
|
|
/* initiator code common to discovery and normal sessions */
|
|
+extern int iscsi_session_set_neg_params(struct iscsi_conn *conn);
|
|
extern int iscsi_session_set_params(struct iscsi_conn *conn);
|
|
extern int iscsi_host_set_params(struct iscsi_session *session);
|
|
extern int iscsi_host_set_net_params(struct iface_rec *iface,
|
|
@@ -353,5 +355,9 @@ extern void iscsi_copy_operational_params(struct iscsi_conn *conn,
|
|
extern int iscsi_setup_authentication(struct iscsi_session *session,
|
|
struct iscsi_auth_config *auth_cfg);
|
|
extern int iscsi_setup_portal(struct iscsi_conn *conn, char *address, int port);
|
|
+extern int iscsi_set_net_config(struct iscsi_transport *t,
|
|
+ iscsi_session_t *session,
|
|
+ struct iface_rec *iface);
|
|
+extern void iscsi_session_init_params(struct iscsi_session *session);
|
|
|
|
#endif /* INITIATOR_H */
|
|
diff --git a/usr/initiator_common.c b/usr/initiator_common.c
|
|
index ef6820c..ee856b3 100644
|
|
--- a/usr/initiator_common.c
|
|
+++ b/usr/initiator_common.c
|
|
@@ -51,21 +51,9 @@ struct iscsi_session *session_find_by_sid(uint32_t sid)
|
|
return NULL;
|
|
}
|
|
|
|
-/*
|
|
- * calculate parameter's padding
|
|
- */
|
|
-static unsigned int
|
|
-__padding(unsigned int param)
|
|
+const static unsigned int align_32_down(unsigned int param)
|
|
{
|
|
- int pad;
|
|
-
|
|
- pad = param & 3;
|
|
- if (pad) {
|
|
- pad = 4 - pad;
|
|
- log_debug(1, "parameter's value %d padded to %d bytes\n",
|
|
- param, param + pad);
|
|
- }
|
|
- return param + pad;
|
|
+ return param & ~0x3;
|
|
}
|
|
|
|
int iscsi_setup_authentication(struct iscsi_session *session,
|
|
@@ -77,7 +65,7 @@ int iscsi_setup_authentication(struct iscsi_session *session,
|
|
if (auth_cfg->username_in[0] || auth_cfg->password_in_length) {
|
|
/* sanity check the config */
|
|
if (auth_cfg->password_length == 0) {
|
|
- log_warning("CHAP configuratoin has incoming "
|
|
+ log_warning("CHAP configuration has incoming "
|
|
"authentication credentials but has no "
|
|
"outgoing credentials configured.");
|
|
return EINVAL;
|
|
@@ -151,11 +139,11 @@ iscsi_copy_operational_params(struct iscsi_conn *conn,
|
|
conn->datadgst_en = conn_conf->DataDigest;
|
|
|
|
conn->max_recv_dlength =
|
|
- __padding(conn_conf->MaxRecvDataSegmentLength);
|
|
+ align_32_down(conn_conf->MaxRecvDataSegmentLength);
|
|
if (conn->max_recv_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN ||
|
|
conn->max_recv_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) {
|
|
log_error("Invalid iscsi.MaxRecvDataSegmentLength. Must be "
|
|
- "within %u and %u. Setting to %u\n",
|
|
+ "within %u and %u. Setting to %u",
|
|
ISCSI_MIN_MAX_RECV_SEG_LEN,
|
|
ISCSI_MAX_MAX_RECV_SEG_LEN,
|
|
DEF_INI_MAX_RECV_SEG_LEN);
|
|
@@ -166,13 +154,13 @@ iscsi_copy_operational_params(struct iscsi_conn *conn,
|
|
|
|
/* zero indicates to use the target's value */
|
|
conn->max_xmit_dlength =
|
|
- __padding(conn_conf->MaxXmitDataSegmentLength);
|
|
+ align_32_down(conn_conf->MaxXmitDataSegmentLength);
|
|
if (conn->max_xmit_dlength == 0)
|
|
conn->max_xmit_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
|
|
if (conn->max_xmit_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN ||
|
|
conn->max_xmit_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) {
|
|
log_error("Invalid iscsi.MaxXmitDataSegmentLength. Must be "
|
|
- "within %u and %u. Setting to %u\n",
|
|
+ "within %u and %u. Setting to %u",
|
|
ISCSI_MIN_MAX_RECV_SEG_LEN,
|
|
ISCSI_MAX_MAX_RECV_SEG_LEN,
|
|
DEF_INI_MAX_RECV_SEG_LEN);
|
|
@@ -184,7 +172,7 @@ iscsi_copy_operational_params(struct iscsi_conn *conn,
|
|
/* session's operational parameters */
|
|
session->initial_r2t_en = session_conf->InitialR2T;
|
|
session->imm_data_en = session_conf->ImmediateData;
|
|
- session->first_burst = __padding(session_conf->FirstBurstLength);
|
|
+ session->first_burst = align_32_down(session_conf->FirstBurstLength);
|
|
/*
|
|
* some targets like netapp fail the login if sent bad first_burst
|
|
* and max_burst lens, even when immediate data=no and
|
|
@@ -193,7 +181,7 @@ iscsi_copy_operational_params(struct iscsi_conn *conn,
|
|
if (session->first_burst < ISCSI_MIN_FIRST_BURST_LEN ||
|
|
session->first_burst > ISCSI_MAX_FIRST_BURST_LEN) {
|
|
log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
|
|
- "within %u and %u. Setting to %u\n",
|
|
+ "within %u and %u. Setting to %u",
|
|
session->first_burst,
|
|
ISCSI_MIN_FIRST_BURST_LEN,
|
|
ISCSI_MAX_FIRST_BURST_LEN,
|
|
@@ -202,11 +190,11 @@ iscsi_copy_operational_params(struct iscsi_conn *conn,
|
|
session->first_burst = DEF_INI_FIRST_BURST_LEN;
|
|
}
|
|
|
|
- session->max_burst = __padding(session_conf->MaxBurstLength);
|
|
+ session->max_burst = align_32_down(session_conf->MaxBurstLength);
|
|
if (session->max_burst < ISCSI_MIN_MAX_BURST_LEN ||
|
|
session->max_burst > ISCSI_MAX_MAX_BURST_LEN) {
|
|
log_error("Invalid iscsi.MaxBurstLength of %u. Must be "
|
|
- "within %u and %u. Setting to %u\n",
|
|
+ "within %u and %u. Setting to %u",
|
|
session->max_burst, ISCSI_MIN_MAX_BURST_LEN,
|
|
ISCSI_MAX_MAX_BURST_LEN, DEF_INI_MAX_BURST_LEN);
|
|
session_conf->MaxBurstLength = DEF_INI_MAX_BURST_LEN;
|
|
@@ -215,7 +203,7 @@ iscsi_copy_operational_params(struct iscsi_conn *conn,
|
|
|
|
if (session->first_burst > session->max_burst) {
|
|
log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
|
|
- "less than iscsi.MaxBurstLength. Setting to %u\n",
|
|
+ "less than iscsi.MaxBurstLength. Setting to %u",
|
|
session->first_burst, session->max_burst);
|
|
session_conf->FirstBurstLength = session->max_burst;
|
|
session->first_burst = session->max_burst;
|
|
@@ -324,12 +312,32 @@ int iscsi_host_set_params(struct iscsi_session *session)
|
|
return 0;
|
|
}
|
|
|
|
-#define MAX_SESSION_PARAMS 32
|
|
+static inline void iscsi_session_clear_param(struct iscsi_session *session,
|
|
+ int param)
|
|
+{
|
|
+ session->param_mask &= ~(1ULL << param);
|
|
+}
|
|
|
|
-int iscsi_session_set_params(struct iscsi_conn *conn)
|
|
+void iscsi_session_init_params(struct iscsi_session *session)
|
|
+{
|
|
+ session->param_mask = ~0ULL;
|
|
+ if (!(session->t->caps & CAP_MULTI_R2T))
|
|
+ iscsi_session_clear_param(session, ISCSI_PARAM_MAX_R2T);
|
|
+ if (!(session->t->caps & CAP_HDRDGST))
|
|
+ iscsi_session_clear_param(session, ISCSI_PARAM_HDRDGST_EN);
|
|
+ if (!(session->t->caps & CAP_DATADGST))
|
|
+ iscsi_session_clear_param(session, ISCSI_PARAM_DATADGST_EN);
|
|
+ if (!(session->t->caps & CAP_MARKERS)) {
|
|
+ iscsi_session_clear_param(session, ISCSI_PARAM_IFMARKER_EN);
|
|
+ iscsi_session_clear_param(session, ISCSI_PARAM_OFMARKER_EN);
|
|
+ }
|
|
+}
|
|
+
|
|
+#define MAX_SESSION_NEG_PARAMS 16
|
|
+
|
|
+int iscsi_session_set_neg_params(struct iscsi_conn *conn)
|
|
{
|
|
struct iscsi_session *session = conn->session;
|
|
- struct iscsi_transport *t = session->t;
|
|
int i, rc;
|
|
uint32_t one = 1, zero = 0;
|
|
struct connparam {
|
|
@@ -337,7 +345,7 @@ int iscsi_session_set_params(struct iscsi_conn *conn)
|
|
int type;
|
|
void *value;
|
|
int conn_only;
|
|
- } conntbl[MAX_SESSION_PARAMS] = {
|
|
+ } conntbl[MAX_SESSION_NEG_PARAMS] = {
|
|
{
|
|
.param = ISCSI_PARAM_MAX_RECV_DLENGTH,
|
|
.value = &conn->max_recv_dlength,
|
|
@@ -411,18 +419,61 @@ int iscsi_session_set_params(struct iscsi_conn *conn)
|
|
}, {
|
|
.param = ISCSI_PARAM_EXP_STATSN,
|
|
.value = &conn->exp_statsn,
|
|
- .type = ISCSI_INT,
|
|
+ .type = ISCSI_UINT,
|
|
.conn_only = 1,
|
|
}, {
|
|
- .param = ISCSI_PARAM_TARGET_NAME,
|
|
- .conn_only = 0,
|
|
- .type = ISCSI_STRING,
|
|
- .value = session->target_name,
|
|
- }, {
|
|
.param = ISCSI_PARAM_TPGT,
|
|
.value = &session->portal_group_tag,
|
|
.type = ISCSI_INT,
|
|
.conn_only = 0,
|
|
+ },
|
|
+ };
|
|
+
|
|
+ iscsi_session_init_params(session);
|
|
+
|
|
+ /* Entered full-feature phase! */
|
|
+ for (i = 0; i < MAX_SESSION_NEG_PARAMS; i++) {
|
|
+ if (conn->id != 0 && !conntbl[i].conn_only)
|
|
+ continue;
|
|
+
|
|
+ if (!(session->param_mask & (1ULL << conntbl[i].param)))
|
|
+ continue;
|
|
+
|
|
+ rc = ipc->set_param(session->t->handle, session->id,
|
|
+ conn->id, conntbl[i].param, conntbl[i].value,
|
|
+ conntbl[i].type);
|
|
+ if (rc && rc != -ENOSYS) {
|
|
+ log_error("can't set operational parameter %d for "
|
|
+ "connection %d:%d, retcode %d (%d)",
|
|
+ conntbl[i].param, session->id, conn->id,
|
|
+ rc, errno);
|
|
+ return EPERM;
|
|
+ }
|
|
+
|
|
+ print_param_value(conntbl[i].param, conntbl[i].value,
|
|
+ conntbl[i].type);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#define MAX_SESSION_PARAMS 20
|
|
+
|
|
+int iscsi_session_set_params(struct iscsi_conn *conn)
|
|
+{
|
|
+ struct iscsi_session *session = conn->session;
|
|
+ int i, rc;
|
|
+ struct connparam {
|
|
+ int param;
|
|
+ int type;
|
|
+ void *value;
|
|
+ int conn_only;
|
|
+ } conntbl[MAX_SESSION_PARAMS] = {
|
|
+ {
|
|
+ .param = ISCSI_PARAM_TARGET_NAME,
|
|
+ .conn_only = 0,
|
|
+ .type = ISCSI_STRING,
|
|
+ .value = session->target_name,
|
|
}, {
|
|
.param = ISCSI_PARAM_PERSISTENT_ADDRESS,
|
|
.value = session->nrec.conn[conn->id].address,
|
|
@@ -492,29 +543,41 @@ int iscsi_session_set_params(struct iscsi_conn *conn)
|
|
.param = ISCSI_PARAM_IFACE_NAME,
|
|
.value = session->nrec.iface.name,
|
|
.type = ISCSI_STRING,
|
|
+ .conn_only = 0,
|
|
}, {
|
|
.param = ISCSI_PARAM_INITIATOR_NAME,
|
|
.value = session->initiator_name,
|
|
.type = ISCSI_STRING,
|
|
+ .conn_only = 0,
|
|
+ }, {
|
|
+ .param = ISCSI_PARAM_BOOT_ROOT,
|
|
+ .value = session->nrec.session.boot_root,
|
|
+ .type = ISCSI_STRING,
|
|
+ .conn_only = 0,
|
|
+ }, {
|
|
+ .param = ISCSI_PARAM_BOOT_NIC,
|
|
+ .value = session->nrec.session.boot_nic,
|
|
+ .type = ISCSI_STRING,
|
|
+ .conn_only = 0,
|
|
+ }, {
|
|
+ .param = ISCSI_PARAM_BOOT_TARGET,
|
|
+ .value = session->nrec.session.boot_target,
|
|
+ .type = ISCSI_STRING,
|
|
+ .conn_only = 0,
|
|
+ }, {
|
|
+ .param = ISCSI_PARAM_DISCOVERY_SESS,
|
|
+ .value = &session->type,
|
|
+ .type = ISCSI_INT,
|
|
+ .conn_only = 0,
|
|
},
|
|
};
|
|
|
|
- session->param_mask = ~0ULL;
|
|
- if (!(t->caps & CAP_MULTI_R2T))
|
|
- session->param_mask &= ~ISCSI_MAX_R2T;
|
|
- if (!(t->caps & CAP_HDRDGST))
|
|
- session->param_mask &= ~ISCSI_HDRDGST_EN;
|
|
- if (!(t->caps & CAP_DATADGST))
|
|
- session->param_mask &= ~ISCSI_DATADGST_EN;
|
|
- if (!(t->caps & CAP_MARKERS)) {
|
|
- session->param_mask &= ~ISCSI_IFMARKER_EN;
|
|
- session->param_mask &= ~ISCSI_OFMARKER_EN;
|
|
- }
|
|
+ iscsi_session_init_params(session);
|
|
|
|
/* some llds will send nops internally */
|
|
if (!iscsi_sysfs_session_supports_nop(session->id)) {
|
|
- session->param_mask &= ~ISCSI_PING_TMO;
|
|
- session->param_mask &= ~ISCSI_RECV_TMO;
|
|
+ iscsi_session_clear_param(session, ISCSI_PARAM_PING_TMO);
|
|
+ iscsi_session_clear_param(session, ISCSI_PARAM_RECV_TMO);
|
|
}
|
|
|
|
/* Entered full-feature phase! */
|
|
@@ -562,6 +625,36 @@ TODO handle this
|
|
return 0;
|
|
}
|
|
|
|
+int iscsi_set_net_config(struct iscsi_transport *t, iscsi_session_t *session,
|
|
+ struct iface_rec *iface)
|
|
+{
|
|
+ if (t->template->set_net_config) {
|
|
+ /* uip needs the netdev name */
|
|
+ struct host_info hinfo;
|
|
+ int hostno, rc;
|
|
+
|
|
+ /* this assumes that the netdev or hw address is going to be
|
|
+ set */
|
|
+ hostno = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc);
|
|
+ if (rc) {
|
|
+ log_debug(4, "Couldn't get host no.");
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ /* uip needs the netdev name */
|
|
+ if (!strlen(iface->netdev)) {
|
|
+ memset(&hinfo, 0, sizeof(hinfo));
|
|
+ hinfo.host_no = hostno;
|
|
+ iscsi_sysfs_get_hostinfo_by_host_no(&hinfo);
|
|
+ strcpy(iface->netdev, hinfo.iface.netdev);
|
|
+ }
|
|
+
|
|
+ return t->template->set_net_config(t, iface, session);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int iscsi_host_set_net_params(struct iface_rec *iface,
|
|
struct iscsi_session *session)
|
|
{
|
|
@@ -571,7 +664,7 @@ int iscsi_host_set_net_params(struct iface_rec *iface,
|
|
struct host_info hinfo;
|
|
|
|
log_debug(3, "setting iface %s, dev %s, set ip %s, hw %s, "
|
|
- "transport %s.\n",
|
|
+ "transport %s.",
|
|
iface->name, iface->netdev, iface->ipaddress,
|
|
iface->hwaddress, iface->transport_name);
|
|
|
|
@@ -580,9 +673,18 @@ int iscsi_host_set_net_params(struct iface_rec *iface,
|
|
|
|
/* if we need to set the ip addr then set all the iface net settings */
|
|
if (!iface_is_bound_by_ipaddr(iface)) {
|
|
- log_warning("Please set the iface.ipaddress for iface %s, "
|
|
- "then retry the login command.\n", iface->name);
|
|
- return EINVAL;
|
|
+ if (t->template->set_host_ip == SET_HOST_IP_REQ) {
|
|
+ log_warning("Please set the iface.ipaddress for iface "
|
|
+ "%s, then retry the login command.",
|
|
+ iface->name);
|
|
+ return EINVAL;
|
|
+ } else if (t->template->set_host_ip == SET_HOST_IP_OPT) {
|
|
+ log_info("Optional iface.ipaddress for iface %s "
|
|
+ "not set.", iface->name);
|
|
+ return 0;
|
|
+ } else {
|
|
+ return EINVAL;
|
|
+ }
|
|
}
|
|
|
|
/* these type of drivers need the netdev upd */
|
|
@@ -600,6 +702,10 @@ int iscsi_host_set_net_params(struct iface_rec *iface,
|
|
log_warning("Could not brining up netdev %s. Try running "
|
|
"'ifup %s' first if login fails.", netdev, netdev);
|
|
|
|
+ rc = iscsi_set_net_config(t, session, iface);
|
|
+ if (rc != 0)
|
|
+ return rc;
|
|
+
|
|
rc = host_set_param(t, session->hostno,
|
|
ISCSI_HOST_PARAM_IPADDRESS,
|
|
iface->ipaddress, ISCSI_STRING);
|
|
diff --git a/usr/io.c b/usr/io.c
|
|
index 45adea5..f552e1e 100644
|
|
--- a/usr/io.c
|
|
+++ b/usr/io.c
|
|
@@ -113,14 +113,14 @@ static int get_hwaddress_from_netdev(char *netdev, char *hwaddress)
|
|
(void *)&(s4->sin_addr), buf,
|
|
INET_ADDRSTRLEN))
|
|
continue;
|
|
- log_debug(4, "name %s addr %s\n", ifa->ifa_name, buf);
|
|
+ log_debug(4, "name %s addr %s", ifa->ifa_name, buf);
|
|
break;
|
|
case AF_INET6:
|
|
s6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
|
|
if (!inet_ntop(ifa->ifa_addr->sa_family,
|
|
(void *)&(s6->sin6_addr), buf, INET6_ADDRSTRLEN))
|
|
continue;
|
|
- log_debug(4, "name %s addr %s\n", ifa->ifa_name, buf);
|
|
+ log_debug(4, "name %s addr %s", ifa->ifa_name, buf);
|
|
break;
|
|
default:
|
|
continue;
|
|
@@ -239,7 +239,7 @@ static int bind_conn_to_iface(iscsi_conn_t *conn, struct iface_rec *iface)
|
|
if (setsockopt(conn->socket_fd, SOL_SOCKET, SO_BINDTODEVICE,
|
|
session->netdev,
|
|
strlen(session->netdev) + 1) < 0) {
|
|
- log_error("Could not bind connection %d to %s\n",
|
|
+ log_error("Could not bind connection %d to %s",
|
|
conn->id, session->netdev);
|
|
return -1;
|
|
}
|
|
@@ -357,7 +357,7 @@ iscsi_io_tcp_poll(iscsi_conn_t *conn, int timeout_ms)
|
|
len = sizeof(int);
|
|
if (getsockopt(conn->socket_fd, SOL_SOCKET, SO_ERROR,
|
|
(char *) &rc, &len) < 0) {
|
|
- log_error("getsockopt for connect poll failed\n");
|
|
+ log_error("getsockopt for connect poll failed");
|
|
return -1;
|
|
}
|
|
if (rc) {
|
|
@@ -366,7 +366,7 @@ iscsi_io_tcp_poll(iscsi_conn_t *conn, int timeout_ms)
|
|
conn->host, sizeof(conn->host), serv, sizeof(serv),
|
|
NI_NUMERICHOST|NI_NUMERICSERV);
|
|
|
|
- log_error("connect to %s:%s failed (%s)\n",
|
|
+ log_error("connect to %s:%s failed (%s)",
|
|
conn->host, serv, strerror(rc));
|
|
return -rc;
|
|
}
|
|
diff --git a/usr/iscsi_err.c b/usr/iscsi_err.c
|
|
index 4fe1c53..11e0348 100644
|
|
--- a/usr/iscsi_err.c
|
|
+++ b/usr/iscsi_err.c
|
|
@@ -51,6 +51,8 @@ static char *iscsi_err_msgs[] = {
|
|
/* 26 */ "iSNS registration failed",
|
|
/* 27 */ "operation not supported",
|
|
/* 28 */ "device or resource in use",
|
|
+ /* 29 */ "operation failed but retry may succeed",
|
|
+ /* 30 */ "unknown discovery type",
|
|
};
|
|
|
|
char *iscsi_err_to_str(int err)
|
|
diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h
|
|
index db5f1f0..5087b5c 100644
|
|
--- a/usr/iscsi_ipc.h
|
|
+++ b/usr/iscsi_ipc.h
|
|
@@ -30,6 +30,7 @@
|
|
|
|
enum {
|
|
ISCSI_INT,
|
|
+ ISCSI_UINT,
|
|
ISCSI_STRING,
|
|
};
|
|
|
|
@@ -143,8 +144,26 @@ struct iscsi_ipc {
|
|
uint16_t chap_tbl_idx, uint32_t num_entries,
|
|
char *chap_buf, uint32_t *valid_chap_entries);
|
|
|
|
+ int (*set_chap) (uint64_t transport_handle, uint32_t host_no,
|
|
+ struct iovec *iovs, uint32_t param_count);
|
|
+
|
|
int (*delete_chap) (uint64_t transport_handle, uint32_t host_no,
|
|
uint16_t chap_tbl_idx);
|
|
+ int (*set_flash_node_params) (uint64_t transport_handle,
|
|
+ uint32_t host_no, uint32_t flashnode_idx,
|
|
+ struct iovec *iovs, uint32_t param_count);
|
|
+ int (*new_flash_node) (uint64_t transport_handle, uint32_t host_no,
|
|
+ void *value, uint32_t *flashnode_idx);
|
|
+ int (*del_flash_node) (uint64_t transport_handle, uint32_t host_no,
|
|
+ uint32_t flashnode_idx);
|
|
+ int (*login_flash_node) (uint64_t transport_handle, uint32_t host_no,
|
|
+ uint32_t flashnode_idx);
|
|
+ int (*logout_flash_node) (uint64_t transport_handle, uint32_t host_no,
|
|
+ uint32_t flashnode_idx);
|
|
+ int (*logout_flash_node_sid) (uint64_t transport_handle,
|
|
+ uint32_t host_no, uint32_t sid);
|
|
+ int (*get_host_stats) (uint64_t transport_handle, uint32_t host_no,
|
|
+ char *host_stats);
|
|
};
|
|
|
|
#endif /* ISCSI_IPC_H */
|
|
diff --git a/usr/iscsi_net_util.c b/usr/iscsi_net_util.c
|
|
index 6d0ebf9..848b4c6 100644
|
|
--- a/usr/iscsi_net_util.c
|
|
+++ b/usr/iscsi_net_util.c
|
|
@@ -188,7 +188,7 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway,
|
|
int ret;
|
|
|
|
if (!strlen(netdev)) {
|
|
- log_error("No netdev name in fw entry.\n");
|
|
+ log_error("No netdev name in fw entry.");
|
|
return EINVAL;
|
|
}
|
|
|
|
@@ -203,13 +203,13 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway,
|
|
* has already been handled (2 targets in IBFT may share one NIC)
|
|
*/
|
|
if (!inet_aton(local_ip, &sk_ipaddr.sin_addr)) {
|
|
- log_error("Invalid or missing ipaddr in fw entry\n");
|
|
+ log_error("Invalid or missing ipaddr in fw entry");
|
|
ret = EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
if (!inet_aton(mask, &sk_netmask.sin_addr)) {
|
|
- log_error("Invalid or missing netmask in fw entry\n");
|
|
+ log_error("Invalid or missing netmask in fw entry");
|
|
ret = EINVAL;
|
|
goto done;
|
|
}
|
|
@@ -217,7 +217,7 @@ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway,
|
|
inet_aton("255.255.255.255", &sk_hostmask.sin_addr);
|
|
|
|
if (!inet_aton(remote_ip, &sk_tgt_ipaddr.sin_addr)) {
|
|
- log_error("Invalid or missing target ipaddr in fw entry\n");
|
|
+ log_error("Invalid or missing target ipaddr in fw entry");
|
|
ret = EINVAL;
|
|
goto done;
|
|
}
|
|
@@ -317,7 +317,7 @@ int net_ifup_netdev(char *netdev)
|
|
int ret = 0;
|
|
|
|
if (!strlen(netdev)) {
|
|
- log_error("No netdev name in fw entry.\n");
|
|
+ log_error("No netdev name in fw entry.");
|
|
return EINVAL;
|
|
}
|
|
|
|
@@ -338,11 +338,11 @@ int net_ifup_netdev(char *netdev)
|
|
}
|
|
|
|
if (ifr.ifr_flags & IFF_UP) {
|
|
- log_debug(3, "%s up\n", netdev);
|
|
+ log_debug(3, "%s up", netdev);
|
|
goto done;
|
|
}
|
|
|
|
- log_debug(3, "bringing %s up\n", netdev);
|
|
+ log_debug(3, "bringing %s up", netdev);
|
|
|
|
/* Bring up interface */
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c
|
|
index 123dde3..3a37a48 100644
|
|
--- a/usr/iscsi_sysfs.c
|
|
+++ b/usr/iscsi_sysfs.c
|
|
@@ -24,11 +24,13 @@
|
|
#include <dirent.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
+#include <sys/wait.h>
|
|
|
|
#include "log.h"
|
|
#include "initiator.h"
|
|
#include "transport.h"
|
|
#include "idbm.h"
|
|
+#include "idbm_fields.h"
|
|
#include "version.h"
|
|
#include "iscsi_sysfs.h"
|
|
#include "sysdeps.h"
|
|
@@ -37,6 +39,7 @@
|
|
#include "session_info.h"
|
|
#include "host.h"
|
|
#include "iscsi_err.h"
|
|
+#include "flashnode.h"
|
|
|
|
/*
|
|
* TODO: remove the _DIR defines and search for subsys dirs like
|
|
@@ -45,18 +48,22 @@
|
|
#define ISCSI_TRANSPORT_DIR "/sys/class/iscsi_transport"
|
|
#define ISCSI_SESSION_DIR "/sys/class/iscsi_session"
|
|
#define ISCSI_HOST_DIR "/sys/class/iscsi_host"
|
|
+#define ISCSI_FLASHNODE_DIR "/sys/bus/iscsi_flashnode/devices"
|
|
|
|
#define ISCSI_SESSION_SUBSYS "iscsi_session"
|
|
#define ISCSI_CONN_SUBSYS "iscsi_connection"
|
|
#define ISCSI_HOST_SUBSYS "iscsi_host"
|
|
#define ISCSI_TRANSPORT_SUBSYS "iscsi_transport"
|
|
#define ISCSI_IFACE_SUBSYS "iscsi_iface"
|
|
+#define ISCSI_FLASHNODE_SUBSYS "iscsi_flashnode"
|
|
#define SCSI_HOST_SUBSYS "scsi_host"
|
|
#define SCSI_SUBSYS "scsi"
|
|
|
|
#define ISCSI_SESSION_ID "session%d"
|
|
#define ISCSI_CONN_ID "connection%d:0"
|
|
#define ISCSI_HOST_ID "host%d"
|
|
+#define ISCSI_FLASHNODE_SESS "flashnode_sess-%d:%d"
|
|
+#define ISCSI_FLASHNODE_CONN "flashnode_conn-%d:%d:0"
|
|
|
|
/*
|
|
* TODO: make this into a real API and check inputs better and add doc.
|
|
@@ -130,7 +137,7 @@ static int read_transports(void)
|
|
if (list_empty(&t->list))
|
|
free(t);
|
|
else
|
|
- log_error("Could not update %s.\n",
|
|
+ log_error("Could not update %s.",
|
|
t->name);
|
|
continue;
|
|
}
|
|
@@ -140,7 +147,7 @@ static int read_transports(void)
|
|
if (list_empty(&t->list))
|
|
free(t);
|
|
else
|
|
- log_error("Could not update %s.\n",
|
|
+ log_error("Could not update %s.",
|
|
t->name);
|
|
continue;
|
|
}
|
|
@@ -265,7 +272,7 @@ uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err)
|
|
if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
|
|
ISCSI_SESSION_SUBSYS, id)) {
|
|
log_error("Could not lookup devpath for %s. Possible sysfs "
|
|
- "incompatibility.\n", id);
|
|
+ "incompatibility.", id);
|
|
*err = ISCSI_ERR_SYSFS_LOOKUP;
|
|
return 0;
|
|
}
|
|
@@ -273,7 +280,7 @@ uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err)
|
|
session_dev = sysfs_device_get(devpath);
|
|
if (!session_dev) {
|
|
log_error("Could not get dev for %s. Possible sysfs "
|
|
- "incompatibility.\n", id);
|
|
+ "incompatibility.", id);
|
|
*err = ISCSI_ERR_SYSFS_LOOKUP;
|
|
return 0;
|
|
}
|
|
@@ -298,7 +305,7 @@ uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err)
|
|
|
|
if (!host_dev) {
|
|
log_error("Could not get host dev for %s. Possible "
|
|
- "sysfs incompatibility.\n", id);
|
|
+ "sysfs incompatibility.", id);
|
|
*err = ISCSI_ERR_SYSFS_LOOKUP;
|
|
return 0;
|
|
}
|
|
@@ -440,6 +447,271 @@ uint32_t iscsi_sysfs_get_host_no_from_hwinfo(struct iface_rec *iface, int *rc)
|
|
}
|
|
|
|
/*
|
|
+ * Read the flash node attributes based on host and flash node index.
|
|
+ */
|
|
+int iscsi_sysfs_get_flashnode_info(struct flashnode_rec *fnode,
|
|
+ uint32_t host_no,
|
|
+ uint32_t flashnode_idx)
|
|
+{
|
|
+ char sess_id[NAME_SIZE] = {'\0'};
|
|
+ char conn_id[NAME_SIZE] = {'\0'};
|
|
+ char fnode_path[PATH_SIZE] = {'\0'};
|
|
+ struct iscsi_transport *t;
|
|
+ int ret = 0;
|
|
+
|
|
+ t = iscsi_sysfs_get_transport_by_hba(host_no);
|
|
+ if (!t)
|
|
+ log_debug(7, "could not get transport name for host%d",
|
|
+ host_no);
|
|
+ else
|
|
+ strncpy(fnode->transport_name, t->name,
|
|
+ ISCSI_TRANSPORT_NAME_MAXLEN);
|
|
+
|
|
+ snprintf(sess_id, sizeof(sess_id), ISCSI_FLASHNODE_SESS, host_no,
|
|
+ flashnode_idx);
|
|
+
|
|
+ snprintf(fnode_path, sizeof(fnode_path), ISCSI_FLASHNODE_DIR"/%s",
|
|
+ sess_id);
|
|
+ if (access(fnode_path, F_OK) != 0)
|
|
+ return errno;
|
|
+
|
|
+ snprintf(conn_id, sizeof(conn_id), ISCSI_FLASHNODE_CONN, host_no,
|
|
+ flashnode_idx);
|
|
+
|
|
+ snprintf(fnode_path, sizeof(fnode_path), ISCSI_FLASHNODE_DIR"/%s",
|
|
+ conn_id);
|
|
+ if (access(fnode_path, F_OK) != 0)
|
|
+ return errno;
|
|
+
|
|
+
|
|
+ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "is_fw_assigned_ipv6",
|
|
+ &((fnode->conn[0]).is_fw_assigned_ipv6));
|
|
+ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "portal_type",
|
|
+ (fnode->sess).portal_type,
|
|
+ sizeof((fnode->sess).portal_type));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "auto_snd_tgt_disable",
|
|
+ &((fnode->sess).auto_snd_tgt_disable));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "discovery_session",
|
|
+ &((fnode->sess).discovery_session));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "entry_enable",
|
|
+ &((fnode->sess).entry_enable));
|
|
+ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "header_digest",
|
|
+ &((fnode->conn[0]).header_digest_en));
|
|
+ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "data_digest",
|
|
+ &((fnode->conn[0]).data_digest_en));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "immediate_data",
|
|
+ &((fnode->sess).immediate_data));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "initial_r2t",
|
|
+ &((fnode->sess).initial_r2t));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "data_seq_in_order",
|
|
+ &((fnode->sess).data_seq_in_order));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "data_pdu_in_order",
|
|
+ &((fnode->sess).data_pdu_in_order));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "chap_auth",
|
|
+ &((fnode->sess).chap_auth_en));
|
|
+ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "snack_req",
|
|
+ &((fnode->conn[0]).snack_req_en));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "discovery_logout",
|
|
+ &((fnode->sess).discovery_logout_en));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "bidi_chap",
|
|
+ &((fnode->sess).bidi_chap_en));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS,
|
|
+ "discovery_auth_optional",
|
|
+ &((fnode->sess).discovery_auth_optional));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "erl",
|
|
+ &((fnode->sess).erl));
|
|
+ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_timestamp_stat",
|
|
+ &((fnode->conn[0]).tcp_timestamp_stat));
|
|
+ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_nagle_disable",
|
|
+ &((fnode->conn[0]).tcp_nagle_disable));
|
|
+ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_wsf_disable",
|
|
+ &((fnode->conn[0]).tcp_wsf_disable));
|
|
+ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_timer_scale",
|
|
+ &((fnode->conn[0]).tcp_timer_scale));
|
|
+ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_timestamp_enable",
|
|
+ &((fnode->conn[0]).tcp_timestamp_en));
|
|
+ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "fragment_disable",
|
|
+ &((fnode->conn[0]).fragment_disable));
|
|
+ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "max_recv_dlength",
|
|
+ &((fnode->conn[0]).max_recv_dlength));
|
|
+ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "max_xmit_dlength",
|
|
+ &((fnode->conn[0]).max_xmit_dlength));
|
|
+ sysfs_get_uint(sess_id, ISCSI_FLASHNODE_SUBSYS, "first_burst_len",
|
|
+ &((fnode->sess).first_burst_len));
|
|
+ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "def_time2wait",
|
|
+ &((fnode->sess).def_time2wait));
|
|
+ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "def_time2retain",
|
|
+ &((fnode->sess).def_time2retain));
|
|
+ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "max_outstanding_r2t",
|
|
+ &((fnode->sess).max_outstanding_r2t));
|
|
+ sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "keepalive_tmo",
|
|
+ &((fnode->conn[0]).keepalive_tmo));
|
|
+ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "isid",
|
|
+ (fnode->sess).isid, sizeof((fnode->sess).isid));
|
|
+ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "tsid",
|
|
+ &((fnode->sess).tsid));
|
|
+ sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "port",
|
|
+ &((fnode->conn[0]).port));
|
|
+ sysfs_get_uint(sess_id, ISCSI_FLASHNODE_SUBSYS, "max_burst_len",
|
|
+ &((fnode->sess).max_burst_len));
|
|
+ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "def_taskmgmt_tmo",
|
|
+ &((fnode->sess).def_taskmgmt_tmo));
|
|
+ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "targetalias",
|
|
+ (fnode->sess).targetalias,
|
|
+ sizeof((fnode->sess).targetalias));
|
|
+ sysfs_get_str(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipaddress",
|
|
+ (fnode->conn[0]).ipaddress,
|
|
+ sizeof((fnode->conn[0]).ipaddress));
|
|
+ sysfs_get_str(conn_id, ISCSI_FLASHNODE_SUBSYS, "redirect_ipaddr",
|
|
+ (fnode->conn[0]).redirect_ipaddr,
|
|
+ sizeof((fnode->conn[0]).redirect_ipaddr));
|
|
+ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "max_segment_size",
|
|
+ &((fnode->conn[0]).max_segment_size));
|
|
+ sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "local_port",
|
|
+ &((fnode->conn[0]).local_port));
|
|
+ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipv4_tos",
|
|
+ &((fnode->conn[0]).ipv4_tos));
|
|
+ sysfs_get_uint8(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipv6_traffic_class",
|
|
+ &((fnode->conn[0]).ipv6_traffic_class));
|
|
+ sysfs_get_uint16(conn_id, ISCSI_FLASHNODE_SUBSYS, "ipv6_flow_label",
|
|
+ &((fnode->conn[0]).ipv6_flow_lbl));
|
|
+ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "targetname",
|
|
+ (fnode->sess).targetname,
|
|
+ sizeof((fnode->sess).targetname));
|
|
+ sysfs_get_str(conn_id, ISCSI_FLASHNODE_SUBSYS, "link_local_ipv6",
|
|
+ (fnode->conn[0]).link_local_ipv6,
|
|
+ sizeof((fnode->conn[0]).link_local_ipv6));
|
|
+ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS,
|
|
+ "discovery_parent_idx",
|
|
+ &((fnode->sess).discovery_parent_idx));
|
|
+ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS,
|
|
+ "discovery_parent_type",
|
|
+ (fnode->sess).discovery_parent_type,
|
|
+ sizeof((fnode->sess).discovery_parent_type));
|
|
+ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "tpgt",
|
|
+ &((fnode->sess).tpgt));
|
|
+ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_xmit_wsf",
|
|
+ &((fnode->conn[0]).tcp_xmit_wsf));
|
|
+ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "tcp_recv_wsf",
|
|
+ &((fnode->conn[0]).tcp_recv_wsf));
|
|
+ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "chap_out_idx",
|
|
+ &((fnode->sess).chap_out_idx));
|
|
+ sysfs_get_uint16(sess_id, ISCSI_FLASHNODE_SUBSYS, "chap_in_idx",
|
|
+ &((fnode->sess).chap_in_idx));
|
|
+ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "username",
|
|
+ (fnode->sess).username, sizeof((fnode->sess).username));
|
|
+ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "username_in",
|
|
+ (fnode->sess).username_in,
|
|
+ sizeof((fnode->sess).username_in));
|
|
+ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "password",
|
|
+ (fnode->sess).password, sizeof((fnode->sess).password));
|
|
+ sysfs_get_str(sess_id, ISCSI_FLASHNODE_SUBSYS, "password_in",
|
|
+ (fnode->sess).password_in,
|
|
+ sizeof((fnode->sess).password_in));
|
|
+ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "statsn",
|
|
+ &((fnode->conn[0]).stat_sn));
|
|
+ sysfs_get_uint(conn_id, ISCSI_FLASHNODE_SUBSYS, "exp_statsn",
|
|
+ &((fnode->conn[0]).exp_stat_sn));
|
|
+ sysfs_get_uint8(sess_id, ISCSI_FLASHNODE_SUBSYS, "is_boot_target",
|
|
+ &((fnode->sess).is_boot_target));
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * For each flash node of the given host, perform operation specified in fn.
|
|
+ */
|
|
+int iscsi_sysfs_for_each_flashnode(void *data, uint32_t host_no, int *nr_found,
|
|
+ iscsi_sysfs_flashnode_op_fn *fn)
|
|
+{
|
|
+ struct dirent **namelist;
|
|
+ int rc = 0, i, n;
|
|
+ struct flashnode_rec *fnode;
|
|
+ uint32_t flashnode_idx;
|
|
+ uint32_t hostno;
|
|
+
|
|
+ fnode = malloc(sizeof(*fnode));
|
|
+ if (!fnode)
|
|
+ return ISCSI_ERR_NOMEM;
|
|
+
|
|
+ n = scandir(ISCSI_FLASHNODE_DIR, &namelist, trans_filter, alphasort);
|
|
+ if (n <= 0)
|
|
+ goto free_fnode;
|
|
+
|
|
+ for (i = 0; i < n; i++) {
|
|
+ memset(fnode, 0, sizeof(*fnode));
|
|
+
|
|
+ if (!strncmp(namelist[i]->d_name, "flashnode_conn",
|
|
+ strlen("flashnode_conn")))
|
|
+ continue;
|
|
+
|
|
+ if (sscanf(namelist[i]->d_name, ISCSI_FLASHNODE_SESS,
|
|
+ &hostno, &flashnode_idx) != 2) {
|
|
+ log_error("Invalid iscsi target dir: %s",
|
|
+ namelist[i]->d_name);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (host_no != hostno)
|
|
+ continue;
|
|
+
|
|
+ rc = iscsi_sysfs_get_flashnode_info(fnode, host_no,
|
|
+ flashnode_idx);
|
|
+ if (rc)
|
|
+ break;
|
|
+
|
|
+ rc = fn(data, fnode, host_no, flashnode_idx);
|
|
+ if (rc != 0)
|
|
+ break;
|
|
+ (*nr_found)++;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < n; i++)
|
|
+ free(namelist[i]);
|
|
+ free(namelist);
|
|
+
|
|
+free_fnode:
|
|
+ free(fnode);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int iscsi_sysfs_read_boot(struct iface_rec *iface, char *session)
|
|
+{
|
|
+ char boot_root[BOOT_NAME_MAXLEN], boot_nic[BOOT_NAME_MAXLEN];
|
|
+ char boot_name[BOOT_NAME_MAXLEN], boot_content[BOOT_NAME_MAXLEN];
|
|
+
|
|
+ /* Extract boot info */
|
|
+ strlcpy(boot_name, "boot_target", sizeof(boot_name));
|
|
+ if (sysfs_get_str(session, ISCSI_SESSION_SUBSYS, boot_name,
|
|
+ boot_content, BOOT_NAME_MAXLEN))
|
|
+ return -1;
|
|
+ strlcpy(boot_name, "boot_nic", sizeof(boot_name));
|
|
+ if (sysfs_get_str(session, ISCSI_SESSION_SUBSYS, boot_name, boot_nic,
|
|
+ BOOT_NAME_MAXLEN))
|
|
+ return -1;
|
|
+ strlcpy(boot_name, "boot_root", sizeof(boot_name));
|
|
+ if (sysfs_get_str(session, ISCSI_SESSION_SUBSYS, boot_name, boot_root,
|
|
+ BOOT_NAME_MAXLEN))
|
|
+ return -1;
|
|
+
|
|
+ /* If all boot_root/boot_target/boot_nic exist, then extract the
|
|
+ info from the boot nic */
|
|
+ if (sysfs_get_str(boot_nic, boot_root, "vlan", boot_content,
|
|
+ BOOT_NAME_MAXLEN))
|
|
+ log_debug(5, "could not read %s/%s/vlan", boot_root, boot_nic);
|
|
+ else
|
|
+ iface->vlan_id = atoi(boot_content);
|
|
+
|
|
+ if (sysfs_get_str(boot_nic, boot_root, "subnet-mask",
|
|
+ iface->subnet_mask, NI_MAXHOST))
|
|
+ log_debug(5, "could not read %s/%s/subnet", boot_root,
|
|
+ boot_nic);
|
|
+
|
|
+ log_debug(5, "sysfs read boot returns %s/%s/ vlan = %d subnet = %s",
|
|
+ boot_root, boot_nic, iface->vlan_id, iface->subnet_mask);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
* Read in iface settings based on host and session values. If
|
|
* session is not passed in, then the ifacename will not be set. And
|
|
* if the session is not passed in then iname will only be set for
|
|
@@ -469,7 +741,7 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no,
|
|
ret = sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "hwaddress",
|
|
iface->hwaddress, sizeof(iface->hwaddress));
|
|
if (ret)
|
|
- log_debug(7, "could not read hwaddress for host%d\n", host_no);
|
|
+ log_debug(7, "could not read hwaddress for host%d", host_no);
|
|
|
|
if (iface_kern_id)
|
|
ret = sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
@@ -480,14 +752,14 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no,
|
|
ret = sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "ipaddress",
|
|
iface->ipaddress, sizeof(iface->ipaddress));
|
|
if (ret)
|
|
- log_debug(7, "could not read local address for host%d\n",
|
|
+ log_debug(7, "could not read local address for host%d",
|
|
host_no);
|
|
|
|
/* if not found just print out default */
|
|
ret = sysfs_get_str(host_id, ISCSI_HOST_SUBSYS, "netdev",
|
|
iface->netdev, sizeof(iface->netdev));
|
|
if (ret)
|
|
- log_debug(7, "could not read netdev for host%d\n", host_no);
|
|
+ log_debug(7, "could not read netdev for host%d", host_no);
|
|
|
|
/*
|
|
* For drivers like qla4xxx we can only set the iname at the
|
|
@@ -527,7 +799,7 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no,
|
|
* global iname so we can just fill it in here.
|
|
*/
|
|
log_debug(7, "Could not read initiatorname for "
|
|
- "host%d\n", host_no);
|
|
+ "host%d", host_no);
|
|
/* optional so do not return error */
|
|
ret = 0;
|
|
}
|
|
@@ -553,7 +825,7 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no,
|
|
iface->name, sizeof(iface->name));
|
|
if (ret) {
|
|
log_debug(7, "could not read iface name for "
|
|
- "session %s\n", session);
|
|
+ "session %s", session);
|
|
/*
|
|
* if the ifacename file is not there then we are
|
|
* using a older kernel and can try to find the
|
|
@@ -562,11 +834,14 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no,
|
|
*/
|
|
if (iface_get_by_net_binding(iface, iface))
|
|
log_debug(7, "Could not find iface for session "
|
|
- "bound to:" iface_fmt "\n",
|
|
+ "bound to:" iface_fmt "",
|
|
iface_str(iface));
|
|
}
|
|
}
|
|
|
|
+ if (session && t->template->use_boot_info)
|
|
+ iscsi_sysfs_read_boot(iface, session);
|
|
+
|
|
if (!iface_kern_id)
|
|
goto done;
|
|
|
|
@@ -581,6 +856,71 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no,
|
|
|
|
sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "subnet",
|
|
iface->subnet_mask, sizeof(iface->subnet_mask));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "dhcp_alt_client_id_en",
|
|
+ iface->dhcp_alt_client_id_state,
|
|
+ sizeof(iface->dhcp_alt_client_id_state));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "dhcp_alt_client_id",
|
|
+ iface->dhcp_alt_client_id,
|
|
+ sizeof(iface->dhcp_alt_client_id));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "dhcp_dns_address_en",
|
|
+ iface->dhcp_dns, sizeof(iface->dhcp_dns));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "dhcp_learn_iqn_en",
|
|
+ iface->dhcp_learn_iqn,
|
|
+ sizeof(iface->dhcp_learn_iqn));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "dhcp_req_vendor_id_en",
|
|
+ iface->dhcp_req_vendor_id_state,
|
|
+ sizeof(iface->dhcp_req_vendor_id_state));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "dhcp_use_vendor_id_en",
|
|
+ iface->dhcp_vendor_id_state,
|
|
+ sizeof(iface->dhcp_vendor_id_state));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "dhcp_vendor_id",
|
|
+ iface->dhcp_vendor_id,
|
|
+ sizeof(iface->dhcp_vendor_id));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "dhcp_slp_da_info_en",
|
|
+ iface->dhcp_slp_da, sizeof(iface->dhcp_slp_da));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "fragment_disable",
|
|
+ iface->fragmentation,
|
|
+ sizeof(iface->fragmentation));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "grat_arp_en",
|
|
+ iface->gratuitous_arp,
|
|
+ sizeof(iface->gratuitous_arp));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "incoming_forwarding_en",
|
|
+ iface->incoming_forwarding,
|
|
+ sizeof(iface->incoming_forwarding));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "tos_en",
|
|
+ iface->tos_state, sizeof(iface->tos_state));
|
|
+
|
|
+ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "tos", &iface->tos))
|
|
+ iface->tos = 0;
|
|
+
|
|
+ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "ttl", &iface->ttl))
|
|
+ iface->ttl = 0;
|
|
} else {
|
|
sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
"ipaddr_autocfg",
|
|
@@ -597,6 +937,53 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no,
|
|
sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "router_addr",
|
|
iface->ipv6_router,
|
|
sizeof(iface->ipv6_router));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "router_state",
|
|
+ iface->router_autocfg,
|
|
+ sizeof(iface->router_autocfg));
|
|
+
|
|
+ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "dup_addr_detect_cnt",
|
|
+ &iface->dup_addr_detect_cnt))
|
|
+ iface->dup_addr_detect_cnt = 0;
|
|
+
|
|
+ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "flow_label", &iface->flow_label))
|
|
+ iface->flow_label = 0;
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "grat_neighbor_adv_en",
|
|
+ iface->gratuitous_neighbor_adv,
|
|
+ sizeof(iface->gratuitous_neighbor_adv));
|
|
+
|
|
+ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "hop_limit", &iface->hop_limit))
|
|
+ iface->hop_limit = 0;
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "mld_en",
|
|
+ iface->mld, sizeof(iface->mld));
|
|
+
|
|
+ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "nd_reachable_tmo",
|
|
+ &iface->nd_reachable_tmo))
|
|
+ iface->nd_reachable_tmo = 0;
|
|
+
|
|
+ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "nd_rexmit_time", &iface->nd_rexmit_time))
|
|
+ iface->nd_rexmit_time = 0;
|
|
+
|
|
+ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "nd_stale_tmo", &iface->nd_stale_tmo))
|
|
+ iface->nd_stale_tmo = 0;
|
|
+
|
|
+ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "router_adv_link_mtu",
|
|
+ &iface->router_adv_link_mtu))
|
|
+ iface->router_adv_link_mtu = 0;
|
|
+
|
|
+ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "traffic_class", &iface->traffic_class))
|
|
+ iface->traffic_class = 0;
|
|
}
|
|
|
|
if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS, "port",
|
|
@@ -613,6 +1000,94 @@ static int iscsi_sysfs_read_iface(struct iface_rec *iface, int host_no,
|
|
&iface->vlan_priority))
|
|
iface->vlan_priority = UINT8_MAX;
|
|
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "vlan_enabled",
|
|
+ iface->vlan_state, sizeof(iface->vlan_state));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "enabled",
|
|
+ iface->state, sizeof(iface->state));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "delayed_ack_en",
|
|
+ iface->delayed_ack, sizeof(iface->delayed_ack));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "tcp_nagle_disable",
|
|
+ iface->nagle, sizeof(iface->nagle));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "tcp_wsf_disable",
|
|
+ iface->tcp_wsf_state, sizeof(iface->tcp_wsf_state));
|
|
+
|
|
+ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, "tcp_wsf",
|
|
+ &iface->tcp_wsf))
|
|
+ iface->tcp_wsf = 0;
|
|
+
|
|
+ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "tcp_timer_scale", &iface->tcp_timer_scale))
|
|
+ iface->tcp_timer_scale = 0;
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "tcp_timestamp_en",
|
|
+ iface->tcp_timestamp, sizeof(iface->tcp_timestamp));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "redirect_en",
|
|
+ iface->redirect, sizeof(iface->redirect));
|
|
+
|
|
+ if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "def_taskmgmt_tmo", &iface->def_task_mgmt_tmo))
|
|
+ iface->def_task_mgmt_tmo = 0;
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "header_digest",
|
|
+ iface->header_digest, sizeof(iface->header_digest));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "data_digest",
|
|
+ iface->data_digest, sizeof(iface->data_digest));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "immediate_data",
|
|
+ iface->immediate_data, sizeof(iface->immediate_data));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "initial_r2t",
|
|
+ iface->initial_r2t, sizeof(iface->initial_r2t));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "data_seq_in_order",
|
|
+ iface->data_seq_inorder, sizeof(iface->data_seq_inorder));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "data_pdu_in_order",
|
|
+ iface->data_pdu_inorder, sizeof(iface->data_pdu_inorder));
|
|
+
|
|
+ if (sysfs_get_uint8(iface_kern_id, ISCSI_IFACE_SUBSYS, "erl",
|
|
+ &iface->erl))
|
|
+ iface->erl = 0;
|
|
+
|
|
+ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "max_recv_dlength", &iface->max_recv_dlength))
|
|
+ iface->max_recv_dlength = 0;
|
|
+
|
|
+ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "first_burst_len", &iface->first_burst_len))
|
|
+ iface->first_burst_len = 0;
|
|
+
|
|
+ if (sysfs_get_uint16(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "max_outstanding_r2t", &iface->max_out_r2t))
|
|
+ iface->max_out_r2t = 0;
|
|
+
|
|
+ if (sysfs_get_uint(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "max_burst_len", &iface->max_burst_len))
|
|
+ iface->max_burst_len = 0;
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "chap_auth",
|
|
+ iface->chap_auth, sizeof(iface->chap_auth));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "bidi_chap",
|
|
+ iface->bidi_chap, sizeof(iface->bidi_chap));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "strict_login_comp_en",
|
|
+ iface->strict_login_comp,
|
|
+ sizeof(iface->strict_login_comp));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS,
|
|
+ "discovery_auth_optional",
|
|
+ iface->discovery_auth, sizeof(iface->discovery_auth));
|
|
+
|
|
+ sysfs_get_str(iface_kern_id, ISCSI_IFACE_SUBSYS, "discovery_logout",
|
|
+ iface->discovery_logout, sizeof(iface->discovery_logout));
|
|
+
|
|
if (sscanf(iface_kern_id, "ipv%d-iface-%u-%u", &iface_type,
|
|
&tmp_host_no, &iface_num) == 3)
|
|
iface->iface_num = iface_num;
|
|
@@ -740,7 +1215,7 @@ int iscsi_sysfs_session_has_leadconn(uint32_t sid)
|
|
* /sys/devices/platform/hostH/sessionS/targetH:B:I
|
|
* /sys/devices/platform/hostH/sessionS
|
|
*
|
|
- * return the sid S. If just the sid is passed in it will be covnerted
|
|
+ * return the sid S. If just the sid is passed in it will be converted
|
|
* to a int.
|
|
*/
|
|
int iscsi_sysfs_get_sid_from_path(char *session)
|
|
@@ -748,15 +1223,16 @@ int iscsi_sysfs_get_sid_from_path(char *session)
|
|
struct sysfs_device *dev_parent, *dev;
|
|
struct stat statb;
|
|
char devpath[PATH_SIZE];
|
|
+ char *end;
|
|
+ int sid;
|
|
+
|
|
+ sid = strtol(session, &end, 10);
|
|
+ if (sid > 0 && *session != '\0' && *end == '\0')
|
|
+ return sid;
|
|
|
|
if (lstat(session, &statb)) {
|
|
- log_debug(1, "Could not stat %s failed with %d",
|
|
- session, errno);
|
|
- if (index(session, '/')) {
|
|
- log_error("%s is an invalid session path\n", session);
|
|
- exit(1);
|
|
- }
|
|
- return atoi(session);
|
|
+ log_error("%s is an invalid session ID or path", session);
|
|
+ exit(1);
|
|
}
|
|
|
|
if (!S_ISDIR(statb.st_mode) && !S_ISLNK(statb.st_mode)) {
|
|
@@ -772,7 +1248,7 @@ int iscsi_sysfs_get_sid_from_path(char *session)
|
|
dev = sysfs_device_get(devpath);
|
|
if (!dev) {
|
|
log_error("Could not get dev for %s. Possible sysfs "
|
|
- "incompatibility.\n", devpath);
|
|
+ "incompatibility.", devpath);
|
|
return -1;
|
|
}
|
|
|
|
@@ -932,11 +1408,13 @@ int iscsi_sysfs_get_sessioninfo_by_id(struct session_info *info, char *session)
|
|
}
|
|
|
|
int iscsi_sysfs_for_each_session(void *data, int *nr_found,
|
|
- iscsi_sysfs_session_op_fn *fn)
|
|
+ iscsi_sysfs_session_op_fn *fn,
|
|
+ int in_parallel)
|
|
{
|
|
struct dirent **namelist;
|
|
- int rc = 0, n, i;
|
|
+ int rc = 0, n, i, chldrc = 0;
|
|
struct session_info *info;
|
|
+ pid_t pid = 0;
|
|
|
|
info = calloc(1, sizeof(*info));
|
|
if (!info)
|
|
@@ -958,14 +1436,52 @@ int iscsi_sysfs_for_each_session(void *data, int *nr_found,
|
|
continue;
|
|
}
|
|
|
|
- rc = fn(data, info);
|
|
- if (rc > 0)
|
|
- break;
|
|
- else if (rc == 0)
|
|
- (*nr_found)++;
|
|
- else
|
|
- /* if less than zero it means it was not a match */
|
|
- rc = 0;
|
|
+ if (in_parallel) {
|
|
+ pid = fork();
|
|
+ }
|
|
+ if (pid == 0) {
|
|
+ rc = fn(data, info);
|
|
+ if (in_parallel) {
|
|
+ exit(rc);
|
|
+ } else {
|
|
+ if (rc > 0) {
|
|
+ break;
|
|
+ } else if (rc == 0) {
|
|
+ (*nr_found)++;
|
|
+ } else {
|
|
+ /* if less than zero it means it was not a match */
|
|
+ rc = 0;
|
|
+ }
|
|
+ }
|
|
+ } else if (pid < 0) {
|
|
+ log_error("could not fork() for session %s, err %d",
|
|
+ namelist[i]->d_name, errno);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (in_parallel) {
|
|
+ while (1) {
|
|
+ if (wait(&chldrc) < 0) {
|
|
+ /*
|
|
+ * ECHILD means no more children which is
|
|
+ * expected to happen sooner or later.
|
|
+ */
|
|
+ if (errno != ECHILD) {
|
|
+ rc = errno;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if ((chldrc > 0) && (rc == 0)) {
|
|
+ /*
|
|
+ * The non-parallel code path returns the first
|
|
+ * error so this keeps the same semantics.
|
|
+ */
|
|
+ rc = chldrc;
|
|
+ } else if (chldrc == 0) {
|
|
+ (*nr_found)++;
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
for (i = 0; i < n; i++)
|
|
@@ -1006,7 +1522,7 @@ int iscsi_sysfs_get_device_state(char *state, int host_no, int target, int lun)
|
|
snprintf(id, sizeof(id), "%d:0:%d:%d", host_no, target, lun);
|
|
if (sysfs_get_str(id, SCSI_SUBSYS, "state", state,
|
|
SCSI_MAX_STATE_VALUE)) {
|
|
- log_debug(3, "Could not read attr state for %s\n", id);
|
|
+ log_debug(3, "Could not read attr state for %s", id);
|
|
return ISCSI_ERR_SYSFS_LOOKUP;
|
|
}
|
|
|
|
@@ -1027,7 +1543,7 @@ char *iscsi_sysfs_get_blockdev_from_lun(int host_no, int target, int lun)
|
|
snprintf(id, sizeof(id), "%d:0:%d:%d", host_no, target, lun);
|
|
if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
|
|
SCSI_SUBSYS, id)) {
|
|
- log_debug(3, "Could not lookup devpath for %s %s\n",
|
|
+ log_debug(3, "Could not lookup devpath for %s %s",
|
|
SCSI_SUBSYS, id);
|
|
return NULL;
|
|
}
|
|
@@ -1055,7 +1571,7 @@ char *iscsi_sysfs_get_blockdev_from_lun(int host_no, int target, int lun)
|
|
* 2.6.25 dropped the symlink and now block is a dir.
|
|
*/
|
|
if (lstat(path_full, &statbuf)) {
|
|
- log_error("Could not stat block path %s err %d\n",
|
|
+ log_error("Could not stat block path %s err %d",
|
|
path_full, errno);
|
|
break;
|
|
}
|
|
@@ -1074,7 +1590,7 @@ char *iscsi_sysfs_get_blockdev_from_lun(int host_no, int target, int lun)
|
|
/* it should not be this hard should it? :) */
|
|
blk_dirfd = opendir(path_full);
|
|
if (!blk_dirfd) {
|
|
- log_debug(3, "Could not open blk path %s\n",
|
|
+ log_debug(3, "Could not open blk path %s",
|
|
path_full);
|
|
break;
|
|
}
|
|
@@ -1110,7 +1626,7 @@ static uint32_t get_target_no_from_sid(uint32_t sid, int *err)
|
|
snprintf(id, sizeof(id), "session%u", sid);
|
|
if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
|
|
ISCSI_SESSION_SUBSYS, id)) {
|
|
- log_debug(3, "Could not lookup devpath for %s %s\n",
|
|
+ log_debug(3, "Could not lookup devpath for %s %s",
|
|
ISCSI_SESSION_SUBSYS, id);
|
|
return 0;
|
|
}
|
|
@@ -1283,7 +1799,7 @@ int iscsi_sysfs_for_each_device(void *data, int host_no, uint32_t sid,
|
|
snprintf(id, sizeof(id), "session%u", sid);
|
|
if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
|
|
ISCSI_SESSION_SUBSYS, id)) {
|
|
- log_debug(3, "Could not lookup devpath for %s %s\n",
|
|
+ log_debug(3, "Could not lookup devpath for %s %s",
|
|
ISCSI_SESSION_SUBSYS, id);
|
|
return ISCSI_ERR_SYSFS_LOOKUP;
|
|
}
|
|
@@ -1367,7 +1883,7 @@ pid_t iscsi_sysfs_scan_host(int hostno, int async)
|
|
snprintf(id, sizeof(id), ISCSI_HOST_ID, hostno);
|
|
sysfs_set_param(id, SCSI_HOST_SUBSYS, "scan", write_buf,
|
|
strlen(write_buf));
|
|
- log_debug(4, "scanning host%d completed\n", hostno);
|
|
+ log_debug(4, "scanning host%d completed", hostno);
|
|
} else if (pid > 0) {
|
|
log_debug(4, "scanning host%d from pid %d", hostno, pid);
|
|
} else
|
|
diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h
|
|
index 2b15d78..9a56105 100644
|
|
--- a/usr/iscsi_sysfs.h
|
|
+++ b/usr/iscsi_sysfs.h
|
|
@@ -31,6 +31,7 @@ struct iscsi_conn;
|
|
struct iscsi_session_operational_config;
|
|
struct iscsi_conn_operational_config;
|
|
struct iscsi_auth_config;
|
|
+struct flashnode_rec;
|
|
|
|
#define SCSI_MAX_STATE_VALUE 32
|
|
|
|
@@ -42,13 +43,16 @@ extern int iscsi_sysfs_session_has_leadconn(uint32_t sid);
|
|
|
|
typedef int (iscsi_sysfs_session_op_fn)(void *, struct session_info *);
|
|
typedef int (iscsi_sysfs_host_op_fn)(void *, struct host_info *);
|
|
+typedef int (iscsi_sysfs_flashnode_op_fn)(void *, struct flashnode_rec *,
|
|
+ uint32_t, uint32_t);
|
|
typedef int (iscsi_sysfs_iface_op_fn)(void *, struct iface_rec *);
|
|
|
|
extern int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no,
|
|
int *nr_found,
|
|
iscsi_sysfs_iface_op_fn *fn);
|
|
extern int iscsi_sysfs_for_each_session(void *data, int *nr_found,
|
|
- iscsi_sysfs_session_op_fn *fn);
|
|
+ iscsi_sysfs_session_op_fn *fn,
|
|
+ int in_parallel);
|
|
extern int iscsi_sysfs_for_each_host(void *data, int *nr_found,
|
|
iscsi_sysfs_host_op_fn *fn);
|
|
extern uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err);
|
|
@@ -56,6 +60,20 @@ extern uint32_t iscsi_sysfs_get_host_no_from_hwinfo(struct iface_rec *iface,
|
|
int *rc);
|
|
extern uint32_t iscsi_sysfs_get_host_no_from_hwaddress(char *hwaddress, int *rc);
|
|
extern int iscsi_sysfs_get_hostinfo_by_host_no(struct host_info *hinfo);
|
|
+extern int iscsi_sysfs_for_each_flashnode(void *data, uint32_t host_no,
|
|
+ int *nr_found,
|
|
+ iscsi_sysfs_flashnode_op_fn *fn);
|
|
+extern int iscsi_sysfs_get_flashnode_info(struct flashnode_rec *fnode,
|
|
+ uint32_t host_no,
|
|
+ uint32_t flashnode_id);
|
|
+extern int iscsi_sysfs_update_flashnode_param(uint32_t host_no,
|
|
+ uint32_t flashnode_id,
|
|
+ char *name, char *val);
|
|
+extern int iscsi_sysfs_create_flashnode(uint32_t host_no, char *ipver);
|
|
+extern int iscsi_sysfs_del_flashnode(uint32_t host_no, uint32_t flashnode_id);
|
|
+extern int iscsi_sysfs_login_flashnode(uint32_t host_no, uint32_t flashnode_id);
|
|
+extern int iscsi_sysfs_logout_flashnode(uint32_t host_no,
|
|
+ uint32_t flashnode_id);
|
|
extern int iscsi_sysfs_get_sid_from_path(char *session);
|
|
extern char *iscsi_sysfs_get_blockdev_from_lun(int hostno, int target, int sid);
|
|
|
|
diff --git a/usr/iscsi_util.c b/usr/iscsi_util.c
|
|
index 5e3420e..a4f33cf 100644
|
|
--- a/usr/iscsi_util.c
|
|
+++ b/usr/iscsi_util.c
|
|
@@ -25,16 +25,28 @@
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
+#include <sys/socket.h>
|
|
+#include <sys/un.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/resource.h>
|
|
|
|
+#include "sysdeps.h"
|
|
#include "log.h"
|
|
#include "iscsi_settings.h"
|
|
#include "iface.h"
|
|
#include "session_info.h"
|
|
#include "iscsi_util.h"
|
|
|
|
+int setup_abstract_addr(struct sockaddr_un *addr, char *unix_sock_name)
|
|
+{
|
|
+ memset(addr, 0, sizeof(*addr));
|
|
+ addr->sun_family = AF_LOCAL;
|
|
+ strlcpy(addr->sun_path + 1, unix_sock_name, sizeof(addr->sun_path) - 1);
|
|
+ return offsetof(struct sockaddr_un, sun_path) +
|
|
+ strlen(addr->sun_path + 1) + 1;
|
|
+}
|
|
+
|
|
void daemon_init(void)
|
|
{
|
|
int fd;
|
|
@@ -60,7 +72,8 @@ int oom_adjust(void)
|
|
char path[ISCSI_OOM_PATH_LEN];
|
|
struct stat statb;
|
|
|
|
- if (nice(-10) < 0)
|
|
+ errno = 0;
|
|
+ if (nice(-10) == -1 && errno != 0)
|
|
log_debug(1, "Could not increase process priority: %s",
|
|
strerror(errno));
|
|
|
|
@@ -135,10 +148,10 @@ int increase_max_files(void)
|
|
|
|
err = getrlimit(RLIMIT_NOFILE, &rl);
|
|
if (err) {
|
|
- log_debug(1, "Could not get file limit (err %d)\n", errno);
|
|
+ log_debug(1, "Could not get file limit (err %d)", errno);
|
|
return errno;
|
|
}
|
|
- log_debug(1, "Max file limits %lu %lu\n", rl.rlim_cur, rl.rlim_max);
|
|
+ log_debug(1, "Max file limits %lu %lu", rl.rlim_cur, rl.rlim_max);
|
|
|
|
if (rl.rlim_cur < ISCSI_MAX_FILES)
|
|
rl.rlim_cur = ISCSI_MAX_FILES;
|
|
@@ -147,7 +160,7 @@ int increase_max_files(void)
|
|
|
|
err = setrlimit(RLIMIT_NOFILE, &rl);
|
|
if (err) {
|
|
- log_debug(1, "Could not set file limit to %lu/%lu (err %d)\n",
|
|
+ log_debug(1, "Could not set file limit to %lu/%lu (err %d)",
|
|
rl.rlim_cur, rl.rlim_max, errno);
|
|
return errno;
|
|
}
|
|
@@ -306,7 +319,7 @@ int __iscsi_match_session(node_rec_t *rec, char *targetname,
|
|
unsigned sid)
|
|
{
|
|
if (!rec) {
|
|
- log_debug(6, "no rec info to match\n");
|
|
+ log_debug(6, "no rec info to match");
|
|
return 1;
|
|
}
|
|
|
|
diff --git a/usr/iscsi_util.h b/usr/iscsi_util.h
|
|
index 110dfa8..ff725eb 100644
|
|
--- a/usr/iscsi_util.h
|
|
+++ b/usr/iscsi_util.h
|
|
@@ -26,4 +26,7 @@ extern int __iscsi_match_session(struct node_rec *rec, char *targetname,
|
|
extern char *strstrip(char *s);
|
|
extern char *cfg_get_string_param(char *pathname, const char *key);
|
|
|
|
+struct sockaddr_un;
|
|
+extern int setup_abstract_addr(struct sockaddr_un *addr, char *unix_sock_name);
|
|
+
|
|
#endif
|
|
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
|
|
index 8f9de05..aa7cf07 100644
|
|
--- a/usr/iscsiadm.c
|
|
+++ b/usr/iscsiadm.c
|
|
@@ -53,6 +53,7 @@
|
|
#include "iscsi_err.h"
|
|
#include "iscsi_ipc.h"
|
|
#include "iscsi_timer.h"
|
|
+#include "flashnode.h"
|
|
|
|
static char program_name[] = "iscsiadm";
|
|
static char config_file[TARGET_NAME_MAXLEN];
|
|
@@ -67,7 +68,9 @@ enum iscsiadm_mode {
|
|
MODE_IFACE,
|
|
MODE_FW,
|
|
MODE_PING,
|
|
- MODE_CHAP
|
|
+ MODE_CHAP,
|
|
+ MODE_FLASHNODE,
|
|
+ MODE_HOST_STATS
|
|
};
|
|
|
|
enum iscsiadm_op {
|
|
@@ -78,7 +81,9 @@ enum iscsiadm_op {
|
|
OP_SHOW = 0x8,
|
|
OP_NONPERSISTENT = 0x10,
|
|
OP_APPLY = 0x20,
|
|
- OP_APPLY_ALL = 0x40
|
|
+ OP_APPLY_ALL = 0x40,
|
|
+ OP_LOGIN = 0x80,
|
|
+ OP_LOGOUT = 0x100
|
|
};
|
|
|
|
static struct option const long_options[] =
|
|
@@ -111,9 +116,11 @@ static struct option const long_options[] =
|
|
{"packetsize", required_argument, NULL, 'b'},
|
|
{"count", required_argument, NULL, 'c'},
|
|
{"interval", required_argument, NULL, 'i'},
|
|
+ {"index", required_argument, NULL, 'x'},
|
|
+ {"portal_type", optional_argument, NULL, 'A'},
|
|
{NULL, 0, NULL, 0},
|
|
};
|
|
-static char *short_options = "RlDVhm:a:b:c:C:p:P:T:H:i:I:U:k:L:d:r:n:v:o:sSt:u";
|
|
+static char *short_options = "RlDVhm:a:b:c:C:p:P:T:H:i:I:U:k:L:d:r:n:v:o:sSt:ux:A:";
|
|
|
|
static void usage(int status)
|
|
{
|
|
@@ -129,8 +136,8 @@ iscsiadm -m node [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -L all,manual,au
|
|
[ [ -o operation ] [ -n name ] [ -v value ] ]\n\
|
|
iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\
|
|
iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename | -H hostno|MAC ] [ [ -o operation ] [ -n name ] [ -v value ] ] [ -C ping [ -a ip ] [ -b packetsize ] [ -c count ] [ -i interval ] ]\n\
|
|
-iscsiadm -m fw [ -l ]\n\
|
|
-iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ] [ -C chap [ -o operation ] [ -v chap_tbl_idx ] ]\n\
|
|
+iscsiadm -m fw [ -d debug_level ] [ -l ]\n\
|
|
+iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ] [ [ -C chap [ -x chap_tbl_idx ] ] | [ -C flashnode [ -A portal_type ] [ -x flashnode_idx ] ] | [ -C stats ] ] [ [ -o operation ] [ -n name ] [ -v value ] ] \n\
|
|
iscsiadm -k priority\n");
|
|
}
|
|
exit(status);
|
|
@@ -155,6 +162,10 @@ str_to_op(char *str)
|
|
op = OP_APPLY;
|
|
else if (!strcmp("applyall", str))
|
|
op = OP_APPLY_ALL;
|
|
+ else if (!strcmp("login", str))
|
|
+ op = OP_LOGIN;
|
|
+ else if (!strcmp("logout", str))
|
|
+ op = OP_LOGOUT;
|
|
else
|
|
op = OP_NOOP;
|
|
|
|
@@ -195,6 +206,11 @@ str_to_submode(char *str)
|
|
sub_mode = MODE_PING;
|
|
else if (!strcmp("chap", str))
|
|
sub_mode = MODE_CHAP;
|
|
+ else if (!strcmp("flashnode", str))
|
|
+ sub_mode = MODE_FLASHNODE;
|
|
+ else if (!strcmp("stats", str))
|
|
+ sub_mode = MODE_HOST_STATS;
|
|
+
|
|
else
|
|
sub_mode = -1;
|
|
|
|
@@ -221,6 +237,21 @@ str_to_type(char *str)
|
|
return type;
|
|
}
|
|
|
|
+static int
|
|
+str_to_portal_type(char *str)
|
|
+{
|
|
+ int ptype;
|
|
+
|
|
+ if (!strcmp("ipv4", str))
|
|
+ ptype = IPV4;
|
|
+ else if (!strcmp("ipv6", str))
|
|
+ ptype = IPV6;
|
|
+ else
|
|
+ ptype = -1;
|
|
+
|
|
+ return ptype;
|
|
+}
|
|
+
|
|
static void kill_iscsid(int priority)
|
|
{
|
|
iscsiadm_req_t req;
|
|
@@ -247,7 +278,7 @@ static void kill_iscsid(int priority)
|
|
if (rc) {
|
|
iscsi_err_print_msg(rc);
|
|
log_error("Could not stop iscsid. Trying sending iscsid "
|
|
- "SIGTERM or SIGKILL signals manually\n");
|
|
+ "SIGTERM or SIGKILL signals manually");
|
|
}
|
|
}
|
|
|
|
@@ -272,7 +303,7 @@ static int print_ifaces(struct iface_rec *iface, int info_level)
|
|
if (iface) {
|
|
err = iface_conf_read(iface);
|
|
if (err) {
|
|
- log_error("Could not read iface %s.\n",
|
|
+ log_error("Could not read iface %s.",
|
|
iface->name);
|
|
return err;
|
|
}
|
|
@@ -320,7 +351,8 @@ match_startup_mode(node_rec_t *rec, char *mode)
|
|
}
|
|
|
|
static int
|
|
-for_each_session(struct node_rec *rec, iscsi_sysfs_session_op_fn *fn)
|
|
+for_each_session(struct node_rec *rec, iscsi_sysfs_session_op_fn *fn,
|
|
+ int in_parallel)
|
|
{
|
|
int err, num_found = 0;
|
|
|
|
@@ -328,7 +360,8 @@ for_each_session(struct node_rec *rec, iscsi_sysfs_session_op_fn *fn)
|
|
num_found = 1;
|
|
err = fn(rec, rec->session.info);
|
|
} else {
|
|
- err = iscsi_sysfs_for_each_session(rec, &num_found, fn);
|
|
+ err = iscsi_sysfs_for_each_session(rec, &num_found, fn,
|
|
+ in_parallel);
|
|
}
|
|
if (err)
|
|
log_error("Could not execute operation on all sessions: %s",
|
|
@@ -370,7 +403,7 @@ __logout_by_startup(void *data, struct list_head *list,
|
|
* this is due to a HW driver or some other driver
|
|
* not hooked in
|
|
*/
|
|
- log_debug(7, "could not read data for [%s,%s.%d]\n",
|
|
+ log_debug(7, "could not read data for [%s,%s.%d]",
|
|
info->targetname, info->persistent_address,
|
|
info->persistent_port);
|
|
return -1;
|
|
@@ -408,7 +441,7 @@ logout_by_startup(char *mode)
|
|
rc = iscsi_logout_portals(mode, &nr_found, 1, __logout_by_startup);
|
|
if (rc == ISCSI_ERR_NO_OBJS_FOUND)
|
|
log_error("No matching sessions found");
|
|
- return rc;
|
|
+ return rc;
|
|
}
|
|
|
|
struct startup_data {
|
|
@@ -452,7 +485,7 @@ __do_leading_login(void *data, struct list_head *list, struct node_rec *rec)
|
|
* If there is an existing session that matcthes the target,
|
|
* the leading login is complete.
|
|
*/
|
|
- if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_target)) {
|
|
+ if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_target, 0)) {
|
|
log_debug(1, "Skipping %s: Already a session for that target",
|
|
rec->name);
|
|
return -1;
|
|
@@ -552,7 +585,7 @@ login_by_startup(char *mode)
|
|
list_for_each_entry_safe(rec, tmp_rec, &startup.leading_logins,
|
|
list) {
|
|
if (!iscsi_sysfs_for_each_session(rec, &nr_found,
|
|
- iscsi_match_target))
|
|
+ iscsi_match_target, 0))
|
|
missed_leading_login++;
|
|
/*
|
|
* Cleanup the list, since 'iscsi_login_portals_safe'
|
|
@@ -582,6 +615,8 @@ static int iscsi_logout_matched_portal(void *data, struct list_head *list,
|
|
{
|
|
struct node_rec *pattern_rec = data;
|
|
struct iscsi_transport *t;
|
|
+ uint32_t host_no;
|
|
+ int rc = 0;
|
|
|
|
t = iscsi_sysfs_get_transport_by_sid(info->sid);
|
|
if (!t)
|
|
@@ -590,7 +625,19 @@ static int iscsi_logout_matched_portal(void *data, struct list_head *list,
|
|
if (!iscsi_match_session(pattern_rec, info))
|
|
return -1;
|
|
|
|
- return iscsi_logout_portal(info, list);
|
|
+ host_no = iscsi_sysfs_get_host_no_from_sid(info->sid, &rc);
|
|
+ if (rc) {
|
|
+ log_error("could not get host_no for session%d: %s.",
|
|
+ info->sid, iscsi_err_to_str(rc));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (!iscsi_sysfs_session_user_created(info->sid))
|
|
+ rc = iscsi_logout_flashnode_sid(t, host_no, info->sid);
|
|
+ else
|
|
+ rc = iscsi_logout_portal(info, list);
|
|
+
|
|
+ return rc;
|
|
}
|
|
|
|
static int rec_match_fn(void *data, node_rec_t *rec)
|
|
@@ -1092,17 +1139,55 @@ do_software_sendtargets(discovery_rec_t *drec, struct list_head *ifaces,
|
|
return rc;
|
|
}
|
|
|
|
+static int do_isns(discovery_rec_t *drec, struct list_head *ifaces,
|
|
+ int info_level, int do_login, int op)
|
|
+{
|
|
+ struct list_head rec_list;
|
|
+ struct node_rec *rec, *tmp;
|
|
+ int rc;
|
|
+
|
|
+ INIT_LIST_HEAD(&rec_list);
|
|
+ /*
|
|
+ * compat: if the user did not pass any op then we do all
|
|
+ * ops for them
|
|
+ */
|
|
+ if (!op)
|
|
+ op = OP_NEW | OP_DELETE | OP_UPDATE;
|
|
+
|
|
+
|
|
+ rc = idbm_bind_ifaces_to_nodes(discovery_isns, drec, ifaces,
|
|
+ &rec_list);
|
|
+ if (rc) {
|
|
+ log_error("Could not perform iSNS discovery: %s",
|
|
+ iscsi_err_to_str(rc));
|
|
+ return rc;
|
|
+ } else if (list_empty(&rec_list)) {
|
|
+ log_error("No portals found");
|
|
+ return ISCSI_ERR_NO_OBJS_FOUND;
|
|
+ }
|
|
+
|
|
+ rc = exec_disc_op_on_recs(drec, &rec_list, info_level, do_login, op);
|
|
+
|
|
+ list_for_each_entry_safe(rec, tmp, &rec_list, list) {
|
|
+ list_del(&rec->list);
|
|
+ free(rec);
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
static int
|
|
-do_sendtargets(discovery_rec_t *drec, struct list_head *ifaces,
|
|
- int info_level, int do_login, int op, int sync_drec)
|
|
+do_target_discovery(discovery_rec_t *drec, struct list_head *ifaces,
|
|
+ int info_level, int do_login, int op, int sync_drec)
|
|
{
|
|
+
|
|
struct iface_rec *tmp, *iface;
|
|
int rc, host_no;
|
|
struct iscsi_transport *t;
|
|
|
|
if (list_empty(ifaces)) {
|
|
ifaces = NULL;
|
|
- goto sw_st;
|
|
+ goto sw_discovery;
|
|
}
|
|
|
|
/* we allow users to mix hw and sw iscsi so we have to sort it out */
|
|
@@ -1131,64 +1216,36 @@ do_sendtargets(discovery_rec_t *drec, struct list_head *ifaces,
|
|
host_no = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc);
|
|
if (rc || host_no == -1) {
|
|
log_debug(1, "Could not match iface" iface_fmt " to "
|
|
- "host.", iface_str(iface));
|
|
+ "host.", iface_str(iface));
|
|
/* try software iscsi */
|
|
continue;
|
|
}
|
|
|
|
- if (t->caps & CAP_SENDTARGETS_OFFLOAD) {
|
|
- do_offload_sendtargets(drec, host_no, do_login);
|
|
- list_del(&iface->list);
|
|
- free(iface);
|
|
- }
|
|
+ if (drec->type == DISCOVERY_TYPE_SENDTARGETS)
|
|
+ if (t->caps & CAP_SENDTARGETS_OFFLOAD) {
|
|
+ do_offload_sendtargets(drec, host_no, do_login);
|
|
+ list_del(&iface->list);
|
|
+ free(iface);
|
|
+ }
|
|
}
|
|
|
|
if (list_empty(ifaces))
|
|
return ISCSI_ERR_NO_OBJS_FOUND;
|
|
|
|
-sw_st:
|
|
- return do_software_sendtargets(drec, ifaces, info_level, do_login,
|
|
- op, sync_drec);
|
|
-}
|
|
-
|
|
-static int do_isns(discovery_rec_t *drec, struct list_head *ifaces,
|
|
- int info_level, int do_login, int op)
|
|
-{
|
|
- struct list_head rec_list;
|
|
- struct node_rec *rec, *tmp;
|
|
- int rc;
|
|
-
|
|
- INIT_LIST_HEAD(&rec_list);
|
|
- /*
|
|
- * compat: if the user did not pass any op then we do all
|
|
- * ops for them
|
|
- */
|
|
- if (!op)
|
|
- op = OP_NEW | OP_DELETE | OP_UPDATE;
|
|
-
|
|
- drec->type = DISCOVERY_TYPE_ISNS;
|
|
-
|
|
- rc = idbm_bind_ifaces_to_nodes(discovery_isns, drec, ifaces,
|
|
- &rec_list);
|
|
- if (rc) {
|
|
- log_error("Could not perform iSNS discovery: %s",
|
|
- iscsi_err_to_str(rc));
|
|
- return rc;
|
|
- } else if (list_empty(&rec_list)) {
|
|
- log_error("No portals found");
|
|
- return ISCSI_ERR_NO_OBJS_FOUND;
|
|
+sw_discovery:
|
|
+ switch (drec->type) {
|
|
+ case DISCOVERY_TYPE_SENDTARGETS:
|
|
+ return do_software_sendtargets(drec, ifaces, info_level,
|
|
+ do_login, op, sync_drec);
|
|
+ case DISCOVERY_TYPE_ISNS:
|
|
+ return do_isns(drec, ifaces, info_level, do_login, op);
|
|
+ default:
|
|
+ log_debug(1, "Unknown Discovery Type : %d", drec->type);
|
|
+ return ISCSI_ERR_UNKNOWN_DISCOVERY_TYPE;
|
|
}
|
|
-
|
|
- rc = exec_disc_op_on_recs(drec, &rec_list, info_level, do_login, op);
|
|
-
|
|
- list_for_each_entry_safe(rec, tmp, &rec_list, list) {
|
|
- list_del(&rec->list);
|
|
- free(rec);
|
|
- }
|
|
-
|
|
- return rc;
|
|
}
|
|
|
|
+
|
|
static int
|
|
verify_mode_params(int argc, char **argv, char *allowed, int skip_m)
|
|
{
|
|
@@ -1229,7 +1286,7 @@ static int iface_apply_net_config(struct iface_rec *iface, int op)
|
|
int fd;
|
|
|
|
log_debug(8, "Calling iscsid, to apply net config for"
|
|
- "iface.name = %s\n", iface->name);
|
|
+ "iface.name = %s", iface->name);
|
|
|
|
if (op == OP_APPLY_ALL)
|
|
iface_all = 1;
|
|
@@ -1373,19 +1430,193 @@ exit_chap_info:
|
|
return rc;
|
|
}
|
|
|
|
-static int delete_host_chap_info(uint32_t host_no, char *value)
|
|
+static int fill_host_chap_rec(struct list_head *params,
|
|
+ struct iscsi_chap_rec *crec, recinfo_t *cinfo,
|
|
+ uint16_t chap_tbl_idx, int type, int *param_count)
|
|
+{
|
|
+ struct user_param *param;
|
|
+ int rc = 0;
|
|
+
|
|
+ crec->chap_tbl_idx = chap_tbl_idx;
|
|
+ crec->chap_type = type;
|
|
+
|
|
+ idbm_recinfo_host_chap(crec, cinfo);
|
|
+
|
|
+ list_for_each_entry(param, params, list) {
|
|
+ rc = idbm_rec_update_param(cinfo, param->name, param->value, 0);
|
|
+ if (rc)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (!rc)
|
|
+ *param_count += 3; /* index, type and password_length */
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int verify_host_chap_params(struct list_head *params, int *type,
|
|
+ int *param_count)
|
|
+{
|
|
+ struct user_param *param;
|
|
+ int username = -1;
|
|
+ int password = -1;
|
|
+ int rc = 0;
|
|
+
|
|
+ list_for_each_entry(param, params, list) {
|
|
+ *param_count += 1;
|
|
+
|
|
+ if (!strcmp(param->name, HOST_AUTH_USERNAME))
|
|
+ username = CHAP_TYPE_OUT;
|
|
+ else if (!strcmp(param->name, HOST_AUTH_PASSWORD))
|
|
+ password = CHAP_TYPE_OUT;
|
|
+ else if (!strcmp(param->name, HOST_AUTH_USERNAME_IN))
|
|
+ username = CHAP_TYPE_IN;
|
|
+ else if (!strcmp(param->name, HOST_AUTH_PASSWORD_IN))
|
|
+ password = CHAP_TYPE_IN;
|
|
+ else
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if ((username == CHAP_TYPE_OUT) && (password == CHAP_TYPE_OUT)) {
|
|
+ if (type)
|
|
+ *type = CHAP_TYPE_OUT;
|
|
+
|
|
+ rc = ISCSI_SUCCESS;
|
|
+ } else if ((username == CHAP_TYPE_IN) && (password == CHAP_TYPE_IN)) {
|
|
+ if (type)
|
|
+ *type = CHAP_TYPE_IN;
|
|
+
|
|
+ rc = ISCSI_SUCCESS;
|
|
+ } else {
|
|
+ rc = ISCSI_ERR;
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int set_host_chap_info(uint32_t host_no, uint64_t chap_index,
|
|
+ struct list_head *params)
|
|
+{
|
|
+ struct iscsi_transport *t = NULL;
|
|
+ struct iscsi_chap_rec crec;
|
|
+ recinfo_t *chap_info = NULL;
|
|
+ struct iovec *iovs = NULL;
|
|
+ struct iovec *iov = NULL;
|
|
+ int type;
|
|
+ int param_count = 0;
|
|
+ int param_used;
|
|
+ int rc = 0;
|
|
+ int fd, i = 0;
|
|
+
|
|
+ if (list_empty(params)) {
|
|
+ log_error("Chap username/password not provided.");
|
|
+ goto exit_set_chap;
|
|
+ }
|
|
+
|
|
+ chap_info = idbm_recinfo_alloc(MAX_KEYS);
|
|
+ if (!chap_info) {
|
|
+ log_error("Out of Memory.");
|
|
+ rc = ISCSI_ERR_NOMEM;
|
|
+ goto exit_set_chap;
|
|
+ }
|
|
+
|
|
+ t = iscsi_sysfs_get_transport_by_hba(host_no);
|
|
+ if (!t) {
|
|
+ log_error("Could not match hostno %d to transport.", host_no);
|
|
+ rc = ISCSI_ERR_TRANS_NOT_FOUND;
|
|
+ goto free_info_rec;
|
|
+ }
|
|
+
|
|
+ rc = verify_host_chap_params(params, &type, ¶m_count);
|
|
+ if (rc) {
|
|
+ log_error("Invalid username/password pair passed. Unable to determine the type of chap entry");
|
|
+ rc = ISCSI_ERR_INVAL;
|
|
+ goto free_info_rec;
|
|
+ }
|
|
+
|
|
+ if (param_count > 2) {
|
|
+ log_error("Only one pair of username/password can be passed.");
|
|
+ rc = ISCSI_ERR;
|
|
+ goto free_info_rec;
|
|
+ }
|
|
+
|
|
+ memset(&crec, 0, sizeof(crec));
|
|
+ rc = fill_host_chap_rec(params, &crec, chap_info, chap_index, type,
|
|
+ ¶m_count);
|
|
+ if (rc) {
|
|
+ log_error("Unable to fill CHAP record");
|
|
+ goto free_info_rec;
|
|
+ }
|
|
+
|
|
+ /* +2 for event and nlmsghdr */
|
|
+ param_count += 2;
|
|
+ iovs = calloc((param_count * sizeof(struct iovec)),
|
|
+ sizeof(char));
|
|
+ if (!iovs) {
|
|
+ log_error("Out of Memory.");
|
|
+ rc = ISCSI_ERR_NOMEM;
|
|
+ goto free_info_rec;
|
|
+ }
|
|
+
|
|
+ /* param_used gives actual number of iovecs used for chap */
|
|
+ param_used = chap_build_config(&crec, iovs);
|
|
+ if (!param_used) {
|
|
+ log_error("Build chap config failed.");
|
|
+ rc = ISCSI_ERR;
|
|
+ goto free_iovec;
|
|
+ }
|
|
+
|
|
+ fd = ipc->ctldev_open();
|
|
+ if (fd < 0) {
|
|
+ rc = ISCSI_ERR_INTERNAL;
|
|
+ log_error("Netlink open failed.");
|
|
+ goto free_iovec;
|
|
+ }
|
|
+
|
|
+ rc = ipc->set_chap(t->handle, host_no, iovs, param_count);
|
|
+ if (rc < 0) {
|
|
+ log_error("CHAP setting failed");
|
|
+ if (rc == -EBUSY) {
|
|
+ rc = ISCSI_ERR_BUSY;
|
|
+ log_error("CHAP index %d is in use.",
|
|
+ crec.chap_tbl_idx);
|
|
+ } else {
|
|
+ rc = ISCSI_ERR;
|
|
+ }
|
|
+
|
|
+ goto exit_set_chap;
|
|
+ }
|
|
+
|
|
+ ipc->ctldev_close();
|
|
+
|
|
+free_iovec:
|
|
+ /* start at 2, because 0 is for nlmsghdr and 1 for event */
|
|
+ iov = iovs + 2;
|
|
+ for (i = 0; i < param_used; i++, iov++) {
|
|
+ if (iov->iov_base)
|
|
+ free(iov->iov_base);
|
|
+ }
|
|
+
|
|
+ free(iovs);
|
|
+
|
|
+free_info_rec:
|
|
+ if (chap_info)
|
|
+ free(chap_info);
|
|
+
|
|
+exit_set_chap:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int delete_host_chap_info(uint32_t host_no, uint16_t chap_tbl_idx)
|
|
{
|
|
struct iscsi_transport *t = NULL;
|
|
int fd, rc = 0;
|
|
- uint16_t chap_tbl_idx;
|
|
|
|
- if (!value) {
|
|
- log_error("CHAP deletion requires --value=table_index.");
|
|
- return ISCSI_ERR_INVAL;
|
|
+ if (chap_tbl_idx > MAX_CHAP_ENTRIES) {
|
|
+ log_error("Invalid chap table index.");
|
|
+ goto exit_delete_chap;
|
|
}
|
|
|
|
- chap_tbl_idx = (uint16_t)atoi(value);
|
|
-
|
|
t = iscsi_sysfs_get_transport_by_hba(host_no);
|
|
if (!t) {
|
|
log_error("Could not match hostno %d to "
|
|
@@ -1401,7 +1632,7 @@ static int delete_host_chap_info(uint32_t host_no, char *value)
|
|
goto exit_delete_chap;
|
|
}
|
|
|
|
- log_info("Deleteing CHAP index: %d\n", chap_tbl_idx);
|
|
+ log_info("Deleteing CHAP index: %d", chap_tbl_idx);
|
|
rc = ipc->delete_chap(t->handle, host_no, chap_tbl_idx);
|
|
if (rc < 0) {
|
|
log_error("CHAP Delete failed.");
|
|
@@ -1419,7 +1650,7 @@ exit_delete_chap:
|
|
}
|
|
|
|
static int exec_host_chap_op(int op, int info_level, uint32_t host_no,
|
|
- char *value)
|
|
+ uint64_t chap_index, struct list_head *params)
|
|
{
|
|
int rc = ISCSI_ERR_INVAL;
|
|
|
|
@@ -1427,8 +1658,12 @@ static int exec_host_chap_op(int op, int info_level, uint32_t host_no,
|
|
case OP_SHOW:
|
|
rc = get_host_chap_info(host_no);
|
|
break;
|
|
+ case OP_NEW:
|
|
+ case OP_UPDATE:
|
|
+ rc = set_host_chap_info(host_no, chap_index, params);
|
|
+ break;
|
|
case OP_DELETE:
|
|
- rc = delete_host_chap_info(host_no, value);
|
|
+ rc = delete_host_chap_info(host_no, chap_index);
|
|
break;
|
|
default:
|
|
log_error("Invalid operation.");
|
|
@@ -1438,6 +1673,588 @@ static int exec_host_chap_op(int op, int info_level, uint32_t host_no,
|
|
return rc;
|
|
}
|
|
|
|
+static int get_flashnode_info(uint32_t host_no, uint32_t flashnode_idx)
|
|
+{
|
|
+ struct flashnode_rec fnode;
|
|
+ int rc = 0;
|
|
+
|
|
+ memset(&fnode, 0, sizeof(fnode));
|
|
+ rc = iscsi_sysfs_get_flashnode_info(&fnode, host_no, flashnode_idx);
|
|
+ if (rc) {
|
|
+ log_error("Could not read info for flashnode %u of host %u, %s",
|
|
+ flashnode_idx, host_no, strerror(rc));
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ idbm_print_flashnode_info(&fnode);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int list_flashnodes(int info_level, uint32_t host_no)
|
|
+{
|
|
+ int rc = 0;
|
|
+ int num_found = 0;
|
|
+
|
|
+ rc = iscsi_sysfs_for_each_flashnode(NULL, host_no, &num_found,
|
|
+ flashnode_info_print_flat);
|
|
+
|
|
+ if (!num_found) {
|
|
+ log_error("No flashnodes attached to host %u.", host_no);
|
|
+ rc = ISCSI_ERR_NO_OBJS_FOUND;
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int iscsi_set_flashnode_params(struct iscsi_transport *t, uint32_t host_no,
|
|
+ uint32_t flashnode_idx, struct list_head *params)
|
|
+{
|
|
+ struct flashnode_rec fnode;
|
|
+ recinfo_t *flashnode_info;
|
|
+ struct user_param *param;
|
|
+ struct iovec *iovs = NULL;
|
|
+ struct iovec *iov = NULL;
|
|
+ int fd, rc = 0;
|
|
+ int param_count = 0;
|
|
+ int param_used = 0;
|
|
+ int i;
|
|
+
|
|
+ flashnode_info = idbm_recinfo_alloc(MAX_KEYS);
|
|
+ if (!flashnode_info) {
|
|
+ log_error("Out of Memory.");
|
|
+ rc = ISCSI_ERR_NOMEM;
|
|
+ goto free_info_rec;
|
|
+ }
|
|
+
|
|
+ memset(&fnode, 0, sizeof(fnode));
|
|
+ rc = iscsi_sysfs_get_flashnode_info(&fnode, host_no, flashnode_idx);
|
|
+ if (rc) {
|
|
+ log_error("Could not read info for flashnode %u, %s",
|
|
+ flashnode_idx, strerror(rc));
|
|
+ goto free_info_rec;
|
|
+ }
|
|
+
|
|
+ idbm_recinfo_flashnode(&fnode, flashnode_info);
|
|
+
|
|
+ i = 0;
|
|
+ list_for_each_entry(param, params, list) {
|
|
+ param_count++;
|
|
+ rc = idbm_verify_param(flashnode_info, param->name);
|
|
+ if (rc)
|
|
+ goto free_info_rec;
|
|
+ }
|
|
+
|
|
+ list_for_each_entry(param, params, list) {
|
|
+ rc = idbm_rec_update_param(flashnode_info, param->name,
|
|
+ param->value, 0);
|
|
+ if (rc)
|
|
+ goto free_info_rec;
|
|
+ }
|
|
+
|
|
+ /* +2 for event and nlmsghdr */
|
|
+ param_count += 2;
|
|
+ iovs = calloc((param_count * sizeof(struct iovec)),
|
|
+ sizeof(char));
|
|
+ if (!iovs) {
|
|
+ log_error("Out of Memory.");
|
|
+ rc = ISCSI_ERR_NOMEM;
|
|
+ goto free_info_rec;
|
|
+ }
|
|
+
|
|
+ /* param_used gives actual number of iovecs used for flashnode */
|
|
+ param_used = flashnode_build_config(params, &fnode, iovs);
|
|
+ if (!param_used) {
|
|
+ log_error("Build flashnode config failed.");
|
|
+ rc = ISCSI_ERR;
|
|
+ goto free_iovec;
|
|
+ }
|
|
+
|
|
+ fd = ipc->ctldev_open();
|
|
+ if (fd < 0) {
|
|
+ log_error("Netlink open failed.");
|
|
+ rc = ISCSI_ERR_INTERNAL;
|
|
+ goto free_iovec;
|
|
+ }
|
|
+
|
|
+ log_info("Update flashnode %u.", flashnode_idx);
|
|
+ rc = ipc->set_flash_node_params(t->handle, host_no, flashnode_idx,
|
|
+ iovs, param_count);
|
|
+ if (rc < 0)
|
|
+ rc = ISCSI_ERR;
|
|
+
|
|
+
|
|
+ ipc->ctldev_close();
|
|
+
|
|
+free_iovec:
|
|
+ /* start at 2, because 0 is for nlmsghdr and 1 for event */
|
|
+ iov = iovs + 2;
|
|
+ for (i = 0; i < param_used; i++, iov++) {
|
|
+ if (iov->iov_base)
|
|
+ free(iov->iov_base);
|
|
+ }
|
|
+
|
|
+ free(iovs);
|
|
+
|
|
+free_info_rec:
|
|
+ if (flashnode_info)
|
|
+ free(flashnode_info);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int iscsi_new_flashnode(struct iscsi_transport *t, uint32_t host_no, char *val,
|
|
+ uint32_t *flashnode_idx)
|
|
+{
|
|
+ int fd, rc = 0;
|
|
+
|
|
+ fd = ipc->ctldev_open();
|
|
+ if (fd < 0) {
|
|
+ log_error("Netlink open failed.");
|
|
+ rc = ISCSI_ERR_INTERNAL;
|
|
+ goto exit_new_flashnode;
|
|
+ }
|
|
+
|
|
+ log_info("Create new flashnode for host %u.", host_no);
|
|
+ rc = ipc->new_flash_node(t->handle, host_no, val, flashnode_idx);
|
|
+ if (rc < 0)
|
|
+ rc = ISCSI_ERR;
|
|
+
|
|
+ ipc->ctldev_close();
|
|
+
|
|
+exit_new_flashnode:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int iscsi_del_flashnode(struct iscsi_transport *t, uint32_t host_no,
|
|
+ uint32_t flashnode_idx)
|
|
+{
|
|
+ int fd, rc = 0;
|
|
+
|
|
+ fd = ipc->ctldev_open();
|
|
+ if (fd < 0) {
|
|
+ log_error("Netlink open failed.");
|
|
+ rc = ISCSI_ERR_INTERNAL;
|
|
+ goto exit_del_flashnode;
|
|
+ }
|
|
+
|
|
+ log_info("Delete flashnode %u.", flashnode_idx);
|
|
+ rc = ipc->del_flash_node(t->handle, host_no, flashnode_idx);
|
|
+ if (rc < 0)
|
|
+ rc = ISCSI_ERR;
|
|
+
|
|
+ ipc->ctldev_close();
|
|
+
|
|
+exit_del_flashnode:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int iscsi_login_flashnode(struct iscsi_transport *t, uint32_t host_no,
|
|
+ uint32_t flashnode_idx)
|
|
+{
|
|
+ int fd, rc = 0;
|
|
+
|
|
+ fd = ipc->ctldev_open();
|
|
+ if (fd < 0) {
|
|
+ log_error("Netlink open failed.");
|
|
+ rc = ISCSI_ERR_INTERNAL;
|
|
+ goto exit_login_flashnode;
|
|
+ }
|
|
+
|
|
+ log_info("Login to flashnode %u.", flashnode_idx);
|
|
+ rc = ipc->login_flash_node(t->handle, host_no, flashnode_idx);
|
|
+ if (rc == -EPERM)
|
|
+ rc = ISCSI_ERR_SESS_EXISTS;
|
|
+ else if (rc < 0)
|
|
+ rc = ISCSI_ERR_LOGIN;
|
|
+
|
|
+ ipc->ctldev_close();
|
|
+
|
|
+exit_login_flashnode:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int iscsi_logout_flashnode(struct iscsi_transport *t, uint32_t host_no,
|
|
+ uint32_t flashnode_idx)
|
|
+{
|
|
+ int fd, rc = 0;
|
|
+
|
|
+ fd = ipc->ctldev_open();
|
|
+ if (fd < 0) {
|
|
+ log_error("Netlink open failed.");
|
|
+ rc = ISCSI_ERR_INTERNAL;
|
|
+ goto exit_logout;
|
|
+ }
|
|
+
|
|
+ log_info("Logout flashnode %u.", flashnode_idx);
|
|
+ rc = ipc->logout_flash_node(t->handle, host_no, flashnode_idx);
|
|
+ if (rc == -ESRCH)
|
|
+ rc = ISCSI_ERR_SESS_NOT_FOUND;
|
|
+ else if (rc < 0)
|
|
+ rc = ISCSI_ERR_LOGOUT;
|
|
+
|
|
+ ipc->ctldev_close();
|
|
+
|
|
+exit_logout:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int iscsi_logout_flashnode_sid(struct iscsi_transport *t, uint32_t host_no,
|
|
+ uint32_t sid)
|
|
+{
|
|
+ int fd, rc = 0;
|
|
+
|
|
+ fd = ipc->ctldev_open();
|
|
+ if (fd < 0) {
|
|
+ log_error("Netlink open failed.");
|
|
+ rc = ISCSI_ERR_INTERNAL;
|
|
+ goto exit_logout_sid;
|
|
+ }
|
|
+
|
|
+ log_info("Logout sid %u.", sid);
|
|
+ rc = ipc->logout_flash_node_sid(t->handle, host_no, sid);
|
|
+ if (rc < 0) {
|
|
+ log_error("Logout of sid %u failed.", sid);
|
|
+ rc = ISCSI_ERR_LOGOUT;
|
|
+ } else {
|
|
+ log_info("Logout of sid %u successful.", sid);
|
|
+ }
|
|
+
|
|
+ ipc->ctldev_close();
|
|
+
|
|
+exit_logout_sid:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int exec_flashnode_op(int op, int info_level, uint32_t host_no,
|
|
+ uint64_t fnode_idx, int type,
|
|
+ struct list_head *params)
|
|
+{
|
|
+ struct iscsi_transport *t = NULL;
|
|
+ int rc = ISCSI_SUCCESS;
|
|
+ char *portal_type;
|
|
+ uint32_t flashnode_idx;
|
|
+
|
|
+ if (op != OP_SHOW && op != OP_NOOP && op != OP_NEW &&
|
|
+ fnode_idx > MAX_FLASHNODE_IDX) {
|
|
+ log_error("Invalid flashnode index");
|
|
+ rc = ISCSI_ERR_INVAL;
|
|
+ goto exit_flashnode_op;
|
|
+ }
|
|
+
|
|
+ flashnode_idx = (uint32_t)fnode_idx;
|
|
+ t = iscsi_sysfs_get_transport_by_hba(host_no);
|
|
+ if (!t) {
|
|
+ log_error("Could not match hostno %u to transport.", host_no);
|
|
+ rc = ISCSI_ERR_TRANS_NOT_FOUND;
|
|
+ goto exit_flashnode_op;
|
|
+ }
|
|
+
|
|
+ switch (op) {
|
|
+ case OP_NOOP:
|
|
+ case OP_SHOW:
|
|
+ if (fnode_idx > MAX_FLASHNODE_IDX)
|
|
+ rc = list_flashnodes(info_level, host_no);
|
|
+ else
|
|
+ rc = get_flashnode_info(host_no, flashnode_idx);
|
|
+ break;
|
|
+ case OP_NEW:
|
|
+ if (type == IPV4) {
|
|
+ portal_type = "ipv4";
|
|
+ } else if (type == IPV6) {
|
|
+ portal_type = "ipv6";
|
|
+ } else {
|
|
+ log_error("Invalid type mentioned for flashnode");
|
|
+ rc = ISCSI_ERR_INVAL;
|
|
+ goto exit_flashnode_op;
|
|
+ }
|
|
+ rc = iscsi_new_flashnode(t, host_no, portal_type,
|
|
+ &flashnode_idx);
|
|
+ if (!rc)
|
|
+ log_info("New flashnode for host %u added at index %u.",
|
|
+ host_no, flashnode_idx);
|
|
+ else
|
|
+ log_error("Creation of flashnode for host %u failed.",
|
|
+ host_no);
|
|
+ break;
|
|
+ case OP_DELETE:
|
|
+ rc = iscsi_del_flashnode(t, host_no, flashnode_idx);
|
|
+ if (!rc)
|
|
+ log_info("Flashnode %u of host %u deleted.",
|
|
+ flashnode_idx, host_no);
|
|
+ else
|
|
+ log_error("Deletion of flashnode %u of host %u failed.",
|
|
+ flashnode_idx, host_no);
|
|
+ break;
|
|
+ case OP_UPDATE:
|
|
+ rc = iscsi_set_flashnode_params(t, host_no, flashnode_idx,
|
|
+ params);
|
|
+ if (!rc)
|
|
+ log_info("Update for flashnode %u of host %u successful.",
|
|
+ flashnode_idx, host_no);
|
|
+ else
|
|
+ log_error("Update for flashnode %u of host %u failed.",
|
|
+ flashnode_idx, host_no);
|
|
+ break;
|
|
+ case OP_LOGIN:
|
|
+ rc = iscsi_login_flashnode(t, host_no, flashnode_idx);
|
|
+ if (!rc)
|
|
+ log_info("Login to flashnode %u of host %u successful.",
|
|
+ flashnode_idx, host_no);
|
|
+ else if (rc == ISCSI_ERR_SESS_EXISTS)
|
|
+ log_info("Flashnode %u of host %u already logged in.",
|
|
+ flashnode_idx, host_no);
|
|
+ else
|
|
+ log_error("Login to flashnode %u of host %u failed.",
|
|
+ flashnode_idx, host_no);
|
|
+ break;
|
|
+ case OP_LOGOUT:
|
|
+ rc = iscsi_logout_flashnode(t, host_no, flashnode_idx);
|
|
+ if (!rc)
|
|
+ log_info("Logout of flashnode %u of host %u successful.",
|
|
+ flashnode_idx, host_no);
|
|
+ else if (rc == ISCSI_ERR_SESS_NOT_FOUND)
|
|
+ log_info("Flashnode %u of host %u not logged in.",
|
|
+ flashnode_idx, host_no);
|
|
+ else
|
|
+ log_error("Logout of flashnode %u of host %u failed.",
|
|
+ flashnode_idx, host_no);
|
|
+ break;
|
|
+ default:
|
|
+ log_error("Invalid operation");
|
|
+ rc = ISCSI_ERR_INVAL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+exit_flashnode_op:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static void print_host_stats(struct iscsi_offload_host_stats *host_stats)
|
|
+{
|
|
+ /* MAC */
|
|
+ printf("Host Statistics:\n"
|
|
+ "\tmactx_frames: %lld\n"
|
|
+ "\tmactx_bytes: %lld\n"
|
|
+ "\tmactx_multicast_frames: %lld\n"
|
|
+ "\tmactx_broadcast_frames: %lld\n"
|
|
+ "\tmactx_pause_frames: %lld\n"
|
|
+ "\tmactx_control_frames: %lld\n"
|
|
+ "\tmactx_deferral: %lld\n"
|
|
+ "\tmactx_excess_deferral: %lld\n"
|
|
+ "\tmactx_late_collision: %lld\n"
|
|
+ "\tmactx_abort: %lld\n"
|
|
+ "\tmactx_single_collision: %lld\n"
|
|
+ "\tmactx_multiple_collision: %lld\n"
|
|
+ "\tmactx_collision: %lld\n"
|
|
+ "\tmactx_frames_dropped: %lld\n"
|
|
+ "\tmactx_jumbo_frames: %lld\n"
|
|
+ "\tmacrx_frames: %lld\n"
|
|
+ "\tmacrx_bytes: %lld\n"
|
|
+ "\tmacrx_unknown_control_frames: %lld\n"
|
|
+ "\tmacrx_pause_frames: %lld\n"
|
|
+ "\tmacrx_control_frames: %lld\n"
|
|
+ "\tmacrx_dribble: %lld\n"
|
|
+ "\tmacrx_frame_length_error: %lld\n"
|
|
+ "\tmacrx_jabber: %lld\n"
|
|
+ "\tmacrx_carrier_sense_error: %lld\n"
|
|
+ "\tmacrx_frame_discarded: %lld\n"
|
|
+ "\tmacrx_frames_dropped: %lld\n"
|
|
+ "\tmac_crc_error: %lld\n"
|
|
+ "\tmac_encoding_error: %lld\n"
|
|
+ "\tmacrx_length_error_large: %lld\n"
|
|
+ "\tmacrx_length_error_small: %lld\n"
|
|
+ "\tmacrx_multicast_frames: %lld\n"
|
|
+ "\tmacrx_broadcast_frames: %lld\n"
|
|
+ /* IP */
|
|
+ "\tiptx_packets: %lld\n"
|
|
+ "\tiptx_bytes: %lld\n"
|
|
+ "\tiptx_fragments: %lld\n"
|
|
+ "\tiprx_packets: %lld\n"
|
|
+ "\tiprx_bytes: %lld\n"
|
|
+ "\tiprx_fragments: %lld\n"
|
|
+ "\tip_datagram_reassembly: %lld\n"
|
|
+ "\tip_invalid_address_error: %lld\n"
|
|
+ "\tip_error_packets: %lld\n"
|
|
+ "\tip_fragrx_overlap: %lld\n"
|
|
+ "\tip_fragrx_outoforder: %lld\n"
|
|
+ "\tip_datagram_reassembly_timeout: %lld\n"
|
|
+ "\tipv6tx_packets: %lld\n"
|
|
+ "\tipv6tx_bytes: %lld\n"
|
|
+ "\tipv6tx_fragments: %lld\n"
|
|
+ "\tipv6rx_packets: %lld\n"
|
|
+ "\tipv6rx_bytes: %lld\n"
|
|
+ "\tipv6rx_fragments: %lld\n"
|
|
+ "\tipv6_datagram_reassembly: %lld\n"
|
|
+ "\tipv6_invalid_address_error: %lld\n"
|
|
+ "\tipv6_error_packets: %lld\n"
|
|
+ "\tipv6_fragrx_overlap: %lld\n"
|
|
+ "\tipv6_fragrx_outoforder: %lld\n"
|
|
+ "\tipv6_datagram_reassembly_timeout: %lld\n"
|
|
+ /* TCP */
|
|
+ "\ttcptx_segments: %lld\n"
|
|
+ "\ttcptx_bytes: %lld\n"
|
|
+ "\ttcprx_segments: %lld\n"
|
|
+ "\ttcprx_byte: %lld\n"
|
|
+ "\ttcp_duplicate_ack_retx: %lld\n"
|
|
+ "\ttcp_retx_timer_expired: %lld\n"
|
|
+ "\ttcprx_duplicate_ack: %lld\n"
|
|
+ "\ttcprx_pure_ackr: %lld\n"
|
|
+ "\ttcptx_delayed_ack: %lld\n"
|
|
+ "\ttcptx_pure_ack: %lld\n"
|
|
+ "\ttcprx_segment_error: %lld\n"
|
|
+ "\ttcprx_segment_outoforder: %lld\n"
|
|
+ "\ttcprx_window_probe: %lld\n"
|
|
+ "\ttcprx_window_update: %lld\n"
|
|
+ "\ttcptx_window_probe_persist: %lld\n"
|
|
+ /* ECC */
|
|
+ "\tecc_error_correction: %lld\n"
|
|
+ /* iSCSI */
|
|
+ "\tiscsi_pdu_tx: %lld\n"
|
|
+ "\tiscsi_data_bytes_tx: %lld\n"
|
|
+ "\tiscsi_pdu_rx: %lld\n"
|
|
+ "\tiscsi_data_bytes_rx: %lld\n"
|
|
+ "\tiscsi_io_completed: %lld\n"
|
|
+ "\tiscsi_unexpected_io_rx: %lld\n"
|
|
+ "\tiscsi_format_error: %lld\n"
|
|
+ "\tiscsi_hdr_digest_error: %lld\n"
|
|
+ "\tiscsi_data_digest_error: %lld\n"
|
|
+ "\tiscsi_sequence_error: %lld\n",
|
|
+ /* MAC */
|
|
+ (unsigned long long)host_stats->mactx_frames,
|
|
+ (unsigned long long)host_stats->mactx_bytes,
|
|
+ (unsigned long long)host_stats->mactx_multicast_frames,
|
|
+ (unsigned long long)host_stats->mactx_broadcast_frames,
|
|
+ (unsigned long long)host_stats->mactx_pause_frames,
|
|
+ (unsigned long long)host_stats->mactx_control_frames,
|
|
+ (unsigned long long)host_stats->mactx_deferral,
|
|
+ (unsigned long long)host_stats->mactx_excess_deferral,
|
|
+ (unsigned long long)host_stats->mactx_late_collision,
|
|
+ (unsigned long long)host_stats->mactx_abort,
|
|
+ (unsigned long long)host_stats->mactx_single_collision,
|
|
+ (unsigned long long)host_stats->mactx_multiple_collision,
|
|
+ (unsigned long long)host_stats->mactx_collision,
|
|
+ (unsigned long long)host_stats->mactx_frames_dropped,
|
|
+ (unsigned long long)host_stats->mactx_jumbo_frames,
|
|
+ (unsigned long long)host_stats->macrx_frames,
|
|
+ (unsigned long long)host_stats->macrx_bytes,
|
|
+ (unsigned long long)host_stats->macrx_unknown_control_frames,
|
|
+ (unsigned long long)host_stats->macrx_pause_frames,
|
|
+ (unsigned long long)host_stats->macrx_control_frames,
|
|
+ (unsigned long long)host_stats->macrx_dribble,
|
|
+ (unsigned long long)host_stats->macrx_frame_length_error,
|
|
+ (unsigned long long)host_stats->macrx_jabber,
|
|
+ (unsigned long long)host_stats->macrx_carrier_sense_error,
|
|
+ (unsigned long long)host_stats->macrx_frame_discarded,
|
|
+ (unsigned long long)host_stats->macrx_frames_dropped,
|
|
+ (unsigned long long)host_stats->mac_crc_error,
|
|
+ (unsigned long long)host_stats->mac_encoding_error,
|
|
+ (unsigned long long)host_stats->macrx_length_error_large,
|
|
+ (unsigned long long)host_stats->macrx_length_error_small,
|
|
+ (unsigned long long)host_stats->macrx_multicast_frames,
|
|
+ (unsigned long long)host_stats->macrx_broadcast_frames,
|
|
+ /* IP */
|
|
+ (unsigned long long)host_stats->iptx_packets,
|
|
+ (unsigned long long)host_stats->iptx_bytes,
|
|
+ (unsigned long long)host_stats->iptx_fragments,
|
|
+ (unsigned long long)host_stats->iprx_packets,
|
|
+ (unsigned long long)host_stats->iprx_bytes,
|
|
+ (unsigned long long)host_stats->iprx_fragments,
|
|
+ (unsigned long long)host_stats->ip_datagram_reassembly,
|
|
+ (unsigned long long)host_stats->ip_invalid_address_error,
|
|
+ (unsigned long long)host_stats->ip_error_packets,
|
|
+ (unsigned long long)host_stats->ip_fragrx_overlap,
|
|
+ (unsigned long long)host_stats->ip_fragrx_outoforder,
|
|
+ (unsigned long long)host_stats->ip_datagram_reassembly_timeout,
|
|
+ (unsigned long long)host_stats->ipv6tx_packets,
|
|
+ (unsigned long long)host_stats->ipv6tx_bytes,
|
|
+ (unsigned long long)host_stats->ipv6tx_fragments,
|
|
+ (unsigned long long)host_stats->ipv6rx_packets,
|
|
+ (unsigned long long)host_stats->ipv6rx_bytes,
|
|
+ (unsigned long long)host_stats->ipv6rx_fragments,
|
|
+ (unsigned long long)host_stats->ipv6_datagram_reassembly,
|
|
+ (unsigned long long)host_stats->ipv6_invalid_address_error,
|
|
+ (unsigned long long)host_stats->ipv6_error_packets,
|
|
+ (unsigned long long)host_stats->ipv6_fragrx_overlap,
|
|
+ (unsigned long long)host_stats->ipv6_fragrx_outoforder,
|
|
+ (unsigned long long)host_stats->ipv6_datagram_reassembly_timeout,
|
|
+ /* TCP */
|
|
+ (unsigned long long)host_stats->tcptx_segments,
|
|
+ (unsigned long long)host_stats->tcptx_bytes,
|
|
+ (unsigned long long)host_stats->tcprx_segments,
|
|
+ (unsigned long long)host_stats->tcprx_byte,
|
|
+ (unsigned long long)host_stats->tcp_duplicate_ack_retx,
|
|
+ (unsigned long long)host_stats->tcp_retx_timer_expired,
|
|
+ (unsigned long long)host_stats->tcprx_duplicate_ack,
|
|
+ (unsigned long long)host_stats->tcprx_pure_ackr,
|
|
+ (unsigned long long)host_stats->tcptx_delayed_ack,
|
|
+ (unsigned long long)host_stats->tcptx_pure_ack,
|
|
+ (unsigned long long)host_stats->tcprx_segment_error,
|
|
+ (unsigned long long)host_stats->tcprx_segment_outoforder,
|
|
+ (unsigned long long)host_stats->tcprx_window_probe,
|
|
+ (unsigned long long)host_stats->tcprx_window_update,
|
|
+ (unsigned long long)host_stats->tcptx_window_probe_persist,
|
|
+ /* ECC */
|
|
+ (unsigned long long)host_stats->ecc_error_correction,
|
|
+ /* iSCSI */
|
|
+ (unsigned long long)host_stats->iscsi_pdu_tx,
|
|
+ (unsigned long long)host_stats->iscsi_data_bytes_tx,
|
|
+ (unsigned long long)host_stats->iscsi_pdu_rx,
|
|
+ (unsigned long long)host_stats->iscsi_data_bytes_rx,
|
|
+ (unsigned long long)host_stats->iscsi_io_completed,
|
|
+ (unsigned long long)host_stats->iscsi_unexpected_io_rx,
|
|
+ (unsigned long long)host_stats->iscsi_format_error,
|
|
+ (unsigned long long)host_stats->iscsi_hdr_digest_error,
|
|
+ (unsigned long long)host_stats->iscsi_data_digest_error,
|
|
+ (unsigned long long)host_stats->iscsi_sequence_error);
|
|
+}
|
|
+
|
|
+static int exec_host_stats_op(int op, int info_level, uint32_t host_no)
|
|
+{
|
|
+ struct iscsi_transport *t = NULL;
|
|
+ char *req_buf = NULL;
|
|
+ int rc = ISCSI_SUCCESS;
|
|
+ int fd = 0, buf_size = 0;
|
|
+
|
|
+ t = iscsi_sysfs_get_transport_by_hba(host_no);
|
|
+ if (!t) {
|
|
+ log_error("Could not match hostno %u to transport.", host_no);
|
|
+ rc = ISCSI_ERR_TRANS_NOT_FOUND;
|
|
+ goto exit_host_stats;
|
|
+ }
|
|
+
|
|
+ buf_size = sizeof(struct iscsi_offload_host_stats) +
|
|
+ sizeof(struct iscsi_uevent);
|
|
+ req_buf = calloc(1, buf_size);
|
|
+ if (!req_buf) {
|
|
+ log_error("Could not allocate memory for host stats request.");
|
|
+ rc = ISCSI_ERR_NOMEM;
|
|
+ goto exit_host_stats;
|
|
+ }
|
|
+
|
|
+ fd = ipc->ctldev_open();
|
|
+ if (fd < 0) {
|
|
+ rc = ISCSI_ERR_INTERNAL;
|
|
+ log_error("Netlink open failed.");
|
|
+ goto exit_host_stats;
|
|
+ }
|
|
+
|
|
+ rc = ipc->get_host_stats(t->handle, host_no, req_buf);
|
|
+ if (rc < 0) {
|
|
+ log_error("get_host_stats failed. errno=%d", errno);
|
|
+ rc = ISCSI_ERR;
|
|
+ goto exit_host_stats;
|
|
+ }
|
|
+
|
|
+ print_host_stats((struct iscsi_offload_host_stats *)(req_buf +
|
|
+ sizeof(struct iscsi_uevent)));
|
|
+
|
|
+ ipc->ctldev_close();
|
|
+
|
|
+exit_host_stats:
|
|
+ free(req_buf);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
static int verify_iface_params(struct list_head *params, struct node_rec *rec)
|
|
{
|
|
struct user_param *param;
|
|
@@ -1473,7 +2290,7 @@ static int verify_iface_params(struct list_head *params, struct node_rec *rec)
|
|
|
|
/* TODO: merge iter helpers and clean them up, so we can use them here */
|
|
static int exec_iface_op(int op, int do_show, int info_level,
|
|
- struct iface_rec *iface, uint32_t host_no,
|
|
+ struct iface_rec *iface, uint64_t host_no,
|
|
struct list_head *params)
|
|
{
|
|
struct host_info hinfo;
|
|
@@ -1594,9 +2411,9 @@ update_fail:
|
|
printf("%s applied.\n", iface->name);
|
|
break;
|
|
case OP_APPLY_ALL:
|
|
- if (host_no == -1) {
|
|
- log_error("Applyall requires a host number or MAC "
|
|
- "passed in with the --host argument.");
|
|
+ if (host_no > MAX_HOST_NO) {
|
|
+ log_error("Applyall requires a valid host number or MAC"
|
|
+ " passed in with the --host argument.");
|
|
rc = ISCSI_ERR_INVAL;
|
|
break;
|
|
}
|
|
@@ -1607,7 +2424,7 @@ update_fail:
|
|
memset(&hinfo, 0, sizeof(struct host_info));
|
|
hinfo.host_no = host_no;
|
|
if (iscsi_sysfs_get_hostinfo_by_host_no(&hinfo)) {
|
|
- log_error("Could not match host%u to ifaces.", host_no);
|
|
+ log_error("Could not match host%lu to ifaces.", host_no);
|
|
rc = ISCSI_ERR_INVAL;
|
|
break;
|
|
}
|
|
@@ -1618,7 +2435,7 @@ update_fail:
|
|
break;
|
|
}
|
|
|
|
- printf("Applied settings to ifaces attached to host%u.\n",
|
|
+ printf("Applied settings to ifaces attached to host%lu.\n",
|
|
host_no);
|
|
break;
|
|
default:
|
|
@@ -1711,12 +2528,12 @@ static int exec_node_op(int op, int do_login, int do_logout,
|
|
}
|
|
|
|
if (do_rescan) {
|
|
- rc = for_each_session(rec, rescan_portal);
|
|
+ rc = for_each_session(rec, rescan_portal, 1);
|
|
goto out;
|
|
}
|
|
|
|
if (do_stats) {
|
|
- rc = for_each_session(rec, session_stats);
|
|
+ rc = for_each_session(rec, session_stats, 0);
|
|
goto out;
|
|
}
|
|
|
|
@@ -1832,7 +2649,7 @@ static int exec_fw_disc_op(discovery_rec_t *drec, struct list_head *ifaces,
|
|
rc = fw_get_targets(&targets);
|
|
if (rc) {
|
|
log_error("Could not get list of targets from firmware. "
|
|
- "(err %d)\n", rc);
|
|
+ "(err %d)", rc);
|
|
return rc;
|
|
}
|
|
rc = iface_create_ifaces_from_boot_contexts(&new_ifaces, &targets);
|
|
@@ -1845,7 +2662,7 @@ discover_fw_tgts:
|
|
rc = idbm_bind_ifaces_to_nodes(discovery_fw, drec,
|
|
ifaces, &rec_list);
|
|
if (rc)
|
|
- log_error("Could not perform fw discovery.\n");
|
|
+ log_error("Could not perform fw discovery.");
|
|
else
|
|
rc = exec_disc_op_on_recs(drec, &rec_list, info_level,
|
|
do_login, op);
|
|
@@ -1883,7 +2700,7 @@ static int exec_fw_op(discovery_rec_t *drec, struct list_head *ifaces,
|
|
rc = fw_get_targets(&targets);
|
|
if (rc) {
|
|
log_error("Could not get list of targets from firmware. "
|
|
- "(err %d)\n", rc);
|
|
+ "(err %d)", rc);
|
|
return rc;
|
|
}
|
|
|
|
@@ -1892,7 +2709,7 @@ static int exec_fw_op(discovery_rec_t *drec, struct list_head *ifaces,
|
|
rec = idbm_create_rec_from_boot_context(context);
|
|
if (!rec) {
|
|
log_error("Could not convert firmware info to "
|
|
- "node record.\n");
|
|
+ "node record.");
|
|
rc = ISCSI_ERR_NOMEM;
|
|
break;
|
|
}
|
|
@@ -1999,16 +2816,10 @@ static int exec_discover(int disc_type, char *ip, int port,
|
|
rc = 0;
|
|
switch (disc_type) {
|
|
case DISCOVERY_TYPE_SENDTARGETS:
|
|
- /*
|
|
- * idbm_add_discovery call above handles drec syncing so
|
|
- * we always pass in 0 here.
|
|
- */
|
|
- rc = do_sendtargets(drec, ifaces, info_level, do_login, op,
|
|
+ case DISCOVERY_TYPE_ISNS:
|
|
+ rc = do_target_discovery(drec, ifaces, info_level, do_login, op,
|
|
0);
|
|
break;
|
|
- case DISCOVERY_TYPE_ISNS:
|
|
- rc = do_isns(drec, ifaces, info_level, do_login, op);
|
|
- break;
|
|
default:
|
|
log_error("Unsupported discovery type.");
|
|
break;
|
|
@@ -2140,8 +2951,7 @@ static int exec_disc_op(int disc_type, char *ip, int port,
|
|
idbm_sendtargets_defaults(&drec.u.sendtargets);
|
|
strlcpy(drec.address, ip, sizeof(drec.address));
|
|
drec.port = port;
|
|
-
|
|
- rc = do_sendtargets(&drec, ifaces, info_level,
|
|
+ rc = do_target_discovery(&drec, ifaces, info_level,
|
|
do_login, op, 1);
|
|
if (rc)
|
|
goto done;
|
|
@@ -2164,7 +2974,9 @@ static int exec_disc_op(int disc_type, char *ip, int port,
|
|
else
|
|
drec.port = port;
|
|
|
|
- rc = do_isns(&drec, ifaces, info_level, do_login, op);
|
|
+ drec.type = DISCOVERY_TYPE_ISNS;
|
|
+ rc = do_target_discovery(&drec, ifaces, info_level,
|
|
+ do_login, op, 0);
|
|
if (rc)
|
|
goto done;
|
|
break;
|
|
@@ -2195,8 +3007,9 @@ static int exec_disc_op(int disc_type, char *ip, int port,
|
|
}
|
|
if ((do_discover || do_login) &&
|
|
drec.type == DISCOVERY_TYPE_SENDTARGETS) {
|
|
- rc = do_sendtargets(&drec, ifaces, info_level,
|
|
- do_login, op, 0);
|
|
+ rc = do_target_discovery(&drec, ifaces,
|
|
+ info_level, do_login,
|
|
+ op, 0);
|
|
} else if (op == OP_NOOP || op == OP_SHOW) {
|
|
if (!idbm_print_discovery_info(&drec,
|
|
do_show)) {
|
|
@@ -2234,10 +3047,10 @@ done:
|
|
return rc;
|
|
}
|
|
|
|
-static uint32_t parse_host_info(char *optarg, int *rc)
|
|
+static uint64_t parse_host_info(char *optarg, int *rc)
|
|
{
|
|
int err = 0;
|
|
- uint32_t host_no = -1;
|
|
+ uint64_t host_no;
|
|
|
|
*rc = 0;
|
|
if (strstr(optarg, ":")) {
|
|
@@ -2250,8 +3063,11 @@ static uint32_t parse_host_info(char *optarg, int *rc)
|
|
*rc = ISCSI_ERR_INVAL;
|
|
}
|
|
} else {
|
|
- host_no = strtoul(optarg, NULL, 10);
|
|
- if (errno) {
|
|
+ host_no = strtoull(optarg, NULL, 10);
|
|
+ if (errno || (host_no > MAX_HOST_NO)) {
|
|
+ if (host_no > MAX_HOST_NO)
|
|
+ errno = ERANGE;
|
|
+
|
|
log_error("Invalid host no %s. %s.",
|
|
optarg, strerror(errno));
|
|
*rc = ISCSI_ERR_INVAL;
|
|
@@ -2286,7 +3102,7 @@ static char *iscsi_ping_stat_strs[] = {
|
|
static char *iscsi_ping_stat_to_str(uint32_t status)
|
|
{
|
|
if (status < 0 || status > ISCSI_PING_NO_ARP_RECEIVED) {
|
|
- log_error("Invalid ping status %u\n", status);
|
|
+ log_error("Invalid ping status %u", status);
|
|
return NULL;
|
|
}
|
|
|
|
@@ -2403,12 +3219,14 @@ main(int argc, char **argv)
|
|
int tpgt = PORTAL_GROUP_TAG_UNKNOWN, killiscsid=-1, do_show=0;
|
|
int packet_size=32, ping_count=1, ping_interval=0;
|
|
int do_discover = 0, sub_mode = -1;
|
|
+ int portal_type = -1;
|
|
struct sigaction sa_old;
|
|
struct sigaction sa_new;
|
|
struct list_head ifaces;
|
|
struct iface_rec *iface = NULL, *tmp;
|
|
struct node_rec *rec = NULL;
|
|
- uint32_t host_no = -1;
|
|
+ uint64_t host_no = (uint64_t)MAX_HOST_NO + 1;
|
|
+ uint64_t index = ULLONG_MAX;
|
|
struct user_param *param;
|
|
struct list_head params;
|
|
|
|
@@ -2551,6 +3369,18 @@ main(int argc, char **argv)
|
|
printf("%s version %s\n", program_name,
|
|
ISCSI_VERSION_STR);
|
|
return 0;
|
|
+ case 'x':
|
|
+ index = strtoull(optarg, NULL, 10);
|
|
+ if (errno) {
|
|
+ log_error("Invalid index %s. %s.",
|
|
+ optarg, strerror(errno));
|
|
+ rc = ISCSI_ERR_INVAL;
|
|
+ goto free_ifaces;
|
|
+ }
|
|
+ break;
|
|
+ case 'A':
|
|
+ portal_type = str_to_portal_type(optarg);
|
|
+ break;
|
|
case 'h':
|
|
usage(0);
|
|
}
|
|
@@ -2583,7 +3413,7 @@ main(int argc, char **argv)
|
|
usage(ISCSI_ERR_INVAL);
|
|
|
|
if (mode == MODE_FW) {
|
|
- if ((rc = verify_mode_params(argc, argv, "ml", 0))) {
|
|
+ if ((rc = verify_mode_params(argc, argv, "dml", 0))) {
|
|
log_error("fw mode: option '-%c' is not "
|
|
"allowed/supported", rc);
|
|
rc = ISCSI_ERR_INVAL;
|
|
@@ -2603,7 +3433,7 @@ main(int argc, char **argv)
|
|
|
|
switch (mode) {
|
|
case MODE_HOST:
|
|
- if ((rc = verify_mode_params(argc, argv, "CHdmPov", 0))) {
|
|
+ if ((rc = verify_mode_params(argc, argv, "CHdmPotnvxA", 0))) {
|
|
log_error("host mode: option '-%c' is not "
|
|
"allowed/supported", rc);
|
|
rc = ISCSI_ERR_INVAL;
|
|
@@ -2612,15 +3442,44 @@ main(int argc, char **argv)
|
|
if (sub_mode != -1) {
|
|
switch (sub_mode) {
|
|
case MODE_CHAP:
|
|
- if (!op || !host_no) {
|
|
+ if (!op || (host_no > MAX_HOST_NO)) {
|
|
log_error("CHAP mode requires host "
|
|
"no and valid operation");
|
|
rc = ISCSI_ERR_INVAL;
|
|
break;
|
|
}
|
|
+
|
|
+ if (index == ULLONG_MAX)
|
|
+ index = (uint64_t)MAX_CHAP_ENTRIES + 1;
|
|
+
|
|
rc = exec_host_chap_op(op, info_level, host_no,
|
|
- value);
|
|
+ index, ¶ms);
|
|
break;
|
|
+ case MODE_FLASHNODE:
|
|
+ if (host_no > MAX_HOST_NO) {
|
|
+ log_error("FLASHNODE mode requires host no");
|
|
+ rc = ISCSI_ERR_INVAL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (index == ULLONG_MAX)
|
|
+ index = (uint64_t)MAX_FLASHNODE_IDX + 1;
|
|
+
|
|
+ rc = exec_flashnode_op(op, info_level, host_no,
|
|
+ index, portal_type,
|
|
+ ¶ms);
|
|
+ break;
|
|
+ case MODE_HOST_STATS:
|
|
+ if (host_no > MAX_HOST_NO) {
|
|
+ log_error("STATS mode requires host no");
|
|
+ rc = ISCSI_ERR_INVAL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ rc = exec_host_stats_op(op, info_level,
|
|
+ host_no);
|
|
+ break;
|
|
+
|
|
default:
|
|
log_error("Invalid Sub Mode");
|
|
break;
|
|
diff --git a/usr/iscsid.c b/usr/iscsid.c
|
|
index b4bb65b..f8ffd23 100644
|
|
--- a/usr/iscsid.c
|
|
+++ b/usr/iscsid.c
|
|
@@ -27,6 +27,7 @@
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
+#include <grp.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/utsname.h>
|
|
#include <sys/types.h>
|
|
@@ -111,9 +112,7 @@ setup_rec_from_negotiated_values(node_rec_t *rec, struct session_info *info)
|
|
strlcpy(rec->name, info->targetname, TARGET_NAME_MAXLEN);
|
|
rec->conn[0].port = info->persistent_port;
|
|
strlcpy(rec->conn[0].address, info->persistent_address, NI_MAXHOST);
|
|
- memcpy(&rec->iface, &info->iface, sizeof(struct iface_rec));
|
|
rec->tpgt = info->tpgt;
|
|
- iface_copy(&rec->iface, &info->iface);
|
|
|
|
iscsi_sysfs_get_negotiated_session_conf(info->sid, &session_conf);
|
|
iscsi_sysfs_get_negotiated_conn_conf(info->sid, &conn_conf);
|
|
@@ -194,7 +193,7 @@ static int sync_session(void *data, struct session_info *info)
|
|
struct iscsi_transport *t;
|
|
int rc, retries = 0;
|
|
|
|
- log_debug(7, "sync session [%d][%s,%s.%d][%s]\n", info->sid,
|
|
+ log_debug(7, "sync session [%d][%s,%s.%d][%s]", info->sid,
|
|
info->targetname, info->persistent_address,
|
|
info->port, info->iface.hwaddress);
|
|
|
|
@@ -236,8 +235,9 @@ static int sync_session(void *data, struct session_info *info)
|
|
info->persistent_address, info->persistent_port,
|
|
&info->iface)) {
|
|
log_warning("Could not read data from db. Using default and "
|
|
- "currently negotiated values\n");
|
|
+ "currently negotiated values");
|
|
setup_rec_from_negotiated_values(&rec, info);
|
|
+ iface_copy(&rec.iface, &info->iface);
|
|
} else {
|
|
/*
|
|
* we have a valid record and iface so lets merge
|
|
@@ -251,13 +251,12 @@ static int sync_session(void *data, struct session_info *info)
|
|
memset(&sysfsrec, 0, sizeof(node_rec_t));
|
|
setup_rec_from_negotiated_values(&sysfsrec, info);
|
|
/*
|
|
- * target, portal and iface name values have to be the same
|
|
+ * target, portal and iface values have to be the same
|
|
* or we would not have found the record, so just copy
|
|
- * CHAP and iface settings.
|
|
+ * CHAP settings.
|
|
*/
|
|
memcpy(&rec.session.auth, &sysfsrec.session.auth,
|
|
sizeof(struct iscsi_auth_config));
|
|
- memcpy(&rec.iface, &info->iface, sizeof(rec.iface));
|
|
}
|
|
|
|
/* multiple drivers could be connected to the same portal */
|
|
@@ -333,7 +332,7 @@ static void missing_iname_warn(char *initiatorname_file)
|
|
"iqn.yyyy-mm.<reversed domain name>[:identifier].\n\n"
|
|
"Example: InitiatorName=iqn.2001-04.com.redhat:fc6.\n"
|
|
"If using hardware iscsi like qla4xxx this message can be "
|
|
- "ignored.\n", initiatorname_file, initiatorname_file);
|
|
+ "ignored.", initiatorname_file, initiatorname_file);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
@@ -342,6 +341,7 @@ int main(int argc, char *argv[])
|
|
char *config_file = CONFIG_FILE;
|
|
char *initiatorname_file = INITIATOR_NAME_FILE;
|
|
char *pid_file = PID_FILE;
|
|
+ char *safe_logout;
|
|
int ch, longindex;
|
|
uid_t uid = 0;
|
|
struct sigaction sa_old;
|
|
@@ -477,11 +477,25 @@ int main(int argc, char *argv[])
|
|
}
|
|
}
|
|
|
|
- if (uid && setuid(uid) < 0)
|
|
- perror("setuid\n");
|
|
+ if (gid && setgid(gid) < 0) {
|
|
+ log_error("Unable to setgid to %d", gid);
|
|
+ log_close(log_pid);
|
|
+ exit(ISCSI_ERR);
|
|
+ }
|
|
|
|
- if (gid && setgid(gid) < 0)
|
|
- perror("setgid\n");
|
|
+ if ((geteuid() == 0) && (getgroups(0, NULL))) {
|
|
+ if (setgroups(0, NULL) != 0) {
|
|
+ log_error("Unable to drop supplementary group ids");
|
|
+ log_close(log_pid);
|
|
+ exit(ISCSI_ERR);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (uid && setuid(uid) < 0) {
|
|
+ log_error("Unable to setuid to %d", uid);
|
|
+ log_close(log_pid);
|
|
+ exit(ISCSI_ERR);
|
|
+ }
|
|
|
|
memset(&daemon_config, 0, sizeof (daemon_config));
|
|
daemon_config.pid_file = pid_file;
|
|
@@ -507,11 +521,17 @@ int main(int argc, char *argv[])
|
|
daemon_config.initiator_name : "NOT SET");
|
|
log_debug(1, "InitiatorAlias=%s", daemon_config.initiator_alias);
|
|
|
|
+ safe_logout = cfg_get_string_param(config_file, "iscsid.safe_logout");
|
|
+ if (safe_logout && !strcmp(safe_logout, "Yes"))
|
|
+ daemon_config.safe_logout = 1;
|
|
+ free(safe_logout);
|
|
+
|
|
pid = fork();
|
|
if (pid == 0) {
|
|
int nr_found = 0;
|
|
/* child */
|
|
- iscsi_sysfs_for_each_session(NULL, &nr_found, sync_session);
|
|
+ /* TODO - test with async support enabled */
|
|
+ iscsi_sysfs_for_each_session(NULL, &nr_found, sync_session, 0);
|
|
exit(0);
|
|
} else if (pid < 0) {
|
|
log_error("Fork failed error %d: existing sessions"
|
|
@@ -534,7 +554,6 @@ int main(int argc, char *argv[])
|
|
exit(ISCSI_ERR);
|
|
}
|
|
|
|
- actor_init();
|
|
event_loop(ipc, control_fd, mgmt_ipc_fd);
|
|
|
|
idbm_terminate();
|
|
diff --git a/usr/iscsid.h b/usr/iscsid.h
|
|
index 15f264f..b9f3d54 100644
|
|
--- a/usr/iscsid.h
|
|
+++ b/usr/iscsid.h
|
|
@@ -29,6 +29,7 @@ struct iscsi_daemon_config {
|
|
char *pid_file;
|
|
char *initiator_name;
|
|
char *initiator_alias;
|
|
+ int safe_logout;
|
|
};
|
|
extern struct iscsi_daemon_config *dconfig;
|
|
|
|
diff --git a/usr/iscsid_req.c b/usr/iscsid_req.c
|
|
index 0902011..75bcf22 100644
|
|
--- a/usr/iscsid_req.c
|
|
+++ b/usr/iscsid_req.c
|
|
@@ -22,6 +22,7 @@
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
+#include <fcntl.h>
|
|
#include <sys/un.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
@@ -32,6 +33,7 @@
|
|
#include "iscsi_util.h"
|
|
#include "config.h"
|
|
#include "iscsi_err.h"
|
|
+#include "uip_mgmt_ipc.h"
|
|
|
|
static void iscsid_startup(void)
|
|
{
|
|
@@ -54,9 +56,9 @@ static void iscsid_startup(void)
|
|
|
|
#define MAXSLEEP 128
|
|
|
|
-static int iscsid_connect(int *fd, int start_iscsid)
|
|
+static int ipc_connect(int *fd, char *unix_sock_name, int start_iscsid)
|
|
{
|
|
- int nsec;
|
|
+ int nsec, addr_len;
|
|
struct sockaddr_un addr;
|
|
|
|
*fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
|
@@ -65,15 +67,13 @@ static int iscsid_connect(int *fd, int start_iscsid)
|
|
return ISCSI_ERR_ISCSID_NOTCONN;
|
|
}
|
|
|
|
- memset(&addr, 0, sizeof(addr));
|
|
- addr.sun_family = AF_LOCAL;
|
|
- memcpy((char *) &addr.sun_path + 1, ISCSIADM_NAMESPACE,
|
|
- strlen(ISCSIADM_NAMESPACE));
|
|
+ addr_len = setup_abstract_addr(&addr, unix_sock_name);
|
|
+
|
|
/*
|
|
* Trying to connect with exponential backoff
|
|
*/
|
|
for (nsec = 1; nsec <= MAXSLEEP; nsec <<= 1) {
|
|
- if (connect(*fd, (struct sockaddr *) &addr, sizeof(addr)) == 0)
|
|
+ if (connect(*fd, (struct sockaddr *) &addr, addr_len) == 0)
|
|
/* Connection established */
|
|
return ISCSI_SUCCESS;
|
|
|
|
@@ -96,6 +96,11 @@ static int iscsid_connect(int *fd, int start_iscsid)
|
|
return ISCSI_ERR_ISCSID_NOTCONN;
|
|
}
|
|
|
|
+static int iscsid_connect(int *fd, int start_iscsid)
|
|
+{
|
|
+ return ipc_connect(fd, ISCSIADM_NAMESPACE, start_iscsid);
|
|
+}
|
|
+
|
|
int iscsid_request(int *fd, iscsiadm_req_t *req, int start_iscsid)
|
|
{
|
|
int err;
|
|
@@ -192,3 +197,82 @@ int iscsid_req_by_sid(iscsiadm_cmd_e cmd, int sid)
|
|
return err;
|
|
return iscsid_req_wait(cmd, fd);
|
|
}
|
|
+
|
|
+static int uip_connect(int *fd)
|
|
+{
|
|
+ return ipc_connect(fd, ISCSID_UIP_NAMESPACE, 0);
|
|
+}
|
|
+
|
|
+int uip_broadcast(void *buf, size_t buf_len)
|
|
+{
|
|
+ int err;
|
|
+ int fd;
|
|
+ iscsid_uip_rsp_t rsp;
|
|
+ int flags;
|
|
+ int count;
|
|
+
|
|
+ err = uip_connect(&fd);
|
|
+ if (err) {
|
|
+ log_warning("uIP daemon is not up");
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ log_debug(3, "connected to uIP daemon");
|
|
+
|
|
+ /* Send the data to uIP */
|
|
+ err = write(fd, buf, buf_len);
|
|
+ if (err != buf_len) {
|
|
+ log_error("got write error (%d/%d), daemon died?",
|
|
+ err, errno);
|
|
+ close(fd);
|
|
+ return ISCSI_ERR_ISCSID_COMM_ERR;
|
|
+ }
|
|
+
|
|
+ log_debug(3, "send iface config to uIP daemon");
|
|
+
|
|
+ /* Set the socket to a non-blocking read, this way if there are
|
|
+ * problems waiting for uIP, iscsid can bailout early */
|
|
+ flags = fcntl(fd, F_GETFL, 0);
|
|
+ if (flags == -1)
|
|
+ flags = 0;
|
|
+ err = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
+ if (err) {
|
|
+ log_error("could not set uip broadcast to non-blocking: %d",
|
|
+ errno);
|
|
+ close(fd);
|
|
+ return ISCSI_ERR;
|
|
+ }
|
|
+
|
|
+#define MAX_UIP_BROADCAST_READ_TRIES 3
|
|
+ for (count = 0; count < MAX_UIP_BROADCAST_READ_TRIES; count++) {
|
|
+ /* Wait for the response */
|
|
+ err = read(fd, &rsp, sizeof(rsp));
|
|
+ if (err == sizeof(rsp)) {
|
|
+ log_debug(3, "Broadcasted to uIP with length: %ld "
|
|
+ "cmd: 0x%x rsp: 0x%x", buf_len,
|
|
+ rsp.command, rsp.err);
|
|
+ err = 0;
|
|
+ break;
|
|
+ } else if ((err == -1) && (errno == EAGAIN)) {
|
|
+ usleep(250000);
|
|
+ continue;
|
|
+ } else {
|
|
+ log_error("Could not read response (%d/%d), daemon "
|
|
+ "died?", err, errno);
|
|
+ err = ISCSI_ERR;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (count == MAX_UIP_BROADCAST_READ_TRIES) {
|
|
+ log_error("Could not broadcast to uIP after %d tries",
|
|
+ count);
|
|
+ err = ISCSI_ERR_AGAIN;
|
|
+ } else if (rsp.err != ISCSID_UIP_MGMT_IPC_DEVICE_UP) {
|
|
+ log_debug(3, "Device is not ready");
|
|
+ err = ISCSI_ERR_AGAIN;
|
|
+ }
|
|
+
|
|
+ close(fd);
|
|
+ return err;
|
|
+}
|
|
diff --git a/usr/iscsid_req.h b/usr/iscsid_req.h
|
|
index 68f5256..4fff43d 100644
|
|
--- a/usr/iscsid_req.h
|
|
+++ b/usr/iscsid_req.h
|
|
@@ -33,4 +33,6 @@ extern int iscsid_req_by_rec(int cmd, struct node_rec *rec);
|
|
extern int iscsid_req_by_sid_async(int cmd, int sid, int *fd);
|
|
extern int iscsid_req_by_sid(int cmd, int sid);
|
|
|
|
+extern int uip_broadcast(void *buf, size_t buf_len);
|
|
+
|
|
#endif
|
|
diff --git a/usr/iscsistart.c b/usr/iscsistart.c
|
|
index 6924d49..7ff2236 100644
|
|
--- a/usr/iscsistart.c
|
|
+++ b/usr/iscsistart.c
|
|
@@ -126,7 +126,7 @@ static int stop_event_loop(void)
|
|
rc = iscsid_exec_req(&req, &rsp, 0);
|
|
if (rc) {
|
|
iscsi_err_print_msg(rc);
|
|
- log_error("Could not stop event_loop\n");
|
|
+ log_error("Could not stop event_loop");
|
|
}
|
|
return rc;
|
|
}
|
|
@@ -287,22 +287,22 @@ static void catch_signal(int signo)
|
|
static int check_params(char *initiatorname)
|
|
{
|
|
if (!initiatorname) {
|
|
- log_error("InitiatorName not set. Exiting %s\n", program_name);
|
|
+ log_error("InitiatorName not set. Exiting %s", program_name);
|
|
return EINVAL;
|
|
}
|
|
|
|
if (config_rec.tpgt == PORTAL_GROUP_TAG_UNKNOWN) {
|
|
- log_error("Portal Group not set. Exiting %s\n", program_name);
|
|
+ log_error("Portal Group not set. Exiting %s", program_name);
|
|
return EINVAL;
|
|
}
|
|
|
|
if (!strlen(config_rec.name)) {
|
|
- log_error("TargetName not set. Exiting %s\n", program_name);
|
|
+ log_error("TargetName not set. Exiting %s", program_name);
|
|
return EINVAL;
|
|
}
|
|
|
|
if (!strlen(config_rec.conn[0].address)) {
|
|
- log_error("IP Address not set. Exiting %s\n", program_name);
|
|
+ log_error("IP Address not set. Exiting %s", program_name);
|
|
return EINVAL;
|
|
}
|
|
|
|
@@ -472,7 +472,7 @@ int main(int argc, char *argv[])
|
|
|
|
mgmt_ipc_fd = mgmt_ipc_listen();
|
|
if (mgmt_ipc_fd < 0) {
|
|
- log_error("Could not setup mgmt ipc\n");
|
|
+ log_error("Could not setup mgmt ipc");
|
|
exit(ISCSI_ERR_NOMEM);
|
|
}
|
|
|
|
@@ -509,7 +509,6 @@ int main(int argc, char *argv[])
|
|
* Start Main Event Loop
|
|
*/
|
|
iscsi_initiator_init();
|
|
- actor_init();
|
|
event_loop(ipc, control_fd, mgmt_ipc_fd);
|
|
ipc->ctldev_close();
|
|
mgmt_ipc_close(mgmt_ipc_fd);
|
|
diff --git a/usr/login.c b/usr/login.c
|
|
index db76c80..8289b03 100644
|
|
--- a/usr/login.c
|
|
+++ b/usr/login.c
|
|
@@ -50,16 +50,14 @@ iscsi_add_text(struct iscsi_hdr *pdu, char *data, int max_data_length,
|
|
int pdu_length = ntoh24(pdu->dlength);
|
|
char *text = data;
|
|
char *end = data + max_data_length;
|
|
- char *pdu_text;
|
|
|
|
/* find the end of the current text */
|
|
text += pdu_length;
|
|
- pdu_text = text;
|
|
pdu_length += length;
|
|
|
|
if (text + length >= end) {
|
|
log_warning("Failed to add login text "
|
|
- "'%s=%s'\n", param, value);
|
|
+ "'%s=%s'", param, value);
|
|
return 0;
|
|
}
|
|
|
|
@@ -170,7 +168,7 @@ resolve_address(char *host, char *port, struct sockaddr_storage *ss)
|
|
|
|
if ((rc = getaddrinfo(host, port, &hints, &res))) {
|
|
log_error("Cannot resolve host %s. getaddrinfo error: "
|
|
- "[%s]\n", host, gai_strerror(rc));
|
|
+ "[%s]", host, gai_strerror(rc));
|
|
return rc;
|
|
}
|
|
|
|
@@ -1558,10 +1556,10 @@ iscsi_login(iscsi_session_t *session, int cid, char *buffer, size_t bufsize,
|
|
repoll:
|
|
pfd.revents = 0;
|
|
ret = poll(&pfd, 1, timeout);
|
|
- log_debug(7, "%s: Poll return %d\n", __FUNCTION__, ret);
|
|
+ log_debug(7, "%s: Poll return %d", __FUNCTION__, ret);
|
|
if (iscsi_timer_expired(&connection_timer)) {
|
|
log_warning("Login response timeout. Waited %d "
|
|
- "seconds and did not get reponse PDU.\n",
|
|
+ "seconds and did not get reponse PDU.",
|
|
session->conn[0].active_timeout);
|
|
c->ret = LOGIN_FAILED;
|
|
return c->ret;
|
|
@@ -1595,7 +1593,7 @@ repoll:
|
|
}
|
|
|
|
} else if (ret < 0) {
|
|
- log_error("Login poll error.\n");
|
|
+ log_error("Login poll error.");
|
|
c->ret = LOGIN_FAILED;
|
|
return c->ret;
|
|
}
|
|
diff --git a/usr/md5.c b/usr/md5.c
|
|
index 4ef1cb7..ba6c86d 100644
|
|
--- a/usr/md5.c
|
|
+++ b/usr/md5.c
|
|
@@ -127,7 +127,7 @@ MD5Final(md5byte digest[16], struct MD5Context *ctx)
|
|
|
|
byteSwap(ctx->buf, 4);
|
|
memcpy(digest, ctx->buf, 16);
|
|
- memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
|
|
+ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
|
|
}
|
|
|
|
#ifndef ASM_MD5
|
|
diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c
|
|
index 5c39c2e..c16bce9 100644
|
|
--- a/usr/mgmt_ipc.c
|
|
+++ b/usr/mgmt_ipc.c
|
|
@@ -36,28 +36,33 @@
|
|
#include "sysdeps.h"
|
|
#include "iscsi_ipc.h"
|
|
#include "iscsi_err.h"
|
|
+#include "iscsi_util.h"
|
|
|
|
#define PEERUSER_MAX 64
|
|
#define EXTMSG_MAX (64 * 1024)
|
|
+#define SD_SOCKET_FDS_START 3
|
|
|
|
int
|
|
mgmt_ipc_listen(void)
|
|
{
|
|
- int fd, err;
|
|
+ int fd, err, addr_len;
|
|
struct sockaddr_un addr;
|
|
|
|
+ /* first check if we have fd handled by systemd */
|
|
+ fd = mgmt_ipc_systemd();
|
|
+ if (fd >= 0)
|
|
+ return fd;
|
|
+
|
|
+ /* manually establish a socket */
|
|
fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
|
if (fd < 0) {
|
|
log_error("Can not create IPC socket");
|
|
return fd;
|
|
}
|
|
|
|
- memset(&addr, 0, sizeof(addr));
|
|
- addr.sun_family = AF_LOCAL;
|
|
- memcpy((char *) &addr.sun_path + 1, ISCSIADM_NAMESPACE,
|
|
- strlen(ISCSIADM_NAMESPACE));
|
|
+ addr_len = setup_abstract_addr(&addr, ISCSIADM_NAMESPACE);
|
|
|
|
- if ((err = bind(fd, (struct sockaddr *) &addr, sizeof(addr))) < 0) {
|
|
+ if ((err = bind(fd, (struct sockaddr *) &addr, addr_len)) < 0 ) {
|
|
log_error("Can not bind IPC socket");
|
|
close(fd);
|
|
return err;
|
|
@@ -72,6 +77,28 @@ mgmt_ipc_listen(void)
|
|
return fd;
|
|
}
|
|
|
|
+int mgmt_ipc_systemd(void)
|
|
+{
|
|
+ const char *env;
|
|
+
|
|
+ env = getenv("LISTEN_PID");
|
|
+
|
|
+ if (!env || (strtoul(env, NULL, 10) != getpid()))
|
|
+ return -EINVAL;
|
|
+
|
|
+ env = getenv("LISTEN_FDS");
|
|
+
|
|
+ if (!env)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (strtoul(env, NULL, 10) != 1) {
|
|
+ log_error("Did not receive exactly one IPC socket from systemd");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return SD_SOCKET_FDS_START;
|
|
+}
|
|
+
|
|
void
|
|
mgmt_ipc_close(int fd)
|
|
{
|
|
@@ -437,7 +464,6 @@ mgmt_ipc_write_rsp(queue_task_t *qtask, int err)
|
|
qtask->rsp.err = err;
|
|
if (write(qtask->mgmt_ipc_fd, &qtask->rsp, sizeof(qtask->rsp)) < 0)
|
|
log_error("IPC qtask write failed: %s", strerror(errno));
|
|
- close(qtask->mgmt_ipc_fd);
|
|
mgmt_ipc_destroy_queue_task(qtask);
|
|
}
|
|
|
|
diff --git a/usr/mgmt_ipc.h b/usr/mgmt_ipc.h
|
|
index 7d8ce72..55972ed 100644
|
|
--- a/usr/mgmt_ipc.h
|
|
+++ b/usr/mgmt_ipc.h
|
|
@@ -112,6 +112,7 @@ typedef int mgmt_ipc_fn_t(struct queue_task *);
|
|
struct queue_task;
|
|
void mgmt_ipc_write_rsp(struct queue_task *qtask, int err);
|
|
int mgmt_ipc_listen(void);
|
|
+int mgmt_ipc_systemd(void);
|
|
void mgmt_ipc_close(int fd);
|
|
void mgmt_ipc_handle(int accept_fd);
|
|
|
|
diff --git a/usr/netlink.c b/usr/netlink.c
|
|
index c43f686..2b85efe 100644
|
|
--- a/usr/netlink.c
|
|
+++ b/usr/netlink.c
|
|
@@ -339,6 +339,10 @@ __kipc_call(struct iovec *iovp, int count)
|
|
} else if (ev->type == ISCSI_UEVENT_GET_CHAP) {
|
|
/* kget_chap() will read */
|
|
return 0;
|
|
+ } else if (ev->type == ISCSI_UEVENT_GET_HOST_STATS) {
|
|
+ /* kget_host_stats() will read */
|
|
+ return 0;
|
|
+
|
|
} else {
|
|
if ((rc = nlpayload_read(ctrl_fd, (void*)ev,
|
|
sizeof(*ev), 0)) < 0) {
|
|
@@ -372,7 +376,7 @@ ksendtargets(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr)
|
|
else if (addr->sa_family == PF_INET6)
|
|
addrlen = sizeof(struct sockaddr_in6);
|
|
else {
|
|
- log_error("%s unknown addr family %d\n",
|
|
+ log_error("%s unknown addr family %d",
|
|
__FUNCTION__, addr->sa_family);
|
|
return -EINVAL;
|
|
}
|
|
@@ -382,7 +386,7 @@ ksendtargets(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr)
|
|
iov[1].iov_len = sizeof(*ev) + addrlen;
|
|
rc = __kipc_call(iov, 2);
|
|
if (rc < 0) {
|
|
- log_error("sendtargets failed rc%d\n", rc);
|
|
+ log_error("sendtargets failed rc%d", rc);
|
|
return rc;
|
|
}
|
|
return 0;
|
|
@@ -674,7 +678,7 @@ kset_host_param(uint64_t transport_handle, uint32_t host_no,
|
|
sprintf(param_str, "%s", (char *)value);
|
|
break;
|
|
default:
|
|
- log_error("invalid type %d\n", type);
|
|
+ log_error("invalid type %d", type);
|
|
return -EINVAL;
|
|
}
|
|
ev->u.set_host_param.len = len = strlen(param_str) + 1;
|
|
@@ -712,13 +716,16 @@ kset_param(uint64_t transport_handle, uint32_t sid, uint32_t cid,
|
|
case ISCSI_INT:
|
|
sprintf(param_str, "%d", *((int *)value));
|
|
break;
|
|
+ case ISCSI_UINT:
|
|
+ sprintf(param_str, "%u", *((unsigned int *)value));
|
|
+ break;
|
|
case ISCSI_STRING:
|
|
if (!strlen(value))
|
|
return 0;
|
|
sprintf(param_str, "%s", (char *)value);
|
|
break;
|
|
default:
|
|
- log_error("invalid type %d\n", type);
|
|
+ log_error("invalid type %d", type);
|
|
return -EINVAL;
|
|
}
|
|
ev->u.set_param.len = len = strlen(param_str) + 1;
|
|
@@ -866,7 +873,7 @@ ktransport_ep_connect(iscsi_conn_t *conn, int non_blocking)
|
|
else if (dst_addr->sa_family == PF_INET6)
|
|
addrlen = sizeof(struct sockaddr_in6);
|
|
else {
|
|
- log_error("%s unknown addr family %d\n",
|
|
+ log_error("%s unknown addr family %d",
|
|
__FUNCTION__, dst_addr->sa_family);
|
|
return -EINVAL;
|
|
}
|
|
@@ -935,7 +942,7 @@ ktransport_ep_disconnect(iscsi_conn_t *conn)
|
|
iov[1].iov_len = sizeof(ev);
|
|
rc = __kipc_call(iov, 2);
|
|
if (rc < 0) {
|
|
- log_error("connnection %d:%d transport disconnect failed for "
|
|
+ log_error("connection %d:%d transport disconnect failed for "
|
|
"ep %" PRIu64 " with error %d.", conn->session->id,
|
|
conn->id, conn->transport_ep_handle, rc);
|
|
} else
|
|
@@ -1031,6 +1038,10 @@ static int krecv_conn_state(struct iscsi_conn *conn, uint32_t *state)
|
|
/* fatal handling error or conn error */
|
|
goto exit;
|
|
|
|
+ /* unexpected event without a receive context */
|
|
+ if (!conn->recv_context)
|
|
+ return -EAGAIN;
|
|
+
|
|
*state = *(enum iscsi_conn_state *)conn->recv_context->data;
|
|
|
|
ipc_ev_clbk->put_ev_context(conn->recv_context);
|
|
@@ -1068,7 +1079,7 @@ ksend_ping(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr,
|
|
else if (addr->sa_family == PF_INET6)
|
|
addrlen = sizeof(struct sockaddr_in6);
|
|
else {
|
|
- log_error("%s unknown addr family %d\n",
|
|
+ log_error("%s unknown addr family %d",
|
|
__FUNCTION__, addr->sa_family);
|
|
return -EINVAL;
|
|
}
|
|
@@ -1228,6 +1239,29 @@ static int kget_chap(uint64_t transport_handle, uint32_t host_no,
|
|
return rc;
|
|
}
|
|
|
|
+static int kset_chap(uint64_t transport_handle, uint32_t host_no,
|
|
+ struct iovec *iovs, uint32_t param_count)
|
|
+{
|
|
+ int rc;
|
|
+ struct iscsi_uevent ev;
|
|
+ struct iovec *iov = iovs + 1;
|
|
+
|
|
+ log_debug(8, "in %s", __func__);
|
|
+
|
|
+ ev.type = ISCSI_UEVENT_SET_CHAP;
|
|
+ ev.transport_handle = transport_handle;
|
|
+ ev.u.set_path.host_no = host_no;
|
|
+
|
|
+ iov->iov_base = &ev;
|
|
+ iov->iov_len = sizeof(ev);
|
|
+
|
|
+ rc = __kipc_call(iovs, param_count);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int kdelete_chap(uint64_t transport_handle, uint32_t host_no,
|
|
uint16_t chap_tbl_idx)
|
|
{
|
|
@@ -1252,6 +1286,211 @@ static int kdelete_chap(uint64_t transport_handle, uint32_t host_no,
|
|
return rc;
|
|
}
|
|
|
|
+static int
|
|
+kset_flashnode_params(uint64_t transport_handle, uint32_t host_no,
|
|
+ uint32_t flashnode_idx, struct iovec *iovs,
|
|
+ uint32_t param_count)
|
|
+{
|
|
+ struct iscsi_uevent ev;
|
|
+ int rc, ev_len;
|
|
+ struct iovec *iov = iovs + 1;
|
|
+
|
|
+ log_debug(8, "in %s", __FUNCTION__);
|
|
+
|
|
+ ev_len = sizeof(ev);
|
|
+ ev.type = ISCSI_UEVENT_SET_FLASHNODE_PARAMS;
|
|
+ ev.transport_handle = transport_handle;
|
|
+ ev.u.set_flashnode.host_no = host_no;
|
|
+ ev.u.set_flashnode.flashnode_idx = flashnode_idx;
|
|
+ /* first two iovs for nlmsg hdr and ev */
|
|
+ ev.u.set_flashnode.count = param_count - 2;
|
|
+
|
|
+ iov->iov_base = &ev;
|
|
+ iov->iov_len = ev_len;
|
|
+ rc = __kipc_call(iovs, param_count);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+knew_flashnode(uint64_t transport_handle, uint32_t host_no, void *value,
|
|
+ uint32_t *flashnode_idx)
|
|
+{
|
|
+ struct iscsi_uevent *ev;
|
|
+ char *param_str;
|
|
+ int rc, len;
|
|
+ struct iovec iov[2];
|
|
+
|
|
+ log_debug(7, "in %s", __FUNCTION__);
|
|
+
|
|
+ memset(setparam_buf, 0, NLM_SETPARAM_DEFAULT_MAX);
|
|
+ ev = (struct iscsi_uevent *)setparam_buf;
|
|
+ ev->type = ISCSI_UEVENT_NEW_FLASHNODE;
|
|
+ ev->transport_handle = transport_handle;
|
|
+ ev->u.new_flashnode.host_no = host_no;
|
|
+
|
|
+ param_str = setparam_buf + sizeof(*ev);
|
|
+ if (!strlen(value))
|
|
+ return 0;
|
|
+ sprintf(param_str, "%s", (char *)value);
|
|
+ len = strlen(param_str) + 1;
|
|
+ ev->u.new_flashnode.len = len;
|
|
+
|
|
+
|
|
+ iov[1].iov_base = ev;
|
|
+ iov[1].iov_len = sizeof(*ev) + len;
|
|
+ rc = __kipc_call(iov, 2);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ *flashnode_idx = ev->r.new_flashnode_ret.flashnode_idx;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+kdel_flashnode(uint64_t transport_handle, uint32_t host_no,
|
|
+ uint32_t flashnode_idx)
|
|
+{
|
|
+ struct iscsi_uevent ev;
|
|
+ int rc;
|
|
+ struct iovec iov[2];
|
|
+
|
|
+ log_debug(7, "in %s", __FUNCTION__);
|
|
+
|
|
+ memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
+ ev.type = ISCSI_UEVENT_DEL_FLASHNODE;
|
|
+ ev.transport_handle = transport_handle;
|
|
+ ev.u.del_flashnode.host_no = host_no;
|
|
+ ev.u.del_flashnode.flashnode_idx = flashnode_idx;
|
|
+
|
|
+ iov[1].iov_base = &ev;
|
|
+ iov[1].iov_len = sizeof(ev);
|
|
+ rc = __kipc_call(iov, 2);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+klogin_flashnode(uint64_t transport_handle, uint32_t host_no,
|
|
+ uint32_t flashnode_idx)
|
|
+{
|
|
+ struct iscsi_uevent ev;
|
|
+ int rc;
|
|
+ struct iovec iov[2];
|
|
+
|
|
+ log_debug(7, "in %s", __FUNCTION__);
|
|
+
|
|
+ memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
+ ev.type = ISCSI_UEVENT_LOGIN_FLASHNODE;
|
|
+ ev.transport_handle = transport_handle;
|
|
+ ev.u.login_flashnode.host_no = host_no;
|
|
+ ev.u.login_flashnode.flashnode_idx = flashnode_idx;
|
|
+
|
|
+ iov[1].iov_base = &ev;
|
|
+ iov[1].iov_len = sizeof(ev);
|
|
+ rc = __kipc_call(iov, 2);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+klogout_flashnode(uint64_t transport_handle, uint32_t host_no,
|
|
+ uint32_t flashnode_idx)
|
|
+{
|
|
+ struct iscsi_uevent ev;
|
|
+ int rc;
|
|
+ struct iovec iov[2];
|
|
+
|
|
+ log_debug(7, "in %s", __FUNCTION__);
|
|
+
|
|
+ memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
+ ev.type = ISCSI_UEVENT_LOGOUT_FLASHNODE;
|
|
+ ev.transport_handle = transport_handle;
|
|
+ ev.u.logout_flashnode.host_no = host_no;
|
|
+ ev.u.logout_flashnode.flashnode_idx = flashnode_idx;
|
|
+
|
|
+ iov[1].iov_base = &ev;
|
|
+ iov[1].iov_len = sizeof(ev);
|
|
+ rc = __kipc_call(iov, 2);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+klogout_flashnode_sid(uint64_t transport_handle, uint32_t host_no,
|
|
+ uint32_t sid)
|
|
+{
|
|
+ struct iscsi_uevent ev;
|
|
+ int rc;
|
|
+ struct iovec iov[2];
|
|
+
|
|
+ log_debug(7, "in %s", __FUNCTION__);
|
|
+
|
|
+ memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
+ ev.type = ISCSI_UEVENT_LOGOUT_FLASHNODE_SID;
|
|
+ ev.transport_handle = transport_handle;
|
|
+ ev.u.logout_flashnode_sid.host_no = host_no;
|
|
+ ev.u.logout_flashnode_sid.sid = sid;
|
|
+
|
|
+ iov[1].iov_base = &ev;
|
|
+ iov[1].iov_len = sizeof(ev);
|
|
+ rc = __kipc_call(iov, 2);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int kget_host_stats(uint64_t transport_handle, uint32_t host_no,
|
|
+ char *host_stats)
|
|
+{
|
|
+ int rc = 0;
|
|
+ int ev_size;
|
|
+ struct iscsi_uevent ev;
|
|
+ struct iovec iov[2];
|
|
+ char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))];
|
|
+ struct nlmsghdr *nlh;
|
|
+
|
|
+ memset(&ev, 0, sizeof(struct iscsi_uevent));
|
|
+
|
|
+ ev.type = ISCSI_UEVENT_GET_HOST_STATS;
|
|
+ ev.transport_handle = transport_handle;
|
|
+ ev.u.get_host_stats.host_no = host_no;
|
|
+
|
|
+ iov[1].iov_base = &ev;
|
|
+ iov[1].iov_len = sizeof(ev);
|
|
+ rc = __kipc_call(iov, 2);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ if ((rc = nl_read(ctrl_fd, nlm_ev,
|
|
+ NLMSG_SPACE(sizeof(struct iscsi_uevent)),
|
|
+ MSG_PEEK)) < 0) {
|
|
+ log_error("can not read nlm_ev, error %d", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ nlh = (struct nlmsghdr *)nlm_ev;
|
|
+ ev_size = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
|
|
+
|
|
+ if ((rc = nlpayload_read(ctrl_fd, (void *)host_stats,
|
|
+ ev_size, 0)) < 0) {
|
|
+ log_error("can not read from NL socket, error %d", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+
|
|
static void drop_data(struct nlmsghdr *nlh)
|
|
{
|
|
int ev_size;
|
|
@@ -1281,7 +1520,7 @@ static int ctldev_handle(void)
|
|
nlh = (struct nlmsghdr *)nlm_ev;
|
|
ev = (struct iscsi_uevent *)NLMSG_DATA(nlm_ev);
|
|
|
|
- log_debug(7, "%s got event type %u\n", __FUNCTION__, ev->type);
|
|
+ log_debug(7, "%s got event type %u", __FUNCTION__, ev->type);
|
|
/* drivers like qla4xxx can be inserted after iscsid is started */
|
|
switch (ev->type) {
|
|
case ISCSI_KEVENT_CREATE_SESSION:
|
|
@@ -1296,10 +1535,10 @@ static int ctldev_handle(void)
|
|
ev->r.c_session_ret.sid);
|
|
return 0;
|
|
case ISCSI_KEVENT_DESTROY_SESSION:
|
|
+ drop_data(nlh);
|
|
if (!ipc_ev_clbk)
|
|
return 0;
|
|
|
|
- drop_data(nlh);
|
|
if (ipc_ev_clbk->destroy_session)
|
|
ipc_ev_clbk->destroy_session(ev->r.d_session.host_no,
|
|
ev->r.d_session.sid);
|
|
@@ -1324,15 +1563,15 @@ static int ctldev_handle(void)
|
|
case ISCSI_KEVENT_HOST_EVENT:
|
|
switch (ev->r.host_event.code) {
|
|
case ISCSI_EVENT_LINKUP:
|
|
- log_warning("Host%u: Link Up.\n",
|
|
+ log_warning("Host%u: Link Up.",
|
|
ev->r.host_event.host_no);
|
|
break;
|
|
case ISCSI_EVENT_LINKDOWN:
|
|
- log_warning("Host%u: Link Down.\n",
|
|
+ log_warning("Host%u: Link Down.",
|
|
ev->r.host_event.host_no);
|
|
break;
|
|
default:
|
|
- log_debug(7, "Host%u: Unknwon host event: %u.\n",
|
|
+ log_debug(7, "Host%u: Unknwon host event: %u.",
|
|
ev->r.host_event.host_no,
|
|
ev->r.host_event.code);
|
|
}
|
|
@@ -1372,7 +1611,7 @@ static int ctldev_handle(void)
|
|
* nl interface.
|
|
*/
|
|
log_debug(1, "Could not verify connection %d:%d. Dropping "
|
|
- "event.\n", sid, cid);
|
|
+ "event.", sid, cid);
|
|
drop_data(nlh);
|
|
return -ENXIO;
|
|
}
|
|
@@ -1382,8 +1621,8 @@ static int ctldev_handle(void)
|
|
|
|
ev_context = ipc_ev_clbk->get_ev_context(conn, ev_size);
|
|
if (!ev_context) {
|
|
- /* retry later */
|
|
log_error("Can not allocate memory for receive context.");
|
|
+ drop_data(nlh);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
@@ -1542,7 +1781,15 @@ struct iscsi_ipc nl_ipc = {
|
|
.recv_conn_state = krecv_conn_state,
|
|
.exec_ping = kexec_ping,
|
|
.get_chap = kget_chap,
|
|
+ .set_chap = kset_chap,
|
|
.delete_chap = kdelete_chap,
|
|
+ .set_flash_node_params = kset_flashnode_params,
|
|
+ .new_flash_node = knew_flashnode,
|
|
+ .del_flash_node = kdel_flashnode,
|
|
+ .login_flash_node = klogin_flashnode,
|
|
+ .logout_flash_node = klogout_flashnode,
|
|
+ .logout_flash_node_sid = klogout_flashnode_sid,
|
|
+ .get_host_stats = kget_host_stats,
|
|
};
|
|
struct iscsi_ipc *ipc = &nl_ipc;
|
|
|
|
diff --git a/usr/session_info.c b/usr/session_info.c
|
|
index 1f84c49..2f48e65 100644
|
|
--- a/usr/session_info.c
|
|
+++ b/usr/session_info.c
|
|
@@ -64,20 +64,32 @@ void session_info_free_list(struct list_head *list)
|
|
}
|
|
}
|
|
|
|
+static char *get_iscsi_node_type(struct session_info *info)
|
|
+{
|
|
+ int pid = iscsi_sysfs_session_user_created(info->sid);
|
|
+
|
|
+ if (!pid)
|
|
+ return "flash";
|
|
+ else
|
|
+ return "non-flash";
|
|
+}
|
|
+
|
|
static int session_info_print_flat(void *data, struct session_info *info)
|
|
{
|
|
struct iscsi_transport *t = iscsi_sysfs_get_transport_by_sid(info->sid);
|
|
|
|
if (strchr(info->persistent_address, '.'))
|
|
- printf("%s: [%d] %s:%d,%d %s\n",
|
|
+ printf("%s: [%d] %s:%d,%d %s (%s)\n",
|
|
t ? t->name : UNKNOWN_VALUE,
|
|
info->sid, info->persistent_address,
|
|
- info->persistent_port, info->tpgt, info->targetname);
|
|
+ info->persistent_port, info->tpgt, info->targetname,
|
|
+ get_iscsi_node_type(info));
|
|
else
|
|
- printf("%s: [%d] [%s]:%d,%d %s\n",
|
|
+ printf("%s: [%d] [%s]:%d,%d %s (%s)\n",
|
|
t ? t->name : UNKNOWN_VALUE,
|
|
info->sid, info->persistent_address,
|
|
- info->persistent_port, info->tpgt, info->targetname);
|
|
+ info->persistent_port, info->tpgt, info->targetname,
|
|
+ get_iscsi_node_type(info));
|
|
return 0;
|
|
}
|
|
|
|
@@ -230,7 +242,8 @@ void session_info_print_tree(struct list_head *list, char *prefix,
|
|
|
|
list_for_each_entry(curr, list, list) {
|
|
if (!prev || strcmp(prev->targetname, curr->targetname)) {
|
|
- printf("%sTarget: %s\n", prefix, curr->targetname);
|
|
+ printf("%sTarget: %s (%s)\n", prefix, curr->targetname,
|
|
+ get_iscsi_node_type(curr));
|
|
prev = NULL;
|
|
}
|
|
|
|
@@ -278,6 +291,7 @@ void session_info_print_tree(struct list_head *list, char *prefix,
|
|
printf("%s\t\tSID: %d\n", prefix, curr->sid);
|
|
print_iscsi_state(curr->sid, prefix);
|
|
}
|
|
+
|
|
if (flags & SESSION_INFO_ISCSI_TIM) {
|
|
printf("%s\t\t*********\n", prefix);
|
|
printf("%s\t\tTimeouts:\n", prefix);
|
|
@@ -368,7 +382,7 @@ int session_info_print(int info_level, struct session_info *info, int do_show)
|
|
num_found = 1;
|
|
} else
|
|
err = iscsi_sysfs_for_each_session(info, &num_found,
|
|
- session_info_print_flat);
|
|
+ session_info_print_flat, 0);
|
|
break;
|
|
case 3:
|
|
version = iscsi_sysfs_get_iscsi_kernel_version();
|
|
@@ -403,7 +417,7 @@ int session_info_print(int info_level, struct session_info *info, int do_show)
|
|
link_info.match_fn = NULL;
|
|
|
|
err = iscsi_sysfs_for_each_session(&link_info, &num_found,
|
|
- session_info_create_list);
|
|
+ session_info_create_list, 0);
|
|
if (err || !num_found)
|
|
break;
|
|
|
|
diff --git a/usr/session_mgmt.c b/usr/session_mgmt.c
|
|
index ec1f43a..87b8e00 100644
|
|
--- a/usr/session_mgmt.c
|
|
+++ b/usr/session_mgmt.c
|
|
@@ -172,18 +172,18 @@ int iscsi_login_portal(void *data, struct list_head *list, struct node_rec *rec)
|
|
* that are missing.
|
|
*/
|
|
rc = iscsi_sysfs_for_each_session(rec, &session_count,
|
|
- iscsi_match_session_count);
|
|
+ iscsi_match_session_count, 0);
|
|
if (rc) {
|
|
log_error("Could not count current number of sessions");
|
|
goto done;
|
|
}
|
|
if (session_count >= rec->session.nr_sessions) {
|
|
- log_debug(1, "%s: %d session%s requested, but %d "
|
|
+ log_warning("%s: %d session%s requested, but %d "
|
|
"already present.",
|
|
rec->iface.name, rec->session.nr_sessions,
|
|
rec->session.nr_sessions == 1 ? "" : "s",
|
|
session_count);
|
|
- rc = 0;
|
|
+ rc = ISCSI_ERR_SESS_EXISTS;
|
|
goto done;
|
|
}
|
|
|
|
@@ -421,7 +421,7 @@ int iscsi_logout_portals(void *data, int *nr_found, int wait,
|
|
*nr_found = 0;
|
|
|
|
err = iscsi_sysfs_for_each_session(&link_info, nr_found,
|
|
- session_info_create_list);
|
|
+ session_info_create_list, 0);
|
|
if (err && !list_empty(&session_list))
|
|
log_error("Could not read in all sessions: %s",
|
|
iscsi_err_to_str(err));
|
|
@@ -466,7 +466,8 @@ free_list:
|
|
int iscsi_check_for_running_session(struct node_rec *rec)
|
|
{
|
|
int nr_found = 0;
|
|
- if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session))
|
|
+ if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session,
|
|
+ 0))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
diff --git a/usr/strings.c b/usr/strings.c
|
|
index 638cb4d..da5df28 100644
|
|
--- a/usr/strings.c
|
|
+++ b/usr/strings.c
|
|
@@ -74,7 +74,7 @@ int str_enlarge_data(struct str_buffer *s, int length)
|
|
if (s) {
|
|
s->data_length += length;
|
|
if (s->data_length > s->allocated_length) {
|
|
- log_debug(7, "enlarge buffer from %lu to %lu\n",
|
|
+ log_debug(7, "enlarge buffer from %lu to %lu",
|
|
s->allocated_length, s->data_length);
|
|
new_buf = realloc(s->buffer, s->data_length);
|
|
if (!new_buf) {
|
|
diff --git a/usr/sysfs.c b/usr/sysfs.c
|
|
index 7f31c1a..6520bf6 100644
|
|
--- a/usr/sysfs.c
|
|
+++ b/usr/sysfs.c
|
|
@@ -82,7 +82,7 @@ int sysfs_init(void)
|
|
remove_trailing_chars(sysfs_path, '/');
|
|
} else
|
|
strlcpy(sysfs_path, "/sys", sizeof(sysfs_path));
|
|
- dbg("sysfs_path='%s'\n", sysfs_path);
|
|
+ dbg("sysfs_path='%s'", sysfs_path);
|
|
|
|
INIT_LIST_HEAD(&dev_list);
|
|
INIT_LIST_HEAD(&attr_list);
|
|
@@ -123,7 +123,7 @@ void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath,
|
|
if (pos == NULL)
|
|
return;
|
|
strlcpy(dev->kernel, &pos[1], sizeof(dev->kernel));
|
|
- dbg("kernel='%s'\n", dev->kernel);
|
|
+ dbg("kernel='%s'", dev->kernel);
|
|
|
|
/* some devices have '!' in their name, change that to '/' */
|
|
pos = dev->kernel;
|
|
@@ -138,7 +138,7 @@ void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath,
|
|
while (isdigit(pos[-1]))
|
|
pos--;
|
|
strlcpy(dev->kernel_number, pos, sizeof(dev->kernel_number));
|
|
- dbg("kernel_number='%s'\n", dev->kernel_number);
|
|
+ dbg("kernel_number='%s'", dev->kernel_number);
|
|
}
|
|
|
|
int sysfs_resolve_link(char *devpath, size_t size)
|
|
@@ -155,11 +155,11 @@ int sysfs_resolve_link(char *devpath, size_t size)
|
|
if (len <= 0)
|
|
return -1;
|
|
link_target[len] = '\0';
|
|
- dbg("path link '%s' points to '%s'\n", devpath, link_target);
|
|
+ dbg("path link '%s' points to '%s'", devpath, link_target);
|
|
|
|
for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
|
|
;
|
|
- dbg("base '%s', tail '%s', back %i\n", devpath, &link_target[back * 3], back);
|
|
+ dbg("base '%s', tail '%s', back %i", devpath, &link_target[back * 3], back);
|
|
for (i = 0; i <= back; i++) {
|
|
char *pos = strrchr(devpath, '/');
|
|
|
|
@@ -167,7 +167,7 @@ int sysfs_resolve_link(char *devpath, size_t size)
|
|
return -1;
|
|
pos[0] = '\0';
|
|
}
|
|
- dbg("after moving back '%s'\n", devpath);
|
|
+ dbg("after moving back '%s'", devpath);
|
|
strlcat(devpath, "/", size);
|
|
strlcat(devpath, &link_target[back * 3], size);
|
|
return 0;
|
|
@@ -195,7 +195,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
|
|
strncmp(devpath, "/block/", 7) != 0)
|
|
return NULL;
|
|
|
|
- dbg("open '%s'\n", devpath);
|
|
+ dbg("open '%s'", devpath);
|
|
strlcpy(devpath_real, devpath, sizeof(devpath_real));
|
|
remove_trailing_chars(devpath_real, '/');
|
|
if (devpath[0] == '\0' )
|
|
@@ -204,7 +204,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
|
|
/* look for device already in cache (we never put an untranslated path in the cache) */
|
|
list_for_each_entry(dev_loop, &dev_list, node) {
|
|
if (strcmp(dev_loop->devpath, devpath_real) == 0) {
|
|
- dbg("found in cache '%s'\n", dev_loop->devpath);
|
|
+ dbg("found in cache '%s'", dev_loop->devpath);
|
|
return dev_loop;
|
|
}
|
|
}
|
|
@@ -213,7 +213,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
|
|
strlcpy(path, sysfs_path, sizeof(path));
|
|
strlcat(path, devpath_real, sizeof(path));
|
|
if (lstat(path, &statbuf) != 0) {
|
|
- dbg("stat '%s' failed: %s\n", path, strerror(errno));
|
|
+ dbg("stat '%s' failed: %s", path, strerror(errno));
|
|
return NULL;
|
|
}
|
|
if (S_ISLNK(statbuf.st_mode)) {
|
|
@@ -223,14 +223,14 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
|
|
/* now look for device in cache after path translation */
|
|
list_for_each_entry(dev_loop, &dev_list, node) {
|
|
if (strcmp(dev_loop->devpath, devpath_real) == 0) {
|
|
- dbg("found in cache '%s'\n", dev_loop->devpath);
|
|
+ dbg("found in cache '%s'", dev_loop->devpath);
|
|
return dev_loop;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* it is a new device */
|
|
- dbg("new uncached device '%s'\n", devpath_real);
|
|
+ dbg("new uncached device '%s'", devpath_real);
|
|
dev = malloc(sizeof(struct sysfs_device));
|
|
if (dev == NULL)
|
|
return NULL;
|
|
@@ -246,7 +246,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
|
|
if (len > 0) {
|
|
/* get subsystem from "subsystem" link */
|
|
link_target[len] = '\0';
|
|
- dbg("subsystem link '%s' points to '%s'\n", link_path, link_target);
|
|
+ dbg("subsystem link '%s' points to '%s'", link_path, link_target);
|
|
pos = strrchr(link_target, '/');
|
|
if (pos != NULL)
|
|
strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem));
|
|
@@ -275,13 +275,13 @@ struct sysfs_device *sysfs_device_get(const char *devpath)
|
|
len = readlink(link_path, link_target, sizeof(link_target));
|
|
if (len > 0) {
|
|
link_target[len] = '\0';
|
|
- dbg("driver link '%s' points to '%s'\n", link_path, link_target);
|
|
+ dbg("driver link '%s' points to '%s'", link_path, link_target);
|
|
pos = strrchr(link_target, '/');
|
|
if (pos != NULL)
|
|
strlcpy(dev->driver, &pos[1], sizeof(dev->driver));
|
|
}
|
|
|
|
- dbg("add to cache 'devpath=%s', subsystem='%s', driver='%s'\n", dev->devpath, dev->subsystem, dev->driver);
|
|
+ dbg("add to cache 'devpath=%s', subsystem='%s', driver='%s'", dev->devpath, dev->subsystem, dev->driver);
|
|
list_add(&dev->node, &dev_list);
|
|
|
|
return dev;
|
|
@@ -292,14 +292,14 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
|
|
char parent_devpath[PATH_SIZE];
|
|
char *pos;
|
|
|
|
- dbg("open '%s'\n", dev->devpath);
|
|
+ dbg("open '%s'", dev->devpath);
|
|
|
|
/* look if we already know the parent */
|
|
if (dev->parent != NULL)
|
|
return dev->parent;
|
|
|
|
strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
|
|
- dbg("'%s'\n", parent_devpath);
|
|
+ dbg("'%s'", parent_devpath);
|
|
|
|
/* strip last element */
|
|
pos = strrchr(parent_devpath, '/');
|
|
@@ -310,12 +310,12 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
|
|
if (strncmp(parent_devpath, "/class", 6) == 0) {
|
|
pos = strrchr(parent_devpath, '/');
|
|
if (pos == &parent_devpath[6] || pos == parent_devpath) {
|
|
- dbg("/class top level, look for device link\n");
|
|
+ dbg("/class top level, look for device link");
|
|
goto device_link;
|
|
}
|
|
}
|
|
if (strcmp(parent_devpath, "/block") == 0) {
|
|
- dbg("/block top level, look for device link\n");
|
|
+ dbg("/block top level, look for device link");
|
|
goto device_link;
|
|
}
|
|
|
|
@@ -364,7 +364,7 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
|
|
ssize_t size;
|
|
size_t sysfs_len;
|
|
|
|
- dbg("open '%s'/'%s'\n", devpath, attr_name);
|
|
+ dbg("open '%s'/'%s'", devpath, attr_name);
|
|
sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
|
|
if(sysfs_len >= sizeof(path_full))
|
|
sysfs_len = sizeof(path_full) - 1;
|
|
@@ -376,23 +376,23 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
|
|
/* look for attribute in cache */
|
|
list_for_each_entry(attr_loop, &attr_list, node) {
|
|
if (strcmp(attr_loop->path, path) == 0) {
|
|
- dbg("found in cache '%s'\n", attr_loop->path);
|
|
+ dbg("found in cache '%s'", attr_loop->path);
|
|
return attr_loop->value;
|
|
}
|
|
}
|
|
|
|
/* store attribute in cache (also negatives are kept in cache) */
|
|
- dbg("new uncached attribute '%s'\n", path_full);
|
|
+ dbg("new uncached attribute '%s'", path_full);
|
|
attr = malloc(sizeof(struct sysfs_attr));
|
|
if (attr == NULL)
|
|
return NULL;
|
|
memset(attr, 0x00, sizeof(struct sysfs_attr));
|
|
strlcpy(attr->path, path, sizeof(attr->path));
|
|
- dbg("add to cache '%s'\n", path_full);
|
|
+ dbg("add to cache '%s'", path_full);
|
|
list_add(&attr->node, &attr_list);
|
|
|
|
if (lstat(path_full, &statbuf) != 0) {
|
|
- dbg("stat '%s' failed: %s\n", path_full, strerror(errno));
|
|
+ dbg("stat '%s' failed: %s", path_full, strerror(errno));
|
|
goto out;
|
|
}
|
|
|
|
@@ -407,7 +407,7 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
|
|
link_target[len] = '\0';
|
|
pos = strrchr(link_target, '/');
|
|
if (pos != NULL) {
|
|
- dbg("cache '%s' with link value '%s'\n", path_full, value);
|
|
+ dbg("cache '%s' with link value '%s'", path_full, value);
|
|
strlcpy(attr->value_local, &pos[1], sizeof(attr->value_local));
|
|
attr->value = attr->value_local;
|
|
}
|
|
@@ -426,7 +426,7 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
|
|
/* read attribute value */
|
|
fd = open(path_full, O_RDONLY);
|
|
if (fd < 0) {
|
|
- dbg("attribute '%s' can not be opened\n", path_full);
|
|
+ dbg("attribute '%s' can not be opened", path_full);
|
|
goto out;
|
|
}
|
|
size = read(fd, value, sizeof(value));
|
|
@@ -439,7 +439,7 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
|
|
/* got a valid value, store and return it */
|
|
value[size] = '\0';
|
|
remove_trailing_chars(value, '\n');
|
|
- dbg("cache '%s' with attribute value '%s'\n", path_full, value);
|
|
+ dbg("cache '%s' with attribute value '%s'", path_full, value);
|
|
strlcpy(attr->value_local, value, sizeof(attr->value_local));
|
|
attr->value = attr->value_local;
|
|
|
|
@@ -554,14 +554,14 @@ char *sysfs_get_value(const char *id, char *subsys, char *param)
|
|
|
|
if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
|
|
subsys, id)) {
|
|
- log_debug(3, "Could not lookup devpath for %s %s\n",
|
|
+ log_debug(3, "Could not lookup devpath for %s %s",
|
|
subsys, id);
|
|
return NULL;
|
|
}
|
|
|
|
sysfs_value = sysfs_attr_get_value(devpath, param);
|
|
if (!sysfs_value) {
|
|
- log_debug(3, "Could not read attr %s on path %s\n",
|
|
+ log_debug(3, "Could not read attr %s on path %s",
|
|
param, devpath);
|
|
return NULL;
|
|
}
|
|
@@ -671,12 +671,11 @@ int sysfs_set_param(char *id, char *subsys, char *attr_name,
|
|
char devpath[PATH_SIZE];
|
|
size_t sysfs_len;
|
|
char path_full[PATH_SIZE];
|
|
- const char *path;
|
|
int rc = 0, fd;
|
|
|
|
if (!sysfs_lookup_devpath_by_subsys_id(devpath, sizeof(devpath),
|
|
subsys, id)) {
|
|
- log_debug(3, "Could not lookup devpath for %s %s\n",
|
|
+ log_debug(3, "Could not lookup devpath for %s %s",
|
|
subsys, id);
|
|
return EIO;
|
|
}
|
|
@@ -684,25 +683,24 @@ int sysfs_set_param(char *id, char *subsys, char *attr_name,
|
|
sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
|
|
if(sysfs_len >= sizeof(path_full))
|
|
sysfs_len = sizeof(path_full) - 1;
|
|
- path = &path_full[sysfs_len];
|
|
strlcat(path_full, devpath, sizeof(path_full));
|
|
strlcat(path_full, "/", sizeof(path_full));
|
|
strlcat(path_full, attr_name, sizeof(path_full));
|
|
|
|
if (lstat(path_full, &statbuf)) {
|
|
- log_debug(3, "Could not stat %s\n", path_full);
|
|
+ log_debug(3, "Could not stat %s", path_full);
|
|
return errno;
|
|
}
|
|
|
|
if ((statbuf.st_mode & S_IWUSR) == 0) {
|
|
- log_error("Could not write to %s. Invalid permissions.\n",
|
|
+ log_error("Could not write to %s. Invalid permissions.",
|
|
path_full);
|
|
return EACCES;
|
|
}
|
|
|
|
fd = open(path_full, O_WRONLY);
|
|
if (fd < 0) {
|
|
- log_error("Could not open %s err %d\n", path_full, errno);
|
|
+ log_error("Could not open %s err %d", path_full, errno);
|
|
return errno;
|
|
}
|
|
|
|
@@ -711,3 +709,43 @@ int sysfs_set_param(char *id, char *subsys, char *attr_name,
|
|
close(fd);
|
|
return rc;
|
|
}
|
|
+
|
|
+char *sysfs_get_uevent_field(const char *path, const char *field)
|
|
+{
|
|
+ char *uevent_path = NULL;
|
|
+ FILE *f = NULL;
|
|
+ char *line, buffer[1024];
|
|
+ char *ff, *d;
|
|
+ char *out = NULL;
|
|
+
|
|
+ uevent_path = calloc(1, PATH_MAX);
|
|
+ if (!uevent_path)
|
|
+ return NULL;
|
|
+ snprintf(uevent_path, PATH_MAX, "%s/uevent", path);
|
|
+
|
|
+ f = fopen(uevent_path, "r");
|
|
+ if (!f)
|
|
+ goto out;
|
|
+ while ((line = fgets(buffer, sizeof (buffer), f))) {
|
|
+ ff = strtok(line, "=");
|
|
+ d = strtok(NULL, "\n");
|
|
+ if (strcmp(ff, field))
|
|
+ continue;
|
|
+ out = strdup(d);
|
|
+ break;
|
|
+ }
|
|
+ fclose(f);
|
|
+out:
|
|
+ free(uevent_path);
|
|
+ return out;
|
|
+}
|
|
+
|
|
+char *sysfs_get_uevent_devtype(const char *path)
|
|
+{
|
|
+ return sysfs_get_uevent_field(path, "DEVTYPE");
|
|
+}
|
|
+
|
|
+char *sysfs_get_uevent_devname(const char *path)
|
|
+{
|
|
+ return sysfs_get_uevent_field(path, "DEVNAME");
|
|
+}
|
|
diff --git a/usr/sysfs.h b/usr/sysfs.h
|
|
index 304dbbf..462060e 100644
|
|
--- a/usr/sysfs.h
|
|
+++ b/usr/sysfs.h
|
|
@@ -66,4 +66,8 @@ extern int sysfs_get_uint16(char *id, char *subsys, char *param,
|
|
extern int sysfs_set_param(char *id, char *subsys, char *attr_name,
|
|
char *write_buf, ssize_t buf_size);
|
|
|
|
+extern char *sysfs_get_uevent_field(const char *path, const char *field);
|
|
+extern char *sysfs_get_uevent_devtype(const char *path);
|
|
+extern char *sysfs_get_uevent_devname(const char *path);
|
|
+
|
|
#endif
|
|
diff --git a/usr/transport.c b/usr/transport.c
|
|
index e6e3dfc..c96d9c6 100644
|
|
--- a/usr/transport.c
|
|
+++ b/usr/transport.c
|
|
@@ -35,6 +35,7 @@
|
|
#include "log.h"
|
|
#include "iscsi_util.h"
|
|
#include "iscsi_sysfs.h"
|
|
+#include "uip_mgmt_ipc.h"
|
|
#include "cxgbi.h"
|
|
#include "be2iscsi.h"
|
|
#include "iser.h"
|
|
@@ -57,7 +58,8 @@ struct iscsi_transport_template iscsi_iser = {
|
|
|
|
struct iscsi_transport_template cxgb3i = {
|
|
.name = "cxgb3i",
|
|
- .set_host_ip = 1,
|
|
+ .set_host_ip = SET_HOST_IP_OPT,
|
|
+ .bind_ep_required = 1,
|
|
.ep_connect = ktransport_ep_connect,
|
|
.ep_poll = ktransport_ep_poll,
|
|
.ep_disconnect = ktransport_ep_disconnect,
|
|
@@ -66,7 +68,8 @@ struct iscsi_transport_template cxgb3i = {
|
|
|
|
struct iscsi_transport_template cxgb4i = {
|
|
.name = "cxgb4i",
|
|
- .set_host_ip = 1,
|
|
+ .set_host_ip = SET_HOST_IP_NOT_REQ,
|
|
+ .bind_ep_required = 1,
|
|
.ep_connect = ktransport_ep_connect,
|
|
.ep_poll = ktransport_ep_poll,
|
|
.ep_disconnect = ktransport_ep_disconnect,
|
|
@@ -75,14 +78,18 @@ struct iscsi_transport_template cxgb4i = {
|
|
|
|
struct iscsi_transport_template bnx2i = {
|
|
.name = "bnx2i",
|
|
- .set_host_ip = 1,
|
|
+ .set_host_ip = SET_HOST_IP_REQ,
|
|
+ .use_boot_info = 1,
|
|
+ .bind_ep_required = 1,
|
|
.ep_connect = ktransport_ep_connect,
|
|
.ep_poll = ktransport_ep_poll,
|
|
.ep_disconnect = ktransport_ep_disconnect,
|
|
+ .set_net_config = uip_broadcast_params,
|
|
};
|
|
|
|
struct iscsi_transport_template be2iscsi = {
|
|
.name = "be2iscsi",
|
|
+ .bind_ep_required = 1,
|
|
.create_conn = be2iscsi_create_conn,
|
|
.ep_connect = ktransport_ep_connect,
|
|
.ep_poll = ktransport_ep_poll,
|
|
@@ -91,7 +98,16 @@ struct iscsi_transport_template be2iscsi = {
|
|
|
|
struct iscsi_transport_template qla4xxx = {
|
|
.name = "qla4xxx",
|
|
- .set_host_ip = 0,
|
|
+ .set_host_ip = SET_HOST_IP_NOT_REQ,
|
|
+ .bind_ep_required = 1,
|
|
+ .ep_connect = ktransport_ep_connect,
|
|
+ .ep_poll = ktransport_ep_poll,
|
|
+ .ep_disconnect = ktransport_ep_disconnect,
|
|
+};
|
|
+
|
|
+struct iscsi_transport_template ocs = {
|
|
+ .name = "ocs",
|
|
+ .bind_ep_required = 1,
|
|
.ep_connect = ktransport_ep_connect,
|
|
.ep_poll = ktransport_ep_poll,
|
|
.ep_disconnect = ktransport_ep_disconnect,
|
|
@@ -105,6 +121,7 @@ static struct iscsi_transport_template *iscsi_transport_templates[] = {
|
|
&bnx2i,
|
|
&qla4xxx,
|
|
&be2iscsi,
|
|
+ &ocs,
|
|
NULL
|
|
};
|
|
|
|
@@ -132,7 +149,7 @@ int transport_probe_for_offload(void)
|
|
for (i = 0; ifni[i].if_index && ifni[i].if_name; i++) {
|
|
struct if_nameindex *n = &ifni[i];
|
|
|
|
- log_debug(6, "kmod probe found %s\n", n->if_name);
|
|
+ log_debug(6, "kmod probe found %s", n->if_name);
|
|
|
|
strlcpy(if_hwaddr.ifr_name, n->if_name, IFNAMSIZ);
|
|
if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0)
|
|
@@ -264,12 +281,12 @@ int set_transport_template(struct iscsi_transport *t)
|
|
|
|
if (!strcmp(tmpl->name, t->name)) {
|
|
t->template = tmpl;
|
|
- log_debug(3, "Matched transport %s\n", t->name);
|
|
+ log_debug(3, "Matched transport %s", t->name);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
log_error("Could not find template for %s. An updated iscsiadm "
|
|
- "is probably needed.\n", t->name);
|
|
+ "is probably needed.", t->name);
|
|
return ENOSYS;
|
|
}
|
|
diff --git a/usr/transport.h b/usr/transport.h
|
|
index 672561b..831403b 100644
|
|
--- a/usr/transport.h
|
|
+++ b/usr/transport.h
|
|
@@ -20,6 +20,12 @@
|
|
#include "types.h"
|
|
#include "config.h"
|
|
|
|
+enum set_host_ip_opts {
|
|
+ SET_HOST_IP_NOT_REQ, /* iface.ipaddress is not supported */
|
|
+ SET_HOST_IP_REQ, /* iface.ipaddress must be specified */
|
|
+ SET_HOST_IP_OPT, /* iface.ipaddress is not required */
|
|
+};
|
|
+
|
|
struct iscsi_transport;
|
|
struct iscsi_conn;
|
|
|
|
@@ -31,10 +37,15 @@ struct iscsi_transport_template {
|
|
* the host's ip address.
|
|
*/
|
|
uint8_t set_host_ip;
|
|
+ uint8_t use_boot_info;
|
|
+ uint8_t bind_ep_required;
|
|
int (*ep_connect) (struct iscsi_conn *conn, int non_blocking);
|
|
int (*ep_poll) (struct iscsi_conn *conn, int timeout_ms);
|
|
void (*ep_disconnect) (struct iscsi_conn *conn);
|
|
void (*create_conn) (struct iscsi_conn *conn);
|
|
+ int (*set_net_config) (struct iscsi_transport *t,
|
|
+ struct iface_rec *iface,
|
|
+ struct iscsi_session *session);
|
|
};
|
|
|
|
/* represents data path provider */
|
|
diff --git a/usr/types.h b/usr/types.h
|
|
index 77e3f97..9d9ba86 100644
|
|
--- a/usr/types.h
|
|
+++ b/usr/types.h
|
|
@@ -10,6 +10,7 @@
|
|
#include <netinet/in.h>
|
|
#include <stdint.h>
|
|
#include <sys/types.h>
|
|
+#include <limits.h>
|
|
|
|
/*
|
|
* using the __be types allows stricter static
|
|
diff --git a/usr/uip_mgmt_ipc.c b/usr/uip_mgmt_ipc.c
|
|
new file mode 100644
|
|
index 0000000..1dfc6d0
|
|
--- /dev/null
|
|
+++ b/usr/uip_mgmt_ipc.c
|
|
@@ -0,0 +1,41 @@
|
|
+/*
|
|
+ * uIP iSCSI Daemon/Admin Management IPC
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published
|
|
+ * by the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful, but
|
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * General Public License for more details.
|
|
+ *
|
|
+ * See the file COPYING included with this distribution for more details.
|
|
+ */
|
|
+
|
|
+#include <string.h>
|
|
+
|
|
+#include "log.h"
|
|
+#include "uip_mgmt_ipc.h"
|
|
+#include "iscsid_req.h"
|
|
+
|
|
+int uip_broadcast_params(struct iscsi_transport *t,
|
|
+ struct iface_rec *iface,
|
|
+ struct iscsi_session *session)
|
|
+{
|
|
+ struct iscsid_uip_broadcast broadcast;
|
|
+
|
|
+ log_debug(3, "broadcasting to uip");
|
|
+
|
|
+ memset(&broadcast, 0, sizeof(broadcast));
|
|
+
|
|
+ broadcast.header.command = ISCSID_UIP_IPC_GET_IFACE;
|
|
+ broadcast.header.payload_len = sizeof(*iface);
|
|
+
|
|
+ memcpy(&broadcast.u.iface_rec, iface, sizeof(*iface));
|
|
+
|
|
+ return uip_broadcast(&broadcast,
|
|
+ sizeof(iscsid_uip_broadcast_header_t) +
|
|
+ sizeof(*iface));
|
|
+}
|
|
diff --git a/usr/uip_mgmt_ipc.h b/usr/uip_mgmt_ipc.h
|
|
new file mode 100644
|
|
index 0000000..29a4769
|
|
--- /dev/null
|
|
+++ b/usr/uip_mgmt_ipc.h
|
|
@@ -0,0 +1,73 @@
|
|
+/*
|
|
+ * uIP iSCSI Daemon/Admin Management IPC
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published
|
|
+ * by the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful, but
|
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * General Public License for more details.
|
|
+ *
|
|
+ * See the file COPYING included with this distribution for more details.
|
|
+ */
|
|
+#ifndef UIP_MGMT_IPC_H
|
|
+#define UIP_MGMT_IPC_H
|
|
+
|
|
+#include "types.h"
|
|
+#include "iscsi_if.h"
|
|
+#include "config.h"
|
|
+#include "mgmt_ipc.h"
|
|
+
|
|
+#include "initiator.h"
|
|
+#include "transport.h"
|
|
+
|
|
+#define ISCSID_UIP_NAMESPACE "ISCSID_UIP_ABSTRACT_NAMESPACE"
|
|
+
|
|
+typedef enum iscsid_uip_cmd {
|
|
+ ISCSID_UIP_IPC_UNKNOWN = 0,
|
|
+ ISCSID_UIP_IPC_GET_IFACE = 1,
|
|
+
|
|
+ __ISCSID_UIP_IPC_MAX_COMMAND
|
|
+} iscsid_uip_cmd_e;
|
|
+
|
|
+typedef struct iscsid_uip_broadcast_header {
|
|
+ iscsid_uip_cmd_e command;
|
|
+ uint32_t payload_len;
|
|
+} iscsid_uip_broadcast_header_t;
|
|
+
|
|
+/* IPC Request */
|
|
+typedef struct iscsid_uip_broadcast {
|
|
+ struct iscsid_uip_broadcast_header header;
|
|
+
|
|
+ union {
|
|
+ /* messages */
|
|
+ struct ipc_broadcast_iface_rec {
|
|
+ struct iface_rec rec;
|
|
+ } iface_rec;
|
|
+ } u;
|
|
+} iscsid_uip_broadcast_t;
|
|
+
|
|
+typedef enum iscsid_uip_mgmt_ipc_err {
|
|
+ ISCSID_UIP_MGMT_IPC_OK = 0,
|
|
+ ISCSID_UIP_MGMT_IPC_ERR = 1,
|
|
+ ISCSID_UIP_MGMT_IPC_ERR_NOT_FOUND = 2,
|
|
+ ISCSID_UIP_MGMT_IPC_ERR_NOMEM = 3,
|
|
+ ISCSID_UIP_MGMT_IPC_DEVICE_UP = 4,
|
|
+ ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING = 5,
|
|
+} iscsid_uip_mgmt_ipc_err_e;
|
|
+
|
|
+/* IPC Response */
|
|
+typedef struct iscsid_uip_mgmt_rsp {
|
|
+ iscsid_uip_cmd_e command;
|
|
+ iscsid_uip_mgmt_ipc_err_e err;
|
|
+} iscsid_uip_rsp_t;
|
|
+
|
|
+extern int uip_broadcast_params(struct iscsi_transport *t,
|
|
+ struct iface_rec *iface,
|
|
+ struct iscsi_session *session);
|
|
+
|
|
+
|
|
+#endif /* UIP_MGMT_IPC_H */
|
|
diff --git a/utils/Makefile b/utils/Makefile
|
|
index 2c7e891..f65f1e7 100644
|
|
--- a/utils/Makefile
|
|
+++ b/utils/Makefile
|
|
@@ -1,12 +1,13 @@
|
|
# This Makefile will work only with GNU make.
|
|
|
|
-CFLAGS += $(OPTFLAGS) -O2 -fno-inline -Wall -Wstrict-prototypes -g
|
|
+CFLAGS ?= -O2 -fno-inline -g
|
|
+CFLAGS += -Wall -Wstrict-prototypes
|
|
PROGRAMS = iscsi-iname
|
|
|
|
all: $(PROGRAMS)
|
|
|
|
iscsi-iname: md5.o iscsi-iname.o
|
|
- $(CC) $(CFLAGS) $^ $(DBM_LIB) -o $@
|
|
+ $(CC) $(CFLAGS) $(LDFLAGS) $^ $(DBM_LIB) -o $@
|
|
|
|
clean:
|
|
rm -f *.o $(PROGRAMS) .depend
|
|
diff --git a/utils/fwparam_ibft/Makefile b/utils/fwparam_ibft/Makefile
|
|
index c72bb7f..773d8eb 100644
|
|
--- a/utils/fwparam_ibft/Makefile
|
|
+++ b/utils/fwparam_ibft/Makefile
|
|
@@ -26,9 +26,9 @@ OBJS := fw_entry.o fwparam_sysfs.o $(SYSDEPS_OBJS) ../../usr/iscsi_net_util.o
|
|
OBJS += prom_lex.o prom_parse.tab.o fwparam_ppc.o
|
|
CLEANFILES = $(OBJS) *.output *~
|
|
|
|
-OPTFLAGS ?= -O2 -g -fPIC
|
|
+CFLAGS ?= -O2 -g
|
|
WARNFLAGS ?= -Wall -Wstrict-prototypes
|
|
-CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -I../../include -I../../usr -D_GNU_SOURCE
|
|
+CFLAGS += -fPIC $(WARNFLAGS) -I../../include -I../../usr -D_GNU_SOURCE
|
|
|
|
all: $(OBJS)
|
|
|
|
diff --git a/utils/fwparam_ibft/fw_entry.c b/utils/fwparam_ibft/fw_entry.c
|
|
index b6f05c1..f94a035 100644
|
|
--- a/utils/fwparam_ibft/fw_entry.c
|
|
+++ b/utils/fwparam_ibft/fw_entry.c
|
|
@@ -67,15 +67,15 @@ int fw_setup_nics(void)
|
|
* to force iSCSI traffic through correct NIC
|
|
*/
|
|
list_for_each_entry(context, &targets, list) {
|
|
- /* if it is a offload nic ignore it */
|
|
- if (!net_get_transport_name_from_netdev(context->iface,
|
|
+ /* if it is a offload nic ignore it */
|
|
+ if (!net_get_transport_name_from_netdev(context->iface,
|
|
transport))
|
|
continue;
|
|
|
|
if (iface_prev == NULL || strcmp(context->iface, iface_prev)) {
|
|
/* Note: test above works because there is a
|
|
- * maximum of two targets in the iBFT
|
|
- */
|
|
+ * maximum of two targets in the iBFT
|
|
+ */
|
|
iface_prev = context->iface;
|
|
needs_bringup = 1;
|
|
}
|
|
@@ -192,10 +192,13 @@ static void dump_network(struct boot_context *context)
|
|
if (strlen(context->mac))
|
|
printf("%s = %s\n", IFACE_HWADDR, context->mac);
|
|
/*
|
|
- * If this has a valid address then DHCP was used (broadcom sends
|
|
- * 0.0.0.0).
|
|
+ * If the 'origin' field is 3 (IBFT_IP_PREFIX_ORIGIN_DHCP),
|
|
+ * then DHCP is used.
|
|
+ * Otherwise evaluate the 'dhcp' field, if this has a valid
|
|
+ * address then DHCP was used (broadcom sends 0.0.0.0).
|
|
*/
|
|
- if (strlen(context->dhcp) && strcmp(context->dhcp, "0.0.0.0"))
|
|
+ if ((context->origin == IBFT_IP_PREFIX_ORIGIN_DHCP) ||
|
|
+ (strlen(context->dhcp) && strcmp(context->dhcp, "0.0.0.0")))
|
|
printf("%s = DHCP\n", IFACE_BOOT_PROTO);
|
|
else
|
|
printf("%s = STATIC\n", IFACE_BOOT_PROTO);
|
|
diff --git a/utils/fwparam_ibft/fwparam_ibft_sysfs.c b/utils/fwparam_ibft/fwparam_ibft_sysfs.c
|
|
index 9185c85..2dc6f6d 100644
|
|
--- a/utils/fwparam_ibft/fwparam_ibft_sysfs.c
|
|
+++ b/utils/fwparam_ibft/fwparam_ibft_sysfs.c
|
|
@@ -201,6 +201,8 @@ static int fill_nic_context(char *id, struct boot_context *context)
|
|
sizeof(context->secondary_dns));
|
|
sysfs_get_str(id, IBFT_SUBSYS, "dhcp", context->dhcp,
|
|
sizeof(context->dhcp));
|
|
+ sysfs_get_str(id, IBFT_SUBSYS, "origin", context->origin,
|
|
+ sizeof(context->origin));
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/utils/fwparam_ibft/fwparam_sysfs.c b/utils/fwparam_ibft/fwparam_sysfs.c
|
|
index 3997363..23eb913 100644
|
|
--- a/utils/fwparam_ibft/fwparam_sysfs.c
|
|
+++ b/utils/fwparam_ibft/fwparam_sysfs.c
|
|
@@ -170,6 +170,18 @@ static int fill_nic_context(char *subsys, char *id,
|
|
{
|
|
int rc;
|
|
|
|
+ rc = sysfs_get_int(id, subsys, "flags", &context->nic_flags);
|
|
+ /*
|
|
+ * Per spec we would need to check against Bit 0
|
|
+ * (Block Valid Flag), but some firmware only
|
|
+ * sets Bit 1 (Firmware Booting Selected).
|
|
+ * So any setting is deemed okay.
|
|
+ */
|
|
+ if (!rc && (context->nic_flags == 0))
|
|
+ rc = ENODEV;
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
rc = sysfs_get_str(id, subsys, "mac", context->mac,
|
|
sizeof(context->mac));
|
|
if (rc)
|
|
@@ -200,6 +212,9 @@ static int fill_nic_context(char *subsys, char *id,
|
|
strlcpy(context->scsi_host_name, subsys,
|
|
sizeof(context->scsi_host_name));
|
|
|
|
+ memset(&context->boot_nic, 0, sizeof(context->boot_nic));
|
|
+ snprintf(context->boot_nic, sizeof(context->boot_nic), "%s", id);
|
|
+
|
|
sysfs_get_str(id, subsys, "ip-addr", context->ipaddr,
|
|
sizeof(context->ipaddr));
|
|
sysfs_get_str(id, subsys, "vlan", context->vlan,
|
|
@@ -214,6 +229,7 @@ static int fill_nic_context(char *subsys, char *id,
|
|
sizeof(context->secondary_dns));
|
|
sysfs_get_str(id, subsys, "dhcp", context->dhcp,
|
|
sizeof(context->dhcp));
|
|
+ sysfs_get_int(id, subsys, "origin", (int *)&context->origin);
|
|
return 0;
|
|
}
|
|
|
|
@@ -224,12 +240,26 @@ static void fill_initiator_context(char *subsys, struct boot_context *context)
|
|
sizeof(context->initiatorname));
|
|
sysfs_get_str("initiator", subsys, "isid", context->isid,
|
|
sizeof(context->isid));
|
|
+
|
|
+ strlcpy(context->boot_root, subsys, sizeof(context->boot_root));
|
|
}
|
|
static int fill_tgt_context(char *subsys, char *id,
|
|
struct boot_context *context)
|
|
{
|
|
int rc;
|
|
|
|
+ rc = sysfs_get_int(id, subsys, "flags", &context->target_flags);
|
|
+ /*
|
|
+ * Per spec we would need to check against Bit 0
|
|
+ * (Block Valid Flag), but some firmware only
|
|
+ * sets Bit 1 (Firmware Booting Selected).
|
|
+ * So any setting is deemed okay.
|
|
+ */
|
|
+ if (!rc && (context->target_flags == 0))
|
|
+ rc = ENODEV;
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
rc = sysfs_get_str(id, subsys, "target-name", context->targetname,
|
|
sizeof(context->targetname));
|
|
if (rc)
|
|
@@ -240,6 +270,9 @@ static int fill_tgt_context(char *subsys, char *id,
|
|
if (rc)
|
|
return rc;
|
|
|
|
+ memset(&context->boot_target, 0, sizeof(context->boot_target));
|
|
+ snprintf(context->boot_target, sizeof(context->boot_target), "%s", id);
|
|
+
|
|
/*
|
|
* We can live without the rest of they do not exist. If we
|
|
* failed to get them we will figure it out when we login.
|
|
@@ -315,7 +348,7 @@ static int get_boot_info(struct boot_context *context, char *rootdir,
|
|
nic_cnt = 0;
|
|
tgt_cnt = 0;
|
|
if (file_exist(initiator_dir)) {
|
|
- /* Find the target's and the ethernet's */
|
|
+ /* Find the targets and the ethernets */
|
|
rc = nftw(rootdir, find_sysfs_dirs, 20, 1);
|
|
|
|
/* Find wihch target and which ethernet have
|
|
@@ -391,7 +424,7 @@ static int get_targets(struct list_head *list, char *rootdir, char *subsys)
|
|
nic_cnt = 0;
|
|
tgt_cnt = 0;
|
|
|
|
- /* Find the target's and the ethernet's */
|
|
+ /* Find the targets and the ethernets */
|
|
nftw(rootdir, find_sysfs_dirs, 20, 1);
|
|
for (i = 0; i < tgt_cnt; i++) {
|
|
context = calloc(1, sizeof(*context));
|
|
diff --git a/utils/iscsi-gen-initiatorname b/utils/iscsi-gen-initiatorname
|
|
new file mode 100755
|
|
index 0000000..88bd43b
|
|
--- /dev/null
|
|
+++ b/utils/iscsi-gen-initiatorname
|
|
@@ -0,0 +1,73 @@
|
|
+#!/bin/bash
|
|
+#
|
|
+# /sbin/iscsi-gen-initiatorname
|
|
+#
|
|
+# Generate a default iSCSI Initiatorname for SUSE installations.
|
|
+#
|
|
+# Copyright (c) 2011 Hannes Reinecke, SUSE Labs
|
|
+# This script is licensed under the GPL.
|
|
+#
|
|
+
|
|
+if [ "$1" ] ; then
|
|
+ if [ "$1" = "-f" ] ; then
|
|
+ FORCE=1
|
|
+ else
|
|
+ echo "Invalid option $1"
|
|
+ echo "Usage: $0 [-f]"
|
|
+ exit 1
|
|
+ fi
|
|
+fi
|
|
+
|
|
+if [ -d /sys/firmware/ibft/initiator ] ; then
|
|
+ read iSCSI_INITIATOR_NAME < /sys/firmware/ibft/initiator/initiator-name
|
|
+fi
|
|
+
|
|
+if [ -f /etc/iscsi/initiatorname.iscsi -a -z "$FORCE" ] ; then
|
|
+ if [ "$iSCSI_INITIATOR_NAME" ] ; then
|
|
+ eval $(cat /etc/iscsi/initiatorname.iscsi | sed -e '/^#/d')
|
|
+ if [ "$iSCSI_INITIATOR_NAME" != "$InitiatorName" ] ; then
|
|
+ echo "iSCSI Initiatorname from iBFT is different from the current setting."
|
|
+ echo "Please call '/sbin/iscsi-gen-initiatorname -f' to update the iSCSI Initiatorname."
|
|
+ exit 1
|
|
+ fi
|
|
+ fi
|
|
+fi
|
|
+
|
|
+if [ "$iSCSI_INITIATOR_NAME" ] ; then
|
|
+ cat << EOF >> /etc/iscsi/initiatorname.iscsi
|
|
+##
|
|
+## /etc/iscsi/iscsi.initiatorname
|
|
+##
|
|
+## iSCSI Initiatorname taken from iBFT BIOS tables.
|
|
+##
|
|
+## DO NOT EDIT OR REMOVE THIS FILE!
|
|
+## If you remove this file, the iSCSI daemon will not start.
|
|
+## Any change here will not be reflected to the iBFT BIOS tables.
|
|
+## If a different initiatorname is required please change the
|
|
+## initiatorname in the BIOS setup and call
|
|
+## /sbin/iscsi-gen-initiatorname -f
|
|
+## to recreate an updated version of this file.
|
|
+##
|
|
+InitiatorName=$iSCSI_INITIATOR_NAME
|
|
+EOF
|
|
+fi
|
|
+
|
|
+if [ ! -f /etc/iscsi/initiatorname.iscsi ] ; then
|
|
+ cat << EOF >> /etc/iscsi/initiatorname.iscsi
|
|
+##
|
|
+## /etc/iscsi/iscsi.initiatorname
|
|
+##
|
|
+## Default iSCSI Initiatorname.
|
|
+##
|
|
+## DO NOT EDIT OR REMOVE THIS FILE!
|
|
+## If you remove this file, the iSCSI daemon will not start.
|
|
+## If you change the InitiatorName, existing access control lists
|
|
+## may reject this initiator. The InitiatorName must be unique
|
|
+## for each iSCSI initiator. Do NOT duplicate iSCSI InitiatorNames.
|
|
+EOF
|
|
+ ISSUEDATE="1996-04"
|
|
+ INAME=$(/sbin/iscsi-iname -p iqn.$ISSUEDATE.de.suse:01)
|
|
+ printf "InitiatorName=$INAME\n" >>/etc/iscsi/initiatorname.iscsi
|
|
+ chmod 0600 /etc/iscsi/initiatorname.iscsi
|
|
+fi
|
|
+
|
|
diff --git a/utils/iscsi_offload b/utils/iscsi_offload
|
|
new file mode 100755
|
|
index 0000000..7cd1dad
|
|
--- /dev/null
|
|
+++ b/utils/iscsi_offload
|
|
@@ -0,0 +1,378 @@
|
|
+#!/bin/bash
|
|
+#
|
|
+# iscsi_offload
|
|
+#
|
|
+# Configure iSCSI offload engines for use with open-iscsi
|
|
+# Usage:
|
|
+# iscsi_offload [-d | -f | -i <ipaddr> | -t ] <nic>
|
|
+#
|
|
+# Copyright (c) 2011 Hannes Reinecke, SUSE Labs
|
|
+# This script is licensed under the GPL.
|
|
+#
|
|
+# The script creates an open-iscsi interface definition
|
|
+# in the style <nic>-<module>, where <nic> matches the
|
|
+# network interface passed on the commandline.
|
|
+# If '-t' (test mode) is passed as an option, the script
|
|
+# will not create nor modify any setting but just print
|
|
+# the currently active ones.
|
|
+#
|
|
+# Currently the script works with Broadcom (bnx2i) and
|
|
+# Chelsio T3 (cxgbi) iSCSI offload engines.
|
|
+# Should work with Chelsio T4, but has not been tested.
|
|
+# ServerEngines (be2iscsi) and QLogic (qla4xxx) can only
|
|
+# be configured via BIOS, open-iscsi support is still in
|
|
+# development.
|
|
+#
|
|
+
|
|
+#
|
|
+# Return codes:
|
|
+# 0: Success
|
|
+# 1: Invalid command line parameter
|
|
+# 2: iSCSI offloading not supported
|
|
+# 3: Error during module loading
|
|
+# 4: Cannot configure interface via iscsiadm, use BIOS setup
|
|
+# 5: internal error running iscsiadm
|
|
+#
|
|
+# Output:
|
|
+# <mac> [none|dhcp|ip <ipaddr>|ibft]
|
|
+# where
|
|
+# <mac>: MAC Address of the iSCSI offload engine
|
|
+# none: No IP configuration set for the iSCSI offload engine
|
|
+# dhcp: iSCSI offload engine configured for DHCP
|
|
+# ip: iSCSI offload engine configured with static IP address <ipaddr>
|
|
+# ibft: iSCSI offload engine configured from iBFT values
|
|
+#
|
|
+
|
|
+#
|
|
+# Figure out the MAC address of the iSCSI offload engine
|
|
+# corresponding to a NIC from a given PCI device.
|
|
+# bnx2 is using one PCI device per port for both network and iSCSI offloading
|
|
+# cxgb3 is using one PCI device for everything.
|
|
+#
|
|
+iscsi_macaddress_from_pcidevice()
|
|
+{
|
|
+ local path=$1
|
|
+ local if=$2
|
|
+ local h
|
|
+ local host
|
|
+
|
|
+ for h in $path/host* ; do
|
|
+ if [ -d "$h" ] ; then
|
|
+ host=${h##*/}
|
|
+ read netdev < /sys/class/iscsi_host/$host/netdev
|
|
+ if [ "$netdev" = "$IFNAME" ] ; then
|
|
+ read mac < /sys/class/iscsi_host/$host/hwaddress
|
|
+ if [ "$mac" != "00:00:00:00:00:00" ] ; then
|
|
+ echo "$mac"
|
|
+ fi
|
|
+ break;
|
|
+ fi
|
|
+ fi
|
|
+ done
|
|
+}
|
|
+
|
|
+#
|
|
+# Figure out the MAC address of the iSCSI offload engine
|
|
+# corresponding to a NIC from a given PCI function.
|
|
+# It is assumed that the MAC address of the iSCSI offload
|
|
+# engine is equal of the MAC address of the NIC plus one.
|
|
+# Suitable for be2iscsi and qla4xxx
|
|
+#
|
|
+iscsi_macaddress_from_pcifn()
|
|
+{
|
|
+ local path=$1
|
|
+ local if=$2
|
|
+ local h
|
|
+ local host
|
|
+ local ifmac
|
|
+
|
|
+ ifmac=$(ip addr show dev $if | sed -n 's/ *link\/ether \(.*\) brd.*/\1/p')
|
|
+ m5=$(( 0x${ifmac##*:} ))
|
|
+ m5=$(( $m5 + 1 ))
|
|
+ ifmac=$(printf "%s:%02x" ${ifmac%:*} $m5)
|
|
+ for host in /sys/class/iscsi_host/host* ; do
|
|
+ if [ -L "$host" ] ; then
|
|
+ read mac < $host/hwaddress
|
|
+ if [ "$mac" = "$ifmac" ] ; then
|
|
+ echo "$mac"
|
|
+ break;
|
|
+ fi
|
|
+ fi
|
|
+ done
|
|
+}
|
|
+
|
|
+update_iface_setting() {
|
|
+ local iface="$1"
|
|
+ local name="$2"
|
|
+ local value="$3"
|
|
+
|
|
+ iface_value=$(iscsiadm -m iface -I $iface | sed -n "s/$name = \(.*\)/\1/p")
|
|
+ if [ "$iface_value" = "<empty>" ] ; then
|
|
+ iface_value=
|
|
+ fi
|
|
+ if [ "$iface_value" != "$value" ] ; then
|
|
+ if ! iscsiadm -m iface -I $iface -o update -n "$name" -v "$value" ; then
|
|
+ return 1
|
|
+ fi
|
|
+ fi
|
|
+ return 0
|
|
+}
|
|
+
|
|
+while getopts di:t options ; do
|
|
+ case $options in
|
|
+ d ) mode=dhcp;;
|
|
+ i ) mode=static
|
|
+ optaddr=$OPTARG
|
|
+ ;;
|
|
+ f ) mode=firmware;;
|
|
+ t ) dry_run=1;;
|
|
+ ?) printf "Usage: %s [-d|-t|-i ipaddr|-f] ifname\n" $0
|
|
+ exit 1;;
|
|
+ esac
|
|
+done
|
|
+shift $(($OPTIND - 1))
|
|
+
|
|
+IFNAME=$1
|
|
+ibft_mode="none"
|
|
+
|
|
+if [ -z "$IFNAME" ] ; then
|
|
+ echo "No interface specified"
|
|
+ exit 1
|
|
+fi
|
|
+
|
|
+if [ "$dry_run" ] ; then
|
|
+ if [ "$mode" = "dhcp" ] ; then
|
|
+ echo "'-t' specified, ignoring '-d'"
|
|
+ mode=
|
|
+ elif [ "$mode" = "static" ] ; then
|
|
+ echo "'-t' specified, ignoring '-s'"
|
|
+ mode=
|
|
+ fi
|
|
+fi
|
|
+
|
|
+if [ ! -L /sys/class/net/$IFNAME ] ; then
|
|
+ echo "Interface $IFNAME not found"
|
|
+ exit 1
|
|
+fi
|
|
+
|
|
+if [ "$optaddr" ] && ! ip route get $optaddr ; then
|
|
+ echo "Invalid IP address $optaddr"
|
|
+ exit 1
|
|
+fi
|
|
+if [ "$dry_run" ] ; then
|
|
+ mode=
|
|
+fi
|
|
+
|
|
+
|
|
+ifpath=$(cd -P /sys/class/net/$IFNAME; echo $PWD)
|
|
+pcipath=$(cd -P $ifpath/device; echo $PWD)
|
|
+
|
|
+if [ -d $pcipath ] ; then
|
|
+ drvlink=$(readlink $pcipath/driver)
|
|
+ driver=${drvlink##*/}
|
|
+fi
|
|
+
|
|
+if [ -z "$driver" ] ; then
|
|
+ echo "No driver found for interface $IFNAME"
|
|
+ exit 1
|
|
+fi
|
|
+
|
|
+case "$driver" in
|
|
+ bnx2*)
|
|
+ mod=bnx2i
|
|
+ ;;
|
|
+ cxgb*)
|
|
+ mod=cxgb3i
|
|
+ ;;
|
|
+ be2*)
|
|
+ mod=be2iscsi
|
|
+ ;;
|
|
+ qla*)
|
|
+ mod=qla4xxx
|
|
+ ;;
|
|
+esac
|
|
+
|
|
+if [ -z "$mod" ] ; then
|
|
+ echo "iSCSI offloading not supported on interface $IFNAME"
|
|
+ exit 2
|
|
+fi
|
|
+
|
|
+# Check if the required modules are already loaded
|
|
+loaded=$(sed -n "/^$mod/p" /proc/modules)
|
|
+if [ -z "$loaded" ] ; then
|
|
+ modprobe $mod
|
|
+fi
|
|
+
|
|
+loaded=$(sed -n "/^$mod/p" /proc/modules)
|
|
+if [ -z "$loaded" ] ; then
|
|
+ echo "Loading of $mod.ko failed, please check dmesg"
|
|
+ exit 3
|
|
+fi
|
|
+
|
|
+# Get the correct MAC address for the various devices
|
|
+if [ "$mod" = "bnx2i" ] ; then
|
|
+ mac=$(iscsi_macaddress_from_pcidevice $pcipath $IFNAME)
|
|
+elif [ "$mod" = "cxgb3i" ] ; then
|
|
+ mac=$(iscsi_macaddress_from_pcidevice $pcipath $IFNAME)
|
|
+elif [ "$mod" = "be2iscsi" ] ; then
|
|
+ mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME)
|
|
+elif [ "$mod" = "qla4xxx" ] ; then
|
|
+ mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME)
|
|
+fi
|
|
+
|
|
+if [ -z "$mac" ] ; then
|
|
+ echo "iSCSI offloading not supported on interface $IFNAME"
|
|
+ exit 2
|
|
+fi
|
|
+
|
|
+gen_iface="$mod.$mac"
|
|
+ioe_iface="${IFNAME}-${mod}"
|
|
+
|
|
+# Get existing settings
|
|
+if iscsiadm -m iface -I $ioe_iface > /dev/null 2>&1 ; then
|
|
+ ioe_mac=$(iscsiadm -m iface -I $ioe_iface 2> /dev/null| sed -n "s/iface\.hwaddress = \(.*\)/\1/p")
|
|
+ ioe_mod=$(iscsiadm -m iface -I $ioe_iface 2> /dev/null| sed -n "s/iface\.transport_name = \(.*\)/\1/p")
|
|
+ ipaddr=$(iscsiadm -m iface -I $ioe_iface 2> /dev/null| sed -n "s/iface\.ipaddress = \(.*\)/\1/p")
|
|
+ if [ "$ipaddr" == "<empty>" ] ; then
|
|
+ ipaddr=
|
|
+ fi
|
|
+elif [ "$mod" = "be2iscsi" ] ; then
|
|
+ ioe_mac=$mac
|
|
+ ioe_mod=$mod
|
|
+else
|
|
+ # Create new interface
|
|
+ iscsiadm -m iface -I $ioe_iface --op=new 2> /dev/null
|
|
+ ioe_mac=
|
|
+ ioe_mod=
|
|
+ ipaddr=
|
|
+fi
|
|
+
|
|
+if [ -z "$dry_run" ] ; then
|
|
+ if [ "$ioe_mac" != "$mac" ] ; then
|
|
+ if [ -n "$ioe_mac" ] ; then
|
|
+ echo "Warning: Updating MAC address on iface $ioe_iface"
|
|
+ fi
|
|
+ update_iface_setting $ioe_iface iface.hwaddress "$mac"
|
|
+ fi
|
|
+
|
|
+ if [ "$ioe_mod" != "$mod" ] ; then
|
|
+ if [ -n "$ioe_mod" ] ; then
|
|
+ echo "Warning: Update transport on iface $ioe_iface"
|
|
+ fi
|
|
+ update_iface_setting $ioe_iface iface.transport_name "$mod"
|
|
+ fi
|
|
+elif [ -z "$ipaddr" ] ; then
|
|
+ ipaddr=$(iscsiadm -m iface -I $gen_iface 2> /dev/null| sed -n "s/iface\.ipaddress = \(.*\)/\1/p")
|
|
+ if [ "$ipaddr" = "<empty>" ] ; then
|
|
+ ipaddr=
|
|
+ fi
|
|
+elif [ "$ioe_mod" != "$mod" ] ; then
|
|
+ echo "Warning: Transport mismatch on iface $ioe_iface: $ioe_mod should be $mod"
|
|
+fi
|
|
+
|
|
+# Check iBFT setting
|
|
+for d in /sys/firmware/* ; do
|
|
+ [ -d $d ] || continue
|
|
+ [ -d $d/ethernet0 ] || continue
|
|
+ iboot_dir=$d
|
|
+done
|
|
+if [ -n "$iboot_dir" ] && [ -d "$iboot_dir" ] ; then
|
|
+ for if in ${iboot_dir}/ethernet* ; do
|
|
+ read ibft_mac < $if/mac
|
|
+ [ "$ibft_mac" = "$mac" ] || continue
|
|
+ ibft_origin=0
|
|
+ [ -f ${if}/origin ] && read ibft_origin < $if/origin
|
|
+ if [ "$ibft_origin" -eq 1 ] ; then
|
|
+ ibft_mode="static"
|
|
+ elif [ "$ibft_origin" -eq 3 ] ; then
|
|
+ ibft_mode="dhcp"
|
|
+ fi
|
|
+ [ -f $if/dhcp ] && read ibft_dhcp < $if/dhcp
|
|
+ if [ -n "$ibft_dhcp" -a "$ibft_mode" != "dhcp" ] ; then
|
|
+ ibft_mode=dhcp
|
|
+ fi
|
|
+ if [ "$ibft_mode" = "dhcp" ] ; then
|
|
+ ibft_ipaddr="0.0.0.0"
|
|
+ ibft_gateway=
|
|
+ ibft_mask=
|
|
+ break
|
|
+ fi
|
|
+ [ -f $if/ip-addr ] && read ibft_ipaddr < $if/ip-addr
|
|
+ [ -f $if/gateway ] && read ibft_gateway < $if/gateway
|
|
+ [ -f $if/subnet-mask ] && read ibft_mask < $if/subnet-mask
|
|
+ break
|
|
+ done
|
|
+fi
|
|
+
|
|
+if [ -z "$optaddr" ] && [ "$ibft_ipaddr" ] ; then
|
|
+ optaddr=$ibft_ipaddr
|
|
+fi
|
|
+
|
|
+# Check if the interface needs to be configured
|
|
+if [ -z "$mode" ] ; then
|
|
+ if [ "$ibft_mode" != "none" ] ; then
|
|
+ echo "$mac ibft"
|
|
+ mode="ibft"
|
|
+ elif [ -z "$ipaddr" ] ; then
|
|
+ echo "$mac none"
|
|
+ mode="none"
|
|
+ elif [ "$ipaddr" = "0.0.0.0" ] ; then
|
|
+ echo "$mac dhcp"
|
|
+ ipaddr=
|
|
+ mode="dhcp"
|
|
+ else
|
|
+ echo "$mac ip $ipaddr"
|
|
+ mode="static"
|
|
+ fi
|
|
+ [ "$dry_run" ] && exit 0
|
|
+elif [ "$mode" = "dhcp" ] ; then
|
|
+ if [ "$ipaddr" = "0.0.0.0" ] ; then
|
|
+ echo "$mac dhcp"
|
|
+ exit 0
|
|
+ fi
|
|
+ optaddr="0.0.0.0"
|
|
+elif [ "$mode" = "static" ] && [ "$ipaddr" = "$optaddr" ] ; then
|
|
+ echo "$mac ip $ipaddr"
|
|
+ exit 0
|
|
+fi
|
|
+
|
|
+if [ "$mod" = "be2iscsi" ] ; then
|
|
+ exit 4
|
|
+fi
|
|
+
|
|
+if ! update_iface_setting $ioe_iface iface.ipaddress "$optaddr" ; then
|
|
+ echo "Failed to set IP address: $?"
|
|
+ exit 1
|
|
+fi
|
|
+if ! update_iface_setting $gen_iface iface.ipaddress "$optaddr" ; then
|
|
+ echo "Failed to set IP address for generic interface: $?"
|
|
+ exit 1
|
|
+fi
|
|
+
|
|
+if ! update_iface_setting $ioe_iface iface.gateway "$ibft_gateway" ; then
|
|
+ echo "Failed to set gateway address: $?"
|
|
+ exit 1
|
|
+fi
|
|
+
|
|
+if ! update_iface_setting $gen_iface iface.gateway "$ibft_gateway" ; then
|
|
+ echo "Failed to set gateway address for generic interface: $?"
|
|
+ exit 1
|
|
+fi
|
|
+
|
|
+if ! update_iface_setting $ioe_iface iface.subnet_mask "$ibft_mask" ; then
|
|
+ echo "Failed to set subnet mask: $?"
|
|
+ exit 1
|
|
+fi
|
|
+
|
|
+if ! update_iface_setting $gen_iface iface.subnet_mask "$ibft_mask" ; then
|
|
+ echo "Failed to set subnet mask for generic interface: $?"
|
|
+ exit 1
|
|
+fi
|
|
+
|
|
+if [ "$mod" = "qla4xxx" ] ; then
|
|
+ iscsiadm -m iface -H $mac -o applyall
|
|
+fi
|
|
+ip link set dev $IFNAME up
|
|
+
|
|
+exit 0
|
|
+
|
|
diff --git a/utils/md5.c b/utils/md5.c
|
|
index 53956c6..cbe8d08 100644
|
|
--- a/utils/md5.c
|
|
+++ b/utils/md5.c
|
|
@@ -133,7 +133,7 @@ MD5Final(md5byte digest[16], struct MD5Context *ctx)
|
|
|
|
byteSwap(ctx->buf, 4);
|
|
memcpy(digest, ctx->buf, 16);
|
|
- memset(ctx, 0, sizeof (ctx)); /* In case it's sensitive */
|
|
+ memset(ctx, 0, sizeof (*ctx)); /* In case it's sensitive */
|
|
}
|
|
|
|
#ifndef ASM_MD5
|
|
diff --git a/utils/open-isns/bitvector.c b/utils/open-isns/bitvector.c
|
|
index 3e23f26..9d66276 100644
|
|
--- a/utils/open-isns/bitvector.c
|
|
+++ b/utils/open-isns/bitvector.c
|
|
@@ -327,10 +327,10 @@ isns_bitvector_is_empty(const isns_bitvector_t *bv)
|
|
wp = bv->ib_words;
|
|
end = wp + bv->ib_count;
|
|
while (wp < end) {
|
|
- unsigned int base, rlen;
|
|
+ unsigned int rlen;
|
|
|
|
- base = *wp++;
|
|
- rlen = *wp++;
|
|
+ rlen = wp[1];
|
|
+ wp += 2;
|
|
|
|
while (rlen--) {
|
|
if (*wp++)
|
|
@@ -462,11 +462,10 @@ isns_bitvector_foreach(const isns_bitvector_t *bv,
|
|
wp = bv->ib_words;
|
|
end = wp + bv->ib_count;
|
|
while (wp < end) {
|
|
- unsigned int base, rlen, bits;
|
|
+ unsigned int base, rlen;
|
|
|
|
base = wp[0];
|
|
rlen = wp[1];
|
|
- bits = rlen * 32;
|
|
wp += 2;
|
|
|
|
while (rlen--) {
|
|
@@ -492,11 +491,10 @@ isns_bitvector_dump(const isns_bitvector_t *bv, isns_print_fn_t *fn)
|
|
wp = bv->ib_words;
|
|
end = wp + bv->ib_count;
|
|
while (wp < end) {
|
|
- unsigned int base, rlen, bits;
|
|
+ unsigned int base, rlen;
|
|
|
|
base = wp[0];
|
|
rlen = wp[1];
|
|
- bits = rlen * 32;
|
|
wp += 2;
|
|
|
|
fn(" <%u:", base);
|
|
@@ -538,11 +536,10 @@ isns_bitvector_print(const isns_bitvector_t *bv,
|
|
wp = bv->ib_words;
|
|
end = wp + bv->ib_count;
|
|
while (wp < end) {
|
|
- unsigned int base, rlen, bits;
|
|
+ unsigned int base, rlen;
|
|
|
|
base = wp[0];
|
|
rlen = wp[1];
|
|
- bits = rlen * 32;
|
|
wp += 2;
|
|
|
|
while (rlen--) {
|
|
diff --git a/utils/open-isns/dd.c b/utils/open-isns/dd.c
|
|
index b392036..c2dcd10 100644
|
|
--- a/utils/open-isns/dd.c
|
|
+++ b/utils/open-isns/dd.c
|
|
@@ -599,10 +599,9 @@ isns_dd_insert(isns_dd_t *dd)
|
|
void
|
|
isns_dd_list_resize(isns_dd_list_t *list, unsigned int last_index)
|
|
{
|
|
- unsigned int new_size, cur_size;
|
|
+ unsigned int new_size;
|
|
isns_dd_t **new_data;
|
|
|
|
- cur_size = LIST_SIZE(list->ddl_count);
|
|
new_size = LIST_SIZE(last_index + 1);
|
|
if (new_size < list->ddl_count)
|
|
return;
|
|
diff --git a/utils/open-isns/doc/isnsadm.8 b/utils/open-isns/doc/isnsadm.8
|
|
index c3e2b83..88ec4cf 100644
|
|
--- a/utils/open-isns/doc/isnsadm.8
|
|
+++ b/utils/open-isns/doc/isnsadm.8
|
|
@@ -25,6 +25,10 @@ isnsadm \- iSNS client utility
|
|
.PP
|
|
.B isnsadm
|
|
.RB [ ... ]
|
|
+.RI --dd-deregister " dd-id attr=value
|
|
+.PP
|
|
+.B isnsadm
|
|
+.RB [ ... ]
|
|
.RI --enroll " client-name attr=value
|
|
.PP
|
|
.B isnsadm
|
|
@@ -452,6 +456,18 @@ Note, in order to add members to an existing domain, you must
|
|
specify the domain's numeric ID. The domain's symbolic name
|
|
is not a valid handle when referring to a discovery domain.
|
|
.\"---------------------------
|
|
+.SS Discovery Domain Deregistration mode
|
|
+In this mode, you can deregister a discoery domain previously registered.
|
|
+Only the node which registered a discovery domain in the first place is
|
|
+permitted to remove it, or any of its members. (Control
|
|
+nodes are not bound by this restriction).
|
|
+.PP
|
|
+In Discovery Domain deregistration mode, the argument list consists of
|
|
+the Discovery Domain ID, followed by a list of
|
|
+.IB attr = value
|
|
+pairs. Discovery Domain Deregistration supports the same set of attributes as
|
|
+query mode.
|
|
+.\"---------------------------
|
|
.SS Client Enrollment
|
|
This mode only works when the server recognizes the client
|
|
as having control node capabilities, which is possible in
|
|
diff --git a/utils/open-isns/isnsadm.c b/utils/open-isns/isnsadm.c
|
|
index fadd87d..db34f8f 100644
|
|
--- a/utils/open-isns/isnsadm.c
|
|
+++ b/utils/open-isns/isnsadm.c
|
|
@@ -272,6 +272,8 @@ usage(int exval, const char *msg)
|
|
"\nThe following actions are supported:\n"
|
|
" --register Register one or more objects\n"
|
|
" --deregister Deregister an object (and children)\n"
|
|
+ " --dd-register Register a Discovery Domain (and members)\n"
|
|
+ " --dd-deregister Deregister a Discovery Domain (and members)\n"
|
|
" --query Query iSNS server for objects\n"
|
|
" --list List all objects of a given type\n"
|
|
" --enroll Create a new policy object for a client\n"
|
|
diff --git a/utils/sysdeps/Makefile b/utils/sysdeps/Makefile
|
|
index 53c10e5..4299164 100644
|
|
--- a/utils/sysdeps/Makefile
|
|
+++ b/utils/sysdeps/Makefile
|
|
@@ -1,6 +1,7 @@
|
|
# This Makefile will work only with GNU make.
|
|
|
|
-CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -O2 -fno-inline -Wall -Wstrict-prototypes -g
|
|
+CFLAGS ?= -O2 -fno-inline -g
|
|
+CFLAGS += $(WARNFLAGS) -Wall -Wstrict-prototypes
|
|
|
|
SYSDEPS_OBJS=sysdeps.o
|
|
|
|
--
|
|
2.1.0
|
|
|